Commit Graph
32 Commits
Author SHA1 Message Date
openhands 17de94d984 feat(nitro): convert imported SWF bundles to WebP Lossless
Newly converted .nitro bundles now store their spritesheet as WebP VP8L
instead of PNG, so imports land much smaller without changing a single
pixel. The texture member and spritesheet.meta.image are both labelled
from the actual bytes, never from a caller's assumption.

- encode through sharp with lossless and exact, so colour hidden under
  alpha 0 survives; this mirrors ImageSharp's TransparentColorMode.Preserve
- detect PNG/WebP by magic bytes and reject anything the client cannot
  render, on create, download and upload paths
- keep the source format when deriving size-32 sheets, scaling composites
  and editing metadata, so existing bundles are never silently rewritten
- report fidelity in the studio: the compression panel re-encodes with the
  same options the importer uses, so it cannot drift and invent false
  warnings, and shows PNG/WebP size estimates

convertSwfToNitro and buildSpritesheet are now async, so the worker, the
main-thread fallback and every import call site await them. PNG stays
supported for existing bundles and icon sidecars are untouched.
2026-09-27 15:42:21 +02:00
Simo c977fe95ba fix(studio): recover uncertain imports with persistent request identities 2026-09-13 18:33:06 +02:00
openhands 0af8d8a398 fix(lint): resolve biome formatting and unused variables across codebase 2026-09-12 19:45:29 +02:00
openhands 4d720ee03c fix(furni): generate scale 32 from bundles with .png frame keys
resolveNitroFrame now matches spritesheet frame keys that carry a .png
suffix or namespaced naming, and isScale/scaleName preserve that suffix.
Broken source sprites (missing frames or references to icon artwork) are
skipped and reported instead of aborting the whole generation, and the
studio UI surfaces the skipped count.
2026-09-12 12:46:17 +02:00
Simo 13bd3695cb feat(studio): recover matching Nitro sources and persist import phases 2026-09-11 10:22:06 +02:00
Simo 88790d1a0d feat(cms): recover drafts and failed imports with verified UI workflows 2026-09-11 08:58:10 +02:00
Simo 76f0420d64 feat(import): run catalog synchronizations as durable jobs 2026-09-11 00:36:22 +02:00
Simo 1ef405be0a feat(cms): add recovery history and operational reliability tools 2026-09-09 21:57:56 +02:00
Simo c389c3893d feat(cms): improve catalog, editorial recovery and operations 2026-09-09 19:36:15 +02:00
Simo a070004e7b feat(admin): reorganize housekeeping and strengthen shared workflows 2026-09-06 17:17:30 +02:00
Simo 570f3dde44 feat(catalog): repair missing furniture components with verified status 2026-09-05 18:12:34 +02:00
Simo dcb5f46eed fix(catalog): resolve namespaced Nitro frames and empty scale declarations 2026-09-05 17:45:42 +02:00
Simo cd75361b9f feat(catalog): generate derived scale 32 with preview and backup restore 2026-09-05 17:36:22 +02:00
Simo 08b0b5021e feat(catalog): inspect Nitro scales and preview original sprites 2026-09-05 17:22:27 +02:00
Simo 2619bec165 feat(catalog): queue furniture imports with history and matching file attachments 2026-09-05 17:02:26 +02:00
Simo 2d14e02a68 fix(catalog): remove suggestions that substitute different furniture 2026-09-05 15:26:46 +02:00
Simo 33b6d1520e fix(catalog): stream single imports and preserve response errors 2026-09-05 15:16:42 +02:00
Simo 159b1f7d1b fix(catalog): check source assets and offer reachable import alternatives 2026-09-05 14:56:04 +02:00
Simo a78d8256e0 Recognize imported furniture by normalized classname and local IDs 2026-09-05 14:04:52 +02:00
Simo 26f071117b Add Catalog Studio inspection and guided import review 2026-09-05 13:10:43 +02:00
openhands 4b7cb519df fix: furniture interaction detection and automatic catalog offer_id rebuild
Interaction detection:
- Trust SWF-derived sit/lay/stand flags only when the logic XML actually
  contains action data (new hasActions metadata); otherwise fall back to
  keyword detection so custom furni without <action> nodes are still
  classified correctly
- Add French/Dutch/German/Spanish/Italian keywords (chaise, banquette,
  stoel, silla, sedia, stuhl, tafel, mesa, ...) to sit/lay/stand detection
  with token-boundary matching to avoid false positives like bedside_table
