1
0
mirror of https://github.com/Escartem/AnimeWwise.git synced 2026-06-04 23:40:25 +08:00

map v3 and update hsr to 3.7

This commit is contained in:
Escartem
2025-11-25 18:12:40 -05:00
parent 872e32e89a
commit 5c9125a7c4
5 changed files with 96 additions and 167 deletions

259
mapper.py
View File

@@ -1,39 +1,33 @@
# reader for the .map format i've made to improve reading speed and mapping size # reader for the .map format i've made to improve reading speed and mapping size
import io
import json
from filereader import FileReader from filereader import FileReader
class Mapper: class Mapper:
def __init__(self, mapping_file): def __init__(self, mapping_file):
file = open(mapping_file, "rb") file = open(mapping_file, "rb")
reader = FileReader(file, "little") # encoded as little self.data = file.read()
file.close()
reader = FileReader(io.BytesIO(self.data), "little")
# check file # check file
if reader.ReadBytes(4) != b"ESFM": if reader.ReadBytes(4) != b"ESFM":
file.close()
raise Exception("mapping was invalid") raise Exception("mapping was invalid")
reader.ReadBytes(2) reader.ReadBytes(2)
map_version = reader.ReadBytes(2) map_version = reader.ReadBytes(2)
if map_version != b"\x32\x31": if map_version != b"\x33\x30":
print(f"Warning: you are using an unknown / unsupported version of the mapping that is no longer supported, please use a newer one or download an older version of this tool.") print(f"Warning: you are using an unknown / unsupported version of the mapping that is no longer supported, please use a newer one or download an older version of this tool.")
raise Exception("incompatible mapping") raise Exception("incompatible mapping")
self.reader = reader
self.process_map()
def process_map(self):
reader = self.reader
# utils
val = lambda length: vl2(reader.ReadBytes(length))
vl2 = lambda data: int.from_bytes(data, "little")
raw = lambda length: rw2(reader.ReadBytes(length))
rw2 = lambda data: data.rstrip(b"\x00").decode("utf-8")
# get map meta
reader.ReadBytes(2) reader.ReadBytes(2)
self.process_map(reader)
def process_map(self, reader):
games = { games = {
"hk4e": "Genshin", "hk4e": "Genshin",
"hkrpg": "Star Rail", "hkrpg": "Star Rail",
@@ -41,156 +35,72 @@ class Mapper:
# more later # more later
} }
coverages = [
"english voicelines",
"chinese voicelines",
"japanese voicelines",
"korean voicelines",
"music",
"sfx"
]
# read sectors
sectors_signature = reader.ReadBytes(9)
if sectors_signature != b"\xFF\x53\x45\x43\x54\x4F\x52\x53\xFF": # ff sectors ff
raise Exception("invalid mapping sectors signature")
n_sectors = val(1)
sectors = {}
for i in range(n_sectors):
name_length = val(1)
name = raw(name_length)
offset = val(4)
size = val(4)
sectors[name] = {
"offset": offset,
"size": size
}
# read config # read config
reader.SetBufferPos(sectors["HEADER"]["offset"]) game_size = reader.ReadInt8()
game = reader.ReadBytes(game_size).decode("utf-8")
header_sig = reader.ReadBytes(8) # hardcoded but lazy, this value is for this sector only
n_configs = val(1)
config = {}
for i in range(n_configs):
name = raw(4)
value = raw(5)
config[name] = value
infos = { infos = {
"game": games[config["game"]], "game": games[game],
"version": config["verS"], "version": ".".join(list(str(reader.ReadInt8())))
# "coverage": config["covR"],
"useBanksSector": config["bnkS"],
# "bankSectorCoverage": config["bCov"]
} }
print(f"> Loading mapping for {infos['game']} v{infos['version']}, this may take a few seconds...") print(f"> Loading mapping for {infos['game']} v{infos['version']}, this may take a few seconds...")
# read prefixes # sectors
prefixes = {} int24 = lambda: int.from_bytes(reader.ReadBytes(3))
n_prefixes = reader.ReadUInt8()
l_prefixes = reader.ReadUInt8()
for i in range(n_prefixes): sectors = {
prefix = raw(l_prefixes) # offset | size
marker = reader.ReadBytes(1) "languages": [int24(), int24()],
prefixes[marker] = prefix "strings": [int24(), int24()],
"words": [int24(), int24()],
"files": [int24(), int24()],
"keys": [int24(), int24()],
"music": [int24(), int24()]
}
# sector jump here # languages
reader.SetBufferPos(sectors["ITEMS"]["offset"]) reader.SetBufferPos(sectors["languages"][0])
self.languages = []
items_sec_sig = reader.ReadBytes(7) # hardcoded too n_langs = reader.ReadInt8()
# read languages
langs_offsets = {}
n_langs = reader.ReadUInt8()
l_langs = reader.ReadUInt8()
for i in range(n_langs): for i in range(n_langs):
offset = reader.GetBufferPos() size = reader.ReadInt8()
langs_offsets[offset] = raw(l_langs) name = reader.ReadBytes(size).decode("utf-8")
self.languages.append(name)
self.langs_offsets = langs_offsets # alloc sectors
reader.SetBufferPos(sectors["strings"][0])
# read folders self.strings = bytearray(reader.ReadBytes(sectors["strings"][1]))
folder_offsets = {} reader.SetBufferPos(sectors["words"][0])
n_folders = reader.ReadUInt16() self.words = bytearray(reader.ReadBytes(sectors["words"][1]))
reader.SetBufferPos(sectors["files"][0])
for i in range(n_folders): self.files = bytearray(reader.ReadBytes(sectors["files"][1]))
offset = reader.GetBufferPos()
length = reader.ReadUInt8()
prefix = reader.ReadBytes(1)
folder = raw(length)
folder = f"{prefixes[prefix]}{folder}"
folder_offsets[offset] = folder
# read files
files_offsets = {}
n_files = val(3)
for i in range(n_files):
offset = reader.GetBufferPos()
path_length = reader.ReadUInt8()
path = []
for i in range(path_length):
path.append(folder_offsets[reader.ReadUInt16()])
name_length = reader.ReadUInt8()
prefix = reader.ReadBytes(1)
if prefix != b"\x00":
prefix = prefixes[prefix]
else:
prefix = ""
name = raw(name_length)
name = f"{prefix}{name}"
path.append(name)
path = "\\".join(path)
files_offsets[offset] = path
self.files_offsets = files_offsets
# read keys # read keys
# GI 3649050 (outdated value, use items sector size instead) reader.SetBufferPos(sectors["keys"][0])
keys_data = {} key_size = reader.ReadInt8()
n_keys = val(3) n_keys = (sectors["keys"][1]-1) // key_size
n_files = n_keys // n_langs
left = reader.GetRemainingLength() keys_data = bytearray(reader.ReadBytes(sectors["keys"][1]-1))
if infos["useBanksSector"] == "TRUE": self.keys = {keys_data[i+3:i+key_size].hex(): int.from_bytes(keys_data[i:i+3]) for i in range(0, len(keys_data), key_size)}
left -= sectors["BANKS"]["size"]
data = bytearray(reader.ReadBytes(left)) # music
keys_data = {rw2(data[i:i+16]): bytes(data[i+16:i+21]) for i in range(0, len(data), 21)} self.music_keys = {}
hasMusic = sectors["music"][1] > 0
self.keys_data = keys_data if hasMusic:
reader.SetBufferPos(sectors["music"][0])
root_size = reader.ReadInt8()
root = reader.ReadBytes(root_size).decode("utf-8")
n_music = int.from_bytes(reader.ReadBytes(2))
# read banks sector for i in range(n_music):
bank_keys = {} key = int.from_bytes(reader.ReadBytes(4))
if infos["useBanksSector"] == "TRUE": name_size = reader.ReadInt8()
reader.SetBufferPos(sectors["BANKS"]["offset"]) name = reader.ReadBytes(name_size).decode("utf-8")
self.music_keys[str(key)] = f"{root}\\{name}"
banks_sec_sig = reader.ReadBytes(7) # hardcoded
global_path_size = val(1)
global_path = raw(global_path_size)
n_bank_keys = val(2)
for i in range(n_bank_keys):
key_length = val(1)
key = raw(key_length)
value_length = val(1)
value = raw(value_length)
bank_keys[key] = f"{global_path}\\{value}"
self.bank_keys = bank_keys
# done # done
print(f"> Finished loading mapping") print(f"> Finished loading mapping")
@@ -198,30 +108,49 @@ class Mapper:
print(f": {n_langs} languages") print(f": {n_langs} languages")
print(f": {n_files} mapped files") print(f": {n_files} mapped files")
print(f": {n_keys} keys") print(f": {n_keys} keys")
if infos["useBanksSector"] == "TRUE": if hasMusic:
print(f"=-=-= Music sector =-=-=") print(f": {n_music} musics")
print(f": {n_bank_keys} keys")
def get_key(self, key, lang=False): def get_key(self, key, lang=False):
keys_data = self.keys_data if (not key in self.keys) and (not key in self.music_keys):
banks_data = self.bank_keys return None
if key in keys_data.keys(): if key in self.music_keys:
key_data = keys_data[key] return [self.music_keys[key], ""]
data = [self.files_offsets[int.from_bytes(key_data[2:], "little")]]
if lang: lang, offset = (self.keys[key] >> 22) & 0x03, self.keys[key] & 0x3FFFFF
data.append(self.langs_offsets[int.from_bytes(key_data[:1], "little")])
return data parts = int.from_bytes(self.files[offset:offset+1])
name = []
if key in banks_data.keys(): for i in range(parts):
return [banks_data[str(key)], ""] word_offset = int.from_bytes(self.files[offset+1+(3*i):offset+4+(3*i)])
word_parts = int.from_bytes(self.words[word_offset:word_offset+1])
word = []
return None for j in range(word_parts):
string_offset = int.from_bytes(self.words[word_offset+1+(2*j):word_offset+3+(2*j)])
string_size = int.from_bytes(self.strings[string_offset:string_offset+1])
if string_size > 128:
string = str(int.from_bytes(self.strings[string_offset+1:string_offset+1+(string_size-128)]))
else:
string = self.strings[string_offset+1:string_offset+1+string_size].decode("utf-8")
word.append(string)
word = "_".join(word)
name.append(word)
name = ["\\".join(name)]
if lang:
name.append(self.languages[lang])
return name
def reset(self): def reset(self):
self.reader = None self.reader = None
self.langs_offsets.clear() self.languages.clear()
self.files_offsets.clear() self.strings.clear()
self.keys_data.clear() self.words.clear()
self.files.clear()
self.music_keys.clear()

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{ {
"version": 221, "version": 221,
"mapsVersion": 119, "mapsVersion": 120,
"maps": [ "maps": [
{ {
"name": "hk4e.map", "name": "hk4e.map",
@@ -10,7 +10,7 @@
{ {
"name": "hkrpg.map", "name": "hkrpg.map",
"game": "Honkai: Star Rail", "game": "Honkai: Star Rail",
"version": "3.6" "version": "3.7"
}, },
{ {
"name": "nap.map", "name": "nap.map",