diff --git a/CHANGELOG.md b/CHANGELOG.md index b4779d76b5a4903cf33c387c40d1496d588a2af1..d46ccc46a1701ad5848831bc7473377af71d7048 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,10 @@ ## [Unreleased] ### Added +- Added the hook PICK_UP_ON_COOKING_EQUIPMENT for finer distinction of actions ### Changed +- Added more infos to many hooks to better track the difference of before and after the hook. ### Deprecated diff --git a/cooperative_cuisine/configs/environment_config.yaml b/cooperative_cuisine/configs/environment_config.yaml index ff908dc3222b2e3a0c2f173f4a03cfaf033c2139..a46d82cf1e57deea914964a087eade5b86994b26 100644 --- a/cooperative_cuisine/configs/environment_config.yaml +++ b/cooperative_cuisine/configs/environment_config.yaml @@ -193,6 +193,8 @@ hook_callbacks: - game_ended_step - score_changed - fire_extinguished + - pick_up_on_cooking_equipment + callback_class: !!python/name:cooperative_cuisine.recording.FileRecorder '' callback_class_kwargs: diff --git a/cooperative_cuisine/counters.py b/cooperative_cuisine/counters.py index 627c0693e9794d5754bf0deae19d3b55b5037c9d..9b5e4aa52d613c645da550c09a7a4155c09438bf 100644 --- a/cooperative_cuisine/counters.py +++ b/cooperative_cuisine/counters.py @@ -34,6 +34,7 @@ The defined counter classes are: """ from __future__ import annotations +import copy import dataclasses import logging import uuid @@ -69,7 +70,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, + DROP_OFF_ON_COOKING_EQUIPMENT_PLATE_DISPENSER, PICK_UP_ON_COOKING_EQUIPMENT, ) from cooperative_cuisine.state_representation import CounterState @@ -150,7 +151,7 @@ class Counter: self.orientation = orientation def pick_up( - self, on_hands: bool = True, player: str = "0" + self, on_hands: bool = True, player: str = "0", player_holding: Item | None = None, ) -> Item | None | Iterable[Item]: """Gets called upon a player performing the pickup action. If the counter can give something to the player, it does so. In the standard counter this is when an item is on the counter. @@ -158,6 +159,7 @@ class Counter: Args: on_hands: Will the item be put on empty hands or on a cooking equipment. player: The player name that tries to pick up from the counter. + player_holding: What the player is currently holding. Returns: The item which the counter is occupied by. None if nothing is there. @@ -172,18 +174,20 @@ class Counter: counter=self, on_hands=on_hands, return_this=occupied_by, - player=player + player=player, + player_holding=player_holding, ) return occupied_by return None if self.occupied_by and isinstance(self.occupied_by, CookingEquipment): return_this = self.occupied_by.release() self.hook( - POST_COUNTER_PICK_UP, - counter=self, - on_hands=on_hands, + PICK_UP_ON_COOKING_EQUIPMENT, return_this=return_this, + occupied_by=self.occupied_by, + counter=self, player=player, + player_holding=player_holding, ) return return_this occupied_by = self.occupied_by @@ -194,6 +198,7 @@ class Counter: on_hands=on_hands, return_this=occupied_by, player=player, + player_holding=player_holding, ) return occupied_by @@ -236,12 +241,15 @@ class Counter: item=item, ) elif self.occupied_by.can_combine(item): + before_combine = copy.copy(item) + occupied_before_combine = copy.deepcopy(self.occupied_by) return_this = self.occupied_by.combine(item) self.hook( DROP_OFF_ON_COOKING_EQUIPMENT, - item=item, + item=before_combine, equipment=self.occupied_by, counter=self, + occupied_before=occupied_before_combine, player=player, return_this=return_this, ) @@ -419,11 +427,12 @@ class CuttingBoard(Counter): passed_time=passed_time, ) if self.occupied_by.progress_percentage == 1.0: + item_before = copy.copy(self.occupied_by) self.occupied_by.reset() self.occupied_by.name = self.inverted_transition_dict[ self.occupied_by.name ].name - self.hook(CUTTING_BOARD_100, counter=self, item=self.occupied_by, player=player) + self.hook(CUTTING_BOARD_100, counter=self, item=self.occupied_by, player=player, before=item_before) class ServingWindow(Counter): @@ -489,7 +498,7 @@ class ServingWindow(Counter): or (len(item.content_list) == 1 and item.content_list[0].name in self.meals) ) - def pick_up(self, on_hands: bool = True, player: str = "0") -> Item | None: + def pick_up(self, on_hands: bool = True, player: str = "0", player_holding: Item | None = None,) -> Item | None: pass def add_plate_dispenser(self, plate_dispenser): @@ -524,7 +533,7 @@ class Dispenser(Counter): **kwargs, ) - def pick_up(self, on_hands: bool = True, player: str = "0") -> Item | None: + def pick_up(self, on_hands: bool = True, player: str = "0", player_holding: Item | None = None,) -> Item | None: self.hook(PRE_DISPENSER_PICK_UP, counter=self, on_hands=on_hands, player=player) return_this = self.occupied_by self.occupied_by = self.create_item() @@ -534,6 +543,7 @@ class Dispenser(Counter): on_hands=on_hands, return_this=return_this, player=player, + player_holding=player_holding, ) return return_this @@ -628,7 +638,7 @@ class PlateDispenser(Counter): """ - def pick_up(self, on_hands: bool = True, player: str = "0") -> Item | None: + def pick_up(self, on_hands: bool = True, player: str = "0", player_holding: Item | None = None,) -> Item | None: self.hook( PRE_PLATE_DISPENSER_PICK_UP, counter=self, @@ -757,7 +767,7 @@ class Trashcan(Counter): def __init__(self, **kwargs): super().__init__(**kwargs) - def pick_up(self, on_hands: bool = True, player: str = "0") -> Item | None: + def pick_up(self, on_hands: bool = True, player: str = "0", player_holding: Item | None = None,) -> Item | None: pass def drop_off(self, item: Item, player: str = "0") -> Item | None: @@ -905,11 +915,12 @@ class Sink(Counter): equipment=self.__class__.__name__, percent=percent ) if self.occupied_by[-1].progress_percentage == 1.0: + plate_before = copy.deepcopy(self.occupied_by[-1]) self.occupied_by[-1].reset() self.occupied_by[-1].name = name plate = self.occupied_by.pop() plate.clean = True - self.hook(PLATE_CLEANED, counter=self, player=player, plate=plate) + self.hook(PLATE_CLEANED, counter=self, player=player, plate=plate, player_before=plate_before) self.sink_addon.add_clean_plate(plate) break @@ -921,7 +932,7 @@ class Sink(Counter): self.hook(ADDED_PLATE_TO_SINK, counter=self, item=item, player=player) return None - def pick_up(self, on_hands: bool = True, player: str = "0") -> Item | None: + def pick_up(self, on_hands: bool = True, player: str = "0", player_holding: Item | None = None,) -> Item | None: return None def set_addon(self, sink_addon: SinkAddon): @@ -947,14 +958,14 @@ class SinkAddon(Counter): return self.occupied_by and self.occupied_by[-1].can_combine(item) def drop_off(self, item: Item, player: str = "0") -> Item | None: - self.hook(DROP_ON_SINK_ADDON, counter=self, item=item, player=player) + self.hook(DROP_ON_SINK_ADDON, counter=self, item=item, occupied_by=self.occupied_by[-1], player=player) return self.occupied_by[-1].combine(item) def add_clean_plate(self, plate: Plate): """Called from the `Sink` after a plate is cleaned / the progress is complete.""" self.occupied_by.appendleft(plate) - def pick_up(self, on_hands: bool = True, player: str = "0") -> Item | None: + def pick_up(self, on_hands: bool = True, player: str = "0", player_holding: Item | None = None,) -> Item | None: if self.occupied_by: self.hook( PICK_UP_FROM_SINK_ADDON, diff --git a/cooperative_cuisine/hooks.py b/cooperative_cuisine/hooks.py index 8ef10d9fe8ca181db6f42b2670ade46f27b46837..3fd05f43403db3b2c5ae8608f8df65525296909b 100644 --- a/cooperative_cuisine/hooks.py +++ b/cooperative_cuisine/hooks.py @@ -151,6 +151,7 @@ Args: 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" @@ -170,6 +171,7 @@ Args: 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" @@ -187,9 +189,9 @@ POST_PLATE_DISPENSER_PICK_UP = "post_plate_dispenser_pick_up" 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. + 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) """ PRE_COUNTER_DROP_OFF = "pre_counter_drop_off" @@ -218,9 +220,20 @@ 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" @@ -251,8 +264,8 @@ 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. + return_this (Item | None): what will be put on the player (holding) """ DISPENSER_ITEM_RETURNED = "dispenser_item_returned" @@ -281,6 +294,7 @@ Args: counter (Counter): the cutting board. item (Item): the item that was chopped. player (str): player id. + before: (Item): What the item was before. """ # --- items.py --- @@ -294,7 +308,8 @@ 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. + before (CookingEquipment): the cooking equipment before the progress. + item (CookingEquipment): the cooking equipment after the progress. """ @@ -370,6 +385,7 @@ DROP_ON_SINK_ADDON = "drop_on_sink_addon" 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" @@ -389,6 +405,7 @@ Args: counter (Sink): The sink on which the plate was cleaned. player (str): the player id. plate (Item): the plate that was cleaned. + plate_before (Item): the plate before cleaning. """ # --- items.py --- @@ -405,8 +422,8 @@ CONTENT_READY = "content_ready" """A meal is ready on a cooking equipment. Args: - result (str): Name of the meal. before (CookingEquipment): the cooking equipment. + result (str): Name of the meal. """ # --- orders.py --- diff --git a/cooperative_cuisine/items.py b/cooperative_cuisine/items.py index 4bc2fa7262834fac1150d4e4b612f9b8142dadfd..8662ed2622c951ab39c92b854527eb9413873906 100644 --- a/cooperative_cuisine/items.py +++ b/cooperative_cuisine/items.py @@ -23,6 +23,7 @@ Additionally, the `Effect` class is defined for the `Fire` effect. from __future__ import annotations import collections +import copy import dataclasses import datetime import logging @@ -186,6 +187,7 @@ class Item: self.active_effects: list[Effect] = [] """The effects that affect the item.""" + @property def extra_repr(self) -> str | Literal[""]: """Additional string to add to the representation of the item (in __repr__).""" @@ -343,8 +345,9 @@ class CookingEquipment(Item): self.active_transition["result"], self ) else: + before = copy.copy(self) self.content_list = [self.active_transition["result"]] - self.hook(PROGRESS_FINISHED, item=self) + self.hook(PROGRESS_FINISHED, item=self, before=before) self.reset() self.check_active_transition() @@ -379,8 +382,9 @@ class CookingEquipment(Item): if ingredients == transition.recipe: # TODO here hook? if transition.seconds == 0: - self.hook(CONTENT_READY, result=result, before=self) + before = copy.deepcopy(self) self.content_ready = Item(name=result, item_info=transition) + self.hook(CONTENT_READY, result=self, before=before) else: self.active_transition = { "seconds": transition.seconds, diff --git a/cooperative_cuisine/player.py b/cooperative_cuisine/player.py index 5628b8e43bbdd92ca39e7c52e29b047085ee1b45..3c32a81962a2785adbb9673f61a3050ac9dd2215 100644 --- a/cooperative_cuisine/player.py +++ b/cooperative_cuisine/player.py @@ -162,7 +162,7 @@ class Player: """ if self.holding is None: - self.holding = counter.pick_up(player=self.name) + self.holding = counter.pick_up(player=self.name, player_holding=self.holding) elif counter.can_drop_off(self.holding): self.holding = counter.drop_off(self.holding, player=self.name) @@ -170,7 +170,7 @@ class Player: elif not isinstance( counter.occupied_by, (list, deque) ) and self.holding.can_combine(counter.occupied_by): - returned_by_counter = counter.pick_up(on_hands=False, player=self.name) + returned_by_counter = counter.pick_up(on_hands=False, player=self.name, player_holding=self.holding) self.holding.combine(returned_by_counter) log.debug( diff --git a/tests/test_counter.py b/tests/test_counter.py index 058a9e17ad95f1365e0dc5be6aec76ecdfa80a3e..fab8a8304e13b2359d5bae0079a09fed98cc9979 100644 --- a/tests/test_counter.py +++ b/tests/test_counter.py @@ -57,7 +57,7 @@ def test_serving_window(): ), "ServingWindow should return the item for not ordered meals." assert ( - serving_window.pick_up() is None + serving_window.pick_up() is None ), "Player should not be able to pick something from the ServingWindow." @@ -78,7 +78,7 @@ def test_dispenser(): dispenser.occupied_by.name == "MyIngredient" ), "Initialized dispenser should be occupied by dispensing item" assert ( - dispenser.pick_up().name == "MyIngredient" + dispenser.pick_up().name == "MyIngredient" ), "Picked up item should be the dispensing item" assert ( dispenser.occupied_by is not None @@ -96,6 +96,6 @@ def test_dispenser(): dispenser.pick_up() ), "Config undo_dispenser_pickup==True should allow the player to drop off picked up items" assert ( - dispenser.drop_off(dispenser.pick_up()) is None + dispenser.drop_off(dispenser.pick_up()) is None ), "Config undo_dispenser_pickup==True should allow the player to drop off picked up items" # check combine?