Added more commands

This commit is contained in:
Amazed 2019-02-19 01:01:31 +01:00
parent 556c9dcc69
commit d962495e48
7 changed files with 207 additions and 170 deletions

View File

@ -123,13 +123,12 @@ class Netserver(asyncio.DatagramProtocol):
appdata.putShort(self.server.points_per_kill) appdata.putShort(self.server.points_per_kill)
appdata.write(b'\x00\x00') # original: 0000 - does not seem to affect client appdata.write(b'\x00\x00') # original: 0000 - does not seem to affect client
appdata.putShort(self.server.detente_time) appdata.putShort(self.server.detente_time)
appdata.write( 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
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(self.server.currentmap.mapname.encode("ascii"))
appdata.write(b'\x00' * (32 - len(self.server.currentmap.mapname))) appdata.write(b'\x00' * (32 - len(self.server.currentmap.mapname)))
er.ApplicationReservedData = appdata.getvalue() 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)) er.ApplicationReservedData += b'\x00' * (32 - len(self.server.currentmap.mapname))
self.send_packet(addr, er.to_packet()) self.send_packet(addr, er.to_packet())
except Exception: except Exception:
@ -220,7 +219,8 @@ class Netserver(asyncio.DatagramProtocol):
sack_sent = True sack_sent = True
# release lock for new packet to be sent # 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 # 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 # 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: if dframe.Command & DFrame.PACKET_COMMAND_POLL:
#logger.debug("Sending SACK") #logger.debug("Sending SACK")
#session.send_cframe_sack() session.send_cframe_sack()
pass 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: if dframe.Payload:
await self.handle_game_packet(session, dframe.Payload) await self.handle_game_packet(session, dframe.Payload)
else: else:
@ -336,11 +339,12 @@ class Netserver(asyncio.DatagramProtocol):
appdata.putShort(self.server.points_per_kill) appdata.putShort(self.server.points_per_kill)
appdata.write(b'\x00\x00') # original: 0000 - does not seem to affect client appdata.write(b'\x00\x00') # original: 0000 - does not seem to affect client
appdata.putShort(self.server.detente_time) 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(self.server.currentmap.mapname.encode("ascii"))
appdata.write(b'\x00' * (32 - len(self.server.currentmap.mapname))) appdata.write(b'\x00' * (32 - len(self.server.currentmap.mapname)))
d.ApplicationReservedData = appdata.getvalue() d.ApplicationReservedData = appdata.getvalue()
session.send(d) session.send(d)
logger.debug("%s:%s > %s (GAMEDATA)", session.ip, session.port, appdata.getvalue().hex())
player.phase = PlayerPhases.DN_SEND_CONNECT_INFO player.phase = PlayerPhases.DN_SEND_CONNECT_INFO
elif payload[0] == 0xc3: 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(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\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 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: elif payload[0] == 0x0f:
player = self.get_player(session) player = self.get_player(session)
if not player: if not player:
@ -410,14 +393,34 @@ class Netserver(asyncio.DatagramProtocol):
out.putULong(playerid) out.putULong(playerid)
out.putByte(status) out.putByte(status)
await player.session.send_gamedata(out.getvalue(), acknow=False) 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) player = self.get_player(session)
if not player: if not player:
logger.debug("Fuck that no player wtf man") logger.debug("Fuck that no player wtf man")
return return
# assign team? p = Packet(payload)
await player.session.send_gamedata(b"\x10"+struct.pack("<B", player.team)+struct.pack("<L", player.id)+b"\x00\x00", acknow=False) opcode = p.getByte()
team = p.getByte()
playerid = p.getULong()
unknown = p.getByte()
await player.change_team(team-128)
await self.server.broadcast_event("on_player_change_team", player, player.team)
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: elif payload[0] == 0x2a:
player = self.get_player(session) player = self.get_player(session)
if not player: if not player:
@ -435,10 +438,12 @@ class Netserver(asyncio.DatagramProtocol):
logger.debug("Fuck that no player wtf man") logger.debug("Fuck that no player wtf man")
return return
playerping = 1 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"\x2f\x02\x00\x00" + struct.pack("<H", playerping) + b"\x00", acknow=False) # acknow=True
for i in range(0x06): for i in range(0x06):
ack = (i % 2 == 0) 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"\x04" + struct.pack("<B", i) + b"\x00\x00\x00\x00" + struct.pack("<B", i+0x07) + b"\x00\x00\x00",acknow=ack)
# spawn position is sent by client wtf
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"\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"\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"\x00"*21, acknow=True)
@ -448,122 +453,34 @@ class Netserver(asyncio.DatagramProtocol):
await player.session.send_gamedata(b"\x3e\x00\x00\x00\x00\x00", acknow=True) 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"\x3f\x00\x00", acknow=False)
await player.session.send_gamedata(b"\x0e\x00", acknow=True) 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) 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] == 0x0a and payload[1] == 0x32:
player = self.get_player(session)
if not player:
logger.debug("Fuck that no player wtf man")
return
p = Packet(payload)
opcode = p.getShort()
unknown1 = p.getULong()
unknown2 = p.getULong()
unknown3 = p.getULong()
playerx = p.getFloat()
playery = p.getFloat()
playerz = p.getFloat()
unknown4 = p.getULong()
unknown5 = p.getULong()
unknown6 = p.getULong()
unknown7 = p.getULong()
unknown8 = p.getULong()
unknown9 = p.getULong()
player.x = playerx
player.y = playery
player.z = playerz
logger.info("%s is now at coords (%s,%s,%s)", player.name, player.x, player.y, player.z)
return await self.server.broadcast_message("%s is now at coords (%s,%s,%s)" % (player.name, player.x, player.y, player.z))
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): def send_packet(self, addr, packet):

