diff --git a/dpnet/netserver.py b/dpnet/netserver.py index 8cc8f51..173e5b9 100644 --- a/dpnet/netserver.py +++ b/dpnet/netserver.py @@ -123,13 +123,12 @@ class Netserver(asyncio.DatagramProtocol): 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.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))) er.ApplicationReservedData = appdata.getvalue() - logger.debug("Current map: %s", self.server.currentmap.mapname) + 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: @@ -220,7 +219,8 @@ class Netserver(asyncio.DatagramProtocol): sack_sent = True # release lock for new packet to be sent - session.lock.release() + 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 @@ -274,10 +274,13 @@ class Netserver(asyncio.DatagramProtocol): if dframe.Command & DFrame.PACKET_COMMAND_POLL: #logger.debug("Sending SACK") - #session.send_cframe_sack() + session.send_cframe_sack() pass - session.next_expected_seq += 1 + 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: @@ -336,11 +339,12 @@ class Netserver(asyncio.DatagramProtocol): 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.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))) d.ApplicationReservedData = appdata.getvalue() session.send(d) + logger.debug("%s:%s > %s (GAMEDATA)", session.ip, session.port, appdata.getvalue().hex()) player.phase = PlayerPhases.DN_SEND_CONNECT_INFO elif payload[0] == 0xc3: @@ -371,27 +375,6 @@ class Netserver(asyncio.DatagramProtocol): 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: @@ -410,14 +393,34 @@ class Netserver(asyncio.DatagramProtocol): out.putULong(playerid) out.putByte(status) await player.session.send_gamedata(out.getvalue(), acknow=False) - elif payload[0] == 0x2c: + + elif payload[0] == 0x2c: # CMSG_CHANGE_TEAM: team (byte), player id (int), unknown (byte) 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("= 0x5c: - await player.session.send_gamedata(bytes.fromhex( - "04" + struct.pack(" + # \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 index ff48d53..bcd0a85 100644 --- a/giants/player.py +++ b/giants/player.py @@ -1,5 +1,7 @@ from .entity import Entity import random +import struct +from . import ChatColor, ChatType class PlayerPhases: @@ -16,7 +18,20 @@ class Player(Entity): super().__init__() self.name = name self.session = session - self.team = 1 + self.team = 4 self.score = 0 self.id = random.getrandbits(32) self.phase = PlayerPhases.NONE + self.ping = 1 + + async def change_team(self, newteam): + self.team = newteam + await self.session.send_gamedata(b"\x10"+struct.pack(" 1 and command[0] == "team": + newteam = command[1].replace("\x00", "") + print("Changing team of %s to %s" % (player.name, newteam)) + await self.server.broadcast_message("%s switched to team %s" % (player.name, newteam)) + await player.change_team(int(newteam)) + + if len(command) > 1 and command[0] == "ping": + newping = command[1].replace("\x00", "") + 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 player.session.send_gamedata(bytes.fromhex("0b1a0000000002070000a5b0d4c35d9714c450abef354a68fb410914000000020700000402000000")+struct.pack("") + 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() + if __name__ == '__main__': - server = Server(name="giantsd", maxplayers=20, register=False) + server = Server(name="giantsd", maxplayers=20, register=False) #, map=Map("Three Way Island - Canyons.gck")) server.load_plugins() loop = asyncio.get_event_loop() listen = loop.create_datagram_endpoint(lambda: Netserver(server), local_addr=(server.listen_ip, server.listen_port)) transport, protocol = loop.run_until_complete(listen) + loop.create_task(server.ask_command()) try: loop.run_forever() except KeyboardInterrupt: