From a0a2068b66204d7d06eb3c3b4aa61b28469121f6 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Sat, 24 Aug 2024 19:11:26 -0700 Subject: improve event parsing and begin sending events from the client --- kennel/engine/systems/network.py | 104 +++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 25 deletions(-) (limited to 'kennel/engine/systems/network.py') diff --git a/kennel/engine/systems/network.py b/kennel/engine/systems/network.py index c9696c8..8dbf4cf 100644 --- a/kennel/engine/systems/network.py +++ b/kennel/engine/systems/network.py @@ -1,15 +1,17 @@ from enum import Enum -from kennel.engine.entities.entity import EntityManager +from kennel.engine.entities.entity import Entity, EntityType, EntityManager from .system import System, SystemType from abc import abstractmethod +from typing import Optional, List import asyncio class EventType(str, Enum): INITIAL_STATE = "INITIAL_STATE" + SET_CONTROLLABLE = "SET_CONTROLLABLE" ENTITY_BORN = "ENTITY_BORN" - ENTITY_POSITION_UPDATE = "ENTITY_POSITION_UPDATE" ENTITY_DEATH = "ENTITY_DEATH" + ENTITY_POSITION_UPDATE = "ENTITY_POSITION_UPDATE" class Event: @@ -17,26 +19,83 @@ class Event: self.event_type = event_type self.data = data - def __str__(self): + def __str__(self) -> str: return f"Event({self.event_type}, {self.data})" - def dict(self): + def to_dict(self) -> dict: return {"event_type": self.event_type, "data": self.data} @staticmethod - def from_dict(data: dict): + def from_dict(data: dict) -> Optional["Event"]: + if "event_type" not in data or "data" not in data: + return + event_type = data["event_type"] + if event_type == EventType.INITIAL_STATE: + return InitialStateEvent( + data["data"]["world"]["width"], + data["data"]["world"]["height"], + data["data"]["entities"], + ) + if event_type == EventType.SET_CONTROLLABLE: + return SetControllableEvent(data["data"]["id"], data["data"]["client_id"]) + if event_type == EventType.ENTITY_BORN: + return EntityBornEvent(data["data"]) + if event_type == EventType.ENTITY_POSITION_UPDATE: + return EntityPositionUpdateEvent( + data["data"]["id"], data["data"]["position"] + ) + if event_type == EventType.ENTITY_DEATH: + return EntityDeathEvent(data["data"]["id"]) + + logger.warn(f"Unknown event type: {data['event_type']}") return Event(EventType(data["event_type"]), data["data"]) -class Publishable: - @abstractmethod - async def publish(self, event: Event): - pass +class InitialStateEvent(Event): + def __init__(self, world_width: int, world_height: int, entities: List[Entity]): + self.world_width = world_width + self.world_height = world_height + self.entities = entities + super().__init__( + EventType.INITIAL_STATE, + { + "world": {"width": world_width, "height": world_height}, + "entities": [entity.to_dict() for entity in entities], + }, + ) + + +class SetControllableEvent(Event): + def __init__(self, entity_id: str, client_id: str): + self.entity_id = entity_id + self.client_id = client_id + super().__init__( + EventType.SET_CONTROLLABLE, {"id": entity_id, "client_id": client_id} + ) -class ClientEventTransformer: +class EntityBornEvent(Event): + def __init__(self, entity: Entity): + self.entity = entity + super().__init__(EventType.ENTITY_BORN, {"entity": entity.to_dict()}) + + +class EntityPositionUpdateEvent(Event): + def __init__(self, entity_id: str, position: dict): + super().__init__( + EventType.ENTITY_POSITION_UPDATE, + {"id": entity_id, "position": position}, + ) + + +class EntityDeathEvent(Event): + def __init__(self, entity_id: str): + super().__init__(EventType.ENTITY_DEATH, {"id": entity_id}) + + +class Publishable: @abstractmethod - def apply(self, event: Event) -> Event: + async def publish(self, event: Event): pass @@ -47,37 +106,32 @@ class EventProcessor: class NetworkSystem(System): - def __init__( - self, - event_processor: EventProcessor, - client_event_transformer: ClientEventTransformer, - ): + def __init__(self, event_processor: EventProcessor): super().__init__(SystemType.NETWORK) self.event_processor = event_processor - self.client_event_transformer = client_event_transformer self.events = [] + self.client_events = [] self.clients = {} async def update(self, entity_manager: EntityManager, delta_time: float) -> None: - for event in self.events: + if len(self.events) + len(self.client_events) == 0: + return + for event in self.events + self.client_events: self.event_processor.accept(entity_manager, event) - client_events = [ - self.client_event_transformer.apply(entity_manager, event) - for event in self.events - ] + client_sendable = self.events + [event for event, _ in self.client_events] await asyncio.gather( *[ client.publish(event) for client in self.clients.values() - for event in client_events + for event in client_sendable ] ) self.events = [] + self.client_events = [] def client_event(self, client_id: str, event: Event) -> None: - event.data["client_id"] = client_id - self.events.append(event) + self.client_events.append((event, client_id)) def add_event(self, event: Event) -> None: self.events.append(event) -- cgit v1.3