Paper/patches/server/1048-SW-Use-optimized-NeighbourTable.patch
Chaoscaot 037a909005
Einige Prüfungen sind fehlgeschlagen
SteamWarCI Build failed
Update to 1.21.1
2024-08-27 13:57:27 +02:00

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) {