mirror of
https://github.com/lcdr/luserver.git
synced 2025-12-30 02:09:30 -06:00
v2016.12.29
- refactor LDF - collectible missions now properly save which specific collectibles have been collected
This commit is contained in:
@@ -31,7 +31,7 @@ class LoginReturnCode:
|
||||
AccountNotActivated = 14
|
||||
|
||||
class AuthServer(server.Server):
|
||||
PEER_TYPE = AuthServerMsg.__int__()
|
||||
PEER_TYPE = AuthServerMsg.header()
|
||||
|
||||
def __init__(self, host, max_connections, db_conn):
|
||||
super().__init__((host, 1001), max_connections, db_conn)
|
||||
|
||||
@@ -3,7 +3,7 @@ from .messages import Message
|
||||
|
||||
def write_header(self, subheader):
|
||||
self.write(c_ubyte(Message.LUPacket))
|
||||
self.write(c_ushort(type(subheader).__int__()))
|
||||
self.write(c_ushort(type(subheader).header()))
|
||||
self.write(c_uint(subheader))
|
||||
self.write(c_ubyte(0x00))
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from persistent.list import PersistentList
|
||||
from persistent.mapping import PersistentMapping
|
||||
|
||||
from ..bitstream import BitStream, c_bit, c_bool, c_float, c_int, c_int64, c_ubyte, c_uint, c_uint64, c_ushort
|
||||
from ..ldf import LDF, LDFDataType
|
||||
from ..messages import WorldClientMsg
|
||||
from ..world import World
|
||||
from ..math.quaternion import Quaternion
|
||||
@@ -287,7 +288,7 @@ class CharacterComponent(Component):
|
||||
loot.append(lot)
|
||||
return loot
|
||||
|
||||
async def transfer_to_world(self, world, respawn_point_name=None):
|
||||
async def transfer_to_world(self, world, respawn_point_name=None, include_self=False):
|
||||
if respawn_point_name is not None:
|
||||
for obj in self.object._v_server.db.world_data[world[0]].objects.values():
|
||||
if obj.lot == 4945 and (not hasattr(obj, "respawn_name") or respawn_point_name == "" or obj.respawn_name == respawn_point_name): # respawn point lot
|
||||
@@ -299,9 +300,9 @@ class CharacterComponent(Component):
|
||||
self.object.physics.rotation.update(self.object._v_server.db.world_data[world[0]].spawnpoint[1])
|
||||
self.object.physics.attr_changed("position")
|
||||
self.object.physics.attr_changed("rotation")
|
||||
self.object._v_server.commit()
|
||||
self.object._v_server.commit()
|
||||
|
||||
server_address = await self.object._v_server.address_for_world(world)
|
||||
server_address = await self.object._v_server.address_for_world(world, include_self)
|
||||
log.info("Sending redirect to world %s", server_address)
|
||||
redirect = BitStream()
|
||||
redirect.write_header(WorldClientMsg.Redirect)
|
||||
@@ -310,6 +311,15 @@ class CharacterComponent(Component):
|
||||
redirect.write(c_bool(False))
|
||||
self.object._v_server.send(redirect, self.address)
|
||||
|
||||
async def transfer_to_last_non_instance(self, position=None, rotation=None):
|
||||
if position is not None:
|
||||
self.object.physics.position.update(position)
|
||||
self.object.physics.attr_changed("position")
|
||||
if rotation is not None:
|
||||
self.object.physics.rotation.update(rotation)
|
||||
self.object.physics.attr_changed("rotation")
|
||||
await self.transfer_to_world(((self.world[0] // 100)*100, self.world[1], self.world[2]))
|
||||
|
||||
def add_mission(self, mission_id):
|
||||
mission_progress = MissionProgress(mission_id, self.object._v_server.db.missions[mission_id])
|
||||
self.missions.append(mission_progress)
|
||||
@@ -439,7 +449,6 @@ class CharacterComponent(Component):
|
||||
if task.type == TaskType.Flag and flag_id in task.target:
|
||||
mission.increment_task(task, self.object)
|
||||
|
||||
|
||||
def player_loaded(self, address, player_id:c_int64=None):
|
||||
pass
|
||||
|
||||
@@ -452,7 +461,7 @@ class CharacterComponent(Component):
|
||||
def set_jet_pack_mode(self, address, bypass_checks:c_bit=True, hover:c_bit=False, enable:c_bit=False, effect_id:c_uint=-1, air_speed:c_float=10, max_air_speed:c_float=15, vertical_velocity:c_float=1, warning_effect_id:c_uint=-1):
|
||||
pass
|
||||
|
||||
def display_tooltip(self, address, do_or_die:c_bit=False, no_repeat:c_bit=False, no_revive:c_bit=False, is_property_tooltip:c_bit=False, show:c_bit=None, translate:c_bit=False, time:c_int=None, id:"wstr"=None, localize_params:"ldf"=None, str_image_name:"wstr"=None, str_text:"wstr"=None):
|
||||
def display_tooltip(self, address, do_or_die:c_bit=False, no_repeat:c_bit=False, no_revive:c_bit=False, is_property_tooltip:c_bit=False, show:c_bit=None, translate:c_bit=False, time:c_int=None, id:"wstr"=None, localize_params:LDF=None, str_image_name:"wstr"=None, str_text:"wstr"=None):
|
||||
pass
|
||||
|
||||
def use_non_equipment_item(self, address, item_to_use:c_int64=None):
|
||||
@@ -562,18 +571,18 @@ class CharacterComponent(Component):
|
||||
def get_models_on_property(self, address, models:(c_uint, c_int64, c_int64)=None):
|
||||
pass
|
||||
|
||||
def match_request(self, address, activator:c_int64=None, player_choices:"ldf"=None, type:c_int=None, value:c_int=None):
|
||||
def match_request(self, address, activator:c_int64=None, player_choices:LDF=None, type:c_int=None, value:c_int=None):
|
||||
# todo: how does the server know which matchmaking activity the client wants?
|
||||
self.object._v_server.send_game_message(self.match_response, response=0, address=address)
|
||||
if type == MatchRequestType.Join:# and value == MatchRequestValue.Join:
|
||||
update_data = {}
|
||||
update_data["time"] = c_float, 60
|
||||
update_data = LDF()
|
||||
update_data.ldf_set("time", LDFDataType.FLOAT, 60.0)
|
||||
self.object._v_server.send_game_message(self.match_update, data=update_data, type=MatchUpdateType.Time, address=address)
|
||||
|
||||
def match_response(self, address, response:c_int=None):
|
||||
pass
|
||||
|
||||
def match_update(self, address, data:"ldf"=None, type:c_int=None):
|
||||
def match_update(self, address, data:LDF=None, type:c_int=None):
|
||||
pass
|
||||
|
||||
def used_information_plaque(self, address, plaque_object_id:c_int64=None):
|
||||
|
||||
@@ -3,8 +3,12 @@ from .component import Component
|
||||
from .mission import MissionState, TaskType
|
||||
|
||||
class CollectibleComponent(Component):
|
||||
def __init__(self, obj, set_vars, comp_id):
|
||||
super().__init__(obj, set_vars, comp_id)
|
||||
self.collectible_id = set_vars.get("collectible_id", 0)
|
||||
|
||||
def serialize(self, out, is_creation):
|
||||
out.write(c_ushort(0)) # todo
|
||||
out.write(c_ushort(self.collectible_id))
|
||||
|
||||
def has_been_collected(self, address, player_id:c_int64=None):
|
||||
player = self.object._v_server.game_objects[player_id]
|
||||
@@ -13,4 +17,5 @@ class CollectibleComponent(Component):
|
||||
if mission.state == MissionState.Active:
|
||||
for task in mission.tasks:
|
||||
if task.type == TaskType.Collect and task.target == self.object.lot:
|
||||
mission.increment_task(task, player)
|
||||
coll_id = self.collectible_id+(self.object._v_server.world_id[0]<<8)
|
||||
mission.increment_task(task, player, increment=coll_id)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import asyncio
|
||||
from ..bitstream import c_bit, c_float, c_int, c_int64
|
||||
from ..ldf import LDF
|
||||
from .component import Component
|
||||
|
||||
class Comp108Component(Component):
|
||||
@@ -25,7 +26,7 @@ class Comp108Component(Component):
|
||||
assert multi_interact_id is None
|
||||
self.driver_id = player.object_id
|
||||
player.char.vehicle_id = self.object.object_id
|
||||
self.object._v_server.send_game_message(player.char.display_tooltip, show=True, time=1000, id="", localize_params={}, str_image_name="", str_text="Use /dismount to dismount.", address=player.char.address)
|
||||
self.object._v_server.send_game_message(player.char.display_tooltip, show=True, time=1000, id="", localize_params=LDF(), str_image_name="", str_text="Use /dismount to dismount.", address=player.char.address)
|
||||
|
||||
def request_die(self, address, unknown_bool:c_bit=None, death_type:"wstr"=None, direction_relative_angle_xz:c_float=None, direction_relative_angle_y:c_float=None, direction_relative_force:c_float=None, kill_type:c_int=0, killer_id:c_int64=None, loot_owner_id:c_int64=None):
|
||||
#self.object.destructible.deal_damage(10000, self) # die permanently on crash
|
||||
|
||||
@@ -36,6 +36,7 @@ from persistent import Persistent
|
||||
from persistent.list import PersistentList
|
||||
|
||||
from ..bitstream import c_bit, c_int, c_int64, c_uint
|
||||
from ..ldf import LDF, LDFDataType
|
||||
from ..math.vector import Vector3
|
||||
from .component import Component
|
||||
from .mission import MissionState, TaskType
|
||||
@@ -196,9 +197,9 @@ class InventoryComponent(Component):
|
||||
|
||||
if hasattr(self.object, "char"):
|
||||
if notify_client:
|
||||
extra_info = {}
|
||||
extra_info = LDF()
|
||||
if hasattr(stack, "module_lots"):
|
||||
extra_info["assemblyPartLOTs"] = str, [(c_int, i) for i in stack.module_lots]
|
||||
extra_info.ldf_set("assemblyPartLOTs", LDFDataType.STRING, [(LDFDataType.INT32, i) for i in stack.module_lots])
|
||||
|
||||
self.object._v_server.send_game_message(self.add_item_to_inventory_client_sync, bound=True, bound_on_equip=True, bound_on_pickup=True, loot_type_source=source_type, extra_info=extra_info, object_template=stack.lot, inv_type=inventory_type, amount=1, new_obj_id=stack.object_id, flying_loot_pos=Vector3.zero, show_flying_loot=show_flying_loot, slot_id=index, address=self.object.char.address)
|
||||
|
||||
@@ -212,7 +213,7 @@ class InventoryComponent(Component):
|
||||
|
||||
return stack
|
||||
|
||||
def add_item_to_inventory_client_sync(self, address, bound:c_bit=False, bound_on_equip:c_bit=False, bound_on_pickup:c_bit=False, loot_type_source:c_int=0, extra_info:"ldf"=None, object_template:c_int=None, subkey:c_int64=0, inv_type:c_int=0, amount:c_uint=1, item_total:c_uint=0, new_obj_id:c_int64=None, flying_loot_pos:Vector3=None, show_flying_loot:c_bit=True, slot_id:c_int=None):
|
||||
def add_item_to_inventory_client_sync(self, address, bound:c_bit=False, bound_on_equip:c_bit=False, bound_on_pickup:c_bit=False, loot_type_source:c_int=0, extra_info:LDF=None, object_template:c_int=None, subkey:c_int64=0, inv_type:c_int=0, amount:c_uint=1, item_total:c_uint=0, new_obj_id:c_int64=None, flying_loot_pos:Vector3=None, show_flying_loot:c_bit=True, slot_id:c_int=None):
|
||||
pass
|
||||
|
||||
def remove_item_from_inv(self, inventory_type, item=None, object_id=0, lot=0, amount=1):
|
||||
@@ -220,9 +221,9 @@ class InventoryComponent(Component):
|
||||
object_id = item.object_id
|
||||
|
||||
if hasattr(self.object, "char"):
|
||||
self.object._v_server.send_game_message(self.remove_item_from_inventory, inventory_type=inventory_type, extra_info={}, force_deletion=True, object_id=object_id, object_template=lot, stack_count=amount, address=self.object.char.address)
|
||||
self.object._v_server.send_game_message(self.remove_item_from_inventory, inventory_type=inventory_type, extra_info=LDF, force_deletion=True, object_id=object_id, object_template=lot, stack_count=amount, address=self.object.char.address)
|
||||
|
||||
def remove_item_from_inventory(self, address, confirmed:c_bit=True, delete_item:c_bit=True, out_success:c_bit=False, inventory_type:c_int=0, loot_type_source:c_int=0, extra_info:"ldf"=None, force_deletion:c_bit=False, loot_type_source_id:c_int64=0, object_id:c_int64=0, object_template:c_int=0, requesting_object_id:c_int64=0, stack_count:c_uint=1, stack_remaining:c_uint=0, subkey:c_int64=0, trade_id:c_int64=0):
|
||||
def remove_item_from_inventory(self, address, confirmed:c_bit=True, delete_item:c_bit=True, out_success:c_bit=False, inventory_type:c_int=0, loot_type_source:c_int=0, extra_info:LDF=None, force_deletion:c_bit=False, loot_type_source_id:c_int64=0, object_id:c_int64=0, object_template:c_int=0, requesting_object_id:c_int64=0, stack_count:c_uint=1, stack_remaining:c_uint=0, subkey:c_int64=0, trade_id:c_int64=0):
|
||||
if confirmed:
|
||||
assert delete_item
|
||||
assert not out_success
|
||||
|
||||
@@ -57,6 +57,8 @@ class MissionTask(Persistent):
|
||||
self.target = target
|
||||
self.value = 0
|
||||
self.target_value = target_value
|
||||
if task_type == TaskType.Collect:
|
||||
parameter = set() # used for collectibles
|
||||
self.parameter = parameter
|
||||
|
||||
class MissionProgress(Persistent):
|
||||
@@ -84,9 +86,16 @@ class MissionProgress(Persistent):
|
||||
if not self.is_mission and not check_prereqs(self.id, player):
|
||||
return
|
||||
|
||||
task.value = min(task.value+increment, task.target_value)
|
||||
task_index = self.tasks.index(task)
|
||||
player._v_server.send_game_message(player.char.notify_mission_task, self.id, task_mask=1<<(task_index+1), updates=[task.value], address=player.char.address)
|
||||
|
||||
if task.type == TaskType.Collect:
|
||||
task.parameter.add(increment)
|
||||
task.value = len(task.parameter)
|
||||
update = increment
|
||||
else:
|
||||
task.value = min(task.value+increment, task.target_value)
|
||||
update = task.value
|
||||
player._v_server.send_game_message(player.char.notify_mission_task, self.id, task_mask=1<<(task_index+1), updates=[update], address=player.char.address)
|
||||
if not self.is_mission:
|
||||
for task in self.tasks:
|
||||
if task.value < task.target_value:
|
||||
|
||||
@@ -8,6 +8,7 @@ from .component import Component
|
||||
class MovingPlatformComponent(Component):
|
||||
def __init__(self, obj, set_vars, comp_id):
|
||||
super().__init__(obj, set_vars, comp_id)
|
||||
self.object.moving_platform = self
|
||||
self._flags["moving_platform_unknown"] = "moving_platform_flag"
|
||||
self._flags["target_position"] = "moving_platform_flag"
|
||||
self.target_position = Vector3()
|
||||
|
||||
@@ -123,6 +123,10 @@ class RebuildComponent(ScriptedActivityComponent):
|
||||
# drop rewards
|
||||
self.object.stats.drop_rewards(*self.completion_rewards, player)
|
||||
|
||||
# if this is a moving platform, set the waypoint
|
||||
if hasattr(self, "moving_platform"):
|
||||
self.moving_platform.update_waypoint()
|
||||
|
||||
# update missions that have completing this rebuild as requirement
|
||||
for mission in player.char.missions:
|
||||
if mission.state == MissionState.Active:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from .. ldf import LDF
|
||||
from ..bitstream import c_bit, c_int, c_int64
|
||||
from .component import Component
|
||||
|
||||
@@ -9,11 +10,15 @@ class ScriptComponent(Component):
|
||||
if "script_vars" in set_vars:
|
||||
self.script_vars = set_vars["script_vars"]
|
||||
|
||||
self.script_network_vars = LDF()
|
||||
|
||||
def serialize(self, out, is_creation):
|
||||
if is_creation:
|
||||
out.write(c_bit(False))
|
||||
out.write(c_bit(self.script_network_vars))
|
||||
if self.script_network_vars:
|
||||
out.write(self.script_network_vars.to_bitstream())
|
||||
|
||||
def script_network_var_update(self, address, script_vars:"ldf"=None):
|
||||
def script_network_var_update(self, address, script_vars:LDF=None):
|
||||
pass
|
||||
|
||||
def notify_client_object(self, address, name:"wstr"=None, param1:c_int=None, param2:c_int=None, param_obj:c_int64=None, param_str:"str"=None):
|
||||
|
||||
@@ -21,6 +21,9 @@ class ScriptedActivityComponent(Component):
|
||||
out.write(c_float(0))
|
||||
self.activity_flag = False
|
||||
|
||||
def activity_start(self, address):
|
||||
pass
|
||||
|
||||
def message_box_respond(self, address, button:c_int=None, identifier:"wstr"=None, user_data:"wstr"=None):
|
||||
if identifier == "LobbyReady" and button == 1:
|
||||
player = self.object._v_server.accounts[address].characters.selected()
|
||||
|
||||
@@ -4,7 +4,7 @@ from collections import OrderedDict
|
||||
|
||||
from persistent import Persistent
|
||||
|
||||
from . import ldf
|
||||
from .ldf import LDF
|
||||
from .bitstream import BitStream, c_bit, c_float, c_int, c_int64, c_ubyte, c_uint, c_ushort
|
||||
from .components.ai import BaseCombatAIComponent
|
||||
from .components.bouncer import BouncerComponent
|
||||
@@ -89,7 +89,7 @@ class GameObject:
|
||||
self.lot = lot
|
||||
self.object_id = object_id
|
||||
self.name = ""
|
||||
self.config = set_vars.get("config", {})
|
||||
self.config = set_vars.get("config", LDF())
|
||||
self.spawner_object = None
|
||||
self.spawner_waypoint_index = 0
|
||||
self.scale = set_vars.get("scale", 1)
|
||||
@@ -170,7 +170,7 @@ class GameObject:
|
||||
out.write(bytes(4)) # time since created on server?
|
||||
out.write(c_bit(self.config))
|
||||
if self.config:
|
||||
out.write(ldf.to_ldf(self.config, ldf_type="binary"))
|
||||
out.write(self.config.to_bitstream())
|
||||
out.write(c_bit(hasattr(self, "trigger")))
|
||||
out.write(c_bit(self.spawner_object is not None))
|
||||
if self.spawner_object is not None:
|
||||
|
||||
213
luserver/ldf.py
213
luserver/ldf.py
@@ -1,55 +1,145 @@
|
||||
import enum
|
||||
|
||||
from .bitstream import BitStream, c_bool, c_float, c_int, c_int64, c_ubyte, c_uint
|
||||
|
||||
DATA_TYPE = {}
|
||||
DATA_TYPE[str] = 0
|
||||
DATA_TYPE[c_int] = 1
|
||||
DATA_TYPE[c_float] = 3
|
||||
DATA_TYPE[c_bool] = 7
|
||||
DATA_TYPE[c_int64] = 9 # or 8?
|
||||
DATA_TYPE[bytes] = 13 # let's just use bytes for 13
|
||||
DATA_TYPE[0] = str
|
||||
DATA_TYPE[1] = int # signed int
|
||||
DATA_TYPE[3] = float
|
||||
DATA_TYPE[5] = int # unsigned int
|
||||
DATA_TYPE[7] = lambda x: bool(int(x))
|
||||
DATA_TYPE[9] = int
|
||||
DATA_TYPE[13] = lambda x: x.encode() # see above
|
||||
class LDFDataType(enum.Enum):
|
||||
STRING = 0
|
||||
INT32 = 1
|
||||
FLOAT = 3
|
||||
UINT32 = 5
|
||||
BOOLEAN = 7
|
||||
INT64_8 = 8
|
||||
INT64_9 = 9
|
||||
BYTES = 13
|
||||
|
||||
def _value_to_ldf_text(type_, value):
|
||||
if isinstance(value, (list, tuple)):
|
||||
str_value = "+".join(_value_to_ldf_text(typ, val) for typ, val in value)
|
||||
value = ""
|
||||
else:
|
||||
str_value = str(value)
|
||||
return "%i:%s" % (DATA_TYPE[type_], str_value)
|
||||
class LDF(dict):
|
||||
def __init__(self, source=None):
|
||||
super().__init__()
|
||||
if source is not None:
|
||||
if isinstance(source, str):
|
||||
self.from_str(source)
|
||||
elif isinstance(source, BitStream):
|
||||
self.from_bitstream(source)
|
||||
|
||||
def to_ldf(obj, ldf_type):
|
||||
if ldf_type == "text":
|
||||
if isinstance(obj, dict):
|
||||
output = "\n".join("%s=%s" % (key, _value_to_ldf_text(*value)) for key, value in obj.items())
|
||||
def __getitem__(self, key):
|
||||
return self.ldf_get(key)[1]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
return self.ldf_set(key, self.ldf_get(key)[0], value)
|
||||
|
||||
def ldf_get(self, key):
|
||||
return super().__getitem__(key)
|
||||
|
||||
def ldf_set(self, key, data_type, value):
|
||||
if not isinstance(data_type, LDFDataType):
|
||||
raise TypeError
|
||||
if data_type == LDFDataType.STRING:
|
||||
if not isinstance(value, (str, list, tuple)):
|
||||
raise TypeError
|
||||
elif data_type in (LDFDataType.INT32, LDFDataType.UINT32, LDFDataType.INT64_8, LDFDataType.INT64_9):
|
||||
if not isinstance(value, int):
|
||||
raise TypeError
|
||||
if data_type == LDFDataType.UINT32:
|
||||
if value < 0:
|
||||
raise ValueError
|
||||
elif data_type == LDFDataType.FLOAT:
|
||||
if not isinstance(value, float):
|
||||
raise TypeError
|
||||
elif data_type == LDFDataType.BOOLEAN:
|
||||
if not isinstance(value, bool):
|
||||
raise TypeError
|
||||
elif data_type == LDFDataType.BYTES:
|
||||
if not isinstance(value, bytes):
|
||||
raise TypeError
|
||||
return super().__setitem__(key, (data_type, value))
|
||||
|
||||
def from_str(self, source):
|
||||
items = source.split("\x0a")
|
||||
for item in items:
|
||||
key, type_value = item.split("=", maxsplit=1)
|
||||
data_type, value = self.from_str_type(type_value)
|
||||
self.ldf_set(key, data_type, value)
|
||||
|
||||
def to_str(self):
|
||||
return "\n".join("%s=%s" % (key, self.to_str_type(*value)) for key, value in super().items())
|
||||
|
||||
@staticmethod
|
||||
def from_str_type(type_value):
|
||||
data_type_id, value = type_value.split(":", maxsplit=1)
|
||||
data_type = LDFDataType(int(data_type_id))
|
||||
if data_type == LDFDataType.STRING:
|
||||
value = value
|
||||
elif data_type in (LDFDataType.INT32, LDFDataType.UINT32, LDFDataType.INT64_8, LDFDataType.INT64_9):
|
||||
value = int(value)
|
||||
elif data_type == LDFDataType.FLOAT:
|
||||
value = float(value)
|
||||
elif data_type == LDFDataType.BOOLEAN:
|
||||
value = bool(int(value))
|
||||
elif data_type == LDFDataType.BYTES:
|
||||
value = value.encode()
|
||||
return data_type, value
|
||||
|
||||
@staticmethod
|
||||
def to_str_type(data_type, value):
|
||||
if isinstance(value, (list, tuple)):
|
||||
str_value = "+".join(LDF.to_str_type(data_type, val) for data_type, val in value)
|
||||
else:
|
||||
output = _value_to_ldf_text(*obj)
|
||||
if data_type == LDFDataType.STRING:
|
||||
str_value = value
|
||||
elif data_type in (LDFDataType.INT32, LDFDataType.FLOAT, LDFDataType.UINT32, LDFDataType.INT64_8, LDFDataType.INT64_9):
|
||||
str_value = str(value)
|
||||
elif data_type == LDFDataType.BOOLEAN:
|
||||
str_value = str(int(value))
|
||||
elif data_type == LDFDataType.BYTES:
|
||||
str_value = value.decode()
|
||||
return "%i:%s" % (data_type.value, str_value)
|
||||
|
||||
elif ldf_type == "binary":
|
||||
if not isinstance(obj, dict):
|
||||
raise NotImplementedError
|
||||
def from_bitstream(self, source):
|
||||
for _ in range(source.read(c_uint)):
|
||||
encoded_key = source.read(bytes, length=source.read(c_ubyte))
|
||||
key = encoded_key.decode("utf-16-le")
|
||||
data_type = LDFDataType(source.read(c_ubyte))
|
||||
if data_type == LDFDataType.STRING:
|
||||
value = source.read(str, length_type=c_uint)
|
||||
elif data_type == LDFDataType.INT32:
|
||||
value = source.read(c_int)
|
||||
elif data_type == LDFDataType.FLOAT:
|
||||
value = source.read(c_float)
|
||||
elif data_type == LDFDataType.UINT32:
|
||||
value = source.read(c_uint)
|
||||
elif data_type == LDFDataType.BOOLEAN:
|
||||
value = source.read(c_bool)
|
||||
elif data_type in (LDFDataType.INT64_8, LDFDataType.INT64_9):
|
||||
value = source.read(c_int64)
|
||||
elif data_type == LDFDataType.BYTES:
|
||||
value = source.read(bytes, length=source.read(c_uint))
|
||||
self.ldf_set(key, data_type, value)
|
||||
|
||||
def to_bitstream(self):
|
||||
uncompressed = BitStream()
|
||||
uncompressed.write(c_uint(len(obj)))
|
||||
for key, value in obj.items():
|
||||
value_type, value_value = value # meh this isn't exactly descriptive
|
||||
|
||||
uncompressed.write(c_uint(len(self)))
|
||||
for key, value in super().items():
|
||||
data_type, value = value
|
||||
# can't use normal variable string writing because this writes the length of the encoded instead of the original (include option for this behavior?)
|
||||
encoded_key = key.encode("utf-16-le")
|
||||
uncompressed.write(c_ubyte(len(encoded_key)))
|
||||
uncompressed.write(encoded_key)
|
||||
uncompressed.write(c_ubyte(DATA_TYPE[value_type]))
|
||||
if value_type == str:
|
||||
uncompressed.write(value_value, length_type=c_uint)
|
||||
|
||||
else:
|
||||
if value_type == bytes:
|
||||
uncompressed.write(c_uint(len(value_value)))
|
||||
uncompressed.write(value_type(value_value))
|
||||
uncompressed.write(c_ubyte(data_type.value))
|
||||
if data_type == LDFDataType.STRING:
|
||||
uncompressed.write(value, length_type=c_uint)
|
||||
elif data_type == LDFDataType.INT32:
|
||||
uncompressed.write(c_int(value))
|
||||
elif data_type == LDFDataType.FLOAT:
|
||||
uncompressed.write(c_float(value))
|
||||
elif data_type == LDFDataType.UINT32:
|
||||
uncompressed.write(c_uint(value))
|
||||
elif data_type == LDFDataType.BOOLEAN:
|
||||
uncompressed.write(c_bool(value))
|
||||
elif data_type in (LDFDataType.INT64_8, LDFDataType.INT64_9):
|
||||
uncompressed.write(c_int64(value))
|
||||
elif data_type == LDFDataType.BYTES:
|
||||
uncompressed.write(c_uint(len(value)))
|
||||
uncompressed.write(value)
|
||||
|
||||
output = BitStream()
|
||||
is_compressed = False
|
||||
@@ -59,43 +149,4 @@ def to_ldf(obj, ldf_type):
|
||||
raise NotImplementedError
|
||||
output.write(c_bool(is_compressed))
|
||||
output.write(uncompressed)
|
||||
|
||||
return output
|
||||
|
||||
def from_ldf_type_value(type_value): # in its own function for use in luz path spawners where the structure is different
|
||||
data_type_id, value = type_value.split(":", maxsplit=1)
|
||||
data_type_id = int(data_type_id)
|
||||
return DATA_TYPE[data_type_id](value)
|
||||
|
||||
def from_ldf(ldf):
|
||||
ldf_dict = {}
|
||||
if isinstance(ldf, str):
|
||||
items = ldf.split("\x0a")
|
||||
for item in items:
|
||||
key, type_value = item.split("=", maxsplit=1)
|
||||
value = from_ldf_type_value(type_value)
|
||||
ldf_dict[key] = value
|
||||
elif isinstance(ldf, BitStream):
|
||||
for _ in range(ldf.read(c_uint)):
|
||||
encoded_key = ldf.read(bytes, length=ldf.read(c_ubyte))
|
||||
key = encoded_key.decode("utf-16-le")
|
||||
data_type_id = ldf.read(c_ubyte)
|
||||
if data_type_id == 0:
|
||||
value = ldf.read(str, length_type=c_uint)
|
||||
elif data_type_id == 1:
|
||||
value = ldf.read(c_int)
|
||||
elif data_type_id == 5:
|
||||
value = ldf.read(c_uint)
|
||||
elif data_type_id == 7:
|
||||
value = ldf.read(c_bool)
|
||||
elif data_type_id in (8, 9):
|
||||
value = ldf.read(c_int64)
|
||||
elif data_type_id == 13:
|
||||
value = ldf.read(bytes, length=ldf.read(c_uint))
|
||||
else:
|
||||
raise NotImplementedError(key, data_type_id)
|
||||
ldf_dict[key] = value
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
return ldf_dict
|
||||
return output
|
||||
|
||||
@@ -4,11 +4,9 @@ from pyraknet.messages import Message
|
||||
|
||||
Message.LUPacket = 0x53
|
||||
|
||||
# for the enums below, __int__() returns the corresponding header
|
||||
|
||||
class GeneralMsg(IntEnum):
|
||||
@staticmethod
|
||||
def __int__():
|
||||
def header():
|
||||
return 0x00
|
||||
|
||||
Handshake = 0x00
|
||||
@@ -17,14 +15,14 @@ class GeneralMsg(IntEnum):
|
||||
|
||||
class AuthServerMsg(IntEnum):
|
||||
@staticmethod
|
||||
def __int__():
|
||||
def header():
|
||||
return 0x01
|
||||
|
||||
LoginRequest = 0x00
|
||||
|
||||
class SocialMsg(IntEnum):
|
||||
@staticmethod
|
||||
def __int__():
|
||||
def header():
|
||||
return 0x02
|
||||
|
||||
GeneralChatMessage = 0x01
|
||||
@@ -40,7 +38,7 @@ class SocialMsg(IntEnum):
|
||||
|
||||
class WorldServerMsg(IntEnum):
|
||||
@staticmethod
|
||||
def __int__():
|
||||
def header():
|
||||
return 0x04
|
||||
|
||||
SessionInfo = 0x01
|
||||
@@ -58,7 +56,7 @@ class WorldServerMsg(IntEnum):
|
||||
|
||||
class WorldClientMsg(IntEnum):
|
||||
@staticmethod
|
||||
def __int__():
|
||||
def header():
|
||||
return 0x05
|
||||
|
||||
LoginResponse = 0x00
|
||||
@@ -90,7 +88,7 @@ msg_enum[0x05] = WorldClientMsg
|
||||
class GameMessage(Enum):
|
||||
Teleport = 19
|
||||
DropClientLoot = 30
|
||||
Die = 37
|
||||
Die = 37
|
||||
RequestDie = 38
|
||||
PlayEmote = 41
|
||||
PlayAnimation = 43
|
||||
@@ -126,6 +124,7 @@ class GameMessage(Enum):
|
||||
BuyFromVendor = 373
|
||||
SellToVendor = 374
|
||||
SetInventorySize = 389
|
||||
ActivityStart = 407
|
||||
VendorStatusUpdate = 417
|
||||
ClientItemConsumed = 428
|
||||
SetFlag = 471
|
||||
|
||||
@@ -218,7 +218,7 @@ class CharHandling(ServerModule):
|
||||
selected_char.char.world = 1000, 0, 0
|
||||
asyncio.ensure_future(selected_char.char.transfer_to_world(selected_char.char.world, respawn_point_name=""))
|
||||
else:
|
||||
asyncio.ensure_future(selected_char.char.transfer_to_world(selected_char.char.world))
|
||||
asyncio.ensure_future(selected_char.char.transfer_to_world(selected_char.char.world, include_self=True))
|
||||
|
||||
def shirt_to_lot(self, color, style):
|
||||
# The LOTs for the shirts are for some reason in two batches of IDs
|
||||
|
||||
@@ -4,10 +4,11 @@ For world server packet handling that is general enough not to be grouped in a s
|
||||
import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from .. import ldf
|
||||
from ..ldf import LDF, LDFDataType
|
||||
from ..bitstream import BitStream, c_bit, c_float, c_int, c_int64, c_uint, c_ushort
|
||||
from ..messages import WorldClientMsg, WorldServerMsg
|
||||
from ..world import World
|
||||
from ..components.mission import TaskType
|
||||
from .module import ServerModule
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -112,8 +113,8 @@ class GeneralHandling(ServerModule):
|
||||
for model in models:
|
||||
i = ET.SubElement(in_5, "i", l=str(model.lot), c=str(model.amount), id=str(model.object_id), s=str(player.inventory.models.index(model)))
|
||||
if hasattr(model, "module_lots"):
|
||||
module_lots = [(c_int, i) for i in model.module_lots]
|
||||
module_lots = ldf.to_ldf((str, module_lots), ldf_type="text")
|
||||
module_lots = [(LDFDataType.INT32, i) for i in model.module_lots]
|
||||
module_lots = LDF().to_str_type(LDFDataType.STRING, module_lots)
|
||||
ET.SubElement(i, "x", ma=module_lots)
|
||||
|
||||
flag = ET.SubElement(root, "flag")
|
||||
@@ -138,6 +139,9 @@ class GeneralHandling(ServerModule):
|
||||
ET.SubElement(m, "sv")
|
||||
else:
|
||||
ET.SubElement(m, "sv", v=str(task.value))
|
||||
if task.type == TaskType.Collect:
|
||||
for collectible_id in task.parameter:
|
||||
ET.SubElement(m, "sv", v=str(collectible_id))
|
||||
elif mission.state == 8:
|
||||
ET.SubElement(done, "m", id=str(mission.id))
|
||||
|
||||
@@ -145,13 +149,13 @@ class GeneralHandling(ServerModule):
|
||||
xml = xml.dom.minidom.parseString((ET.tostring(root, encoding="unicode")))
|
||||
#log.debug(xml.toprettyxml(indent=" "))
|
||||
|
||||
chd_ldf = {}
|
||||
chd_ldf["objid"] = c_int64, player.object_id
|
||||
chd_ldf["template"] = c_int, 1
|
||||
chd_ldf["name"] = str, player.name
|
||||
chd_ldf["xmlData"] = bytes, ET.tostring(root)
|
||||
chd_ldf = LDF()
|
||||
chd_ldf.ldf_set("objid", LDFDataType.INT64_9, player.object_id)
|
||||
chd_ldf.ldf_set("template", LDFDataType.INT32, 1)
|
||||
chd_ldf.ldf_set("name", LDFDataType.STRING, player.name)
|
||||
chd_ldf.ldf_set("xmlData", LDFDataType.BYTES, ET.tostring(root))
|
||||
|
||||
encoded_ldf = ldf.to_ldf(chd_ldf, ldf_type="binary")
|
||||
encoded_ldf = chd_ldf.to_bitstream()
|
||||
chardata.write(encoded_ldf)
|
||||
self.server.send(chardata, address)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import logging
|
||||
|
||||
from ..bitstream import c_float, c_int
|
||||
from ..ldf import LDF, LDFDataType
|
||||
from ..math.vector import Vector3
|
||||
from .module import ServerModule
|
||||
|
||||
@@ -25,7 +25,7 @@ class AABB: # axis aligned bounding box
|
||||
def __init__(self, obj):
|
||||
if obj.lot in (10042, 14510, 16506):
|
||||
if obj.primitive_model_type != 1:
|
||||
log.warn("Primitive model type not 1 %s", obj)
|
||||
log.warning("Primitive model type not 1 %s", obj)
|
||||
rel_min = MODEL_DIMENSIONS[obj.lot][0] * obj.primitive_model_scale
|
||||
rel_max = MODEL_DIMENSIONS[obj.lot][1] * obj.primitive_model_scale
|
||||
else:
|
||||
@@ -113,11 +113,11 @@ class PhysicsHandling(ServerModule):
|
||||
self.debug_markers.append(self.server.spawn_object(obj.lot, set_vars=set_vars))
|
||||
set_vars = {}
|
||||
set_vars["position"] = Vector3((aabb.min.x+aabb.max.x)/2, aabb.min.y, (aabb.min.z+aabb.max.z)/2)
|
||||
config = {}
|
||||
config["primitiveModelType"] = c_int, 1
|
||||
config["primitiveModelValueX"] = c_float, aabb.max.x-aabb.min.x
|
||||
config["primitiveModelValueY"] = c_float, aabb.max.y-aabb.min.y
|
||||
config["primitiveModelValueZ"] = c_float, aabb.max.z-aabb.min.z
|
||||
config = LDF()
|
||||
config.ldf_set("primitiveModelType", LDFDataType.INT32, 1)
|
||||
config.ldf_set("primitiveModelValueX", LDFDataType.FLOAT, aabb.max.x-aabb.min.x)
|
||||
config.ldf_set("primitiveModelValueY", LDFDataType.FLOAT, aabb.max.y-aabb.min.y)
|
||||
config.ldf_set("primitiveModelValueZ", LDFDataType.FLOAT, aabb.max.z-aabb.min.z)
|
||||
set_vars["config"] = config
|
||||
self.debug_markers.append(self.server.spawn_object(14510, set_vars=set_vars))
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ class SocialHandling(ServerModule):
|
||||
response.write(c_bool(False)) # is FTP
|
||||
self.server.send(response, address)
|
||||
|
||||
|
||||
def on_add_friend_response(self, response, address):
|
||||
assert response.read(c_int64) == 0
|
||||
request_declined = response.read(c_bool)
|
||||
|
||||
@@ -1,12 +1,44 @@
|
||||
import asyncio
|
||||
|
||||
import luserver.components.script as script
|
||||
from luserver.ldf import LDFDataType
|
||||
from luserver.bitstream import c_bool, c_int
|
||||
from luserver.math.vector import Vector3
|
||||
from luserver.math.quaternion import Quaternion
|
||||
|
||||
class ScriptComponent(script.ScriptComponent):
|
||||
def on_startup(self):
|
||||
self.script_network_vars.ldf_set("NumberOfPlayers", LDFDataType.INT32, 1)
|
||||
|
||||
def set_player_spawn_points(self):
|
||||
for index, player_id in enumerate(self.object.scripted_activity.players):
|
||||
player = self.object._v_server.get_object(player_id)
|
||||
spawn = self.object._v_server.get_objects_in_group("P%i_Spawn" % (index+1))[0]
|
||||
self.object._v_server.send_game_message(player.char.teleport, ignore_y=False, pos=spawn.physics.position, set_rotation=True, x=spawn.physics.rotation.x, y=spawn.physics.rotation.y, z=spawn.physics.rotation.z, w=spawn.physics.rotation.w, address=player.char.address)
|
||||
|
||||
def start(self):
|
||||
self.object._v_server.send_game_message(self.object.scripted_activity.activity_start, broadcast=True)
|
||||
self.script_network_vars.clear()
|
||||
self.script_network_vars.ldf_set("Clear_Scoreboard", LDFDataType.BOOLEAN, True)
|
||||
self.script_network_vars.ldf_set("Start_Wave_Message", LDFDataType.STRING, "Start!")
|
||||
self.script_network_vars.ldf_set("wavesStarted", LDFDataType.BOOLEAN, True)
|
||||
self.object._v_server.send_game_message(self.script_network_var_update, self.script_network_vars, broadcast=True)
|
||||
|
||||
|
||||
def player_ready(self, address):
|
||||
player = self.object._v_server.accounts[address].characters.selected()
|
||||
script_vars = {}
|
||||
script_vars["NumberOfPlayers"] = c_int, 1
|
||||
script_vars["Define_Player_To_UI"] = bytes, player.object_id
|
||||
script_vars["Show_ScoreBoard"] = c_bool, int(True)
|
||||
script_vars["Update_ScoreBoard_Players.1"] = bytes, player.object_id
|
||||
self.object._v_server.send_game_message(self.script_network_var_update, script_vars, broadcast=True)
|
||||
self.object.scripted_activity.players.append(player.object_id)
|
||||
self.script_network_vars.ldf_set("Define_Player_To_UI", LDFDataType.BYTES, str(player.object_id).encode())
|
||||
self.script_network_vars.ldf_set("Show_ScoreBoard", LDFDataType.BOOLEAN, True)
|
||||
self.script_network_vars.ldf_set("Update_ScoreBoard_Players.1", LDFDataType.BYTES, str(player.object_id).encode())
|
||||
self.object._v_server.send_game_message(self.script_network_var_update, self.script_network_vars, broadcast=True)
|
||||
|
||||
self.set_player_spawn_points()
|
||||
|
||||
def message_box_respond(self, address, button:c_int=None, identifier:"wstr"=None, user_data:"wstr"=None):
|
||||
if identifier == "RePlay":
|
||||
self.start()
|
||||
|
||||
elif identifier == "Exit_Question" and button == 1:
|
||||
player = self.object._v_server.accounts[address].characters.selected()
|
||||
asyncio.ensure_future(player.char.transfer_to_last_non_instance(Vector3(131.83, 376, -180.31), Quaternion(0, -0.268720, 0, 0.963218)))
|
||||
|
||||
@@ -11,4 +11,4 @@ class ScriptComponent(script.ScriptComponent):
|
||||
def message_box_respond(self, address, button:c_int=None, identifier:"wstr"=None, user_data:"wstr"=None):
|
||||
if identifier == "instance_exit" and button == 1:
|
||||
player = self.object._v_server.accounts[address].characters.selected()
|
||||
asyncio.ensure_future(player.char.transfer_to_world(((player.char.world[0] // 100)*100, player.char.world[1], player.char.world[2])))
|
||||
asyncio.ensure_future(player.char.transfer_to_last_non_instance())
|
||||
|
||||
@@ -9,7 +9,7 @@ from .modules.mail import MailID
|
||||
class Server(pyraknet.server.Server):
|
||||
NETWORK_VERSION = 171022
|
||||
SERVER_PASSWORD = b"3.25 ND1"
|
||||
EXPECTED_PEER_TYPE = WorldClientMsg.__int__()
|
||||
EXPECTED_PEER_TYPE = WorldClientMsg.header()
|
||||
|
||||
def __init__(self, address, max_connections, db_conn):
|
||||
super().__init__(address, max_connections, self.SERVER_PASSWORD)
|
||||
@@ -23,12 +23,12 @@ class Server(pyraknet.server.Server):
|
||||
|
||||
def packetname(self, data):
|
||||
if data[0] == Message.LUPacket:
|
||||
if data[1] == WorldServerMsg.__int__() and data[3] == WorldServerMsg.Routing:
|
||||
if data[1] == WorldServerMsg.header() and data[3] == WorldServerMsg.Routing:
|
||||
data = b"\x53"+data[12:]
|
||||
if (data[1], data[3]) == (WorldServerMsg.__int__(), WorldServerMsg.GameMessage) or (data[1], data[3]) == (WorldClientMsg.__int__(), WorldClientMsg.GameMessage):
|
||||
if (data[1], data[3]) == (WorldServerMsg.header(), WorldServerMsg.GameMessage) or (data[1], data[3]) == (WorldClientMsg.header(), WorldClientMsg.GameMessage):
|
||||
message_name = GameMessage(c_ushort.unpack(data[16:18])[0]).name
|
||||
return "GameMessage/" + message_name
|
||||
if (data[1], data[3]) == (WorldServerMsg.__int__(), WorldServerMsg.Mail) or (data[1], data[3]) == (WorldClientMsg.__int__(), WorldClientMsg.Mail):
|
||||
if (data[1], data[3]) == (WorldServerMsg.header(), WorldServerMsg.Mail) or (data[1], data[3]) == (WorldClientMsg.header(), WorldClientMsg.Mail):
|
||||
packetname = MailID(c_uint.unpack(data[8:12])[0]).name
|
||||
return "Mail/" + packetname
|
||||
return msg_enum[data[1]](data[3]).name
|
||||
@@ -36,30 +36,30 @@ class Server(pyraknet.server.Server):
|
||||
|
||||
def unknown_packetname(self, data):
|
||||
if data[0] == Message.LUPacket:
|
||||
if data[1] == WorldServerMsg.__int__() and data[3] == WorldServerMsg.Routing:
|
||||
if data[1] == WorldServerMsg.header() and data[3] == WorldServerMsg.Routing:
|
||||
data = b"\x53"+data[12:]
|
||||
if (data[1], data[3]) == (WorldServerMsg.__int__(), WorldServerMsg.GameMessage) or (data[1], data[3]) == (WorldClientMsg.__int__(), WorldClientMsg.GameMessage):
|
||||
if (data[1], data[3]) == (WorldServerMsg.header(), WorldServerMsg.GameMessage) or (data[1], data[3]) == (WorldClientMsg.header(), WorldClientMsg.GameMessage):
|
||||
return "GameMessage/%i" % c_ushort.unpack(data[16:18])[0]
|
||||
return msg_enum[data[1]].__name__ + "/%.2x" % data[3]
|
||||
return super().unknown_packetname(data)
|
||||
|
||||
def packet_id(self, data):
|
||||
if data[0] == Message.LUPacket:
|
||||
if data[1] == WorldServerMsg.__int__() and data[3] == WorldServerMsg.Routing:
|
||||
if data[1] == WorldServerMsg.header() and data[3] == WorldServerMsg.Routing:
|
||||
return data[12], data[14]
|
||||
return data[1], data[3]
|
||||
return super().packet_id(data)
|
||||
|
||||
def handler_data(self, data):
|
||||
if data[0] == Message.LUPacket:
|
||||
if data[1] == WorldServerMsg.__int__() and data[3] == WorldServerMsg.Routing:
|
||||
if data[1] == WorldServerMsg.header() and data[3] == WorldServerMsg.Routing:
|
||||
return data[19:]
|
||||
return data[8:]
|
||||
return super().handler_data(data)
|
||||
|
||||
def register_handler(self, packet_id, callback, origin=None):
|
||||
if isinstance(packet_id, (GeneralMsg, AuthServerMsg, SocialMsg, WorldServerMsg, WorldClientMsg)):
|
||||
header = type(packet_id).__int__()
|
||||
header = type(packet_id).header()
|
||||
subheader = packet_id
|
||||
packet_id = header, subheader
|
||||
return super().register_handler(packet_id, callback, origin)
|
||||
@@ -101,11 +101,13 @@ class Server(pyraknet.server.Server):
|
||||
def conn_sync(self):
|
||||
self.conn.sync()
|
||||
|
||||
async def address_for_world(self, world_id):
|
||||
async def address_for_world(self, world_id, include_self=False):
|
||||
while True:
|
||||
self.conn_sync()
|
||||
for server_address, server_world in self.db.servers.items():
|
||||
if server_world == world_id and (not hasattr(self, "external_address") or server_address != self.external_address):
|
||||
if server_world == world_id:
|
||||
if not include_self and hasattr(self, "external_address") and server_address == self.external_address:
|
||||
continue
|
||||
return server_address
|
||||
# no server found, spawn a new one
|
||||
# todo: os.system probably isn't the best way to do this
|
||||
|
||||
@@ -50,10 +50,10 @@ import time
|
||||
|
||||
import pyraknet.replicamanager
|
||||
from . import amf3
|
||||
from . import ldf
|
||||
from . import server
|
||||
from .bitstream import BitStream, c_bit, c_float, c_int64, c_uint, c_ushort
|
||||
from .game_object import GameObject
|
||||
from .ldf import LDF
|
||||
from .messages import GameMessage, WorldClientMsg, WorldServerMsg
|
||||
from .math.quaternion import Quaternion
|
||||
from .components.property import PropertyData, PropertySelectQueryProperty
|
||||
@@ -72,7 +72,7 @@ BITS_LOCAL = 1 << 46
|
||||
BITS_SPAWNED = 1 << 58 | BITS_LOCAL
|
||||
|
||||
class WorldServer(server.Server, pyraknet.replicamanager.ReplicaManager):
|
||||
PEER_TYPE = WorldServerMsg.__int__()
|
||||
PEER_TYPE = WorldServerMsg.header()
|
||||
|
||||
def __init__(self, address, external_host, world_id, max_connections, db_conn):
|
||||
server.Server.__init__(self, address, max_connections, db_conn)
|
||||
@@ -288,7 +288,7 @@ class WorldServer(server.Server, pyraknet.replicamanager.ReplicaManager):
|
||||
return self.game_objects[object_id]
|
||||
elif self.world_id[0] != 0 and object_id in self.world_data.objects:
|
||||
return self.world_data.objects[object_id]
|
||||
log.warn("Object %i not found", object_id)
|
||||
log.warning("Object %i not found", object_id)
|
||||
|
||||
def get_objects_in_group(self, group):
|
||||
matches = []
|
||||
@@ -432,13 +432,13 @@ class WorldServer(server.Server, pyraknet.replicamanager.ReplicaManager):
|
||||
elif type == BitStream:
|
||||
out.write(c_uint(len(value)))
|
||||
out.write(bytes(value))
|
||||
elif type == "amf":
|
||||
amf3.write(value, out)
|
||||
elif type == "ldf":
|
||||
ldf_text = ldf.to_ldf(value, ldf_type="text")
|
||||
elif type == LDF:
|
||||
ldf_text = value.to_str()
|
||||
out.write(ldf_text, length_type=c_uint)
|
||||
if ldf_text:
|
||||
out.write(bytes(2)) # for some reason has a null terminator
|
||||
elif type == "amf":
|
||||
amf3.write(value, out)
|
||||
elif type == "str":
|
||||
out.write(value, char_size=1, length_type=c_uint)
|
||||
elif type == "wstr":
|
||||
@@ -473,14 +473,14 @@ class WorldServer(server.Server, pyraknet.replicamanager.ReplicaManager):
|
||||
if type == BitStream:
|
||||
length = message.read(c_uint)
|
||||
return BitStream(message.read(bytes, length=length))
|
||||
if type == "amf":
|
||||
return amf3.read(message)
|
||||
if type == "ldf":
|
||||
if type == LDF:
|
||||
value = message.read(str, length_type=c_uint)
|
||||
if value:
|
||||
assert message.read(c_ushort) == 0 # for some reason has a null terminator
|
||||
# todo: convert to dict
|
||||
# todo: convert to LDF
|
||||
return value
|
||||
if type == "amf":
|
||||
return amf3.read(message)
|
||||
if type == "str":
|
||||
return message.read(str, char_size=1, length_type=c_uint)
|
||||
if type == "wstr":
|
||||
|
||||
@@ -282,8 +282,8 @@ if GENERATE_COMPS:
|
||||
if currency_index is not None:
|
||||
_, minvalue, maxvalue = currency_table[currency_index][0]
|
||||
else:
|
||||
minvalue = None
|
||||
maxvalue = None
|
||||
minvalue = None
|
||||
maxvalue = None
|
||||
|
||||
activity_rewards[object_template] = loot, minvalue, maxvalue
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ from types import SimpleNamespace
|
||||
|
||||
import BTrees
|
||||
|
||||
import luserver.ldf as ldf
|
||||
from luserver.bitstream import BitStream, c_float, c_int, c_int64, c_ubyte, c_uint, c_uint64, c_ushort
|
||||
from luserver.game_object import GameObject
|
||||
from luserver.ldf import LDF
|
||||
from luserver.world import BITS_LOCAL, World
|
||||
from luserver.math.quaternion import Quaternion
|
||||
from luserver.math.vector import Vector3
|
||||
from luserver.world import BITS_LOCAL, World
|
||||
import scripts
|
||||
|
||||
LUZ_PATHS = {}
|
||||
@@ -133,7 +133,7 @@ def lvl_parse_chunk_type_2001(lvl, conn, world_data, triggers):
|
||||
|
||||
object_id |= BITS_LOCAL
|
||||
if lot in WHITELISTED_SERVERSIDE_LOTS:
|
||||
config = ldf.from_ldf(config_data)
|
||||
config = LDF(config_data)
|
||||
|
||||
spawned_vars = {}
|
||||
spawned_vars["scale"] = scale
|
||||
@@ -187,6 +187,8 @@ def lvl_parse_chunk_type_2001(lvl, conn, world_data, triggers):
|
||||
spawned_vars["activity_id"] = config["activityID"]
|
||||
if "attached_path" in config:
|
||||
spawned_vars["attached_path"] = config["attached_path"]
|
||||
if "collectible_id" in config:
|
||||
spawned_vars["collectible_id"] = config["collectible_id"]
|
||||
if "rebuild_activators" in config:
|
||||
spawned_vars["rebuild_activator_position"] = Vector3(*(float(i) for i in config["rebuild_activators"].split("\x1f")))
|
||||
if "rail_path" in config:
|
||||
@@ -331,7 +333,7 @@ def load_world_data(conn, maps_path):
|
||||
config_name = luz.read(str, length_type=c_ubyte)
|
||||
config_type_and_value = luz.read(str, length_type=c_ubyte)
|
||||
try:
|
||||
config[config_name] = ldf.from_ldf_type_value(config_type_and_value)
|
||||
config[config_name] = LDF.from_str_type(config_type_and_value)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Modification of pyraknet.__main__ manual server, with number sorting for packet
|
||||
Mostly intended for manually replaying captures.
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import threading
|
||||
@@ -11,6 +12,8 @@ import traceback
|
||||
|
||||
import pyraknet.server
|
||||
|
||||
logging.basicConfig(format="%(levelname).1s:%(message)s", level=logging.DEBUG)
|
||||
|
||||
def atoi(text):
|
||||
return int(text) if text.isdigit() else text
|
||||
|
||||
|
||||
Reference in New Issue
Block a user