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)
This commit is contained in:
openhands committed 2026-08-21 13:39:21 +02:00
1 parent 652d331402
commit 4b7cb519df
14 files changed
+418 -58

No files matched your search

+1
View File
@@ -425,6 +425,7 @@ export function convertSwfToNitro(
canstandon: logic.canstandon,
cansiton: logic.cansiton,
canlayon: logic.canlayon,
hasActions: logic.hasActions,
specialtype: indexData?.specialtype ?? 0,
defaultdir: computeDefaultDir(logic.directions),
partcolors: extractPartColors(visualizations),
+4
View File
@@ -226,6 +226,8 @@ export interface LogicResult {
canstandon: boolean;
cansiton: boolean;
canlayon: boolean;
/** True when the logic XML actually declared <action> nodes — flags are then authoritative. */
hasActions: boolean;
action?: { link?: string; startState?: number };
credits?: string;
soundSample?: { id: number; noPitch?: boolean };
@@ -242,6 +244,7 @@ export function processLogic(xml: string): LogicResult {
canstandon: false,
cansiton: false,
canlayon: false,
hasActions: false,
};
const root = parseXml(xml);
if (!root) return defaults;
@@ -285,6 +288,7 @@ export function processLogic(xml: string): LogicResult {
canstandon,
cansiton,
canlayon,
hasActions: actions.length > 0,
};
// Parse action link/startState