Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI v0.5.0 #24

Merged
merged 5 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:

- run: unzip assets/vanilla_structures.zip -d structures

- run: python __main__.py
- run: python cli/__main__.py

test_regolith_filter:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -65,4 +65,4 @@ jobs:
- name: Compiles
shell: bash
working-directory: './regolith-test-project'
run: regolith run default
run: regolith run default
83 changes: 0 additions & 83 deletions __main__.py

This file was deleted.

124 changes: 124 additions & 0 deletions cli/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from rich.progress import Progress, TextColumn, BarColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
import pathlib
import gzip
import pynbt
from time import time
from java_structures import javaToBedrock
from os import listdir, makedirs, remove
from os.path import isfile, join, isdir
import threading
import json
import re

structurePath = 'structures' # Path of structures
settings_path = './settings.json'

def get_block_mapping(structure_id: str, settings: dict):
for entry in settings.get("block_mapping", []):
pattern = entry["structure_id"]
if "*" in pattern:
regex = re.compile("^" + re.escape(pattern).replace("\\*", ".*") + "$")
if regex.match(structure_id):
return entry["mapping"]
elif pattern == structure_id:
return entry["mapping"]
return {}

def get_structure_id(file_path: str) -> str:
return pathlib.Path(file_path).stem

def convert(file: str, settings: dict):
mcstructureFile = file.replace(pathlib.Path(file).suffix, '') + '.mcstructure'
structure_id = get_structure_id(file)
print(f"Converting '{file}' to '{mcstructureFile}' with structure ID '{structure_id}'")

print("Reading " + file)
io = gzip.open(file, mode="rb+")

print("Parsing " + file)
startTime = time()
nbt = pynbt.NBTFile(io)
print(f"Loaded {file} in {round((time() - startTime) * 1000, 2)} ms")

# Get custom mapping
block_mapping = get_block_mapping(structure_id, settings)

mcstructure, size = javaToBedrock(nbt, structure_id, block_mapping)
startTime = time()

with open(mcstructureFile, 'wb') as io:
columns = (
TextColumn("[progress.description]{task.description}"),
BarColumn(),
DownloadColumn(),
TransferSpeedColumn(),
TextColumn("eta"),
TimeRemainingColumn(),
)
with Progress(*columns, refresh_per_second=30) as progress:
task = progress.add_task("[cyan]Writing mcstructure...", total=size)
global completed
global timer
completed = 0

def write(data: bytes):
global completed
io.write(data)
completed += len(data)

def renderWriteProgress():
global timer
progress.update(task, completed=completed)
timer = threading.Timer(1 / 30, renderWriteProgress)
timer.start()

renderWriteProgress()
mcstructure.save(write, True)

# stop progress as mcstructure file has been saved
timer.cancel()
progress.update(task, completed=completed, total=completed)
progress.stop()

print(f"Wrote {mcstructureFile} in {round((time() - startTime) * 1000, 2)} ms\n")

def get_nbtFiles(dirpath: str) -> list[str]:
files = []
for f in listdir(dirpath):
path = join(dirpath, f)
if isfile(path) and f.endswith(".nbt"):
files.append(path)
elif isdir(path):
for file in get_nbtFiles(path):
files.append(file)
return files

## -----------
## MAIN
## -----------
def main():
# Load settings file
if isfile(settings_path):
f = open(settings_path, "r")
json_file = f.read()
settings = json.loads(json_file)
else:
settings = {}

# Convert structures
makedirs(structurePath, exist_ok=True)
nbtFiles = get_nbtFiles(structurePath)
if len(nbtFiles) == 0:
print(f"There are 0 .nbt files in '{structurePath}' folder.")
else:
for file in nbtFiles:
convert(file, settings)

# Delete .nbt files after processing
for file in nbtFiles:
try:
remove(file)
except Exception as e:
print(f"Error deleting file {file}: {e}")

