mirror of
https://github.com/drmext/MonkeyBusiness.git
synced 2024-11-30 18:24:33 +01:00
DDR score import
This commit is contained in:
parent
5d40fe2454
commit
6a5ad537d9
36
utils/db/README.md
Normal file
36
utils/db/README.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Database Utilities
|
||||||
|
|
||||||
|
**Backup db.json before shrinking or importing**
|
||||||
|
|
||||||
|
## Shrink DB
|
||||||
|
|
||||||
|
### [trim_monkey_db.py](trim_monkey_db.py)
|
||||||
|
|
||||||
|
This deletes unused Gitadora and IIDX non-best scores, which can drastically reduce the size of db.json in a multiuser environment
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`python utils\db\trim_monkey_db.py`
|
||||||
|
|
||||||
|
## Score Import
|
||||||
|
|
||||||
|
### [import_ddr_spice_automap.py](import_ddr_spice_automap.py)
|
||||||
|
|
||||||
|
Instructions:
|
||||||
|
|
||||||
|
1. Enable `EA Automap` and `EA Netdump` in spicecfg
|
||||||
|
|
||||||
|
1. Boot the game on the source network to export
|
||||||
|
|
||||||
|
1. Card in on the source profile to export (all the way to music select menu)
|
||||||
|
|
||||||
|
1. Exit the game
|
||||||
|
|
||||||
|
1. Disable `EA Automap` and `EA Netdump` in spicecfg
|
||||||
|
|
||||||
|
1. Run the import script
|
||||||
|
|
||||||
|
Example: `python utils\db\import_ddr_spice_automap.py --automap_xml automap_0.xml --version 19 --monkey_db db.json --ddr_id 12345678`
|
||||||
|
|
||||||
|
- `--version` {19 for A20P or 20 for A3}
|
||||||
|
|
||||||
|
- `--ddr_id` {destination profile in db.json}
|
140
utils/db/import_ddr_spice_automap.py
Normal file
140
utils/db/import_ddr_spice_automap.py
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import argparse
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
from tinydb import TinyDB, where
|
||||||
|
from tinydb.middlewares import CachingMiddleware
|
||||||
|
from tinydb.storages import JSONStorage
|
||||||
|
|
||||||
|
|
||||||
|
def main(automap_xml, version, monkey_db, ddr_id):
|
||||||
|
storage = CachingMiddleware(JSONStorage)
|
||||||
|
storage.WRITE_CACHE_SIZE = 5000
|
||||||
|
|
||||||
|
db = TinyDB(
|
||||||
|
monkey_db,
|
||||||
|
indent=2,
|
||||||
|
encoding="utf-8",
|
||||||
|
ensure_ascii=False,
|
||||||
|
storage=storage,
|
||||||
|
)
|
||||||
|
|
||||||
|
ddr_id = int(ddr_id.replace("-", ""))
|
||||||
|
|
||||||
|
profile = db.table("ddr_profile").get(where("ddr_id") == ddr_id)
|
||||||
|
if profile == None:
|
||||||
|
raise SystemExit(f"ERROR: DDR profile {ddr_id} not in {monkey_db}")
|
||||||
|
|
||||||
|
game_version = 19
|
||||||
|
if profile["version"].get(str(game_version), None) == None:
|
||||||
|
raise SystemExit(
|
||||||
|
f"ERROR: DDR profile {ddr_id} version {game_version} not in {monkey_db}"
|
||||||
|
)
|
||||||
|
|
||||||
|
scores = []
|
||||||
|
|
||||||
|
with open(automap_xml, "rb") as fp:
|
||||||
|
automap_0 = fp.read().split(b"\n\n")
|
||||||
|
|
||||||
|
if version == 19:
|
||||||
|
playerdata = "playerdata"
|
||||||
|
else:
|
||||||
|
playerdata = "playerdata_2"
|
||||||
|
|
||||||
|
scores_xml = False
|
||||||
|
for xml in automap_0:
|
||||||
|
tree = ET.ElementTree(ET.fromstring(xml.decode(encoding="shift-jis")))
|
||||||
|
root = tree.getroot()
|
||||||
|
if scores_xml:
|
||||||
|
for music in root.findall(f"{playerdata}/music"):
|
||||||
|
mcode = int(music.find("mcode").text)
|
||||||
|
for difficulty, chart in enumerate(music.findall("note")):
|
||||||
|
if int(chart.find("count").text) > 0:
|
||||||
|
rank = int(chart.find("rank").text)
|
||||||
|
clearkind = int(chart.find("clearkind").text)
|
||||||
|
score = int(chart.find("score").text)
|
||||||
|
scores.append([mcode, difficulty, rank, clearkind, score])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if root.find(f"{playerdata}/data/mode").text == "userload":
|
||||||
|
if len(root.find(f"{playerdata}/data/refid").text) == 16:
|
||||||
|
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:
|
||||||
|
mcode = s[0]
|
||||||
|
difficulty = s[1]
|
||||||
|
rank = s[2]
|
||||||
|
lamp = s[3]
|
||||||
|
score = s[4]
|
||||||
|
exscore = 0
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"mcode: {mcode}, difficulty: {difficulty}, rank: {rank}, score: {score}, lamp: {lamp}"
|
||||||
|
)
|
||||||
|
|
||||||
|
best = db.table("ddr_scores_best").get(
|
||||||
|
(where("ddr_id") == ddr_id)
|
||||||
|
& (where("game_version") == game_version)
|
||||||
|
& (where("mcode") == mcode)
|
||||||
|
& (where("difficulty") == difficulty)
|
||||||
|
)
|
||||||
|
best = {} if best is None else best
|
||||||
|
|
||||||
|
best_score_data = {
|
||||||
|
"game_version": game_version,
|
||||||
|
"ddr_id": ddr_id,
|
||||||
|
"playstyle": 0 if difficulty < 5 else 1,
|
||||||
|
"mcode": mcode,
|
||||||
|
"difficulty": difficulty,
|
||||||
|
"rank": min(rank, best.get("rank", rank)),
|
||||||
|
"lamp": max(lamp, best.get("lamp", lamp)),
|
||||||
|
"score": max(score, best.get("score", score)),
|
||||||
|
"exscore": max(exscore, best.get("exscore", exscore)),
|
||||||
|
}
|
||||||
|
|
||||||
|
ghostid = db.table("ddr_scores").get(
|
||||||
|
(where("ddr_id") == ddr_id)
|
||||||
|
& (where("game_version") == game_version)
|
||||||
|
& (where("mcode") == mcode)
|
||||||
|
& (where("difficulty") == difficulty)
|
||||||
|
& (where("exscore") == best.get("exscore", exscore))
|
||||||
|
)
|
||||||
|
if ghostid:
|
||||||
|
best_score_data["ghostid"] = ghostid.doc_id
|
||||||
|
else:
|
||||||
|
best_score_data["ghostid"] = -1
|
||||||
|
|
||||||
|
db.table("ddr_scores_best").upsert(
|
||||||
|
best_score_data,
|
||||||
|
(where("ddr_id") == ddr_id)
|
||||||
|
& (where("game_version") == game_version)
|
||||||
|
& (where("mcode") == mcode)
|
||||||
|
& (where("difficulty") == difficulty),
|
||||||
|
)
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
print()
|
||||||
|
print(f"{total_count} scores imported to DDR profile {ddr_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="19 is A20P, 20 is A3",
|
||||||
|
default=19,
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
parser.add_argument("--monkey_db", help="Output json file", required=True)
|
||||||
|
parser.add_argument("--ddr_id", help="12345678", required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
main(args.automap_xml, args.version, args.monkey_db, args.ddr_id)
|
36
utils/db/trim_monkey_db.py
Normal file
36
utils/db/trim_monkey_db.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import time
|
||||||
|
from os import stat
|
||||||
|
from shutil import copy
|
||||||
|
|
||||||
|
from tinydb import TinyDB
|
||||||
|
from tinydb.middlewares import CachingMiddleware
|
||||||
|
from tinydb.storages import JSONStorage
|
||||||
|
|
||||||
|
storage = CachingMiddleware(JSONStorage)
|
||||||
|
storage.WRITE_CACHE_SIZE = 5000
|
||||||
|
|
||||||
|
infile = "db.json"
|
||||||
|
outfile = f"db_{round(time.time())}.json"
|
||||||
|
|
||||||
|
copy(infile, outfile)
|
||||||
|
|
||||||
|
db = TinyDB(
|
||||||
|
infile,
|
||||||
|
indent=2,
|
||||||
|
encoding="utf-8",
|
||||||
|
ensure_ascii=False,
|
||||||
|
storage=storage,
|
||||||
|
)
|
||||||
|
|
||||||
|
start_size = stat(infile).st_size
|
||||||
|
|
||||||
|
# Non-best tables for GITADORA and IIDX are not used in game
|
||||||
|
for table in ("guitarfreaks_scores", "drummania_scores", "iidx_scores"):
|
||||||
|
db.drop_table(table)
|
||||||
|
print("Dropped", table)
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
end_size = stat(infile).st_size
|
||||||
|
|
||||||
|
print(f"{infile} {round((start_size - end_size) / 1024 / 1024, 2)} MiB trimmed")
|
Loading…
Reference in New Issue
Block a user