mirror of
https://github.com/skillbert/rsmv.git
synced 2025-12-23 21:47:48 -05:00
cache write functions
This commit is contained in:
74
generated/achievements.d.ts
vendored
74
generated/achievements.d.ts
vendored
@@ -3,19 +3,19 @@
|
||||
// run `npm run filetypes` to rebuild
|
||||
|
||||
export type achievements = {
|
||||
name?: string | undefined
|
||||
name?: string | null
|
||||
description?: {
|
||||
hasironman: number,
|
||||
unk0: number,
|
||||
descr: string,
|
||||
unk1: number | undefined,
|
||||
descr_ironman: string | undefined,
|
||||
} | undefined
|
||||
category?: number | undefined
|
||||
spriteId?: number | undefined
|
||||
runescore?: number | undefined
|
||||
unknown_0x06?: number | undefined
|
||||
rewardtext?: string | undefined
|
||||
unk1: number | null,
|
||||
descr_ironman: string | null,
|
||||
} | null
|
||||
category?: number | null
|
||||
spriteId?: number | null
|
||||
runescore?: number | null
|
||||
unknown_0x06?: number | null
|
||||
rewardtext?: string | null
|
||||
subach_skills?: {
|
||||
ironman: number,
|
||||
level: number,
|
||||
@@ -23,73 +23,73 @@ export type achievements = {
|
||||
unk_0: number,
|
||||
unk_1: number,
|
||||
skill: number,
|
||||
}[] | undefined
|
||||
}[] | null
|
||||
subach_varbits?: {
|
||||
type: number,
|
||||
value: number,
|
||||
name: string,
|
||||
stepsize: number,
|
||||
varbit: number,
|
||||
}[] | undefined
|
||||
}[] | null
|
||||
varbit_partial_state?: {
|
||||
type: number,
|
||||
value: number,
|
||||
name: string,
|
||||
stepsize: number,
|
||||
varbit: number,
|
||||
}[] | undefined
|
||||
previous_achievements?: number[] | undefined
|
||||
}[] | null
|
||||
previous_achievements?: number[] | null
|
||||
skill_reqs_2?: {
|
||||
unk0: number,
|
||||
level: number,
|
||||
name: string,
|
||||
unk1: number,
|
||||
skill: number,
|
||||
}[] | undefined
|
||||
}[] | null
|
||||
progress_states?: {
|
||||
unk0: number,
|
||||
value: number,
|
||||
name: string,
|
||||
varbits: number[],
|
||||
}[] | undefined
|
||||
}[] | null
|
||||
subreqs?: {
|
||||
unk0: number,
|
||||
value: number,
|
||||
name: string,
|
||||
varbits: number[],
|
||||
}[] | undefined
|
||||
}[] | null
|
||||
sub_achievements?: {
|
||||
unk0: number,
|
||||
achievement: number,
|
||||
}[] | undefined
|
||||
subcategory?: number | undefined
|
||||
hidden?: number | undefined
|
||||
f2p?: true | undefined
|
||||
quest_req_for_miniquests?: number[] | undefined
|
||||
quest_ids?: number[] | undefined
|
||||
}[] | null
|
||||
subcategory?: number | null
|
||||
hidden?: number | null
|
||||
f2p?: true | null
|
||||
quest_req_for_miniquests?: number[] | null
|
||||
quest_ids?: number[] | null
|
||||
reqs23?: {
|
||||
type: number,
|
||||
varbit: number,
|
||||
stepsize: number,
|
||||
name: string | undefined,
|
||||
requirement: number | undefined,
|
||||
name: string | null,
|
||||
requirement: number | null,
|
||||
subbit: number,
|
||||
}[] | undefined
|
||||
}[] | null
|
||||
reqs25?: {
|
||||
type: number,
|
||||
varbit: number,
|
||||
value: number,
|
||||
name: string | undefined,
|
||||
requirement: number | undefined,
|
||||
name: string | null,
|
||||
requirement: number | null,
|
||||
subbit: number,
|
||||
}[] | undefined
|
||||
unknown_0x13?: true | undefined
|
||||
skill_req_count?: number[] | undefined
|
||||
unknown_0x1D?: number | undefined
|
||||
subreq_count?: number[] | undefined
|
||||
unknown_0x1F?: number | undefined
|
||||
unknown_0x20?: number | undefined
|
||||
unknown_0x23?: true | undefined
|
||||
unknown_0x25?: number | undefined
|
||||
unknown_0x26?: true | undefined
|
||||
}[] | null
|
||||
unknown_0x13?: true | null
|
||||
skill_req_count?: number[] | null
|
||||
unknown_0x1D?: number | null
|
||||
subreq_count?: number[] | null
|
||||
unknown_0x1F?: number | null
|
||||
unknown_0x20?: number | null
|
||||
unknown_0x23?: true | null
|
||||
unknown_0x25?: number | null
|
||||
unknown_0x26?: true | null
|
||||
};
|
||||
|
||||
2
generated/cacheindex.d.ts
vendored
2
generated/cacheindex.d.ts
vendored
@@ -9,7 +9,7 @@ export type cacheindex = {
|
||||
indices: ({
|
||||
minor: number,
|
||||
} & {
|
||||
name: number | undefined,
|
||||
name: number | null,
|
||||
} & {
|
||||
crc: number,
|
||||
} & {
|
||||
|
||||
22
generated/enums.d.ts
vendored
22
generated/enums.d.ts
vendored
@@ -3,33 +3,33 @@
|
||||
// run `npm run filetypes` to rebuild
|
||||
|
||||
export type enums = {
|
||||
key_type1?: number | undefined
|
||||
value_type1?: number | undefined
|
||||
key_type2?: number | undefined
|
||||
value_type2?: number | undefined
|
||||
stringValue?: string | undefined
|
||||
intValue?: number | undefined
|
||||
key_type1?: number | null
|
||||
value_type1?: number | null
|
||||
key_type2?: number | null
|
||||
value_type2?: number | null
|
||||
stringValue?: string | null
|
||||
intValue?: number | null
|
||||
stringArrayValue1?: [
|
||||
number,
|
||||
string,
|
||||
][] | undefined
|
||||
][] | null
|
||||
intArrayValue1?: [
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
][] | null
|
||||
stringArrayValue2?: {
|
||||
max: number,
|
||||
values: [
|
||||
number,
|
||||
string,
|
||||
][],
|
||||
} | undefined
|
||||
} | null
|
||||
intArrayValue2?: {
|
||||
max: number,
|
||||
values: [
|
||||
number,
|
||||
number,
|
||||
][],
|
||||
} | undefined
|
||||
unknown_83?: true | undefined
|
||||
} | null
|
||||
unknown_83?: true | null
|
||||
};
|
||||
|
||||
200
generated/items.d.ts
vendored
200
generated/items.d.ts
vendored
@@ -3,168 +3,168 @@
|
||||
// run `npm run filetypes` to rebuild
|
||||
|
||||
export type items = {
|
||||
baseModel?: number | undefined
|
||||
name?: string | undefined
|
||||
buff_effect?: string | undefined
|
||||
rotation_0?: number | undefined
|
||||
rotation_1?: number | undefined
|
||||
rotation_2?: number | undefined
|
||||
modelTranslate_0?: number | undefined
|
||||
modelTranslate_1?: number | undefined
|
||||
unknown_0A?: true | undefined
|
||||
stackable_1?: true | undefined
|
||||
value?: number | undefined
|
||||
equipSlotId?: number | undefined
|
||||
equipId?: number | undefined
|
||||
unknown_0F?: true | undefined
|
||||
members?: true | undefined
|
||||
multiStackSize?: number | undefined
|
||||
maleModels_0?: number | undefined
|
||||
maleModels_1?: number | undefined
|
||||
femaleModels_0?: number | undefined
|
||||
femaleModels_1?: number | undefined
|
||||
unknown_1B?: number | undefined
|
||||
ground_actions_0?: string | undefined
|
||||
ground_actions_1?: string | undefined
|
||||
ground_actions_2?: string | undefined
|
||||
ground_actions_3?: string | undefined
|
||||
ground_actions_4?: string | undefined
|
||||
widget_actions_0?: string | undefined
|
||||
widget_actions_1?: string | undefined
|
||||
widget_actions_2?: string | undefined
|
||||
widget_actions_3?: string | undefined
|
||||
widget_actions_4?: string | undefined
|
||||
baseModel?: number | null
|
||||
name?: string | null
|
||||
buff_effect?: string | null
|
||||
rotation_0?: number | null
|
||||
rotation_1?: number | null
|
||||
rotation_2?: number | null
|
||||
modelTranslate_0?: number | null
|
||||
modelTranslate_1?: number | null
|
||||
unknown_0A?: true | null
|
||||
stackable_1?: true | null
|
||||
value?: number | null
|
||||
equipSlotId?: number | null
|
||||
equipId?: number | null
|
||||
unknown_0F?: true | null
|
||||
members?: true | null
|
||||
multiStackSize?: number | null
|
||||
maleModels_0?: number | null
|
||||
maleModels_1?: number | null
|
||||
femaleModels_0?: number | null
|
||||
femaleModels_1?: number | null
|
||||
unknown_1B?: number | null
|
||||
ground_actions_0?: string | null
|
||||
ground_actions_1?: string | null
|
||||
ground_actions_2?: string | null
|
||||
ground_actions_3?: string | null
|
||||
ground_actions_4?: string | null
|
||||
widget_actions_0?: string | null
|
||||
widget_actions_1?: string | null
|
||||
widget_actions_2?: string | null
|
||||
widget_actions_3?: string | null
|
||||
widget_actions_4?: string | null
|
||||
color_replacements?: [
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
][] | null
|
||||
material_replacements?: [
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
][] | null
|
||||
recolourPalette?: [
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
nameColor?: number | undefined
|
||||
recolorDstIndices?: number | undefined
|
||||
retextureDstIndices?: number | undefined
|
||||
tradeable?: true | undefined
|
||||
buy_limit?: number | undefined
|
||||
maleModels_2?: number | undefined
|
||||
femaleModels_2?: number | undefined
|
||||
maleHeads_0?: number | undefined
|
||||
femaleHeads_0?: number | undefined
|
||||
maleHeads_1?: number | undefined
|
||||
femaleHeads_1?: number | undefined
|
||||
category?: number | undefined
|
||||
modelYaw?: number | undefined
|
||||
dummyItem?: number | undefined
|
||||
noteData?: number | undefined
|
||||
noteTemplate?: number | undefined
|
||||
][] | null
|
||||
nameColor?: number | null
|
||||
recolorDstIndices?: number | null
|
||||
retextureDstIndices?: number | null
|
||||
tradeable?: true | null
|
||||
buy_limit?: number | null
|
||||
maleModels_2?: number | null
|
||||
femaleModels_2?: number | null
|
||||
maleHeads_0?: number | null
|
||||
femaleHeads_0?: number | null
|
||||
maleHeads_1?: number | null
|
||||
femaleHeads_1?: number | null
|
||||
category?: number | null
|
||||
modelYaw?: number | null
|
||||
dummyItem?: number | null
|
||||
noteData?: number | null
|
||||
noteTemplate?: number | null
|
||||
stack_info_0?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
stack_info_1?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
stack_info_2?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
stack_info_3?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
stack_info_4?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
stack_info_5?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
stack_info_6?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
stack_info_7?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
stack_info_8?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
stack_info_9?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
scale_0?: number | undefined
|
||||
scale_1?: number | undefined
|
||||
scale_2?: number | undefined
|
||||
ambiance?: number | undefined
|
||||
contrast?: number | undefined
|
||||
team?: number | undefined
|
||||
loanId?: number | undefined
|
||||
loanTemplate?: number | undefined
|
||||
] | null
|
||||
scale_0?: number | null
|
||||
scale_1?: number | null
|
||||
scale_2?: number | null
|
||||
ambiance?: number | null
|
||||
contrast?: number | null
|
||||
team?: number | null
|
||||
loanId?: number | null
|
||||
loanTemplate?: number | null
|
||||
male_translate?: [
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
female_translate?: [
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
unknown_7F?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
unknown_80?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
unknown_81?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
unknown_82?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
] | null
|
||||
quests?: [
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
pickSizeShift?: number | undefined
|
||||
bindLink?: number | undefined
|
||||
bindTemplate?: number | undefined
|
||||
ground_actions_cursor_0?: number | undefined
|
||||
ground_actions_cursor_1?: number | undefined
|
||||
ground_actions_cursor_2?: number | undefined
|
||||
ground_actions_cursor_3?: number | undefined
|
||||
ground_actions_cursor_4?: number | undefined
|
||||
widget_actions_cursor_0?: number | undefined
|
||||
widget_actions_cursor_1?: number | undefined
|
||||
widget_actions_cursor_2?: number | undefined
|
||||
widget_actions_cursor_3?: number | undefined
|
||||
widget_actions_cursor_4?: number | undefined
|
||||
dummy?: true | undefined
|
||||
randomizeGroundPos?: true | undefined
|
||||
combine_info?: number | undefined
|
||||
combine_template?: number | undefined
|
||||
combine_num_required?: number | undefined
|
||||
combine_shard_name?: string | undefined
|
||||
neverStackable?: true | undefined
|
||||
unknown_A7?: true | undefined
|
||||
unknown_A8?: true | undefined
|
||||
][] | null
|
||||
pickSizeShift?: number | null
|
||||
bindLink?: number | null
|
||||
bindTemplate?: number | null
|
||||
ground_actions_cursor_0?: number | null
|
||||
ground_actions_cursor_1?: number | null
|
||||
ground_actions_cursor_2?: number | null
|
||||
ground_actions_cursor_3?: number | null
|
||||
ground_actions_cursor_4?: number | null
|
||||
widget_actions_cursor_0?: number | null
|
||||
widget_actions_cursor_1?: number | null
|
||||
widget_actions_cursor_2?: number | null
|
||||
widget_actions_cursor_3?: number | null
|
||||
widget_actions_cursor_4?: number | null
|
||||
dummy?: true | null
|
||||
randomizeGroundPos?: true | null
|
||||
combine_info?: number | null
|
||||
combine_template?: number | null
|
||||
combine_num_required?: number | null
|
||||
combine_shard_name?: string | null
|
||||
neverStackable?: true | null
|
||||
unknown_A7?: true | null
|
||||
unknown_A8?: true | null
|
||||
extra?: {
|
||||
prop: number,
|
||||
intvalue: number | undefined,
|
||||
stringvalue: string | undefined,
|
||||
}[] | undefined
|
||||
intvalue: number | null,
|
||||
stringvalue: string | null,
|
||||
}[] | null
|
||||
};
|
||||
|
||||
10
generated/mapscenes.d.ts
vendored
10
generated/mapscenes.d.ts
vendored
@@ -3,9 +3,9 @@
|
||||
// run `npm run filetypes` to rebuild
|
||||
|
||||
export type mapscenes = {
|
||||
sprite_id?: number | undefined
|
||||
unknown_2?: number | undefined
|
||||
unknown_3?: true | undefined
|
||||
unknown_4?: true | undefined
|
||||
unknown_5?: true | undefined
|
||||
sprite_id?: number | null
|
||||
unknown_2?: number | null
|
||||
unknown_3?: true | null
|
||||
unknown_4?: true | null
|
||||
unknown_5?: true | null
|
||||
};
|
||||
|
||||
18
generated/mapsquare_locations.d.ts
vendored
18
generated/mapsquare_locations.d.ts
vendored
@@ -13,15 +13,15 @@ export type mapsquare_locations = {
|
||||
type: number,
|
||||
extra: {
|
||||
flags: number,
|
||||
rotation: number[] | undefined,
|
||||
translateX: number | undefined,
|
||||
translateY: number | undefined,
|
||||
translateZ: number | undefined,
|
||||
scale: number | undefined,
|
||||
scaleX: number | undefined,
|
||||
scaleY: number | undefined,
|
||||
scaleZ: number | undefined,
|
||||
} | undefined,
|
||||
rotation: number[] | null,
|
||||
translateX: number | null,
|
||||
translateY: number | null,
|
||||
translateZ: number | null,
|
||||
scale: number | null,
|
||||
scaleX: number | null,
|
||||
scaleY: number | null,
|
||||
scaleZ: number | null,
|
||||
} | null,
|
||||
}[],
|
||||
}[],
|
||||
};
|
||||
|
||||
24
generated/mapsquare_overlays.d.ts
vendored
24
generated/mapsquare_overlays.d.ts
vendored
@@ -3,16 +3,16 @@
|
||||
// run `npm run filetypes` to rebuild
|
||||
|
||||
export type mapsquare_overlays = {
|
||||
primary_colour?: number[] | undefined
|
||||
material?: number | undefined
|
||||
unknown_0x05?: true | undefined
|
||||
secondary_colour?: number[] | undefined
|
||||
unknown_0x08?: true | undefined
|
||||
unknown_0x09?: number | undefined
|
||||
unknown_0x0A?: true | undefined
|
||||
unknown_0x0B?: number | undefined
|
||||
bleedToUnderlay?: true | undefined
|
||||
tertiary_colour?: number[] | undefined
|
||||
unknown_0x0E?: number | undefined
|
||||
unknown_0x10?: number | undefined
|
||||
primary_colour?: number[] | null
|
||||
material?: number | null
|
||||
unknown_0x05?: true | null
|
||||
secondary_colour?: number[] | null
|
||||
unknown_0x08?: true | null
|
||||
unknown_0x09?: number | null
|
||||
unknown_0x0A?: true | null
|
||||
unknown_0x0B?: number | null
|
||||
bleedToUnderlay?: true | null
|
||||
tertiary_colour?: number[] | null
|
||||
unknown_0x0E?: number | null
|
||||
unknown_0x10?: number | null
|
||||
};
|
||||
|
||||
10
generated/mapsquare_tiles.d.ts
vendored
10
generated/mapsquare_tiles.d.ts
vendored
@@ -4,9 +4,9 @@
|
||||
|
||||
export type mapsquare_tiles = {
|
||||
flags: number,
|
||||
shape: number | undefined,
|
||||
overlay: number | undefined,
|
||||
settings: number | undefined,
|
||||
underlay: number | undefined,
|
||||
height: number | undefined,
|
||||
shape: number | null,
|
||||
overlay: number | null,
|
||||
settings: number | null,
|
||||
underlay: number | null,
|
||||
height: number | null,
|
||||
}[];
|
||||
|
||||
10
generated/mapsquare_underlays.d.ts
vendored
10
generated/mapsquare_underlays.d.ts
vendored
@@ -3,9 +3,9 @@
|
||||
// run `npm run filetypes` to rebuild
|
||||
|
||||
export type mapsquare_underlays = {
|
||||
color?: number[] | undefined
|
||||
material?: number | undefined
|
||||
unknown_0x03?: number | undefined
|
||||
unknown_0x04?: true | undefined
|
||||
unknown_0x05?: true | undefined
|
||||
color?: number[] | null
|
||||
material?: number | null
|
||||
unknown_0x03?: number | null
|
||||
unknown_0x04?: true | null
|
||||
unknown_0x05?: true | null
|
||||
};
|
||||
|
||||
10
generated/mapsquare_watertiles.d.ts
vendored
10
generated/mapsquare_watertiles.d.ts
vendored
@@ -4,9 +4,9 @@
|
||||
|
||||
export type mapsquare_watertiles = {
|
||||
flags: number,
|
||||
shape: number | undefined,
|
||||
overlay: number | undefined,
|
||||
settings: number | undefined,
|
||||
underlay: number | undefined,
|
||||
height: number | undefined,
|
||||
shape: number | null,
|
||||
overlay: number | null,
|
||||
settings: number | null,
|
||||
underlay: number | null,
|
||||
height: number | null,
|
||||
}[];
|
||||
|
||||
150
generated/npcs.d.ts
vendored
150
generated/npcs.d.ts
vendored
@@ -3,119 +3,119 @@
|
||||
// run `npm run filetypes` to rebuild
|
||||
|
||||
export type npcs = {
|
||||
models?: number[] | undefined
|
||||
name?: string | undefined
|
||||
boundSize?: number | undefined
|
||||
actions_0?: string | undefined
|
||||
actions_1?: string | undefined
|
||||
actions_2?: string | undefined
|
||||
actions_3?: string | undefined
|
||||
actions_4?: string | undefined
|
||||
models?: number[] | null
|
||||
name?: string | null
|
||||
boundSize?: number | null
|
||||
actions_0?: string | null
|
||||
actions_1?: string | null
|
||||
actions_2?: string | null
|
||||
actions_3?: string | null
|
||||
actions_4?: string | null
|
||||
color_replacements?: [
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
][] | null
|
||||
material_replacements?: [
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
recolourPalette?: number[] | undefined
|
||||
recolor_indices?: number | undefined
|
||||
retexture_indices?: number | undefined
|
||||
headModels?: number[] | undefined
|
||||
drawMapDot?: false | undefined
|
||||
combat?: number | undefined
|
||||
scaleXZ?: number | undefined
|
||||
scaleY?: number | undefined
|
||||
unknown_63?: true | undefined
|
||||
ambience?: number | undefined
|
||||
modelContract?: number | undefined
|
||||
head_icon_data?: number | undefined
|
||||
unknown_67?: number | undefined
|
||||
][] | null
|
||||
recolourPalette?: number[] | null
|
||||
recolor_indices?: number | null
|
||||
retexture_indices?: number | null
|
||||
headModels?: number[] | null
|
||||
drawMapDot?: false | null
|
||||
combat?: number | null
|
||||
scaleXZ?: number | null
|
||||
scaleY?: number | null
|
||||
unknown_63?: true | null
|
||||
ambience?: number | null
|
||||
modelContract?: number | null
|
||||
head_icon_data?: number | null
|
||||
unknown_67?: number | null
|
||||
morphs_1?: {
|
||||
unk1: number,
|
||||
unk2: number[],
|
||||
unk3: number,
|
||||
} | undefined
|
||||
unknown_6B?: false | undefined
|
||||
slowWalk?: false | undefined
|
||||
animateIdle?: false | undefined
|
||||
} | null
|
||||
unknown_6B?: false | null
|
||||
slowWalk?: false | null
|
||||
animateIdle?: false | null
|
||||
shadow?: {
|
||||
SrcColor: number,
|
||||
DstColor: number,
|
||||
} | undefined
|
||||
} | null
|
||||
shadowAlphaIntensity?: {
|
||||
Src: number,
|
||||
Dst: number,
|
||||
} | undefined
|
||||
} | null
|
||||
morphs_2?: {
|
||||
unk1: number,
|
||||
unk2: number,
|
||||
unk3: number[],
|
||||
unk4: number,
|
||||
} | undefined
|
||||
movementCapabilities?: number | undefined
|
||||
} | null
|
||||
movementCapabilities?: number | null
|
||||
translations?: [
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
iconHeight?: number | undefined
|
||||
respawnDirection?: number | undefined
|
||||
animation_group?: number | undefined
|
||||
movementType?: number | undefined
|
||||
][] | null
|
||||
iconHeight?: number | null
|
||||
respawnDirection?: number | null
|
||||
animation_group?: number | null
|
||||
movementType?: number | null
|
||||
ambient_sound?: {
|
||||
unk1: number,
|
||||
unk2: number,
|
||||
unk3: number,
|
||||
unk4: number,
|
||||
unk45: number,
|
||||
} | undefined
|
||||
} | null
|
||||
oldCursor?: {
|
||||
Op: number,
|
||||
Cursor: number,
|
||||
} | undefined
|
||||
} | null
|
||||
oldCursor2?: {
|
||||
Op: number,
|
||||
Cursor: number,
|
||||
} | undefined
|
||||
attackCursor?: number | undefined
|
||||
armyIcon?: number | undefined
|
||||
unknown_8C?: number | undefined
|
||||
unknown_8D?: true | undefined
|
||||
mapFunction?: number | undefined
|
||||
unknown_8F?: true | undefined
|
||||
members_actions_0?: string | undefined
|
||||
members_actions_1?: string | undefined
|
||||
members_actions_2?: string | undefined
|
||||
members_actions_3?: string | undefined
|
||||
members_actions_4?: string | undefined
|
||||
} | null
|
||||
attackCursor?: number | null
|
||||
armyIcon?: number | null
|
||||
unknown_8C?: number | null
|
||||
unknown_8D?: true | null
|
||||
mapFunction?: number | null
|
||||
unknown_8F?: true | null
|
||||
members_actions_0?: string | null
|
||||
members_actions_1?: string | null
|
||||
members_actions_2?: string | null
|
||||
members_actions_3?: string | null
|
||||
members_actions_4?: string | null
|
||||
unknown_9B?: {
|
||||
unknown_1: number,
|
||||
unknown_2: number,
|
||||
unknown_3: number,
|
||||
unknown_4: number,
|
||||
} | undefined
|
||||
aByte3076_set_1?: true | undefined
|
||||
aByte3076_set_0?: false | undefined
|
||||
quests?: number[] | undefined
|
||||
dummy_1?: true | undefined
|
||||
unknown_A3?: number | undefined
|
||||
} | null
|
||||
aByte3076_set_1?: true | null
|
||||
aByte3076_set_0?: false | null
|
||||
quests?: number[] | null
|
||||
dummy_1?: true | null
|
||||
unknown_A3?: number | null
|
||||
unknown_A4?: {
|
||||
unknown_1: number,
|
||||
unknown_2: number,
|
||||
} | undefined
|
||||
unknown_A5?: number | undefined
|
||||
unknown_A8?: number | undefined
|
||||
unknown_A9?: false | undefined
|
||||
action_cursors_0?: number | undefined
|
||||
action_cursors_1?: number | undefined
|
||||
action_cursors_2?: number | undefined
|
||||
action_cursors_3?: number | undefined
|
||||
action_cursors_4?: number | undefined
|
||||
action_cursors_5?: number | undefined
|
||||
dummy_2?: true | undefined
|
||||
} | null
|
||||
unknown_A5?: number | null
|
||||
unknown_A8?: number | null
|
||||
unknown_A9?: false | null
|
||||
action_cursors_0?: number | null
|
||||
action_cursors_1?: number | null
|
||||
action_cursors_2?: number | null
|
||||
action_cursors_3?: number | null
|
||||
action_cursors_4?: number | null
|
||||
action_cursors_5?: number | null
|
||||
dummy_2?: true | null
|
||||
unknown_B3?: {
|
||||
unknown_1: number,
|
||||
unknown_2: number,
|
||||
@@ -123,17 +123,17 @@ export type npcs = {
|
||||
unknown_4: number,
|
||||
unknown_5: number,
|
||||
unknown_6: number,
|
||||
} | undefined
|
||||
unknown_B4?: number | undefined
|
||||
} | null
|
||||
unknown_B4?: number | null
|
||||
unknown_B5?: {
|
||||
unknown_1: number,
|
||||
unknown_2: number,
|
||||
} | undefined
|
||||
unknown_B6?: true | undefined
|
||||
unknown_B8?: number | undefined
|
||||
} | null
|
||||
unknown_B6?: true | null
|
||||
unknown_B8?: number | null
|
||||
extra?: {
|
||||
prop: number,
|
||||
intvalue: number | undefined,
|
||||
stringvalue: string | undefined,
|
||||
}[] | undefined
|
||||
intvalue: number | null,
|
||||
stringvalue: string | null,
|
||||
}[] | null
|
||||
};
|
||||
|
||||
196
generated/objects.d.ts
vendored
196
generated/objects.d.ts
vendored
@@ -6,142 +6,142 @@ export type objects = {
|
||||
models?: {
|
||||
type: number,
|
||||
values: number[],
|
||||
}[] | undefined
|
||||
name?: string | undefined
|
||||
width?: number | undefined
|
||||
length?: number | undefined
|
||||
probably_nocollision?: true | undefined
|
||||
maybe_allows_lineofsight?: true | undefined
|
||||
deletable?: boolean | undefined
|
||||
probably_morphFloor?: true | undefined
|
||||
unknown_16?: true | undefined
|
||||
occludes_1?: false | undefined
|
||||
probably_animation?: number | undefined
|
||||
maybe_blocks_movement?: true | undefined
|
||||
wallkit_related_1C?: number | undefined
|
||||
ambient?: number | undefined
|
||||
actions_0?: string | undefined
|
||||
actions_1?: string | undefined
|
||||
actions_2?: string | undefined
|
||||
actions_3?: string | undefined
|
||||
actions_4?: string | undefined
|
||||
contrast?: number | undefined
|
||||
}[] | null
|
||||
name?: string | null
|
||||
width?: number | null
|
||||
length?: number | null
|
||||
probably_nocollision?: true | null
|
||||
maybe_allows_lineofsight?: true | null
|
||||
deletable?: boolean | null
|
||||
probably_morphFloor?: true | null
|
||||
unknown_16?: true | null
|
||||
occludes_1?: false | null
|
||||
probably_animation?: number | null
|
||||
maybe_blocks_movement?: true | null
|
||||
wallkit_related_1C?: number | null
|
||||
ambient?: number | null
|
||||
actions_0?: string | null
|
||||
actions_1?: string | null
|
||||
actions_2?: string | null
|
||||
actions_3?: string | null
|
||||
actions_4?: string | null
|
||||
contrast?: number | null
|
||||
color_replacements?: [
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
][] | null
|
||||
material_replacements?: [
|
||||
number,
|
||||
number,
|
||||
][] | undefined
|
||||
recolourPalette?: number[] | undefined
|
||||
unknown_2C?: number | undefined
|
||||
unknown_2D?: number | undefined
|
||||
mirror?: true | undefined
|
||||
unknown_40?: true | undefined
|
||||
scaleX?: number | undefined
|
||||
scaleY?: number | undefined
|
||||
scaleZ?: number | undefined
|
||||
dummy_45?: number | undefined
|
||||
translateX?: number | undefined
|
||||
translateY?: number | undefined
|
||||
translateZ?: number | undefined
|
||||
unknown_49?: true | undefined
|
||||
unknown_4A?: true | undefined
|
||||
unknown_4B?: number | undefined
|
||||
][] | null
|
||||
recolourPalette?: number[] | null
|
||||
unknown_2C?: number | null
|
||||
unknown_2D?: number | null
|
||||
mirror?: true | null
|
||||
unknown_40?: true | null
|
||||
scaleX?: number | null
|
||||
scaleY?: number | null
|
||||
scaleZ?: number | null
|
||||
dummy_45?: number | null
|
||||
translateX?: number | null
|
||||
translateY?: number | null
|
||||
translateZ?: number | null
|
||||
unknown_49?: true | null
|
||||
unknown_4A?: true | null
|
||||
unknown_4B?: number | null
|
||||
morphs_1?: {
|
||||
unk1: number,
|
||||
unk2: number[],
|
||||
unk3: number,
|
||||
} | undefined
|
||||
} | null
|
||||
light_source_related_4E?: {
|
||||
maybe_color: number,
|
||||
maybe_radius: number,
|
||||
} | undefined
|
||||
} | null
|
||||
unknown_4F?: {
|
||||
unknown_1: number,
|
||||
unknown_2: number,
|
||||
unknown_3: number,
|
||||
unknown_4: number[],
|
||||
} | undefined
|
||||
unknown_51?: number | undefined
|
||||
unknown_52?: true | undefined
|
||||
is_members?: true | undefined
|
||||
unknown_59?: true | undefined
|
||||
isMembers?: true | undefined
|
||||
} | null
|
||||
unknown_51?: number | null
|
||||
unknown_52?: true | null
|
||||
is_members?: true | null
|
||||
unknown_59?: true | null
|
||||
isMembers?: true | null
|
||||
morphs_2?: {
|
||||
unk1: number,
|
||||
unk2: number,
|
||||
unk3: number[],
|
||||
unk4: number,
|
||||
} | undefined
|
||||
} | null
|
||||
tilt_xz?: [
|
||||
number,
|
||||
number,
|
||||
] | undefined
|
||||
under_water?: true | undefined
|
||||
probably_morphCeilingOffset?: number | undefined
|
||||
ground_decoration_related_61?: true | undefined
|
||||
has_animated_texture?: true | undefined
|
||||
] | null
|
||||
under_water?: true | null
|
||||
probably_morphCeilingOffset?: number | null
|
||||
ground_decoration_related_61?: true | null
|
||||
has_animated_texture?: true | null
|
||||
dummy_63?: {
|
||||
unknown_2: number,
|
||||
unknown_1: number,
|
||||
} | undefined
|
||||
} | null
|
||||
dummy_64?: {
|
||||
unknown_2: number,
|
||||
unknown_1: number,
|
||||
} | undefined
|
||||
unused_65?: number | undefined
|
||||
mapscene?: number | undefined
|
||||
occludes_2?: false | undefined
|
||||
interactable_related_68?: number | undefined
|
||||
invertMapScene?: true | undefined
|
||||
} | null
|
||||
unused_65?: number | null
|
||||
mapscene?: number | null
|
||||
occludes_2?: false | null
|
||||
interactable_related_68?: number | null
|
||||
invertMapScene?: true | null
|
||||
headModels?: {
|
||||
model: number,
|
||||
unknown_2: number,
|
||||
}[] | undefined
|
||||
mapFunction?: number | undefined
|
||||
members_action_1?: string | undefined
|
||||
members_action_2?: string | undefined
|
||||
members_action_3?: string | undefined
|
||||
members_action_4?: string | undefined
|
||||
members_action_5?: string | undefined
|
||||
unknown_A0?: number[] | undefined
|
||||
singleuse_A2?: number | undefined
|
||||
}[] | null
|
||||
mapFunction?: number | null
|
||||
members_action_1?: string | null
|
||||
members_action_2?: string | null
|
||||
members_action_3?: string | null
|
||||
members_action_4?: string | null
|
||||
members_action_5?: string | null
|
||||
unknown_A0?: number[] | null
|
||||
singleuse_A2?: number | null
|
||||
unknown_A3?: {
|
||||
unknown_1: number,
|
||||
unknown_2: number,
|
||||
unknown_3: number,
|
||||
unknown_4: number,
|
||||
} | undefined
|
||||
singleuse_A4?: number | undefined
|
||||
singleuse_A5?: number | undefined
|
||||
singleuse_A6?: number | undefined
|
||||
floor_thickness?: number | undefined
|
||||
unused_a8?: true | undefined
|
||||
unused_a9?: true | undefined
|
||||
wallkit_related_AA?: number | undefined
|
||||
possibly_wallkit_skew_AB?: number | undefined
|
||||
} | null
|
||||
singleuse_A4?: number | null
|
||||
singleuse_A5?: number | null
|
||||
singleuse_A6?: number | null
|
||||
floor_thickness?: number | null
|
||||
unused_a8?: true | null
|
||||
unused_a9?: true | null
|
||||
wallkit_related_AA?: number | null
|
||||
possibly_wallkit_skew_AB?: number | null
|
||||
lightsource_related_AD?: {
|
||||
unknown_1: number,
|
||||
unknown_2: number,
|
||||
} | undefined
|
||||
can_change_color?: true | undefined
|
||||
unknown_B2?: number | undefined
|
||||
unknown_BA?: number | undefined
|
||||
dummy_bc?: true | undefined
|
||||
treerockordoor_BD?: true | undefined
|
||||
action_cursors_0?: number | undefined
|
||||
action_cursors_1?: number | undefined
|
||||
action_cursors_2?: number | undefined
|
||||
action_cursors_3?: number | undefined
|
||||
action_cursors_4?: number | undefined
|
||||
action_cursors_5?: number | undefined
|
||||
tileplacement_related_c4?: number | undefined
|
||||
clan_citadel_C5?: number | undefined
|
||||
invisible_c6?: true | undefined
|
||||
flooroverlay_c7?: true | undefined
|
||||
singleuse_C8?: true | undefined
|
||||
} | null
|
||||
can_change_color?: true | null
|
||||
unknown_B2?: number | null
|
||||
unknown_BA?: number | null
|
||||
dummy_bc?: true | null
|
||||
treerockordoor_BD?: true | null
|
||||
action_cursors_0?: number | null
|
||||
action_cursors_1?: number | null
|
||||
action_cursors_2?: number | null
|
||||
action_cursors_3?: number | null
|
||||
action_cursors_4?: number | null
|
||||
action_cursors_5?: number | null
|
||||
tileplacement_related_c4?: number | null
|
||||
clan_citadel_C5?: number | null
|
||||
invisible_c6?: true | null
|
||||
flooroverlay_c7?: true | null
|
||||
singleuse_C8?: true | null
|
||||
unknown_C9?: {
|
||||
unknown_1: number,
|
||||
unknown_2: number,
|
||||
@@ -149,11 +149,11 @@ export type objects = {
|
||||
unknown_4: number,
|
||||
unknown_5: number,
|
||||
unknown_6: number,
|
||||
} | undefined
|
||||
singleuse_CA?: number | undefined
|
||||
} | null
|
||||
singleuse_CA?: number | null
|
||||
extra?: {
|
||||
prop: number,
|
||||
intvalue: number | undefined,
|
||||
stringvalue: string | undefined,
|
||||
}[] | undefined
|
||||
intvalue: number | null,
|
||||
stringvalue: string | null,
|
||||
}[] | null
|
||||
};
|
||||
|
||||
15
package-lock.json
generated
15
package-lock.json
generated
@@ -7,7 +7,7 @@
|
||||
"": {
|
||||
"name": "gloopvis",
|
||||
"version": "0.1.0",
|
||||
"license": "ISC",
|
||||
"license": "GPL-4",
|
||||
"dependencies": {
|
||||
"autobind-decorator": "^2.4.0",
|
||||
"bzip2": "^0.1.1",
|
||||
@@ -28,6 +28,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/crc": "^3.4.0",
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/leaflet": "^1.7.6",
|
||||
"@types/react": "^17.0.33",
|
||||
"@types/react-dom": "^17.0.10",
|
||||
@@ -204,6 +205,12 @@
|
||||
"integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
||||
"integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/keyv": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz",
|
||||
@@ -7503,6 +7510,12 @@
|
||||
"integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
||||
"integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/keyv": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz",
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"license": "GPL-4",
|
||||
"devDependencies": {
|
||||
"@types/crc": "^3.4.0",
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/leaflet": "^1.7.6",
|
||||
"@types/react": "^17.0.33",
|
||||
"@types/react-dom": "^17.0.10",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Stream, packedHSL2HSL, HSL2RGB, ModelModifications } from "./utils";
|
||||
import { GLTFBuilder } from "./gltf";
|
||||
import { CacheFileSource, CacheIndex, CacheIndexFile, SubFile } from "../cache";
|
||||
import { GlTf, MeshPrimitive, Material } from "./gltftype";
|
||||
import { cacheConfigPages, cacheMajors } from "../constants";
|
||||
import { cacheConfigPages, cacheMajors, cacheMapFiles } from "../constants";
|
||||
import { ParsedTexture } from "./textures";
|
||||
import { AttributeSoure, buildAttributeBuffer, glTypeIds } from "./gltfutil";
|
||||
import { parseMapscenes, parseMapsquareLocations, parseMapsquareOverlays, parseMapsquareTiles, parseMapsquareUnderlays, parseMapsquareWaterTiles, parseObject } from "../opdecoder";
|
||||
@@ -485,7 +485,7 @@ function boxMesh(width: number, length: number, height: number) {
|
||||
export function modifyMesh(mesh: ModelMeshData, mods: ModelModifications) {
|
||||
let newmat = mods.replaceMaterials?.find(q => q[0] == mesh.materialId)?.[1];
|
||||
let newmesh = { ...mesh };
|
||||
if (typeof newmat != "undefined") {
|
||||
if (newmat != undefined) {
|
||||
newmesh.materialId = (newmat == (1 << 16) - 1 ? -1 : newmat);
|
||||
}
|
||||
|
||||
@@ -817,26 +817,26 @@ export class TileGrid {
|
||||
let height = 0;
|
||||
for (let level = 0; level < squareLevels; level++) {
|
||||
let tile = tiles[tileindex];
|
||||
if (typeof tile.height != "undefined") {
|
||||
if (tile.height != undefined) {
|
||||
height += tile.height;
|
||||
} else {
|
||||
//TODO this is a guess that sort of fits
|
||||
height += 30;
|
||||
}
|
||||
let visible = false;
|
||||
let shape = (typeof tile.shape == "undefined" ? defaulttileshape : tileshapes[tile.shape]);
|
||||
let shape = (tile.shape == undefined ? defaulttileshape : tileshapes[tile.shape]);
|
||||
let bleedsOverlayMaterial = false;
|
||||
let underlayprop: TileVertex | undefined = undefined;
|
||||
let overlayprop: TileVertex | undefined = undefined;
|
||||
//TODO bound checks
|
||||
let underlay = (typeof tile.underlay != "undefined" ? this.mapconfig.underlays[tile.underlay - 1] : undefined);
|
||||
let underlay = (tile.underlay != undefined ? this.mapconfig.underlays[tile.underlay - 1] : undefined);
|
||||
if (underlay) {
|
||||
if (underlay.color && (underlay.color[0] != 255 || underlay.color[1] != 0 || underlay.color[2] != 255)) {
|
||||
visible = true;
|
||||
}
|
||||
underlayprop = { material: underlay.material ?? -1, color: underlay.color ?? [255, 0, 255], usesColor: !underlay.unknown_0x04 };
|
||||
}
|
||||
let overlay = (typeof tile.overlay != "undefined" ? this.mapconfig.overlays[tile.overlay - 1] : undefined);
|
||||
let overlay = ( tile.overlay != undefined ? this.mapconfig.overlays[tile.overlay - 1] : undefined);
|
||||
if (overlay) {
|
||||
overlayprop = { material: overlay.material ?? -1, color: overlay.primary_colour ?? [255, 0, 255], usesColor: !overlay.unknown_0x0A };
|
||||
bleedsOverlayMaterial = !!overlay.bleedToUnderlay;
|
||||
@@ -929,8 +929,8 @@ export async function parseMapsquare(source: CacheFileSource, rect: MapRect, opt
|
||||
continue;
|
||||
}
|
||||
let selfarchive = (await source.getFileArchive(selfindex));
|
||||
let tileindex = selfindex.subindices.indexOf(3);
|
||||
let tileindexwater = selfindex.subindices.indexOf(4);
|
||||
let tileindex = selfindex.subindices.indexOf(cacheMapFiles.squares);
|
||||
let tileindexwater = selfindex.subindices.indexOf(cacheMapFiles.squaresWater);
|
||||
|
||||
if (tileindex == -1) {
|
||||
console.log(`skipping mapsquare ${rect.x + x} ${rect.z + z} as it has no tiles`);
|
||||
@@ -1217,7 +1217,7 @@ async function mapsquareOverlays(source: CacheFileSource, grid: TileGrid, locs:
|
||||
let group = floors[loc.effectiveLevel].mapscenes.get(sceneid);
|
||||
if (!group) {
|
||||
let mapscene = grid.mapconfig.mapscenes[sceneid];
|
||||
if (typeof mapscene.sprite_id == "undefined") { return; }
|
||||
if (mapscene.sprite_id == undefined) { return; }
|
||||
let spritefile = await source.getFileById(cacheMajors.sprites, mapscene.sprite_id);
|
||||
let sprite = parseSprite(spritefile);
|
||||
let mat = new THREE.MeshBasicMaterial();
|
||||
@@ -1271,7 +1271,7 @@ async function mapsquareOverlays(source: CacheFileSource, grid: TileGrid, locs:
|
||||
addwall(wallmodels.diagonal, loc);
|
||||
}
|
||||
|
||||
if (typeof loc.location.mapscene != "undefined") {
|
||||
if (loc.location.mapscene != undefined) {
|
||||
await addMapscene(loc, loc.location.mapscene);
|
||||
}
|
||||
}
|
||||
@@ -1295,8 +1295,8 @@ function mapsquareObjectModels(locs: WorldLocation[]) {
|
||||
let objectmeta = inst.location;
|
||||
if (!model) {
|
||||
let modelmods: ModelModifications = {
|
||||
replaceColors: objectmeta.color_replacements,
|
||||
replaceMaterials: objectmeta.material_replacements
|
||||
replaceColors: objectmeta.color_replacements??undefined,
|
||||
replaceMaterials: objectmeta.material_replacements??undefined
|
||||
};
|
||||
const translatefactor = 4;//no clue why but seems right
|
||||
let translate = new Vector3().set(
|
||||
@@ -1478,7 +1478,7 @@ export type WorldLocation = {
|
||||
export async function mapsquareObjects(source: CacheFileSource, chunk: ChunkData, grid: TileGrid, collision = false) {
|
||||
let locs: WorldLocation[] = [];
|
||||
|
||||
let locationindex = chunk.cacheIndex.subindices.indexOf(0);
|
||||
let locationindex = chunk.cacheIndex.subindices.indexOf(cacheMapFiles.locations);
|
||||
if (locationindex == -1) { return locs; }
|
||||
let locations = parseMapsquareLocations.read(chunk.archive[locationindex].buffer).locations;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { crc32 } from "crc";
|
||||
import { cacheMajors } from "./constants";
|
||||
import { parseCacheIndex } from "./opdecoder";
|
||||
|
||||
@@ -79,6 +80,8 @@ export function packBufferArchive(buffers: Buffer[]) {
|
||||
lastsize = buf.byteLength;
|
||||
footerindex += 4;
|
||||
}
|
||||
result.writeUInt8(1, len - 1);
|
||||
//TODO write last byte, whats in it?
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -86,6 +89,8 @@ export function unpackBufferArchive(buffer: Buffer, length: number) {
|
||||
var subbufs: SubFile[] = [];
|
||||
var scan = 0x0;
|
||||
//whats in our missing byte?
|
||||
let endbyte = buffer.readUInt8(buffer.length - 1);
|
||||
if (endbyte != 1) { console.log("unexpected archive end byte", endbyte) }
|
||||
var suboffsetScan = buffer.length - 0x1 - (0x4 * length);
|
||||
var lastRecordSize = 0;
|
||||
|
||||
@@ -144,6 +149,7 @@ const mappedFileIds = {
|
||||
[cacheMajors.npcs]: 256,//not sure
|
||||
[cacheMajors.enums]: 256,
|
||||
[cacheMajors.objects]: 256,
|
||||
[cacheMajors.achievements]: 128,
|
||||
[cacheMajors.materials]: Infinity
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
import * as cache from "./cache";
|
||||
import { decompress, decompressSqlite } from "./decompress";
|
||||
import { compressSqlite, decompress, decompressSqlite } from "./decompress";
|
||||
import * as path from "path";
|
||||
//only type info, import the actual thing at runtime so it can be avoided if not used
|
||||
import type * as sqlite3 from "sqlite3";
|
||||
import { crc32 } from "crc";
|
||||
|
||||
type CacheTable = {
|
||||
db: sqlite3.Database,
|
||||
ready: Promise<void>,
|
||||
indices: Promise<cache.CacheIndexFile>,
|
||||
dbget: (q: string, params: any[]) => Promise<any>
|
||||
dbget: (q: string, params: any[]) => Promise<any>,
|
||||
dbrun: (q: string, params: any[]) => Promise<any>
|
||||
}
|
||||
|
||||
export class GameCacheLoader extends cache.CacheFileSource {
|
||||
cachedir: string;
|
||||
writable: boolean;
|
||||
opentables = new Map<number, CacheTable>();
|
||||
|
||||
constructor(cachedir: string) {
|
||||
constructor(cachedir: string, writable?: boolean) {
|
||||
super();
|
||||
this.cachedir = cachedir;
|
||||
this.writable = !!writable;
|
||||
}
|
||||
|
||||
openTable(major: number) {
|
||||
let sqlite = require("sqlite3") as typeof import("sqlite3");
|
||||
if (!this.opentables.get(major)) {
|
||||
let db = new sqlite.Database(path.resolve(this.cachedir, `js5-${major}.jcache`), sqlite.OPEN_READONLY);
|
||||
let db = new sqlite.Database(path.resolve(this.cachedir, `js5-${major}.jcache`), this.writable ? sqlite.OPEN_READWRITE : sqlite.OPEN_READONLY);
|
||||
let ready = new Promise<void>(done => db.once("open", done));
|
||||
let dbget = async (query: string, args: any[]) => {
|
||||
await ready;
|
||||
@@ -34,11 +38,20 @@ export class GameCacheLoader extends cache.CacheFileSource {
|
||||
})
|
||||
})
|
||||
}
|
||||
let dbrun = async (query: string, args: any[]) => {
|
||||
await ready;
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
db.run(query, args, (err, res) => {
|
||||
if (err) { reject(err); }
|
||||
else { resolve(res); }
|
||||
})
|
||||
})
|
||||
}
|
||||
let indices = dbget(`SELECT DATA FROM cache_index`, []).then(row => {
|
||||
return cache.indexBufferToObject(major, decompressSqlite(Buffer.from(row.DATA.buffer, row.DATA.byteOffset, row.DATA.byteLength)));
|
||||
});
|
||||
|
||||
this.opentables.set(major, { db, ready, dbget, indices });
|
||||
this.opentables.set(major, { db, ready, dbget, dbrun, indices });
|
||||
}
|
||||
return this.opentables.get(major)!;
|
||||
}
|
||||
@@ -48,13 +61,28 @@ export class GameCacheLoader extends cache.CacheFileSource {
|
||||
let row = await dbget(`SELECT DATA,CRC FROM cache WHERE KEY=?`, [minor]);
|
||||
if (typeof crc == "number" && row.CRC != crc) {
|
||||
//TODO this is always off by either 1 or 2
|
||||
//console.log(`crc from cache (${row.CRC}) did not match requested crc (${crc}) for ${major}.${minor}`);
|
||||
// console.log(`crc from cache (${row.CRC}) did not match requested crc (${crc}) for ${major}.${minor}`);
|
||||
}
|
||||
return decompressSqlite(Buffer.from(row.DATA.buffer, row.DATA.byteOffset, row.DATA.byteLength));
|
||||
let file = Buffer.from(row.DATA.buffer, row.DATA.byteOffset, row.DATA.byteLength);
|
||||
let res = decompressSqlite(file);
|
||||
return res;
|
||||
}
|
||||
|
||||
async getFileArchive(index: cache.CacheIndex) {
|
||||
return cache.unpackSqliteBufferArchive(await this.getFile(index.major, index.minor, index.crc), index.subindexcount);
|
||||
let arch = await this.getFile(index.major, index.minor, index.crc);
|
||||
let res = cache.unpackSqliteBufferArchive(arch, index.subindexcount);
|
||||
return res;
|
||||
}
|
||||
|
||||
writeFile(major: number, minor: number, file: Buffer) {
|
||||
let { dbrun } = this.openTable(major);
|
||||
let compressed = compressSqlite(file, "zlib");
|
||||
return dbrun("UPDATE `cache` SET `DATA`=? WHERE `KEY`=?", [compressed, minor]);
|
||||
}
|
||||
|
||||
writeFileArchive(index: cache.CacheIndex, files: Buffer[]) {
|
||||
let arch = cache.packSqliteBufferArchive(files);
|
||||
return this.writeFile(index.major, index.minor, arch);
|
||||
}
|
||||
|
||||
async getIndexFile(major: number) {
|
||||
|
||||
@@ -24,11 +24,11 @@ export function setLoadingIndicator(ind: typeof loadingIndicator) {
|
||||
loadingIndicator = ind;
|
||||
}
|
||||
|
||||
const ReadCacheSource: Type<string, () => Promise<CacheFileSource>> = {
|
||||
const ReadCacheSource: Type<string, (opts?: { writable?: boolean }) => Promise<CacheFileSource>> = {
|
||||
async from(str) {
|
||||
let [mode, ...argparts] = str.split(":",);
|
||||
let arg = argparts.join(":");
|
||||
return async () => {
|
||||
return async (opts) => {
|
||||
switch (mode) {
|
||||
case "live":
|
||||
return new Downloader();
|
||||
@@ -39,7 +39,7 @@ const ReadCacheSource: Type<string, () => Promise<CacheFileSource>> = {
|
||||
await loadingIndicator.done();
|
||||
return updater.fileSource;
|
||||
case "cache":
|
||||
return new GameCacheLoader(arg || path.resolve(process.env.ProgramData!, "jagex/runescape"));
|
||||
return new GameCacheLoader(arg || path.resolve(process.env.ProgramData!, "jagex/runescape"), !!opts?.writable);
|
||||
default:
|
||||
throw new Error("unknown mode");
|
||||
}
|
||||
|
||||
@@ -20,6 +20,12 @@ export const cacheMajors = {
|
||||
index: 255
|
||||
}
|
||||
|
||||
export const cacheMapFiles={
|
||||
locations:0,
|
||||
squares:3,
|
||||
squaresWater:4
|
||||
}
|
||||
|
||||
export const cacheConfigPages = {
|
||||
mapunderlays: 1,
|
||||
mapoverlays: 4,
|
||||
|
||||
@@ -92,7 +92,7 @@ var _lzma = function (input: Buffer) {
|
||||
// var lzma = require("lzma");
|
||||
// return Buffer.from(lzma.decompress(processed));
|
||||
var lzma = require("lzma-native").LZMA();
|
||||
return lzma.decompress(processed);
|
||||
return lzma.decompress(processed) as Buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ export async function svgfloor(source: CacheFileSource, grid: TileGrid, locs: Wo
|
||||
|
||||
let transparent = 0xff00ff;
|
||||
|
||||
let coltoint = (col: number[] | undefined) => {
|
||||
let coltoint = (col: number[] | undefined | null) => {
|
||||
if (!col) { return transparent; }
|
||||
return col[0] << 16 | col[1] << 8 | col[2];
|
||||
}
|
||||
@@ -162,7 +162,7 @@ export async function svgfloor(source: CacheFileSource, grid: TileGrid, locs: Wo
|
||||
if (!tile || tile?.effectiveLevel != loc.effectiveLevel) { break; }
|
||||
if (tile.effectiveLevel == maplevel && (getOverlayColor(tile) != transparent || tile.visible)) { occluded = true; }
|
||||
}
|
||||
if (typeof loc.location.mapscene == "undefined") {
|
||||
if (loc.location.mapscene == undefined) {
|
||||
if (drawwalls && !occluded) {
|
||||
if (loc.type == 0) {
|
||||
addline(linegroup, loc.x - rect.x, loc.z - rect.z, 3, 0, loc.rotation);
|
||||
@@ -181,7 +181,7 @@ export async function svgfloor(source: CacheFileSource, grid: TileGrid, locs: Wo
|
||||
let src = "";
|
||||
let width = 0;
|
||||
let height = 0;
|
||||
if (typeof mapscene.sprite_id != "undefined") {
|
||||
if (mapscene.sprite_id != undefined) {
|
||||
let spritefile = await source.getFileById(cacheMajors.sprites, mapscene.sprite_id);
|
||||
let sprite = parseSprite(spritefile);
|
||||
let pngfile = await sharp(sprite[0].data, { raw: { width: sprite[0].width, height: sprite[0].height, channels: 4 } }).png().toBuffer();
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
import type * as jsonschema from "json-schema";
|
||||
|
||||
type PrimitiveInt = {
|
||||
primitive: "int",
|
||||
unsigned: boolean,
|
||||
@@ -48,7 +50,9 @@ type ParserContext = Record<string, number>;
|
||||
export type ChunkParser<T> = {
|
||||
read(buf: ScanBuffer, ctx: ParserContext): T,
|
||||
write(buf: ScanBuffer, v: unknown): void,
|
||||
bubbleConditionValue?(statevalue: T, prop: string, currentvalue: number, isBubbling: boolean): number,
|
||||
getTypescriptType(indent: string): string,
|
||||
getJsonSChema(): jsonschema.JSONSchema6Definition,
|
||||
condName?: string,
|
||||
condValue?: number,
|
||||
condMode?: CompareMode
|
||||
@@ -211,6 +215,7 @@ function opcodesParser<T extends Record<string, any>>(opcodetype: ChunkParser<nu
|
||||
write(buffer, value) {
|
||||
if (typeof value != "object") { throw new Error("oject expected") }
|
||||
for (let key in value) {
|
||||
if (key.startsWith("$")) { continue; }
|
||||
let parser = opts[key];
|
||||
if (!parser) { throw new Error("unknown property " + key); }
|
||||
opcodetype.write(buffer, parser.condValue);
|
||||
@@ -226,13 +231,21 @@ function opcodesParser<T extends Record<string, any>>(opcodetype: ChunkParser<nu
|
||||
}
|
||||
r += indent + "}";
|
||||
return r;
|
||||
},
|
||||
getJsonSChema() {
|
||||
return {
|
||||
type: "object",
|
||||
properties: Object.fromEntries([...map.values()].map((prop) => {
|
||||
return [prop.key, prop.parser.getJsonSChema()];
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function structParser<TUPPLE extends boolean, T extends Record<TUPPLE extends true ? number : string, any>>(props: { [key in keyof T]: ChunkParser<T[key]> }, isTuple: TUPPLE): ChunkParser<T> {
|
||||
let keys: (keyof T)[] = Object.keys(props) as any;
|
||||
return {
|
||||
let keys = Object.keys(props);
|
||||
let r: ChunkParser<T> = {
|
||||
read(buffer, parentctx) {
|
||||
let r = (isTuple ? [] : {}) as T;
|
||||
let ctx: ParserContext = Object.create(parentctx);
|
||||
@@ -249,16 +262,26 @@ function structParser<TUPPLE extends boolean, T extends Record<TUPPLE extends tr
|
||||
},
|
||||
write(buffer, value) {
|
||||
if (typeof value != "object" || !value) { throw new Error("object expected"); }
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
if (key[0] == "$") { continue; }
|
||||
if (!(key in value)) { throw new Error(`struct has no property ${key}`); }
|
||||
let propvalue = value[key as string];
|
||||
for (let key of keys) {
|
||||
let propvalue: any;
|
||||
if (key[0] == "$") {
|
||||
propvalue = r.bubbleConditionValue!(value as any, key, 0, false);
|
||||
} else {
|
||||
// if (!(key in value)) { throw new Error(`struct has no property ${key}`); }
|
||||
propvalue = value[key];
|
||||
}
|
||||
let prop = props[key];
|
||||
//TODO calculate dependent values
|
||||
prop.write(buffer, propvalue);
|
||||
}
|
||||
},
|
||||
bubbleConditionValue(state, prop, val, isBubbling) {
|
||||
//prop is shadowed
|
||||
if (isBubbling && keys.indexOf(prop as any) != -1) { return val; }
|
||||
for (let key of keys) {
|
||||
val = props[key].bubbleConditionValue?.(state[key], prop, val, true) ?? val;
|
||||
}
|
||||
return val;
|
||||
},
|
||||
getTypescriptType(indent) {
|
||||
let r = (isTuple ? "[" : "{") + "\n";
|
||||
let newindent = indent + "\t";
|
||||
@@ -268,25 +291,49 @@ function structParser<TUPPLE extends boolean, T extends Record<TUPPLE extends tr
|
||||
}
|
||||
r += indent + (isTuple ? "]" : "}");
|
||||
return r;
|
||||
},
|
||||
getJsonSChema() {
|
||||
return {
|
||||
type: "object",
|
||||
properties: Object.fromEntries([...Object.entries(props)].map(([key, prop]) => {
|
||||
return [key, (prop as ChunkParser<any>).getJsonSChema()];
|
||||
})),
|
||||
required: keys
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function optParser<T>(type: ChunkParser<T>, condvar: string, condvalue: number, compare: CompareMode): ChunkParser<T | undefined> {
|
||||
let r: ChunkParser<T | undefined> = {
|
||||
function optParser<T>(type: ChunkParser<T>, condvar: string, condvalue: number, compare: CompareMode): ChunkParser<T | null> {
|
||||
let r: ChunkParser<T | null> = {
|
||||
read(buffer, ctx) {
|
||||
if (!checkCondition(r, ctx[condvar])) {
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
return type.read(buffer, ctx);
|
||||
},
|
||||
write(buffer, value) {
|
||||
if (typeof value != "undefined") {
|
||||
if ( value != null) {
|
||||
return type.write(buffer, value);
|
||||
}
|
||||
},
|
||||
bubbleConditionValue(state, prop, val) {
|
||||
if (prop == condvar) {
|
||||
val = forceCondition(this, val, state != null);
|
||||
}
|
||||
return val;
|
||||
},
|
||||
getTypescriptType(indent) {
|
||||
return type.getTypescriptType(indent) + " | undefined";
|
||||
return type.getTypescriptType(indent) + " | null";
|
||||
},
|
||||
getJsonSChema() {
|
||||
return {
|
||||
oneOf: [
|
||||
type.getJsonSChema(),
|
||||
{ type: "null" }
|
||||
]
|
||||
}
|
||||
},
|
||||
condName: condvar,
|
||||
condValue: condvalue,
|
||||
@@ -295,6 +342,19 @@ function optParser<T>(type: ChunkParser<T>, condvar: string, condvalue: number,
|
||||
return r;
|
||||
}
|
||||
|
||||
function forceCondition(parser: ChunkParser<any>, oldvalue: number, state: boolean) {
|
||||
switch (parser.condMode!) {
|
||||
case "eq":
|
||||
return state ? parser.condValue! : oldvalue;
|
||||
case "bitflag":
|
||||
return (state ? oldvalue | (1 << parser.condValue!) : oldvalue & ~(1 << parser.condValue!));
|
||||
case "bitflagnot":
|
||||
return (state ? oldvalue & ~(1 << parser.condValue!) : oldvalue | (1 << parser.condValue!));
|
||||
default:
|
||||
throw new Error("unkown condition " + parser.condMode);
|
||||
}
|
||||
}
|
||||
|
||||
function checkCondition(parser: ChunkParser<any>, v: number) {
|
||||
switch (parser.condMode!) {
|
||||
case "eq":
|
||||
@@ -315,7 +375,7 @@ function chunkedArrayParser<T>(lengthtype: ChunkParser<number>, chunktypes: Chun
|
||||
let r: T[] = [];
|
||||
let ctxs: any[] = [];
|
||||
for (let chunkindex = 0; chunkindex < chunktypes.length; chunkindex++) {
|
||||
let proptype = chunktypes[chunkindex]
|
||||
let proptype = chunktypes[chunkindex];
|
||||
for (let i = 0; i < len; i++) {
|
||||
let ctx: any;
|
||||
let obj: T;
|
||||
@@ -338,10 +398,23 @@ function chunkedArrayParser<T>(lengthtype: ChunkParser<number>, chunktypes: Chun
|
||||
write(buf, v) {
|
||||
throw new Error("not implemented");
|
||||
},
|
||||
bubbleConditionValue(state, prop, val) {
|
||||
if (state.length != 0) {
|
||||
for (let chunk of chunktypes) {
|
||||
val = chunk.bubbleConditionValue?.(state[0], prop, val, true) ?? val;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
},
|
||||
getTypescriptType(indent: string) {
|
||||
let joined = chunktypes.map(c => c.getTypescriptType(indent)).join(" & ");
|
||||
if (chunktypes.length == 1) { return `${joined}[]`; }
|
||||
else { return `(${joined})[]`; }
|
||||
},
|
||||
getJsonSChema() {
|
||||
return {
|
||||
allOf: chunktypes.flatMap(chunk => chunk.getJsonSChema())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,8 +436,20 @@ function arrayParser<T>(lengthtype: ChunkParser<number>, subtype: ChunkParser<T>
|
||||
subtype.write(buffer, value[i]);
|
||||
}
|
||||
},
|
||||
bubbleConditionValue(state, prop, val) {
|
||||
if (state.length != 0) {
|
||||
val = subtype.bubbleConditionValue?.(state[0], prop, val, true) ?? val;
|
||||
}
|
||||
return val;
|
||||
},
|
||||
getTypescriptType(indent) {
|
||||
return `${subtype.getTypescriptType(indent)}[]`;
|
||||
},
|
||||
getJsonSChema() {
|
||||
return {
|
||||
type: "array",
|
||||
items: subtype.getJsonSChema()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -387,7 +472,6 @@ function arrayNullTerminatedParser<T>(lengthtype: ChunkParser<number>, proptype:
|
||||
return r;
|
||||
},
|
||||
write(buffer, value) {
|
||||
//throw new Error("not implemented");
|
||||
if (!Array.isArray(value)) { throw new Error("array expected"); }
|
||||
for (let prop of value) {
|
||||
const lengthvalue = 1;//TODO get this from"prop"
|
||||
@@ -396,8 +480,20 @@ function arrayNullTerminatedParser<T>(lengthtype: ChunkParser<number>, proptype:
|
||||
}
|
||||
lengthtype.write(buffer, 0);
|
||||
},
|
||||
bubbleConditionValue(state, prop, val) {
|
||||
if (state.length != 0) {
|
||||
val = proptype.bubbleConditionValue?.(state[0], prop, val, true) ?? val;
|
||||
}
|
||||
return val;
|
||||
},
|
||||
getTypescriptType(indent) {
|
||||
return `${proptype.getTypescriptType(indent)}[]`;
|
||||
},
|
||||
getJsonSChema() {
|
||||
return {
|
||||
type: "array",
|
||||
items: proptype.getJsonSChema()
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -459,8 +555,8 @@ function intParser(primitive: PrimitiveInt): ChunkParser<number> {
|
||||
|
||||
let mask = ~(~0 << (bytes * 8 - 1));
|
||||
let int = (value & mask) | ((fitshalf ? 0 : 1) << (bytes * 8 - 1));
|
||||
//always write as signed since bitwise operations in js cast to int32
|
||||
buffer[`writeIntBE`](int, buffer.scan, bytes);
|
||||
//write 32bit ints as unsigned since js bitwise operations cast to int32
|
||||
buffer[`write${unsigned && bytes != 4 ? "U" : ""}IntBE`](int, buffer.scan, bytes);
|
||||
buffer.scan += bytes;
|
||||
} else if (readmode == "sumtail") {
|
||||
throw new Error("not implemented");
|
||||
@@ -471,6 +567,13 @@ function intParser(primitive: PrimitiveInt): ChunkParser<number> {
|
||||
},
|
||||
getTypescriptType() {
|
||||
return "number";
|
||||
},
|
||||
getJsonSChema() {
|
||||
return {
|
||||
type: "integer",
|
||||
maximum: 2 ** (primitive.bytes * 8 + (primitive.unsigned ? 0 : -1)) - 1,
|
||||
minimum: (primitive.unsigned ? 0 : 2 ** (primitive.bytes * 8 - 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
return parser;
|
||||
@@ -492,7 +595,11 @@ function literalValueParser<T>(primitive: PrimitiveValue<T>): ChunkParser<T> {
|
||||
} else {
|
||||
return typeof primitive.value;
|
||||
}
|
||||
|
||||
},
|
||||
getJsonSChema() {
|
||||
return {
|
||||
type: typeof primitive.value as any
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -506,11 +613,21 @@ function referenceValueParser(propname: string, minbit: number, bitlength: numbe
|
||||
return v;
|
||||
},
|
||||
write(buffer, value) {
|
||||
//need to make the struct writer grab its value from here for invisible props
|
||||
throw new Error("write for ref not implemented");
|
||||
//nop, value is written elsewhere
|
||||
},
|
||||
bubbleConditionValue(state, prop, val) {
|
||||
if (propname == prop) { val |= state << minbit; }
|
||||
return val;
|
||||
},
|
||||
getTypescriptType() {
|
||||
return "number";
|
||||
},
|
||||
getJsonSChema() {
|
||||
return {
|
||||
type: "integer",
|
||||
minimum: 0,
|
||||
maximum: 2 ** (bitlength * 8) - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,6 +663,9 @@ function intAccumlatorParser(refname: string, value: ChunkParser<number | undefi
|
||||
},
|
||||
getTypescriptType() {
|
||||
return "number";
|
||||
},
|
||||
getJsonSChema() {
|
||||
return { type: "integer" };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -576,7 +696,7 @@ function stringParser(primitive: PrimitiveString): ChunkParser<string> {
|
||||
validateStringType(primitive);
|
||||
let encoding = primitive.encoding;
|
||||
let termination = primitive.termination;
|
||||
let strbuf = Buffer.from(value, encoding);
|
||||
let strbuf = Buffer.from([...primitive.prebytes, ...Buffer.from(value, encoding)]);
|
||||
//either pad with 0's to fixed length and truncate and longer strings, or add a single 0 at the end
|
||||
let strbinbuf = Buffer.alloc(termination == null ? strbuf.byteLength + 1 : termination, 0);
|
||||
strbuf.copy(strbinbuf, 0, 0, Math.max(strbuf.byteLength, strbinbuf.byteLength));
|
||||
@@ -585,6 +705,9 @@ function stringParser(primitive: PrimitiveString): ChunkParser<string> {
|
||||
},
|
||||
getTypescriptType() {
|
||||
return "string";
|
||||
},
|
||||
getJsonSChema() {
|
||||
return { type: "string" };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -601,6 +724,9 @@ function booleanParser(): ChunkParser<boolean> {
|
||||
},
|
||||
getTypescriptType() {
|
||||
return "boolean";
|
||||
},
|
||||
getJsonSChema() {
|
||||
return { type: "boolean" };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
"extrasmap": [ "array",["struct",
|
||||
["$type","unsigned byte"],
|
||||
["prop","unsigned tribyte"],
|
||||
["intvalue",["opt",["$type",0],"unsigned int"]],
|
||||
["intvalue",["opt",["$type",0],"int"]],
|
||||
["stringvalue",["opt",["$type",1],"string"]]
|
||||
]]
|
||||
}
|
||||
@@ -2,12 +2,15 @@ import { filesource, cliArguments } from "../cliparser";
|
||||
import { run, command, number, option, string, boolean, Type, flag, oneOf } from "cmd-ts";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { cacheConfigPages, cacheMajors } from "../constants";
|
||||
import { parseAchievement, parseItem, parseObject, parseNpc, parseMapsquareTiles, FileParser, parseMapsquareUnderlays, parseMapsquareOverlays, parseMapZones, parseEnums, parseMapscenes } from "../opdecoder";
|
||||
import { achiveToFileId, CacheFileSource } from "../cache";
|
||||
import { cacheConfigPages, cacheMajors, cacheMapFiles } from "../constants";
|
||||
import { parseAchievement, parseItem, parseObject, parseNpc, parseMapsquareTiles, FileParser, parseMapsquareUnderlays, parseMapsquareOverlays, parseMapZones, parseEnums, parseMapscenes, parseMapsquareLocations } from "../opdecoder";
|
||||
import { achiveToFileId, CacheFileSource, CacheIndex, CacheIndexStub, fileIdToArchiveminor, SubFile } from "../cache";
|
||||
import { parseSprite } from "../3d/sprite";
|
||||
import sharp from "sharp";
|
||||
import { FlatImageData } from "../3d/utils";
|
||||
import { crc32 } from "crc";
|
||||
import * as cache from "../cache";
|
||||
import { GameCacheLoader } from "../cacheloader";
|
||||
|
||||
type KnownType = {
|
||||
index: number,
|
||||
@@ -18,12 +21,174 @@ type KnownType = {
|
||||
img?: (b: Buffer, source: CacheFileSource) => Promise<FlatImageData[]>
|
||||
}
|
||||
|
||||
type CacheFileId = {
|
||||
index: CacheIndex,
|
||||
subfile: number
|
||||
}
|
||||
|
||||
type LogicalIndex = number[];
|
||||
|
||||
async function filerange(source: CacheFileSource, startindex: FileId, endindex: FileId) {
|
||||
if (startindex.major != endindex.major) { throw new Error("range must span one major"); }
|
||||
let indexfile = await source.getIndexFile(startindex.major);
|
||||
let files: CacheFileId[] = [];
|
||||
for (let index of indexfile) {
|
||||
if (!index) { continue; }
|
||||
if (index.minor >= startindex.minor && index.minor <= endindex.minor) {
|
||||
for (let fileindex = 0; fileindex < index.subindices.length; fileindex++) {
|
||||
let subfileid = index.subindices[fileindex];
|
||||
if (index.minor == startindex.minor && subfileid < startindex.subindex) { continue; }
|
||||
if (index.minor == endindex.minor && subfileid > endindex.subindex) { continue; }
|
||||
files.push({ index, subfile: fileindex });
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
function worldmapIndex(subfile: number): DecodeLookup {
|
||||
const major = cacheMajors.mapsquares;
|
||||
const worldStride = 128;
|
||||
return {
|
||||
major,
|
||||
async logicalRangeToFiles(source, start, end) {
|
||||
let indexfile = await source.getIndexFile(major);
|
||||
let files: CacheFileId[] = [];
|
||||
for (let index of indexfile) {
|
||||
if (!index) { continue; }
|
||||
let x = index.minor % worldStride;
|
||||
let z = Math.floor(index.minor / worldStride);
|
||||
if (x >= start[0] && x <= end[0] && z >= start[1] && z <= end[1]) {
|
||||
for (let fileindex = 0; fileindex < index.subindices.length; fileindex++) {
|
||||
let subfileid = index.subindices[fileindex];
|
||||
if (subfileid == subfile) {
|
||||
files.push({ index, subfile: fileindex });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
},
|
||||
fileToLogical(major, minor, subfile) {
|
||||
return [minor % worldStride, Math.floor(minor / worldStride)];
|
||||
},
|
||||
logicalToFile(id: LogicalIndex) {
|
||||
return { major, minor: id[0] + id[1] * worldStride, subindex: subfile };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function singleMinorIndex(major: number, minor: number): DecodeLookup {
|
||||
return {
|
||||
major,
|
||||
async logicalRangeToFiles(source, start, end) {
|
||||
return filerange(source, { major, minor, subindex: start[0] }, { major, minor, subindex: end[0] });
|
||||
},
|
||||
fileToLogical(major, minor, subfile) {
|
||||
return [subfile];
|
||||
},
|
||||
logicalToFile(id: LogicalIndex) {
|
||||
return { major, minor, subindex: id[0] };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function chunkedIndex(major: number): DecodeLookup {
|
||||
return {
|
||||
major,
|
||||
async logicalRangeToFiles(source, start, end) {
|
||||
let startindex = fileIdToArchiveminor(major, start[0]);
|
||||
let endindex = fileIdToArchiveminor(major, end[0]);
|
||||
return filerange(source, startindex, endindex);
|
||||
},
|
||||
fileToLogical(major, minor, subfile) {
|
||||
return [achiveToFileId(major, minor, subfile)];
|
||||
},
|
||||
logicalToFile(id: LogicalIndex) {
|
||||
return fileIdToArchiveminor(major, id[0]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function standardFile(parser: FileParser<any>, lookup: DecodeLookup): DecodeModeFactory {
|
||||
let constr: DecodeModeFactory = (outdir) => {
|
||||
let name = Object.entries(modes).find(q => q[1] == constr);
|
||||
if (!name) { throw new Error(); }
|
||||
let schema = parser.parser.getJsonSChema();
|
||||
let relurl = `./.schema-${name[0]}.json`;
|
||||
fs.writeFileSync(path.resolve(outdir, relurl), JSON.stringify(schema, undefined, "\t"));
|
||||
return {
|
||||
...lookup,
|
||||
ext: "json",
|
||||
read(b) {
|
||||
let obj = parser.read(b);
|
||||
obj.$schema = relurl;
|
||||
return JSON.stringify(obj, undefined, "\t");
|
||||
},
|
||||
write(b) {
|
||||
return parser.write(JSON.parse(b.toString("utf8")));
|
||||
}
|
||||
}
|
||||
}
|
||||
return constr;
|
||||
}
|
||||
|
||||
type DecodeModeFactory = (outdir: string) => DecodeMode;
|
||||
|
||||
type FileId = { major: number, minor: number, subindex: number };
|
||||
|
||||
type DecodeLookup = {
|
||||
major: number | undefined,
|
||||
logicalRangeToFiles(source: CacheFileSource, start: LogicalIndex, end: LogicalIndex): Promise<CacheFileId[]>,
|
||||
fileToLogical(major: number, minor: number, subfile: number): LogicalIndex,
|
||||
logicalToFile(id: LogicalIndex): FileId,
|
||||
}
|
||||
|
||||
type DecodeMode = {
|
||||
ext: string,
|
||||
read(buf: Buffer): (Buffer | string),
|
||||
write(files: Buffer): Buffer
|
||||
} & DecodeLookup;
|
||||
|
||||
const decodeBinary: DecodeModeFactory = () => {
|
||||
return {
|
||||
ext: "bin",
|
||||
major: undefined,
|
||||
fileToLogical(major, minor, subfile) { return [major, minor, subfile]; },
|
||||
logicalToFile(id) { return { major: id[0], minor: id[1], subindex: id[2] }; },
|
||||
async logicalRangeToFiles(source, start, end) {
|
||||
if (start[0] != end[0]) { throw new Error("can only do one major at a time"); }
|
||||
let major = start[0];
|
||||
return filerange(source, { major, minor: start[1], subindex: start[2] }, { major, minor: start[1], subindex: start[2] });
|
||||
},
|
||||
read(b) { return b; },
|
||||
write(b) { return b; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const modes: Record<string, DecodeModeFactory> = {
|
||||
bin: decodeBinary,
|
||||
|
||||
items: standardFile(parseItem, chunkedIndex(cacheMajors.items)),
|
||||
npcs: standardFile(parseNpc, chunkedIndex(cacheMajors.npcs)),
|
||||
objects: standardFile(parseObject, chunkedIndex(cacheMajors.objects)),
|
||||
achievements: standardFile(parseAchievement, chunkedIndex(cacheMajors.achievements)),
|
||||
|
||||
overlays: standardFile(parseMapsquareOverlays, singleMinorIndex(cacheMajors.config, cacheConfigPages.mapoverlays)),
|
||||
underlays: standardFile(parseMapsquareUnderlays, singleMinorIndex(cacheMajors.config, cacheConfigPages.mapunderlays)),
|
||||
mapscenes: standardFile(parseMapscenes, singleMinorIndex(cacheMajors.config, cacheConfigPages.mapscenes)),
|
||||
|
||||
maptiles: standardFile(parseMapsquareTiles, worldmapIndex(cacheMapFiles.squares)),
|
||||
maplocations: standardFile(parseMapsquareLocations, worldmapIndex(cacheMapFiles.locations)),
|
||||
}
|
||||
|
||||
const decoders: Record<string, KnownType> = {
|
||||
items: { index: cacheMajors.items, parser: parseItem },
|
||||
npcs: { index: cacheMajors.npcs, parser: parseNpc },
|
||||
objects: { index: cacheMajors.objects, parser: parseObject },
|
||||
achievements: { index: cacheMajors.achievements, parser: parseAchievement },
|
||||
sprites: { index: cacheMajors.sprites, img: (b) => Promise.resolve(parseSprite(b)) },
|
||||
sprites: { index: cacheMajors.sprites, img: async (b) => parseSprite(b) },
|
||||
|
||||
overlays: { index: cacheMajors.config, minor: cacheConfigPages.mapoverlays, parser: parseMapsquareOverlays },
|
||||
underlays: { index: cacheMajors.config, minor: cacheConfigPages.mapunderlays, parser: parseMapsquareOverlays },
|
||||
@@ -32,10 +197,97 @@ const decoders: Record<string, KnownType> = {
|
||||
mapzones: { index: cacheMajors.worldmap, minor: 0, parser: parseMapZones },
|
||||
|
||||
enums: { index: cacheMajors.enums, minor: 0, parser: parseEnums },
|
||||
|
||||
|
||||
maptiles: { index: cacheMajors.mapsquares, subfile: 3, parser: parseMapsquareTiles },
|
||||
}
|
||||
|
||||
let cmd2 = command({
|
||||
name: "run",
|
||||
args: {
|
||||
...filesource,
|
||||
save: option({ long: "save", short: "s", type: string, defaultValue: () => "extract" }),
|
||||
mode: option({ long: "mode", short: "m", type: string }),
|
||||
files: option({ long: "ids", short: "i", type: string }),
|
||||
edit: flag({ long: "edit", short: "e" })
|
||||
},
|
||||
handler: async (args) => {
|
||||
let modeconstr = modes[args.mode];
|
||||
if (!modeconstr) { throw new Error("unknown mode"); }
|
||||
let outdir = path.resolve(args.save);
|
||||
let mode = modeconstr(outdir);
|
||||
fs.mkdirSync(outdir, { recursive: true });
|
||||
|
||||
let parts = args.files.split(",");
|
||||
let ranges = parts.map(q => {
|
||||
let ends = q.split("-");
|
||||
let start = ends[0].split(".");
|
||||
let end = (ends[1] ?? ends[0]).split(".");
|
||||
return {
|
||||
start: [+start[0], +(start[1] ?? 0)] as [number, number],
|
||||
end: [+end[0], +(end[1] ?? Infinity)] as [number, number]
|
||||
}
|
||||
});
|
||||
|
||||
let source = await args.source({ writable: args.edit });
|
||||
|
||||
let allfiles = (await Promise.all(ranges.map(q => mode.logicalRangeToFiles(source, q.start, q.end))))
|
||||
.flat()
|
||||
.sort((a, b) => a.index.major != b.index.major ? a.index.major - b.index.major : a.index.minor != b.index.minor ? a.index.minor - b.index.minor : a.subfile - b.subfile);
|
||||
|
||||
|
||||
let lastarchive: null | { index: CacheIndex, subfiles: SubFile[] } = null;
|
||||
for (let fileid of allfiles) {
|
||||
let arch: SubFile[];
|
||||
if (lastarchive && lastarchive.index == fileid.index) {
|
||||
arch = lastarchive.subfiles;
|
||||
} else {
|
||||
arch = await source.getFileArchive(fileid.index);
|
||||
lastarchive = { index: fileid.index, subfiles: arch };
|
||||
|
||||
// let modenet = cache.packBufferArchive(arch.map(q => q.buffer));
|
||||
// console.log("modenet", modenet.byteLength, crc32(modenet));
|
||||
// console.log("actual", fileid.index.uncompressed_size, fileid.index.uncompressed_crc);
|
||||
}
|
||||
let file = arch[fileid.subfile].buffer;
|
||||
let res = mode.read(file);
|
||||
let logicalid = mode.fileToLogical(fileid.index.major, fileid.index.minor, fileid.subfile);
|
||||
let filename = path.resolve(outdir, `${args.mode}-${logicalid.join("_")}.${mode.ext}`);
|
||||
fs.writeFileSync(filename, res);
|
||||
}
|
||||
|
||||
|
||||
if (args.edit) {
|
||||
await new Promise<any>(d => process.stdin.once('data', d));
|
||||
|
||||
let archedited = () => {
|
||||
if (!(source instanceof GameCacheLoader)) { throw new Error("can only do this on file source of type gamecacheloader"); }
|
||||
if (lastarchive) {
|
||||
console.log("writing archive", lastarchive.index.major, lastarchive.index.minor, "files", lastarchive.subfiles.length);
|
||||
return source.writeFileArchive(lastarchive.index, lastarchive.subfiles.map(q => q.buffer));
|
||||
}
|
||||
}
|
||||
|
||||
for (let fileid of allfiles) {
|
||||
let arch: SubFile[];
|
||||
if (lastarchive && lastarchive.index == fileid.index) {
|
||||
arch = lastarchive.subfiles;
|
||||
} else {
|
||||
await archedited();
|
||||
arch = await source.getFileArchive(fileid.index);
|
||||
lastarchive = { index: fileid.index, subfiles: arch };
|
||||
}
|
||||
let logicalid = mode.fileToLogical(fileid.index.major, fileid.index.minor, fileid.subfile);
|
||||
let filename = path.resolve(outdir, `${args.mode}-${logicalid.join("_")}.${mode.ext}`);
|
||||
let newfile = fs.readFileSync(filename);
|
||||
arch[fileid.subfile].buffer = mode.write(newfile);
|
||||
}
|
||||
await archedited();
|
||||
}
|
||||
source.close();
|
||||
console.log("done");
|
||||
}
|
||||
})
|
||||
|
||||
let cmd = command({
|
||||
name: "download",
|
||||
args: {
|
||||
@@ -135,4 +387,4 @@ let cmd = command({
|
||||
}
|
||||
});
|
||||
|
||||
run(cmd, cliArguments());
|
||||
run(cmd2, cliArguments());
|
||||
|
||||
Reference in New Issue
Block a user