Commit Graph

2377 Commits

Author SHA1 Message Date
Aaron Kimbrell
07154c58d2 refactor(ugc): remove the path traced hidden-face method; the renders are the only one
The path tracer that imitated LU Toolbox's Remove Hidden Faces took 17 to 100
times as long as the renders from 42 directions around the model, too heavy to
use. It goes with its settings (hsr_method, hsr_samples, hsr_bounces,
hsr_sample_spacing, hsr_min_points), its side by side tracing for GPUs and its
tests. The renders (UgcRender::VisibleFromAround) remove hidden faces as before
that method existed; their size is hsr_resolution (1024), and the memory
estimate counts their buffers again.

The hidden-face method is no longer a processing option: the dashboard's picker,
/reprocessproperty and --make-model take only the ray backend (the occlusion's)
and denoising. Options stored before (made_options, process_options,
ugc_process_runs, --make-model arguments) that name toolbox or fast still
parse; the word is skipped.

Check: the settings page has no hsr_method or path settings and has
hsr_resolution; /reprocessproperty embree toolbox still works (toolbox
ignored); models made with the defaults keep their hashes (UGC tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
b897681f67 docs(ugc): processing options (ray backend, hidden-face method, denoising)
docs/UgcServer.md gets "Processing options": the three settings and their
choices, how they compare with builtin/toolbox/off, the optional builds
(DLU_OIDN, DLU_HIPRT) and what they need, what each make records and where the
dashboard shows it; the migration, /reprocessproperty's options, the command
line's and the UGC page's buttons.

Check: the section reads right against the settings page and the UGC page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
07dbf30dc8 feat(ugc): ray_backend=hiprt traces on the GPU with HIPRT and Orochi (optional build)
HIPRT (MIT) behind the CMake option DLU_HIPRT (off): its headers come from its
SDK (HIPRT_ROOT, else ROCm's /opt/rocm) and are copied next to the servers; its
library is loaded when first used (hiprtew), as HIP or CUDA are by Orochi
(MIT, fetched pinned by hash; CUDA when its toolkit is found). The trace
kernels (nearest hit skipping the triangle a ray leaves, any hit) are compiled
the first time and kept in cache/hiprt. One GPU context for the process
(hiprt_device picks the GPU); the workers take turns on it. When HIPRT, the
GPU or a scene's upload fails, Embree is used instead, and the UGC server logs
why at start.

For a GPU the rays go in batches (UgcRays::Scene gets batch queries; the CPU
backends answer them a ray at a time):
- hidden faces: with a batch backend the paths are traced side by side, a
  bounce at a time (the path code split into Start, Scatter and Bounce, the one
  by one tracing unchanged); the same paths with the same random numbers, so
  the same triangles are decided (tested with builtin side by side)
- the occlusion bake and the denoised icons' traced occlusion always ask in
  batches (the same rays, the same results)

Its symbols are hidden: the servers export theirs (-rdynamic), and HIPRT's
library, which has an Orochi of its own, would otherwise call ours.

Check: configure with -DDLU_HIPRT=ON on a machine with ROCm (or HIPRT's SDK)
and an AMD RDNA or NVIDIA GPU; UgcServer --make-model x.lxfml out hiprt; the
UGC tests (hits, hidden faces and occlusion against builtin); a build without
it leaves everything as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
2e2e8153e2 feat(ugc): denoise=oidn traces icons' occlusion per pixel and denoises it (optional build)
Intel Open Image Denoise 2 (Apache-2.0) behind the CMake option DLU_OIDN (off):
an installed OIDN is used when found, else Intel's release package (pinned by
hash) is downloaded and its libraries copied next to the servers.

A denoiser only removes noise that differs from pixel to pixel; the icons'
occlusion comes from the bake, per vertex, which it leaves as it is (checked:
white noise 0.17 -> 0.006 relative spread, per-vertex blocks unchanged). So
with denoise=oidn a model's icon is drawn from model.noao.nif (its colors
before the bake) with its occlusion traced per pixel of the supersampled image
(denoise_samples rays, default 4, with the bake's distance and strength and the
ray backend), box filtered and denoised at the icon's size, guided by the colors
and normals. The model keeps its baked occlusion. Icons drawn again from stored
files use the stored model.noao.nif the same way.

OIDN works on a thread of its own; its time is charged to the job's thread
(UgcThrottle::Charge), so the CPU budget and the recorded CPU time include it.

Check: configure with -DDLU_OIDN=ON; UgcServer --make-model x.lxfml out oidn
and compare its icon.png with one made with off; an OFF build leaves icons as
they were.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
1700b7e2e3 feat(dashboard): pick processing options for Make again; compare them on the UGC page
The UGC page's Make again buttons (a model's, the failed ones, everything) use
the ray tracer, hidden-face method and denoising picked next to them (the
settings' when left alone). The List view's new Options column shows what made
each model and what its next make will use; "Processing options compared"
shows every combination the made models used with its makes, models and the
average time, CPU time, hidden faces', occlusion's and icon's time and share of
triangles removed per make.

Check: the three selects next to Make again (models only); make a model again
with embree fast and see its Options column and the comparison table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
ef3c74f715 feat(ugc): processing options per make, recorded per model with their times
Staff can make models again with other processing options than the UGC
settings' (ray backend, hidden-face method, denoising) and every make records
what made it, for comparing the options.

- migration mysql 99 / sqlite 82 (ugc_process_options): ugc.process_options
  (picked for the next make, cleared once made), ugc.made_options (what made
  the current files) and ugc_process_runs (every successful make: options,
  wall and CPU time, hidden faces', occlusion's and icon's time, bricks,
  triangles before and after)
- IUgc: ResetUgcModelProcessing and ResetPropertyUgcModelProcessing take the
  options; PendingModel carries them; RecordUgcModelRun, GetUgcRunSummaries;
  list entries have madeOptions and processOptions
- the UGC server applies a job's options over its settings and records the run
- /api/ugc/reprocess takes options ("embree fast oidn"); /api/ugc/options
  lists the choices, the settings' defaults and averages per combination
- /reprocessproperty [builtin|embree|hiprt] [toolbox|fast] [off|oidn], any
  order, all optional

Check: run the migration on MySQL and SQLite; /reprocessproperty embree fast
on a property, then the models' made_options and ugc_process_runs rows;
/api/ugc/options.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
06be40471b feat(ugc): settings for the ray tracer, hidden-face method and denoising
New UGC settings (ugcconfig.ini and the dashboard's settings page):

- ray_backend: builtin (default), embree or hiprt (falls back to embree when
  the build or machine can't); the hidden faces' paths and the occlusion rays
- hsr_method: toolbox (default, LU Toolbox's paths) or fast (the renders from
  around the model), and hsr_fast_resolution (1024) for the fast one
- denoise: off (default) or oidn (icons; off until a build has it)

UgcProcessOptions (dCommon/UgcKeys.h) names the choices for everything that
passes them on ("embree fast oidn", any order, left out: the setting's).
UgcJobs::ApplyOptions puts a choice over the settings and MadeWith says what a
make used after fallbacks; a made model's stats.json records it (rays,
hsrMethod, denoise). UgcServer --make-model and --make-modular take the
choices after the folder and print the CPU time and what made it.

Check: the defaults make the same files as before; the settings page shows the
four settings under UGC; UgcServer --make-model model.lxfml out embree fast.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
00607a20a6 feat(ugc): the fast hidden-face method back, next to LU Toolbox's
UgcHsr::Options::method picks how hidden faces are found: toolbox (LU Toolbox's
paths, the default, unchanged) or fast, the test the UGC server used before
"hidden faces removed as LU Toolbox's Remove Hidden Faces decides them",
restored unchanged as UgcRender::VisibleFromAround: the opaque mesh rendered
from 42 directions around the model (Options::fastResolution pixels square,
1024 as before) and the triangles that show in none removed. It is much
faster, but it also removes faces seen only by bounced light (interiors,
recesses), which LU Toolbox keeps. Nothing sets it yet.

Check: the UGC tests (the fast method removes a box seen only through a
chimney, which the paths keep; its files are the same every time).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
57110a7081 feat(ugc): rays behind a backend interface, with Embree as a second backend
UgcRays::Scene answers the two ray queries the UGC server makes: the nearest
hit for the hidden faces' paths (never the triangle a path leaves) and any hit
for the ambient occlusion rays. Two backends:

- builtin: the two hierarchies the queries had before, moved unchanged (each
  built the first time it is asked), so the files made are the same bytes
- embree: Embree 4 on the job's thread (a device per worker thread, no threads
  of its own, so its time counts in the CPU budget), watertight, the skipped
  triangle filtered out

UgcHsr::Options::rays and UgcRender::AoOptions::rays pick the backend; both
default to builtin, and nothing sets them yet.

Check: the UGC tests (builtin's files keep their hashes; UgcRays tests compare
embree's hits, hidden faces and occlusion with builtin's).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
6ca265a4d9 build(ugc): fetch and build Embree 4 for the UGC server's rays
Embree 4.4.0 (Apache-2.0) is fetched like glm and curl and built as a static
library: its own task scheduler (no TBB), triangles only, single rays, no ISPC,
SYCL, tutorials or tests; SSE2, AVX and AVX2 kernels picked at run time. Its
Debug build keeps its optimizations but not its assertions. Nothing uses it yet.

Check: a clean configure fetches embree and the build links (Linux and Windows);
the extra build time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:29:08 -05:00
Aaron Kimbrell
7dc85692d9 docs: issue tracker: commit ids after rebasing issues 307, 1045, 1568, 1970 and 2016
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:53:00 -05:00
Aaron Kimbrell
873f5d89ba docs: issue tracker: issue 1568
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:52:54 -05:00
Aaron Kimbrell
585e2a6ace fix(inventory): a removed item is freed by its inventory, not by itself (issue 1568)
Item::RemoveFromInventory ended with `delete this`, so every caller that still used the item afterwards (SetCount(0)
returning into its caller, loops that remove several items, proxies purged while their parent is handled) touched
freed memory. The inventory now takes the removed item and frees it at the inventory component's next update, or
with the inventory.

Check in game: sell, drop, delete, trade, mail and use up stacks (including the last of a stack); unequip and
remove an item set piece and a proxy-bearing item (rocket, modular car); donate items; nothing crashes and the
inventory shows the right counts after relogging.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:52:54 -05:00
Aaron Kimbrell
1aa70c523b docs: issue tracker: issue 1045
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:52:54 -05:00
Aaron Kimbrell
3300784cd9 fix(combat): TacArc targets are read and written in the client's order (issue 1045)
The client's TacArcBehavior::DoHit (0x00fb10c0) writes the closest max-targets ids from a set, so ascending and
each once, then the action data per id in that same order; DoUnserializeBS (0x00fb26a0) reads them the same way and
skips empty ids. The server handled the targets in list order and skipped ids whose object it could not find
without reading their action data, so every later target read the wrong bits (several pirates under a Doom Slicer).
Handle now reads the action for every listed id in ascending order, and the server's own casts write ids and actions
in ascending order after picking the closest targets.

TacArcBehavior::Cast (0x00fb2d10): a picked target that passes the filter gets the action with no TacArc data (the
server's own cast now calculates that action instead of handling it); otherwise the target is dropped, and an arc
measured from the target's position writes nothing.

Check in game: Doom Slicer and multi-target katanas on groups of pirates/admirals damage each of them; apes still
take damage during their stun; enemies with arc attacks (apes, Maelstrom horsemen) still hit players.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:52:54 -05:00
Aaron Kimbrell
f1f8785b26 docs: issue tracker: issues 307, 1970 and 2016
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:52:54 -05:00
Aaron Kimbrell
5dba7d5136 fix(scripts): Spider Queen rain of fire hits two spots in each outer ring (issue 2016)
The live boss script's rain of fire takes every target of the first ROF target group and ROFImpactCnt (2) different
random targets of each other group. The server took one per group, so the rain was sparser than live. The impacts are
now picked like the live script (without repeats inside a group).

Check in game: AG Spider Queen stage 3; the rain of fire lands on the centre ring and on two spots in each outer ring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:52:54 -05:00
Aaron Kimbrell
300932c657 fix(scripts): Spider Queen rapid fire sweeps the three zone target groups around a player (issue 2016)
The live boss script tracks which arena zone volume (Zone1Vol..Zone8Vol, TeleVol for the default Zone3Vol) each
player last entered, and its rapid fire picks a random player, takes the three RFS target groups around that zone,
sorts each by the targets' CWOrder (CWOrder2 when the sweep crosses between zones 8 and 1), clockwise or
counter-clockwise at random, drops the first and last target of the middle group (shared with its neighbours),
turns with skill 1480 at the fourth target and fires 1394 at every target in turn, playing attack-shoot-right or
attack-shoot-left. The server shot a single random target with the single-shot animation, and the AG property zone
never subscribed the boss to the zone volumes. The zone now registers the volumes (retrying until they are spawned)
and the boss builds the sweep like the live script.

Check in game: AG Spider Queen stage 2; the rapid fire is an arc of many shots sweeping across the arena near the
player, left or right, and follows the player to other parts of the arena; after teleporting it starts from the
default side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:52:54 -05:00
Aaron Kimbrell
990cc74aa0 fix(scripts): Spider Queen specials follow her stage and wait out the smash (issue 1970)
Every hit started both the rapid fire shooter and the rain of fire timers, from stage 1 on, so the two specials
ran in every stage and on top of each other, each turning the boss's AI off and on again under the other's
animations. They also wrote the "stoppedFlag" that the no-players-around attack stop uses, which could leave her
stopped for good. As the live script: after she comes back down, a skill manager fires the rapid fire shooter in
stage 2 and the rain of fire in stage 3 only, again 10 to 15 s after each ends; for 3.1 s after her melee smash
(skill 322) a due special waits and fires when the smash ends. The rain of fire keeps her from attacking until
its last impact.

Check in game: Spider Queen fight: no specials before the first spiderling wave; stage 2 only rapid fire, stage 3
only rain of fire; she never freezes in the smash animation and keeps attacking after each special.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:52:54 -05:00
Aaron Kimbrell
4900f11cf1 fix(scripts): the Spider Queen screams from the mountain when a spiderling dies (issue 307)
The zone script never handed the boss her landing target and scream emitter: ZoneAgProperty::ProcessGroupObjects
was empty and nothing answered the boss client script's "QueryZoneScript" event. As the live scripts: the boss asks
the zone ("RetrieveZoneData"), the zone stores the first object of Land_Target and Spider_Scream on her as
LandingTarget and ScreamEmitter (looking again every 0.3 s until they are spawned), and each spiderling death sends
NotifyClientObject "EmitScream" with the emitter, which the boss's client script plays as the scream. The landing
skill and camera shake now come from the landing target, not the boss.

Check in game: AG Spider Queen (property or instance): kill a spiderling: the scream plays from the mountain; when
she comes back down, the landing blast hits around the landing spot and the camera shakes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:52:54 -05:00
Aaron Kimbrell
fb525b6fa4 docs: warn to back up the database before running the experimental branch
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:34:41 -05:00
Aaron Kimbrell
5853c96872 docs: issue tracker: issues 917 and 1189
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:39:17 -05:00
Aaron Kimbrell
45f9ffdf34 fix(combat): area attacks handle each target once, in the client's order (issues 917, 1189)
The client's AreaOfEffectBehavior::Cast (0x004ec590) writes every target id, then runs and writes the action once
per unique target in ascending id order. The server ran it for every listed target in list order, so a target
listed twice (the caster with a magnet, Everlasting items' refill) was handled twice, and later targets' data was
read against the wrong target. Handle and the server's own Calculate now go through the unique ids in ascending
order. Check: Thumpin' Bass / Flowin' MC refill once; Shinobi charge with a magnet gives imagination once; area
attacks on several enemies still hit each of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:39:17 -05:00
Aaron Kimbrell
32fe441d57 feat(scripts): Portabello's frog bridge puts its tongue out for players who earned it
WBL_Frog_Bridge had no script. As the live script: when a player who finished mission 946 comes within 25 units,
the four FrogBridge pieces move out to form the bridge; after 10 seconds they go back one a second from the tip,
and 7 seconds later the frog looks for players again. Check: in Portabello, with mission 946 done, walk up to the
frog: the tongue bridge comes out and goes back; without the mission it doesn't. Depends on moving platforms
following their paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:35:12 -05:00
Aaron Kimbrell
88b2ef5f38 feat(scripts): Portabello's starflies start moving when their mission is handed in
WBL_Starflies had no script. As the live script: when the mission given at that object is handed in, every object of
the Starflies group starts its path. Check: in Portabello, hand in the starflies mission: the starflies fly off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:33:04 -05:00
Aaron Kimbrell
342269cf61 fix(scripts): the Forbidden Valley cavalry of the horsemen path gets its script
L_ACT_HORSEMEN_1 (one path spawner of Maelstrom Cavalry, LOT 7816, in Forbidden Valley) had no script. It does what
L_FV_MAELSTROM_CAVALRY does (tell the group's turret it spawned, report a Brick Fury kill to the horsemen trigger),
so it uses that port. Check: the cavalry on that path wakes the ninja turret and Brick Fury kills count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:29:59 -05:00
Aaron Kimbrell
22f6a76f46 feat(scripts): turret enemies are immovable as L_TURRET makes them
L_TURRET (LOTs 12286 and 13093, e.g. the Crux Prime auto turrets) had no script, so these turrets could be stunned,
knocked back and pulled. They now push the same immunities the live script does. Check: stun and knock back a
Crux Prime auto turret: nothing happens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:27:48 -05:00
Aaron Kimbrell
f35862b596 feat(scripts): the Assembly Engineer turret works as TURRET.lua
The turret (LOT 9303-9305, 12618) had no script: it fought as soon as it was spawned and lasted the generic 60
seconds. As TURRET.lua: its combat AI is off until it is built, it can't be stunned, interrupted, knocked back or
pulled, and it dies 30 seconds after it was placed once nobody is building it. Kill credit going to the builder is
not done. Check: summon the turret with Engineer gear: it doesn't shoot until built, then fights and goes away
after about 30 seconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:25:37 -05:00
Aaron Kimbrell
e0169a0a63 docs: issue tracker: issue 1113
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:22:59 -05:00
Aaron Kimbrell
9ee1431aab feat(master): say which folder setting is wrong at startup (issue 1113)
Master stops with a message naming client_location, its value and the folder it resolves to when that folder
doesn't exist, instead of failing later on missing client files; a missing dump_folder gets a warning. Check: set
client_location to a folder that doesn't exist: master says so and stops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:22:59 -05:00
Aaron Kimbrell
495d62e559 docs: issue tracker: issue 928
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:22:01 -05:00
Aaron Kimbrell
6335c87f56 docs: CMake from Kitware's repository without apt-key (issue 928)
The WSL steps used software-properties-common, lsb-release and the deprecated apt-key. They now follow Kitware's
current instructions: the key as a keyring referenced with signed-by, the release codename from /etc/os-release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:21:55 -05:00
Aaron Kimbrell
9e5a4b2ba0 docs: issue tracker: issue 1256
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:19:57 -05:00
Aaron Kimbrell
c120be0bcc fix(scripts): concert instruments place the player as live did (issue 1256)
RepositionPlayer added the offsets in world X/Z, set the height to 0 and built the keyboard turn around the position
vector. As l_ns_concert_instrument_qb.lua: the offset is in the instrument's own frame, the instrument's height is
kept, the player faces the instrument's way, and at the keyboard turns -0.8 further. Check: build and play all four
instruments on the Nimbus Station stage: the player stands at each one facing it, not below the stage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:19:57 -05:00
Aaron Kimbrell
dceec20ac2 docs: issue tracker: issue 957
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:18:53 -05:00
Aaron Kimbrell
57925d1e11 feat(moderation): a name decision shows as a popup to the player, as live did (issue 957)
When staff approve or reject a character name while the player is online, the player gets a private announcement
popup ("Name approved" / "Name not approved") as well as the chat line. Players who are offline still aren't told
at their next login. Check: approve and reject a pending name while its player is online.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:18:53 -05:00
Aaron Kimbrell
826dd9ee59 fix(scripts): Gnarled Forest tiki torches lock while in use, cooldown from the animation
The port turned the in-use flag off on a second use instead of refusing it, so a torch could be used again at
once; it now stays in use until the interact animation is done, as L_GF_TORCH does, and the cooldown is that
animation's length (4 seconds when it has none) instead of a flat 4. Check: use a tiki torch twice quickly: the
second use does nothing until the torch is done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:18:04 -05:00
Aaron Kimbrell
8bf01a6c43 fix(scripts): the water gun blows Forbidden Valley candles out
L_ACT_CANDLE also blows a candle out on the "waterspray" skill event; the port only did it on a hit. The 169
candles in Forbidden Valley now go out (and count for missions 850, 1431, 1529, 1566 and 1603) when sprayed. Check:
spray a candle with the water gun: it goes out, smokes, relights after 5 seconds, and the candle missions count it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:15:32 -05:00
Aaron Kimbrell
f7d21b22c2 docs: issue tracker: issue 611
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:12:32 -05:00
Aaron Kimbrell
154ff1f16f fix(minimap): venture vision shows again after logging in (issue 611)
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>
2026-09-29 09:12:26 -05:00
Aaron Kimbrell
c75205a0e2 fix(enemies): spiderlings can't be stunned, interrupted, knocked back or pulled
L_BASE_ENEMY_SPIDERLING was excluded, so the 7 spiderlings in Avant Gardens and 3 in Venture Explorer had none of the
immunities its onStartup pushes: stun immunity to attack, interrupt, move, turn, use item, equip and interact, and
status immunity to pull-to-point and knockback. BaseEnemySpiderling does the same. Check: stun and knock back a
spiderling: nothing happens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:11:18 -05:00
Aaron Kimbrell
33402425e4 feat(dashboard): pending guild names count on the Review Queue and Guilds badges
The dashboard snapshot counts guilds whose name waits for moderation; the moderation counts (WebSocket and
/api/moderation/counts) include it, the Review Queue badge adds it for staff with guilds_manage, and the Guilds menu
entry has its own badge. Check: create a guild with a name off the allow list: both badges go up; approve it: they
go down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:46:34 -05:00
Aaron Kimbrell
24d96f13df docs: issue tracker commit hashes as they are on the branch now
The table named commits by their hashes from before earlier rebases; each is now the current hash of the commit
with the same subject.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:41:32 -05:00
Aaron Kimbrell
3a14dc4c9f chore: stop tracking Python bytecode
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:39:37 -05:00
Aaron Kimbrell
5cd8b183cc test(zone): use neutral names and IDs in the zone file tests
The zone file tests' sample zones now use generic world IDs, file names
and path names instead of ones taken from real files. What they test is
unchanged.

Check in game: nothing (test only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:39:37 -05:00
Aaron Kimbrell
f73f4da0e4 fix(level): split a scene object's config as the client does
LDF_FROM_STRING (1.10.64, 0x010fa220) splits an object's config at
every comma and line break, leaves out empty entries and entries with
no '=', and sets each key=value it finds. The reader split at line
breaks only and parsed every piece, so an object with no config got an
empty entry of unknown type, and a value with a comma would have stayed
whole.

Live scene files are unchanged; objects in older client files with an
empty config no longer get the empty entry.

Check in game: every world spawns its objects as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:39:37 -05:00
Aaron Kimbrell
272fafc886 test(zone): read every zone, scene and terrain file the client reads
ClientZoneFilesTests now
- reads sd0 files instead of skipping them: some clients' loose sd0
  files hold what followed the file in its pack, and the file is the
  first sd0 stream, up to the first chunk that does not fit;
- reads the terrain (.raw) of every zone of version 30 or newer, once
  per terrain file shipped by several clients;
- skips a damaged file (by the MD5 of its bytes) only when it does not
  read, so only the files the client cannot read either are left out:
  a scene file that claims 81 objects and ends after the first, and six
  version 30 terrain files with a width x width scene map per chunk
  where the client reads one byte (RAWReadSceneMap, 1.10.64) and so
  misreads every chunk after the first.

Every other zone, scene and terrain file of every client on disk reads,
in about 80 seconds.

Check in game: nothing (test only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:39:37 -05:00
Aaron Kimbrell
eb06bc86e0 perf(terrain): read a chunk's heights and mesh lists in one read each
The heights of a terrain chunk (millions of floats in the big zones)
and the mesh index lists were read one value at a time; they are now
read in one read each, as the client does (ReadBytesTimes4 /
RAWReadU16 with a count). The values are the same.

Check in game: nothing (terrain reads the same, only faster).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:39:37 -05:00
Aaron Kimbrell
21f1f3f8e1 fix(zone): zones older than version 30 have no terrain scene map
For a zone file older than version 30 the client reads the terrain in
an older format (OpenTerrain, 1.10.64: mapVersion < 30), and the game
client never reads that format's scene map (only the editor does), so
scene loading goes by the zone's scenes alone. The world now does the
same instead of reading the terrain file as the newer format.

Check in game: nothing to check (all live zones are version 36+).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:39:37 -05:00
Aaron Kimbrell
93c7b1948f fix(terrain): read terrain files before version 32 as the client does
The client reads a terrain chunk of a file older than version 32
(1.10.64):
- its color map as width x width BGRA pixels, keeping the
  (width - 1) x (width - 1) before the last row and column, as RGBA
  (RAWReadColorandLightMaps); the reader kept all the pixels as
  written;
- its texture blend map's pixels as BGRA, kept as RGBA (0x0103aaf0);
- before version 31 no scene map, only a byte: the client's scene map is
  all scene 0 (RAWReadSceneMap); the reader had none.

A chunk of width or height 0, which the client reads (no heights, no
color map), no longer fails the whole file.

Live terrain files are version 32, so they read as before.

Check in game: nothing to check (no live terrain changes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:39:37 -05:00