from .packet import Packet from .EnumQuery import EnumQuery from .EnumResponse import EnumResponse from .CFrame import CFrame from .DFrame import DFrame import traceback import uuid from utils.logger import setup_logger from giants import GameTypes, Teams import asyncio logger = setup_logger(__name__) class Netserver(asyncio.DatagramProtocol): def __init__(self, server): self.remotesocket = None self.statssocket = None self.server = server self.addrs = [] self.guid = uuid.uuid4().bytes self.incoming_packets = [] super().__init__() def connection_made(self, transport): logger.debug("Connection made") self.remotesocket = transport def datagram_received(self, data, addr): loop = asyncio.get_event_loop() loop.create_task(self.handle_new_packet(addr, data)) async def handle_new_packet(self, addr, bData): pPacket = Packet(bData) first = pPacket.getByte() if len(bData) >= 4 and first & DFrame.PACKET_COMMAND_DATA: return elif len(bData) >= 12 and first & CFrame.PACKET_COMMAND_FRAME: return elif first == EnumQuery.LEAD or first == EnumResponse.LEAD: logger.debug("%s:%s > %s (ENUM)", addr[0], addr[1], bData.hex()) await self.handle_new_enum(addr, pPacket) else: logger.error("Unknown frame received") return async def handle_new_enum(self, addr, data): # EnumQuery or EnumResponse second = data.getByte() if second == EnumQuery.COMMAND: # EnumQuery try: eq = EnumQuery(data) version, server_name, player_count, max_player_count, map_name = await self.server.on_connection_received(addr[0], addr[1]) er = EnumResponse() er.Payload = eq.Payload er.ApplicationDescSize = 0x50 er.ApplicationDescFlags = 0x41 er.MaxPlayers = max_player_count er.CurrentPlayers = player_count er.SessionName = server_name er.ApplicationInstanceGUID = self.guid er.ApplicationGUID = eq.ApplicationGUID appdata = Packet() appdata.putByte(0xff) # map ID appdata.putByte(GameTypes.GTypeNull) # game type appdata.putByte(Teams.MvRvK) # teams appdata.write(b'\x00') # original: 0x00 - does not seem to affect client appdata.putShort(int(version * 1000)) appdata.write(b'\x02\x92') # original: 0292 - does not seem to affect client appdata.putShort(0) # points per capture appdata.putShort(0) # points per kill appdata.write(b'\x00\x00') # original: 0000 - does not seem to affect client appdata.putShort(0) # detente time appdata.write("\x00\x00\x00\x00") # Seems to be a checksum of current map OR linked to the number of chars in the map name appdata.write(map_name.encode("ascii")) appdata.write(b'\x00' * (32 - len(map_name))) er.ApplicationReservedData = appdata.getvalue() logger.debug("Current map: %s, checksum: %s", self.server.currentmap.mapname, self.server.currentmap.checksum) er.ApplicationReservedData += b'\x00' * (32 - len(self.server.currentmap.mapname)) self.send_packet(addr, er.to_packet()) except Exception: logger.error("Could not parse EnumQuery or forge EnumResponse: ") traceback.print_exc() return else: logger.error("Unknown DPLHP command: %s", second) def send_packet(self, addr, packet): self.remotesocket.sendto(packet.getvalue(), addr)