文件
AutoStore/analyze_holes.py

126 行
4.0 KiB
Python

import json, math, urllib.request, sys
sys.dont_write_bytecode = True
URL = "http://bgjq.simpfun.cn/tiles/minecraft_overworld/markers.json"
data = urllib.request.urlopen(
urllib.request.Request(URL, headers={"User-Agent": "Mozilla/5.0 autostore/1.0"}),
timeout=20).read()
root = json.loads(data.decode("utf-8"))
CLAIM_PATTERN_prefix = "疆土归属:"
def extract_polygons(points):
result = []
if points is None or not isinstance(points, list):
return result
if len(points) == 0:
return result
if isinstance(points[0], dict) and "x" in points[0] and "z" in points[0]:
poly = [(p["x"], p["z"]) for p in points]
if len(poly) >= 3:
result.append(poly)
else:
for el in points:
result.extend(extract_polygons(el))
return result
def point_in_polygon(x, z, poly):
inside = False
j = len(poly) - 1
for i in range(len(poly)):
xi, zi = poly[i]
xj, zj = poly[j]
if (zi > z) != (zj > z) and x < (xj - xi) * (z - zi) / (zj - zi) + xi:
inside = not inside
j = i
return inside
def fill_polygon(out, poly):
minx = min(math.floor(p[0]/16) for p in poly)
maxx = max(math.floor(p[0]/16) for p in poly)
minz = min(math.floor(p[1]/16) for p in poly)
maxz = max(math.floor(p[1]/16) for p in poly)
area = (maxx - minx + 1) * (maxz - minz + 1)
if area > 6_000_000:
return
for cx in range(minx, maxx+1):
for cz in range(minz, maxz+1):
if point_in_polygon(cx*16+8, cz*16+8, poly):
out.add((cx, cz))
# Polygon count per marker
poly_counts = {}
for layer in root:
if layer.get("id") != "union_claims":
continue
for marker in layer.get("markers", []):
popup = marker.get("popup", "")
idx = popup.find(CLAIM_PATTERN_prefix)
if idx < 0:
continue
rest = popup[idx+len(CLAIM_PATTERN_prefix):].lstrip()
name = ""
for ch in rest:
if ch in "<\r\n":
break
name += ch
name = name.strip()
if not name:
continue
polys = extract_polygons(marker.get("points"))
poly_counts.setdefault(name, 0)
poly_counts[name] += len(polys)
print("=== markers with multiple polygons (potential holes as inner rings) ===")
for name, cnt in poly_counts.items():
if cnt > 1:
print(f" {name}: {cnt} polygons")
# Also report how many total markers
print(f"\nTotal markers: {sum(poly_counts.values())}, distinct countries: {len(poly_counts)}")
claims = {}
for layer in root:
if layer.get("id") != "union_claims":
continue
for marker in layer.get("markers", []):
popup = marker.get("popup", "")
idx = popup.find(CLAIM_PATTERN_prefix)
if idx < 0:
continue
rest = popup[idx+len(CLAIM_PATTERN_prefix):].lstrip()
name = ""
for ch in rest:
if ch in "<\r\n":
break
name += ch
name = name.strip()
if not name:
continue
s = claims.setdefault(name, set())
for poly in extract_polygons(marker.get("points")):
fill_polygon(s, poly)
print(f"Total countries parsed: {len(claims)}")
print(f"Total claimed chunks: {sum(len(v) for v in claims.values())}")
print("\n=== Flying chunks (holes) per country ===")
total_holes = 0
for name, chunks in claims.items():
if not chunks:
continue
xs = [c[0] for c in chunks]
zs = [c[1] for c in chunks]
minx, maxx = min(xs), max(xs)
minz, maxz = min(zs), max(zs)
holes = []
for cx in range(minx, maxx+1):
for cz in range(minz, maxz+1):
if (cx, cz) in chunks:
continue
if all(((cx+dx, cz+dz) in chunks) for dx, dz in [(1,0),(-1,0),(0,1),(0,-1)]):
holes.append((cx, cz))
if holes:
total_holes += len(holes)
print(f" {name}: {len(holes)} holes, e.g. {holes[:8]}")
print(f"\n=== TOTAL flying chunks: {total_holes} ===")