diff --git a/cooperative_cuisine/configs/environment_config.yaml b/cooperative_cuisine/configs/environment_config.yaml index e9188198069ad26875177645f39bcf8d39f1838d..b005d07a014b62adac291f8716d42a709f789fac 100644 --- a/cooperative_cuisine/configs/environment_config.yaml +++ b/cooperative_cuisine/configs/environment_config.yaml @@ -179,6 +179,7 @@ hook_callbacks: - players_collide - post_plate_dispenser_pick_up - post_plate_dispenser_drop_off + - drop_off_on_cooking_equipment_plate_dispenser - on_item_transition - progress_started - progress_finished diff --git a/cooperative_cuisine/configs/human_readable_print_templates.yaml b/cooperative_cuisine/configs/human_readable_print_templates.yaml index cb9c47e9d634a2a320ec0456858e58a444e021fb..e2cf2e2e1813ad48dc220789363a3716b48dbb15 100644 --- a/cooperative_cuisine/configs/human_readable_print_templates.yaml +++ b/cooperative_cuisine/configs/human_readable_print_templates.yaml @@ -21,6 +21,7 @@ fire_spreading: "A fire spread to target." drop_off_on_cooking_equipment: "Player $player put $item in/on $equipment at $counter." post_plate_dispenser_pick_up: "Player $player picked up $returned_item from $counter." post_plate_dispenser_drop_off: "Player $player dropped $item on $counter." +drop_off_on_cooking_equipment_plate_dispenser: "Player $player dropped $item on $counter." on_item_transition: "$item became $result." progress_started: "Item $item started progressing." progress_finished: "Item $item finished its progress." diff --git a/cooperative_cuisine/counters.py b/cooperative_cuisine/counters.py index bf97c26b5886f738d122c282e8aa57cbcfe3d113..97dd339359c6887ffad601782084813cae5eaefe 100644 --- a/cooperative_cuisine/counters.py +++ b/cooperative_cuisine/counters.py @@ -69,6 +69,7 @@ from cooperative_cuisine.hooks import ( PRE_PLATE_DISPENSER_PICK_UP, POST_PLATE_DISPENSER_PICK_UP, DISPENSER_ITEM_RETURNED, + DROP_OFF_ON_COOKING_EQUIPMENT_PLATE_DISPENSER, ) from cooperative_cuisine.state_representation import CounterState @@ -235,14 +236,16 @@ class Counter: item=item, ) elif self.occupied_by.can_combine(item): + return_this = self.occupied_by.combine(item) self.hook( DROP_OFF_ON_COOKING_EQUIPMENT, item=item, equipment=self.occupied_by, counter=self, player=player, + return_this=return_this, ) - return self.occupied_by.combine(item) + return return_this return None @@ -606,6 +609,7 @@ class PlateDispenser(Counter): self.hook( PRE_PLATE_DISPENSER_PICK_UP, counter=self, + on_hands=on_hands, player=player, ) if self.occupied_by: @@ -614,6 +618,7 @@ class PlateDispenser(Counter): POST_PLATE_DISPENSER_PICK_UP, counter=self, player=player, + on_hands=on_hands, returned_item=returned_item, ) return returned_item @@ -628,6 +633,7 @@ class PlateDispenser(Counter): player=player, item=item, ) + # unnecessary hooks? if not self.occupied_by: self.occupied_by.append(item) self.hook( @@ -639,10 +645,12 @@ class PlateDispenser(Counter): elif self.occupied_by[-1].can_combine(item): returned_item = self.occupied_by[-1].combine(item) self.hook( - POST_PLATE_DISPENSER_DROP_OFF, + DROP_OFF_ON_COOKING_EQUIPMENT_PLATE_DISPENSER, counter=self, player=player, - item=returned_item, + item=item, + equipment=self.occupied_by[-1], + return_this=returned_item, ) return returned_item return None diff --git a/cooperative_cuisine/environment.py b/cooperative_cuisine/environment.py index 25eff9e6734879d45dfad4ad6359c2b75fc1826f..f4c087fa1a55b21efc2c558b3bd9c4bddacce0f2 100644 --- a/cooperative_cuisine/environment.py +++ b/cooperative_cuisine/environment.py @@ -193,7 +193,9 @@ class Environment: self.item_info: dict[str, ItemInfo] = self.load_item_info(item_info) """The loaded item info dict. Keys are the item names.""" - self.hook(ITEM_INFO_LOADED, item_info=item_info) + self.hook( + ITEM_INFO_LOADED, item_info=item_info, parsed_item_info=self.item_info + ) if self.environment_config["orders"]["meals"]["all"]: self.allowed_meal_names: Set[str] = set( @@ -371,7 +373,7 @@ class Environment: Utility method to pass a reference to the serving window.""" return self.env_time - def load_item_info(self, item_info) -> dict[str, ItemInfo]: + def load_item_info(self, item_info: str) -> dict[str, ItemInfo]: """Load `item_info.yml`, create ItemInfo classes and replace equipment strings with item infos.""" self.hook(ITEM_INFO_CONFIG, item_info_config=item_info) item_lookup = yaml.safe_load(item_info) @@ -554,9 +556,9 @@ class Environment: def reset_env_time(self): """Reset the env time to the initial time, defined by `create_init_env_time`.""" - self.hook(PRE_RESET_ENV_TIME) + self.hook(PRE_RESET_ENV_TIME, env_time=self.env_time) self.env_time = create_init_env_time() - self.hook(POST_RESET_ENV_TIME) + self.hook(POST_RESET_ENV_TIME, env_time=self.env_time) log.debug(f"Reset env time to {self.env_time}") def register_callback_for_hook(self, hook_ref: str | list[str], callback: Callable): diff --git a/cooperative_cuisine/hooks.py b/cooperative_cuisine/hooks.py index c541562b25e7018c8442e3a0b562af5b8ae40b99..edb4aa3c4d76adf38f44ec24c15829e7814f0f9a 100644 --- a/cooperative_cuisine/hooks.py +++ b/cooperative_cuisine/hooks.py @@ -21,69 +21,282 @@ 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`. The kwargs are the passed config -(`item_info`) to the environment from which it was loaded and if it is a file path or the config string (`as_files`)""" +"""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. No additional kwargs. Everything is stored in the env.""" +"""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.""" +"""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.""" +"""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`.""" +"""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.""" PRE_STATE = "pre_state" +"""Called before the state is calculated for a player. + +Args: + player_id (str): The id of the player for which the state is calculated. +""" PRE_STEP = "pre_step" +"""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. +""" + + POST_STEP = "post_step" +"""When the step function is called after the execution. + +Args: + passed_time (timedelta): the time elapsed since the last step call. +""" STATE_DICT = "state_dict" +"""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" -PRE_COUNTER_DROP_OFF = "pre_counter_drop_off" -POST_COUNTER_DROP_OFF = "post_counter_drop_off" +"""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. +""" 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. -DROP_OFF_ON_COOKING_EQUIPMENT = "drop_off_on_cooking_equipment" +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. +""" 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. + 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. +""" + +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. + player (str): player id. + return_this (Item | None): what will be put on the player (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. + return_this (Item | None): what will be put on the player (holding) + equipment (Item | None | deque[Item]): the cooking equipment that combined the items. +""" 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. +""" +# --- items.py --- 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: + item (CookingEquipment): the cooking equipment that did the progress. +""" + PRE_SERVING = "pre_serving" POST_SERVING = "post_serving" @@ -99,6 +312,11 @@ DROP_ON_SINK_ADDON = "drop_on_sink_addon" PICK_UP_FROM_SINK_ADDON = "pick_up_from_sink_addon" PLATE_CLEANED = "plate_cleaned" +ON_ITEM_TRANSITION = "on_item_transition" +CONTENT_READY = "content_ready" + +# --- orders.py --- + SERVE_NOT_ORDERED_MEAL = "serve_not_ordered_meal" SERVE_WITHOUT_PLATE = "serve_without_plate" @@ -108,22 +326,27 @@ INIT_ORDERS = "init_orders" NEW_ORDERS = "new_orders" ORDER_EXPIRED = "order_expired" +# --- environment.py --- but player related. + ACTION_ON_NOT_REACHABLE_COUNTER = "action_on_not_reachable_counter" ACTION_PUT = "action_put" ACTION_INTERACT_START = "action_interact_start" +# --- effects.py --- + ITEM_BURNED = "item_burned" # MISSING NEW_FIRE = "new_fire" FIRE_SPREADING = "fire_spreading" +# --- movement.py --- + PLAYERS_COLLIDE = "players_collide" +# --- players.py --- + PLAYER_START_INTERACT = "player_start_interaction" PLAYER_END_INTERACT = "player_end_interact" -ON_ITEM_TRANSITION = "on_item_transition" -CONTENT_READY = "content_ready" - class Hooks: """Represents a collection of hooks and provides methods to register callbacks for hooks and invoke the callbacks when hooks are triggered.