Fix the first #setInstance being called in the main update thread

This commit is contained in:
themode 2020-10-12 04:14:06 +02:00
parent 88ef4eb3c0
commit 9184b3054f
5 changed files with 32 additions and 16 deletions

View File

@ -70,7 +70,7 @@ public final class UpdateManager {
futures = threadProvider.update(time);
}
// Waiting players update (newly connected waiting to get into the server)
// Waiting players update (newly connected clients waiting to get into the server)
entityManager.updateWaitingPlayers();
// Keep Alive Handling

View File

@ -20,6 +20,7 @@ import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.WorldBorder;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.thread.ThreadProvider;
import net.minestom.server.utils.ArrayUtils;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Position;
@ -33,6 +34,7 @@ import net.minestom.server.utils.validate.Check;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@ -114,7 +116,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
protected boolean noGravity;
protected Pose pose = Pose.STANDING;
protected final List<Consumer<Entity>> nextTick = Collections.synchronizedList(new ArrayList<>());
// list of scheduled tasks to be executed during the next entity tick
protected final ConcurrentLinkedQueue<Consumer<Entity>> nextTick = new ConcurrentLinkedQueue<>();
// Tick related
private long ticks;
@ -134,8 +137,14 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
setVelocityUpdatePeriod(5);
}
/**
* Schedule a task to be run during the next entity tick
* It ensures that the task will be executed in the same thread as the entity (depending of the {@link ThreadProvider})
*
* @param callback the task to execute during the next entity tick
*/
public void scheduleNextTick(Consumer<Entity> callback) {
nextTick.add(callback);
this.nextTick.add(callback);
}
public Entity(EntityType entityType) {
@ -353,12 +362,14 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return;
}
synchronized (nextTick) {
for (final Consumer<Entity> e : nextTick) {
e.accept(this);
// scheduled tasks
if (!nextTick.isEmpty()) {
Consumer<Entity> callback;
while ((callback = nextTick.poll()) != null) {
callback.accept(this);
}
nextTick.clear();
}
// Synchronization with updated fields in #getPosition()
{
// X/Y/Z axis

View File

@ -36,17 +36,20 @@ public final class EntityManager {
Check.notNull(spawningInstance, "You need to specify a spawning instance in the PlayerLoginEvent");
waitingPlayer.setInstance(spawningInstance);
{
final Player finalWaitingPlayer = waitingPlayer;
spawningInstance.scheduleNextTick(instance -> finalWaitingPlayer.setInstance(instance));
}
}
}
/**
* Call the player initialization callbacks and the event {@link PlayerPreLoginEvent}
* If the player hasn't been kicked, add him to the waiting list
* Call the player initialization callbacks and the event {@link PlayerPreLoginEvent}.
* If the {@link Player} hasn't been kicked, add him to the waiting list.
* <p>
* Can be considered as a pre-init thing
* Can be considered as a pre-init thing.
*
* @param player the player to add
* @param player the {@link Player} to add
*/
public void addWaitingPlayer(Player player) {

View File

@ -176,8 +176,10 @@ public class Player extends LivingEntity implements CommandSender {
}
/**
* Used when the player is created
* Init the player and spawn him
* Used when the player is created.
* Init the player and spawn him.
* <p>
* WARNING: executed in the main update thread
*/
protected void init() {
JoinGamePacket joinGamePacket = new JoinGamePacket();

View File

@ -938,8 +938,8 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
* @param time the current time
*/
public void tick(long time) {
{
// scheduled tasks
// scheduled tasks
if (!nextTick.isEmpty()) {
Consumer<Instance> callback;
while ((callback = nextTick.poll()) != null) {
callback.accept(this);