diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java index 814886efa9..9aa5217452 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Map; import java.util.Random; import org.bukkit.Bukkit; // CraftBukkit +import org.bukkit.craftbukkit.util.UnsafeList; // CraftBukkit public class Chunk { @@ -53,7 +54,7 @@ public class Chunk { this.heightMap = new int[256]; for (int k = 0; k < this.entitySlices.length; ++k) { - this.entitySlices[k] = new ArrayList(); + this.entitySlices[k] = new UnsafeList(); // CraftBukkit - use UnsafeList } Arrays.fill(this.b, -999); @@ -697,10 +698,10 @@ public class Chunk { } for (int k = i; k <= j; ++k) { - List list1 = this.entitySlices[k]; + UnsafeList list1 = (UnsafeList) this.entitySlices[k]; // CraftBukkit - use UnsafeList for (int l = 0; l < list1.size(); ++l) { - Entity entity1 = (Entity) list1.get(l); + Entity entity1 = (Entity) list1.unsafeGet(l); // CraftBukkit - use unsafeGet if (entity1 != entity && entity1.boundingBox.a(axisalignedbb)) { list.add(entity1); @@ -736,10 +737,10 @@ public class Chunk { } for (int k = i; k <= j; ++k) { - List list1 = this.entitySlices[k]; + UnsafeList list1 = (UnsafeList) this.entitySlices[k]; // CraftBukkit - use UnsafeList for (int l = 0; l < list1.size(); ++l) { - Entity entity = (Entity) list1.get(l); + Entity entity = (Entity) list1.unsafeGet(l); // CraftBukkit - use unsafeGet if (oclass.isAssignableFrom(entity.getClass()) && entity.boundingBox.a(axisalignedbb)) { list.add(entity); diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java index 1f19227588..83933467ce 100644 --- a/src/main/java/net/minecraft/server/EntityLiving.java +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -1095,22 +1095,22 @@ public abstract class EntityLiving extends Entity { d1 += 1.0D; this.setPosition(d0, d1, d2); } - //List list = this.world.getCubes(this, this.boundingBox.shrink(0.03125D, 0.0D, 0.03125D)); + /*List list = this.world.getCubes(this, this.boundingBox.shrink(0.03125D, 0.0D, 0.03125D)); - //if (list.size() > 0) { - // double d4 = 0.0D; + if (list.size() > 0) { + double d4 = 0.0D; - // for (int i = 0; i < list.size(); ++i) { - // AxisAlignedBB axisalignedbb = (AxisAlignedBB) list.get(i); + for (int i = 0; i < list.size(); ++i) { + AxisAlignedBB axisalignedbb = (AxisAlignedBB) list.get(i); - // if (axisalignedbb.e > d4) { - // d4 = axisalignedbb.e; - // } - // } + if (axisalignedbb.e > d4) { + d4 = axisalignedbb.e; + } + } - // d1 += d4 - this.boundingBox.b; - // this.setPosition(d0, d1, d2); - //} + d1 += d4 - this.boundingBox.b; + this.setPosition(d0, d1, d2); + }*/ // CraftBukkit end } @@ -1240,14 +1240,10 @@ public abstract class EntityLiving extends Entity { this.m.a(); //MethodProfiler.a(); // CraftBukkit - not in production code //MethodProfiler.a("targetSelector"); // CraftBukkit - not in production code - // CraftBukkit start - run goal selectors every other tick - if ((this.aV & 1) == 0) { - this.targetSelector.a(); + this.targetSelector.a(); //MethodProfiler.a(); // CraftBukkit - not in production code //MethodProfiler.a("goalSelector"); // CraftBukkit - not in production code - this.goalSelector.a(); - } - // CraftBukkit end + this.goalSelector.a(); //MethodProfiler.a(); // CraftBukkit - not in production code //MethodProfiler.a("navigation"); // CraftBukkit - not in production code this.navigation.d(); diff --git a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java index 054777c412..90350e29f0 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java @@ -2,12 +2,15 @@ package net.minecraft.server; import java.util.ArrayList; import java.util.Iterator; +import org.bukkit.craftbukkit.util.UnsafeList; // CraftBukkit public class PathfinderGoalSelector { - private ArrayList a = new ArrayList(); - private ArrayList b = new ArrayList(); - private ArrayList arraylist = new ArrayList(); // CraftBukkit - create list for object reuse + // CraftBukkit start - use UnsafeList, add boolean for picking goals + private UnsafeList a = new UnsafeList(16); + private UnsafeList b = new UnsafeList(16); + boolean oddCall = true; + // CraftBukkit end public PathfinderGoalSelector() {} @@ -16,12 +19,12 @@ public class PathfinderGoalSelector { } public void a() { - //ArrayList arraylist = new ArrayList(); // CraftBukkit - arraylist.clear(); // CraftBukkit - prepare reused list + //ArrayList arraylist = new ArrayList(); // CraftBukkit - removed usage - // CraftBukkit start - don't use iterators for private fields + // CraftBukkit start - don't use iterators for private fields, only run every other call + if (oddCall) { for (int i = 0; i < this.a.size(); i++) { - PathfinderGoalSelectorItem pathfindergoalselectoritem = (PathfinderGoalSelectorItem) this.a.get(i); + PathfinderGoalSelectorItem pathfindergoalselectoritem = (PathfinderGoalSelectorItem) this.a.unsafeGet(i); // CraftBukkit - use unsafeGet boolean flag = this.b.contains(pathfindergoalselectoritem); if (flag) { @@ -34,36 +37,44 @@ public class PathfinderGoalSelector { } if (this.a(pathfindergoalselectoritem) && pathfindergoalselectoritem.a.a()) { - arraylist.add(pathfindergoalselectoritem); + // CraftBukkit start - call method now + // arraylist.add(pathfindergoalselectoritem); + pathfindergoalselectoritem.a.c(); + // CraftBukkit end this.b.add(pathfindergoalselectoritem); } } + } + oddCall = !oddCall; // CraftBukkit end boolean flag1 = false; - if (flag1 && arraylist.size() > 0) { + // CraftBukkit start - removed usage of arraylist + /*if (flag1 && arraylist.size() > 0) { System.out.println("Starting: "); - } + }*/ + // CraftBukkit end Iterator iterator1; PathfinderGoalSelectorItem pathfindergoalselectoritem1; - //CraftBukkit start - don't use iterators for private fields - for (int i = 0; i < arraylist.size(); i++) { - pathfindergoalselectoritem1 = (PathfinderGoalSelectorItem) arraylist.get(i); - pathfindergoalselectoritem1.a.c(); + // CraftBukkit start - removed usage of arraylist + /*for (iterator1 = arraylist.iterator(); iterator1.hasNext(); pathfindergoalselectoritem1.a.c()) { + pathfindergoalselectoritem1 = (PathfinderGoalSelectorItem) iterator1.next(); if (flag1) { System.out.println(pathfindergoalselectoritem1.a.toString() + ", "); } - } + }*/ + // CraftBukkit end if (flag1 && this.b.size() > 0) { System.out.println("Running: "); } + // CraftBukkit start - don't use iterators for private fields for (int i = 0; i < this.b.size(); i++) { - pathfindergoalselectoritem1 = (PathfinderGoalSelectorItem) this.b.get(i); + pathfindergoalselectoritem1 = (PathfinderGoalSelectorItem) this.b.unsafeGet(i); // CraftBukkit - use unsafeGet pathfindergoalselectoritem1.a.e(); if (flag1) { System.out.println(pathfindergoalselectoritem1.a.toString()); @@ -75,14 +86,14 @@ public class PathfinderGoalSelector { private boolean a(PathfinderGoalSelectorItem pathfindergoalselectoritem) { // CraftBukkit start - don't use iterators for private fields for (int i = 0; i < this.a.size(); i++) { - PathfinderGoalSelectorItem pathfindergoalselectoritem1 = (PathfinderGoalSelectorItem) this.a.get(i); + PathfinderGoalSelectorItem pathfindergoalselectoritem1 = (PathfinderGoalSelectorItem) this.a.unsafeGet(i); // CraftBukkit - use unsafeGet if (pathfindergoalselectoritem1 != pathfindergoalselectoritem) { if (pathfindergoalselectoritem.b >= pathfindergoalselectoritem1.b) { - if (this.b.contains(pathfindergoalselectoritem1) && !this.a(pathfindergoalselectoritem, pathfindergoalselectoritem1)) { + if (!this.a(pathfindergoalselectoritem, pathfindergoalselectoritem1) && this.b.contains(pathfindergoalselectoritem1)) { // CraftBukkit - switch order return false; } - } else if (this.b.contains(pathfindergoalselectoritem1) && !pathfindergoalselectoritem1.a.g()) { + } else if (!pathfindergoalselectoritem1.a.g() && this.b.contains(pathfindergoalselectoritem1)) { // CraftBukkit - switch order return false; } } diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java index b5879e8269..3d7cdfc9a1 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -20,6 +20,7 @@ import org.bukkit.generator.ChunkGenerator; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.craftbukkit.util.UnsafeList; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockFormEvent; @@ -40,7 +41,7 @@ public class World implements IBlockAccess { private List J = new ArrayList(); private List K = new ArrayList(); public List players = new ArrayList(); - public List e = new ArrayList(); + public UnsafeList e = new UnsafeList(); // CraftBukkit - use UnsafeList private long L = 16777215L; public int f = 0; protected int g = (new Random()).nextInt(); @@ -1104,7 +1105,7 @@ public class World implements IBlockAccess { Entity entity; for (i = 0; i < this.e.size(); ++i) { - entity = (Entity) this.e.get(i); + entity = (Entity) this.e.unsafeGet(i); // CraftBukkit - use unsafeGet // CraftBukkit start - fixed an NPE if (entity == null) { continue; diff --git a/src/main/java/org/bukkit/craftbukkit/util/UnsafeList.java b/src/main/java/org/bukkit/craftbukkit/util/UnsafeList.java new file mode 100644 index 0000000000..f23801e45b --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/UnsafeList.java @@ -0,0 +1,154 @@ +package org.bukkit.craftbukkit.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.AbstractList; +import java.util.Arrays; +import java.util.List; +import java.util.RandomAccess; + +// implementation of an ArrayList that offers a getter without range checks +public class UnsafeList extends AbstractList implements List, RandomAccess, Cloneable, Serializable { + private static final long serialVersionUID = 8683452581112892189L; + private transient Object[] data; + private int size; + + public UnsafeList(int capacity) { + super(); + if (capacity < 0) capacity = 128; + int rounded = Integer.highestOneBit(capacity - 1) << 1; + data = new Object[rounded]; + } + + public UnsafeList() { + this(128); + } + + public E get(int index) { + rangeCheck(index); + + return (E) data[index]; + } + + public E unsafeGet(int index) { + return (E) data[index]; + } + + public E set(int index, E element) { + rangeCheck(index); + + E old = (E) data[index]; + data[index] = element; + return old; + } + + public boolean add(E element) { + growIfNeeded(); + data[size++] = element; + return true; + } + + public void add(int index, E element) { + growIfNeeded(); + System.arraycopy(data, index, data, index + 1, size - index); + data[index] = element; + size++; + } + + public E remove(int index) { + rangeCheck(index); + + E old = (E) data[index]; + int movedCount = size - index - 1; + if (movedCount > 0) { + System.arraycopy(data, index + 1, data, index, movedCount); + } + data[--size] = null; + + return old; + } + + public boolean remove(Object o) { + int index = indexOf(o); + if (index >= 0) { + remove(index); + return true; + } + + return false; + } + + public int indexOf(Object o) { + for (int i = 0; i < size; i++) { + if (o == data[i] || o.equals(data[i])) { + return i; + } + } + + return -1; + } + + public boolean contains(Object o) { + return indexOf(o) >= 0; + } + + public void clear() { + for (int i = 0; i < size; i++) { + data[i] = null; + } + + size = 0; + } + + // actually rounds up to nearest power of two + public void trimToSize() { + int old = data.length; + int rounded = Integer.highestOneBit(size - 1) << 1; + if (rounded < old) { + data = Arrays.copyOf(data, rounded); + } + } + + public int size() { + return size; + } + + public boolean isEmpty() { + return size != 0; + } + + private void rangeCheck(int index) { + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + } + + private void growIfNeeded() { + if (size == data.length) { + Object[] newData = new Object[data.length << 1]; + System.arraycopy(data, 0, newData, 0, size); + data = newData; + } + } + + private void writeObject(ObjectOutputStream os) throws IOException { + os.defaultWriteObject(); + + os.writeInt(size); + for (int i = 0; i < size; i++) { + os.writeObject(data[i]); + } + } + + private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { + is.defaultReadObject(); + + size = is.readInt(); + data = new Object[Integer.highestOneBit(size - 1) << 1]; + for (int i = 0; i < size; i++) { + data[i] = is.readObject(); + } + } +}