feat: auto interaction detection from real furniture data
CI / check (push) Successful in 31s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m17s

Replace classname/name keyword guessing with real data so sit/lay/stand
has zero false positives:
- autoDetectInteraction() now accepts real flags (cansiton/canlayon/
  canstandon), logicType, and animation-state count; real data wins and
  keywords are only a fallback when no real data exists.
- New furni-real-interaction helper reads the local FurnitureData.json
  (highest-revision entries win; a true flag in any duplicate is kept)
  and falls back to the official Habbo furnidata.
- interaction_modes_count now uses emulator conventions: dice=6,
  gate/teleport=2, roller=1, generic multistate = animation-state count,
  chairs/beds=1, plain items=0.
- verifyAndFixInteractionModesCount only touches items with real data
  and skips everything else (no keyword overwrites).
- parseNitroBundle falls back to gunzip for gzip-compressed .nitro files.
- Wired through furni-import, upload-import, clone-import, and the nitro
  editor auto-detect button.
This commit is contained in:
openhands committed 2026-08-19 20:28:24 +02:00
1 parent 121dda7249
commit 3fa192a108
8 files changed
+626 -78

No files matched your search

+16 -3
View File
@@ -1,4 +1,4 @@
import { deflateSync, inflateSync } from "node:zlib";
import { deflateSync, gunzipSync, inflateSync } from "node:zlib";
import type { SpriteImage } from "./image-decoder";
// ── Minimal PNG Encoder ────────────────────────────────────────────
@@ -267,7 +267,7 @@ export function parseNitroBundle(buffer: Buffer): {
offset += 4;
const jsonCompressed = buffer.subarray(offset, offset + jsonCompressedLen);
offset += jsonCompressedLen;
const jsonStr = inflateSync(jsonCompressed).toString("utf-8");
const jsonStr = inflateJsonOrGzip(jsonCompressed).toString("utf-8");
const json = JSON.parse(jsonStr);
// File 2: PNG
@@ -279,7 +279,20 @@ export function parseNitroBundle(buffer: Buffer): {
offset += 4;
const pngCompressed = buffer.subarray(offset, offset + pngCompressedLen);
offset += pngCompressedLen;
const png = inflateSync(pngCompressed);
const png = inflateJsonOrGzip(pngCompressed);
return { json, jsonFileName, png, pngFileName };
}
/**
* Some bundled .nitro files (e.g. official /var/www/Gamedata furniture)
* gzip their contents instead of raw-deflate. Try inflate first, then fall
* back to gunzip so both formats parse.
*/
function inflateJsonOrGzip(input: Buffer): Buffer {
try {
return inflateSync(input);
} catch {
return gunzipSync(input);
}
}