From c9d424b7f7c7d8c8d339e115d5b403b2d155e24c Mon Sep 17 00:00:00 2001 From: HipsterCat Date: Wed, 27 May 2020 14:09:44 +0200 Subject: [PATCH] Clean --- dpnet/DN_MSG_INTERNAL_SEND_CONNECT_INFO.py | 179 ----- dpnet/gamepackets.py | 258 ------- dpnet/netclient.py | 18 - dpnet/netserver.py | 754 +-------------------- dpnet/session.py | 96 --- giants/entity.py | 11 - giants/gameobject.py | 5 - giants/map.py | 42 -- giants/player.py | 58 -- giants/projectile.py | 6 - plugins/__init__.py | 0 plugins/bullets.py | 28 - plugins/commands.py | 185 ----- plugins/greetings.py | 24 - plugins/instagib.py | 59 -- sendenum.py | 9 - server.py | 286 +------- 17 files changed, 30 insertions(+), 1988 deletions(-) delete mode 100644 dpnet/DN_MSG_INTERNAL_SEND_CONNECT_INFO.py delete mode 100644 dpnet/gamepackets.py delete mode 100644 dpnet/netclient.py delete mode 100644 dpnet/session.py delete mode 100644 giants/entity.py delete mode 100644 giants/gameobject.py delete mode 100644 giants/map.py delete mode 100644 giants/player.py delete mode 100644 giants/projectile.py delete mode 100644 plugins/__init__.py delete mode 100644 plugins/bullets.py delete mode 100644 plugins/commands.py delete mode 100644 plugins/greetings.py delete mode 100644 plugins/instagib.py delete mode 100644 sendenum.py diff --git a/dpnet/DN_MSG_INTERNAL_SEND_CONNECT_INFO.py b/dpnet/DN_MSG_INTERNAL_SEND_CONNECT_INFO.py deleted file mode 100644 index de16112..0000000 --- a/dpnet/DN_MSG_INTERNAL_SEND_CONNECT_INFO.py +++ /dev/null @@ -1,179 +0,0 @@ -from .packet import Packet -from .DFrame import DFrame -from giants import APPLICATION_GUID - - -class DN_NAMETABLE_ENTRY_INFO: - def __init__(self): - self.dpnid = 0 - self.dpnidOwner = 0 - self.dwFlags = 0 - self.dwVersion = 2 - self.dwVersionNotUsed = 0 - self.dwDNETVersion = 7 - self.dwNameOffset = 0 - self.dwNameSize = 0 - self.dwDataOffset = 0 - self.dwDataSize = 0 - self.dwURLOffset = 0 - self.dwURLSize = 0 - self.URL = b'' - self.Data = b'' - self.Name = b'' - - def to_packet(self): - p = Packet() - p.putULong(self.dpnid) - p.putULong(self.dpnidOwner) - p.putULong(self.dwFlags) - p.putULong(self.dwVersion) - p.putULong(self.dwVersionNotUsed) - p.putULong(self.dwDNETVersion) - p.putULong(self.dwNameOffset) - p.putULong(self.dwNameSize) - p.putULong(self.dwDataOffset) - p.putULong(self.dwDataSize) - p.putULong(self.dwURLOffset) - p.putULong(self.dwURLSize) - return p - -class DN_MSG_INTERNAl_SEND_CONNECT_INFO(DFrame): - dwPacketType = 0xc2 - - def __init__(self, netserver, newplayer, packet=None): - super().__init__(packet) - self.Command = DFrame.PACKET_COMMAND_DATA | DFrame.PACKET_COMMAND_RELIABLE | DFrame.PACKET_COMMAND_SEQUENTIAL | DFrame.PACKET_COMMAND_POLL | DFrame.PACKET_COMMAND_NEW_MSG | DFrame.PACKET_COMMAND_END_MSG | DFrame.PACKET_COMMAND_USER_1 - self.Control = 0x00 - self.netserver = netserver - self.newplayer = newplayer - self.dwPacketType = DN_MSG_INTERNAl_SEND_CONNECT_INFO.dwPacketType - self.dwReplyOffset = 0 - self.dwReplySize = 0 - self.dwSize = 0x50 - self.dwFlags = 0x41 - self.dwMaxPlayers = netserver.server.maxplayers - self.dwCurrentPlayers = len(netserver.server.players) + len(netserver.server.tempplayers) - self.dwSessionNameOffset = 0 - self.dwSessionNameSize = len((netserver.server.name+"\x00").encode("utf-16-le")) - self.dwPasswordOffset = 0 - self.dwPasswordSize = 0 - self.dwReservedDataOffset = 0 - self.dwReservedDataSize = 0 - self.dwApplicationReservedDataOffset = 0 - self.dwApplicationReservedDataSize = 0 - self.guidInstance = netserver.guid - self.guidApplication = APPLICATION_GUID - self.dpnid = newplayer.id - self.dwVersion = 3 - self.dwVersionNotUsed = 0 - self.dwEntryCount = 0 - self.dwMembershipCount = 0 - self.DN_NameTable_Entry_Info = [] - self.DN_NameTable_Membership_Info = [] - self.ApplicationReservedData = b'' - self.ReservedData = b'' - self.Password = b'' - self.SessionName = (netserver.server.name+"\x00").encode("utf-16-le") - self.Reply = b'' - - if packet: - self.parse(packet) - - def parse(self, packet): - pass - - def to_packet(self): - var = 108 - - s = self.netserver.server.players[0] - entry_server = DN_NAMETABLE_ENTRY_INFO() - self.DN_NameTable_Entry_Info.append(entry_server) - - p = self.newplayer - entry_player = DN_NAMETABLE_ENTRY_INFO() - self.DN_NameTable_Entry_Info.append(entry_player) - - self.dwEntryCount = len(self.DN_NameTable_Entry_Info) - self.dwMembershipCount = len(self.DN_NameTable_Membership_Info) - - entry_server.dpnid = s.id - entry_server.dwFlags = 0x0402 - entry_server.dwVersion = 2 - - entry_player.dpnid = p.id - entry_player.dwFlags = 0x0200 - entry_player.Name = p.name.encode("utf-16-le") - entry_player.dwVersion = 3 - - var = var + self.dwEntryCount * 48 # 48=size of DN_NAMETABLE_ENTRY_INFO - entry_player.dwNameOffset = var - entry_player.dwNameSize = len(entry_player.Name) - - var += entry_player.dwNameSize - - if self.ApplicationReservedData: - self.dwApplicationReservedDataSize = len(self.ApplicationReservedData) - self.dwApplicationReservedDataOffset = var - var += self.dwApplicationReservedDataSize - if self.ReservedData: - self.dwReservedDataSize = len(self.ReservedData) - self.dwReservedDataOffset = var - var += self.dwReservedDataSize - if self.Password: - self.dwPasswordSize = len(self.Password) - self.dwPasswordOffset = var - var += self.dwPasswordSize - if self.SessionName: - self.dwSessionNameSize = len(self.SessionName) - self.dwSessionNameOffset = var - var += self.dwSessionNameSize - if self.Reply: - self.dwReplySize = len(self.Reply) - self.dwReplyOffset = var - var += self.dwReplySize - - packet = Packet() - packet.putULong(self.dwPacketType) - packet.putULong(self.dwReplyOffset) - packet.putULong(self.dwReplySize) - packet.putULong(self.dwSize) - packet.putULong(self.dwFlags) - packet.putLong(self.dwMaxPlayers) - packet.putULong(self.dwCurrentPlayers) - packet.putULong(self.dwSessionNameOffset) - packet.putULong(self.dwSessionNameSize) - packet.putULong(self.dwPasswordOffset) - packet.putULong(self.dwPasswordSize) - packet.putULong(self.dwReservedDataOffset) - packet.putULong(self.dwReservedDataSize) - packet.putULong(self.dwApplicationReservedDataOffset) - packet.putULong(self.dwApplicationReservedDataSize) - packet.putBytes(self.guidInstance) - packet.putBytes(self.guidApplication) - packet.putULong(self.dpnid) - packet.putULong(self.dwVersion) - packet.putULong(self.dwVersionNotUsed) - packet.putULong(self.dwEntryCount) - packet.putULong(self.dwMembershipCount) - - for entry in self.DN_NameTable_Entry_Info: - packet.putBytes(entry.to_packet().getvalue()) - for entry in self.DN_NameTable_Membership_Info: - packet.putBytes(entry.to_packet().getvalue()) - - if entry_player.URL: - packet.putBytes(entry_player.URL) - if entry_player.Data: - packet.putBytes(entry_player.Data) - if entry_player.Name: - packet.putBytes(entry_player.Name) - - packet.putBytes(self.ApplicationReservedData) - packet.putBytes(self.ReservedData) - packet.putBytes(self.Password) - packet.putBytes(self.SessionName) - packet.putBytes(self.Reply) - - self.Payload = packet.getvalue() - - return super().to_packet() diff --git a/dpnet/gamepackets.py b/dpnet/gamepackets.py deleted file mode 100644 index b6bba9c..0000000 --- a/dpnet/gamepackets.py +++ /dev/null @@ -1,258 +0,0 @@ -from dpnet.packet import Packet - - -class MSG_CHANGE_TEAM(): - def __init__(self, player, teamid: int, respawn: bool = True): - self.player = player - self.teamid = teamid - self.respawn = respawn - if self.teamid > 255: - raise ValueError("Team ID must be < 256") - - def to_packet(self): - p = Packet() - p.putByte(0x10) # opcode - p.putByte(self.teamid) - p.putULong(self.player.id) - p.putByte(self.respawn) - p.putByte(0x00) # end - return p.getvalue() - - -class MSG_MOVE_PLAYER(): - def __init__(self, player, direction, orientation): - self.player = player - self.direction = direction - self.orientation = orientation - - def to_packet(self): - p = Packet() - p.putByte(0x0f) # opcode - p.putByte(0x12) # opcode2? - p.putByte(0x00) # unknown - p.putByte(0x00) # unknown - p.putByte(0x00) # unknown - p.putByte(self.player) # player index - p.putShort(self.player.oid) - p.putByte(0x00) # unknown - p.putByte(0x00) # unknown - p.putULong(self.player.model()) - p.putShort(self.direction) - p.putShort(self.orientation) - p.putByte(0x00) # end - return p.getvalue() - - -class MSG_PLAYER_PING(): - def __init__(self, player, ping): - self.player = player - self.ping = ping - - def to_packet(self): - p = Packet() - p.putByte(0x2f) # opcode - p.putByte(self.player.get_index()) - p.putByte(0x00) # unknown - p.putByte(0x00) # unknown - p.putShort(self.ping) # ping - p.putByte(0x00) # end - return p.getvalue() - - -class MSG_SWITCH_WEAPON(): - def __init__(self, player, newweapon): - self.player = player - self.newweapon = newweapon - - def to_packet(self): - p = Packet() - p.putByte(0x09) # opcode - p.putByte(0x0f) # opcode2? - p.putByte(0x00) - p.putShort(0x0000) - p.putByte(self.player.get_index()) - p.putShort(self.player.oid) - p.putByte(0x00) - p.putByte(0x0a) - p.putULong(0x02) - p.putByte(self.newweapon) - p.putByte(0x00) # end - return p.getvalue() - - -class MSG_DROP_WEAPON(): - def __init__(self, player, oid, weapon, ammo): - self.player = player - self.weapon = weapon - self.ammo = ammo - self.oid = oid - - def to_packet(self): - p = Packet() - p.putByte(0x20) # opcode - # TODO: fixit - p.putShort(0x012e) # can also be 1303 ... oid? my oid was 7 at the time - #p.putShort(self.oid) # can also be 1303 ... oid? my oid was 7 at the time - p.putShort(0x0000) - p.putByte(self.player.get_index()) - p.putByte(0x38) - p.putShort(0x0000) - p.putFloat(self.player.x) - p.putFloat(self.player.y) - p.putFloat(self.player.z) - p.putFloat(self.player.o) - p.putFloat(0xc79e28c1) # ?? - p.putShort(0x0000) - p.putULong(0x70410000) - p.putByte(self.weapon) - p.putByte(0x00) - p.putULong(self.ammo) - p.putShort(0x0000) - p.putShort(0x0000) - p.putByte(0x00) - return p.getvalue() - -class MSG_NEW_PROJECTILE(): - def __init__(self, player, oid, projectiletype, x, y, z, o): - self.player = player - self.x = x - self.y = y - self.z = z - self.o = o - self.projectiletype = projectiletype - self.oid = oid - - def to_packet(self): - p = Packet() - p.putByte(0x09) # opcode - p.putULong(0x23) - p.putByte(self.player.get_index()) - p.putShort(self.player.oid) - p.putByte(0x00) - p.putByte(0x10) - p.putULong(0x02) - p.putFloat(self.x) - p.putFloat(self.y) - p.putFloat(self.z) - p.putULong(self.o) - p.putShort(self.oid) - p.putShort(0x00) - p.putByte(self.projectiletype) - p.putByte(0x00) - return p.getvalue() - - -class MSG_BULLET_EXPLOSION(): - def __init__(self, player, oid, x, y, z, isbackpackitem): - self.player = player - self.oid = oid - self.x = x - self.y = y - self.z = z - self.isbackpackitem = isbackpackitem - - def to_packet(self): - p = Packet() - p.putByte(0x09) # opcode - p.putULong(0x1a) - p.putByte(self.player.get_index()) - p.putShort(self.oid) - p.putByte(0x00) - p.putByte(0x03) if not self.isbackpackitem else p.putByte(0x01) # 0x01 for backpackitem, 0x03 for anything else? - p.putULong(0x4d) - p.putFloat(self.x) - p.putFloat(self.y) - p.putFloat(self.z) - p.putByte(0x00) - return p.getvalue() - -class MSG_PLAYER_DIE(): - def __init__(self, player, deathtype): - self.player = player - self.deathtype = deathtype - - def to_packet(self): - p = Packet() - p.putByte(0x0b) # opcode - p.putULong(0x1a) - p.putByte(0x00) - p.putByte(self.player.get_index()) - p.putByte(0x07) - p.putShort(0x0000) - p.putFloat(self.player.x) - p.putFloat(self.player.y) - p.putFloat(self.player.z) - p.putFloat(self.player.o) - p.putShort(0x1409) # oid? - p.putByte(0x00) - p.putShort(0x0000) - p.putByte(self.player.get_index()) - p.putByte(0x07) - p.putShort(0x0000) - p.putByte(0x04) - p.putByte(0x02) - p.putShort(0x0000) - p.putByte(0x00) - p.putULong(self.deathtype) - p.putByte(0x00) - p.putByte(0x00) # end - return p.getvalue() - - -class MSG_PLAYER_TELEPORT(): - def __init__(self, player, newx, newy, newz, newo): - self.player = player - self.newx = newx - self.newy = newy - self.newz = newz - self.newo = newo - - def to_packet(self): - p = Packet() - p.putByte(0x13) # opcode - p.putByte(self.player.get_index()) - p.putShort(self.player.oid) - p.putByte(0x00) - p.putFloat(0x00000000) - p.putFloat(self.newx) - p.putFloat(self.newy) - p.putFloat(self.newz) - p.putByte(0x00) - return p.getvalue() - - -class MSG_PLAYER_USE_BACKPACK(): - def __init__(self, player, backpackitem): - self.player = player - self.backpackitem = backpackitem - - def to_packet(self): - p = Packet() - p.putByte(0x09) # opcode - p.putULong(0x12) - p.putByte(self.player.get_index()) - p.putShort(self.player.oid) - p.putByte(0x00) - p.putByte(self.backpackitem) # popup? - p.putULong(0x02) - p.putULong(0x46aae90a) # ? - p.putByte(0x00) - return p.getvalue() - - -class MSG_PLAYER_DROP_BACKPACK(): - def __init__(self, player): - self.player = player - - def to_packet(self): - p = Packet() - p.putByte(0x09) # opcode - p.putULong(0x13) - p.putByte(self.player.get_index()) - p.putShort(self.player.oid) - p.putByte(0x11) - p.putULong(0x02) - p.putULong(0x3a04) - p.putByte(0x0a) - p.putByte(0x00) - return p.getvalue() diff --git a/dpnet/netclient.py b/dpnet/netclient.py deleted file mode 100644 index da9c2fc..0000000 --- a/dpnet/netclient.py +++ /dev/null @@ -1,18 +0,0 @@ -from .packet import Packet -from .EnumQuery import EnumQuery -import socket -import threading - - -class Netclient: - def __init__(self, ip, port): - self.ip = ip - self.port = port - self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP - - def send(self, packet): - self.socket.sendto(packet.getvalue(), (self.ip, self.port)) - print("R>", packet.getvalue().hex()) - - def receive(self): - return self.socket.recv(4096) \ No newline at end of file diff --git a/dpnet/netserver.py b/dpnet/netserver.py index 254554a..04db0da 100644 --- a/dpnet/netserver.py +++ b/dpnet/netserver.py @@ -1,26 +1,13 @@ -import os - 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 -import random -from .DN_MSG_INTERNAL_SEND_CONNECT_INFO import DN_MSG_INTERNAl_SEND_CONNECT_INFO +from giants import GameTypes, Teams import asyncio -from dpnet.gamepackets import * logger = setup_logger(__name__) @@ -39,36 +26,6 @@ class Netserver(asyncio.DatagramProtocol): 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)) @@ -77,9 +34,9 @@ class Netserver(asyncio.DatagramProtocol): pPacket = Packet(bData) first = pPacket.getByte() if len(bData) >= 4 and first & DFrame.PACKET_COMMAND_DATA: - await self.handle_new_dframe(addr, pPacket) + return elif len(bData) >= 12 and first & CFrame.PACKET_COMMAND_FRAME: - await self.handle_new_cframe(addr, pPacket) + 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) @@ -94,42 +51,31 @@ class Netserver(asyncio.DatagramProtocol): # EnumQuery try: eq = EnumQuery(data) - #logger.debug("Got EnumQuery, sending EnumResponse") + 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 = self.server.maxplayers - er.CurrentPlayers = len(self.server.players) - er.SessionName = self.server.name + er.MaxPlayers = max_player_count + er.CurrentPlayers = player_count + er.SessionName = 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(" - # \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.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(self.server.version * 1000)) + appdata.putShort(int(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.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(self.server.detente_time) - appdata.write(self.server.currentmap.checksum) # 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))) + 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) @@ -139,674 +85,8 @@ class Netserver(asyncio.DatagramProtocol): 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: - if False: - logger.error("Session %s:%s was already fully connected. Ignoring.", session.ip, session.port) - return - else: - logger.error("Session %s:%s was already fully connected. Kicking the old one.", session.ip, session.port) - player = self.get_player(session) - if player: - self.server.remove_player(self.get_player(session)) - self.addrs.remove(session) - 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.server, 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(" %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 - if session.lock.locked(): - 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 and not dframe.Control & DFrame.PACKET_CONTROL_END_STREAM: - logger.debug("%s sent a DFRAME without having sent a CONNECT before. GTFO.", addr) - logger.debug("%s:%s > %s (DFRAME)", addr[0], addr[1], data.getvalue().hex()) - return - - if dframe.Control & DFrame.PACKET_CONTROL_END_STREAM: - logger.debug("%s:%s > %s (END_STREAM)", addr[0], addr[1], data.getvalue().hex()) - if not session: - logger.error("Received a END STREAM packet for a non fully connected session") - session = Session(self.server, self.remotesocket) - session.ip = addr[0] - session.port = addr[1] - session.SessID = dframe.SessID - session.next_send = dframe.NRcv - session.next_expected_seq = dframe.Seq+1 - - session.send_cframe_sack() - 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 - logger.debug(" %s:%s < %s (END_STREAM)", session.ip, session.port, resp.to_packet().getvalue().hex()) - session.send(resp) - - # TODO: broadcast session has disconnected - if self.get_session(addr): - self.addrs.remove(session) - - 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_KEEPALIVE_OR_CORRELATE: - pass - #session.send_dframe_keepalive() - - if dframe.Command & DFrame.PACKET_COMMAND_POLL: - #logger.debug("Sending SACK") - session.send_cframe_sack() - pass - - if session.next_expected_seq == 255: - session.next_expected_seq = 0 - else: - 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(" %s (GAMEDATA)", session.ip, session.port, appdata.getvalue().hex()) - player.phase = PlayerPhases.DN_SEND_CONNECT_INFO - - elif payload[0] == 0xc3: - # CMESG_CONNECTED - 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) - await player.session.send_gamedata(b'\x3c'+struct.pack(" 3 >= team % 128: - # ignore - logger.info("%s tried to change team to %s but failed" % (player.name, team)) - else: - await player.change_team(team % 128) - elif payload[0] == 0x35: # CMSG_SEND_CHAT_MESSAGE: messagetype? (byte), team? (byte), message (string) - player = self.get_player(session) - if not player: - logger.debug("Fuck that no player wtf man") - return - - p = Packet(payload) - opcode = p.getByte() - type = p.getByte() - team = p.getByte() - message = p.read().decode("utf8").replace("\x00", "") - await self.server.broadcast_event("on_player_chat", player, type, team, message) - - 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(" - objid = "75" - plix = "01" - model = "4b" - #async def spawn(objid, plix, model): - # await player.session.send_gamedata(bytes.fromhex("05"+plix+objid+"0000"+model+"00000000"), acknow=False) - # await player.session.send_gamedata(bytes.fromhex("0a32000000"+plix+objid+"000001"+model+"0000000000000000000000000000000000000000000000000000000000000000000000000000000a12000000"+plix+objid+"0000"+model+"020000000000000000"), acknow=False) - #await spawn(objid, plix, model) - - # makes one player change team - #await player.session.send_gamedata(bytes.fromhex("0f1c49e2450e0000000000"), acknow=False) - #await player.session.send_gamedata(bytes.fromhex("0f1e"+struct.pack("= 4 and rawbytes[0] & DFrame.PACKET_COMMAND_DATA: - self.next_send += 1 - - def setup_Connect_Retry_Timer(self): - time = 0.2 * pow(2, self.connect_retry_timer_num) - if time > 5: - return False - t = Timer(time, self._send_connected) - t.start() - return t - - def cancel_Connect_Retry_Timer(self): - if self.connect_retry_timer: - self.connect_retry_timer.cancel() - self.connect_retry_timer_num = 0 - - def _send_connected(self): - response = CFrame() - response.ExtOpCode = CFrame.FRAME_EXOPCODE_CONNECTED - response.RspId = self.LastMsgID - response.SessID = self.SessID - logger.debug("Timer sending CONNECTED") - self.send(response) - self.connect_retry_timer = self.setup_Connect_Retry_Timer() - - async def send_gamedata(self, bPayload, **kwargs): - acknow = kwargs.get("acknow", False) - dframe = DFrame() - dframe.Command = DFrame.PACKET_COMMAND_DATA | DFrame.PACKET_COMMAND_RELIABLE | DFrame.PACKET_COMMAND_SEQUENTIAL | DFrame.PACKET_COMMAND_NEW_MSG | DFrame.PACKET_COMMAND_END_MSG - if acknow: - dframe.Command = dframe.Command | DFrame.PACKET_COMMAND_POLL - dframe.Control = 0x00 - dframe.Seq = self.next_send - dframe.NRcv = self.next_expected_seq - dframe.Payload = bPayload - logger.debug(" %s:%s < %s (GAMEDATA)", self.ip, self.port, bPayload.hex()) - self.send(dframe) - if acknow: - await self.lock.acquire() - return dframe - - def send_cframe_connected(self, connect): - response = CFrame() - response.ExtOpCode = CFrame.FRAME_EXOPCODE_CONNECTED - response.RspId = connect.MsgID - response.SessID = connect.SessID - logger.debug(" %s:%s < %s (CFRAME CONNECTED)", self.ip, self.port, response.to_packet().getvalue().hex()) - self.send(response) - - def send_cframe_sack(self): - r = CFrame() - r.Command = CFrame.PACKET_COMMAND_FRAME - r.ExtOpCode = CFrame.FRAME_EXOPCODE_SACK - r.Flags = CFrame.SACK_FLAGS_RESPONSE - r.NRecv = self.next_expected_seq - r.NSeq = self.next_send - logger.debug(" %s:%s < %s (CFRAME SACK)", self.ip, self.port, r.to_packet().getvalue().hex()) - self.send(r) - - def send_dframe_keepalive(self): - dframe = DFrame() - dframe.Command = DFrame.PACKET_COMMAND_DATA | DFrame.PACKET_COMMAND_RELIABLE | DFrame.PACKET_COMMAND_SEQUENTIAL | DFrame.PACKET_COMMAND_POLL | DFrame.PACKET_COMMAND_NEW_MSG | DFrame.PACKET_COMMAND_END_MSG - dframe.Control = DFrame.PACKET_CONTROL_KEEPALIVE_OR_CORRELATE - dframe.Seq = self.next_send - dframe.NRcv = self.next_expected_seq - dframe.SessID = self.SessID - self.send(dframe) diff --git a/giants/entity.py b/giants/entity.py deleted file mode 100644 index 12b49df..0000000 --- a/giants/entity.py +++ /dev/null @@ -1,11 +0,0 @@ -class Entity: - def __init__(self): - self.x = 0 - self.y = 0 - self.z = 0 - self.o = 0 - self.oid = 0 - self._model = 0 - - def model(self): - return self._model diff --git a/giants/gameobject.py b/giants/gameobject.py deleted file mode 100644 index cdc8c7a..0000000 --- a/giants/gameobject.py +++ /dev/null @@ -1,5 +0,0 @@ -from giants.entity import Entity - - -class GameObject(Entity): - pass diff --git a/giants/map.py b/giants/map.py deleted file mode 100644 index 0b278c2..0000000 --- a/giants/map.py +++ /dev/null @@ -1,42 +0,0 @@ -import os - - -class Map: - def __init__(self, mappath): - self.mappath = mappath - self.checksum = None - self.mapname = "Unknown map" - self.load_map(mappath) - - def load_map(self, mappath): - if not os.path.exists("maps/"+mappath): - raise Exception("Map not found: "+mappath) - - if not mappath.endswith(".gck"): - raise Exception("Server only supports GCK maps") - - self.mapname = mappath.split(".gck")[0] - self.checksum = Map.checksum(mappath) - - @staticmethod - def checksum(mappath): - # TODO - if mappath == "Three Way Island - Canyons.gck": - return b"\x9c\x53\xf4\xdd" - if mappath == "test1.gck": - return b"\x9f\xb2\x42\xec" - if mappath == "test.gck": - return b"\x48\x52\x33\x23" - if mappath == "test2.gck": - return b"\xc7\x5f\x61\x1f" - if mappath == "test3.gck": - return b"\x59\xbb\xab\x52" - if mappath == "Testmap.gck": - return b"\x74\x07\x98\xaf" - # \x00\x00\x00\x00: [None] - # \x00\x00\x00\x01: - # \x9c\x53\xf4\xdd: Three Way Island - Canyons - # \x1e\xe9\x39\xe1: Still Winter - # \x9f\xb2\x42\xec: testv1 - # \x48\x52\x33\x23: testv2 - return b"\x00\x00\x00\x00" diff --git a/giants/player.py b/giants/player.py deleted file mode 100644 index d7ca045..0000000 --- a/giants/player.py +++ /dev/null @@ -1,58 +0,0 @@ -from .entity import Entity -import random -import struct -from . import ChatColor, ChatType, Models -from dpnet.DFrame import DFrame -from dpnet.gamepackets import MSG_CHANGE_TEAM, MSG_PLAYER_PING - - -class PlayerPhases: - NONE = 0 - CFRAME_CONNECT = 1 - CFRAME_CONNECTED = 2 - DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO_EX = 3 - DN_SEND_CONNECT_INFO = 4 - DN_ACK_CONNECT_INFO = 5 - INGAME = 6 - - -class Player(Entity): - def __init__(self, name, session): - super().__init__() - self.name = name - self.session = session - self.team = 2 - self.score = 0 - self.id = random.getrandbits(16) - self.phase = PlayerPhases.NONE - self.ping = 1 - self.opts = {"debug": True} - - def get_index(self): - return self.session.server.get_player_index(self) - - async def change_team(self, newteam, respawn=True): - self.team = newteam - await self.session.server.broadcast_event("on_player_change_team", self, self.team) - await self.session.server.broadcast_gamedata(MSG_CHANGE_TEAM(self, newteam, respawn).to_packet()) - - async def send_ping(self, ping): - await self.session.server.broadcast_gamedata(MSG_PLAYER_PING(self, ping).to_packet()) - - async def send_message(self, message, type=ChatType.All, playerindex=0, color=ChatColor.Orange): - options = type | color - playeri = 0x80 + playerindex - await self.session.send_gamedata(b"\x35" + struct.pack(" 1 and command[0] == "bullet": - t = int(command[1]) - player.opts["bullet"] = t - - async def on_player_shoot(self, player, payload): - if "bullet" in player.opts and player.opts["bullet"] != 0: - oid = struct.unpack(" 1 and command[0] == "team": - newteam = command[1] - respawn = True - if len(command) > 2: - respawn = False if command[2] == "off" or command[2] == "no" or command[2] == "false" else True - print("Changing team of %s to %s" % (player.name, newteam)) - await self.server.broadcast_message("%s switched to team %s using command" % (player.name, newteam)) - await player.change_team(int(newteam), respawn=respawn) - - if len(command) > 1 and command[0] == "ping": - newping = command[1] - print("Changing ping of %s to %s" % (player.name, newping)) - await self.server.broadcast_message("%s set his ping to %s" % (player.name, newping)) - await player.send_ping(int(newping)) - - if command[0] == "ping": - print("ping function") - await self.server.broadcast_message("pong") - - if command[0] == "colors": - # color codes seem to go from 01 to 0F, loop and show each value: - for i in range(1, 0xf + 1): - print("Trying value %s" % i) - await player.send_message("Color %s" % i, color=i) - await asyncio.sleep(2) # sleep between each value to see what value makes the client crash - - if command[0] == "chattypes": - # type codes seem to go from 00 to 0F, loop and show each value: CRASH - for i in range(0, 0xf+1): - print("Trying value %s" % i) - await self.server.broadcast_message("Type %s" % i, type=i) - await asyncio.sleep(2) # sleep between each value to see what value makes the client crash - - if command[0] == "doomchat": - # tries every value of first byte and second byte - for i in range(3,0xff+1): - for j in range(0, 0x81): - if i == 0 and j == 2: - break # ;) - message = "(%s, %s)" % (i, j) - print(message) - await player.session.send_gamedata(b"\x35" + struct.pack(" 1: - diemethod = int(command[1]) - await player.send_message("Death by id: %s" % diemethod) - await self.server.broadcast_gamedata(MSG_PLAYER_DIE(player, diemethod).to_packet()) - #await player.session.send_gamedata(bytes.fromhex("0b1a0000000002070000a5b0d4c35d9714c450abef354a68fb410914000000020700000402000000")+struct.pack(" 1: - await self.server.broadcast_message("Spawning " + command[1] + "") - await self.server.spawn(player, int(command[1])) - - if command[0] == "changeme" and len(command) > 1: - await self.server.broadcast_message("Changing your model to " + command[1] + "") - await self.server.change_model(player, int(command[1])) - - if command[0] == "change" and len(command) > 2: - await self.server.broadcast_message("Changing model of "+command[1]+" to "+command[2]+"") - await self.server.change_model(self.server.get_player_by_index(int(command[1])), int(command[2])) - - if command[0] == "debug": - if player.opts["debug"]: - player.opts["debug"] = False - await player.send_message("Debug disabled") - else: - player.opts["debug"] = True - await player.send_message("Debug enabled") - - if command[0] == "record": - self.recording = True - self.recordingplayer = player - await player.send_message("Recording next packet...", color=ChatColor.Cyan) - - if command[0] == "replayshow": - await player.send_message("Packet: %s" % (self.recorded.hex(),), color=ChatColor.Cyan) - - if command[0] == "replay" or command[0] == "r" and len(command) == 1: - await player.session.send_gamedata(self.recorded) - await player.send_message("Sent packet %s to you" % (self.recorded.hex(),), color=ChatColor.Cyan) - - if command[0] == "switch" and len(command) > 1: - newweap = int(command[1]) - await player.send_message("Got you weapon %s" % newweap, color=ChatColor.Cyan) - await self.server.broadcast_gamedata(MSG_SWITCH_WEAPON(player, newweap).to_packet()) - - if command[0] == "s": - await player.send_message("Got you weapon %s" % (self.nextweapon,), color=ChatColor.Cyan) - await self.server.broadcast_gamedata(MSG_SWITCH_WEAPON(player, self.nextweapon).to_packet()) - self.nextweapon += 1 - - if command[0] == "emptyweapons": - for _ in range(4): - await self.server.broadcast_gamedata(MSG_SWITCH_WEAPON(player, 0xff).to_packet()) - await player.send_message("Emptied your weapons", color=ChatColor.Cyan) - - if command[0] == "sniper": - p = Packet() - p.putByte(0x20) - p.putShort(self.server._nextid) # oid? - self.server._nextid += 1 - p.putShort(0x0000) - p.putShort(0x0440) - p.putShort(0x0100) - p.putFloat(0) # x - p.putFloat(0) # y - p.putFloat(0) # z - p.putFloat(0) # o - p.putFloat(0x621c68c1) # wtf? - p.putShort(0x0000) - p.putShort(0x7041) # oid? - p.putShort(0x0000) - p.putShort(0x0300) - p.putLong(0x1e0000) - p.putLong(0x0) - p.putByte(0x00) # end - await self.server.broadcast_gamedata(p.getvalue()) - - if len(command) > 1 and command[0] == "drop": - weap = int(command[1]) - await player.send_message("Dropped weapon %s" % weap, color=ChatColor.Cyan) - await self.server.broadcast_gamedata(MSG_DROP_WEAPON(player, self.server.new_oid(), weap, 255).to_packet()) - - if command[0] == "coords": - await player.send_message("You are at (%s,%s,%s)" % (player.x, player.y, player.z), color=ChatColor.Cyan) - - if command[0] == "tp": - x = randint(-200,200) - y = randint(-200,200) - z = randint(-200,200) - o = 0 - await player.send_message("Teleporting you to (%s,%s,%s)" % (x, y, z), color=ChatColor.Cyan) - await self.server.broadcast_gamedata(MSG_PLAYER_TELEPORT(player, x, y, z, o).to_packet()) - - if len(command) > 1 and command[0] == "fire": - weap = int(command[1]) - - if len(command) > 2: - i = int(command[2]) - else: - i = 1 - - for _ in range(i): - x = randint(-200, 200) - y = randint(-200, 200) - z = randint(-200, 200) - o = 0 - await player.send_message("Firing to (%s,%s,%s)" % (x, y, z), color=ChatColor.Cyan) - await self.server.broadcast_gamedata(MSG_NEW_PROJECTILE(player, self.server.new_oid(), weap, x, y, z, o).to_packet()) - - if command[0] == "popup": - await player.send_message("Spawned popup", color=ChatColor.Cyan) - await self.server.broadcast_gamedata(bytes.fromhex("09160000000438000002250000000a000000040700000913000000040700001102000000041d00000a090e00000004380000032500000000")) - -def setup(server): - plugin = Commands(server) - server.add_plugin(plugin) diff --git a/plugins/greetings.py b/plugins/greetings.py deleted file mode 100644 index 0ec3085..0000000 --- a/plugins/greetings.py +++ /dev/null @@ -1,24 +0,0 @@ -import random - -class Greetings: - def __init__(self, server): - self.server = server - self.join_messages = ["Welcome %s!", "Beware! %s has arrived!", "A wild %s appears.", "%s has come and is ready to pwn."] - self.left_messages = ["%s has left.", "%s has stopped Giants and started playing Apex. Shame!", "A wild %s disappeared.", "%s was happy with the score and left the game."] - - async def on_player_join(self, player): - await self.server.broadcast_message(random.choice(self.join_messages) % player.name) - - async def on_map_change(self, newmap): - await self.server.broadcast_message("You are now playing on "+newmap.mapname) - - async def on_player_change_team(self, player, newteam): - await self.server.broadcast_message("%s switched to team %s" % (player.name, newteam)) - - async def on_player_left(self, player): - await self.server.broadcast_message(random.choice(self.left_messages) % player.name) - - -def setup(server): - plugin = Greetings(server) - server.add_plugin(plugin) diff --git a/plugins/instagib.py b/plugins/instagib.py deleted file mode 100644 index 242948e..0000000 --- a/plugins/instagib.py +++ /dev/null @@ -1,59 +0,0 @@ -from dpnet.packet import Packet -from dpnet.gamepackets import * -from random import randint - -class Instagib: - def __init__(self, server): - self.server = server - - async def on_player_spawn(self, player): - await self.server.broadcast_message("%s has spawned" % player.name) - - # random teleport - await self.random_teleport(player) - - # give stuff - await self.give_stuff(player) - - async def on_player_respawn(self, player): - await self.server.broadcast_message("%s has respawned" % player.name) - - # random teleport - await self.random_teleport(player) - - # give stuff - await self.give_stuff(player) - - async def on_player_shoot(self, player, payload): - await self.spawn_sniper(player) - - async def on_player_hit(self, player, shooter, damage, weapon): - # make player die - #await self.server.broadcast_gamedata(MSG_PLAYER_DIE(player, 1)) - pass - - async def give_stuff(self, player): - # remove current weapon - #await self.remove_current_weapon(player) - - # add sniper - await self.spawn_sniper(player) - - async def spawn_sniper(self, player): - await self.server.broadcast_gamedata(MSG_DROP_WEAPON(player, self.server.new_oid(), 6, 255).to_packet()) - - async def remove_current_weapon(self, player): - await self.server.broadcast_gamedata(MSG_SWITCH_WEAPON(player, 0xff).to_packet()) - - async def random_teleport(self, player): - # random teleport - maxdist = 2000 - x = randint(-(maxdist/2), maxdist/2) - y = randint(-(maxdist/2), maxdist/2) - z = randint(-(maxdist/2), maxdist/2) - await self.server.broadcast_gamedata(MSG_PLAYER_TELEPORT(player, x, y, z, 0).to_packet()) - - -def setup(server): - plugin = Instagib(server) - server.add_plugin(plugin) diff --git a/sendenum.py b/sendenum.py deleted file mode 100644 index d348a9e..0000000 --- a/sendenum.py +++ /dev/null @@ -1,9 +0,0 @@ -from dpnet.EnumQuery import EnumQuery -from dpnet.netclient import Netclient - -client = Netclient("163.158.182.243", 19711) -eq = EnumQuery() -eq.ApplicationGUID = b"\x10\x5e\x62\xa7\x96\x1a\xd2\x11\x9a\xfc\x00\x60\x08\x45\xe5\x71" -client.send(eq.to_packet()) -data = client.receive() -print("") - logger.debug("Sending game payload %s", cmd) - for player in self.players: - if player.name == "[Server]": - continue - await player.session.send_gamedata(bytes.fromhex(cmd), acknow=False) - except: - traceback.print_exc() - - async def broadcast_gamedata(self, payload, **kwargs): - for player in self.players: - if player.name == "[Server]": - continue - await player.session.send_gamedata(payload, **kwargs) - - async def broadcast_gamedata_except(self, player, payload, **kwargs): - for pplayer in self.players: - if pplayer.name == "[Server]" or pplayer == player: - continue - await pplayer.session.send_gamedata(payload, **kwargs) - - async def broadcast_message_except(self, player, text, color=ChatColor.Yellow, type=ChatType.All): - for pplayer in self.players: - if pplayer.name == "[Server]" or pplayer == player: - continue - await pplayer.send_message(text, color=color, type=type) - - async def new_object(self, model): - oid = self._nextid - p = Packet() - p.putByte(0x05) # opcode - p.putByte(0) - p.putShort(self._nextid) - p.putByte(0x00) - p.putULong(model) - p.putByte(0x00) - self._nextid += 1 - await self.broadcast_gamedata(p.getvalue()) - return oid - - async def spawn(self, player, model): - plix = self.get_player_index(player) - p = Packet() - p.putByte(0x05) # opcode - p.putByte(plix) - p.putShort(self._nextid) - p.putByte(0x00) - p.putULong(model) - p.putByte(0x00) - - await self.broadcast_gamedata(p.getvalue(), acknow=False) - #await self.broadcast_gamedata(bytes.fromhex("05" + plix + struct.pack(" death, 3 -> little move - # p.putULong(model) # model - # p.putFloat(player.x) # x - # p.putFloat(player.y) # y - # p.putFloat(player.z) # z - # p.putULong(0x00) # unknown - # p.putULong(0x00) # unknown - # p.putULong(0x00) # unknown - # p.putULong(0x00) # unknown - # p.putULong(player.o + 30) # orientation - # p.putULong(0x00) # unknown - - p = Packet() - p.putByte(0x0a) # opcode - p.putByte(0x32) # length - p.putByte(0x00) # unknown - p.putByte(0x00) # unknown - p.putByte(0x00) # unknown - p.putByte(plid) # player index - p.putShort(player.oid) # object id - p.putByte(0x00) # unknown - p.putByte(0x01) # 1 -> stand still, 4 -> death, 3 -> little move - p.putULong(model) # model - p.putFloat(0x00) # x - p.putFloat(player.y) # y - p.putFloat(player.z) # z - p.putULong(0x00) # unknown - p.putULong(0x00) # unknown - p.putULong(0x00) # unknown - p.putULong(0x00) # unknown - p.putULong((player.o + 30) % 360) # orientation - p.putULong(0x00) # unknown - - p.putByte(0x0a) # opcode - p.putByte(0x12) # length - p.putByte(0x00) # unknown - p.putByte(0x00) # unknown - p.putByte(0x00) # unknown - p.putByte(plid) # player index - p.putShort(player.oid) # object id - p.putByte(0x00) # unknown - p.putByte(0x00) # 1 -> stand still, 4 -> death, 3 -> little move - p.putULong(model) # model - p.putULong(0x00) - p.putByte(0x00) - p.putByte(0x00) - - await self.broadcast_gamedata(p.getvalue(), acknow=False) - #await self.broadcast_gamedata(bytes.fromhex("0a32000000" + plix + struct.pack("