Many things, I guess

This commit is contained in:
Amazed 2019-02-28 04:01:03 +01:00
parent d962495e48
commit b303320d69
6 changed files with 141 additions and 32 deletions

View File

@ -63,8 +63,7 @@ class CFrame:
packet.putByte(self.Retry)
packet.putByte(self.NSeq)
packet.putByte(self.NRecv)
packet.putByte(0) # padding
packet.putByte(0) # padding
packet.putShort(0) # padding
packet.putULong(self.Timestamp)
else:
packet.putByte(self.MsgID)

View File

@ -15,6 +15,7 @@ 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
import asyncio
@ -177,7 +178,7 @@ class Netserver(asyncio.DatagramProtocol):
for b1, b2 in zip(b1, b2):
result.append(b1 ^ b2)
return result
player.id = struct.unpack(">L", bxor(struct.pack("<L", len(self.server.players)), self.guid[0:4]))[0]
#player.id = struct.unpack(">L", bxor(struct.pack("<L", len(self.server.players)), self.guid[0:4]))[0]
logger.debug("Value for connected player: %s", player.id)
player.phase = PlayerPhases.CFRAME_CONNECT
self.server.create_temp_player(player)
@ -243,31 +244,42 @@ class Netserver(asyncio.DatagramProtocol):
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:
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(self.addrs)
logger.debug("%s:%s > %s (DFRAME)", addr[0], addr[1], data.getvalue().hex())
return
if not dframe.Seq == session.next_expected_seq:
logger.error("%s unexpected SEQ. Got %s, expected %s", addr, dframe.Seq, session.next_expected_seq)
#return
if dframe.Control & DFrame.PACKET_CONTROL_END_STREAM:
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")
return
# disconnect
session = Session(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)
session.send_cframe_sack()
# TODO: broadcast session has disconnected
self.addrs.remove(session)
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()
@ -354,8 +366,6 @@ class Netserver(asyncio.DatagramProtocol):
player.phase = PlayerPhases.DN_ACK_CONNECT_INFO
await self.server.add_player(player)
#player.session.send_cframe_sack()
await player.session.send_gamedata(b'\x3c'+struct.pack("<L", player.id)+b"\x00", acknow=True)
p1 = b'\x01' + struct.pack("<B", len(self.server.players))
@ -373,8 +383,11 @@ class Netserver(asyncio.DatagramProtocol):
p1 += b'\x00\x00'
await player.session.send_gamedata(p1, acknow=False)
await player.session.send_gamedata(b'\x3d\x00\x5b\x53\x65\x72\x76\x65\x72\x5d'+b"\x00"*25, acknow=True) # [SERVER]
await player.session.send_gamedata(b'\x3d\x01'+player.name.encode("ascii")+b"\x00"*(33-len(player.name.encode("ascii"))), acknow=True) # playername
#await player.session.send_gamedata(b'\x3d\x00\x5b\x53\x65\x72\x76\x65\x72\x5d'+b"\x00"*25, acknow=True) # [SERVER]
plid=0
for pplayer in self.server.players:
await player.session.send_gamedata(b'\x3d'+struct.pack("<B", plid)+pplayer.name.encode("ascii")+b"\x00"*(33-len(pplayer.name.encode("ascii"))), acknow=True) # playername
plid+=1
elif payload[0] == 0x0f:
player = self.get_player(session)
if not player:
@ -383,15 +396,14 @@ class Netserver(asyncio.DatagramProtocol):
inc = Packet(payload)
opcode = inc.getByte()
playerid = inc.getULong()
status = inc.getByte()
if status == 7:
status = 8
status = inc.getULong()
padding = inc.getShort()
out = Packet()
out.putByte(opcode)
out.putULong(playerid)
out.putByte(status)
out.putULong(status)
out.putShort(padding)
await player.session.send_gamedata(out.getvalue(), acknow=False)
elif payload[0] == 0x2c: # CMSG_CHANGE_TEAM: team (byte), player id (int), unknown (byte)
@ -406,7 +418,7 @@ class Netserver(asyncio.DatagramProtocol):
playerid = p.getULong()
unknown = p.getByte()
await player.change_team(team-128)
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)
@ -443,18 +455,71 @@ class Netserver(asyncio.DatagramProtocol):
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)
# spawn position is sent by client wtf
# needed to avoid crash after Loading textures
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)
# has something to do with the base build
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)
# useless?
await player.session.send_gamedata(b"\x39"+b"\x00"*21, acknow=True)
# useless? can be game status
await player.session.send_gamedata(b"\x39"+b"\x01"*4+b"\x00"*17, acknow=False)
# useless? can be game status
await player.session.send_gamedata(b"\x2e"+b"\x00"*9, acknow=True)
# useless? can be game status
await player.session.send_gamedata(b"\x3b\x00\x04\x00\x00\x00\x04\x00\x00\x00", acknow=False)
# useless?
await player.session.send_gamedata(b"\x3e\x00\x00\x00\x00\x00", acknow=True)
# useless?
await player.session.send_gamedata(b"\x3f\x00\x00", acknow=False)
# stuck in awaiting snapshot if not sent (could be the packet to go ingame?)
await player.session.send_gamedata(b"\x0e\x00", acknow=True)
# change team packet
await player.session.send_gamedata(b"\x10" + struct.pack("<B", player.team) + struct.pack("<L", player.id) + b"\x00\x00", acknow=False)
# spawn server as mecc
await player.session.send_gamedata(bytes.fromhex("05007300000200000000"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a320000000073000001020000000000000000000000000000000000000000000000000000000000000000000000000000000a120000000073000003020000000000000000"), acknow=False)
# spawn Bot 1 as kab
#await player.session.send_gamedata(bytes.fromhex("05017400000100000000"), acknow=False)
#await player.session.send_gamedata(bytes.fromhex("0a320000000174000001010000000000000000000000000000000000000000000000000000000000000000000000000000000a120000000174000003020000000000000000"), acknow=False)
# spawn Bot 2 as reap
await player.session.send_gamedata(bytes.fromhex("05027500000300000000"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("0a320000000275000001030000000000000000000000000000000000000000000000000000000000000000000000000000000a120000000275000003020000000000000000"), acknow=False)
# spawn Bot 3 as <id>
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)
#for i in range(76, 200):
# await spawn(struct.pack("<B", i).hex(), 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("<L", player.id)+"0000000000"), acknow=False)
#await player.session.send_gamedata(bytes.fromhex("0f1e123456780000000000"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("090f000000015500000a02000000ff090f000000015500000a0200000001090f000000015500000a020000000300"), acknow=False)
await player.session.send_gamedata(bytes.fromhex("2b0000000066fe954400"), acknow=False)
player.phase = PlayerPhases.INGAME
elif payload[0] == 0x0a and payload[1] == 0x32:
player = self.get_player(session)
if not player:
@ -479,8 +544,18 @@ class Netserver(asyncio.DatagramProtocol):
player.y = playery
player.z = playerz
logger.info("%s is now at coords (%s,%s,%s)", player.name, player.x, player.y, player.z)
await self.server.broadcast_message("%s is now at coords (%s,%s,%s)" % (player.name, player.x, player.y, player.z))
#logger.info("%s is now at coords (%s,%s,%s)", player.name, player.x, player.y, player.z)
#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"", acknow=False)
elif payload[0] == 0x3a:
# CLIENT EXITED
player = self.get_player(session)
if not player:
logger.debug("Fuck that no player wtf man")
return
await self.server.broadcast_event("on_player_left", player)
await self.server.remove_player(player)
def send_packet(self, addr, packet):

View File

@ -27,6 +27,10 @@ class Map:
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"
# \x00\x00\x00\x00: [None]
# \x00\x00\x00\x01: <custom map>
# \x9c\x53\xf4\xdd: Three Way Island - Canyons

View File

@ -2,6 +2,7 @@ from .entity import Entity
import random
import struct
from . import ChatColor, ChatType
from dpnet.DFrame import DFrame
class PlayerPhases:
@ -11,6 +12,7 @@ class PlayerPhases:
DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO_EX = 3
DN_SEND_CONNECT_INFO = 4
DN_ACK_CONNECT_INFO = 5
INGAME = 6
class Player(Entity):
@ -18,15 +20,16 @@ class Player(Entity):
super().__init__()
self.name = name
self.session = session
self.team = 4
self.team = 2
self.score = 0
self.id = random.getrandbits(32)
self.id = random.getrandbits(16)
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)
await self.session.send_gamedata(b"\x10"+struct.pack("<B", self.team)+struct.pack("<L", self.id)+b"\x01\x00", acknow=False)
await self.session.send_gamedata(b"\x10"+struct.pack("<B", self.team)+struct.pack("<L", self.id)+b"\x01\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)
@ -34,4 +37,13 @@ class Player(Entity):
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)
await self.session.send_gamedata(b"\x35" + struct.pack("<B", playeri)+ struct.pack("<B", options) + message.encode("utf8") + b"\x00\x00", acknow=False)
async def kick(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_END_STREAM
dframe.Seq = self.session.next_send
dframe.NRcv = self.session.next_expected_seq
dframe.SessID = self.session.SessID
self.session.send(dframe)

View File

@ -14,6 +14,9 @@ class Greetings:
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("%s has left the game" % player.name)
def setup(server):
plugin = Greetings(server)

View File

@ -21,7 +21,7 @@ class Server:
self.register_with_ms = kwargs.get("register", False)
self.teams = kwargs.get("teams", Teams.MvM)
self.game_type = kwargs.get("gametype", GameTypes.TeamDeathmatchWithFullBase)
self.currentmap = kwargs.get("map", Map("test.gck"))
self.currentmap = kwargs.get("map", Map("test3.gck"))
self.maxplayers = kwargs.get("maxplayers", 20)
self.name = kwargs.get("name", "Default Server Name")
@ -35,6 +35,16 @@ class Server:
fake_player.port = 3334
self.players.append(Player("Bot 1", fake_player))
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 2", fake_player))
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 3", fake_player))
self.accept_new_players = True
self.version = 1.497
self.points_per_kill = 1
@ -121,9 +131,15 @@ class Server:
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)
if __name__ == '__main__':
server = Server(name="giantsd", maxplayers=20, register=False) #, 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"))
server.load_plugins()
loop = asyncio.get_event_loop()