Compare commits
1 Commits
8ec7f53682
...
e47d451426
Author | SHA1 | Date |
---|---|---|
|
e47d451426 |
|
@ -17,7 +17,5 @@ class Config:
|
|||
|
||||
COOKIE_MAX_AGE = int(os.getenv("COOKIE_MAX_AGE", 60 * 60 * 24 * 7)) # 1 week
|
||||
|
||||
KENNEL_CATS_POLL_SEC = int(os.getenv("KENNEL_CATS_POLL_SEC", 10))
|
||||
|
||||
|
||||
config = Config()
|
||||
|
|
|
@ -5,7 +5,6 @@ from enum import Enum
|
|||
class ComponentType(str, Enum):
|
||||
POSITION = "POSITION"
|
||||
CONTROLLABLE = "CONTROLLABLE"
|
||||
MARKOV = "MARKOV"
|
||||
|
||||
|
||||
class Component:
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
from kennel.engine.components.component import Component, ComponentType
|
||||
|
||||
|
||||
class MarkovTransitionState(Component):
|
||||
def __init__(
|
||||
self,
|
||||
state_names: dict[int, str],
|
||||
initial_state_vector: list[float],
|
||||
transition_matrix: list[list[float]],
|
||||
):
|
||||
# TODO: Poll rate per state?
|
||||
# TODO: State being an enum instead of a vector, just choose max and map
|
||||
self.state_names = state_names
|
||||
self.state = initial_state_vector
|
||||
self.transition_matrix = transition_matrix
|
||||
|
||||
super().__init__(ComponentType.MARKOV)
|
||||
|
||||
def get_max_state_name(self, state_vector: list[float]):
|
||||
max_val = max(state_vector)
|
||||
return self.state_names[state_vector.index(max_val)]
|
||||
|
||||
def to_dict(self):
|
||||
return {"state": self.get_max_state_name(self.state)}
|
|
@ -1,18 +1,6 @@
|
|||
from kennel.engine.components.position import Position
|
||||
|
||||
from .entity import Entity, EntityType
|
||||
|
||||
|
||||
class Cat(Entity):
|
||||
def __init__(self, id: str):
|
||||
components = [Position(0, 0)]
|
||||
|
||||
super().__init__(EntityType.CAT, id, components)
|
||||
|
||||
|
||||
#
|
||||
# # IDLE, FROLICKING, EEPY, ALERT, CHASING_CURSOR, CHASING_CAT, SCRATCHING, ITCHY
|
||||
# state_stochastic_matrix = [ [1, 0]
|
||||
# state_stochastic_matrix = [
|
||||
# # IDLE
|
||||
# [0.5, 0.1, 0.1, 0.1, 0.1, 0.05, 0.05, 0],
|
||||
# # FROLICKING
|
||||
|
|
|
@ -6,7 +6,6 @@ from kennel.engine.components.component import Component, ComponentType
|
|||
|
||||
class EntityType(str, Enum):
|
||||
LASER = "LASER"
|
||||
CAT = "CAT"
|
||||
|
||||
|
||||
class Entity:
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
from kennel.engine.components.component import ComponentType
|
||||
from kennel.engine.entities.entity import EntityManager
|
||||
from kennel.engine.systems.system import System, SystemType
|
||||
from kennel.engine.systems.network import NetworkSystem
|
||||
|
||||
|
||||
class MarkovTransitionStateSystem(System):
|
||||
def __init__(self, network_system: NetworkSystem):
|
||||
super().__init__(SystemType.MARKOV)
|
||||
|
||||
def update(self, entity_manager: EntityManager, delta_time: float):
|
||||
entity_manager.get_entities_with_component(ComponentType.MARKOV)
|
||||
return
|
|
@ -7,7 +7,6 @@ from kennel.engine.entities.entity import EntityManager
|
|||
class SystemType(str, Enum):
|
||||
NETWORK = "NETWORK"
|
||||
WORLD = "WORLD"
|
||||
MARKOV = "MARKOV"
|
||||
|
||||
|
||||
class System:
|
||||
|
@ -15,7 +14,7 @@ class System:
|
|||
self.system_type = system_type
|
||||
|
||||
@abstractmethod
|
||||
async def update(self, entity_manager: EntityManager, delta_time: float) -> None:
|
||||
async def update(self, entity_manager: EntityManager, delta_time: float):
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -1,27 +1,18 @@
|
|||
import asyncio
|
||||
import uuid
|
||||
import time
|
||||
from typing import List, Optional
|
||||
|
||||
from kennel.config import config
|
||||
from kennel.engine.components.component import ComponentType
|
||||
from kennel.engine.entities.entity import Entity, EntityManager
|
||||
from kennel.engine.entities.laser import Laser
|
||||
from kennel.engine.entities.cat import Cat
|
||||
from kennel.engine.game import Game
|
||||
from kennel.engine.systems.markov_transition_state_system import (
|
||||
MarkovTransitionStateSystem,
|
||||
)
|
||||
from kennel.engine.systems.network import (
|
||||
EntityPositionUpdateEvent,
|
||||
EntityBornEvent,
|
||||
EntityDeathEvent,
|
||||
Event,
|
||||
EventType,
|
||||
NetworkSystem,
|
||||
UpstreamEventProcessor,
|
||||
)
|
||||
from kennel.kennelcats import KennelCatService, KennelCat
|
||||
from kennel.engine.systems.system import SystemManager
|
||||
from kennel.engine.systems.world import WorldSystem
|
||||
|
||||
|
@ -67,76 +58,12 @@ class KennelEventProcessor(UpstreamEventProcessor):
|
|||
return event
|
||||
|
||||
|
||||
class KennelCatsManager:
|
||||
kennel_cat_service: KennelCatService
|
||||
entity_manager: EntityManager
|
||||
network_system: NetworkSystem
|
||||
last_seen: set[str]
|
||||
poll_interval_sec: int
|
||||
running: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
kennel_cat_service: KennelCatService,
|
||||
entity_manager: EntityManager,
|
||||
network_system: NetworkSystem,
|
||||
poll_interval_sec: int,
|
||||
):
|
||||
self.kennel_cat_service = kennel_cat_service
|
||||
self.entity_manager = entity_manager
|
||||
self.network_system = network_system
|
||||
self.poll_interval_sec = poll_interval_sec
|
||||
|
||||
self.last_seen = set()
|
||||
self.running = False
|
||||
|
||||
async def start(self) -> None:
|
||||
logger.info("starting kennel cats manager")
|
||||
if self.running:
|
||||
return
|
||||
|
||||
self.running = True
|
||||
while self.running:
|
||||
logger.info("polling kennel cats service")
|
||||
cats = self.kennel_cat_service.get_kennel()
|
||||
cats_table = {cat.id: cat for cat in cats}
|
||||
cat_ids = set([cat.id for cat in cats])
|
||||
|
||||
removed_cats = [cats_table[id] for id in self.last_seen.difference(cat_ids)]
|
||||
added_cats = [cats_table[id] for id in cat_ids.difference(self.last_seen)]
|
||||
logger.info(f"removing {removed_cats}")
|
||||
logger.info(f"adding {added_cats}")
|
||||
|
||||
for removed in removed_cats:
|
||||
self.entity_manager.remove_entity(removed)
|
||||
entity_death = EntityDeathEvent(removed.id)
|
||||
self.network_system.server_global_event(entity_death)
|
||||
|
||||
for added in added_cats:
|
||||
new_cat = Cat(added.id)
|
||||
self.entity_manager.add_entity(new_cat)
|
||||
entity_born = EntityBornEvent(new_cat)
|
||||
self.network_system.server_global_event(entity_born)
|
||||
|
||||
self.last_seen = cat_ids
|
||||
await asyncio.sleep(self.poll_interval_sec)
|
||||
|
||||
def stop(self) -> None:
|
||||
logger.info("stopping kennel cats manager")
|
||||
self.running = False
|
||||
|
||||
|
||||
network_system = NetworkSystem(KennelEventProcessor())
|
||||
world_system = WorldSystem(config.WORLD_WIDTH, config.WORLD_HEIGHT)
|
||||
markov_transition_state_system = MarkovTransitionStateSystem(network_system)
|
||||
system_manager.add_system(network_system)
|
||||
system_manager.add_system(world_system)
|
||||
system_manager.add_system(WorldSystem(config.WORLD_WIDTH, config.WORLD_HEIGHT))
|
||||
system_manager.add_system(
|
||||
NetworkSystem(KennelEventProcessor()),
|
||||
)
|
||||
|
||||
kennel = Game(entity_manager, system_manager, config.MIN_TIME_STEP)
|
||||
kennel_cat_service = KennelCatService(config.HATECOMPUTERS_ENDPOINT)
|
||||
kennel_cats_manager = KennelCatsManager(
|
||||
kennel_cat_service, entity_manager, network_system, config.KENNEL_CATS_POLL_SEC
|
||||
)
|
||||
|
||||
|
||||
def create_session_controllable_entities(session: str) -> List[Entity]:
|
||||
|
|
|
@ -37,10 +37,10 @@ class KennelCat:
|
|||
|
||||
|
||||
class KennelCatService:
|
||||
def __init__(self, hc_endpoint: str):
|
||||
self.hc_endpoint = hc_endpoint
|
||||
def __init__(self, endpoint: str):
|
||||
self.endpoint = endpoint
|
||||
|
||||
def get_kennel(self) -> List[KennelCat]:
|
||||
response = requests.get(f"{self.hc_endpoint}/kennel")
|
||||
response = requests.get(f"{self.endpoint}/kennel")
|
||||
response.raise_for_status()
|
||||
return [KennelCat.from_dict(cat) for cat in response.json()]
|
||||
|
|
|
@ -30,7 +30,6 @@ from kennel.kennel import (
|
|||
create_session_controllable_entities,
|
||||
entity_manager,
|
||||
kennel,
|
||||
kennel_cats_manager,
|
||||
system_manager,
|
||||
)
|
||||
|
||||
|
@ -44,14 +43,12 @@ loop = asyncio.get_event_loop()
|
|||
async def startup_event():
|
||||
logger.info("Starting Kennel...")
|
||||
loop.create_task(kennel.run())
|
||||
loop.create_task(kennel_cats_manager.start())
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown_event():
|
||||
logger.info("Stopping Kennel...")
|
||||
kennel.stop()
|
||||
kennel_cats_manager.stop()
|
||||
loop.stop()
|
||||
logger.info("Kennel stopped")
|
||||
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"dev": "./node_modules/nodemon/bin/nodemon.js --watch './src/**/*' -e ts,html --exec \"npm run build\""
|
||||
"watch": "./node_modules/nodemon/bin/nodemon.js --watch './src/**/*' -e ts,html --exec \"npm run build\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-inject": "^5.0.5",
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
import {
|
||||
Component,
|
||||
ComponentType,
|
||||
PositionComponent,
|
||||
RenderableComponent,
|
||||
TrailingPositionComponent,
|
||||
} from "./component";
|
||||
|
||||
export enum EntityType {
|
||||
LASER = "LASER",
|
||||
CAT = "CAT",
|
||||
}
|
||||
|
||||
export interface Entity {
|
||||
|
@ -30,16 +28,3 @@ export const create_laser = (base: Entity) => {
|
|||
base.components[ComponentType.RENDERABLE] = renderable;
|
||||
return base;
|
||||
};
|
||||
|
||||
export const create_cat = (base: Entity) => {
|
||||
const renderable: RenderableComponent = {
|
||||
name: ComponentType.RENDERABLE,
|
||||
};
|
||||
base.components[ComponentType.RENDERABLE] = renderable;
|
||||
base.components[ComponentType.POSITION] = {
|
||||
component: ComponentType.POSITION,
|
||||
x: Math.random() * 1_000,
|
||||
y: Math.random() * 1_000,
|
||||
} as unknown as PositionComponent; // TODO: hack
|
||||
return base;
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
PositionComponent,
|
||||
TrailingPositionComponent,
|
||||
} from "./component";
|
||||
import { create_cat, create_laser, Entity, EntityType } from "./entity";
|
||||
import { create_laser, Entity, EntityType } from "./entity";
|
||||
import {
|
||||
EntityBornEvent,
|
||||
EntityDeathEvent,
|
||||
|
@ -110,9 +110,6 @@ export class NetworkSystem extends System {
|
|||
if (entity.entity_type === EntityType.LASER) {
|
||||
return create_laser(entity);
|
||||
}
|
||||
if (entity.entity_type === EntityType.CAT) {
|
||||
return create_cat(entity);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
import {
|
||||
ComponentType,
|
||||
PositionComponent,
|
||||
TrailingPositionComponent,
|
||||
} from "./component";
|
||||
import { ComponentType, TrailingPositionComponent } from "./component";
|
||||
import { Game } from "./game";
|
||||
import { System, SystemType } from "./system";
|
||||
import { drawLaserPen } from "laser-pen";
|
||||
|
@ -29,17 +25,6 @@ export class RenderSystem extends System {
|
|||
] as TrailingPositionComponent;
|
||||
if (trailing_position.trails.length < 3) return;
|
||||
drawLaserPen(ctx, trailing_position.trails);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ComponentType.POSITION in entity.components) {
|
||||
const position = entity.components[
|
||||
ComponentType.POSITION
|
||||
] as PositionComponent;
|
||||
ctx.beginPath();
|
||||
ctx.arc(position.x, position.y, 50, 0, 2 * Math.PI);
|
||||
ctx.stroke();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -28,11 +28,11 @@ $(async () => {
|
|||
const publisher: EventPublisher = new WebsocketEventPublisher(ws);
|
||||
const network_system = new NetworkSystem(queue, publisher);
|
||||
|
||||
const gamecanvas = $("#gamecanvas").get(0)! as HTMLCanvasElement;
|
||||
const gamecanvas = $("#gamecanvas").get(0)!;
|
||||
const input_system = new InputSystem(publisher, gamecanvas);
|
||||
|
||||
setDelay(500);
|
||||
const render_system = new RenderSystem(gamecanvas);
|
||||
setDelay(1_000);
|
||||
const render_system = new RenderSystem(gamecanvas as HTMLCanvasElement);
|
||||
|
||||
const trailing_position = new TrailingPositionSystem(drainPoints);
|
||||
|
||||
|
|
Loading…
Reference in New Issue