robolib.plugin
plugin.py Class definition for Plugin, Events and Messages used in the Plugin System. Import level: 3
1""" 2plugin.py Class definition for Plugin, Events and Messages used in the Plugin System. 3Import level: 3 4""" 5from __future__ import annotations 6from abc import ABC, abstractmethod 7from dataclasses import dataclass 8from enum import StrEnum 9from typing import Any 10from microecs import EntityId, World 11from microspec import Endpoint 12from micronetcode import Message 13 14from robolib.traits import Drawable, Restorable 15 16# pylint: disable=invalid-name 17class ResponseKind(StrEnum): 18 """The kind of responses a plugin may respond with: 'ok' (msg4wire), 'error' (wire) or 'physics' (becomes event)""" 19 Ok = "ok" 20 Error = "error" 21 Physics = "physics" 22 23@dataclass 24class Response: 25 """The response class as returned by the 'plugin.on_message_receive(w, eid)' method for all plugins and entities""" 26 kind: ResponseKind 27 payload: dict[str, Any] 28 29 @staticmethod 30 def ok(status_message: str | dict[str, Any], **kwargs) -> Response: 31 """creates an ok/status response to a message""" 32 return Response(kind=ResponseKind.Ok, payload={"status": status_message, **kwargs}) 33 34 @staticmethod 35 def err(error_message: str | dict[str, Any], **kwargs) -> Response: 36 """creates an error response to a message""" 37 return Response(kind=ResponseKind.Error, payload={"error": error_message, **kwargs}) 38 39 @staticmethod 40 def physics(**payload) -> Response: 41 """creates a physics response to a message. The payload is read by the physics system and targets components""" 42 return Response(kind=ResponseKind.Physics, payload=payload) 43 44@dataclass 45class Event: 46 """Basic event with a source and a destination, a payload an a status (physics or error)""" 47 source: Plugin # who created this 48 target: EntityId # what this event influences (anything with .id) 49 message: Message | None = None # the message that created this event (for responses!) 50 payload: dict[str, Any] | None = None # what to update the ECS data with (all fields k=>v) 51 applied: bool = False # whether this even was applied in the physics system 52 response: dict | None = None # the 'response' to be sent back to the source (channel) 53 54class Plugin(Drawable, Restorable, ABC): 55 """ 56 Plugin for world-level logic customization. Each handles a subset of network-level endpoints (e.g. 'move') 57 A plugin can also update the physics or rendering logic through callbacks. 58 Order of execution: 59 [start tick] -> on_message_receive(w, eid) -> on_tick(w) -> [update] -> on_before_physics(w) -> 60 -> [physics] -> on_after_physics(w) -> draw(w, eid?) -> on_message_response(w, eid, evt) -> [end tick] 61 """ 62 63 @property 64 @abstractmethod 65 def endpoints(self) -> list[Endpoint]: 66 """the endpoints (commands) of this plugin""" 67 68 @abstractmethod 69 def on_message_receive(self, world: World, entity_id: int, message: Message) -> Response: 70 """Called for each message and the associated entity of this plugin. Messages influence the World via Events""" 71 72 @abstractmethod 73 def on_message_response(self, world: World, event: Event) -> Response: 74 """Called for each event generated by on_message_receive if they still need answering (.response not set)""" 75 76 def on_tick(self, world: World) -> list[Event]: # pylint: disable=unused-argument 77 """ 78 Called on each tick. Returns a list of events, one or many each per entity. These are internal plugin events 79 (e.g. wind, or fixed trajectory) that will also influence the physics system. 80 """ 81 return [] 82 83 def on_before_physics(self, world: World): 84 """callback called in the main loop after state (motion) updates and before physics""" 85 86 def on_after_physics(self, world: World): 87 """callback called in the main loop after physics and before drawing""" 88 89 def draw(self, world: World, entity_id: int | None = None): # pylint: disable=arguments-differ 90 """callback called during the drawing phase. Called twice, one for global camera and one for FPV (id is set)"""
18class ResponseKind(StrEnum): 19 """The kind of responses a plugin may respond with: 'ok' (msg4wire), 'error' (wire) or 'physics' (becomes event)""" 20 Ok = "ok" 21 Error = "error" 22 Physics = "physics"
The kind of responses a plugin may respond with: 'ok' (msg4wire), 'error' (wire) or 'physics' (becomes event)
24@dataclass 25class Response: 26 """The response class as returned by the 'plugin.on_message_receive(w, eid)' method for all plugins and entities""" 27 kind: ResponseKind 28 payload: dict[str, Any] 29 30 @staticmethod 31 def ok(status_message: str | dict[str, Any], **kwargs) -> Response: 32 """creates an ok/status response to a message""" 33 return Response(kind=ResponseKind.Ok, payload={"status": status_message, **kwargs}) 34 35 @staticmethod 36 def err(error_message: str | dict[str, Any], **kwargs) -> Response: 37 """creates an error response to a message""" 38 return Response(kind=ResponseKind.Error, payload={"error": error_message, **kwargs}) 39 40 @staticmethod 41 def physics(**payload) -> Response: 42 """creates a physics response to a message. The payload is read by the physics system and targets components""" 43 return Response(kind=ResponseKind.Physics, payload=payload)
The response class as returned by the 'plugin.on_message_receive(w, eid)' method for all plugins and entities
30 @staticmethod 31 def ok(status_message: str | dict[str, Any], **kwargs) -> Response: 32 """creates an ok/status response to a message""" 33 return Response(kind=ResponseKind.Ok, payload={"status": status_message, **kwargs})
creates an ok/status response to a message
35 @staticmethod 36 def err(error_message: str | dict[str, Any], **kwargs) -> Response: 37 """creates an error response to a message""" 38 return Response(kind=ResponseKind.Error, payload={"error": error_message, **kwargs})
creates an error response to a message
40 @staticmethod 41 def physics(**payload) -> Response: 42 """creates a physics response to a message. The payload is read by the physics system and targets components""" 43 return Response(kind=ResponseKind.Physics, payload=payload)
creates a physics response to a message. The payload is read by the physics system and targets components
45@dataclass 46class Event: 47 """Basic event with a source and a destination, a payload an a status (physics or error)""" 48 source: Plugin # who created this 49 target: EntityId # what this event influences (anything with .id) 50 message: Message | None = None # the message that created this event (for responses!) 51 payload: dict[str, Any] | None = None # what to update the ECS data with (all fields k=>v) 52 applied: bool = False # whether this even was applied in the physics system 53 response: dict | None = None # the 'response' to be sent back to the source (channel)
Basic event with a source and a destination, a payload an a status (physics or error)
55class Plugin(Drawable, Restorable, ABC): 56 """ 57 Plugin for world-level logic customization. Each handles a subset of network-level endpoints (e.g. 'move') 58 A plugin can also update the physics or rendering logic through callbacks. 59 Order of execution: 60 [start tick] -> on_message_receive(w, eid) -> on_tick(w) -> [update] -> on_before_physics(w) -> 61 -> [physics] -> on_after_physics(w) -> draw(w, eid?) -> on_message_response(w, eid, evt) -> [end tick] 62 """ 63 64 @property 65 @abstractmethod 66 def endpoints(self) -> list[Endpoint]: 67 """the endpoints (commands) of this plugin""" 68 69 @abstractmethod 70 def on_message_receive(self, world: World, entity_id: int, message: Message) -> Response: 71 """Called for each message and the associated entity of this plugin. Messages influence the World via Events""" 72 73 @abstractmethod 74 def on_message_response(self, world: World, event: Event) -> Response: 75 """Called for each event generated by on_message_receive if they still need answering (.response not set)""" 76 77 def on_tick(self, world: World) -> list[Event]: # pylint: disable=unused-argument 78 """ 79 Called on each tick. Returns a list of events, one or many each per entity. These are internal plugin events 80 (e.g. wind, or fixed trajectory) that will also influence the physics system. 81 """ 82 return [] 83 84 def on_before_physics(self, world: World): 85 """callback called in the main loop after state (motion) updates and before physics""" 86 87 def on_after_physics(self, world: World): 88 """callback called in the main loop after physics and before drawing""" 89 90 def draw(self, world: World, entity_id: int | None = None): # pylint: disable=arguments-differ 91 """callback called during the drawing phase. Called twice, one for global camera and one for FPV (id is set)"""
Plugin for world-level logic customization. Each handles a subset of network-level endpoints (e.g. 'move') A plugin can also update the physics or rendering logic through callbacks. Order of execution: [start tick] -> on_message_receive(w, eid) -> on_tick(w) -> [update] -> on_before_physics(w) -> -> [physics] -> on_after_physics(w) -> draw(w, eid?) -> on_message_response(w, eid, evt) -> [end tick]
64 @property 65 @abstractmethod 66 def endpoints(self) -> list[Endpoint]: 67 """the endpoints (commands) of this plugin"""
the endpoints (commands) of this plugin
69 @abstractmethod 70 def on_message_receive(self, world: World, entity_id: int, message: Message) -> Response: 71 """Called for each message and the associated entity of this plugin. Messages influence the World via Events"""
Called for each message and the associated entity of this plugin. Messages influence the World via Events
73 @abstractmethod 74 def on_message_response(self, world: World, event: Event) -> Response: 75 """Called for each event generated by on_message_receive if they still need answering (.response not set)"""
Called for each event generated by on_message_receive if they still need answering (.response not set)
77 def on_tick(self, world: World) -> list[Event]: # pylint: disable=unused-argument 78 """ 79 Called on each tick. Returns a list of events, one or many each per entity. These are internal plugin events 80 (e.g. wind, or fixed trajectory) that will also influence the physics system. 81 """ 82 return []
Called on each tick. Returns a list of events, one or many each per entity. These are internal plugin events (e.g. wind, or fixed trajectory) that will also influence the physics system.
84 def on_before_physics(self, world: World): 85 """callback called in the main loop after state (motion) updates and before physics"""
callback called in the main loop after state (motion) updates and before physics
87 def on_after_physics(self, world: World): 88 """callback called in the main loop after physics and before drawing"""
callback called in the main loop after physics and before drawing
90 def draw(self, world: World, entity_id: int | None = None): # pylint: disable=arguments-differ 91 """callback called during the drawing phase. Called twice, one for global camera and one for FPV (id is set)"""
callback called during the drawing phase. Called twice, one for global camera and one for FPV (id is set)