From edf18fd8fc99a2f5df131844dcd6d1becb92fd08 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Schr=C3=B6der?=
 <fschroeder@techfak.uni-bielefeld.de>
Date: Wed, 31 Jan 2024 09:00:59 +0100
Subject: [PATCH] Implement Fog of War feature in game environment

Added a Fog of War option that if activated, restricts the player's view in the game environment. This feature is an attribute in the game state, view_restriction, and incorporated into the get_json_state method to return player's viewing direction and angle if Fog of War is enabled. Additionally, added view restriction handling in the gui_2d_vis drawing method.
---
 overcooked_simulator/game_server.py           |  2 +-
 overcooked_simulator/gui_2d_vis/drawing.py    |  6 ++-
 .../overcooked_environment.py                 | 42 ++++++++++++-------
 overcooked_simulator/state_representation.py  |  1 +
 4 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/overcooked_simulator/game_server.py b/overcooked_simulator/game_server.py
index 95e8e18f..ba9ab75f 100644
--- a/overcooked_simulator/game_server.py
+++ b/overcooked_simulator/game_server.py
@@ -235,7 +235,7 @@ class EnvironmentHandler:
         ):
             return self.envs[
                 self.player_data[player_hash].env_id
-            ].environment.get_json_state()
+            ].environment.get_json_state(self.player_data[player_hash].player_id)
 
     def pause_env(self, manager_id: str, env_id: str, reason: str):
         """Pause the specified environment.
diff --git a/overcooked_simulator/gui_2d_vis/drawing.py b/overcooked_simulator/gui_2d_vis/drawing.py
index d2f44c42..e7279571 100644
--- a/overcooked_simulator/gui_2d_vis/drawing.py
+++ b/overcooked_simulator/gui_2d_vis/drawing.py
@@ -91,7 +91,11 @@ class Visualizer:
             grid_size,
         )
 
-        print(state)
+        if "view_restriction" in state:
+            direction = state["view_restriction"][0]
+            angel = state["view_restriction"][1]
+            # rotate direction vector in both direction with the angel
+            # draw 2 large rect which are rotated so that one edge is the viewing border
 
     def draw_background(self, surface, width, height, grid_size):
         """Visualizes a game background."""
diff --git a/overcooked_simulator/overcooked_environment.py b/overcooked_simulator/overcooked_environment.py
index 84d63128..64757f8c 100644
--- a/overcooked_simulator/overcooked_environment.py
+++ b/overcooked_simulator/overcooked_environment.py
@@ -31,6 +31,8 @@ from overcooked_simulator.utils import create_init_env_time, get_closest
 
 log = logging.getLogger(__name__)
 
+FOG_OF_WAR = True
+
 
 class ActionType(Enum):
     """The 3 different types of valid actions. They can be extended via the `Action.action_data` attribute."""
@@ -605,22 +607,30 @@ class Environment:
             "remaining_time": max(self.env_time_end - self.env_time, timedelta(0)),
         }
 
-    def get_json_state(self, player_id: str = None):
-        state = {
-            "players": [p.to_dict() for p in self.players.values()],
-            "counters": [c.to_dict() for c in self.counters],
-            "kitchen": {"width": self.kitchen_width, "height": self.kitchen_height},
-            "score": self.order_and_score.score,
-            "orders": self.order_and_score.order_state(),
-            "ended": self.game_ended,
-            "env_time": self.env_time.isoformat(),
-            "remaining_time": max(
-                self.env_time_end - self.env_time, timedelta(0)
-            ).total_seconds(),
-        }
-        json_data = json.dumps(state)
-        assert StateRepresentation.model_validate_json(json_data=json_data)
-        return json_data
+    def get_json_state(self, player_id: str = None) -> str:
+        if player_id in self.players:
+            state = {
+                "players": [p.to_dict() for p in self.players.values()],
+                "counters": [c.to_dict() for c in self.counters],
+                "kitchen": {"width": self.kitchen_width, "height": self.kitchen_height},
+                "score": self.order_and_score.score,
+                "orders": self.order_and_score.order_state(),
+                "ended": self.game_ended,
+                "env_time": self.env_time.isoformat(),
+                "remaining_time": max(
+                    self.env_time_end - self.env_time, timedelta(0)
+                ).total_seconds(),
+                "view_restriction": [
+                    self.players[player_id].facing_direction.tolist(),
+                    40.0,
+                ]
+                if FOG_OF_WAR
+                else None,
+            }
+            json_data = json.dumps(state)
+            assert StateRepresentation.model_validate_json(json_data=json_data)
+            return json_data
+        raise ValueError(f"No valid {player_id=}")
 
     def reset_env_time(self):
         """Reset the env time to the initial time, defined by `create_init_env_time`."""
diff --git a/overcooked_simulator/state_representation.py b/overcooked_simulator/state_representation.py
index 4fc0a137..199a61e3 100644
--- a/overcooked_simulator/state_representation.py
+++ b/overcooked_simulator/state_representation.py
@@ -64,6 +64,7 @@ class StateRepresentation(BaseModel):
     ended: bool
     env_time: datetime  # isoformat str
     remaining_time: float
+    view_restriction: None | list[list[float] | float]
 
 
 def create_json_schema():
-- 
GitLab