Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skewer doesn't update when sims arrive or leave. #95 #97

Merged
merged 6 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/control_any_sim/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
46 changes: 46 additions & 0 deletions src/control_any_sim/services/selection_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down Expand Up @@ -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()

TitanNano marked this conversation as resolved.
Show resolved Hide resolved
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")
TitanNano marked this conversation as resolved.
Show resolved Hide resolved

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,
)
9 changes: 8 additions & 1 deletion src/control_any_sim/ts4_services/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
"""Wrapper for service module to add types."""
from __future__ import annotations

from typing import TYPE_CHECKING
TitanNano marked this conversation as resolved.
Show resolved Hide resolved

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:
Expand All @@ -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)
41 changes: 41 additions & 0 deletions src/control_any_sim/util/game_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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")

Expand All @@ -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:
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
Loading