diff --git a/dpnet/gamepackets.py b/dpnet/gamepackets.py new file mode 100644 index 0000000..bffb180 --- /dev/null +++ b/dpnet/gamepackets.py @@ -0,0 +1,190 @@ +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_BULLET_EXPLOSION(): + def __init__(self, player, projectile, x, y, z): + self.player = player + self.projectile = projectile + self.x = x + self.y = y + self.z = z + + def to_packet(self): + p = Packet() + p.putByte(0x09) # opcode + p.putULong(0x1a) + p.putByte(self.player.get_index()) + p.putShort(0x0631) + p.putByte(0x00) + p.putByte(0x03) + 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() \ No newline at end of file diff --git a/dpnet/netserver.py b/dpnet/netserver.py index bae0bb5..75930db 100644 --- a/dpnet/netserver.py +++ b/dpnet/netserver.py @@ -20,6 +20,7 @@ from giants import APPLICATION_GUID import random from .DN_MSG_INTERNAL_SEND_CONNECT_INFO import DN_MSG_INTERNAl_SEND_CONNECT_INFO import asyncio +from dpnet.gamepackets import * logger = setup_logger(__name__) @@ -317,6 +318,10 @@ class Netserver(asyncio.DatagramProtocol): #logger.debug("OPCODE: %s VALUES: %s", struct.pack(" objid = "75" plix = "01" @@ -520,6 +526,8 @@ class Netserver(asyncio.DatagramProtocol): await player.session.send_gamedata(bytes.fromhex("090f000000015500000a02000000ff090f000000015500000a0200000001090f000000015500000a020000000300"), acknow=False) await player.session.send_gamedata(bytes.fromhex("2b0000000066fe954400"), acknow=False) + await self.server.broadcast_event("on_player_spawn", player) + player.phase = PlayerPhases.INGAME elif payload[0] == 0x0a and payload[1] == 0x32: @@ -553,10 +561,6 @@ class Netserver(asyncio.DatagramProtocol): player.z = playerz player.oid = objid player.o = orientation - - #logger.info("%s is now at coords (%s,%s,%s)", player.name, player.x, player.y, player.z) - if player.opts["debug"]: - await player.send_message("%s is now at coords (%s,%s,%s, %s). Model: %s" % (player.name, player.x, player.y, player.z, player.o, model)) await self.server.broadcast_gamedata_except(player, payload) elif payload[0] == 0x3a: @@ -638,29 +642,7 @@ class Netserver(asyncio.DatagramProtocol): if not direction == 0: if player.opts["debug"]: await player.send_message("ObjID %s went: %s, o: %s" % (objid, direction, orientation)) - await self.server.broadcast_gamedata_except(player, payload) - elif payload[0] == 0x0a and payload[1] == 0x12: - player = self.get_player(session) - if not player: - logger.debug("Fuck that no player wtf man") - return - p = Packet(payload) - opcode = p.getByte() - length = p.getByte() # length? - unknown1 = p.getByte() - unknown2 = p.getByte() - unknown3 = p.getByte() - playerindex = p.getByte() - objid = p.getShort() - unknown5 = p.getByte() - unknown6 = p.getByte() - model = p.getULong() - direction = p.getShort() - orientation = p.getShort() - - if not direction == 0: - if player.opts["debug"]: - await player.send_message("ObjID %s went: %s, o: %s" % (objid, direction, orientation)) + # TODO: Replace with MSG_MOVE_PLAYER await self.server.broadcast_gamedata_except(player, payload) elif payload[0] == 0x05: # SPAWN OBJECT @@ -678,6 +660,56 @@ class Netserver(asyncio.DatagramProtocol): player.oid = oid await self.server.broadcast_gamedata_except(player, payload) + await player.send_message("SPAWN: %s" % payload.hex()) + elif payload[0] == 0x09 and payload[1] == 0x23: + player = self.get_player(session) + if not player: + logger.debug("Fuck that no player wtf man") + return + await player.send_message("PROJECTILE SHOOT: %s" % payload.hex()) + await self.server.broadcast_gamedata_except(player, payload) + await self.server.broadcast_event("on_player_shoot", player) + elif payload[0] == 0x09 and payload[1] == 0x1a: + player = self.get_player(session) + if not player: + logger.debug("Fuck that no player wtf man") + return + await player.send_message("PROJECTILE EXPLOSION: %s" % payload.hex()) + #await self.server.broadcast_gamedata_except(player, payload) + x = struct.unpack(" 1 and command[0] == "team": - newteam = command[1].replace("\x00", "") + 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)) + await player.change_team(int(newteam), respawn=respawn) if len(command) > 1 and command[0] == "ping": - newping = command[1].replace("\x00", "") + 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)) @@ -56,7 +72,8 @@ class Commands: if command[0] == "die" and len(command) > 1: diemethod = int(command[1]) await player.send_message("Death by id: %s" % diemethod) - await player.session.send_gamedata(bytes.fromhex("0b1a0000000002070000a5b0d4c35d9714c450abef354a68fb410914000000020700000402000000")+struct.pack(" 1: await self.server.broadcast_message("Spawning " + command[1] + "") @@ -78,6 +95,72 @@ class Commands: 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._nextid, weap, 255).to_packet()) + self.server._nextid += 1 + + 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()) + def setup(server): plugin = Commands(server) diff --git a/plugins/instagib.py b/plugins/instagib.py new file mode 100644 index 0000000..af54f27 --- /dev/null +++ b/plugins/instagib.py @@ -0,0 +1,59 @@ +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): + 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)) + + 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._nextid, 6, 255).to_packet()) + self.server._nextid += 1 + + 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 = 300 + 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).to_packet()) + + +def setup(server): + plugin = Instagib(server) + server.add_plugin(plugin) diff --git a/server.py b/server.py index 7730762..065a477 100644 --- a/server.py +++ b/server.py @@ -12,6 +12,7 @@ import traceback import asyncio from aioconsole import ainput import struct +from curses import wrapper logger = setup_logger(__name__) @@ -152,6 +153,19 @@ class Server: 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() @@ -264,13 +278,13 @@ class Server: return self.players[playerindex] if __name__ == '__main__': - server = Server(name="giantsd", maxplayers=20, register=False, teams=Teams.MvM) #, map=Map("Three Way Island - Canyons.gck")) + server = Server(name="giantsd", maxplayers=20, register=False, teams=Teams.MvM, map=Map("Three Way Island - Canyons.gck")) #, 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()) + loop.create_task(server.ask_command()) try: loop.run_forever() except KeyboardInterrupt: diff --git a/utils/logger.py b/utils/logger.py index 2fe2b18..747574a 100644 --- a/utils/logger.py +++ b/utils/logger.py @@ -6,7 +6,7 @@ def setup_logger(name): #_fh.setLevel("INFO") _ch = logging.StreamHandler() _ch.setLevel("DEBUG") - _formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + _formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") _ch.setFormatter(_formatter) #_fh.setFormatter(_formatter) logger = logging.getLogger(name)