main()
52 changes: 41 additions & 11 deletions java_structures.py → cli/java_structures.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from time import time
import os
import json, re
from pynbt import (
NBTFile,
Expand All @@ -12,10 +13,27 @@
)
from progress_bar import track

blocksj2b = json.loads(open("./assets/blocksJ2B.json", "r").read())
bedsj2b = json.loads(open("./assets/bedsJ2B.json", "r").read())
skullj2b = json.loads(open("./assets/skullJ2B.json", "r").read())
blockstates = json.loads(open("./assets/blockstates.json", "r").read())
assets_dir = os.path.abspath('./assets/')

# Construct full paths to your files
blocksj2b_path = os.path.join(assets_dir, "blocksJ2B.json")
bedsj2b_path = os.path.join(assets_dir, "bedsJ2B.json")
skullj2b_path = os.path.join(assets_dir, "skullJ2B.json")
blockstates_path = os.path.join(assets_dir, "blockstates.json")

# Load JSON files
with open(blocksj2b_path, "r") as f:
blocksj2b = json.load(f)

with open(bedsj2b_path, "r") as f:
bedsj2b = json.load(f)

with open(skullj2b_path, "r") as f:
skullj2b = json.load(f)

with open(blockstates_path, "r") as f:
blockstates = json.load(f)

MC_VERSION = "1.21.0.03"

def checkEntry(blocks, entry):
Expand Down Expand Up @@ -106,8 +124,8 @@ def getDynamicBlockIdentifier(blockobject):

def getBlockObject(dynamicblockid: str, format="bedrock"):
baseidentifier = dynamicblockid.split("[")[0]
properties = dynamicblockid.split("[")[1].replace("]", "")
if properties.split(",")[0] != "":
properties = dynamicblockid.split("[")[1].replace("]", "") if "[" in dynamicblockid else ""
if properties:
properties = properties.split(",")
else:
properties = []
Expand Down Expand Up @@ -150,7 +168,7 @@ def getBlockObject(dynamicblockid: str, format="bedrock"):
print(f"Warning: State name {statename} with value {statevalue} is not a valid state for {baseidentifier}. Valid values: {validValues}.")
return object

def javaToBedrock(structure: NBTFile):
def javaToBedrock(structure: NBTFile, structure_id: str, block_mapping: dict):
blocks: TAG_List = structure["blocks"].value
palette: TAG_List = structure["palette"].value
oldsize: TAG_List = structure["size"].value
Expand Down Expand Up @@ -191,13 +209,25 @@ def javaToBedrock(structure: NBTFile):
# applying palette
startTime = time()
for i in track(sequence=palette, description="[green]Applying Palette"):
# Using prismarine-data, find the java edition ID
blockId = getDynamicBlockIdentifier(i)
if not blockId in blocksj2b:
newPalette.append(getBlockObject("minecraft:air[]", "bedrock"))
else:
baseBlockId = blockId.split("[")[0] # Get the base block identifier

# Check for exact match in custom mapping (with brackets)
if blockId in block_mapping:
mapped_id = block_mapping[blockId]
newPalette.append(getBlockObject(mapped_id, "bedrock"))
# Check for base identifier match in custom mapping (ignore brackets)
elif baseBlockId in block_mapping:
mapped_id = block_mapping[baseBlockId]
newPalette.append(getBlockObject(mapped_id, "bedrock"))
# Fallback to default mapping
elif blockId in blocksj2b:
javaId = blocksj2b[blockId]
newPalette.append(getBlockObject(javaId, "bedrock"))
# Fallback to air if no mapping found
else:
newPalette.append(getBlockObject("minecraft:air[]", "bedrock"))

if applyWaterloggedBlock:
newPalette.append(getBlockObject("minecraft:water[liquid_depth=0]", "bedrock"))
print(f"Finished applying palette in {round((time() - startTime) * 1000, 2)} ms")
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion nbt-to-mcstructure.spec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ block_cipher = None


a = Analysis(
['__main__.py'],
['cli/__main__.py'],
pathex=[],
binaries=[],
datas=[],
Expand Down
Loading