Optimize BlockStateList/BlockData

Mojang included some sanity checks on arguments passed to the BlockData.
This code results in the Hash look up occuring twice per call, one to test if it exists
and another to retrieve the result.

This code should ideally never be hit, unless mojang released a bad build. We can discover bugs with this as furthur code that never expects a null
would then NPE, so it would not result in hidden issues.

This is super hot code, so removing those checks should give decent gains.
This commit is contained in:
Aikar 2016-03-18 19:25:43 -04:00
parent e546c55b6e
commit c51bf9d9f3
2 changed files with 378 additions and 2 deletions

View file

@ -1,4 +1,4 @@
From 93c3ea89eb16b2069bf0f078276f208780ea2920 Mon Sep 17 00:00:00 2001
From 620e9058fe63c0f5eff7f4a44e168979a856af22 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Mon, 29 Feb 2016 21:09:10 -0600
Subject: [PATCH] mc-dev imports
@ -1986,6 +1986,337 @@ index 0000000..e7a95f3
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/server/BlockStateList.java b/src/main/java/net/minecraft/server/BlockStateList.java
new file mode 100644
index 0000000..a11c62f
--- /dev/null
+++ b/src/main/java/net/minecraft/server/BlockStateList.java
@@ -0,0 +1,325 @@
+package net.minecraft.server;
+
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+public class BlockStateList {
+
+ private static final Pattern a = Pattern.compile("^[a-z0-9_]+$");
+ private static final Function<IBlockState<?>, String> b = new Function() {
+ public String a(IBlockState<?> iblockstate) {
+ return iblockstate == null ? "<NULL>" : iblockstate.a();
+ }
+
+ public Object apply(Object object) {
+ return this.a((IBlockState) object);
+ }
+ };
+ private final Block c;
+ private final ImmutableSortedMap<String, IBlockState<?>> d;
+ private final ImmutableList<IBlockData> e;
+
+ public BlockStateList(Block block, IBlockState<?>... aiblockstate) {
+ this.c = block;
+ HashMap hashmap = Maps.newHashMap();
+ IBlockState[] aiblockstate1 = aiblockstate;
+ int i = aiblockstate.length;
+
+ for (int j = 0; j < i; ++j) {
+ IBlockState iblockstate = aiblockstate1[j];
+
+ a(block, iblockstate);
+ hashmap.put(iblockstate.a(), iblockstate);
+ }
+
+ this.d = ImmutableSortedMap.copyOf(hashmap);
+ LinkedHashMap linkedhashmap = Maps.newLinkedHashMap();
+ ArrayList arraylist = Lists.newArrayList();
+ Iterable iterable = IteratorUtils.a(this.e());
+ Iterator iterator = iterable.iterator();
+
+ while (iterator.hasNext()) {
+ List list = (List) iterator.next();
+ Map map = MapGeneratorUtils.b(this.d.values(), list);
+ BlockStateList.BlockData blockstatelist_blockdata = new BlockStateList.BlockData(block, ImmutableMap.copyOf(map), null);
+
+ linkedhashmap.put(map, blockstatelist_blockdata);
+ arraylist.add(blockstatelist_blockdata);
+ }
+
+ iterator = arraylist.iterator();
+
+ while (iterator.hasNext()) {
+ BlockStateList.BlockData blockstatelist_blockdata1 = (BlockStateList.BlockData) iterator.next();
+
+ blockstatelist_blockdata1.a((Map) linkedhashmap);
+ }
+
+ this.e = ImmutableList.copyOf(arraylist);
+ }
+
+ public static <T extends Comparable<T>> String a(Block block, IBlockState<T> iblockstate) {
+ String s = iblockstate.a();
+
+ if (!BlockStateList.a.matcher(s).matches()) {
+ throw new IllegalArgumentException("Block: " + block.getClass() + " has invalidly named property: " + s);
+ } else {
+ for (T t : iblockstate.c()) {
+ String s1 = iblockstate.a(t);
+
+ if (!a.matcher(s1).matches())
+ {
+ throw new IllegalArgumentException("Block: " + block.getClass() + " has property: " + s + " with invalidly named value: " + s1);
+ }
+ }
+ }
+ return s;
+ }
+
+ public ImmutableList<IBlockData> a() {
+ return this.e;
+ }
+
+ private List<Iterable<Comparable<?>>> e() {
+ ArrayList arraylist = Lists.newArrayList();
+ ImmutableCollection immutablecollection = this.d.values();
+ Iterator iterator = immutablecollection.iterator();
+
+ while (iterator.hasNext()) {
+ IBlockState iblockstate = (IBlockState) iterator.next();
+
+ arraylist.add(iblockstate.c());
+ }
+
+ return arraylist;
+ }
+
+ public IBlockData getBlockData() {
+ return (IBlockData) this.e.get(0);
+ }
+
+ public Block getBlock() {
+ return this.c;
+ }
+
+ public Collection<IBlockState<?>> d() {
+ return this.d.values();
+ }
+
+ public String toString() {
+ return Objects.toStringHelper(this).add("block", Block.REGISTRY.b(this.c)).add("properties", Iterables.transform(this.d.values(), BlockStateList.b)).toString();
+ }
+
+ static class BlockData extends BlockDataAbstract {
+
+ private final Block a;
+ private final ImmutableMap<IBlockState<?>, Comparable<?>> b;
+ private ImmutableTable<IBlockState<?>, Comparable<?>, IBlockData> c;
+
+ private BlockData(Block block, ImmutableMap<IBlockState<?>, Comparable<?>> immutablemap) {
+ this.a = block;
+ this.b = immutablemap;
+ }
+
+ public Collection<IBlockState<?>> r() {
+ return Collections.unmodifiableCollection(this.b.keySet());
+ }
+
+ public <T extends Comparable<T>> T get(IBlockState<T> iblockstate) {
+ if (!this.b.containsKey(iblockstate)) {
+ throw new IllegalArgumentException("Cannot get property " + iblockstate + " as it does not exist in " + this.a.t());
+ } else {
+ return iblockstate.b().cast(this.b.get(iblockstate));
+ }
+ }
+
+ public <T extends Comparable<T>, V extends T> IBlockData set(IBlockState<T> iblockstate, V v0) {
+ if (!this.b.containsKey(iblockstate)) {
+ throw new IllegalArgumentException("Cannot set property " + iblockstate + " as it does not exist in " + this.a.t());
+ } else if (!iblockstate.c().contains(v0)) {
+ throw new IllegalArgumentException("Cannot set property " + iblockstate + " to " + v0 + " on block " + Block.REGISTRY.b(this.a) + ", it is not an allowed value");
+ } else {
+ return (IBlockData) (this.b.get(iblockstate) == v0 ? this : (IBlockData) this.c.get(iblockstate, v0));
+ }
+ }
+
+ public ImmutableMap<IBlockState<?>, Comparable<?>> s() {
+ return this.b;
+ }
+
+ public Block getBlock() {
+ return this.a;
+ }
+
+ public boolean equals(Object object) {
+ return this == object;
+ }
+
+ public int hashCode() {
+ return this.b.hashCode();
+ }
+
+ public void a(Map<Map<IBlockState<?>, Comparable<?>>, BlockStateList.BlockData> map) {
+ if (this.c != null) {
+ throw new IllegalStateException();
+ } else {
+ HashBasedTable hashbasedtable = HashBasedTable.create();
+ Iterator iterator = this.b.entrySet().iterator();
+
+ while (iterator.hasNext()) {
+ Entry entry = (Entry) iterator.next();
+ IBlockState iblockstate = (IBlockState) entry.getKey();
+ Iterator iterator1 = iblockstate.c().iterator();
+
+ while (iterator1.hasNext()) {
+ Comparable comparable = (Comparable) iterator1.next();
+
+ if (comparable != entry.getValue()) {
+ hashbasedtable.put(iblockstate, comparable, map.get(this.b(iblockstate, comparable)));
+ }
+ }
+ }
+
+ this.c = ImmutableTable.copyOf(hashbasedtable);
+ }
+ }
+
+ private Map<IBlockState<?>, Comparable<?>> b(IBlockState<?> iblockstate, Comparable<?> comparable) {
+ HashMap hashmap = Maps.newHashMap(this.b);
+
+ hashmap.put(iblockstate, comparable);
+ return hashmap;
+ }
+
+ public Material getMaterial() {
+ return this.a.q(this);
+ }
+
+ public boolean b() {
+ return this.a.l(this);
+ }
+
+ public int c() {
+ return this.a.m(this);
+ }
+
+ public int d() {
+ return this.a.o(this);
+ }
+
+ public boolean f() {
+ return this.a.p(this);
+ }
+
+ public MaterialMapColor g() {
+ return this.a.r(this);
+ }
+
+ public IBlockData a(EnumBlockRotation enumblockrotation) {
+ return this.a.a((IBlockData) this, enumblockrotation);
+ }
+
+ public IBlockData a(EnumBlockMirror enumblockmirror) {
+ return this.a.a((IBlockData) this, enumblockmirror);
+ }
+
+ public boolean h() {
+ return this.a.c((IBlockData) this);
+ }
+
+ public EnumRenderType i() {
+ return this.a.a((IBlockData) this);
+ }
+
+ public boolean k() {
+ return this.a.s(this);
+ }
+
+ public boolean l() {
+ return this.a.isOccluding(this);
+ }
+
+ public boolean m() {
+ return this.a.isPowerSource(this);
+ }
+
+ public int a(IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
+ return this.a.b((IBlockData) this, iblockaccess, blockposition, enumdirection);
+ }
+
+ public boolean n() {
+ return this.a.isComplexRedstone(this);
+ }
+
+ public int a(World world, BlockPosition blockposition) {
+ return this.a.d(this, world, blockposition);
+ }
+
+ public float b(World world, BlockPosition blockposition) {
+ return this.a.b(this, world, blockposition);
+ }
+
+ public float a(EntityHuman entityhuman, World world, BlockPosition blockposition) {
+ return this.a.getDamage(this, entityhuman, world, blockposition);
+ }
+
+ public int b(IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
+ return this.a.c(this, iblockaccess, blockposition, enumdirection);
+ }
+
+ public EnumPistonReaction o() {
+ return this.a.h(this);
+ }
+
+ public IBlockData b(IBlockAccess iblockaccess, BlockPosition blockposition) {
+ return this.a.updateState(this, iblockaccess, blockposition);
+ }
+
+ public boolean p() {
+ return this.a.b((IBlockData) this);
+ }
+
+ public AxisAlignedBB d(World world, BlockPosition blockposition) {
+ return this.a.a((IBlockData) this, world, blockposition);
+ }
+
+ public void a(World world, BlockPosition blockposition, AxisAlignedBB axisalignedbb, List<AxisAlignedBB> list, Entity entity) {
+ this.a.a((IBlockData) this, world, blockposition, axisalignedbb, list, entity);
+ }
+
+ public AxisAlignedBB c(IBlockAccess iblockaccess, BlockPosition blockposition) {
+ return this.a.a((IBlockData) this, iblockaccess, blockposition);
+ }
+
+ public MovingObjectPosition a(World world, BlockPosition blockposition, Vec3D vec3d, Vec3D vec3d1) {
+ return this.a.a(this, world, blockposition, vec3d, vec3d1);
+ }
+
+ public boolean q() {
+ return this.a.k(this);
+ }
+
+ BlockData(Block block, ImmutableMap immutablemap, Object object) {
+ this(block, immutablemap);
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/server/ChunkProviderFlat.java b/src/main/java/net/minecraft/server/ChunkProviderFlat.java
new file mode 100644
index 0000000..17e0b8e
@ -5158,5 +5489,5 @@ index 0000000..2286c9e
+ }
+}
--
2.7.3
2.7.4

View file

@ -0,0 +1,45 @@
From 23c5437c07a1bf673509fc5f20aed2117defe615 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Mar 2016 19:15:44 -0400
Subject: [PATCH] Optimize BlockStateList/BlockData
Mojang included some sanity checks on arguments passed to the BlockData.
This code results in the Hash look up occuring twice per call, one to test if it exists
and another to retrieve the result.
This code should ideally never be hit, unless mojang released a bad build. We can discover bugs with this as furthur code that never expects a null
would then NPE, so it would not result in hidden issues.
This is super hot code, so removing those checks should give decent gains.
diff --git a/src/main/java/net/minecraft/server/BlockStateList.java b/src/main/java/net/minecraft/server/BlockStateList.java
index a11c62f..43f198b 100644
--- a/src/main/java/net/minecraft/server/BlockStateList.java
+++ b/src/main/java/net/minecraft/server/BlockStateList.java
@@ -145,21 +145,11 @@ public class BlockStateList {
}
public <T extends Comparable<T>> T get(IBlockState<T> iblockstate) {
- if (!this.b.containsKey(iblockstate)) {
- throw new IllegalArgumentException("Cannot get property " + iblockstate + " as it does not exist in " + this.a.t());
- } else {
- return iblockstate.b().cast(this.b.get(iblockstate));
- }
+ return iblockstate.b().cast(this.b.get(iblockstate)); // Paper
}
public <T extends Comparable<T>, V extends T> IBlockData set(IBlockState<T> iblockstate, V v0) {
- if (!this.b.containsKey(iblockstate)) {
- throw new IllegalArgumentException("Cannot set property " + iblockstate + " as it does not exist in " + this.a.t());
- } else if (!iblockstate.c().contains(v0)) {
- throw new IllegalArgumentException("Cannot set property " + iblockstate + " to " + v0 + " on block " + Block.REGISTRY.b(this.a) + ", it is not an allowed value");
- } else {
- return (IBlockData) (this.b.get(iblockstate) == v0 ? this : (IBlockData) this.c.get(iblockstate, v0));
- }
+ return this.b.get(iblockstate) == v0 ? this : this.c.get(iblockstate, v0); // Paper
}
public ImmutableMap<IBlockState<?>, Comparable<?>> s() {
--
2.7.4