From 5e8cd8b24681290234004dcfe414e3bb9e0d8559 Mon Sep 17 00:00:00 2001 From: Jovan Gerodetti Date: Fri, 14 Jun 2024 17:44:00 +0200 Subject: [PATCH 1/6] Skewer doesn't update when sims arrive or leave. --- src/control_any_sim/main.py | 2 +- .../services/selection_group.py | 46 +++++++++++++++++++ src/control_any_sim/ts4_services/__init__.py | 9 +++- src/control_any_sim/util/game_events.py | 41 +++++++++++++++++ 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/control_any_sim/main.py b/src/control_any_sim/main.py index 59081b9..53bd02f 100644 --- a/src/control_any_sim/main.py +++ b/src/control_any_sim/main.py @@ -249,6 +249,6 @@ def canys_client_get_selector_visual_type( return original(self, sim_info) -Logger.log("starting control_any_sim") +Logger.log("starting control_any_sim...") InteractionsService.bootstrap() diff --git a/src/control_any_sim/services/selection_group.py b/src/control_any_sim/services/selection_group.py index 06b5d9a..dd88866 100644 --- a/src/control_any_sim/services/selection_group.py +++ b/src/control_any_sim/services/selection_group.py @@ -131,6 +131,8 @@ def __init__( GameEvents.on_zone_teardown(self.on_zone_teardown) GameEvents.on_active_sim_changed(self.on_active_sim_changed) + GameEvents.on_post_spawn_sim(self.on_spawn_sim) + GameEvents.on_travel_sim_out(self.on_sim_travel_out) def persist_state(self: Self) -> None: """Write current state of the service to disk.""" @@ -311,3 +313,47 @@ def remove_household_npc(self: Self, sim_info: SimInfo) -> None: def is_household_npc(self: Self, sim_info: SimInfo) -> bool: """Check if a given SimInfo is a household NPC.""" return sim_info.id in self.household_npcs + + def on_spawn_sim( + self: Self, + sim: Sim, + ) -> None: + """ + Event handler for when a sim finished spawning. + + Send selectable sim update if the new sim is a controlled NPC. + """ + if not self.is_custom_sim(sim.id): + return + + Logger.log(f'Sending selectable sim update for spawned NPC "{sim.first_name} {sim.last_name}"') + Logger.log("".join(traceback.format_list(traceback.extract_stack()))) + self.client.send_selectable_sims_update() + + def on_sim_travel_out( + self: Self, + sim_info: SimInfo, + ) -> None: + """ + Event handler for when a sim travels out of the current zone. + + Send selectable sim update if the leaving sim is a controlled NPC. + """ + if not self.is_custom_sim(sim_info.id): + Logger.log( + "Traveling a sim out of the current zone, but it's not a custom selection NPC.", + ) + return + + sim_instance: Sim = sim_info.get_sim_instance(allow_hidden_flags=ALL_HIDDEN_REASONS) + + if not sim_instance: + Logger.log("there is no sim instance during travel") + + Logger.log( + f'Sending selectable sim update for traveling NPC "{sim_info.first_name} {sim_info.last_name}"', + ) + + sim_instance.schedule_destroy_asap( + post_delete_func=self.client.send_selectable_sims_update, + ) diff --git a/src/control_any_sim/ts4_services/__init__.py b/src/control_any_sim/ts4_services/__init__.py index 4ee79d6..2046420 100644 --- a/src/control_any_sim/ts4_services/__init__.py +++ b/src/control_any_sim/ts4_services/__init__.py @@ -1,14 +1,16 @@ """Wrapper for service module to add types.""" +from __future__ import annotations from typing import TYPE_CHECKING import services -from sims.sim_info_manager import SimInfoManager from .clientmanager import ClientManager if TYPE_CHECKING: import server + from sims.sim_info_manager import SimInfoManager + from sims.sim_spawner_service import SimSpawnerService def client_manager() -> ClientManager: @@ -21,3 +23,8 @@ def client_manager() -> ClientManager: def sim_info_manager() -> SimInfoManager: """Typed version of services.sim_info_manager.""" return services.sim_info_manager() + + +def sim_spawner_service(zone_id: int | None = None) -> SimSpawnerService: + """Typed version of services.sim_spawner_manager.""" + return services.sim_spawner_service(zone_id) diff --git a/src/control_any_sim/util/game_events.py b/src/control_any_sim/util/game_events.py index daa1b70..8488568 100644 --- a/src/control_any_sim/util/game_events.py +++ b/src/control_any_sim/util/game_events.py @@ -7,10 +7,13 @@ import services from server.client import Client +from sims.self_interactions import TravelInteraction from sims.sim import Sim +from sims.sim_info import SimInfo from zone import Zone from zone_types import ZoneState +from control_any_sim import ts4_services from control_any_sim.util.inject import inject_method_to from control_any_sim.util.logger import Logger @@ -26,6 +29,8 @@ class GameEvents: OnAddSim: TypeAlias = Callable[[Sim], None] OnLoadingScreenAnimationFinished: TypeAlias = Callable[[Zone], None] OnActiveSimChanged: TypeAlias = Callable[[Sim, Sim], None] + OnTravelSimOut: TypeAlias = Callable[[SimInfo], None] + OnPostSpawnSim: TypeAlias = Callable[[Sim], None] C = TypeVar("C", bound="GameEvents") @@ -35,6 +40,7 @@ class GameEvents: loading_screen_animation_finished_handlers: ClassVar[ list[OnLoadingScreenAnimationFinished] ] = [] + travel_sim_out_handlers: ClassVar[list[OnTravelSimOut]] = [] @classmethod def on_zone_teardown(cls: type[C], handler: OnZoneTeardown) -> None: @@ -108,6 +114,22 @@ def emit_loading_screen_animation_finished( for handler in cls.loading_screen_animation_finished_handlers: handler(current_zone) + @classmethod + def on_travel_sim_out(cls: type[C], handler: OnTravelSimOut) -> None: + """Add a listener for the travel_sim_out event.""" + cls.travel_sim_out_handlers.append(handler) + + @classmethod + def emit_travel_sim_out(cls: type[C], sim_info: SimInfo) -> None: + """Emit the travel sim out event.""" + for handler in cls.travel_sim_out_handlers: + handler(sim_info) + + @staticmethod + def on_post_spawn_sim(handler: OnPostSpawnSim) -> None: + """Adda listener for the post spawn sim event.""" + ts4_services.sim_spawner_service().register_sim_spawned_callback(handler) + @inject_method_to(Zone, "on_teardown") def canys_zone_on_teardown( @@ -177,3 +199,22 @@ def canys_zone_on_loading_screen_animation_finished( Logger.error(traceback.format_exc()) return original(self) + + +@inject_method_to(TravelInteraction, "save_and_destroy_sim") +def canys_travel_internaction_save_and_destroy_sim( + original: Callable[[TravelInteraction, bool, SimInfo], None], + self: TravelInteraction, + on_reset: bool, # noqa: FBT001 + sim_info: SimInfo, +) -> None: + """Wrap the TravelInteraction::save_and_destroy_sim method to emit the corresponding event.""" + try: + result = original(self, on_reset, sim_info) + + GameEvents.emit_travel_sim_out(sim_info) + except Exception as err: + Logger.error(f"{err}") + Logger.error(traceback.format_exc()) + + return result From e6a378dc2d56b9fe77d59181881ba6dde6d2df75 Mon Sep 17 00:00:00 2001 From: Jovan Gerodetti Date: Fri, 14 Jun 2024 17:51:34 +0200 Subject: [PATCH 2/6] Update src/control_any_sim/services/selection_group.py Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/control_any_sim/services/selection_group.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/control_any_sim/services/selection_group.py b/src/control_any_sim/services/selection_group.py index dd88866..ac84a87 100644 --- a/src/control_any_sim/services/selection_group.py +++ b/src/control_any_sim/services/selection_group.py @@ -326,7 +326,9 @@ def on_spawn_sim( if not self.is_custom_sim(sim.id): return - Logger.log(f'Sending selectable sim update for spawned NPC "{sim.first_name} {sim.last_name}"') + Logger.log( + f'Sending selectable sim update for spawned NPC "{sim.first_name} {sim.last_name}"' + ) Logger.log("".join(traceback.format_list(traceback.extract_stack()))) self.client.send_selectable_sims_update() From 7f50cc6199aa959dae36ca0fa842777f26ca729a Mon Sep 17 00:00:00 2001 From: Jovan Gerodetti Date: Fri, 14 Jun 2024 17:51:46 +0200 Subject: [PATCH 3/6] Update src/control_any_sim/services/selection_group.py Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/control_any_sim/services/selection_group.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/control_any_sim/services/selection_group.py b/src/control_any_sim/services/selection_group.py index ac84a87..e0b544b 100644 --- a/src/control_any_sim/services/selection_group.py +++ b/src/control_any_sim/services/selection_group.py @@ -347,7 +347,9 @@ def on_sim_travel_out( ) return - sim_instance: Sim = sim_info.get_sim_instance(allow_hidden_flags=ALL_HIDDEN_REASONS) + sim_instance: Sim = sim_info.get_sim_instance( + allow_hidden_flags=ALL_HIDDEN_REASONS + ) if not sim_instance: Logger.log("there is no sim instance during travel") From 4e3e090fe98eafaab45c05563599f7a17c3ba0c1 Mon Sep 17 00:00:00 2001 From: Jovan Gerodetti Date: Fri, 14 Jun 2024 17:51:51 +0200 Subject: [PATCH 4/6] Update src/control_any_sim/ts4_services/__init__.py Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/control_any_sim/ts4_services/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/control_any_sim/ts4_services/__init__.py b/src/control_any_sim/ts4_services/__init__.py index 2046420..073ea36 100644 --- a/src/control_any_sim/ts4_services/__init__.py +++ b/src/control_any_sim/ts4_services/__init__.py @@ -1,4 +1,5 @@ """Wrapper for service module to add types.""" + from __future__ import annotations from typing import TYPE_CHECKING From d8612588dd135ae0961b7ade9c451c1655932d93 Mon Sep 17 00:00:00 2001 From: Jovan Gerodetti Date: Fri, 14 Jun 2024 17:54:55 +0200 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/control_any_sim/services/selection_group.py | 4 +++- src/control_any_sim/ts4_services/__init__.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/control_any_sim/services/selection_group.py b/src/control_any_sim/services/selection_group.py index e0b544b..9a187ec 100644 --- a/src/control_any_sim/services/selection_group.py +++ b/src/control_any_sim/services/selection_group.py @@ -327,7 +327,7 @@ def on_spawn_sim( return Logger.log( - f'Sending selectable sim update for spawned NPC "{sim.first_name} {sim.last_name}"' + f'Sending selectable sim update for spawned NPC "{sim.first_name} {sim.last_name}"', ) Logger.log("".join(traceback.format_list(traceback.extract_stack()))) self.client.send_selectable_sims_update() @@ -351,6 +351,8 @@ def on_sim_travel_out( allow_hidden_flags=ALL_HIDDEN_REASONS ) + if not sim_instance: + Logger.log("there is no sim instance during travel") if not sim_instance: Logger.log("there is no sim instance during travel") diff --git a/src/control_any_sim/ts4_services/__init__.py b/src/control_any_sim/ts4_services/__init__.py index 073ea36..7c42af1 100644 --- a/src/control_any_sim/ts4_services/__init__.py +++ b/src/control_any_sim/ts4_services/__init__.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import TYPE_CHECKING from typing import TYPE_CHECKING import services From 6741839ef77f5447fa4e81cd7abd91deb4a35ab4 Mon Sep 17 00:00:00 2001 From: Jovan Gerodetti Date: Fri, 14 Jun 2024 17:56:42 +0200 Subject: [PATCH 6/6] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/control_any_sim/services/selection_group.py | 2 +- src/control_any_sim/ts4_services/__init__.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/control_any_sim/services/selection_group.py b/src/control_any_sim/services/selection_group.py index 9a187ec..1af12ab 100644 --- a/src/control_any_sim/services/selection_group.py +++ b/src/control_any_sim/services/selection_group.py @@ -348,7 +348,7 @@ def on_sim_travel_out( return sim_instance: Sim = sim_info.get_sim_instance( - allow_hidden_flags=ALL_HIDDEN_REASONS + allow_hidden_flags=ALL_HIDDEN_REASONS, ) if not sim_instance: diff --git a/src/control_any_sim/ts4_services/__init__.py b/src/control_any_sim/ts4_services/__init__.py index 7c42af1..073ea36 100644 --- a/src/control_any_sim/ts4_services/__init__.py +++ b/src/control_any_sim/ts4_services/__init__.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from typing import TYPE_CHECKING import services