A character's editor level is its account's GM level for accounts at editor_gm_level
or above, and 0 for everyone else (it was 1 or 0). It is written as the save's edit
attribute, sent with the character after the GM level (the editor flag, then the
level) and given in answer to the GetEditorLevel game message.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This reverts commit f6914940. The client's level editor builds a zone's objects
itself from its own files, so a world server that constructs none of them has no use.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
With -editmode 1 the world loads the zone file, terrain scene map, navmesh and
level revisions, but makes no level objects, carver blockers, spawners, spawner
networks, triggers, vanity objects or live event objects. The zone control
object stays with the zone's own template, as the client makes the same one
itself (LevelManager::LoadZoneControlObject, 0x01082660); its server script
does nothing and a race track's does not take the player into a race. Such a
world lets in only accounts at editor_gm_level.
Plumbing only: no command starts an edit mode instance yet (docs/EditMode.md).
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The master server dropped a transfer request it started no instance
for, so the world server never heard back and the player waited. It
now answers the request with an empty address and the reason in place
of the port: no room for another instance (max_instances), a zone that
is not in the ZoneTable, or another reason. A request for a private
zone that does not exist is answered the same way.
The world server passes this on as a TRANSFER_TO_WORLD without an
address, which the client shows as a failed map change, and leaves the
character where it is. The auth server fails the login when there is
no character select to send the player to.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
A player could change their offer after the other player gave the final
accept, and the trade completed with the new offer on their own accept.
Both clients drop their accepts when an offer changes, the one that
changed it and the one that receives the update, so the trade now does
the same and both players have to accept the offers as they are.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The client's trade window has 8 slots for each player and takes neither
a bound item nor an equipped one. An offer with more than 8 items, a
bound item or an equipped item is now refused like the other offers the
window can not make, when it arrives and again when the trade
completes.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
A zone transfer from a launchpad took the zone from the message when
the message asked for that. The client never does, so the zone is now
always the launchpad's default zone or the zone the player picked on
it. The log line no longer uses the sender named in the message.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Several messages used the player, the character or the user they named
without checking that there is one. A match request and a trade request
are now only handled for the player that sent them, a linked mission
request and a build mode change only for the sending player, and the
remaining handlers return when the player, character or user is
missing.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The messages that set a property's privacy option and name, start and
finish building, place, move and remove models and change a model's
behaviors were handled for any player on the property, and outside of
a property they used a property that is not there. They are now only
handled for the owner of the property the player is on. Only an item
from a model inventory is placed as a model.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The die request, the smash request, the loaded notice, chat commands
and the racing pickup notice were handled for whichever object they
named. They are now only handled for the player that sent them, or for
the vehicle that player drives where the client sends them for it. A
racing pickup also has to be an object of a race track that is not a
player, a vehicle or the zone's own object.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
A level up was applied every time the client reported one. The next
level now has to exist, the player needs the score that level asks
for, and the message has to come from the player it is for.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
MissionDialogueOK accepted or completed the mission for whichever
object the message named as the responder. The responder now has to be
the player that sent the message, the object the dialogue belongs to
has to give or take the mission (on its own or through a random
mission's pool), a mission is only accepted when the player can accept
it and only completed when it is ready to complete. The object's
script runs after these checks.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
A trade used the LOT and the count from the offer as the player sent
it. The offer is now resolved when it arrives and again when the trade
completes: the LOT comes from the held item, the count stops at the
held count, and an offer that names an unknown item, the same item
twice or a count of 0 is refused. The other player only receives an
item that was taken from the offering player.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The source no longer destroys the player's own ghost: losing it hid the character, and the target's construction
brought it back with the login effect (LWOGhostComponent::OnGhostReceiveDestruction, 0x00c99410,
LWOBaseRenderComponent::OnEnterScope, 0x00be2150). The target constructs the player to its own client without a
position and with world transition state 3. The client sends PlayerLoaded itself after that construction, so the
server only runs it when none came within 5 s, and PlayerReady (camera pitch reset) is not sent. A seamless arrival is
only expected for 30 s, so a later login gets LOAD_STATIC_ZONE.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Jetpack mode is not saved, and the equip skill that turns it on was cast
only when the item was put on, so a player still wearing a jetpack lost
it in the next world. Live sent SetJetPackMode (use, bypass checks, effect
167, the values of the jetpack's equip skill) shortly after the player's
own construction in 12 of 28 world loads of a player with a jetpack, and
constructed the player in jetpack mode in the other 16.
The jetpack behaviors among the equip skills of the equipped items are
run again when the player has loaded. Nothing new is saved.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sg_cannon.lua puts a moving platform target (the subs and the kraken) on its path with SetCurrentPath{ pathName, startPoint = 0 }; its SetPathingSpeed is read by nothing on a moving platform, so these run their paths at the waypoints' speeds (10, 15 and 35 in the zone), as the client's mover does. Live constructed them with the path and the mover waiting at waypoint 0 (9) and serialized the mover at each waypoint (9, then 2). They had a movement AI and a made up PlatformResync instead, and the kraken a speed chosen to look right, which goes back to the script's.
PlatformResync's constructor that overrode its arguments for a few LOTs (the FV tree platform 9483 among them) has no user left and is gone; a resync request is answered by movers only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's model behaviors (every rotation, DoDamage, OnTimer, OnStartup, MoveBackToStart, moves along the model's
local axes), raw terrain reading with scene lookups and scene tools, property model and brick by brick fixes and the
chat server's player count fix, merged onto this branch's structures:
- game messages stay structs; the angular velocity messages join them and the handler sets a message's target
- strips own their speed again and the block names, moves and rotations stay in the shared action table
(PropertyBehaviorActions, which the dashboard's behavior player reads; it now lists rotations too)
- the zone keeps reading its file through ZoneFile and takes the boundaries from it, then loads the raw terrain as main
does; the old dNavigation terrain reader is gone
- the show all response stays a struct and logs a player count mismatch as main does
- the property management component tells models who sent a chat message
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: the server mock keeps a copy of the last bitstream sent
The bitstreams sent are usually on the sender's stack, so the pointer it kept was dangling once Send returned.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: PlaceModelResponse writes the model's rotation
The client's PlaceModelResponse::Deserialize (0x00dc0170) reads the rotation as an optional w, x, y, z quaternion, but the server wrote the 4-byte response after the rotation flag, so with any rotation other than identity the client ran out of data.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: naming a model no longer renames the property
The model info window sends UpdatePropertyOrModelForFilterCheck with isProperty false (client 0x00cc42e0); only the property editor sends it true (0x00c2e710). A model's name and description aren't stored yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: keep a model item's blueprint across saves
A brick built model item's config has blueprintid (lowercase), which the saved item XML didn't keep (only blueprintID), so a picked up model lost its blueprint on the next load and could not be placed again. It is now saved as bp.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: write model behaviors only for property and inventory models
The client makes the mutable model component, which reads the behaviors and editing info, only when the object's config has propertyObjectID or inInventory (ObjectLoader2::LoadModelBehaviorsComponent); every other model gets the plain one, which reads only the model block. Writing the behaviors for every model made the client read them as the next component's data.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: the model vault uses the models' inventory groups, as the client
LWOInventoryComponent_Common::msgUpdateInventoryGroup (0x00c955b0) and msgUpdateInventoryGroupContents (0x00ce1f50) look the inventory type up in m_VaultToPlayerInventory first, which maps VAULT_MODELS to MODELS. The server refused group updates for the model vault.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A client that loads the zone again while its player is in the world (the
Happy Flower editor reloads the zone in place) sent LEVEL_LOAD_COMPLETE a
second time; LoadPlayer returned at once because the player existed, so
the client waited forever. Now the server resends the character
(CreateCharacter, ServerStates), forgets what it had sent that client,
constructs every object again and sends the done-loading sequence at the
player's current place. A first load is unchanged.
The Happy Flower editor messages (GetEditorLevel, the HF_* messages) are
logged when they arrive, until the server handles them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* add rotation behavior logic (not working correctly for multiple axes)
* Fix FetchContent_Declare speed
* remove manual quaternion math
* feat: working rotations
* remove flag
* feat: make directional movements based on model rotation and not world axes
* poggers rotation on the strip
* Add OnStartup and OnTimer
* go home works
* Add DoDamage behavior and dont try and start the same node multiple times
* fix: pause bbb models
* interrupt rotations and save interrupt count across resets
LWOMissionComponent::MissionWindowOK (0x00d501f0) turns a mission in only
when CanReceiveAllRewards (msgCanReceiveAllRewards 0x00d17e20,
sub_00d17750) passes for the reward the player picked: the reward items
(the repeat ones once completed, each at least 1) must fit after the items
the tasks take (a gather task's target unless it keeps them, one of a
delivery task's target) with the first completion's bag rewards added.
The fit is LWOInventoryComponent_Common::CheckCanAddItems (0x00d53de0):
turned in items leave first (an item of 1 settles the whole count), a
unique item fails while one is held outside the buyback, then each item
tops up stacks of its LOT (stack size 0 is no limit, LookupItemInfo
0x00c1c190) and takes free slots.
MissionDialogueOK now refuses a turn-in that does not pass, which the
client never sends. The client's max currency part is not checked: the
server writes no cm, so the client has no limit either.
InventoryComponent::GetDefaultInventorySize is split out of GetInventory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client keeps a viewed flag on each mission in progress, sets it with
SetMissionViewed (LWOMissionComponent::msgSetMissionViewed 0x00bec7a0, only
for missions in progress) and reads it as v on the mission's <cur> entry
(LWOMissionComponent::LoadFromSaveData 0x00d171c0, a number or "true", false
when missing). The server now handles SetMissionViewed, saves v="1" for a
viewed mission in progress and loads it back; saves without v load as not
viewed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A client asking to resync a simple mover that has no path got a
PlatformResync anyway, and the client's simple mover then reads waypoints
from its null path and crashes (LWOPlatformSimpleMover::Resync 0x00bf9ec0,
Path::GetWaypointAtIndex). The two LOTs special-cased for this before are
examples of the same thing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LWOInventoryComponent_Common::msgUseNonEquipmentItem (0x00cdeba0) asks
GetStunned first and uses nothing when canUseItem is false
(LWOControllablePhysComponent::msgGetStunned 0x00be0df0: stunned from
using items, or dead). The server now counts the use-item stun of every
SetStunned it sends for an entity as msgSetStunned (0x00bf1d10) does
(push/pop, never below 0, characters only, unless immune and not
bIgnoreImmunity), and checks it with IsDead before using an item. The
server never checked either.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LWOSkillComponent::msgStartSkill (0x00d45cb0) starts no cooldown for cast
types 1 and 2, and inserts the cooldown (std::map insert), so a cooldown
group already running keeps its time left. The server started one for
every cast type and extended a running group to the longer cooldown.
Live client casts used cast types 0, 3 and 4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LWOSkillComponent::msgStartSkill (0x00d45cb0) logs and ignores a StartSkill
whose skill handle is still waiting on behavior syncs. The server ran it a
second time: the hits, the imagination cost and the mission progress twice.
Live captures hold 22 byte-identical StartSkill resends with the same
handle a few packets apart.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client's RequestLinkedMission handler (LWOMissionOfferComponent
0x00cd6eb0) takes the giver's list without the mission the window was
for, and a new mission (AVAILABLE, never completed) at its head is the
one offered. DLU offered every qualifying mission again, so a mission
just accepted was offered once more. The live captures match the client:
no offer after an accept, and after a turn in the next mission of the
chain, once per RequestLinkedMission.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RequestResurrect resurrected whoever sent it, so a living player could reset
their health and imagination, and repeated requests stacked respawns. The
client's destroyable resurrects only when smashed and not resurrecting
(LWODestroyableComponent::SendMessage 0x00d29e40); live, all 17 requests in
the captures came after the player's Die and before its Resurrect.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Physics/, Activity/ (activity, scripted activity, shooting gallery,
quickbuild, minigame control, racing control base, racing control, gate rush),
Vendor/, Character/ (what the client makes with a character, plus ghost,
minifig and mission), Sound/ and Property/; the rest stays where it was.
File moves only; DLU_COMPONENT_INCLUDE_DIRS gives every target the folders.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Components no longer have a virtual OnUse; each component that reacts to a
use registers a RequestUse handler, like the client's components. The entity
runs the INTERACT trigger and the script, then delivers a RequestUseEvent
(carrying the user) to the handlers. The mission choice of a multi-interact
use goes only to the mission offer, as before. Switches keep a direct
EnterIfResponding for touches and pets.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client's LWOPlatform logic (ArrivedAtWaypoint 0x00c86c30, ProcessStateChange 0x00cce380, GetNextWaypoint, the waypoint speeds) runs on the server: stopped at a waypoint (25 at an end) for its wait, then travelling (2), serialized on arrival and departure as in the NT mover captures; constructions carry the path and the mover state; RequestPlatformResync gets the current state, percent and position. The LOT 9483 timers are gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The model info window sends UpdatePropertyOrModelForFilterCheck with isProperty false (client 0x00cc42e0); only the property editor sends it true (0x00c2e710).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live servers put _Metric_ keys in AddItemToInventoryClientSync's extra info,
after the item's own config, saying where the items came from: the source
object's LOT (_Metric_Souce_LOT_Int, misspelt as live had it), the mission,
activity, coins paid, mail or trade. LootMetrics holds them and writes them
with the key names and name value types live used (the mail ID as type 8,
the trade ID as type 9). AddItem, ReceiveItem (its options), the new item
constructor and Item::SetCount pass them through to the message; the item
does not keep them.
RemoveItem and Item::SetCount can also say what took items away
(ItemRemovalSource), filling RemoveItemFromInventory's loot source and
source object instead of none.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every LU MessageType has a struct or is listed as never used by this server; every game message struct reads;
samples of each family and of sent game messages read back; replica constructions, updates and destructions written
by the server's own serializers read back. Generator finds constructors defined in the .cpp.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GameMessageDecoder reads every NetGameMsg struct (generated member lists in GameMessageFields.inc) instead of 10
hand-written ones; DisplayTooltip gets the Deserialize it lacked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fixture check now also reads every recorded client game message with the
struct the server reads it with (GameMessageHandler::CreateReceived) and writes
it again: it must read the whole message and give back the same bits. Game
message fields are decoded with the server's structs in the fixture tests.
A synthetic fixture, built in the test from the server's own structs (login,
position update, a client game message), goes through the export steps
(portable, anonymised, saved, read again) and passes the same checks; recorded
fixtures stay in tests/fixtures-local and are never committed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Venture vision from an equipped item was sent while the character loaded, before the client's UI existed, so after a
login the minimap stayed empty until the item was equipped again (a world transfer keeps the UI, so it worked
there). The player's active venture vision effects are sent again once the player has loaded. Check: wear the
Venture Vision helmet, log out and back in: the minimap shows the icons.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guild packets of the 1.10.64 client (docs/Guilds.md) as Serialize/Deserialize structs, laid out the way the client's
packet handlers read them: GUILD_CREATE_RESPONSE, GUILD_INVITE, GUILD_INVITE_INITIAL_RESPONSE, _FINAL_RESPONSE,
_CONFIRM, GUILD_ADD_PLAYER, GUILD_REMOVE_PLAYER, GUILD_LOGIN_LOGOUT and GUILD_DATA (ClientPackets), the world packet
TMP_GUILD_CREATE the create box sends, the chat packets the client sends through its world (GUILD_INVITE,
GUILD_INVITE_RESPONSE, GUILD_LEAVE, GUILD_GET_ALL), DLU's world <-> chat packets (GUILD_CREATE, GUILD_KICK,
GUILD_GET_STATUS as the chat server's guild update to a world, and GUILD_SET_RANK and GUILD_DISBAND appended to
MessageType::Chat after CREATE_TEAM) and the game message DisplayGuildCreateBox (626). Fixed-size names always keep a
NUL, since the client reads them as C strings. Enums eGuildCreateResponse, eGuildInviteResponse,
eGuildInviteFinalResponse, eGuildRank and eGuildLeaveReason. Nothing sends them yet.
Check: GuildPacketsTests compares every packet with the bytes at the client's offsets. Nothing to check in game.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live sent, right before TRANSFER_TO_WORLD on every rocket launch (131
captured): NotifyClientFlagChange(32, true), TransferToZone
(check_transfer_allowed, the target map, the landing spawn point, the
clone only for properties, no position or rotation),
TransferToZoneCheckedIM (no queue) and NotifyClientFlagChange(32,
false). DLU went straight to TRANSFER_TO_WORLD.
In the client TransferToZone runs the civilian INVALIDMAPTRANSFERLIST
check, and TransferToZoneCheckedIM pauses the player's controls, starts
the target zone's loading screen and leaves the gameplay state
(LWOCharacterComponent, cases TransferToZone and
TransferToZoneCheckedIM). They are sent from the transfer callback, so
a failed zone request never leaves the client paused. Instance exits
through a message box used TransferToLastNonInstance in live instead
and are not changed here.
Check: launch rockets to Nimbus Station, Gnarled Forest and your
property: controls lock and the destination's loading screen shows as
the rocket leaves, and you land at the usual spawn point.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live sent PlayerReachedRespawnCheckpoint right after
ServerDoneLoadingAllObjects on 143 of 157 captured loads, with a
rotation: the spawn point the player arrived at, or a checkpoint they
had reached before. DLU sent it before constructing the zone's objects,
only when a checkpoint was saved for the zone, and always unrotated.
It now goes right after ServerDoneLoadingAllObjects on every load: the
saved checkpoint when there is one (DLU saves no rotation for it, so
that one stays unrotated), otherwise the position and facing the
player loaded in at. Inferred: that the loaded-in spot matches live's
spawn point choice (live's is the spawn point object, a few tenths of
a unit from the player's start).
Check: log in fresh to a zone, die before touching any checkpoint and
respawn: you come back where you arrived, facing the same way; reach
a checkpoint, change zones and come back, die: you respawn at that
checkpoint.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live answered PlayerLoaded with PlayerReady to the player and then a
second PlayerReady to the zone control object (0x3FFFFFFFFFFE), both
to the loading client: 235 of 237 captured loads carry exactly that
pair. DLU sent only the first. The zone control object's client-side
zone scripts are what can react to it (inferred: the client's
component handlers only act on the player's own PlayerReady).
Check: load into Avant Gardens, Nimbus Station, a property and an
instance (a survival or dragon battle): the zone plays its intro,
music and UI as before and nothing is stuck waiting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live filled SetCurrency's source fields per source type (16,816 decoded
live SetCurrency): pickups carry the position the client picked the
coins up at (the one in its PickupCurrency) and no source; mission,
achievement and activity rewards name the player (object and LOT 1);
vendor buys, sells and buybacks name the vendor and its LOT; trades
carry the trade ID; death, mail and everything else name nothing. No
live SetCurrency sets loot_type. DLU wrote a present source LOT of 0,
no object and a zero position for all of them.
The position is the one the client uses: for pickups it projects it to
the screen as the start of the coin counter animation
(LWOCharacterComponent::SetCurrency), so it started from the world
origin before. PickupCurrency now reads that position (the client
always sends it). The trade ID is an 8-byte object ID in the client;
DLU declared it 4 bytes, which only never broke because it was never
set.
Check: pick up coins and watch the coin counter animate from where the
coins were; buy and sell at a vendor, finish a mission and trade coins
with another player, and the coin total updates each time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live sends used_mouse false, no caster latency, no clicked position and
a zero originator rotation (present, all four components 0) in every
echo: 78,841 of 78,841 in the live captures, player and server casts
alike. DLU forwarded the casting client's values and wrote the caster's
facing for server casts. The client copies the rotation into its local
StartSkill (LWOSkillComponent::msgEchoStartSkill), which is why a real
rotation made power-up pickups jitter; the per-call override that
worked around that is no longer needed and is removed.
Check: with two players, attack, use a thrown or ranged item and pick
up power-ups; the other player sees the same animations and the
caster no longer snaps or jitters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CollectibleComponent (79 rows: id, requirement_mission) is only in the
CDClient for the server: the 1.10.64 client has no string for it. DLU
never read it.
What the column holds (1.10.64 CDClient, joined with ComponentsRegistry,
Missions and MissionTasks): for 63 rows it is the mission the collectible
belongs to. Mostly that is the achievement whose collection task
(taskType 3) targets the collectible's LOT (the flags, imagination bricks,
Johnny Thunder collectibles). For a few it is a mission to accept from an
NPC that does not collect the item itself: the four Ninjago dragon relics
(16483-16485) are collected by the hidden achievements 2064-2067 but
their requirement is 2040 (accepted from LOT 13789, "complete 2064-2067").
Other values: -1 and 66666666 (no such mission) on test rows.
So a collectible whose requirement_mission is a mission to accept
(Missions.isMission) now only counts (HasBeenCollected progresses
nothing) while the player has that mission accepted and not handed in
(ACTIVE, READY_TO_COMPLETE or their repeat states). Achievements, missing
missions and rows without one are unchanged. Without this, a player who
had not accepted 2040 could collect the relics early and have 2040
complete as soon as it was accepted. The gate itself is inferred from the
data: the captures show collections but not the live server's check.
The collectible's object report shows the requirement mission.
Check in game: in Ninjago Monastery, before accepting the dragon relic
mission (2040), touch a dragon relic: it does not count; accept 2040 and
collect them: each counts and 2040 completes after the fourth. Flags,
imagination bricks and Johnny Thunder collectibles still count as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LWOCharacterComponent sends ModifyGhostingDistance (1485: an optional
fDistanceScalar, default 1) on load. All 239 live packets were
the single byte 00 (default scale), so there is nothing for the server to
change; it was logged as an unknown game message. It is now read and
ignored.
Check in game: nothing changes; the world server log no longer has
"Received Unknown GM ... 1485" on each load.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client's rail activator sends RequestRailActivatorState (1479, no
payload) when it is added to the world (LWORailActivatorComponent::
SendMessage 0x00c00da0) and live answered with
NotifyRailActivatorStateChange (1478, bActive) to that client; the client
stores rail_activator_active and updates the rail's pick type (usable or
not). Live: 152 requests, 413 answers, every one bActive = true. DLU
dropped the request and never answered.
RailActivatorComponent keeps the level key rail_activator_active
(default true; every rail in the live levels sets it to 1) and the
request is answered with it.
Check in game: in Ninjago Monastery and Nimbus Station, rails (spinjitzu
posts, the Nexus Tower rails) show as usable and work as before when
first loading the world and after zone changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>