Skip to content
Snippets Groups Projects
Commit 5055e503 authored by Florian Schröder's avatar Florian Schröder
Browse files

Add in-game information messages feature

The updates have introduced an in-game information messages feature, allowing messages to be delivered to players during gameplay. This could be used to notify about certain events or conditions such as new fires or fire spreading. The updates also included the necessary hooks and message levels, which are 'Normal', 'Warning', and 'Success'. Furthermore, these messages can be displayed in the game's GUI.
parent beea6895
No related branches found
No related tags found
1 merge request!53Resolve "Info screens (pop ups etc)"
Pipeline #45789 passed
...@@ -12,7 +12,7 @@ from overcooked_simulator.game_items import ( ...@@ -12,7 +12,7 @@ from overcooked_simulator.game_items import (
Effect, Effect,
CookingEquipment, CookingEquipment,
) )
from overcooked_simulator.hooks import Hooks from overcooked_simulator.hooks import Hooks, NEW_FIRE, FIRE_SPREADING
from overcooked_simulator.utils import get_touching_counters, find_item_on_counters from overcooked_simulator.utils import get_touching_counters, find_item_on_counters
if TYPE_CHECKING: if TYPE_CHECKING:
...@@ -74,6 +74,7 @@ class FireEffectManager(EffectManager): ...@@ -74,6 +74,7 @@ class FireEffectManager(EffectManager):
self.next_finished_timer = min( self.next_finished_timer = min(
self.next_finished_timer, self.effect_to_timer[effect.uuid] self.next_finished_timer, self.effect_to_timer[effect.uuid]
) )
self.hook(NEW_FIRE, target=target)
self.active_effects.append((effect, target)) self.active_effects.append((effect, target))
self.new_effects = [] self.new_effects = []
if self.next_finished_timer < now: if self.next_finished_timer < now:
...@@ -110,6 +111,7 @@ class FireEffectManager(EffectManager): ...@@ -110,6 +111,7 @@ class FireEffectManager(EffectManager):
if effect.name not in target.active_effects and target.uuid not in [ if effect.name not in target.active_effects and target.uuid not in [
t.uuid for _, t in self.active_effects t.uuid for _, t in self.active_effects
]: ]:
self.hook(FIRE_SPREADING, target=target)
if isinstance(target, CookingEquipment): if isinstance(target, CookingEquipment):
if target.content_list: if target.content_list:
for content in target.content_list: for content in target.content_list:
......
...@@ -129,4 +129,18 @@ extra_setup_functions: ...@@ -129,4 +129,18 @@ extra_setup_functions:
log_class_kwargs: log_class_kwargs:
log_path: USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl log_path: USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl
add_hook_ref: true add_hook_ref: true
info_msg:
func: !!python/name:overcooked_simulator.recording.class_recording_with_hooks ''
kwargs:
hooks: [ cutting_board_100 ]
log_class: !!python/name:overcooked_simulator.info_msg.InfoMsgManager ''
log_class_kwargs:
msg: Glückwunsch du hast was geschnitten!
fire_msg:
func: !!python/name:overcooked_simulator.recording.class_recording_with_hooks ''
kwargs:
hooks: [ new_fire ]
log_class: !!python/name:overcooked_simulator.info_msg.InfoMsgManager ''
log_class_kwargs:
msg: Feuer, Feuer, Feuer
level: Warning
\ No newline at end of file
...@@ -604,6 +604,22 @@ class PyGameGUI: ...@@ -604,6 +604,22 @@ class PyGameGUI:
self.update_score_label(state) self.update_score_label(state)
if state["info_msg"]:
text_surface = self.comic_sans.render(
state["info_msg"][0][0],
antialias=True,
color=(0, 0, 0)
if state["info_msg"][0][1] == "Normal"
else (
(255, 0, 0) if state["info_msg"][0][1] == "Warning" else (0, 255, 0)
),
# bgcolor=(255, 255, 255),
)
self.main_window.blit(
text_surface,
(self.window_width / 4, self.window_height - self.screen_margin + 5),
)
def set_window_size(self): def set_window_size(self):
self.game_screen = pygame.Surface( self.game_screen = pygame.Surface(
( (
...@@ -965,6 +981,7 @@ class PyGameGUI: ...@@ -965,6 +981,7 @@ class PyGameGUI:
log.debug(f"Starting pygame gui at {self.FPS} fps") log.debug(f"Starting pygame gui at {self.FPS} fps")
pygame.init() pygame.init()
pygame.font.init() pygame.font.init()
self.comic_sans = pygame.font.SysFont("Comic Sans MS", 30)
pygame.display.set_caption("Simple Overcooked Simulator") pygame.display.set_caption("Simple Overcooked Simulator")
......
...@@ -96,6 +96,10 @@ ACTION_PUT = "action_put" ...@@ -96,6 +96,10 @@ ACTION_PUT = "action_put"
ACTION_INTERACT_START = "action_interact_start" ACTION_INTERACT_START = "action_interact_start"
NEW_FIRE = "new_fire"
FIRE_SPREADING = "fire_spreading"
class Hooks: class Hooks:
def __init__(self, env): def __init__(self, env):
......
from datetime import timedelta
from overcooked_simulator.overcooked_environment import Environment
class InfoMsgManager:
def __init__(
self,
name: str,
env: Environment,
msg: str,
duration: int = 5,
level: str = "Normal",
):
self.msg = msg
self.duration = timedelta(seconds=duration)
self.level = level
def __call__(self, hook_ref: str, env: Environment, **kwargs):
for player_id in env.players:
env.info_msgs_per_player[player_id].append(
{
"msg": self.msg,
"start_time": env.env_time,
"end_time": env.env_time + self.duration,
"level": self.level,
}
)
...@@ -5,6 +5,7 @@ import inspect ...@@ -5,6 +5,7 @@ import inspect
import json import json
import logging import logging
import sys import sys
from collections import defaultdict
from datetime import timedelta, datetime from datetime import timedelta, datetime
from enum import Enum from enum import Enum
from pathlib import Path from pathlib import Path
...@@ -50,7 +51,7 @@ from overcooked_simulator.order import ( ...@@ -50,7 +51,7 @@ from overcooked_simulator.order import (
OrderConfig, OrderConfig,
) )
from overcooked_simulator.player import Player, PlayerConfig from overcooked_simulator.player import Player, PlayerConfig
from overcooked_simulator.state_representation import StateRepresentation from overcooked_simulator.state_representation import StateRepresentation, InfoMsg
from overcooked_simulator.utils import create_init_env_time, get_closest from overcooked_simulator.utils import create_init_env_time, get_closest
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -279,6 +280,8 @@ class Environment: ...@@ -279,6 +280,8 @@ class Environment:
str, EffectManager str, EffectManager
] = self.counter_factory.setup_effect_manger(self.counters) ] = self.counter_factory.setup_effect_manger(self.counters)
self.info_msgs_per_player: dict[str, list[InfoMsg]] = defaultdict(list)
self.hook( self.hook(
ENV_INITIALIZED, ENV_INITIALIZED,
environment_config=env_config, environment_config=env_config,
...@@ -783,6 +786,12 @@ class Environment: ...@@ -783,6 +786,12 @@ class Environment:
} }
if self.player_view_restricted if self.player_view_restricted
else None, else None,
"info_msg": [
(msg["msg"], msg["level"])
for msg in self.info_msgs_per_player[player_id]
if msg["start_time"] < self.env_time
and msg["end_time"] > self.env_time
],
} }
self.hook(STATE_DICT, state=state, player_id=player_id) self.hook(STATE_DICT, state=state, player_id=player_id)
json_data = json.dumps(state) json_data = json.dumps(state)
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
Type hint classes for the representation of the json state. Type hint classes for the representation of the json state.
""" """
from datetime import datetime from datetime import datetime
from enum import Enum
from pydantic import BaseModel from pydantic import BaseModel
from typing_extensions import Literal, TypedDict from typing_extensions import Literal, TypedDict
...@@ -73,6 +74,19 @@ class ViewRestriction(BaseModel): ...@@ -73,6 +74,19 @@ class ViewRestriction(BaseModel):
counter_mask: None | list[bool] counter_mask: None | list[bool]
class InfoMsgLevel(Enum):
Normal = "Normal"
Warning = "Warning"
Success = "Success"
class InfoMsg(TypedDict):
msg: str
start_time: datetime
end_time: datetime
level: InfoMsgLevel
class StateRepresentation(BaseModel): class StateRepresentation(BaseModel):
"""The format of the returned state representation.""" """The format of the returned state representation."""
...@@ -85,6 +99,7 @@ class StateRepresentation(BaseModel): ...@@ -85,6 +99,7 @@ class StateRepresentation(BaseModel):
env_time: datetime # isoformat str env_time: datetime # isoformat str
remaining_time: float remaining_time: float
view_restriction: None | ViewRestriction view_restriction: None | ViewRestriction
info_msg: list[tuple[str, str]]
def create_json_schema(): def create_json_schema():
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment