tsacnhsaves 0.1.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/LICENSE +674 -0
- package/README.md +37 -0
- package/dist/encryption/aes-ctr.d.ts +14 -0
- package/dist/encryption/aes-ctr.d.ts.map +1 -0
- package/dist/encryption/aes-ctr.js +28 -0
- package/dist/encryption/aes-ctr.js.map +1 -0
- package/dist/encryption/encrypted-int32.d.ts +18 -0
- package/dist/encryption/encrypted-int32.d.ts.map +1 -0
- package/dist/encryption/encrypted-int32.js +50 -0
- package/dist/encryption/encrypted-int32.js.map +1 -0
- package/dist/encryption/encrypted-int32.test.d.ts +2 -0
- package/dist/encryption/encrypted-int32.test.d.ts.map +1 -0
- package/dist/encryption/encrypted-int32.test.js +45 -0
- package/dist/encryption/encrypted-int32.test.js.map +1 -0
- package/dist/encryption/encryption.d.ts +23 -0
- package/dist/encryption/encryption.d.ts.map +1 -0
- package/dist/encryption/encryption.js +71 -0
- package/dist/encryption/encryption.js.map +1 -0
- package/dist/encryption/index.d.ts +6 -0
- package/dist/encryption/index.d.ts.map +1 -0
- package/dist/encryption/index.js +4 -0
- package/dist/encryption/index.js.map +1 -0
- package/dist/encryption/xor-shift-128.d.ts +17 -0
- package/dist/encryption/xor-shift-128.d.ts.map +1 -0
- package/dist/encryption/xor-shift-128.js +37 -0
- package/dist/encryption/xor-shift-128.js.map +1 -0
- package/dist/encryption/xor-shift-128.test.d.ts +2 -0
- package/dist/encryption/xor-shift-128.test.d.ts.map +1 -0
- package/dist/encryption/xor-shift-128.test.js +53 -0
- package/dist/encryption/xor-shift-128.test.js.map +1 -0
- package/dist/hashing/file-hash-info.d.ts +14 -0
- package/dist/hashing/file-hash-info.d.ts.map +1 -0
- package/dist/hashing/file-hash-info.js +7 -0
- package/dist/hashing/file-hash-info.js.map +1 -0
- package/dist/hashing/file-hash-region.d.ts +14 -0
- package/dist/hashing/file-hash-region.d.ts.map +1 -0
- package/dist/hashing/file-hash-region.js +12 -0
- package/dist/hashing/file-hash-region.js.map +1 -0
- package/dist/hashing/file-hash-revision.d.ts +19 -0
- package/dist/hashing/file-hash-revision.d.ts.map +1 -0
- package/dist/hashing/file-hash-revision.js +391 -0
- package/dist/hashing/file-hash-revision.js.map +1 -0
- package/dist/hashing/index.d.ts +6 -0
- package/dist/hashing/index.d.ts.map +1 -0
- package/dist/hashing/index.js +4 -0
- package/dist/hashing/index.js.map +1 -0
- package/dist/hashing/murmur3.d.ts +21 -0
- package/dist/hashing/murmur3.d.ts.map +1 -0
- package/dist/hashing/murmur3.js +68 -0
- package/dist/hashing/murmur3.js.map +1 -0
- package/dist/hashing/murmur3.test.d.ts +2 -0
- package/dist/hashing/murmur3.test.d.ts.map +1 -0
- package/dist/hashing/murmur3.test.js +55 -0
- package/dist/hashing/murmur3.test.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/save/index.d.ts +2 -0
- package/dist/save/index.d.ts.map +1 -0
- package/dist/save/index.js +2 -0
- package/dist/save/index.js.map +1 -0
- package/dist/save/meta/encrypted-file-pair.d.ts +23 -0
- package/dist/save/meta/encrypted-file-pair.d.ts.map +1 -0
- package/dist/save/meta/encrypted-file-pair.js +51 -0
- package/dist/save/meta/encrypted-file-pair.js.map +1 -0
- package/dist/save/meta/file-header-info.d.ts +15 -0
- package/dist/save/meta/file-header-info.d.ts.map +1 -0
- package/dist/save/meta/file-header-info.js +24 -0
- package/dist/save/meta/file-header-info.js.map +1 -0
- package/dist/save/meta/horizon-save.d.ts +64 -0
- package/dist/save/meta/horizon-save.d.ts.map +1 -0
- package/dist/save/meta/horizon-save.js +126 -0
- package/dist/save/meta/horizon-save.js.map +1 -0
- package/dist/save/meta/horizon-save.test.d.ts +2 -0
- package/dist/save/meta/horizon-save.test.d.ts.map +1 -0
- package/dist/save/meta/horizon-save.test.js +86 -0
- package/dist/save/meta/horizon-save.test.js.map +1 -0
- package/dist/save/meta/index.d.ts +8 -0
- package/dist/save/meta/index.d.ts.map +1 -0
- package/dist/save/meta/index.js +4 -0
- package/dist/save/meta/index.js.map +1 -0
- package/dist/save/meta/revision-checker.d.ts +20 -0
- package/dist/save/meta/revision-checker.d.ts.map +1 -0
- package/dist/save/meta/revision-checker.js +152 -0
- package/dist/save/meta/revision-checker.js.map +1 -0
- package/dist/save/offsets/index.d.ts +4 -0
- package/dist/save/offsets/index.d.ts.map +1 -0
- package/dist/save/offsets/index.js +2 -0
- package/dist/save/offsets/index.js.map +1 -0
- package/dist/save/offsets/main-offsets.d.ts +50 -0
- package/dist/save/offsets/main-offsets.d.ts.map +1 -0
- package/dist/save/offsets/main-offsets.js +401 -0
- package/dist/save/offsets/main-offsets.js.map +1 -0
- package/dist/save/offsets/personal-offsets.d.ts +33 -0
- package/dist/save/offsets/personal-offsets.d.ts.map +1 -0
- package/dist/save/offsets/personal-offsets.js +259 -0
- package/dist/save/offsets/personal-offsets.js.map +1 -0
- package/dist/structures/achievements.d.ts +36 -0
- package/dist/structures/achievements.d.ts.map +1 -0
- package/dist/structures/achievements.js +223 -0
- package/dist/structures/achievements.js.map +1 -0
- package/dist/structures/building.d.ts +17 -0
- package/dist/structures/building.d.ts.map +1 -0
- package/dist/structures/building.js +25 -0
- package/dist/structures/building.js.map +1 -0
- package/dist/structures/catalog.d.ts +44 -0
- package/dist/structures/catalog.d.ts.map +1 -0
- package/dist/structures/catalog.js +86 -0
- package/dist/structures/catalog.js.map +1 -0
- package/dist/structures/date-time.d.ts +30 -0
- package/dist/structures/date-time.d.ts.map +1 -0
- package/dist/structures/date-time.js +42 -0
- package/dist/structures/date-time.js.map +1 -0
- package/dist/structures/enums.d.ts +126 -0
- package/dist/structures/enums.d.ts.map +1 -0
- package/dist/structures/enums.js +131 -0
- package/dist/structures/enums.js.map +1 -0
- package/dist/structures/index.d.ts +20 -0
- package/dist/structures/index.d.ts.map +1 -0
- package/dist/structures/index.js +11 -0
- package/dist/structures/index.js.map +1 -0
- package/dist/structures/item.d.ts +20 -0
- package/dist/structures/item.d.ts.map +1 -0
- package/dist/structures/item.js +38 -0
- package/dist/structures/item.js.map +1 -0
- package/dist/structures/museum.d.ts +15 -0
- package/dist/structures/museum.d.ts.map +1 -0
- package/dist/structures/museum.js +27 -0
- package/dist/structures/museum.js.map +1 -0
- package/dist/structures/reactions.d.ts +31 -0
- package/dist/structures/reactions.d.ts.map +1 -0
- package/dist/structures/reactions.js +65 -0
- package/dist/structures/reactions.js.map +1 -0
- package/dist/structures/recipe-book.d.ts +19 -0
- package/dist/structures/recipe-book.d.ts.map +1 -0
- package/dist/structures/recipe-book.js +41 -0
- package/dist/structures/recipe-book.js.map +1 -0
- package/dist/structures/turnips.d.ts +34 -0
- package/dist/structures/turnips.d.ts.map +1 -0
- package/dist/structures/turnips.js +37 -0
- package/dist/structures/turnips.js.map +1 -0
- package/dist/structures/villager.d.ts +49 -0
- package/dist/structures/villager.d.ts.map +1 -0
- package/dist/structures/villager.js +116 -0
- package/dist/structures/villager.js.map +1 -0
- package/dist/util/binary.d.ts +8 -0
- package/dist/util/binary.d.ts.map +1 -0
- package/dist/util/binary.js +29 -0
- package/dist/util/binary.js.map +1 -0
- package/dist/util/flags.d.ts +6 -0
- package/dist/util/flags.d.ts.map +1 -0
- package/dist/util/flags.js +14 -0
- package/dist/util/flags.js.map +1 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +2 -0
- package/dist/util/index.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactions.d.ts","sourceRoot":"","sources":["../../src/structures/reactions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,4CAA4C;AAC5C,eAAO,MAAM,UAAU,MAAO,CAAC;AAC/B,4CAA4C;AAC5C,eAAO,MAAM,YAAY,MAAQ,CAAC;AAElC,MAAM,WAAW,YAAY;IAC5B,gCAAgC;IAChC,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,6CAA6C;IAC7C,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,+DAA+D;IAC/D,QAAQ,EAAE,OAAO,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAiB9E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAiB5E;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,GACnB,YAAY,CAMd;AAED,iDAAiD;AACjD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,CAM1E"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reaction wheel / learned reactions reader.
|
|
3
|
+
* Ported from NHSE.Core GSavePlayerManpu / GSavePlayerManpu15
|
|
4
|
+
*/
|
|
5
|
+
import { readU8 } from '../util/binary.js';
|
|
6
|
+
import { Reaction } from './enums.js';
|
|
7
|
+
/** GSavePlayerManpu (1.0-1.4): 64 slots. */
|
|
8
|
+
export const MANPU_SIZE = 0x88;
|
|
9
|
+
/** GSavePlayerManpu15 (1.5+): 256 slots. */
|
|
10
|
+
export const MANPU15_SIZE = 0x208;
|
|
11
|
+
/**
|
|
12
|
+
* Read reactions for format 1.5+ (256 slots).
|
|
13
|
+
*/
|
|
14
|
+
export function readReactions15(data, offset) {
|
|
15
|
+
const learned = [];
|
|
16
|
+
for (let i = 0; i < 256; i++) {
|
|
17
|
+
learned.push(readU8(data, offset + i));
|
|
18
|
+
}
|
|
19
|
+
const wheel = [];
|
|
20
|
+
for (let i = 0; i < 8; i++) {
|
|
21
|
+
wheel.push(readU8(data, offset + 256 + i));
|
|
22
|
+
}
|
|
23
|
+
const newFlags = [];
|
|
24
|
+
for (let i = 0; i < 256; i++) {
|
|
25
|
+
newFlags.push(readU8(data, offset + 256 + 8 + i) !== 0);
|
|
26
|
+
}
|
|
27
|
+
return { learned, wheel, newFlags };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read reactions for format 1.0-1.4 (64 slots).
|
|
31
|
+
*/
|
|
32
|
+
export function readReactions(data, offset) {
|
|
33
|
+
const learned = [];
|
|
34
|
+
for (let i = 0; i < 64; i++) {
|
|
35
|
+
learned.push(readU8(data, offset + i));
|
|
36
|
+
}
|
|
37
|
+
const wheel = [];
|
|
38
|
+
for (let i = 0; i < 8; i++) {
|
|
39
|
+
wheel.push(readU8(data, offset + 64 + i));
|
|
40
|
+
}
|
|
41
|
+
const newFlags = [];
|
|
42
|
+
for (let i = 0; i < 64; i++) {
|
|
43
|
+
newFlags.push(readU8(data, offset + 64 + 8 + i) !== 0);
|
|
44
|
+
}
|
|
45
|
+
return { learned, wheel, newFlags };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Read reactions based on revision index.
|
|
49
|
+
*/
|
|
50
|
+
export function readReactionsForRevision(data, offset, revisionIndex) {
|
|
51
|
+
// GSavePlayerManpu15 starts at revision 13 (1.5.0)
|
|
52
|
+
if (revisionIndex >= 13) {
|
|
53
|
+
return readReactions15(data, offset);
|
|
54
|
+
}
|
|
55
|
+
return readReactions(data, offset);
|
|
56
|
+
}
|
|
57
|
+
/** Get the set of non-None learned reactions. */
|
|
58
|
+
export function getLearnedReactions(reactions) {
|
|
59
|
+
const set = new Set();
|
|
60
|
+
for (const r of reactions.learned) {
|
|
61
|
+
if (r !== Reaction.None)
|
|
62
|
+
set.add(r);
|
|
63
|
+
}
|
|
64
|
+
return set;
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactions.js","sourceRoot":"","sources":["../../src/structures/reactions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recipe book data (DIY recipes).
|
|
3
|
+
* Ported from NHSE.Core
|
|
4
|
+
*/
|
|
5
|
+
export declare const RECIPE_BOOK_SIZE: number;
|
|
6
|
+
export declare const RECIPE_COUNT: number;
|
|
7
|
+
export interface RecipeBookData {
|
|
8
|
+
/** Raw recipe book bytes for flag queries. */
|
|
9
|
+
raw: Uint8Array;
|
|
10
|
+
}
|
|
11
|
+
export declare function readRecipeBook(data: Uint8Array, offset: number): RecipeBookData;
|
|
12
|
+
export declare function isRecipeKnown(book: RecipeBookData, recipe: number): boolean;
|
|
13
|
+
export declare function isRecipeMade(book: RecipeBookData, recipe: number): boolean;
|
|
14
|
+
export declare function isRecipeNew(book: RecipeBookData, recipe: number): boolean;
|
|
15
|
+
export declare function isRecipeFavorite(book: RecipeBookData, recipe: number): boolean;
|
|
16
|
+
/** Returns a set of recipe indices that are known. */
|
|
17
|
+
export declare function getKnownRecipes(book: RecipeBookData, maxRecipeId: number): Set<number>;
|
|
18
|
+
/** Returns a set of recipe indices that have been crafted. */
|
|
19
|
+
export declare function getCraftedRecipes(book: RecipeBookData, maxRecipeId: number): Set<number>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-book.d.ts","sourceRoot":"","sources":["../../src/structures/recipe-book.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,eAAO,MAAM,gBAAgB,QAA0B,CAAC;AACxD,eAAO,MAAM,YAAY,QAA0B,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC9B,8CAA8C;IAC9C,GAAG,EAAE,UAAU,CAAC;CAChB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAE/E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE3E;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAEzE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAMtF;AAED,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAMxF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recipe book data (DIY recipes).
|
|
3
|
+
* Ported from NHSE.Core
|
|
4
|
+
*/
|
|
5
|
+
import { getFlag } from '../util/flags.js';
|
|
6
|
+
const BIT_FLAG_ARRAY_SIZE = 0x100;
|
|
7
|
+
export const RECIPE_BOOK_SIZE = BIT_FLAG_ARRAY_SIZE * 4; // 0x400
|
|
8
|
+
export const RECIPE_COUNT = BIT_FLAG_ARRAY_SIZE * 8; // 2048
|
|
9
|
+
export function readRecipeBook(data, offset) {
|
|
10
|
+
return { raw: data.slice(offset, offset + RECIPE_BOOK_SIZE) };
|
|
11
|
+
}
|
|
12
|
+
export function isRecipeKnown(book, recipe) {
|
|
13
|
+
return getFlag(book.raw, 0, recipe);
|
|
14
|
+
}
|
|
15
|
+
export function isRecipeMade(book, recipe) {
|
|
16
|
+
return getFlag(book.raw, BIT_FLAG_ARRAY_SIZE, recipe);
|
|
17
|
+
}
|
|
18
|
+
export function isRecipeNew(book, recipe) {
|
|
19
|
+
return getFlag(book.raw, BIT_FLAG_ARRAY_SIZE * 2, recipe);
|
|
20
|
+
}
|
|
21
|
+
export function isRecipeFavorite(book, recipe) {
|
|
22
|
+
return getFlag(book.raw, BIT_FLAG_ARRAY_SIZE * 3, recipe);
|
|
23
|
+
}
|
|
24
|
+
/** Returns a set of recipe indices that are known. */
|
|
25
|
+
export function getKnownRecipes(book, maxRecipeId) {
|
|
26
|
+
const known = new Set();
|
|
27
|
+
for (let i = 0; i < maxRecipeId; i++) {
|
|
28
|
+
if (isRecipeKnown(book, i))
|
|
29
|
+
known.add(i);
|
|
30
|
+
}
|
|
31
|
+
return known;
|
|
32
|
+
}
|
|
33
|
+
/** Returns a set of recipe indices that have been crafted. */
|
|
34
|
+
export function getCraftedRecipes(book, maxRecipeId) {
|
|
35
|
+
const crafted = new Set();
|
|
36
|
+
for (let i = 0; i < maxRecipeId; i++) {
|
|
37
|
+
if (isRecipeMade(book, i))
|
|
38
|
+
crafted.add(i);
|
|
39
|
+
}
|
|
40
|
+
return crafted;
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-book.js","sourceRoot":"","sources":["../../src/structures/recipe-book.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAClC,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAAmB,GAAG,CAAC,CAAC,CAAC,QAAQ;AACjE,MAAM,CAAC,MAAM,YAAY,GAAG,mBAAmB,GAAG,CAAC,CAAC,CAAC,OAAO;AAO5D,MAAM,UAAU,cAAc,CAAC,IAAgB,EAAE,MAAc;IAC9D,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAoB,EAAE,MAAc;IACjE,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAoB,EAAE,MAAc;IAChE,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAoB,EAAE,MAAc;IAC/D,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAoB,EAAE,MAAc;IACpE,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AAC3D,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,eAAe,CAAC,IAAoB,EAAE,WAAmB;IACxE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,iBAAiB,CAAC,IAAoB,EAAE,WAAmB;IAC1E,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turnip (Stalk Market) data.
|
|
3
|
+
* Ported from NHSE.Core TurnipStonk (GSaveShopKabu).
|
|
4
|
+
*/
|
|
5
|
+
export declare const TURNIP_STONK_SIZE = 68;
|
|
6
|
+
export declare enum TurnipPattern {
|
|
7
|
+
Fluctuating = 0,
|
|
8
|
+
LargeSpike = 1,
|
|
9
|
+
Decreasing = 2,
|
|
10
|
+
SmallSpike = 3
|
|
11
|
+
}
|
|
12
|
+
export interface TurnipPrices {
|
|
13
|
+
sundayAM: number;
|
|
14
|
+
sundayPM: number;
|
|
15
|
+
mondayAM: number;
|
|
16
|
+
mondayPM: number;
|
|
17
|
+
tuesdayAM: number;
|
|
18
|
+
tuesdayPM: number;
|
|
19
|
+
wednesdayAM: number;
|
|
20
|
+
wednesdayPM: number;
|
|
21
|
+
thursdayAM: number;
|
|
22
|
+
thursdayPM: number;
|
|
23
|
+
fridayAM: number;
|
|
24
|
+
fridayPM: number;
|
|
25
|
+
saturdayAM: number;
|
|
26
|
+
saturdayPM: number;
|
|
27
|
+
}
|
|
28
|
+
export interface TurnipStonk {
|
|
29
|
+
buyPrice: number;
|
|
30
|
+
sellPrices: TurnipPrices;
|
|
31
|
+
pattern: TurnipPattern;
|
|
32
|
+
feverStart: number;
|
|
33
|
+
}
|
|
34
|
+
export declare function readTurnipStonk(data: Uint8Array, offset: number): TurnipStonk;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turnips.d.ts","sourceRoot":"","sources":["../../src/structures/turnips.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,eAAO,MAAM,iBAAiB,KAAO,CAAC;AAEtC,oBAAY,aAAa;IACxB,WAAW,IAAI;IACf,UAAU,IAAI;IACd,UAAU,IAAI;IACd,UAAU,IAAI;CACd;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,YAAY,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAuB7E"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turnip (Stalk Market) data.
|
|
3
|
+
* Ported from NHSE.Core TurnipStonk (GSaveShopKabu).
|
|
4
|
+
*/
|
|
5
|
+
import { readU32LE } from '../util/binary.js';
|
|
6
|
+
export const TURNIP_STONK_SIZE = 0x44;
|
|
7
|
+
export var TurnipPattern;
|
|
8
|
+
(function (TurnipPattern) {
|
|
9
|
+
TurnipPattern[TurnipPattern["Fluctuating"] = 0] = "Fluctuating";
|
|
10
|
+
TurnipPattern[TurnipPattern["LargeSpike"] = 1] = "LargeSpike";
|
|
11
|
+
TurnipPattern[TurnipPattern["Decreasing"] = 2] = "Decreasing";
|
|
12
|
+
TurnipPattern[TurnipPattern["SmallSpike"] = 3] = "SmallSpike";
|
|
13
|
+
})(TurnipPattern || (TurnipPattern = {}));
|
|
14
|
+
export function readTurnipStonk(data, offset) {
|
|
15
|
+
const u32 = (rel) => readU32LE(data, offset + rel);
|
|
16
|
+
return {
|
|
17
|
+
buyPrice: u32(0x00),
|
|
18
|
+
sellPrices: {
|
|
19
|
+
sundayAM: u32(0x04),
|
|
20
|
+
sundayPM: u32(0x08),
|
|
21
|
+
mondayAM: u32(0x0c),
|
|
22
|
+
mondayPM: u32(0x10),
|
|
23
|
+
tuesdayAM: u32(0x14),
|
|
24
|
+
tuesdayPM: u32(0x18),
|
|
25
|
+
wednesdayAM: u32(0x1c),
|
|
26
|
+
wednesdayPM: u32(0x20),
|
|
27
|
+
thursdayAM: u32(0x24),
|
|
28
|
+
thursdayPM: u32(0x28),
|
|
29
|
+
fridayAM: u32(0x2c),
|
|
30
|
+
fridayPM: u32(0x30),
|
|
31
|
+
saturdayAM: u32(0x34),
|
|
32
|
+
saturdayPM: u32(0x38),
|
|
33
|
+
},
|
|
34
|
+
pattern: u32(0x3c),
|
|
35
|
+
feverStart: u32(0x40),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turnips.js","sourceRoot":"","sources":["../../src/structures/turnips.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAEtC,MAAM,CAAN,IAAY,aAKX;AALD,WAAY,aAAa;IACxB,+DAAe,CAAA;IACf,6DAAc,CAAA;IACd,6DAAc,CAAA;IACd,6DAAc,CAAA;AACf,CAAC,EALW,aAAa,KAAb,aAAa,QAKxB;AA0BD,MAAM,UAAU,eAAe,CAAC,IAAgB,EAAE,MAAc;IAC/D,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC;IAC3D,OAAO;QACN,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC;QACnB,UAAU,EAAE;YACX,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC;YACnB,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC;YACnB,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC;YACnB,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC;YACnB,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC;YACpB,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC;YACpB,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC;YACtB,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC;YACtB,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC;YACrB,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC;YACrB,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC;YACnB,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC;YACnB,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC;YACrB,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC;SACrB;QACD,OAAO,EAAE,GAAG,CAAC,IAAI,CAAkB;QACnC,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC;KACrB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Villager data reader.
|
|
3
|
+
* Ported from NHSE.Core Villager2
|
|
4
|
+
*/
|
|
5
|
+
import type { VillagerPersonality } from './enums.js';
|
|
6
|
+
/** Size of a Villager2 structure (used in save format 1.5+). */
|
|
7
|
+
export declare const VILLAGER2_SIZE = 78384;
|
|
8
|
+
/** Size of a Villager1 structure (used in save format 1.0-1.4). */
|
|
9
|
+
export declare const VILLAGER1_SIZE = 76464;
|
|
10
|
+
/** Number of player memory slots per villager. */
|
|
11
|
+
export declare const VILLAGER_MEMORY_COUNT = 8;
|
|
12
|
+
/** Size of a GSaveMemory structure. */
|
|
13
|
+
export declare const GSAVE_MEMORY_SIZE = 1520;
|
|
14
|
+
export interface VillagerData {
|
|
15
|
+
species: number;
|
|
16
|
+
variant: number;
|
|
17
|
+
personality: VillagerPersonality;
|
|
18
|
+
catchPhrase: string;
|
|
19
|
+
birthType: number;
|
|
20
|
+
inducementType: number;
|
|
21
|
+
moveType: number;
|
|
22
|
+
movingOut: boolean;
|
|
23
|
+
gender: number;
|
|
24
|
+
diyRecipeIndex: number;
|
|
25
|
+
eventFlags: number[];
|
|
26
|
+
memories: VillagerMemory[];
|
|
27
|
+
}
|
|
28
|
+
export interface VillagerMemory {
|
|
29
|
+
townId: number;
|
|
30
|
+
townName: string;
|
|
31
|
+
playerId: number;
|
|
32
|
+
playerName: string;
|
|
33
|
+
friendship: number;
|
|
34
|
+
nickname: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Read a Villager2 structure (format 1.5+).
|
|
38
|
+
*/
|
|
39
|
+
export declare function readVillager2(data: Uint8Array, offset: number): VillagerData;
|
|
40
|
+
/**
|
|
41
|
+
* Read a Villager1 structure (format 1.0-1.4).
|
|
42
|
+
*/
|
|
43
|
+
export declare function readVillager1(data: Uint8Array, offset: number): VillagerData;
|
|
44
|
+
/**
|
|
45
|
+
* Read the appropriate villager format based on revision index.
|
|
46
|
+
*/
|
|
47
|
+
export declare function readVillager(data: Uint8Array, offset: number, revisionIndex: number): VillagerData;
|
|
48
|
+
/** Get the villager size for a given revision. */
|
|
49
|
+
export declare function getVillagerSize(revisionIndex: number): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"villager.d.ts","sourceRoot":"","sources":["../../src/structures/villager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,gEAAgE;AAChE,eAAO,MAAM,cAAc,QAAU,CAAC;AACtC,mEAAmE;AACnE,eAAO,MAAM,cAAc,QAAU,CAAC;AACtC,kDAAkD;AAClD,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,uCAAuC;AACvC,eAAO,MAAM,iBAAiB,OAAQ,CAAC;AAEvC,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,mBAAmB,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CA0C5E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAyC5E;AAaD;;GAEG;AACH,wBAAgB,YAAY,CAC3B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,GACnB,YAAY,CAMd;AAED,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE7D"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Villager data reader.
|
|
3
|
+
* Ported from NHSE.Core Villager2
|
|
4
|
+
*/
|
|
5
|
+
import { readString, readU8, readU16LE } from '../util/binary.js';
|
|
6
|
+
/** Size of a Villager2 structure (used in save format 1.5+). */
|
|
7
|
+
export const VILLAGER2_SIZE = 0x13230;
|
|
8
|
+
/** Size of a Villager1 structure (used in save format 1.0-1.4). */
|
|
9
|
+
export const VILLAGER1_SIZE = 0x12ab0;
|
|
10
|
+
/** Number of player memory slots per villager. */
|
|
11
|
+
export const VILLAGER_MEMORY_COUNT = 8;
|
|
12
|
+
/** Size of a GSaveMemory structure. */
|
|
13
|
+
export const GSAVE_MEMORY_SIZE = 0x5f0;
|
|
14
|
+
/**
|
|
15
|
+
* Read a Villager2 structure (format 1.5+).
|
|
16
|
+
*/
|
|
17
|
+
export function readVillager2(data, offset) {
|
|
18
|
+
const species = readU8(data, offset);
|
|
19
|
+
const variant = readU8(data, offset + 1);
|
|
20
|
+
const personality = readU8(data, offset + 2);
|
|
21
|
+
// Read memories
|
|
22
|
+
const memories = [];
|
|
23
|
+
for (let i = 0; i < VILLAGER_MEMORY_COUNT; i++) {
|
|
24
|
+
const memOfs = offset + 0x4 + i * GSAVE_MEMORY_SIZE;
|
|
25
|
+
memories.push(readVillagerMemory(data, memOfs));
|
|
26
|
+
}
|
|
27
|
+
const catchPhrase = readString(data, offset + 0x10768 + 0x2c, 12);
|
|
28
|
+
const birthType = readU8(data, offset + 0x12678);
|
|
29
|
+
const inducementType = readU8(data, offset + 0x12679);
|
|
30
|
+
const moveType = readU8(data, offset + 0x1267a);
|
|
31
|
+
const movingOut = (moveType & 1) !== 0;
|
|
32
|
+
// Event flags: 256 uint16 values
|
|
33
|
+
const eventFlags = [];
|
|
34
|
+
for (let i = 0; i < 256; i++) {
|
|
35
|
+
eventFlags.push(readU16LE(data, offset + 0x1267c + i * 2));
|
|
36
|
+
}
|
|
37
|
+
const diyRecipeIndex = readU16LE(data, offset + 0x13154);
|
|
38
|
+
const gender = Math.floor(personality / 4) & 1;
|
|
39
|
+
return {
|
|
40
|
+
species,
|
|
41
|
+
variant,
|
|
42
|
+
personality,
|
|
43
|
+
catchPhrase,
|
|
44
|
+
birthType,
|
|
45
|
+
inducementType,
|
|
46
|
+
moveType,
|
|
47
|
+
movingOut,
|
|
48
|
+
gender,
|
|
49
|
+
diyRecipeIndex,
|
|
50
|
+
eventFlags,
|
|
51
|
+
memories,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Read a Villager1 structure (format 1.0-1.4).
|
|
56
|
+
*/
|
|
57
|
+
export function readVillager1(data, offset) {
|
|
58
|
+
const species = readU8(data, offset);
|
|
59
|
+
const variant = readU8(data, offset + 1);
|
|
60
|
+
const personality = readU8(data, offset + 2);
|
|
61
|
+
const memories = [];
|
|
62
|
+
for (let i = 0; i < VILLAGER_MEMORY_COUNT; i++) {
|
|
63
|
+
const memOfs = offset + 0x4 + i * GSAVE_MEMORY_SIZE;
|
|
64
|
+
memories.push(readVillagerMemory(data, memOfs));
|
|
65
|
+
}
|
|
66
|
+
// Villager1 has slightly different offsets for later fields
|
|
67
|
+
const catchPhrase = readString(data, offset + 0x10024 + 0x2c, 12);
|
|
68
|
+
const birthType = readU8(data, offset + 0x11f30);
|
|
69
|
+
const inducementType = readU8(data, offset + 0x11f31);
|
|
70
|
+
const moveType = readU8(data, offset + 0x11f32);
|
|
71
|
+
const movingOut = (moveType & 1) !== 0;
|
|
72
|
+
const eventFlags = [];
|
|
73
|
+
for (let i = 0; i < 256; i++) {
|
|
74
|
+
eventFlags.push(readU16LE(data, offset + 0x11f34 + i * 2));
|
|
75
|
+
}
|
|
76
|
+
const diyRecipeIndex = readU16LE(data, offset + 0x12a0c);
|
|
77
|
+
const gender = Math.floor(personality / 4) & 1;
|
|
78
|
+
return {
|
|
79
|
+
species,
|
|
80
|
+
variant,
|
|
81
|
+
personality,
|
|
82
|
+
catchPhrase,
|
|
83
|
+
birthType,
|
|
84
|
+
inducementType,
|
|
85
|
+
moveType,
|
|
86
|
+
movingOut,
|
|
87
|
+
gender,
|
|
88
|
+
diyRecipeIndex,
|
|
89
|
+
eventFlags,
|
|
90
|
+
memories,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function readVillagerMemory(data, offset) {
|
|
94
|
+
return {
|
|
95
|
+
townId: readU16LE(data, offset) | (readU16LE(data, offset + 2) << 16),
|
|
96
|
+
townName: readString(data, offset + 0x04, 10),
|
|
97
|
+
playerId: readU16LE(data, offset + 0x1c) | (readU16LE(data, offset + 0x1e) << 16),
|
|
98
|
+
playerName: readString(data, offset + 0x20, 10),
|
|
99
|
+
friendship: readU8(data, offset + 0x42),
|
|
100
|
+
nickname: readString(data, offset + 0x138, 10),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Read the appropriate villager format based on revision index.
|
|
105
|
+
*/
|
|
106
|
+
export function readVillager(data, offset, revisionIndex) {
|
|
107
|
+
// Villager2 format starts at revision index 13 (1.5.0)
|
|
108
|
+
if (revisionIndex >= 13) {
|
|
109
|
+
return readVillager2(data, offset);
|
|
110
|
+
}
|
|
111
|
+
return readVillager1(data, offset);
|
|
112
|
+
}
|
|
113
|
+
/** Get the villager size for a given revision. */
|
|
114
|
+
export function getVillagerSize(revisionIndex) {
|
|
115
|
+
return revisionIndex >= 13 ? VILLAGER2_SIZE : VILLAGER1_SIZE;
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"villager.js","sourceRoot":"","sources":["../../src/structures/villager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary reading helpers for working with save data.
|
|
3
|
+
*/
|
|
4
|
+
export declare function readU8(data: Uint8Array, offset: number): number;
|
|
5
|
+
export declare function readU16LE(data: Uint8Array, offset: number): number;
|
|
6
|
+
export declare function readU32LE(data: Uint8Array, offset: number): number;
|
|
7
|
+
export declare function readI32LE(data: Uint8Array, offset: number): number;
|
|
8
|
+
export declare function readString(data: Uint8Array, offset: number, maxChars: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary.d.ts","sourceRoot":"","sources":["../../src/util/binary.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAQlE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOlE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMrF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary reading helpers for working with save data.
|
|
3
|
+
*/
|
|
4
|
+
export function readU8(data, offset) {
|
|
5
|
+
return data[offset];
|
|
6
|
+
}
|
|
7
|
+
export function readU16LE(data, offset) {
|
|
8
|
+
return data[offset] | (data[offset + 1] << 8);
|
|
9
|
+
}
|
|
10
|
+
export function readU32LE(data, offset) {
|
|
11
|
+
return ((data[offset] |
|
|
12
|
+
(data[offset + 1] << 8) |
|
|
13
|
+
(data[offset + 2] << 16) |
|
|
14
|
+
(data[offset + 3] << 24)) >>>
|
|
15
|
+
0);
|
|
16
|
+
}
|
|
17
|
+
export function readI32LE(data, offset) {
|
|
18
|
+
return (data[offset] |
|
|
19
|
+
(data[offset + 1] << 8) |
|
|
20
|
+
(data[offset + 2] << 16) |
|
|
21
|
+
(data[offset + 3] << 24));
|
|
22
|
+
}
|
|
23
|
+
export function readString(data, offset, maxChars) {
|
|
24
|
+
const decoder = new TextDecoder('utf-16le');
|
|
25
|
+
const slice = data.subarray(offset, offset + maxChars * 2);
|
|
26
|
+
const str = decoder.decode(slice);
|
|
27
|
+
const nullIdx = str.indexOf('\0');
|
|
28
|
+
return nullIdx >= 0 ? str.substring(0, nullIdx) : str;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary.js","sourceRoot":"","sources":["../../src/util/binary.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,MAAM,CAAC,IAAgB,EAAE,MAAc;IACtD,OAAO,IAAI,CAAC,MAAM,CAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAgB,EAAE,MAAc;IACzD,OAAO,IAAI,CAAC,MAAM,CAAE,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,IAAI,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAgB,EAAE,MAAc;IACzD,OAAO,CACN,CAAC,IAAI,CAAC,MAAM,CAAE;QACb,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,IAAI,CAAC,CAAC;QACxB,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,IAAI,EAAE,CAAC;QACzB,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,IAAI,EAAE,CAAC,CAAC;QAC3B,CAAC,CACD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAgB,EAAE,MAAc;IACzD,OAAO,CACN,IAAI,CAAC,MAAM,CAAE;QACb,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,IAAI,CAAC,CAAC;QACxB,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,IAAI,EAAE,CAAC;QACzB,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,IAAI,EAAE,CAAC,CACzB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAgB,EAAE,MAAc,EAAE,QAAgB;IAC5E,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility logic for dealing with bitflags in a byte array.
|
|
3
|
+
* Ported from NHSE.Core FlagUtil
|
|
4
|
+
*/
|
|
5
|
+
export declare function getFlag(data: Uint8Array, offset: number, bitIndex: number): boolean;
|
|
6
|
+
export declare function setFlag(data: Uint8Array, offset: number, bitIndex: number, value: boolean): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../../src/util/flags.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAInF;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAIhG"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility logic for dealing with bitflags in a byte array.
|
|
3
|
+
* Ported from NHSE.Core FlagUtil
|
|
4
|
+
*/
|
|
5
|
+
export function getFlag(data, offset, bitIndex) {
|
|
6
|
+
const byteIndex = offset + (bitIndex >> 3);
|
|
7
|
+
const mask = 1 << (bitIndex & 7);
|
|
8
|
+
return (data[byteIndex] & mask) !== 0;
|
|
9
|
+
}
|
|
10
|
+
export function setFlag(data, offset, bitIndex, value) {
|
|
11
|
+
const byteOffset = offset + (bitIndex >> 3);
|
|
12
|
+
const bit = bitIndex & 7;
|
|
13
|
+
data[byteOffset] = (data[byteOffset] & ~(1 << bit)) | ((value ? 1 : 0) << bit);
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/util/flags.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,OAAO,CAAC,IAAgB,EAAE,MAAc,EAAE,QAAgB;IACzE,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAgB,EAAE,MAAc,EAAE,QAAgB,EAAE,KAAc;IACzF,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAE,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tsacnhsaves",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript library for reading Animal Crossing: New Horizons save files. Port of NHSE.Core.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"prepublishOnly": "tsc",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"check": "biome check",
|
|
25
|
+
"check:fix": "biome check --write",
|
|
26
|
+
"format": "biome format --write",
|
|
27
|
+
"lint": "biome lint"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"acnh",
|
|
31
|
+
"animal-crossing",
|
|
32
|
+
"animal-crossing-new-horizons",
|
|
33
|
+
"save-editor",
|
|
34
|
+
"save-file",
|
|
35
|
+
"nhse"
|
|
36
|
+
],
|
|
37
|
+
"license": "GPL-3.0-or-later",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/KhloeLeclair/tsacnhsaves.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/KhloeLeclair/tsacnhsaves/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/KhloeLeclair/tsacnhsaves#readme",
|
|
46
|
+
"packageManager": "pnpm@10.12.1",
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@biomejs/biome": "2.4.11",
|
|
49
|
+
"@types/node": "^25.6.0",
|
|
50
|
+
"typescript": "^6.0.2",
|
|
51
|
+
"vitest": "^4.1.4"
|
|
52
|
+
}
|
|
53
|
+
}
|