commit 6002620d4dc269b96df35bf1d92dc6c8181685a8 Author: dfsek Date: Sun Oct 17 15:38:31 2021 -0700 Initial commit diff --git a/common/addons/structure-sponge-loader/build.gradle.kts b/common/addons/structure-sponge-loader/build.gradle.kts new file mode 100644 index 000000000..e1fa2c43d --- /dev/null +++ b/common/addons/structure-sponge-loader/build.gradle.kts @@ -0,0 +1,23 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + id("com.github.johnrengelman.shadow") +} + +repositories { + maven { url = uri("https://jitpack.io/") } +} + +dependencies { + "shadedApi"("commons-io:commons-io:2.6") + "shadedApi"("com.github.Querz:NBT:6.1") +} + +tasks.named("shadowJar") { + archiveClassifier.set("") + relocate("org.apache.commons", "com.dfsek.terra.addons.sponge.lib.commons") +} + +tasks.named("build") { + finalizedBy(tasks.named("shadowJar")) +} \ No newline at end of file diff --git a/common/addons/structure-sponge-loader/src/main/java/com/dfsek/terra/addons/sponge/SpongeSchematicAddon.java b/common/addons/structure-sponge-loader/src/main/java/com/dfsek/terra/addons/sponge/SpongeSchematicAddon.java new file mode 100644 index 000000000..24d966a8f --- /dev/null +++ b/common/addons/structure-sponge-loader/src/main/java/com/dfsek/terra/addons/sponge/SpongeSchematicAddon.java @@ -0,0 +1,101 @@ +package com.dfsek.terra.addons.sponge; + +import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.addon.TerraAddon; +import com.dfsek.terra.api.addon.annotations.Addon; +import com.dfsek.terra.api.addon.annotations.Author; +import com.dfsek.terra.api.addon.annotations.Version; +import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; +import com.dfsek.terra.api.event.functional.FunctionalEventHandler; +import com.dfsek.terra.api.inject.annotations.Inject; +import com.dfsek.terra.api.registry.CheckedRegistry; +import com.dfsek.terra.api.structure.Structure; + +import com.dfsek.terra.api.util.StringUtil; + +import net.querz.nbt.io.NBTDeserializer; +import net.querz.nbt.tag.ByteArrayTag; +import net.querz.nbt.tag.CompoundTag; +import net.querz.nbt.tag.IntTag; +import net.querz.nbt.tag.Tag; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.GZIPInputStream; + +@Addon("structure-sponge-loader") +@Author("Terra") +@Version("1.0.0") +public class SpongeSchematicAddon extends TerraAddon { + @Inject + private Platform platform; + + + @Override + public void initialize() { + platform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigPackPreLoadEvent.class) + .then(event -> { + CheckedRegistry structureRegistry = event.getPack().getOrCreateRegistry(Structure.class); + event.getPack().getLoader().open("", ".schem").thenEntries(entries -> { + for(Map.Entry entry : entries) { + String id = StringUtil.fileName(entry.getKey()); + structureRegistry.register(id, convert(entry.getValue(), id)); + } + }).close(); + }) + .failThrough(); + } + + + public SpongeStructure convert(InputStream in, String id) { + try { + CompoundTag baseTag = (CompoundTag) new NBTDeserializer(false).fromStream(detectDecompression(in)).getTag(); + int wid = baseTag.getShort("Width"); + int len = baseTag.getShort("Length"); + int hei = baseTag.getShort("Height"); + + ByteArrayTag blocks = baseTag.getByteArrayTag("BlockData"); + + CompoundTag palette = (CompoundTag) baseTag.get("Palette"); + Map data = new HashMap<>(); + + for(Map.Entry> entry : palette.entrySet()) { + data.put(((IntTag) entry.getValue()).asInt(), entry.getKey()); + } + + BlockState[][][] states = new BlockState[wid][len][hei]; + + byte[] arr = blocks.getValue(); + for(int x = 0; x < wid; x++) { + for(int z = 0; z < len; z++) { + for(int y = 0; y < hei; y++) { + String block = data.get((int) arr[x + z * wid + y * wid * len]); + if(block.startsWith("minecraft:structure_void")) continue; + states[x][z][y] = platform.getWorldHandle().createBlockData(block); + } + } + } + + return new SpongeStructure(states, platform, id); + } catch(IOException e) { + throw new IllegalArgumentException("Failed to parse Sponge schematic: ", e); + } + } + + private static InputStream detectDecompression(InputStream is) throws IOException { + PushbackInputStream pbis = new PushbackInputStream(is, 2); + int signature = (pbis.read() & 0xFF) + (pbis.read() << 8); + pbis.unread(signature >> 8); + pbis.unread(signature & 0xFF); + if(signature == GZIPInputStream.GZIP_MAGIC) { + return new GZIPInputStream(pbis); + } + return pbis; + } +} diff --git a/common/addons/structure-sponge-loader/src/main/java/com/dfsek/terra/addons/sponge/SpongeStructure.java b/common/addons/structure-sponge-loader/src/main/java/com/dfsek/terra/addons/sponge/SpongeStructure.java new file mode 100644 index 000000000..a427e4359 --- /dev/null +++ b/common/addons/structure-sponge-loader/src/main/java/com/dfsek/terra/addons/sponge/SpongeStructure.java @@ -0,0 +1,97 @@ +package com.dfsek.terra.addons.sponge; + +import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.structure.Structure; +import com.dfsek.terra.api.structure.buffer.Buffer; +import com.dfsek.terra.api.structure.buffer.items.BufferedBlock; +import com.dfsek.terra.api.structure.rotation.Rotation; +import com.dfsek.terra.api.util.RotationUtil; +import com.dfsek.terra.api.util.vector.Vector2; +import com.dfsek.terra.api.util.vector.Vector3; +import com.dfsek.terra.api.world.Chunk; +import com.dfsek.terra.api.world.World; + +import net.jafama.FastMath; + +import java.util.Random; + + +public class SpongeStructure implements Structure { + + private final BlockState[][][] blocks; + private final Platform platform; + + private final String id; + + public SpongeStructure(BlockState[][][] blocks, Platform platform, String id) { + this.blocks = blocks; + this.platform = platform; + this.id = id; + } + + @Override + public boolean generate(Vector3 location, World world, Chunk chunk, Random random, Rotation rotation) { + int bX = location.getBlockX(); + int bY = location.getBlockY(); + int bZ = location.getBlockZ(); + for(int x = 0; x < blocks.length; x++) { + for(int z = 0; z < blocks[x].length; z++) { + Vector2 r = RotationUtil.rotateVector(new Vector2(x, z), rotation); + int rX = r.getBlockX(); + int rZ = r.getBlockZ(); + if(FastMath.floorDiv(bX+rX, 16) != chunk.getX() || FastMath.floorDiv(bZ+rZ, 16) != chunk.getZ()) { + continue; + } + for(int y = 0; y < blocks[z].length; y++) { + BlockState state = blocks[x][z][y]; + if(state == null) continue; + world.setBlockData(bX+rX, bY+y, bZ+rZ, state); + } + } + } + return true; + } + + @Override + public boolean generate(Buffer buffer, World world, Random random, Rotation rotation, int recursions) { + for(int x = 0; x < blocks.length; x++) { + for(int z = 0; z < blocks[x].length; z++) { + Vector2 r = RotationUtil.rotateVector(new Vector2(x, z), rotation); + int rX = r.getBlockX(); + int rZ = r.getBlockZ(); + for(int y = 0; y < blocks[z].length; y++) { + BlockState state = blocks[x][z][y]; + if(state == null) continue; + buffer.addItem(new BufferedBlock(state, true, platform, false), new Vector3(rX, y, rZ)); + } + } + } + return true; + } + + @Override + public boolean generate(Vector3 location, World world, Random random, Rotation rotation) { + int bX = location.getBlockX(); + int bY = location.getBlockY(); + int bZ = location.getBlockZ(); + for(int x = 0; x < blocks.length; x++) { + for(int z = 0; z < blocks[x].length; z++) { + Vector2 r = RotationUtil.rotateVector(new Vector2(x, z), rotation); + int rX = r.getBlockX(); + int rZ = r.getBlockZ(); + for(int y = 0; y < blocks[z].length; y++) { + BlockState state = blocks[x][z][y]; + if(state == null) continue; + world.setBlockData(bX+rX, bY+y, bZ+rZ, state); + } + } + } + return true; + } + + @Override + public String getID() { + return id; + } +}