mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-05 10:20:53 +01:00
bd38e0318a
Updated Upstream (Bukkit/CraftBukkit) 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: f02baa38 PR-988: Add World#getIntersectingChunks(BoundingBox) 9321d665 Move getItemInUse up to LivingEntity 819eef73 PR-959: Add access to current item's remaining ticks c4fdadb0 SPIGOT-7601: Add AbstractArrow#getItem be8261ca Add support for Java 22 26119676 PR-979: Add more translation keys 66753362 PR-985: Correct book maximum pages and characters per page documentation c8be92fa PR-980: Improve getArmorContents() documentation f1120ee2 PR-983: Expose riptide velocity to PlayerRiptideEvent CraftBukkit Changes: dfaa89bbe PR-1369: Add World#getIntersectingChunks(BoundingBox) 51bbab2b9 Move getItemInUse up to LivingEntity 668e09602 PR-1331: Add access to current item's remaining ticks a639406d1 SPIGOT-7601: Add AbstractArrow#getItem 0398930fc SPIGOT-7602: Allow opening in-world horse and related inventories ffd15611c SPIGOT-7608: Allow empty lists to morph to any PDT list 2188dcfa9 Add support for Java 22 45d6a609f SPIGOT-7604: Revert "SPIGOT-7365: DamageCause blocked by shield should trigger invulnerableTime" 06d915943 SPIGOT-7365: DamageCause blocked by shield should trigger invulnerableTime ca3bc3707 PR-1361: Add more translation keys 366c3ca80 SPIGOT-7600: EntityChangeBlockEvent is not fired for frog eggs 06d0f9ba8 SPIGOT-7593: Fix sapling growth physics / client-side updates 45c2608e4 PR-1366: Expose riptide velocity to PlayerRiptideEvent 29b6bb79b SPIGOT-7587: Remove fixes for now-resolved MC-142590 and MC-109346
344 lines
15 KiB
Diff
344 lines
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 8da64429eaf083578c672cd34f52dd42389ff396..bdd7d9c80eda872496272e46d8772634e44e622a 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 0a7a6c0e7635d0ada101074d4229df7edc6dd31b..e658d0b1a025192b48090e865b082ac4d99088d4 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 cbe6e4579cc55a427dd8f8fe403478faf6d35b8f..765b1092d50608d479bbbe09c457999790ecf42c 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 08c2e4ba9147fbea41e0fce26ad20586832a525b..1d8c3f2e57aa9b0830cf7cfb6354fcf636e9c74b 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;
|