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} ===")