View File

@ -59,4 +59,21 @@ class GameTypes:
GTypeStone = 0x08 GTypeStone = 0x08
GTypeWood = 0x09 GTypeWood = 0x09
Crash = 0x0a Crash = 0x0a
GTypeNull = 0x0c GTypeNull = 0x0c
class ChatColor:
Black = 0x00
Cyan = 0x01 # or 0x06
Yellow = 0x02
LightBlue = 0x03
Orange = 0x04
DarkBlue = 0x05
White = 0x07
Blue = 0x0c
class ChatType:
All = 0x00
AllFromPlayer = 0xc0
TeamFromPlayer = 0xf0

View File

@ -19,6 +19,18 @@ class Map:
self.checksum = Map.checksum(mappath) self.checksum = Map.checksum(mappath)
@staticmethod @staticmethod
def checksum(mapname): def checksum(mappath):
# TODO # TODO
return 1 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"
# \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: testv1
# \x48\x52\x33\x23: testv2
return b"\x00\x00\x00\x00"

View File

@ -1,5 +1,7 @@
from .entity import Entity from .entity import Entity
import random import random
import struct
from . import ChatColor, ChatType
class PlayerPhases: class PlayerPhases:
@ -16,7 +18,20 @@ class Player(Entity):
super().__init__() super().__init__()
self.name = name self.name = name
self.session = session self.session = session
self.team = 1 self.team = 4
self.score = 0 self.score = 0
self.id = random.getrandbits(32) self.id = random.getrandbits(32)
self.phase = PlayerPhases.NONE 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("<B", self.team)+struct.pack("<L", self.id)+b"\x00\x00", acknow=False)
async def send_ping(self, ping):
await self.session.send_gamedata(b"\x2f\x02\x00\x00" + struct.pack("<H", ping) + b"\x00", acknow=False)
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("<B", playeri)+ struct.pack("<B", options) + message.encode("utf8") + b"\x00\x00", acknow=False)

64
plugins/commands.py Normal file
View File

@ -0,0 +1,64 @@
from giants import ChatColor
import asyncio
import struct
class Commands:
def __init__(self, server):
self.server = server
async def on_player_chat(self, player, type, team, message):
await self.server.broadcast_message("%s (%s,%s): %s" % (player.name, type, team, message), color=ChatColor.Yellow)
print(message)
command = message.split(" ")
if len(command) > 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("<B", i)+ struct.pack("<B", j) + message.encode("utf8") + b"\x00\x00", acknow=False)
await asyncio.sleep(0.1) # sleep between each value to see what value makes the client crash
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("<L",diemethod)+bytes.fromhex("0000"))
def setup(server):
plugin = Commands(server)
server.add_plugin(plugin)

View File

@ -1,6 +1,4 @@
import random import random
import asyncio
import struct
class Greetings: class Greetings:
def __init__(self, server): def __init__(self, server):
@ -9,20 +7,14 @@ class Greetings:
async def on_player_join(self, player): async def on_player_join(self, player):
await self.server.broadcast_message(random.choice(self.messages) % player.name) await self.server.broadcast_message(random.choice(self.messages) % player.name)
#await Greetings.send_ping(player)
@staticmethod
async def send_ping(player):
while 1:
for ping in range(0, 999):
await player.session.send_gamedata(b"\x2f\x02\x00\x00" + struct.pack("<H", ping) + b"\x00",acknow=True) # acknow=True
for ping in range(999, 0, -1):
await player.session.send_gamedata(b"\x2f\x02\x00\x00" + struct.pack("<H", ping) + b"\x00",acknow=True) # acknow=True
async def on_map_change(self, newmap): async def on_map_change(self, newmap):
await self.server.broadcast_message("You are now playing on "+newmap.mapname) 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))
def setup(server): def setup(server):
plugin = Greetings(server) plugin = Greetings(server)
server.add_plugin(plugin) server.add_plugin(plugin)

