Remove generic Acquirable

This commit is contained in:
TheMode 2021-04-22 16:38:37 +02:00
parent 86faa435f7
commit 297652c610
9 changed files with 84 additions and 111 deletions

View File

@ -4,7 +4,7 @@ import com.google.common.collect.Queues;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.lock.Acquisition;
import net.minestom.server.entity.acquirable.Acquisition;
import net.minestom.server.monitoring.TickMonitor;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.player.NettyPlayerConnection;

View File

@ -13,6 +13,7 @@ import net.minestom.server.collision.BoundingBox;
import net.minestom.server.collision.CollisionUtils;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.entity.acquirable.AcquirableEntity;
import net.minestom.server.entity.metadata.EntityMeta;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventCallback;
@ -22,8 +23,6 @@ import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.lock.Acquirable;
import net.minestom.server.lock.LockedElement;
import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.permission.Permission;
@ -60,7 +59,7 @@ import java.util.function.UnaryOperator;
* <p>
* To create your own entity you probably want to extends {@link LivingEntity} or {@link EntityCreature} instead.
*/
public class Entity implements Viewable, Tickable, LockedElement, EventHandler, DataContainer, PermissionHandler, HoverEventSource<ShowEntity> {
public class Entity implements Viewable, Tickable, EventHandler, DataContainer, PermissionHandler, HoverEventSource<ShowEntity> {
private static final Map<Integer, Entity> ENTITY_BY_ID = new ConcurrentHashMap<>();
private static final Map<UUID, Entity> ENTITY_BY_UUID = new ConcurrentHashMap<>();
@ -125,7 +124,7 @@ public class Entity implements Viewable, Tickable, LockedElement, EventHandler,
private long ticks;
private final EntityTickEvent tickEvent = new EntityTickEvent(this);
private final Acquirable<Entity> acquirable = new Acquirable<>(this);
private final AcquirableEntity acquirableEntity = new AcquirableEntity(this);
/**
* Lock used to support #switchEntityType
@ -1567,9 +1566,8 @@ public class Entity implements Viewable, Tickable, LockedElement, EventHandler,
return Objects.requireNonNullElse(this.customSynchronizationCooldown, SYNCHRONIZATION_COOLDOWN);
}
@Override
public @NotNull <T> Acquirable<T> getAcquiredElement() {
return (Acquirable<T>) acquirable;
public @NotNull AcquirableEntity getAcquirable() {
return acquirableEntity;
}
public enum Pose {

View File

@ -44,7 +44,6 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.metadata.WrittenBookMeta;
import net.minestom.server.listener.PlayerDiggingListener;
import net.minestom.server.lock.Acquirable;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.PlayerProvider;

View File

@ -0,0 +1,25 @@
package net.minestom.server.entity.acquirable;
import net.minestom.server.entity.Entity;
import net.minestom.server.utils.collection.CollectionView;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.function.Consumer;
public class AcquirableCollection<E extends Entity> extends CollectionView<E, AcquirableEntity> {
private final Collection<AcquirableEntity> acquirableEntityCollection;
public AcquirableCollection(@NotNull Collection<AcquirableEntity> acquirableEntityCollection) {
super(acquirableEntityCollection,
Entity::getAcquirable,
acquirableEntity -> (E) acquirableEntity.unwrap());
this.acquirableEntityCollection = acquirableEntityCollection;
}
@Override
public void forEach(Consumer<? super E> action) {
// Acquisition.acquireForEach(acquirableEntityCollection, action);
}
}

View File

@ -1,4 +1,4 @@
package net.minestom.server.lock;
package net.minestom.server.entity.acquirable;
import net.minestom.server.entity.Entity;
import net.minestom.server.thread.BatchThread;
@ -15,10 +15,8 @@ import java.util.function.Consumer;
/**
* Represents an element which can be acquired.
* Used for synchronization purpose.
*
* @param <T> the acquirable object type
*/
public final class Acquirable<T> {
public final class AcquirableEntity {
public static final ThreadLocal<Collection<Entity>> CURRENT_ENTITIES = ThreadLocal.withInitial(Collections::emptyList);
@ -46,11 +44,11 @@ public final class Acquirable<T> {
CURRENT_ENTITIES.set(entities);
}
private final T value;
private final Entity entity;
private final Handler handler;
public Acquirable(@NotNull T value) {
this.value = value;
public AcquirableEntity(@NotNull Entity entity) {
this.entity = entity;
this.handler = new Handler();
}
@ -60,7 +58,7 @@ public final class Acquirable<T> {
*
* @param consumer the acquisition consumer
*/
public void acquire(@NotNull Consumer<@NotNull T> consumer) {
public void acquire(@NotNull Consumer<@NotNull Entity> consumer) {
final Thread currentThread = Thread.currentThread();
final BatchThread elementThread = getHandler().getBatchThread();
Acquisition.acquire(currentThread, elementThread, () -> consumer.accept(unwrap()));
@ -74,7 +72,7 @@ public final class Acquirable<T> {
* @return true if the acquisition happened without synchronization,
* false otherwise
*/
public boolean tryAcquire(@NotNull Consumer<@NotNull T> consumer) {
public boolean tryAcquire(@NotNull Consumer<@NotNull Entity> consumer) {
final Thread currentThread = Thread.currentThread();
final BatchThread elementThread = getHandler().getBatchThread();
if (Objects.equals(currentThread, elementThread)) {
@ -90,7 +88,7 @@ public final class Acquirable<T> {
*
* @return this element or null if unsafe
*/
public @Nullable T tryAcquire() {
public @Nullable Entity tryAcquire() {
final Thread currentThread = Thread.currentThread();
final BatchThread elementThread = getHandler().getBatchThread();
if (Objects.equals(currentThread, elementThread)) {
@ -106,7 +104,7 @@ public final class Acquirable<T> {
*
* @param consumer the consumer of the acquired object
*/
public void scheduledAcquire(@NotNull Consumer<T> consumer) {
public void scheduledAcquire(@NotNull Consumer<Entity> consumer) {
Acquisition.scheduledAcquireRequest(this, consumer);
}
@ -117,8 +115,8 @@ public final class Acquirable<T> {
*
* @return the unwraped value
*/
public @NotNull T unwrap() {
return value;
public @NotNull Entity unwrap() {
return entity;
}
/**

View File

@ -1,5 +1,6 @@
package net.minestom.server.lock;
package net.minestom.server.entity.acquirable;
import net.minestom.server.entity.Entity;
import net.minestom.server.thread.BatchThread;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -27,22 +28,21 @@ public final class Acquisition {
*
* @param collection the collection to acquire
* @param consumer the consumer called for each of the collection element
* @param <E> the object type
*/
public static <E> void acquireForEach(@NotNull Collection<Acquirable<E>> collection,
@NotNull Consumer<? super E> consumer) {
public static void acquireForEach(@NotNull Collection<AcquirableEntity> collection,
@NotNull Consumer<Entity> consumer) {
final Thread currentThread = Thread.currentThread();
Map<BatchThread, List<E>> threadCacheMap = retrieveOptionalThreadMap(collection, currentThread, consumer);
Map<BatchThread, List<Entity>> threadCacheMap = retrieveOptionalThreadMap(collection, currentThread, consumer);
// Acquire all the threads one by one
{
for (Map.Entry<BatchThread, List<E>> entry : threadCacheMap.entrySet()) {
for (Map.Entry<BatchThread, List<Entity>> entry : threadCacheMap.entrySet()) {
final BatchThread batchThread = entry.getKey();
final List<E> elements = entry.getValue();
final List<Entity> entities = entry.getValue();
acquire(currentThread, batchThread, () -> {
for (E element : elements) {
consumer.accept(element);
for (Entity entity : entities) {
consumer.accept(entity);
}
});
}
@ -55,20 +55,20 @@ public final class Acquisition {
public static void processThreadTick() {
ScheduledAcquisition scheduledAcquisition = SCHEDULED_ACQUISITION.get();
final List<Acquirable<Object>> acquirableElements = scheduledAcquisition.acquirableElements;
final List<AcquirableEntity> acquirableEntityElements = scheduledAcquisition.acquirableEntityElements;
if (!acquirableElements.isEmpty()) {
final Map<Object, List<Consumer<Object>>> callbacks = scheduledAcquisition.callbacks;
if (!acquirableEntityElements.isEmpty()) {
final Map<Object, List<Consumer<Entity>>> callbacks = scheduledAcquisition.callbacks;
acquireForEach(acquirableElements, element -> {
List<Consumer<Object>> consumers = callbacks.get(element);
acquireForEach(acquirableEntityElements, element -> {
List<Consumer<Entity>> consumers = callbacks.get(element);
if (consumers == null || consumers.isEmpty())
return;
consumers.forEach(objectConsumer -> objectConsumer.accept(element));
});
// Clear collections..
acquirableElements.clear();
acquirableEntityElements.clear();
callbacks.clear();
}
}
@ -129,12 +129,12 @@ public final class Acquisition {
GLOBAL_LOCK.unlock();
}
protected synchronized static <T> void scheduledAcquireRequest(@NotNull Acquirable<T> acquirable, Consumer<T> consumer) {
protected synchronized static void scheduledAcquireRequest(@NotNull AcquirableEntity acquirableEntity, Consumer<Entity> consumer) {
ScheduledAcquisition scheduledAcquisition = SCHEDULED_ACQUISITION.get();
scheduledAcquisition.acquirableElements.add((Acquirable<Object>) acquirable);
scheduledAcquisition.acquirableEntityElements.add(acquirableEntity);
scheduledAcquisition.callbacks
.computeIfAbsent(acquirable.unwrap(), objectAcquirable -> new ArrayList<>())
.add((Consumer<Object>) consumer);
.computeIfAbsent(acquirableEntity.unwrap(), objectAcquirable -> new ArrayList<>())
.add(consumer);
}
/**
@ -143,18 +143,17 @@ public final class Acquisition {
* @param collection the acquirable collection
* @param currentThread the current thread
* @param consumer the consumer to execute when an element is already in the current thread
* @param <E> the acquirable element type
* @return a new Thread to acquirable elements map
*/
protected static <E> Map<BatchThread, List<E>> retrieveOptionalThreadMap(@NotNull Collection<Acquirable<E>> collection,
@NotNull Thread currentThread,
@NotNull Consumer<? super E> consumer) {
protected static Map<BatchThread, List<Entity>> retrieveOptionalThreadMap(@NotNull Collection<AcquirableEntity> collection,
@NotNull Thread currentThread,
@NotNull Consumer<? super Entity> consumer) {
// Separate a collection of acquirable elements into a map of thread->elements
// Useful to reduce the number of acquisition
Map<BatchThread, List<E>> threadCacheMap = new HashMap<>();
for (Acquirable<E> element : collection) {
final E value = element.unwrap();
Map<BatchThread, List<Entity>> threadCacheMap = new HashMap<>();
for (AcquirableEntity element : collection) {
final Entity value = element.unwrap();
final BatchThread elementThread = element.getHandler().getBatchThread();
if (currentThread == elementThread) {
@ -162,7 +161,7 @@ public final class Acquisition {
consumer.accept(value);
} else {
// The element is manager in a different thread, cache it
List<E> threadCacheList = threadCacheMap.computeIfAbsent(elementThread, batchThread -> new ArrayList<>());
List<Entity> threadCacheList = threadCacheMap.computeIfAbsent(elementThread, batchThread -> new ArrayList<>());
threadCacheList.add(value);
}
}
@ -170,16 +169,16 @@ public final class Acquisition {
return threadCacheMap;
}
protected static <E> Map<BatchThread, List<E>> retrieveThreadMap(@NotNull Collection<Acquirable<E>> collection) {
protected static Map<BatchThread, List<Entity>> retrieveThreadMap(@NotNull Collection<AcquirableEntity> collection) {
// Separate a collection of acquirable elements into a map of thread->elements
// Useful to reduce the number of acquisition
Map<BatchThread, List<E>> threadCacheMap = new HashMap<>();
for (Acquirable<E> element : collection) {
final E value = element.unwrap();
final BatchThread elementThread = element.getHandler().getBatchThread();
Map<BatchThread, List<Entity>> threadCacheMap = new HashMap<>();
for (AcquirableEntity acquirableEntity : collection) {
final Entity entity = acquirableEntity.unwrap();
final BatchThread elementThread = acquirableEntity.getHandler().getBatchThread();
List<E> threadCacheList = threadCacheMap.computeIfAbsent(elementThread, batchThread -> new ArrayList<>());
threadCacheList.add(value);
List<Entity> threadCacheList = threadCacheMap.computeIfAbsent(elementThread, batchThread -> new ArrayList<>());
threadCacheList.add(entity);
}
return threadCacheMap;
@ -194,7 +193,7 @@ public final class Acquisition {
}
private static class ScheduledAcquisition {
private final List<Acquirable<Object>> acquirableElements = new ArrayList<>();
private final Map<Object, List<Consumer<Object>>> callbacks = new HashMap<>();
private final List<AcquirableEntity> acquirableEntityElements = new ArrayList<>();
private final Map<Object, List<Consumer<Entity>>> callbacks = new HashMap<>();
}
}

View File

@ -1,24 +0,0 @@
package net.minestom.server.lock;
import net.minestom.server.utils.collection.CollectionView;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.function.Consumer;
public class AcquirableCollection<E extends LockedElement> extends CollectionView<E, Acquirable<E>> {
private final Collection<Acquirable<E>> acquirableCollection;
public AcquirableCollection(@NotNull Collection<Acquirable<E>> acquirableCollection) {
super(acquirableCollection,
LockedElement::getAcquiredElement,
Acquirable::unwrap);
this.acquirableCollection = acquirableCollection;
}
@Override
public void forEach(Consumer<? super E> action) {
Acquisition.acquireForEach(acquirableCollection, action);
}
}

View File

@ -1,22 +0,0 @@
package net.minestom.server.lock;
import org.jetbrains.annotations.NotNull;
/**
* Represents an element that have a {@link Acquirable} linked to it.
* <p>
* Useful if you want to provide an access point to an object without risking to compromise
* the thread-safety of your code.
*/
public interface LockedElement {
/**
* Gets the {@link Acquirable} of this locked element.
* <p>
* Should be a constant.
*
* @return the acquirable element linked to this object
*/
<T> @NotNull Acquirable<T> getAcquiredElement();
}

View File

@ -2,11 +2,11 @@ package net.minestom.server.thread;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.acquirable.AcquirableEntity;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.SharedInstance;
import net.minestom.server.lock.Acquirable;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.chunk.ChunkUtils;
import org.jetbrains.annotations.NotNull;
@ -148,7 +148,7 @@ public abstract class ThreadProvider {
final var entities = entitiesList.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
Acquirable.refreshEntities(Collections.unmodifiableList(entities));
AcquirableEntity.refreshEntities(Collections.unmodifiableList(entities));
final ReentrantLock lock = thread.getLock();
lock.lock();
@ -177,8 +177,8 @@ public abstract class ThreadProvider {
// Clear removed entities
{
for (Entity entity : removedEntities) {
Acquirable<Entity> acquirable = entity.getAcquiredElement();
ChunkEntry chunkEntry = acquirable.getHandler().getChunkEntry();
AcquirableEntity acquirableEntity = entity.getAcquirable();
ChunkEntry chunkEntry = acquirableEntity.getHandler().getChunkEntry();
// Remove from list
if (chunkEntry != null) {
chunkEntry.entities.remove(entity);
@ -242,8 +242,8 @@ public abstract class ThreadProvider {
private void refreshEntitiesThread(Instance instance, Chunk chunk) {
var entities = instance.getChunkEntities(chunk);
for (Entity entity : entities) {
Acquirable<Entity> acquirable = entity.getAcquiredElement();
ChunkEntry handlerChunkEntry = acquirable.getHandler().getChunkEntry();
AcquirableEntity acquirableEntity = entity.getAcquirable();
ChunkEntry handlerChunkEntry = acquirableEntity.getHandler().getChunkEntry();
Chunk batchChunk = handlerChunkEntry != null ? handlerChunkEntry.getChunk() : null;
Chunk entityChunk = entity.getChunk();
@ -262,7 +262,7 @@ public abstract class ThreadProvider {
ChunkEntry chunkEntry = chunkEntryMap.get(entityChunk);
if (chunkEntry != null) {
chunkEntry.entities.add(entity);
acquirable.getHandler().refreshChunkEntry(chunkEntry);
acquirableEntity.getHandler().refreshChunkEntry(chunkEntry);
}
}
}