diff --git a/examples/health_plugin.py b/examples/health_plugin.py deleted file mode 100644 index a795d33..0000000 --- a/examples/health_plugin.py +++ /dev/null @@ -1,88 +0,0 @@ -from typing import final - -from pydantic import Field - -from snakia.core.ecs import Component -from snakia.core.ecs.system import System -from snakia.core.engine import Engine -from snakia.core.es import Event -from snakia.core.loader import Meta, Plugin, PluginProcessor -from snakia.types import Version - - -class HealthComponent(Component): - max_value: int = Field(default=100, ge=0) - value: int = Field(default=100, ge=0) - - -class DamageComponent(Component): - damage: int = Field(ge=0) - ticks: int = Field(default=1, ge=0) - - -class HealComponent(Component): - heal: int = Field(ge=0) - ticks: int = Field(default=1, ge=0) - - -class DeathEvent(Event): - entity: int = Field() - - -class HealthProcessor(PluginProcessor): - def process(self, system: System) -> None: - for entity, (heal, health) in system.get_components( - HealComponent, HealthComponent - ): - health.value += heal.heal - heal.ticks -= 1 - if heal.ticks <= 0: - system.remove_component(entity, HealComponent) - for entity, (damage, health) in system.get_components( - DamageComponent, HealthComponent - ): - health.value -= damage.damage - damage.ticks -= 1 - if damage.ticks <= 0: - system.remove_component(entity, DamageComponent) - if health.value <= 0: - system.remove_component(entity, HealthComponent) - self.plugin.dispatcher.publish(DeathEvent(entity=entity)) - - -@final -class HealthPlugin( - Plugin, - meta=Meta( - name="health", - author="snakia", - version=Version.from_args(1, 0, 0), - subscribers=(), - processors=(HealthProcessor,), - ), -): - def on_load(self) -> None: - pass - - def on_unload(self) -> None: - pass - - -def main() -> None: - engine = Engine() - engine.loader.register(HealthPlugin) - engine.loader.load_all() - - @engine.dispatcher.on(DeathEvent) - def on_death(event: DeathEvent) -> None: - print(f"Entity: {event.entity} is death!") - - player = engine.system.create_entity() - engine.system.add_component(player, HealthComponent()) - engine.system.add_component(player, DamageComponent(damage=10, ticks=10)) - - engine.start() - - -if __name__ == "__main__": - main() diff --git a/src/snakia/core/engine.py b/src/snakia/core/engine.py index 047c26e..a4f47b2 100644 --- a/src/snakia/core/engine.py +++ b/src/snakia/core/engine.py @@ -3,14 +3,12 @@ from typing import Final from .ecs import System from .es import Dispatcher -from .loader.loader import Loader class Engine: __slots__ = ( "system", "dispatcher", - "loader", "__system_thread", "__dispatcher_thread", ) @@ -18,12 +16,13 @@ class Engine: def __init__(self) -> None: self.system: Final = System() self.dispatcher: Final = Dispatcher() - self.loader: Final = Loader(self) self.__system_thread: threading.Thread | None = None self.__dispatcher_thread: threading.Thread | None = None def start(self) -> None: - self.__system_thread = threading.Thread(target=self.system.start, daemon=False) + self.__system_thread = threading.Thread( + target=self.system.start, daemon=False + ) self.__dispatcher_thread = threading.Thread( target=self.dispatcher.start, daemon=False ) diff --git a/src/snakia/core/loader/__init__.py b/src/snakia/core/loader/__init__.py deleted file mode 100644 index 9e099c5..0000000 --- a/src/snakia/core/loader/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .loadable import Loadable -from .meta import Meta -from .plugin import Plugin -from .plugin_processor import PluginProcessor - -__all__ = ["Loadable", "Meta", "Plugin", "PluginProcessor"] diff --git a/src/snakia/core/loader/loadable.py b/src/snakia/core/loader/loadable.py deleted file mode 100644 index 51e75d0..0000000 --- a/src/snakia/core/loader/loadable.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from snakia.core.engine import Engine - - -class Loadable(ABC): - @abstractmethod - def __init__(self, engine: Engine) -> None: ... - - @abstractmethod - def load(self) -> None: ... - - @abstractmethod - def unload(self) -> None: ... diff --git a/src/snakia/core/loader/loader.py b/src/snakia/core/loader/loader.py deleted file mode 100644 index 0dcf807..0000000 --- a/src/snakia/core/loader/loader.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Callable, Final - -if TYPE_CHECKING: - from snakia.core.engine import Engine - from snakia.core.loader import Loadable - - -class Loader: - __slots__ = ("__engine", "__loadables") - - def __init__(self, engine: Engine) -> None: - self.__engine: Final = engine - self.__loadables: Final[list[Loadable]] = [] - - def register(self, loadable: Callable[[Engine], Loadable]) -> None: - self.__loadables.append(loadable(self.__engine)) - - def load_all(self) -> None: - for loadable in self.__loadables: - loadable.load() - - def unload_all(self) -> None: - for loadable in reversed(self.__loadables): - loadable.unload() diff --git a/src/snakia/core/loader/meta.py b/src/snakia/core/loader/meta.py deleted file mode 100644 index 429d4b4..0000000 --- a/src/snakia/core/loader/meta.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict, Field - -from snakia.core.es import Event, Subscriber -from snakia.types import Version - -from .plugin_processor import PluginProcessor - - -class Meta(BaseModel): - model_config = ConfigDict(frozen=True, arbitrary_types_allowed=True) - - name: str = Field( - default="unknown", - min_length=4, - max_length=32, - pattern="^[a-z0-9_]{4,32}$", - ) - author: str = Field( - default="unknown", - min_length=4, - max_length=32, - pattern="^[a-z0-9_]{4,32}$", - ) - version: Version = Field(default_factory=lambda: Version(major=1, minor=0, patch=0)) - - subscribers: tuple[tuple[type[Event], Subscriber[Event]], ...] = Field( - default_factory=tuple - ) - processors: tuple[type[PluginProcessor], ...] = Field(default_factory=tuple) - - @property - def id(self) -> str: - return f"{self.author}.{self.name}" diff --git a/src/snakia/core/loader/plugin.py b/src/snakia/core/loader/plugin.py deleted file mode 100644 index f8abfa5..0000000 --- a/src/snakia/core/loader/plugin.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import annotations - -from abc import abstractmethod -from typing import TYPE_CHECKING, ClassVar, Final, final - -from snakia.core.ecs import System -from snakia.core.es import Dispatcher - -from .loadable import Loadable -from .meta import Meta - -if TYPE_CHECKING: - from snakia.core.engine import Engine - - -class Plugin(Loadable): - __meta: ClassVar[Meta] - - @final - def __init__(self, engine: Engine) -> None: - self.__engine: Final = engine - - @final - @property - def meta(self) -> Meta: - """The plugin's metadata.""" - return self.__meta - - @final - @property - def dispatcher(self) -> Dispatcher: - return self.__engine.dispatcher - - @final - @property - def system(self) -> System: - return self.__engine.system - - @final - def load(self) -> None: - for processor in self.meta.processors: - self.__engine.system.add_processor(processor(self)) - for event_type, subscriber in self.meta.subscribers: - self.__engine.dispatcher.subscribe(event_type, subscriber) - self.on_load() - - @final - def unload(self) -> None: - for processor in self.meta.processors: - self.__engine.system.remove_processor(processor) - for event_type, subscriber in self.meta.subscribers: - self.__engine.dispatcher.unsubscribe(event_type, subscriber) - self.on_unload() - - @abstractmethod - def on_load(self) -> None: - pass - - @abstractmethod - def on_unload(self) -> None: - pass - - if TYPE_CHECKING: - - @final - def __init_subclass__(cls, meta: Meta) -> None: - pass - - else: - - def __init_subclass__(cls, meta: Meta) -> None: - cls.meta = meta diff --git a/src/snakia/core/loader/plugin_processor.py b/src/snakia/core/loader/plugin_processor.py deleted file mode 100644 index f959327..0000000 --- a/src/snakia/core/loader/plugin_processor.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Final, final - -from snakia.core.ecs import Processor - -if TYPE_CHECKING: - from .plugin import Plugin - - -class PluginProcessor(Processor): - @final - def __init__(self, plugin: Plugin) -> None: - self.plugin: Final = plugin