feat!: remove broken plugin system
This commit is contained in:
parent
34b5a1272b
commit
e61dd387d4
8 changed files with 3 additions and 263 deletions
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
@ -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: ...
|
||||
|
|
@ -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()
|
||||
|
|
@ -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}"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue