Newer
Older
"""
You can add callbacks at specific points in the environment.
This "hook" mechanism is defined here.
You can add hooks via the `environment_config` under `hook_callbacks` and the here defined
`hooks_via_callback_class` function.
Each hook get different kwargs. But `env` with the environment object and `hook_ref` with the name of the hook are
always present.
# Code Documentation
"""
from __future__ import annotations
from abc import abstractmethod
from collections import defaultdict
from functools import partial
from typing import Callable, Any, TYPE_CHECKING, Type
if TYPE_CHECKING:
from cooperative_cuisine.environment import Environment
# --- environment.py ---
ITEM_INFO_LOADED = "item_info_load"
"""Called after the item info is loaded and stored in the env attribute `item_info`.
Args:
item_info (str): the string content of the item info config file.
parsed_item_info (dict[str, ItemInfo]): the parsed item info.
"""
LAYOUT_FILE_PARSED = "layout_file_parsed"
"""After the layout file was parsed. No additional kwargs. Everything is stored in the env."""
ITEM_INFO_CONFIG = "item_info_config"
"""Called before the item info is parsed.
Args:
item_info_config (str): the string content of the item info config file.
"""
ENV_INITIALIZED = "env_initialized"
"""At the end of the __init__ method.
Args:
environment_config (str): the str content of the environment config file.
layout_config (str): the str content of the layout config file.
seed (int): the random seed.
env_start_time_worldtime (datetime): the "real" world time when the hook was called.
"""
PRE_PERFORM_ACTION = "pre_perform_action"
"""Before an action is performed / entered into the environment. `action` kwarg with the entered action.
Args:
action (Action): the action that will be performed.
"""
POST_PERFORM_ACTION = "post_perform_action"
"""After an action is performed / entered into the environment. `action` kwarg with the entered action.
Args:
action (Action): the action that was performed.
"""
# TODO Pre and Post Perform Movement
PLAYER_ADDED = "player_added"
"""Called after a player has been added. Kwargs: `player` and `pos`.
Args:
player (Player): the new player object that was created.
pos (npt.NDArray[float]): the 2d position of the player.
"""
GAME_ENDED_STEP = "game_ended_step"
"""When the step function is called but the game ended already. No kwargs."""
"""Called before the state is calculated for a player.
Args:
player_id (str): The id of the player for which the state is calculated.
"""
"""When the step function is called before the execution happens. Currently not active (Optimization).
Args:
passed_time (timedelta): the time elapsed since the last step call.
"""
"""When the step function is called after the execution.
Args:
passed_time (timedelta): the time elapsed since the last step call.
"""
"""When the dictionary (containing the state) is generated.
Args:
state (dict): the current state for a player. Should follow the `StateRepresentation`.
player_id (str): the id of the player.
"""
JSON_STATE = "json_state"
"""When the json string was generated for a state.
Args:
json_data (str): the json string containing the state.
player_id (str): the id of the player.
"""
PRE_RESET_ENV_TIME = "pre_reset_env_time"
"""Before the time of the environment is reset.
Args:
env_time (datetime): the env time before the reset.
"""
POST_RESET_ENV_TIME = "post_reset_env_time"
"""After the time of the environment is reset.
Args:
env_time (datetime): the env time after the reset.
"""
# --- counters.py ---
PRE_COUNTER_PICK_UP = "pre_counter_pick_up"
"""Before the pick up on a counter is executed.
Args:
counter (Counter): the counter from which to pick up.
on_hands (bool): if the picked up item is put on the free player hands (True) or on a cooking equipment (False).
player (str): player id.
"""
POST_COUNTER_PICK_UP = "post_counter_pick_up"
"""After the pick up on a counter is executed.
Args:
counter (Counter): the counter from which to pick up.
on_hands (bool): if the picked up item is put on the free player hands (True) or on a cooking equipment (False).
return_this (Item | None): what will be put on the player (holding)
player (str): player id.
player_holding: (Item | None): the item that the player is holding.
PRE_DISPENSER_PICK_UP = "pre_dispenser_pick_up"
"""Before the pick up on a dispenser happens. `PRE_COUNTER_PICK_UP` is not called.
Args:
counter (Counter): the counter(dispenser) from which to pick up.
on_hands (bool): if the picked up item is put on the free player hands (True) or on a cooking equipment (False).
player (str): player id.
"""
POST_DISPENSER_PICK_UP = "post_dispenser_pick_up"
"""After the new item on a dispenser is generated when a pick up happens.
Args:
counter (Counter): the counter/dispenser from which to pick up.
on_hands (bool): if the picked up item is put on the free player hands (True) or on a cooking equipment (False).
return_this (Item | None): what will be put on the player (holding) - the new item / the item that was on the counter.
player (str): player id.
player_holding (Item): What the player was holding.
PRE_PLATE_DISPENSER_PICK_UP = "pre_plate_dispenser_pick_up"
"""Before the pick up on a plate dispenser happens. `PRE_COUNTER_PICK_UP` and `PRE_DISPENSER_PICK_UP` is not called.
Args:
counter (Counter): the plate dispenser from which to pick up.
on_hands (bool): if the picked up item is put on the free player hands (True) or on a cooking equipment (False).
player (str): player id.
"""
POST_PLATE_DISPENSER_PICK_UP = "post_plate_dispenser_pick_up"
"""After the pick up from a plate dispenser is executed.
Args:
counter (Counter): the counter from which to pick up.
player (str): player id.
on_hands (bool): if the picked up item is put on the free player hands (True) or on a cooking equipment (False).
returned_item (Item | None): what will be put on the player (holding)
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
"""
PRE_COUNTER_DROP_OFF = "pre_counter_drop_off"
"""Before the drop off on a counter is executed.
Args:
item (Item): the item to drop on the counter.
equipment (Item | None | deque[Item]): what is currently on the counter.
counter (Counter): the counter from which to drop off.
player (str): player id.
"""
POST_COUNTER_DROP_OFF = "post_counter_drop_off"
"""Drop off on a free counter (nothing on it).
Args:
counter (Counter): the counter from which to drop off.
player (str): player id.
item (Item): the item to drop on the counter.
"""
DROP_OFF_ON_COOKING_EQUIPMENT = "drop_off_on_cooking_equipment"
"""When drop off on a counter with a cooking equipment is on it. Before the combining happens.
Args:
item (Item): the item to drop on the counter.
equipment (Item | None | deque[Item]): what is currently on the counter.
counter (Counter): the counter from which to drop off.
occupied_before (Item): What was on the counter before the drop off.
player (str): player id.
return_this (Item | None): what will be put on the player (holding)
"""
PICK_UP_ON_COOKING_EQUIPMENT = "pick_up_on_cooking_equipment"
"""When pick up from a counter when the player is holding a cooking equipment. Before the combining happens.
Args:
return_this (Item): the item returned from the counter.
occupied_by (Item): What is now in the counter.
counter (Counter): the counter from which to pick up.
player (str): player id.
player_holding (Item): What the player was holding.
PRE_PLATE_DISPENSER_DROP_OFF = "pre_plate_dispenser_drop_off"
"""Before something is dropped on a plate dispenser.
Args:
counter (Counter): the plate dispenser from which to drop off.
player (str): player id.
item (Item): the item to drop on the counter.
"""
POST_PLATE_DISPENSER_DROP_OFF = "post_plate_dispenser_drop_off"
"""Something is dropped on a free plate dispenser.
Args:
counter (Counter): the counter from which to drop off.
player (str): player id.
item (Item): the item to drop on the counter.
"""
DROP_OFF_ON_COOKING_EQUIPMENT_PLATE_DISPENSER = (
"drop_off_on_cooking_equipment_plate_dispenser"
)
"""After something is dropped on a plate dispenser and is combined with the top plate.
Args:
counter (Counter): the counter from which to drop off.
player (str): player id.
item (Item): the item to drop on the counter.
equipment (Item | None | deque[Item]): the cooking equipment that combined the items.
return_this (Item | None): what will be put on the player (holding)
DISPENSER_ITEM_RETURNED = "dispenser_item_returned"
"""Undo the pickup on a dispenser. (Drop off action.)
Args:
counter (Counter): the dispenser.
player (str): player id.
item (Item): the item that is returned.
"""
CUTTING_BOARD_PROGRESS = "cutting_board_progress"
"""Valid cutting board interaction step.
Args:
counter (Counter): the cutting board which is used to chop the ingredient.
player (str): player id.
percent (float): how much percent is added in the progress call.
passed_time (timedelta): passed time since the last step call in the environment-
"""
CUTTING_BOARD_100 = "cutting_board_100"
"""Chopping finished on a cutting board.
Args:
counter (Counter): the cutting board.
player (str): player id.
before: (Item): What the item was before.
PROGRESS_STARTED = "progress_started"
"""Progress on a cooking equipment is started.
Args:
item (CookingEquipment): the cooking equipment that does the progress.
"""
PROGRESS_FINISHED = "progress_finished"
"""Progress on a cooking equipment is finished. (Does not include fire.)
Args:
before (CookingEquipment): the cooking equipment before the progress.
item (CookingEquipment): the cooking equipment after the progress.
PRE_SERVING = "pre_serving"
"""Called if player wants to drop off on `ServingWindow`.
Args:
counter (ServingWindow): the serving window the player wants to serve on.
item (Item): the item to serve (on the player's hand).
env_time (datetime): current env time.
player (str): the player id.
"""
POST_SERVING = "post_serving"
"""Serving was successful.
Args:
counter (ServingWindow): the serving window on which the item was served on.
item (Item): the item that was served. (Plate)
env_time (datetime): current env time.
player (str): the player id.
"""
"""Serving was not successful. (Rejected from the order manager)
Args:
counter (ServingWindow): the serving window the player wanted to serve on.
item (Item): the item that cannot be serves (now still on the player's hand).
env_time (datetime): current env time.
player (str): the player id.
"""
SCORE_CHANGED = "score_changed"
"""The score was changed.
Args:
increase (float): the increase of the score.
score (float): the new (increased) score.
info (str): additional info.
"""
PLATE_OUT_OF_KITCHEN_TIME = "plate_out_of_kitchen_time"
"""A plate is out of the kitchen (after successful serving).
Args:
time_plate_to_add (datetime): the time the plate will arrive back in the kitchen
"""
DIRTY_PLATE_ARRIVES = "dirty_plate_arrives"
"""A plate arrived at the kitchen (some time after serving)
Args:
counter (Counter):
"""
TRASHCAN_USAGE = "trashcan_usage"
"""Successful usage of the trashcan.
Args:
counter (Trashcan): the trashcan used.
item (Item): the item the player holding. (If it is a `CookingEquipmeent` only content_list is removed).
player (str): the player id.
"""
ADDED_PLATE_TO_SINK = "added_plate_to_sink"
"""Dirty Plate dropped on the sink.
Args:
counter (Sink): the sink, target of the drop off.
item (Plate): the dirty plate.
player (str): the player id.
"""
DROP_ON_SINK_ADDON = "drop_on_sink_addon"
"""Something is dropped on the sink addon and combined with the top plate.
Args:
counter (SinkAddon): the target counter of the drop off.
item (Item): the item which is combined with the top plate.
occupied_by: (Item | None): What the sink addon is occupied by.
player (str): the player id.
"""
PICK_UP_FROM_SINK_ADDON = "pick_up_from_sink_addon"
"""Player picks up the top plate.
Args:
player (str): the player id.
occupied_by (Plate): the top plate that is picked up.
counter (SinkAddon): the counter class from it picked up.
"""
PLATE_CLEANED = "plate_cleaned"
"""The player finished cleaning a plate.
Plate is transferred to the SinkAddon afterwards.
Args:
counter (Sink): The sink on which the plate was cleaned.
player (str): the player id.

Fabian Heinrich
committed
plate (Item): the plate that was cleaned.
plate_before (Item): the plate before cleaning.
"""
# --- items.py ---
ON_ITEM_TRANSITION = "on_item_transition"
"""A new Effect appears (Fire starts).
Args:
item (CookingEquipment): the pot, pan, ... on which the fire starts.
result (Effect): the fire effect that is now active on the equipment.
seconds (float/int): how long it took to create the fire.
"""
CONTENT_READY = "content_ready"
"""A meal is ready on a cooking equipment.
Args:
before (CookingEquipment): the cooking equipment.
"""
PLATED_MEAL = "plated_meal"
"""A ready meal was plated on a Plate"""
COOKING_FINISHED = "cooking_finished"
# --- orders.py ---
SERVE_NOT_ORDERED_MEAL = "serve_not_ordered_meal"
"""If a meal does not match to an order but `serve_not_ordered_meals`is active.
Args:
meal (Item): the meal that is served.
meal_name (str): equivalent to meal.name. The name of the meal.

Fabian Heinrich
committed
player (str): the player id.
"""
SERVE_WITHOUT_PLATE = "serve_without_plate"
"""Somehow tried to serve without a plate. Will not be served.
Args:
item (Item): The item that the player has in his hands.

Fabian Heinrich
committed
player (str): the player id.
"""
COMPLETED_ORDER = "completed_order"
"""A meal was served that completed an order.
Args:
order (Order): the order that was fulfilled.
meal (Item): The meal that was served.

Fabian Heinrich
committed
item (Item): The plate that was used to serve the meal (with content).
relative_order_time (timedelta): the time that the player needed to fulfill the order.
remaining_time_ratio (float): the ratio of the remaining time of the order relative to order duration.
meal_name (str): name of the meal.

Fabian Heinrich
committed
player (str): the player id.
"""
"""The initial orders were generated.
Args:
init_orders (list[Order]): the init orders.
"""
"""New orders (not init orders) were generated.
Args:
new_orders (list[Order]): the new orders.
"""
ORDER_EXPIRED = "order_expired"
"""An order expired (took too long).
Args:
order (Order): the order that expired.
"""
# --- environment.py --- but player related.
ACTION_ON_NOT_REACHABLE_COUNTER = "action_on_not_reachable_counter"
"""Player wants to interact or pick/drop but no counter is in reach.
Args:
action (Action): the action with the player id.
counter (Counter): closest but not reachable counter.

Fabian Heinrich
committed
player (str): the player id.
"""
"""Player does the put (pick or drop) action
Args:
action (Action): the action with the player id.
counter (Counter): on which the put action is performed.

Fabian Heinrich
committed
player (str): the player id.
"""
ACTION_INTERACT_START = "action_interact_start"
"""Player starts interacting on a counter.
Args:
action (Action): the action with the player id
counter (Counter): on which the player starts the interaction.

Fabian Heinrich
committed
player (str): the player id.
"""
# --- effects.py ---
ITEM_BURNED = "item_burned" # MISSING
"""NOT IMPLEMENTED"""
"""New fire from cooking equipment (Does not include spreading).
Args:
target (Counter|Item): on which the fire was created.
"""

Fabian Heinrich
committed
FIRE_EXTINGUISHED = "fire_extinguished"
"""Fire was extinguished.
Args:
target (Counter|Item): on which the fire was extinguished.
player (str): the player id.
"""
FIRE_SPREADING = "fire_spreading"
"""Fire spreads on other counter/items after some time.
Args:
target (Counter|Item): on which the fire is spreading.
"""
# --- movement.py ---
PLAYERS_COLLIDE = "players_collide"
"""Every frame player collides.
Args:
collisions (npt.NDArray[bool]): the players which collide.
"""
# --- players.py ---
PLAYER_START_INTERACT = "player_start_interaction"
"""Same as `ACTION_INTERACT_START` but in the player.py
Args:
player (str): the player id.
counter (Counter): the last interacted counter.

Fabian Heinrich
committed
item (Item): the item that the player is holding.
"""
PLAYER_END_INTERACT = "player_end_interact"
"""The interaction with a counter stopped. Either stopped by the player through button press or move away.
Args:
player (str): the player id.
counter (Counter): the last interacted counter.

Fabian Heinrich
committed
item (Item): the item that the player is holding.
"""
# -- extra --
ADDITIONAL_STATE_UPDATE = "additional_state_update"
"""Update of the additional content of the state.
Args:
update (dict[str, Any]): update of the additional state content.
"""
"""Represents a collection of hooks and provides methods to register callbacks for hooks and invoke the callbacks when hooks are triggered.
Attributes:
hooks (defaultdict[list]): A defaultdict containing lists of callbacks for each hook reference.
env (any): The environment variable passed to the Hooks instance.
Methods:
__init__(self, env: Environment)
Initializes a new instance of Hooks.
__call__(self, hook_ref: str, **kwargs)
Invokes the callbacks associated with the specified hook reference.
"""
def __init__(self, env: Environment):
"""Constructor for the Hooks object.
Args:
env (Environment): The environment object to be referenced.
"""
self.hooks: dict[str, list[Callable]] = defaultdict(list)
"""The hook callbacks per hook_ref."""
self.env: Environment = env
"""Reference to the environment object."""
def __call__(self, hook_ref, **kwargs):
for callback in self.hooks[hook_ref]:
callback(hook_ref=hook_ref, env=self.env, **kwargs)
def register_callback(self, hook_ref: str | list[str], callback: Callable):
"""Register a callback for a hook which is called when the hook is touched during execution.
Args:
hook_ref: A string or a list of strings representing the reference(s) of the hook(s) to register the callback for.
callback: A callable object (function or method) to be registered as a callback.
"""
if isinstance(hook_ref, (tuple, list, set)): # TODO check for iterable
for ref in hook_ref:
self.hooks[ref].append(callback)
else:
self.hooks[hook_ref].append(callback)
def print_hook_callback(text, env, **kwargs):
"""Dummy hook callback. Print env time and hook ref."""
#print(env.env_time, text)
class HookCallbackClass:
"""
Class: HookCallbackClass
Represents a callback class for hook events.
Attributes:
- name: A string representing the name of the callback.
- env: An Environment object representing the environment in which the callback is being executed.
Methods:
- __init__(self, name: str, env: Environment, **kwargs):
Initializes a new instance of HookCallbackClass.
- __call__(self, hook_ref: str, env: Environment, **kwargs):
Abstract method that executes the callback logic when called.
Note:
- This class is meant to be subclassed and the __call__ method implemented according to specific needs.
- The **kwargs parameter allows for additional arguments to be passed to the callback function.
Usage Example:
```python
# Create an instance of HookCallbackClass
callback = HookCallbackClass("my_callback", my_env)
# Subclass HookCallbackClass and implement the __call__ method
class MyCallback(HookCallbackClass):
def __call__(self, hook_ref: str, env: Environment, **kwargs):
# Add custom callback logic here
# Create an instance of the subclass
my_callback = MyCallback("my_callback", my_env)
# Call the callback
my_callback("hook_reference", my_env)
def __init__(self, name: str, env: Environment, **kwargs):
"""Constructor of HookCallbackClass.
Args:
name: A string representing the name of the callback.
env: An instance of the Environment class representing the reference to the environment.
**kwargs: Additional keyword arguments.
"""
self.name: str = name
"""The name of the callback."""
self.env: Environment = env
"""Reference to the environment."""
@abstractmethod
def __call__(self, hook_ref: str, env: Environment, **kwargs):
...
def hooks_via_callback_class(
name: str,
env: Environment,
hooks: list[str],
callback_class: Type[HookCallbackClass],
callback_class_kwargs: dict[str, Any],
):
"""Setup hook callback class.
Args:
name: A string representing the name of the callback class instance.
env: An instance of the Environment class.
hooks: A list of strings representing the hooks for which the callback class instance needs to be registered.
callback_class: A type representing the class of the callback instance to be created.
callback_class_kwargs: A dictionary containing additional keyword arguments to be passed to the callback class constructor.
"""
recorder = callback_class(name=name, env=env, **callback_class_kwargs)
for hook in hooks:
env.register_callback_for_hook(hook, recorder)
def add_dummy_callbacks(env):
"""Checking the hooks-callback functionality.
Args:
env: The environment object that represents the system environment.
This method adds dummy callbacks to the given environment object. Each callback is registered for a specific hook using the `register_callback_for_hook` method of the environment.
The callbacks are defined using the `partial` function from the `functools` module. This allows us to pass additional arguments to the callback while registering it. The `print_hook
*_callback` function is used as the callback function, and it prints a message to the console.
Here are the hooks and corresponding messages that are registered:
1. SERVE_NOT_ORDERED_MEAL: Prints the message "You tried to serve a meal that was not ordered!"
2. SINK_START_INTERACT: Prints the message "You started to use the Sink!"
3. COMPLETED_ORDER: Prints the message "You completed an order!"
4. TRASHCAN_USAGE: Prints the message "You used the trashcan!"
These dummy callbacks can be used for testing or demonstration purposes.
"""
env.register_callback_for_hook(
SERVE_NOT_ORDERED_MEAL,
partial(
print_hook_callback,
text="You tried to served a meal that was not ordered!",
),
)
env.register_callback_for_hook(
COMPLETED_ORDER,
partial(
print_hook_callback,
text="You completed an order!",
),
)
env.register_callback_for_hook(
TRASHCAN_USAGE,
partial(
print_hook_callback,
text="You used the trashcan!",
),
)