net.minestom.server.thread.Acquirable Maven / Gradle / Ivy
Show all versions of minestom-snapshots Show documentation
package net.minestom.server.thread;
import net.minestom.server.entity.Entity;
import net.minestom.server.utils.async.AsyncUtils;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Stream;
@ApiStatus.Experimental
public sealed interface Acquirable permits AcquirableImpl {
/**
* Gets all the {@link Entity entities} being ticked in the current thread.
*
* Useful when you want to ensure that no acquisition is ever done.
*
* Be aware that the entity stream is only updated at the beginning of the thread tick.
*
* @return the entities ticked in the current thread
*/
static @NotNull Stream<@NotNull Entity> currentEntities() {
final Thread currentThread = Thread.currentThread();
if (currentThread instanceof TickThread) {
return ((TickThread) currentThread).entries().stream()
.flatMap(partitionEntry -> partitionEntry.elements().stream())
.filter(tickable -> tickable instanceof Entity)
.map(tickable -> (Entity) tickable);
}
return Stream.empty();
}
/**
* Retrieve and reset acquiring time.
*/
@ApiStatus.Internal
static long resetAcquiringTime() {
return AcquirableImpl.WAIT_COUNTER_NANO.getAndSet(0);
}
/**
* Creates a new {@link Acquirable} object.
*
* Mostly for internal use, as a {@link TickThread} has to be used
* and properly synchronized.
*
* @param value the acquirable element
* @param the acquirable element type
* @return a new acquirable object
*/
@ApiStatus.Internal
static @NotNull Acquirable of(@NotNull T value) {
return new AcquirableImpl<>(value);
}
/**
* Returns a new {@link Acquired} object which will be locked to the current thread.
*
* Useful when your code cannot be done inside a callback and need to be sync.
* Do not forget to call {@link Acquired#unlock()} once you are done with it.
*
* @return an acquired object
* @see #sync(Consumer) for auto-closeable capability
*/
default @NotNull Acquired lock() {
return new Acquired<>(unwrap(), assignedThread());
}
/**
* Retrieves the acquirable value if and only if the element
* is already present/ticked in the current thread.
*
* Useful when you want only want to acquire an element when you are guaranteed
* to do not create a huge performance impact.
*
* @return an optional containing the acquired element if safe,
* {@link Optional#empty()} otherwise
*/
default @NotNull Optional local() {
if (isLocal()) return Optional.of(unwrap());
return Optional.empty();
}
/**
* Gets if the acquirable element is local to this thread
*
* @return true if the element is linked to the current thread
*/
default boolean isLocal() {
return Thread.currentThread() == assignedThread();
}
/**
* Locks the acquirable element, execute {@code consumer} synchronously and unlock the thread.
*
* Free if the element is already present in the current thread, blocking otherwise.
*
* @param consumer the callback to execute once the element has been safely acquired
* @see #async(Consumer)
*/
default void sync(@NotNull Consumer consumer) {
Acquired acquired = lock();
try {
consumer.accept(acquired.get());
} finally {
acquired.unlock();
}
}
/**
* Async version of {@link #sync(Consumer)}.
*
* @param consumer the callback to execute once the element has been safely acquired
* @see #sync(Consumer)
*/
default void async(@NotNull Consumer consumer) {
// TODO per-thread list
AsyncUtils.runAsync(() -> sync(consumer));
}
/**
* Unwrap the contained object unsafely.
*
* Should only be considered when thread-safety is not necessary (e.g. comparing positions)
*
* @return the unwrapped value
*/
@NotNull T unwrap();
@ApiStatus.Internal
@NotNull TickThread assignedThread();
}