2021-10-21 21:15:01 +08:00
|
|
|
import os
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
from tqdm import tqdm
|
2022-04-14 16:37:54 -03:00
|
|
|
|
2021-10-21 21:15:01 +08:00
|
|
|
from dev_tools.slpp import slpp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LuaLoader:
|
|
|
|
|
"""
|
|
|
|
|
Load decrypted scripts
|
|
|
|
|
"""
|
|
|
|
|
|
2021-11-14 12:36:42 +08:00
|
|
|
server_alias = [
|
|
|
|
|
['zh-CN', 'zh-cn', 'cn', 'CN'],
|
|
|
|
|
['en-US', 'en-us', 'en', 'EN'],
|
|
|
|
|
['ja-JP', 'ja-jp', 'jp', 'JP'],
|
|
|
|
|
['zh-TW', 'zh-tw', 'tw', 'TW'],
|
|
|
|
|
['ko-KR', 'ko-kr', 'kr', 'KR'],
|
|
|
|
|
]
|
|
|
|
|
|
2021-10-21 21:15:01 +08:00
|
|
|
def __init__(self, folder, server='zh-CN'):
|
2024-06-28 03:19:37 +08:00
|
|
|
self.folder = folder
|
2021-11-14 12:36:42 +08:00
|
|
|
self._server = ''
|
2021-10-21 21:15:01 +08:00
|
|
|
self.server = server
|
|
|
|
|
|
2021-11-14 12:36:42 +08:00
|
|
|
@property
|
|
|
|
|
def server(self):
|
|
|
|
|
return self._server
|
|
|
|
|
|
|
|
|
|
@server.setter
|
|
|
|
|
def server(self, value):
|
|
|
|
|
self._server = self.get_alias(value)
|
|
|
|
|
|
|
|
|
|
def get_alias(self, server):
|
|
|
|
|
for alias_list in self.server_alias:
|
|
|
|
|
if server in alias_list:
|
|
|
|
|
for alias in alias_list:
|
|
|
|
|
folder = os.path.join(self.folder, alias)
|
|
|
|
|
if os.path.exists(folder) and os.path.isdir(folder):
|
|
|
|
|
return alias
|
|
|
|
|
|
|
|
|
|
return server
|
|
|
|
|
|
2021-10-21 21:15:01 +08:00
|
|
|
def filepath(self, path):
|
|
|
|
|
return os.path.join(self.folder, self.server, path)
|
|
|
|
|
|
2026-05-11 17:04:48 +08:00
|
|
|
def _find_matching_brace(self, text, start_index):
|
|
|
|
|
depth = 0
|
|
|
|
|
in_string = None
|
|
|
|
|
escape = False
|
|
|
|
|
for i in range(start_index, len(text)):
|
|
|
|
|
ch = text[i]
|
|
|
|
|
if in_string:
|
|
|
|
|
if escape:
|
|
|
|
|
escape = False
|
|
|
|
|
elif ch == '\\':
|
|
|
|
|
escape = True
|
|
|
|
|
elif ch == in_string:
|
|
|
|
|
in_string = None
|
|
|
|
|
else:
|
|
|
|
|
if ch in ('"', "'"):
|
|
|
|
|
in_string = ch
|
|
|
|
|
elif ch == '{':
|
|
|
|
|
depth += 1
|
|
|
|
|
elif ch == '}':
|
|
|
|
|
depth -= 1
|
|
|
|
|
if depth == 0:
|
|
|
|
|
return i
|
|
|
|
|
return -1
|
|
|
|
|
|
|
|
|
|
def _infer_base_name(self, file, keyword):
|
|
|
|
|
if keyword:
|
|
|
|
|
keyword = keyword.strip()
|
|
|
|
|
if keyword.startswith('pg.base.'):
|
2026-05-11 18:55:23 +08:00
|
|
|
return keyword[len('pg.base.'):]
|
2026-05-11 17:04:48 +08:00
|
|
|
if keyword.startswith('pg.'):
|
2026-05-11 18:55:23 +08:00
|
|
|
return keyword[len('pg.'):]
|
2026-05-11 17:04:48 +08:00
|
|
|
return keyword
|
|
|
|
|
return os.path.splitext(os.path.basename(file))[0]
|
|
|
|
|
|
|
|
|
|
def _load_pg_base_entries(self, text, base_name):
|
|
|
|
|
pattern = rf"pg\.base\.{re.escape(base_name)}\[(\d+)\]\s*=\s*\{{"
|
|
|
|
|
result = {}
|
|
|
|
|
for m in re.finditer(pattern, text):
|
|
|
|
|
start = m.end() - 1
|
|
|
|
|
end = self._find_matching_brace(text, start)
|
|
|
|
|
if end == -1:
|
|
|
|
|
continue
|
|
|
|
|
table_text = text[start:end + 1]
|
|
|
|
|
result[int(m.group(1))] = slpp.decode(table_text)
|
|
|
|
|
return result
|
|
|
|
|
|
2025-12-09 12:24:23 +08:00
|
|
|
def _load_file(self, file, keyword=None):
|
2021-10-21 21:15:01 +08:00
|
|
|
"""
|
|
|
|
|
Args:
|
|
|
|
|
file (str):
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
dict:
|
|
|
|
|
"""
|
|
|
|
|
with open(self.filepath(file), 'r', encoding='utf-8') as f:
|
|
|
|
|
text = f.read()
|
|
|
|
|
|
2026-05-11 17:04:48 +08:00
|
|
|
if 'pg.base.' in text:
|
|
|
|
|
base_name = self._infer_base_name(file, keyword)
|
|
|
|
|
if not base_name:
|
|
|
|
|
m = re.search(r"pg\.base\.([A-Za-z0-9_]+)\[", text)
|
|
|
|
|
base_name = m.group(1) if m else None
|
|
|
|
|
if base_name:
|
|
|
|
|
result = self._load_pg_base_entries(text, base_name)
|
|
|
|
|
if result:
|
|
|
|
|
return result
|
|
|
|
|
|
2021-10-21 21:15:01 +08:00
|
|
|
result = {}
|
2025-12-18 18:00:39 +08:00
|
|
|
matched = re.findall('function \(\)(.*?)end[()]', text, re.S)
|
|
|
|
|
if matched:
|
|
|
|
|
# Most files are in this format
|
|
|
|
|
"""
|
|
|
|
|
pg = pg or {}
|
|
|
|
|
slot0 = pg
|
|
|
|
|
slot0.chapter_template = {}
|
|
|
|
|
|
|
|
|
|
(function ()
|
|
|
|
|
...
|
|
|
|
|
end)()
|
|
|
|
|
"""
|
|
|
|
|
for func in matched:
|
|
|
|
|
add = slpp.decode('{' + func + '}')
|
|
|
|
|
result.update(add)
|
|
|
|
|
elif text.startswith('pg'):
|
|
|
|
|
# Old format
|
|
|
|
|
"""
|
|
|
|
|
pg = pg or {}
|
|
|
|
|
pg.item_data_statistics = {
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
"""
|
|
|
|
|
# or
|
|
|
|
|
"""
|
|
|
|
|
pg = pg or {}
|
|
|
|
|
|
|
|
|
|
rawset(pg, "item_data_statistics", rawget(pg, "item_data_statistics") or {
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
"""
|
|
|
|
|
text = '{' + text.split('{', 2)[2]
|
2021-10-21 21:15:01 +08:00
|
|
|
result = slpp.decode(text)
|
2025-12-09 12:24:23 +08:00
|
|
|
else:
|
2025-12-18 18:00:39 +08:00
|
|
|
# Another format, just bare data
|
|
|
|
|
"""
|
|
|
|
|
_G.pg.expedition_data_template[...] = {
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
_G.pg.expedition_data_template[...] = {
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
...
|
|
|
|
|
"""
|
|
|
|
|
text = '{' + text + '}'
|
|
|
|
|
result = slpp.decode(text)
|
|
|
|
|
|
2021-10-21 21:15:01 +08:00
|
|
|
return result
|
|
|
|
|
|
2025-12-09 12:24:23 +08:00
|
|
|
def load(self, path, keyword=None):
|
2021-10-21 21:15:01 +08:00
|
|
|
"""
|
|
|
|
|
Load a lua file to python dictionary, handling the differences
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
path (str): Relavice path from {folder}/{server}.
|
|
|
|
|
Can be a file or a directory
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
dict:
|
|
|
|
|
"""
|
|
|
|
|
print(f'Loading {path}')
|
|
|
|
|
if os.path.isdir(self.filepath(path)):
|
|
|
|
|
result = {}
|
|
|
|
|
for file in tqdm(os.listdir(self.filepath(path))):
|
2026-05-11 17:04:48 +08:00
|
|
|
result.update(self._load_file(f'./{path}/{file}', keyword=keyword))
|
2021-10-21 21:15:01 +08:00
|
|
|
else:
|
2025-12-09 12:24:23 +08:00
|
|
|
result = self._load_file(path, keyword=keyword)
|
2021-10-21 21:15:01 +08:00
|
|
|
|
|
|
|
|
print(f'{len(result.keys())} items loaded')
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
# Use example
|
|
|
|
|
lua = LuaLoader(r'xxx/AzurLaneData', server='en-US')
|
|
|
|
|
res = lua.load('./sharecfg/item_data_statistics.lua')
|