#!/usr/bin/env python3 """Generate crates/horizon-client/src/lan/tracking.rs: every entity type's tracking settings (EntityType.Builder clientTrackingRange, updateInterval and trackDeltas, which ChunkMap.TrackedEntity and ServerEntity use to decide who sees an entity and how often its movement is sent), read from the decompiled EntityTypes.java. generate_entity_tracking.py [--sources .local/minecraft//sources/client] """ import argparse import re from pathlib import Path try: from . import lab except ImportError: import lab ROOT = Path(__file__).resolve().parents[1] INT_MAX = 2147483647 def parse(sources): text = (sources / "net/minecraft/world/entity/EntityTypes.java").read_text() out = [] for m in re.finditer(r"public static final EntityType<[\w.]+> (\w+) = register\((.*?)\n \);", text, re.S): name, body = m.group(1).lower(), m.group(2) range_ = re.findall(r"\.clientTrackingRange\((\d+)\)", body) interval = re.findall(r"\.updateInterval\((\w+(?:\.\w+)?)\)", body) track = ".dontTrackDeltas()" not in body r = int(range_[-1]) if range_ else 5 if ".noUpdateInterval()" in body or (interval and interval[-1] == "Integer.MAX_VALUE"): i = 0 else: i = int(interval[-1]) if interval else 3 out.append((f"minecraft:{name}", r, i, track)) return sorted(out) def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--sources", type=Path, default=lab.GAME / "sources/client") parser.add_argument("--out", type=Path, default=ROOT / "crates/horizon-client/src/lan/tracking.rs") args = parser.parse_args() rows = parse(args.sources) if len(rows) < 100: raise SystemExit(f"only {len(rows)} entity types found") lines = [ "//! Entity tracking settings per entity type (EntityType.Builder", "//! clientTrackingRange in chunks, updateInterval in ticks with 0 for never,", "//! trackDeltas). Generated by tools/generate_entity_tracking.py from the", "//! decompiled EntityTypes.java; do not edit by hand.", "", "/// (entity type, tracking range in chunks, update interval, track deltas), sorted.", "pub const TRACKING: &[(&str, u8, u32, bool)] = &[", ] lines += [f' ("{n}", {r}, {i}, {str(t).lower()}),' for n, r, i, t in rows] lines += [ "];", "", "/// The settings of one entity type; unknown types get the builder defaults.", "pub fn settings(kind: &str) -> (u8, u32, bool) {", " TRACKING", " .binary_search_by(|row| row.0.cmp(kind))", " .map_or((5, 3, true), |i| (TRACKING[i].1, TRACKING[i].2, TRACKING[i].3))", "}", "", ] args.out.write_text("\n".join(lines)) print(f"wrote {len(rows)} entity types to {args.out}") if __name__ == "__main__": main()