MonkeyBusiness/utils/db/import_iidx_spice_automap.py

200 lines
8.6 KiB
Python
Raw Normal View History

2023-06-11 17:29:42 +02:00
import argparse
import xml.etree.ElementTree as ET
from enum import IntEnum
from tinydb import TinyDB, where
from tinydb.middlewares import CachingMiddleware
from tinydb.storages import JSONStorage
def main(automap_xml, version, monkey_db, iidx_id):
class ClearFlags(IntEnum):
NO_PLAY = 0
FAILED = 1
ASSIST_CLEAR = 2
EASY_CLEAR = 3
CLEAR = 4
HARD_CLEAR = 5
EX_HARD_CLEAR = 6
FULL_COMBO = 7
storage = CachingMiddleware(JSONStorage)
storage.WRITE_CACHE_SIZE = 5000
db = TinyDB(
monkey_db,
indent=2,
encoding="utf-8",
ensure_ascii=False,
storage=storage,
)
iidx_id = int(iidx_id.replace("-", ""))
profile = db.table("iidx_profile").get(where("iidx_id") == iidx_id)
if profile == None:
raise SystemExit(f"ERROR: IIDX profile {iidx_id} not in {monkey_db}")
game_version = 30
scores = []
with open(automap_xml, "rb") as fp:
automap_0 = fp.read().split(b"\n\n")
scores_xml = False
for xml in automap_0:
try:
tree = ET.ElementTree(ET.fromstring(xml.decode(encoding="shift-jis")))
root = tree.getroot()
except:
continue
if scores_xml:
sp_dp = int(root.find(f"IIDX{version}music/style").get("type"))
print(sp_dp)
for m in root.findall(f"IIDX{version}music/m"):
score = [int(x) for x in m.text.split()]
if score[0] != -1:
# skip rivals
continue
music_id = score[1]
for difficulty in range(5):
d = difficulty + 2
if score[d] != -1:
clear_flg = score[d]
ex_score = score[d + 5]
miss_count = score[d + 10]
scores.append(
[
sp_dp,
music_id,
difficulty,
clear_flg,
ex_score,
miss_count,
]
)
scores_xml = False
else:
try:
if root.find(f"IIDX{version}music").get("method") == "getrank":
scores_xml = True
except AttributeError:
continue
total_count = len(scores)
if total_count == 0:
raise SystemExit("ERROR: No scores to import")
for s in scores:
play_style = s[0]
music_id = s[1]
difficulty = s[2]
clear_flg = s[3]
ex_score = s[4]
miss_count = s[5]
print(
f"music_id: {music_id}, sp_dp: {play_style}, difficulty: {difficulty}, clear_flg: {clear_flg}, ex_score: {ex_score}, miss_count: {miss_count}"
)
best_score = db.table("iidx_scores_best").get(
(where("iidx_id") == iidx_id)
& (where("play_style") == play_style)
& (where("music_id") == music_id)
& (where("chart_id") == difficulty)
)
best_score = {} if best_score is None else best_score
if clear_flg < ClearFlags.EASY_CLEAR:
miss_count = -1
best_miss_count = best_score.get("miss_count", miss_count)
if best_miss_count == -1:
miss_count = max(miss_count, best_miss_count)
elif clear_flg > ClearFlags.ASSIST_CLEAR:
miss_count = min(miss_count, best_miss_count)
else:
miss_count = best_miss_count
best_ex_score = best_score.get("ex_score", ex_score)
best_score_data = {
"game_version": game_version,
"iidx_id": iidx_id,
"pid": 13,
"play_style": play_style,
"music_id": music_id,
"chart_id": difficulty,
"miss_count": miss_count,
"ex_score": max(ex_score, best_ex_score),
"ghost": best_score.get(
"ghost",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
),
"ghost_gauge": best_score.get(
"ghost_gauge",
"4c0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
),
"clear_flg": max(clear_flg, best_score.get("clear_flg", clear_flg)),
"gauge_type": best_score.get("gauge_type", 4),
}
db.table("iidx_scores_best").upsert(
best_score_data,
(where("iidx_id") == iidx_id)
& (where("play_style") == play_style)
& (where("music_id") == music_id)
& (where("chart_id") == difficulty),
)
score_stats = db.table("iidx_score_stats").get(
(where("music_id") == music_id)
& (where("play_style") == play_style)
& (where("chart_id") == difficulty)
)
score_stats = {} if score_stats is None else score_stats
score_stats["game_version"] = game_version
score_stats["play_style"] = play_style
score_stats["music_id"] = music_id
score_stats["chart_id"] = difficulty
score_stats["play_count"] = score_stats.get("play_count", 0) + 1
score_stats["fc_count"] = score_stats.get("fc_count", 0) + (
1 if clear_flg == ClearFlags.FULL_COMBO else 0
)
score_stats["clear_count"] = score_stats.get("clear_count", 0) + (
1 if clear_flg >= ClearFlags.EASY_CLEAR else 0
)
score_stats["fc_rate"] = int(
(score_stats["fc_count"] / score_stats["play_count"]) * 1000
)
score_stats["clear_rate"] = int(
(score_stats["clear_count"] / score_stats["play_count"]) * 1000
)
db.table("iidx_score_stats").upsert(
score_stats,
(where("music_id") == music_id)
& (where("play_style") == play_style)
& (where("chart_id") == difficulty),
)
db.close()
print()
print(f"{total_count} scores imported to IIDX profile {iidx_id} in {monkey_db}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--automap_xml", help="Input xml file", required=True)
parser.add_argument(
"--version",
help="",
default=30,
type=int,
)
parser.add_argument("--monkey_db", help="Output json file", required=True)
parser.add_argument("--iidx_id", help="12345678", required=True)
args = parser.parse_args()
main(args.automap_xml, args.version, args.monkey_db, args.iidx_id)