Source code for mciwb.switch

from typing import Callable, List

from mcipc.rcon.enumerations import Item, SetblockMode
from mcwb.types import Vec3

from mciwb.logging import log
from mciwb.monitor import Monitor
from mciwb.threads import get_client

SwitchCallback = Callable[["Switch"], None]


item_types = {
    "BUTTON": "[face=floor, facing=north]",
    "LEVER": "[face=floor, facing=north]",
    "TRIPWIRE_HOOK": "[]",
    "PRESSURE_PLATE": "[]",
}
"""
supported switch types and the properties to set on them
"""


[docs] class Switch: """ Defines a class for representing a lever, button or any other activator in the world. Implements monitoring of the switch's state with callbacks. :param position: the position of the switch in the world :param item: the item type of the switch (must be one of `item_types`) :param callback: the callback to call when the switch's state changes :param name: the name of the switch (defaults to "switch" + id) :ivar id: the id of the switch :ivar name: the name of the switch :ivar pos: the position of the switch in the world :ivar powered: the current state of the switch (True if powered) :ivar callback: the callback to call when the switch's state changes :ivar monitor: the `Monitor` object for the switch :ivar switches: the list of all switches in the world :ivar next_id: the next id to assign to a switch :ivar on: the state to check for a powered switch :ivar off: the state to check for an un-powered switch :ivar monitor: the `Monitor` object for the switch """ switches: List["Switch"] = [] next_id: int = 0 def __init__( self, position: Vec3, item: Item, callback: SwitchCallback, name: str = "", ) -> None: self.pos = position self.callback = callback Switch.next_id += 1 self.id = Switch.next_id self.name = name if name else f"switch{self.id}" Switch.switches.append(self) self.powered = False for key, val in item_types.items(): if key in str(item).upper(): properties = val break else: raise ValueError(f"{item} is not a supported type of switch") self.on = str(item) + "[powered=true]" self.off = str(item) + "[powered=false]" # TODO pass properties for orientation to the constructor full_item = str(item) + properties res = get_client().setblock(position, full_item, mode=SetblockMode.REPLACE) if "Changed the block" not in res: log.warning(res) log.info(f"Created switch {self.name}, id {self.id} at {position}") self.monitor = Monitor(self._poll, name=self.name)
[docs] @classmethod def remove_named(cls, name: str): """ Remove a switch by name. """ for switch in cls.switches: if switch.name == name: switch.remove()
# fail silently if the switch isn't found
[docs] def remove(self): """ Remove the switch from the world. Clean up the monitor. """ if self in self.switches: self.switches.remove(self) self.monitor.stop() get_client().setblock(self.pos, str(Item.AIR), mode=SetblockMode.REPLACE) log.info(f"Deleted switch {self.id} at {self.pos}")
[docs] @classmethod def stop(cls): """ Stop monitoring the state of all switches. """ # TODO this does nothing currently? cls.monitoring = False
[docs] def check_state(self, state: str) -> bool: """ Test the state of one of the switch's properties. :param state: the state to test for, should be one of *self.on* or *self.off* """ res = get_client().execute.if_.block(self.pos, state).run("seed") if "Seed" in res: result = True else: result = False return result
def _poll(self): if self.powered: if self.check_state(self.off): self.powered = False if self.callback: self.callback(self) else: if self.check_state(self.on): self.powered = True if self.callback: self.callback(self)