Bootstrap Warium NeoForge port scaffold
Some checks failed
Build / build (push) Failing after 13m38s
Release Dry Run / release-dry-run (push) Successful in 5s
Codex Template Compliance / template-compliance (push) Successful in 5s

This commit is contained in:
Codex
2026-05-09 20:59:05 +02:00
commit 6ef5fdd378
36 changed files with 3073 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
from __future__ import annotations
from pathlib import Path
from warium_source import ROOT
def main() -> None:
required_private = [
ROOT / "ci" / "required-mods" / "wariumapi-neoforge-1.21.1.jar",
ROOT / "ci" / "required-mods" / "wariumvs-neoforge-1.21.1.jar",
]
missing = [path for path in required_private if not path.exists()]
if missing:
print("Required private integration jars are not present yet:")
for path in missing:
print(f"- {path}")
print("The built jar includes private compatibility shim mod metadata for wariumapi and wariumvs.")
print("Replace the shims with real jars when NeoForge 1.21.1 artifacts are available.")
else:
print("Required private integration jars are present.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,40 @@
from __future__ import annotations
import shutil
import subprocess
import urllib.request
from pathlib import Path
from warium_source import BUILD_DIR, ROOT, clean_dir, download_original
VINEFLOWER_URL = "https://repo1.maven.org/maven2/org/vineflower/vineflower/1.11.1/vineflower-1.11.1.jar"
VINEFLOWER_JAR = BUILD_DIR / "vineflower-1.11.1.jar"
DECOMPILED_DIR = ROOT / "build" / "decompiled" / "warium-1.2.7"
def main() -> None:
original = download_original()
BUILD_DIR.mkdir(parents=True, exist_ok=True)
if not VINEFLOWER_JAR.exists():
request = urllib.request.Request(VINEFLOWER_URL, headers={"User-Agent": "MrSphay/Warium-NeoForge-Port/1.0"})
with urllib.request.urlopen(request) as response, VINEFLOWER_JAR.open("wb") as out:
shutil.copyfileobj(response, out)
clean_dir(DECOMPILED_DIR)
subprocess.run(
["java", "-jar", str(VINEFLOWER_JAR), str(original), str(DECOMPILED_DIR)],
cwd=ROOT,
check=True,
)
report = ROOT / "docs" / "inventory" / "decompile-report.md"
report.parent.mkdir(parents=True, exist_ok=True)
report.write_text(
"# Decompile Report\n\n"
f"- Source: `{original}`\n"
f"- Output: `{DECOMPILED_DIR}`\n"
"- Decompiler: Vineflower 1.11.1\n",
encoding="utf-8",
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,141 @@
from __future__ import annotations
import json
import shutil
import zipfile
from pathlib import Path
from warium_source import MODID, ROOT, clean_dir, download_original, safe_java_identifier, write_json
GENERATED_JAVA = ROOT / "src" / "generated" / "java"
GENERATED_RESOURCES = ROOT / "src" / "generated" / "resources"
INVENTORY_DIR = ROOT / "docs" / "inventory"
def main() -> None:
jar = download_original()
clean_dir(GENERATED_JAVA)
clean_dir(GENERATED_RESOURCES)
INVENTORY_DIR.mkdir(parents=True, exist_ok=True)
with zipfile.ZipFile(jar) as archive:
names = archive.namelist()
block_names = sorted(stem(n) for n in names if n.startswith(f"assets/{MODID}/blockstates/") and n.endswith(".json"))
item_model_names = sorted(stem(n) for n in names if n.startswith(f"assets/{MODID}/models/item/") and n.endswith(".json"))
standalone_items = sorted(name for name in item_model_names if name not in set(block_names))
extract_resources(archive)
inventory = {
"source": "Warium 1.2.7",
"source_sha1": "528d81630a23fb4004e3abdd99b16bd225cd1e92",
"modid": MODID,
"blocks_from_blockstates": block_names,
"standalone_items_from_item_models": standalone_items,
"counts": {
"blockstates": len(block_names),
"item_models": len(item_model_names),
"standalone_items": len(standalone_items),
"classes": len([n for n in names if n.endswith(".class")]),
"procedures": len([n for n in names if n.startswith("net/mcreator/crustychunks/procedures/") and n.endswith(".class")]),
"entities": len([n for n in names if n.startswith("net/mcreator/crustychunks/entity/") and n.endswith(".class")]),
"recipes": len([n for n in names if n.startswith(f"data/{MODID}/recipes/") and n.endswith(".json")]),
"loot_tables": len([n for n in names if n.startswith(f"data/{MODID}/loot_tables/") and n.endswith(".json")]),
},
}
write_json(INVENTORY_DIR / "original-inventory.json", inventory)
write_generated_registries(block_names, standalone_items)
def stem(path: str) -> str:
return Path(path).name.removesuffix(".json")
def extract_resources(archive: zipfile.ZipFile) -> None:
for info in archive.infolist():
if info.is_dir():
continue
name = info.filename
if name.startswith(f"assets/{MODID}/"):
target = GENERATED_RESOURCES / name
elif name.startswith(f"data/{MODID}/"):
target = GENERATED_RESOURCES / migrate_data_path(name)
elif name == "pack.mcmeta":
continue
else:
continue
target.parent.mkdir(parents=True, exist_ok=True)
with archive.open(info) as src, target.open("wb") as dst:
shutil.copyfileobj(src, dst)
def migrate_data_path(path: str) -> str:
path = path.replace(f"data/{MODID}/loot_tables/", f"data/{MODID}/loot_table/")
path = path.replace(f"data/{MODID}/tags/items/", f"data/{MODID}/tags/item/")
path = path.replace(f"data/{MODID}/tags/blocks/", f"data/{MODID}/tags/block/")
path = path.replace(f"data/{MODID}/tags/entity_types/", f"data/{MODID}/tags/entity_type/")
path = path.replace(f"data/{MODID}/tags/fluids/", f"data/{MODID}/tags/fluid/")
return path
def write_generated_registries(blocks: list[str], items: list[str]) -> None:
package_dir = GENERATED_JAVA / "net" / "mcreator" / "crustychunks" / "init"
package_dir.mkdir(parents=True, exist_ok=True)
used: set[str] = set()
lines: list[str] = [
"package net.mcreator.crustychunks.init;",
"",
"import net.mcreator.crustychunks.CrustyChunksMod;",
"import net.minecraft.core.registries.Registries;",
"import net.minecraft.network.chat.Component;",
"import net.minecraft.world.item.BlockItem;",
"import net.minecraft.world.item.CreativeModeTab;",
"import net.minecraft.world.item.Item;",
"import net.minecraft.world.item.ItemStack;",
"import net.minecraft.world.item.Items;",
"import net.minecraft.world.level.block.Block;",
"import net.minecraft.world.level.block.state.BlockBehaviour;",
"import net.neoforged.bus.api.IEventBus;",
"import net.neoforged.neoforge.registries.DeferredHolder;",
"import net.neoforged.neoforge.registries.DeferredRegister;",
"",
"public final class GeneratedRegistries {",
" public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(Registries.BLOCK, CrustyChunksMod.MODID);",
" public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(Registries.ITEM, CrustyChunksMod.MODID);",
" public static final DeferredRegister<CreativeModeTab> CREATIVE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, CrustyChunksMod.MODID);",
"",
]
for name in blocks:
ident = safe_java_identifier(name, used)
lines.append(f' public static final DeferredHolder<Block, Block> {ident} = BLOCKS.register("{name}", () -> new Block(BlockBehaviour.Properties.of().strength(2.0F, 6.0F)));')
lines.append(f' public static final DeferredHolder<Item, BlockItem> {ident}_ITEM = ITEMS.register("{name}", () -> new BlockItem({ident}.get(), new Item.Properties()));')
for name in items:
ident = safe_java_identifier(name, used)
lines.append(f' public static final DeferredHolder<Item, Item> {ident} = ITEMS.register("{name}", () -> new Item(new Item.Properties()));')
lines.extend([
"",
' public static final DeferredHolder<CreativeModeTab, CreativeModeTab> WARIUM_TAB = CREATIVE_TABS.register("warium", () -> CreativeModeTab.builder()',
' .title(Component.translatable("itemGroup.crusty_chunks.warium"))',
" .icon(() -> new ItemStack(Items.IRON_INGOT))",
" .displayItems((parameters, output) -> ITEMS.getEntries().forEach(entry -> output.accept(entry.get())))",
" .build());",
"",
" private GeneratedRegistries() {",
" }",
"",
" public static void register(IEventBus modBus) {",
" BLOCKS.register(modBus);",
" ITEMS.register(modBus);",
" CREATIVE_TABS.register(modBus);",
" }",
"}",
"",
])
(package_dir / "GeneratedRegistries.java").write_text("\n".join(lines), encoding="utf-8")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,50 @@
from __future__ import annotations
import json
import shutil
import urllib.parse
import urllib.request
from pathlib import Path
from warium_source import ROOT
MODS_DIR = ROOT / "run" / "server" / "mods"
REQUIRED_MODRINTH = [
("geckolib", "4.7.5.1"),
("rpl", "2.1.2"),
]
def main() -> None:
MODS_DIR.mkdir(parents=True, exist_ok=True)
for project, version in REQUIRED_MODRINTH:
download_modrinth_version(project, version)
private_dir = ROOT / "ci" / "required-mods"
if private_dir.exists():
for jar in private_dir.glob("*.jar"):
shutil.copy2(jar, MODS_DIR / jar.name)
print(f"Runtime mods prepared in {MODS_DIR}")
def download_modrinth_version(project: str, version_number: str) -> None:
encoded_project = urllib.parse.quote(project)
loaders = urllib.parse.quote(json.dumps(["neoforge"]))
game_versions = urllib.parse.quote(json.dumps(["1.21.1"]))
url = f"https://api.modrinth.com/v2/project/{encoded_project}/version?loaders={loaders}&game_versions={game_versions}"
request = urllib.request.Request(url, headers={"User-Agent": "MrSphay/Warium-NeoForge-Port/1.0"})
with urllib.request.urlopen(request) as response:
data = json.loads(response.read().decode("utf-8"))
selected = next((entry for entry in data if entry.get("version_number") == version_number), None)
if selected is None:
available = ", ".join(entry.get("version_number", "?") for entry in data[:10])
raise SystemExit(f"No NeoForge 1.21.1 build found for {project} {version_number}. Available: {available}")
primary = next((file for file in selected["files"] if file.get("primary")), selected["files"][0])
target = MODS_DIR / primary["filename"].replace(" ", "-")
request = urllib.request.Request(primary["url"], headers={"User-Agent": "MrSphay/Warium-NeoForge-Port/1.0"})
with urllib.request.urlopen(request) as response, target.open("wb") as out:
shutil.copyfileobj(response, out)
if __name__ == "__main__":
main()

31
tools/registry_parity.py Normal file
View File

@@ -0,0 +1,31 @@
from __future__ import annotations
import json
from pathlib import Path
from warium_source import ROOT
def main() -> None:
inventory_path = ROOT / "docs" / "inventory" / "original-inventory.json"
generated_source = ROOT / "src" / "generated" / "java" / "net" / "mcreator" / "crustychunks" / "init" / "GeneratedRegistries.java"
if not inventory_path.exists() or not generated_source.exists():
raise SystemExit("Generated inventory is missing; run generatePortSources first.")
inventory = json.loads(inventory_path.read_text(encoding="utf-8"))
source = generated_source.read_text(encoding="utf-8")
missing_blocks = [name for name in inventory["blocks_from_blockstates"] if f'"{name}"' not in source]
missing_items = [name for name in inventory["standalone_items_from_item_models"] if f'"{name}"' not in source]
if missing_blocks or missing_items:
raise SystemExit(
"Registry parity failed: "
f"{len(missing_blocks)} blocks missing, {len(missing_items)} standalone items missing"
)
print(
"Registry parity OK: "
f"{len(inventory['blocks_from_blockstates'])} blocks and "
f"{len(inventory['standalone_items_from_item_models'])} standalone items generated."
)
if __name__ == "__main__":
main()

76
tools/warium_source.py Normal file
View File

@@ -0,0 +1,76 @@
from __future__ import annotations
import hashlib
import json
import re
import shutil
import urllib.request
import zipfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
BUILD_DIR = ROOT / "build" / "warium-port"
ORIGINAL_JAR = BUILD_DIR / "Warium-1.2.7.jar"
ORIGINAL_URL = "https://cdn.modrinth.com/data/xgjvEen1/versions/4oIhAhRz/Warium%201.2.7.jar"
ORIGINAL_SHA1 = "528d81630a23fb4004e3abdd99b16bd225cd1e92"
MODID = "crusty_chunks"
def download_original() -> Path:
BUILD_DIR.mkdir(parents=True, exist_ok=True)
if not ORIGINAL_JAR.exists() or sha1(ORIGINAL_JAR) != ORIGINAL_SHA1:
request = urllib.request.Request(
ORIGINAL_URL,
headers={"User-Agent": "MrSphay/Warium-NeoForge-Port/1.0"},
)
with urllib.request.urlopen(request) as response, ORIGINAL_JAR.open("wb") as out:
shutil.copyfileobj(response, out)
actual = sha1(ORIGINAL_JAR)
if actual != ORIGINAL_SHA1:
raise SystemExit(f"Original jar SHA1 mismatch: expected {ORIGINAL_SHA1}, got {actual}")
return ORIGINAL_JAR
def sha1(path: Path) -> str:
digest = hashlib.sha1()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def clean_dir(path: Path) -> None:
if path.exists():
shutil.rmtree(path)
path.mkdir(parents=True, exist_ok=True)
def safe_java_identifier(name: str, used: set[str]) -> str:
ident = re.sub(r"[^a-zA-Z0-9_]", "_", name).upper()
if not ident or ident[0].isdigit():
ident = "_" + ident
if ident in JAVA_KEYWORDS:
ident = ident + "_ENTRY"
base = ident
suffix = 2
while ident in used:
ident = f"{base}_{suffix}"
suffix += 1
used.add(ident)
return ident
def write_json(path: Path, data: object) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8")
JAVA_KEYWORDS = {
"ABSTRACT", "ASSERT", "BOOLEAN", "BREAK", "BYTE", "CASE", "CATCH", "CHAR",
"CLASS", "CONST", "CONTINUE", "DEFAULT", "DO", "DOUBLE", "ELSE", "ENUM",
"EXTENDS", "FINAL", "FINALLY", "FLOAT", "FOR", "GOTO", "IF", "IMPLEMENTS",
"IMPORT", "INSTANCEOF", "INT", "INTERFACE", "LONG", "NATIVE", "NEW",
"PACKAGE", "PRIVATE", "PROTECTED", "PUBLIC", "RETURN", "SHORT", "STATIC",
"STRICTFP", "SUPER", "SWITCH", "SYNCHRONIZED", "THIS", "THROW", "THROWS",
"TRANSIENT", "TRY", "VOID", "VOLATILE", "WHILE",
}