@alexislours/ltd-sharemii 1.0.0

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/dist/index.js ADDED
@@ -0,0 +1,1230 @@
1
+ // src/sidecar.ts
2
+ var EMPTY_SIDECAR = {
3
+ origin: "none",
4
+ files: /* @__PURE__ */ new Map()
5
+ };
6
+ function normalizeName(name) {
7
+ const idx = Math.max(name.lastIndexOf("/"), name.lastIndexOf("\\"));
8
+ return idx >= 0 ? name.slice(idx + 1) : name;
9
+ }
10
+ function isSidecarFileName(name) {
11
+ const lower = name.toLowerCase();
12
+ return lower.endsWith(".canvas.zs") || lower.endsWith(".ugctex.zs");
13
+ }
14
+ function isJunkArchiveEntry(path) {
15
+ if (!path) return true;
16
+ if (path.endsWith("/") || path.endsWith("\\")) return true;
17
+ if (path.includes("__MACOSX/") || path.includes("__MACOSX\\")) return true;
18
+ const idx = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
19
+ const base = idx >= 0 ? path.slice(idx + 1) : path;
20
+ if (!base || base.startsWith(".")) return true;
21
+ return false;
22
+ }
23
+
24
+ // src/errors.ts
25
+ var ShareMiiError = class extends Error {
26
+ code;
27
+ params;
28
+ constructor(code, params = {}) {
29
+ super(code);
30
+ this.name = "ShareMiiError";
31
+ this.code = code;
32
+ this.params = params;
33
+ }
34
+ };
35
+
36
+ // src/utf16.ts
37
+ function decodeUtf16Name(buf) {
38
+ let end = 0;
39
+ while (end + 1 < buf.byteLength) {
40
+ if (buf[end] === 0 && buf[end + 1] === 0) break;
41
+ end += 2;
42
+ }
43
+ const code = [];
44
+ for (let i = 0; i < end; i += 2) {
45
+ code.push(buf[i] | buf[i + 1] << 8);
46
+ }
47
+ return String.fromCharCode(...code);
48
+ }
49
+ function sanitizeFileName(name) {
50
+ const cleaned = name.replace(/[^\w.-]/g, "_");
51
+ return cleaned.length > 0 ? cleaned : "mii";
52
+ }
53
+ function encodeUtf16Name(text, byteLen) {
54
+ const out = new Uint8Array(byteLen);
55
+ const maxChars = Math.floor((byteLen - 2) / 2);
56
+ const truncated = text.length > maxChars ? text.slice(0, maxChars) : text;
57
+ for (let i = 0; i < truncated.length; i++) {
58
+ const code = truncated.charCodeAt(i);
59
+ out[i * 2] = code & 255;
60
+ out[i * 2 + 1] = code >> 8 & 255;
61
+ }
62
+ return out;
63
+ }
64
+
65
+ // src/ugcKinds.ts
66
+ var UGC_KINDS = [
67
+ "Food",
68
+ "Cloth",
69
+ "Goods",
70
+ "Interior",
71
+ "Exterior",
72
+ "MapObject",
73
+ "MapFloor"
74
+ ];
75
+ var UGC_DISPLAY_LABELS = {
76
+ Food: "Food",
77
+ Cloth: "Clothing",
78
+ Goods: "Treasure",
79
+ Interior: "Interior",
80
+ Exterior: "Exterior",
81
+ MapObject: "Objects",
82
+ MapFloor: "Landscaping"
83
+ };
84
+ var UGC_FILE_EXTENSIONS = {
85
+ Food: ".ltdf",
86
+ Cloth: ".ltdc",
87
+ Goods: ".ltdg",
88
+ Interior: ".ltdi",
89
+ Exterior: ".ltde",
90
+ MapObject: ".ltdo",
91
+ MapFloor: ".ltdl"
92
+ };
93
+ function ugcKindIndex(kind) {
94
+ return UGC_KINDS.indexOf(kind);
95
+ }
96
+ var UGC_MAX_SLOTS = {
97
+ Food: 99,
98
+ Cloth: 299,
99
+ Goods: 99,
100
+ Interior: 99,
101
+ Exterior: 99,
102
+ MapObject: 99,
103
+ MapFloor: 99
104
+ };
105
+ function ugcFileBase(kind, slot) {
106
+ return `Ugc${kind}${String(slot).padStart(3, "0")}`;
107
+ }
108
+ function ugcCanvasFileName(kind, slot) {
109
+ return `${ugcFileBase(kind, slot)}.canvas.zs`;
110
+ }
111
+ function ugcTexFileName(kind, slot) {
112
+ return `${ugcFileBase(kind, slot)}.ugctex.zs`;
113
+ }
114
+ function ugcThumbFileName(kind, slot) {
115
+ return `${ugcFileBase(kind, slot)}_Thumb.ugctex.zs`;
116
+ }
117
+ function facepaintFileBase(id) {
118
+ return `UgcFacePaint${String(id).padStart(3, "0")}`;
119
+ }
120
+ function facepaintCanvasFileName(id) {
121
+ return `${facepaintFileBase(id)}.canvas.zs`;
122
+ }
123
+ function facepaintTexFileName(id) {
124
+ return `${facepaintFileBase(id)}.ugctex.zs`;
125
+ }
126
+ var UGC_HASHES = {
127
+ Food: {
128
+ fields: [
129
+ 813690618,
130
+ 1871970237,
131
+ 1554592622,
132
+ 4150813194,
133
+ 1525697515,
134
+ 766601413,
135
+ 1665663150,
136
+ 3717033050,
137
+ 2937161423,
138
+ 1491512019
139
+ ],
140
+ names: [1082430709, 3121564591]
141
+ },
142
+ Cloth: {
143
+ fields: [
144
+ 3356837374,
145
+ 800658541,
146
+ 2050092951,
147
+ 2129409513,
148
+ 1580399935,
149
+ 230342183,
150
+ 1902255256,
151
+ 757535545,
152
+ 3455262389,
153
+ 673438675
154
+ ],
155
+ names: [1081148994, 3482981354]
156
+ },
157
+ Goods: {
158
+ fields: [
159
+ 1068114466,
160
+ 2185200279,
161
+ 2127333984,
162
+ 2296126787,
163
+ 2291588566,
164
+ 3220345970,
165
+ 1570133858,
166
+ 2027131400,
167
+ 1405575856,
168
+ 1087555326,
169
+ 3232153670,
170
+ 2922855181,
171
+ 2103442359,
172
+ 2660732766,
173
+ 4130642217,
174
+ 2419641808,
175
+ 2589586826
176
+ ],
177
+ names: [796475057, 4132811578, 4083833355, 2791532523],
178
+ vector: 4083961384
179
+ },
180
+ Interior: {
181
+ fields: [
182
+ 2836489218,
183
+ 2203129025,
184
+ 3966100196,
185
+ 175960773,
186
+ 1714214919,
187
+ 28534302,
188
+ 1525981343,
189
+ 1107239425
190
+ ],
191
+ names: [1038271965, 2242083728]
192
+ },
193
+ Exterior: {
194
+ fields: [
195
+ 3986018063,
196
+ 1140132282,
197
+ 2812311356,
198
+ 2812311356,
199
+ 884629785,
200
+ 1584308108,
201
+ 688373824,
202
+ 2542165355,
203
+ 1621039485,
204
+ 1201997093,
205
+ 1911191348
206
+ ],
207
+ names: [667448790, 236315640],
208
+ vector: 1007944286,
209
+ vector2: 3117554511
210
+ },
211
+ MapObject: {
212
+ fields: [
213
+ 658921937,
214
+ 3706201852,
215
+ 3763215979,
216
+ 91172640,
217
+ 3162340912,
218
+ 1009501487,
219
+ 3489582274,
220
+ 1544938297,
221
+ 1593794062,
222
+ 2553816651,
223
+ 1215794662,
224
+ 1655525687,
225
+ 3518214551
226
+ ],
227
+ names: [1459196728, 4002552546],
228
+ vector: 670231774,
229
+ vector2: 798367803
230
+ },
231
+ MapFloor: {
232
+ fields: [
233
+ 567640793,
234
+ 3732715812,
235
+ 3904736393,
236
+ 3277556495,
237
+ 1625456891,
238
+ 2126742378,
239
+ 4060734201,
240
+ 1837378252
241
+ ],
242
+ names: [2441639337, 1345622240]
243
+ }
244
+ };
245
+ var UGC_ENABLE_HASHES = {
246
+ Food: 4104362341,
247
+ Cloth: 2937232435,
248
+ Goods: 446431486,
249
+ Interior: 2744599785,
250
+ Exterior: 4106137026,
251
+ MapObject: 1498481931,
252
+ MapFloor: 2702339378
253
+ };
254
+ var UGC_TEXTURE_HASHES = {
255
+ Food: 895006591,
256
+ Cloth: 1505733075,
257
+ Goods: 1892747848,
258
+ Interior: 3891909689,
259
+ Exterior: 371358800,
260
+ MapObject: 2848313272,
261
+ MapFloor: 111649100
262
+ };
263
+ var UGC_HASH_ID_HASHES = {
264
+ Food: 1833498850,
265
+ Cloth: 2314362028,
266
+ Goods: 1444946176,
267
+ Interior: 2146402173,
268
+ Exterior: 953624469,
269
+ MapObject: 455651696,
270
+ MapFloor: 2171424931
271
+ };
272
+ var UGC_TEX_DATA = new Uint8Array([
273
+ 65,
274
+ 73,
275
+ 147,
276
+ 86,
277
+ 227,
278
+ 194,
279
+ 47,
280
+ 180,
281
+ 65,
282
+ 73,
283
+ 147,
284
+ 86,
285
+ 227,
286
+ 194,
287
+ 47,
288
+ 180,
289
+ 227,
290
+ 194,
291
+ 47,
292
+ 180,
293
+ 227,
294
+ 194,
295
+ 47,
296
+ 180,
297
+ 227,
298
+ 194,
299
+ 47,
300
+ 180
301
+ ]);
302
+ var UGC_HASH_INDICES = {
303
+ Food: 1,
304
+ Cloth: 3,
305
+ Goods: 2,
306
+ Interior: 6,
307
+ Exterior: 7,
308
+ MapObject: 4,
309
+ MapFloor: 5
310
+ };
311
+ var FACEPAINT_HASHES = {
312
+ price: 1285036516,
313
+ textureSourceType: 3737946452,
314
+ state: 588471237,
315
+ unknown: 4291252406,
316
+ hash: 2775466732
317
+ };
318
+ var MII_HASHES = {
319
+ facePaintIndex: 1580379636,
320
+ tempSlotMii: 290389897,
321
+ names: 614055898,
322
+ pronunciation: 979294725,
323
+ rawMii: 2283577978,
324
+ isLoveGender: 3754435107,
325
+ satisfyLevel: 2576988121,
326
+ personality: [
327
+ 1137522255,
328
+ 3448617720,
329
+ 632586788,
330
+ 1618714976,
331
+ 1759581006,
332
+ 1226026522,
333
+ 337567878,
334
+ 129618293,
335
+ 2177845002,
336
+ 1299767906,
337
+ 4223926192,
338
+ 594423155,
339
+ 4089699929,
340
+ 1712083527,
341
+ 1568489285,
342
+ 2878005387,
343
+ 625337731,
344
+ 1827964148
345
+ ]
346
+ };
347
+ var UGC_NAME_HASHES = {
348
+ Food: 1082430709,
349
+ Cloth: 1081148994,
350
+ Goods: 796475057,
351
+ Interior: 1038271965,
352
+ Exterior: 667448790,
353
+ MapObject: 1459196728,
354
+ MapFloor: 2441639337
355
+ };
356
+
357
+ // src/savAccess.ts
358
+ import { buildHashMap } from "@alexislours/ltd-savedata";
359
+ import "@alexislours/ltd-savedata/schema";
360
+ function leafByHashOrThrow(schema, hash, label, expected) {
361
+ const leaf = buildHashMap(schema).get(hash >>> 0);
362
+ if (!leaf) throw new ShareMiiError("save_format_error", { label });
363
+ if (leaf.type !== expected) {
364
+ throw new ShareMiiError("save_format_error", { label });
365
+ }
366
+ return leaf;
367
+ }
368
+
369
+ // src/codec.ts
370
+ var MII_BLOCK = 156;
371
+ var PERSONALITY_LEN = 18 * 4;
372
+ var NAME_LEN = 64;
373
+ var PRONOUNCE_LEN = 128;
374
+ var SEXUALITY_LEN = 4;
375
+ var MARK_CANVAS = new Uint8Array([163, 163, 163, 163]);
376
+ var MARK_UGC = new Uint8Array([164, 164, 164, 164]);
377
+ var MARK_NAME = new Uint8Array([162, 162, 162, 162]);
378
+ var MARK_THUMB = new Uint8Array([165, 165, 165, 165]);
379
+ function encodeLtdMii(m) {
380
+ if (m.miiBlock.byteLength !== MII_BLOCK) throw new Error("miiBlock must be 156 bytes");
381
+ if (m.personality.byteLength !== PERSONALITY_LEN) throw new Error("personality must be 72 bytes");
382
+ if (m.name.byteLength !== NAME_LEN) throw new Error("name must be 64 bytes");
383
+ if (m.pronounce.byteLength !== PRONOUNCE_LEN) throw new Error("pronounce must be 128 bytes");
384
+ if (m.sexuality.byteLength !== SEXUALITY_LEN) throw new Error("sexuality must be 4 bytes");
385
+ const total = 4 + MII_BLOCK + PERSONALITY_LEN + NAME_LEN + PRONOUNCE_LEN + SEXUALITY_LEN + 4 + m.canvasTex.byteLength + 4 + m.ugcTex.byteLength;
386
+ const out = new Uint8Array(total);
387
+ let p = 0;
388
+ out[p++] = m.version & 255;
389
+ out[p++] = m.hasCanvas ? 1 : 0;
390
+ out[p++] = m.hasUgcTex ? 1 : 0;
391
+ out[p++] = 0;
392
+ out.set(m.miiBlock, p);
393
+ p += MII_BLOCK;
394
+ out.set(m.personality, p);
395
+ p += PERSONALITY_LEN;
396
+ out.set(m.name, p);
397
+ p += NAME_LEN;
398
+ out.set(m.pronounce, p);
399
+ p += PRONOUNCE_LEN;
400
+ out.set(m.sexuality, p);
401
+ p += SEXUALITY_LEN;
402
+ out.set(MARK_CANVAS, p);
403
+ p += 4;
404
+ out.set(m.canvasTex, p);
405
+ p += m.canvasTex.byteLength;
406
+ out.set(MARK_UGC, p);
407
+ p += 4;
408
+ out.set(m.ugcTex, p);
409
+ return out;
410
+ }
411
+ function decodeLtdMii(bytes) {
412
+ if (bytes.byteLength < 4) throw new ShareMiiError("invalid_ltd_file");
413
+ let buf = new Uint8Array(bytes);
414
+ const originalVersion = buf[0];
415
+ let version = originalVersion;
416
+ if (version < 1 || version > 3) {
417
+ throw new ShareMiiError("unsupported_ltd_version", { version });
418
+ }
419
+ if (version < 3) {
420
+ buf = upgradeToV3(buf);
421
+ version = 3;
422
+ }
423
+ const hasCanvas = buf[1] !== 0;
424
+ const hasUgcTex = buf[2] !== 0;
425
+ let p = 4;
426
+ const miiBlock = buf.slice(p, p + MII_BLOCK);
427
+ p += MII_BLOCK;
428
+ const personality = buf.slice(p, p + PERSONALITY_LEN);
429
+ p += PERSONALITY_LEN;
430
+ const name = buf.slice(p, p + NAME_LEN);
431
+ p += NAME_LEN;
432
+ const pronounce = buf.slice(p, p + PRONOUNCE_LEN);
433
+ p += PRONOUNCE_LEN;
434
+ const sexuality = buf.slice(p, p + SEXUALITY_LEN);
435
+ p += SEXUALITY_LEN;
436
+ const canvasStart = findMarker(buf, MARK_CANVAS, p);
437
+ if (canvasStart < 0) throw new ShareMiiError("ltd_missing_marker", { marker: "canvas" });
438
+ const ugcStart = findMarker(buf, MARK_UGC, canvasStart + 4);
439
+ if (ugcStart < 0) throw new ShareMiiError("ltd_missing_marker", { marker: "ugc" });
440
+ const canvasTex = buf.slice(canvasStart + 4, ugcStart);
441
+ const ugcTex = buf.slice(ugcStart + 4);
442
+ return {
443
+ version,
444
+ originalVersion,
445
+ hasCanvas,
446
+ hasUgcTex,
447
+ miiBlock,
448
+ personality,
449
+ name,
450
+ pronounce,
451
+ sexuality,
452
+ canvasTex,
453
+ ugcTex
454
+ };
455
+ }
456
+ function upgradeToV3(input) {
457
+ const mii = Array.from(input);
458
+ const originalVersion = mii[0];
459
+ mii.splice(4, 1);
460
+ if (originalVersion === 2) {
461
+ mii.splice(427, 0, 0);
462
+ const canvasMarkerStart = findMarkerArr(mii, [163, 163, 163]);
463
+ if (canvasMarkerStart < 0)
464
+ throw new ShareMiiError("ltd_missing_marker", { marker: "v2_canvas" });
465
+ const canvasStart = canvasMarkerStart + 3;
466
+ const ugcMarkerStart = lastFindMarkerArr(mii, [163, 163, 163]);
467
+ mii.splice(canvasStart, 0, 163);
468
+ mii[ugcMarkerStart + 1] = 164;
469
+ mii[ugcMarkerStart + 2] = 164;
470
+ mii[ugcMarkerStart + 3] = 164;
471
+ mii.splice(ugcMarkerStart + 3, 0, 164);
472
+ }
473
+ mii[0] = 3;
474
+ return new Uint8Array(mii);
475
+ }
476
+ function findMarker(buf, marker, from) {
477
+ outer: for (let i = from; i <= buf.byteLength - marker.byteLength; i++) {
478
+ for (let j = 0; j < marker.byteLength; j++) {
479
+ if (buf[i + j] !== marker[j]) continue outer;
480
+ }
481
+ return i;
482
+ }
483
+ return -1;
484
+ }
485
+ function findMarkerArr(buf, marker) {
486
+ outer: for (let i = 0; i <= buf.length - marker.length; i++) {
487
+ for (let j = 0; j < marker.length; j++) {
488
+ if (buf[i + j] !== marker[j]) continue outer;
489
+ }
490
+ return i;
491
+ }
492
+ return -1;
493
+ }
494
+ function lastFindMarkerArr(buf, marker) {
495
+ outer: for (let i = buf.length - marker.length; i >= 0; i--) {
496
+ for (let j = 0; j < marker.length; j++) {
497
+ if (buf[i + j] !== marker[j]) continue outer;
498
+ }
499
+ return i;
500
+ }
501
+ return -1;
502
+ }
503
+ function encodeLtdUgc(u) {
504
+ const ltdHeader = new Uint8Array([u.kindIndex & 255, 0, 0, 0]);
505
+ const namesBlock = u.goodsText ? concat(u.name, u.pronounce, u.goodsText, u.goodsPronounce ?? new Uint8Array(0)) : concat(u.name, u.pronounce);
506
+ return concat(
507
+ ltdHeader,
508
+ u.fields,
509
+ u.vector,
510
+ u.vector2,
511
+ MARK_NAME,
512
+ namesBlock,
513
+ MARK_CANVAS,
514
+ u.canvasTex,
515
+ MARK_UGC,
516
+ u.ugcTex,
517
+ MARK_THUMB,
518
+ u.thumbTex
519
+ );
520
+ }
521
+ function decodeLtdUgc(bytes) {
522
+ if (bytes.byteLength < 4) throw new ShareMiiError("invalid_ltd_file");
523
+ const kindIndex = bytes[0];
524
+ const nameStart = findMarker(bytes, MARK_NAME, 4);
525
+ if (nameStart < 0) throw new ShareMiiError("ltd_missing_marker", { marker: "name" });
526
+ const canvasStart = findMarker(bytes, MARK_CANVAS, nameStart + 4);
527
+ if (canvasStart < 0) throw new ShareMiiError("ltd_missing_marker", { marker: "canvas" });
528
+ const ugcStart = findMarker(bytes, MARK_UGC, canvasStart + 4);
529
+ if (ugcStart < 0) throw new ShareMiiError("ltd_missing_marker", { marker: "ugc" });
530
+ const thumbStart = findMarker(bytes, MARK_THUMB, ugcStart + 4);
531
+ if (thumbStart < 0) throw new ShareMiiError("ltd_missing_marker", { marker: "thumb" });
532
+ return {
533
+ kindIndex,
534
+ fieldsAndVectors: bytes.slice(4, nameStart),
535
+ namesBlock: bytes.slice(nameStart + 4, canvasStart),
536
+ canvasTex: bytes.slice(canvasStart + 4, ugcStart),
537
+ ugcTex: bytes.slice(ugcStart + 4, thumbStart),
538
+ thumbTex: bytes.slice(thumbStart + 4)
539
+ };
540
+ }
541
+ function concat(...parts) {
542
+ let total = 0;
543
+ for (const p of parts) total += p.byteLength;
544
+ const out = new Uint8Array(total);
545
+ let off = 0;
546
+ for (const p of parts) {
547
+ out.set(p, off);
548
+ off += p.byteLength;
549
+ }
550
+ return out;
551
+ }
552
+
553
+ // src/applyMii.ts
554
+ import { DataType as DataType2, buildHashMap as buildHashMap2 } from "@alexislours/ltd-savedata";
555
+ import { MII_SCHEMA as MII_SCHEMA2, PLAYER_SCHEMA as PLAYER_SCHEMA2 } from "@alexislours/ltd-savedata/schema";
556
+ var MII_SLOTS = 70;
557
+ var MII_BLOCK_LEN = 156;
558
+ var MII_DATA_LEN = 152;
559
+ function wrapMiiBlock(data) {
560
+ const out = new Uint8Array(MII_BLOCK_LEN);
561
+ new DataView(out.buffer).setUint32(0, MII_DATA_LEN, true);
562
+ out.set(data, 4);
563
+ return out;
564
+ }
565
+ function unwrapMiiBlock(block) {
566
+ return block.slice(4, MII_BLOCK_LEN);
567
+ }
568
+ var FP_TEX_SRC_USED = 1452493121 | 0;
569
+ var FP_TEX_SRC_UNUSED = 3069107721 | 0;
570
+ var FP_STATE_USED = 494906868 | 0;
571
+ var FP_STATE_UNUSED = 2952759973 | 0;
572
+ var FP_UNKNOWN_USED = 32768 | 0;
573
+ var FP_UNKNOWN_UNUSED = 0 | 0;
574
+ var FP_PRICE = 500;
575
+ var FP_HASH_UNUSED = 0 | 0;
576
+ var FP_INDEX_UNUSED = -1;
577
+ function fpHashValue(facepaintId) {
578
+ return 8 << 16 | facepaintId | 0;
579
+ }
580
+ var PLAYER_LEAVES = {
581
+ fpPrice: leafByHashOrThrow(
582
+ PLAYER_SCHEMA2,
583
+ FACEPAINT_HASHES.price,
584
+ "Facepaint.Price",
585
+ DataType2.IntArray
586
+ ),
587
+ fpTexSrc: leafByHashOrThrow(
588
+ PLAYER_SCHEMA2,
589
+ FACEPAINT_HASHES.textureSourceType,
590
+ "Facepaint.TextureSourceType",
591
+ DataType2.EnumArray
592
+ ),
593
+ fpState: leafByHashOrThrow(
594
+ PLAYER_SCHEMA2,
595
+ FACEPAINT_HASHES.state,
596
+ "Facepaint.State",
597
+ DataType2.EnumArray
598
+ ),
599
+ fpUnknown: leafByHashOrThrow(
600
+ PLAYER_SCHEMA2,
601
+ FACEPAINT_HASHES.unknown,
602
+ "Facepaint.Unknown",
603
+ DataType2.UIntArray
604
+ ),
605
+ fpHash: leafByHashOrThrow(
606
+ PLAYER_SCHEMA2,
607
+ FACEPAINT_HASHES.hash,
608
+ "Facepaint.Hash",
609
+ DataType2.UIntArray
610
+ ),
611
+ tempSlot: leafByHashOrThrow(
612
+ PLAYER_SCHEMA2,
613
+ MII_HASHES.tempSlotMii,
614
+ "Player.TempSlotMii",
615
+ DataType2.Binary
616
+ )
617
+ };
618
+ var MII_LEAVES = {
619
+ facePaintIndex: leafByHashOrThrow(
620
+ MII_SCHEMA2,
621
+ MII_HASHES.facePaintIndex,
622
+ "Mii.FacePaintIndex",
623
+ DataType2.IntArray
624
+ ),
625
+ names: leafByHashOrThrow(MII_SCHEMA2, MII_HASHES.names, "Mii.Names", DataType2.WString32Array),
626
+ pronunciation: leafByHashOrThrow(
627
+ MII_SCHEMA2,
628
+ MII_HASHES.pronunciation,
629
+ "Mii.Pronunciation",
630
+ DataType2.WString64Array
631
+ ),
632
+ rawMii: leafByHashOrThrow(MII_SCHEMA2, MII_HASHES.rawMii, "Mii.Raw", DataType2.BinaryArray),
633
+ isLoveGender: leafByHashOrThrow(
634
+ MII_SCHEMA2,
635
+ MII_HASHES.isLoveGender,
636
+ "Mii.IsLoveGender",
637
+ DataType2.BoolArray
638
+ ),
639
+ satisfyLevel: leafByHashOrThrow(
640
+ MII_SCHEMA2,
641
+ MII_HASHES.satisfyLevel,
642
+ "Mii.SatisfyInfo.Level",
643
+ DataType2.IntArray
644
+ ),
645
+ personality: MII_HASHES.personality.map((h, i) => {
646
+ const leaf = buildHashMap2(MII_SCHEMA2).get(h >>> 0);
647
+ if (!leaf) throw new ShareMiiError("save_format_error", { label: `Personality[${i}]` });
648
+ if (leaf.type !== DataType2.IntArray && leaf.type !== DataType2.EnumArray) {
649
+ throw new ShareMiiError("save_format_error", { label: `Personality[${i}]` });
650
+ }
651
+ return leaf;
652
+ })
653
+ };
654
+ function getPersonalityElement(mii, leaf, i) {
655
+ if (leaf.type === DataType2.IntArray) return mii.getElement(leaf, i);
656
+ return mii.getElement(leaf, i);
657
+ }
658
+ function setPersonalityElement(mii, leaf, i, v) {
659
+ if (leaf.type === DataType2.IntArray) mii.setElement(leaf, i, v);
660
+ else mii.setElement(leaf, i, v >>> 0);
661
+ }
662
+ function listMiiSlots(saves) {
663
+ const out = [];
664
+ out.push({ slot: 0, empty: false, name: "In-Progress Mii" });
665
+ for (let s = 0; s < MII_SLOTS; s++) {
666
+ const data = saves.mii.getElement(MII_LEAVES.rawMii, s);
667
+ const empty = isEmptyDataBlock(data);
668
+ const name = saves.mii.getElement(MII_LEAVES.names, s);
669
+ out.push({ slot: s + 1, empty, name: empty ? "" : name });
670
+ }
671
+ return out;
672
+ }
673
+ function isEmptyDataBlock(data) {
674
+ if (data.byteLength !== MII_DATA_LEN) return false;
675
+ for (const b of data) if (b !== 0) return false;
676
+ return true;
677
+ }
678
+ function isEmptyMiiBlock(block) {
679
+ if (block.byteLength !== MII_BLOCK_LEN) return false;
680
+ let sum = 0;
681
+ for (const b of block) sum += b;
682
+ return sum === 152;
683
+ }
684
+ function readMiiBlock(saves, isTemp, slotIdx) {
685
+ if (isTemp) {
686
+ const data2 = saves.player.get(PLAYER_LEAVES.tempSlot);
687
+ if (data2.byteLength < MII_DATA_LEN) throw new ShareMiiError("mii_not_initialized");
688
+ return wrapMiiBlock(data2.subarray(0, MII_DATA_LEN));
689
+ }
690
+ const data = saves.mii.getElement(MII_LEAVES.rawMii, slotIdx);
691
+ if (data.byteLength !== MII_DATA_LEN) {
692
+ throw new ShareMiiError("save_format_error", { label: "Mii.Raw" });
693
+ }
694
+ return wrapMiiBlock(data);
695
+ }
696
+ function writeMiiBlock(saves, isTemp, slotIdx, block) {
697
+ const data = unwrapMiiBlock(block);
698
+ if (isTemp) {
699
+ const buf = saves.player.get(PLAYER_LEAVES.tempSlot);
700
+ buf.set(data, 0);
701
+ saves.player.set(PLAYER_LEAVES.tempSlot, buf);
702
+ } else {
703
+ saves.mii.setElement(MII_LEAVES.rawMii, slotIdx, data);
704
+ }
705
+ }
706
+ function extractMii(saves, slot, sidecar = EMPTY_SIDECAR) {
707
+ const isTemp = slot === 0;
708
+ const slotIdx = slot - 1;
709
+ const block = readMiiBlock(saves, isTemp, slotIdx);
710
+ if (isEmptyMiiBlock(block)) {
711
+ throw new ShareMiiError("mii_not_initialized");
712
+ }
713
+ let facepaintId = null;
714
+ if (isTemp) {
715
+ if (saves.player.getElement(PLAYER_LEAVES.fpState, 70) !== FP_STATE_UNUSED) facepaintId = 70;
716
+ } else {
717
+ const id = saves.mii.getElement(MII_LEAVES.facePaintIndex, slotIdx);
718
+ if (id !== FP_INDEX_UNUSED) facepaintId = id;
719
+ }
720
+ const personality = new Uint8Array(72);
721
+ const dv = new DataView(personality.buffer);
722
+ for (let i = 0; i < 18; i++) {
723
+ const v = isTemp ? 0 : getPersonalityElement(saves.mii, MII_LEAVES.personality[i], slotIdx);
724
+ dv.setInt32(i * 4, v | 0, true);
725
+ }
726
+ const name = new Uint8Array(64);
727
+ let decodedName;
728
+ if (isTemp) {
729
+ const tempName = new TextEncoder().encode("Temp");
730
+ for (let i = 0; i < tempName.length; i++) name[i * 2] = tempName[i];
731
+ decodedName = "Mii";
732
+ } else {
733
+ const nameStr = saves.mii.getElement(MII_LEAVES.names, slotIdx);
734
+ name.set(encodeUtf16Name(nameStr, 64));
735
+ decodedName = decodeUtf16Name(name);
736
+ }
737
+ const pronounce = new Uint8Array(128);
738
+ if (!isTemp) {
739
+ const pStr = saves.mii.getElement(MII_LEAVES.pronunciation, slotIdx);
740
+ pronounce.set(encodeUtf16Name(pStr, 128));
741
+ }
742
+ const sexuality = new Uint8Array(4);
743
+ if (!isTemp) {
744
+ const base = slotIdx * 3;
745
+ sexuality[0] = saves.mii.getElement(MII_LEAVES.isLoveGender, base) ? 1 : 0;
746
+ sexuality[1] = saves.mii.getElement(MII_LEAVES.isLoveGender, base + 1) ? 1 : 0;
747
+ sexuality[2] = saves.mii.getElement(MII_LEAVES.isLoveGender, base + 2) ? 1 : 0;
748
+ }
749
+ let canvasTex = new Uint8Array(0);
750
+ let ugcTex = new Uint8Array(0);
751
+ const facepaint = [];
752
+ if (facepaintId !== null) {
753
+ const canvasName = facepaintCanvasFileName(facepaintId);
754
+ const texName = facepaintTexFileName(facepaintId);
755
+ const c = sidecar.files.get(canvasName);
756
+ const t = sidecar.files.get(texName);
757
+ if (c && t) {
758
+ canvasTex = new Uint8Array(c);
759
+ ugcTex = new Uint8Array(t);
760
+ facepaint.push({ name: canvasName, bytes: canvasTex }, { name: texName, bytes: ugcTex });
761
+ }
762
+ }
763
+ const ltd = {
764
+ version: isTemp ? 1 : 3,
765
+ originalVersion: isTemp ? 1 : 3,
766
+ hasCanvas: canvasTex.byteLength > 0,
767
+ hasUgcTex: ugcTex.byteLength > 0,
768
+ miiBlock: block.slice(),
769
+ personality,
770
+ name,
771
+ pronounce,
772
+ sexuality,
773
+ canvasTex,
774
+ ugcTex
775
+ };
776
+ const bytes = encodeLtdMii(ltd);
777
+ const baseName = isTemp ? "Mii" : sanitizeFileName(decodedName);
778
+ return {
779
+ bytes,
780
+ fileName: `${baseName}.ltd`,
781
+ miiName: decodedName || "Mii",
782
+ facepaint
783
+ };
784
+ }
785
+ function applyMii(saves, slot, ltdBytes, sidecar = EMPTY_SIDECAR) {
786
+ const ltd = decodeLtdMii(ltdBytes);
787
+ const isTemp = slot === 0;
788
+ const slotIdx = slot - 1;
789
+ if (!isTemp && isEmptyMiiBlock(readMiiBlock(saves, isTemp, slotIdx))) {
790
+ throw new ShareMiiError("mii_not_initialized");
791
+ }
792
+ writeMiiBlock(saves, isTemp, slotIdx, ltd.miiBlock);
793
+ const facepaintAvailable = ltd.hasCanvas && ltd.hasUgcTex ? "inline" : null;
794
+ const prevFacepaintId = isTemp ? FP_INDEX_UNUSED : saves.mii.getElement(MII_LEAVES.facePaintIndex, slotIdx);
795
+ let facepaintId = prevFacepaintId;
796
+ const facepaintWrites = [];
797
+ if (facepaintAvailable === "inline") {
798
+ if (isTemp) {
799
+ facepaintId = 70;
800
+ } else if (facepaintId === FP_INDEX_UNUSED) {
801
+ facepaintId = pickFacepaintId(saves.mii);
802
+ saves.mii.setElement(MII_LEAVES.facePaintIndex, slotIdx, facepaintId);
803
+ }
804
+ saves.player.setElement(PLAYER_LEAVES.fpPrice, facepaintId, FP_PRICE);
805
+ saves.player.setElement(PLAYER_LEAVES.fpTexSrc, facepaintId, FP_TEX_SRC_USED);
806
+ saves.player.setElement(PLAYER_LEAVES.fpState, facepaintId, FP_STATE_USED);
807
+ saves.player.setElement(PLAYER_LEAVES.fpUnknown, facepaintId, FP_UNKNOWN_USED);
808
+ saves.player.setElement(PLAYER_LEAVES.fpHash, facepaintId, fpHashValue(facepaintId));
809
+ facepaintWrites.push({
810
+ name: facepaintCanvasFileName(facepaintId),
811
+ bytes: ltd.canvasTex
812
+ });
813
+ facepaintWrites.push({
814
+ name: facepaintTexFileName(facepaintId),
815
+ bytes: ltd.ugcTex
816
+ });
817
+ } else if (prevFacepaintId !== FP_INDEX_UNUSED) {
818
+ if (!isTemp) {
819
+ saves.mii.setElement(MII_LEAVES.facePaintIndex, slotIdx, FP_INDEX_UNUSED);
820
+ }
821
+ saves.player.setElement(PLAYER_LEAVES.fpPrice, prevFacepaintId, 0);
822
+ saves.player.setElement(PLAYER_LEAVES.fpTexSrc, prevFacepaintId, FP_TEX_SRC_UNUSED);
823
+ saves.player.setElement(PLAYER_LEAVES.fpState, prevFacepaintId, FP_STATE_UNUSED);
824
+ saves.player.setElement(PLAYER_LEAVES.fpUnknown, prevFacepaintId, FP_UNKNOWN_UNUSED);
825
+ saves.player.setElement(PLAYER_LEAVES.fpHash, prevFacepaintId, FP_HASH_UNUSED);
826
+ }
827
+ if (ltd.originalVersion >= 2 && !isTemp) {
828
+ const sdv = new DataView(
829
+ ltd.personality.buffer,
830
+ ltd.personality.byteOffset,
831
+ ltd.personality.byteLength
832
+ );
833
+ for (let i = 0; i < 18; i++) {
834
+ setPersonalityElement(
835
+ saves.mii,
836
+ MII_LEAVES.personality[i],
837
+ slotIdx,
838
+ sdv.getInt32(i * 4, true)
839
+ );
840
+ }
841
+ saves.mii.setElement(MII_LEAVES.names, slotIdx, decodeUtf16Name(ltd.name));
842
+ saves.mii.setElement(MII_LEAVES.pronunciation, slotIdx, decodeUtf16Name(ltd.pronounce));
843
+ if (saves.mii.getElement(MII_LEAVES.satisfyLevel, slotIdx) < 2) {
844
+ const base = slotIdx * 3;
845
+ saves.mii.setElement(MII_LEAVES.isLoveGender, base, (ltd.sexuality[0] & 1) === 1);
846
+ saves.mii.setElement(MII_LEAVES.isLoveGender, base + 1, (ltd.sexuality[1] & 1) === 1);
847
+ saves.mii.setElement(MII_LEAVES.isLoveGender, base + 2, (ltd.sexuality[2] & 1) === 1);
848
+ }
849
+ }
850
+ if (sidecar.origin !== "none" && facepaintWrites.length > 0) {
851
+ for (const f of facepaintWrites) sidecar.files.set(f.name, f.bytes);
852
+ }
853
+ return { facepaintWrites };
854
+ }
855
+ function pickFacepaintId(mii) {
856
+ const used = /* @__PURE__ */ new Set();
857
+ for (let s = 0; s < MII_SLOTS; s++) {
858
+ const id = mii.getElement(MII_LEAVES.facePaintIndex, s);
859
+ if (id !== FP_INDEX_UNUSED) used.add(id);
860
+ }
861
+ for (let i = 0; i < MII_SLOTS; i++) {
862
+ if (!used.has(i)) return i;
863
+ }
864
+ throw new ShareMiiError("no_free_facepaint_slot");
865
+ }
866
+
867
+ // src/applyUgc.ts
868
+ import { arrayElementSize, DataType as DataType3, buildHashMap as buildHashMap3 } from "@alexislours/ltd-savedata";
869
+ import { PLAYER_SCHEMA as PLAYER_SCHEMA3 } from "@alexislours/ltd-savedata/schema";
870
+ var ENABLE_USED = 494906868 >>> 0;
871
+ function resolveScalarFieldLeaf(hash, label) {
872
+ const leaf = buildHashMap3(PLAYER_SCHEMA3).get(hash >>> 0);
873
+ if (!leaf) throw new ShareMiiError("save_format_error", { label });
874
+ const t = leaf.type;
875
+ if (t !== DataType3.IntArray && t !== DataType3.UIntArray && t !== DataType3.EnumArray && t !== DataType3.FloatArray && t !== DataType3.BoolArray) {
876
+ throw new ShareMiiError("save_format_error", { label });
877
+ }
878
+ return leaf;
879
+ }
880
+ function resolveNameLeaf(hash, label) {
881
+ const leaf = buildHashMap3(PLAYER_SCHEMA3).get(hash >>> 0);
882
+ if (!leaf) throw new ShareMiiError("save_format_error", { label });
883
+ const t = leaf.type;
884
+ if (t !== DataType3.WString32Array && t !== DataType3.WString64Array) {
885
+ throw new ShareMiiError("save_format_error", { label });
886
+ }
887
+ return leaf;
888
+ }
889
+ function resolveUgcLeaves(kind) {
890
+ const h = UGC_HASHES[kind];
891
+ return {
892
+ fields: h.fields.map((hash, i) => resolveScalarFieldLeaf(hash, `${kind}.field[${i}]`)),
893
+ names: h.names.map((hash, i) => resolveNameLeaf(hash, `${kind}.name[${i}]`)),
894
+ vector: h.vector ? leafByHashOrThrow(PLAYER_SCHEMA3, h.vector, `${kind}.vector`, DataType3.Vector3Array) : null,
895
+ vector2: h.vector2 ? leafByHashOrThrow(PLAYER_SCHEMA3, h.vector2, `${kind}.vector2`, DataType3.Vector2Array) : null,
896
+ enable: leafByHashOrThrow(
897
+ PLAYER_SCHEMA3,
898
+ UGC_ENABLE_HASHES[kind],
899
+ `${kind}.enable`,
900
+ DataType3.EnumArray
901
+ ),
902
+ texture: leafByHashOrThrow(
903
+ PLAYER_SCHEMA3,
904
+ UGC_TEXTURE_HASHES[kind],
905
+ `${kind}.texture`,
906
+ DataType3.EnumArray
907
+ ),
908
+ hashId: leafByHashOrThrow(
909
+ PLAYER_SCHEMA3,
910
+ UGC_HASH_ID_HASHES[kind],
911
+ `${kind}.hashId`,
912
+ DataType3.UIntArray
913
+ )
914
+ };
915
+ }
916
+ function ugcSlotCapacity(saves, leaves, kind) {
917
+ const player = saves.player;
918
+ let cap = UGC_MAX_SLOTS[kind];
919
+ for (const leaf of leaves.fields) cap = Math.min(cap, player.get(leaf).length);
920
+ for (const leaf of leaves.names) cap = Math.min(cap, player.get(leaf).length);
921
+ if (leaves.vector) cap = Math.min(cap, player.get(leaves.vector).length);
922
+ if (leaves.vector2) cap = Math.min(cap, player.get(leaves.vector2).length);
923
+ cap = Math.min(cap, player.get(leaves.enable).length);
924
+ cap = Math.min(cap, player.get(leaves.texture).length);
925
+ cap = Math.min(cap, player.get(leaves.hashId).length);
926
+ return cap;
927
+ }
928
+ function readField4(player, leaf, slotIdx) {
929
+ const out = new Uint8Array(4);
930
+ const dv = new DataView(out.buffer);
931
+ switch (leaf.type) {
932
+ case DataType3.IntArray:
933
+ dv.setInt32(0, player.getElement(leaf, slotIdx) | 0, true);
934
+ return out;
935
+ case DataType3.UIntArray:
936
+ dv.setUint32(
937
+ 0,
938
+ player.getElement(leaf, slotIdx) >>> 0,
939
+ true
940
+ );
941
+ return out;
942
+ case DataType3.EnumArray:
943
+ dv.setUint32(
944
+ 0,
945
+ player.getElement(leaf, slotIdx) >>> 0,
946
+ true
947
+ );
948
+ return out;
949
+ case DataType3.FloatArray:
950
+ dv.setFloat32(0, player.getElement(leaf, slotIdx), true);
951
+ return out;
952
+ case DataType3.BoolArray:
953
+ out[0] = player.getElement(leaf, slotIdx) ? 1 : 0;
954
+ return out;
955
+ }
956
+ }
957
+ function writeField4(player, leaf, slotIdx, src) {
958
+ const dv = new DataView(src.buffer, src.byteOffset, 4);
959
+ switch (leaf.type) {
960
+ case DataType3.IntArray:
961
+ player.setElement(leaf, slotIdx, dv.getInt32(0, true) | 0);
962
+ return;
963
+ case DataType3.UIntArray:
964
+ player.setElement(
965
+ leaf,
966
+ slotIdx,
967
+ dv.getUint32(0, true) >>> 0
968
+ );
969
+ return;
970
+ case DataType3.EnumArray:
971
+ player.setElement(
972
+ leaf,
973
+ slotIdx,
974
+ dv.getUint32(0, true) >>> 0
975
+ );
976
+ return;
977
+ case DataType3.FloatArray:
978
+ player.setElement(leaf, slotIdx, dv.getFloat32(0, true));
979
+ return;
980
+ case DataType3.BoolArray:
981
+ player.setElement(
982
+ leaf,
983
+ slotIdx,
984
+ (src[0] | src[1] | src[2] | src[3]) !== 0
985
+ );
986
+ return;
987
+ }
988
+ }
989
+ function nameByteLen(leaf) {
990
+ const sz = arrayElementSize(leaf.type);
991
+ if (sz !== 64 && sz !== 128) {
992
+ throw new ShareMiiError("save_format_error", { label: "name" });
993
+ }
994
+ return sz;
995
+ }
996
+ function readNameBlock(player, leaf, slotIdx) {
997
+ const str = player.getElement(leaf, slotIdx);
998
+ return encodeUtf16Name(str, nameByteLen(leaf));
999
+ }
1000
+ function writeNameBlock(player, leaf, slotIdx, src) {
1001
+ player.setElement(leaf, slotIdx, decodeUtf16Name(src));
1002
+ }
1003
+ function readVector3(player, leaf, slotIdx) {
1004
+ const v = player.getElement(leaf, slotIdx);
1005
+ const out = new Uint8Array(12);
1006
+ const dv = new DataView(out.buffer);
1007
+ dv.setFloat32(0, v.x, true);
1008
+ dv.setFloat32(4, v.y, true);
1009
+ dv.setFloat32(8, v.z, true);
1010
+ return out;
1011
+ }
1012
+ function writeVector3(player, leaf, slotIdx, src) {
1013
+ const dv = new DataView(src.buffer, src.byteOffset, 12);
1014
+ player.setElement(leaf, slotIdx, {
1015
+ x: dv.getFloat32(0, true),
1016
+ y: dv.getFloat32(4, true),
1017
+ z: dv.getFloat32(8, true)
1018
+ });
1019
+ }
1020
+ function readVector2(player, leaf, slotIdx) {
1021
+ const v = player.getElement(leaf, slotIdx);
1022
+ const out = new Uint8Array(8);
1023
+ const dv = new DataView(out.buffer);
1024
+ dv.setFloat32(0, v.x, true);
1025
+ dv.setFloat32(4, v.y, true);
1026
+ return out;
1027
+ }
1028
+ function writeVector2(player, leaf, slotIdx, src) {
1029
+ const dv = new DataView(src.buffer, src.byteOffset, 8);
1030
+ player.setElement(leaf, slotIdx, {
1031
+ x: dv.getFloat32(0, true),
1032
+ y: dv.getFloat32(4, true)
1033
+ });
1034
+ }
1035
+ function listUgcSlots(saves, kind, sidecar = EMPTY_SIDECAR) {
1036
+ const out = [];
1037
+ let max = UGC_MAX_SLOTS[kind];
1038
+ let nameLeaf;
1039
+ try {
1040
+ const leaves = resolveUgcLeaves(kind);
1041
+ nameLeaf = resolveNameLeaf(UGC_NAME_HASHES[kind], `${kind}.names`);
1042
+ max = ugcSlotCapacity(saves, leaves, kind);
1043
+ } catch {
1044
+ nameLeaf = null;
1045
+ }
1046
+ let foundAddSlot = false;
1047
+ for (let i = 0; i < max; i++) {
1048
+ const fileName = ugcCanvasFileName(kind, i);
1049
+ const exists = sidecar.files.has(fileName);
1050
+ const decoded = nameLeaf ? saves.player.getElement(nameLeaf, i) : "";
1051
+ const looksFilled = decoded.length > 0;
1052
+ if (exists || sidecar.origin === "none" && looksFilled) {
1053
+ out.push({ slot: i + 1, empty: false, name: decoded, isAddNew: false });
1054
+ } else if (!foundAddSlot) {
1055
+ out.push({ slot: i + 1, empty: true, name: "", isAddNew: true });
1056
+ foundAddSlot = true;
1057
+ }
1058
+ }
1059
+ return out;
1060
+ }
1061
+ function extractUgc(saves, slot, kind, sidecar = EMPTY_SIDECAR) {
1062
+ const leaves = resolveUgcLeaves(kind);
1063
+ const player = saves.player;
1064
+ const slotIdx = slot - 1;
1065
+ const kindIndex = ugcKindIndex(kind);
1066
+ const fields = new Uint8Array(leaves.fields.length * 4);
1067
+ for (let i = 0; i < leaves.fields.length; i++) {
1068
+ fields.set(readField4(player, leaves.fields[i], slotIdx), i * 4);
1069
+ }
1070
+ const vector = leaves.vector ? readVector3(player, leaves.vector, slotIdx) : new Uint8Array(12);
1071
+ const vector2 = leaves.vector2 ? readVector2(player, leaves.vector2, slotIdx) : new Uint8Array(8);
1072
+ const name = readNameBlock(player, leaves.names[0], slotIdx);
1073
+ const pronounce = readNameBlock(player, leaves.names[1], slotIdx);
1074
+ let goodsText;
1075
+ let goodsPronounce;
1076
+ if (kind === "Goods" && leaves.names[2] !== void 0 && leaves.names[3] !== void 0) {
1077
+ goodsText = readNameBlock(player, leaves.names[2], slotIdx);
1078
+ goodsPronounce = readNameBlock(player, leaves.names[3], slotIdx);
1079
+ }
1080
+ const canvasName = ugcCanvasFileName(kind, slotIdx);
1081
+ const texName = ugcTexFileName(kind, slotIdx);
1082
+ const thumbName = ugcThumbFileName(kind, slotIdx);
1083
+ const canvasTex = sidecar.files.get(canvasName);
1084
+ const ugcTex = sidecar.files.get(texName);
1085
+ const thumbTex = sidecar.files.get(thumbName);
1086
+ if (!canvasTex || !ugcTex || !thumbTex) {
1087
+ throw new ShareMiiError("ugc_missing_textures");
1088
+ }
1089
+ const ltd = {
1090
+ kindIndex,
1091
+ fields,
1092
+ vector,
1093
+ vector2,
1094
+ name,
1095
+ pronounce,
1096
+ goodsText,
1097
+ goodsPronounce,
1098
+ canvasTex,
1099
+ ugcTex,
1100
+ thumbTex
1101
+ };
1102
+ const bytes = encodeLtdUgc(ltd);
1103
+ const decodedName = decodeUtf16Name(name) || `Ugc${kind}${slotIdx}`;
1104
+ const fileName = `${sanitizeFileName(decodedName)}${UGC_FILE_EXTENSIONS[kind]}`;
1105
+ return {
1106
+ bytes,
1107
+ fileName,
1108
+ itemName: decodedName,
1109
+ textures: [
1110
+ { name: canvasName, bytes: canvasTex },
1111
+ { name: texName, bytes: ugcTex },
1112
+ { name: thumbName, bytes: thumbTex }
1113
+ ]
1114
+ };
1115
+ }
1116
+ function applyUgc(saves, slot, kind, ltdBytes, isAdding, sidecar = EMPTY_SIDECAR) {
1117
+ const decoded = decodeLtdUgc(ltdBytes);
1118
+ const expected = ugcKindIndex(kind);
1119
+ if (decoded.kindIndex !== expected) {
1120
+ throw new ShareMiiError("wrong_ugc_kind", { got: decoded.kindIndex, expected });
1121
+ }
1122
+ const leaves = resolveUgcLeaves(kind);
1123
+ const player = saves.player;
1124
+ const slotIdx = slot - 1;
1125
+ const capacity = ugcSlotCapacity(saves, leaves, kind);
1126
+ if (slotIdx < 0 || slotIdx >= capacity) {
1127
+ throw new ShareMiiError("slot_out_of_range", { slot, kind, capacity });
1128
+ }
1129
+ if ((kind === "Cloth" || kind === "Goods") && !isAdding) {
1130
+ const existing = readField4(player, leaves.fields[0], slotIdx);
1131
+ const incoming = decoded.fieldsAndVectors.subarray(0, 4);
1132
+ if (!buffersEqual(existing, incoming)) {
1133
+ throw new ShareMiiError("subtype_mismatch");
1134
+ }
1135
+ }
1136
+ if ((kind === "Exterior" || kind === "MapObject") && !isAdding) {
1137
+ throw new ShareMiiError("cannot_replace_kind", { kind });
1138
+ }
1139
+ for (let i = 0; i < leaves.fields.length; i++) {
1140
+ const src = decoded.fieldsAndVectors.subarray(i * 4, i * 4 + 4);
1141
+ writeField4(player, leaves.fields[i], slotIdx, src);
1142
+ }
1143
+ if (isAdding) {
1144
+ player.setElement(leaves.enable, slotIdx, ENABLE_USED);
1145
+ const texDv = new DataView(
1146
+ UGC_TEX_DATA.buffer,
1147
+ UGC_TEX_DATA.byteOffset,
1148
+ UGC_TEX_DATA.byteLength
1149
+ );
1150
+ const texVal = texDv.getUint32(expected * 4, true) >>> 0;
1151
+ player.setElement(leaves.texture, slotIdx, texVal);
1152
+ const hashIdVal = (slotIdx & 255 | (UGC_HASH_INDICES[kind] & 255) << 16) >>> 0;
1153
+ player.setElement(leaves.hashId, slotIdx, hashIdVal);
1154
+ }
1155
+ const namesBlock = decoded.namesBlock;
1156
+ writeNameBlock(player, leaves.names[0], slotIdx, namesBlock.subarray(0, 128));
1157
+ writeNameBlock(player, leaves.names[1], slotIdx, namesBlock.subarray(128, 256));
1158
+ if (kind === "Goods" && leaves.names[2] !== void 0 && leaves.names[3] !== void 0) {
1159
+ writeNameBlock(player, leaves.names[2], slotIdx, namesBlock.subarray(256, 320));
1160
+ writeNameBlock(player, leaves.names[3], slotIdx, namesBlock.subarray(320, 448));
1161
+ }
1162
+ const fav = decoded.fieldsAndVectors;
1163
+ if (leaves.vector) {
1164
+ const vStart = fav.byteLength - 20;
1165
+ writeVector3(player, leaves.vector, slotIdx, fav.subarray(vStart, vStart + 12));
1166
+ }
1167
+ if (leaves.vector2) {
1168
+ const v2Start = fav.byteLength - 8;
1169
+ writeVector2(player, leaves.vector2, slotIdx, fav.subarray(v2Start, v2Start + 8));
1170
+ }
1171
+ const writes = [
1172
+ { name: ugcCanvasFileName(kind, slotIdx), bytes: decoded.canvasTex },
1173
+ { name: ugcTexFileName(kind, slotIdx), bytes: decoded.ugcTex },
1174
+ { name: ugcThumbFileName(kind, slotIdx), bytes: decoded.thumbTex }
1175
+ ];
1176
+ if (sidecar.origin !== "none") {
1177
+ for (const f of writes) sidecar.files.set(f.name, f.bytes);
1178
+ }
1179
+ return { textureWrites: writes };
1180
+ }
1181
+ function buffersEqual(a, b) {
1182
+ if (a.byteLength !== b.byteLength) return false;
1183
+ for (let i = 0; i < a.byteLength; i++) {
1184
+ if (a[i] !== b[i]) return false;
1185
+ }
1186
+ return true;
1187
+ }
1188
+ export {
1189
+ EMPTY_SIDECAR,
1190
+ FACEPAINT_HASHES,
1191
+ FP_STATE_UNUSED,
1192
+ MII_HASHES,
1193
+ MII_SLOTS,
1194
+ ShareMiiError,
1195
+ UGC_DISPLAY_LABELS,
1196
+ UGC_ENABLE_HASHES,
1197
+ UGC_FILE_EXTENSIONS,
1198
+ UGC_HASHES,
1199
+ UGC_HASH_ID_HASHES,
1200
+ UGC_HASH_INDICES,
1201
+ UGC_KINDS,
1202
+ UGC_MAX_SLOTS,
1203
+ UGC_NAME_HASHES,
1204
+ UGC_TEXTURE_HASHES,
1205
+ UGC_TEX_DATA,
1206
+ applyMii,
1207
+ applyUgc,
1208
+ decodeLtdMii,
1209
+ decodeLtdUgc,
1210
+ decodeUtf16Name,
1211
+ encodeLtdMii,
1212
+ encodeLtdUgc,
1213
+ encodeUtf16Name,
1214
+ extractMii,
1215
+ extractUgc,
1216
+ facepaintCanvasFileName,
1217
+ facepaintTexFileName,
1218
+ isJunkArchiveEntry,
1219
+ isSidecarFileName,
1220
+ leafByHashOrThrow,
1221
+ listMiiSlots,
1222
+ listUgcSlots,
1223
+ normalizeName,
1224
+ sanitizeFileName,
1225
+ ugcCanvasFileName,
1226
+ ugcKindIndex,
1227
+ ugcTexFileName,
1228
+ ugcThumbFileName
1229
+ };
1230
+ //# sourceMappingURL=index.js.map