I've added some cheats based on the cheats on the following website.
https://fearlessrevolution.com/viewtopic.php?t=23502
・fixed the issue where the HP and DP cheats weren't working.
・Add the following cheats
- Inventory Editor (Item / Soul Pact / Catalyst / Equip).
- Max Soul Pact Stars when selected
- Set Selected Item to 50
- Set All Inventory Items to 50 (Exclude Valuables)
- Mana & Silver Coin Editor
You can extract the master data (CSV/TSV) from data.dat. This contains information useful for cheat analysis.
The game data isn't simply compressed into a ZIP file or folder;
it has a triple-layered structure: "proprietary archive structure" + "LZ4 compression" + "PhyreEngine binary container".
The method for obtaining it is described below.
Code: Select all
data.dat (Full Archive)
│
├── [1. Header & Metadata Table] … File List, Placement Offset, Size
│
└── [2. YKCMP_V1 (LZ4 Compressed Data)]
│
▼ (Decompress with lz4.dll)
[3. .csv.phyre (Sony PhyreEngine Binary)]
│
▼ (Header Removed & Raw Text Extracted)
Actual Data CSV (TSV / Tab-Delimited Text)
Specific Extraction Procedure (4 Steps)
Step 1: Index Analysis of data.dat (Reading the Table of Contents)
The first 64 bytes of data.dat (header) contain the table of contents information for the entire archive.
Header Structure (64-bit Little Endian):
0x08–0x0F: Total number of files (num_files)
0x10–0x17: Start offset of the filename table (name_table_off)
0x18–0x1F: Size of the filename table (name_table_sz)
0x20–0x27: Start offset of the metadata table (meta_table_off)
Metadata Table:
Each entry consists of 48 bytes (8 bytes × 6 numbers), recording the "filename offset," "data storage offset," and "file size" for each file.
Step 2: Identify the Path to the Target CSV File
Expand the filename table and find the path where the game parameters are stored.
Internal path: data/win/bin/csv/ (Example: data/win/bin/csv/equip/equip_table.csv.phyre)
Exclude dialogue text (adv/) and UI data (ui/), and list master data (approximately 100 files) such as equipment, items, soul books, and catalysts.
Step 3: Data extraction and LZ4 decompression
Read the binary from data.dat based on the identified offset and size.
If the signature YKCMP_V1 is present near the beginning of the data (offset 0x0C to 0x14), it is LZ4 compressed data with Nippon Ichi Software's proprietary compression header.
Call lz4.dll located in the game's installation folder via Python's ctypes and decompress it into memory using the LZ4_decompress_safe function.
Step 4: Recovering the Raw CSV Text from the .phyre Container
The unzipped data is in a binary format (.phyre) specific to the game engine (Sony PhyreEngine).
A binary scan of the binary revealed that the tab-separated CSV body, written in UTF-8, is embedded directly after the internal path name (csv/.../*.csv).
By slicing from the first tab character (\t) immediately following the path to the terminating null byte (\x00\x00), the data was written to a file as a pure .csv (TSV format) text file.
The following is a Python script that combines the above steps into one:
Before use, please specify the data.dat, l4z.dll, and the output folder for multiple CSV files according to your environment.
Code: Select all
import struct, os, re, ctypes
dat_path = r"Please enter the path to the data.dat file located directly under the game folder."
lz4_dll = ctypes.cdll.LoadLibrary(r"Please enter the path to the lz4.dll file located directly under the game folder.")
out_dir = r"Please specify multiple output destinations for the CSV files."
# 1. ヘッダーとメタデータを読む (Read the header and metadata)
with open(dat_path, "rb") as f:
hdr = f.read(64)
num_files = struct.unpack("<Q", hdr[8:16])[0]
name_table_off = struct.unpack("<Q", hdr[16:24])[0]
name_table_sz = struct.unpack("<Q", hdr[24:32])[0]
meta_table_off = struct.unpack("<Q", hdr[32:40])[0]
f.seek(name_table_off)
name_table = f.read(name_table_sz)
f.seek(meta_table_off)
meta_table = f.read(num_files * 48)
# 2. メタデータの対応付け(Metadata mapping)
name_to_meta = {}
for i in range(num_files):
chunk = meta_table[i*48:(i+1)*48]
vals = struct.unpack("<QQQQQQ", chunk)
name_to_meta[vals[1]] = (vals[3], vals[4]) # (サイズ(size), オフセット(offset))
# 3. data/win/bin/csv/ 以下のファイルを対象にする(The files under data/win/bin/csv/ are targeted.)
prefix = b"data/win/bin/csv/"
with open(dat_path, "rb") as f:
for n_pos, (sz, foff) in name_to_meta.items():
null_idx = name_table.find(b"\x00", n_pos)
fn_bytes = name_table[n_pos:null_idx]
if not fn_bytes.startswith(prefix):
continue
rel_path = fn_bytes[len(prefix):].decode("ascii", errors="ignore")
if rel_path.startswith("adv/") or rel_path.startswith("ui/"):
continue
# 4. 切り出し & LZ4 解凍(Cutting & LZ4 Defrosting)
f.seek(foff)
comp_data = f.read(sz)
if comp_data[0x0C:0x14] == b"YKCMP_V1":
uncomp_sz = struct.unpack("<I", comp_data[0x1C:0x20])[0]
payload = comp_data[0x20:]
dst = ctypes.create_string_buffer(uncomp_sz + 4096)
ret = lz4_dll.LZ4_decompress_safe(payload, dst, len(payload), len(dst))
data = dst.raw[:ret]
else:
data = comp_data
# 5. .phyre 内から CSV テキスト領域を切り出して保存(Extract and save the CSV text area from within the .phyre file.)
m = re.search(rb"csv/[a-zA-Z0-9_\-/]+\.csv", data)
if m:
null_pos = data.find(b"\x00", m.start())
first_tab = data.find(b"\t", null_pos)
text_start = data.rfind(b"\x00", null_pos, first_tab) + 1
end_pos = data.find(b"\x00\x00", text_start)
csv_bytes = data[text_start:end_pos if end_pos != -1 else len(data)]
save_path = os.path.join(out_dir, rel_path.replace(".phyre", ""))
os.makedirs(os.path.dirname(save_path), exist_ok=True)
with open(save_path, "wb") as out:
out.write(csv_bytes)