- Unify interaction_modes_count priority: mechanic fixed modes, then raw
  animation state count, then sit/lay fallback, then keyword default
- Detect mechanic type even when real flags are not used

Catalog integrity:
- Skip duplicate catalog_items inserts in clone and upload imports
- Re-check live catalog rows before applying generated repair SQL
- Add rebuildCatalogOfferIds() which rebuilds every catalog_items.offer_id
  from the local FurnitureData.json (matched by entry id, then classname)
  and run it after every import path (single, batch, batch-regen, clone)
2026-08-21 13:39:21 +02:00
openhands 6021a91ef7 fix: harden furni import pipeline for production
- importSingleFurni: actually update an existing item instead of failing on a primary key INSERT collision; refuse to reassign a spriteId owned by a different classname
- reconcileFurniDataWithItemsBase: also sync each entry's offerid to the DB sprite id, not just the id
- Move the full-table interaction_modes_count verification out of the per-item import hot path and run it once per batch/single import
- clone-import: apply the auto-detected interaction_type (was hardcoded 'default'), set FurnitureData offerid and catalog_items.offer_id to the new local sprite id (was the source hotel's id / -1)
- clone batch route: run the same post-import reconcile/verify/ownership/RCON consolidation as the furni batch route
- upload-import: set offer_id to the allocated id in both the direct insert and the generated SQL migration (was -1)
- generateCatalogSql: use the classname as catalog_name and the item id as offer_id so rows match the app-managed import convention
- stats + missing-nitro endpoints: match catalog membership via item_ids instead of the catalog_name join, so translated display names no longer break counts
- deleteImportedItem/rollback: delete catalog rows by the canonical item_ids link only
- classifyFurni: wall items always classify as 'walls' before prefix rules (rare_/val_/xmas_) can misfile them
2026-08-20 11:48:51 +02:00
openhands 3fa192a108 feat: auto interaction detection from real furniture data
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.
2026-08-19 20:28:24 +02:00
openhands dee843106f feat: add auto furniture interaction detection
- New auto-interaction.ts: detects canSit/canLay/canStand from classname/name keywords
- Maps keywords to interaction types (bench, chair, bed, table, etc.)
- Returns clickLimit and interactionModesCount for proper click/interaction limits
- Nitro editor: added auto-detect button with preview of detected settings
- furni-import.ts: auto-sets interaction_modes_count during import
- upload-import.ts: auto-detects for direct insert and SQL migrations
- clone-import.ts: auto-detects when cloning from other hotels
2026-08-18 22:33:40 +02:00
openhands 5b09179404 Add all-in-one Studio merging furni import and catalog management
Add a full-viewport /admin/studio workspace that unifies the import and
catalog systems into a single automated flow:

- Furni library browser against official Habbo furnidata with search,
  type/status filters, live previews and pagination
- Catalog structure rail showing where imported furniture lands
- Detail drawer with automatic placement preview (category + price via
  classifyFurni/autoPriceFurni) and one-click import that downloads
  assets, converts SWF to nitro, writes items_base, updates
  FurnitureData.json and creates an auto-priced catalog entry
- Batch auto-import with SSE progress and RCON cache refresh
- Nitro editor integration and imported-item deletion

Extract pure auto-catalog helpers (CATEGORY_PAGE, CLASSNAME_RULES,
classifyFurni, autoPriceFurni) into a client-safe module shared by the
server pipeline and the Studio UI so the preview always matches what the
emulator import applies.
2026-08-15 15:34:07 +02:00
openhands 82e8448f26 test: add unit tests for pure logic modules
Add 22 test files covering imager, soundtracks, browser-headers, source-keys (figure/pet/effect), effect-source, plus catalog-translations, catalog-layouts, client-translation-files, translations-utils, and various admin/services/helpers modules. Total test count increases by 120+.
2026-08-07 18:53:59 +02:00
openhands df38dccbf1 style: format code biome 2026-07-13 21:57:41 +02:00
openhands 2e4ed76121 style: format code with prettier 2026-07-12 21:07:34 +02:00
Remco e85e4d74ea revert fb8e77bb68
revert style: clean up code with prettier and eslint
2026-07-12 21:02:03 +02:00
openhands fb8e77bb68 style: clean up code with prettier and eslint 2026-07-12 20:31:05 +02:00
Simo 8d37ae9ae0 style: normalize restored source endings 2026-07-11 21:19:54 +02:00
Simo 0cd753c735 fix: restore complete admin feature dependencies 2026-07-11 21:15:54 +02:00