mirror of
https://github.com/lcdr/luserver.git
synced 2025-12-20 13:09:55 -06:00
v2017.11.26
- fixed spider cinematic being played for everyone connected - fixed rocco sirocco's cinematic not being played - implemented teleports between NS, starbase and lego club station
This commit is contained in:
@@ -16,17 +16,6 @@ class AddMission(ChatCommand):
|
|||||||
else:
|
else:
|
||||||
sender.char.add_mission(int(args.mission))
|
sender.char.add_mission(int(args.mission))
|
||||||
|
|
||||||
class AutocompleteMissions(ChatCommand):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__("autocompletemissions")
|
|
||||||
self.command.add_argument("--enable", type=toggle_bool)
|
|
||||||
|
|
||||||
def run(self, args, sender):
|
|
||||||
if args.enable is None:
|
|
||||||
sender.char.autocomplete_missions = not sender.char.autocomplete_missions
|
|
||||||
else:
|
|
||||||
sender.char.autocomplete_missions = args.enable
|
|
||||||
|
|
||||||
class CompleteMission(ChatCommand):
|
class CompleteMission(ChatCommand):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("completemission")
|
super().__init__("completemission")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
import math
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import secrets
|
import secrets
|
||||||
@@ -8,8 +9,12 @@ import time
|
|||||||
|
|
||||||
from ..auth import Account, GMLevel, PasswordState
|
from ..auth import Account, GMLevel, PasswordState
|
||||||
from ..bitstream import BitStream, c_bool, c_ushort
|
from ..bitstream import BitStream, c_bool, c_ushort
|
||||||
|
from ..ldf import LDF, LDFDataType
|
||||||
from ..messages import WorldClientMsg
|
from ..messages import WorldClientMsg
|
||||||
from ..world import server
|
from ..world import server
|
||||||
|
from ..components.physics import AABB, CollisionSphere, PrimitiveModelType
|
||||||
|
from ..math.quaternion import Quaternion
|
||||||
|
from ..math.vector import Vector3
|
||||||
from .command import ChatCommand, normal_bool
|
from .command import ChatCommand, normal_bool
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@@ -112,6 +117,45 @@ class Mute(ChatCommand):
|
|||||||
else:
|
else:
|
||||||
server.chat.sys_msg_sender("Player not connected")
|
server.chat.sys_msg_sender("Player not connected")
|
||||||
|
|
||||||
|
class PhysicsDebug(ChatCommand):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("physicsdebug")
|
||||||
|
self.debug_markers = []
|
||||||
|
server.add_handler("proximity_radius", self.on_proximity_radius)
|
||||||
|
|
||||||
|
def run(self, args, sender):
|
||||||
|
if self.debug_markers:
|
||||||
|
for marker in self.debug_markers:
|
||||||
|
server.replica_manager.destruct(marker)
|
||||||
|
self.debug_markers.clear()
|
||||||
|
else:
|
||||||
|
for obj in server.general.tracked_objects.copy():
|
||||||
|
self.spawn_debug_marker(obj)
|
||||||
|
|
||||||
|
def on_proximity_radius(self, obj):
|
||||||
|
if not self.debug_markers:
|
||||||
|
return
|
||||||
|
self.spawn_debug_marker(obj)
|
||||||
|
|
||||||
|
def spawn_debug_marker(self, obj):
|
||||||
|
coll = server.general.tracked_objects[obj]
|
||||||
|
set_vars = {"parent": obj, "rotation": Quaternion.identity}
|
||||||
|
if isinstance(coll, AABB):
|
||||||
|
config = LDF()
|
||||||
|
config.ldf_set("primitiveModelType", LDFDataType.INT32, PrimitiveModelType.Cuboid)
|
||||||
|
config.ldf_set("primitiveModelValueX", LDFDataType.FLOAT, coll.max.x-coll.min.x)
|
||||||
|
config.ldf_set("primitiveModelValueY", LDFDataType.FLOAT, coll.max.y-coll.min.y)
|
||||||
|
config.ldf_set("primitiveModelValueZ", LDFDataType.FLOAT, coll.max.z-coll.min.z)
|
||||||
|
|
||||||
|
set_vars["position"] = Vector3((coll.min.x+coll.max.x)/2, coll.min.y, (coll.min.z+coll.max.z)/2)
|
||||||
|
set_vars["config"] = config
|
||||||
|
marker = server.spawn_object(14510, set_vars)
|
||||||
|
elif isinstance(coll, CollisionSphere):
|
||||||
|
set_vars["position"] = coll.position
|
||||||
|
set_vars["scale"] = math.sqrt(coll.sq_radius)/5
|
||||||
|
marker = server.spawn_object(6548, set_vars)
|
||||||
|
self.debug_markers.append(marker)
|
||||||
|
|
||||||
class ResetPassword(ChatCommand):
|
class ResetPassword(ChatCommand):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("resetpassword")
|
super().__init__("resetpassword")
|
||||||
|
|||||||
@@ -561,6 +561,10 @@ class CharacterComponent(Component, CharActivity, CharCamera, CharMission, CharP
|
|||||||
def bounce_notification(self, object_id_bounced:c_int64=None, object_id_bouncer:c_int64=None, success:bool=None):
|
def bounce_notification(self, object_id_bounced:c_int64=None, object_id_bouncer:c_int64=None, success:bool=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@single
|
||||||
|
def display_zone_summary(self, is_property_map:bool=False, is_zone_start:bool=False, sender:GameObject=None):
|
||||||
|
pass
|
||||||
|
|
||||||
@broadcast
|
@broadcast
|
||||||
def start_arranging_with_item(self, first_time:bool=True, build_area:GameObject=0, build_start_pos:Vector3=None, source_bag:c_int=None, source_id:c_int64=None, source_lot:c_int=None, source_type:c_int=None, target_id:c_int64=None, target_lot:c_int=None, target_pos:Vector3=None, target_type:c_int=None):
|
def start_arranging_with_item(self, first_time:bool=True, build_area:GameObject=0, build_start_pos:Vector3=None, source_bag:c_int=None, source_id:c_int64=None, source_lot:c_int=None, source_type:c_int=None, target_id:c_int64=None, target_lot:c_int=None, target_pos:Vector3=None, target_type:c_int=None):
|
||||||
self.object.inventory.push_equipped_items_state()
|
self.object.inventory.push_equipped_items_state()
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ from ..mission import check_prereqs, MissionProgress, MissionState, ObtainItemTy
|
|||||||
|
|
||||||
class CharMission:
|
class CharMission:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.autocomplete_missions = False
|
|
||||||
self.missions = PersistentMapping()
|
self.missions = PersistentMapping()
|
||||||
# add achievements
|
# add achievements
|
||||||
for mission_id, data in server.db.missions.items():
|
for mission_id, data in server.db.missions.items():
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ from ...messages import single
|
|||||||
|
|
||||||
class CharUI:
|
class CharUI:
|
||||||
@single
|
@single
|
||||||
def display_message_box(self, show:bool=None, callback_client:GameObject=None, identifier:str=None, image_id:c_int=None, text:str=None, user_data:str=None):
|
def display_message_box(self, show:bool=None, callback_client:GameObject=None, id:str=None, image_id:c_int=None, text:str=None, user_data:str=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def disp_message_box(self, text):
|
def disp_message_box(self, text, id="", callback=None):
|
||||||
"""display_message_box with default parameters."""
|
"""display_message_box with default parameters."""
|
||||||
self.display_message_box(show=True, callback_client=None, identifier="", image_id=0, text=text, user_data="")
|
self.display_message_box(show=True, callback_client=callback, id=id, image_id=0, text=text, user_data="")
|
||||||
|
|
||||||
@single
|
@single
|
||||||
def display_tooltip(self, do_or_die:bool=False, no_repeat:bool=False, no_revive:bool=False, is_property_tooltip:bool=False, show:bool=None, translate:bool=False, time:c_int=None, id:str=None, localize_params:LDF=None, image_name:str=None, text:str=None):
|
def display_tooltip(self, do_or_die:bool=False, no_repeat:bool=False, no_revive:bool=False, is_property_tooltip:bool=False, show:bool=None, translate:bool=False, time:c_int=None, id:str=None, localize_params:LDF=None, image_name:str=None, text:str=None):
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ class Comp108Component(Component):
|
|||||||
if self.driver_id != 0:
|
if self.driver_id != 0:
|
||||||
server.game_objects[self.driver_id].char.dismount()
|
server.game_objects[self.driver_id].char.dismount()
|
||||||
|
|
||||||
def request_die(self, unknown_bool:bool=None, death_type:str=None, direction_relative_angle_xz:float=None, direction_relative_angle_y:float=None, direction_relative_force:float=None, kill_type:c_int=0, killer:GameObject=None, loot_owner:GameObject=0):
|
def request_die(self, unknown_bool:bool=None, death_type:str=None, direction_relative_angle_xz:float=None, direction_relative_angle_y:float=None, direction_relative_force:float=None, kill_type:c_int=0, killer:GameObject=None, loot_owner:GameObject=None):
|
||||||
#self.object.destructible.deal_damage(10000, self) # die permanently on crash
|
#self.object.destructible.deal_damage(10000, self) # die permanently on crash
|
||||||
self.object.call_later(3, self.object.destructible.resurrect)
|
self.object.call_later(3, self.object.destructible.resurrect)
|
||||||
|
|||||||
@@ -46,11 +46,11 @@ class DestructibleComponent(Component):
|
|||||||
self.object.stats.life = max(0, self.object.stats.life - (damage - self.object.stats.armor))
|
self.object.stats.life = max(0, self.object.stats.life - (damage - self.object.stats.armor))
|
||||||
self.object.stats.armor = max(0, self.object.stats.armor - damage)
|
self.object.stats.armor = max(0, self.object.stats.armor - damage)
|
||||||
|
|
||||||
def simply_die(self, death_type:str="", kill_type:c_int=KillType.Violent, killer:GameObject=None, loot_owner:GameObject=0):
|
def simply_die(self, death_type:str="", kill_type:c_int=KillType.Violent, killer:GameObject=None, loot_owner:GameObject=None):
|
||||||
"""Shorthand for request_die with default values."""
|
"""Shorthand for request_die with default values."""
|
||||||
self.request_die(False, death_type, 0, 0, 10, kill_type, killer, loot_owner)
|
self.request_die(False, death_type, 0, 0, 10, kill_type, killer, loot_owner)
|
||||||
|
|
||||||
def request_die(self, unknown_bool:bool=None, death_type:str=None, direction_relative_angle_xz:float=None, direction_relative_angle_y:float=None, direction_relative_force:float=None, kill_type:c_int=KillType.Violent, killer:GameObject=None, loot_owner:GameObject=0):
|
def request_die(self, unknown_bool:bool=None, death_type:str=None, direction_relative_angle_xz:float=None, direction_relative_angle_y:float=None, direction_relative_force:float=None, kill_type:c_int=KillType.Violent, killer:GameObject=None, loot_owner:GameObject=None):
|
||||||
if self.object.stats.life == 0:
|
if self.object.stats.life == 0:
|
||||||
# already dead
|
# already dead
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ class MissionProgress(Persistent):
|
|||||||
self.tasks = [MissionTask(task_type, target, target_value, parameter) for task_type, target, target_value, parameter in mission_data[2]]
|
self.tasks = [MissionTask(task_type, target, target_value, parameter) for task_type, target, target_value, parameter in mission_data[2]]
|
||||||
self.is_mission = mission_data[3]
|
self.is_mission = mission_data[3]
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
|
|
||||||
@@ -66,7 +65,6 @@ from ..bitstream import c_int
|
|||||||
from ..game_object import GameObject
|
from ..game_object import GameObject
|
||||||
from ..messages import single
|
from ..messages import single
|
||||||
from ..world import server
|
from ..world import server
|
||||||
from ..commands.mission import CompleteMission
|
|
||||||
from .component import Component
|
from .component import Component
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@@ -149,9 +147,6 @@ class MissionNPCComponent(Component):
|
|||||||
if mission_state == MissionState.Available:
|
if mission_state == MissionState.Available:
|
||||||
assert not is_complete
|
assert not is_complete
|
||||||
player.char.add_mission(mission_id)
|
player.char.add_mission(mission_id)
|
||||||
if player.char.autocomplete_missions:
|
|
||||||
asyncio.get_event_loop().call_soon(CompleteMission.async_complete_mission, CompleteMission, mission_id, False, player)
|
|
||||||
|
|
||||||
elif mission_state == MissionState.ReadyToComplete:
|
elif mission_state == MissionState.ReadyToComplete:
|
||||||
assert is_complete
|
assert is_complete
|
||||||
player.char.complete_mission(mission_id)
|
player.char.complete_mission(mission_id)
|
||||||
|
|||||||
@@ -36,31 +36,11 @@ class PhysicsComponent(Component):
|
|||||||
for comp in self.object.components:
|
for comp in self.object.components:
|
||||||
if hasattr(comp, "on_enter") or hasattr(comp, "on_exit"):
|
if hasattr(comp, "on_enter") or hasattr(comp, "on_exit"):
|
||||||
server.general.tracked_objects[self.object] = CollisionSphere(self.object, radius)
|
server.general.tracked_objects[self.object] = CollisionSphere(self.object, radius)
|
||||||
if server.get_objects_in_group("physics_debug_marker"):
|
if "proximity_radius" in server._handlers:
|
||||||
self.spawn_debug_marker()
|
for handler in server._handlers["proximity_radius"]:
|
||||||
|
handler(self)
|
||||||
break
|
break
|
||||||
|
|
||||||
def spawn_debug_marker(self):
|
|
||||||
if self.object not in server.general.tracked_objects:
|
|
||||||
return
|
|
||||||
coll = server.general.tracked_objects[self.object]
|
|
||||||
set_vars = {"groups": ("physics_debug_marker",), "parent": self.object, "rotation": Quaternion.identity}
|
|
||||||
if isinstance(coll, AABB):
|
|
||||||
config = LDF()
|
|
||||||
config.ldf_set("primitiveModelType", LDFDataType.INT32, PrimitiveModelType.Cuboid)
|
|
||||||
config.ldf_set("primitiveModelValueX", LDFDataType.FLOAT, coll.max.x-coll.min.x)
|
|
||||||
config.ldf_set("primitiveModelValueY", LDFDataType.FLOAT, coll.max.y-coll.min.y)
|
|
||||||
config.ldf_set("primitiveModelValueZ", LDFDataType.FLOAT, coll.max.z-coll.min.z)
|
|
||||||
|
|
||||||
set_vars["position"] = Vector3((coll.min.x+coll.max.x)/2, coll.min.y, (coll.min.z+coll.max.z)/2)
|
|
||||||
set_vars["config"] = config
|
|
||||||
server.spawn_object(14510, set_vars)
|
|
||||||
elif isinstance(coll, CollisionSphere):
|
|
||||||
set_vars["position"] = coll.position
|
|
||||||
set_vars["scale"] = math.sqrt(coll.sq_radius)/5
|
|
||||||
server.spawn_object(6548, set_vars)
|
|
||||||
|
|
||||||
|
|
||||||
# not really related to physics, but depends on physics and hasn't been conclusively associated with a component
|
# not really related to physics, but depends on physics and hasn't been conclusively associated with a component
|
||||||
|
|
||||||
def drop_rewards(self, loot_matrix, currency_min, currency_max, owner):
|
def drop_rewards(self, loot_matrix, currency_min, currency_max, owner):
|
||||||
@@ -339,8 +319,6 @@ class PhantomPhysicsComponent(PhysicsComponent):
|
|||||||
continue
|
continue
|
||||||
if hasattr(comp, "on_enter") or hasattr(comp, "on_exit"):
|
if hasattr(comp, "on_enter") or hasattr(comp, "on_exit"):
|
||||||
server.general.tracked_objects[self.object] = AABB(self.object)
|
server.general.tracked_objects[self.object] = AABB(self.object)
|
||||||
if server.get_objects_in_group("physics_debug_marker"):
|
|
||||||
self.spawn_debug_marker()
|
|
||||||
break
|
break
|
||||||
|
|
||||||
def on_enter(self, player):
|
def on_enter(self, player):
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ class ScriptedActivityComponent(Component):
|
|||||||
def activity_start(self):
|
def activity_start(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def message_box_respond(self, player, button:c_int=None, identifier:str=None, user_data:str=None):
|
def message_box_respond(self, player, button:c_int=None, id:str=None, user_data:str=None):
|
||||||
if identifier == "LobbyReady" and button == 1:
|
if id == "LobbyReady" and button == 1:
|
||||||
asyncio.ensure_future(player.char.transfer_to_world((self.transfer_world_id, 0, 0)))
|
asyncio.ensure_future(player.char.transfer_to_world((self.transfer_world_id, 0, 0)))
|
||||||
|
|
||||||
@single
|
@single
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ class GameObject:
|
|||||||
self.attr_changed(name)
|
self.attr_changed(name)
|
||||||
super().__setattr__(name, value)
|
super().__setattr__(name, value)
|
||||||
|
|
||||||
def __init__(self, lot, object_id, set_vars={}):
|
def __init__(self, lot, object_id, set_vars=None):
|
||||||
|
if set_vars is None:
|
||||||
|
set_vars = {}
|
||||||
self._handlers = {}
|
self._handlers = {}
|
||||||
self._flags = {}
|
self._flags = {}
|
||||||
self._flags["parent_flag"] = "related_objects_flag"
|
self._flags["parent_flag"] = "related_objects_flag"
|
||||||
@@ -81,11 +83,19 @@ class GameObject:
|
|||||||
for component_type, component_id in sorted(comp_ids, key=lambda x: component_order.index(x[0]) if x[0] in component_order else 99999):
|
for component_type, component_id in sorted(comp_ids, key=lambda x: component_order.index(x[0]) if x[0] in component_order else 99999):
|
||||||
if component_type == 5:
|
if component_type == 5:
|
||||||
if "custom_script" in set_vars and set_vars["custom_script"] is not None:
|
if "custom_script" in set_vars and set_vars["custom_script"] is not None:
|
||||||
script = importlib.import_module("luserver.scripts."+set_vars["custom_script"])
|
try:
|
||||||
comp = script.ScriptComponent,
|
script = importlib.import_module("luserver.scripts."+set_vars["custom_script"])
|
||||||
|
comp = script.ScriptComponent,
|
||||||
|
except ModuleNotFoundError as e:
|
||||||
|
log.warning(str(e))
|
||||||
|
comp = ScriptComponent,
|
||||||
elif component_id is not None and component_id in server.db.script_component:
|
elif component_id is not None and component_id in server.db.script_component:
|
||||||
script = importlib.import_module("luserver.scripts."+server.db.script_component[component_id])
|
try:
|
||||||
comp = script.ScriptComponent,
|
script = importlib.import_module("luserver.scripts."+server.db.script_component[component_id])
|
||||||
|
comp = script.ScriptComponent,
|
||||||
|
except ModuleNotFoundError as e:
|
||||||
|
log.warning(str(e))
|
||||||
|
comp = ScriptComponent,
|
||||||
else:
|
else:
|
||||||
comp = ScriptComponent,
|
comp = ScriptComponent,
|
||||||
elif component_type in component:
|
elif component_type in component:
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ class GameMessage(Enum):
|
|||||||
BounceNotification = 932
|
BounceNotification = 932
|
||||||
BBBSaveRequest = 1001
|
BBBSaveRequest = 1001
|
||||||
NotifyClientObject = 1042
|
NotifyClientObject = 1042
|
||||||
|
DisplayZoneSummary = 1043
|
||||||
StartBuildingWithItem = 1057
|
StartBuildingWithItem = 1057
|
||||||
StartArrangingWithItem = 1061
|
StartArrangingWithItem = 1061
|
||||||
FinishArrangingWithItem = 1062
|
FinishArrangingWithItem = 1062
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# Constant checksums that the client expects to verify map version
|
# Constant checksums that the client expects to verify map version
|
||||||
# (likely value of the last map revision)
|
# (likely value of the last map revision)
|
||||||
checksum = {
|
_CHECKSUMS = {
|
||||||
World.VentureExplorer: 0x20b8087c,
|
World.VentureExplorer: 0x20b8087c,
|
||||||
World.ReturnToTheVentureExplorer: 0x26680a3c,
|
World.ReturnToTheVentureExplorer: 0x26680a3c,
|
||||||
World.AvantGardens: 0x49525511,
|
World.AvantGardens: 0x49525511,
|
||||||
@@ -57,22 +57,11 @@ class GeneralHandling:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
server.general = self
|
server.general = self
|
||||||
self.tracked_objects = {}
|
self.tracked_objects = {}
|
||||||
physics_debug_cmd = server.chat.commands.add_parser("physicsdebug")
|
|
||||||
physics_debug_cmd.set_defaults(func=self.physics_debug_cmd)
|
|
||||||
|
|
||||||
server.register_handler(WorldServerMsg.LoadComplete, self.on_client_load_complete)
|
server.register_handler(WorldServerMsg.LoadComplete, self.on_client_load_complete)
|
||||||
server.register_handler(WorldServerMsg.PositionUpdate, self.on_position_update)
|
server.register_handler(WorldServerMsg.PositionUpdate, self.on_position_update)
|
||||||
server.register_handler(WorldServerMsg.GameMessage, self.on_game_message)
|
server.register_handler(WorldServerMsg.GameMessage, self.on_game_message)
|
||||||
|
|
||||||
def physics_debug_cmd(self, args, sender):
|
|
||||||
debug_markers = server.get_objects_in_group("physics_debug_marker")
|
|
||||||
if not debug_markers:
|
|
||||||
for obj in self.tracked_objects.copy():
|
|
||||||
obj.physics.spawn_debug_marker()
|
|
||||||
else:
|
|
||||||
for marker in debug_markers:
|
|
||||||
server.replica_manager.destruct(marker)
|
|
||||||
|
|
||||||
def on_validated(self, address):
|
def on_validated(self, address):
|
||||||
player = server.accounts[address].characters.selected()
|
player = server.accounts[address].characters.selected()
|
||||||
if server.world_id[0] != 0:
|
if server.world_id[0] != 0:
|
||||||
@@ -100,7 +89,7 @@ class GeneralHandling:
|
|||||||
load_world.write(c_ushort(world_id))
|
load_world.write(c_ushort(world_id))
|
||||||
load_world.write(c_ushort(world_instance))
|
load_world.write(c_ushort(world_instance))
|
||||||
load_world.write(c_uint(world_clone))
|
load_world.write(c_uint(world_clone))
|
||||||
load_world.write(c_uint(checksum.get(World(world_id), 0)))
|
load_world.write(c_uint(_CHECKSUMS.get(World(world_id), 0)))
|
||||||
load_world.write(bytes(2))
|
load_world.write(bytes(2))
|
||||||
load_world.write(c_float(player.physics.position.x))
|
load_world.write(c_float(player.physics.position.x))
|
||||||
load_world.write(c_float(player.physics.position.y))
|
load_world.write(c_float(player.physics.position.y))
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ class ScriptComponent(script.ScriptComponent):
|
|||||||
assert multi_interact_id is None
|
assert multi_interact_id is None
|
||||||
player.char.set_flag(True, FLAG_ID)
|
player.char.set_flag(True, FLAG_ID)
|
||||||
player.inventory.remove_item(InventoryType.Items, lot=MAELSTROM_CUBE_LOT)
|
player.inventory.remove_item(InventoryType.Items, lot=MAELSTROM_CUBE_LOT)
|
||||||
server.get_objects_in_group("cagedSpider")[0].script.fire_event_client_side(args="toggle", obj=None, sender=player)
|
server.get_objects_in_group("cagedSpider")[0].script.fire_event_client_side(args="toggle", obj=None, sender=player, player=player)
|
||||||
|
|||||||
14
luserver/scripts/avant_gardens/caged_spider.py
Normal file
14
luserver/scripts/avant_gardens/caged_spider.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import luserver.components.script as script
|
||||||
|
from luserver.bitstream import c_int, c_int64
|
||||||
|
from luserver.game_object import GameObject
|
||||||
|
from luserver.messages import single
|
||||||
|
|
||||||
|
class ScriptComponent(script.ScriptComponent):
|
||||||
|
# hacky workaround incoming:
|
||||||
|
# the clientside implementation is broken and doesn't check the sender param
|
||||||
|
# so the cinematic would get displayed for everyone since this message is broadcast
|
||||||
|
# easiest fix is to override it for this script to be single instead
|
||||||
|
# other option would be to allow broadcast messages to be single per-call, but that seems like even more of a hack
|
||||||
|
@single
|
||||||
|
def fire_event_client_side(self, args:str=None, obj:GameObject=None, param1:c_int64=0, param2:c_int=-1, sender:GameObject=None):
|
||||||
|
pass
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import luserver.components.script as script
|
import luserver.components.script as script
|
||||||
from luserver.bitstream import c_int
|
from luserver.bitstream import c_int
|
||||||
from luserver.game_object import GameObject
|
from luserver.game_object import GameObject
|
||||||
|
from luserver.messages import single
|
||||||
from luserver.components.inventory import InventoryType
|
from luserver.components.inventory import InventoryType
|
||||||
from luserver.components.mission import MissionState
|
from luserver.components.mission import MissionState
|
||||||
|
|
||||||
@@ -13,3 +14,10 @@ class ScriptComponent(script.ScriptComponent):
|
|||||||
player.char.complete_mission(1729)
|
player.char.complete_mission(1729)
|
||||||
elif mission_state == MissionState.ReadyToComplete:
|
elif mission_state == MissionState.ReadyToComplete:
|
||||||
player.inventory.remove_item(InventoryType.Items, lot=14397)
|
player.inventory.remove_item(InventoryType.Items, lot=14397)
|
||||||
|
self.notify_client_object(name="switch", param1=0, param2=0, param_str=b"", param_obj=None, player=player)
|
||||||
|
|
||||||
|
# manually changed from broadcast to single because the client script abuses this message
|
||||||
|
# see also caged_spider
|
||||||
|
@single
|
||||||
|
def notify_client_object(self, name:str=None, param1:c_int=None, param2:c_int=None, param_obj:GameObject=None, param_str:bytes=None):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -128,11 +128,11 @@ class ScriptComponent(script.ScriptComponent):
|
|||||||
|
|
||||||
self.set_player_spawn_points()
|
self.set_player_spawn_points()
|
||||||
|
|
||||||
def message_box_respond(self, player, button:c_int=None, identifier:str=None, user_data:str=None):
|
def message_box_respond(self, player, button:c_int=None, id:str=None, user_data:str=None):
|
||||||
if identifier == "RePlay":
|
if id == "RePlay":
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
elif identifier == "Exit_Question" and button == 1:
|
elif id == "Exit_Question" and button == 1:
|
||||||
self.game_over(player)
|
self.game_over(player)
|
||||||
self.object.scripted_activity.remove_player(player)
|
self.object.scripted_activity.remove_player(player)
|
||||||
asyncio.ensure_future(player.char.transfer_to_last_non_instance(Vector3(131.83, 376, -180.31), Quaternion(0, -0.268720, 0, 0.963218)))
|
asyncio.ensure_future(player.char.transfer_to_last_non_instance(Vector3(131.83, 376, -180.31), Quaternion(0, -0.268720, 0, 0.963218)))
|
||||||
|
|||||||
10
luserver/scripts/general/console_teleport.py
Normal file
10
luserver/scripts/general/console_teleport.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
import luserver.components.script as script
|
||||||
|
|
||||||
|
# todo: not completely implemented
|
||||||
|
|
||||||
|
class ScriptComponent(script.ScriptComponent):
|
||||||
|
def transfer(self, player, world, respawn_point_name):
|
||||||
|
player.render.play_animation("lup-teleport")
|
||||||
|
asyncio.get_event_loop().call_later(4, asyncio.ensure_future, player.char.transfer_to_world(world, respawn_point_name=respawn_point_name))
|
||||||
21
luserver/scripts/general/teleport_to_ns_or_nt.py
Normal file
21
luserver/scripts/general/teleport_to_ns_or_nt.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import luserver.scripts.general.console_teleport as script
|
||||||
|
from luserver.amf3 import AMF3
|
||||||
|
from luserver.bitstream import c_int
|
||||||
|
from luserver.world import server
|
||||||
|
from luserver.components.char import TerminateType
|
||||||
|
# todo: implement visited worlds so the NS/NT choice UI can work
|
||||||
|
|
||||||
|
class ScriptComponent(script.ScriptComponent):
|
||||||
|
def on_use(self, player, multi_interact_id):
|
||||||
|
assert multi_interact_id is None
|
||||||
|
# todo: check if player has been to NT, if yes then display choice UI
|
||||||
|
player.char.disp_message_box(id="TransferBox", text="UI_TRAVEL_TO_LUP_STATION", callback=self.object)
|
||||||
|
|
||||||
|
def message_box_respond(self, player, button:c_int=None, id:str=None, user_data:str=None):
|
||||||
|
if id == "TransferBox":
|
||||||
|
if button == 1:
|
||||||
|
# todo: display zone summary (callback not working right now for some reason)
|
||||||
|
#player.char.display_zone_summary(sender=self.object)
|
||||||
|
self.transfer(player, (1200, 0, 0), "NS_LEGO_Club")
|
||||||
|
else:
|
||||||
|
player.char.terminate_interaction(terminator=self.object, type=TerminateType.FromInteraction)
|
||||||
@@ -6,8 +6,8 @@ from luserver.bitstream import c_int
|
|||||||
class ScriptComponent(script.ScriptComponent):
|
class ScriptComponent(script.ScriptComponent):
|
||||||
def on_use(self, player, multi_interact_id):
|
def on_use(self, player, multi_interact_id):
|
||||||
assert multi_interact_id is None
|
assert multi_interact_id is None
|
||||||
player.char.display_message_box(show=True, callback_client=self.object, identifier="instance_exit", image_id=0, text=self.script_vars.get("transfer_text", "DRAGON_EXIT_QUESTION"), user_data="")
|
player.char.display_message_box(show=True, callback_client=self.object, id="instance_exit", image_id=0, text=self.script_vars.get("transfer_text", "DRAGON_EXIT_QUESTION"), user_data="")
|
||||||
|
|
||||||
def message_box_respond(self, player, button:c_int=None, identifier:str=None, user_data:str=None):
|
def message_box_respond(self, player, button:c_int=None, id:str=None, user_data:str=None):
|
||||||
if identifier == "instance_exit" and button == 1:
|
if id == "instance_exit" and button == 1:
|
||||||
asyncio.ensure_future(player.char.transfer_to_last_non_instance())
|
asyncio.ensure_future(player.char.transfer_to_last_non_instance())
|
||||||
|
|||||||
28
luserver/scripts/nimbus_station/lego_club_door.py
Normal file
28
luserver/scripts/nimbus_station/lego_club_door.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import luserver.scripts.general.teleport_to_ns_or_nt as script
|
||||||
|
from luserver.amf3 import AMF3
|
||||||
|
from luserver.bitstream import c_int
|
||||||
|
from luserver.world import server
|
||||||
|
from luserver.components.char import TerminateType
|
||||||
|
|
||||||
|
# todo: not completely implemented
|
||||||
|
# todo: implement visited worlds so the NS/NT choice UI can work
|
||||||
|
|
||||||
|
class ScriptComponent(script.ScriptComponent):
|
||||||
|
def on_use(self, player, multi_interact_id):
|
||||||
|
assert multi_interact_id is None
|
||||||
|
if server.world_id[0] == 1700:
|
||||||
|
# todo: check if player has been to NT, if yes then display choice UI
|
||||||
|
player.char.disp_message_box(id="TransferBox", text="UI_TRAVEL_TO_NS", callback=self.object)
|
||||||
|
else:
|
||||||
|
player.char.u_i_message_server_to_single_client(message_name=b"pushGameState", args=AMF3({"state": "Lobby", "context": {"user": str(player.object_id), "callbackObj": str(self.object.object_id), "HelpVisible": "show", "type": "Lego_Club_Valid"}}))
|
||||||
|
|
||||||
|
def message_box_respond(self, player, button:c_int=None, id:str=None, user_data:str=None):
|
||||||
|
if id == "PlayButton":
|
||||||
|
self.transfer(player, (1700, 0, 0), "")
|
||||||
|
elif id == "TransferBox":
|
||||||
|
if button == 1:
|
||||||
|
# todo: display zone summary (callback not working right now for some reason)
|
||||||
|
#player.char.display_zone_summary(sender=self.object)
|
||||||
|
self.transfer(player, (1200, 0, 0), "NS_LEGO_Club")
|
||||||
|
else:
|
||||||
|
player.char.terminate_interaction(terminator=self.object, type=TerminateType.FromInteraction)
|
||||||
35
luserver/scripts/nimbus_station/lup_teleport.py
Normal file
35
luserver/scripts/nimbus_station/lup_teleport.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
import luserver.scripts.general.teleport_to_ns_or_nt as script
|
||||||
|
from luserver.amf3 import AMF3
|
||||||
|
from luserver.bitstream import c_int
|
||||||
|
from luserver.world import server
|
||||||
|
from luserver.components.char import TerminateType
|
||||||
|
|
||||||
|
# todo: not completely implemented
|
||||||
|
# todo: implement visited worlds so the NS/NT choice UI can work
|
||||||
|
|
||||||
|
class ScriptComponent(script.ScriptComponent):
|
||||||
|
def on_use(self, player, multi_interact_id):
|
||||||
|
assert multi_interact_id is None
|
||||||
|
# todo: check if player has been to NT, if yes then display choice UI
|
||||||
|
if server.world_id[0] == 1600:
|
||||||
|
text = "UI_TRAVEL_TO_NS"
|
||||||
|
else:
|
||||||
|
text = "UI_TRAVEL_TO_LUP_STATION"
|
||||||
|
player.char.disp_message_box(id="TransferBox", text=text, callback=self.object)
|
||||||
|
|
||||||
|
def message_box_respond(self, player, button:c_int=None, id:str=None, user_data:str=None):
|
||||||
|
if id == "TransferBox":
|
||||||
|
if button == 1:
|
||||||
|
# todo: display zone summary (callback not working right now for some reason)
|
||||||
|
#player.char.display_zone_summary(sender=self.object)
|
||||||
|
if server.world_id[0] == 1600:
|
||||||
|
dest = 1200
|
||||||
|
spawnpoint = "NS_LW"
|
||||||
|
else:
|
||||||
|
dest = 1600
|
||||||
|
spawnpoint = ""
|
||||||
|
self.transfer(player, (dest, 0, 0), spawnpoint)
|
||||||
|
else:
|
||||||
|
player.char.terminate_interaction(terminator=self.object, type=TerminateType.FromInteraction)
|
||||||
@@ -116,6 +116,7 @@ class WorldServer(Server):
|
|||||||
self.not_console_logged_packets.add("GameMessage/ReadyForUpdates")
|
self.not_console_logged_packets.add("GameMessage/ReadyForUpdates")
|
||||||
self.not_console_logged_packets.add("GameMessage/ScriptNetworkVarUpdate")
|
self.not_console_logged_packets.add("GameMessage/ScriptNetworkVarUpdate")
|
||||||
self.multi = MultiInstanceAccess()
|
self.multi = MultiInstanceAccess()
|
||||||
|
self._handlers = {}
|
||||||
CharHandling()
|
CharHandling()
|
||||||
ChatHandling()
|
ChatHandling()
|
||||||
GeneralHandling()
|
GeneralHandling()
|
||||||
@@ -199,6 +200,19 @@ class WorldServer(Server):
|
|||||||
lot, position, rotation = spawn_data
|
lot, position, rotation = spawn_data
|
||||||
self.spawn_model(spawner_id, lot, position, rotation)
|
self.spawn_model(spawner_id, lot, position, rotation)
|
||||||
|
|
||||||
|
EVENT_NAMES = "proximity_radius"
|
||||||
|
def add_handler(self, event_name: str, handler):
|
||||||
|
if event_name not in WorldServer.EVENT_NAMES:
|
||||||
|
raise ValueError("Invalid event name %s", event_name)
|
||||||
|
self._handlers.setdefault(event_name, []).append(handler)
|
||||||
|
|
||||||
|
def remove_handler(self, event_name: str, handler):
|
||||||
|
if event_name not in WorldServer.EVENT_NAMES:
|
||||||
|
raise ValueError("Invalid event name %s", event_name)
|
||||||
|
if event_name not in self._handlers or handler not in self._handlers[event_name]:
|
||||||
|
raise RuntimeError("handler not found")
|
||||||
|
self._handlers[event_name].remove(handler)
|
||||||
|
|
||||||
def spawn_model(self, spawner_id, lot, position, rotation):
|
def spawn_model(self, spawner_id, lot, position, rotation):
|
||||||
spawned_vars = {}
|
spawned_vars = {}
|
||||||
spawned_vars["position"] = position
|
spawned_vars["position"] = position
|
||||||
|
|||||||
@@ -284,13 +284,10 @@ class Init:
|
|||||||
self.root.components_registry.setdefault(row[0], []).append((row[1], row[2]))
|
self.root.components_registry.setdefault(row[0], []).append((row[1], row[2]))
|
||||||
|
|
||||||
if row[1] == 5 and row[2] not in self.root.script_component:
|
if row[1] == 5 and row[2] not in self.root.script_component:
|
||||||
comp_row = self.cdclient.execute("select id, script_name from ScriptComponent where id == %i" % row[2]).fetchone()
|
# we don't even need to query the db since we've got our own scripts table
|
||||||
if comp_row is None:
|
script_id = row[2]
|
||||||
continue
|
if script_id in scripts.SCRIPTS:
|
||||||
id, script_name = comp_row
|
self.root.script_component[script_id] = scripts.SCRIPTS[script_id]
|
||||||
script_name = scripts.SCRIPTS.get(id)
|
|
||||||
if script_name is not None:
|
|
||||||
self.root.script_component[id] = script_name
|
|
||||||
|
|
||||||
elif row[1] == 7 and row[2] not in self.root.destructible_component:
|
elif row[1] == 7 and row[2] not in self.root.destructible_component:
|
||||||
faction, faction_list, level, loot_matrix_index, currency_index, life, armor, imagination, is_smashable = self.cdclient.execute("select faction, factionList, level, LootMatrixIndex, CurrencyIndex, life, armor, imagination, isSmashable from DestructibleComponent where id == %i" % row[2]).fetchone()
|
faction, faction_list, level, loot_matrix_index, currency_index, life, armor, imagination, is_smashable = self.cdclient.execute("select faction, factionList, level, LootMatrixIndex, CurrencyIndex, life, armor, imagination, isSmashable from DestructibleComponent where id == %i" % row[2]).fetchone()
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ SCRIPTS = {
|
|||||||
847: "avant_gardens.rusty_steele",
|
847: "avant_gardens.rusty_steele",
|
||||||
849: "nimbus_station.concert_quickbuild",
|
849: "nimbus_station.concert_quickbuild",
|
||||||
867: "avant_gardens.survival.buff_station",
|
867: "avant_gardens.survival.buff_station",
|
||||||
|
877: "avant_gardens.caged_spider",
|
||||||
882: "avant_gardens.survival.world_control",
|
882: "avant_gardens.survival.world_control",
|
||||||
901: "avant_gardens.survival.stromling_mech",
|
901: "avant_gardens.survival.stromling_mech",
|
||||||
946: "gnarled_forest.torch",
|
946: "gnarled_forest.torch",
|
||||||
@@ -43,10 +44,11 @@ SCRIPTS = {
|
|||||||
1216: "items.cauldron_of_life",
|
1216: "items.cauldron_of_life",
|
||||||
1218: "items.anvil_of_armor",
|
1218: "items.anvil_of_armor",
|
||||||
1219: "items.fountain_of_imagination",
|
1219: "items.fountain_of_imagination",
|
||||||
|
1239: "nimbus_station.lego_club_door",
|
||||||
1270: "avant_gardens.saluting_npcs",
|
1270: "avant_gardens.saluting_npcs",
|
||||||
1271: "avant_gardens.saluting_npcs",
|
1271: "avant_gardens.saluting_npcs",
|
||||||
1272: "avant_gardens.saluting_npcs",
|
1272: "avant_gardens.saluting_npcs",
|
||||||
1276: "general.transfer_world_on_use",
|
1276: "nimbus_station.lup_teleport",
|
||||||
1329: "crux_prime.aura_blossom_flower",
|
1329: "crux_prime.aura_blossom_flower",
|
||||||
1345: "general.poi_mission",
|
1345: "general.poi_mission",
|
||||||
1349: "crux_prime.scroll_shrine",
|
1349: "crux_prime.scroll_shrine",
|
||||||
@@ -54,8 +56,8 @@ SCRIPTS = {
|
|||||||
1419: "nexus_tower.water_fountain",
|
1419: "nexus_tower.water_fountain",
|
||||||
1458: "items.sunflower",
|
1458: "items.sunflower",
|
||||||
1481: "nexus_tower.vault",
|
1481: "nexus_tower.vault",
|
||||||
1484: "general.transfer_world_on_use",
|
1484: "nimbus_station.lup_teleport",
|
||||||
1485: "general.transfer_world_on_use",
|
1485: "nimbus_station.lego_club_door",
|
||||||
1486: "general.transfer_world_on_use",
|
1486: "general.transfer_world_on_use",
|
||||||
1519: "nexus_tower.venture_cannon",
|
1519: "nexus_tower.venture_cannon",
|
||||||
1527: "general.transfer_world_on_use",
|
1527: "general.transfer_world_on_use",
|
||||||
@@ -86,6 +88,7 @@ SCRIPTS = {
|
|||||||
r"02_server\Map\General\L_FRICTION_VOLUME_SERVER.lua": "general.friction_volume",
|
r"02_server\Map\General\L_FRICTION_VOLUME_SERVER.lua": "general.friction_volume",
|
||||||
r"02_server\Map\General\L_POI_MISSION.lua": "general.poi_mission",
|
r"02_server\Map\General\L_POI_MISSION.lua": "general.poi_mission",
|
||||||
r"02_server\Map\General\L_TOUCH_MISSION_UPDATE_SERVER.lua": "general.touch_complete_mission",
|
r"02_server\Map\General\L_TOUCH_MISSION_UPDATE_SERVER.lua": "general.touch_complete_mission",
|
||||||
|
r"02_server\Map\NS\L_NS_LUP_TELEPORT.lua": "nimbus_station.lup_teleport",
|
||||||
r"02_server\Map\NS\L_NS_TOKEN_CONSOLE_SERVER.lua": "nimbus_station.token_console",
|
r"02_server\Map\NS\L_NS_TOKEN_CONSOLE_SERVER.lua": "nimbus_station.token_console",
|
||||||
r"02_server\Map\NT\L_NT_ASSEMBLYTUBE_SERVER.lua": "nexus_tower.assembly_tube",
|
r"02_server\Map\NT\L_NT_ASSEMBLYTUBE_SERVER.lua": "nexus_tower.assembly_tube",
|
||||||
r"02_server\Map\NT\L_NT_PARADOXTELE_SERVER.lua": "nexus_tower.paradox_teleporter",
|
r"02_server\Map\NT\L_NT_PARADOXTELE_SERVER.lua": "nexus_tower.paradox_teleporter",
|
||||||
@@ -109,3 +112,4 @@ SCRIPTS = {
|
|||||||
r"ai\NS\L_NS_MODULAR_BUILD.lua": "nimbus_station.rocket_modular_build",
|
r"ai\NS\L_NS_MODULAR_BUILD.lua": "nimbus_station.rocket_modular_build",
|
||||||
r"ai\NS\L_NS_QB_IMAGINATION_STATUE.lua": "nimbus_station.imagination_statue",
|
r"ai\NS\L_NS_QB_IMAGINATION_STATUE.lua": "nimbus_station.imagination_statue",
|
||||||
r"ai\NS\NS_PP_01\L_NS_PP_01_TELEPORT.lua": "property.teleport"}
|
r"ai\NS\NS_PP_01\L_NS_PP_01_TELEPORT.lua": "property.teleport"}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user