diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/BitStorage.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/BitStorage.java
new file mode 100644
index 000000000..e509b87cc
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/BitStorage.java
@@ -0,0 +1,145 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import org.apache.commons.lang3.Validate;
+
+import java.util.function.IntConsumer;
+
+public class BitStorage {
+ 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,
+ 0, Integer.MIN_VALUE, 0, 2, 477218588, 477218588, 0, 429496729, 429496729, 0,
+ 390451572, 390451572, 0, 357913941, 357913941, 0, 330382099, 330382099, 0, 306783378,
+ 306783378, 0, 286331153, 286331153, 0, Integer.MIN_VALUE, 0, 3, 252645135, 252645135,
+ 0, 238609294, 238609294, 0, 226050910, 226050910, 0, 214748364, 214748364, 0,
+ 204522252, 204522252, 0, 195225786, 195225786, 0, 186737708, 186737708, 0, 178956970,
+ 178956970, 0, 171798691, 171798691, 0, 165191049, 165191049, 0, 159072862, 159072862,
+ 0, 153391689, 153391689, 0, 148102320, 148102320, 0, 143165576, 143165576, 0,
+ 138547332, 138547332, 0, Integer.MIN_VALUE, 0, 4, 130150524, 130150524, 0, 126322567,
+ 126322567, 0, 122713351, 122713351, 0, 119304647, 119304647, 0, 116080197, 116080197,
+ 0, 113025455, 113025455, 0, 110127366, 110127366, 0, 107374182, 107374182, 0,
+ 104755299, 104755299, 0, 102261126, 102261126, 0, 99882960, 99882960, 0, 97612893,
+ 97612893, 0, 95443717, 95443717, 0, 93368854, 93368854, 0, 91382282, 91382282,
+ 0, 89478485, 89478485, 0, 87652393, 87652393, 0, 85899345, 85899345, 0,
+ 84215045, 84215045, 0, 82595524, 82595524, 0, 81037118, 81037118, 0, 79536431,
+ 79536431, 0, 78090314, 78090314, 0, 76695844, 76695844, 0, 75350303, 75350303,
+ 0, 74051160, 74051160, 0, 72796055, 72796055, 0, 71582788, 71582788, 0,
+ 70409299, 70409299, 0, 69273666, 69273666, 0, 68174084, 68174084, 0, Integer.MIN_VALUE,
+ 0, 5 };
+
+ private final long[] data;
+
+ private final int bits;
+
+ private final long mask;
+
+ private final int size;
+
+ private final int valuesPerLong;
+
+ private final int divideMul;
+
+ private final int divideAdd;
+
+ private final int divideShift;
+
+ public BitStorage(int var0, int var1) {
+ this(var0, var1, null);
+ }
+
+ public BitStorage(int var0, int var1, long[] var2) {
+ Validate.inclusiveBetween(1L, 32L, var0);
+ this.size = var1;
+ this.bits = var0;
+ this.mask = (1L << var0) - 1L;
+ this.valuesPerLong = (char)(64 / var0);
+ int var3 = 3 * (this.valuesPerLong - 1);
+ this.divideMul = MAGIC[var3 + 0];
+ this.divideAdd = MAGIC[var3 + 1];
+ this.divideShift = MAGIC[var3 + 2];
+ int var4 = (var1 + this.valuesPerLong - 1) / this.valuesPerLong;
+ if (var2 != null) {
+ if (var2.length != var4)
+ throw new RuntimeException("NO!");
+ this.data = var2;
+ } else {
+ this.data = new long[var4];
+ }
+ }
+
+ private int cellIndex(int var0) {
+ long var1 = Integer.toUnsignedLong(this.divideMul);
+ long var3 = Integer.toUnsignedLong(this.divideAdd);
+ return (int)(var0 * var1 + var3 >> 32L >> this.divideShift);
+ }
+
+ public int getAndSet(int var0, int var1) {
+ Validate.inclusiveBetween(0L, (this.size - 1), var0);
+ Validate.inclusiveBetween(0L, this.mask, var1);
+ int var2 = cellIndex(var0);
+ long var3 = this.data[var2];
+ int var5 = (var0 - var2 * this.valuesPerLong) * this.bits;
+ int var6 = (int)(var3 >> var5 & this.mask);
+ this.data[var2] = var3 & (this.mask << var5 ^ 0xFFFFFFFFFFFFFFFFL) | (var1 & this.mask) << var5;
+ return var6;
+ }
+
+ public void set(int var0, int var1) {
+ Validate.inclusiveBetween(0L, (this.size - 1), var0);
+ Validate.inclusiveBetween(0L, this.mask, var1);
+ int var2 = cellIndex(var0);
+ long var3 = this.data[var2];
+ int var5 = (var0 - var2 * this.valuesPerLong) * this.bits;
+ this.data[var2] = var3 & (this.mask << var5 ^ 0xFFFFFFFFFFFFFFFFL) | (var1 & this.mask) << var5;
+ }
+
+ public int get(int var0) {
+ Validate.inclusiveBetween(0L, (this.size - 1), var0);
+ int var1 = cellIndex(var0);
+ long var2 = this.data[var1];
+ int var4 = (var0 - var1 * this.valuesPerLong) * this.bits;
+ return (int)(var2 >> var4 & this.mask);
+ }
+
+ public long[] getRaw() {
+ return this.data;
+ }
+
+ public int getSize() {
+ return this.size;
+ }
+
+ public int getBits() {
+ return this.bits;
+ }
+
+ public void getAll(IntConsumer var0) {
+ int var1 = 0;
+ for (long var5 : this.data) {
+ for (int var7 = 0; var7 < this.valuesPerLong; var7++) {
+ var0.accept((int)(var5 & this.mask));
+ var5 >>= this.bits;
+ if (++var1 >= this.size)
+ return;
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/CountConsumer.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/CountConsumer.java
new file mode 100644
index 000000000..ede8a5404
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/CountConsumer.java
@@ -0,0 +1,24 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+@FunctionalInterface
+public interface CountConsumer {
+ void accept(T paramT, int paramInt);
+}
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/CrudeIncrementalIntIdentityHashBiMap.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/CrudeIncrementalIntIdentityHashBiMap.java
new file mode 100644
index 000000000..5c40c7aa5
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/CrudeIncrementalIntIdentityHashBiMap.java
@@ -0,0 +1,167 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterators;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+public class CrudeIncrementalIntIdentityHashBiMap implements IdMap {
+ public static final int NOT_FOUND = -1;
+
+ private static final Object EMPTY_SLOT = null;
+
+ private static final float LOADFACTOR = 0.8F;
+
+ private K[] keys;
+
+ private int[] values;
+
+ private K[] byId;
+
+ private int nextId;
+
+ private int size;
+
+ public CrudeIncrementalIntIdentityHashBiMap(int var0) {
+ var0 = (int)(var0 / 0.8F);
+ this.keys = (K[])new Object[var0];
+ this.values = new int[var0];
+ this.byId = (K[])new Object[var0];
+ }
+
+ public int getId(K var0) {
+ return getValue(indexOf(var0, hash(var0)));
+ }
+
+
+ public K byId(int var0) {
+ if (var0 < 0 || var0 >= this.byId.length)
+ return null;
+ return this.byId[var0];
+ }
+
+ private int getValue(int var0) {
+ if (var0 == -1)
+ return -1;
+ return this.values[var0];
+ }
+
+ public boolean contains(K var0) {
+ return (getId(var0) != -1);
+ }
+
+ public boolean contains(int var0) {
+ return (byId(var0) != null);
+ }
+
+ public int add(K var0) {
+ int var1 = nextId();
+ addMapping(var0, var1);
+ return var1;
+ }
+
+ private int nextId() {
+ while (this.nextId < this.byId.length && this.byId[this.nextId] != null)
+ this.nextId++;
+ return this.nextId;
+ }
+
+ private void grow(int var0) {
+ K[] var1 = this.keys;
+ int[] var2 = this.values;
+ this.keys = (K[])new Object[var0];
+ this.values = new int[var0];
+ this.byId = (K[])new Object[var0];
+ this.nextId = 0;
+ this.size = 0;
+ for (int var3 = 0; var3 < var1.length; var3++) {
+ if (var1[var3] != null)
+ addMapping(var1[var3], var2[var3]);
+ }
+ }
+
+ public void addMapping(K var0, int var1) {
+ int var2 = Math.max(var1, this.size + 1);
+ if (var2 >= this.keys.length * 0.8F) {
+ int i = this.keys.length << 1;
+ while (i < var1)
+ i <<= 1;
+ grow(i);
+ }
+ int var3 = findEmpty(hash(var0));
+ this.keys[var3] = var0;
+ this.values[var3] = var1;
+ this.byId[var1] = var0;
+ this.size++;
+ if (var1 == this.nextId)
+ this.nextId++;
+ }
+
+ private int hash( K var0) {
+ return (Mth.murmurHash3Mixer(System.identityHashCode(var0)) & Integer.MAX_VALUE) % this.keys.length;
+ }
+
+ private int indexOf( K var0, int var1) {
+ int var2;
+ for (var2 = var1; var2 < this.keys.length; var2++) {
+ if (this.keys[var2] == var0)
+ return var2;
+ if (this.keys[var2] == EMPTY_SLOT)
+ return -1;
+ }
+ for (var2 = 0; var2 < var1; var2++) {
+ if (this.keys[var2] == var0)
+ return var2;
+ if (this.keys[var2] == EMPTY_SLOT)
+ return -1;
+ }
+ return -1;
+ }
+
+ private int findEmpty(int var0) {
+ int var1;
+ for (var1 = var0; var1 < this.keys.length; var1++) {
+ if (this.keys[var1] == EMPTY_SLOT)
+ return var1;
+ }
+ for (var1 = 0; var1 < var0; var1++) {
+ if (this.keys[var1] == EMPTY_SLOT)
+ return var1;
+ }
+ throw new RuntimeException("Overflowed :(");
+ }
+
+ public Iterator iterator() {
+ return (Iterator) Iterators.filter((Iterator)Iterators.forArray((Object[])this.byId), Predicates.notNull());
+ }
+
+ public void clear() {
+ Arrays.fill((Object[])this.keys, (Object)null);
+ Arrays.fill((Object[])this.byId, (Object)null);
+ this.nextId = 0;
+ this.size = 0;
+ }
+
+ public int size() {
+ return this.size;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/GlobalPalette.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/GlobalPalette.java
new file mode 100644
index 000000000..82d59dad0
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/GlobalPalette.java
@@ -0,0 +1,54 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import com.volmit.iris.util.nbt.tag.ListTag;
+
+import java.util.function.Predicate;
+
+public class GlobalPalette implements Palette {
+ private final IdMapper registry;
+
+ private final T defaultValue;
+
+ public GlobalPalette(IdMapper var0, T var1) {
+ this.registry = var0;
+ this.defaultValue = var1;
+ }
+
+ public int idFor(T var0) {
+ int var1 = this.registry.getId(var0);
+ return (var1 == -1) ? 0 : var1;
+ }
+
+ public boolean maybeHas(Predicate var0) {
+ return true;
+ }
+
+ public T valueFor(int var0) {
+ T var1 = (T)this.registry.byId(var0);
+ return (var1 == null) ? this.defaultValue : var1;
+ }
+
+ public int getSize() {
+ return this.registry.size();
+ }
+
+ public void read(ListTag var0) {}
+}
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/HashMapPalette.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/HashMapPalette.java
new file mode 100644
index 000000000..09b77f912
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/HashMapPalette.java
@@ -0,0 +1,85 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import com.volmit.iris.util.nbt.tag.CompoundTag;
+import com.volmit.iris.util.nbt.tag.ListTag;
+
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+public class HashMapPalette implements Palette {
+ private final IdMapper registry;
+
+ private final CrudeIncrementalIntIdentityHashBiMap values;
+
+ private final PaletteResize resizeHandler;
+
+ private final Function reader;
+
+ private final Function writer;
+
+ private final int bits;
+
+ public HashMapPalette(IdMapper var0, int var1, PaletteResize var2, Function var3, Function var4) {
+ this.registry = var0;
+ this.bits = var1;
+ this.resizeHandler = var2;
+ this.reader = var3;
+ this.writer = var4;
+ this.values = new CrudeIncrementalIntIdentityHashBiMap(1 << var1);
+ }
+
+ public int idFor(T var0) {
+ int var1 = this.values.getId(var0);
+ if (var1 == -1) {
+ var1 = this.values.add(var0);
+ if (var1 >= 1 << this.bits)
+ var1 = this.resizeHandler.onResize(this.bits + 1, var0);
+ }
+ return var1;
+ }
+
+ public boolean maybeHas(Predicate var0) {
+ for (int var1 = 0; var1 < getSize(); var1++) {
+ if (var0.test((T)this.values.byId(var1)))
+ return true;
+ }
+ return false;
+ }
+
+ public T valueFor(int var0) {
+ return (T)this.values.byId(var0);
+ }
+
+ public int getSize() {
+ return this.values.size();
+ }
+
+ public void read(ListTag var0) {
+ this.values.clear();
+ for (int var1 = 0; var1 < var0.size(); var1++)
+ this.values.add(this.reader.apply((CompoundTag) var0.get(var1)));
+ }
+
+ public void write(ListTag var0) {
+ for (int var1 = 0; var1 < getSize(); var1++)
+ var0.add(this.writer.apply((T)this.values.byId(var1)));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/IdMap.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/IdMap.java
new file mode 100644
index 000000000..d3d63ea54
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/IdMap.java
@@ -0,0 +1,25 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+public interface IdMap extends Iterable {
+ int getId(T paramT);
+
+ T byId(int paramInt);
+}
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/IdMapper.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/IdMapper.java
new file mode 100644
index 000000000..469e1c3c6
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/IdMapper.java
@@ -0,0 +1,88 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+
+public class IdMapper implements IdMap {
+ public static final int DEFAULT = -1;
+
+ private int nextId;
+
+ private final IdentityHashMap tToId;
+
+ private final List idToT;
+
+ public IdMapper(IdentityHashMap tToId, List idToT, int nextId) {
+ this.tToId = tToId;
+ this.idToT = idToT;
+ this.nextId = nextId;
+ }
+
+ public IdMapper() {
+ this(512);
+ }
+
+ public IdMapper(int var0) {
+ this.idToT = Lists.newArrayListWithExpectedSize(var0);
+ this.tToId = new IdentityHashMap<>(var0);
+ }
+
+ public void addMapping(T var0, int var1) {
+ this.tToId.put(var0, Integer.valueOf(var1));
+ while (this.idToT.size() <= var1)
+ this.idToT.add(null);
+ this.idToT.set(var1, var0);
+ if (this.nextId <= var1)
+ this.nextId = var1 + 1;
+ }
+
+ public void add(T var0) {
+ addMapping(var0, this.nextId);
+ }
+
+ public int getId(T var0) {
+ Integer var1 = this.tToId.get(var0);
+ return (var1 == null) ? -1 : var1.intValue();
+ }
+
+ public final T byId(int var0) {
+ if (var0 >= 0 && var0 < this.idToT.size())
+ return this.idToT.get(var0);
+ return null;
+ }
+
+ public Iterator iterator() {
+ return (Iterator) Iterators.filter(this.idToT.iterator(), Predicates.notNull());
+ }
+
+ public boolean contains(int var0) {
+ return (byId(var0) != null);
+ }
+
+ public int size() {
+ return this.tToId.size();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/LinearPalette.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/LinearPalette.java
new file mode 100644
index 000000000..b7ba0e48b
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/LinearPalette.java
@@ -0,0 +1,86 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import com.volmit.iris.util.nbt.tag.CompoundTag;
+import com.volmit.iris.util.nbt.tag.ListTag;
+
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+public class LinearPalette implements Palette {
+ private final IdMapper registry;
+
+ private final T[] values;
+
+ private final PaletteResize resizeHandler;
+
+ private final Function reader;
+
+ private final int bits;
+
+ private int size;
+
+ public LinearPalette(IdMapper var0, int var1, PaletteResize var2, Function var3) {
+ this.registry = var0;
+ this.values = (T[])new Object[1 << var1];
+ this.bits = var1;
+ this.resizeHandler = var2;
+ this.reader = var3;
+ }
+
+ public int idFor(T var0) {
+ int var1;
+ for (var1 = 0; var1 < this.size; var1++) {
+ if (this.values[var1] == var0)
+ return var1;
+ }
+ var1 = this.size;
+ if (var1 < this.values.length) {
+ this.values[var1] = var0;
+ this.size++;
+ return var1;
+ }
+ return this.resizeHandler.onResize(this.bits + 1, var0);
+ }
+
+ public boolean maybeHas(Predicate var0) {
+ for (int var1 = 0; var1 < this.size; var1++) {
+ if (var0.test(this.values[var1]))
+ return true;
+ }
+ return false;
+ }
+
+ public T valueFor(int var0) {
+ if (var0 >= 0 && var0 < this.size)
+ return this.values[var0];
+ return null;
+ }
+
+ public int getSize() {
+ return this.size;
+ }
+
+ public void read(ListTag var0) {
+ for (int var1 = 0; var1 < var0.size(); var1++)
+ this.values[var1] = this.reader.apply((CompoundTag) var0.get(var1));
+ this.size = var0.size();
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/Mth.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/Mth.java
new file mode 100644
index 000000000..1c40f8f0b
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/Mth.java
@@ -0,0 +1,733 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import java.util.Random;
+import java.util.UUID;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class Mth {
+ private static final int BIG_ENOUGH_INT = 1024;
+
+ private static final float BIG_ENOUGH_FLOAT = 1024.0F;
+
+ private static final long UUID_VERSION = 61440L;
+
+ private static final long UUID_VERSION_TYPE_4 = 16384L;
+
+ private static final long UUID_VARIANT = -4611686018427387904L;
+
+ private static final long UUID_VARIANT_2 = -9223372036854775808L;
+
+ public static final float PI = 3.1415927F;
+
+ public static final float HALF_PI = 1.5707964F;
+
+ public static final float TWO_PI = 6.2831855F;
+
+ public static final float DEG_TO_RAD = 0.017453292F;
+
+ public static final float RAD_TO_DEG = 57.295776F;
+
+ public static final float EPSILON = 1.0E-5F;
+
+ public static final float SQRT_OF_TWO = sqrt(2.0F);
+
+ private static final float SIN_SCALE = 10430.378F;
+
+ private static final float[] SIN;
+
+ static {
+ SIN = (float[])make(new float[65536], var0 -> {
+ for (int var1 = 0; var1 < var0.length; var1++)
+ var0[var1] = (float)Math.sin(var1 * Math.PI * 2.0D / 65536.0D);
+ });
+ }
+
+ public static T make(Supplier var0) {
+ return var0.get();
+ }
+
+ public static T make(T var0, Consumer var1) {
+ var1.accept(var0);
+ return var0;
+ }
+
+ private static final Random RANDOM = new Random();
+
+ public static float sin(float var0) {
+ return SIN[(int)(var0 * 10430.378F) & 0xFFFF];
+ }
+
+ public static float cos(float var0) {
+ return SIN[(int)(var0 * 10430.378F + 16384.0F) & 0xFFFF];
+ }
+
+ public static float sqrt(float var0) {
+ return (float)Math.sqrt(var0);
+ }
+
+ public static int floor(float var0) {
+ int var1 = (int)var0;
+ return (var0 < var1) ? (var1 - 1) : var1;
+ }
+
+ public static int fastFloor(double var0) {
+ return (int)(var0 + 1024.0D) - 1024;
+ }
+
+ public static int floor(double var0) {
+ int var2 = (int)var0;
+ return (var0 < var2) ? (var2 - 1) : var2;
+ }
+
+ public static long lfloor(double var0) {
+ long var2 = (long)var0;
+ return (var0 < var2) ? (var2 - 1L) : var2;
+ }
+
+ public static int absFloor(double var0) {
+ return (int)((var0 >= 0.0D) ? var0 : (-var0 + 1.0D));
+ }
+
+ public static float abs(float var0) {
+ return Math.abs(var0);
+ }
+
+ public static int abs(int var0) {
+ return Math.abs(var0);
+ }
+
+ public static int ceil(float var0) {
+ int var1 = (int)var0;
+ return (var0 > var1) ? (var1 + 1) : var1;
+ }
+
+ public static int ceil(double var0) {
+ int var2 = (int)var0;
+ return (var0 > var2) ? (var2 + 1) : var2;
+ }
+
+ public static byte clamp(byte var0, byte var1, byte var2) {
+ if (var0 < var1)
+ return var1;
+ if (var0 > var2)
+ return var2;
+ return var0;
+ }
+
+ public static int clamp(int var0, int var1, int var2) {
+ if (var0 < var1)
+ return var1;
+ if (var0 > var2)
+ return var2;
+ return var0;
+ }
+
+ public static long clamp(long var0, long var2, long var4) {
+ if (var0 < var2)
+ return var2;
+ if (var0 > var4)
+ return var4;
+ return var0;
+ }
+
+ public static float clamp(float var0, float var1, float var2) {
+ if (var0 < var1)
+ return var1;
+ if (var0 > var2)
+ return var2;
+ return var0;
+ }
+
+ public static double clamp(double var0, double var2, double var4) {
+ if (var0 < var2)
+ return var2;
+ if (var0 > var4)
+ return var4;
+ return var0;
+ }
+
+ public static double clampedLerp(double var0, double var2, double var4) {
+ if (var4 < 0.0D)
+ return var0;
+ if (var4 > 1.0D)
+ return var2;
+ return lerp(var4, var0, var2);
+ }
+
+ public static float clampedLerp(float var0, float var1, float var2) {
+ if (var2 < 0.0F)
+ return var0;
+ if (var2 > 1.0F)
+ return var1;
+ return lerp(var2, var0, var1);
+ }
+
+ public static double absMax(double var0, double var2) {
+ if (var0 < 0.0D)
+ var0 = -var0;
+ if (var2 < 0.0D)
+ var2 = -var2;
+ return (var0 > var2) ? var0 : var2;
+ }
+
+ public static int intFloorDiv(int var0, int var1) {
+ return Math.floorDiv(var0, var1);
+ }
+
+ public static int nextInt(Random var0, int var1, int var2) {
+ if (var1 >= var2)
+ return var1;
+ return var0.nextInt(var2 - var1 + 1) + var1;
+ }
+
+ public static float nextFloat(Random var0, float var1, float var2) {
+ if (var1 >= var2)
+ return var1;
+ return var0.nextFloat() * (var2 - var1) + var1;
+ }
+
+ public static double nextDouble(Random var0, double var1, double var3) {
+ if (var1 >= var3)
+ return var1;
+ return var0.nextDouble() * (var3 - var1) + var1;
+ }
+
+ public static double average(long[] var0) {
+ long var1 = 0L;
+ for (long var6 : var0)
+ var1 += var6;
+ return var1 / var0.length;
+ }
+
+ public static boolean equal(float var0, float var1) {
+ return (Math.abs(var1 - var0) < 1.0E-5F);
+ }
+
+ public static boolean equal(double var0, double var2) {
+ return (Math.abs(var2 - var0) < 9.999999747378752E-6D);
+ }
+
+ public static int positiveModulo(int var0, int var1) {
+ return Math.floorMod(var0, var1);
+ }
+
+ public static float positiveModulo(float var0, float var1) {
+ return (var0 % var1 + var1) % var1;
+ }
+
+ public static double positiveModulo(double var0, double var2) {
+ return (var0 % var2 + var2) % var2;
+ }
+
+ public static int wrapDegrees(int var0) {
+ int var1 = var0 % 360;
+ if (var1 >= 180)
+ var1 -= 360;
+ if (var1 < -180)
+ var1 += 360;
+ return var1;
+ }
+
+ public static float wrapDegrees(float var0) {
+ float var1 = var0 % 360.0F;
+ if (var1 >= 180.0F)
+ var1 -= 360.0F;
+ if (var1 < -180.0F)
+ var1 += 360.0F;
+ return var1;
+ }
+
+ public static double wrapDegrees(double var0) {
+ double var2 = var0 % 360.0D;
+ if (var2 >= 180.0D)
+ var2 -= 360.0D;
+ if (var2 < -180.0D)
+ var2 += 360.0D;
+ return var2;
+ }
+
+ public static float degreesDifference(float var0, float var1) {
+ return wrapDegrees(var1 - var0);
+ }
+
+ public static float degreesDifferenceAbs(float var0, float var1) {
+ return abs(degreesDifference(var0, var1));
+ }
+
+ public static float rotateIfNecessary(float var0, float var1, float var2) {
+ float var3 = degreesDifference(var0, var1);
+ float var4 = clamp(var3, -var2, var2);
+ return var1 - var4;
+ }
+
+ public static float approach(float var0, float var1, float var2) {
+ var2 = abs(var2);
+ if (var0 < var1)
+ return clamp(var0 + var2, var0, var1);
+ return clamp(var0 - var2, var1, var0);
+ }
+
+ public static float approachDegrees(float var0, float var1, float var2) {
+ float var3 = degreesDifference(var0, var1);
+ return approach(var0, var0 + var3, var2);
+ }
+
+ public static int getInt(String var0, int var1) {
+ return Integer.valueOf(var0, var1);
+ }
+
+ public static int getInt(String var0, int var1, int var2) {
+ return Math.max(var2, getInt(var0, var1));
+ }
+
+ public static double getDouble(String var0, double var1) {
+ try {
+ return Double.parseDouble(var0);
+ } catch (Throwable var3) {
+ return var1;
+ }
+ }
+
+ public static double getDouble(String var0, double var1, double var3) {
+ return Math.max(var3, getDouble(var0, var1));
+ }
+
+ public static int smallestEncompassingPowerOfTwo(int var0) {
+ int var1 = var0 - 1;
+ var1 |= var1 >> 1;
+ var1 |= var1 >> 2;
+ var1 |= var1 >> 4;
+ var1 |= var1 >> 8;
+ var1 |= var1 >> 16;
+ return var1 + 1;
+ }
+
+ public static boolean isPowerOfTwo(int var0) {
+ return (var0 != 0 && (var0 & var0 - 1) == 0);
+ }
+
+ private static final int[] MULTIPLY_DE_BRUIJN_BIT_POSITION = new int[] {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22,
+ 20, 15, 25, 17, 4, 8, 31, 27, 13, 23,
+ 21, 19, 16, 7, 26, 12, 18, 6, 11, 5,
+ 10, 9 };
+
+ private static final double ONE_SIXTH = 0.16666666666666666D;
+
+ private static final int FRAC_EXP = 8;
+
+ private static final int LUT_SIZE = 257;
+
+ public static int ceillog2(int var0) {
+ var0 = isPowerOfTwo(var0) ? var0 : smallestEncompassingPowerOfTwo(var0);
+ return MULTIPLY_DE_BRUIJN_BIT_POSITION[(int)(var0 * 125613361L >> 27L) & 0x1F];
+ }
+
+ public static int log2(int var0) {
+ return ceillog2(var0) - (isPowerOfTwo(var0) ? 0 : 1);
+ }
+
+ public static int color(float var0, float var1, float var2) {
+ return color(floor(var0 * 255.0F), floor(var1 * 255.0F), floor(var2 * 255.0F));
+ }
+
+ public static int color(int var0, int var1, int var2) {
+ int var3 = var0;
+ var3 = (var3 << 8) + var1;
+ var3 = (var3 << 8) + var2;
+ return var3;
+ }
+
+ public static int colorMultiply(int var0, int var1) {
+ int var2 = (var0 & 0xFF0000) >> 16;
+ int var3 = (var1 & 0xFF0000) >> 16;
+ int var4 = (var0 & 0xFF00) >> 8;
+ int var5 = (var1 & 0xFF00) >> 8;
+ int var6 = (var0 & 0xFF) >> 0;
+ int var7 = (var1 & 0xFF) >> 0;
+ int var8 = (int)(var2 * var3 / 255.0F);
+ int var9 = (int)(var4 * var5 / 255.0F);
+ int var10 = (int)(var6 * var7 / 255.0F);
+ return var0 & 0xFF000000 | var8 << 16 | var9 << 8 | var10;
+ }
+
+ public static int colorMultiply(int var0, float var1, float var2, float var3) {
+ int var4 = (var0 & 0xFF0000) >> 16;
+ int var5 = (var0 & 0xFF00) >> 8;
+ int var6 = (var0 & 0xFF) >> 0;
+ int var7 = (int)(var4 * var1);
+ int var8 = (int)(var5 * var2);
+ int var9 = (int)(var6 * var3);
+ return var0 & 0xFF000000 | var7 << 16 | var8 << 8 | var9;
+ }
+
+ public static float frac(float var0) {
+ return var0 - floor(var0);
+ }
+
+ public static double frac(double var0) {
+ return var0 - lfloor(var0);
+ }
+
+ public static long getSeed(int var0, int var1, int var2) {
+ long var3 = (var0 * 3129871) ^ var2 * 116129781L ^ var1;
+ var3 = var3 * var3 * 42317861L + var3 * 11L;
+ return var3 >> 16L;
+ }
+
+ public static UUID createInsecureUUID(Random var0) {
+ long var1 = var0.nextLong() & 0xFFFFFFFFFFFF0FFFL | 0x4000L;
+ long var3 = var0.nextLong() & 0x3FFFFFFFFFFFFFFFL | Long.MIN_VALUE;
+ return new UUID(var1, var3);
+ }
+
+ public static UUID createInsecureUUID() {
+ return createInsecureUUID(RANDOM);
+ }
+
+ public static double inverseLerp(double var0, double var2, double var4) {
+ return (var0 - var2) / (var4 - var2);
+ }
+
+ public static double atan2(double var0, double var2) {
+ double var4 = var2 * var2 + var0 * var0;
+ if (Double.isNaN(var4))
+ return Double.NaN;
+ boolean var6 = (var0 < 0.0D);
+ if (var6)
+ var0 = -var0;
+ boolean var7 = (var2 < 0.0D);
+ if (var7)
+ var2 = -var2;
+ boolean var8 = (var0 > var2);
+ if (var8) {
+ double d = var2;
+ var2 = var0;
+ var0 = d;
+ }
+ double var9 = fastInvSqrt(var4);
+ var2 *= var9;
+ var0 *= var9;
+ double var11 = FRAC_BIAS + var0;
+ int var13 = (int)Double.doubleToRawLongBits(var11);
+ double var14 = ASIN_TAB[var13];
+ double var16 = COS_TAB[var13];
+ double var18 = var11 - FRAC_BIAS;
+ double var20 = var0 * var16 - var2 * var18;
+ double var22 = (6.0D + var20 * var20) * var20 * 0.16666666666666666D;
+ double var24 = var14 + var22;
+ if (var8)
+ var24 = 1.5707963267948966D - var24;
+ if (var7)
+ var24 = Math.PI - var24;
+ if (var6)
+ var24 = -var24;
+ return var24;
+ }
+
+ public static float fastInvSqrt(float var0) {
+ float var1 = 0.5F * var0;
+ int var2 = Float.floatToIntBits(var0);
+ var2 = 1597463007 - (var2 >> 1);
+ var0 = Float.intBitsToFloat(var2);
+ var0 *= 1.5F - var1 * var0 * var0;
+ return var0;
+ }
+
+ public static double fastInvSqrt(double var0) {
+ double var2 = 0.5D * var0;
+ long var4 = Double.doubleToRawLongBits(var0);
+ var4 = 6910469410427058090L - (var4 >> 1L);
+ var0 = Double.longBitsToDouble(var4);
+ var0 *= 1.5D - var2 * var0 * var0;
+ return var0;
+ }
+
+ public static float fastInvCubeRoot(float var0) {
+ int var1 = Float.floatToIntBits(var0);
+ var1 = 1419967116 - var1 / 3;
+ float var2 = Float.intBitsToFloat(var1);
+ var2 = 0.6666667F * var2 + 1.0F / 3.0F * var2 * var2 * var0;
+ var2 = 0.6666667F * var2 + 1.0F / 3.0F * var2 * var2 * var0;
+ return var2;
+ }
+
+ private static final double FRAC_BIAS = Double.longBitsToDouble(4805340802404319232L);
+
+ private static final double[] ASIN_TAB = new double[257];
+
+ private static final double[] COS_TAB = new double[257];
+
+ static {
+ for (int var0 = 0; var0 < 257; var0++) {
+ double var1 = var0 / 256.0D;
+ double var3 = Math.asin(var1);
+ COS_TAB[var0] = Math.cos(var3);
+ ASIN_TAB[var0] = var3;
+ }
+ }
+
+ public static int hsvToRgb(float var0, float var1, float var2) {
+ float var8, var9, var10;
+ int var11, var12, var13, var3 = (int)(var0 * 6.0F) % 6;
+ float var4 = var0 * 6.0F - var3;
+ float var5 = var2 * (1.0F - var1);
+ float var6 = var2 * (1.0F - var4 * var1);
+ float var7 = var2 * (1.0F - (1.0F - var4) * var1);
+ switch (var3) {
+ case 0:
+ var8 = var2;
+ var9 = var7;
+ var10 = var5;
+ var11 = clamp((int)(var8 * 255.0F), 0, 255);
+ var12 = clamp((int)(var9 * 255.0F), 0, 255);
+ var13 = clamp((int)(var10 * 255.0F), 0, 255);
+ return var11 << 16 | var12 << 8 | var13;
+ case 1:
+ var8 = var6;
+ var9 = var2;
+ var10 = var5;
+ var11 = clamp((int)(var8 * 255.0F), 0, 255);
+ var12 = clamp((int)(var9 * 255.0F), 0, 255);
+ var13 = clamp((int)(var10 * 255.0F), 0, 255);
+ return var11 << 16 | var12 << 8 | var13;
+ case 2:
+ var8 = var5;
+ var9 = var2;
+ var10 = var7;
+ var11 = clamp((int)(var8 * 255.0F), 0, 255);
+ var12 = clamp((int)(var9 * 255.0F), 0, 255);
+ var13 = clamp((int)(var10 * 255.0F), 0, 255);
+ return var11 << 16 | var12 << 8 | var13;
+ case 3:
+ var8 = var5;
+ var9 = var6;
+ var10 = var2;
+ var11 = clamp((int)(var8 * 255.0F), 0, 255);
+ var12 = clamp((int)(var9 * 255.0F), 0, 255);
+ var13 = clamp((int)(var10 * 255.0F), 0, 255);
+ return var11 << 16 | var12 << 8 | var13;
+ case 4:
+ var8 = var7;
+ var9 = var5;
+ var10 = var2;
+ var11 = clamp((int)(var8 * 255.0F), 0, 255);
+ var12 = clamp((int)(var9 * 255.0F), 0, 255);
+ var13 = clamp((int)(var10 * 255.0F), 0, 255);
+ return var11 << 16 | var12 << 8 | var13;
+ case 5:
+ var8 = var2;
+ var9 = var5;
+ var10 = var6;
+ var11 = clamp((int)(var8 * 255.0F), 0, 255);
+ var12 = clamp((int)(var9 * 255.0F), 0, 255);
+ var13 = clamp((int)(var10 * 255.0F), 0, 255);
+ return var11 << 16 | var12 << 8 | var13;
+ }
+ throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + var0 + ", " + var1 + ", " + var2);
+ }
+
+ public static int murmurHash3Mixer(int var0) {
+ var0 ^= var0 >>> 16;
+ var0 *= -2048144789;
+ var0 ^= var0 >>> 13;
+ var0 *= -1028477387;
+ var0 ^= var0 >>> 16;
+ return var0;
+ }
+
+ public static long murmurHash3Mixer(long var0) {
+ var0 ^= var0 >>> 33L;
+ var0 *= -49064778989728563L;
+ var0 ^= var0 >>> 33L;
+ var0 *= -4265267296055464877L;
+ var0 ^= var0 >>> 33L;
+ return var0;
+ }
+
+ public static double[] cumulativeSum(double... var0) {
+ float var1 = 0.0F;
+ for (double var5 : var0)
+ var1 = (float)(var1 + var5);
+ int var2;
+ for (var2 = 0; var2 < var0.length; var2++)
+ var0[var2] = var0[var2] / var1;
+ for (var2 = 0; var2 < var0.length; var2++)
+ var0[var2] = ((var2 == 0) ? 0.0D : var0[var2 - 1]) + var0[var2];
+ return var0;
+ }
+
+ public static int getRandomForDistributionIntegral(Random var0, double[] var1) {
+ double var2 = var0.nextDouble();
+ for (int var4 = 0; var4 < var1.length; var4++) {
+ if (var2 < var1[var4])
+ return var4;
+ }
+ return var1.length;
+ }
+
+ public static double[] binNormalDistribution(double var0, double var2, double var4, int var6, int var7) {
+ double[] var8 = new double[var7 - var6 + 1];
+ int var9 = 0;
+ for (int var10 = var6; var10 <= var7; var10++) {
+ var8[var9] = Math.max(0.0D, var0 *
+
+ StrictMath.exp(-(var10 - var4) * (var10 - var4) / 2.0D * var2 * var2));
+ var9++;
+ }
+ return var8;
+ }
+
+ public static double[] binBiModalNormalDistribution(double var0, double var2, double var4, double var6, double var8, double var10, int var12, int var13) {
+ double[] var14 = new double[var13 - var12 + 1];
+ int var15 = 0;
+ for (int var16 = var12; var16 <= var13; var16++) {
+ var14[var15] = Math.max(0.0D, var0 *
+
+ StrictMath.exp(-(var16 - var4) * (var16 - var4) / 2.0D * var2 * var2) + var6 *
+ StrictMath.exp(-(var16 - var10) * (var16 - var10) / 2.0D * var8 * var8));
+ var15++;
+ }
+ return var14;
+ }
+
+ public static double[] binLogDistribution(double var0, double var2, int var4, int var5) {
+ double[] var6 = new double[var5 - var4 + 1];
+ int var7 = 0;
+ for (int var8 = var4; var8 <= var5; var8++) {
+ var6[var7] = Math.max(var0 * StrictMath.log(var8) + var2, 0.0D);
+ var7++;
+ }
+ return var6;
+ }
+
+ public static float lerp(float var0, float var1, float var2) {
+ return var1 + var0 * (var2 - var1);
+ }
+
+ public static double lerp(double var0, double var2, double var4) {
+ return var2 + var0 * (var4 - var2);
+ }
+
+ public static double lerp2(double var0, double var2, double var4, double var6, double var8, double var10) {
+ return lerp(var2,
+
+ lerp(var0, var4, var6),
+ lerp(var0, var8, var10));
+ }
+
+ public static double lerp3(double var0, double var2, double var4, double var6, double var8, double var10, double var12, double var14, double var16, double var18, double var20) {
+ return lerp(var4,
+
+ lerp2(var0, var2, var6, var8, var10, var12),
+ lerp2(var0, var2, var14, var16, var18, var20));
+ }
+
+ public static double smoothstep(double var0) {
+ return var0 * var0 * var0 * (var0 * (var0 * 6.0D - 15.0D) + 10.0D);
+ }
+
+ public static double smoothstepDerivative(double var0) {
+ return 30.0D * var0 * var0 * (var0 - 1.0D) * (var0 - 1.0D);
+ }
+
+ public static int sign(double var0) {
+ if (var0 == 0.0D)
+ return 0;
+ return (var0 > 0.0D) ? 1 : -1;
+ }
+
+ public static float rotLerp(float var0, float var1, float var2) {
+ return var1 + var0 * wrapDegrees(var2 - var1);
+ }
+
+ public static float diffuseLight(float var0, float var1, float var2) {
+ return Math.min(var0 * var0 * 0.6F + var1 * var1 * (3.0F + var1) / 4.0F + var2 * var2 * 0.8F, 1.0F);
+ }
+
+ @Deprecated
+ public static float rotlerp(float var0, float var1, float var2) {
+ float var3 = var1 - var0;
+ while (var3 < -180.0F)
+ var3 += 360.0F;
+ while (var3 >= 180.0F)
+ var3 -= 360.0F;
+ return var0 + var2 * var3;
+ }
+
+ @Deprecated
+ public static float rotWrap(double var0) {
+ while (var0 >= 180.0D)
+ var0 -= 360.0D;
+ while (var0 < -180.0D)
+ var0 += 360.0D;
+ return (float)var0;
+ }
+
+ public static float triangleWave(float var0, float var1) {
+ return (Math.abs(var0 % var1 - var1 * 0.5F) - var1 * 0.25F) / var1 * 0.25F;
+ }
+
+ public static float square(float var0) {
+ return var0 * var0;
+ }
+
+ public static double square(double var0) {
+ return var0 * var0;
+ }
+
+ public static int square(int var0) {
+ return var0 * var0;
+ }
+
+ public static double clampedMap(double var0, double var2, double var4, double var6, double var8) {
+ return clampedLerp(var6, var8, inverseLerp(var0, var2, var4));
+ }
+
+ public static double map(double var0, double var2, double var4, double var6, double var8) {
+ return lerp(inverseLerp(var0, var2, var4), var6, var8);
+ }
+
+ public static double wobble(double var0) {
+ return var0 + (2.0D * (new Random(floor(var0 * 3000.0D))).nextDouble() - 1.0D) * 1.0E-7D / 2.0D;
+ }
+
+ public static int roundToward(int var0, int var1) {
+ return (var0 + var1 - 1) / var1 * var1;
+ }
+
+ public static int randomBetweenInclusive(Random var0, int var1, int var2) {
+ return var0.nextInt(var2 - var1 + 1) + var1;
+ }
+
+ public static float randomBetween(Random var0, float var1, float var2) {
+ return var0.nextFloat() * (var2 - var1) + var1;
+ }
+
+ public static float normal(Random var0, float var1, float var2) {
+ return var1 + (float)var0.nextGaussian() * var2;
+ }
+
+ public static double length(int var0, double var1, int var3) {
+ return Math.sqrt((var0 * var0) + var1 * var1 + (var3 * var3));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/Palette.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/Palette.java
new file mode 100644
index 000000000..886dbf861
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/Palette.java
@@ -0,0 +1,35 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import com.volmit.iris.util.nbt.tag.ListTag;
+
+import java.util.function.Predicate;
+
+public interface Palette {
+ int idFor(T paramT);
+
+ boolean maybeHas(Predicate paramPredicate);
+
+ T valueFor(int paramInt);
+
+ int getSize();
+
+ void read(ListTag paramListTag);
+}
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/PaletteAccess.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/PaletteAccess.java
new file mode 100644
index 000000000..cdf5ae3a6
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/PaletteAccess.java
@@ -0,0 +1,33 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import com.volmit.iris.util.nbt.mca.NBTWorld;
+import com.volmit.iris.util.nbt.tag.CompoundTag;
+import org.bukkit.block.data.BlockData;
+
+public interface PaletteAccess {
+ public void setBlock(int x, int y, int z, CompoundTag data);
+
+ public CompoundTag getBlock(int x, int y, int z);
+
+ public void writeToSection(CompoundTag tag);
+
+ public void readFromSection(CompoundTag tag);
+}
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/PaletteResize.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/PaletteResize.java
new file mode 100644
index 000000000..dc5fe8d71
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/PaletteResize.java
@@ -0,0 +1,23 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+interface PaletteResize {
+ int onResize(int paramInt, T paramT);
+}
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/PalettedContainer.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/PalettedContainer.java
new file mode 100644
index 000000000..7039c5975
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/PalettedContainer.java
@@ -0,0 +1,187 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import com.volmit.iris.util.nbt.tag.CompoundTag;
+import com.volmit.iris.util.nbt.tag.ListTag;
+import it.unimi.dsi.fastutil.Pair;
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+import net.minecraft.util.DebugBuffer;
+import net.minecraft.util.ThreadingDetector;
+
+import java.util.concurrent.Semaphore;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+public class PalettedContainer implements PaletteResize {
+ private static final int SIZE = 4096;
+
+ public static final int GLOBAL_PALETTE_BITS = 9;
+
+ public static final int MIN_PALETTE_SIZE = 4;
+
+ private final Palette globalPalette;
+
+ private final PaletteResize dummyPaletteResize = (var0, var1) -> 0;
+
+ private final IdMapper registry;
+
+ private final Function reader;
+
+ private final Function writer;
+
+ private final T defaultValue;
+
+ protected BitStorage storage;
+
+ private Palette palette;
+
+ private int bits;
+
+ public PalettedContainer(Palette var0, IdMapper var1, Function var2, Function var3, T var4) {
+ this.globalPalette = var0;
+ this.registry = var1;
+ this.reader = var2;
+ this.writer = var3;
+ this.defaultValue = var4;
+ setBits(4);
+ }
+
+ private static int getIndex(int var0, int var1, int var2) {
+ return var1 << 8 | var2 << 4 | var0;
+ }
+
+ private void setBits(int var0) {
+ if (var0 == this.bits)
+ return;
+ this.bits = var0;
+ if (this.bits <= 4) {
+ this.bits = 4;
+ this.palette = new LinearPalette<>(this.registry, this.bits, this, this.reader);
+ } else if (this.bits < 9) {
+ this.palette = new HashMapPalette<>(this.registry, this.bits, this, this.reader, this.writer);
+ } else {
+ this.palette = this.globalPalette;
+ this.bits = Mth.ceillog2(this.registry.size());
+ }
+ this.palette.idFor(this.defaultValue);
+ this.storage = new BitStorage(this.bits, 4096);
+ }
+
+ public int onResize(int var0, T var1) {
+ BitStorage var2 = this.storage;
+ Palette var3 = this.palette;
+ setBits(var0);
+ for (int var4 = 0; var4 < var2.getSize(); var4++) {
+ T var5 = var3.valueFor(var2.get(var4));
+ if (var5 != null)
+ set(var4, var5);
+ }
+ return this.palette.idFor(var1);
+ }
+
+ public T getAndSet(int var0, int var1, int var2, T var3) {
+ return getAndSet(getIndex(var0, var1, var2), var3);
+ }
+
+ public T getAndSetUnchecked(int var0, int var1, int var2, T var3) {
+ return getAndSet(getIndex(var0, var1, var2), var3);
+ }
+
+ private T getAndSet(int var0, T var1) {
+ int var2 = this.palette.idFor(var1);
+ int var3 = this.storage.getAndSet(var0, var2);
+ T var4 = this.palette.valueFor(var3);
+ return (var4 == null) ? this.defaultValue : var4;
+ }
+
+ public void set(int var0, int var1, int var2, T var3) {
+ set(getIndex(var0, var1, var2), var3);
+ }
+
+ private void set(int var0, T var1) {
+ int var2 = this.palette.idFor(var1);
+ this.storage.set(var0, var2);
+ }
+
+ public T get(int var0, int var1, int var2) {
+ return get(getIndex(var0, var1, var2));
+ }
+
+ protected T get(int var0) {
+ T var1 = this.palette.valueFor(this.storage.get(var0));
+ return (var1 == null) ? this.defaultValue : var1;
+ }
+
+ public void read(ListTag var0, long[] var1) {
+ int var2 = Math.max(4, Mth.ceillog2(var0.size()));
+ if (var2 != this.bits)
+ setBits(var2);
+ this.palette.read(var0);
+ int var3 = var1.length * 64 / 4096;
+ if (this.palette == this.globalPalette) {
+ Palette var4 = new HashMapPalette<>(this.registry, var2, this.dummyPaletteResize, this.reader, this.writer);
+ var4.read(var0);
+ BitStorage var5 = new BitStorage(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 {
+ BitStorage var4 = new BitStorage(var3, 4096, var1);
+ for (int var5 = 0; var5 < 4096; var5++)
+ this.storage.set(var5, var4.get(var5));
+ }
+ }
+
+ public void write(CompoundTag var0, String var1, String var2) {
+ HashMapPalette var3 = new HashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer);
+ T var4 = this.defaultValue;
+ int var5 = var3.idFor(this.defaultValue);
+ int[] var6 = new int[4096];
+ for (int i = 0; i < 4096; i++) {
+ T t = get(i);
+ if (t != var4) {
+ var4 = t;
+ var5 = var3.idFor(t);
+ }
+ var6[i] = var5;
+ }
+ ListTag paletteList = (ListTag) ListTag.createUnchecked(CompoundTag.class);
+ var3.write(paletteList);
+ var0.put(var1, paletteList);
+ int var8 = Math.max(4, Mth.ceillog2(paletteList.size()));
+ BitStorage var9 = new BitStorage(var8, 4096);
+ for (int var10 = 0; var10 < var6.length; var10++)
+ {
+ var9.set(var10, var6[var10]);
+ }
+ var0.putLongArray(var2, var9.getRaw());
+ }
+
+ public boolean maybeHas(Predicate var0) {
+ return this.palette.maybeHas(var0);
+ }
+
+ public void count(CountConsumer var0) {
+ Int2IntOpenHashMap int2IntOpenHashMap = new Int2IntOpenHashMap();
+ this.storage.getAll(var1 -> int2IntOpenHashMap.put(var1, int2IntOpenHashMap.get(var1) + 1));
+ int2IntOpenHashMap.int2IntEntrySet().forEach(var1 -> var0.accept(this.palette.valueFor(var1.getIntKey()), var1.getIntValue()));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/WrappedPalettedContainer.java b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/WrappedPalettedContainer.java
new file mode 100644
index 000000000..db6dfc651
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/nbt/mca/nmspalettes/WrappedPalettedContainer.java
@@ -0,0 +1,54 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 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
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.nbt.mca.nmspalettes;
+
+import com.volmit.iris.util.nbt.mca.MCAUtil;
+import com.volmit.iris.util.nbt.mca.NBTWorld;
+import com.volmit.iris.util.nbt.tag.CompoundTag;
+import lombok.RequiredArgsConstructor;
+import org.bukkit.block.data.BlockData;
+
+import java.util.function.Function;
+
+@RequiredArgsConstructor
+public class WrappedPalettedContainer implements PaletteAccess {
+ private final PalettedContainer container;
+ private final Function reader;
+ private final Function writer;
+
+ public void setBlock(int x, int y, int z, CompoundTag data)
+ {
+ container.set(x,y,z,writer.apply(data));
+ }
+
+ public CompoundTag getBlock(int x, int y, int z)
+ {
+ return reader.apply(container.get(x,y,z));
+ }
+
+ public void writeToSection(CompoundTag tag)
+ {
+ container.write(tag, "Palette", "BlockStates");
+ }
+
+ public void readFromSection(CompoundTag tag)
+ {
+ container.read(tag.getListTag("Palette"), tag.getLongArrayTag("BlockStates").getValue());
+ }
+}