c0936a71bd
Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 01aa02eb PR-858: Add LivingEntity#playHurtAnimation() 9421320f PR-884: Refinements to new ban API for improved compatibility and correctness 37a60b45 SPIGOT-6455, SPIGOT-7030, PR-750: Improve ban API 4eeb174b All smithing inventories are now the new smithing inventory f2bb168e PR-880: Add methods to get/set FallingBlock CancelDrop e7a807fa PR-879: Add Player#sendHealthUpdate() 692b8e96 SPIGOT-7370: Remove float value conversion in plugin.yml 2d033390 SPIGOT-7403: Add direct API for waxed signs 16a08373 PR-876: Add missing Raider API and 'no action ticks' CraftBukkit Changes: b60a95c8c PR-1189: Add LivingEntity#playHurtAnimation() 95c335c63 PR-1226: Fix VehicleEnterEvent not being called for certain entities 0a0fc3bee PR-1227: Refinements to new ban API for improved compatibility and correctness 0d0b1e5dc Revert bad change to PathfinderGoalSit causing all cats to sit 648196070 SPIGOT-6455, SPIGOT-7030, PR-1054: Improve ban API 31fe848d6 All smithing inventories are now the new smithing inventory 9a919a143 SPIGOT-7416: SmithItemEvent not firing in Smithing Table 9f64f0d22 PR-1221: Add methods to get/set FallingBlock CancelDrop 3be9ac171 PR-1220: Add Player#sendHealthUpdate() c1279f775 PR-1209: Clean up various patches c432e4397 Fix Raider#setCelebrating() implementation 504d96665 SPIGOT-7403: Add direct API for waxed signs c68c1f1b3 PR-1216: Add missing Raider API and 'no action ticks' 85b89c3dd Increase outdated build delay Spigot Changes: 9ebce8af Rebuild patches 64b565e6 Rebuild patches
344 Zeilen
15 KiB
Diff
344 Zeilen
15 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
|
Date: Thu, 11 Mar 2021 20:05:44 -0800
|
|
Subject: [PATCH] Custom table implementation for blockstate state lookups
|
|
|
|
Testing some redstone intensive machines showed to bring about a 10%
|
|
improvement.
|
|
|
|
diff --git a/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java b/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..57d0cd3ad6f972e986c72a57f1a6e36003f190c2
|
|
--- /dev/null
|
|
+++ b/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java
|
|
@@ -0,0 +1,160 @@
|
|
+package io.papermc.paper.util.table;
|
|
+
|
|
+import com.google.common.collect.Table;
|
|
+import net.minecraft.world.level.block.state.StateHolder;
|
|
+import net.minecraft.world.level.block.state.properties.Property;
|
|
+import java.util.Collection;
|
|
+import java.util.HashSet;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
+
|
|
+public final class ZeroCollidingReferenceStateTable {
|
|
+
|
|
+ // upper 32 bits: starting index
|
|
+ // lower 32 bits: bitset for contained ids
|
|
+ protected final long[] this_index_table;
|
|
+ protected final Comparable<?>[] this_table;
|
|
+ protected final StateHolder<?, ?> this_state;
|
|
+
|
|
+ protected long[] index_table;
|
|
+ protected StateHolder<?, ?>[][] value_table;
|
|
+
|
|
+ public ZeroCollidingReferenceStateTable(final StateHolder<?, ?> state, final Map<Property<?>, Comparable<?>> this_map) {
|
|
+ this.this_state = state;
|
|
+ this.this_index_table = this.create_table(this_map.keySet());
|
|
+
|
|
+ int max_id = -1;
|
|
+ for (final Property<?> property : this_map.keySet()) {
|
|
+ final int id = lookup_vindex(property, this.this_index_table);
|
|
+ if (id > max_id) {
|
|
+ max_id = id;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ this.this_table = new Comparable[max_id + 1];
|
|
+ for (final Map.Entry<Property<?>, Comparable<?>> entry : this_map.entrySet()) {
|
|
+ this.this_table[lookup_vindex(entry.getKey(), this.this_index_table)] = entry.getValue();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void loadInTable(final Table<Property<?>, Comparable<?>, StateHolder<?, ?>> table,
|
|
+ final Map<Property<?>, Comparable<?>> this_map) {
|
|
+ final Set<Property<?>> combined = new HashSet<>(table.rowKeySet());
|
|
+ combined.addAll(this_map.keySet());
|
|
+
|
|
+ this.index_table = this.create_table(combined);
|
|
+
|
|
+ int max_id = -1;
|
|
+ for (final Property<?> property : combined) {
|
|
+ final int id = lookup_vindex(property, this.index_table);
|
|
+ if (id > max_id) {
|
|
+ max_id = id;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ this.value_table = new StateHolder[max_id + 1][];
|
|
+
|
|
+ final Map<Property<?>, Map<Comparable<?>, StateHolder<?, ?>>> map = table.rowMap();
|
|
+ for (final Property<?> property : map.keySet()) {
|
|
+ final Map<Comparable<?>, StateHolder<?, ?>> propertyMap = map.get(property);
|
|
+
|
|
+ final int id = lookup_vindex(property, this.index_table);
|
|
+ final StateHolder<?, ?>[] states = this.value_table[id] = new StateHolder[property.getPossibleValues().size()];
|
|
+
|
|
+ for (final Map.Entry<Comparable<?>, StateHolder<?, ?>> entry : propertyMap.entrySet()) {
|
|
+ if (entry.getValue() == null) {
|
|
+ // TODO what
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ states[((Property)property).getIdFor(entry.getKey())] = entry.getValue();
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
+ for (final Map.Entry<Property<?>, Comparable<?>> entry : this_map.entrySet()) {
|
|
+ final Property<?> property = entry.getKey();
|
|
+ final int index = lookup_vindex(property, this.index_table);
|
|
+
|
|
+ if (this.value_table[index] == null) {
|
|
+ this.value_table[index] = new StateHolder[property.getPossibleValues().size()];
|
|
+ }
|
|
+
|
|
+ this.value_table[index][((Property)property).getIdFor(entry.getValue())] = this.this_state;
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
+ protected long[] create_table(final Collection<Property<?>> collection) {
|
|
+ int max_id = -1;
|
|
+ for (final Property<?> property : collection) {
|
|
+ final int id = property.getId();
|
|
+ if (id > max_id) {
|
|
+ max_id = id;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ final long[] ret = new long[((max_id + 1) + 31) >>> 5]; // ceil((max_id + 1) / 32)
|
|
+
|
|
+ for (final Property<?> property : collection) {
|
|
+ final int id = property.getId();
|
|
+
|
|
+ ret[id >>> 5] |= (1L << (id & 31));
|
|
+ }
|
|
+
|
|
+ int total = 0;
|
|
+ for (int i = 1, len = ret.length; i < len; ++i) {
|
|
+ ret[i] |= (long)(total += Long.bitCount(ret[i - 1] & 0xFFFFFFFFL)) << 32;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ public Comparable<?> get(final Property<?> state) {
|
|
+ final Comparable<?>[] table = this.this_table;
|
|
+ final int index = lookup_vindex(state, this.this_index_table);
|
|
+
|
|
+ if (index < 0 || index >= table.length) {
|
|
+ return null;
|
|
+ }
|
|
+ return table[index];
|
|
+ }
|
|
+
|
|
+ public StateHolder<?, ?> get(final Property<?> property, final Comparable<?> with) {
|
|
+ final int withId = ((Property)property).getIdFor(with);
|
|
+ if (withId < 0) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ final int index = lookup_vindex(property, this.index_table);
|
|
+ final StateHolder<?, ?>[][] table = this.value_table;
|
|
+ if (index < 0 || index >= table.length) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ final StateHolder<?, ?>[] values = table[index];
|
|
+
|
|
+ if (withId >= values.length) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ return values[withId];
|
|
+ }
|
|
+
|
|
+ protected static int lookup_vindex(final Property<?> property, final long[] index_table) {
|
|
+ final int id = property.getId();
|
|
+ final long bitset_mask = (1L << (id & 31));
|
|
+ final long lower_mask = bitset_mask - 1;
|
|
+ final int index = id >>> 5;
|
|
+ if (index >= index_table.length) {
|
|
+ return -1;
|
|
+ }
|
|
+ final long index_value = index_table[index];
|
|
+ final long contains_check = ((index_value & bitset_mask) - 1) >> (Long.SIZE - 1); // -1L if doesn't contain
|
|
+
|
|
+ // index = total bits set in lower table values (upper 32 bits of index_value) plus total bits set in lower indices below id
|
|
+ // contains_check is 0 if the bitset had id set, else it's -1: so index is unaffected if contains_check == 0,
|
|
+ // otherwise it comes out as -1.
|
|
+ return (int)(((index_value >>> 32) + Long.bitCount(index_value & lower_mask)) | contains_check);
|
|
+ }
|
|
+}
|
|
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 89ba12d44865ecddebabbc39c769af4cd8c82702..5f285d190186a2ff5a61d05070593e1d633dd79a 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
|
|
@@ -39,11 +39,13 @@ public abstract class StateHolder<O, S> {
|
|
private final ImmutableMap<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
|
|
|
|
protected StateHolder(O owner, ImmutableMap<Property<?>, Comparable<?>> entries, MapCodec<S> codec) {
|
|
this.owner = owner;
|
|
this.values = entries;
|
|
this.propertiesCodec = codec;
|
|
+ this.optimisedTable = new io.papermc.paper.util.table.ZeroCollidingReferenceStateTable(this, entries); // Paper - optimise state lookup
|
|
}
|
|
|
|
public <T extends Comparable<T>> S cycle(Property<T> property) {
|
|
@@ -84,11 +86,11 @@ public abstract class StateHolder<O, S> {
|
|
}
|
|
|
|
public <T extends Comparable<T>> boolean hasProperty(Property<T> property) {
|
|
- return this.values.containsKey(property);
|
|
+ return this.optimisedTable.get(property) != null; // Paper - optimise state lookup
|
|
}
|
|
|
|
public <T extends Comparable<T>> T getValue(Property<T> property) {
|
|
- Comparable<?> comparable = this.values.get(property);
|
|
+ Comparable<?> comparable = this.optimisedTable.get(property); // Paper - optimise state lookup
|
|
if (comparable == null) {
|
|
throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner);
|
|
} else {
|
|
@@ -97,24 +99,18 @@ public abstract class StateHolder<O, S> {
|
|
}
|
|
|
|
public <T extends Comparable<T>> Optional<T> getOptionalValue(Property<T> property) {
|
|
- Comparable<?> comparable = this.values.get(property);
|
|
+ Comparable<?> comparable = this.optimisedTable.get(property); // Paper - optimise state lookup
|
|
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) {
|
|
- Comparable<?> comparable = this.values.get(property);
|
|
- if (comparable == null) {
|
|
- throw new IllegalArgumentException("Cannot set property " + property + " as it does not exist in " + this.owner);
|
|
- } else if (comparable.equals(value)) {
|
|
- return (S)this;
|
|
- } else {
|
|
- 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;
|
|
- }
|
|
+ // 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
|
|
}
|
|
|
|
public <T extends Comparable<T>, V extends T> S trySetValue(Property<T> property, V value) {
|
|
@@ -147,7 +143,7 @@ public abstract class StateHolder<O, S> {
|
|
}
|
|
}
|
|
|
|
- this.neighbours = (Table<Property<?>, Comparable<?>, S>)(table.isEmpty() ? table : ArrayTable.create(table));
|
|
+ this.neighbours = (Table<Property<?>, Comparable<?>, S>)(table.isEmpty() ? table : ArrayTable.create(table)); this.optimisedTable.loadInTable((Table)this.neighbours, this.values); // Paper - optimise state lookup
|
|
}
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java
|
|
index ff1a0d125edd2ea10c870cbb62ae9aa23644b6dc..233215280f8494dbc33a2fd0b14e37e59f1cb643 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java
|
|
@@ -7,6 +7,13 @@ import java.util.Optional;
|
|
public class BooleanProperty extends Property<Boolean> {
|
|
private final ImmutableSet<Boolean> values = ImmutableSet.of(true, false);
|
|
|
|
+ // Paper start - optimise iblockdata state lookup
|
|
+ @Override
|
|
+ public final int getIdFor(final Boolean value) {
|
|
+ return value.booleanValue() ? 1 : 0;
|
|
+ }
|
|
+ // Paper end - optimise iblockdata state lookup
|
|
+
|
|
protected BooleanProperty(String name) {
|
|
super(name, Boolean.class);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java
|
|
index 0bca0f971dac994bd8b6ecd87e8b33e26c0f18f9..edd3c745efb40ee79a1393199c7a27ddaa2f8026 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java
|
|
@@ -15,6 +15,15 @@ public class EnumProperty<T extends Enum<T> & StringRepresentable> extends Prope
|
|
private final ImmutableSet<T> values;
|
|
private final Map<String, T> names = Maps.newHashMap();
|
|
|
|
+ // Paper start - optimise iblockdata state lookup
|
|
+ private int[] idLookupTable;
|
|
+
|
|
+ @Override
|
|
+ public final int getIdFor(final T value) {
|
|
+ return this.idLookupTable[value.ordinal()];
|
|
+ }
|
|
+ // Paper end - optimise iblockdata state lookup
|
|
+
|
|
protected EnumProperty(String name, Class<T> type, Collection<T> values) {
|
|
super(name, type);
|
|
this.values = ImmutableSet.copyOf(values);
|
|
@@ -28,6 +37,14 @@ public class EnumProperty<T extends Enum<T> & StringRepresentable> extends Prope
|
|
this.names.put(string, enum_);
|
|
}
|
|
|
|
+ // Paper start - optimise iblockdata state lookup
|
|
+ int id = 0;
|
|
+ this.idLookupTable = new int[type.getEnumConstants().length];
|
|
+ java.util.Arrays.fill(this.idLookupTable, -1);
|
|
+ for (final T value : this.getPossibleValues()) {
|
|
+ this.idLookupTable[value.ordinal()] = id++;
|
|
+ }
|
|
+ // Paper end - optimise iblockdata state lookup
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java
|
|
index bdbe0362e49e73c05237f9f3143230e0b03e494e..8eb20ea852a8e89c431fea55a7b60833a6c8104f 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java
|
|
@@ -11,6 +11,16 @@ public class IntegerProperty extends Property<Integer> {
|
|
public final int min;
|
|
public final int max;
|
|
|
|
+ // Paper start - optimise iblockdata state lookup
|
|
+ @Override
|
|
+ public final int getIdFor(final Integer value) {
|
|
+ final int val = value.intValue();
|
|
+ final int ret = val - this.min;
|
|
+
|
|
+ return ret | ((this.max - ret) >> 31);
|
|
+ }
|
|
+ // Paper end - optimise iblockdata state lookup
|
|
+
|
|
protected IntegerProperty(String name, int min, int max) {
|
|
super(name, Integer.class);
|
|
if (min < 0) {
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java
|
|
index 66b8e23d799adaf872233ea44c54330d75135544..9d4faa3da8d62028074ce25f4a728e9ba5281428 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java
|
|
@@ -24,6 +24,17 @@ public abstract class Property<T extends Comparable<T>> {
|
|
}, this::getName);
|
|
private final Codec<Property.Value<T>> valueCodec = this.codec.xmap(this::value, Property.Value::value);
|
|
|
|
+ // Paper start - optimise iblockdata state lookup
|
|
+ private static final java.util.concurrent.atomic.AtomicInteger ID_GENERATOR = new java.util.concurrent.atomic.AtomicInteger();
|
|
+ private final int id = ID_GENERATOR.getAndIncrement();
|
|
+
|
|
+ public final int getId() {
|
|
+ return this.id;
|
|
+ }
|
|
+
|
|
+ public abstract int getIdFor(final T value);
|
|
+ // Paper end - optimise state lookup
|
|
+
|
|
protected Property(String name, Class<T> type) {
|
|
this.clazz = type;
|
|
this.name = name;
|