Files
RustNotMC/tools/gen_version_consts.py
SashegDev 874b6f20c2 Клиент: начальный импорт кодовой базы
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
2026-10-29 22:04:28 +03:00

80 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""Generate crates/horizon-core/src/version.rs: what the pinned Minecraft version states about itself in its
client jar's version.json (name, protocol, data version, pack formats, Java, build time). Every Rust site that
needs one of these facts reads it from there, so a version bump rewrites this one file
(docs/version-ports.md, "Regenerate").
gen_version_consts.py [--jar CLIENT_JAR] [--out PATH] [--check]
The default jar is the pinned one (.local/minecraft/<research-lock.json version>/jars/client.jar).
--check exits 1 when the committed file differs from what the jar says.
"""
import argparse
from datetime import datetime, timezone
import json
from pathlib import Path
import sys
try:
from . import lab
except ImportError:
import lab
OUT = lab.ROOT / "crates/horizon-core/src/version.rs"
def java_date(iso):
"""`Date.toString()` of an ISO-8601 instant, in UTC (Locale.ROOT names)."""
return datetime.fromisoformat(iso).astimezone(timezone.utc).strftime("%a %b %d %H:%M:%S UTC %Y")
def render(info):
pack = info["pack_version"]
return "\n".join([
f"//! What Minecraft {info['name']} states about itself (the client jar's `version.json`,",
"//! `SharedConstants.getCurrentVersion()`). Generated by tools/gen_version_consts.py; do not edit by hand.",
"",
"/// `WorldVersion.id()`.",
f"pub const VERSION_ID: &str = {json.dumps(info['id'])};",
"/// `WorldVersion.name()`: level.dat, the server list, crash reports.",
f"pub const VANILLA_VERSION: &str = {json.dumps(info['name'])};",
"/// `SharedConstants.getProtocolVersion()`.",
f"pub const PROTOCOL_VERSION: i32 = {info['protocol_version']};",
"/// `WorldVersion.dataVersion()`: the DataVersion of saved chunks, entities and level.dat.",
f"pub const DATA_VERSION: i32 = {info['world_version']};",
"/// `WorldVersion.packVersion(PackType.CLIENT_RESOURCES)`: (major, minor).",
f"pub const RESOURCE_PACK_FORMAT: (i64, i64) = ({pack['resource_major']}, {pack['resource_minor']});",
"/// `WorldVersion.packVersion(PackType.SERVER_DATA)`: (major, minor).",
f"pub const DATA_PACK_FORMAT: (i64, i64) = ({pack['data_major']}, {pack['data_minor']});",
"/// The Java major version the game runs on.",
f"pub const JAVA_VERSION: u32 = {info['java_version']};",
"/// `WorldVersion.stable()`: false for snapshots and pre-releases.",
f"pub const STABLE: bool = {'true' if info['stable'] else 'false'};",
"/// `WorldVersion.buildTime()` as `Date.toString()` prints it in UTC (`/version`).",
f"pub const BUILD_TIME: &str = {json.dumps(java_date(info['build_time']))};",
"",
])
def main():
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--jar", type=Path, help="client jar (default: the pinned one in .local)")
parser.add_argument("--out", type=Path, default=OUT)
parser.add_argument("--check", action="store_true", help="exit 1 if --out differs instead of writing it")
args = parser.parse_args()
jar = args.jar or lab.GAME / "jars" / "client.jar"
text = render(lab.version_info(jar))
if args.check:
if not args.out.exists() or args.out.read_text() != text:
print(f"{args.out} does not match {jar}; run tools/gen_version_consts.py", file=sys.stderr)
return 1
return 0
args.out.write_text(text)
print(f"wrote {args.out}")
return 0
if __name__ == "__main__":
sys.exit(main())