214 lines
9.7 KiB
Python
214 lines
9.7 KiB
Python
"""Import the revision-bound subset used by our CW adapter; no player files change."""
|
|||
|
|
import argparse
|
||
|
|
import hashlib
|
||
|
|
import json
|
||
|
|
import pathlib
|
||
|
|
import subprocess
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
||
|
|
parser.add_argument("--source", type=pathlib.Path, required=True)
|
||
|
|
parser.add_argument("--root", type=pathlib.Path, default=pathlib.Path(__file__).resolve().parents[1])
|
||
|
|
args = parser.parse_args()
|
||
|
|
source, root = args.source.resolve(), args.root.resolve()
|
||
|
|
catalog = json.loads((root / "resources/CurrencyWarsCatalog.json").read_text(encoding="utf-8"))
|
||
|
|
inputs = [
|
||
|
|
"resources/grid_fight/elite_rewards.json",
|
||
|
|
"resources/grid_fight/rounds.raw.json",
|
||
|
|
"resources/grid_fight/score.json",
|
||
|
|
"resources/grid_fight/offering_levels.json",
|
||
|
|
"resources/grid_fight/traits.json",
|
||
|
|
"resources/grid_fight/trait_effects.json",
|
||
|
|
"resources/grid_fight/augments.json",
|
||
|
|
"resources/grid_fight/orb_rewards.json",
|
||
|
|
"gameserver/src/services/grid_fight.zig",
|
||
|
|
"gameserver/src/services/grid_fight_rewards.zig",
|
||
|
|
"gameserver/src/services/grid_fight_strategy.zig",
|
||
|
|
"gameserver/src/services/grid_fight_traits.zig",
|
||
|
|
"gameserver/src/services/grid_fight_bonds.zig",
|
||
|
|
"gameserver/src/services/grid_fight_talent.zig",
|
||
|
|
]
|
||
|
|
hashes = {name: hashlib.sha256((source / name).read_bytes()).hexdigest() for name in inputs}
|
||
|
|
elite = json.loads((source / inputs[0]).read_text(encoding="utf-8"))
|
||
|
|
rounds = json.loads((source / inputs[1]).read_text(encoding="utf-8"))
|
||
|
|
score_raw = json.loads((source / inputs[2]).read_text(encoding="utf-8"))
|
||
|
|
offering_raw = json.loads((source / inputs[3]).read_text(encoding="utf-8"))
|
||
|
|
traits_raw = json.loads((source / inputs[4]).read_text(encoding="utf-8"))
|
||
|
|
effects_raw = json.loads((source / inputs[5]).read_text(encoding="utf-8"))
|
||
|
|
augments_raw = json.loads((source / inputs[6]).read_text(encoding="utf-8"))
|
||
|
|
orbs_raw = json.loads((source / inputs[7]).read_text(encoding="utf-8"))
|
||
|
|
|
||
|
|
assembly = catalog["provenance"]["game_assembly_sha256"]
|
||
|
|
if elite["source"]["game_assembly_sha256"] != assembly:
|
||
|
|
raise ValueError("source Client assembly does not match installed CW catalog")
|
||
|
|
|
||
|
|
commit = subprocess.check_output(["git", "-C", str(source), "rev-parse", "HEAD"], text=True).strip()
|
||
|
|
|
||
|
|
active = {row["ID"] for row in catalog["active_stage_wrappers"]}
|
||
|
|
divisions = [{key: row.get(key, 0) for key in
|
||
|
|
("DivisionID", "EnemyDifficultyLevel", "BinaryNodeDiffAddRule")}
|
||
|
|
for row in rounds["GridFightDivisionStageRow"] if row["DivisionID"] in active]
|
||
|
|
if {row["DivisionID"] for row in divisions} != active or len(divisions) != len(active):
|
||
|
|
raise ValueError("source division table does not cover captured stages uniquely")
|
||
|
|
for row in divisions:
|
||
|
|
captured = next(stage for stage in catalog["active_stage_wrappers"] if stage["ID"] == row["DivisionID"])
|
||
|
|
if row["EnemyDifficultyLevel"] != captured["EnemyHardLevel"]:
|
||
|
|
raise ValueError("source division difficulty differs from installed capture")
|
||
|
|
|
||
|
|
output_cw = {
|
||
|
|
"format_version": 1,
|
||
|
|
"target_client_version": catalog["client_version"],
|
||
|
|
"target_assembly_sha256": assembly,
|
||
|
|
"provenance": {
|
||
|
|
"repository": "https://gaytea.cod-algieba.ts.net/xaodev/Currency-War-SR",
|
||
|
|
"commit": commit,
|
||
|
|
"license": "AGPL-3.0-only",
|
||
|
|
"inputs_sha256": hashes,
|
||
|
|
"native_source": elite["source"],
|
||
|
|
"adapted_functions": ["eliteOffers", "powerfulQuality", "encounter", "branchDropPreview", "sendEliteSelected", "roundExp"]
|
||
|
|
},
|
||
|
|
"node_rules": elite["node_rules"],
|
||
|
|
"diff_add": elite["diff_add"],
|
||
|
|
"difficulty_levels": [{"chapter": row["chapter"], "level": row["level"]} for row in elite["difficulty"]],
|
||
|
|
"divisions": sorted(divisions, key=lambda row: row["DivisionID"]),
|
||
|
|
"generation_policy": {
|
||
|
|
"source": "grid_fight.zig encounter fallback for EliteBranch nodes without a node_profile; server-authored, not official wave data",
|
||
|
|
"monster_count": 3, "monster_tier": 2, "star_cap": 3,
|
||
|
|
"normal_quality": 1, "powerful_qualities": [2, 3, 4],
|
||
|
|
"seed_policy": "sha256 of run id, route, chapter and section; local deterministic sampling, not upstream Wyhash",
|
||
|
|
"reward_policy": "preview_base_gold_already_paid_by_settlement",
|
||
|
|
"extra_rewards_supported": False
|
||
|
|
},
|
||
|
|
"gameplay_verified": False
|
||
|
|
}
|
||
|
|
destination = root / "resources/CurrencyWarsXaodev.json"
|
||
|
|
destination.write_text(json.dumps(output_cw, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||
|
|
|
||
|
|
# 1. Score & Offering Levels
|
||
|
|
offering_s2 = [
|
||
|
|
{"level": row["Level"], "item_cost": row["ItemCost"], "reward_id": row["RewardID"]}
|
||
|
|
for row in offering_raw if row.get("TypeID") == 16
|
||
|
|
]
|
||
|
|
offering_s2.sort(key=lambda x: x["level"])
|
||
|
|
score_output = {
|
||
|
|
"format_version": 1,
|
||
|
|
"target_client_version": catalog["client_version"],
|
||
|
|
"target_assembly_sha256": assembly,
|
||
|
|
"provenance": {
|
||
|
|
"repository": "https://gaytea.cod-algieba.ts.net/xaodev/Currency-War-SR",
|
||
|
|
"commit": commit,
|
||
|
|
"license": "AGPL-3.0-only",
|
||
|
|
"inputs_sha256": {
|
||
|
|
"score.json": hashes["resources/grid_fight/score.json"],
|
||
|
|
"offering_levels.json": hashes["resources/grid_fight/offering_levels.json"],
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"weekly_cap": score_raw.get("weekly_cap", 18000),
|
||
|
|
"weekly_ranks": score_raw.get("weekly_ranks", []),
|
||
|
|
"divisions": score_raw.get("divisions", {}),
|
||
|
|
"rules": score_raw.get("rules", {}),
|
||
|
|
"offering_levels": offering_s2
|
||
|
|
}
|
||
|
|
(root / "resources/CurrencyWarsScore.json").write_text(
|
||
|
|
json.dumps(score_output, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
|
||
|
|
)
|
||
|
|
|
||
|
|
# 2. Traits & Effects
|
||
|
|
traits_list = [
|
||
|
|
{
|
||
|
|
"id": t["id"],
|
||
|
|
"name": t.get("name", ""),
|
||
|
|
"thresholds": t.get("thresholds", []),
|
||
|
|
"activation_type": t.get("raw", {}).get("base", {}).get("ActivationType", 1),
|
||
|
|
"trait_type": t.get("raw", {}).get("base", {}).get("TraitType", 0),
|
||
|
|
"season_id": t.get("raw", {}).get("base", {}).get("SeasonID", 1)
|
||
|
|
}
|
||
|
|
for t in traits_raw
|
||
|
|
]
|
||
|
|
traits_list.sort(key=lambda x: x["id"])
|
||
|
|
traits_output = {
|
||
|
|
"format_version": 1,
|
||
|
|
"target_client_version": catalog["client_version"],
|
||
|
|
"target_assembly_sha256": assembly,
|
||
|
|
"provenance": {
|
||
|
|
"repository": "https://gaytea.cod-algieba.ts.net/xaodev/Currency-War-SR",
|
||
|
|
"commit": commit,
|
||
|
|
"license": "AGPL-3.0-only",
|
||
|
|
"inputs_sha256": {
|
||
|
|
"traits.json": hashes["resources/grid_fight/traits.json"],
|
||
|
|
"trait_effects.json": hashes["resources/grid_fight/trait_effects.json"],
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"traits": traits_list,
|
||
|
|
"effects": effects_raw.get("effects", {}),
|
||
|
|
"constants": effects_raw.get("constants", {})
|
||
|
|
}
|
||
|
|
(root / "resources/CurrencyWarsTraits.json").write_text(
|
||
|
|
json.dumps(traits_output, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
|
||
|
|
)
|
||
|
|
|
||
|
|
# 3. Augments
|
||
|
|
augments_list = [
|
||
|
|
{
|
||
|
|
"id": a["id"],
|
||
|
|
"quality": a.get("quality", 1),
|
||
|
|
"chapters": a.get("chapters", []),
|
||
|
|
"oc": a.get("oc", False),
|
||
|
|
"grants": a.get("grants", []),
|
||
|
|
"grants_complete": a.get("grants_complete", True)
|
||
|
|
}
|
||
|
|
for a in augments_raw.get("augments", [])
|
||
|
|
]
|
||
|
|
augments_list.sort(key=lambda x: x["id"])
|
||
|
|
augments_output = {
|
||
|
|
"format_version": 1,
|
||
|
|
"target_client_version": catalog["client_version"],
|
||
|
|
"target_assembly_sha256": assembly,
|
||
|
|
"provenance": {
|
||
|
|
"repository": "https://gaytea.cod-algieba.ts.net/xaodev/Currency-War-SR",
|
||
|
|
"commit": commit,
|
||
|
|
"license": "AGPL-3.0-only",
|
||
|
|
"inputs_sha256": {
|
||
|
|
"augments.json": hashes["resources/grid_fight/augments.json"],
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"season_id": augments_raw.get("season_id", 2),
|
||
|
|
"augments": augments_list
|
||
|
|
}
|
||
|
|
(root / "resources/CurrencyWarsAugments.json").write_text(
|
||
|
|
json.dumps(augments_output, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
|
||
|
|
)
|
||
|
|
|
||
|
|
# 4. Node Drops
|
||
|
|
node_drops_output = {
|
||
|
|
"format_version": 1,
|
||
|
|
"target_client_version": catalog["client_version"],
|
||
|
|
"target_assembly_sha256": assembly,
|
||
|
|
"provenance": {
|
||
|
|
"repository": "https://gaytea.cod-algieba.ts.net/xaodev/Currency-War-SR",
|
||
|
|
"commit": commit,
|
||
|
|
"license": "AGPL-3.0-only",
|
||
|
|
"inputs_sha256": {
|
||
|
|
"orb_rewards.json": hashes["resources/grid_fight/orb_rewards.json"],
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"node_drops": orbs_raw.get("node_drops", {})
|
||
|
|
}
|
||
|
|
(root / "resources/CurrencyWarsNodeDrops.json").write_text(
|
||
|
|
json.dumps(node_drops_output, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
|
||
|
|
)
|
||
|
|
|
||
|
|
license_dir = root / "third_party/currency-war-sr"
|
||
|
|
license_dir.mkdir(parents=True, exist_ok=True)
|
||
|
|
(license_dir / "LICENSE").write_bytes((source / "LICENSE").read_bytes())
|
||
|
|
print(f"Imported CW resources:")
|
||
|
|
print(f" - CurrencyWarsXaodev.json: {len(output_cw['node_rules'])} branch rules, {len(divisions)} divisions")
|
||
|
|
print(f" - CurrencyWarsScore.json: {len(score_output['divisions'])} score divisions, {len(offering_s2)} offering levels")
|
||
|
|
print(f" - CurrencyWarsTraits.json: {len(traits_list)} traits")
|
||
|
|
print(f" - CurrencyWarsAugments.json: {len(augments_list)} augments")
|
||
|
|
print(f" - CurrencyWarsNodeDrops.json: {len(node_drops_output['node_drops'])} drop rules")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|