View File

@ -5,10 +5,11 @@ from dpnet.session import Session
import socket import socket
import importlib import importlib
import os import os
from giants import Teams, GameTypes from giants import Teams, GameTypes, ChatColor, ChatType
from utils.logger import setup_logger from utils.logger import setup_logger
import traceback import traceback
import asyncio import asyncio
from aioconsole import ainput
logger = setup_logger(__name__) logger = setup_logger(__name__)
@ -20,7 +21,7 @@ class Server:
self.register_with_ms = kwargs.get("register", False) self.register_with_ms = kwargs.get("register", False)
self.teams = kwargs.get("teams", Teams.MvM) self.teams = kwargs.get("teams", Teams.MvM)
self.game_type = kwargs.get("gametype", GameTypes.TeamDeathmatchWithFullBase) self.game_type = kwargs.get("gametype", GameTypes.TeamDeathmatchWithFullBase)
self.currentmap = kwargs.get("map", Map("Three Way Island - Canyons.gck")) self.currentmap = kwargs.get("map", Map("test.gck"))
self.maxplayers = kwargs.get("maxplayers", 20) self.maxplayers = kwargs.get("maxplayers", 20)
self.name = kwargs.get("name", "Default Server Name") self.name = kwargs.get("name", "Default Server Name")
@ -29,6 +30,11 @@ class Server:
fake_session.port = 3333 fake_session.port = 3333
self.players = [Player("[Server]", fake_session)] self.players = [Player("[Server]", fake_session)]
fake_player = Session(socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
fake_player.ip = "127.0.0.1"
fake_player.port = 3334
self.players.append(Player("Bot 1", fake_player))
self.accept_new_players = True self.accept_new_players = True
self.version = 1.497 self.version = 1.497
self.points_per_kill = 1 self.points_per_kill = 1
@ -46,7 +52,7 @@ class Server:
async def add_player(self, player): async def add_player(self, player):
self.tempplayers.remove(player) self.tempplayers.remove(player)
self.players.append(player) self.players.append(player)
await self._broadcast_event("on_player_join", player) await self.broadcast_event("on_player_join", player)
# todo: remove # todo: remove
def create_temp_player(self, player): def create_temp_player(self, player):
@ -54,7 +60,7 @@ class Server:
async def remove_player(self, player): async def remove_player(self, player):
self.players.remove(player) self.players.remove(player)
await self._broadcast_event("on_player_left", player) await self.broadcast_event("on_player_left", player)
def add_plugin(self, plugin): def add_plugin(self, plugin):
self._plugins.append(plugin) self._plugins.append(plugin)
@ -62,11 +68,11 @@ class Server:
async def change_map(self, mappath): async def change_map(self, mappath):
try: try:
self.currentmap = Map(mappath) self.currentmap = Map(mappath)
await self._broadcast_event("on_map_change", self.currentmap) await self.broadcast_event("on_map_change", self.currentmap)
except Exception: except Exception:
logger.error("Could not change map") logger.error("Could not change map")
async def _broadcast_event(self, event, *args): async def broadcast_event(self, event, *args):
logger.debug("Broadcasting event "+event) logger.debug("Broadcasting event "+event)
for plugin in self._plugins: for plugin in self._plugins:
if hasattr(plugin, event): if hasattr(plugin, event):
@ -97,19 +103,33 @@ class Server:
logger.warning("Could not load plugin "+plugin) logger.warning("Could not load plugin "+plugin)
traceback.print_exc() traceback.print_exc()
async def broadcast_message(self, text): async def broadcast_message(self, text, color=ChatColor.Orange, type=ChatType.All):
for player in self.players: for player in self.players:
if player.name == "[Server]": if player.name == "[Server]":
continue continue
await player.session.send_gamedata(b'\x35\x80\x81'+text.encode("ascii")+b'\x00\x00', acknow=False) await player.send_message(text, color=color, type=type)
async def ask_command(self):
while True:
try:
cmd = await ainput(">")
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__': 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() server.load_plugins()
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
listen = loop.create_datagram_endpoint(lambda: Netserver(server), local_addr=(server.listen_ip, server.listen_port)) listen = loop.create_datagram_endpoint(lambda: Netserver(server), local_addr=(server.listen_ip, server.listen_port))
transport, protocol = loop.run_until_complete(listen) transport, protocol = loop.run_until_complete(listen)
loop.create_task(server.ask_command())
try: try:
loop.run_forever() loop.run_forever()
except KeyboardInterrupt: except KeyboardInterrupt: