Skip to content

Commit fd1ecc2

Browse files
Merge pull request #25 from swesner411/main
Palworld REST API Support
2 parents 2b15b65 + 84d1e9e commit fd1ecc2

File tree

8 files changed

+140
-0
lines changed

8 files changed

+140
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ from opengsq.protocols import (
2727
Kaillera,
2828
KillingFloor,
2929
Minecraft,
30+
Palworld,
3031
Quake1,
3132
Quake2,
3233
Quake3,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.. _test_palworld:
2+
3+
test_palworld
4+
=================
5+
6+
.. toctree::
7+
test_get_status
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
test_get_status
2+
===============
3+
4+
Here are the results for the test method.
5+
6+
.. code-block:: json
7+
8+
{
9+
"num_players": 3,
10+
"max_players": 32,
11+
"server_name": "A Palworld Server"
12+
}

opengsq/protocols/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from opengsq.protocols.kaillera import Kaillera
1111
from opengsq.protocols.killingfloor import KillingFloor
1212
from opengsq.protocols.minecraft import Minecraft
13+
from opengsq.protocols.palworld import Palworld
1314
from opengsq.protocols.quake1 import Quake1
1415
from opengsq.protocols.quake2 import Quake2
1516
from opengsq.protocols.quake3 import Quake3

opengsq/protocols/palworld.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import struct
2+
import time
3+
import aiohttp
4+
5+
from opengsq.responses.palworld import Status
6+
from opengsq.protocol_base import ProtocolBase
7+
8+
9+
class Palworld(ProtocolBase):
10+
"""
11+
This class represents the Palworld Protocol. It provides methods to interact with the Palworld REST API.
12+
"""
13+
14+
full_name = "Palworld Protocol"
15+
16+
def __init__(self, host: str, port: int, api_username: str, api_password: str, timeout: float = 5):
17+
"""
18+
Initializes the Palworld object with the given parameters.
19+
20+
:param host: The host of the server.
21+
:param port: The port of the server.
22+
:param api_username: The API username.
23+
:param api_password: The API password.
24+
:param timeout: The timeout for the server connection.
25+
"""
26+
27+
super().__init__(host, port, timeout)
28+
29+
if api_username is None:
30+
raise ValueError("api_username must not be None")
31+
if api_password is None:
32+
raise ValueError("api_password must not be None")
33+
34+
self.api_url = f"http://{self._host}:{self._port}/v1/api"
35+
self.api_username = api_username
36+
self.api_password = api_password
37+
38+
async def api_request(self,url):
39+
"""
40+
Asynchronously retrieves data from the game server through the REST API.
41+
"""
42+
auth = aiohttp.BasicAuth(self.api_username,self.api_password)
43+
async with aiohttp.ClientSession(auth=auth) as session:
44+
async with session.get(url) as response:
45+
data = await response.json()
46+
return data
47+
48+
async def get_status(self) -> Status:
49+
"""
50+
Retrieves the status of the game server. The status includes the server state, name, player count and max player count.
51+
"""
52+
info_data = await self.api_request(f"{self.api_url}/info")
53+
metrics_data = await self.api_request(f"{self.api_url}/metrics")
54+
55+
server_name = info_data["servername"]
56+
server_cur_players = metrics_data["currentplayernum"]
57+
server_max_players = metrics_data["maxplayernum"]
58+
59+
return Status(
60+
server_name=server_name,
61+
num_players=server_cur_players,
62+
max_players=server_max_players,
63+
)
64+
65+
66+
if __name__ == "__main__":
67+
import asyncio
68+
69+
async def main_async():
70+
palworld = Palworld(
71+
host="79.136.0.124",
72+
port=8212,
73+
timeout=5.0,
74+
api_username="admin",
75+
api_password="",
76+
)
77+
status = await palworld.get_status()
78+
print(status)
79+
80+
asyncio.run(main_async())
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .status import Status

opengsq/responses/palworld/status.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from dataclasses import dataclass
2+
3+
4+
@dataclass
5+
class Status:
6+
"""
7+
Represents the status response from a server.
8+
"""
9+
10+
num_players: int
11+
"""The number of players currently connected to the server."""
12+
13+
max_players: int
14+
"""The maximum number of players that can connect to the server."""
15+
16+
server_name: str
17+
"""The name of the server."""

tests/protocols/test_palworld.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import pytest
2+
from opengsq.protocols.palworld import Palworld
3+
4+
from ..result_handler import ResultHandler
5+
6+
handler = ResultHandler(__file__)
7+
# handler.enable_save = True
8+
9+
# Palworld
10+
test = Palworld(
11+
host="72.65.106.166",
12+
port=8212,
13+
api_username="admin",
14+
api_password="admin",
15+
)
16+
17+
18+
@pytest.mark.asyncio
19+
async def test_get_status():
20+
result = await test.get_status()
21+
await handler.save_result("test_get_status", result)

0 commit comments

Comments
 (0)