diff --git a/overcooked_simulator/__main__.py b/overcooked_simulator/__main__.py index 47abd53849bda818e27012ceac33a3db4db44d4f..7b79494b06b5c03a01526a97caf124d2c08278e4 100644 --- a/overcooked_simulator/__main__.py +++ b/overcooked_simulator/__main__.py @@ -86,22 +86,21 @@ def main(cli_args=None): if USE_STUDY_SERVER: print("Start PyGame GUI:") - pygame_gui_2 = Process(target=start_pygame_gui, args=(cli_args,)) - pygame_gui_2.start() - - # print("Start PyGame GUI:") - # pygame_gui_3 = Process(target=start_pygame_gui, args=(cli_args,)) - # pygame_gui_3.start() - while ( - pygame_gui.is_alive() - and pygame_gui_2.is_alive() - # and pygame_gui_3.is_alive() - ): - time.sleep(1) - - else: - while pygame_gui.is_alive(): - time.sleep(1) + # pygame_gui_2 = Process(target=start_pygame_gui, args=(cli_args,)) + # pygame_gui_2.start() + # + # # print("Start PyGame GUI:") + # # pygame_gui_3 = Process(target=start_pygame_gui, args=(cli_args,)) + # # pygame_gui_3.start() + # while ( + # pygame_gui.is_alive() + # and pygame_gui_2.is_alive() + # # and pygame_gui_3.is_alive() + # ): + # time.sleep(1) + + while pygame_gui.is_alive(): + time.sleep(1) except KeyboardInterrupt: print("Received Keyboard interrupt") diff --git a/overcooked_simulator/example_study_server.py b/overcooked_simulator/example_study_server.py index c58854203d859b52d9c6c6bf3daa18bd82fed714..b1fac496276de729608d8a3bbf6dcceac25a8615 100644 --- a/overcooked_simulator/example_study_server.py +++ b/overcooked_simulator/example_study_server.py @@ -40,21 +40,6 @@ game_server_url = "localhost:8000" server_manager_id = None -# @app.get("/") -# async def root(response_class=HTMLResponse): -# return """ -# <html> -# <head> -# <title>Overcooked Game</title> -# </head> -# <body> -# <h1>Start Game!</h1> -# <button type="button">Click Me!</button> -# </body> -# </html> -# """ - - HARDCODED_MANAGER_ID = "1234" @@ -191,7 +176,7 @@ class StudyManager: self.current_free_envs = [] def create_study(self): - study = StudyState(ROOT_DIR / "game_content" / "study_config.yaml") + study = StudyState(ROOT_DIR / "game_content" / "study" / "study_config.yaml") study.start() self.running_studies.append(study) diff --git a/overcooked_simulator/game_content/layouts/large.layout b/overcooked_simulator/game_content/layouts/test_layouts/large.layout similarity index 100% rename from overcooked_simulator/game_content/layouts/large.layout rename to overcooked_simulator/game_content/layouts/test_layouts/large.layout diff --git a/overcooked_simulator/game_content/layouts/large_t.layout b/overcooked_simulator/game_content/layouts/test_layouts/large_t.layout similarity index 100% rename from overcooked_simulator/game_content/layouts/large_t.layout rename to overcooked_simulator/game_content/layouts/test_layouts/large_t.layout diff --git a/overcooked_simulator/game_content/layouts/rot_test.layout b/overcooked_simulator/game_content/layouts/test_layouts/rot_test.layout similarity index 100% rename from overcooked_simulator/game_content/layouts/rot_test.layout rename to overcooked_simulator/game_content/layouts/test_layouts/rot_test.layout diff --git a/overcooked_simulator/game_content/layouts/split.layout b/overcooked_simulator/game_content/layouts/test_layouts/split.layout similarity index 100% rename from overcooked_simulator/game_content/layouts/split.layout rename to overcooked_simulator/game_content/layouts/test_layouts/split.layout diff --git a/overcooked_simulator/game_content/study/environment_config.yaml b/overcooked_simulator/game_content/study/environment_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..eadb5b3dde08eddc106ffb0b8eb81ccf2aa77280 --- /dev/null +++ b/overcooked_simulator/game_content/study/environment_config.yaml @@ -0,0 +1,157 @@ +plates: + clean_plates: 1 + dirty_plates: 2 + plate_delay: [ 5, 10 ] + # range of seconds until the dirty plate arrives. + +game: + time_limit_seconds: 20 + +meals: + all: true + # if all: false -> only orders for these meals are generated + # TODO: what if this list is empty? + list: + - TomatoSoup + - OnionSoup + - Salad + +layout_chars: + _: Free + hash: Counter # # + A: Agent + pipe: Extinguisher + P: PlateDispenser + C: CuttingBoard + X: Trashcan + $: ServingWindow + S: Sink + +: SinkAddon + at: Plate # @ just a clean plate on a counter + U: Pot # with Stove + Q: Pan # with Stove + O: Peel # with Oven + F: Basket # with DeepFryer + T: Tomato + N: Onion # oNioN + L: Lettuce + K: Potato # Kartoffel + I: Fish # fIIIsh + D: Dough + E: Cheese # chEEEse + G: Sausage # sausaGe + B: Bun + M: Meat + question: Counter # ? mushroom + ↓: Counter + ^: Counter + right: Counter + left: Counter + wave: Free # ~ Water + minus: Free # - Ice + dquote: Counter # " wall/truck + p: Counter # second plate return ?? + + +orders: + order_gen_class: !!python/name:overcooked_simulator.order.RandomOrderGeneration '' + # the class to that receives the kwargs. Should be a child class of OrderGeneration in order.py + order_gen_kwargs: + order_duration_random_func: + # how long should the orders be alive + # 'random' library call with getattr, kwargs are passed to the function + func: uniform + kwargs: + a: 40 + b: 60 + max_orders: 6 + # maximum number of active orders at the same time + num_start_meals: 2 + # number of orders generated at the start of the environment + sample_on_dur_random_func: + # 'random' library call with getattr, kwargs are passed to the function + func: uniform + kwargs: + a: 10 + b: 20 + sample_on_serving: false + # Sample the delay for the next order only after a meal was served. + score_calc_gen_func: !!python/name:overcooked_simulator.order.simple_score_calc_gen_func '' + score_calc_gen_kwargs: + # the kwargs for the score_calc_gen_func + other: 20 + scores: + Burger: 15 + OnionSoup: 10 + Salad: 5 + TomatoSoup: 10 + expired_penalty_func: !!python/name:overcooked_simulator.order.simple_expired_penalty '' + expired_penalty_kwargs: + default: -5 + serving_not_ordered_meals: !!python/name:overcooked_simulator.order.serving_not_ordered_meals_with_zero_score '' + # a func that calcs a store for not ordered but served meals. Input: meal + penalty_for_trash: !!python/name:overcooked_simulator.order.penalty_for_each_item '' + # a func that calcs the penalty for items that the player puts into the trashcan. + +player_config: + radius: 0.4 + player_speed_units_per_seconds: 6 + interaction_range: 1.6 + restricted_view: False + view_angle: 70 + view_range: 5.5 # in grid units, can be "null" + +effect_manager: + FireManager: + class: !!python/name:overcooked_simulator.effect_manager.FireEffectManager '' + kwargs: + spreading_duration: [ 5, 10 ] + fire_burns_ingredients_and_meals: true + + +extra_setup_functions: + # json_states: + # func: !!python/name:overcooked_simulator.recording.class_recording_with_hooks '' + # kwargs: + # hooks: [ json_state ] + # log_class: !!python/name:overcooked_simulator.recording.LogRecorder '' + # log_class_kwargs: + # log_path: USER_LOG_DIR/ENV_NAME/json_states.jsonl + actions: + func: !!python/name:overcooked_simulator.recording.class_recording_with_hooks '' + kwargs: + hooks: [ pre_perform_action ] + log_class: !!python/name:overcooked_simulator.recording.LogRecorder '' + log_class_kwargs: + log_path: USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl + random_env_events: + func: !!python/name:overcooked_simulator.recording.class_recording_with_hooks '' + kwargs: + hooks: [ order_duration_sample, plate_out_of_kitchen_time ] + log_class: !!python/name:overcooked_simulator.recording.LogRecorder '' + log_class_kwargs: + log_path: USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl + add_hook_ref: true + env_configs: + func: !!python/name:overcooked_simulator.recording.class_recording_with_hooks '' + kwargs: + hooks: [ env_initialized, item_info_config ] + log_class: !!python/name:overcooked_simulator.recording.LogRecorder '' + log_class_kwargs: + log_path: USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl + 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 diff --git a/overcooked_simulator/game_content/environment_config_dark.yaml b/overcooked_simulator/game_content/study/environment_config_dark.yaml similarity index 99% rename from overcooked_simulator/game_content/environment_config_dark.yaml rename to overcooked_simulator/game_content/study/environment_config_dark.yaml index 2520eff236d095836a11d406bcfe37fb7f21e29b..b11ae4fdda0647e4cf772698dc961b0659e309d2 100644 --- a/overcooked_simulator/game_content/environment_config_dark.yaml +++ b/overcooked_simulator/game_content/study/environment_config_dark.yaml @@ -5,7 +5,7 @@ plates: # range of seconds until the dirty plate arrives. game: - time_limit_seconds: 300 + time_limit_seconds: 20 meals: all: true diff --git a/overcooked_simulator/game_content/study/item_info.yaml b/overcooked_simulator/game_content/study/item_info.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1266f61ebd611cd5c2a9097b1be9dd7eff65b7f7 --- /dev/null +++ b/overcooked_simulator/game_content/study/item_info.yaml @@ -0,0 +1,232 @@ +CuttingBoard: + type: Equipment + +Sink: + type: Equipment + +Stove: + type: Equipment + +DeepFryer: + type: Equipment + +Oven: + type: Equipment + +Pot: + type: Equipment + equipment: Stove + +Pan: + type: Equipment + equipment: Stove + +Basket: + type: Equipment + equipment: DeepFryer + +Peel: + type: Equipment + equipment: Oven + +DirtyPlate: + type: Equipment + +Plate: + type: Equipment + needs: [ DirtyPlate ] + seconds: 2.0 + equipment: Sink + +# -------------------------------------------------------------------------------- + +Tomato: + type: Ingredient + +Lettuce: + type: Ingredient + +Onion: + type: Ingredient + +Meat: + type: Ingredient + +Bun: + type: Ingredient + +Potato: + type: Ingredient + +Fish: + type: Ingredient + +Dough: + type: Ingredient + +Cheese: + type: Ingredient + +Sausage: + type: Ingredient + +ChoppedTomato: + type: Ingredient + needs: [ Tomato ] + seconds: 4.0 + equipment: CuttingBoard + +ChoppedLettuce: + type: Ingredient + needs: [ Lettuce ] + seconds: 3.0 + equipment: CuttingBoard + +ChoppedOnion: + type: Ingredient + needs: [ Onion ] + seconds: 5.0 + equipment: CuttingBoard + +RawPatty: + type: Ingredient + needs: [ Meat ] + seconds: 4.0 + equipment: CuttingBoard + +RawChips: + type: Ingredient + needs: [ Potato ] + seconds: 4.0 + equipment: CuttingBoard + +ChoppedFish: + type: Ingredient + needs: [ Fish ] + seconds: 4.0 + equipment: CuttingBoard + +PizzaBase: + type: Ingredient + needs: [ Dough ] + seconds: 4.0 + equipment: CuttingBoard + +GratedCheese: + type: Ingredient + needs: [ Cheese ] + seconds: 4.0 + equipment: CuttingBoard + +ChoppedSausage: + type: Ingredient + needs: [ Sausage ] + seconds: 4.0 + equipment: CuttingBoard + +CookedPatty: + type: Ingredient + seconds: 5.0 + needs: [ RawPatty ] + equipment: Pan + +# -------------------------------------------------------------------------------- + +Chips: + type: Meal + seconds: 5.0 + needs: [ RawChips ] + equipment: Basket + +FriedFish: + type: Meal + seconds: 5.0 + needs: [ ChoppedFish ] + equipment: Basket + +Burger: + type: Meal + needs: [ Bun, ChoppedLettuce, ChoppedTomato, CookedPatty ] + equipment: ~ + +Salad: + type: Meal + needs: [ ChoppedLettuce, ChoppedTomato ] + equipment: ~ + +TomatoSoup: + type: Meal + needs: [ ChoppedTomato, ChoppedTomato, ChoppedTomato ] + seconds: 6.0 + equipment: Pot + +OnionSoup: + type: Meal + needs: [ ChoppedOnion, ChoppedOnion, ChoppedOnion ] + seconds: 6.0 + equipment: Pot + +FishAndChips: + type: Meal + needs: [ FriedFish, Chips ] + equipment: ~ + +Pizza: + type: Meal + needs: [ PizzaBase, ChoppedTomato, GratedCheese, ChoppedSausage ] + seconds: 7.0 + equipment: Peel + +# -------------------------------------------------------------------------------- + +BurntCookedPatty: + type: Waste + seconds: 5.0 + needs: [ CookedPatty ] + equipment: Pan + +BurntChips: + type: Waste + seconds: 5.0 + needs: [ Chips ] + equipment: Basket + +BurntFriedFish: + type: Waste + seconds: 5.0 + needs: [ FriedFish ] + equipment: Basket + +BurntTomatoSoup: + type: Waste + needs: [ TomatoSoup ] + seconds: 6.0 + equipment: Pot + +BurntOnionSoup: + type: Waste + needs: [ OnionSoup ] + seconds: 6.0 + equipment: Pot + +BurntPizza: + type: Waste + needs: [ Pizza ] + seconds: 7.0 + equipment: Peel + +# -------------------------------------------------------------------------------- + +Fire: + type: Effect + seconds: 5.0 + needs: [ BurntCookedPatty, BurntChips, BurntFriedFish, BurntTomatoSoup, BurntOnionSoup, BurntPizza ] + manager: FireManager + effect_type: Unusable + +# -------------------------------------------------------------------------------- + +Extinguisher: + type: Tool + seconds: 1.0 + needs: [ Fire ] diff --git a/overcooked_simulator/game_content/study/study_config.yaml b/overcooked_simulator/game_content/study/study_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..883f4304842c768aaa8492da4acaef6a61fecb70 --- /dev/null +++ b/overcooked_simulator/game_content/study/study_config.yaml @@ -0,0 +1,23 @@ +levels: + - config_path: environment_config.yaml + layout_path: overcooked-1/1-1-far-apart.layout + item_info_path: item_info.yaml + name: "Level 1-1: Far Apart" + + # - config_path: environment_config.yaml + # layout_path: overcooked-1/1-4-bottleneck.layout + # item_info_path: item_info.yaml + # name: "Level 1-4: Bottleneck" + # + # - config_path: environment_config.yaml + # layout_path: overcooked-1/1-5-circle.layout + # item_info_path: item_info.yaml + # name: "Level 1-5: Circle" + + - config_path: environment_config_dark.yaml + layout_path: overcooked-1/4-2-dark.layout + item_info_path: item_info.yaml + name: "Level 4-2: Dark" + + +num_players: 2 diff --git a/overcooked_simulator/game_content/study_config.yaml b/overcooked_simulator/game_content/study_config.yaml deleted file mode 100644 index 8667ee4159e20bf8fa3e782fccd5b20a0deaa7e9..0000000000000000000000000000000000000000 --- a/overcooked_simulator/game_content/study_config.yaml +++ /dev/null @@ -1,23 +0,0 @@ -levels: - - config_path: environment_config.yaml - layout_path: overcooked-1/1-1-far-apart.layout - item_info_path: item_info.yaml - name: "Level 1-1: Far Apart" - - - config_path: environment_config.yaml - layout_path: overcooked-1/1-4-bottleneck.layout - item_info_path: item_info.yaml - name: "Level 1-4: Bottleneck" - - - config_path: environment_config.yaml - layout_path: overcooked-1/1-5-circle.layout - item_info_path: item_info.yaml - name: "Level 1-5: Circle" - - - config_path: environment_config_dark.yaml - layout_path: overcooked-1/4-2-dark.layout - item_info_path: item_info.yaml - name: "Level 4-2: Dark" - - -num_players: 2 diff --git a/overcooked_simulator/gui_2d_vis/gui_theme.json b/overcooked_simulator/gui_2d_vis/gui_theme.json index 9f41fea590a7d36ecb6d2f3a175c46c5500a348d..24d6386e11db7011bc512f63ed2d43e05ea74227 100644 --- a/overcooked_simulator/gui_2d_vis/gui_theme.json +++ b/overcooked_simulator/gui_2d_vis/gui_theme.json @@ -167,4 +167,4 @@ "bold": 1 } } -} \ No newline at end of file +} diff --git a/overcooked_simulator/gui_2d_vis/overcooked_gui.py b/overcooked_simulator/gui_2d_vis/overcooked_gui.py index b318680709603233b33ccbbe60b7b32e9b8ce346..2804fd6891c5a91090cbb069f529bce8fa6de2ca 100644 --- a/overcooked_simulator/gui_2d_vis/overcooked_gui.py +++ b/overcooked_simulator/gui_2d_vis/overcooked_gui.py @@ -171,6 +171,8 @@ class PyGameGUI: ) self.current_layout_idx = 0 + self.last_level = False + self.beeped_once = False def setup_player_keys(self, number_players, number_key_sets=1, disjunct=False): @@ -427,7 +429,25 @@ class PyGameGUI: text="Start Game", manager=self.manager, anchors={"center": "center"}, + object_id="#start_button", + ) + + img = pygame.image.load( + ROOT_DIR / "gui_2d_vis" / "press_a.drawio.png" + ).convert_alpha() + + image_rect = img.get_rect() + image_rect.centery += 60 + self.press_a_image = pygame_gui.elements.UIImage( + image_rect, + img, + manager=self.manager, + anchors={"centerx": "centerx", "centery": "centery"}, ) + img_width = self.buttons_width + img_height = img_width * (image_rect.height / image_rect.width) + new_dims = (img_width, img_height) + self.press_a_image.set_dimensions(new_dims) rect = pygame.Rect((0, 0), (self.buttons_width, self.buttons_height)) rect.topright = (0, 0) @@ -771,6 +791,7 @@ class PyGameGUI: self.quit_button, self.fullscreen_button, self.player_selection_container, + self.press_a_image, ] self.tutorial_screen_elements = [ @@ -781,6 +802,7 @@ class PyGameGUI: self.pregame_screen_elements = [ self.recipe_image, self.level_name, + self.press_a_image, self.continue_button, ] @@ -1377,7 +1399,6 @@ class PyGameGUI: match event.ui_element: case self.continue_button: self.menu_state = MenuStates.PreGame - if self.CONNECT_WITH_STUDY_SERVER: self.send_tutorial_finished() self.start_study() @@ -1419,8 +1440,8 @@ class PyGameGUI: case self.next_game_button: if not self.CONNECT_WITH_STUDY_SERVER: self.current_layout_idx += 1 - if self.current_layout_idx == len(self.layout_file_paths): - self.current_layout_idx = 0 + if self.current_layout_idx == len(self.layout_file_paths) - 1: + self.last_level = True else: log.debug( f"LEVEL: {self.layout_file_paths[self.current_layout_idx]}" @@ -1486,6 +1507,18 @@ class PyGameGUI: print(f"Joystick {event.instance_id} disconnected") print("Number of joysticks:", pygame.joystick.get_count()) + # Press key instead of mouse button press + if self.menu_state == MenuStates.Start: + if event.type in [pygame.JOYBUTTONDOWN, pygame.KEYDOWN]: + self.menu_state = MenuStates.ControllerTutorial + self.update_screen_elements() + elif self.menu_state == MenuStates.PreGame: + if event.type in [pygame.JOYBUTTONDOWN, pygame.KEYDOWN]: + self.setup_game() + self.set_game_size() + self.menu_state = MenuStates.Game + self.update_screen_elements() + if event.type == pygame_gui.UI_BUTTON_PRESSED: self.manage_button_event(event) self.update_screen_elements()