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

use an env time instead of datetime now. Pass the passed time via the step function. Add a test

parent 625a3f15
No related branches found
No related tags found
1 merge request!24Resolve "Environment has internal time not datetime now"
Pipeline #42497 passed
......@@ -5,6 +5,8 @@ from collections import deque
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Optional
from overcooked_simulator.utils import create_init_env_time
if TYPE_CHECKING:
from overcooked_simulator.overcooked_environment import (
GameScore,
......@@ -97,7 +99,7 @@ class CuttingBoard(Counter):
self.progressing = False
super().__init__(pos)
def progress(self):
def progress(self, passed_time: timedelta, now: datetime):
"""Called by environment step function for time progression"""
if self.progressing:
if isinstance(self.occupied_by, CuttableItem):
......@@ -194,6 +196,7 @@ class PlateDispenser(Counter):
self.plate_config = {"plate_delay": [5, 10]}
self.plate_config.update(plate_config)
self.next_plate_time = datetime.max
self.env_time = create_init_env_time() # is overwritten in progress anyway
self.setup_plates()
def pick_up(self, on_hands: bool = True):
......@@ -223,7 +226,8 @@ class PlateDispenser(Counter):
def update_plate_out_of_kitchen(self):
"""Is called from the serving window to add a plate out of kitchen."""
time_plate_to_add = datetime.now() + timedelta(
# not perfect identical to datetime.now but based on framerate enough.
time_plate_to_add = self.env_time + timedelta(
seconds=np.random.uniform(
low=self.plate_config["plate_delay"][0],
high=self.plate_config["plate_delay"][1],
......@@ -251,9 +255,9 @@ class PlateDispenser(Counter):
]
)
def progress(self):
def progress(self, passed_time: timedelta, now: datetime):
"""Check if plates arrive from outside the kitchen and add a dirty plate accordingly"""
now = datetime.now()
self.env_time = now
if self.next_plate_time < now:
idx_delete = []
for i, times in enumerate(self.out_of_kitchen_timer):
......@@ -294,7 +298,7 @@ class Stove(Counter):
else:
return self.occupied_by.can_combine(item)
def progress(self):
def progress(self, passed_time: timedelta, now: datetime):
"""Called by environment step function for time progression"""
if (
self.occupied_by
......@@ -311,7 +315,7 @@ class Sink(Counter):
self.sink_addon: SinkAddon = sink_addon
self.occupied_by = deque()
def progress(self):
def progress(self, passed_time: timedelta, now: datetime):
"""Called by environment step function for time progression"""
if self.progressing:
if self.occupied_by:
......
......@@ -2,6 +2,7 @@ from __future__ import annotations
import logging
import random
from datetime import timedelta
from pathlib import Path
from threading import Lock
......@@ -23,6 +24,7 @@ from overcooked_simulator.counters import (
)
from overcooked_simulator.game_items import ItemInfo, ItemType
from overcooked_simulator.player import Player
from overcooked_simulator.utils import create_init_env_time
log = logging.getLogger(__name__)
......@@ -131,6 +133,8 @@ class Environment:
self.world_width: int = environment_config["world_width"]
self.world_height: int = environment_config["world_height"]
self.env_time = create_init_env_time()
def load_item_info(self) -> dict[str, ItemInfo]:
with open(self.item_info_path, "r") as file:
item_lookup = yaml.safe_load(file)
......@@ -429,14 +433,15 @@ class Environment:
)
return collisions_lower or collisions_upper
def step(self):
def step(self, passed_time: timedelta):
"""Performs a step of the environment. Affects time based events such as cooking or cutting things, orders
and time limits.
"""
self.env_time += passed_time
with self.lock:
for counter in self.counters:
if isinstance(counter, (CuttingBoard, Stove, Sink, PlateDispenser)):
counter.progress()
counter.progress(passed_time=passed_time, now=self.env_time)
def get_state(self):
"""Get the current state of the game environment. The state here is accessible by the current python objects.
......@@ -484,3 +489,7 @@ class Environment:
return list(
filter(lambda counter: isinstance(counter, counter_type), self.counters)
)
def reset_env_time(self):
self.env_time = create_init_env_time()
log.debug(f"Reset env time to {self.env_time}")
import logging
import time
from datetime import timedelta
from threading import Thread
import numpy as np
......@@ -44,9 +45,9 @@ class Simulator(Thread):
super().__init__()
def step(self):
def step(self, passed_time: timedelta):
"""One simulation step of the environment."""
self.env.step()
self.env.step(passed_time)
def enter_action(self, action: Action):
"""Takes an action and executes it in the environment.
......@@ -96,10 +97,10 @@ class Simulator(Thread):
"""Starts the simulator thread. Runs in a loop until stopped."""
overslept_in_ns = 0
self.env.reset_env_time()
while not self.finished:
step_start = time.time_ns()
self.step()
self.step(timedelta(seconds=overslept_in_ns / 1_000_000_000))
step_duration = time.time_ns() - step_start
time_to_sleep_ns = self.preferred_sleep_time_ns - (
......
from datetime import datetime
def create_init_env_time():
return datetime(
year=2000, month=1, day=1, hour=0, minute=0, second=0, microsecond=0
)
import time
from datetime import timedelta
import numpy as np
import pytest
......@@ -6,8 +7,9 @@ import pytest
from overcooked_simulator import ROOT_DIR
from overcooked_simulator.counters import Counter, CuttingBoard
from overcooked_simulator.game_items import CuttableItem
from overcooked_simulator.overcooked_environment import Action
from overcooked_simulator.overcooked_environment import Action, Environment
from overcooked_simulator.simulation_runner import Simulator
from overcooked_simulator.utils import create_init_env_time
layouts_folder = ROOT_DIR / "game_content" / "layouts"
......@@ -51,9 +53,12 @@ def test_simulator_frequency():
def __init__(self):
self.c = 0
def step(self):
def step(self, passed_time):
self.c += 1
def reset_env_time(self):
pass
frequency = 2000
running_time_seconds = 2
......@@ -68,7 +73,6 @@ def test_simulator_frequency():
time.sleep(running_time_seconds)
sim.stop()
print(sim.env.c)
accepted_tolerance = 0.02
lower = frequency * running_time_seconds * (1 - accepted_tolerance)
upper = frequency * running_time_seconds * (1 + accepted_tolerance)
......@@ -216,7 +220,7 @@ def test_processing():
counter_pos = np.array([100, 100])
counter = CuttingBoard(counter_pos)
sim.env.counters = [counter]
sim.env.counters.append(counter)
tomato = CuttableItem(name="Tomato", item_info=None)
sim.register_player("p1", np.array([100, 150]))
......@@ -243,3 +247,24 @@ def test_processing():
sim.enter_action(button_up)
sim.stop()
def test_time_passed():
np.random.seed(42)
env = Environment(
ROOT_DIR / "game_content" / "environment_config.yaml",
layouts_folder / "empty.layout",
ROOT_DIR / "game_content" / "item_info.yaml",
)
env.reset_env_time()
passed_time = timedelta(seconds=10)
env.step(passed_time)
assert (
env.env_time == create_init_env_time() + passed_time
), "Env time needs to be updated via the step function"
passed_time_2 = timedelta(seconds=12)
env.step(passed_time_2)
assert (
env.env_time == create_init_env_time() + passed_time + passed_time_2
), "Env time needs to be updated via the step function"
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