def Enable(self) -> None: def WillowClientDisableLoadingMovie(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: for clas, handler in self.CLASS_HANDLER_MAP.items(): for obj in unrealsdk.FindAll(clas): if obj not in self.MenuObjects: handler(obj) return True unrealsdk.RegisterHook( "WillowGame.WillowPlayerController.WillowClientDisableLoadingMovie", self.Name, WillowClientDisableLoadingMovie) # If you're re-enabling then we can exit right here, the rest of this is non-reversible if len(self.MenuObjects) > 0: return # Objects we load here will still be alive for all the FindAll commands, we don't need to # parse them yet for package, objects in self.FORCE_LOAD.items(): unrealsdk.LoadPackage(package) for obj_name in objects: obj = unrealsdk.FindObject(obj_name[0], obj_name[1]) if obj is None: unrealsdk.Log( f"[{self.Name}] Unable to find object '{obj_name[1]}'") unrealsdk.KeepAlive(obj) # Do our inital parse over everything, saving what we can access for clas, handler in self.CLASS_HANDLER_MAP.items(): for obj in unrealsdk.FindAll(clas): self.MenuObjects.add(obj) handler(obj)
def Enable(self) -> None: def CreateWeaponScopeMovie(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: for clas, handler in self.CLASS_HANDLER_MAP.items(): for obj in unrealsdk.FindAll(clas): if obj not in self.MenuObjects: handler(obj) return True unrealsdk.RegisterHook("WillowGame.WillowHUD.CreateWeaponScopeMovie", "ItemLevelUncapper", CreateWeaponScopeMovie) # If you're re-enabling then we can exit right here, the rest of this is non-reversible if len(self.MenuObjects) > 0: return # Objects we load here will still be alive for all the FindAll commands, we don't need to # parse them yet for package, objects in self.FORCE_LOAD.items(): unrealsdk.LoadPackage(package) for obj in objects: unrealsdk.KeepAlive(unrealsdk.FindObject(obj[0], obj[1])) # Do our inital parse over everything, saving what we can access for clas, handler in self.CLASS_HANDLER_MAP.items(): for obj in unrealsdk.FindAll(clas): self.MenuObjects.add(obj) handler(obj)
def load_packages(self, packages): """ Load the specified packages, then wait for the given delay """ for pkg in packages: unrealsdk.LoadPackage(pkg) self.setNextDelay(self.pkgload_delay)
def handle_load_package(args: argparse.Namespace) -> None: upks = fnmatch.filter(all_upks, args.package) if len(upks) <= 0: unrealsdk.Log(f"Could not find package '{args.package}'!") elif len(upks) > 10: unrealsdk.Log(f"'{args.package}' matches more than 10 packages!") else: for package in upks: unrealsdk.LoadPackage(package)
def ForceLoad(self): # Needed for the cool Katana moves unrealsdk.LoadPackage("GD_Assassin_Streaming_SF") unrealsdk.KeepAlive( unrealsdk.FindObject( "WillowAnimDefinition", "GD_Assassin_Hologram.SpecialMove.SpecialMove_HologramScrewAround" )) unrealsdk.KeepAlive( unrealsdk.FindObject("AnimSet", "Anim_Assassin.Base_Assassin")) # We dont want these animations to unload Objects = [ "GD_NPCShared.Perches.Perch_NPC_ArmsCrossedForever:SpecialMove_PerchLoop_0", "GD_NPCShared.Perches.Perch_NPC_BangOnSomething:SpecialMove_PerchLoop_0", "GD_NPCShared.Perches.Perch_NPC_BarrelSitForever:SpecialMove_PerchLoop_0", "GD_NPCShared.Perches.Perch_NPC_ChairSitForever:SpecialMove_PerchLoop_0", "GD_NPCShared.Perches.Perch_NPC_DartsHit:SpecialMove_PerchLoop_0", "GD_NPCShared.Perches.Perch_NPC_KickGround:SpecialMove_PerchLoop_0", "GD_NPCShared.Perches.Perch_NPC_LeanOnCounterForever:SpecialMove_PerchLoop_0", "GD_NPCShared.Perches.Perch_NPC_LeanOnWallNonRandom:SpecialMove_PerchLoop_0", "GD_NPCShared.Perches.Perch_NPC_LookAtGround:SpecialMove_PerchLoop_0", "GD_NPCShared.Perches.Perch_NPC_PeerUnder:SpecialMove_PerchLoop_0", "GD_Moxxi.Perches.Perch_Moxxi_Dance:SpecialMove_PerchLoop_0", "GD_Moxxi.Perches.Perch_Moxxi_WipeBar:SpecialMove_PerchLoop_0", "GD_TannisNPC.Perches.Perch_Tannis_HandsOnHips:SpecialMove_PerchLoop_0", "GD_BrickNPC.Perches.Perch_Brick_Pushups:SpecialMove_PerchLoop_0" ] unrealsdk.LoadPackage("SanctuaryAir_Dynamic") for Object in Objects: x = unrealsdk.FindObject("SpecialMove_PerchLoop", Object) unrealsdk.KeepAlive(x) # This are our Particles that can be used Particles = [ "FX_ENV_Misc.Particles.Part_Confetti", "FX_Distillery.Particles.PS_Hearts_Looping_8-Bit", "FX_CHAR_Merc.Particles.Part_Merc_MoneyShotImpact", "FX_Distillery.Particles.PS_Nast_Drunk_Thresher" ] unrealsdk.LoadPackage("Distillery_Dynamic") unrealsdk.LoadPackage("Distillery_Mission") unrealsdk.LoadPackage("GD_Mercenary_Streaming_SF") for Particle in Particles: x = unrealsdk.FindObject("ParticleSystem", Particle) unrealsdk.KeepAlive(x)
def __init__(self) -> None: unrealsdk.LoadPackage("GD_Mercenary_Streaming_SF") self.NumWeapObj = unrealsdk.FindObject( "NumberWeaponsEquippedExpressionEvaluator", "GD_Mercenary_Skills.ActionSkill.Skill_Gunzerking:ExpressionTree_0.NumberWeaponsEquippedExpressionEvaluator_0" ) unrealsdk.KeepAlive(self.NumWeapObj) if self.NumWeapObj is None: del self.SettingsInputs["Enter"] self.WeaponMap = {}
def PreloadPackages(self): packages = [ "GD_Assassin_Streaming_SF", "GD_Mercenary_Streaming_SF", "GD_Siren_Streaming_SF", "GD_Lilac_Psycho_Streaming_SF", "GD_Tulip_Mechro_Streaming_SF", "GD_Soldier_Streaming_SF", ] for package in packages: unrealsdk.LoadPackage(package)
def keep_loaded(self) -> None: """ Small helper function for easily keeping objects loaded. "#" defines what Package to load, "-" are comments. Searches for any text file with the custom ending ".loaded" and tries to keep the objects listet in the file loaded. """ for file in self.l_files: with open(file, "r") as TemplateFile: for line in TemplateFile: if not line.split() or line[0] == "-": continue elif line[0] == "#": package = line[1:].strip() unrealsdk.LoadPackage(package) else: unrealsdk.KeepAlive(unrealsdk.FindObject("Object", line.strip()))
def __init__(self) -> None: # Hopefully I can remove this in a future SDK update self.Author += "\nVersion: " + str(self.Version) # type: ignore unrealsdk.LoadPackage("GD_Mercenary_Streaming_SF") obj = unrealsdk.FindObject( "NumberWeaponsEquippedExpressionEvaluator", "GD_Mercenary_Skills.ActionSkill.Skill_Gunzerking:ExpressionTree_0.NumberWeaponsEquippedExpressionEvaluator_0" ) # Almost certainly because you tried to load this in TPS if obj is None: unrealsdk.Log( "[Onezerker] Unable to find NumberWeaponsEquiped object, assuming loaded in TPS" ) self.Name = f"<font color='#ff0000'>{self.Name}</font>" # type: ignore self.Description += "\n<font color='#ff0000'>Incompatible with TPS</font>" # type: ignore self.SettingsInputs = {} self.NumWeapObj = None else: unrealsdk.KeepAlive(obj) self.NumWeapObj = obj self.WeaponMap = {}
def on_end_load(self, curr_map: str) -> None: if logging.logger.level in logging.logger.levels[:2]: self.load_files() # After the map loads, we want to check our loaded file data for things to spawn. random_spawn_group = {} add_to_group = None in_class = None region_game_stage: int = set_iterpreter.get_current_region_stage() b_skip_to_next: bool = False b_skip_once: bool = False for line in self.file_data: # type: str try: if line[0] == "/": # we now want to check if it's the map we just loaded in if line[1:].strip().lower() == curr_map or line[1:].strip( ).lower() == "none": b_skip_to_next = False continue else: b_skip_to_next = True elif line[0] == "-" or b_skip_to_next: continue elif line[0] == "!": unrealsdk.LoadPackage(line[1:].strip()) elif line[ 0] == "#": # We now have the class of the objects that we will spawn in_class: str in_class = line[1:].lstrip() elif line[0] == "+": # check the given conditions __conditional_ret = set_iterpreter.check_conditions( line[1:]) if isinstance(__conditional_ret, bool): b_skip_once = __conditional_ret else: add_to_group = __conditional_ret else: # This should now be the "<Object> <Location> <Rotation> [level offset] if b_skip_once: # earlier given conditions failed, skip this b_skip_once = False continue if add_to_group is not None: random_spawn_group.setdefault( in_class, {add_to_group: []})[add_to_group].append( (line, region_game_stage)) add_to_group = None # we always only want to add the next line to the group else: # if not added to randomGroup just exec now if in_class.lower() == "WeaponBalanceDefinition".lower() \ or in_class.lower() == "InventoryBalanceDefinition".lower(): self.spawn_item_from_balance_definition( in_class, line, region_game_stage) elif in_class.lower( ) == "AIPawnBalanceDefinition".lower(): self.spawn_ai_pawn(line, region_game_stage) elif in_class.lower() == "InteractiveObjectBalanceDefinition".lower() \ or in_class.lower() == "InteractiveObjectDefinition".lower(): self.spawn_interactive_object( line, region_game_stage) except Exception as e: logging.logger.error(repr(e)) logging.logger.error( f"Please check the following line in your .spawn file:\n-> {line}" ) for cls, group in random_spawn_group.items(): for g_name, choice_of in group.items(): l: Tuple[str, int] = random.choice(choice_of) try: if cls.lower() == "WeaponBalanceDefinition".lower() \ or cls.lower() == "InventoryBalanceDefinition".lower(): self.spawn_item_from_balance_definition(cls, *l) elif cls.lower() == "AIPawnBalanceDefinition".lower(): self.spawn_ai_pawn(*l) elif in_class.lower() == "InteractiveObjectBalanceDefinition".lower() \ or in_class.lower() == "InteractiveObjectDefinition".lower(): self.spawn_interactive_object(*l) except Exception as e: logging.logger.error(repr(e)) logging.logger.error( f"Please check the following line in your .spawn file:\n-> {l}" )
def Enable(self) -> None: unrealsdk.LoadPackage("GD_Mercenary_Streaming_SF") self.NumWeapObj = unrealsdk.FindObject( "NumberWeaponsEquippedExpressionEvaluator", "GD_Mercenary_Skills.ActionSkill.Skill_Gunzerking:ExpressionTree_0.NumberWeaponsEquippedExpressionEvaluator_0" ) unrealsdk.KeepAlive(self.NumWeapObj) if self.NumWeapObj is None: unrealsdk.Log(f"[{self.Name}] Didn't load correctly, not enabling") self.SettingsInputPressed("Disable") return self.NumWeapObj.NumberOfWeapons = 1 def OnActionSkillEnded(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller.MyWillowPC != unrealsdk.GetEngine().GamePlayers[0].Actor: return True self.WeaponMap = {} return True def EquipInitialWeapons(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller.MyWillowPC != unrealsdk.GetEngine().GamePlayers[0].Actor: return True if caller.MyWillowPawn is None: return True weap = caller.MyWillowPawn.Weapon if weap is None: return False # This is the only real bit of the function we overwrite weap_alt = self.DupeWeapon(weap) caller.MyWillowPawn.OffHandWeapon = weap_alt caller.MyWillowPawn.InvManager.SetCurrentWeapon(weap, False) caller.MyWillowPawn.InvManager.SetCurrentWeapon(weap_alt, True) weap.RefillClip() weap_alt.RefillClip() if caller.MyWillowPC.bInSprintState: caller.SetTimer( min(weap.GetEquipTime(), weap_alt.GetEquipTime()), False, "SprintTransition") caller.SetLeftSideControl() return False # Called when switching weapons by scrolling/controller quick switch def NextWeapon(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: return ScrollWeapons(caller, True) def PrevWeapon(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: return ScrollWeapons(caller, False) def ScrollWeapons(caller: unrealsdk.UObject, next: bool) -> bool: pawn = unrealsdk.GetEngine().GamePlayers[0].Actor.Pawn if caller.Owner != pawn: return True if pawn.MyActionSkill is None: return True if pawn.MyActionSkill.Class.Name != "DualWieldActionSkill": return True weapon_list = [None, None, None, None] weapon = pawn.InvManager.InventoryChain while weapon is not None: weapon_list[weapon.QuickSelectSlot - 1] = weapon weapon = weapon.Inventory # Don't think this could actually happen but to be safe if weapon_list.count(None) >= 4: return True index = pawn.Weapon.QuickSelectSlot - 1 if next: index = (index + 1) % 4 while weapon_list[index] is None: index = (index + 1) % 4 else: index = (index - 1) % 4 while weapon_list[index] is None: index = (index - 1) % 4 weapon = weapon_list[index] weap_alt = self.DupeWeapon(weapon) pawn.InvManager.SetCurrentWeapon(weapon, False) pawn.InvManager.SetCurrentWeapon(weap_alt, True) pawn.MyActionSkill.SetOffHandCrosshair(weap_alt) return False # Called when switching weapons (while gunzerking) using the number keys/dpad def SwitchToWeapon(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller.MyWillowPC != unrealsdk.GetEngine().GamePlayers[0].Actor: return True if params.NewWeapon != caller.MyWillowPawn.Weapon: caller.MyWillowPawn.InvManager.SetCurrentWeapon( params.NewWeapon, False) weap_alt = self.DupeWeapon(params.NewWeapon) caller.MyWillowPawn.InvManager.SetCurrentWeapon(weap_alt, True) caller.SetOffHandCrosshair(weap_alt) return False # Called on exiting menus def BringWeaponsUpAfterPutDown(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller.MyWillowPC != unrealsdk.GetEngine().GamePlayers[0].Actor: return True weapon = caller.MyWillowPawn.InvManager.InventoryChain while weapon is not None: if weapon.QuickSelectSlot == params.MainHandWeaponSlot: break weapon = weapon.Inventory # If you dropped the equiped slot default to the start of the list - not sure if other # behaviour might be better? if weapon is None: weapon = caller.MyWillowPawn.InvManager.InventoryChain # If you dropped all weapons just let the game handle it if weapon is None: return True caller.ForceRefreshSkills() caller.ClientBringWeaponsUpAfterPutDown(weapon, self.DupeWeapon(weapon)) return False def ApplyBehaviorToContext(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: """ The only `Behavior_RefillWeapon` is auto loader - this is only called when it triggers All the other hooks guarentee that items only get duplicated if they're from the local player, so we can assume that if an item is in the map, the local player owns it. Auto loader only reloads unequipped weapons, so we can also guarentee that you will have to go through one of the other hooks to switch back to it. Because of this we can just remove the object from the map, it'll get recreated. For some reason just replicating the `.RefillClip()` call doesn't work. Now this might break if you do inventory merging, but really that's kinda on you. """ if params.ContextObject in self.WeaponMap: del self.WeaponMap[params.ContextObject] return True # These two are identical except for the bit where I re-call the hooked function # I wish there was a neat way to merge them def TossInventory(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: pawn = unrealsdk.GetEngine().GamePlayers[0].Actor.Pawn if caller != pawn: return True if pawn.MyActionSkill is None: return True if pawn.MyActionSkill.Class.Name != "DualWieldActionSkill": return True unrealsdk.DoInjectedCallNext() caller.TossInventory( params.Inv, (params.ForceVelocity.X, params.ForceVelocity.Y, params.ForceVelocity.Z)) if pawn.Weapon is not None: pawn.InvManager.SetCurrentWeapon(self.DupeWeapon(pawn.Weapon), True) return False def EndClimbLadder(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: pawn = unrealsdk.GetEngine().GamePlayers[0].Actor.Pawn if caller != pawn: return True if pawn.MyActionSkill is None: return True if pawn.MyActionSkill.Class.Name != "DualWieldActionSkill": return True unrealsdk.DoInjectedCallNext() caller.EndClimbLadder(params.OldLadder) if pawn.Weapon is not None: pawn.InvManager.SetCurrentWeapon(self.DupeWeapon(pawn.Weapon), True) return False """ Called whenever anyone: 1. Picks up a weapon while having empty slots available 2. Equips a new weapon in your inventory screen 3. Force equip a new weapon Very conviniently, in case 3 alone the paramater "bDoNotActivate" is false """ def ClientGivenTo(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: pawn = unrealsdk.GetEngine().GamePlayers[0].Actor.Pawn if params.NewOwner != pawn: return True if params.bDoNotActivate: return True if pawn.MyActionSkill is None: return True if pawn.MyActionSkill.Class.Name != "DualWieldActionSkill": return True pawn.InvManager.SetCurrentWeapon(self.DupeWeapon(caller), True) return True unrealsdk.RegisterHook( "WillowGame.DualWieldActionSkill.OnActionSkillEnded", self.Name, OnActionSkillEnded) unrealsdk.RegisterHook( "WillowGame.DualWieldActionSkill.EquipInitialWeapons", self.Name, EquipInitialWeapons) unrealsdk.RegisterHook("WillowGame.WillowInventoryManager.NextWeapon", self.Name, NextWeapon) unrealsdk.RegisterHook("WillowGame.WillowInventoryManager.PrevWeapon", self.Name, PrevWeapon) unrealsdk.RegisterHook( "WillowGame.DualWieldActionSkill.SwitchToWeapon", self.Name, SwitchToWeapon) unrealsdk.RegisterHook( "WillowGame.DualWieldActionSkill.BringWeaponsUpAfterPutDown", self.Name, BringWeaponsUpAfterPutDown) unrealsdk.RegisterHook( "WillowGame.Behavior_RefillWeapon.ApplyBehaviorToContext", self.Name, ApplyBehaviorToContext) unrealsdk.RegisterHook("WillowGame.WillowPawn.TossInventory", self.Name, TossInventory) unrealsdk.RegisterHook("WillowGame.WillowPlayerPawn.EndClimbLadder", self.Name, EndClimbLadder) unrealsdk.RegisterHook("Engine.Weapon.ClientGivenTo", self.Name, ClientGivenTo)