294 lines
9.1 KiB
Java
294 lines
9.1 KiB
Java
![]() |
package kcauldron;
|
||
|
|
||
|
import java.util.HashSet;
|
||
|
import java.util.Iterator;
|
||
|
import java.util.NavigableSet;
|
||
|
import java.util.Set;
|
||
|
import java.util.TreeSet;
|
||
|
import java.util.concurrent.locks.ReadWriteLock;
|
||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||
|
|
||
|
import gnu.trove.iterator.TLongObjectIterator;
|
||
|
import gnu.trove.map.TLongObjectMap;
|
||
|
import gnu.trove.map.hash.TLongObjectHashMap;
|
||
|
import net.minecraft.block.Block;
|
||
|
import net.minecraft.world.NextTickListEntry;
|
||
|
import net.minecraft.world.WorldServer;
|
||
|
import net.minecraft.world.chunk.Chunk;
|
||
|
|
||
|
public final class BlockUpdatesTracker implements Iterable<BlockUpdateEntry> {
|
||
|
private long lastEntryId = Long.MIN_VALUE;
|
||
|
private final WorldServer world;
|
||
|
private final NavigableSet<BlockUpdateEntry> sortedTree = new TreeSet<BlockUpdateEntry>();
|
||
|
private final TLongObjectMap<BlockUpdateEntry> trackerMap = new TLongObjectHashMap<BlockUpdateEntry>();
|
||
|
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||
|
|
||
|
public BlockUpdatesTracker(WorldServer world) {
|
||
|
this.world = world;
|
||
|
}
|
||
|
|
||
|
public BlockUpdateEntry allocateEntry(int x, int y, int z, int priority, long time, Block block) {
|
||
|
return allocateEntry(x, y, z, priority, time, block, true);
|
||
|
}
|
||
|
|
||
|
public BlockUpdateEntry allocateEntry(int x, int y, int z, int priority, long time, Block block,
|
||
|
boolean allowChunkTracking) {
|
||
|
lock.writeLock().lock();
|
||
|
try {
|
||
|
Chunk chunk = allowChunkTracking ? world.getChunkIfLoaded(x >> 4, z >> 4) : null;
|
||
|
BlockUpdateEntry entry = new BlockUpdateEntry(x, y, z, priority, time, block, lastEntryId++);
|
||
|
BlockUpdateEntry oldEntry = trackerMap.remove(entry.key);
|
||
|
if (oldEntry != null) {
|
||
|
sortedTree.remove(oldEntry);
|
||
|
if (chunk != null)
|
||
|
chunk.blockUpdates.remove(oldEntry);
|
||
|
}
|
||
|
trackerMap.put(entry.key, entry);
|
||
|
sortedTree.add(entry);
|
||
|
if (chunk != null)
|
||
|
chunk.blockUpdates.add(entry);
|
||
|
return entry;
|
||
|
} finally {
|
||
|
lock.writeLock().unlock();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public BlockUpdateEntry removeEntry(int x, int y, int z) {
|
||
|
return removeEntry(x, y, z, true);
|
||
|
}
|
||
|
|
||
|
public BlockUpdateEntry removeEntry(int x, int y, int z, boolean allowChunkTracking) {
|
||
|
lock.writeLock().lock();
|
||
|
try {
|
||
|
Chunk chunk = allowChunkTracking ? world.getChunkIfLoaded(x >> 4, z >> 4) : null;
|
||
|
BlockUpdateEntry entry = trackerMap.remove(new BlockCoords(x, y, z).key);
|
||
|
if (entry != null) {
|
||
|
sortedTree.remove(entry);
|
||
|
if (chunk != null)
|
||
|
chunk.blockUpdates.remove(entry);
|
||
|
}
|
||
|
return entry;
|
||
|
} finally {
|
||
|
lock.writeLock().unlock();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public BlockUpdateEntry removeEntry(BlockUpdateEntry entry, boolean allowChunkTracking) {
|
||
|
lock.writeLock().lock();
|
||
|
try {
|
||
|
Chunk chunk = allowChunkTracking ? world.getChunkIfLoaded(entry.x >> 4, entry.z >> 4) : null;
|
||
|
trackerMap.remove(entry.key);
|
||
|
if (entry != null) {
|
||
|
sortedTree.remove(entry);
|
||
|
if (chunk != null)
|
||
|
chunk.blockUpdates.remove(entry);
|
||
|
}
|
||
|
return entry;
|
||
|
} finally {
|
||
|
lock.writeLock().unlock();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public BlockUpdateEntry getEntry(int x, int y, int z) {
|
||
|
lock.readLock().lock();
|
||
|
try {
|
||
|
return trackerMap.get(new BlockCoords(x, y, z).key);
|
||
|
} finally {
|
||
|
lock.readLock().unlock();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public BlockUpdateEntry peek() {
|
||
|
lock.readLock().lock();
|
||
|
try {
|
||
|
return sortedTree.first();
|
||
|
} finally {
|
||
|
lock.readLock().unlock();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public boolean isEmpty() {
|
||
|
lock.readLock().lock();
|
||
|
try {
|
||
|
return trackerMap.isEmpty();
|
||
|
} finally {
|
||
|
lock.readLock().unlock();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int size() {
|
||
|
lock.readLock().lock();
|
||
|
try {
|
||
|
return trackerMap.size();
|
||
|
} finally {
|
||
|
lock.readLock().unlock();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public Iterator<BlockUpdateEntry> iterator() {
|
||
|
return new Iterator<BlockUpdateEntry>() {
|
||
|
private final Iterator<BlockUpdateEntry> iterator = sortedTree.iterator();;
|
||
|
private BlockUpdateEntry next;
|
||
|
|
||
|
@Override
|
||
|
public boolean hasNext() {
|
||
|
next = null;
|
||
|
return iterator.hasNext();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public BlockUpdateEntry next() {
|
||
|
return next = iterator.next();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void remove() {
|
||
|
if (next == null)
|
||
|
next();
|
||
|
if (next != null)
|
||
|
removeEntry(next, true);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
private final VanillaWrapper wrapper = new VanillaWrapper();
|
||
|
public final HashSet<NextTickListEntry> hashSet = new VanillaHashSetWrapper();
|
||
|
public final TreeSet<NextTickListEntry> treeSet = new VanillaTreeSetWrapper();
|
||
|
|
||
|
private final class VanillaWrapper {
|
||
|
private Set<NextTickListEntry> add = new HashSet<NextTickListEntry>();
|
||
|
private Set<NextTickListEntry> remove = new HashSet<NextTickListEntry>();
|
||
|
|
||
|
public boolean add(NextTickListEntry e) {
|
||
|
if (add.remove(e)) {
|
||
|
allocateEntry(e.xCoord, e.yCoord, e.zCoord, e.priority, e.scheduledTime, e.func_151351_a());
|
||
|
return true;
|
||
|
}
|
||
|
return add.add(e);
|
||
|
}
|
||
|
|
||
|
public boolean remove(NextTickListEntry e) {
|
||
|
if (remove.remove(e)) {
|
||
|
removeEntry(e.xCoord, e.yCoord, e.zCoord);
|
||
|
return true;
|
||
|
}
|
||
|
return remove.add(e);
|
||
|
}
|
||
|
|
||
|
public boolean contains(NextTickListEntry e, boolean allowInterscan) {
|
||
|
if (allowInterscan) {
|
||
|
if (add.contains(e))
|
||
|
return true;
|
||
|
if (remove.contains(e))
|
||
|
return false;
|
||
|
}
|
||
|
return getEntry(e.xCoord, e.yCoord, e.zCoord) != null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private final class VanillaHashSetWrapper extends HashSet<NextTickListEntry> {
|
||
|
@Override
|
||
|
public Iterator<NextTickListEntry> iterator() {
|
||
|
return new Iterator<NextTickListEntry>() {
|
||
|
private final TLongObjectIterator<BlockUpdateEntry> iterator = trackerMap.iterator();;
|
||
|
|
||
|
@Override
|
||
|
public boolean hasNext() {
|
||
|
return iterator.hasNext();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public NextTickListEntry next() {
|
||
|
iterator.advance();
|
||
|
return iterator.value().asMCEntry();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void remove() {
|
||
|
removeEntry(iterator.value(), true);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean add(NextTickListEntry e) {
|
||
|
return wrapper.add(e);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean remove(Object o) {
|
||
|
return wrapper.remove((NextTickListEntry) o);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean contains(Object o) {
|
||
|
return wrapper.contains((NextTickListEntry) o, true);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isEmpty() {
|
||
|
return BlockUpdatesTracker.this.sortedTree.isEmpty();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int size() {
|
||
|
return BlockUpdatesTracker.this.sortedTree.size();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private final class VanillaTreeSetWrapper extends TreeSet<NextTickListEntry> {
|
||
|
@Override
|
||
|
public Iterator<NextTickListEntry> iterator() {
|
||
|
return new Iterator<NextTickListEntry>() {
|
||
|
private final Iterator<BlockUpdateEntry> iterator = sortedTree.iterator();;
|
||
|
private BlockUpdateEntry next;
|
||
|
|
||
|
@Override
|
||
|
public boolean hasNext() {
|
||
|
next = null;
|
||
|
return iterator.hasNext();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public NextTickListEntry next() {
|
||
|
return (next = iterator.next()).asMCEntry();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void remove() {
|
||
|
if (next == null)
|
||
|
next();
|
||
|
if (next != null)
|
||
|
removeEntry(next, true);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean add(NextTickListEntry e) {
|
||
|
return wrapper.add(e);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean remove(Object o) {
|
||
|
return wrapper.remove((NextTickListEntry) o);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean contains(Object o) {
|
||
|
return wrapper.contains((NextTickListEntry) o, false);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isEmpty() {
|
||
|
return BlockUpdatesTracker.this.sortedTree.isEmpty();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int size() {
|
||
|
return BlockUpdatesTracker.this.sortedTree.size();
|
||
|
}
|
||
|
}
|
||
|
}
|