Commit Graph

14 Commits

Author SHA1 Message Date
Aaron Kimbrell
1d72766330 feat(ugc): icons as DXT5 DDS like the client's own
The client's 128x128 UI icons are almost all DXT5 without mipmaps, with
header flags caps|height|width|pixel format|linear size (0x81007) and
caps 0x1000. The UGC server's icon.dds is now written the same way
instead of as uncompressed 32-bit BGRA with a pitch.

The BC3 encoder fits each block's colour endpoints along the principal
axis of its visible pixels (transparent ones are never seen), refines
them by least squares, and stores alpha with the block's own range.
Tests check the header against the client's format and decode the
result back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:14 -05:00
Aaron Kimbrell
79235702b3 feat(ugc): answer the client's UGC manifest requests without 3D services
With UGCUSE3DSERVICES=7:0 (the client's default) the client asks its world for
a blueprint file's MD5 and size (REQUEST_UGC_MANIFEST_INFO, world 27) and then
downloads BrickModels/UserMade/<id % 1000>/<id>.<ext>.sd0. Layouts checked in
the 1.10.64 client: the request is a u64 blueprint id and a u8 resource type;
the answer (UGC_MANIFEST_RESPONSE, client 60) repeats them and adds a u8 valid,
the u32 size and the 16 byte MD5 of the inflated file, 37 bytes after the 0x53
exactly or the client drops it.

- dNet: WorldPackets::RequestUgcManifestInfo, ClientPackets::UgcManifestResponse
  (eUgcResourceType), with byte tests against the client's layouts.
- Database: ugc_file_checksums (per model or module combination and file) and
  ugc_modular_build.combination_id (migrations 89 / 72), GetUgcFileChecksum
  looks a blueprint up as a model, else as a build through its combination.
- UGC server: every download is also written as .sd0 (Sd0::Compress); workers
  hand the checksums back and the main thread stores them; old items get their
  sd0 icon and checksum, and builds their combination id, once at start-up, a
  few per tick; serves <dir>/BrickModels/UserMade/<bucket>/<id>.<ext>.sd0 under
  client_path, /<folder>/UserBrickModels and the root (.hkx 404).
- World: UgcManifest answers on the main thread with one indexed query per
  request; files not made yet are answered when they are (looked at again
  every 5 seconds), and a model in its quiet period is made right away. No
  worker threads, HTTP or file reads in the world.

Off by default (ugc_manifest=0): checked in game, the client then downloads
from http://127.0.0.1:80/lwoclient/UserBrickModels/ whatever its boot.cfg says
and logs the player out when it can't connect, so icons need the UGC server on
port 80 of each player's machine. docs/UgcServer.md has the details.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:14 -05:00
Aaron Kimbrell
36cefc1ede feat(ugc): brick data through the client's assets; colours from Materials.xml everywhere
The UGC server reads brickdb.zip and brickprimitives through DLU's
AssetManager (loose files first, then the client's packs, as the game
does), so packed clients and bricks added to a client work. It falls
back to loose files under res/ as before.

In the LU Toolbox palette (the default), a colour LU Toolbox doesn't
know but the client's Materials.xml has, such as one added to the brick
database, is drawn in its Materials.xml colour instead of black. Ids
neither knows stay LU Toolbox's black.

The dashboard's 3D viewers get the brick colours from the client's
Materials.xml (/api/bricks/materials.js) instead of a hardcoded copy, so
added colours show there too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:13 -05:00
Aaron Kimbrell
888168ff55 docs: the UGC icon pose, the assembled mesh, the UGC page's assemblies, search, editor and settings
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:12 -05:00
Aaron Kimbrell
962797d6a2 docs: UGC server page with both the dashboard links and the client findings
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:10 -05:00
Aaron Kimbrell
5de59b99ef feat(ugc): models with no bricks are "empty", not failed
A model with no bricks has nothing to make: it gets its own state
(is_optimized = 3), isn't counted as a failure or retried, shows as Empty
on the UGC page (with its own filter and count), in the status and in
Prometheus, and its downloads answer 404 like HKX. State names come from
the enum (magic_enum). Migrations dlu/mysql/87 and dlu/sqlite/70 move the
rows that failed only because they had no bricks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:10 -05:00
Aaron Kimbrell
76cbbcc4ea feat(ugc): draw player models' icons from their generated NIF
The icon was rendered from a second mesh built only for it (the icon
renderer's color corrections, no variation, occlusion worked out again). It
is now drawn from the .nif just made, read back with NifFile at LOD 0, so it
shows exactly what the game shows: the color variation, the removed faces and
the lighting baked into the vertex colors (so it adds no occlusion of its
own). icon_correct_colors and icon_color_variation are gone; the camera and
light settings stay. Cars and rockets are drawn as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:09 -05:00
Aaron Kimbrell
27955d8cc6 docs: UGC search and creations on property and character pages
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:08 -05:00
Aaron Kimbrell
05d6f55e25 docs: UGC server parity with LU Toolbox, CPU and memory limits, viewer
A step by step table of LU Toolbox's pipeline against the UGC server's, the
new settings and their defaults, the measured effect of max_cpu_percent and
max_memory_mb, and the dashboard's gallery, viewer and internal address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:07 -05:00
Aaron Kimbrell
0de9decc7c fix(ugc): name crash dumps like the other servers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:06 -05:00
Aaron Kimbrell
5828fe99c7 docs: describe the UGC server on the dashboard
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:06 -05:00
Aaron Kimbrell
347a0a7286 feat(dashboard): UGC server page
Counts, a paged list and failures of what the UGC server made of players'
models and modular builds, making one, the failed ones or everything again
(new ugc_manage permission), the UGC server's live status and icons from
ugc_public_url, and a 3D view of a model's LXFML. The UGC settings are in the
settings catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:57 -05:00
Aaron Kimbrell
abf1cc1d80 feat: UGC server that makes and serves player models' meshes and icons
A new server (dUgcServer, started by master with enable_ugc_server=1) that
takes unprocessed ugc and ugc_modular_build rows from the database and makes
what the client downloads with UGCUSE3DSERVICES: an optimized NIF (hidden
faces removed, ambient occlusion baked into vertex colors) and a 128px DDS
icon for player models, rendered by a software rasterizer from the client's
LDD brick primitives, and icons for cars and rockets assembled from their
modules per ModularBuildComponent/ModuleComponent. It serves them, with the
models' LXFML, over HTTP in the client's UGCC<dc>/3DOPTIMIZED and
IMAGE128DDS layout with .gz and .checksum files, and keeps its folder under
a size cap.

Processing state lives in ugc.is_optimized plus new processed_at,
process_attempts and process_error columns (and the same on
ugc_modular_build). ServiceType::UGC is appended. NifFile moves to dCommon
and records named node transforms for the modules' attach points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:57 -05:00
Aaron Kimbrell
90ded73596 docs: design for the UGC server
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:57 -05:00