diff --git a/README.md b/README.md index fe1c721bf289d88cbbc4ffb7c9cc49c327e5998c..2798a4f0bf10be8d1b5f63dccb2ce0f29106497d 100644 --- a/README.md +++ b/README.md @@ -27,26 +27,23 @@ pip install -e . Run it via the command line (in your pyenv/conda environment): ```bash -cooperative_cuisine --url "localhost" --port 8000 +cooperative_cuisine -s localhost -sp 8080 -g localhost -gp 8000 ``` -_The arguments are the defaults. Therefore, they are optional._ +*The arguments shown are the defaults.* -You can also start the **Game Server** and the **PyGame GUI** individually in different terminals. +You can also start the **Game Server**m **Study Server** (Matchmaking),and the **PyGame GUI** individually in different +terminals. ```bash -python3 cooperative_cuisine/game_server.py --url "localhost" --port 8000 --manager_ids SECRETKEY1 SECRETKEY2 +python3 cooperative_cuisine/game_server.py -g localhost -gp 8000 --manager_ids SECRETKEY1 SECRETKEY2 -python3 cooperative_cuisine/pygame_2d_vis/gui.py --url "localhost" --port 8000 --manager_ids SECRETKEY1 -``` - -You can start also several GUIs. +python3 cooperative_cuisine/study_server.py -s localhost -sp 8080 --manager_ids SECRETKEY1 -```bash -python3 cooperative_cuisine/pygame_2d_vis/gui.py --url "localhost" --port 8000 --manager_ids SECRETKEY2 +python3 cooperative_cuisine/pygame_2d_vis/gui.py -s localhost -sp 8080 -g localhost -gp 8000 ``` -You can replace the GUI with your own GUI (+ study server/matchmaking server). +You can start also several GUIs. The study server does the matchmaking. ### Library Installation diff --git a/cooperative_cuisine/__init__.py b/cooperative_cuisine/__init__.py index ba4ea0fc2df0f3a1e5417fcf0161966f7fcbd195..c32875fb9546c2096f130f0f95c37af06046c29e 100644 --- a/cooperative_cuisine/__init__.py +++ b/cooperative_cuisine/__init__.py @@ -41,17 +41,19 @@ options. Run it via the command line (in your pyenv/conda environment): ```bash -cooperative_cuisine --url "localhost" --port 8000 +cooperative_cuisine -s localhost -sp 8080 -g localhost -gp 8000 ``` *The arguments shown are the defaults.* -You can also start the **Game Server** and the **PyGame GUI** individually in different terminals. +You can also start the **Game Server**m **Study Server** (Matchmaking),and the **PyGame GUI** individually in different terminals. ```bash -python3 cooperative_cuisine/game_server.py --url "localhost" --port 8000 --manager_ids SECRETKEY1 SECRETKEY2 +python3 cooperative_cuisine/game_server.py -g localhost -gp 8000 --manager_ids SECRETKEY1 SECRETKEY2 -python3 cooperative_cuisine/pygame_2d_vis/gui.py --url "localhost" --port 8000 --manager_ids SECRETKEY1 +python3 cooperative_cuisine/study_server.py -s localhost -sp 8080 --manager_ids SECRETKEY1 + +python3 cooperative_cuisine/pygame_2d_vis/gui.py -s localhost -sp 8080 -g localhost -gp 8000 ``` ## Connect with agent and receive game state @@ -191,7 +193,7 @@ python state_representation.py ``` Should look like ``` -{'$defs': {'CookingEquipmentState': {'properties': {'content_list': {'items': {'$ref': '#/$defs/ItemState'}, 'title': 'Content List', 'type': 'array'}, 'content_ready': {'anyOf': [{'$ref': '#/$defs/ItemState'}, {'type': 'null'}]}}, 'required': ['content_list', 'content_ready'], 'title': 'CookingEquipmentState', 'type': 'object'}, 'CounterState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'category': {'const': 'Counter', 'title': 'Category'}, 'type': {'title': 'Type', 'type': 'string'}, 'pos': {'items': {'type': 'number'}, 'title': 'Pos', 'type': 'array'}, 'occupied_by': {'anyOf': [{'items': {'anyOf': [{'$ref': '#/$defs/ItemState'}, {'$ref': '#/$defs/CookingEquipmentState'}]}, 'type': 'array'}, {'$ref': '#/$defs/ItemState'}, {'$ref': '#/$defs/CookingEquipmentState'}, {'type': 'null'}], 'title': 'Occupied By'}}, 'required': ['id', 'category', 'type', 'pos', 'occupied_by'], 'title': 'CounterState', 'type': 'object'}, 'ItemState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'category': {'anyOf': [{'const': 'Item'}, {'const': 'ItemCookingEquipment'}], 'title': 'Category'}, 'type': {'title': 'Type', 'type': 'string'}, 'progress_percentage': {'anyOf': [{'type': 'number'}, {'type': 'integer'}], 'title': 'Progress Percentage'}}, 'required': ['id', 'category', 'type', 'progress_percentage'], 'title': 'ItemState', 'type': 'object'}, 'KitchenInfo': {'properties': {'width': {'title': 'Width', 'type': 'number'}, 'height': {'title': 'Height', 'type': 'number'}}, 'required': ['width', 'height'], 'title': 'KitchenInfo', 'type': 'object'}, 'OrderState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'category': {'const': 'Order', 'title': 'Category'}, 'meal': {'title': 'Meal', 'type': 'string'}, 'start_time': {'format': 'date-time', 'title': 'Start Time', 'type': 'string'}, 'max_duration': {'title': 'Max Duration', 'type': 'number'}}, 'required': ['id', 'category', 'meal', 'start_time', 'max_duration'], 'title': 'OrderState', 'type': 'object'}, 'PlayerState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'pos': {'items': {'type': 'number'}, 'title': 'Pos', 'type': 'array'}, 'facing_direction': {'items': {'type': 'number'}, 'title': 'Facing Direction', 'type': 'array'}, 'holding': {'anyOf': [{'$ref': '#/$defs/ItemState'}, {'$ref': '#/$defs/CookingEquipmentState'}, {'type': 'null'}], 'title': 'Holding'}, 'current_nearest_counter_pos': {'anyOf': [{'items': {'type': 'number'}, 'type': 'array'}, {'type': 'null'}], 'title': 'Current Nearest Counter Pos'}, 'current_nearest_counter_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Current Nearest Counter Id'}}, 'required': ['id', 'pos', 'facing_direction', 'holding', 'current_nearest_counter_pos', 'current_nearest_counter_id'], 'title': 'PlayerState', 'type': 'object'}}, 'properties': {'players': {'items': {'$ref': '#/$defs/PlayerState'}, 'title': 'Players', 'type': 'array'}, 'counters': {'items': {'$ref': '#/$defs/CounterState'}, 'title': 'Counters', 'type': 'array'}, 'kitchen': {'$ref': '#/$defs/KitchenInfo'}, 'score': {'anyOf': [{'type': 'number'}, {'type': 'integer'}], 'title': 'Score'}, 'orders': {'items': {'$ref': '#/$defs/OrderState'}, 'title': 'Orders', 'type': 'array'}, 'ended': {'title': 'Ended', 'type': 'boolean'}, 'env_time': {'format': 'date-time', 'title': 'Env Time', 'type': 'string'}, 'remaining_time': {'title': 'Remaining Time', 'type': 'number'}}, 'required': ['players', 'counters', 'kitchen', 'score', 'orders', 'ended', 'env_time', 'remaining_time'], 'title': 'StateRepresentation', 'type': 'object'} +{'$defs': {'CookingEquipmentState': {'properties': {'content_list': {'items': {'$ref': '#/$defs/ItemState'}, 'title': 'Content List', 'type': 'array'}, 'content_ready': {'anyOf': [{'$ref': '#/$defs/ItemState'}, {'type': 'null'}]}}, 'required': ['content_list', 'content_ready'], 'title': 'CookingEquipmentState', 'type': 'object'}, 'CounterState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'category': {'const': 'Counter', 'title': 'Category'}, 'type': {'title': 'Type', 'type': 'string'}, 'pos': {'items': {'type': 'number'}, 'title': 'Pos', 'type': 'array'}, 'orientation': {'items': {'type': 'number'}, 'title': 'Orientation', 'type': 'array'}, 'occupied_by': {'anyOf': [{'items': {'anyOf': [{'$ref': '#/$defs/ItemState'}, {'$ref': '#/$defs/CookingEquipmentState'}]}, 'type': 'array'}, {'$ref': '#/$defs/ItemState'}, {'$ref': '#/$defs/CookingEquipmentState'}, {'type': 'null'}], 'title': 'Occupied By'}, 'active_effects': {'items': {'$ref': '#/$defs/EffectState'}, 'title': 'Active Effects', 'type': 'array'}}, 'required': ['id', 'category', 'type', 'pos', 'orientation', 'occupied_by', 'active_effects'], 'title': 'CounterState', 'type': 'object'}, 'EffectState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'type': {'title': 'Type', 'type': 'string'}, 'progress_percentage': {'anyOf': [{'type': 'number'}, {'type': 'integer'}], 'title': 'Progress Percentage'}, 'inverse_progress': {'title': 'Inverse Progress', 'type': 'boolean'}}, 'required': ['id', 'type', 'progress_percentage', 'inverse_progress'], 'title': 'EffectState', 'type': 'object'}, 'ItemState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'category': {'anyOf': [{'const': 'Item'}, {'const': 'ItemCookingEquipment'}], 'title': 'Category'}, 'type': {'title': 'Type', 'type': 'string'}, 'progress_percentage': {'anyOf': [{'type': 'number'}, {'type': 'integer'}], 'title': 'Progress Percentage'}, 'inverse_progress': {'title': 'Inverse Progress', 'type': 'boolean'}, 'active_effects': {'items': {'$ref': '#/$defs/EffectState'}, 'title': 'Active Effects', 'type': 'array'}}, 'required': ['id', 'category', 'type', 'progress_percentage', 'inverse_progress', 'active_effects'], 'title': 'ItemState', 'type': 'object'}, 'KitchenInfo': {'description': 'Basic information of the kitchen.', 'properties': {'width': {'title': 'Width', 'type': 'number'}, 'height': {'title': 'Height', 'type': 'number'}}, 'required': ['width', 'height'], 'title': 'KitchenInfo', 'type': 'object'}, 'OrderState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'category': {'const': 'Order', 'title': 'Category'}, 'meal': {'title': 'Meal', 'type': 'string'}, 'start_time': {'format': 'date-time', 'title': 'Start Time', 'type': 'string'}, 'max_duration': {'title': 'Max Duration', 'type': 'number'}}, 'required': ['id', 'category', 'meal', 'start_time', 'max_duration'], 'title': 'OrderState', 'type': 'object'}, 'PlayerState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'pos': {'items': {'type': 'number'}, 'title': 'Pos', 'type': 'array'}, 'facing_direction': {'items': {'type': 'number'}, 'title': 'Facing Direction', 'type': 'array'}, 'holding': {'anyOf': [{'$ref': '#/$defs/ItemState'}, {'$ref': '#/$defs/CookingEquipmentState'}, {'type': 'null'}], 'title': 'Holding'}, 'current_nearest_counter_pos': {'anyOf': [{'items': {'type': 'number'}, 'type': 'array'}, {'type': 'null'}], 'title': 'Current Nearest Counter Pos'}, 'current_nearest_counter_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Current Nearest Counter Id'}}, 'required': ['id', 'pos', 'facing_direction', 'holding', 'current_nearest_counter_pos', 'current_nearest_counter_id'], 'title': 'PlayerState', 'type': 'object'}, 'ViewRestriction': {'properties': {'direction': {'items': {'type': 'number'}, 'title': 'Direction', 'type': 'array'}, 'position': {'items': {'type': 'number'}, 'title': 'Position', 'type': 'array'}, 'angle': {'title': 'Angle', 'type': 'integer'}, 'counter_mask': {'anyOf': [{'items': {'type': 'boolean'}, 'type': 'array'}, {'type': 'null'}], 'title': 'Counter Mask'}, 'range': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'title': 'Range'}}, 'required': ['direction', 'position', 'angle', 'counter_mask', 'range'], 'title': 'ViewRestriction', 'type': 'object'}}, 'description': 'The format of the returned state representation.', 'properties': {'players': {'items': {'$ref': '#/$defs/PlayerState'}, 'title': 'Players', 'type': 'array'}, 'counters': {'items': {'$ref': '#/$defs/CounterState'}, 'title': 'Counters', 'type': 'array'}, 'kitchen': {'$ref': '#/$defs/KitchenInfo'}, 'score': {'anyOf': [{'type': 'number'}, {'type': 'integer'}], 'title': 'Score'}, 'orders': {'items': {'$ref': '#/$defs/OrderState'}, 'title': 'Orders', 'type': 'array'}, 'all_players_ready': {'title': 'All Players Ready', 'type': 'boolean'}, 'ended': {'title': 'Ended', 'type': 'boolean'}, 'env_time': {'format': 'date-time', 'title': 'Env Time', 'type': 'string'}, 'remaining_time': {'title': 'Remaining Time', 'type': 'number'}, 'view_restrictions': {'anyOf': [{'items': {'$ref': '#/$defs/ViewRestriction'}, 'type': 'array'}, {'type': 'null'}], 'title': 'View Restrictions'}, 'served_meals': {'items': {'maxItems': 2, 'minItems': 2, 'prefixItems': [{'type': 'string'}, {'type': 'string'}], 'type': 'array'}, 'title': 'Served Meals', 'type': 'array'}, 'info_msg': {'items': {'maxItems': 2, 'minItems': 2, 'prefixItems': [{'type': 'string'}, {'type': 'string'}], 'type': 'array'}, 'title': 'Info Msg', 'type': 'array'}}, 'required': ['players', 'counters', 'kitchen', 'score', 'orders', 'all_players_ready', 'ended', 'env_time', 'remaining_time', 'view_restrictions', 'served_meals', 'info_msg'], 'title': 'StateRepresentation', 'type': 'object'} ``` The BaseModel and TypedDicts can be found in `cooperative_cuisine.state_representation`. The @@ -207,6 +209,11 @@ python3 cooperative_cuisine/pygame_2d_vis/drawing.py --state my_state.json - You can specify a different visualization config with `-v` or `--visualization_config`. - You can specify the name of the output file with `-o` or `--output_file`. The default is `screenshot.jpg`. +## Generate images/videos from recordings +You can record json states or only the actions and the environment config via hooks and the recording class. + +If you want to generate images or complete videos, see `cooperative_cuisine.pygame_2d_vis.video_replay`. + # Configuration The environment configuration is currently done with 3 config files + GUI configuration. @@ -311,6 +318,38 @@ player_config: Here the visualisation for all objects is defined. Reference the images or define a list of base shapes that represent the counters, ingredients, meals and players. +## Study Config + +You can setup a study with a study config. +It defines which levels the player will play after they connect to the study server. +Further, you define how many players play together within on environment. + +An example study config is: +```yaml +# Config paths are relative to configs folder. +# Layout files are relative to layouts folder. + + +levels: + - config_path: study/level1/level1_config.yaml + layout_path: overcooked-1/1-1-far-apart.layout + item_info_path: study/level1/level1_item_info.yaml + name: "Level 1-1: Far Apart" + + - config_path: environment_config.yaml + layout_path: basic.layout + item_info_path: item_info.yaml + name: "Basic" + + - config_path: study/level2/level2_config.yaml + layout_path: overcooked-1/1-4-bottleneck.layout + item_info_path: study/level2/level2_item_info.yaml + name: "Level 1-4: Bottleneck" + + +num_players: 1 +num_bots: 0 +``` # Citation