From 0065087bac22460f8d7fba1e7506b91209da4363 Mon Sep 17 00:00:00 2001 From: drmext <71258889+drmext@users.noreply.github.com> Date: Sat, 8 Feb 2025 05:30:00 +0000 Subject: [PATCH] Fix --- modules/iidx/iidx32gamesystem.py | 96 ++++-- modules/iidx/iidx32lobby.py | 2 +- modules/iidx/iidx32pc.py | 91 +++++ utils/musicdata_tool.py | 556 +++++++------------------------ 4 files changed, 288 insertions(+), 457 deletions(-) diff --git a/modules/iidx/iidx32gamesystem.py b/modules/iidx/iidx32gamesystem.py index 9972758..b8a94ab 100644 --- a/modules/iidx/iidx32gamesystem.py +++ b/modules/iidx/iidx32gamesystem.py @@ -34,11 +34,11 @@ async def iidx32gamesystem_systeminfo(request: Request): E.grade_course( E.play_style(0, __type="s32"), E.grade_id(15, __type="s32"), - E.music_id_0(25090, __type="s32"), + E.music_id_0(19022, __type="s32"), E.class_id_0(3, __type="s32"), E.music_id_1(23068, __type="s32"), E.class_id_1(3, __type="s32"), - E.music_id_2(19004, __type="s32"), + E.music_id_2(27013, __type="s32"), E.class_id_2(3, __type="s32"), E.music_id_3(29045, __type="s32"), E.class_id_3(3, __type="s32"), @@ -47,33 +47,33 @@ async def iidx32gamesystem_systeminfo(request: Request): E.grade_course( E.play_style(0, __type="s32"), E.grade_id(16, __type="s32"), - E.music_id_0(23005, __type="s32"), + E.music_id_0(27034, __type="s32"), E.class_id_0(3, __type="s32"), - E.music_id_1(27078, __type="s32"), + E.music_id_1(24023, __type="s32"), E.class_id_1(3, __type="s32"), - E.music_id_2(22065, __type="s32"), + E.music_id_2(16009, __type="s32"), E.class_id_2(3, __type="s32"), - E.music_id_3(27060, __type="s32"), + E.music_id_3(25085, __type="s32"), E.class_id_3(3, __type="s32"), E.is_valid(1, __type="bool"), ), E.grade_course( E.play_style(0, __type="s32"), E.grade_id(17, __type="s32"), - E.music_id_0(29007, __type="s32"), + E.music_id_0(26087, __type="s32"), E.class_id_0(3, __type="s32"), - E.music_id_1(26108, __type="s32"), + E.music_id_1(19002, __type="s32"), E.class_id_1(3, __type="s32"), - E.music_id_2(19002, __type="s32"), + E.music_id_2(29050, __type="s32"), E.class_id_2(3, __type="s32"), - E.music_id_3(18004, __type="s32"), + E.music_id_3(30024, __type="s32"), E.class_id_3(3, __type="s32"), E.is_valid(1, __type="bool"), ), E.grade_course( E.play_style(0, __type="s32"), E.grade_id(18, __type="s32"), - E.music_id_0(25007, __type="s32"), + E.music_id_0(30052, __type="s32"), E.class_id_0(3, __type="s32"), E.music_id_1(18032, __type="s32"), E.class_id_1(3, __type="s32"), @@ -86,11 +86,11 @@ async def iidx32gamesystem_systeminfo(request: Request): E.grade_course( E.play_style(1, __type="s32"), E.grade_id(15, __type="s32"), - E.music_id_0(15032, __type="s32"), + E.music_id_0(12002, __type="s32"), E.class_id_0(3, __type="s32"), - E.music_id_1(29033, __type="s32"), + E.music_id_1(31063, __type="s32"), E.class_id_1(3, __type="s32"), - E.music_id_2(27092, __type="s32"), + E.music_id_2(23046, __type="s32"), E.class_id_2(3, __type="s32"), E.music_id_3(30020, __type="s32"), E.class_id_3(3, __type="s32"), @@ -99,11 +99,11 @@ async def iidx32gamesystem_systeminfo(request: Request): E.grade_course( E.play_style(1, __type="s32"), E.grade_id(16, __type="s32"), - E.music_id_0(10028, __type="s32"), + E.music_id_0(26106, __type="s32"), E.class_id_0(3, __type="s32"), - E.music_id_1(26070, __type="s32"), + E.music_id_1(14021, __type="s32"), E.class_id_1(3, __type="s32"), - E.music_id_2(28091, __type="s32"), + E.music_id_2(29052, __type="s32"), E.class_id_2(3, __type="s32"), E.music_id_3(23075, __type="s32"), E.class_id_3(3, __type="s32"), @@ -112,9 +112,9 @@ async def iidx32gamesystem_systeminfo(request: Request): E.grade_course( E.play_style(1, __type="s32"), E.grade_id(17, __type="s32"), - E.music_id_0(26012, __type="s32"), + E.music_id_0(29042, __type="s32"), E.class_id_0(3, __type="s32"), - E.music_id_1(28002, __type="s32"), + E.music_id_1(26043, __type="s32"), E.class_id_1(3, __type="s32"), E.music_id_2(17017, __type="s32"), E.class_id_2(3, __type="s32"), @@ -125,9 +125,9 @@ async def iidx32gamesystem_systeminfo(request: Request): E.grade_course( E.play_style(1, __type="s32"), E.grade_id(18, __type="s32"), - E.music_id_0(28008, __type="s32"), + E.music_id_0(25007, __type="s32"), E.class_id_0(3, __type="s32"), - E.music_id_1(15001, __type="s32"), + E.music_id_1(29017, __type="s32"), E.class_id_1(3, __type="s32"), E.music_id_2(19002, __type="s32"), E.class_id_2(3, __type="s32"), @@ -135,8 +135,62 @@ async def iidx32gamesystem_systeminfo(request: Request): E.class_id_3(3, __type="s32"), E.is_valid(1, __type="bool"), ), + E.arena_schedule( + E.season(1, __type="u8"), + E.phase(4, __type="u8"), + E.rule_type(0, __type="u8"), + E.start(current_time - 600, __type="u32"), + E.end(current_time + 600, __type="u32"), + ), + *[ + E.arena_reward( + E.index(unlock.index(mid), __type="s32"), + E.cube_num((unlock.index(mid) + 1) * 50, __type="s32"), + E.kind(0, __type="s32"), + E.value(mid, __type="str"), + ) + for mid in unlock + ], + *[ + E.arena_music_difficult( + E.play_style(sp_dp, __type="s32"), + E.arena_class(arena_class, __type="s32"), + E.low_difficult(8, __type="s32"), + E.high_difficult(12, __type="s32"), + E.is_leggendaria(1, __type="bool"), + E.force_music_list_id(0, __type="s32"), + ) + for sp_dp in (0, 1) + for arena_class in range(20) + ], + *[ + E.arena_cpu_define( + E.play_style(sp_dp, __type="s32"), + E.arena_class(arena_class, __type="s32"), + E.grade_id(18, __type="s32"), + E.low_music_difficult(8, __type="s32"), + E.high_music_difficult(12, __type="s32"), + E.is_leggendaria(0, __type="bool"), + ) + for sp_dp in (0, 1) + for arena_class in range(20) + ], + *[ + E.maching_class_range( + E.play_style(sp_dp, __type="s32"), + E.matching_class(arena_class, __type="s32"), + E.low_arena_class(arena_class, __type="s32"), + E.high_arena_class(arena_class, __type="s32"), + ) + for sp_dp in (0, 1) + for arena_class in range(20) + ], + E.Event1Phase(val=0), E.isNewSongAnother12OpenFlg(val=1), + E.isKiwamiOpenFlg(val=1), + E.WorldTourismOpenList(val=-1), E.OldBPLBattleOpenPhase(val=3), + E.BPLBattleOpenPhase(val=3), ) ) diff --git a/modules/iidx/iidx32lobby.py b/modules/iidx/iidx32lobby.py index b10babb..aaacd06 100644 --- a/modules/iidx/iidx32lobby.py +++ b/modules/iidx/iidx32lobby.py @@ -6,7 +6,7 @@ from fastapi import APIRouter, Request, Response from core_common import core_process_request, core_prepare_response, E -router = APIRouter(prefix="/lobby", tags=["lobby"]) +router = APIRouter(prefix="/lobby2", tags=["lobby2"]) router.model_whitelist = ["LDJ"] diff --git a/modules/iidx/iidx32pc.py b/modules/iidx/iidx32pc.py index 13eeb4f..addfdde 100644 --- a/modules/iidx/iidx32pc.py +++ b/modules/iidx/iidx32pc.py @@ -216,6 +216,97 @@ async def iidx32pc_get(request: Request): keyboard_kind=profile.get("lightning_setting_keyboard_kind", 0), brightness=profile.get("lightning_setting_brightness", 0), ), + E.arena_data( + E.achieve_data( + play_style=0, + arena_class=19, + rating_value=90, + now_top_class_continuing=19, + best_top_class_continuing=19, + win_count=0, + now_winning_streak_count=0, + best_winning_streak_count=0, + perfect_win_count=0, + counterattack_num=0, + mission_clear_num=0, + ), + E.achieve_data( + play_style=1, + arena_class=19, + rating_value=90, + now_top_class_continuing=19, + best_top_class_continuing=19, + win_count=0, + now_winning_streak_count=0, + best_winning_streak_count=0, + perfect_win_count=0, + counterattack_num=0, + mission_clear_num=0, + ), + E.cube_data( + cube=200, + season_id=0, + ), + E.ranker_data( + play_style=0, + pref_id=0, + rank_num=(random.choice([random.randint(1, 5), 573])), + ), + E.ranker_data( + play_style=1, + pref_id=0, + rank_num=(random.choice([random.randint(1, 5), 573])), + ), + E.lose_data( + play_style=0, + lose_value=0, + ), + E.lose_data( + play_style=1, + lose_value=0, + ), + E.chat_data( + E.is_chat_0(1, __type="bool"), + E.is_chat_1(1, __type="bool"), + E.is_chat_2(1, __type="bool"), + E.is_chat_3(1, __type="bool"), + chat_type_0="hi", + chat_type_1="やあ", + chat_type_2="こんにちは", + chat_type_3="おす", + ), + E.tendency( + play_style=0, + rank0=1, + rank1=2, + rank2=3, + rank3=4, + rank4=3, + rank5=1, + ), + E.default_chat(), + # E.player_kind_data( + # kind=(random.choice([random.randint(0, 13), 0])), + # ), + E.setting( + E.hide_shopname(0, __type="bool"), + stats_type=0, + ), + E.qpro_motion( + motion_0=1, + motion_1=2, + motion_2=3, + ), + play_num=6, + play_num_dp=3, + play_num_sp=3, + prev_best_class_sp=18, + prev_best_class_dp=18, + ), + E.arena_pre_data( + season_id=1, + play_num=6, + ), # E.weekly_achieve_sp( # weekly_achieve_0=0, # weekly_achieve_1=0, diff --git a/utils/musicdata_tool.py b/utils/musicdata_tool.py index 4be226b..ac87bb8 100644 --- a/utils/musicdata_tool.py +++ b/utils/musicdata_tool.py @@ -1,36 +1,28 @@ import argparse -import ctypes import json import struct def read_string(infile, length, encoding="cp932"): - string_data = infile.read(length) - try: - return string_data.decode(encoding).strip("\0") - except UnicodeDecodeError: - # Can't decode truncated string with half multibyte sequence appended (0x83) - return string_data[:-1].decode(encoding).strip("\0") + return infile.read(length).decode(encoding, errors="ignore").rstrip("\0") -def write_string(outfile, input, length, fill="\0", encoding="cp932"): +def write_string(outfile, input, length, encoding="cp932"): string_data = input[:length].encode(encoding) outfile.write(string_data) - - if len(input) < length: - outfile.write("".join([fill] * (length - len(string_data))).encode("utf-8")) + outfile.write(b"\0" * (length - len(string_data))) -def reader(data_ver, infile, song_count): - song_entries = [] +def reader(version, infile, song_count): + all_song_entries = [] for i in range(song_count): - if data_ver >= 32: + if version >= 32 and version != 80: title = read_string(infile, 0x100, encoding="utf-16-le") title_ascii = read_string(infile, 0x40) genre = read_string(infile, 0x80, encoding="utf-16-le") artist = read_string(infile, 0x100, encoding="utf-16-le") - unk_sect0 = infile.read(0x100) + subtitle = read_string(infile, 0x100, encoding="utf-16-le") else: title = read_string(infile, 0x40) title_ascii = read_string(infile, 0x40) @@ -44,25 +36,23 @@ def reader(data_ver, infile, song_count): texture_load, texture_list, ) = struct.unpack("= 32: - texture_unk = struct.unpack("= 32 and version != 80: + texture_subtitle = struct.unpack("= 32: + if version >= 32 and version != 80: ( other_folder, bemani_folder, - unk_folder0, - unk_folder1, - unk_folder2, + beginner_rec_folder, + iidx_rec_folder, + bemani_rec_folder, splittable_diff, - unk_folder3, + unk_unused, ) = struct.unpack("= 27: + if version >= 27: ( SPB_level, SPN_level, @@ -89,16 +79,16 @@ def reader(data_ver, infile, song_count): SPL_level = 0 DPL_level = 0 - if data_ver == 80: + if version == 80: unk_sect1 = infile.read(0x146) - elif data_ver >= 27: + elif version >= 27: unk_sect1 = infile.read(0x286) else: unk_sect1 = infile.read(0xA0) song_id, volume = struct.unpack("= 27: + if version >= 27: ( SPB_ident, SPN_ident, @@ -125,28 +115,21 @@ def reader(data_ver, infile, song_count): SPL_ident = 48 DPL_ident = 48 - bga_delay = ctypes.c_short(struct.unpack("= 22: - afp_data = [] - for x in range(10): - afp_data.append(infile.read(0x20).hex()) - else: - afp_data = [] - for x in range(9): - afp_data.append(infile.read(0x20).hex()) + afp_data = [read_string(infile, 0x20) for _ in range(10 if version >= 22 else 9)] - if data_ver >= 26: + if version >= 26: unk_sect4 = infile.read(4) entries = { @@ -192,96 +175,59 @@ def reader(data_ver, infile, song_count): "afp_data": afp_data, } - if data_ver >= 32: - # if data_ver == 80: - # unk = { - # "unk_sect1": unk_sect1.hex(), - # "unk_sect2": unk_sect2.hex(), - # "unk_sect3": unk_sect3.hex(), - # "unk_sect4": unk_sect4.hex(), - # } - unk = { - "unk_sect0": unk_sect0.hex(), - "texture_unk": texture_unk, - "unk_folder0": unk_folder0, - "unk_folder1": unk_folder1, - "unk_folder2": unk_folder2, - "unk_folder3": unk_folder3, - # "unk_sect1": unk_sect1.hex(), - # "unk_sect2": unk_sect2.hex(), - # "unk_sect3": unk_sect3.hex(), - # "unk_sect4": unk_sect4.hex(), + if version >= 32 and version != 80: + new_version_entries = { + "subtitle": subtitle, + "texture_subtitle": texture_subtitle, + "beginner_rec_folder": beginner_rec_folder, + "iidx_rec_folder": iidx_rec_folder, + "bemani_rec_folder": bemani_rec_folder, + "unk_unused": unk_unused, } - # elif data_ver >= 27: - # unk = { - # "unk_sect1": unk_sect1.hex(), - # "unk_sect4": unk_sect4.hex(), - # } - # elif data_ver == 26: - # unk = { - # "unk_sect1": unk_sect1.hex(), - # "unk_sect2": unk_sect2.hex(), - # "unk_sect4": unk_sect4.hex(), - # } - # elif data_ver <= 25: - # unk = { - # "unk_sect1": unk_sect1.hex(), - # "unk_sect2": unk_sect2.hex(), - # } + entries.update(new_version_entries) - entries.update(unk) + all_song_entries.append(entries) - song_entries.append(entries) - - return song_entries + return all_song_entries -def writer(data_ver, outfile, data): - DATA_VERSION = data_ver - MAX_ENTRIES = data_ver * 1000 + 1000 - CUR_STYLE_ENTRIES = MAX_ENTRIES - 1000 +def writer(version, outfile, data): + cur_style_entries = version * 1000 + max_entries = cur_style_entries + 1000 + entries_struct_format = "= 32 and version != 80 else "= 32: - outfile.write(struct.pack("= 32: + outfile.write(struct.pack("= 32 else "= CUR_STYLE_ENTRIES: + outfile.write(struct.pack(entries_struct_format, current_song)) + current_song += 1 + elif i >= cur_style_entries: outfile.write(struct.pack(entries_struct_format, 0)) else: outfile.write(struct.pack(entries_struct_format, -1)) # Write song entries - for k in sorted(exist_ids.keys()): + for k in sorted(exist_ids): song_data = data[exist_ids[k]] - if data_ver >= 32: + if version >= 32 and version != 80: write_string(outfile, song_data["title"], 0x100, encoding="utf-16-le") write_string(outfile, song_data["title_ascii"], 0x40) write_string(outfile, song_data["genre"], 0x80, encoding="utf-16-le") write_string(outfile, song_data["artist"], 0x100, encoding="utf-16-le") - outfile.write( - bytes.fromhex( - song_data.get( - "unk_sect0", - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - ) - ) - ) + write_string(outfile, song_data.get("subtitle", ""), 0x100, encoding="utf-16-le") else: write_string(outfile, song_data["title"], 0x40) write_string(outfile, song_data["title_ascii"], 0x40) @@ -298,22 +244,20 @@ def writer(data_ver, outfile, data): song_data["texture_list"], ) ) - if data_ver >= 32: - outfile.write(struct.pack("= 32: + if version >= 32 and version != 80: + outfile.write(struct.pack("= 32 and version != 80: outfile.write( struct.pack( "= 27: + if version >= 27: outfile.write( struct.pack( "= 32: - outfile.write( - bytes.fromhex( - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - ) - ) - elif data_ver >= 27: - outfile.write( - bytes.fromhex( - "00000000000001000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - ) - ) + if version == 80: + outfile.write(bytes.fromhex(f"{1:014}{2:08}{3:0248}{4:08}{3:0120}{4:08}{0:0246}")) + elif version >= 32: + outfile.write(bytes.fromhex(f"{0:01292}")) + elif version >= 27: + outfile.write(bytes.fromhex(f"{1:014}{2:08}{3:0248}{4:08}{0:01014}")) else: - outfile.write( - bytes.fromhex( - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - ) - ) + outfile.write(bytes.fromhex(f"{0:0320}")) outfile.write(struct.pack("= 27: + if version >= 27: outfile.write( struct.pack( "= 22: - for afp_data in song_data["afp_data"]: - outfile.write(bytes.fromhex(afp_data)) - if len(song_data["afp_data"]) == 9: - outfile.write( - bytes.fromhex( - "0000000000000000000000000000000000000000000000000000000000000000" - ) - ) - elif len(song_data["afp_data"]) == 10 and data_ver <= 21: - for afp_data in song_data["afp_data"][:9]: - outfile.write(bytes.fromhex(afp_data)) - elif len(song_data["afp_data"]) == 9 and data_ver <= 21: - for afp_data in song_data["afp_data"]: - outfile.write(bytes.fromhex(afp_data)) + for idx in range(10 if version >= 22 else 9): + try: + write_string(outfile, song_data["afp_data"][idx], 0x20) + except IndexError: + write_string(outfile, "", 0x20) - if data_ver >= 26: - outfile.write(bytes.fromhex("00000000")) - - -def course_reader(infile, total_entries): - course_entries = [] - - for i in range(total_entries): - is_DP, course_num, stages = struct.unpack("= 26: + outfile.write(bytes.fromhex("00" * 4)) handlers = { @@ -545,246 +386,91 @@ handlers = { def extract_file(input, output, in_memory=False): with open(input, "rb") as infile: if infile.read(4) != b"IIDX": - print("Invalid", input) - exit(-1) + raise SystemExit(f"Input file ({input}) is not valid") - infile.seek(4, 0) - data_ver = int.from_bytes(infile.read(4), "little") + version = struct.unpack("= 32 and version != 80 else "= 32: - available_entries, unk4, total_entries = struct.unpack( - "= 32: + available_entries, unk4, total_entries = struct.unpack("= 32: - song_id = struct.unpack("= 32: - available_entries, unk4, total_entries = struct.unpack( - "= 32: - song_id = struct.unpack("= 32: - available_entries, unk4, total_entries = struct.unpack( - "= 32: - song_id = struct.unpack("