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
|
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()
|
config = Config()
|
||||||
|
|
|
@ -5,7 +5,6 @@ from enum import Enum
|
||||||
class ComponentType(str, Enum):
|
class ComponentType(str, Enum):
|
||||||
POSITION = "POSITION"
|
POSITION = "POSITION"
|
||||||
CONTROLLABLE = "CONTROLLABLE"
|
CONTROLLABLE = "CONTROLLABLE"
|
||||||
MARKOV = "MARKOV"
|
|
||||||
|
|
||||||
|
|
||||||
class Component:
|
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
|
# # IDLE, FROLICKING, EEPY, ALERT, CHASING_CURSOR, CHASING_CAT, SCRATCHING, ITCHY
|
||||||
# state_stochastic_matrix = [ [1, 0]
|
# state_stochastic_matrix = [
|
||||||
# # IDLE
|
# # IDLE
|
||||||
# [0.5, 0.1, 0.1, 0.1, 0.1, 0.05, 0.05, 0],
|
# [0.5, 0.1, 0.1, 0.1, 0.1, 0.05, 0.05, 0],
|
||||||
# # FROLICKING
|
# # FROLICKING
|
||||||
|
|
|
@ -6,7 +6,6 @@ from kennel.engine.components.component import Component, ComponentType
|
||||||
|
|
||||||
class EntityType(str, Enum):
|
class EntityType(str, Enum):
|
||||||
LASER = "LASER"
|
LASER = "LASER"
|
||||||
CAT = "CAT"
|
|
||||||
|
|
||||||
|
|
||||||
class Entity:
|
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):
|
class SystemType(str, Enum):
|
||||||
NETWORK = "NETWORK"
|
NETWORK = "NETWORK"
|
||||||
WORLD = "WORLD"
|
WORLD = "WORLD"
|
||||||
MARKOV = "MARKOV"
|
|
||||||
|
|
||||||
|
|
||||||
class System:
|
class System:
|
||||||
|
@ -15,7 +14,7 @@ class System:
|
||||||
self.system_type = system_type
|
self.system_type = system_type
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def update(self, entity_manager: EntityManager, delta_time: float) -> None:
|
async def update(self, entity_manager: EntityManager, delta_time: float):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,18 @@
|
||||||
import asyncio
|
|
||||||
import uuid
|
import uuid
|
||||||
import time
|
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from kennel.config import config
|
from kennel.config import config
|
||||||
from kennel.engine.components.component import ComponentType
|
from kennel.engine.components.component import ComponentType
|
||||||
from kennel.engine.entities.entity import Entity, EntityManager
|
from kennel.engine.entities.entity import Entity, EntityManager
|
||||||
from kennel.engine.entities.laser import Laser
|
from kennel.engine.entities.laser import Laser
|
||||||
from kennel.engine.entities.cat import Cat
|
|
||||||
from kennel.engine.game import Game
|
from kennel.engine.game import Game
|
||||||
from kennel.engine.systems.markov_transition_state_system import (
|
|
||||||
MarkovTransitionStateSystem,
|
|
||||||
)
|
|
||||||
from kennel.engine.systems.network import (
|
from kennel.engine.systems.network import (
|
||||||
EntityPositionUpdateEvent,
|
EntityPositionUpdateEvent,
|
||||||
EntityBornEvent,
|
|
||||||
EntityDeathEvent,
|
|
||||||
Event,
|
Event,
|
||||||
EventType,
|
EventType,
|
||||||
NetworkSystem,
|
NetworkSystem,
|
||||||
UpstreamEventProcessor,
|
UpstreamEventProcessor,
|
||||||
)
|
)
|
||||||
from kennel.kennelcats import KennelCatService, KennelCat
|
|
||||||
from kennel.engine.systems.system import SystemManager
|
from kennel.engine.systems.system import SystemManager
|
||||||
from kennel.engine.systems.world import WorldSystem
|
from kennel.engine.systems.world import WorldSystem
|
||||||
|
|
||||||
|
@ -67,76 +58,12 @@ class KennelEventProcessor(UpstreamEventProcessor):
|
||||||
return event
|
return event
|
||||||
|
|
||||||
|
|
||||||
class KennelCatsManager:
|
system_manager.add_system(WorldSystem(config.WORLD_WIDTH, config.WORLD_HEIGHT))
|
||||||
kennel_cat_service: KennelCatService
|
system_manager.add_system(
|
||||||
entity_manager: EntityManager
|
NetworkSystem(KennelEventProcessor()),
|
||||||
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)
|
|
||||||
|
|
||||||
kennel = Game(entity_manager, system_manager, config.MIN_TIME_STEP)
|
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]:
|
def create_session_controllable_entities(session: str) -> List[Entity]:
|
||||||
|
|
|
@ -37,10 +37,10 @@ class KennelCat:
|
||||||
|
|
||||||
|
|
||||||
class KennelCatService:
|
class KennelCatService:
|
||||||
def __init__(self, hc_endpoint: str):
|
def __init__(self, endpoint: str):
|
||||||
self.hc_endpoint = hc_endpoint
|
self.endpoint = endpoint
|
||||||
|
|
||||||
def get_kennel(self) -> List[KennelCat]:
|
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()
|
response.raise_for_status()
|
||||||
return [KennelCat.from_dict(cat) for cat in response.json()]
|
return [KennelCat.from_dict(cat) for cat in response.json()]
|
||||||
|
|
|
@ -30,7 +30,6 @@ from kennel.kennel import (
|
||||||
create_session_controllable_entities,
|
create_session_controllable_entities,
|
||||||
entity_manager,
|
entity_manager,
|
||||||
kennel,
|
kennel,
|
||||||
kennel_cats_manager,
|
|
||||||
system_manager,
|
system_manager,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,14 +43,12 @@ loop = asyncio.get_event_loop()
|
||||||
async def startup_event():
|
async def startup_event():
|
||||||
logger.info("Starting Kennel...")
|
logger.info("Starting Kennel...")
|
||||||
loop.create_task(kennel.run())
|
loop.create_task(kennel.run())
|
||||||
loop.create_task(kennel_cats_manager.start())
|
|
||||||
|
|
||||||
|
|
||||||
@app.on_event("shutdown")
|
@app.on_event("shutdown")
|
||||||
async def shutdown_event():
|
async def shutdown_event():
|
||||||
logger.info("Stopping Kennel...")
|
logger.info("Stopping Kennel...")
|
||||||
kennel.stop()
|
kennel.stop()
|
||||||
kennel_cats_manager.stop()
|
|
||||||
loop.stop()
|
loop.stop()
|
||||||
logger.info("Kennel stopped")
|
logger.info("Kennel stopped")
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview",
|
"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": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-inject": "^5.0.5",
|
"@rollup/plugin-inject": "^5.0.5",
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
PositionComponent,
|
|
||||||
RenderableComponent,
|
RenderableComponent,
|
||||||
TrailingPositionComponent,
|
TrailingPositionComponent,
|
||||||
} from "./component";
|
} from "./component";
|
||||||
|
|
||||||
export enum EntityType {
|
export enum EntityType {
|
||||||
LASER = "LASER",
|
LASER = "LASER",
|
||||||
CAT = "CAT",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Entity {
|
export interface Entity {
|
||||||
|
@ -30,16 +28,3 @@ export const create_laser = (base: Entity) => {
|
||||||
base.components[ComponentType.RENDERABLE] = renderable;
|
base.components[ComponentType.RENDERABLE] = renderable;
|
||||||
return base;
|
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,
|
PositionComponent,
|
||||||
TrailingPositionComponent,
|
TrailingPositionComponent,
|
||||||
} from "./component";
|
} from "./component";
|
||||||
import { create_cat, create_laser, Entity, EntityType } from "./entity";
|
import { create_laser, Entity, EntityType } from "./entity";
|
||||||
import {
|
import {
|
||||||
EntityBornEvent,
|
EntityBornEvent,
|
||||||
EntityDeathEvent,
|
EntityDeathEvent,
|
||||||
|
@ -110,9 +110,6 @@ export class NetworkSystem extends System {
|
||||||
if (entity.entity_type === EntityType.LASER) {
|
if (entity.entity_type === EntityType.LASER) {
|
||||||
return create_laser(entity);
|
return create_laser(entity);
|
||||||
}
|
}
|
||||||
if (entity.entity_type === EntityType.CAT) {
|
|
||||||
return create_cat(entity);
|
|
||||||
}
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
import {
|
import { ComponentType, TrailingPositionComponent } from "./component";
|
||||||
ComponentType,
|
|
||||||
PositionComponent,
|
|
||||||
TrailingPositionComponent,
|
|
||||||
} from "./component";
|
|
||||||
import { Game } from "./game";
|
import { Game } from "./game";
|
||||||
import { System, SystemType } from "./system";
|
import { System, SystemType } from "./system";
|
||||||
import { drawLaserPen } from "laser-pen";
|
import { drawLaserPen } from "laser-pen";
|
||||||
|
@ -29,17 +25,6 @@ export class RenderSystem extends System {
|
||||||
] as TrailingPositionComponent;
|
] as TrailingPositionComponent;
|
||||||
if (trailing_position.trails.length < 3) return;
|
if (trailing_position.trails.length < 3) return;
|
||||||
drawLaserPen(ctx, trailing_position.trails);
|
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 publisher: EventPublisher = new WebsocketEventPublisher(ws);
|
||||||
const network_system = new NetworkSystem(queue, publisher);
|
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);
|
const input_system = new InputSystem(publisher, gamecanvas);
|
||||||
|
|
||||||
setDelay(500);
|
setDelay(1_000);
|
||||||
const render_system = new RenderSystem(gamecanvas);
|
const render_system = new RenderSystem(gamecanvas as HTMLCanvasElement);
|
||||||
|
|
||||||
const trailing_position = new TrailingPositionSystem(drainPoints);
|
const trailing_position = new TrailingPositionSystem(drainPoints);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue