giantsd/dpnet/netserver.py

605 lines
34 KiB
Python

from .packet import Packet
from .EnumQuery import EnumQuery
from .EnumResponse import EnumResponse
from .CFrame import CFrame
from .DFrame import DFrame
from giants.masterserver import MasterServer
from .session import Session
import socket
import threading
import traceback
import uuid
import struct
from _datetime import datetime
from utils.logger import setup_logger
from giants.player import Player, PlayerPhases
import time
from giants import APPLICATION_GUID
from .DN_MSG_INTERNAL_SEND_CONNECT_INFO import DN_MSG_INTERNAl_SEND_CONNECT_INFO
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 run(self):
logger.debug("Run")
return
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.socket.bind((self.server.listen_ip, self.server.listen_port))
logger.debug("Listening to %s:%s", self.server.listen_ip, self.server.listen_port)
networkthread = threading.Thread(target=self.handle_packets)
networkthread.start()
if self.server.register_with_ms:
ms = MasterServer(self.server)
ms.register()
while self.server.running:
start = datetime.now()
self.read_packets()
self.server.update()
self.send_packets()
sleep_ms = (start-datetime.now()).total_seconds()+1/self.server.ticks
if sleep_ms > 0:
time.sleep(sleep_ms)
networkthread.join()
def read_packets(self):
pass
def send_packets(self):
pass
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:
await self.handle_new_dframe(addr, pPacket)
elif len(bData) >= 12 and first & CFrame.PACKET_COMMAND_FRAME:
await self.handle_new_cframe(addr, pPacket)
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)
#logger.debug("Got EnumQuery, sending EnumResponse")
er = EnumResponse()
er.Payload = eq.Payload
er.ApplicationDescSize = 0x50
er.ApplicationDescFlags = 0x41
er.MaxPlayers = self.server.maxplayers
er.CurrentPlayers = len(self.server.players)
er.SessionName = self.server.name
er.ApplicationInstanceGUID = self.guid
er.ApplicationGUID = eq.ApplicationGUID
'''er.ApplicationReservedData = b'\xff' # Map ID
er.ApplicationReservedData += b'\x00\x04\x00' # game type and teams
er.ApplicationReservedData += struct.pack("<L", int(self.server.version*1000)) # game version
er.ApplicationReservedData += b'\x02\x92\x05\x00\x01\x00\x00\x00\x00\x00' # Unknown
er.ApplicationReservedData += b'\x9c\x53\xf4\xdd' # Seems to be a checksum of current map
# \x00\x00\x00\x00: [None]
# \x00\x00\x00\x01: <custom map>
# \x9c\x53\xf4\xdd: Three Way Island - Canyons
# \x1e\xe9\x39\xe1: Still Winter
# \x9f\xb2\x42\xec: test
er.ApplicationReservedData += self.server.currentmap.mapname.encode("ascii")'''
appdata = Packet()
appdata.putByte(0xff) # map ID
appdata.putByte(self.server.game_type) # game type
appdata.putByte(self.server.teams) # teams
appdata.write(b'\x00') # original: 0x00 - does not seem to affect client
appdata.putShort(int(self.server.version * 1000))
appdata.write(b'\x02\x92') # original: 0292 - does not seem to affect client
appdata.putShort(self.server.points_per_capture)
appdata.putShort(self.server.points_per_kill)
appdata.write(b'\x00\x00') # original: 0000 - does not seem to affect client
appdata.putShort(self.server.detente_time)
appdata.write(
b'\x9f\xb2\x42\xec') # Seems to be a checksum of current map OR linked to the number of chars in the map name
appdata.write(self.server.currentmap.mapname.encode("ascii"))
appdata.write(b'\x00' * (32 - len(self.server.currentmap.mapname)))
er.ApplicationReservedData = appdata.getvalue()
logger.debug("Current map: %s", self.server.currentmap.mapname)
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
elif second == EnumResponse.COMMAND:
# wait what? ignore that shit
return
else:
logger.error("Unknown DPLHP command: %s", second)
async def handle_new_cframe(self, addr, data):
try:
cframe = CFrame(data)
session = self.get_session(addr)
player = self.get_player(session) if session else None
if cframe.ExtOpCode == CFrame.FRAME_EXOPCODE_CONNECT:
logger.debug("%s:%s > %s (CFRAME CONNECT)", addr[0], addr[1], data.getvalue().hex())
# CONNECT CFRAME
if session and session.Full:
logger.error("Session %s:%s was already fully connected. Ignoring.", session.ip, session.port)
return
elif session and not session.Full and session.SessID == cframe.SessID:
# send CONNECTED
logger.debug("Already partially established connection. Sending a CFRAME CONNECTED again.")
session.send_cframe_connected(cframe)
#session.setup_Connect_Retry_Timer()
return
if not self.server.accept_new_players:
# ignore new players
return
else:
logger.debug("New connection. Sending a CFRAME CONNECTED.")
session = Session(self.remotesocket)
session.SessID = cframe.SessID
session.ip = addr[0]
session.port = addr[1]
await session.lock.acquire()
self.addrs.append(session)
session.send_cframe_connected(cframe)
player = Player("Unknown", session)
def bxor(b1, b2): # use xor for bytes
result = bytearray()
for b1, b2 in zip(b1, b2):
result.append(b1 ^ b2)
return result
player.id = struct.unpack(">L", bxor(struct.pack("<L", len(self.server.players)), self.guid[0:4]))[0]
logger.debug("Value for connected player: %s", player.id)
player.phase = PlayerPhases.CFRAME_CONNECT
self.server.create_temp_player(player)
#session.setup_Connect_Retry_Timer()
elif cframe.ExtOpCode == CFrame.FRAME_EXOPCODE_CONNECTED:
logger.debug("%s:%s > %s (CFRAME CONNECTED)", addr[0], addr[1], data.getvalue().hex())
# CONNECTED CFRAME
# check if already sent a CONNECT packet
logger.debug("%s:%s sent back a CONNECTED CFrame.", session.ip, session.port)
if not session:
logger.error("%s sent a CONNECTED opcode without having sent a CONNECT before. GTFO.", addr)
return
if not cframe.SessID == session.SessID or cframe.Command & CFrame.PACKET_COMMAND_POLL:
logger.error("Sent a CONNECTED packet with incorrect SessID or had COMMAND_POLL")
return
session.Full = True # fully connected
session.cancel_Connect_Retry_Timer()
player.phase = PlayerPhases.CFRAME_CONNECTED
session.send_dframe_keepalive()
elif cframe.ExtOpCode == CFrame.FRAME_EXOPCODE_SACK:
logger.debug("%s:%s > %s (CFRAME SACK)", addr[0], addr[1], data.getvalue().hex())
if not session or not session.Full:
logger.error("Received a SACK packet for a non fully connected session")
return
sack_sent = False
if not cframe.NSeq == session.next_expected_seq:
logger.error("Received CFRAME (%s) does not have the same NSeq (%s). Did we miss a packet?", cframe.NSeq, session.next_expected_seq)
if not sack_sent:
session.send_cframe_sack()
sack_sent = True
if not session.next_send == cframe.NRecv:
logger.error("Received CFRAME (%s) does not have same NRcv (%s). One sent packet might have been lost.", cframe.NRecv, session.next_send)
if not sack_sent:
session.send_cframe_sack()
sack_sent = True
# release lock for new packet to be sent
session.lock.release()
# WIP: The bNSeq, bNRcv, optional selective acknowledgment (SACK), and optional send mask fields are then processed by using the standard rules in sections 3.1.5.2.1 through 3.1.5.2.4
# TODO: A successfully validated SACK packet SHOULD count as a valid receive and thus restart the KeepAlive timer
if cframe.Command & CFrame.PACKET_COMMAND_POLL:
if not session:
logger.error("Received a POLL packet for a non fully connected session")
return
#logger.debug("Got a CFrame POLL. Replying with a SACK.")
# must send back a ACK
session.send_cframe_sack()
except Exception:
logger.error("Should have been a CFRAME but could not parse it")
traceback.print_exc()
return
async def handle_new_dframe(self, addr, data):
try:
dframe = DFrame(data)
#logger.debug("Received DFRAME")
session = next((x for x in self.addrs if x.ip == addr[0] and x.port == addr[1]), None)
if not session:
logger.debug("%s sent a DFRAME without having sent a CONNECT before. GTFO.", addr)
logger.debug(self.addrs)
return
if not dframe.Seq == session.next_expected_seq:
logger.error("%s unexpected SEQ. Got %s, expected %s", addr, dframe.Seq, session.next_expected_seq)
#return
if dframe.Control & DFrame.PACKET_CONTROL_END_STREAM:
if not session:
logger.error("Received a END STREAM packet for a non fully connected session")
return
# disconnect
resp = DFrame()
resp.Command = DFrame.PACKET_COMMAND_DATA | DFrame.PACKET_COMMAND_NEW_MSG | DFrame.PACKET_COMMAND_END_MSG | DFrame.PACKET_COMMAND_RELIABLE | DFrame.PACKET_COMMAND_SEQUENTIAL
resp.Control = DFrame.PACKET_CONTROL_END_STREAM
resp.Seq = dframe.NRcv
resp.NRcv = session.next_send
session.send(resp)
session.send_cframe_sack()
# TODO: broadcast session has disconnected
self.addrs.remove(session)
return
if dframe.Control & DFrame.PACKET_CONTROL_KEEPALIVE_OR_CORRELATE:
pass
#session.send_dframe_keepalive()
if dframe.Command & DFrame.PACKET_COMMAND_POLL:
#logger.debug("Sending SACK")
#session.send_cframe_sack()
pass
session.next_expected_seq += 1
if dframe.Payload:
await self.handle_game_packet(session, dframe.Payload)
else:
pass
except Exception as e:
logger.error("Could not parse DFRAME: ")
traceback.print_exc()
return
async def handle_game_packet(self, session, payload):
player = self.get_temp_player(session)
logger.debug("%s:%s > %s (GAMEDATA)", session.ip, session.port, payload.hex())
#logger.debug("OPCODE: %s VALUES: %s", struct.pack("<B", payload[0]).hex(), payload[1:].hex())
#await self.server.broadcast_message("SENT OPCODE: %s VALUES: %s" % (struct.pack("<B", payload[0]).hex(), payload[1:].hex()))
if payload[0] == 0xc1:
if not player or not player.phase == PlayerPhases.CFRAME_CONNECTED:
logger.error("Fuck you. Playerphase was %s", player.phase)
return
# DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO_EX
ppayload = Packet(payload)
dwPacketType = ppayload.getULong()
dwFlags = ppayload.getULong()
dwDNETVersion = ppayload.getULong()
dwNameOffset = ppayload.getULong()
dwNameSize = ppayload.getULong()
dwDataOffset = ppayload.getULong()
dwDataSize = ppayload.getULong()
dwPasswordOffset = ppayload.getULong()
dwPasswordSize = ppayload.getULong()
dwConnectDataOffset = ppayload.getULong()
dwConnectDataSize = ppayload.getULong()
dwURLOffset = ppayload.getULong()
dwURLSize = ppayload.getULong()
guidInstance = payload[52:68]
guidApplication = payload[68:84]
name = payload[dwNameOffset+4:dwNameOffset+2+dwNameSize]
name = name.decode("utf-16-le")
logger.debug("%s connected!", name)
player.name = name
#session.send_dframe_keepalive()
# Response: DN_MSG_INTERNAL_SEND_CONNECT_INFO
d = DN_MSG_INTERNAl_SEND_CONNECT_INFO(self, player)
d.Seq = session.next_send
d.NRcv = session.next_expected_seq
appdata = Packet()
appdata.putByte(0xff) # map ID
appdata.putByte(self.server.game_type) # game type
appdata.putByte(self.server.teams) # teams
appdata.write(b'\x00') # original: 0x00 - does not seem to affect client
appdata.putShort(int(self.server.version * 1000))
appdata.write(b'\x03\x90') # original: 0292 - does not seem to affect client
appdata.putShort(self.server.points_per_capture)
appdata.putShort(self.server.points_per_kill)
appdata.write(b'\x00\x00') # original: 0000 - does not seem to affect client
appdata.putShort(self.server.detente_time)
appdata.write(b'\x9f\xb2\x42\xec') # Seems to be a checksum of current map OR linked to the number of chars in the map name
appdata.write(self.server.currentmap.mapname.encode("ascii"))
appdata.write(b'\x00' * (32 - len(self.server.currentmap.mapname)))
d.ApplicationReservedData = appdata.getvalue()
session.send(d)
player.phase = PlayerPhases.DN_SEND_CONNECT_INFO
elif payload[0] == 0xc3:
player = self.get_temp_player(session)
if not player or not player.phase == PlayerPhases.DN_SEND_CONNECT_INFO:
return
player.phase = PlayerPhases.DN_ACK_CONNECT_INFO
await self.server.add_player(player)
#player.session.send_cframe_sack()
await player.session.send_gamedata(b'\x3c'+struct.pack("<L", player.id)+b"\x00", acknow=True)
p1 = b'\x01' + struct.pack("<B", len(self.server.players))
for pplayer in self.server.players:
p1 += struct.pack("<L", pplayer.id)
for pplayer in self.server.players:
if pplayer.name == "[Server]":
continue
p1 += b'\x0e'
p1 += b"\x01\x00"
for pplayer in self.server.players:
if pplayer == player or pplayer.name == "[Server]":
continue
p1 += struct.pack("<B", pplayer.team)
p1 += b'\x00\x00'
await player.session.send_gamedata(p1, acknow=False)
await player.session.send_gamedata(b'\x3d\x00\x5b\x53\x65\x72\x76\x65\x72\x5d'+b"\x00"*25, acknow=True) # [SERVER]
await player.session.send_gamedata(b'\x3d\x01'+player.name.encode("ascii")+b"\x00"*(33-len(player.name.encode("ascii"))), acknow=True) # playername
"""
player.session.send_gamedata(b'\x0f\x56\xab\x31\x96\x06\x00\x00\x00\x00\x00\x00\x00\x00') # unknown
player.session.send_gamedata(b'\x10\x02\x56\xab\x31\x96\x00\x00\x00\x00\x00\x00\x00\x00') # unknown
player.session.send_gamedata(b'\x29\x28\x00\x00\x80\x32\x00\x00\x80\x05\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00') # unknown
player.session.send_gamedata(b'\x39\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') # unknown
player.session.send_gamedata(b'\x39\x01\x02\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') # unknown
player.session.send_gamedata(b'\x0f\x56\xab\x31\x96\x07\x00\x00\x00\x00\x00\x00\x00\x00') # unknown
player.session.send_gamedata(b'\x0a\x12\x00\x00\x00\x00\x28\x10\x03\x10\x12\x00\x00\x00\xc1\xff\x41\xff\x00', acknow=True) # unknown
player.session.send_gamedata(b'\x0f\x56\xab\x31\x96\x08\x00\x00\x00\x00\x00\x00\x00\x00', acknow=True) # unknown
player.session.send_gamedata(b'\x0a\x12\x00\x00\x00\x00\x2c\x10\x03\x10\x12\x00\x00\x00\x08\x00\xb6\x01\x0a\x14\x00\x00\x00\x00\x2d\x10\x03\x01\x12\x00\x00\x00\xd4\xfc\x9b\xfd\x00\x00\x00', acknow=True) # unknown
#\x00
player.session.send_gamedata(b'\x2f\x02\x00\x00\xbe\x00\x00\x00\x00\x00\x00\x00\x00\x00', acknow=True) # unknown
player.session.send_gamedata(b'\x0a\x12\x00\x00\x00\x00\x2e\x10\x03\x10\x12\x00\x00\x00\xa8\xfd\x2d\x03\x0a\x14\x00\x00\x00\x00\x2e\x10\x03\x01\x12\x00\x00\x00\x60\xfd\x14\x03\x00\x00\x00', acknow=True) # unknown
player.session.send_gamedata(b'\x0a\x14\x00\x00\x00\x00\x28\x10\x03\x01\x12\x00\x00\x00\xbf\xff\x3f\xff\x00\x00\x00', acknow=True) # unknown
player.session.send_gamedata(b'\x0a\x12\x00\x00\x00\x00\x2a\x10\x03\x10\x12\x00\x00\x00\x73\x01\x42\x02\x0a\x14\x00\x00\x00\x00\x2a\x10\x03\x01\x12\x00\x00\x00\xbe\x01\x8c\x02\x00\x00\x00', acknow=True) # unknown
player.session.send_gamedata(b'\x2f\x02\x00\x00\xc2\x00\x00\x00\x00\x00\x00\x00\x00\x00',acknow=True) # unknown
player.session.send_gamedata(b'\x0a\x14\x00\x00\x00\x00\x2c\x10\x03\x01\x12\x00\x00\x00\x06\x00\xb5\x01\x00\x00\x00', acknow=True) # unknown
player.session.send_gamedata(b'\x0a\x12\x00\x00\x00\x00\x2e\x10\x03\x10\x12\x00\x00\x00\xa4\xfd\x2c\x03\x00',acknow=True) # unknown
player.session.send_gamedata(b'\x2f\x02\x00\x00\xc2\x00\x00\x00\x00\x00\x00\x00\x00\x00', acknow=True) # unknown
"""
elif payload[0] == 0x0f:
player = self.get_player(session)
if not player:
logger.debug("Fuck that no player wtf man")
return
inc = Packet(payload)
opcode = inc.getByte()
playerid = inc.getULong()
status = inc.getByte()
if status == 7:
status = 8
out = Packet()
out.putByte(opcode)
out.putULong(playerid)
out.putByte(status)
await player.session.send_gamedata(out.getvalue(), acknow=False)
elif payload[0] == 0x2c:
player = self.get_player(session)
if not player:
logger.debug("Fuck that no player wtf man")
return
# assign team?
await player.session.send_gamedata(b"\x10"+struct.pack("<B", player.team)+struct.pack("<L", player.id)+b"\x00\x00", acknow=False)
elif payload[0] == 0x2a:
player = self.get_player(session)
if not player:
logger.debug("Fuck that no player wtf man")
return
# winning condition time limit
time_limit_minutes = 60 # 1 hour
await player.session.send_gamedata(b"\x29"+struct.pack("<H", time_limit_minutes)+b"\x00\x80"+(b"\x00"*17), acknow=True)
await player.session.send_gamedata(b"\x39"+(b"\x00"*21), acknow=False) # acknow=True
await player.session.send_gamedata(b"\x39\x01\x01\x01\x01"+(b"\x00"*17), acknow=True)
elif payload[0] == 0x0c:
player = self.get_player(session)
if not player:
logger.debug("Fuck that no player wtf man")
return
playerping = 1
await player.session.send_gamedata(b"\x2f\x02\x00\x00" + struct.pack("<H", playerping) + b"\x00",acknow=False) # acknow=True
for i in range(0x06):
ack = (i % 2 == 0)
await player.session.send_gamedata(b"\x04" + struct.pack("<B", i) + b"\x00\x00\x00\x00" + struct.pack("<B", i+0x07) + b"\x00\x00\x00",acknow=ack)
await player.session.send_gamedata(b"\x1a\xee\x02\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x83\x5f\xa4\x44\x00\xf9\xa3\xc2\x00\x00\x00\x00\xff\xff\x33\x43\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x9e\xdc\x07\x00", acknow=True)
await player.session.send_gamedata(b"\x19\x96\x03\x00\x10\x00\x00\x04\x00\x0d\x00\x00\x83\x5f\xa4\x44\x00\xf9\xa3\xc2\x00\x00\x00\x00\xff\xff\x33\x43\x00\x00\x7a\x44\x00\x00\x00\x00\x00\x00\x00\x00\x00", acknow=False)
await player.session.send_gamedata(b"\x39"+b"\x00"*21, acknow=True)
await player.session.send_gamedata(b"\x39"+b"\x01"*4+b"\x00"*17, acknow=False)
await player.session.send_gamedata(b"\x2e"+b"\x00"*9, acknow=True)
await player.session.send_gamedata(b"\x3b\x00\x04\x00\x00\x00\x04\x00\x00\x00", acknow=False)
await player.session.send_gamedata(b"\x3e\x00\x00\x00\x00\x00", acknow=True)
await player.session.send_gamedata(b"\x3f\x00\x00", acknow=False)
await player.session.send_gamedata(b"\x0e\x00", acknow=True)
await player.session.send_gamedata(b"\x10" + struct.pack("<B", player.team) + struct.pack("<L", player.id) + b"\x00\x00", acknow=False)
return
await player.session.send_gamedata(
b"\x0a\x12\x00\x00\x00\x00\x71\xa6\x08\x10\x12\x00\x00\x00\xde\xfe\x83\xfd\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x12\x00\x00\x00\x00\x68\xa6\x08\x10\x12\x00\x00\x00\x50\xff\x5a\xfd\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(b"\x4b\xe0\xe8\x0c\x00\x00\x8a\x14\x00\x00", acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x12\x00\x00\x00\x00\xa9\xa5\x08\x01\x2d\x00\x00\x00\x25\x54\x05\x46\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x16\x00\x00\x00\x00\x53\xa6\x08\x04\x15\x00\x00\x00\xc2\xfd\x6d\x01\x40\x00\xf4\xff\x0a\x14\x00\x00\x00\x00\x71\xa6\x08\x01\x12\x00\x00\x00\xde\xfe\x81\xfd\x00\x00\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x14\x00\x00\x00\x00\x68\xa6\x08\x01\x12\x00\x00\x00\x51\xff\x5c\xfd\x00\x00\x00",
acknow=False) # acknow=True
playerping = 1
await player.session.send_gamedata(b"\x2f\x02\x00\x00" + struct.pack("<H", playerping) + b"\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x12\x00\x00\x00\x00\x57\xa6\x08\x10\x12\x00\x00\x00\x2e\xff\xa7\xfd\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x14\x00\x00\x00\x00\x57\xa6\x08\x01\x12\x00\x00\x00\x5b\xff\x75\xfd\x00\x00\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x16\x00\x00\x00\x00\x50\xa6\x08\x04\x15\x00\x00\x00\xe2\xfd\x51\x01\x3d\x00\xed\xff\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x16\x00\x00\x00\x00\x55\xa6\x08\x04\x15\x00\x00\x00\xe5\xfd\x40\x01\xe5\xff\xf8\xff\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x12\x00\x00\x00\x00\x72\xa6\x08\x10\x12\x00\x00\x00\xf2\xfe\x79\xfd\x0a\x14\x00\x00\x00\x00\x72\xa6\x08\x01\x12\x00\x00\x00\x28\xff\x48\xfd\x00\x00\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x16\x00\x00\x00\x00\x4e\xa6\x08\x04\x15\x00\x00\x00\xc8\xfd\x2f\x01\xa1\xff\x06\x00\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(
b"\x0a\x12\x00\x00\x00\x00\xa9\xa5\x08\x01\x2d\x00\x00\x00\x19\x3d\x09\x46\x00",
acknow=False) # acknow=True
await player.session.send_gamedata(bytes.fromhex("0a120000000057a608101200000031ffa4fd00"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a120000000057a608101200000031ffa4fd00"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a160000000056a6080415000000b1fd4001c8ff120000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a160000000056a6080415000000b1fd4001c8ff120000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a12000000005ca608101200000077ff03fe00"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a14000000005ca608011200000050ffd6fd000000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a160000000047a6080415000000bafd1001d0ff0a0000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a120000000072a6081012000000f5fe75fd00"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a160000000052a6080415000000c9fd45011800080000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a16000000004ca6080415000000c1fdab01e7ff0d0000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a140000000057a608011200000030ffa6fd000000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("2b00000000fa5e5b4500"), acknow=False)
await player.session.send_gamedata(bytes.fromhex(
"0a12000000005ca608101200000074fffffd0a12000000005da608101200000092ff6afd0a140000000072a6080112000000f4fe77fd00000a14000000005da6080112000000a7ff80fd000000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a1200000000a9a508012d000000fe280d4600"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("091200000000c9a50802260000000073a60800"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a140000000073a608011200000009ff97fd000000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("2e070700000000000000"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a160000000054a6080415000000befd88010d00e4ff00"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a16000000004aa6080415000000b0fd5301b4ffb4ff00"),
acknow=False)
await player.session.send_gamedata(
bytes.fromhex("0a120000000068a608101200000075ff7dfd0a140000000068a608011200000051ff5cfd000000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a12000000005da608101200000095ff6dfd00"), acknow=False)
await player.session.send_gamedata(bytes.fromhex(
"0a16000000004ba6080415000000e7fd3f01e0ffa6ff0a160000000049a6080415000000b5fd6101c0ffe5ff00"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a14000000005ca608011200000076ff00fe000000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a120000000068a608101200000071ff79fd00"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("090e00000000c9a508012600000000"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a1200000000a9a508012d000000c016114600"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a16000000004fa6080415000000b2fd8801c9ffceff00"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a14000000005da608011200000094ff6cfd000000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a160000000048a608041500000011fe5201e2ff2c0000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a120000000073a6081012000000c0fe5efd00"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a140000000073a608011200000009ff83fd000000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a120000000071a6081012000000fbfec2fd00"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a140000000071a6080112000000defe81fd000000"),
acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a140000000068a608011200000072ff7afd000000"),
acknow=False)
for i in range(0x7f):
if i >= 0x5c:
await player.session.send_gamedata(bytes.fromhex(
"04" + struct.pack("<B", i).hex() + "00000000" + struct.pack("<B", (
0xa4 + i) % 0xff).hex() + "a60800"), acknow=False)
else:
await player.session.send_gamedata(bytes.fromhex(
"04" + struct.pack("<B", i).hex() + "00000000" + struct.pack("<B", 0xa4 + i).hex() + "a50800"),
acknow=False)
await player.session.send_gamedata(b"\x05\x01\x7b\x02\x00\x03\x00\x00\x00\x00", acknow=False) # acknow=True
# 0f packet
# final packet
await player.session.send_gamedata(b"\x2b\x00\x00\x00\x00\xa0\xe8\x5a\x45\x00", acknow=False) # acknow=True
def send_packet(self, addr, packet):
self.remotesocket.sendto(packet.getvalue(), addr)
#logger.debug("%s:%s < %s", addr[0], addr[1], packet.getvalue().hex())
def get_session(self, iporaddr, port=None):
if not port:
return next((x for x in self.addrs if x.ip == iporaddr[0] and x.port == iporaddr[1]), None)
else:
return next((x for x in self.addrs if x.ip == iporaddr and x.port == port), None)
def get_player(self, iporaddr, port=None):
if type(iporaddr) == Session:
a = next((x for x in self.server.players if x.session.ip == iporaddr.ip and x.session.port == iporaddr.port), None)
if a:
return a
else:
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr.ip and x.session.port == iporaddr.port),None)
if not port:
a = next((x for x in self.server.players if x.session.ip == iporaddr[0] and x.session.port == iporaddr[1]), None)
if a:
return a
else:
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr[0] and x.session.port == iporaddr[1]),None)
else:
a = next((x for x in self.server.players if x.session.ip == iporaddr and x.session.port == port), None)
if a:
return a
else:
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr and x.session.port == port), None)
def get_temp_player(self, iporaddr, port=None):
if type(iporaddr) == Session:
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr.ip and x.session.port == iporaddr.port), None)
if not port:
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr[0] and x.session.port == iporaddr[1]), None)
else:
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr and x.session.port == port), None)