@xivdyetools/core 2.6.0 → 4.0.1
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/README.md +85 -67
- package/dist/blending/blending.d.ts +22 -0
- package/dist/blending/blending.d.ts.map +1 -0
- package/dist/blending/blending.js +129 -0
- package/dist/blending/blending.js.map +1 -0
- package/dist/blending/conversions.d.ts +53 -0
- package/dist/blending/conversions.d.ts.map +1 -0
- package/dist/blending/conversions.js +256 -0
- package/dist/blending/conversions.js.map +1 -0
- package/dist/blending/index.d.ts +8 -0
- package/dist/blending/index.d.ts.map +1 -0
- package/dist/blending/index.js +3 -0
- package/dist/blending/index.js.map +1 -0
- package/dist/blending/types.d.ts +36 -0
- package/dist/blending/types.d.ts.map +1 -0
- package/dist/blending/types.js +21 -0
- package/dist/blending/types.js.map +1 -0
- package/dist/config/band-calibration.d.ts +68 -0
- package/dist/config/band-calibration.d.ts.map +1 -0
- package/dist/config/band-calibration.js +196 -0
- package/dist/config/band-calibration.js.map +1 -0
- package/dist/config/band-vocabulary.d.ts +82 -0
- package/dist/config/band-vocabulary.d.ts.map +1 -0
- package/dist/config/band-vocabulary.js +117 -0
- package/dist/config/band-vocabulary.js.map +1 -0
- package/dist/config/consolidated-ids.js +2 -2
- package/dist/config/consolidated-ids.js.map +1 -1
- package/dist/config/dye-vocabulary.d.ts +45 -0
- package/dist/config/dye-vocabulary.d.ts.map +1 -0
- package/dist/config/dye-vocabulary.js +58 -0
- package/dist/config/dye-vocabulary.js.map +1 -0
- package/dist/config/facewear.d.ts +24 -0
- package/dist/config/facewear.d.ts.map +1 -0
- package/dist/config/facewear.js +35 -0
- package/dist/config/facewear.js.map +1 -0
- package/dist/config/learn-links.d.ts +70 -0
- package/dist/config/learn-links.d.ts.map +1 -0
- package/dist/config/learn-links.js +171 -0
- package/dist/config/learn-links.js.map +1 -0
- package/dist/config/product-links.d.ts +44 -0
- package/dist/config/product-links.d.ts.map +1 -0
- package/dist/config/product-links.js +44 -0
- package/dist/config/product-links.js.map +1 -0
- package/dist/constants/index.d.ts +14 -1
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +38 -22
- package/dist/constants/index.js.map +1 -1
- package/dist/data/character_colors/race_specific/hair_colors.json +1 -1
- package/dist/data/character_colors/race_specific/skin_colors.json +1 -1
- package/dist/data/dyes.json +1127 -0
- package/dist/data/facewear_colors.json +57 -0
- package/dist/data/locales/de.json +4 -50
- package/dist/data/locales/en.json +4 -50
- package/dist/data/locales/fr.json +4 -50
- package/dist/data/locales/ja.json +4 -50
- package/dist/data/locales/ko.json +4 -50
- package/dist/data/locales/zh.json +4 -50
- package/dist/data/presets.json +59 -301
- package/dist/index.d.ts +156 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +114 -10
- package/dist/index.js.map +1 -1
- package/dist/services/APIService.d.ts +39 -62
- package/dist/services/APIService.d.ts.map +1 -1
- package/dist/services/APIService.js +156 -150
- package/dist/services/APIService.js.map +1 -1
- package/dist/services/CharacterColorService.d.ts +4 -36
- package/dist/services/CharacterColorService.d.ts.map +1 -1
- package/dist/services/CharacterColorService.js +57 -79
- package/dist/services/CharacterColorService.js.map +1 -1
- package/dist/services/ColorService.d.ts +57 -68
- package/dist/services/ColorService.d.ts.map +1 -1
- package/dist/services/ColorService.js +86 -94
- package/dist/services/ColorService.js.map +1 -1
- package/dist/services/DyeService.d.ts +11 -104
- package/dist/services/DyeService.d.ts.map +1 -1
- package/dist/services/DyeService.js +19 -157
- package/dist/services/DyeService.js.map +1 -1
- package/dist/services/LocalizationService.d.ts +48 -59
- package/dist/services/LocalizationService.d.ts.map +1 -1
- package/dist/services/LocalizationService.js +86 -95
- package/dist/services/LocalizationService.js.map +1 -1
- package/dist/services/PaletteService.d.ts +8 -9
- package/dist/services/PaletteService.d.ts.map +1 -1
- package/dist/services/PaletteService.js +10 -22
- package/dist/services/PaletteService.js.map +1 -1
- package/dist/services/PresetService.d.ts +2 -34
- package/dist/services/PresetService.d.ts.map +1 -1
- package/dist/services/PresetService.js +12 -59
- package/dist/services/PresetService.js.map +1 -1
- package/dist/services/chara/chara-models.d.ts +68 -0
- package/dist/services/chara/chara-models.d.ts.map +1 -0
- package/dist/services/chara/chara-models.js +87 -0
- package/dist/services/chara/chara-models.js.map +1 -0
- package/dist/services/chara/chara-parser.d.ts +95 -0
- package/dist/services/chara/chara-parser.d.ts.map +1 -0
- package/dist/services/chara/chara-parser.js +299 -0
- package/dist/services/chara/chara-parser.js.map +1 -0
- package/dist/services/chara/chara-resolver.d.ts +103 -0
- package/dist/services/chara/chara-resolver.d.ts.map +1 -0
- package/dist/services/chara/chara-resolver.js +233 -0
- package/dist/services/chara/chara-resolver.js.map +1 -0
- package/dist/services/color/ColorConverter.d.ts +112 -35
- package/dist/services/color/ColorConverter.d.ts.map +1 -1
- package/dist/services/color/ColorConverter.js +205 -89
- package/dist/services/color/ColorConverter.js.map +1 -1
- package/dist/services/color/ColorManipulator.d.ts +11 -0
- package/dist/services/color/ColorManipulator.d.ts.map +1 -1
- package/dist/services/color/ColorManipulator.js +24 -9
- package/dist/services/color/ColorManipulator.js.map +1 -1
- package/dist/services/color/ColorblindnessSimulator.d.ts +17 -0
- package/dist/services/color/ColorblindnessSimulator.d.ts.map +1 -1
- package/dist/services/color/ColorblindnessSimulator.js +57 -3
- package/dist/services/color/ColorblindnessSimulator.js.map +1 -1
- package/dist/services/color/SpectralMixer.d.ts +0 -34
- package/dist/services/color/SpectralMixer.d.ts.map +1 -1
- package/dist/services/color/SpectralMixer.js +0 -73
- package/dist/services/color/SpectralMixer.js.map +1 -1
- package/dist/services/dye/DyeDatabase.d.ts +5 -21
- package/dist/services/dye/DyeDatabase.d.ts.map +1 -1
- package/dist/services/dye/DyeDatabase.js +98 -130
- package/dist/services/dye/DyeDatabase.js.map +1 -1
- package/dist/services/dye/DyeSearch.d.ts +17 -31
- package/dist/services/dye/DyeSearch.d.ts.map +1 -1
- package/dist/services/dye/DyeSearch.js +45 -141
- package/dist/services/dye/DyeSearch.js.map +1 -1
- package/dist/services/dye/HarmonyGenerator.d.ts +11 -18
- package/dist/services/dye/HarmonyGenerator.d.ts.map +1 -1
- package/dist/services/dye/HarmonyGenerator.js +33 -38
- package/dist/services/dye/HarmonyGenerator.js.map +1 -1
- package/dist/services/localization/LocaleLoader.d.ts.map +1 -1
- package/dist/services/localization/LocaleLoader.js +0 -1
- package/dist/services/localization/LocaleLoader.js.map +1 -1
- package/dist/services/localization/TranslationProvider.d.ts +1 -42
- package/dist/services/localization/TranslationProvider.d.ts.map +1 -1
- package/dist/services/localization/TranslationProvider.js +4 -82
- package/dist/services/localization/TranslationProvider.js.map +1 -1
- package/dist/types/index.d.ts +39 -52
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +50 -10
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +36 -123
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +54 -413
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/kd-tree.d.ts +0 -4
- package/dist/utils/kd-tree.d.ts.map +1 -1
- package/dist/utils/kd-tree.js +0 -6
- package/dist/utils/kd-tree.js.map +1 -1
- package/package.json +24 -15
- package/dist/data/character_colors/index.json +0 -40
- package/dist/data/colors_xiv.json +0 -3538
- package/dist/version.d.ts +0 -11
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js +0 -11
- package/dist/version.js.map +0 -1
|
@@ -116,17 +116,6 @@ export class PresetService {
|
|
|
116
116
|
getPreset(id) {
|
|
117
117
|
return this.presetById.get(id);
|
|
118
118
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Get preset count by category
|
|
121
|
-
* @returns Map of category to preset count
|
|
122
|
-
*/
|
|
123
|
-
getPresetCountByCategory() {
|
|
124
|
-
const counts = new Map();
|
|
125
|
-
for (const preset of this.data.palettes) {
|
|
126
|
-
counts.set(preset.category, (counts.get(preset.category) ?? 0) + 1);
|
|
127
|
-
}
|
|
128
|
-
return counts;
|
|
129
|
-
}
|
|
130
119
|
// ============================================================================
|
|
131
120
|
// Search Operations
|
|
132
121
|
// ============================================================================
|
|
@@ -146,23 +135,22 @@ export class PresetService {
|
|
|
146
135
|
* // Returns: Paladin, Warrior, Dark Knight, Gunbreaker
|
|
147
136
|
* ```
|
|
148
137
|
*/
|
|
149
|
-
searchPresets(query) {
|
|
138
|
+
searchPresets(query, dyeService) {
|
|
150
139
|
const lowerQuery = query.toLowerCase().trim();
|
|
151
140
|
if (!lowerQuery) {
|
|
152
141
|
return [];
|
|
153
142
|
}
|
|
143
|
+
// With a dye service, a palette also matches on the names of the dyes it
|
|
144
|
+
// contains — "search presets, dyes, tags" is only true if dyes count.
|
|
145
|
+
const matchesDye = (p) => {
|
|
146
|
+
if (!dyeService)
|
|
147
|
+
return false;
|
|
148
|
+
return p.dyes.some((stainId) => dyeService.getByStainId(stainId)?.name.toLowerCase().includes(lowerQuery));
|
|
149
|
+
};
|
|
154
150
|
return this.data.palettes.filter((p) => p.name.toLowerCase().includes(lowerQuery) ||
|
|
155
151
|
p.description.toLowerCase().includes(lowerQuery) ||
|
|
156
|
-
p.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Search presets by tag (exact match)
|
|
160
|
-
* @param tag - Tag to search for (case-insensitive)
|
|
161
|
-
* @returns Array of presets with that tag
|
|
162
|
-
*/
|
|
163
|
-
getPresetsByTag(tag) {
|
|
164
|
-
const lowerTag = tag.toLowerCase().trim();
|
|
165
|
-
return this.data.palettes.filter((p) => p.tags.some((t) => t.toLowerCase() === lowerTag));
|
|
152
|
+
p.tags.some((tag) => tag.toLowerCase().includes(lowerQuery)) ||
|
|
153
|
+
matchesDye(p));
|
|
166
154
|
}
|
|
167
155
|
// ============================================================================
|
|
168
156
|
// Random Selection
|
|
@@ -220,44 +208,9 @@ export class PresetService {
|
|
|
220
208
|
}
|
|
221
209
|
return {
|
|
222
210
|
...preset,
|
|
223
|
-
|
|
211
|
+
// 5.0: presets.json 2.0.0 stores stainIDs (never derived from ranges)
|
|
212
|
+
resolvedDyes: preset.dyes.map((stainId) => dyeService.getByStainId(stainId)),
|
|
224
213
|
};
|
|
225
214
|
}
|
|
226
|
-
/**
|
|
227
|
-
* Resolve multiple presets with their Dye objects
|
|
228
|
-
* @param presets - Array of presets to resolve
|
|
229
|
-
* @param dyeService - DyeService instance for resolving dye IDs
|
|
230
|
-
* @returns Array of resolved presets
|
|
231
|
-
*/
|
|
232
|
-
resolvePresets(presets, dyeService) {
|
|
233
|
-
return presets.map((preset) => ({
|
|
234
|
-
...preset,
|
|
235
|
-
resolvedDyes: preset.dyes.map((dyeId) => dyeService.getDyeById(dyeId)),
|
|
236
|
-
}));
|
|
237
|
-
}
|
|
238
|
-
// ============================================================================
|
|
239
|
-
// Metadata
|
|
240
|
-
// ============================================================================
|
|
241
|
-
/**
|
|
242
|
-
* Get data version
|
|
243
|
-
* @returns Version string from preset data
|
|
244
|
-
*/
|
|
245
|
-
getVersion() {
|
|
246
|
-
return this.data.version;
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* Get last update timestamp
|
|
250
|
-
* @returns ISO date string of last update
|
|
251
|
-
*/
|
|
252
|
-
getLastUpdated() {
|
|
253
|
-
return this.data.lastUpdated;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Get total number of presets
|
|
257
|
-
* @returns Total preset count
|
|
258
|
-
*/
|
|
259
|
-
getPresetCount() {
|
|
260
|
-
return this.data.palettes.length;
|
|
261
|
-
}
|
|
262
215
|
}
|
|
263
216
|
//# sourceMappingURL=PresetService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PresetService.js","sourceRoot":"","sources":["../../src/services/PresetService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"PresetService.js","sourceRoot":"","sources":["../../src/services/PresetService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.chara` equipment identity — the model keys a character file carries and
|
|
3
|
+
* how they pack into the Item sheet's `ModelMain` / `ModelSub` values.
|
|
4
|
+
*
|
|
5
|
+
* Measured rules (docs/research/chara-equipment-resolution, 47-file corpus,
|
|
6
|
+
* resolved live against XIVAPI v2 — 273/273 gear keys, 41/41 weapons):
|
|
7
|
+
* - The Item sheet stores a model reference as one `uint64`, four
|
|
8
|
+
* little-endian 16-bit lanes (SaintCoinach `Quad`). The `.chara` fields are
|
|
9
|
+
* those lanes: armour/accessories `ModelMain = base | variant << 16`,
|
|
10
|
+
* weapons `ModelMain = set | base << 16 | variant << 32`.
|
|
11
|
+
* - The slot is a mandatory second key: one gear *set* shares a `ModelMain`
|
|
12
|
+
* across head/body/hands/legs/feet, so a search must also filter on the
|
|
13
|
+
* `EquipSlotCategory` boolean column (rings: `FingerL` / `FingerR`).
|
|
14
|
+
* - `ModelBase == 0` (weapons: `ModelSet == 0` too) means the slot is empty.
|
|
15
|
+
* - Off-hands resolve THROUGH the main hand — see the resolver on api-worker.
|
|
16
|
+
*
|
|
17
|
+
* Nothing here touches the network; these are the pure packing helpers the
|
|
18
|
+
* parser, the api-worker resolver and the web-app client all share.
|
|
19
|
+
*/
|
|
20
|
+
import type { CharaGearSlotId } from './chara-parser.js';
|
|
21
|
+
/** A worn piece's model identity, as the `.chara` file spells it. */
|
|
22
|
+
export interface CharaGearModel {
|
|
23
|
+
slot: CharaGearSlotId;
|
|
24
|
+
/** Weapon slots only — the `w0634` set number. Absent on armour/accessories. */
|
|
25
|
+
set?: number;
|
|
26
|
+
/** Armour: the `e0361` set. Weapons: the `b0019` body. */
|
|
27
|
+
base: number;
|
|
28
|
+
/** Material variant */
|
|
29
|
+
variant: number;
|
|
30
|
+
}
|
|
31
|
+
/** The two slots whose model is a weapon triple rather than a gear pair. */
|
|
32
|
+
export declare const CHARA_WEAPON_SLOTS: readonly CharaGearSlotId[];
|
|
33
|
+
export declare function isCharaWeaponSlot(slot: CharaGearSlotId): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* `.chara` slot → `EquipSlotCategory` boolean column. This is the mandatory
|
|
36
|
+
* second search key: `+EquipSlotCategory.<field>=1`.
|
|
37
|
+
*/
|
|
38
|
+
export declare const CHARA_SLOT_SEARCH_FIELD: Record<CharaGearSlotId, string>;
|
|
39
|
+
/**
|
|
40
|
+
* Armour / accessory `ModelMain`: `base | variant << 16`. Computed with
|
|
41
|
+
* arithmetic rather than `<<` so a variant above 0x7FFF cannot overflow the
|
|
42
|
+
* signed 32-bit shift — the value is an unsigned 32-bit lane pair.
|
|
43
|
+
*
|
|
44
|
+
* Beech Mask of Casting: `gearModelKey(361, 5) === 328041` (Item#18085).
|
|
45
|
+
*/
|
|
46
|
+
export declare function gearModelKey(base: number, variant: number): number;
|
|
47
|
+
/**
|
|
48
|
+
* Weapon `ModelMain`: `set | base << 16 | variant << 32`. Exceeds 2^32, so it
|
|
49
|
+
* is a BigInt — serialise with `String()` for JSON / cache keys.
|
|
50
|
+
*
|
|
51
|
+
* Runaway Bow: `weaponModelKey(634, 19, 1) === 4296213114n` (Item#49486);
|
|
52
|
+
* its quiver `{698, 149, 1}` is that item's `ModelSub`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function weaponModelKey(set: number, base: number, variant: number): bigint;
|
|
55
|
+
/**
|
|
56
|
+
* The packed key as a decimal string — the form used on the wire and in
|
|
57
|
+
* cache keys (weapon values do not fit a JS number exactly past 2^53 only in
|
|
58
|
+
* theory, but a BigInt never round-trips JSON, so everything is a string).
|
|
59
|
+
*/
|
|
60
|
+
export declare function charaModelKey(model: CharaGearModel): string;
|
|
61
|
+
/**
|
|
62
|
+
* The human label for a model with no Item row: `set·base·variant` for a
|
|
63
|
+
* weapon, `base·variant` otherwise (the design's "MODEL 9903·1").
|
|
64
|
+
*/
|
|
65
|
+
export declare function formatCharaModelLabel(model: CharaGearModel): string;
|
|
66
|
+
/** True when the record describes a worn piece rather than an empty slot. */
|
|
67
|
+
export declare function isWornCharaModel(slot: CharaGearSlotId, set: number, base: number): boolean;
|
|
68
|
+
//# sourceMappingURL=chara-models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chara-models.d.ts","sourceRoot":"","sources":["../../../src/services/chara/chara-models.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,eAAe,CAAC;IACtB,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,EAAE,SAAS,eAAe,EAA4B,CAAC;AAEtF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAEhE;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAanE,CAAC;AAIF;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAI3D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAInE;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,OAAO,CAET"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.chara` equipment identity — the model keys a character file carries and
|
|
3
|
+
* how they pack into the Item sheet's `ModelMain` / `ModelSub` values.
|
|
4
|
+
*
|
|
5
|
+
* Measured rules (docs/research/chara-equipment-resolution, 47-file corpus,
|
|
6
|
+
* resolved live against XIVAPI v2 — 273/273 gear keys, 41/41 weapons):
|
|
7
|
+
* - The Item sheet stores a model reference as one `uint64`, four
|
|
8
|
+
* little-endian 16-bit lanes (SaintCoinach `Quad`). The `.chara` fields are
|
|
9
|
+
* those lanes: armour/accessories `ModelMain = base | variant << 16`,
|
|
10
|
+
* weapons `ModelMain = set | base << 16 | variant << 32`.
|
|
11
|
+
* - The slot is a mandatory second key: one gear *set* shares a `ModelMain`
|
|
12
|
+
* across head/body/hands/legs/feet, so a search must also filter on the
|
|
13
|
+
* `EquipSlotCategory` boolean column (rings: `FingerL` / `FingerR`).
|
|
14
|
+
* - `ModelBase == 0` (weapons: `ModelSet == 0` too) means the slot is empty.
|
|
15
|
+
* - Off-hands resolve THROUGH the main hand — see the resolver on api-worker.
|
|
16
|
+
*
|
|
17
|
+
* Nothing here touches the network; these are the pure packing helpers the
|
|
18
|
+
* parser, the api-worker resolver and the web-app client all share.
|
|
19
|
+
*/
|
|
20
|
+
/** The two slots whose model is a weapon triple rather than a gear pair. */
|
|
21
|
+
export const CHARA_WEAPON_SLOTS = ['MainHand', 'OffHand'];
|
|
22
|
+
export function isCharaWeaponSlot(slot) {
|
|
23
|
+
return CHARA_WEAPON_SLOTS.includes(slot);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* `.chara` slot → `EquipSlotCategory` boolean column. This is the mandatory
|
|
27
|
+
* second search key: `+EquipSlotCategory.<field>=1`.
|
|
28
|
+
*/
|
|
29
|
+
export const CHARA_SLOT_SEARCH_FIELD = {
|
|
30
|
+
MainHand: 'MainHand',
|
|
31
|
+
OffHand: 'OffHand',
|
|
32
|
+
HeadGear: 'Head',
|
|
33
|
+
Body: 'Body',
|
|
34
|
+
Hands: 'Gloves',
|
|
35
|
+
Legs: 'Legs',
|
|
36
|
+
Feet: 'Feet',
|
|
37
|
+
Ears: 'Ears',
|
|
38
|
+
Neck: 'Neck',
|
|
39
|
+
Wrists: 'Wrists',
|
|
40
|
+
LeftRing: 'FingerL',
|
|
41
|
+
RightRing: 'FingerR',
|
|
42
|
+
};
|
|
43
|
+
const LANE = 65536;
|
|
44
|
+
/**
|
|
45
|
+
* Armour / accessory `ModelMain`: `base | variant << 16`. Computed with
|
|
46
|
+
* arithmetic rather than `<<` so a variant above 0x7FFF cannot overflow the
|
|
47
|
+
* signed 32-bit shift — the value is an unsigned 32-bit lane pair.
|
|
48
|
+
*
|
|
49
|
+
* Beech Mask of Casting: `gearModelKey(361, 5) === 328041` (Item#18085).
|
|
50
|
+
*/
|
|
51
|
+
export function gearModelKey(base, variant) {
|
|
52
|
+
return base + variant * LANE;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Weapon `ModelMain`: `set | base << 16 | variant << 32`. Exceeds 2^32, so it
|
|
56
|
+
* is a BigInt — serialise with `String()` for JSON / cache keys.
|
|
57
|
+
*
|
|
58
|
+
* Runaway Bow: `weaponModelKey(634, 19, 1) === 4296213114n` (Item#49486);
|
|
59
|
+
* its quiver `{698, 149, 1}` is that item's `ModelSub`.
|
|
60
|
+
*/
|
|
61
|
+
export function weaponModelKey(set, base, variant) {
|
|
62
|
+
return BigInt(set) + (BigInt(base) << 16n) + (BigInt(variant) << 32n);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The packed key as a decimal string — the form used on the wire and in
|
|
66
|
+
* cache keys (weapon values do not fit a JS number exactly past 2^53 only in
|
|
67
|
+
* theory, but a BigInt never round-trips JSON, so everything is a string).
|
|
68
|
+
*/
|
|
69
|
+
export function charaModelKey(model) {
|
|
70
|
+
return isCharaWeaponSlot(model.slot)
|
|
71
|
+
? String(weaponModelKey(model.set ?? 0, model.base, model.variant))
|
|
72
|
+
: String(gearModelKey(model.base, model.variant));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The human label for a model with no Item row: `set·base·variant` for a
|
|
76
|
+
* weapon, `base·variant` otherwise (the design's "MODEL 9903·1").
|
|
77
|
+
*/
|
|
78
|
+
export function formatCharaModelLabel(model) {
|
|
79
|
+
return isCharaWeaponSlot(model.slot)
|
|
80
|
+
? `${model.set ?? 0}·${model.base}·${model.variant}`
|
|
81
|
+
: `${model.base}·${model.variant}`;
|
|
82
|
+
}
|
|
83
|
+
/** True when the record describes a worn piece rather than an empty slot. */
|
|
84
|
+
export function isWornCharaModel(slot, set, base) {
|
|
85
|
+
return isCharaWeaponSlot(slot) ? set > 0 || base > 0 : base > 0;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=chara-models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chara-models.js","sourceRoot":"","sources":["../../../src/services/chara/chara-models.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAeH,4EAA4E;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAA+B,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;AAEtF,MAAM,UAAU,iBAAiB,CAAC,IAAqB;IACrD,OAAO,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAoC;IACtE,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,MAAM;IAChB,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,QAAQ;IACf,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,SAAS;IACnB,SAAS,EAAE,SAAS;CACrB,CAAC;AAEF,MAAM,IAAI,GAAG,KAAK,CAAC;AAEnB;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,OAAe;IACxD,OAAO,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC;AAC/B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,IAAY,EAAE,OAAe;IACvE,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAqB;IACjD,OAAO,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC;QAClC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACnE,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAqB;IACzD,OAAO,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC;QAClC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,EAAE;QACpD,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;AACvC,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,gBAAgB,CAC9B,IAAqB,EACrB,GAAW,EACX,IAAY;IAEZ,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.chara` character-file parser — the 5.0 Swatch Matcher import.
|
|
3
|
+
*
|
|
4
|
+
* Rules measured across 112 sample files (design register, Swatch Matcher
|
|
5
|
+
* 10A, confirmed):
|
|
6
|
+
* - **Parse by key presence, never the declared `TypeName`** — producers
|
|
7
|
+
* (Anamnesis versions, Ktisis) write different key sets. `TypeName` is
|
|
8
|
+
* captured only to *show* the producer.
|
|
9
|
+
* - **`REyeColor` holds the LEFT eye and `LEyeColor` the right** — crossed
|
|
10
|
+
* against the extended floats (`LeftEyeColor`/`RightEyeColor`); trust the
|
|
11
|
+
* extended naming. Never "fix" this by swapping — 16% of samples are
|
|
12
|
+
* heterochromia and a swap corrupts them silently.
|
|
13
|
+
* - **Extended floats are linear RGB** — gamma-encode before use or every
|
|
14
|
+
* colour is wrong-but-plausible.
|
|
15
|
+
* - **Flags gate live-looking data**: `EnableHighlights: false` inerts the
|
|
16
|
+
* highlight index (54% of samples, 47 of those with a live-looking index);
|
|
17
|
+
* `FacePaint: 0` inerts `FacePaintColor` (only 0 is load-bearing — values
|
|
18
|
+
* ≥128 exist, do not range-validate `FacePaint` itself).
|
|
19
|
+
* - **`LipsToneFurPattern` is a fur-pattern enum on Hrothgar**, not a colour.
|
|
20
|
+
* - **`MouthColor` alpha is a continuous opacity**: `0` = no lip; an absent
|
|
21
|
+
* key ≠ 0 (Ktisis omits it and the index stays valid).
|
|
22
|
+
* - **`IsExtendedAppearanceValid` is unreliable** (declared in 16 of 96
|
|
23
|
+
* float-bearing files): the floats count as live only when it is present
|
|
24
|
+
* and true — a missing flag means the index wins, and the UI says so.
|
|
25
|
+
* - **Gear dyes are stain IDs** (`DyeId`/`DyeId2` per slot, 0 = undyed; 35%
|
|
26
|
+
* of dyed channels are the second one).
|
|
27
|
+
* - **Gear models are emitted beside the dyes** (`gearModels`): the
|
|
28
|
+
* `ModelBase`/`ModelVariant` pair (weapons add `ModelSet`) of every WORN
|
|
29
|
+
* slot — `ModelBase == 0` (weapons: `ModelSet == 0` too) is an empty slot
|
|
30
|
+
* and is skipped. `null` hand records (one Anamnesis file) are empty.
|
|
31
|
+
* `Glasses` is `{ GlassesId }` or, on Brio-era Ktisis, a bare integer —
|
|
32
|
+
* both are accepted; 0 = no facewear. Resolution to item names happens
|
|
33
|
+
* off-device (api-worker) — the parser only carries the keys.
|
|
34
|
+
* - **Never read `Base64Image`.**
|
|
35
|
+
* - An unrecognised tribe/race/gender fails loudly (name got vs expected),
|
|
36
|
+
* never an empty palette.
|
|
37
|
+
*/
|
|
38
|
+
import type { Gender, Race, RGB, SubRace } from '@xivdyetools/types';
|
|
39
|
+
import { type CharaGearModel } from './chara-models.js';
|
|
40
|
+
/** Colour slots a `.chara` file can populate. */
|
|
41
|
+
export type CharaSlotId = 'leftEye' | 'rightEye' | 'hair' | 'highlights' | 'skin' | 'limbal' | 'lip' | 'facePaint';
|
|
42
|
+
/** Equipment slots that can carry dye channels. */
|
|
43
|
+
export type CharaGearSlotId = 'MainHand' | 'OffHand' | 'HeadGear' | 'Body' | 'Hands' | 'Legs' | 'Feet' | 'Ears' | 'Neck' | 'Wrists' | 'LeftRing' | 'RightRing';
|
|
44
|
+
export type CharaSlotInertReason = 'highlightsDisabled' | 'facePaintNone' | 'furPattern' | 'noLip';
|
|
45
|
+
export interface CharaColorSlotRaw {
|
|
46
|
+
slot: CharaSlotId;
|
|
47
|
+
/** Raw palette index; null = key absent from the file */
|
|
48
|
+
index: number | null;
|
|
49
|
+
/** False when a flag gates the index off (see inertReason) */
|
|
50
|
+
indexActive: boolean;
|
|
51
|
+
inertReason?: CharaSlotInertReason;
|
|
52
|
+
/** Extended float colour, gamma-encoded to sRGB; null = key absent */
|
|
53
|
+
float: RGB | null;
|
|
54
|
+
/** The raw linear-RGB float triple as stored in the file */
|
|
55
|
+
floatLinear: [number, number, number] | null;
|
|
56
|
+
/** Lip only: continuous opacity. null = key absent (absent ≠ 0) */
|
|
57
|
+
alpha: number | null;
|
|
58
|
+
}
|
|
59
|
+
export interface CharaGearDye {
|
|
60
|
+
slot: CharaGearSlotId;
|
|
61
|
+
/** Which dye channel (1 = DyeId, 2 = DyeId2) */
|
|
62
|
+
channel: 1 | 2;
|
|
63
|
+
/** Stain ID as stored (1-254); 0/undyed channels are not emitted */
|
|
64
|
+
stainId: number;
|
|
65
|
+
}
|
|
66
|
+
export interface ParsedCharaFile {
|
|
67
|
+
/** Declared producer (`TypeName`), shown in UI — never used for parsing */
|
|
68
|
+
producer: string | null;
|
|
69
|
+
race: Race | null;
|
|
70
|
+
tribe: SubRace | null;
|
|
71
|
+
/** The tribe string exactly as the file spelled it */
|
|
72
|
+
tribeRaw: string | null;
|
|
73
|
+
gender: Gender | null;
|
|
74
|
+
/** Ktisis nickname — the default name for exported palettes */
|
|
75
|
+
nickname: string | null;
|
|
76
|
+
/** True only when IsExtendedAppearanceValid is present AND true */
|
|
77
|
+
extendedValid: boolean;
|
|
78
|
+
/** Whether the IsExtendedAppearanceValid key was present at all */
|
|
79
|
+
extendedDeclared: boolean;
|
|
80
|
+
slots: CharaColorSlotRaw[];
|
|
81
|
+
/** Dyed gear channels only (stainId > 0), in file slot order */
|
|
82
|
+
gearDyes: CharaGearDye[];
|
|
83
|
+
/** Worn pieces only (model base > 0), in file slot order — undyed pieces included */
|
|
84
|
+
gearModels: CharaGearModel[];
|
|
85
|
+
/** Facewear `Glasses` sheet row; null when none / absent */
|
|
86
|
+
glassesId: number | null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Parse a `.chara` file's text content. Structural problems (invalid JSON,
|
|
90
|
+
* unrecognised tribe/race/gender, malformed colour values) throw AppError
|
|
91
|
+
* naming field and value; per-slot range problems are left to the resolver,
|
|
92
|
+
* which reports them as loud slot states.
|
|
93
|
+
*/
|
|
94
|
+
export declare function parseCharaFile(text: string): ParsedCharaFile;
|
|
95
|
+
//# sourceMappingURL=chara-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chara-parser.d.ts","sourceRoot":"","sources":["../../../src/services/chara/chara-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAGrE,OAAO,EAAuC,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE7F,iDAAiD;AACjD,MAAM,MAAM,WAAW,GACrB,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,WAAW,CAAC;AAE3F,mDAAmD;AACnD,MAAM,MAAM,eAAe,GACvB,UAAU,GACV,SAAS,GACT,UAAU,GACV,MAAM,GACN,OAAO,GACP,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,QAAQ,GACR,UAAU,GACV,WAAW,CAAC;AAEhB,MAAM,MAAM,oBAAoB,GAAG,oBAAoB,GAAG,eAAe,GAAG,YAAY,GAAG,OAAO,CAAC;AAEnG,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,yDAAyD;IACzD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,8DAA8D;IAC9D,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC,sEAAsE;IACtE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAClB,4DAA4D;IAC5D,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7C,mEAAmE;IACnE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,eAAe,CAAC;IACtB,gDAAgD;IAChD,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;IACf,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACtB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,mEAAmE;IACnE,aAAa,EAAE,OAAO,CAAC;IACvB,mEAAmE;IACnE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,qFAAqF;IACrF,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAuKD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAiI5D"}
|