From 2ec878e712c2bc10206ded07121b8d3c6d27b487 Mon Sep 17 00:00:00 2001 From: lcdr Date: Thu, 1 Sep 2016 10:08:16 +0200 Subject: [PATCH] v2016.09.01 --- README.md | 13 +-- luserver/components/char.py | 22 ++++- luserver/components/collectible.py | 2 +- luserver/components/destructible.py | 10 +-- luserver/components/inventory.py | 14 +-- luserver/components/mission.py | 59 +++++++------ luserver/components/modular_build.py | 10 +++ luserver/components/pet.py | 2 +- luserver/components/rebuild.py | 86 +++++++++++++------ luserver/components/skill.py | 2 +- luserver/components/stats.py | 14 ++- luserver/components/vendor.py | 2 +- luserver/game_object_template.py | 10 ++- luserver/messages.py | 3 + luserver/modules/chat.py | 17 +++- luserver/modules/physics.py | 2 +- .../avant_gardens/quickbuild_elevator.py | 4 + .../scripts/general/shark_death_trigger.py | 2 +- .../scripts/general/touch_complete_mission.py | 2 +- .../nimbus_station/imagination_statue.py | 14 +++ luserver/scripts/nimbus_station/nexus_jay.py | 2 +- luserver/scripts/venture_explorer/bob.py | 2 +- luserver/world.py | 2 - runtime/db/init.py | 11 ++- runtime/db/luz_importer.py | 14 ++- runtime/db/scripts.py | 5 +- 26 files changed, 217 insertions(+), 109 deletions(-) create mode 100644 luserver/scripts/avant_gardens/quickbuild_elevator.py create mode 100644 luserver/scripts/nimbus_station/imagination_statue.py diff --git a/README.md b/README.md index 56ec4e5..c20a654 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,8 @@ or If you don't want to compile the packages yourself, you can download precompiled ones from http://www.lfd.uci.edu/~gohlke/pythonlibs/ . -##### Bugfixes - -ZEO has some unfixed bugs which you'll need to fix manually: -in `/Lib/site-packages/ZEO/zrpc/client.py` -line 453 -comment out: - - if socktype != socket.SOCK_STREAM: - continue - -and in `/Lib/site-packages/ZEO/zrpc/trigger.py` +ZEO has an unfixed bug which you'll need to fix manually: +in `/Lib/site-packages/ZEO/zrpc/trigger.py` line 235 change diff --git a/luserver/components/char.py b/luserver/components/char.py index efa7c69..29f1344 100644 --- a/luserver/components/char.py +++ b/luserver/components/char.py @@ -16,6 +16,11 @@ from .mission import MissionProgress, MissionState, TaskType log = logging.getLogger(__name__) +class TerminateType: + Range = 0 + User = 1 + FromInteraction = 2 + class BuildType: BuildNowhere = 0 BuildInWorld = 1 @@ -230,6 +235,12 @@ class CharacterComponent: del self._v_server.dropped_loot[self.object_id] self.vehicle_id = 0 self.online = False + self.check_for_leaks() + + def check_for_leaks(self): + if self.temp_models: + print("Temp Models not empty") + print(self.temp_models) async def transfer_to_world(self, world, respawn_point_name=None): if respawn_point_name is not None: @@ -261,7 +272,7 @@ class CharacterComponent: if task.type == TaskType.ObtainItem: for item in self.items: if item is not None and item.lot in task.target: - mission_progress.increment_task(task, self._v_server, self, increment=item.amount) + mission_progress.increment_task(task, self, increment=item.amount) if task.value == task.target_value: break @@ -312,6 +323,9 @@ class CharacterComponent: def notify_mission_task(self, address, mission_id:c_int=None, task_mask:c_int=None, updates:(c_ubyte, c_float)=None): pass + def terminate_interaction(self, address, obj_id_terminator:c_int64=None, type:c_int=None): + pass + def request_use(self, address, is_multi_interact_use:c_bit=None, multi_interact_id:c_uint=None, multi_interact_type:c_int=None, object_id:c_int64=None, secondary:c_bit=False): if not is_multi_interact_use: assert multi_interact_id == 0 @@ -334,7 +348,7 @@ class CharacterComponent: if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.Interact and task.target == obj.lot: - mission.increment_task(task, self._v_server, self) + mission.increment_task(task, self) def get_flag(self, flag_id): return bool(self.flags & (1 << flag_id)) @@ -350,7 +364,7 @@ class CharacterComponent: if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.Flag and flag_id in task.target: - mission.increment_task(task, self._v_server, self) + mission.increment_task(task, self) def player_loaded(self, address, player_id:c_int64=None): @@ -454,7 +468,7 @@ class CharacterComponent: self._v_server.mail.send_mail(self.name, "Bug Report: "+selection, body, account.characters.selected()) def request_smash_player(self, address): - self._v_server.send_game_message(self.request_die, unknown_bool=False, death_type="", direction_relative_angle_xz=0, direction_relative_angle_y=0, direction_relative_force=0, killer_id=self.object_id, loot_owner_id=0, address=self.address) + self.request_die(None, unknown_bool=False, death_type="", direction_relative_angle_xz=0, direction_relative_angle_y=0, direction_relative_force=0, killer_id=self.object_id, loot_owner_id=0) def handle_u_g_c_equip_post_delete_based_on_edit_mode(self, address, inv_item:c_int64=None, items_total:c_int=0): pass diff --git a/luserver/components/collectible.py b/luserver/components/collectible.py index 3e4f37f..1d8cb27 100644 --- a/luserver/components/collectible.py +++ b/luserver/components/collectible.py @@ -15,4 +15,4 @@ class CollectibleComponent: if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.Collect and task.target == self.lot: - mission.increment_task(task, self._v_server, player) + mission.increment_task(task, player) diff --git a/luserver/components/destructible.py b/luserver/components/destructible.py index f2c754a..09e7b9f 100644 --- a/luserver/components/destructible.py +++ b/luserver/components/destructible.py @@ -1,7 +1,6 @@ import random from ..bitstream import c_bit, c_float, c_int, c_int64, c_uint -from ..math.vector import Vector3 from .comp108 import Comp108Component from .mission import MissionState, TaskType from .stats import StatsSubcomponent @@ -20,6 +19,7 @@ class DestructibleComponent: self.life = self.max_life self.armor = self.max_armor self.imagination = self.max_imagination + self.is_smashable = comp[7] def serialize(self, out, is_creation): if is_creation: @@ -44,12 +44,6 @@ class DestructibleComponent: loot.append(lot) return loot - def drop_loot(self, lot, owner): - object_id = self._v_server.new_spawned_id() - self._v_server.dropped_loot.setdefault(owner.object_id, {})[object_id] = lot - self._v_server.send_game_message(owner.drop_client_loot, use_position=True, spawn_position=self.position, final_position=Vector3(self.position.x+(random.random()-0.5)*20, self.position.y, self.position.z+(random.random()-0.5)*20), currency=0, item_template=lot, loot_id=object_id, owner=owner.object_id, source_obj=self.object_id, address=owner.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): if self.armor != 0: self.armor = 0 @@ -67,7 +61,7 @@ class DestructibleComponent: if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.KillEnemy and self.lot in task.target: - mission.increment_task(task, self._v_server, killer) + mission.increment_task(task, killer) # drops diff --git a/luserver/components/inventory.py b/luserver/components/inventory.py index 8943914..53e84de 100644 --- a/luserver/components/inventory.py +++ b/luserver/components/inventory.py @@ -183,7 +183,7 @@ class InventoryComponent: if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.ObtainItem and stack.lot in task.target: - mission.increment_task(task, self._v_server, self) + mission.increment_task(task, self) return stack @@ -282,10 +282,14 @@ class InventoryComponent: return def move_item_between_inventory_types(self, address, inventory_type_a:c_int=None, inventory_type_b:c_int=None, object_id:c_int64=None, show_flying_loot:c_bit=True, stack_count:c_uint=1, template_id:c_int=-1): - assert stack_count == 1 source = self.inventory_type_to_inventory(inventory_type_a) for item in source: if item is not None and (item.object_id == object_id or item.lot == template_id): - self.add_item_to_inventory(item.lot, item.amount, inventory_type=inventory_type_b, show_flying_loot=show_flying_loot) - self.remove_item_from_inv(inventory_type_a, item) - break + if stack_count == 0: + move_stack_count = item.amount + else: + assert item.amount >= stack_count + move_stack_count = stack_count + new_item = self.add_item_to_inventory(item.lot, move_stack_count, inventory_type=inventory_type_b, show_flying_loot=show_flying_loot) + self.remove_item_from_inv(inventory_type_a, item, amount=move_stack_count) + return new_item diff --git a/luserver/components/mission.py b/luserver/components/mission.py index 317698c..91b5fbe 100644 --- a/luserver/components/mission.py +++ b/luserver/components/mission.py @@ -38,6 +38,23 @@ class MissionState: ReadyToComplete = 4 Completed = 8 +def check_prereqs(mission_id, player): + player_missions = {mission.id: mission.state for mission in player.missions} + prereqs = player._v_server.db.missions[mission_id][1] + for prereq_ors in prereqs: + for prereq_mission in prereq_ors: + if isinstance(prereq_mission, tuple): # prereq requires special mission state + prereq_mission, prereq_mission_state = prereq_mission + else: + prereq_mission_state = MissionState.Completed + if prereq_mission in player_missions and player_missions[prereq_mission] == prereq_mission_state: + break # an element was found, this prereq_ors is satisfied + else: + break # no elements found, not satisfied, checking further prereq_ors unnecessary + else: # all preconditions satisfied + return True + return False + class MissionTask(Persistent): def __init__(self, task_type, target, target_value, parameter): self.type = task_type @@ -64,20 +81,23 @@ class MissionProgress(Persistent): 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] - def increment_task(self, task, server, player, increment=1): + def increment_task(self, task, player, increment=1): if task.value == task.target_value: return + 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) - server.send_game_message(player.notify_mission_task, self.id, task_mask=1<<(task_index+1), updates=[task.value], address=player.address) + player._v_server.send_game_message(player.notify_mission_task, self.id, task_mask=1<<(task_index+1), updates=[task.value], address=player.address) if not self.is_mission: for task in self.tasks: if task.value < task.target_value: break else: - self.complete(server, player) + self.complete(player) - def complete(self, server, player): + def complete(self, player): self.state = MissionState.Completed if self.is_mission: @@ -85,23 +105,23 @@ class MissionProgress(Persistent): else: source_type = LootType.Achievement - server.send_game_message(player.notify_mission, self.id, mission_state=MissionState.Unavailable, sending_rewards=True, address=player.address) - server.send_game_message(player.set_currency, currency=player.currency + self.rew_currency, position=Vector3.zero, source_type=source_type, address=player.address) - server.send_game_message(player.modify_lego_score, self.rew_universe_score, source_type=source_type, address=player.address) + player._v_server.send_game_message(player.notify_mission, self.id, mission_state=MissionState.Unavailable, sending_rewards=True, address=player.address) + player._v_server.send_game_message(player.set_currency, currency=player.currency + self.rew_currency, position=Vector3.zero, source_type=source_type, address=player.address) + player._v_server.send_game_message(player.modify_lego_score, self.rew_universe_score, source_type=source_type, address=player.address) for lot, amount in self.rew_items: player.add_item_to_inventory(lot, amount, source_type=source_type) if self.rew_emote is not None: - server.send_game_message(player.set_emote_lock_state, lock=False, emote_id=self.rew_emote, address=player.address) + player._v_server.send_game_message(player.set_emote_lock_state, lock=False, emote_id=self.rew_emote, address=player.address) player.max_life += self.rew_max_life player.max_imagination += self.rew_max_imagination if self.rew_max_items: - server.send_game_message(player.set_inventory_size, inventory_type=InventoryType.Items, size=len(player.items)+self.rew_max_items, address=player.address) + player._v_server.send_game_message(player.set_inventory_size, inventory_type=InventoryType.Items, size=len(player.items)+self.rew_max_items, address=player.address) - server.send_game_message(player.notify_mission, self.id, mission_state=MissionState.Completed, sending_rewards=False, address=player.address) + player._v_server.send_game_message(player.notify_mission, self.id, mission_state=MissionState.Completed, sending_rewards=False, address=player.address) # No longer required, delete to free memory in db @@ -121,9 +141,9 @@ class MissionProgress(Persistent): if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.MissionComplete and self.id in task.target: - mission.increment_task(task, server, player) + mission.increment_task(task, player) - server.commit() + player._v_server.commit() class MissionNPCComponent: def __init__(self, comp_id): @@ -147,18 +167,7 @@ class MissionNPCComponent: break elif offers_mission: log.debug("assessing %i", mission_id) - prereqs = self._v_server.db.missions[mission_id][1] - for prereq_ors in prereqs: - for prereq_mission in prereq_ors: - if isinstance(prereq_mission, tuple): # prereq requires special mission state - prereq_mission, prereq_mission_state = prereq_mission - else: - prereq_mission_state = MissionState.Completed - if prereq_mission in player_missions and player_missions[prereq_mission] == prereq_mission_state: - break # an element was found, this prereq_ors is satisfied - else: - break # no elements found, not satisfied, checking further prereq_ors unnecessary - else: # all preconditions satisfied + if check_prereqs(mission_id, player): offer = mission_id if offer is not None: @@ -185,7 +194,7 @@ class MissionNPCComponent: assert is_complete for mission_progress in player.missions: if mission_progress.id == mission_id: - mission_progress.complete(self._v_server, player) + mission_progress.complete(player) break def request_linked_mission(self, address, player_id:c_int64=None, mission_id:c_int=None, mission_offered:c_bit=None): diff --git a/luserver/components/modular_build.py b/luserver/components/modular_build.py index 1581634..75cc23a 100644 --- a/luserver/components/modular_build.py +++ b/luserver/components/modular_build.py @@ -19,6 +19,16 @@ class ModularBuildComponent: player = self._v_server.accounts[address].characters.selected() self._v_server.send_game_message(player.start_arranging_with_item, first_time, self.object_id, player.position, source_bag, source_id, source_lot, source_type, target_id, target_lot, target_pos, target_type, address=address) + def done_arranging_with_item(self, address, new_source_bag:c_int=None, new_source_id:c_int64=None, new_source_lot:c_int=None, new_source_type:c_int=None, new_target_id:c_int64=None, new_target_lot:c_int=None, new_target_type:c_int=None, new_target_pos:Vector3=None, old_item_bag:c_int=None, old_item_id:c_int64=None, old_item_lot:c_int=None, old_item_type:c_int=None): + player = self._v_server.accounts[address].characters.selected() + for model in player.temp_models.copy(): + player.move_item_between_inventory_types(None, inventory_type_a=InventoryType.TempModels, inventory_type_b=InventoryType.Models, object_id=model.object_id, stack_count=0) + + def modular_build_move_and_equip(self, address, template_id:c_int=None): + player = self._v_server.accounts[address].characters.selected() + new_item = player.move_item_between_inventory_types(None, inventory_type_a=InventoryType.TempModels, inventory_type_b=InventoryType.Models, object_id=0, template_id=template_id) + player.equip_inventory(None, item_to_equip=new_item.object_id) + def modular_build_finish(self, address, module_lots:(c_ubyte, c_int)=None): player = self._v_server.accounts[address].characters.selected() for model in player.temp_models.copy(): diff --git a/luserver/components/pet.py b/luserver/components/pet.py index 43df846..2478c97 100644 --- a/luserver/components/pet.py +++ b/luserver/components/pet.py @@ -40,5 +40,5 @@ class PetComponent: if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.TamePet and self.lot in task.target: - mission.increment_task(task, self._v_server, player) + mission.increment_task(task, player) diff --git a/luserver/components/rebuild.py b/luserver/components/rebuild.py index f5d63cc..e64af80 100644 --- a/luserver/components/rebuild.py +++ b/luserver/components/rebuild.py @@ -1,7 +1,9 @@ import asyncio +import time from ..bitstream import c_bit, c_float, c_int, c_int64, c_uint from ..math.vector import Vector3 +from .char import TerminateType from .mission import MissionState, TaskType from .scripted_activity import ScriptedActivityComponent @@ -10,6 +12,7 @@ class RebuildState: Completed = 2 Resetting = 4 Building = 5 + Incomplete = 6 class FailReason: NotGiven = 0 @@ -22,19 +25,31 @@ class RebuildComponent(ScriptedActivityComponent): super().__init__(comp_id) self.complete_time = self._v_server.db.rebuild_component[comp_id][0] self.smash_time = self._v_server.db.rebuild_component[comp_id][1] - + self.reset_time = self._v_server.db.rebuild_component[comp_id][2] + self.imagination_cost = self._v_server.db.rebuild_component[comp_id][3] + self.callback_handles = [] + self.rebuild_start_time = 0 + self.last_progress = 0 self._flags["rebuild_state"] = "rebuild_flag" self._flags["success"] = "rebuild_flag" self._flags["enabled"] = "rebuild_flag" - self._flags["rebuild_duration"] = "rebuild_flag" - self.rebuild_state = RebuildState.Open + self._rebuild_state = RebuildState.Open self.success = False self.enabled = True - self.rebuild_duration = 0 if not hasattr(self, "rebuild_activator_position"): self.rebuild_activator_position = Vector3(self.position) + @property + def rebuild_state(self): + return self._rebuild_state + + @rebuild_state.setter + def rebuild_state(self, value): + player = self._v_server.get_object(self.players[0]) + self._v_server.send_game_message(self.rebuild_notify_state, self.rebuild_state, value, player=player.object_id, address=player.address) + self._rebuild_state = value + def serialize(self, out, is_creation): super().serialize(out, is_creation) out.write(c_bit(self.rebuild_flag or is_creation)) @@ -42,7 +57,7 @@ class RebuildComponent(ScriptedActivityComponent): out.write(c_uint(self.rebuild_state)) out.write(c_bit(self.success)) out.write(c_bit(self.enabled)) - out.write(c_float(self.rebuild_duration)) + out.write(c_float(time.time() - self.rebuild_start_time)) out.write(c_uint(0)) if is_creation: out.write(c_bit(False)) @@ -53,29 +68,36 @@ class RebuildComponent(ScriptedActivityComponent): self.rebuild_flag = False def on_use(self, player, multi_interact_id): - if self.rebuild_state == RebuildState.Open: - assert multi_interact_id is None - prev_state = self.rebuild_state - self.rebuild_state = RebuildState.Building - self.players.append(player.object_id) - self.activity_flag = True - player.rebuilding = 1 - self._v_server.send_game_message(self.rebuild_notify_state, prev_state, self.rebuild_state, player=player.object_id, address=player.address) - self._v_server.send_game_message(self.enable_rebuild, enable=True, fail=False, success=False, duration=0, user=player.object_id, address=player.address) + assert multi_interact_id is None + assert self.rebuild_state in (RebuildState.Open, RebuildState.Incomplete) + for handle in self.callback_handles: + handle.cancel() + self.callback_handles.clear() + self.players.append(player.object_id) + self.activity_flag = True + self.rebuild_state = RebuildState.Building + player.rebuilding = 1 + self._v_server.send_game_message(self.enable_rebuild, enable=self.enabled, fail=False, success=self.success, duration=0, user=player.object_id, address=player.address) + self.rebuild_start_time = time.time() + drain_interval = self.complete_time/self.imagination_cost + remaining_cost = int((self.complete_time - self.last_progress) // drain_interval) + for i in range(remaining_cost): + self.callback_handles.append(asyncio.get_event_loop().call_later(self.last_progress%drain_interval + drain_interval*i, self.drain_imagination, player)) + self.callback_handles.append(asyncio.get_event_loop().call_later(self.complete_time-self.last_progress, self.complete_rebuild, player)) + return True - - asyncio.get_event_loop().call_later(self.complete_time, self.complete_rebuild, player) - return True + def drain_imagination(self, player): + player.imagination -= 1 + if player.imagination == 0: + self.rebuild_cancel(None, early_release=False, user_id=player.object_id) def complete_rebuild(self, player): - prev_state = self.rebuild_state self.rebuild_state = RebuildState.Completed self.success = True self.enabled = False - self.rebuild_duration = self.complete_time player.rebuilding = 0 - self._v_server.send_game_message(self.rebuild_notify_state, prev_state, self.rebuild_state, player=player.object_id, address=player.address) - self._v_server.send_game_message(self.enable_rebuild, enable=False, fail=False, success=True, duration=0, user=player.object_id, address=player.address) + self._v_server.send_game_message(self.enable_rebuild, enable=self.enabled, fail=False, success=self.success, duration=0, user=player.object_id, address=player.address) + self._v_server.send_game_message(self.play_f_x_effect, name="BrickFadeUpVisCompleteEffect", effect_type="create", effect_id=507, address=player.address) self._v_server.send_game_message(player.play_animation, animation_id="rebuild-celebrate", play_immediate=False, address=player.address) assert len(self.children) == 1 @@ -87,16 +109,30 @@ class RebuildComponent(ScriptedActivityComponent): if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.QuickBuild and task.target == self.lot: - mission.increment_task(task, self._v_server, player) + mission.increment_task(task, player) def smash_rebuild(self): self._v_server.send_game_message(self.die, death_type="", direction_relative_angle_xz=0, direction_relative_angle_y=0, direction_relative_force=10, killer_id=0, broadcast=True) self._v_server.destruct(self) def rebuild_cancel(self, address, early_release:c_bit=None, user_id:c_int64=None): - pass#self.rebuild_state = RebuildState.Open - #self.players.remove(user_id) - #self.activity_flag = True + player = self._v_server.get_object(user_id) + if self.rebuild_state == RebuildState.Building: + for handle in self.callback_handles: + handle.cancel() + self.callback_handles.clear() + self.last_progress += time.time() - self.rebuild_start_time + self.rebuild_state = RebuildState.Incomplete + self.players.remove(user_id) + self.activity_flag = True + player.rebuilding = 0 + if early_release: + fail_reason = FailReason.CanceledEarly + else: + fail_reason = FailReason.OutOfImagination + self._v_server.send_game_message(self.enable_rebuild, enable=False, fail=True, success=self.success, fail_reason=fail_reason, duration=self.last_progress, user=player.object_id, address=player.address) + self.callback_handles.append(asyncio.get_event_loop().call_later(self.reset_time, self.smash_rebuild)) + self._v_server.send_game_message(player.terminate_interaction, obj_id_terminator=self.object_id, type=TerminateType.FromInteraction, address=player.address) def enable_rebuild(self, address, enable:c_bit=None, fail:c_bit=None, success:c_bit=None, fail_reason:c_uint=FailReason.NotGiven, duration:c_float=None, user:c_int64=None): pass diff --git a/luserver/components/skill.py b/luserver/components/skill.py index 06c3671..6505474 100644 --- a/luserver/components/skill.py +++ b/luserver/components/skill.py @@ -123,7 +123,7 @@ class SkillComponent: if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.UseSkill and skill_id in task.parameter: - mission.increment_task(task, self._v_server, self) + mission.increment_task(task, self) target = self self.picked_target_id = optional_target_id diff --git a/luserver/components/stats.py b/luserver/components/stats.py index a06f7c0..6ad4c6e 100644 --- a/luserver/components/stats.py +++ b/luserver/components/stats.py @@ -1,6 +1,8 @@ import asyncio +import random from ..bitstream import c_bit, c_float, c_int, c_int64, c_uint +from ..math.vector import Vector3 class StatsSubcomponent: def __init__(self, comp_id): @@ -16,7 +18,7 @@ class StatsSubcomponent: self.life = self.max_life self.armor = self.max_armor self.imagination = self.max_imagination - + self.is_smashable = False @property def max_life(self): @@ -93,12 +95,11 @@ class StatsSubcomponent: out.write(c_float(self.max_imagination)) out.write(c_uint(1)) out.write(c_int(self.faction)) - show_smashable_glint = True - out.write(c_bit(show_smashable_glint)) + out.write(c_bit(self.is_smashable)) if is_creation: out.write(c_bit(False)) out.write(c_bit(False)) - if show_smashable_glint: + if self.is_smashable: out.write(c_bit(False)) out.write(c_bit(False)) @@ -110,5 +111,10 @@ class StatsSubcomponent: if self.spawner is not None: asyncio.get_event_loop().call_later(8, self.spawner.spawn) + def drop_loot(self, lot, owner): + object_id = self._v_server.new_spawned_id() + self._v_server.dropped_loot.setdefault(owner.object_id, {})[object_id] = lot + self._v_server.send_game_message(owner.drop_client_loot, use_position=True, spawn_position=self.position, final_position=Vector3(self.position.x+(random.random()-0.5)*20, self.position.y, self.position.z+(random.random()-0.5)*20), currency=0, item_template=lot, loot_id=object_id, owner=owner.object_id, source_obj=self.object_id, address=owner.address) + def die(self, address, client_death:c_bit=False, spawn_loot:c_bit=True, 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_uint=0, killer_id:c_int64=None, loot_owner_id:c_int64=0): pass diff --git a/luserver/components/vendor.py b/luserver/components/vendor.py index 5527b5a..c27d355 100644 --- a/luserver/components/vendor.py +++ b/luserver/components/vendor.py @@ -32,7 +32,7 @@ class VendorComponent: player = self._v_server.accounts[address].characters.selected() for item in player.items: if item is not None and item.object_id == item_obj_id: - self._v_server.send_game_message(player.set_currency, currency=player.currency + (item.base_value*count)//10, position=Vector3.zero, source_type=source_type, address=player.address) + self._v_server.send_game_message(player.set_currency, currency=player.currency + (item.base_value*count)//10, position=Vector3.zero, address=player.address) player.remove_item_from_inv(InventoryType.Items, object_id=item_obj_id, amount=count) break else: diff --git a/luserver/game_object_template.py b/luserver/game_object_template.py index 61edfff..bb47889 100644 --- a/luserver/game_object_template.py +++ b/luserver/game_object_template.py @@ -59,7 +59,6 @@ component[65] = PropertyVendorComponent, component[67] = LaunchpadComponent, component[104] = RailActivatorComponent, - component_order = list(component.keys()) def restore_template(*args): @@ -83,8 +82,11 @@ def Template(lot_, conn=None, comps=None, custom_script=None): 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_id is None: - script = importlib.import_module("luserver.scripts."+custom_script) - comp = script.ScriptComponent, + if custom_script != "": + script = importlib.import_module("luserver.scripts."+custom_script) + comp = script.ScriptComponent, + else: + comp = ScriptComponent, elif component_id in conn.root.script_component: script = importlib.import_module("luserver.scripts."+conn.root.script_component[component_id]) comp = script.ScriptComponent, @@ -213,7 +215,7 @@ def Template(lot_, conn=None, comps=None, custom_script=None): if mission.state == MissionState.Active: for task in mission.tasks: if task.type == TaskType.UseEmote and emote_id in task.parameter and task.target == self._v_server.game_objects[target_id].lot: - mission.increment_task(task, self._v_server, self) + mission.increment_task(task, self) def play_animation(self, address, animation_id:"wstr"=None, expect_anim_to_exist:c_bit=True, play_immediate:c_bit=None, trigger_on_complete_msg:c_bit=False, priority:c_float=2, f_scale:c_float=1): diff --git a/luserver/messages.py b/luserver/messages.py index e889ad8..ed7d8f4 100644 --- a/luserver/messages.py +++ b/luserver/messages.py @@ -119,6 +119,7 @@ class GameMessage(Enum): NotifyMission = 254 NotifyMissionTask = 255 RebuildNotifyState = 336 + TerminateInteraction = 357 RequestUse = 364 VendorOpenWindow = 369 EmotePlayed = 371 @@ -168,9 +169,11 @@ class GameMessage(Enum): StartBuildingWithItem = 1057 StartArrangingWithItem = 1061 FinishArrangingWithItem = 1062 + DoneArrangingWithItem = 1063 SetBuildMode = 1068 SetBuildModeConfirmed = 1073 MoveItemBetweenInventoryTypes = 1093 + ModularBuildMoveAndEquip = 1096 ModularBuildFinish = 1097 EchoSyncSkill = 1144 SyncSkill = 1145 diff --git a/luserver/modules/chat.py b/luserver/modules/chat.py index 7728c63..3b7437a 100644 --- a/luserver/modules/chat.py +++ b/luserver/modules/chat.py @@ -102,6 +102,9 @@ class ChatHandling(ServerModule): build_cmd.add_argument("type", type=int) build_cmd.set_defaults(func=self.build_cmd) + check_for_leaks_cmd = cmds.add_parser("checkforleaks") + check_for_leaks_cmd.set_defaults(func=self.check_for_leaks_cmd) + complete_mission_cmd = cmds.add_parser("completemission") complete_mission_cmd.add_argument("--id", type=int) complete_mission_cmd.set_defaults(func=self.complete_mission_cmd) @@ -119,6 +122,9 @@ class ChatHandling(ServerModule): faction_cmd.add_argument("faction", type=int) faction_cmd.set_defaults(func=self.faction_cmd) + glow_cmd = cmds.add_parser("glow") + glow_cmd.set_defaults(func=self.glow_cmd) + filelog_cmd = cmds.add_parser("filelog", description="Change which packets are logged to file") filelog_cmd.add_argument("action", choices=("add", "remove", "show"), default="show") filelog_cmd.add_argument("packetname") @@ -280,6 +286,9 @@ class ChatHandling(ServerModule): def build_cmd(self, args, sender): self.server.send_game_message(sender.activate_brick_mode, build_type=args.type, address=sender.address) + def check_for_leaks_cmd(self, args, sender): + sender.check_for_leaks() + def complete_mission_cmd(self, args, sender): if args.id: for mission in sender.missions: @@ -290,7 +299,7 @@ class ChatHandling(ServerModule): if mission.state == 2: for task_index, task_data in enumerate(self.server.db.missions[mission.id][2]): target_value = task_data[2] - mission.increment_task(mission.tasks[task_index], self.server, sender, target_value) + mission.increment_task(mission.tasks[task_index], sender, target_value) self.server.commit() def dismount_cmd(self, args, sender): @@ -313,6 +322,12 @@ class ChatHandling(ServerModule): elif args.action == "show": print(self.server.file_logged_packets) + def glow_cmd(self, args, sender): + if sender.rebuilding == 0: + sender.rebuilding = 1 + else: + sender.rebuilding = 0 + def help_cmd(self, args, sender): print("Please use -h / --help for help.") diff --git a/luserver/modules/physics.py b/luserver/modules/physics.py index e3efb71..b5c76ef 100644 --- a/luserver/modules/physics.py +++ b/luserver/modules/physics.py @@ -11,7 +11,7 @@ MODEL_DIMENSIONS[5633] = Vector3(-819.2, 0, -819.2), Vector3(819.2, 13.521, 819. MODEL_DIMENSIONS[5652] = Vector3(-2.5, -2.5, -2.5), Vector3(2.5, 2.5, 2.5) MODEL_DIMENSIONS[8419] = Vector3(-5.2644, 0.0051, -0.5011), Vector3(4.7356, 5.0051, 0.4989) -DEBUG_INCLUDE_NO_SCRIPT = True +DEBUG_INCLUDE_NO_SCRIPT = False log = logging.getLogger(__file__) diff --git a/luserver/scripts/avant_gardens/quickbuild_elevator.py b/luserver/scripts/avant_gardens/quickbuild_elevator.py new file mode 100644 index 0000000..945657c --- /dev/null +++ b/luserver/scripts/avant_gardens/quickbuild_elevator.py @@ -0,0 +1,4 @@ +import luserver.components.script as script + +class ScriptComponent(script.ScriptComponent): + pass # currently not implemented diff --git a/luserver/scripts/general/shark_death_trigger.py b/luserver/scripts/general/shark_death_trigger.py index a7e8102..b4e29b3 100644 --- a/luserver/scripts/general/shark_death_trigger.py +++ b/luserver/scripts/general/shark_death_trigger.py @@ -17,4 +17,4 @@ class ScriptComponent(script.ScriptComponent): if mission.state == MissionState.Active and mission.id == achievement_id: for task in mission.tasks: if task.type == TaskType.Script and self.lot in task.target: - mission.increment_task(task, self._v_server, player) + mission.increment_task(task, player) diff --git a/luserver/scripts/general/touch_complete_mission.py b/luserver/scripts/general/touch_complete_mission.py index 6694e04..85a2ffd 100644 --- a/luserver/scripts/general/touch_complete_mission.py +++ b/luserver/scripts/general/touch_complete_mission.py @@ -7,4 +7,4 @@ class ScriptComponent(script.ScriptComponent): if mission.state == MissionState.Active and mission.id == self.script_vars["touch_complete_mission_id"]: for task in mission.tasks: if task.type == TaskType.Script and self.lot in task.target: - mission.increment_task(task, self._v_server, player) + mission.increment_task(task, player) diff --git a/luserver/scripts/nimbus_station/imagination_statue.py b/luserver/scripts/nimbus_station/imagination_statue.py new file mode 100644 index 0000000..0d03a39 --- /dev/null +++ b/luserver/scripts/nimbus_station/imagination_statue.py @@ -0,0 +1,14 @@ +import asyncio + +import luserver.components.script as script +from luserver.components.rebuild import RebuildComponent + +IMAGINATION_POWERUP_LOT = 935 +SPAWN_AMOUNT = 10 +SPAWN_INTERVAL = 1.5 + +class ScriptComponent(script.ScriptComponent): + def complete_rebuild(self, player): + RebuildComponent.complete_rebuild(self, player) + for i in range(SPAWN_AMOUNT): + asyncio.get_event_loop().call_later(i*SPAWN_INTERVAL, self.drop_loot, IMAGINATION_POWERUP_LOT, player) diff --git a/luserver/scripts/nimbus_station/nexus_jay.py b/luserver/scripts/nimbus_station/nexus_jay.py index d523fb7..2cb2738 100644 --- a/luserver/scripts/nimbus_station/nexus_jay.py +++ b/luserver/scripts/nimbus_station/nexus_jay.py @@ -34,5 +34,5 @@ class ScriptComponent(script.ScriptComponent): for achievement_id in achievements: for mission in player.missions: if mission.id == achievement_id: - mission.complete(self._v_server, player) + mission.complete(player) break diff --git a/luserver/scripts/venture_explorer/bob.py b/luserver/scripts/venture_explorer/bob.py index b5da749..894a92c 100644 --- a/luserver/scripts/venture_explorer/bob.py +++ b/luserver/scripts/venture_explorer/bob.py @@ -11,5 +11,5 @@ class ScriptComponent(script.ScriptComponent): player.imagination = 6 for mission in player.missions: if mission.id == 664: - mission.complete(self._v_server, player) + mission.complete(player) break diff --git a/luserver/world.py b/luserver/world.py index a274779..618288a 100644 --- a/luserver/world.py +++ b/luserver/world.py @@ -116,8 +116,6 @@ class WorldServer(server.Server, pyraknet.replicamanager.ReplicaManager): console_log = packetname not in self.not_console_logged_packets except ValueError: packetname = self.unknown_packetname(data) - with open("logs/"+packetname+".bin", "wb") as file: - file.write(data) console_log = True if console_log: diff --git a/runtime/db/init.py b/runtime/db/init.py index d9c3227..8f2f6aa 100644 --- a/runtime/db/init.py +++ b/runtime/db/init.py @@ -79,7 +79,6 @@ def get_behavior(behavior_id): if behavior_id not in root.behavior: global behavs_accessed behavs_accessed += 1 - print(behavior_id) if behavior_id not in templates: return None template_id = templates[behavior_id] @@ -311,7 +310,7 @@ if GENERATE_COMPS: root.script_component[id] = script_name elif row[1] == 7 and row[2] not in root.destructible_component: - faction, faction_list, level, loot_matrix_index, currency_index, life, armor, imagination = cdclient.execute("select faction, factionList, level, LootMatrixIndex, CurrencyIndex, life, armor, imagination from DestructibleComponent where id == %i" % row[2]).fetchone() + faction, faction_list, level, loot_matrix_index, currency_index, life, armor, imagination, is_smashable = cdclient.execute("select faction, factionList, level, LootMatrixIndex, CurrencyIndex, life, armor, imagination, isSmashable from DestructibleComponent where id == %i" % row[2]).fetchone() if faction is None: faction = int(faction_list) # fallback, i have no idea why both columns exist in the first place if level is not None and currency_index is not None: @@ -332,7 +331,7 @@ if GENERATE_COMPS: if armor is not None: armor = int(armor) - root.destructible_component[row[2]] = faction, loot, minvalue, maxvalue, life, armor, imagination + root.destructible_component[row[2]] = faction, loot, minvalue, maxvalue, life, armor, imagination, is_smashable elif row[1] == 16 and row[2] not in root.vendor_component: comp_row = cdclient.execute("select LootMatrixIndex from VendorComponent where id == %i" % row[2]).fetchone() @@ -344,12 +343,12 @@ if GENERATE_COMPS: root.inventory_component.setdefault(row[2], []).append((comp_row[0], comp_row[1])) elif row[1] == 48 and row[2] not in root.rebuild_component: - comp_row = cdclient.execute("select complete_time, time_before_smash from RebuildComponent where id == %i" % row[2]).fetchone() + comp_row = cdclient.execute("select complete_time, time_before_smash, reset_time, take_imagination from RebuildComponent where id == %i" % row[2]).fetchone() if comp_row is not None: - complete_time, smash_time = comp_row + complete_time, smash_time, reset_time, take_imagination = comp_row if complete_time is None: complete_time = 0 - root.rebuild_component[row[2]] = complete_time, smash_time + root.rebuild_component[row[2]] = complete_time, smash_time, reset_time, take_imagination elif row[1] == 53 and row[2] not in root.package_component: comp_row = cdclient.execute("select LootMatrixIndex from PackageComponent where id == %i" % row[2]).fetchone() diff --git a/runtime/db/luz_importer.py b/runtime/db/luz_importer.py index cf5cf15..3e470e5 100644 --- a/runtime/db/luz_importer.py +++ b/runtime/db/luz_importer.py @@ -94,8 +94,11 @@ def parse_lvl(conn, world_data, lvl_path): config = ldf.from_ldf(config_data) custom_script = None - if lot != 176 and config.get("custom_script_server") not in (None, ""): - custom_script = scripts.SCRIPTS.get(config["custom_script_server"][len("scripts\\"):]) + if lot != 176 and "custom_script_server" in config: + if config["custom_script_server"] == "": + custom_script = "" + else: + custom_script = scripts.SCRIPTS.get(config["custom_script_server"][len("scripts\\"):]) spawned_vars = {} if "groupID" in config: @@ -135,8 +138,11 @@ def parse_lvl(conn, world_data, lvl_path): spawn_vars = {} obj.spawntemplate = config["spawntemplate"] - if config.get("custom_script_server") not in (None, ""): - spawn_vars["custom_script"] = scripts.SCRIPTS.get(config["custom_script_server"][len("scripts\\"):]) + if "custom_script_server" in config: + if config["custom_script_server"] == "": + spawn_vars["custom_script"] = "" + else: + spawn_vars["custom_script"] = scripts.SCRIPTS.get(config["custom_script_server"][len("scripts\\"):]) if "attached_path" in config: spawned_vars["attached_path"] = config["attached_path"] diff --git a/runtime/db/scripts.py b/runtime/db/scripts.py index 621c96e..701983e 100644 --- a/runtime/db/scripts.py +++ b/runtime/db/scripts.py @@ -1,4 +1,5 @@ -# consider converting all to path +# consider converting all to path so components using the same script are automatically handled +# some paths are removed from the database though SCRIPTS = {} SCRIPTS[313] = "general.death_trigger" @@ -34,7 +35,9 @@ SCRIPTS[r"02_server\Map\General\L_TOUCH_MISSION_UPDATE_SERVER.lua"] = "general.t SCRIPTS[r"02_server\Map\NT\L_NT_PARADOXTELE_SERVER.lua"] = "nexus_tower.paradox_teleporter" SCRIPTS[r"ai\AG\L_ACT_SHARK_PLAYER_DEATH_TRIGGER.lua"] = "general.shark_death_trigger" SCRIPTS[r"ai\AG\L_AG_PICNIC_BLANKET.lua"] = "avant_gardens.picnic_blanket" +SCRIPTS[r"ai\AG\L_AG_QB_Elevator.lua"] = "avant_gardens.quickbuild_elevator" SCRIPTS[r"ai\AG\L_AG_SHIP_PLAYER_DEATH_TRIGGER.lua"] = "venture_explorer.death_trigger" SCRIPTS[r"ai\AG\L_AG_SHIP_PLAYER_SHOCK_SERVER.lua"] = "venture_explorer.broken_console" SCRIPTS[r"ai\AG\L_AG_SHIP_SHAKE.lua"] = "venture_explorer.ship_shake" SCRIPTS[r"ai\NS\L_NS_JONNY_FLAG_MISSION_SERVER.lua"] = "nimbus_station.johnny_thunder" +SCRIPTS[r"ai\NS\L_NS_QB_IMAGINATION_STATUE.lua"] = "nimbus_station.imagination_statue"