mirror of
https://github.com/Wesley-DeMontigny/WLUS.git
synced 2026-05-20 08:09:41 -05:00
Added World Loading (Replica Components Not Implemented)
This commit is contained in:
+3
-3
@@ -38,12 +38,12 @@ if __name__ == "__main__":
|
||||
auth_server = services.AuthServerService(game)
|
||||
game.register_service(auth_server)
|
||||
|
||||
world = services.WorldService(game)
|
||||
game.register_service(world)
|
||||
|
||||
world_server = services.WorldServerService(game)
|
||||
game.register_service(world_server)
|
||||
|
||||
world = services.WorldService(game)
|
||||
game.register_service(world)
|
||||
|
||||
game.start()
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
@@ -22,6 +22,7 @@ class Game(game_types.BaseObject):
|
||||
for service in self._services:
|
||||
service_thread = game_types.GameThread(target=service.initialize)
|
||||
service_thread.start()
|
||||
self.trigger_event("GameStarted")
|
||||
|
||||
def generate_object_id(self):
|
||||
id = random.randint(100000000000000000, 999999999999999999)
|
||||
|
||||
+65
-33
@@ -14,7 +14,7 @@ class PacketHeaderEnum(Enum):
|
||||
CLIENT_DELETE_MINIFIGURE_REQUEST = b'S\x04\x00\x06\x00\x00\x00\x00'
|
||||
WORLD_INFO = b'S\x05\x00\x02\x00\x00\x00\x00'
|
||||
CLINET_ENTER_WORLD = b'S\x04\x00\x04\x00\x00\x00\x00'
|
||||
CLINET_LOAD_COMPLETE = b'S\x04\x00\x13\x00\x00\x00\x00'
|
||||
CLIENT_LOAD_COMPLETE = b'S\x04\x00\x13\x00\x00\x00\x00'
|
||||
DETAILED_USER_INFO = b'S\x05\x00\x04\x00\x00\x00\x00'
|
||||
ROUTED_PACKET = b'S\x04\x00\x15\x00\x00\x00\x00'
|
||||
CLIENT_GAME_MESSAGE = b'S\x04\x00\x05\x00\x00\x00\x00'
|
||||
@@ -74,7 +74,7 @@ class ItemLOTs(IntEnum):
|
||||
PANTS_REDDISH_BROWN = 2526
|
||||
PANTS_DARK_RED = 2527
|
||||
|
||||
ZoneChecksums = {
|
||||
zone_checksums = {
|
||||
1000: 0x20b8087c,
|
||||
1001: 0x26680a3c,
|
||||
1100: 0x49525511,
|
||||
@@ -108,37 +108,69 @@ ZoneChecksums = {
|
||||
2001: 0x09eb00ef
|
||||
}
|
||||
|
||||
DefaultZoneSpawns = {1000 : [-624.13, 613.326233, -30.974],
|
||||
1001 : [-187.2391, 608.2743, 54.5554352],
|
||||
1100 : [522.9949, 406.040375, 129.992722],
|
||||
1101 : [35.0297, 365.780426, -201.578369],
|
||||
1102 : [-18.7062054, 440.20932, 37.5326424],
|
||||
1150 : [-18.7062054, 440.20932, 37.5326424],
|
||||
1151 : [25.0526543, 472.215027, -24.318882],
|
||||
1200 : [-40.0, 293.047, -16.0],
|
||||
1201 : [111.670906, 229.282776, 179.87793],
|
||||
1203 : [0.0, 0.0, 0.0],
|
||||
1204 : [-12.1019106, 212.900024, 191.147964],
|
||||
1250 : [-17.8299046, 440.509674, 30.0326862],
|
||||
1251 : [31.55009, 470.885254, 193.457321],
|
||||
1300 : [-329.965881, 302.470184, -470.232758],
|
||||
1302 : [-293.072571, 233.0, -4.16148],
|
||||
1303 : [0.0, 0.0, 0.0],
|
||||
1350 : [-19.713892, 440.20932, 26.935009],
|
||||
1400 : [390.284363, 229.452881, -511.350983],
|
||||
1402 : [-264.426575, 290.3452, 308.619049],
|
||||
1403 : [-1457.71826, 794.0, -332.2917],
|
||||
1450 : [-26.8431015, 425.11496, 53.7349777],
|
||||
1600 : [34.6352119, 1571.29309, 48.0321465],
|
||||
1601 : [-90.30964, 211.087067, -126.3196],
|
||||
1602 : [-163.2, 217.254913, 172.0],
|
||||
1603 : [9.18036652, 48.79997, 109.610374],
|
||||
1604 : [-99.80103, 231.916946, -162.67955],
|
||||
1700 : [-359.979156, 1066.328, -369.287781],
|
||||
1800 : [-241.965515, 92.78052, 557.327942],
|
||||
1900 : [165.355682, 1164.17822, -543.9093],
|
||||
2000 : [-446.79715, 171.158859, 1122.83545],
|
||||
2001 : [11.26009, 211.05188, 40.6721039]}
|
||||
default_zone_spawns = {1000 : [-624.13, 613.326233, -30.974],
|
||||
1001 : [-187.2391, 608.2743, 54.5554352],
|
||||
1100 : [522.9949, 406.040375, 129.992722],
|
||||
1101 : [35.0297, 365.780426, -201.578369],
|
||||
1102 : [-18.7062054, 440.20932, 37.5326424],
|
||||
1150 : [-18.7062054, 440.20932, 37.5326424],
|
||||
1151 : [25.0526543, 472.215027, -24.318882],
|
||||
1200 : [-40.0, 293.047, -16.0],
|
||||
1201 : [111.670906, 229.282776, 179.87793],
|
||||
1203 : [0.0, 0.0, 0.0],
|
||||
1204 : [-12.1019106, 212.900024, 191.147964],
|
||||
1250 : [-17.8299046, 440.509674, 30.0326862],
|
||||
1251 : [31.55009, 470.885254, 193.457321],
|
||||
1300 : [-329.965881, 302.470184, -470.232758],
|
||||
1302 : [-293.072571, 233.0, -4.16148],
|
||||
1303 : [0.0, 0.0, 0.0],
|
||||
1350 : [-19.713892, 440.20932, 26.935009],
|
||||
1400 : [390.284363, 229.452881, -511.350983],
|
||||
1402 : [-264.426575, 290.3452, 308.619049],
|
||||
1403 : [-1457.71826, 794.0, -332.2917],
|
||||
1450 : [-26.8431015, 425.11496, 53.7349777],
|
||||
1600 : [34.6352119, 1571.29309, 48.0321465],
|
||||
1601 : [-90.30964, 211.087067, -126.3196],
|
||||
1602 : [-163.2, 217.254913, 172.0],
|
||||
1603 : [9.18036652, 48.79997, 109.610374],
|
||||
1604 : [-99.80103, 231.916946, -162.67955],
|
||||
1700 : [-359.979156, 1066.328, -369.287781],
|
||||
1800 : [-241.965515, 92.78052, 557.327942],
|
||||
1900 : [165.355682, 1164.17822, -543.9093],
|
||||
2000 : [-446.79715, 171.158859, 1122.83545],
|
||||
2001 : [11.26009, 211.05188, 40.6721039]}
|
||||
|
||||
zone_names = {1000 : "Venture Explorer",
|
||||
1001 : "Return To The Venture Explorer",
|
||||
1100 : "Avant Gardens",
|
||||
1101 : "Avant Gardens Survival",
|
||||
1102 : "Spider Queen Battle",
|
||||
1150 : "Block Yard",
|
||||
1151 : "Avant Grove",
|
||||
1200 : "Nimbus Station",
|
||||
1201 : "Pet Cove",
|
||||
1203 : "Vertigo Loop",
|
||||
1204 : "Battle of Nimbus Station",
|
||||
1250 : "Nimbus Rock",
|
||||
1251 : "Nimbus Isle",
|
||||
1300 : "Gnarled Forest",
|
||||
1302 : "Canyon Cove",
|
||||
1303 : "Keelhaul Canyon",
|
||||
1350 : "Chantey Shantey",
|
||||
1400 : "Forbidden Valley",
|
||||
1402 : "Forbidden Valley Dragon",
|
||||
1403 : "Dragonmaw Chasm",
|
||||
1450 : "Raven Bluff",
|
||||
1600 : "Starbase 3001",
|
||||
1601 : "Deep Freeze",
|
||||
1602 : "Robot City",
|
||||
1603 : "Moon Base",
|
||||
1604 : "Portabello",
|
||||
1700 : "LEGO Club",
|
||||
1800 : "Crux Prime",
|
||||
1900 : "Nexus Tower",
|
||||
2000 : "Ninjago Monastery",
|
||||
2001 : "Frakjaw Battle"}
|
||||
|
||||
class MinifigureCreationResponseEnum(IntEnum):
|
||||
SUCCESS = 0x00
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
'''
|
||||
This script will do things that are supposed to happen on bootup
|
||||
'''
|
||||
|
||||
|
||||
game = self._parent
|
||||
@game.register_event_handler("ServiceRegistered")
|
||||
def register_zones(service):
|
||||
from game_enums import zone_names
|
||||
if(service.get_name() == "World"):
|
||||
for zone in zone_names:
|
||||
service.register_scene(level=zone, name=zone_names[zone])
|
||||
print("Registered {}!".format(zone_names[zone]))
|
||||
@@ -1,10 +0,0 @@
|
||||
'''
|
||||
This is a test script.
|
||||
'''
|
||||
|
||||
|
||||
print("'{}' Has Been Started (This Is A Test Message)".format(self._name))
|
||||
|
||||
|
||||
|
||||
|
||||
+47
-7
@@ -3,6 +3,7 @@ import typing
|
||||
from pyraknet.bitstream import *
|
||||
import pyraknet.replicamanager
|
||||
from pyraknet.messages import *
|
||||
from xml.etree import ElementTree
|
||||
|
||||
class BaseObject():
|
||||
def __init__(self, parent):
|
||||
@@ -67,9 +68,9 @@ class Vector3():
|
||||
self.Z : float = Z
|
||||
if(str_val is not None):
|
||||
vector_list = str_val.split(",")
|
||||
self.X = vector_list[0]
|
||||
self.Y = vector_list[1]
|
||||
self.Z = vector_list[2]
|
||||
self.X = float(vector_list[0])
|
||||
self.Y = float(vector_list[1])
|
||||
self.Z = float(vector_list[2])
|
||||
|
||||
def __add__(self, other):
|
||||
return Vector3(self.X + other.X,self.Y + other.Y,self.Z + other.Z)
|
||||
@@ -85,7 +86,46 @@ class Vector3():
|
||||
def __str__(self):
|
||||
return "{},{},{}".format(self.X, self.Y, self.Z)
|
||||
|
||||
def __eq__(self, other):
|
||||
if(self.X == other.X and self.Y == other.Y and self.Z == other.Z):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
class LDF():
|
||||
def __init__(self):
|
||||
self._keys : list = []
|
||||
def register_key(self, key_name : str, value : any, type : int):
|
||||
self._keys.append([key_name, value, type])
|
||||
def write_to_stream(self, stream : WriteStream):
|
||||
key_num = len(self._keys)
|
||||
stream.write(c_uint(key_num))
|
||||
for key in self._keys:
|
||||
name = key[0]
|
||||
value = key[1]
|
||||
type = key[2]
|
||||
stream.write(c_uint8(len(name) * 2))
|
||||
for char in name:
|
||||
stream.write(char.encode('latin1'))
|
||||
stream.write(b'\0')
|
||||
stream.write(c_ubyte(type))
|
||||
if(type == 0):
|
||||
stream.write(value, length_type=c_uint)
|
||||
elif(type == 1):
|
||||
stream.write(c_int(value))
|
||||
elif(type == 3):
|
||||
stream.write(c_float(value))
|
||||
elif(type == 5):
|
||||
stream.write(c_uint(value))
|
||||
elif(type == 7):
|
||||
stream.write(c_bool(value))
|
||||
elif(type == 8 or type == 9):
|
||||
stream.write(c_int64(value))
|
||||
elif(type == 13):
|
||||
xml_str = bytes(ElementTree.tostring(value))
|
||||
xml_str = b'<?xml version="1.0">' + xml_str
|
||||
stream.write(c_ulong(xml_str.__len__()))
|
||||
stream.write(xml_str)
|
||||
|
||||
class Vector4():
|
||||
def __init__(self, X : float = 0.0, Y : float = 0.0, Z : float = 0.0, W : float = 0.0, str_val: str = None):
|
||||
@@ -95,10 +135,10 @@ class Vector4():
|
||||
self.W : float = W
|
||||
if(str_val is not None):
|
||||
vector_list = str_val.split(",")
|
||||
self.X = vector_list[0]
|
||||
self.Y = vector_list[1]
|
||||
self.Z = vector_list[2]
|
||||
self.W = vector_list[3]
|
||||
self.X = float(vector_list[0])
|
||||
self.Y = float(vector_list[1])
|
||||
self.Z = float(vector_list[2])
|
||||
self.W = float(vector_list[3])
|
||||
|
||||
def __add__(self, other):
|
||||
return Vector4(self.X + other.X, self.Y + other.Y, self.Z + other.Z, self.W + other.W)
|
||||
|
||||
+4
-3
@@ -39,9 +39,10 @@ class PlayerService(services.GameService):
|
||||
account = account_table.select(["account_id", "username", "banned", "is_admin"], "account_id = {}".format(account_id))[0]
|
||||
characters = character_table.select_all("account_id = {}".format(account_id))
|
||||
for character in characters:
|
||||
character["Data"] = character_data_table.select_all("player_id = {}".format(character["player_id"]))[0]
|
||||
character["Data"]["position"] = game_types.Vector3(str_val=character["Data"]["position"])
|
||||
character["Data"]["rotation"] = game_types.Vector4(str_val=character["Data"]["rotation"])
|
||||
data = character_data_table.select_all("player_id = {}".format(character["player_id"]))[0]
|
||||
data["position"] = game_types.Vector3(str_val=data["position"])
|
||||
data["rotation"] = game_types.Vector4(str_val=data["rotation"])
|
||||
character["Data"] = data
|
||||
character["Stats"] = character_stats_table.select_all("player_id = {}".format(character["player_id"]))[0]
|
||||
character["CompletedMissions"] = completed_missions_table.select_all("player_id = {}".format(character["player_id"]))
|
||||
character["CurrentMissions"] = current_missions_table.select_all("player_id = {}".format(character["player_id"]))
|
||||
|
||||
Binary file not shown.
+9
-5
@@ -29,8 +29,11 @@ class WorldService(GameService):
|
||||
self._name = "World"
|
||||
self._scenes : typing.List[scene.Scene] = []
|
||||
|
||||
def add_scene(self, level : int, name : str = "Scene"):
|
||||
self._scenes.append(scene.Scene(self, level, name))
|
||||
def register_scene(self, level : int, name : str = "Scene"):
|
||||
new_scene = scene.Scene(self, level, name)
|
||||
self._scenes.append(new_scene)
|
||||
self.get_parent().trigger_event("SceneRegistered", args=(new_scene,))
|
||||
|
||||
|
||||
def get_scene_by_id(self, id : int):
|
||||
for scene in self._scenes:
|
||||
@@ -45,11 +48,12 @@ class WorldService(GameService):
|
||||
scenes.append(scene)
|
||||
return scenes
|
||||
|
||||
def get_scene_by_name(self, name: str):
|
||||
def get_scenes_by_name(self, name: str):
|
||||
scenes = []
|
||||
for scene in self._scenes:
|
||||
if(scene.get_name() == name):
|
||||
return scene
|
||||
return None
|
||||
scenes.append(scene)
|
||||
return scene
|
||||
|
||||
def get_scenes(self):
|
||||
return self._scenes
|
||||
|
||||
+98
-9
@@ -5,6 +5,8 @@ import game_enums
|
||||
import os
|
||||
import game_types
|
||||
from pyraknet.bitstream import *
|
||||
import zlib
|
||||
from xml.etree import ElementTree
|
||||
|
||||
|
||||
class WorldServer(pyraknet.server.Server):
|
||||
@@ -19,7 +21,9 @@ class WorldServer(pyraknet.server.Server):
|
||||
"world_session_info":["OnPacket_World_{}".format(game_enums.PacketHeaderEnum.CLIENT_USER_SESSION_INFO.value), self.handle_session_info],
|
||||
"world_minifigure_list":["OnPacket_World_{}".format(game_enums.PacketHeaderEnum.CLIENT_MINIFIGURE_LIST_REQUEST.value), self.handle_minifig_list_request],
|
||||
"world_minifig_creation":["OnPacket_World_{}".format(game_enums.PacketHeaderEnum.CLIENT_MINIFIGURE_CREATE_REQUEST.value), self.handle_minifig_creation],
|
||||
"world_minifig_deletion:":["OnPacket_World_{}".format(game_enums.PacketHeaderEnum.CLIENT_DELETE_MINIFIGURE_REQUEST.value), self.handle_minifig_deletion]}
|
||||
"world_minifig_deletion:":["OnPacket_World_{}".format(game_enums.PacketHeaderEnum.CLIENT_DELETE_MINIFIGURE_REQUEST.value), self.handle_minifig_deletion],
|
||||
"world_join_world":["OnPacket_World_{}".format(game_enums.PacketHeaderEnum.CLINET_ENTER_WORLD.value), self.handle_join_world],
|
||||
"world_detailed_user_info":["OnPacket_World_{}".format(game_enums.PacketHeaderEnum.CLIENT_LOAD_COMPLETE.value), self.handle_detailed_user_info]}
|
||||
|
||||
def handle_handshake(self, data: bytes, address):
|
||||
stream = ReadStream(data)
|
||||
@@ -85,24 +89,25 @@ class WorldServer(pyraknet.server.Server):
|
||||
time.sleep(.5)
|
||||
self.handle_minifig_list_request(data, address)
|
||||
|
||||
def load_world(self, player_id: int, level_id: int, spawn_at_default: bool = False):
|
||||
def load_world(self, player_id: int, level_id: int, address, spawn_at_default: bool = False):
|
||||
packet = WriteStream()
|
||||
player = game.get_service("Player").get_player_by_id(player_id)
|
||||
world = game.get_service("World")
|
||||
session = game.get_service("Session").get_session_by_player_id(player_id)
|
||||
session = game.get_service("Session").get_session_by_address(address)
|
||||
session.player_id = player_id
|
||||
scene = world.get_scenes_by_level(level_id)[0]
|
||||
print("Sending Player {} to {}".format(player_id, scene.get_name()))
|
||||
packet.write(game_enums.PacketHeaderEnum.WORLD_INFO)
|
||||
packet.write(game_enums.PacketHeaderEnum.WORLD_INFO.value)
|
||||
|
||||
packet.write(c_uint16(level_id))
|
||||
packet.write(c_uint16(0)) # Map Instance
|
||||
packet.write(c_ulong(0)) # Map Clone
|
||||
packet.write(c_ulong(game_enums.ZoneChecksums[level_id]))
|
||||
packet.write(c_ulong(game_enums.zone_checksums[level_id]))
|
||||
if (spawn_at_default):
|
||||
packet.write(c_float(game_enums.DefaultZoneSpawns[level_id][0]))
|
||||
packet.write(c_float(game_enums.DefaultZoneSpawns[level_id][1]))
|
||||
packet.write(c_float(game_enums.DefaultZoneSpawns[level_id][2]))
|
||||
player["position"] = game_types.Vector3(game_enums.DefaultZoneSpawns[level_id][0], game_enums.DefaultZoneSpawns[level_id][1], game_enums.DefaultZoneSpawns[level_id][2])
|
||||
packet.write(c_float(game_enums.default_zone_spawns[level_id][0]))
|
||||
packet.write(c_float(game_enums.default_zone_spawns[level_id][1]))
|
||||
packet.write(c_float(game_enums.default_zone_spawns[level_id][2]))
|
||||
player["position"] = game_types.Vector3(game_enums.default_zone_spawns[level_id][0], game_enums.default_zone_spawns[level_id][1], game_enums.default_zone_spawns[level_id][2])
|
||||
else:
|
||||
packet.write(c_float(player["position"].X))
|
||||
packet.write(c_float(player["position"].Y))
|
||||
@@ -116,8 +121,92 @@ class WorldServer(pyraknet.server.Server):
|
||||
else:
|
||||
game.get_pyobject(session.scene_id).remove_player(player_id)
|
||||
scene.add_player(player_id)
|
||||
session.scene_id = scene.get_py_id()
|
||||
self.send(packet, session.address)
|
||||
|
||||
def handle_detailed_user_info(self, data: bytes, address):
|
||||
session = game.get_service("Session").get_session_by_address(address)
|
||||
player = game.get_service("Player").get_player_by_id(session.player_id)
|
||||
|
||||
ldf = game_types.LDF()
|
||||
ldf.register_key("levelid", player["zone"], 1)
|
||||
ldf.register_key("objid", player["player_id"], 9)
|
||||
ldf.register_key("template", 1, 1)
|
||||
ldf.register_key("name", player["name"], 0)
|
||||
|
||||
root = ElementTree.Element("obj")
|
||||
root.set("v", "1")
|
||||
buff = ElementTree.SubElement(root, "buff")
|
||||
skill = ElementTree.SubElement(root, "skill")
|
||||
|
||||
inv = ElementTree.SubElement(root, "inv")
|
||||
bag = ElementTree.SubElement(inv, "bag")
|
||||
bag_info = ElementTree.SubElement(bag, "b")
|
||||
bag_info.set("t", "0")
|
||||
bag_info.set("m", str(player["Data"]["backpack_space"]))
|
||||
items = ElementTree.SubElement(inv, "items")
|
||||
item_in = ElementTree.SubElement(items, "in")
|
||||
for item in player["Inventory"]:
|
||||
i = ElementTree.SubElement(item_in, "i")
|
||||
i.set("l", str(item["lot"]))
|
||||
i.set("id", str(item["item_id"]))
|
||||
i.set("s", str(item["lot"]))
|
||||
i.set("c", str(item["quantity"]))
|
||||
i.set("b", str(int(item["linked"])))
|
||||
i.set("eq", str(int(item["equipped"])))
|
||||
|
||||
mf = ElementTree.SubElement(root, "mf")
|
||||
char = ElementTree.SubElement(root, "char")
|
||||
char.set("cc", str(player["currency"]))
|
||||
char.set("ls", str(player["universe_score"]))
|
||||
lvl = ElementTree.SubElement(root, "lvl")
|
||||
lvl.set("l", str(player["level"]))
|
||||
|
||||
pets = ElementTree.SubElement(root, "pet")
|
||||
|
||||
mis = ElementTree.SubElement(root, "mis")
|
||||
done = ElementTree.SubElement(mis, "done")
|
||||
for mission in player["CompletedMissions"]:
|
||||
m = ElementTree.SubElement(done, "m")
|
||||
m.set("id", str(mission["mission_id"]))
|
||||
m.set("cct", "1")
|
||||
m.set("cts", "0")
|
||||
cur = ElementTree.SubElement(mis, "cur")
|
||||
for mission in player["CurrentMissions"]:
|
||||
m = ElementTree.SubElement(cur, "m")
|
||||
m.set("id", str(mission["mission_id"]))
|
||||
sv = ElementTree.SubElement(m, "sv")
|
||||
sv.set("v", str(mission["progress"]))
|
||||
|
||||
ldf.register_key("xmlData", root, 13)
|
||||
|
||||
lego_data = WriteStream()
|
||||
ldf.write_to_stream(lego_data)
|
||||
ldf_bytes = bytes(lego_data)
|
||||
compressed = zlib.compress(ldf_bytes)
|
||||
|
||||
packet = WriteStream()
|
||||
packet.write(game_enums.PacketHeaderEnum.DETAILED_USER_INFO)
|
||||
packet.write(c_ulong(len(compressed) + 9))
|
||||
packet.write(c_bool(True))
|
||||
packet.write(c_ulong(len(ldf_bytes)))
|
||||
packet.write(c_ulong(len(compressed)))
|
||||
packet.write(compressed)
|
||||
|
||||
self.send(packet, address)
|
||||
print("Sent Detailed User Info To {}".format(player["name"]))
|
||||
|
||||
def handle_join_world(self, data: bytes, address):
|
||||
stream = ReadStream(data)
|
||||
player_id = stream.read(c_longlong)
|
||||
player = game.get_service("Player").get_player_by_id(player_id)
|
||||
if (player["zone"] == 0):
|
||||
player["zone"] = 1000
|
||||
spawn_at_default = False
|
||||
if (player["Data"]["position"].X < 2 and player["Data"]["position"].Y < 2 and player["Data"]["position"].Z < 2):
|
||||
spawn_at_default = True
|
||||
self.load_world(player_id, player["zone"], address, spawn_at_default=spawn_at_default)
|
||||
|
||||
def handle_session_info(self, data: bytes, address):
|
||||
stream = ReadStream(data)
|
||||
username = stream.read(str, allocated_length=33)
|
||||
|
||||
Reference in New Issue
Block a user