Initial commit

This commit is contained in:
nejdetckenobi committed 2026-10-02 22:07:25 +03:00
1 parent afe548e9f8
commit e4184b7cde
7 files changed
+213 -17

No files matched your search

+2 -1
View File
@@ -1,3 +1,4 @@
.venv
.vscode
*.pyc
**__pycache__/
**__pycache__/
+55
View File
@@ -0,0 +1,55 @@
from dataclasses import dataclass, field
from enum import Enum, StrEnum
@dataclass
class Name:
value: str
@dataclass
class BaseStat:
value: int
@dataclass
class Health(BaseStat):
pass
@dataclass
class Satiety(BaseStat):
pass
@dataclass
class Hydration(BaseStat):
pass
@dataclass
class Hygiene(BaseStat):
pass
@dataclass
class Capacity(BaseStat):
pass
@dataclass
class Tags:
values: list = field(default_factory=list)
class LocationType(StrEnum):
NO_WHERE = "no_where"
PADDOCK = "paddock"
STORE = "store"
INVENTORY = "inventory"
@dataclass
class Location:
type: "LocationType" = LocationType.NO_WHERE
id: int | None = None
+57
View File
@@ -0,0 +1,57 @@
from dataclasses import dataclass, field
from typing import Any, Iterator, Protocol
type Entity = int
type Archetype = frozenset[type]
type ComponentMap = dict[type, Any]
type EntityComponentStorage = dict[Entity, ComponentMap]
class System(Protocol):
@classmethod
def process(cls, world: "World") -> None: ...
@dataclass
class World:
registry: dict[Archetype, EntityComponentStorage] = field(default_factory=dict)
next_entity_index: int = 0
systems: list[type[System]] = field(default_factory=list)
def generate_id(self) -> int:
self.next_entity_index += 1
return self.next_entity_index
def spawn(self, *components) -> int:
archetype = frozenset([type(c) for c in components])
if archetype not in self.registry:
self.registry[archetype] = {}
entity = self.generate_id()
self.registry[archetype][entity] = {type(c): c for c in components}
return entity
def query(
self, *component_types, exact=False
) -> Iterator[tuple[Entity, ComponentMap]]:
component_subset_signature = frozenset(component_types)
for archetype, entity_component_storage in self.registry.items():
if (exact and component_subset_signature == archetype) or (
not exact and component_subset_signature.issubset(archetype)
):
for entity, component_storage in entity_component_storage.items():
yield entity, component_storage
def get_components(self, entity: int, pop=False):
for componentstorage in self.registry.values():
if entity in componentstorage:
if pop:
return componentstorage.pop(entity, None)
else:
return componentstorage[entity]
return None
def tick(self):
for system in self.systems:
system.process(self)
-14
View File
@@ -1,14 +0,0 @@
from dataclasses import dataclass, field
ENTITY_INDEX = 0
def generate_id():
global ENTITY_INDEX
ENTITY_INDEX += 1
return ENTITY_INDEX
@dataclass
class BaseEntity:
id: int = field(default_factory=generate_id)
+33
View File
@@ -0,0 +1,33 @@
from dataclasses import dataclass, field
from components import (
Health,
Satiety,
Location,
LocationType,
Name,
Hydration,
Hygiene,
Tags,
)
from ecs import World
def create_pet(world: World, name: str):
return world.spawn(
Name(name),
Health(100),
Satiety(80),
Hydration(80),
Hygiene(80),
Tags(),
)
def move_pet_to(world: World, pet_id, container_entity=None) -> bool:
component_map = world.get_components(pet_id, pop=True)
if component_map is None:
return False
component_map[Location].id = container_entity
component_map[Location].type = LocationType.PADDOCK
return True
+41
View File
@@ -0,0 +1,41 @@
from components import Health, Hydration, Hygiene, Satiety
from ecs import World
class SatietySystem:
@classmethod
def process(cls, world: World):
for _, component_map in world.query(Satiety):
health: Health = component_map[Health]
hunger: Satiety = component_map[Satiety]
if hunger.value <= 0:
health.value -= 1
hunger.value = 0
else:
hunger.value -= 1
class HydrationSystem:
@classmethod
def process(cls, world: World):
for _, component_map in world.query(Hydration):
health: Health = component_map[Health]
hydration: Hydration = component_map[Hydration]
if hydration.value <= 0:
health.value -= 1
hydration.value = 0
else:
hydration.value -= 1
class HygieneSystem:
@classmethod
def process(cls, world: World):
for _, component_map in world.query(Hygiene):
health: Health = component_map[Health]
hygiene: Hygiene = component_map[Hygiene]
if hygiene.value <= 0:
health.value -= 1
hygiene.value = 0
else:
hygiene.value -= 1
+25 -2
View File
@@ -1,3 +1,26 @@
from entities import BaseEntity
from imp import World, create_pet
from systems import SatietySystem, HydrationSystem, HygieneSystem
object = BaseEntity()
def test_systems_tick():
world = World()
world.systems.extend(
(
HydrationSystem,
SatietySystem,
HygieneSystem,
)
)
entity = create_pet(world, "karabas")
for _ in range(81):
world.tick()
components = world.get_components(entity)
print(components)
if __name__ == "__main__":
test_systems_tick()