diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChaosSchemReader.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChaosSchemReader.java
new file mode 100644
index 00000000..8aab6440
--- /dev/null
+++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChaosSchemReader.java
@@ -0,0 +1,261 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.extension.platform.Capability;
+import com.sk89q.worldedit.extension.platform.Platform;
+import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
+import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.regions.CuboidRegion;
+import com.sk89q.worldedit.regions.Region;
+import com.sk89q.worldedit.world.DataFixer;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ChaosSchemReader implements ClipboardReader {
+
+ private final DataInputStream stream;
+
+ public ChaosSchemReader(DataInputStream stream) {
+ this.stream = stream;
+ }
+
+ @Override
+ public Clipboard read() throws IOException {
+ byte tag = stream.readByte();
+
+ if (tag != 0x0A) error("Invalid NBT");
+
+ String name = stream.readUTF();
+
+ if (name.isEmpty()) {
+ tag = stream.readByte();
+ if (tag != 0x0A) error("Invalid NBT");
+
+ stream.readUTF();
+
+ readSchemTag();
+
+ stream.readByte();
+ } else {
+ readSchemTag();
+ }
+ }
+
+ private int version;
+ private int dataVersion;
+ private DataFixer fixer;
+
+ private int width;
+ private int height;
+ private int length;
+
+ private int[] offset = new int[3];
+
+ private Map palette = new HashMap<>();
+ private int[] blocks;
+
+ private Map metadata;
+
+ private Clipboard constructSchematic() {
+ BlockVector3 min = BlockVector3.at(offset[0], offset[1], offset[2]);
+
+ Region region = new CuboidRegion(min);
+
+ BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
+ }
+
+ private void readSchemTag() throws IOException {
+ parseCompoundTag((type, name) -> {
+ switch (name) {
+ case "Version" -> version = stream.readInt();
+ case "DataVersion" -> {
+ dataVersion = stream.readInt();
+
+ Platform platform = WorldEdit.getInstance().getPlatformManager()
+ .queryCapability(Capability.WORLD_EDITING);
+
+ if (dataVersion < platform.getDataVersion()) {
+ this.fixer = platform.getDataFixer();
+ }
+ }
+ case "Metadata" -> metadata = (Map) readByType((byte) 0x0A);
+ case "Width" -> width = stream.readUnsignedShort();
+ case "Height" -> height = stream.readUnsignedShort();
+ case "Length" -> length = stream.readUnsignedShort();
+ case "Offset" -> offset = readIntArray();
+ case "PaletteMax" -> stream.skipNBytes(4);
+ case "Palette" -> readPalette();
+ case "BlockData" -> readBlockData();
+ case "Blocks" -> readBlockContainer();
+
+ default -> skipByType(type);
+ }
+ });
+ }
+
+ private void readBlockContainer() throws IOException {
+ parseCompoundTag((type, name) -> {
+ switch (name) {
+ case "Palette" -> readPalette();
+ case "Data" -> readBlockData();
+
+ default -> skipByType(type);
+ }
+ });
+ }
+
+ private void readPalette() throws IOException {
+ parseCompoundTag((aByte, string) -> palette.put(string, stream.readInt()));
+ }
+
+ private static final int SEGMENT_BITS = 0x7F;
+ private static final int CONTINUE_BIT = 0x80;
+
+ private void readBlockData() throws IOException {
+ byte[] data = readByteArray();
+
+ int[] blocks = new int[data.length];
+
+ int x = 0;
+ int position = 0;
+
+ for (byte current : data) {
+ blocks[x] |= (current & SEGMENT_BITS) << position;
+
+ if ((current & CONTINUE_BIT) == 0) {
+ x++;
+ position = 0;
+ } else {
+ position += 7;
+
+ if (position >= 32) throw new RuntimeException("VarInt is too big");
+ }
+ }
+
+ this.blocks = blocks;
+ }
+
+ private void parseCompoundTag(CompoundReader tag) throws IOException {
+ byte type;
+ while ((type = stream.readByte()) != 0x00) {
+ String name = stream.readUTF();
+
+ tag.read(type, name);
+ }
+ }
+
+ private int[] readIntArray() throws IOException {
+ int length = stream.readInt();
+ int[] arr = new int[length];
+
+ for (int i = 0; i < length; i++) {
+ arr[i] = stream.readInt();
+ }
+
+ return arr;
+ }
+
+ private byte[] readByteArray() throws IOException {
+ return stream.readNBytes(stream.readInt());
+ }
+
+ private void skipByType(byte type, String str) throws IOException {
+ skipByType(type);
+ }
+
+ private void skipByType(byte type) throws IOException {
+ switch (type) {
+ case 0x00 -> stream.skipNBytes(0);
+ case 0x01 -> stream.skipNBytes(1);
+ case 0x02 -> stream.skipNBytes(2);
+ case 0x03, 0x05 -> stream.skipNBytes(4);
+ case 0x04, 0x06 -> stream.skipNBytes(8);
+ case 0x07 -> stream.skipNBytes(stream.readInt());
+ case 0x08 -> stream.readUTF();
+ case 0x09 -> {
+ byte t = stream.readByte();
+ int length = stream.readInt();
+ for (int i = 0; i < length; i++) { skipByType(t); }
+ }
+ case 0x0A -> parseCompoundTag(this::skipByType);
+ case 0x0B -> stream.skipNBytes(4L * stream.readInt());
+ case 0x0C -> stream.skipNBytes(8L * stream.readInt());
+ default -> error("Invalid Type");
+ }
+ }
+
+ private Object readByType(byte type) throws IOException {
+ return switch (type) {
+ case 0x00 -> null;
+ case 0x01 -> stream.readByte();
+ case 0x02 -> stream.readShort();
+ case 0x03 -> stream.readInt();
+ case 0x04 -> stream.readLong();
+ case 0x05 -> stream.readFloat();
+ case 0x06 -> stream.readDouble();
+ case 0x07 -> stream.readNBytes(stream.readInt());
+ case 0x08 -> stream.readUTF();
+ case 0x09 -> readArray();
+ case 0x0A -> readCompound();
+ case 0x0B -> stream.skipNBytes(4L * stream.readInt());
+ case 0x0C -> stream.skipNBytes(8L * stream.readInt());
+ default -> error("Invalid Type");
+ };
+ }
+
+ private Object[] readArray() throws IOException {
+ byte t = stream.readByte();
+ int length = stream.readInt();
+ Object[] obj = new Object[length];
+ for (int i = 0; i < length; i++) {
+ obj[i] = readByType(t);
+ }
+
+ return obj;
+ }
+
+ private Map readCompound() throws IOException {
+ Map entries = new HashMap<>();
+
+ parseCompoundTag((type, name) -> entries.put(name, readByType(type)));
+
+ return entries;
+ }
+
+ private void error(String message) {
+ throw new IllegalStateException("Could not read Schem: " + message);
+ }
+
+ @Override
+ public void close() throws IOException {
+ stream.close();
+ }
+
+ private interface CompoundReader {
+ void read(byte type, String name) throws IOException;
+ }
+}