Fix player position being wrong inside tests

This commit is contained in:
themode 2022-03-14 19:01:48 +01:00
parent 9215e33e80
commit acee29c20a
10 changed files with 66 additions and 50 deletions

View File

@ -23,5 +23,6 @@ tasks {
useJUnitPlatform() useJUnitPlatform()
// Viewable packets make tracking harder. Could be re-enabled later. // Viewable packets make tracking harder. Could be re-enabled later.
jvmArgs("-Dminestom.viewable-packet=false") jvmArgs("-Dminestom.viewable-packet=false")
jvmArgs("-Dminestom.inside-test=true")
} }
} }

View File

@ -236,7 +236,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
* *
* @param spawnInstance the player spawn instance (defined in {@link PlayerLoginEvent}) * @param spawnInstance the player spawn instance (defined in {@link PlayerLoginEvent})
*/ */
public void UNSAFE_init(@NotNull Instance spawnInstance) { public CompletableFuture<Void> UNSAFE_init(@NotNull Instance spawnInstance) {
this.dimensionType = spawnInstance.getDimensionType(); this.dimensionType = spawnInstance.getDimensionType();
NBTCompound nbt = NBT.Compound(Map.of( NBTCompound nbt = NBT.Compound(Map.of(
@ -301,7 +301,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
refreshHealth(); // Heal and send health packet refreshHealth(); // Heal and send health packet
refreshAbilities(); // Send abilities packet refreshAbilities(); // Send abilities packet
setInstance(spawnInstance); return setInstance(spawnInstance);
} }
/** /**

View File

@ -15,6 +15,7 @@ import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection; import net.minestom.server.network.player.PlayerSocketConnection;
import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.StringUtils;
import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.async.AsyncUtils;
import net.minestom.server.utils.debug.DebugUtils;
import net.minestom.server.utils.validate.Check; import net.minestom.server.utils.validate.Check;
import org.jctools.queues.MessagePassingQueue; import org.jctools.queues.MessagePassingQueue;
import org.jctools.queues.MpscUnboundedArrayQueue; import org.jctools.queues.MpscUnboundedArrayQueue;
@ -22,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Function; import java.util.function.Function;
@ -213,8 +215,8 @@ public final class ConnectionManager {
* @param player the player * @param player the player
* @param register true to register the newly created player in {@link ConnectionManager} lists * @param register true to register the newly created player in {@link ConnectionManager} lists
*/ */
public void startPlayState(@NotNull Player player, boolean register) { public CompletableFuture<Void> startPlayState(@NotNull Player player, boolean register) {
AsyncUtils.runAsync(() -> { return AsyncUtils.runAsync(() -> {
final PlayerConnection playerConnection = player.getPlayerConnection(); final PlayerConnection playerConnection = player.getPlayerConnection();
// Call pre login event // Call pre login event
AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(player); AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(player);
@ -290,7 +292,12 @@ public final class ConnectionManager {
final Instance spawningInstance = loginEvent.getSpawningInstance(); final Instance spawningInstance = loginEvent.getSpawningInstance();
Check.notNull(spawningInstance, "You need to specify a spawning instance in the PlayerLoginEvent"); Check.notNull(spawningInstance, "You need to specify a spawning instance in the PlayerLoginEvent");
// Spawn the player at Player#getRespawnPoint // Spawn the player at Player#getRespawnPoint
waitingPlayer.UNSAFE_init(spawningInstance); if (DebugUtils.INSIDE_TEST) {
// Required to get the exact moment the player spawns
waitingPlayer.UNSAFE_init(spawningInstance).join();
} else {
waitingPlayer.UNSAFE_init(spawningInstance);
}
}); });
} }

View File

@ -49,9 +49,9 @@ import java.util.zip.Inflater;
public final class PacketUtils { public final class PacketUtils {
private static final LocalCache<Deflater> LOCAL_DEFLATER = LocalCache.of(Deflater::new); private static final LocalCache<Deflater> LOCAL_DEFLATER = LocalCache.of(Deflater::new);
public static final boolean GROUPED_PACKET = getBoolean("minestom.grouped-packet", true); public static final boolean GROUPED_PACKET = PropertyUtils.getBoolean("minestom.grouped-packet", true);
public static final boolean CACHED_PACKET = getBoolean("minestom.cached-packet", true); public static final boolean CACHED_PACKET = PropertyUtils.getBoolean("minestom.cached-packet", true);
public static final boolean VIEWABLE_PACKET = getBoolean("minestom.viewable-packet", true); public static final boolean VIEWABLE_PACKET = PropertyUtils.getBoolean("minestom.viewable-packet", true);
// Viewable packets // Viewable packets
private static final Cache<Viewable, ViewableStorage> VIEWABLE_STORAGE_MAP = Caffeine.newBuilder().weakKeys().build(); private static final Cache<Viewable, ViewableStorage> VIEWABLE_STORAGE_MAP = Caffeine.newBuilder().weakKeys().build();
@ -339,14 +339,4 @@ public final class PacketUtils {
// TODO for non-socket connection // TODO for non-socket connection
} }
} }
private static boolean getBoolean(String name, boolean defaultValue) {
boolean result = defaultValue;
try {
final String value = System.getProperty(name);
if (value != null) result = Boolean.parseBoolean(value);
} catch (IllegalArgumentException | NullPointerException ignored) {
}
return result;
}
} }

View File

@ -0,0 +1,18 @@
package net.minestom.server.utils;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public final class PropertyUtils {
private PropertyUtils() {}
public static boolean getBoolean(String name, boolean defaultValue) {
boolean result = defaultValue;
try {
final String value = System.getProperty(name);
if (value != null) result = Boolean.parseBoolean(value);
} catch (IllegalArgumentException | NullPointerException ignored) {
}
return result;
}
}

View File

@ -1,12 +1,16 @@
package net.minestom.server.utils.debug; package net.minestom.server.utils.debug;
import net.minestom.server.utils.PropertyUtils;
import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Utils class useful for debugging purpose. * Utils class useful for debugging purpose.
*/ */
@ApiStatus.Internal
public final class DebugUtils { public final class DebugUtils {
public static boolean INSIDE_TEST = PropertyUtils.getBoolean("minestom.inside-test", false);
public final static Logger LOGGER = LoggerFactory.getLogger(DebugUtils.class); public final static Logger LOGGER = LoggerFactory.getLogger(DebugUtils.class);

View File

@ -0,0 +1,13 @@
package net.minestom.server;
import net.minestom.server.utils.debug.DebugUtils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class InsideTest {
@Test
public void inside() {
assertTrue(DebugUtils.INSIDE_TEST);
}
}

View File

@ -7,15 +7,9 @@ import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public interface TestConnection { public interface TestConnection {
@NotNull CompletableFuture<@NotNull Player> connect(@NotNull Instance instance, @NotNull Pos pos, @NotNull Consumer<Player> loginCallback); @NotNull CompletableFuture<@NotNull Player> connect(@NotNull Instance instance, @NotNull Pos pos);
default @NotNull CompletableFuture<@NotNull Player> connect(@NotNull Instance instance, @NotNull Pos pos) {
return connect(instance, pos, (player) -> {
});
}
<T extends ServerPacket> @NotNull Collector<T> trackIncoming(@NotNull Class<T> type); <T extends ServerPacket> @NotNull Collector<T> trackIncoming(@NotNull Class<T> type);

View File

@ -3,7 +3,6 @@ package net.minestom.server.api;
import net.minestom.server.ServerProcess; import net.minestom.server.ServerProcess;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.EventListener;
import net.minestom.server.event.player.PlayerLoginEvent; import net.minestom.server.event.player.PlayerLoginEvent;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.SendablePacket;
@ -17,8 +16,6 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
final class TestConnectionImpl implements TestConnection { final class TestConnectionImpl implements TestConnection {
private final Env env; private final Env env;
@ -27,32 +24,24 @@ final class TestConnectionImpl implements TestConnection {
private final List<IncomingCollector<ServerPacket>> incomingTrackers = new CopyOnWriteArrayList<>(); private final List<IncomingCollector<ServerPacket>> incomingTrackers = new CopyOnWriteArrayList<>();
public TestConnectionImpl(Env env) { TestConnectionImpl(Env env) {
this.env = env; this.env = env;
this.process = env.process(); this.process = env.process();
} }
@Override @Override
public @NotNull CompletableFuture<Player> connect(@NotNull Instance instance, @NotNull Pos pos, @NotNull Consumer<Player> loginCallback) { public @NotNull CompletableFuture<Player> connect(@NotNull Instance instance, @NotNull Pos pos) {
AtomicReference<EventListener<PlayerLoginEvent>> listenerRef = new AtomicReference<>(); Player player = new Player(UUID.randomUUID(), "RandName", playerConnection);
var listener = EventListener.builder(PlayerLoginEvent.class) player.eventNode().addListener(PlayerLoginEvent.class, event -> {
.handler(event -> { event.setSpawningInstance(instance);
if (event.getPlayer().getPlayerConnection() == playerConnection) { event.getPlayer().setRespawnPoint(pos);
event.setSpawningInstance(instance); });
event.getPlayer().setRespawnPoint(pos);
process.eventHandler().removeListener(listenerRef.get());
loginCallback.accept(event.getPlayer());
}
}).build();
listenerRef.set(listener);
process.eventHandler().addListener(listener);
var player = new Player(UUID.randomUUID(), "RandName", playerConnection); return process.connection().startPlayState(player, true)
process.connection().startPlayState(player, true); .thenApply(unused -> {
while (player.getInstance() != instance) { // TODO replace with proper future process.connection().updateWaitingPlayers();
env.tick(); return player;
} });
return CompletableFuture.completedFuture(player);
} }
@Override @Override

View File

@ -25,9 +25,9 @@ public class EntityInstanceIntegrationTest {
@Test @Test
public void playerJoin(Env env) { public void playerJoin(Env env) {
var instance = env.createFlatInstance(); var instance = env.createFlatInstance();
var connection = env.createConnection(); var player = env.createPlayer(instance, new Pos(0, 42, 0));
var player = connection.connect(instance, new Pos(0, 42, 0)).join();
assertEquals(instance, player.getInstance()); assertEquals(instance, player.getInstance());
assertEquals(new Pos(0, 42, 0), player.getPosition());
} }
@Test @Test