Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4
Expand Down
194 changes: 135 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

This Python package provides a client for interacting with the Satisfactory Dedicated Server API. The client allows for managing various aspects of the server, including querying server state, logging in, adjusting game settings, handling save files, and issuing administrative commands.

Both a **synchronous** (`SatisfactoryAPI`) and an **asynchronous** (`AsyncSatisfactoryAPI`) client are provided.

## Features

- Perform health checks on the server
Expand All @@ -11,6 +13,8 @@ This Python package provides a client for interacting with the Satisfactory Dedi
- Create, load, save, and delete game sessions
- Set client and admin passwords
- Run server commands and shut down the server
- SSL certificate pinning for self-signed server certificates
- Full async support via `AsyncSatisfactoryAPI`

## Installation

Expand All @@ -24,29 +28,43 @@ pip install satisfactory-api-client

- Python 3.10+
- `requests` library
- `aiohttp` library (for async client)

## Usage

### Initializing the Client

The `SatisfactoryAPI` class is the main entry point for interacting with the server API.

```python
from satisfactory_api_client import SatisfactoryAPI

# Initialize the API client
# Basic initialization
api = SatisfactoryAPI(host='your-server-ip')

# You can also specify a custom port
# Custom port
api = SatisfactoryAPI(host='your-server-ip', port=15000)

# You can also give a token directly without login
# With an existing auth token
api = SatisfactoryAPI(host='your-server-ip', auth_token='your-token')

# Skip SSL verification (not recommended for production)
api = SatisfactoryAPI(host='your-server-ip', skip_ssl_verification=True)
```

### Login
### SSL Certificate Pinning

You can log in to the server using passwordless or password-based methods.
Satisfactory dedicated servers use self-signed certificates. You can pin the server's certificate so that requests are verified against it instead of skipping SSL entirely:

```python
api = SatisfactoryAPI(host='your-server-ip')

# Fetches and saves the certificate to certs/<host>_<port>.pem
# All subsequent requests will be verified against it
api.init_certificate()
```

The certificate is saved locally and reused on future runs. If `skip_ssl_verification=True` is set, calling `init_certificate()` raises a `RuntimeError`.

### Login

```python
from satisfactory_api_client.data import MinimumPrivilegeLevel
Expand All @@ -57,58 +75,51 @@ response = api.passwordless_login(MinimumPrivilegeLevel.ADMINISTRATOR)
# Password login
response = api.password_login(MinimumPrivilegeLevel.ADMINISTRATOR, password='your-admin-password')

# You can check if the token is valid by
# Verify the stored token
response = api.verify_authentication_token()
print(response.data)
```

#### Minimum Privilege Levels

The `MinimumPrivilegeLevel` enum is used to specify the type of token you want to obtain. The following levels are available:
- NOT_AUTHENTICATED
- CLIENT
- ADMINISTRATOR
- INITIAL_ADMIN
- API_TOKEN
The `MinimumPrivilegeLevel` enum specifies the type of token to obtain:

| Level | Description |
|---|---|
| `NOT_AUTHENTICATED` | No authentication required |
| `CLIENT` | Standard client access |
| `ADMINISTRATOR` | Full administrative access |
| `INITIAL_ADMIN` | Initial setup admin access |
| `API_TOKEN` | API token access |

### Health Check

To verify that the server is running and responsive, you can perform a health check. This will return the server's current state. You dont need a token to perform a health check.

```python
response = api.health_check()
print(response.data)
```

### Querying server state

You can query the server's current state. This return information about the server and the current game session.
### Querying Server State

```python
# Get server state
response = api.query_server_state()
print(response.data)
```

### Server Options

You can query the server's current options and apply new ones:

```python
# Get server options
response = api.get_server_options()
print(response.data)

# Apply new server options
new_options = {"server_name": "New Server Name"}
response = api.apply_server_options(new_options)
from satisfactory_api_client.data import ServerOptions
response = api.apply_server_options(ServerOptions(...))
```

### Advanced Game Settings

Fetch and apply advanced game settings:

```python
from satisfactory_api_client.data import AdvancedGameSettings

Expand All @@ -117,20 +128,16 @@ response = api.get_advanced_game_settings()
print(response.data)

# Apply advanced game settings
new_settings = AdvancedGameSettings(your_custom_settings)
response = api.apply_advanced_game_settings(new_settings)
response = api.apply_advanced_game_settings(AdvancedGameSettings(...))
```

### Managing Game Sessions

You can create, load, save, and delete game sessions. The `NewGameData` class is used to specify the parameters for creating a new game.

```python
from satisfactory_api_client.data import NewGameData

# Create a new game
new_game_data = NewGameData(save_name="MyNewGame", ...)
response = api.create_new_game(new_game_data)
response = api.create_new_game(NewGameData(save_name="MyNewGame", ...))

# Load a saved game
response = api.load_game("MySaveGame")
Expand All @@ -140,64 +147,133 @@ response = api.save_game("MySaveGame")

# Delete a save file
response = api.delete_save_file("MySaveGame")
```

### Running Commands and Managing the Server
# List all sessions (requires admin)
response = api.enumerate_sessions()
```

You can run commands on the server or shut it down using the API. The `run_command` method is used to execute a server command. The `shutdown` method is used to shut down the server.
### Running Commands and Shutdown

```python
# Run a server command
response = api.run_command("SomeCommand")

