1311 lines
45 KiB
Diff
1311 lines
45 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Simon Gardling <titaniumtown@gmail.com>
|
|
Date: Tue, 11 Jan 2022 18:07:35 -0500
|
|
Subject: [PATCH] hydrogen
|
|
|
|
Original code by CaffeineMC, licensed under GNU Lesser General Public License v3.0
|
|
You can find the original code on https://github.com/CaffeineMC/hydrogen-fabric (Yarn mappings)
|
|
This code specifically was taken from MeeniMc's PR implementing 1.18.x support here: https://github.com/CaffeineMC/hydrogen-fabric/pull/60
|
|
|
|
diff --git a/src/main/java/com/google/common/collect/HydrogenEntrySet.java b/src/main/java/com/google/common/collect/HydrogenEntrySet.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..290ace0b7c8c6836fa61babf53aca5f2ae0959c1
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/google/common/collect/HydrogenEntrySet.java
|
|
@@ -0,0 +1,36 @@
|
|
+package com.google.common.collect;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+class HydrogenEntrySet<K, V> extends ImmutableSet<Map.Entry<K, V>> {
|
|
+ private final K[] key;
|
|
+ private final V[] value;
|
|
+
|
|
+ private final int size;
|
|
+
|
|
+ HydrogenEntrySet(K[] key, V[] value, int size) {
|
|
+ this.key = key;
|
|
+ this.value = value;
|
|
+ this.size = size;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public UnmodifiableIterator<Map.Entry<K, V>> iterator() {
|
|
+ return new HydrogenEntrySetIterator<>(this.key, this.value, this.size);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(Object object) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ boolean isPartialView() {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return this.size;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/google/common/collect/HydrogenEntrySetIterator.java b/src/main/java/com/google/common/collect/HydrogenEntrySetIterator.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..4346ae9da9fe01f89ed77dba37236d068e720aea
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/google/common/collect/HydrogenEntrySetIterator.java
|
|
@@ -0,0 +1,41 @@
|
|
+package com.google.common.collect;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+class HydrogenEntrySetIterator<K, V> extends UnmodifiableIterator<Map.Entry<K, V>> {
|
|
+ private final K[] key;
|
|
+ private final V[] value;
|
|
+
|
|
+ private int remaining;
|
|
+ private int idx;
|
|
+
|
|
+ public HydrogenEntrySetIterator(K[] key, V[] value, int remaining) {
|
|
+ this.remaining = remaining;
|
|
+ this.key = key;
|
|
+ this.value = value;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return this.remaining > 0;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Map.Entry<K, V> next() {
|
|
+ this.skipEmpty();
|
|
+
|
|
+ Map.Entry<K, V> entry = new HydrogenImmutableMapEntry<>(this.key[this.idx],
|
|
+ this.value[this.idx]);
|
|
+
|
|
+ this.remaining--;
|
|
+ this.idx++;
|
|
+
|
|
+ return entry;
|
|
+ }
|
|
+
|
|
+ private void skipEmpty() {
|
|
+ while (this.key[this.idx] == null) {
|
|
+ this.idx++;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/google/common/collect/HydrogenImmutableMapEntry.java b/src/main/java/com/google/common/collect/HydrogenImmutableMapEntry.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..c74ce1d2f8dfc6e50d2ffba462193093c7633c6c
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/google/common/collect/HydrogenImmutableMapEntry.java
|
|
@@ -0,0 +1,28 @@
|
|
+package com.google.common.collect;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+public class HydrogenImmutableMapEntry<K, V> implements Map.Entry<K, V> {
|
|
+ private final K key;
|
|
+ private final V value;
|
|
+
|
|
+ public HydrogenImmutableMapEntry(K key, V value) {
|
|
+ this.key = key;
|
|
+ this.value = value;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public K getKey() {
|
|
+ return this.key;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V getValue() {
|
|
+ return this.value;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V setValue(V value) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/google/common/collect/HydrogenImmutableReferenceHashMap.java b/src/main/java/com/google/common/collect/HydrogenImmutableReferenceHashMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..7772a4218fbc76a3f055881aa5301624b6961fe6
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/google/common/collect/HydrogenImmutableReferenceHashMap.java
|
|
@@ -0,0 +1,134 @@
|
|
+package com.google.common.collect;
|
|
+
|
|
+import it.unimi.dsi.fastutil.Hash;
|
|
+import it.unimi.dsi.fastutil.HashCommon;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+import static it.unimi.dsi.fastutil.HashCommon.arraySize;
|
|
+
|
|
+@SuppressWarnings("unused")
|
|
+public class HydrogenImmutableReferenceHashMap<K, V> extends ImmutableMap<K, V> {
|
|
+ protected transient K[] key;
|
|
+ protected transient V[] value;
|
|
+ protected transient int mask;
|
|
+ protected transient int size;
|
|
+
|
|
+ public HydrogenImmutableReferenceHashMap() {
|
|
+
|
|
+ }
|
|
+
|
|
+ public HydrogenImmutableReferenceHashMap(Map<K, V> map) {
|
|
+ this(map.size(), Hash.DEFAULT_LOAD_FACTOR);
|
|
+
|
|
+ for (Map.Entry<K, V> entry : map.entrySet()) {
|
|
+ this.putInternal(entry.getKey(), entry.getValue());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ private HydrogenImmutableReferenceHashMap(final int size, final float loadFactor) {
|
|
+ if (loadFactor <= 0 || loadFactor > 1) {
|
|
+ throw new IllegalArgumentException("Load factor must be greater than 0 and smaller than or equal to 1");
|
|
+ }
|
|
+
|
|
+ if (size < 0) {
|
|
+ throw new IllegalArgumentException("The expected number of elements must be nonnegative");
|
|
+ }
|
|
+
|
|
+ int n = arraySize(size, loadFactor);
|
|
+
|
|
+ this.key = (K[]) new Object[n];
|
|
+ this.value = (V[]) new Object[n];
|
|
+ this.mask = n - 1;
|
|
+ this.size = size;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return this.size;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V get(final Object k) {
|
|
+ int pos = HashCommon.mix(System.identityHashCode(k)) & this.mask;
|
|
+ K curr = this.key[pos];
|
|
+
|
|
+ // The starting point.
|
|
+ if (curr == null) {
|
|
+ return null;
|
|
+ } else if (k == curr) {
|
|
+ return this.value[pos];
|
|
+ }
|
|
+
|
|
+ // There's always an unused entry.
|
|
+ while (true) {
|
|
+ pos = pos + 1 & this.mask;
|
|
+ curr = this.key[pos];
|
|
+
|
|
+ if (curr == null) {
|
|
+ return null;
|
|
+ } else if (k == curr) {
|
|
+ return this.value[pos];
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void putInternal(final K k, final V v) {
|
|
+ final int pos = this.find(k);
|
|
+
|
|
+ if (pos < 0) {
|
|
+ int n = -pos - 1;
|
|
+
|
|
+ this.key[n] = k;
|
|
+ this.value[n] = v;
|
|
+ } else {
|
|
+ this.value[pos] = v;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private int find(final K k) {
|
|
+ int pos = HashCommon.mix(System.identityHashCode(k)) & this.mask;
|
|
+ K curr = this.key[pos];
|
|
+
|
|
+ // The starting point.
|
|
+ if (curr == null) {
|
|
+ return -(pos + 1);
|
|
+ } else if (k == curr) {
|
|
+ return pos;
|
|
+ }
|
|
+
|
|
+ // There's always an unused entry.
|
|
+ while (true) {
|
|
+ pos = pos + 1 & this.mask;
|
|
+ curr = this.key[pos];
|
|
+
|
|
+ if (curr == null) {
|
|
+ return -(pos + 1);
|
|
+ } else if (k == curr) {
|
|
+ return pos;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ ImmutableSet<Entry<K, V>> createEntrySet() {
|
|
+ return new HydrogenEntrySet<>(this.key, this.value, this.size);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ ImmutableSet<K> createKeySet() {
|
|
+ return new ImmutableMapKeySet<>(this);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ ImmutableCollection<V> createValues() {
|
|
+ return new ImmutableMapValues<>(this);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ boolean isPartialView() {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/cache/StatePropertyTableCache.java b/src/main/java/me/jellysquid/mods/hydrogen/common/cache/StatePropertyTableCache.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..68c69bd90f5ecf3b72d631faac21f89b88fe37cb
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/cache/StatePropertyTableCache.java
|
|
@@ -0,0 +1,38 @@
|
|
+package me.jellysquid.mods.hydrogen.common.cache;
|
|
+
|
|
+import me.jellysquid.mods.hydrogen.common.collections.FastImmutableTableCache;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.level.block.state.properties.Property;
|
|
+import net.minecraft.world.level.material.Fluid;
|
|
+import net.minecraft.world.level.material.FluidState;
|
|
+
|
|
+/**
|
|
+ * Many of the column and row key arrays in block state tables will be duplicated, leading to an unnecessary waste of
|
|
+ * memory. Since we have very limited options for trying to construct more optimized table types without throwing
|
|
+ * maintainability or mod compatibility out the window, this class acts as a dirty way to find and de-duplicate arrays
|
|
+ * after we construct our table types.
|
|
+ *
|
|
+ * While this global cache does not provide the ability to remove or clear entries from it, the reality is that it
|
|
+ * shouldn't matter because block state tables are only initialized once and remain loaded for the entire lifetime of
|
|
+ * the game. Even in the event of classloader pre-boot shenanigans, we still shouldn't leak memory as our cache will be
|
|
+ * dropped along with the rest of the loaded classes when the class loader is reaped.
|
|
+ */
|
|
+public class StatePropertyTableCache {
|
|
+ public static final FastImmutableTableCache<Property<?>, Comparable<?>, BlockState> BLOCK_STATE_TABLE =
|
|
+ new FastImmutableTableCache<>();
|
|
+
|
|
+ public static final FastImmutableTableCache<Property<?>, Comparable<?>, FluidState> FLUID_STATE_TABLE =
|
|
+ new FastImmutableTableCache<>();
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ public static <S, O> FastImmutableTableCache<Property<?>, Comparable<?>, S> getTableCache(O owner) {
|
|
+ if (owner instanceof Block) {
|
|
+ return (FastImmutableTableCache<Property<?>, Comparable<?>, S>) BLOCK_STATE_TABLE;
|
|
+ } else if (owner instanceof Fluid) {
|
|
+ return (FastImmutableTableCache<Property<?>, Comparable<?>, S>) FLUID_STATE_TABLE;
|
|
+ } else {
|
|
+ throw new IllegalArgumentException("");
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/collections/CollectionHelper.java b/src/main/java/me/jellysquid/mods/hydrogen/common/collections/CollectionHelper.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..1f4dd657d1cb7c7dcf4bf4b9e213548adb1bae33
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/collections/CollectionHelper.java
|
|
@@ -0,0 +1,16 @@
|
|
+package me.jellysquid.mods.hydrogen.common.collections;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.stream.Collector;
|
|
+import java.util.stream.Collectors;
|
|
+
|
|
+public class CollectionHelper {
|
|
+ public static <T> List<T> fixed(List<T> src) {
|
|
+ return new FixedArrayList<>(src);
|
|
+ }
|
|
+
|
|
+ public static <T> Collector<T, ?, List<T>> toSizedList(int size) {
|
|
+ return Collectors.toCollection(() -> new ArrayList<>(size));
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FastImmutableTable.java b/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FastImmutableTable.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..f87f4d1452dc65dc621493d6dcfaa678bf46069e
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FastImmutableTable.java
|
|
@@ -0,0 +1,227 @@
|
|
+package me.jellysquid.mods.hydrogen.common.collections;
|
|
+
|
|
+import com.google.common.collect.Table;
|
|
+import it.unimi.dsi.fastutil.Hash;
|
|
+import it.unimi.dsi.fastutil.HashCommon;
|
|
+import org.apache.commons.lang3.ArrayUtils;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
+
|
|
+import static it.unimi.dsi.fastutil.HashCommon.arraySize;
|
|
+
|
|
+public class FastImmutableTable<R, C, V> implements Table<R, C, V> {
|
|
+ private R[] rowKeys;
|
|
+ private int[] rowIndices;
|
|
+ private final int rowMask;
|
|
+ private final int rowCount;
|
|
+
|
|
+ private C[] colKeys;
|
|
+ private int[] colIndices;
|
|
+ private final int colMask;
|
|
+ private final int colCount;
|
|
+
|
|
+ private V[] values;
|
|
+ private final int size;
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ public FastImmutableTable(Table<R, C, V> table, FastImmutableTableCache<R, C, V> cache) {
|
|
+ if (cache == null) {
|
|
+ throw new IllegalArgumentException("Cache must not be null");
|
|
+ }
|
|
+
|
|
+ float loadFactor = Hash.DEFAULT_LOAD_FACTOR;
|
|
+
|
|
+ Set<R> rowKeySet = table.rowKeySet();
|
|
+ Set<C> colKeySet = table.columnKeySet();
|
|
+
|
|
+ this.rowCount = rowKeySet.size();
|
|
+ this.colCount = colKeySet.size();
|
|
+
|
|
+ int rowN = arraySize(this.rowCount, loadFactor);
|
|
+ int colN = arraySize(this.colCount, loadFactor);
|
|
+
|
|
+ this.rowMask = rowN - 1;
|
|
+ this.rowKeys = (R[]) new Object[rowN];
|
|
+ this.rowIndices = new int[rowN];
|
|
+
|
|
+ this.colMask = colN - 1;
|
|
+ this.colKeys = (C[]) new Object[colN];
|
|
+ this.colIndices = new int[colN];
|
|
+
|
|
+ this.createIndex(this.colKeys, this.colIndices, this.colMask, colKeySet);
|
|
+ this.createIndex(this.rowKeys, this.rowIndices, this.rowMask, rowKeySet);
|
|
+
|
|
+ this.values = (V[]) new Object[this.rowCount * this.colCount];
|
|
+
|
|
+ for (Cell<R, C, V> cell : table.cellSet()) {
|
|
+ int colIdx = this.getIndex(this.colKeys, this.colIndices, this.colMask, cell.getColumnKey());
|
|
+ int rowIdx = this.getIndex(this.rowKeys, this.rowIndices, this.rowMask, cell.getRowKey());
|
|
+
|
|
+ if (colIdx < 0 || rowIdx < 0) {
|
|
+ throw new IllegalStateException("Missing index for " + cell);
|
|
+ }
|
|
+
|
|
+ this.values[this.colCount * rowIdx + colIdx] = cell.getValue();
|
|
+ }
|
|
+
|
|
+ this.size = table.size();
|
|
+
|
|
+ this.rowKeys = cache.dedupRows(this.rowKeys);
|
|
+ this.rowIndices = cache.dedupIndices(this.rowIndices);
|
|
+
|
|
+ this.colIndices = cache.dedupIndices(this.colIndices);
|
|
+ this.colKeys = cache.dedupColumns(this.colKeys);
|
|
+
|
|
+ this.values = cache.dedupValues(this.values);
|
|
+ }
|
|
+
|
|
+ private <T> void createIndex(T[] keys, int[] indices, int mask, Collection<T> iterable) {
|
|
+ int index = 0;
|
|
+
|
|
+ for (T obj : iterable) {
|
|
+ int i = this.find(keys, mask, obj);
|
|
+
|
|
+ if (i < 0) {
|
|
+ int pos = -i - 1;
|
|
+
|
|
+ keys[pos] = obj;
|
|
+ indices[pos] = index++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private <T> int getIndex(T[] keys, int[] indices, int mask, T key) {
|
|
+ int pos = this.find(keys, mask, key);
|
|
+
|
|
+ if (pos < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return indices[pos];
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(Object rowKey, Object columnKey) {
|
|
+ return this.get(rowKey, columnKey) != null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsRow(Object rowKey) {
|
|
+ return this.find(this.rowKeys, this.rowMask, rowKey) >= 0;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsColumn(Object columnKey) {
|
|
+ return this.find(this.colKeys, this.colMask, columnKey) >= 0;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsValue(Object value) {
|
|
+ return ArrayUtils.contains(this.values, value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V get(Object rowKey, Object columnKey) {
|
|
+ final int row = this.getIndex(this.rowKeys, this.rowIndices, this.rowMask, rowKey);
|
|
+ final int col = this.getIndex(this.colKeys, this.colIndices, this.colMask, columnKey);
|
|
+
|
|
+ if (row < 0 || col < 0) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ return this.values[this.colCount * row + col];
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return this.size() == 0;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return this.size;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V put(R rowKey, C columnKey, V val) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ private <T> int find(T[] key, int mask, T value) {
|
|
+ T curr;
|
|
+ int pos;
|
|
+ // The starting point.
|
|
+ if ((curr = key[pos = HashCommon.mix(value.hashCode()) & mask]) == null) {
|
|
+ return -(pos + 1);
|
|
+ }
|
|
+ if (value.equals(curr)) {
|
|
+ return pos;
|
|
+ }
|
|
+ // There's always an unused entry.
|
|
+ while (true) {
|
|
+ if ((curr = key[pos = pos + 1 & mask]) == null) {
|
|
+ return -(pos + 1);
|
|
+ }
|
|
+ if (value.equals(curr)) {
|
|
+ return pos;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V remove(Object rowKey, Object columnKey) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Map<C, V> row(R rowKey) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Map<R, V> column(C columnKey) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Set<Cell<R, C, V>> cellSet() {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Set<R> rowKeySet() {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Set<C> columnKeySet() {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Collection<V> values() {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Map<R, Map<C, V>> rowMap() {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Map<C, Map<R, V>> columnMap() {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FastImmutableTableCache.java b/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FastImmutableTableCache.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..8fd17d2738be1cacedf56bb5c22ead9e473a9b99
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FastImmutableTableCache.java
|
|
@@ -0,0 +1,44 @@
|
|
+package me.jellysquid.mods.hydrogen.common.collections;
|
|
+
|
|
+import it.unimi.dsi.fastutil.Hash;
|
|
+import it.unimi.dsi.fastutil.ints.IntArrays;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectArrays;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
|
+
|
|
+/**
|
|
+ * @param <R> The type used by the
|
|
+ * @param <C>
|
|
+ * @param <V>
|
|
+ */
|
|
+public class FastImmutableTableCache<R, C, V> {
|
|
+ private final ObjectOpenCustomHashSet<R[]> rows;
|
|
+ private final ObjectOpenCustomHashSet<C[]> columns;
|
|
+ private final ObjectOpenCustomHashSet<V[]> values;
|
|
+
|
|
+ private final ObjectOpenCustomHashSet<int[]> indices;
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ public FastImmutableTableCache() {
|
|
+ this.rows = new ObjectOpenCustomHashSet<>((Hash.Strategy<R[]>) ObjectArrays.HASH_STRATEGY);
|
|
+ this.columns = new ObjectOpenCustomHashSet<>((Hash.Strategy<C[]>) ObjectArrays.HASH_STRATEGY);
|
|
+ this.values = new ObjectOpenCustomHashSet<>((Hash.Strategy<V[]>) ObjectArrays.HASH_STRATEGY);
|
|
+
|
|
+ this.indices = new ObjectOpenCustomHashSet<>(IntArrays.HASH_STRATEGY);
|
|
+ }
|
|
+
|
|
+ public synchronized V[] dedupValues(V[] values) {
|
|
+ return this.values.addOrGet(values);
|
|
+ }
|
|
+
|
|
+ public synchronized R[] dedupRows(R[] rows) {
|
|
+ return this.rows.addOrGet(rows);
|
|
+ }
|
|
+
|
|
+ public synchronized C[] dedupColumns(C[] columns) {
|
|
+ return this.columns.addOrGet(columns);
|
|
+ }
|
|
+
|
|
+ public synchronized int[] dedupIndices(int[] ints) {
|
|
+ return this.indices.addOrGet(ints);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FixedArrayList.java b/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FixedArrayList.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..35e4c91e9b87d7fc8394b046c85b2b7f75afeb27
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FixedArrayList.java
|
|
@@ -0,0 +1,153 @@
|
|
+package me.jellysquid.mods.hydrogen.common.collections;
|
|
+
|
|
+import com.google.common.collect.Iterators;
|
|
+import org.apache.commons.lang3.ArrayUtils;
|
|
+
|
|
+import java.util.*;
|
|
+
|
|
+public class FixedArrayList<T> implements List<T> {
|
|
+ private final T[] array;
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ public FixedArrayList(List<T> list) {
|
|
+ this(list.toArray((T[]) new Object[0]));
|
|
+ }
|
|
+
|
|
+ public FixedArrayList(T[] array) {
|
|
+ this.array = array;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return this.array.length;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return this.array.length == 0;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(Object o) {
|
|
+ return ArrayUtils.contains(this.array, o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Iterator<T> iterator() {
|
|
+ return Iterators.forArray(this.array);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return this.array.clone();
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public <T1> T1[] toArray(T1[] dst) {
|
|
+ T[] src = this.array;
|
|
+
|
|
+ if (dst.length < src.length) {
|
|
+ return (T1[]) Arrays.copyOf(src, src.length, dst.getClass());
|
|
+ }
|
|
+
|
|
+ System.arraycopy(src, 0, dst, 0, src.length);
|
|
+
|
|
+ if (dst.length > src.length) {
|
|
+ dst[src.length] = null;
|
|
+ }
|
|
+
|
|
+ return dst;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(T t) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(Object o) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ for (Object o : c) {
|
|
+ if (!ArrayUtils.contains(this.array, o)) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends T> c) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(int index, Collection<? extends T> c) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T get(int index) {
|
|
+ return this.array[index];
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T set(int index, T element) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void add(int index, T element) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T remove(int index) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int indexOf(Object o) {
|
|
+ return ArrayUtils.indexOf(this.array, o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int lastIndexOf(Object o) {
|
|
+ return ArrayUtils.lastIndexOf(this.array, o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ListIterator<T> listIterator() {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ListIterator<T> listIterator(int index) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<T> subList(int fromIndex, int toIndex) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/dedup/DeduplicationCache.java b/src/main/java/me/jellysquid/mods/hydrogen/common/dedup/DeduplicationCache.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..c4ebb3c59f2ddb63f39d0fdea62f41a042b68c25
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/dedup/DeduplicationCache.java
|
|
@@ -0,0 +1,56 @@
|
|
+package me.jellysquid.mods.hydrogen.common.dedup;
|
|
+
|
|
+import it.unimi.dsi.fastutil.Hash;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
|
+
|
|
+import java.util.Objects;
|
|
+
|
|
+public class DeduplicationCache<T> {
|
|
+ private final ObjectOpenCustomHashSet<T> pool;
|
|
+
|
|
+ private int attemptedInsertions = 0;
|
|
+ private int deduplicated = 0;
|
|
+
|
|
+ public DeduplicationCache(Hash.Strategy<T> strategy) {
|
|
+ this.pool = new ObjectOpenCustomHashSet<>(strategy);
|
|
+ }
|
|
+
|
|
+ public DeduplicationCache() {
|
|
+ this.pool = new ObjectOpenCustomHashSet<>(new Hash.Strategy<T>() {
|
|
+ @Override
|
|
+ public int hashCode(T o) {
|
|
+ return Objects.hashCode(o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(T a, T b) {
|
|
+ return Objects.equals(a, b);
|
|
+ }
|
|
+ });
|
|
+ }
|
|
+
|
|
+ public synchronized T deduplicate(T item) {
|
|
+ this.attemptedInsertions++;
|
|
+
|
|
+ T result = this.pool.addOrGet(item);
|
|
+
|
|
+ if (result != item) {
|
|
+ this.deduplicated++;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ public synchronized void clearCache() {
|
|
+ this.attemptedInsertions = 0;
|
|
+ this.deduplicated = 0;
|
|
+
|
|
+ this.pool.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized String toString() {
|
|
+ return String.format("DeduplicationCache ( %d/%d de-duplicated, %d pooled )",
|
|
+ this.deduplicated, this.attemptedInsertions, this.pool.size());
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/dedup/IdentifierCaches.java b/src/main/java/me/jellysquid/mods/hydrogen/common/dedup/IdentifierCaches.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..69246b3e2944c273818c4ef4731d6b2f2e6d18fc
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/dedup/IdentifierCaches.java
|
|
@@ -0,0 +1,6 @@
|
|
+package me.jellysquid.mods.hydrogen.common.dedup;
|
|
+
|
|
+public class IdentifierCaches {
|
|
+ public static final DeduplicationCache<String> NAMESPACES = new DeduplicationCache<>();
|
|
+ public static final DeduplicationCache<String> PATH = new DeduplicationCache<>();
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/jvm/ClassConstructors.java b/src/main/java/me/jellysquid/mods/hydrogen/common/jvm/ClassConstructors.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..7b3a7c6e2ce171b5ab7444e16e75c1a53ff3b899
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/jvm/ClassConstructors.java
|
|
@@ -0,0 +1,44 @@
|
|
+package me.jellysquid.mods.hydrogen.common.jvm;
|
|
+
|
|
+import com.google.common.collect.ImmutableMap;
|
|
+
|
|
+import java.lang.invoke.MethodHandle;
|
|
+import java.lang.invoke.MethodHandles;
|
|
+import java.lang.invoke.MethodType;
|
|
+import java.lang.reflect.Constructor;
|
|
+import java.util.Map;
|
|
+
|
|
+@SuppressWarnings("unchecked")
|
|
+public class ClassConstructors {
|
|
+ private static MethodHandle FAST_IMMUTABLE_REFERENCE_HASH_MAP_CONSTRUCTOR;
|
|
+
|
|
+ public static void init() {
|
|
+ initGuavaExtensions();
|
|
+ }
|
|
+
|
|
+ private static void initGuavaExtensions() { // Note: maybe this isn't needed as this is no longer a mod, need to look into this further.
|
|
+ // define classes in their reverse link order to prevent duplicate definition issues
|
|
+ ClassDefineTool.defineClass(ImmutableMap.class, "com.google.common.collect.HydrogenImmutableMapEntry");
|
|
+ ClassDefineTool.defineClass(ImmutableMap.class, "com.google.common.collect.HydrogenEntrySetIterator");
|
|
+ ClassDefineTool.defineClass(ImmutableMap.class, "com.google.common.collect.HydrogenEntrySet");
|
|
+
|
|
+ Class<?> immutableRefHashMapClass = ClassDefineTool.defineClass(ImmutableMap.class, "com.google.common.collect.HydrogenImmutableReferenceHashMap");
|
|
+
|
|
+ try {
|
|
+ FAST_IMMUTABLE_REFERENCE_HASH_MAP_CONSTRUCTOR = MethodHandles.lookup()
|
|
+ .findConstructor(immutableRefHashMapClass, MethodType.methodType(Void.TYPE, Map.class))
|
|
+ // compiler can only generate a desc returning ImmutableMap below
|
|
+ .asType(MethodType.methodType(ImmutableMap.class, Map.class));
|
|
+ } catch (ReflectiveOperationException e) {
|
|
+ throw new RuntimeException("Failed to find constructor", e);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static <K, V> ImmutableMap<K, V> createFastImmutableMap(Map<K, V> orig) {
|
|
+ try {
|
|
+ return (ImmutableMap<K, V>) FAST_IMMUTABLE_REFERENCE_HASH_MAP_CONSTRUCTOR.invokeExact((Map<K, V>) orig);
|
|
+ } catch (Throwable e) {
|
|
+ throw new RuntimeException("Could not instantiate collection", e);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/jvm/ClassDefineTool.java b/src/main/java/me/jellysquid/mods/hydrogen/common/jvm/ClassDefineTool.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..db7d91dfb8b852e1c204c44f62847f48261371f7
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/jvm/ClassDefineTool.java
|
|
@@ -0,0 +1,44 @@
|
|
+package me.jellysquid.mods.hydrogen.common.jvm;
|
|
+
|
|
+import org.apache.commons.io.IOUtils;
|
|
+import org.apache.logging.log4j.LogManager;
|
|
+import org.apache.logging.log4j.Logger;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.lang.invoke.MethodHandles;
|
|
+import java.net.URL;
|
|
+
|
|
+public class ClassDefineTool {
|
|
+ private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
|
+
|
|
+ private static final Logger LOGGER = LogManager.getLogger("Hydrogen");
|
|
+
|
|
+ public static Class<?> defineClass(Class<?> context, String name) {
|
|
+ String path = "/" + name.replace('.', '/') + ".class";
|
|
+ URL url = ClassDefineTool.class.getResource(path);
|
|
+
|
|
+ if (url == null) {
|
|
+ throw new RuntimeException("Couldn't find resource: " + path);
|
|
+ }
|
|
+
|
|
+ LOGGER.info("Injecting class '{}' (url: {})", name, url);
|
|
+
|
|
+ byte[] code;
|
|
+
|
|
+ try {
|
|
+ code = IOUtils.toByteArray(url);
|
|
+ } catch (IOException e) {
|
|
+ throw new RuntimeException("Could not read class bytes from resources: " + path, e);
|
|
+ }
|
|
+
|
|
+ try {
|
|
+ // The context class need to be in a module that exports and opens to ClassDefineTool
|
|
+ // Example: guava's automatic module exports and opens to everything
|
|
+ MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn(context, LOOKUP);
|
|
+ return privateLookup.defineClass(code);
|
|
+ } catch (Throwable throwable) {
|
|
+ throw new RuntimeException("Failed to define class", throwable);
|
|
+ }
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/state/all/AllMatchOneBoolean.java b/src/main/java/me/jellysquid/mods/hydrogen/common/state/all/AllMatchOneBoolean.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..55844de0ca4247c165a49b307f66d0d141134b2a
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/state/all/AllMatchOneBoolean.java
|
|
@@ -0,0 +1,46 @@
|
|
+package me.jellysquid.mods.hydrogen.common.state.all;
|
|
+
|
|
+import me.jellysquid.mods.hydrogen.common.state.single.SingleMatchOne;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.level.block.state.properties.Property;
|
|
+import java.util.List;
|
|
+import java.util.function.Predicate;
|
|
+
|
|
+public class AllMatchOneBoolean implements Predicate<BlockState> {
|
|
+ private final Property<?>[] properties;
|
|
+ private final boolean[] values;
|
|
+
|
|
+ public AllMatchOneBoolean(List<Predicate<BlockState>> list) {
|
|
+ int size = list.size();
|
|
+
|
|
+ this.properties = new Property[size];
|
|
+ this.values = new boolean[size];
|
|
+
|
|
+ for (int i = 0; i < size; i++) {
|
|
+ SingleMatchOne predicate = (SingleMatchOne) list.get(i);
|
|
+
|
|
+ this.properties[i] = predicate.property;
|
|
+ this.values[i] = (boolean) predicate.value;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static boolean canReplace(List<Predicate<BlockState>> list) {
|
|
+ return list.stream()
|
|
+ .allMatch(p -> {
|
|
+ return p instanceof SingleMatchOne && ((SingleMatchOne) p).value instanceof Boolean;
|
|
+ });
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean test(BlockState blockState) {
|
|
+ for (int i = 0; i < this.properties.length; i++) {
|
|
+ Boolean value = (Boolean) blockState.getValue(this.properties[i]);
|
|
+
|
|
+ if (value != this.values[i]) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/state/all/AllMatchOneObject.java b/src/main/java/me/jellysquid/mods/hydrogen/common/state/all/AllMatchOneObject.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..49be1c9d9da46dee2a14a5423d25a09ccfb19e3a
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/state/all/AllMatchOneObject.java
|
|
@@ -0,0 +1,37 @@
|
|
+package me.jellysquid.mods.hydrogen.common.state.all;
|
|
+
|
|
+import me.jellysquid.mods.hydrogen.common.state.single.SingleMatchOne;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.level.block.state.properties.Property;
|
|
+import java.util.List;
|
|
+import java.util.function.Predicate;
|
|
+
|
|
+public class AllMatchOneObject implements Predicate<BlockState> {
|
|
+ private final Property<?>[] properties;
|
|
+ private final Object[] values;
|
|
+
|
|
+ public AllMatchOneObject(List<Predicate<BlockState>> list) {
|
|
+ int size = list.size();
|
|
+
|
|
+ this.properties = new Property[size];
|
|
+ this.values = new Object[size];
|
|
+
|
|
+ for (int i = 0; i < size; i++) {
|
|
+ SingleMatchOne predicate = (SingleMatchOne) list.get(i);
|
|
+
|
|
+ this.properties[i] = predicate.property;
|
|
+ this.values[i] = predicate.value;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean test(BlockState blockState) {
|
|
+ for (int i = 0; i < this.properties.length; i++) {
|
|
+ if (blockState.getValue(this.properties[i]) != this.values[i]) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/state/any/AllMatchAnyObject.java b/src/main/java/me/jellysquid/mods/hydrogen/common/state/any/AllMatchAnyObject.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..b46cdb3fd8131d3ce570ed9fadae2c790645eba6
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/state/any/AllMatchAnyObject.java
|
|
@@ -0,0 +1,39 @@
|
|
+package me.jellysquid.mods.hydrogen.common.state.any;
|
|
+
|
|
+import me.jellysquid.mods.hydrogen.common.state.single.SingleMatchAny;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.level.block.state.properties.Property;
|
|
+import org.apache.commons.lang3.ArrayUtils;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.function.Predicate;
|
|
+
|
|
+public class AllMatchAnyObject implements Predicate<BlockState> {
|
|
+ private final Property<?>[] properties;
|
|
+ private final Object[][] values;
|
|
+
|
|
+ public AllMatchAnyObject(List<Predicate<BlockState>> list) {
|
|
+ int size = list.size();
|
|
+
|
|
+ this.properties = new Property[size];
|
|
+ this.values = new Object[size][];
|
|
+
|
|
+ for (int i = 0; i < size; i++) {
|
|
+ SingleMatchAny predicate = (SingleMatchAny) list.get(i);
|
|
+
|
|
+ this.properties[i] = predicate.property;
|
|
+ this.values[i] = predicate.values;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean test(BlockState blockState) {
|
|
+ for (int i = 0; i < this.properties.length; i++) {
|
|
+ if (!ArrayUtils.contains(this.values[i], blockState.getValue(this.properties[i]))) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/state/single/SingleMatchAny.java b/src/main/java/me/jellysquid/mods/hydrogen/common/state/single/SingleMatchAny.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..5ba47d431bb53cb1ccb32cff4663d26466b53a33
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/state/single/SingleMatchAny.java
|
|
@@ -0,0 +1,63 @@
|
|
+package me.jellysquid.mods.hydrogen.common.state.single;
|
|
+
|
|
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
|
+import org.apache.commons.lang3.ArrayUtils;
|
|
+
|
|
+import java.util.Arrays;
|
|
+import java.util.List;
|
|
+import java.util.Objects;
|
|
+import java.util.function.Predicate;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.level.block.state.properties.Property;
|
|
+
|
|
+public class SingleMatchAny implements Predicate<BlockState> {
|
|
+ public static final ObjectOpenHashSet<SingleMatchAny> PREDICATES = new ObjectOpenHashSet<>();
|
|
+
|
|
+ public final Property<?> property;
|
|
+ public final Object[] values;
|
|
+
|
|
+ private SingleMatchAny(Property<?> property, List<Object> values) {
|
|
+ this.property = property;
|
|
+ this.values = values.toArray();
|
|
+ }
|
|
+
|
|
+ public static SingleMatchAny create(Property<?> property, List<Object> values) {
|
|
+ return PREDICATES.addOrGet(new SingleMatchAny(property, values));
|
|
+ }
|
|
+
|
|
+ public static boolean areOfType(List<Predicate<BlockState>> predicates) {
|
|
+ return predicates.stream()
|
|
+ .allMatch(p -> {
|
|
+ return p instanceof SingleMatchAny;
|
|
+ });
|
|
+ }
|
|
+
|
|
+ public static boolean valuesMatchType(List<Predicate<BlockState>> predicates, Class<?> type) {
|
|
+ return predicates.stream()
|
|
+ .allMatch(p -> {
|
|
+ return p instanceof SingleMatchAny &&
|
|
+ Arrays.stream(((SingleMatchAny) p).values).allMatch(t -> type.isInstance(p));
|
|
+ });
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean test(BlockState blockState) {
|
|
+ return ArrayUtils.contains(this.values, blockState.getValue(this.property));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(Object o) {
|
|
+ if (this == o) return true;
|
|
+ if (o == null || getClass() != o.getClass()) return false;
|
|
+ SingleMatchAny that = (SingleMatchAny) o;
|
|
+ return Objects.equals(property, that.property) &&
|
|
+ Arrays.equals(values, that.values);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ int result = Objects.hash(property);
|
|
+ result = 31 * result + Arrays.hashCode(values);
|
|
+ return result;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/state/single/SingleMatchOne.java b/src/main/java/me/jellysquid/mods/hydrogen/common/state/single/SingleMatchOne.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..18649ef152ea6f7ae08bfa217fd1a1ad6581245e
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/state/single/SingleMatchOne.java
|
|
@@ -0,0 +1,35 @@
|
|
+package me.jellysquid.mods.hydrogen.common.state.single;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.function.Predicate;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.level.block.state.properties.Property;
|
|
+
|
|
+public class SingleMatchOne implements Predicate<BlockState> {
|
|
+ public final Property<?> property;
|
|
+ public final Object value;
|
|
+
|
|
+ public SingleMatchOne(Property<?> property, Object value) {
|
|
+ this.property = property;
|
|
+ this.value = value;
|
|
+ }
|
|
+
|
|
+ public static boolean areOfType(List<Predicate<BlockState>> predicates) {
|
|
+ return predicates.stream()
|
|
+ .allMatch(p -> {
|
|
+ return p instanceof SingleMatchOne;
|
|
+ });
|
|
+ }
|
|
+
|
|
+ public static boolean valuesMatchType(List<Predicate<BlockState>> predicates, Class<?> type) {
|
|
+ return predicates.stream()
|
|
+ .allMatch(p -> {
|
|
+ return p instanceof SingleMatchOne && type.isInstance(((SingleMatchOne) p).value);
|
|
+ });
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean test(BlockState blockState) {
|
|
+ return blockState.getValue(this.property) == this.value;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/util/AllPredicate.java b/src/main/java/me/jellysquid/mods/hydrogen/common/util/AllPredicate.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a4836a1a6616072b2cc5cc78a7b4902ca92f99b6
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/util/AllPredicate.java
|
|
@@ -0,0 +1,22 @@
|
|
+package me.jellysquid.mods.hydrogen.common.util;
|
|
+
|
|
+import java.util.function.Predicate;
|
|
+
|
|
+public class AllPredicate<T> implements Predicate<T> {
|
|
+ private final Predicate<T>[] predicates;
|
|
+
|
|
+ public AllPredicate(Predicate<T>[] predicates) {
|
|
+ this.predicates = predicates;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean test(T t) {
|
|
+ for (Predicate<T> predicate : this.predicates) {
|
|
+ if (!predicate.test(t)) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/jellysquid/mods/hydrogen/common/util/AnyPredicate.java b/src/main/java/me/jellysquid/mods/hydrogen/common/util/AnyPredicate.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..6877466f27fe8a22e2a68cf954dfaf313f4db94e
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/hydrogen/common/util/AnyPredicate.java
|
|
@@ -0,0 +1,22 @@
|
|
+package me.jellysquid.mods.hydrogen.common.util;
|
|
+
|
|
+import java.util.function.Predicate;
|
|
+
|
|
+public class AnyPredicate<T> implements Predicate<T> {
|
|
+ private final Predicate<T>[] predicates;
|
|
+
|
|
+ public AnyPredicate(Predicate<T>[] predicates) {
|
|
+ this.predicates = predicates;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean test(T t) {
|
|
+ for (Predicate<T> predicate : this.predicates) {
|
|
+ if (predicate.test(t)) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/minecraft/resources/ResourceLocation.java b/src/main/java/net/minecraft/resources/ResourceLocation.java
|
|
index 6e5d13e63c97cb95b93af1d997dc0eb53f966566..231448a1a49f1c4034ce09e06dcbdabe103bd8dd 100644
|
|
--- a/src/main/java/net/minecraft/resources/ResourceLocation.java
|
|
+++ b/src/main/java/net/minecraft/resources/ResourceLocation.java
|
|
@@ -18,6 +18,7 @@ import net.minecraft.ResourceLocationException;
|
|
import net.minecraft.network.chat.TranslatableComponent;
|
|
import net.minecraft.util.GsonHelper;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
+import me.jellysquid.mods.hydrogen.common.dedup.IdentifierCaches; // JettPack
|
|
|
|
public class ResourceLocation implements Comparable<ResourceLocation> {
|
|
public static final Codec<ResourceLocation> CODEC = Codec.STRING.comapFlatMap(ResourceLocation::read, ResourceLocation::toString).stable();
|
|
@@ -29,8 +30,10 @@ public class ResourceLocation implements Comparable<ResourceLocation> {
|
|
protected final String path;
|
|
|
|
protected ResourceLocation(String[] id) {
|
|
- this.namespace = StringUtils.isEmpty(id[0]) ? "minecraft" : id[0];
|
|
- this.path = id[1];
|
|
+ // JettPack start - port Hydrogen
|
|
+ this.namespace = IdentifierCaches.NAMESPACES.deduplicate(StringUtils.isEmpty(id[0]) ? "minecraft" : id[0]);
|
|
+ this.path = IdentifierCaches.PATH.deduplicate(id[1]);
|
|
+ // JettPack end
|
|
if (!isValidNamespace(this.namespace)) {
|
|
throw new ResourceLocationException("Non [a-z0-9_.-] character in namespace of location: " + org.apache.commons.lang3.StringUtils.normalizeSpace(this.namespace) + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(this.path)); // Paper
|
|
} else if (!isValidPath(this.path)) {
|
|
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
|
index 2f5c021b6849acb81064d55418707921424b649b..8cf835307c36fb048d62af9f417daeeeb71a0cff 100644
|
|
--- a/src/main/java/net/minecraft/server/Main.java
|
|
+++ b/src/main/java/net/minecraft/server/Main.java
|
|
@@ -64,6 +64,7 @@ public class Main {
|
|
|
|
@DontObfuscate
|
|
public static void main(final OptionSet optionset) { // CraftBukkit - replaces main(String[] astring)
|
|
+ me.jellysquid.mods.hydrogen.common.jvm.ClassConstructors.init(); // JettPack
|
|
SharedConstants.tryDetectVersion();
|
|
/* CraftBukkit start - Replace everything
|
|
OptionParser optionparser = new OptionParser();
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
|
|
index 5be5eabc222b9e20c083ff83fae52010b19ea854..c263220bc504bdb2067ac8920fceac6de1bb850e 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
|
|
@@ -44,7 +44,7 @@ public abstract class StateHolder<O, S> {
|
|
|
|
protected StateHolder(O owner, ImmutableMap<Property<?>, Comparable<?>> entries, MapCodec<S> codec) {
|
|
this.owner = owner;
|
|
- this.values = entries;
|
|
+ this.values = me.jellysquid.mods.hydrogen.common.jvm.ClassConstructors.createFastImmutableMap(entries); // JettPack - port hydrogen
|
|
this.propertiesCodec = codec;
|
|
this.optimisedTable = new io.papermc.paper.util.table.ZeroCollidingReferenceStateTable(this, entries); // Paper - optimise state lookup
|
|
}
|