# MLGame3D
A framework for playing Unity games with Python MLPlay classes using ML-Agents for communication with Unity.
## Installation
```bash
pip install mlgame3d
```
## Usage
### Command-line Interface
MLGame3D provides a command-line interface that allows you to launch games directly from the command line:
```bash
python -m mlgame3d [options] <Unity game executable>
```
Options include:
- `--version`, `-v`: Display version information
- `--help`, `-h`: Display help information (built-in argparse option)
- `--no-graphics`, `-ng`: Run the Unity simulator in no-graphics mode
- `--worker-id`, `-w`: Set the worker ID for running multiple environments simultaneously (default: 0)
- `--base-port`, `-p`: Set the base port (default: None, will use Unity default port)
- `--seed`, `-s`: Set the random seed (default: 0)
- `--timeout`, `-t`: Set the timeout for waiting for environment connection (default: 60 seconds)
- `--episodes`, `-e`: Set the number of episodes to run (default: 5)
- `--fps`, `-f`: Target number of frames per second for rendering (default: 60)
- `--time-scale`, `-ts`: Time scale factor for the simulation. Higher values make the simulation run faster. Note: Values less than 1.0 will be clamped to 1.0 by Unity and have no effect (default: 1.0)
- `--decision-period`, `-dp`: Number of FixedUpdate steps between AI decisions. Should be a multiple of 20ms. Range: 1-20 (default: 5)
- `--ai`, `-i`: Control mode for an instance (auto-numbered). Can be specified multiple times. Each occurrence is equivalent to `--ai1`, `--ai2`, etc. in order.
- `--ai1`, `-i1`: Control mode for instance 1. Can be a path to a Python file containing an MLPlay class, 'hidden', or 'manual' (default).
- `--ai2`, `-i2`: Control mode for instance 2. Can be a path to a Python file containing an MLPlay class, 'hidden', or 'manual' (default).
- `--ai3`, `-i3`: Control mode for instance 3. Can be a path to a Python file containing an MLPlay class, 'hidden', or 'manual' (default).
- `--ai4`, `-i4`: Control mode for instance 4. Can be a path to a Python file containing an MLPlay class, 'hidden', or 'manual' (default).
- `--game-param`, `-gp`: Game parameter in the format KEY VALUE. Can be specified multiple times for different parameters.
- `--result-output-file`, `-o`: Path to a CSV file where result data will be saved. Each episode's result will be appended to this file with the episode column always appearing first. If the file path doesn't end with '.csv', it will be automatically added.
Examples:
```bash
# Connect to an already running Unity editor
python -m mlgame3d
# Launch a Unity game and run 10 episodes
python -m mlgame3d --episodes 10 path/to/your/game.exe
# Or using short options
python -m mlgame3d -e 10 path/to/your/game.exe
# Run without graphics
python -m mlgame3d --no-graphics path/to/your/game.exe
# Or using short options
python -m mlgame3d -ng path/to/your/game.exe
# Set random seed and worker ID
python -m mlgame3d -s 42 -w 1 path/to/your/game.exe
# Use 2 AI instances, with a custom MLPlay for the first one and manual control for the second one
python -m mlgame3d -i examples/simple_mlplay.py -i manual path/to/your/game.exe
# Use 3 AI instances: first controlled by MLPlay, second hidden, third controlled by another MLPlay
python -m mlgame3d -i mlplay1.py -i hidden -i mlplay2.py path/to/your/game.exe
# Specify control modes for specific player positions
python -m mlgame3d -i1 mlplay1.py -i2 manual -i3 mlplay2.py -i4 hidden path/to/your/game.exe
# Pass game parameters (checkpoint_count and checkpoint_mode)
python -m mlgame3d -i examples/simple_mlplay.py -gp checkpoint_count 10 -gp checkpoint_mode random path/to/your/game.exe
# Set simulation parameters (fps, time-scale, and decision-period)
python -m mlgame3d -f 60 -ts 2.0 -dp 10 path/to/your/game.exe
# Save result data to a CSV file
python -m mlgame3d -i examples/simple_mlplay.py -o results.csv path/to/your/game.exe
# Or specify a path without .csv extension (it will be added automatically)
python -m mlgame3d -i examples/simple_mlplay.py -o results/game_results path/to/your/game.exe
```
### Code Interface
You can also use this framework in your Python code:
```python
from mlgame3d.game_env import GameEnvironment
from mlgame3d.mlplay import RandomMLPlay
from mlgame3d.game_runner import GameRunner
# Create the environment with controlled players
env = GameEnvironment(
file_name="YourUnityGame.exe", # Or None to connect to a running Unity editor
worker_id=0,
no_graphics=False,
fps=60, # Target frames per second for rendering
time_scale=1.0, # Time scale factor for simulation speed
decision_period=5, # Number of FixedUpdate steps between AI decisions
controlled_players=[0, 1], # Control P1 and P2
control_modes=["mlplay", "mlplay"], # Both controlled by MLPlay
game_parameters=[("checkpoint_count", 10), ("checkpoint_mode", "random")], # Game parameters
result_output_file="results.csv" # Save result data to this CSV file
)
# Get information about the action space for each behavior
action_space_info_p1 = env.get_action_space_info(env.behavior_names[0])
action_space_info_p2 = env.get_action_space_info(env.behavior_names[1])
# Create MLPlay instances
mlplay1 = RandomMLPlay(action_space_info_p1, name="MLPlay1")
mlplay2 = RandomMLPlay(action_space_info_p2, name="MLPlay2")
# Create a mapping from MLPlay index to behavior name
mlplay_to_behavior_map = {
0: env.behavior_names[0], # First MLPlay controls first behavior
1: env.behavior_names[1] # Second MLPlay controls second behavior
}
# Create a game runner
runner = GameRunner(
env=env,
mlplays=[mlplay1, mlplay2],
max_episodes=5,
render=True,
mlplay_timeout=0.1, # Timeout for MLPlay actions in seconds
game_parameters={"checkpoint_count": 10, "checkpoint_mode": "random"},
mlplay_to_behavior_map=mlplay_to_behavior_map
)
# Run the game
runner.run()
# Close the environment
env.close()
```
### Creating Custom MLPlay Classes
You can create a standalone `MLPlay` class without inheriting from any base class. This approach is simple and flexible.
Requirements for `MLPlay` class:
1. The class must be named `MLPlay`
2. The class must implement `__init__`, `update`, and `reset` methods
Here's an example of a minimal `MLPlay` class:
```python
import numpy as np
from typing import Dict, Any
class MLPlay:
def __init__(self, action_space_info=None):
# Initialize your MLPlay instance
pass
def reset(self):
# Reset your MLPlay instance for a new episode
pass
def update(self, observations, reward=0.0, done=False, info=None):
# Process observations and choose an action
# This is a simple example that returns a random 2D movement vector
action = np.random.uniform(-1, 1, 2)
# Normalize the action vector
if np.linalg.norm(action) > 0:
action = action / np.linalg.norm(action)
return action
```
### Loading External MLPlay Files
You can create custom MLPlay classes in separate Python files and load them at runtime using the command-line interface. The framework will automatically find and instantiate the `MLPlay` class in the file.
Requirements for external MLPlay files:
1. The file must contain a class named `MLPlay`
2. The class must implement `__init__`, `update`, and `reset` methods
Example of an external MLPlay file (`simple_mlplay.py`):
```python
import numpy as np
from typing import Dict, Any
class MLPlay:
def __init__(self, action_space_info=None):
self.step_counter = 0
def reset(self):
self.step_counter = 0
def update(self, observations, reward=0.0, done=False, info=None):
self.step_counter += 1
# Alternate between different actions
if self.step_counter % 2 == 0:
return np.array([1.0, 0.0]) # Move right
else:
return np.array([0.0, 1.0]) # Move forward
```
You can then use these MLPlay classes with the command-line interface:
```bash
python -m mlgame3d -i simple_mlplay.py path/to/your/game.exe
```
Or specify a specific player position:
```bash
python -m mlgame3d -i1 simple_mlplay.py path/to/your/game.exe
```
Or load them programmatically:
```python
from mlgame3d.mlplay_loader import create_mlplay_from_file
# Create an MLPlay instance from an external file
mlplay = create_mlplay_from_file("simple_mlplay.py", action_space_info)
```
## Framework Structure
- `game_env.py`: Provides the `GameEnvironment` class for communicating with Unity games
- `mlplay.py`: Provides the `RandomMLPlay` class for generating random actions
- `game_runner.py`: Provides the `GameRunner` class for running games and collecting statistics
- `mlplay_loader.py`: Provides functionality for loading MLPlay classes from external Python files
- `__main__.py`: Provides the command-line interface
- `examples/`: Contains example MLPlay implementations
## Notes
- Make sure your Unity game has integrated the ML-Agents package
- If you want to connect to a Unity editor, make sure the editor is running and the game scene is loaded
- If you want to connect to a Unity executable, make sure to provide the correct file path
- When using multiple MLPlay instances, make sure your Unity environment supports the requested number of agents
- Control modes:
- `manual`: Player is controlled manually via keyboard/gamepad
- `hidden`: Player is hidden (not visible in the game)
- Python file path: Player is controlled by an MLPlay instance loaded from the specified file
- Result data:
- When using the `--result-output-file` option, result data will be saved to the specified CSV file
- Each episode's result data will be appended to the file with the episode column always appearing first
- If the file path doesn't end with '.csv', it will be automatically added
## Contributing
Pull requests and issues are welcome to improve this framework.
## License
MIT
Raw data
{
"_id": null,
"home_page": "https://github.com/PAIA-Playful-AI-Arena/MLGame3D",
"name": "mlgame3d",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": null,
"author": "PAIA",
"author_email": "PAIA <service@paia-tech.com>",
"download_url": "https://files.pythonhosted.org/packages/03/57/c6b8407240fd070b280585e488034c1ed5f4ac556f17390937ab6ab94f4d/mlgame3d-0.4.1.tar.gz",
"platform": null,
"description": "# MLGame3D\n\nA framework for playing Unity games with Python MLPlay classes using ML-Agents for communication with Unity.\n\n## Installation\n\n```bash\npip install mlgame3d\n```\n\n## Usage\n\n### Command-line Interface\n\nMLGame3D provides a command-line interface that allows you to launch games directly from the command line:\n\n```bash\npython -m mlgame3d [options] <Unity game executable>\n```\n\nOptions include:\n\n- `--version`, `-v`: Display version information\n- `--help`, `-h`: Display help information (built-in argparse option)\n- `--no-graphics`, `-ng`: Run the Unity simulator in no-graphics mode\n- `--worker-id`, `-w`: Set the worker ID for running multiple environments simultaneously (default: 0)\n- `--base-port`, `-p`: Set the base port (default: None, will use Unity default port)\n- `--seed`, `-s`: Set the random seed (default: 0)\n- `--timeout`, `-t`: Set the timeout for waiting for environment connection (default: 60 seconds)\n- `--episodes`, `-e`: Set the number of episodes to run (default: 5)\n- `--fps`, `-f`: Target number of frames per second for rendering (default: 60)\n- `--time-scale`, `-ts`: Time scale factor for the simulation. Higher values make the simulation run faster. Note: Values less than 1.0 will be clamped to 1.0 by Unity and have no effect (default: 1.0)\n- `--decision-period`, `-dp`: Number of FixedUpdate steps between AI decisions. Should be a multiple of 20ms. Range: 1-20 (default: 5)\n- `--ai`, `-i`: Control mode for an instance (auto-numbered). Can be specified multiple times. Each occurrence is equivalent to `--ai1`, `--ai2`, etc. in order.\n- `--ai1`, `-i1`: Control mode for instance 1. Can be a path to a Python file containing an MLPlay class, 'hidden', or 'manual' (default).\n- `--ai2`, `-i2`: Control mode for instance 2. Can be a path to a Python file containing an MLPlay class, 'hidden', or 'manual' (default).\n- `--ai3`, `-i3`: Control mode for instance 3. Can be a path to a Python file containing an MLPlay class, 'hidden', or 'manual' (default).\n- `--ai4`, `-i4`: Control mode for instance 4. Can be a path to a Python file containing an MLPlay class, 'hidden', or 'manual' (default).\n- `--game-param`, `-gp`: Game parameter in the format KEY VALUE. Can be specified multiple times for different parameters.\n- `--result-output-file`, `-o`: Path to a CSV file where result data will be saved. Each episode's result will be appended to this file with the episode column always appearing first. If the file path doesn't end with '.csv', it will be automatically added.\n\nExamples:\n\n```bash\n# Connect to an already running Unity editor\npython -m mlgame3d\n\n# Launch a Unity game and run 10 episodes\npython -m mlgame3d --episodes 10 path/to/your/game.exe\n# Or using short options\npython -m mlgame3d -e 10 path/to/your/game.exe\n\n# Run without graphics\npython -m mlgame3d --no-graphics path/to/your/game.exe\n# Or using short options\npython -m mlgame3d -ng path/to/your/game.exe\n\n# Set random seed and worker ID\npython -m mlgame3d -s 42 -w 1 path/to/your/game.exe\n\n# Use 2 AI instances, with a custom MLPlay for the first one and manual control for the second one\npython -m mlgame3d -i examples/simple_mlplay.py -i manual path/to/your/game.exe\n\n# Use 3 AI instances: first controlled by MLPlay, second hidden, third controlled by another MLPlay\npython -m mlgame3d -i mlplay1.py -i hidden -i mlplay2.py path/to/your/game.exe\n\n# Specify control modes for specific player positions\npython -m mlgame3d -i1 mlplay1.py -i2 manual -i3 mlplay2.py -i4 hidden path/to/your/game.exe\n\n# Pass game parameters (checkpoint_count and checkpoint_mode)\npython -m mlgame3d -i examples/simple_mlplay.py -gp checkpoint_count 10 -gp checkpoint_mode random path/to/your/game.exe\n\n# Set simulation parameters (fps, time-scale, and decision-period)\npython -m mlgame3d -f 60 -ts 2.0 -dp 10 path/to/your/game.exe\n\n# Save result data to a CSV file\npython -m mlgame3d -i examples/simple_mlplay.py -o results.csv path/to/your/game.exe\n# Or specify a path without .csv extension (it will be added automatically)\npython -m mlgame3d -i examples/simple_mlplay.py -o results/game_results path/to/your/game.exe\n```\n\n### Code Interface\n\nYou can also use this framework in your Python code:\n\n```python\nfrom mlgame3d.game_env import GameEnvironment\nfrom mlgame3d.mlplay import RandomMLPlay\nfrom mlgame3d.game_runner import GameRunner\n\n# Create the environment with controlled players\nenv = GameEnvironment(\n file_name=\"YourUnityGame.exe\", # Or None to connect to a running Unity editor\n worker_id=0,\n no_graphics=False,\n fps=60, # Target frames per second for rendering\n time_scale=1.0, # Time scale factor for simulation speed\n decision_period=5, # Number of FixedUpdate steps between AI decisions\n controlled_players=[0, 1], # Control P1 and P2\n control_modes=[\"mlplay\", \"mlplay\"], # Both controlled by MLPlay\n game_parameters=[(\"checkpoint_count\", 10), (\"checkpoint_mode\", \"random\")], # Game parameters\n result_output_file=\"results.csv\" # Save result data to this CSV file\n)\n\n# Get information about the action space for each behavior\naction_space_info_p1 = env.get_action_space_info(env.behavior_names[0])\naction_space_info_p2 = env.get_action_space_info(env.behavior_names[1])\n\n# Create MLPlay instances\nmlplay1 = RandomMLPlay(action_space_info_p1, name=\"MLPlay1\")\nmlplay2 = RandomMLPlay(action_space_info_p2, name=\"MLPlay2\")\n\n# Create a mapping from MLPlay index to behavior name\nmlplay_to_behavior_map = {\n 0: env.behavior_names[0], # First MLPlay controls first behavior\n 1: env.behavior_names[1] # Second MLPlay controls second behavior\n}\n\n# Create a game runner\nrunner = GameRunner(\n env=env,\n mlplays=[mlplay1, mlplay2],\n max_episodes=5,\n render=True,\n mlplay_timeout=0.1, # Timeout for MLPlay actions in seconds\n game_parameters={\"checkpoint_count\": 10, \"checkpoint_mode\": \"random\"},\n mlplay_to_behavior_map=mlplay_to_behavior_map\n)\n\n# Run the game\nrunner.run()\n\n# Close the environment\nenv.close()\n```\n\n### Creating Custom MLPlay Classes\n\nYou can create a standalone `MLPlay` class without inheriting from any base class. This approach is simple and flexible.\n\nRequirements for `MLPlay` class:\n1. The class must be named `MLPlay`\n2. The class must implement `__init__`, `update`, and `reset` methods\n\nHere's an example of a minimal `MLPlay` class:\n\n```python\nimport numpy as np\nfrom typing import Dict, Any\n\nclass MLPlay:\n def __init__(self, action_space_info=None):\n # Initialize your MLPlay instance\n pass\n \n def reset(self):\n # Reset your MLPlay instance for a new episode\n pass\n \n def update(self, observations, reward=0.0, done=False, info=None):\n # Process observations and choose an action\n # This is a simple example that returns a random 2D movement vector\n action = np.random.uniform(-1, 1, 2)\n \n # Normalize the action vector\n if np.linalg.norm(action) > 0:\n action = action / np.linalg.norm(action)\n \n return action\n```\n\n### Loading External MLPlay Files\n\nYou can create custom MLPlay classes in separate Python files and load them at runtime using the command-line interface. The framework will automatically find and instantiate the `MLPlay` class in the file.\n\nRequirements for external MLPlay files:\n1. The file must contain a class named `MLPlay`\n2. The class must implement `__init__`, `update`, and `reset` methods\n\nExample of an external MLPlay file (`simple_mlplay.py`):\n\n```python\nimport numpy as np\nfrom typing import Dict, Any\n\nclass MLPlay:\n def __init__(self, action_space_info=None):\n self.step_counter = 0\n \n def reset(self):\n self.step_counter = 0\n \n def update(self, observations, reward=0.0, done=False, info=None):\n self.step_counter += 1\n \n # Alternate between different actions\n if self.step_counter % 2 == 0:\n return np.array([1.0, 0.0]) # Move right\n else:\n return np.array([0.0, 1.0]) # Move forward\n```\n\nYou can then use these MLPlay classes with the command-line interface:\n\n```bash\npython -m mlgame3d -i simple_mlplay.py path/to/your/game.exe\n```\n\nOr specify a specific player position:\n\n```bash\npython -m mlgame3d -i1 simple_mlplay.py path/to/your/game.exe\n```\n\nOr load them programmatically:\n\n```python\nfrom mlgame3d.mlplay_loader import create_mlplay_from_file\n\n# Create an MLPlay instance from an external file\nmlplay = create_mlplay_from_file(\"simple_mlplay.py\", action_space_info)\n```\n\n## Framework Structure\n\n- `game_env.py`: Provides the `GameEnvironment` class for communicating with Unity games\n- `mlplay.py`: Provides the `RandomMLPlay` class for generating random actions\n- `game_runner.py`: Provides the `GameRunner` class for running games and collecting statistics\n- `mlplay_loader.py`: Provides functionality for loading MLPlay classes from external Python files\n- `__main__.py`: Provides the command-line interface\n- `examples/`: Contains example MLPlay implementations\n\n## Notes\n\n- Make sure your Unity game has integrated the ML-Agents package\n- If you want to connect to a Unity editor, make sure the editor is running and the game scene is loaded\n- If you want to connect to a Unity executable, make sure to provide the correct file path\n- When using multiple MLPlay instances, make sure your Unity environment supports the requested number of agents\n- Control modes:\n - `manual`: Player is controlled manually via keyboard/gamepad\n - `hidden`: Player is hidden (not visible in the game)\n - Python file path: Player is controlled by an MLPlay instance loaded from the specified file\n- Result data:\n - When using the `--result-output-file` option, result data will be saved to the specified CSV file\n - Each episode's result data will be appended to the file with the episode column always appearing first\n - If the file path doesn't end with '.csv', it will be automatically added\n\n## Contributing\n\nPull requests and issues are welcome to improve this framework.\n\n## License\n\nMIT\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A framework for playing Unity games with Python agents using ML-Agents Environment.",
"version": "0.4.1",
"project_urls": {
"Homepage": "https://github.com/PAIA-Playful-AI-Arena/MLGame3D",
"Repository": "https://github.com/PAIA-Playful-AI-Arena/MLGame3D"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "c0ad3f4b66459a88d0ede1b3dae88bda149509beaf4b2f92e1586c97d5377e3f",
"md5": "176ad8ca487aefbb3b86643bfbaf94fe",
"sha256": "ab25b8adde0f6b5f1ede0da39c5a9821504923da15a787bf6ae34cf1c36cd73b"
},
"downloads": -1,
"filename": "mlgame3d-0.4.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "176ad8ca487aefbb3b86643bfbaf94fe",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 26822,
"upload_time": "2025-07-11T07:42:15",
"upload_time_iso_8601": "2025-07-11T07:42:15.463422Z",
"url": "https://files.pythonhosted.org/packages/c0/ad/3f4b66459a88d0ede1b3dae88bda149509beaf4b2f92e1586c97d5377e3f/mlgame3d-0.4.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "0357c6b8407240fd070b280585e488034c1ed5f4ac556f17390937ab6ab94f4d",
"md5": "b63077b2e6e0ccd57401a976bd9ddeb3",
"sha256": "3aef217280af906105a2ebdc65cb480ddeb7f42f4a5a43e4cda727bec7adc485"
},
"downloads": -1,
"filename": "mlgame3d-0.4.1.tar.gz",
"has_sig": false,
"md5_digest": "b63077b2e6e0ccd57401a976bd9ddeb3",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 23601,
"upload_time": "2025-07-11T07:42:16",
"upload_time_iso_8601": "2025-07-11T07:42:16.840389Z",
"url": "https://files.pythonhosted.org/packages/03/57/c6b8407240fd070b280585e488034c1ed5f4ac556f17390937ab6ab94f4d/mlgame3d-0.4.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-11 07:42:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "PAIA-Playful-AI-Arena",
"github_project": "MLGame3D",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "mlgame3d-envs",
"specs": []
},
{
"name": "pandas",
"specs": []
}
],
"lcname": "mlgame3d"
}