From a919b91efbf5181dff1d5661e04e755ad06c3484 Mon Sep 17 00:00:00 2001 From: RePixelatedMC Date: Tue, 30 Apr 2024 11:14:35 +0200 Subject: [PATCH] Whohoo! we can now read mca files! --- build.gradle | 4 +- .../iris/core/commands/CommandDeveloper.java | 2 +- .../volmit/iris/core/tools/IrisWorldDump.java | 27 ++++- .../com/volmit/iris/util/nbt/mca/Chunk.java | 14 +-- .../com/volmit/iris/util/nbt/mca/Section.java | 6 +- .../mca/palette/MCABitStorageByteArray.java | 112 ++++++++++++++++++ ...orage.java => MCABitStorageLongArray.java} | 7 +- .../nbt/mca/palette/MCAPalettedContainer.java | 70 ++++++++++- .../palette/MCAWrappedPalettedContainer.java | 22 +++- core/src/main/resources/plugin.yml | 2 + 10 files changed, 236 insertions(+), 30 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorageByteArray.java rename core/src/main/java/com/volmit/iris/util/nbt/mca/palette/{MCABitStorage.java => MCABitStorageLongArray.java} (96%) diff --git a/build.gradle b/build.gradle index 9186ae4a8..434a1ccad 100644 --- a/build.gradle +++ b/build.gradle @@ -237,8 +237,6 @@ allprojects { implementation "net.kyori:adventure-text-minimessage:4.13.1" implementation 'net.kyori:adventure-platform-bukkit:4.3.2' implementation 'net.kyori:adventure-api:4.13.1' - //implementation 'org.bytedeco:javacpp:1.5.10' - //implementation 'org.bytedeco:cuda-platform:12.3-8.9-1.5.10' compileOnly 'io.lumine:Mythic-Dist:5.2.1' // Dynamically Loaded @@ -255,6 +253,8 @@ allprojects { compileOnly 'org.apache.commons:commons-lang3:3.12.0' compileOnly 'net.bytebuddy:byte-buddy:1.14.14' compileOnly 'net.bytebuddy:byte-buddy-agent:1.12.8' + compileOnly 'org.bytedeco:javacpp:1.5.10' + compileOnly 'org.bytedeco:cuda-platform:12.3-8.9-1.5.10' } /** diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index 2f67233b3..fb1e3c405 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -174,7 +174,7 @@ public class CommandDeveloper implements DecreeExecutor { try { File[] McaFiles = new File(world.getName(), "region").listFiles((dir, name) -> name.endsWith(".mca")); for (File mca : McaFiles) { - IrisWorldDump dump = new IrisWorldDump(world, sender()); + IrisWorldDump dump = new IrisWorldDump(world, sender(), IrisWorldDump.mode.RAW); dump.dump(); } } catch (Exception e) { diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisWorldDump.java b/core/src/main/java/com/volmit/iris/core/tools/IrisWorldDump.java index d113bca1f..f8cf1f8c4 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisWorldDump.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisWorldDump.java @@ -19,8 +19,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReferenceArray; public class IrisWorldDump { - public static int Failed = 0; - public static int Success = 0; private KList mcaList; private World world; private File MCADirectory; @@ -29,8 +27,9 @@ public class IrisWorldDump { private Engine engine = null; private Boolean IrisWorld; private VolmitSender sender; + private mode mode; - public IrisWorldDump(World world, VolmitSender sender) { + public IrisWorldDump(World world, VolmitSender sender, mode mode) { this.world = world; this.sender = sender; this.MCADirectory = new File(world.getWorldFolder(), "region"); @@ -54,6 +53,22 @@ public class IrisWorldDump { } } + public enum mode { + RAW { + @Override + public void methodDump() { + + } + }, + DISK { + @Override + public void methodDump() { + + } + }; + public abstract void methodDump(); + } + public void dump() { for (MCAFile mca : mcaList) { AtomicReferenceArray chunks = new AtomicReferenceArray<>(1024); @@ -68,6 +83,8 @@ public class IrisWorldDump { for (int z = 0; z < 16; z++) { for (int y = 0; y < CHUNK_HEIGHT; y++) { // CompoundTag tag = chunk.getBlockStateAt(x,y,z); + //net.minecraft.world.level.chunk.PalettedContainer; + //net.minecraft.world.level.chunk.storage.ChunkSerializer; } } } @@ -107,8 +124,8 @@ public class IrisWorldDump { if (f > 0) { sender.sendMessage(C.RED +"Failed " + C.GRAY + "to load: " + f + " MCA Regions"); } - Iris.info("Successfull: " + Form.f(Success)); - Iris.info("Failed: " + Form.f(Failed)); + Iris.info("Successfull: " + Form.f(l)); + Iris.info("Failed: " + Form.f(f)); return mcaFiles; } diff --git a/core/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java b/core/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java index 6b56fcfda..7fbe2e106 100644 --- a/core/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java +++ b/core/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java @@ -162,17 +162,11 @@ public class Chunk { if (sectionIndex > 15 || sectionIndex < 0) { continue; } - try { - Section newSection = new Section(section, dataVersion, loadFlags); - if (newSection.isEmpty()) { - continue; - } - sections.put(sectionIndex, newSection); - IrisWorldDump.Success++; - } catch (Exception e) { - IrisWorldDump.Failed++; - // e.printStackTrace(); + Section newSection = new Section(section, dataVersion, loadFlags); + if (newSection.isEmpty()) { + continue; } + sections.put(sectionIndex, newSection); } } diff --git a/core/src/main/java/com/volmit/iris/util/nbt/mca/Section.java b/core/src/main/java/com/volmit/iris/util/nbt/mca/Section.java index 0b8ea71b2..713d7ee1f 100644 --- a/core/src/main/java/com/volmit/iris/util/nbt/mca/Section.java +++ b/core/src/main/java/com/volmit/iris/util/nbt/mca/Section.java @@ -43,7 +43,11 @@ public class Section { return; } palette = INMS.get().createPalette(); - palette.readFromSection(sectionRoot); + try { + palette.readFromSection(sectionRoot); + } catch (Exception e) { + e.printStackTrace(); + } ByteArrayTag blockLight = sectionRoot.getByteArrayTag("BlockLight"); ByteArrayTag skyLight = sectionRoot.getByteArrayTag("SkyLight"); this.blockLight = blockLight != null ? blockLight.getValue() : null; diff --git a/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorageByteArray.java b/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorageByteArray.java new file mode 100644 index 000000000..22a073314 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorageByteArray.java @@ -0,0 +1,112 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2022 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * abyte with this program. If not, see . + */ + +package com.volmit.iris.util.nbt.mca.palette; + +import org.apache.commons.lang3.Validate; +// todo Cool idea but im way to dumb for this for now +public class MCABitStorageByteArray { + private final byte[] data; + private final int bits; + private final int mask; + private final int size; + private final int valuesPerByte; + + private final int divideMul; + private final int divideAdd; + private final int divideShift; + + public MCABitStorageByteArray(int bits, int length) { + this(bits, length, null); + } + + public MCABitStorageByteArray(int bits, int length, byte[] data) { + Validate.inclusiveBetween(1L, 8L, bits); // Ensure bits are between 1 and 8 + this.size = length; + this.bits = bits; + this.mask = (1 << bits) - 1; + this.valuesPerByte = 8 / bits; + int[] divisionParams = computeDivisionParameters(this.valuesPerByte); + this.divideMul = divisionParams[0]; + this.divideAdd = divisionParams[1]; + this.divideShift = divisionParams[2]; + int numBytes = (length + this.valuesPerByte - 1) / this.valuesPerByte; + if (data != null) { + if (data.length != numBytes) + throw new IllegalArgumentException("Data array length does not match the required size."); + this.data = data; + } else { + this.data = new byte[numBytes]; + } + } + + private int[] computeDivisionParameters(int denom) { + long two32 = 1L << 32; + long magic = two32 / denom; + int shift = 0; + while ((1L << (shift + 32)) < magic * denom) { + shift++; + } + return new int[]{(int) magic, 0, shift}; + } + + private int cellIndex(int index) { + long indexLong = Integer.toUnsignedLong(this.divideMul); + long addLong = Integer.toUnsignedLong(this.divideAdd); + return (int) ((index * indexLong + addLong) >>> 32 >>> this.divideShift); + } + + public int getAndSet(int index, int newValue) { + Validate.inclusiveBetween(0L, (this.size - 1), index); + Validate.inclusiveBetween(0L, this.mask, newValue); + int byteIndex = cellIndex(index); + int bitOffset = (index - byteIndex * this.valuesPerByte) * this.bits; + int currentValue = (this.data[byteIndex] >> bitOffset) & this.mask; + this.data[byteIndex] = (byte) ((this.data[byteIndex] & ~(this.mask << bitOffset)) | (newValue & this.mask) << bitOffset); + return currentValue; + } + + public void set(int index, int value) { + Validate.inclusiveBetween(0L, (this.size - 1), index); + Validate.inclusiveBetween(0L, this.mask, value); + int byteIndex = cellIndex(index); + int bitOffset = (index - byteIndex * this.valuesPerByte) * this.bits; + this.data[byteIndex] = (byte) ((this.data[byteIndex] & ~(this.mask << bitOffset)) | (value & this.mask) << bitOffset); + } + + public int get(int index) { + Validate.inclusiveBetween(0L, (this.size - 1), index); + int byteIndex = cellIndex(index); + int bitOffset = (index - byteIndex * this.valuesPerByte) * this.bits; + return (this.data[byteIndex] >> bitOffset) & this.mask; + } + + public byte[] getRaw() { + return this.data; + } + + public int getSize() { + return this.size; + } + + public int getBits() { + return this.bits; + } +} + + diff --git a/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorage.java b/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorageLongArray.java similarity index 96% rename from core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorage.java rename to core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorageLongArray.java index b3413bf5b..e2d9e157f 100644 --- a/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorage.java +++ b/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCABitStorageLongArray.java @@ -20,9 +20,10 @@ package com.volmit.iris.util.nbt.mca.palette; import org.apache.commons.lang3.Validate; +import java.util.BitSet; import java.util.function.IntConsumer; -public class MCABitStorage { +public class MCABitStorageLongArray { private static final int[] MAGIC = new int[]{ -1, -1, 0, Integer.MIN_VALUE, 0, 0, 1431655765, 1431655765, 0, Integer.MIN_VALUE, 0, 1, 858993459, 858993459, 0, 715827882, 715827882, 0, 613566756, 613566756, @@ -61,11 +62,11 @@ public class MCABitStorage { private final int divideShift; - public MCABitStorage(int bits, int length) { + public MCABitStorageLongArray(int bits, int length) { this(bits, length, null); } - public MCABitStorage(int bits, int length, long[] data) { + public MCABitStorageLongArray(int bits, int length, long[] data) { Validate.inclusiveBetween(1L, 32L, bits); this.size = length; this.bits = bits; diff --git a/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCAPalettedContainer.java b/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCAPalettedContainer.java index 941c37447..4af6e234e 100644 --- a/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCAPalettedContainer.java +++ b/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCAPalettedContainer.java @@ -41,7 +41,8 @@ public class MCAPalettedContainer implements MCAPaletteResize { private final T defaultValue; - protected MCABitStorage storage; + // Todo multiple storage systems cause long isnt the only one? + protected MCABitStorageLongArray storage; private MCAPalette palette; @@ -74,11 +75,11 @@ public class MCAPalettedContainer implements MCAPaletteResize { this.bits = MCAMth.ceillog2(this.registry.size()); } this.palette.idFor(this.defaultValue); - this.storage = new MCABitStorage(this.bits, 4096); + this.storage = new MCABitStorageLongArray(this.bits, 4096); } public int onResize(int var0, T var1) { - MCABitStorage var2 = this.storage; + MCABitStorageLongArray var2 = this.storage; MCAPalette var3 = this.palette; setBits(var0); for (int var4 = 0; var4 < var2.getSize(); var4++) { @@ -121,6 +122,12 @@ public class MCAPalettedContainer implements MCAPaletteResize { T var1 = this.palette.valueFor(this.storage.get(var0)); return (var1 == null) ? this.defaultValue : var1; } + /** + /** + * Reads and processes block data from encoded byte arrays. + * @param var0 BlockID Strings - List of block types identified by strings. + * @param var1 Encoded Locations - Long array containing compactly encoded block IDs, representing sequential block positions within a chunk. + */ public void read(ListTag var0, long[] var1) { int var2 = Math.max(4, MCAMth.ceillog2(var0.size())); @@ -131,18 +138,69 @@ public class MCAPalettedContainer implements MCAPaletteResize { if (this.palette == this.globalPalette) { MCAPalette var4 = new MCAHashMapPalette<>(this.registry, var2, this.dummyPaletteResize, this.reader, this.writer); var4.read(var0); - MCABitStorage var5 = new MCABitStorage(var2, 4096, var1); + MCABitStorageLongArray var5 = new MCABitStorageLongArray(var2, 4096, var1); for (int var6 = 0; var6 < 4096; var6++) this.storage.set(var6, this.globalPalette.idFor(var4.valueFor(var5.get(var6)))); } else if (var3 == this.bits) { System.arraycopy(var1, 0, this.storage.getRaw(), 0, var1.length); } else { - MCABitStorage var4 = new MCABitStorage(var3, 4096, var1); + MCABitStorageLongArray var4 = new MCABitStorageLongArray(var3, 4096, var1); for (int var5 = 0; var5 < 4096; var5++) this.storage.set(var5, var4.get(var5)); } } + /** + * Reads and processes block data from encoded byte arrays. + * @param var0 BlockID Strings - List of block types identified by strings. + * @param var1 Encoded Locations - Byte array containing compactly encoded block IDs, representing sequential block positions within a chunk. + * Currently, Minecraft doesn't use ByteArray storage. + */ + + public void read(ListTag var0, byte[] var1) { + int requiredBits = Math.max(4, MCAMth.ceillog2(var0.size())); + if (requiredBits != this.bits) { + setBits(requiredBits); + } + this.palette.read(var0); + + int bitsPerByte = 8 * var1.length / 4096; + if (this.palette == this.globalPalette) { + MCAPalette var4 = new MCAHashMapPalette<>(this.registry, requiredBits, this.dummyPaletteResize, this.reader, this.writer); + var4.read(var0); + MCABitStorageByteArray var5 = new MCABitStorageByteArray(requiredBits, 4096, var1); + for (int var6 = 0; var6 < 4096; var6++) { + this.storage.set(var6, this.globalPalette.idFor(var4.valueFor(var5.get(var6)))); + } + } else if (bitsPerByte == this.bits) { + System.arraycopy(var1, 0, this.storage.getRaw(), 0, var1.length); + } else { + MCABitStorageByteArray var4 = new MCABitStorageByteArray(bitsPerByte, 4096, var1); + for (int var5 = 0; var5 < 4096; var5++) { + this.storage.set(var5, var4.get(var5)); + } + } + } + + /** + * Reads and processes block data from encoded byte arrays. + * @param var0 BlockID Strings - List of block types identified by strings. + * This method is primarily used to read air sections. + */ + + public void read(ListTag var0) { + int requiredBits = Math.max(4, MCAMth.ceillog2(var0.size())); + if (requiredBits != this.bits) { + setBits(requiredBits); + } + this.palette.read(var0); + int defaultValue = 0; + for (int i = 0; i < 4096; i++) { + this.storage.set(i, defaultValue); + } + } + + public void write(CompoundTag var0, String var1, String var2) { MCAHashMapPalette var3 = new MCAHashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer); T var4 = this.defaultValue; @@ -160,7 +218,7 @@ public class MCAPalettedContainer implements MCAPaletteResize { var3.write(paletteList); var0.put(var1, paletteList); int var8 = Math.max(4, MCAMth.ceillog2(paletteList.size())); - MCABitStorage var9 = new MCABitStorage(var8, 4096); + MCABitStorageLongArray var9 = new MCABitStorageLongArray(var8, 4096); for (int var10 = 0; var10 < var6.length; var10++) { var9.set(var10, var6[var10]); } diff --git a/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCAWrappedPalettedContainer.java b/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCAWrappedPalettedContainer.java index 3749e74f3..06ba7c439 100644 --- a/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCAWrappedPalettedContainer.java +++ b/core/src/main/java/com/volmit/iris/util/nbt/mca/palette/MCAWrappedPalettedContainer.java @@ -18,7 +18,10 @@ package com.volmit.iris.util.nbt.mca.palette; +import com.volmit.iris.Iris; +import com.volmit.iris.util.nbt.tag.ByteArrayTag; import com.volmit.iris.util.nbt.tag.CompoundTag; +import com.volmit.iris.util.nbt.tag.LongArrayTag; import lombok.RequiredArgsConstructor; import java.util.function.Function; @@ -42,7 +45,22 @@ public class MCAWrappedPalettedContainer implements MCAPaletteAccess { } public void readFromSection(CompoundTag tag) { - //container.read(tag.getListTag("palette"), tag.getLongArrayTag("block_states").getValue()); - container.read(tag.getCompoundTag("block_states").getListTag("palette"), tag.getCompoundTag("block_states").getLongArrayTag("data").getValue()); + // container.read(tag.getCompoundTag("block_states").getListTag("palette"), tag.getCompoundTag("block_states").getLongArrayTag("data").getValue()); + CompoundTag blockStates = tag.getCompoundTag("block_states"); + if (blockStates == null) { + throw new IllegalArgumentException("block_states tag is missing"); + } + LongArrayTag longData = blockStates.getLongArrayTag("data"); + if (longData != null && longData.getValue() != null) { + container.read(tag.getCompoundTag("block_states").getListTag("palette"), tag.getCompoundTag("block_states").getLongArrayTag("data").getValue()); + } else { + ByteArrayTag byteData = blockStates.getByteArrayTag("data"); + if (byteData == null) { + container.read(tag.getCompoundTag("block_states").getListTag("palette")); + } else { + throw new IllegalArgumentException("No palette data tag found or data value is null"); + } + } } + } diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index b186c4f75..e34922e78 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -6,6 +6,8 @@ authors: [ cyberpwn, NextdoorPsycho, Vatuu ] website: volmit.com description: More than a Dimension! libraries: + - org.bytedeco:cuda-platform:12.3-8.9-1.5.10 + - org.bytedeco:javacpp:1.5.10 - net.bytebuddy:byte-buddy:1.14.14 - net.bytebuddy:byte-buddy-agent:1.12.8 - com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2