def OnRun(self, msg: JSON) -> None: """ Callback function for whenever a queued messages should be activated. This implementation makes sure the effect properly runs for the specified duration, so if you need to overwrite it make sure to call this function from your's. If the effect is already running then this function will restart the timer. """ AsyncUtil.CancelFutureCallbacks(f"CC-{self.Name}-Stop") self.OnStart(msg) AsyncUtil.RunIn(self._DurationOption.CurrentValue, self.OnEnd, f"CC-{self.Name}-Stop")
def OnRun(self, msg: JSON) -> None: time: float = 0 for i in range(4): time += max(0, random.uniform( self.DROP_DELAY - self.DROP_VARIATION, self.DROP_DELAY - self.DROP_VARIATION )) AsyncUtil.RunIn( time, unrealsdk.GetEngine().GamePlayers[0].Actor.ServerThrowPawnActiveWeapon ) if i == 1: AsyncUtil.RunIn(time + self.DISPLAY_DELAY, lambda: self.ShowRedemption(msg))
def ModOptionChanged(self, option: unrealsdk.Options.Boolean, new_value: bool) -> None: if option != self.UpdatingOption: return # If you turn on updating and there are people close to vendors, start updating if new_value: if len(self.TouchingActors) > 0: AsyncUtil.RunEvery(self.UPDATE_DELAY, self.OnUpdate, self.Name) # If you turn off updating, stop updating and make sure all vendors are usable at no cost else: AsyncUtil.CancelFutureCallbacks(self.Name) for vendor in unrealsdk.FindAll("WillowVendingMachine"): if vendor.ShopType == 1 or vendor.ShopType == 2: vendor.SetUsability(True, 1) vendor.Behavior_ChangeUsabilityCost(1, 0, 0, 1)
def WillowClientDisableLoadingMovie(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: # On level change reset all our caching self.TouchingActors = {} self.VialCosts = {} self.AmmoCosts = {} self.PlayerAmmoPools = {} AsyncUtil.CancelFutureCallbacks(self.Name) return True
def OnEnd(self) -> None: ShowChatMessage("Crowd Control:", f"{self.Name} wore off.", ShowTimestamp=False) unrealsdk.RemoveHook("WillowGame.WillowHUDGFxMovie.Start", "CCHideHUD") # Seems the hook sticks around a tick or something, this doesn't work unless I delay it AsyncUtil.RunIn(0.05, unrealsdk.GetEngine().GamePlayers[0].Actor.DisplayHUD)
def Disable(self) -> None: AsyncUtil.CancelFutureCallbacks(self.Name) unrealsdk.RemoveHook("WillowGame.WillowInteractiveObject.ConditionalReactToUse", self.Name) unrealsdk.RemoveHook("WillowGame.WillowInteractiveObject.InitializeFromDefinition", self.Name) unrealsdk.RemoveHook("WillowGame.WillowInteractiveObject.Touch", self.Name) unrealsdk.RemoveHook("WillowGame.WillowInteractiveObject.UnTouch", self.Name) unrealsdk.RemoveHook("WillowGame.WillowPlayerController.WillowClientDisableLoadingMovie", self.Name) unrealsdk.RemoveHook("WillowGame.WillowVendingMachine.GenerateInventory", self.Name) unrealsdk.RemoveHook("WillowGame.WillowPlayerController.PayForUsedObject", self.Name)
def Enable(self) -> None: if self.Token is None: return startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= STARTF_USESHOWWINDOW startupinfo.wShowWindow = SW_SHOWMINNOACTIVE self._listener = subprocess.Popen( ["python", "-m", "Listener", self.Token], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.BASE_PATH, startupinfo=startupinfo) def OnTick() -> None: if self._listener is None: return if self._listener.poll() is not None: # Since the lister has quit we can safely call read without blocking # Only do this on stderr though cause that's where exceptions go if self._listener.stderr is not None: line = self._listener.stderr.read() if len(line) > 0: self.HandleStderr( line.decode("utf8").replace("\\n", "\n")[:-2]) self.HandleChildQuit() return if self._listener.stdout is not None and GetPipeAvailableLen( self._listener.stdout) > 0: line = self._listener.stdout.readline() self.HandleStdout( line.decode("utf8").replace("\\n", "\n")[:-2]) if self._listener.stderr is not None and GetPipeAvailableLen( self._listener.stderr) > 0: line = self._listener.stderr.readline() self.HandleStderr( line.decode("utf8").replace("\\n", "\n")[:-2]) def OnQuit(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if self._listener is not None: self._listener.kill() return True AsyncUtil.RunEveryTick(OnTick, self.Name) # TODO: better quit hook unrealsdk.RegisterHook( "WillowGame.FrontendGFxMovie.ConfirmQuit_Clicked", self.Name, OnQuit) for callback in Effects.ON_ENABLE: callback()
def Disable(self) -> None: AsyncUtil.CancelFutureCallbacks("CrowdControl") unrealsdk.RemoveHook("WillowGame.FrontendGFxMovie.ConfirmQuit_Clicked", "CrowdControl") if self._listener is not None: self._listener.kill() self._listener = None for callback in Effects.ON_DISABLE: callback()
def Disable(self) -> None: AsyncUtil.CancelFutureCallbacks(self.Name) unrealsdk.RemoveHook( "WillowGame.WillowInteractiveObject.ConditionalReactToUse", self.Name) unrealsdk.RemoveHook( "WillowGame.WillowInteractiveObject.InitializeFromDefinition", self.Name) unrealsdk.RemoveHook("WillowGame.WillowInteractiveObject.Touch", self.Name) unrealsdk.RemoveHook("WillowGame.WillowInteractiveObject.UnTouch", self.Name)
def OnRun(self, msg: JSON) -> None: # Replicate `self.ShowRedemption()` but using the fake name def Internal() -> None: user = "******" try: user = msg["data"]["redemption"]["user"]["login"] except KeyError: pass ShowHUDMessage("Crowd Control", f"{user} redeemed '{self.FakeName}'") AsyncUtil.RunIn(0.1, Internal)
def Touch(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if not self.UpdatingOption.CurrentValue: return True if str(caller).split(" ")[0] != "WillowVendingMachine": return True self.TouchingActors.add(params.Other) if self.UpdatingOption.CurrentValue and len( self.TouchingActors) == 1: AsyncUtil.RunEvery(self.UPDATE_DELAY, self.OnUpdate, self.Name) return True
def ShowFailedMessage(self, msg: JSON) -> None: def Internal() -> None: user = "******" try: user = msg["data"]["redemption"]["user"]["login"] except KeyError: pass ShowHUDMessage( "Crowd Control", f"{user} tried to redeem '{self.Name}', but forgot that this world doesn't have any enemies." ) # There's a small delay after closing menus before we can properly show a message AsyncUtil.RunIn(0.1, Internal)
def UnTouch(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if str(caller).split(" ")[0] != "WillowVendingMachine": return True try: self.TouchingActors.remove(params.Other) except KeyError: # If the player is not already in the set pass if self.UpdatingOption.CurrentValue and len( self.TouchingActors) == 0: AsyncUtil.CancelFutureCallbacks(self.Name) return True
def Touch(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller.Class.Name != "WillowVendingMachine": return True if params.Other.Class.Name != "WillowPlayerPawn": return True # If no one's currently near a vendor, but is about to be, and if updating costs are on, # start the update loop if self.UpdatingOption.CurrentValue and len(self.TouchingActors) == 0: AsyncUtil.RunEvery(self.UPDATE_DELAY, self.OnUpdate, self.Name) if caller not in self.TouchingActors: self.TouchingActors[caller] = set() self.TouchingActors[caller].add(params.Other) return True
def UnTouch(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller.Class.Name != "WillowVendingMachine": return True if params.Other.Class.Name != "WillowPlayerPawn": return True try: self.TouchingActors[caller].remove(params.Other) if len(self.TouchingActors[caller]) == 0: del self.TouchingActors[caller] except (KeyError, ValueError): # If the player or vendor aren't in the dict pass if self.UpdatingOption.CurrentValue and len(self.TouchingActors) == 0: AsyncUtil.CancelFutureCallbacks(self.Name) return True
def OnRedeem(self, msg: JSON) -> None: """ Callback function called whenever someone redeems the reward associated with this effect. This implementation adds messages to the queue - if you need to overwrite it make sure to call this function from your's. """ def _RunFront() -> None: self.OnRun(self._Queue[0]) AsyncUtil.RunIn(self._IntervalOption.CurrentValue, _Loop) def _Loop() -> None: self._Queue.pop(0) if len(self._Queue) > 0: AsyncUtil.RunWhen(self.Condition, _RunFront) self._Queue.append(msg) if len(self._Queue) == 1: AsyncUtil.RunWhen(self.Condition, _RunFront)
def OnRun(self, msg: JSON) -> None: def Internal() -> None: self.ShowRedemption(msg) PC = unrealsdk.GetEngine().GamePlayers[0].Actor wanted_vel = max(self.MIN_VELOCITY, maths.sqrt(PC.Pawn.Velocity.X ** 2 + PC.Pawn.Velocity.Y ** 2)) conversion = maths.pi / 0x7fff PC.Pawn.DoJump(PC.bUpdating) PC.Pawn.Velocity = ( maths.cos(PC.Rotation.Yaw * conversion) * wanted_vel, maths.sin(PC.Rotation.Yaw * conversion) * wanted_vel, PC.Pawn.Velocity.Z # This now includes jumping velocity ) # There's a bit of a delay after unpausing before this works right AsyncUtil.RunIn(0.2, Internal)
def ShowRedemption(self, msg: JSON) -> None: """ Small helper function that displays a UserFeedback HUDMessage with info about who redeemed this effect. Args: msg: The decoded JSON channel points event message. """ def Internal() -> None: user = "******" try: user = msg["data"]["redemption"]["user"]["login"] except KeyError: pass ShowHUDMessage("Crowd Control", f"{user} redeemed '{self.Name}'") # There's a small delay after closing menus before we can properly show a message AsyncUtil.RunIn(0.1, Internal)
def _RunFront() -> None: self.OnRun(self._Queue[0]) AsyncUtil.RunIn(self._IntervalOption.CurrentValue, _Loop)
def OnRun(self, msg: JSON) -> None: unrealsdk.GetEngine().GamePlayers[0].Actor.ServerThrowPawnActiveWeapon() AsyncUtil.RunIn(self.DISPLAY_DELAY, lambda: self.ShowRedemption(msg))
def OnRun(self, msg: JSON) -> None: self.ShowRedemption(msg) AsyncUtil.RunIn(self.TIME_BEFORE_ACTIVATE, lambda: AsyncUtil.RunWhen(IsInGame, self.Activate))
def _Loop() -> None: self._Queue.pop(0) if len(self._Queue) > 0: AsyncUtil.RunWhen(self.Condition, _RunFront)
def Execute(self) -> None: AsyncUtil.RunIn(self.Delay, self.OnFinishExecution)