@energy8platform/game-engine 0.33.4 → 0.33.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energy8platform/game-engine",
3
- "version": "0.33.4",
3
+ "version": "0.33.6",
4
4
  "description": "Universal casino game engine built on PixiJS v8 and @energy8platform/game-sdk",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs.js",
@@ -312,22 +312,28 @@ export function mergeGameInfo(derived: GameInfoContent, override?: GameInfoConte
312
312
  // here so the rest of the function works against the pixi-widened type.
313
313
  const derivedSections = (derived.sections ?? []) as GameInfoSection[];
314
314
  const overrideSections = (override.sections ?? []) as GameInfoSection[];
315
- const authorByKey = new Map<string, GameInfoSection>();
316
- for (const s of overrideSections) authorByKey.set(sectionKey(s), s);
315
+ // The FIRST author section of a given key is the one that REPLACES a matching derived section;
316
+ // every other author section is appended. Keying by title means several `custom` sections can
317
+ // share a key (same/absent title) — those must NOT annihilate each other, so consumption is
318
+ // tracked by section IDENTITY, not by key. (Key-gated appends silently dropped all but one.)
319
+ const replacementByKey = new Map<string, GameInfoSection>();
320
+ for (const s of overrideSections) {
321
+ const k = sectionKey(s);
322
+ if (!replacementByKey.has(k)) replacementByKey.set(k, s);
323
+ }
317
324
 
318
325
  const out: GameInfoSection[] = [];
319
- const used = new Set<string>();
320
- // Keep derived order; swap in the author's version where identities collide.
326
+ const consumed = new Set<GameInfoSection>();
327
+ // Keep derived order; swap in the author's version where an identity matches a derived section.
321
328
  for (const s of derivedSections) {
322
- const k = sectionKey(s);
323
- const replacement = authorByKey.get(k);
324
- if (replacement) { out.push(replacement); used.add(k); }
329
+ const replacement = replacementByKey.get(sectionKey(s));
330
+ if (replacement && !consumed.has(replacement)) { out.push(replacement); consumed.add(replacement); }
325
331
  else out.push(s);
326
332
  }
327
- // Append author sections whose identity wasn't in the derived set, in author order.
333
+ // Append every author section not already used as a replacement, in author order — including
334
+ // multiple `custom` sections that share (or omit) a title.
328
335
  for (const s of overrideSections) {
329
- const k = sectionKey(s);
330
- if (!used.has(k)) { out.push(s); used.add(k); }
336
+ if (!consumed.has(s)) { out.push(s); consumed.add(s); }
331
337
  }
332
338
  return { sections: out };
333
339
  }
@@ -393,11 +399,12 @@ export function buildShellConfig(
393
399
  // authors can wrap player-facing copy explicitly; the full merged set is still socialized below
394
400
  // (section pass) as a safety net so restricted words can't slip through even if t() was missed.
395
401
  const { t } = createI18n({ language: runtime.language ?? 'en', isSocial, messages: opts.i18n });
396
- // The legal disclaimer body localizes but must NEVER socialize (mandated copy per language). In
397
- // social mode `t` would word-swap English; use a translation-only resolver so en+social keeps it
398
- // verbatim while de/ru/… still translate. For non-social, `t` already never socializes.
402
+ // The legal disclaimer body must NEVER socialize (mandated copy word-swaps like "bet → play"
403
+ // would corrupt legal text). In NON-social mode it localizes per language. In SOCIAL mode the whole
404
+ // shell is forced to English, so the disclaimer follows: resolve against English (source verbatim),
405
+ // never the requested locale — otherwise it'd be the lone non-English holdout in an English UI.
399
406
  const tDisclaimer = isSocial
400
- ? createI18n({ language: runtime.language ?? 'en', isSocial: false, messages: opts.i18n }).t
407
+ ? createI18n({ language: 'en', isSocial: false }).t
401
408
  : t;
402
409
  const authored = typeof opts.gameInfo === 'function' ? opts.gameInfo(t) : opts.gameInfo;
403
410
  // Pass t() through to spec-derived sections so symbol names, mode titles, and descriptions are