simoleo89 31598b8883 feat(communication): housekeeping ban-user + generic action-result
* HousekeepingBanUserComposer (OutgoingHeader 9102): (userId,
  reason, hours).

* HousekeepingActionResultEvent + Parser (IncomingHeader 9201):
  generic ack carrying (actionKey, ok, actionId, message). Same
  parser will back mute / kick / give-credits / room-close / etc.
  callers — adding a new HK action only needs a new outgoing
  composer plus the right ACTION_KEY constant on the server side.

vitest 138/138, `yarn compile:fast` clean.
2026-05-24 16:26:06 +02:00
2024-04-03 09:27:56 +02:00
2024-04-03 09:27:56 +02:00
2024-07-04 15:03:26 +02:00
2024-07-04 15:03:26 +02:00
2024-04-03 09:27:56 +02:00
2024-04-03 09:27:56 +02:00
2024-04-03 09:27:56 +02:00
🆙 Updates
2026-01-31 13:21:59 +01:00

Nitro Renderer

nitro-renderer is a Javascript library for rendering Nitro in the browser using PixiJS

Installation

npm

npm install @nitrots/nitro-renderer

yarn

yarn add @nitrots/nitro-renderer

JSON / JSON5 configuration parser

Every configuration file and gamedata file loaded by the renderer (figuredata, furnidata, productdata, effectmap, avatar actions, etc.) goes through @nitrots/utilsJsonParser.ts. The parser supports three modes, selected at the host build time through the compile-time constant __NITRO_JSON_MODE__:

Mode Behaviour
legacy Strict JSON.parse only. Comments / trailing commas raise a clear error.
json5 JSON5.parse only. Accepts comments, trailing commas, single quotes.
auto Try strict JSON first, fall back to JSON5. Default when the flag is unset.

URL hints are still honoured: files ending in .json5 (or served with a application/json5 content-type) always go through JSON5, regardless of mode.

Wiring the flag into a host

The renderer does not ship its own build for the flag — the host application (typically Nitro V3) defines it via its bundler. Example with Vite:

// vite.config.mjs in the host
export default defineConfig({
    define: {
        __NITRO_JSON_MODE__: JSON.stringify('json5')   // or 'legacy' / 'auto'
    }
});

If the constant is not defined the parser falls back to auto, which preserves the original behaviour of older releases — so existing hosts keep working without any change.

Using the parser directly

import { parseConfigJson, fetchConfigJson } from '@nitrots/utils';

const data  = parseConfigJson<MyConfig>(rawText, '/configuration/ui-config.json');
const data2 = await fetchConfigJson<MyConfig>('/configuration/ui-config.json5');

Errors carry the source URL and, in legacy mode, a hint about switching to JSON5 — making misconfigurations easy to diagnose in production logs.

Split-aware gamedata loader

@nitrots/utils also exports loadGamedata, the loader that backs every gamedata consumer in the renderer (FurnitureDataLoader, ProductDataLoader, EffectAssetDownloadManager, AvatarRenderManager, LocalizationManager). It accepts either a single-file URL (legacy) or a directory URL (split mode) — detected automatically by the trailing slash.

Directory layout

<gamedata-dir>/
  manifest.json5            # OPTIONAL — { "tiers": ["core", "custom", "seasonal"] }
  core/
    manifest.json5          # REQUIRED — { "files": ["a.json5", "b.json5", ...] }
    a.json5
    b.json5
  custom/                   # OPTIONAL tier
    manifest.json5
    overrides.json5
  seasonal/                 # OPTIONAL tier
    manifest.json5
    xmas.json5

If the directory manifest.json5 is absent, the loader falls back to the default tier order core → custom → seasonal. Each tier is skipped silently if its manifest.json5 is missing.

Merge semantics

mergeGamedata(a, b) (also exported) implements the rules below; tiers and files within a tier are merged in order, with later layers overriding earlier ones:

Combination Result
Two plain objects recursive merge, key by key
Two arrays of objects sharing an id key merged by id (later overrides earlier)
Two arrays without an id key concatenated
Anything else later value wins

Recognised id keys (in priority order): id, classname, name. Pass mergeArrayIdKeys in the options object to extend or override them.

Programmatic usage

import { loadGamedata, mergeGamedata } from '@nitrots/utils';

// host code never needs to care whether the URL is split or not
const furnidata = await loadGamedata('https://example.com/gamedata/furnidata/');

// merge ad-hoc if you load tiers manually
const merged = mergeGamedata(coreData, customData);

A CLI splitter for legacy single-file gamedata lives in the Nitro V3 client repo at scripts/split-gamedata.mjs — see the Nitro V3 README for usage.

S
Description
No description provided
Readme GPL-3.0 4.9 MiB
Languages
TypeScript 99.9%
JavaScript 0.1%