forked from hipstercat/giantsd
Clean
This commit is contained in:
parent
14cc33b3d8
commit
c9d424b7f7
@ -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()
|
|
@ -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()
|
|
@ -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)
|
|
@ -1,26 +1,13 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from .packet import Packet
|
from .packet import Packet
|
||||||
from .EnumQuery import EnumQuery
|
from .EnumQuery import EnumQuery
|
||||||
from .EnumResponse import EnumResponse
|
from .EnumResponse import EnumResponse
|
||||||
from .CFrame import CFrame
|
from .CFrame import CFrame
|
||||||
from .DFrame import DFrame
|
from .DFrame import DFrame
|
||||||
from giants.masterserver import MasterServer
|
|
||||||
from .session import Session
|
|
||||||
import socket
|
|
||||||
import threading
|
|
||||||
import traceback
|
import traceback
|
||||||
import uuid
|
import uuid
|
||||||
import struct
|
|
||||||
from _datetime import datetime
|
|
||||||
from utils.logger import setup_logger
|
from utils.logger import setup_logger
|
||||||
from giants.player import Player, PlayerPhases
|
from giants import GameTypes, Teams
|
||||||
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
|
import asyncio
|
||||||
from dpnet.gamepackets import *
|
|
||||||
|
|
||||||
logger = setup_logger(__name__)
|
logger = setup_logger(__name__)
|
||||||
|
|
||||||
@ -39,36 +26,6 @@ class Netserver(asyncio.DatagramProtocol):
|
|||||||
logger.debug("Connection made")
|
logger.debug("Connection made")
|
||||||
self.remotesocket = transport
|
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):
|
def datagram_received(self, data, addr):
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
loop.create_task(self.handle_new_packet(addr, data))
|
loop.create_task(self.handle_new_packet(addr, data))
|
||||||
@ -77,9 +34,9 @@ class Netserver(asyncio.DatagramProtocol):
|
|||||||
pPacket = Packet(bData)
|
pPacket = Packet(bData)
|
||||||
first = pPacket.getByte()
|
first = pPacket.getByte()
|
||||||
if len(bData) >= 4 and first & DFrame.PACKET_COMMAND_DATA:
|
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:
|
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:
|
elif first == EnumQuery.LEAD or first == EnumResponse.LEAD:
|
||||||
logger.debug("%s:%s > %s (ENUM)", addr[0], addr[1], bData.hex())
|
logger.debug("%s:%s > %s (ENUM)", addr[0], addr[1], bData.hex())
|
||||||
await self.handle_new_enum(addr, pPacket)
|
await self.handle_new_enum(addr, pPacket)
|
||||||
@ -94,42 +51,31 @@ class Netserver(asyncio.DatagramProtocol):
|
|||||||
# EnumQuery
|
# EnumQuery
|
||||||
try:
|
try:
|
||||||
eq = EnumQuery(data)
|
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 = EnumResponse()
|
||||||
er.Payload = eq.Payload
|
er.Payload = eq.Payload
|
||||||
er.ApplicationDescSize = 0x50
|
er.ApplicationDescSize = 0x50
|
||||||
er.ApplicationDescFlags = 0x41
|
er.ApplicationDescFlags = 0x41
|
||||||
er.MaxPlayers = self.server.maxplayers
|
er.MaxPlayers = max_player_count
|
||||||
er.CurrentPlayers = len(self.server.players)
|
er.CurrentPlayers = player_count
|
||||||
er.SessionName = self.server.name
|
er.SessionName = server_name
|
||||||
er.ApplicationInstanceGUID = self.guid
|
er.ApplicationInstanceGUID = self.guid
|
||||||
er.ApplicationGUID = eq.ApplicationGUID
|
er.ApplicationGUID = eq.ApplicationGUID
|
||||||
'''er.ApplicationReservedData = b'\xff' # Map ID
|
|
||||||
er.ApplicationReservedData += b'\x00\x04\x00' # game type and teams
|
|
||||||
er.ApplicationReservedData += struct.pack("<L", int(self.server.version*1000)) # game version
|
|
||||||
er.ApplicationReservedData += b'\x02\x92\x05\x00\x01\x00\x00\x00\x00\x00' # Unknown
|
|
||||||
er.ApplicationReservedData += b'\x9c\x53\xf4\xdd' # Seems to be a checksum of current map
|
|
||||||
# \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: test
|
|
||||||
er.ApplicationReservedData += self.server.currentmap.mapname.encode("ascii")'''
|
|
||||||
|
|
||||||
appdata = Packet()
|
appdata = Packet()
|
||||||
appdata.putByte(0xff) # map ID
|
appdata.putByte(0xff) # map ID
|
||||||
appdata.putByte(self.server.game_type) # game type
|
appdata.putByte(GameTypes.GTypeNull) # game type
|
||||||
appdata.putByte(self.server.teams) # teams
|
appdata.putByte(Teams.MvRvK) # teams
|
||||||
appdata.write(b'\x00') # original: 0x00 - does not seem to affect client
|
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.write(b'\x02\x92') # original: 0292 - does not seem to affect client
|
||||||
appdata.putShort(self.server.points_per_capture)
|
appdata.putShort(0) # points per capture
|
||||||
appdata.putShort(self.server.points_per_kill)
|
appdata.putShort(0) # 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(0) # 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("\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(self.server.currentmap.mapname.encode("ascii"))
|
appdata.write(map_name.encode("ascii"))
|
||||||
appdata.write(b'\x00' * (32 - len(self.server.currentmap.mapname)))
|
appdata.write(b'\x00' * (32 - len(map_name)))
|
||||||
er.ApplicationReservedData = appdata.getvalue()
|
er.ApplicationReservedData = appdata.getvalue()
|
||||||
|
|
||||||
logger.debug("Current map: %s, checksum: %s", self.server.currentmap.mapname, self.server.currentmap.checksum)
|
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: ")
|
logger.error("Could not parse EnumQuery or forge EnumResponse: ")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return
|
return
|
||||||
elif second == EnumResponse.COMMAND:
|
|
||||||
# wait what? ignore that shit
|
|
||||||
return
|
|
||||||
else:
|
else:
|
||||||
logger.error("Unknown DPLHP command: %s", second)
|
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("<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)
|
|
||||||
#session.setup_Connect_Retry_Timer()
|
|
||||||
elif cframe.ExtOpCode == CFrame.FRAME_EXOPCODE_CONNECTED:
|
|
||||||
logger.debug("%s:%s > %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("<B", payload[0]).hex(), payload[1:].hex())
|
|
||||||
#await self.server.broadcast_message("SENT OPCODE: %s VALUES: %s" % (struct.pack("<B", payload[0]).hex(), payload[1:].hex()))
|
|
||||||
|
|
||||||
event_player = self.get_player(session)
|
|
||||||
if event_player:
|
|
||||||
await self.server.broadcast_event("on_player_gamedata", player, payload)
|
|
||||||
|
|
||||||
if payload[0] == 0xc1:
|
|
||||||
if not player or not player.phase == PlayerPhases.CFRAME_CONNECTED:
|
|
||||||
logger.error("Fuck you. Playerphase was %s", player.phase)
|
|
||||||
return
|
|
||||||
# DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO_EX
|
|
||||||
ppayload = Packet(payload)
|
|
||||||
dwPacketType = ppayload.getULong()
|
|
||||||
dwFlags = ppayload.getULong()
|
|
||||||
dwDNETVersion = ppayload.getULong()
|
|
||||||
dwNameOffset = ppayload.getULong()
|
|
||||||
dwNameSize = ppayload.getULong()
|
|
||||||
dwDataOffset = ppayload.getULong()
|
|
||||||
dwDataSize = ppayload.getULong()
|
|
||||||
dwPasswordOffset = ppayload.getULong()
|
|
||||||
dwPasswordSize = ppayload.getULong()
|
|
||||||
dwConnectDataOffset = ppayload.getULong()
|
|
||||||
dwConnectDataSize = ppayload.getULong()
|
|
||||||
dwURLOffset = ppayload.getULong()
|
|
||||||
dwURLSize = ppayload.getULong()
|
|
||||||
guidInstance = payload[52:68]
|
|
||||||
guidApplication = payload[68:84]
|
|
||||||
name = payload[dwNameOffset+4:dwNameOffset+2+dwNameSize]
|
|
||||||
name = name.decode("utf-16-le")
|
|
||||||
logger.debug("%s connected!", name)
|
|
||||||
player.name = name
|
|
||||||
#session.send_dframe_keepalive()
|
|
||||||
|
|
||||||
# Response: DN_MSG_INTERNAL_SEND_CONNECT_INFO
|
|
||||||
d = DN_MSG_INTERNAl_SEND_CONNECT_INFO(self, player)
|
|
||||||
d.Seq = session.next_send
|
|
||||||
d.NRcv = session.next_expected_seq
|
|
||||||
|
|
||||||
appdata = Packet()
|
|
||||||
appdata.putByte(0xff) # map ID
|
|
||||||
appdata.putByte(self.server.game_type) # game type
|
|
||||||
appdata.putByte(self.server.teams) # teams
|
|
||||||
appdata.write(b'\x00') # original: 0x00 - does not seem to affect client
|
|
||||||
appdata.putShort(int(self.server.version * 1000))
|
|
||||||
appdata.write(b'\x03\x90') # original: 0292 - does not seem to affect client
|
|
||||||
appdata.putShort(self.server.points_per_capture)
|
|
||||||
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(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:
|
|
||||||
# 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("<L", player.id)+b"\x00", acknow=True)
|
|
||||||
|
|
||||||
await player.session.send_gamedata(self.build_players_dpid(player))
|
|
||||||
await self.server.broadcast_gamedata_except(player, self.build_players_dpid())
|
|
||||||
|
|
||||||
plid=0
|
|
||||||
for pplayer in self.server.players:
|
|
||||||
await self.server.broadcast_gamedata(b'\x3d'+struct.pack("<B", plid)+pplayer.name.encode("ascii")+b"\x00"*(33-len(pplayer.name.encode("ascii")))) # playername
|
|
||||||
plid+=1
|
|
||||||
elif payload[0] == 0x0f:
|
|
||||||
player = self.get_player(session)
|
|
||||||
if not player:
|
|
||||||
logger.debug("Fuck that no player wtf man")
|
|
||||||
return
|
|
||||||
inc = Packet(payload)
|
|
||||||
opcode = inc.getByte()
|
|
||||||
playerid = inc.getULong()
|
|
||||||
status = inc.getULong()
|
|
||||||
padding = inc.getShort()
|
|
||||||
|
|
||||||
out = Packet()
|
|
||||||
out.putByte(opcode)
|
|
||||||
out.putULong(playerid)
|
|
||||||
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)
|
|
||||||
player = self.get_player(session)
|
|
||||||
if not player:
|
|
||||||
logger.debug("Fuck that no player wtf man")
|
|
||||||
return
|
|
||||||
|
|
||||||
p = Packet(payload)
|
|
||||||
opcode = p.getByte()
|
|
||||||
team = p.getByte()
|
|
||||||
playerid = p.getULong()
|
|
||||||
unknown = p.getByte()
|
|
||||||
|
|
||||||
if player.team > 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("<H", time_limit_minutes)+b"\x00\x80"+(b"\x00"*17), acknow=True)
|
|
||||||
|
|
||||||
await player.session.send_gamedata(b"\x39"+(b"\x00"*21), acknow=False) # acknow=True
|
|
||||||
await player.session.send_gamedata(b"\x39\x01\x01\x01\x01"+(b"\x00"*17), acknow=True)
|
|
||||||
elif payload[0] == 0x0c:
|
|
||||||
player = self.get_player(session)
|
|
||||||
if not player:
|
|
||||||
logger.debug("Fuck that no player wtf man")
|
|
||||||
return
|
|
||||||
playerping = 1
|
|
||||||
await player.session.send_gamedata(b"\x2f\x02\x00\x00" + struct.pack("<H", playerping) + b"\x00", acknow=False) # acknow=True
|
|
||||||
|
|
||||||
# TODO: Understand this vv SPAWN TREES vv
|
|
||||||
#for i in range(0x06):
|
|
||||||
# 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", 0) + b"\x00\x00\x00\x00" + struct.pack("<B", 0 + 0x07) + b"\x00\x00\x00")
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
# TODO: spawn all players except himself
|
|
||||||
await self.spawn_all_players_except(player)
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
await self.server.broadcast_event("on_player_spawn", player)
|
|
||||||
|
|
||||||
player.phase = PlayerPhases.INGAME
|
|
||||||
|
|
||||||
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.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()
|
|
||||||
playerx = p.getFloat()
|
|
||||||
playery = p.getFloat()
|
|
||||||
playerz = p.getFloat()
|
|
||||||
unknown4 = p.getULong()
|
|
||||||
unknown5 = p.getULong()
|
|
||||||
unknown6 = p.getULong()
|
|
||||||
unknown7 = p.getULong()
|
|
||||||
orientation = p.getULong() # orientation
|
|
||||||
unknown9 = p.getULong()
|
|
||||||
|
|
||||||
player.x = playerx
|
|
||||||
player.y = playery
|
|
||||||
player.z = playerz
|
|
||||||
player.oid = objid
|
|
||||||
player.o = orientation
|
|
||||||
await self.server.broadcast_gamedata_except(player, payload)
|
|
||||||
|
|
||||||
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.remove_player(player)
|
|
||||||
await self.server.broadcast_gamedata(self.build_players_dpid())
|
|
||||||
|
|
||||||
plid = 0
|
|
||||||
for pplayer in self.server.players:
|
|
||||||
await self.server.broadcast_gamedata(b'\x3d' + struct.pack("<B", plid) + pplayer.name.encode("ascii") + b"\x00" * (33 - len(pplayer.name.encode("ascii"))), acknow=False) # playername
|
|
||||||
plid += 1
|
|
||||||
await self.server.broadcast_event("on_player_left", player)
|
|
||||||
elif payload[0] == 0x4d:
|
|
||||||
# CLIENT DOWNLOAD MAP
|
|
||||||
player = self.get_player(session)
|
|
||||||
if not player:
|
|
||||||
logger.debug("Fuck that no player wtf man")
|
|
||||||
return
|
|
||||||
|
|
||||||
payload = Packet()
|
|
||||||
payload.putByte(0x4e) # packet opcode
|
|
||||||
#payload.putByte(0x9d) # packet opcode?
|
|
||||||
|
|
||||||
mapsize = os.stat("maps/"+self.server.currentmap.mappath).st_size
|
|
||||||
payload.putULong(mapsize) # map size
|
|
||||||
payload.putBytes((self.server.currentmap.mapname+"\x00"*(128-len(self.server.currentmap.mapname))).encode("ascii"))
|
|
||||||
|
|
||||||
await player.session.send_gamedata(payload.getvalue())
|
|
||||||
|
|
||||||
with open("maps/"+self.server.currentmap.mappath, "rb") as fh:
|
|
||||||
data = fh.read(512)
|
|
||||||
while data != b"":
|
|
||||||
if len(data) == 512:
|
|
||||||
# full packet
|
|
||||||
mapdl = Packet()
|
|
||||||
mapdl.putByte(0x4f) # opcode
|
|
||||||
mapdl.putByte(0x00) # unknown
|
|
||||||
mapdl.putByte(0x02) # unknown
|
|
||||||
mapdl.putByte(0x00) # unknown
|
|
||||||
mapdl.putByte(0x00) # unknown
|
|
||||||
mapdl.putBytes(data)
|
|
||||||
mapdl.putByte(0x00) # ending
|
|
||||||
await player.session.send_gamedata(mapdl.getvalue(), acknow=False) # map chunk
|
|
||||||
else:
|
|
||||||
# last packet
|
|
||||||
mapdl = Packet()
|
|
||||||
mapdl.putByte(0x4f) # opcode
|
|
||||||
mapdl.putULong(len(data)) # map end length
|
|
||||||
mapdl.putBytes(data)
|
|
||||||
# fill with crap at the end
|
|
||||||
mapdl.putBytes(b"\x00"*(512-len(data)))
|
|
||||||
mapdl.putByte(0x00) # ending
|
|
||||||
await player.session.send_gamedata(mapdl.getvalue(), acknow=False) # map chunk
|
|
||||||
data = fh.read(512)
|
|
||||||
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
|
|
||||||
player = self.get_player(session)
|
|
||||||
if not player:
|
|
||||||
logger.debug("Fuck that no player wtf man")
|
|
||||||
return
|
|
||||||
p = Packet(payload)
|
|
||||||
opcode = p.getByte()
|
|
||||||
plix = p.getByte() # length?
|
|
||||||
oid = p.getShort()
|
|
||||||
unknown = p.getByte()
|
|
||||||
model = p.getULong()
|
|
||||||
|
|
||||||
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, payload)
|
|
||||||
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)
|
|
||||||
oid = struct.unpack("<H", payload[6:8])[0]
|
|
||||||
x = struct.unpack("<f", payload[14:18])[0]
|
|
||||||
y = struct.unpack("<f", payload[18:22])[0]
|
|
||||||
z = struct.unpack("<f", payload[22:26])[0]
|
|
||||||
#await self.server.broadcast_gamedata(MSG_BULLET_EXPLOSION(player, oid, x, y, z).to_packet())
|
|
||||||
|
|
||||||
# POPUP
|
|
||||||
#popupoid = self.server.new_oid()
|
|
||||||
#type = 12 # maybe
|
|
||||||
#await self.server.broadcast_gamedata(MSG_NEW_PROJECTILE(player, popupoid, type, x, y, z, 0).to_packet())
|
|
||||||
|
|
||||||
#await self.server.broadcast_gamedata(bytes.fromhex("09160000000438000002250000000a00000004070000091300000004070000110200000004"+ struct.pack("<H", popupoid).hex() +"000a090e00000004380000032500000000")) # put popup on backpack
|
|
||||||
#await self.server.broadcast_gamedata(MSG_PLAYER_DROP_BACKPACK(player).to_packet()) # drop popup
|
|
||||||
#await self.server.broadcast_gamedata(MSG_BULLET_EXPLOSION(player, popupoid, x, y, z, True).to_packet()) # explode popup
|
|
||||||
#await self.server.broadcast_gamedata(MSG_PLAYER_USE_BACKPACK(player, 0x16).to_packet()) # use popup
|
|
||||||
|
|
||||||
elif payload[0] == 0x09 and payload[1] == 0x0f:
|
|
||||||
player = self.get_player(session)
|
|
||||||
if not player:
|
|
||||||
logger.debug("Fuck that no player wtf man")
|
|
||||||
return
|
|
||||||
p = Packet(payload)
|
|
||||||
opcode = p.getByte()
|
|
||||||
opcode2 = p.getByte()
|
|
||||||
unknown = p.getByte()
|
|
||||||
unknown = p.getShort()
|
|
||||||
player_index = p.getByte()
|
|
||||||
unknown = p.getShort()
|
|
||||||
unknown = p.getByte()
|
|
||||||
unknown = p.getByte()
|
|
||||||
unknown = p.getULong()
|
|
||||||
weapon = p.getByte()
|
|
||||||
await player.send_message("SWITCH WEAPON: %s" % payload.hex())
|
|
||||||
await self.server.broadcast_gamedata_except(player, MSG_SWITCH_WEAPON(player, weapon).to_packet())
|
|
||||||
elif payload[0] == 0x0b: # MESSAGE_HIT
|
|
||||||
# 0b380437000004070000d48325c32dea66c2c0a0cf429fea0442091a00000004370000034d000000d48325c32dea66c2c0a0cf4200
|
|
||||||
player = self.get_player(session)
|
|
||||||
if not player:
|
|
||||||
logger.debug("Fuck that no player wtf man")
|
|
||||||
return
|
|
||||||
|
|
||||||
await self.server.broadcast_event("on_player_hit", player, None, None)
|
|
||||||
await player.send_message("HIT: %s" % payload.hex())
|
|
||||||
|
|
||||||
else:
|
|
||||||
player = self.get_player(session)
|
|
||||||
if not player:
|
|
||||||
logger.debug("Fuck that no player wtf man")
|
|
||||||
return
|
|
||||||
if player.opts["debug"]:
|
|
||||||
await player.send_message("Unknown: %s" % payload.hex())
|
|
||||||
|
|
||||||
await self.server.broadcast_gamedata_except(player, payload)
|
|
||||||
|
|
||||||
|
|
||||||
def build_players_dpid(self, exceptplayer=False):
|
|
||||||
p1 = b'\x01' + struct.pack("<B", len(self.server.players))
|
|
||||||
for pplayer in self.server.players:
|
|
||||||
p1 += struct.pack("<L", pplayer.id)
|
|
||||||
for pplayer in self.server.players:
|
|
||||||
if pplayer.name == "[Server]":
|
|
||||||
continue
|
|
||||||
p1 += b'\x0e'
|
|
||||||
p1 += b"\x01\x00"
|
|
||||||
for pplayer in self.server.players:
|
|
||||||
if pplayer == exceptplayer or pplayer.name == "[Server]":
|
|
||||||
continue
|
|
||||||
p1 += struct.pack("<B", pplayer.team)
|
|
||||||
p1 += b'\x00\x00'
|
|
||||||
return p1
|
|
||||||
|
|
||||||
async def spawn_player_except(self, player):
|
|
||||||
plix = self.server.get_player_index(player)
|
|
||||||
p = Packet()
|
|
||||||
p.putByte(0x05) # opcode
|
|
||||||
p.putByte(plix)
|
|
||||||
p.putShort(player.oid)
|
|
||||||
p.putByte(0x00)
|
|
||||||
p.putULong(2) # 2: mecc
|
|
||||||
p.putByte(0x00)
|
|
||||||
|
|
||||||
await self.server.broadcast_gamedata_except(player, p.getvalue())
|
|
||||||
|
|
||||||
async def spawn_all_players_except(self, player):
|
|
||||||
for pplayer in self.server.players:
|
|
||||||
if pplayer.name == "[Server]" or pplayer == player:
|
|
||||||
continue
|
|
||||||
plix = self.server.get_player_index(pplayer)
|
|
||||||
p = Packet()
|
|
||||||
p.putByte(0x05) # opcode
|
|
||||||
p.putByte(plix)
|
|
||||||
p.putShort(pplayer.oid)
|
|
||||||
p.putByte(0x00)
|
|
||||||
p.putULong(2) # 2: mecc
|
|
||||||
p.putByte(0x00)
|
|
||||||
await player.session.send_gamedata(p.getvalue())
|
|
||||||
|
|
||||||
def send_packet(self, addr, packet):
|
def send_packet(self, addr, packet):
|
||||||
self.remotesocket.sendto(packet.getvalue(), addr)
|
self.remotesocket.sendto(packet.getvalue(), addr)
|
||||||
#logger.debug("%s:%s < %s", addr[0], addr[1], packet.getvalue().hex())
|
|
||||||
|
|
||||||
def get_session(self, iporaddr, port=None):
|
|
||||||
if not port:
|
|
||||||
return next((x for x in self.addrs if x.ip == iporaddr[0] and x.port == iporaddr[1]), None)
|
|
||||||
else:
|
|
||||||
return next((x for x in self.addrs if x.ip == iporaddr and x.port == port), None)
|
|
||||||
|
|
||||||
def get_player(self, iporaddr, port=None):
|
|
||||||
if type(iporaddr) == Session:
|
|
||||||
a = next((x for x in self.server.players if x.session.ip == iporaddr.ip and x.session.port == iporaddr.port), None)
|
|
||||||
if a:
|
|
||||||
return a
|
|
||||||
else:
|
|
||||||
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr.ip and x.session.port == iporaddr.port),None)
|
|
||||||
if not port:
|
|
||||||
a = next((x for x in self.server.players if x.session.ip == iporaddr[0] and x.session.port == iporaddr[1]), None)
|
|
||||||
if a:
|
|
||||||
return a
|
|
||||||
else:
|
|
||||||
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr[0] and x.session.port == iporaddr[1]),None)
|
|
||||||
else:
|
|
||||||
a = next((x for x in self.server.players if x.session.ip == iporaddr and x.session.port == port), None)
|
|
||||||
if a:
|
|
||||||
return a
|
|
||||||
else:
|
|
||||||
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr and x.session.port == port), None)
|
|
||||||
|
|
||||||
def get_temp_player(self, iporaddr, port=None):
|
|
||||||
if type(iporaddr) == Session:
|
|
||||||
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr.ip and x.session.port == iporaddr.port), None)
|
|
||||||
if not port:
|
|
||||||
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr[0] and x.session.port == iporaddr[1]), None)
|
|
||||||
else:
|
|
||||||
return next((x for x in self.server.tempplayers if x.session.ip == iporaddr and x.session.port == port), None)
|
|
@ -1,96 +0,0 @@
|
|||||||
from threading import Timer
|
|
||||||
from utils.logger import setup_logger
|
|
||||||
from dpnet.CFrame import CFrame
|
|
||||||
from dpnet.DFrame import DFrame
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
logger = setup_logger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class Session:
|
|
||||||
def __init__(self, server, serversock):
|
|
||||||
self.serversock = serversock
|
|
||||||
self.server = server
|
|
||||||
self.ip = ""
|
|
||||||
self.port = 0
|
|
||||||
self.SessID = 0
|
|
||||||
self.next_expected_seq = 0
|
|
||||||
self.next_send = 0
|
|
||||||
self.Full = False
|
|
||||||
self.LastMsgID = 0
|
|
||||||
self.connect_retry_timer_num = 0
|
|
||||||
self.connect_retry_timer = False
|
|
||||||
|
|
||||||
self.lock = asyncio.Lock()
|
|
||||||
|
|
||||||
def send(self, packet):
|
|
||||||
rawpacket = packet.to_packet()
|
|
||||||
rawbytes = rawpacket.getvalue()
|
|
||||||
self.serversock.sendto(rawbytes, (self.ip, self.port))
|
|
||||||
if len(rawbytes) >= 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)
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
|||||||
from giants.entity import Entity
|
|
||||||
|
|
||||||
|
|
||||||
class GameObject(Entity):
|
|
||||||
pass
|
|
@ -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: <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"
|
|
@ -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("<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)
|
|
||||||
|
|
||||||
def model(self):
|
|
||||||
# TODO: Fix
|
|
||||||
return Models.Characters_Mecc
|
|
@ -1,6 +0,0 @@
|
|||||||
from giants.entity import Entity
|
|
||||||
|
|
||||||
|
|
||||||
class Projectile(Entity):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
@ -1,28 +0,0 @@
|
|||||||
from dpnet.gamepackets import *
|
|
||||||
import struct
|
|
||||||
|
|
||||||
class Bullets:
|
|
||||||
def __init__(self, server):
|
|
||||||
self.server = server
|
|
||||||
|
|
||||||
async def on_player_chat(self, player, type, team, message):
|
|
||||||
command = message.split(" ")
|
|
||||||
if len(command) > 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("<H", payload[31:33])[0]
|
|
||||||
print(oid)
|
|
||||||
x = struct.unpack("<f", payload[14:18])[0]
|
|
||||||
y = struct.unpack("<f", payload[18:22])[0]
|
|
||||||
z = struct.unpack("<f", payload[22:26])[0]
|
|
||||||
o = struct.unpack("<L", payload[26:30])[0]
|
|
||||||
await self.server.broadcast_gamedata(MSG_BULLET_EXPLOSION(player, oid, x, y, z, False).to_packet())
|
|
||||||
await self.server.broadcast_gamedata(MSG_NEW_PROJECTILE(player, self.server.new_oid(), player.opts["bullet"], x, y, z, o).to_packet())
|
|
||||||
|
|
||||||
|
|
||||||
def setup(server):
|
|
||||||
plugin = Bullets(server)
|
|
||||||
server.add_plugin(plugin)
|
|
@ -1,185 +0,0 @@
|
|||||||
from giants import ChatColor
|
|
||||||
import asyncio
|
|
||||||
import struct
|
|
||||||
from dpnet.packet import Packet
|
|
||||||
from dpnet.gamepackets import *
|
|
||||||
from random import randint
|
|
||||||
|
|
||||||
|
|
||||||
class Commands:
|
|
||||||
def __init__(self, server):
|
|
||||||
self.server = server
|
|
||||||
self.recorded = b''
|
|
||||||
self.recording = False
|
|
||||||
self.recordingplayer = None
|
|
||||||
self.nextweapon = 1
|
|
||||||
|
|
||||||
async def on_player_gamedata(self, player, gamedatabytes):
|
|
||||||
if self.recording:
|
|
||||||
self.recorded = gamedatabytes
|
|
||||||
self.recording = False
|
|
||||||
await self.recordingplayer.send_message("Packet recorded: %s" % (self.recorded.hex(),), color=ChatColor.Cyan)
|
|
||||||
|
|
||||||
async def on_player_chat(self, player, type, team, message):
|
|
||||||
await self.server.broadcast_message_except(player, "%s: %s" % (player.name, message), color=ChatColor.Yellow)
|
|
||||||
print(message)
|
|
||||||
command = message.split(" ")
|
|
||||||
|
|
||||||
if len(command) > 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("<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 self.server.broadcast_gamedata(MSG_PLAYER_DIE(player, diemethod).to_packet())
|
|
||||||
#await player.session.send_gamedata(bytes.fromhex("0b1a0000000002070000a5b0d4c35d9714c450abef354a68fb410914000000020700000402000000")+struct.pack("<L",diemethod)+bytes.fromhex("0000"))
|
|
||||||
|
|
||||||
if command[0] == "spawn" and len(command) > 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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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("<R", data.hex())
|
|
286
server.py
286
server.py
@ -1,18 +1,7 @@
|
|||||||
from dpnet.packet import Packet
|
|
||||||
from giants.map import Map
|
|
||||||
from giants.player import Player
|
|
||||||
from dpnet.netserver import Netserver
|
from dpnet.netserver import Netserver
|
||||||
from dpnet.session import Session
|
from giants.masterserver import MasterServer
|
||||||
import socket
|
|
||||||
import importlib
|
|
||||||
import os
|
|
||||||
from giants import Teams, GameTypes, ChatColor, ChatType
|
|
||||||
from utils.logger import setup_logger
|
from utils.logger import setup_logger
|
||||||
import traceback
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from aioconsole import ainput
|
|
||||||
import struct
|
|
||||||
from curses import wrapper
|
|
||||||
|
|
||||||
logger = setup_logger(__name__)
|
logger = setup_logger(__name__)
|
||||||
|
|
||||||
@ -21,275 +10,26 @@ class Server:
|
|||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.listen_ip = kwargs.get("ip", "0.0.0.0")
|
self.listen_ip = kwargs.get("ip", "0.0.0.0")
|
||||||
self.listen_port = kwargs.get("port", 19711)
|
self.listen_port = kwargs.get("port", 19711)
|
||||||
self.register_with_ms = kwargs.get("register", False)
|
self.register_with_ms = kwargs.get("register", True)
|
||||||
self.teams = kwargs.get("teams", Teams.MvM)
|
|
||||||
self.game_type = kwargs.get("gametype", GameTypes.TeamDeathmatchWithFullBase)
|
|
||||||
self.currentmap = kwargs.get("map", Map("Testmap.gck"))
|
|
||||||
self.maxplayers = kwargs.get("maxplayers", 20)
|
|
||||||
self.name = kwargs.get("name", "Default Server Name")
|
|
||||||
|
|
||||||
fake_session = Session(self, socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
|
async def on_connection_received(self, ip, port):
|
||||||
fake_session.ip = "127.0.0.1"
|
version = 1.497
|
||||||
fake_session.port = 3333
|
server_name = "Okay"
|
||||||
self.players = [Player("[Server]", fake_session)]
|
player_count = 2
|
||||||
|
max_player_count = 20
|
||||||
|
map_name = "blah"
|
||||||
|
return version, server_name, player_count, max_player_count, map_name
|
||||||
|
|
||||||
fake_player = Session(self, 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))
|
|
||||||
|
|
||||||
fake_player = Session(self, 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(self, 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
|
|
||||||
self.points_per_capture = 5
|
|
||||||
self.detente_time = 0 # minutes
|
|
||||||
self._plugins = []
|
|
||||||
self.tempplayers = []
|
|
||||||
self.running = True
|
|
||||||
self.ticks = 60
|
|
||||||
|
|
||||||
self._nextid = 118
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
#logger.debug("Calling update")
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def add_player(self, player):
|
|
||||||
self.tempplayers.remove(player)
|
|
||||||
self.players.append(player)
|
|
||||||
await self.broadcast_event("on_player_join", player)
|
|
||||||
|
|
||||||
# todo: remove
|
|
||||||
def create_temp_player(self, player):
|
|
||||||
self.tempplayers.append(player)
|
|
||||||
|
|
||||||
async def remove_player(self, player):
|
|
||||||
self.players.remove(player)
|
|
||||||
|
|
||||||
def add_plugin(self, plugin):
|
|
||||||
self._plugins.append(plugin)
|
|
||||||
|
|
||||||
async def change_map(self, mappath):
|
|
||||||
try:
|
|
||||||
self.currentmap = Map(mappath)
|
|
||||||
await self.broadcast_event("on_map_change", self.currentmap)
|
|
||||||
except Exception:
|
|
||||||
logger.error("Could not change map")
|
|
||||||
|
|
||||||
async def broadcast_event(self, event, *args):
|
|
||||||
logger.debug("Broadcasting event "+event)
|
|
||||||
for plugin in self._plugins:
|
|
||||||
if hasattr(plugin, event):
|
|
||||||
func = getattr(plugin, event)
|
|
||||||
if callable(func):
|
|
||||||
try:
|
|
||||||
await func(*args)
|
|
||||||
except Exception:
|
|
||||||
logger.error("Could not call plugin function: "+plugin.__class__.__name__+"."+event)
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
def load_plugins(self):
|
|
||||||
plugins = os.listdir("plugins")
|
|
||||||
for plugin in plugins:
|
|
||||||
if os.path.isdir("plugins/"+plugin) or plugin == "__init__.py":
|
|
||||||
continue
|
|
||||||
if not plugin.endswith(".py"):
|
|
||||||
continue
|
|
||||||
pluginname = plugin.split(".py")[0]
|
|
||||||
try:
|
|
||||||
module = importlib.import_module("plugins."+pluginname)
|
|
||||||
if hasattr(module, "setup"):
|
|
||||||
setup = getattr(module, "setup")
|
|
||||||
if callable(setup):
|
|
||||||
logger.info("Loading plugin "+module.__name__)
|
|
||||||
module.setup(self)
|
|
||||||
except Exception:
|
|
||||||
logger.warning("Could not load plugin "+plugin)
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
async def broadcast_message(self, text, color=ChatColor.Orange, type=ChatType.All):
|
|
||||||
for player in self.players:
|
|
||||||
if player.name == "[Server]":
|
|
||||||
continue
|
|
||||||
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()
|
|
||||||
|
|
||||||
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("<H", self._nextid).hex() + "00" + model + "00000000"), acknow=False)
|
|
||||||
|
|
||||||
p = Packet()
|
|
||||||
p.putByte(0x0a) # opcode
|
|
||||||
p.putByte(0x12) # length
|
|
||||||
p.putByte(0x00) # unknown
|
|
||||||
p.putByte(0x00) # unknown
|
|
||||||
p.putByte(0x00) # unknown
|
|
||||||
p.putByte(plix) # player index
|
|
||||||
p.putShort(self._nextid) # object id
|
|
||||||
p.putByte(0x00) # unknown
|
|
||||||
p.putByte(0x01) # unknown
|
|
||||||
p.putULong(model) # model
|
|
||||||
p.putFloat(player.x) # player x
|
|
||||||
p.putFloat(player.y) # player y
|
|
||||||
p.putFloat(player.z) # player z
|
|
||||||
p.putULong(0x00) # unknown
|
|
||||||
p.putULong(0x00) # unknown
|
|
||||||
p.putULong(0x00) # unknown
|
|
||||||
p.putULong(0x00) # unknown
|
|
||||||
p.putULong(0x00) # orientation
|
|
||||||
p.putULong(0x00) # unknown
|
|
||||||
|
|
||||||
await self.broadcast_gamedata(p.getvalue(), acknow=False)
|
|
||||||
|
|
||||||
self._nextid+=1
|
|
||||||
|
|
||||||
#await self.broadcast_gamedata(bytes.fromhex("0a12000000" + plix + struct.pack("<H", self._nextid).hex() + "0003" + model + "00000000"), acknow=False)
|
|
||||||
#await self.broadcast_gamedata(bytes.fromhex("0a32000000" + plix + struct.pack("<B", self._nextid).hex() + "000001" + model + "000000ff00000000000000000000000000000000000000000000000000000000000000000000000a12000000" + plix + struct.pack("<B", self._nextid).hex() + "0000" + model + "020000000000000000"), acknow=False)
|
|
||||||
|
|
||||||
async def change_model(self, player, model):
|
|
||||||
plid = self.get_player_index(player)
|
|
||||||
# p = Packet()
|
|
||||||
# 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(0x02) # 4 -> 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("<B", objid).hex() + "000001" + model + "000000ff00000000000000000000000000000000000000000000000000000000000000000000000a12000000" + plix + struct.pack("<B", objid).hex() + "0000" + model + "020000000000000000"), acknow=False)
|
|
||||||
|
|
||||||
def new_oid(self):
|
|
||||||
a = self._nextid
|
|
||||||
self._nextid += 1
|
|
||||||
return a
|
|
||||||
|
|
||||||
def get_player_index(self, player):
|
|
||||||
for iplayer in range(len(self.players)):
|
|
||||||
if self.players[iplayer] == player:
|
|
||||||
return iplayer
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_player_by_index(self, playerindex):
|
|
||||||
return self.players[playerindex]
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
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 = Server()
|
||||||
server.load_plugins()
|
if server.register_with_ms:
|
||||||
|
ms = MasterServer(server)
|
||||||
|
ms.register()
|
||||||
|
|
||||||
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:
|
||||||
|
Loading…
Reference in New Issue
Block a user