diff --git a/CHANGELOG.md b/CHANGELOG.md
index 01fe2e8fc1478e88420e03f3568cfb9df451c09d..817d255463cdd268a6511bb907974164524de0a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,8 +13,14 @@
 
 ### Added
 
+- More Docstrings
+
 ### Changed
 
+- No keyboard tutorial. Only the controller is described. In the future, add config option which to show.
+- Study Doc is now a .jsonl file.
+- Other default processing time.
+
 ### Deprecated
 
 ### Removed
diff --git a/cooperative_cuisine/__init__.py b/cooperative_cuisine/__init__.py
index e30632759d68efe1389179f31f912fecd9ac26f7..ae22c4821557167170e293e37cdc9e7229e49bed 100644
--- a/cooperative_cuisine/__init__.py
+++ b/cooperative_cuisine/__init__.py
@@ -11,13 +11,12 @@ can be found [here](https://gitlab.ub.uni-bielefeld.de/scs/cocosy/godot-overcook
 # Background / Literature
 The overcooked/cooking domain is a well established cooperation domain/task. There exists
 environments designed for reinforcement learning agents as well as the game and adaptations of the game for human
-players in a more "real-time"-like environment. They all mostly differ in the visual and graphics dimension. 2D versions
-like overcooked-ai, ... are most well-known in the community. But more visually appealing 3D versions for cooperation with
-humans are getting developed more frequently (cite,...). Besides, the general adaptations of the original overcooked
-game.
-CooperativeCuisine, we want to bring both worlds together: the reinforcement learning and real-time playable
-environment with an appealing visualisation. Enable the potential of developing artificial agents that play with humans
-like a "real", cooperative, human partner.
+players in a more "real-time"-like environment. They all mostly differ in the visual and graphics dimension. 2D
+versions like [overcooked-ai](https://github.com/HumanCompatibleAI/overcooked_ai), [gym-cooking](
+https://github.com/rosewang2008/gym-cooking) are most well-known in the community. Besides, the general
+adaptations of the original overcooked game. CooperativeCuisine, we want to bring both worlds together: the
+reinforcement learning and real-time playable environment with an appealing visualisation. Enable the potential of
+developing artificial agents that play with humans like a "real", cooperative, human partner.
 
 # Installation
 
@@ -200,7 +199,7 @@ python state_representation.py
 ```
 Should look like - to have an interactive view, have a look at [jsonschemaviewer](https://navneethg.github.io/jsonschemaviewer/):
 ```
-{'$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'}
+{"$defs": {"CookingEquipmentState": {"description": "Format of the state representation of cooking equipment.", "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"}, "content_list": {"items": {"$ref": "#/$defs/ItemState"}, "title": "Content List", "type": "array"}, "content_ready": {"anyOf": [{"$ref": "#/$defs/ItemState"}, {"type": "null"}]}}, "required": ["id", "category", "type", "progress_percentage", "inverse_progress", "active_effects", "content_list", "content_ready"], "title": "CookingEquipmentState", "type": "object"}, "CounterState": {"description": "Format of the state representation of a counter.", "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": {"description": "Format of the state representation of an effect (fire).", "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": {"description": "Format of the state representation of an item.", "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": "Format of the state representation of basic information of the kitchen.", "properties": {"width": {"title": "Width", "type": "number"}, "height": {"title": "Height", "type": "number"}}, "required": ["width", "height"], "title": "KitchenInfo", "type": "object"}, "OrderState": {"description": "Format of the state representation of an order.", "properties": {"id": {"title": "Id", "type": "string"}, "category": {"const": "Order", "title": "Category"}, "meal": {"title": "Meal", "type": "string"}, "start_time": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "string"}], "title": "Start Time"}, "max_duration": {"title": "Max Duration", "type": "number"}, "score": {"anyOf": [{"type": "number"}, {"type": "integer"}], "title": "Score"}}, "required": ["id", "category", "meal", "start_time", "max_duration", "score"], "title": "OrderState", "type": "object"}, "PlayerState": {"description": "Format of the state representation of a player.", "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": {"description": "Format of the state representation of a view restriction from the players perspectives.\nCurrently, as a view cone, like a flashlight in the dark.", "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"}, "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", "ended", "env_time", "remaining_time", "view_restrictions", "served_meals", "info_msg"], "title": "StateRepresentation", "type": "object"}
 ```
 
 
@@ -295,10 +294,8 @@ plates:
 
 game:
   time_limit_seconds: 300
-    undo_dispenser_pickup: true
-
-meals:
-  all: true
+  undo_dispenser_pickup: true
+  validate_recipes: true
 
 layout_chars:
   _: Free
@@ -314,6 +311,8 @@ layout_chars:
   T: Tomato
 
 orders:  # how to create orders
+  meals:
+    all: true
   ...
 
 player_config:
diff --git a/cooperative_cuisine/argument_parser.py b/cooperative_cuisine/argument_parser.py
index f6bc86eb06d4c011239af26b467f2ea42c3541a6..d5c6fd4660c47e70a359de5fb95a735d19d43235 100644
--- a/cooperative_cuisine/argument_parser.py
+++ b/cooperative_cuisine/argument_parser.py
@@ -77,7 +77,6 @@ def disable_websocket_logging_arguments(parser):
     Args:
         parser: The argument parser object (argparse.ArgumentParser) to which the
             "--enable-websocket-logging" argument will be added.
-
     """
     parser.add_argument(
         "--enable-websocket-logging" "", action="store_true", default=True
@@ -89,9 +88,6 @@ def add_list_of_manager_ids_arguments(parser):
 
     Args:
         parser: An ArgumentParser object used to parse command line arguments.
-
-    Returns:
-        None
     """
     parser.add_argument(
         "-m",
diff --git a/cooperative_cuisine/counters.py b/cooperative_cuisine/counters.py
index eb39a753b95e938c077def8ebd36697bcef37eac..1b03174774dabac65690c83f4313ea07e3dc03ad 100644
--- a/cooperative_cuisine/counters.py
+++ b/cooperative_cuisine/counters.py
@@ -106,7 +106,7 @@ class Counter:
         pos: npt.NDArray[float],
         hook: Hooks,
         occupied_by: Item | None = None,
-        uid: hex = None,
+        uid: str = None,
         **kwargs,
     ):
         """Constructor setting the arguments as attributes.
@@ -255,6 +255,24 @@ class Counter:
         )
 
     def do_tool_interaction(self, passed_time: timedelta, tool: Item):
+        """Progress call for player that interact with a counter (optionally via a tool).
+
+        Args:
+            passed_time: The amount of time that has passed between the environment step calls.
+            tool: The tool being used for interaction.
+
+        This method performs tool interaction on the specified tool. It can handle cases where the location is
+        occupied by a single item or a deque of items.
+
+        If the location is occupied by a deque of items, the method will iterate through each item and attempt to
+        perform the tool interaction. If succesful, it will set the 'successful' flag to True.
+
+        If the location is occupied by a single item, the method will directly call the 'do_single_tool_interaction'
+        method to perform the interaction.
+
+        If none of the attempts were successful, the method will call the 'do_single_tool_interaction' method on
+        itself to perform the interaction.
+        """
         successful = False
         if self.occupied_by:
             if isinstance(self.occupied_by, deque):
diff --git a/cooperative_cuisine/effects.py b/cooperative_cuisine/effects.py
index 53989c0916dd9d8f2fe82b44ef2be4f971e1da29..5c7ff26e80b2c9123d7f3d024a1752b217ae40af 100644
--- a/cooperative_cuisine/effects.py
+++ b/cooperative_cuisine/effects.py
@@ -43,16 +43,16 @@ class EffectManager:
             hook: An instance of the Hooks class representing the hooks in the environment.
             random: An instance of the Random class representing the random number generator.
         """
-        self.effects = []
+        self.effects: list[ItemInfo] = []
         """A list of ItemInfo objects representing the effects managed by the manager."""
-        self.counters = []
+        self.counters: list[Counter] = []
         """A list of Counter objects representing the counters in the environment."""
-        self.hook = hook
+        self.hook: Hooks = hook
         """An instance of the Hooks class representing the hooks in the environment."""
         self.new_effects: list[Tuple[Effect, Item | Counter]] = []
         """A list of tuples containing an Effect object and either an Item or Counter object representing the new 
         active effects."""
-        self.random = random
+        self.random: Random = random
         """An instance of the Random class representing the random number generator."""
 
     def add_effect(self, effect: ItemInfo):
diff --git a/cooperative_cuisine/environment.py b/cooperative_cuisine/environment.py
index 90be31686eb64c7cd15a3a034cb5c2e2fc4edf34..8f8cc1b650be6a5275000a0a5571e908c6171560 100644
--- a/cooperative_cuisine/environment.py
+++ b/cooperative_cuisine/environment.py
@@ -17,7 +17,7 @@ from collections import defaultdict
 from datetime import timedelta, datetime
 from pathlib import Path
 from random import Random
-from typing import Literal, TypedDict, Callable, Set
+from typing import Literal, TypedDict, Callable, Set, Any
 
 import numpy as np
 import numpy.typing as npt
@@ -94,7 +94,7 @@ class EnvironmentConfig(TypedDict):
     """Definition of which characters in the layout file correspond to which kitchen counter."""
     hook_callbacks: dict[str, dict]
     """Configuration of callbacks via HookCallbackClass."""
-    effect_manager: dict
+    effect_manager: dict[str, dict]
     """Config of different effects in the environment, which control for example fire behavior."""
 
 
@@ -136,7 +136,7 @@ class Environment:
             env_name: (optional) The name of the environment. Defaults to "overcooked_sim".
             seed: (optional) The seed for generating random numbers. Defaults to 56789223842348.
         """
-        self.env_name = env_name
+        self.env_name: str = env_name
         """Reference to the run. E.g, the env id."""
         self.env_time: datetime = create_init_env_time()
         """the internal time of the environment. An environment starts always with the time from 
@@ -305,7 +305,7 @@ class Environment:
         self.order_manager.create_init_orders(self.env_time)
         self.start_time: datetime = self.env_time
         """The relative env time when it started."""
-        self.env_time_end = self.env_time + timedelta(
+        self.env_time_end: datetime = self.env_time + timedelta(
             seconds=self.environment_config["game"]["time_limit_seconds"]
         )
         """The relative env time when it will stop/end"""
@@ -314,7 +314,7 @@ class Environment:
         self.info_msgs_per_player: dict[str, list[InfoMsg]] = defaultdict(list)
         """Cache of info messages per player which should be showed in the visualization of each player."""
 
-        self.additional_state_content = {}
+        self.additional_state_content: dict[str, Any] = {}
         """The environment will extend the content of each state with this dictionary. Adapt it with the setter 
         function."""
 
@@ -587,5 +587,12 @@ class Environment:
         log.debug(f"Score: {self.score} ({score}) - {info}")
 
     def update_additional_state_content(self, **kwargs):
+        """
+        Update the additional state content with the given key-value pairs.
+
+        Args:
+            **kwargs: The key-value pairs to update the additional state content with.
+
+        """
         self.hook(ADDITIONAL_STATE_UPDATE, update=kwargs)
         self.additional_state_content.update(kwargs)
diff --git a/cooperative_cuisine/game_server.py b/cooperative_cuisine/game_server.py
index e565cbe91a1652af87d51cbc3b7de066e8903700..4d2fa765ee65156cfc28168febbd105a9d39ca65 100644
--- a/cooperative_cuisine/game_server.py
+++ b/cooperative_cuisine/game_server.py
@@ -132,11 +132,11 @@ class EnvironmentHandler:
         """A dictionary of player hashes and their respective data."""
         self.manager_envs: dict[str, Set[str]] = defaultdict(set)
         """A dictionary of manager IDs and the environment IDs managed by each manager."""
-        self.env_step_frequency = env_step_frequency
+        self.env_step_frequency: int = env_step_frequency
         """The frequency at which the environment steps."""
-        self.preferred_sleep_time_ns = 1e9 / self.env_step_frequency
+        self.preferred_sleep_time_ns: float = 1e9 / self.env_step_frequency
         """The preferred sleep time between environment steps in nanoseconds based on the `env_step_frequency`."""
-        self.client_ids_to_player_hashes = {}
+        self.client_ids_to_player_hashes: dict[str, str] = {}
         """A dictionary mapping client IDs to player hashes."""
         self.allowed_manager: list[str] = []
         """List of manager ids that are allowed to manage/create environments."""
@@ -567,9 +567,23 @@ class EnvironmentHandler:
         return False
 
     def extend_allowed_manager(self, manager: list[str]):
+        """
+        Extends the list of allowed managers.
+
+        Args:
+            manager: A list of strings representing the managers to be added to the allowed managers list.
+
+        """
         self.allowed_manager.extend(manager)
 
-    def set_host_and_port(self, host, port):
+    def set_host_and_port(self, host: str, port: int):
+        """Set the host and the port of the game server.
+
+        Args:
+            host: The host value to set for the object.
+            port: The port value to set for the object.
+
+        """
         self.host = host
         self.port = port
 
@@ -632,10 +646,13 @@ class PlayerConnectionManager:
 
 
 connection_manager = PlayerConnectionManager()
+"""Manage the player connection for the game server."""
 frequency = 200
+"""How often the step function is called for all environments in a second. (Hz)."""
 environment_handler: EnvironmentHandler = EnvironmentHandler(
     env_step_frequency=frequency
 )
+"""The environment handler for the game server. Manages the running environments (step calles, action passing, etc.)."""
 
 
 class PlayerRequestType(Enum):
@@ -650,13 +667,20 @@ class PlayerRequestType(Enum):
 
 
 class WebsocketMessage(BaseModel):
+    """Type hint for a websocket response/request from the client."""
+
     type: str
+    """What kind/type of request is it? (get_state, action, ready)"""
     action: None | Action = None
+    """The data for an action (if type=="action")."""
     player_hash: str
+    """The provided player_hash from the game server for validation of the player."""
 
     class Config:
         arbitrary_types_allowed = True
 
+    # maybe replace BaseModel with dataclass for better performance?
+
 
 def manage_websocket_message(message: str, client_id: str) -> PlayerRequestResult | str:
     """Manage WebSocket Message by validating the message and passing it to the environment.
@@ -687,14 +711,6 @@ def manage_websocket_message(message: str, client_id: str) -> PlayerRequestResul
                         "player_hash": None,
                     }
                 return state
-            case PlayerRequestType.READY:
-                accepted = environment_handler.set_player_ready(ws_message.player_hash)
-                return {
-                    "request_type": request_type.value,
-                    "msg": f"ready{' ' if accepted else ' not '}accepted",
-                    "status": 200 if accepted else 400,
-                    "player_hash": ws_message.player_hash,
-                }
             case PlayerRequestType.ACTION:
                 assert (
                     ws_message.action is not None
@@ -712,6 +728,14 @@ def manage_websocket_message(message: str, client_id: str) -> PlayerRequestResul
                     "msg": f"action{' ' if accepted else ' not '}accepted",
                     "player_hash": ws_message.player_hash,
                 }
+            case PlayerRequestType.READY:
+                accepted = environment_handler.set_player_ready(ws_message.player_hash)
+                return {
+                    "request_type": request_type.value,
+                    "msg": f"ready{' ' if accepted else ' not '}accepted",
+                    "status": 200 if accepted else 400,
+                    "player_hash": ws_message.player_hash,
+                }
         return {
             "request_type": request_type.value,
             "status": 400,
@@ -736,36 +760,60 @@ def manage_websocket_message(message: str, client_id: str) -> PlayerRequestResul
 
 @app.get("/")
 def read_root():
+    """Simple response when calling the root of the url."""
     return {"Cooperative": "Cuisine"}
 
 
 class CreateEnvironmentConfig(BaseModel):
+    """Datastructure for `create_env` post requests."""
+
     manager_id: str
+    """Check validity of the request by providing one of the allowed `manager_ids`"""
     number_players: int
+    """Number of players to generate player info for."""
     same_websocket_player: list[list[str]] | None = None
+    """Future: allow players connect via one websocket."""
     environment_settings: EnvironmentSettings
+    """Various other enviroment settings."""
     item_info_config: str  # file content
+    """The file content of the item info for the environment."""
     environment_config: str  # file content
+    """The file content of the environment_config."""
     layout_config: str  # file content
+    """The layout of the environment. Characters represent counter in grid. Rows split by newline character."""
     seed: int
+    """The random seed for the environment. (Order generation, etc.)"""
     env_name: str
+    """The name of the environment / env_id."""
 
 
 class ManageEnv(BaseModel):
+    """Datastructure for the post request to manage environments (stop_env)."""
+
     manager_id: str
+    """For validation if the client is allowed to manage environments."""
     env_id: str
+    """The reference to the environment to manage."""
     reason: str
+    """The reason to manage the environment (why to stop it.)."""
 
 
 class AdditionalPlayer(BaseModel):
+    """Add a player to an environment / create player_info."""
+
     manager_id: str
+    """For validation if the client is allowed to manage environments."""
     env_id: str
+    """The reference to the environment."""
     number_players: int
+    """How many players to add."""
     existing_websocket: str | None = None
+    """Future: allow players connect via one websocket that already exists."""
 
 
 @app.post("/manage/create_env/")
 async def create_env(creation: CreateEnvironmentConfig) -> CreateEnvResult:
+    """Post request for creating an environment. See `CreateEnvironmentConfig` for the datastructure."""
     result = environment_handler.create_env(creation)
     if result == 1:
         raise HTTPException(status_code=403, detail="Manager ID not known/registered.")
@@ -774,12 +822,14 @@ async def create_env(creation: CreateEnvironmentConfig) -> CreateEnvResult:
 
 @app.post("/manage/additional_player/")
 async def additional_player(creation: AdditionalPlayer) -> dict[str, PlayerInfo]:
+    """Post request for adding additional players (not mentioned in create_env). See `AdditionalPlayer`."""
     result = environment_handler.add_player(creation)
     return result
 
 
 @app.post("/manage/stop_env/")
 async def stop_env(manage_env: ManageEnv) -> str:
+    """Post request for stop an environment. See `ManageEnv`."""
     accept = environment_handler.stop_env(
         manage_env.manager_id, manage_env.env_id, manage_env.reason
     )
@@ -829,6 +879,7 @@ async def websocket_player_endpoint(websocket: WebSocket, client_id: str):
 def main(
     host: str, port: int, manager_ids: list[str], enable_websocket_logging: bool = False
 ):
+    """Start a game server."""
     print("Manager IDs:", manager_ids)
     setup_logging(enable_websocket_logging)
     loop = asyncio.new_event_loop()
diff --git a/cooperative_cuisine/hooks.py b/cooperative_cuisine/hooks.py
index ea6d6c59d46637d3ed2795793af63e4a3308c0bd..6b2dc39821a2ed08eabf630b744e7c1eae4c1470 100644
--- a/cooperative_cuisine/hooks.py
+++ b/cooperative_cuisine/hooks.py
@@ -537,8 +537,15 @@ class Hooks:
     """
 
     def __init__(self, env: Environment):
-        self.hooks = defaultdict(list)
-        self.env = env
+        """Constructor for the Hooks object.
+
+        Args:
+            env (Environment): The environment object to be referenced.
+        """
+        self.hooks: dict[str, list[Callable]] = defaultdict(list)
+        """The hook callbacks per hook_ref."""
+        self.env: Environment = env
+        """Reference to the environment object."""
 
     def __call__(self, hook_ref, **kwargs):
         for callback in self.hooks[hook_ref]:
diff --git a/cooperative_cuisine/orders.py b/cooperative_cuisine/orders.py
index 9a98314a352324fb787b32e1a8121d6aeb11d193..1afe120e322259839545b8d3e1a65866f48e8d3a 100644
--- a/cooperative_cuisine/orders.py
+++ b/cooperative_cuisine/orders.py
@@ -121,7 +121,7 @@ class OrderGeneration:
         """Available meals restricted through the `environment_config.yml`."""
         self.hook: Hooks = hook
         """Reference to the hook manager."""
-        self.random = random
+        self.random: Random = random
         """Random instance."""
 
     @abstractmethod
@@ -156,7 +156,7 @@ class OrderManager:
             hook: An instance of the Hooks class.
             random: An instance of the Random class.
         """
-        self.random = random
+        self.random: Random = random
         """Random instance."""
         self.order_gen: OrderGeneration = order_config["order_gen_class"](
             hook=hook,
@@ -169,7 +169,7 @@ class OrderManager:
         ] = order_config["serving_not_ordered_meals"]
         """Function that decides if not ordered meals can be served and what score it gives"""
 
-        self.available_meals = None
+        self.available_meals: dict[str, ItemInfo] | None = None
         """The meals for that orders can be sampled from."""
         self.open_orders: Deque[Order] = deque()
         """Current open orders. This attribute is used for the environment state."""
@@ -186,11 +186,11 @@ class OrderManager:
 
         self.hook: Hooks = hook
         """Reference to the hook manager."""
-        self.score_callbacks = []
+        self.score_callbacks: list[ScoreViaHooks] = []
         """List of score callbacks."""
         self.find_score_hook_callbacks()
 
-    def set_available_meals(self, available_meals):
+    def set_available_meals(self, available_meals: dict[str, ItemInfo]):
         """Set the available meals from which orders can be generated.
 
         Args:
@@ -545,6 +545,13 @@ class RandomOrderGeneration(OrderGeneration):
         return orders
 
     def create_random_next_time_delta(self, now: datetime):
+        """
+        Creates a random time delta for the next order based on order_duration_random_func in kwargs.
+
+        Args:
+            now (datetime): The current datetime.
+
+        """
         if isinstance(self.kwargs.order_duration_random_func["func"], str):
             seconds = getattr(
                 self.random, self.kwargs.sample_on_dur_random_func["func"]
diff --git a/cooperative_cuisine/pygame_2d_vis/__init__.py b/cooperative_cuisine/pygame_2d_vis/__init__.py
index c6af81b3aade3d2245e5e9e7da26abc028f5eeb2..ed6999e471c45593c051232617d9e2202481acd0 100644
--- a/cooperative_cuisine/pygame_2d_vis/__init__.py
+++ b/cooperative_cuisine/pygame_2d_vis/__init__.py
@@ -22,4 +22,5 @@ The keys for the control of the players are:
 - Interact: `O`
 - Swap Players (if configured): `P`
 
+There is also a video game controller support. Just connect it to your PC (USB?) and it should work.
 """
diff --git a/cooperative_cuisine/scores.py b/cooperative_cuisine/scores.py
index eb8529381456cbd4b5d438964d6425d713ef2c35..4e084d4985e693c87b0ba2649e778523cfa1cfd9 100644
--- a/cooperative_cuisine/scores.py
+++ b/cooperative_cuisine/scores.py
@@ -81,7 +81,7 @@ hook_callbacks:
 """
 from __future__ import annotations
 
-from typing import Any, TYPE_CHECKING
+from typing import Any, TYPE_CHECKING, Callable
 
 import numpy as np
 
@@ -176,7 +176,7 @@ class ScoreViaHooks(HookCallbackClass):
         static_score: float = 0,
         score_map: dict[str, float] = None,
         score_on_specific_kwarg: str = None,
-        time_dependence_func: callable = constant_score,
+        time_dependence_func: Callable = constant_score,
         time_dependence_kwargs: dict[str, Any] = None,
         kwarg_filter: dict[str, Any] = None,
         **kwargs,
@@ -201,7 +201,7 @@ class ScoreViaHooks(HookCallbackClass):
         """Filtering condition for keyword arguments."""
         self.score_on_specific_kwarg: str = score_on_specific_kwarg
         """The specific keyword argument to score on."""
-        self.time_dependence_func: callable = time_dependence_func
+        self.time_dependence_func: Callable = time_dependence_func
         """The function to calculate the score based on time."""
         self.time_dependence_kwargs: dict[str, Any] = (
             time_dependence_kwargs if time_dependence_kwargs else {}
diff --git a/cooperative_cuisine/study_server.py b/cooperative_cuisine/study_server.py
index fbce4f2ecfa828b22110a6774336ca7bbdd4be7d..90e0534563e0d325ec91e004201cc05a3f98ef9d 100644
--- a/cooperative_cuisine/study_server.py
+++ b/cooperative_cuisine/study_server.py
@@ -143,14 +143,17 @@ class Study:
 
     @property
     def study_done(self) -> bool:
+        """Is the study done."""
         return self.current_level_idx >= len(self.levels)
 
     @property
     def last_level(self) -> bool:
+        """Is it the last level that is played?"""
         return self.current_level_idx >= len(self.levels) - 1
 
     @property
     def is_full(self) -> bool:
+        """Can the study start? No new players can join."""
         return (
             len(self.participant_id_to_player_info) == self.study_config["num_players"]
         )
@@ -299,6 +302,7 @@ class Study:
 
         Args:
             participant_id: The participant id which requests the connections.
+            participant_host: ip-address of the participant.
 
         Returns:
             The player info for the game server connections, level name and information if the level is the last
@@ -523,6 +527,7 @@ class StudyManager:
         the fastapi requests act on top level of the python script.
 
         Args:
+            use_ssl: A boolean indicating whether to use SSL for the game server URL.
             game_host: The game server host address.
             game_port: The game server port.
         """
@@ -531,6 +536,11 @@ class StudyManager:
         self.create_game_server_url(use_ssl)
 
     def create_game_server_url(self, use_ssl: bool):
+        """Update `game_server_url` attribute.
+        Args:
+            use_ssl: A boolean indicating whether to use SSL for the game server URL.
+
+        """
         self.game_server_url = (
             f"http{'s' if use_ssl else ''}://{self.game_host}:{self.game_port}"
         )
@@ -554,7 +564,14 @@ class StudyManager:
         # TODO validate study_config?
         self.study_config_path = study_config_path
 
-    def start_tutorial(self, participant_id: str):
+    @staticmethod
+    def start_tutorial(participant_id: str):
+        """Start the tutorial by instructing a game server to create a tutorial env.
+
+        Args:
+            participant_id: The ID of the participant who wants to start the tutorial.
+
+        """
         environment_config_path = ROOT_DIR / "configs" / "tutorial_env_config.yaml"
         layout_path = ROOT_DIR / "configs" / "layouts" / "tutorial.layout"
         item_info_path = ROOT_DIR / "configs" / "item_info.yaml"
@@ -596,7 +613,24 @@ class StudyManager:
                     detail=f"Game server crashed: {env_info.json()['detail']}",
                 )
 
-    def end_tutorial(self, participant_id: str):
+    @staticmethod
+    def end_tutorial(participant_id: str):
+        """End a tutorial by doing clean up on the game server.
+
+        This static method is used to end a tutorial for a specified participant.
+        It retrieves the environment information from the `running_tutorials` dictionary using the participant ID.
+        It then sends a request to the game server to stop the environment associated with the tutorial,
+        providing the manager ID, environment ID, and reason for ending the tutorial.
+        If the request is successful (status code 200), the tutorial is removed from the `running_tutorials` dictionary.
+        If the request fails, an HTTPException with status code 503 is raised.
+
+        Args:
+            participant_id (str): The ID of the participant whose tutorial is ending.
+
+        Raises:
+            HTTPException: If there is an error disconnecting from the tutorial.
+
+        """
         env = study_manager.running_tutorials[participant_id]
         answer = request_game_server(
             f"{study_manager.game_server_url}/manage/stop_env/",
@@ -614,6 +648,7 @@ class StudyManager:
 
 
 study_manager = StudyManager()
+"""Study manager instance for the study server."""
 
 
 @app.post("/start_study/{participant_id}/{number_players}")
@@ -649,6 +684,7 @@ async def get_game_connection(
 
     Args:
         participant_id: ID of the requesting participant.
+        request: Info about the post request, e.g, ip address.
 
     Returns:
         A dict containing the game server connection information and information about the current level.
@@ -694,6 +730,7 @@ def main(
     study_config_path,
     use_ssl,
 ):
+    """Start a study server."""
     study_manager.set_game_server_url(
         game_host=game_host, game_port=game_port, use_ssl=use_ssl
     )
@@ -701,7 +738,7 @@ def main(
     study_manager.set_study_config(study_config_path=study_config_path)
 
     print(
-        f"Use {study_manager.server_manager_id=} for game_server_url=http://{game_host}:{game_port}"
+        f"Use {study_manager.server_manager_id=} for game_server_url=http{'s' if use_ssl else ''}://{game_host}:{game_port}"
     )
     loop = asyncio.new_event_loop()
     config = uvicorn.Config(app, host=study_host, port=study_port, loop=loop)
diff --git a/cooperative_cuisine/utils.py b/cooperative_cuisine/utils.py
index 601a1f3dc946b7901665e0d74f16cfc63a6df1df..ae8b3384eb3f6eace76f7b1120f0fd3f6218f04b 100644
--- a/cooperative_cuisine/utils.py
+++ b/cooperative_cuisine/utils.py
@@ -331,6 +331,13 @@ def create_layout_with_counters(w, h) -> str:
 
 
 def deep_update(d, u):
+    """Deep update of a nested dictionary.
+
+    Args:
+        d: A dictionary to be updated. This dictionary will be modified in place.
+        u: A dictionary containing the updates to be applied to d.
+
+    """
     for k, v in u.items():
         if isinstance(v, collections.abc.Mapping):
             d[k] = deep_update(d.get(k, {}), v)