geforkt von Mirrors/Paper
224 Zeilen
11 KiB
Diff
224 Zeilen
11 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Chaoscaot <chaos@chaoscaot.de>
|
|
Date: Tue, 13 Aug 2024 11:44:11 +0200
|
|
Subject: [PATCH] SW Use optimized NeighbourTable
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/state/StateDefinition.java b/src/main/java/net/minecraft/world/level/block/state/StateDefinition.java
|
|
index 46af72761c0bfbc10c14d78c855255969e2cf8a3..3a449e13951ea183b9ae7910a424b51e841608da 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/state/StateDefinition.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/state/StateDefinition.java
|
|
@@ -11,10 +11,8 @@ import com.mojang.serialization.Decoder;
|
|
import com.mojang.serialization.Encoder;
|
|
import com.mojang.serialization.MapCodec;
|
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
|
|
-import java.util.Collection;
|
|
-import java.util.Collections;
|
|
-import java.util.List;
|
|
-import java.util.Map;
|
|
+
|
|
+import java.util.*;
|
|
import java.util.Map.Entry;
|
|
import java.util.function.Function;
|
|
import java.util.function.Supplier;
|
|
@@ -22,7 +20,8 @@ import java.util.regex.Pattern;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Stream;
|
|
import javax.annotation.Nullable;
|
|
-import net.minecraft.world.level.block.state.properties.Property;
|
|
+
|
|
+import net.minecraft.world.level.block.state.properties.*;
|
|
|
|
public class StateDefinition<O, S extends StateHolder<O, S>> {
|
|
static final Pattern NAME_PATTERN = Pattern.compile("^[a-z0-9_]+$");
|
|
@@ -41,7 +40,6 @@ public class StateDefinition<O, S extends StateHolder<O, S>> {
|
|
}
|
|
|
|
MapCodec<S> mapCodec2 = mapCodec;
|
|
- Map<Map<Property<?>, Comparable<?>>, S> map = Maps.newLinkedHashMap();
|
|
List<S> list = Lists.newArrayList();
|
|
Stream<List<Pair<Property<?>, Comparable<?>>>> stream = Stream.of(Collections.emptyList());
|
|
|
|
@@ -53,6 +51,7 @@ public class StateDefinition<O, S extends StateHolder<O, S>> {
|
|
}));
|
|
}
|
|
|
|
+ NeighbourTable<S> table = new NeighbourTable<>(propertiesMap);
|
|
stream.forEach(list2 -> {
|
|
Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap = new Reference2ObjectArrayMap<>(list2.size());
|
|
|
|
@@ -61,13 +60,12 @@ public class StateDefinition<O, S extends StateHolder<O, S>> {
|
|
}
|
|
|
|
S stateHolderx = factory.create(owner, reference2ObjectArrayMap, mapCodec2);
|
|
- map.put(reference2ObjectArrayMap, stateHolderx);
|
|
list.add(stateHolderx);
|
|
- });
|
|
|
|
- for (S stateHolder : list) {
|
|
- stateHolder.populateNeighbours(map);
|
|
- }
|
|
+ int index = table.put(reference2ObjectArrayMap, stateHolderx);
|
|
+
|
|
+ stateHolderx.populateNeighbours(table, index);
|
|
+ });
|
|
|
|
this.states = ImmutableList.copyOf(list);
|
|
}
|
|
@@ -157,4 +155,60 @@ public class StateDefinition<O, S extends StateHolder<O, S>> {
|
|
public interface Factory<O, S> {
|
|
S create(O owner, Reference2ObjectArrayMap<Property<?>, Comparable<?>> propertyMap, MapCodec<S> codec);
|
|
}
|
|
+
|
|
+ public static class NeighbourTable<S> {
|
|
+ private final Map<Property<?>, Pair<Integer, Integer>> offsetMasks;
|
|
+ private final Object[] array;
|
|
+
|
|
+ public NeighbourTable(Map<String, Property<?>> propertiesMap) {
|
|
+ offsetMasks = new IdentityHashMap<>(propertiesMap.size());
|
|
+ int offset = 0;
|
|
+ for(Property<?> property : propertiesMap.values()) {
|
|
+ int bits = Integer.SIZE - Integer.numberOfLeadingZeros((property instanceof EnumProperty<?> ? property.getValueClass().getEnumConstants().length : property.getPossibleValues().size()) - 1);
|
|
+ offsetMasks.put(property, Pair.of(offset, ~(((1<<bits)-1) << offset)));
|
|
+ offset += bits;
|
|
+ }
|
|
+
|
|
+ array = new Object[1 << offset];
|
|
+ }
|
|
+
|
|
+ public int put(Map<Property<?>, Comparable<?>> key, S value) {
|
|
+ int index = 0;
|
|
+ for(Map.Entry<Property<?>, Comparable<?>> k : key.entrySet()) {
|
|
+ index = setIndex(index, k.getKey(), k.getValue());
|
|
+ }
|
|
+ array[index] = value;
|
|
+ return index;
|
|
+ }
|
|
+
|
|
+ private int setIndex(int index, Property<?> property, Comparable<?> value) {
|
|
+ Pair<Integer, Integer> offsetMask = offsetMasks.get(property);
|
|
+ if(property instanceof BooleanProperty) {
|
|
+ return index | (((Boolean)value) ? 1 : 0) << offsetMask.getFirst();
|
|
+ } else if(property instanceof EnumProperty) {
|
|
+ return index | ((Enum<?>)value).ordinal() << offsetMask.getFirst();
|
|
+ } else if(property instanceof IntegerProperty intProperty) {
|
|
+ return index | (((Integer)value) - intProperty.min) << offsetMask.getFirst();
|
|
+ } else {
|
|
+ throw new IllegalArgumentException("Unknown property type " + property.getClass().getName());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public S getNeighbour(int index, Property<?> property, Comparable<?> value) {
|
|
+ return (S)array[modIndex(index, property, value)];
|
|
+ }
|
|
+
|
|
+ private int modIndex(int index, Property<?> property, Comparable<?> value) {
|
|
+ Pair<Integer, Integer> offsetMask = offsetMasks.get(property);
|
|
+ if(property instanceof BooleanProperty) {
|
|
+ return (index & offsetMask.getSecond()) | (((Boolean)value) ? 1 : 0) << offsetMask.getFirst();
|
|
+ } else if(property instanceof EnumProperty) {
|
|
+ return (index & offsetMask.getSecond()) | ((Enum<?>)value).ordinal() << offsetMask.getFirst();
|
|
+ } else if(property instanceof IntegerProperty intProperty) {
|
|
+ return (index & offsetMask.getSecond()) | (((Integer)value) - intProperty.min) << offsetMask.getFirst();
|
|
+ } else {
|
|
+ throw new IllegalArgumentException("Unknown property type " + property.getClass().getName());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
}
|
|
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 45744d86e9582a93a0cec26009deea091080fbbe..7e2ecb0457150dedc665f05c6c8ad068c00e3642 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
|
|
@@ -37,15 +37,14 @@ public abstract class StateHolder<O, S> {
|
|
};
|
|
protected final O owner;
|
|
private final Reference2ObjectArrayMap<Property<?>, Comparable<?>> values;
|
|
- private Table<Property<?>, Comparable<?>, S> neighbours;
|
|
protected final MapCodec<S> propertiesCodec;
|
|
- protected final io.papermc.paper.util.table.ZeroCollidingReferenceStateTable optimisedTable; // Paper - optimise state lookup
|
|
+ private StateDefinition.NeighbourTable<S> neighbourTable;
|
|
+ private int neighbourIndex;
|
|
|
|
protected StateHolder(O owner, Reference2ObjectArrayMap<Property<?>, Comparable<?>> propertyMap, MapCodec<S> codec) {
|
|
this.owner = owner;
|
|
this.values = propertyMap;
|
|
this.propertiesCodec = codec;
|
|
- this.optimisedTable = new io.papermc.paper.util.table.ZeroCollidingReferenceStateTable(this, propertyMap); // Paper - optimise state lookup
|
|
}
|
|
|
|
public <T extends Comparable<T>> S cycle(Property<T> property) {
|
|
@@ -86,11 +85,11 @@ public abstract class StateHolder<O, S> {
|
|
}
|
|
|
|
public <T extends Comparable<T>> boolean hasProperty(Property<T> property) {
|
|
- return this.optimisedTable.get(property) != null; // Paper - optimise state lookup
|
|
+ return this.values.containsKey(property);
|
|
}
|
|
|
|
public <T extends Comparable<T>> T getValue(Property<T> property) {
|
|
- Comparable<?> comparable = this.optimisedTable.get(property); // Paper - optimise state lookup
|
|
+ Comparable<?> comparable = this.values.get(property);
|
|
if (comparable == null) {
|
|
throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner);
|
|
} else {
|
|
@@ -99,52 +98,26 @@ public abstract class StateHolder<O, S> {
|
|
}
|
|
|
|
public <T extends Comparable<T>> Optional<T> getOptionalValue(Property<T> property) {
|
|
- Comparable<?> comparable = this.optimisedTable.get(property); // Paper - optimise state lookup
|
|
+ Comparable<?> comparable = this.values.get(property);
|
|
return comparable == null ? Optional.empty() : Optional.of(property.getValueClass().cast(comparable));
|
|
}
|
|
|
|
public <T extends Comparable<T>, V extends T> S setValue(Property<T> property, V value) {
|
|
- // Paper start - optimise state lookup
|
|
- final S ret = (S)this.optimisedTable.get(property, value);
|
|
- if (ret == null) {
|
|
- throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value");
|
|
- }
|
|
- return ret;
|
|
- // Paper end - optimise state lookup
|
|
+ return this.neighbourTable.getNeighbour(this.neighbourIndex, property, value);
|
|
}
|
|
|
|
public <T extends Comparable<T>, V extends T> S trySetValue(Property<T> property, V value) {
|
|
Comparable<?> comparable = this.values.get(property);
|
|
if (comparable != null && !comparable.equals(value)) {
|
|
- S object = this.neighbours.get(property, value);
|
|
- if (object == null) {
|
|
- throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value");
|
|
- } else {
|
|
- return object;
|
|
- }
|
|
+ return this.neighbourTable.getNeighbour(this.neighbourIndex, property, value);
|
|
} else {
|
|
return (S)this;
|
|
}
|
|
}
|
|
|
|
- public void populateNeighbours(Map<Map<Property<?>, Comparable<?>>, S> states) {
|
|
- if (this.neighbours != null) {
|
|
- throw new IllegalStateException();
|
|
- } else {
|
|
- Table<Property<?>, Comparable<?>, S> table = HashBasedTable.create();
|
|
-
|
|
- for (Entry<Property<?>, Comparable<?>> entry : this.values.entrySet()) {
|
|
- Property<?> property = entry.getKey();
|
|
-
|
|
- for (Comparable<?> comparable : property.getPossibleValues()) {
|
|
- if (!comparable.equals(entry.getValue())) {
|
|
- table.put(property, comparable, states.get(this.makeNeighbourValues(property, comparable)));
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- this.neighbours = (Table<Property<?>, Comparable<?>, S>)(table.isEmpty() ? table : ArrayTable.create(table)); this.optimisedTable.loadInTable((Table)this.neighbours, this.values); // Paper - optimise state lookup
|
|
- }
|
|
+ public void populateNeighbours(StateDefinition.NeighbourTable<S> states, int ownIndex) {
|
|
+ this.neighbourTable = states;
|
|
+ this.neighbourIndex = ownIndex;
|
|
}
|
|
|
|
private Map<Property<?>, Comparable<?>> makeNeighbourValues(Property<?> property, Comparable<?> value) {
|