# Shutdown the server
response = api.shutdown()
```

## Methods
---

## Async Client

`AsyncSatisfactoryAPI` mirrors the full API of `SatisfactoryAPI` but uses `async`/`await` via `aiohttp`. All methods, including `init_certificate`, are async.

### Initializing the Async Client

```python
from satisfactory_api_client import AsyncSatisfactoryAPI

api = AsyncSatisfactoryAPI(host='your-server-ip')

# Skip SSL verification
api = AsyncSatisfactoryAPI(host='your-server-ip', skip_ssl_verification=True)
```

### SSL Certificate Pinning (async)

```python
api = AsyncSatisfactoryAPI(host='your-server-ip')
await api.init_certificate()
```

### Example

```python
import asyncio
from satisfactory_api_client import AsyncSatisfactoryAPI
from satisfactory_api_client.data import MinimumPrivilegeLevel

async def main():
api = AsyncSatisfactoryAPI(host='your-server-ip')
await api.init_certificate()

await api.password_login(MinimumPrivilegeLevel.ADMINISTRATOR, password='your-password')

state = await api.query_server_state()
print(state.data)

asyncio.run(main())
```

All methods on `AsyncSatisfactoryAPI` are `async def` and must be awaited.

---

## Methods Reference

### Authentication

- `passwordless_login(minimum_privilege_level: MinimumPrivilegeLevel)`: Log in without a password to obtain a token that is automatically saved.
- `password_login(minimum_privilege_level: MinimumPrivilegeLevel, password: str)`: Log in using a password to obtain a token that is automatically saved.
- `verify_authentication_token()`: Verify that the current token is valid.
| Method | Description |
|---|---|
| `passwordless_login(minimum_privilege_level)` | Log in without a password |
| `password_login(minimum_privilege_level, password)` | Log in with a password |
| `verify_authentication_token()` | Verify the stored token is valid |

### Server Management
### SSL

- `health_check(client_custom_data: str = '')`: Perform a health check on the server. This will return the server's current state.
- `query_server_state()`: Query the server's current state. This includes information about the server and the current game session.
- `shutdown()`: Shut down the server. This will stop the server process.
| Method | Description |
|---|---|
| `init_certificate()` | Fetch and pin the server's SSL certificate |

### Game Management
### Server Management

- `create_new_game(game_data: NewGameData)`: Create a new game session. This will start a new game with the specified settings.
- `load_game(save_name: str, enable_advanced_game_settings: bool = False)`: Load a saved game. This will load a previously saved game session.
- `save_game(save_name: str)`: Save the current game session. This will save the current game state to a file.
- `delete_save_file(save_name: str)`: Delete a saved game. This will delete a previously saved game session.
- `enumerate_sessions()`: List all available game sessions. This will return a list of saved game sessions.
| Method | Description |
|---|---|
| `health_check(client_custom_data='')` | Check server health (no token required) |
| `query_server_state()` | Get the current server and session state |
| `claim_server(server_name, admin_password)` | Claim an unclaimed server |
| `rename_server(server_name)` | Rename the server |
| `run_command(command)` | Execute a console command |
| `shutdown()` | Shut down the server |

### Server Settings

- `get_server_options()`: Get current server settings. This includes the server name, description, and other options.
- `apply_server_options(options: ServerOptions)`: Apply new server settings. This will update the server options with the specified values.
- `get_advanced_game_settings()`: Get advanced game settings. This includes settings such as resource settings, enemy settings, and other advanced options.
- `apply_advanced_game_settings(settings: AdvancedGameSettings)`: Apply new advanced game settings. This will update the advanced game settings with the specified values.
| Method | Description |
|---|---|
| `get_server_options()` | Get current server options |
| `apply_server_options(options)` | Apply new server options |
| `get_advanced_game_settings()` | Get advanced game settings |
| `apply_advanced_game_settings(settings)` | Apply advanced game settings |
| `set_client_password(password)` | Set the client password |
| `set_admin_password(password, auth_token)` | Set the admin password |
| `set_auto_load_session_name(session_name)` | Set the session to auto-load on start |

### Game Management

### Commands
| Method | Description |
|---|---|
| `create_new_game(game_data)` | Start a new game session |
| `load_game(save_name, enable_advanced_game_settings)` | Load a saved game |
| `save_game(save_name)` | Save the current game |
| `delete_save_file(save_name)` | Delete a save file |
| `delete_save_session(session_name)` | Delete all saves for a session |
| `enumerate_sessions()` | List all saved sessions (admin required) |
| `download_save_game(save_name)` | Download a save file as bytes |

- `run_command(command: str)`: Run a server command. This will execute the specified command on the server.
---

## Error Handling

Errors returned by the API will raise an `APIError` exception, which contains the error message from the server. You can catch and handle these errors in your code. For example:
All API errors raise `APIError`:

```python
from satisfactory_api_client import APIError

try:
response = api.some_method()
except APIError as e:
print(f"Error: {e}")
```

---

## Contributing

Contributions are welcome! If you find a bug or have a feature request, please create an issue on the GitHub repository.
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
python-dotenv~=1.0.1
requests~=2.32.3
requests~=2.32.3
aiohttp~=3.9
1 change: 1 addition & 0 deletions satisfactory_api_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import urllib3
from .api_client import SatisfactoryAPI
from .async_api_client import AsyncSatisfactoryAPI
from .exceptions import APIError, InvalidParameterError


Expand Down
Loading
Loading