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: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ from opengsq.protocols import (
Scum,
Source,
TeamSpeak3,
UDK,
Unreal2,
UT3,
Vcmp,
WON,
)
Expand Down
39 changes: 20 additions & 19 deletions docs/tests/protocols/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,30 @@ Protocols Tests
===============

.. toctree::
test_ase/index
test_battlefield/index
test_doom3/index
test_eos/index
test_fivem/index
test_gamespy1/index
test_gamespy2/index
test_gamespy3/index
test_gamespy4/index
test_kaillera/index
test_killingfloor/index
test_teamspeak3/index
test_won/index
test_gamespy1/index
test_minecraft/index
test_nadeo/index
test_palworld/index
test_quake1/index
test_quake2/index
test_quake3/index
test_raknet/index
test_eos/index
test_kaillera/index
test_ase/index
test_quake1/index
test_killingfloor/index
test_source/index
test_samp/index
test_satisfactory/index
test_scum/index
test_source/index
test_teamspeak3/index
test_ut3/index
test_unreal2/index
test_quake3/index
test_nadeo/index
test_battlefield/index
test_fivem/index
test_palworld/index
test_quake2/index
test_gamespy2/index
test_doom3/index
test_vcmp/index
test_won/index
test_satisfactory/index
test_gamespy3/index
7 changes: 7 additions & 0 deletions docs/tests/protocols/test_ut3/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.. _test_ut3:

test_ut3
========

.. toctree::
test_ut3_status
167 changes: 167 additions & 0 deletions docs/tests/protocols/test_ut3/test_ut3_status.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
test_ut3_status
===============

Here are the results for the test method.

.. code-block:: json

{
"name": "Test UT3 InstaGib Server",
"map": "DM-Deck",
"game_type": "UTGame.UTDeathmatch",
"num_players": 0,
"max_players": 32,
"password_protected": false,
"stats_enabled": false,
"lan_mode": true,
"players": [],
"raw": {
"hostaddress": "0.0.0.0",
"hostport": 7777,
"num_players": 0,
"max_players": 32,
"lan_mode": true,
"uses_stats": false,
"owner_id": "0000000000000000",
"owner_name": "Test UT3 InstaGib Server",
"localized_settings": [
{
"id": 32779,
"value_index": 0,
"advertisement_type": 1
},
{
"id": 0,
"value_index": 2,
"advertisement_type": 1
},
{
"id": 1,
"value_index": 0,
"advertisement_type": 1
},
{
"id": 6,
"value_index": 1,
"advertisement_type": 1
},
{
"id": 7,
"value_index": 0,
"advertisement_type": 1
},
{
"id": 8,
"value_index": 0,
"advertisement_type": 1
},
{
"id": 9,
"value_index": 0,
"advertisement_type": 1
},
{
"id": 10,
"value_index": 0,
"advertisement_type": 1
},
{
"id": 11,
"value_index": 0,
"advertisement_type": 1
},
{
"id": 12,
"value_index": 0,
"advertisement_type": 1
},
{
"id": 13,
"value_index": 1,
"advertisement_type": 1
},
{
"id": 14,
"value_index": 1,
"advertisement_type": 1
}
],
"settings_properties": [
{
"id": 1073741825,
"data": "DM-Deck",
"advertisement_type": 2
},
{
"id": 1073741826,
"data": "UTGame.UTDeathmatch",
"advertisement_type": 2
},
{
"id": 268435704,
"data": 25,
"advertisement_type": 1
},
{
"id": 268435705,
"data": 20,
"advertisement_type": 1
},
{
"id": 268435703,
"data": 6,
"advertisement_type": 1
},
{
"id": 1073741827,
"data": "",
"advertisement_type": 2
},
{
"id": 268435717,
"data": 32,
"advertisement_type": 1
},
{
"id": 1073741828,
"data": "",
"advertisement_type": 2
},
{
"id": 1073741829,
"data": "",
"advertisement_type": 2
},
{
"id": 268435706,
"data": 6,
"advertisement_type": 0
},
{
"id": 268435968,
"data": 0,
"advertisement_type": 0
},
{
"id": 268435969,
"data": 0,
"advertisement_type": 0
}
],
"map": "DM-Deck",
"gametype": "UTGame.UTDeathmatch",
"frag_limit": 25,
"time_limit": 20,
"numbots": 6,
"stock_mutators": [
"Instagib"
],
"custom_mutators": [],
"gamemode": "Deathmatch",
"bot_skill": "Experienced",
"pure_server": 1,
"password": 0,
"vs_bots": "None",
"force_respawn": 0
}
}
1 change: 1 addition & 0 deletions opengsq/protocol_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ def __init__(self, host: str, port: int, timeout: float = 5.0):
self._host = host
self._port = port
self._timeout = timeout
self._allow_broadcast = False
54 changes: 49 additions & 5 deletions opengsq/protocol_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,41 @@ class Socket():
async def gethostbyname(hostname: str):
return await asyncio.get_running_loop().run_in_executor(None, socket.gethostbyname, hostname)

class Protocol(asyncio.Protocol):
def __init__(self, timeout: float):
self.__packets = asyncio.Queue()
self.__timeout = timeout

async def recv(self):
return await asyncio.wait_for(self.__packets.get(), timeout=self.__timeout)

def connection_made(self, transport):
pass

def connection_lost(self, exc):
pass

def data_received(self, data):
self.__packets.put_nowait(data)

def eof_received(self):
pass

def datagram_received(self, data, addr):
self.__packets.put_nowait(data)

def error_received(self, exc):
pass

def __init__(self, kind: SocketKind):
self.__timeout = None
self.__transport = None
self.__protocol = None
self.__kind = kind
self.__local_port = None

def bind_port(self, port: int):
self.__local_port = port

async def __aenter__(self):
return self
Expand Down Expand Up @@ -48,11 +78,13 @@ async def __connect(self, remote_addr):
lambda: self.__protocol,
host=remote_addr[0],
port=remote_addr[1],
local_addr=('0.0.0.0', self.__local_port) if self.__local_port else None
)
else:
self.__transport, _ = await loop.create_datagram_endpoint(
lambda: self.__protocol,
remote_addr=remote_addr,
local_addr=('0.0.0.0', self.__local_port) if self.__local_port else None
)

def close(self):
Expand Down Expand Up @@ -115,12 +147,24 @@ def error_received(self, exc):

class UdpClient(Socket):
@staticmethod
async def communicate(protocol: ProtocolBase, data: bytes):
async def communicate(protocol: ProtocolBase, data: bytes, source_port: int = None):
with UdpClient() as udpClient:
if source_port:
udpClient.bind_port(source_port)
udpClient.settimeout(protocol._timeout)
await udpClient.connect((protocol._host, protocol._port))
udpClient.send(data)
return await udpClient.recv()

loop = asyncio.get_running_loop()
transport, protocol_instance = await loop.create_datagram_endpoint(
lambda: Socket.Protocol(protocol._timeout), # Use public Protocol class
local_addr=('0.0.0.0', source_port if source_port else 0),
allow_broadcast=protocol._allow_broadcast
)

try:
transport.sendto(data, (protocol._host, protocol._port))
return await protocol_instance.recv()
finally:
transport.close()

def __init__(self):
super().__init__(SocketKind.SOCK_DGRAM)
Expand Down Expand Up @@ -150,4 +194,4 @@ async def test_socket_async():

loop = asyncio.get_event_loop()
loop.run_until_complete(test_socket_async())
loop.close()
loop.close()
4 changes: 3 additions & 1 deletion opengsq/protocols/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from opengsq.protocols.scum import Scum
from opengsq.protocols.source import Source
from opengsq.protocols.teamspeak3 import TeamSpeak3
from opengsq.protocols.udk import UDK
from opengsq.protocols.unreal2 import Unreal2
from opengsq.protocols.ut3 import UT3
from opengsq.protocols.vcmp import Vcmp
from opengsq.protocols.won import WON
from opengsq.protocols.won import WON
Loading
Loading