Added ChunkMap and ChunkSet
This commit is contained in:
parent
f921acf317
commit
c6677ec8fd
@ -25,12 +25,13 @@ import glm.vec._3.i.Vec3i;
|
|||||||
import gnu.trove.impl.sync.TSynchronizedLongObjectMap;
|
import gnu.trove.impl.sync.TSynchronizedLongObjectMap;
|
||||||
import gnu.trove.map.TLongObjectMap;
|
import gnu.trove.map.TLongObjectMap;
|
||||||
import gnu.trove.map.hash.TLongObjectHashMap;
|
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||||
import gnu.trove.set.TLongSet;
|
|
||||||
import ru.windcorp.progressia.common.collision.CollisionModel;
|
import ru.windcorp.progressia.common.collision.CollisionModel;
|
||||||
import ru.windcorp.progressia.common.util.CoordinatePacker;
|
|
||||||
import ru.windcorp.progressia.common.world.block.BlockData;
|
import ru.windcorp.progressia.common.world.block.BlockData;
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||||
|
import ru.windcorp.progressia.common.world.generic.ChunkMap;
|
||||||
|
import ru.windcorp.progressia.common.world.generic.ChunkSet;
|
||||||
import ru.windcorp.progressia.common.world.generic.GenericWorld;
|
import ru.windcorp.progressia.common.world.generic.GenericWorld;
|
||||||
|
import ru.windcorp.progressia.common.world.generic.LongBasedChunkMap;
|
||||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||||
import ru.windcorp.progressia.common.world.tile.TileDataStack;
|
import ru.windcorp.progressia.common.world.tile.TileDataStack;
|
||||||
import ru.windcorp.progressia.test.TestContent;
|
import ru.windcorp.progressia.test.TestContent;
|
||||||
@ -44,11 +45,12 @@ implements GenericWorld<
|
|||||||
EntityData
|
EntityData
|
||||||
>{
|
>{
|
||||||
|
|
||||||
private final TLongObjectMap<ChunkData> chunksByPos =
|
private final ChunkMap<ChunkData> chunksByPos = new LongBasedChunkMap<>(
|
||||||
new TSynchronizedLongObjectMap<>(new TLongObjectHashMap<>(), this);
|
new TSynchronizedLongObjectMap<>(new TLongObjectHashMap<>(), this)
|
||||||
|
);
|
||||||
|
|
||||||
private final Collection<ChunkData> chunks =
|
private final Collection<ChunkData> chunks =
|
||||||
Collections.unmodifiableCollection(chunksByPos.valueCollection());
|
Collections.unmodifiableCollection(chunksByPos.values());
|
||||||
|
|
||||||
private final TLongObjectMap<EntityData> entitiesById =
|
private final TLongObjectMap<EntityData> entitiesById =
|
||||||
new TSynchronizedLongObjectMap<>(new TLongObjectHashMap<>(), this);
|
new TSynchronizedLongObjectMap<>(new TLongObjectHashMap<>(), this);
|
||||||
@ -67,7 +69,7 @@ implements GenericWorld<
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChunkData getChunk(Vec3i pos) {
|
public ChunkData getChunk(Vec3i pos) {
|
||||||
return chunksByPos.get(CoordinatePacker.pack3IntsIntoLong(pos));
|
return chunksByPos.get(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -75,6 +77,10 @@ implements GenericWorld<
|
|||||||
return chunks;
|
return chunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ChunkSet getLoadedChunks() {
|
||||||
|
return chunksByPos.keys();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<EntityData> getEntities() {
|
public Collection<EntityData> getEntities() {
|
||||||
return entities;
|
return entities;
|
||||||
@ -102,9 +108,7 @@ implements GenericWorld<
|
|||||||
public synchronized void addChunk(ChunkData chunk) {
|
public synchronized void addChunk(ChunkData chunk) {
|
||||||
addChunkListeners(chunk);
|
addChunkListeners(chunk);
|
||||||
|
|
||||||
long key = getChunkKey(chunk);
|
ChunkData previous = chunksByPos.get(chunk);
|
||||||
|
|
||||||
ChunkData previous = chunksByPos.get(key);
|
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
throw new IllegalArgumentException(String.format(
|
throw new IllegalArgumentException(String.format(
|
||||||
"Chunk at (%d; %d; %d) already exists",
|
"Chunk at (%d; %d; %d) already exists",
|
||||||
@ -112,7 +116,7 @@ implements GenericWorld<
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
chunksByPos.put(key, chunk);
|
chunksByPos.put(chunk, chunk);
|
||||||
|
|
||||||
chunk.forEachEntity(entity ->
|
chunk.forEachEntity(entity ->
|
||||||
entitiesById.put(entity.getEntityId(), entity)
|
entitiesById.put(entity.getEntityId(), entity)
|
||||||
@ -130,11 +134,7 @@ implements GenericWorld<
|
|||||||
entitiesById.remove(entity.getEntityId())
|
entitiesById.remove(entity.getEntityId())
|
||||||
);
|
);
|
||||||
|
|
||||||
chunksByPos.remove(getChunkKey(chunk));
|
chunksByPos.remove(chunk);
|
||||||
}
|
|
||||||
|
|
||||||
private static long getChunkKey(ChunkData chunk) {
|
|
||||||
return CoordinatePacker.pack3IntsIntoLong(chunk.getPosition());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) {
|
public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) {
|
||||||
@ -149,10 +149,6 @@ implements GenericWorld<
|
|||||||
chunk.setBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null), block, notify);
|
chunk.setBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null), block, notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TLongSet getChunkKeys() {
|
|
||||||
return chunksByPos.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityData getEntity(long entityId) {
|
public EntityData getEntity(long entityId) {
|
||||||
return entitiesById.get(entityId);
|
return entitiesById.get(entityId);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
package ru.windcorp.progressia.common.world.generic;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.BiPredicate;
|
||||||
|
import glm.vec._3.i.Vec3i;
|
||||||
|
|
||||||
|
public interface ChunkMap<V> {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size
|
||||||
|
*/
|
||||||
|
|
||||||
|
int size();
|
||||||
|
|
||||||
|
default boolean isEmpty() {
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
boolean containsKey(Vec3i pos);
|
||||||
|
|
||||||
|
V get(Vec3i pos);
|
||||||
|
V put(Vec3i pos, V obj);
|
||||||
|
V remove(Vec3i pos);
|
||||||
|
|
||||||
|
default boolean containsValue(V value) {
|
||||||
|
return values().contains(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
default V getOrDefault(Vec3i pos, V def) {
|
||||||
|
return containsKey(pos) ? def : get(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
default V compute(Vec3i pos, BiFunction<? super Vec3i, ? super V, ? extends V> remappingFunction) {
|
||||||
|
V newValue = remappingFunction.apply(pos, get(pos));
|
||||||
|
|
||||||
|
if (newValue == null) {
|
||||||
|
remove(pos);
|
||||||
|
} else {
|
||||||
|
put(pos, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO implement ALL default methods from Map
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic operation wrappers
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO implement (int, int, int) and GenericChunk versions of all of the above
|
||||||
|
|
||||||
|
default boolean containsChunk(GenericChunk<?, ?, ?, ?> chunk) {
|
||||||
|
return containsKey(chunk.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
default V get(GenericChunk<?, ?, ?, ?> chunk) {
|
||||||
|
return get(chunk.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
default V put(GenericChunk<?, ?, ?, ?> chunk, V obj) {
|
||||||
|
return put(chunk.getPosition(), obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
default V remove(GenericChunk<?, ?, ?, ?> chunk) {
|
||||||
|
return remove(chunk.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
default V getOrDefault(GenericChunk<?, ?, ?, ?> chunk, V def) {
|
||||||
|
return containsChunk(chunk) ? def : get(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
default <C extends GenericChunk<C, ?, ?, ?>> V compute(C chunk, BiFunction<? super C, ? super V, ? extends V> remappingFunction) {
|
||||||
|
V newValue = remappingFunction.apply(chunk, get(chunk));
|
||||||
|
|
||||||
|
if (newValue == null) {
|
||||||
|
remove(chunk);
|
||||||
|
} else {
|
||||||
|
put(chunk, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Views
|
||||||
|
*/
|
||||||
|
|
||||||
|
Collection<V> values();
|
||||||
|
ChunkSet keys();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bulk operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
boolean removeIf(BiPredicate<? super Vec3i, ? super V> condition);
|
||||||
|
void forEach(BiConsumer<? super Vec3i, ? super V> action);
|
||||||
|
|
||||||
|
default <C extends GenericChunk<C, ?, ?, ?>> void forEachIn(GenericWorld<?, ?, ?, C, ?> world, BiConsumer<? super C, ? super V> action) {
|
||||||
|
forEach((pos, value) -> {
|
||||||
|
C chunk = world.getChunk(pos);
|
||||||
|
if (chunk == null) return;
|
||||||
|
action.accept(chunk, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,212 @@
|
|||||||
|
package ru.windcorp.progressia.common.world.generic;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import glm.vec._3.i.Vec3i;
|
||||||
|
import gnu.trove.set.hash.TLongHashSet;
|
||||||
|
import ru.windcorp.progressia.common.util.Vectors;
|
||||||
|
|
||||||
|
public interface ChunkSet extends Iterable<Vec3i> {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size
|
||||||
|
*/
|
||||||
|
|
||||||
|
int size();
|
||||||
|
|
||||||
|
default boolean isEmpty() {
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
boolean contains(Vec3i pos);
|
||||||
|
boolean add(Vec3i pos);
|
||||||
|
boolean remove(Vec3i pos);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic operation wrappers
|
||||||
|
*/
|
||||||
|
|
||||||
|
default boolean contains(int x, int y, int z) {
|
||||||
|
Vec3i v = Vectors.grab3i();
|
||||||
|
boolean result = contains(v);
|
||||||
|
Vectors.release(v);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean add(int x, int y, int z) {
|
||||||
|
Vec3i v = Vectors.grab3i();
|
||||||
|
boolean result = add(v);
|
||||||
|
Vectors.release(v);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean remove(int x, int y, int z) {
|
||||||
|
Vec3i v = Vectors.grab3i();
|
||||||
|
boolean result = remove(v);
|
||||||
|
Vectors.release(v);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean contains(GenericChunk<?, ?, ?, ?> chunk) {
|
||||||
|
return contains(chunk.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean add(GenericChunk<?, ?, ?, ?> chunk) {
|
||||||
|
return add(chunk.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean remove(GenericChunk<?, ?, ?, ?> chunk) {
|
||||||
|
return remove(chunk.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
default <C extends GenericChunk<C, ?, ?, ?>> void forEachIn(GenericWorld<?, ?, ?, C, ?> world, Consumer<? super C> action) {
|
||||||
|
forEach(position -> {
|
||||||
|
C chunk = world.getChunk(position);
|
||||||
|
if (chunk == null) return;
|
||||||
|
action.accept(chunk);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bulk operations on ChunkSets
|
||||||
|
*/
|
||||||
|
|
||||||
|
boolean containsAll(ChunkSet other);
|
||||||
|
boolean containsAny(ChunkSet other);
|
||||||
|
|
||||||
|
void addAll(ChunkSet other);
|
||||||
|
void removeAll(ChunkSet other);
|
||||||
|
void retainAll(ChunkSet other);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Other bulk operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
default boolean containsAll(Iterable<? extends Vec3i> other) {
|
||||||
|
boolean[] hasMissing = new boolean[] { false };
|
||||||
|
|
||||||
|
other.forEach(v -> {
|
||||||
|
if (!contains(v)) {
|
||||||
|
hasMissing[0] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return hasMissing[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean containsAny(Iterable<? extends Vec3i> other) {
|
||||||
|
boolean[] hasPresent = new boolean[] { false };
|
||||||
|
|
||||||
|
other.forEach(v -> {
|
||||||
|
if (contains(v)) {
|
||||||
|
hasPresent[0] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return hasPresent[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
default void addAll(Iterable<? extends Vec3i> other) {
|
||||||
|
other.forEach(this::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void removeAll(Iterable<? extends Vec3i> other) {
|
||||||
|
other.forEach(this::remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void retainAll(Iterable<? extends Vec3i> other) {
|
||||||
|
if (other instanceof ChunkSet) {
|
||||||
|
// We shouldn't invoke retainAll(ChunkSet) because we could be the fallback for it
|
||||||
|
removeIf(v -> !((ChunkSet) other).contains(v));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int threshold = 16; // Maximum size of other at which point creating a Set becomes faster than iterating
|
||||||
|
|
||||||
|
Collection<? extends Vec3i> collection = null;
|
||||||
|
int otherSize = -1;
|
||||||
|
|
||||||
|
if (other instanceof Set<?>) {
|
||||||
|
collection = (Set<? extends Vec3i>) other;
|
||||||
|
} else if (other instanceof Collection<?>) {
|
||||||
|
Collection<? extends Vec3i> otherAsCollection = ((Collection<? extends Vec3i>) other);
|
||||||
|
otherSize = otherAsCollection.size();
|
||||||
|
|
||||||
|
if (otherSize < threshold) {
|
||||||
|
collection = otherAsCollection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collection != null) {
|
||||||
|
final Collection<? extends Vec3i> c = collection;
|
||||||
|
removeIf(v -> !c.contains(v));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherSize < 0) {
|
||||||
|
otherSize = gnu.trove.impl.Constants.DEFAULT_CAPACITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
retainAll(new LongBasedChunkSet(new TLongHashSet(otherSize), other));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default void removeIf(Predicate<? super Vec3i> condition) {
|
||||||
|
for (Iterator<? extends Vec3i> it = iterator(); it.hasNext();) {
|
||||||
|
if (condition.test(it.next())) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default void retainIf(Predicate<? super Vec3i> condition) {
|
||||||
|
for (Iterator<? extends Vec3i> it = iterator(); it.hasNext();) {
|
||||||
|
if (!condition.test(it.next())) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean containsAllChunks(Iterable<? extends GenericChunk<?, ?, ?, ?>> chunks) {
|
||||||
|
boolean[] hasMissing = new boolean[] { false };
|
||||||
|
|
||||||
|
chunks.forEach(c -> {
|
||||||
|
if (!contains(c.getPosition())) {
|
||||||
|
hasMissing[0] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return hasMissing[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean containsAnyChunks(Iterable<? extends GenericChunk<?, ?, ?, ?>> chunks) {
|
||||||
|
boolean[] hasPresent = new boolean[] { false };
|
||||||
|
|
||||||
|
chunks.forEach(c -> {
|
||||||
|
if (contains(c.getPosition())) {
|
||||||
|
hasPresent[0] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return hasPresent[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
default void addAllChunks(Iterable<? extends GenericChunk<?, ?, ?, ?>> chunks) {
|
||||||
|
chunks.forEach(this::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void removeAllChunks(Iterable<? extends GenericChunk<?, ?, ?, ?>> chunks) {
|
||||||
|
chunks.forEach(this::remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package ru.windcorp.progressia.common.world.generic;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BiPredicate;
|
||||||
|
|
||||||
|
import glm.vec._3.i.Vec3i;
|
||||||
|
import gnu.trove.map.TLongObjectMap;
|
||||||
|
import ru.windcorp.progressia.common.util.CoordinatePacker;
|
||||||
|
import ru.windcorp.progressia.common.util.Vectors;
|
||||||
|
|
||||||
|
public class LongBasedChunkMap<V> implements ChunkMap<V> {
|
||||||
|
|
||||||
|
protected final TLongObjectMap<V> impl;
|
||||||
|
private final ChunkSet keys;
|
||||||
|
|
||||||
|
public LongBasedChunkMap(TLongObjectMap<V> impl) {
|
||||||
|
this.impl = impl;
|
||||||
|
this.keys = new LongBasedChunkSet(impl.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getKey(Vec3i v) {
|
||||||
|
return CoordinatePacker.pack3IntsIntoLong(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3i getVector(long key, Vec3i output) {
|
||||||
|
return CoordinatePacker.unpack3IntsFromLong(key, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return impl.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsKey(Vec3i pos) {
|
||||||
|
return impl.containsKey(getKey(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public V get(Vec3i pos) {
|
||||||
|
return impl.get(getKey(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public V put(Vec3i pos, V obj) {
|
||||||
|
return impl.put(getKey(pos), obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public V remove(Vec3i pos) {
|
||||||
|
return impl.remove(getKey(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<V> values() {
|
||||||
|
return impl.valueCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkSet keys() {
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeIf(BiPredicate<? super Vec3i, ? super V> condition) {
|
||||||
|
Vec3i v = Vectors.grab3i();
|
||||||
|
|
||||||
|
boolean result = impl.retainEntries((key, value) -> {
|
||||||
|
return !condition.test(getVector(key, v), value);
|
||||||
|
});
|
||||||
|
|
||||||
|
Vectors.release(v);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEach(BiConsumer<? super Vec3i, ? super V> action) {
|
||||||
|
Vec3i v = Vectors.grab3i();
|
||||||
|
|
||||||
|
impl.forEachEntry((key, value) -> {
|
||||||
|
action.accept(getVector(key, v), value);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Vectors.release(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
package ru.windcorp.progressia.common.world.generic;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import glm.vec._3.i.Vec3i;
|
||||||
|
import gnu.trove.iterator.TLongIterator;
|
||||||
|
import gnu.trove.set.TLongSet;
|
||||||
|
import ru.windcorp.progressia.common.util.CoordinatePacker;
|
||||||
|
import ru.windcorp.progressia.common.util.Vectors;
|
||||||
|
|
||||||
|
public class LongBasedChunkSet implements ChunkSet {
|
||||||
|
|
||||||
|
protected final TLongSet impl;
|
||||||
|
|
||||||
|
public LongBasedChunkSet(TLongSet impl) {
|
||||||
|
this.impl = impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongBasedChunkSet(TLongSet impl, ChunkSet copyFrom) {
|
||||||
|
this(impl);
|
||||||
|
addAll(copyFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongBasedChunkSet(TLongSet impl, Iterable<? extends Vec3i> copyFrom) {
|
||||||
|
this(impl);
|
||||||
|
addAll(copyFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongBasedChunkSet(TLongSet impl, GenericWorld<?, ?, ?, ?, ?> copyFrom) {
|
||||||
|
this(impl);
|
||||||
|
addAllChunks(copyFrom.getChunks());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getKey(Vec3i v) {
|
||||||
|
return CoordinatePacker.pack3IntsIntoLong(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3i getVector(long key, Vec3i output) {
|
||||||
|
return CoordinatePacker.unpack3IntsFromLong(key, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Vec3i> iterator() {
|
||||||
|
return new IteratorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return impl.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Vec3i pos) {
|
||||||
|
return impl.contains(getKey(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(Vec3i pos) {
|
||||||
|
return impl.add(getKey(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Vec3i pos) {
|
||||||
|
return impl.remove(getKey(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsAll(ChunkSet other) {
|
||||||
|
if (other instanceof LongBasedChunkSet) {
|
||||||
|
return impl.containsAll(((LongBasedChunkSet) other).impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChunkSet.super.containsAll((Iterable<? extends Vec3i>) other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsAny(ChunkSet other) {
|
||||||
|
return ChunkSet.super.containsAny((Iterable<? extends Vec3i>) other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAll(ChunkSet other) {
|
||||||
|
if (other instanceof LongBasedChunkSet) {
|
||||||
|
impl.addAll(((LongBasedChunkSet) other).impl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkSet.super.addAll((Iterable<? extends Vec3i>) other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAll(ChunkSet other) {
|
||||||
|
if (other instanceof LongBasedChunkSet) {
|
||||||
|
impl.removeAll(((LongBasedChunkSet) other).impl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkSet.super.removeAll((Iterable<? extends Vec3i>) other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void retainAll(ChunkSet other) {
|
||||||
|
if (other instanceof LongBasedChunkSet) {
|
||||||
|
impl.retainAll(((LongBasedChunkSet) other).impl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkSet.super.retainAll((Iterable<? extends Vec3i>) other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
impl.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEach(Consumer<? super Vec3i> action) {
|
||||||
|
Vec3i v = Vectors.grab3i();
|
||||||
|
|
||||||
|
impl.forEach(key -> {
|
||||||
|
getVector(key, v);
|
||||||
|
action.accept(v);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Vectors.release(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IteratorImpl implements Iterator<Vec3i> {
|
||||||
|
|
||||||
|
private final Vec3i vector = new Vec3i();
|
||||||
|
private final TLongIterator parent = LongBasedChunkSet.this.impl.iterator();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return parent.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec3i next() {
|
||||||
|
return getVector(parent.next(), vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
parent.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,10 +5,10 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import glm.vec._3.i.Vec3i;
|
import glm.vec._3.i.Vec3i;
|
||||||
import gnu.trove.set.TLongSet;
|
|
||||||
import gnu.trove.set.hash.TLongHashSet;
|
import gnu.trove.set.hash.TLongHashSet;
|
||||||
import ru.windcorp.progressia.common.util.CoordinatePacker;
|
|
||||||
import ru.windcorp.progressia.common.world.ChunkData;
|
import ru.windcorp.progressia.common.world.ChunkData;
|
||||||
|
import ru.windcorp.progressia.common.world.generic.ChunkSet;
|
||||||
|
import ru.windcorp.progressia.common.world.generic.LongBasedChunkSet;
|
||||||
import ru.windcorp.progressia.test.TestContent;
|
import ru.windcorp.progressia.test.TestContent;
|
||||||
|
|
||||||
public class ChunkLoadManager {
|
public class ChunkLoadManager {
|
||||||
@ -18,9 +18,9 @@ public class ChunkLoadManager {
|
|||||||
private final Collection<Collection<? extends ChunkLoader>> allChunkLoaders =
|
private final Collection<Collection<? extends ChunkLoader>> allChunkLoaders =
|
||||||
Collections.synchronizedCollection(new ArrayList<>());
|
Collections.synchronizedCollection(new ArrayList<>());
|
||||||
|
|
||||||
private final TLongSet requested = new TLongHashSet();
|
private final ChunkSet requested = new LongBasedChunkSet(new TLongHashSet());
|
||||||
private final TLongSet toLoad = new TLongHashSet();
|
private final ChunkSet toLoad = new LongBasedChunkSet(new TLongHashSet());
|
||||||
private final TLongSet toUnload = new TLongHashSet();
|
private final ChunkSet toUnload = new LongBasedChunkSet(new TLongHashSet());
|
||||||
|
|
||||||
public ChunkLoadManager(Server server) {
|
public ChunkLoadManager(Server server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
@ -42,11 +42,11 @@ public class ChunkLoadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void gatherRequests(ChunkLoader loader) {
|
private void gatherRequests(ChunkLoader loader) {
|
||||||
loader.requestChunksToLoad(v -> requested.add(CoordinatePacker.pack3IntsIntoLong(v)));
|
loader.requestChunksToLoad(requested::add);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateQueues() {
|
private void updateQueues() {
|
||||||
TLongSet loaded = getServer().getWorld().getData().getChunkKeys();
|
ChunkSet loaded = getServer().getWorld().getData().getLoadedChunks();
|
||||||
|
|
||||||
toLoad.clear();
|
toLoad.clear();
|
||||||
toLoad.addAll(requested);
|
toLoad.addAll(requested);
|
||||||
@ -58,17 +58,8 @@ public class ChunkLoadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processQueues() {
|
private void processQueues() {
|
||||||
Vec3i v = new Vec3i();
|
toUnload.forEach(this::unloadChunk);
|
||||||
|
toLoad.forEach(this::loadChunk);
|
||||||
toLoad.forEach(key -> {
|
|
||||||
loadChunk(CoordinatePacker.unpack3IntsFromLong(key, v));
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
toUnload.forEach(key -> {
|
|
||||||
unloadChunk(CoordinatePacker.unpack3IntsFromLong(key, v));
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Server getServer() {
|
public Server getServer() {
|
||||||
|
Reference in New Issue
Block a user