send the initial state to clients
	
		
			
	
		
	
	
		
			
				
	
				continuous-integration/drone/pr Build is failing
				
					Details
				
			
		
	
				
					
				
			
				
	
				continuous-integration/drone/pr Build is failing
				
					Details
				
			
		
	This commit is contained in:
		
							parent
							
								
									b414046001
								
							
						
					
					
						commit
						6f374aac7f
					
				|  | @ -5,8 +5,8 @@ load_dotenv() | |||
| 
 | ||||
| 
 | ||||
| class Config: | ||||
|     SIMULATION_WIDTH = int(os.getenv("SIMULATION_WIDTH", 1000)) | ||||
|     SIMULATION_HEIGHT = int(os.getenv("SIMULATION_HEIGHT", 1000)) | ||||
|     WORLD_WIDTH = int(os.getenv("WORLD_WIDTH", 1000)) | ||||
|     WORLD_HEIGHT = int(os.getenv("WORLD_HEIGHT", 1000)) | ||||
| 
 | ||||
|     HATECOMPUTERS_ENDPOINT = os.getenv( | ||||
|         "HATECOMPUTERS_ENDPOINT", "https://hatecomputers.club" | ||||
|  |  | |||
|  | @ -10,4 +10,5 @@ class Controllable(Component): | |||
|         return f"Controllable(by={self.by})" | ||||
| 
 | ||||
|     def dict(self) -> dict: | ||||
|         return {"by": self.by} | ||||
|         # don't serialize who owns this | ||||
|         return {} | ||||
|  |  | |||
|  | @ -23,6 +23,13 @@ class Entity: | |||
|     def add_component(self, component: Component) -> None: | ||||
|         self.components[component.component_type] = component | ||||
| 
 | ||||
|     def to_dict(self) -> dict: | ||||
|         return { | ||||
|             "entity_type": self.entity_type, | ||||
|             "id": self.id, | ||||
|             "components": {k: v.dict() for k, v in self.components.items()}, | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| class EntityManager: | ||||
|     def __init__(self): | ||||
|  | @ -58,3 +65,6 @@ class EntityManager: | |||
| 
 | ||||
|     def get_entity(self, entity_id: str) -> Optional[Entity]: | ||||
|         return self.entities.get(entity_id) | ||||
| 
 | ||||
|     def to_dict(self) -> dict: | ||||
|         return {k: v.to_dict() for k, v in self.entities.items()} | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ import asyncio | |||
| 
 | ||||
| 
 | ||||
| class EventType(str, Enum): | ||||
|     INITIAL_STATE = "INITIAL_STATE" | ||||
|     ENTITY_BORN = "ENTITY_BORN" | ||||
|     ENTITY_POSITION_UPDATE = "ENTITY_POSITION_UPDATE" | ||||
|     ENTITY_DEATH = "ENTITY_DEATH" | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ from abc import abstractmethod | |||
| 
 | ||||
| class SystemType(str, Enum): | ||||
|     NETWORK = "NETWORK" | ||||
|     WORLD = "WORLD" | ||||
| 
 | ||||
| 
 | ||||
| class System: | ||||
|  |  | |||
|  | @ -0,0 +1,24 @@ | |||
| from kennel.engine.systems.system import System, SystemType | ||||
| from kennel.engine.entities.entity import EntityManager | ||||
| from kennel.engine.components.component import ComponentType | ||||
| from kennel.app import logger | ||||
| 
 | ||||
| 
 | ||||
| class WorldSystem(System): | ||||
|     def __init__(self, width: int, height: int): | ||||
|         super().__init__(SystemType.WORLD) | ||||
|         self.width = width | ||||
|         self.height = height | ||||
| 
 | ||||
|     async def update(self, entity_manager: EntityManager, delta_time: float): | ||||
|         entities = entity_manager.get_entities_with_component(ComponentType.POSITION) | ||||
|         for entity in entities: | ||||
|             position = entity.get_component(ComponentType.POSITION) | ||||
|             if position is None: | ||||
|                 logger.error(f"Entity {entity} has no position component") | ||||
|                 continue | ||||
| 
 | ||||
|             position.x = max(0, min(self.width, position.x)) | ||||
|             position.y = max(0, min(self.height, position.y)) | ||||
| 
 | ||||
|             entity.add_component(position) | ||||
|  | @ -10,6 +10,7 @@ from kennel.engine.systems.network import ( | |||
|     Event, | ||||
|     EventType, | ||||
| ) | ||||
| from kennel.engine.systems.world import WorldSystem | ||||
| from kennel.config import config | ||||
| from .app import logger | ||||
| from typing import List | ||||
|  | @ -59,9 +60,6 @@ class KennelClientEventTransformer(ClientEventTransformer): | |||
|                 logger.error(f"Entity {id} does not exist") | ||||
|                 return event | ||||
|             for component_type in entity.components: | ||||
|                 if component_type == ComponentType.CONTROLLABLE: | ||||
|                     # Do not send controllable components to clients | ||||
|                     continue | ||||
|                 component = entity.get_component(component_type) | ||||
|                 if component is not None: | ||||
|                     event.data[component_type] = component.dict() | ||||
|  | @ -69,8 +67,9 @@ class KennelClientEventTransformer(ClientEventTransformer): | |||
|         return event | ||||
| 
 | ||||
| 
 | ||||
| system_manager.add_system(WorldSystem(config.WORLD_WIDTH, config.WORLD_HEIGHT)) | ||||
| system_manager.add_system( | ||||
|     NetworkSystem(EventProcessor(), KennelClientEventTransformer()) | ||||
|     NetworkSystem(EventProcessor(), KennelClientEventTransformer()), | ||||
| ) | ||||
| 
 | ||||
| kennel = Game(entity_manager, system_manager, config.MIN_TIME_STEP) | ||||
|  |  | |||
|  | @ -12,16 +12,16 @@ from fastapi.staticfiles import StaticFiles | |||
| from kennel.engine.systems.system import SystemType | ||||
| from kennel.engine.systems.network import Event, Publishable, EventType | ||||
| from typing import Annotated, Optional | ||||
| from .kennel import ( | ||||
| from kennel.kennel import ( | ||||
|     kennel, | ||||
|     system_manager, | ||||
|     entity_manager, | ||||
|     create_session_controllable_entities, | ||||
| ) | ||||
| from .app import app, templates, logger | ||||
| from .kennelcats import KennelCatService | ||||
| from .middleware import logger_middleware | ||||
| from .config import config | ||||
| from kennel.app import app, templates, logger | ||||
| from kennel.kennelcats import KennelCatService | ||||
| from kennel.middleware import logger_middleware | ||||
| from kennel.config import config | ||||
| import asyncio | ||||
| import uuid | ||||
| 
 | ||||
|  | @ -85,6 +85,16 @@ async def websocket_endpoint( | |||
|     await websocket.accept() | ||||
|     logger.info(f"Websocket connection established for session {session}") | ||||
| 
 | ||||
|     await websocket.send_json( | ||||
|         { | ||||
|             "event_type": EventType.INITIAL_STATE, | ||||
|             "data": { | ||||
|                 "world": {"width": config.WORLD_WIDTH, "height": config.WORLD_HEIGHT}, | ||||
|                 "entities": kennel.entity_manager.to_dict(), | ||||
|             }, | ||||
|         } | ||||
|     ) | ||||
| 
 | ||||
|     session_entities = create_session_controllable_entities(session) | ||||
|     try: | ||||
|         network_system = system_manager.get_system(SystemType.NETWORK) | ||||
|  |  | |||
|  | @ -5,10 +5,10 @@ | |||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|     <meta http-equiv="X-UA-Compatible" content="ie=edge"> | ||||
|     <title>Kennel Club</title> | ||||
|     <script src='https://unpkg.com/panzoom@9.4.0/dist/panzoom.min.js'></script> | ||||
|   </head> | ||||
|   <body> | ||||
|     <div id="kennel-window"></div> | ||||
|     <script src="{{ url_for('static', path='/index.js') }}"></script> | ||||
|   </body> | ||||
| </html> | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue