mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-27 02:21:38 +01:00
Fix permission level resetting & make entity in EntityMeta nullable (#595)
This commit is contained in:
parent
87d5a33c76
commit
6a83fd6ac8
@ -296,6 +296,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
|
|
||||||
// Some client updates
|
// Some client updates
|
||||||
this.playerConnection.sendPacket(getPropertiesPacket()); // Send default properties
|
this.playerConnection.sendPacket(getPropertiesPacket()); // Send default properties
|
||||||
|
triggerStatus((byte) (24 + permissionLevel)); // Set permission level
|
||||||
refreshHealth(); // Heal and send health packet
|
refreshHealth(); // Heal and send health packet
|
||||||
refreshAbilities(); // Send abilities packet
|
refreshAbilities(); // Send abilities packet
|
||||||
|
|
||||||
@ -424,6 +425,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
RespawnPacket respawnPacket = new RespawnPacket(getDimensionType(), getDimensionType().getName().asString(),
|
RespawnPacket respawnPacket = new RespawnPacket(getDimensionType(), getDimensionType().getName().asString(),
|
||||||
0, gameMode, gameMode, false, levelFlat, true);
|
0, gameMode, gameMode, false, levelFlat, true);
|
||||||
getPlayerConnection().sendPacket(respawnPacket);
|
getPlayerConnection().sendPacket(respawnPacket);
|
||||||
|
|
||||||
PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(this);
|
PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(this);
|
||||||
EventDispatcher.call(respawnEvent);
|
EventDispatcher.call(respawnEvent);
|
||||||
triggerStatus((byte) (24 + permissionLevel)); // Set permission level
|
triggerStatus((byte) (24 + permissionLevel)); // Set permission level
|
||||||
@ -433,6 +435,16 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
teleport(respawnEvent.getRespawnPosition()).thenRun(this::refreshAfterTeleport);
|
teleport(respawnEvent.getRespawnPosition()).thenRun(this::refreshAfterTeleport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends necessary packets to synchronize player data after a {@link RespawnPacket}
|
||||||
|
*/
|
||||||
|
private void refreshClientStateAfterRespawn() {
|
||||||
|
this.playerConnection.sendPacket(new UpdateHealthPacket(this.getHealth(), food, foodSaturation));
|
||||||
|
this.playerConnection.sendPacket(new SetExperiencePacket(exp, level, 0));
|
||||||
|
triggerStatus((byte) (24 + permissionLevel)); // Set permission level
|
||||||
|
refreshAbilities();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes the command list for this player. This checks the
|
* Refreshes the command list for this player. This checks the
|
||||||
* {@link net.minestom.server.command.builder.condition.CommandCondition}s
|
* {@link net.minestom.server.command.builder.condition.CommandCondition}s
|
||||||
@ -901,6 +913,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
playerConnection.sendPacket(destroyEntitiesPacket);
|
playerConnection.sendPacket(destroyEntitiesPacket);
|
||||||
playerConnection.sendPacket(respawnPacket);
|
playerConnection.sendPacket(respawnPacket);
|
||||||
playerConnection.sendPacket(addPlayerPacket);
|
playerConnection.sendPacket(addPlayerPacket);
|
||||||
|
refreshClientStateAfterRespawn();
|
||||||
|
|
||||||
{
|
{
|
||||||
// Remove player
|
// Remove player
|
||||||
@ -1207,7 +1220,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the player {@link GameMode}.
|
* Changes the player {@link GameMode}
|
||||||
*
|
*
|
||||||
* @param gameMode the new player GameMode
|
* @param gameMode the new player GameMode
|
||||||
*/
|
*/
|
||||||
@ -1219,6 +1232,27 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
sendPacketToViewersAndSelf(new PlayerInfoPacket(PlayerInfoPacket.Action.UPDATE_GAMEMODE,
|
sendPacketToViewersAndSelf(new PlayerInfoPacket(PlayerInfoPacket.Action.UPDATE_GAMEMODE,
|
||||||
new PlayerInfoPacket.UpdateGameMode(getUuid(), gameMode)));
|
new PlayerInfoPacket.UpdateGameMode(getUuid(), gameMode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The client updates their abilities based on the GameMode as follows
|
||||||
|
switch (gameMode) {
|
||||||
|
case CREATIVE -> {
|
||||||
|
this.allowFlying = true;
|
||||||
|
this.instantBreak = true;
|
||||||
|
this.invulnerable = true;
|
||||||
|
}
|
||||||
|
case SPECTATOR -> {
|
||||||
|
this.allowFlying = true;
|
||||||
|
this.instantBreak = false;
|
||||||
|
this.invulnerable = true;
|
||||||
|
this.flying = true;
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
this.allowFlying = false;
|
||||||
|
this.instantBreak = false;
|
||||||
|
this.invulnerable = false;
|
||||||
|
this.flying = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1242,6 +1276,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
this.dimensionType = dimensionType;
|
this.dimensionType = dimensionType;
|
||||||
sendPacket(new RespawnPacket(dimensionType, dimensionType.getName().asString(),
|
sendPacket(new RespawnPacket(dimensionType, dimensionType.getName().asString(),
|
||||||
0, gameMode, gameMode, false, levelFlat, true));
|
0, gameMode, gameMode, false, levelFlat, true));
|
||||||
|
refreshClientStateAfterRespawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1465,10 +1500,13 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
|
|
||||||
this.permissionLevel = permissionLevel;
|
this.permissionLevel = permissionLevel;
|
||||||
|
|
||||||
// Magic values: https://wiki.vg/Entity_statuses#Player
|
// Condition to prevent sending the packets before spawning the player
|
||||||
// TODO remove magic values
|
if (isActive()) {
|
||||||
final byte permissionLevelStatus = (byte) (24 + permissionLevel);
|
// Magic values: https://wiki.vg/Entity_statuses#Player
|
||||||
triggerStatus(permissionLevelStatus);
|
// TODO remove magic values
|
||||||
|
final byte permissionLevelStatus = (byte) (24 + permissionLevel);
|
||||||
|
triggerStatus(permissionLevelStatus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,20 +32,6 @@ public class EntityInstanceIntegrationTest {
|
|||||||
assertEquals(instance, player.getInstance());
|
assertEquals(instance, player.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void playerJoinPacket(Env env) {
|
|
||||||
var instance = env.createFlatInstance();
|
|
||||||
var connection = env.createConnection();
|
|
||||||
var tracker = connection.trackIncoming(JoinGamePacket.class);
|
|
||||||
var tracker2 = connection.trackIncoming(ServerPacket.class);
|
|
||||||
var player = connection.connect(instance, new Pos(0, 40, 0)).join();
|
|
||||||
assertEquals(instance, player.getInstance());
|
|
||||||
assertEquals(new Pos(0, 40, 0), player.getPosition());
|
|
||||||
|
|
||||||
assertEquals(1, tracker.collect().size());
|
|
||||||
assertTrue(tracker2.collect().size() > 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void playerSwitch(Env env) {
|
public void playerSwitch(Env env) {
|
||||||
var instance = env.createFlatInstance();
|
var instance = env.createFlatInstance();
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
package net.minestom.server.entity.player;
|
||||||
|
|
||||||
|
import net.minestom.server.api.Env;
|
||||||
|
import net.minestom.server.api.EnvTest;
|
||||||
|
import net.minestom.server.api.TestConnection;
|
||||||
|
import net.minestom.server.coordinate.Pos;
|
||||||
|
import net.minestom.server.entity.GameMode;
|
||||||
|
import net.minestom.server.entity.Player;
|
||||||
|
import net.minestom.server.network.packet.server.ServerPacket;
|
||||||
|
import net.minestom.server.network.packet.server.play.*;
|
||||||
|
import net.minestom.server.utils.NamespaceID;
|
||||||
|
import net.minestom.server.world.DimensionType;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@EnvTest
|
||||||
|
public class PlayerIntegrationTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to see whether player abilities are updated correctly when changing gamemodes
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void gamemodeTest(Env env) {
|
||||||
|
var instance = env.createFlatInstance();
|
||||||
|
var connection = env.createConnection();
|
||||||
|
var player = connection.connect(instance, new Pos(0, 42, 0)).join();
|
||||||
|
assertEquals(instance, player.getInstance());
|
||||||
|
|
||||||
|
player.setGameMode(GameMode.CREATIVE);
|
||||||
|
assertAbilities(player, true, false, true, true);
|
||||||
|
player.setGameMode(GameMode.SPECTATOR);
|
||||||
|
assertAbilities(player, true, true, true, false);
|
||||||
|
player.setGameMode(GameMode.CREATIVE);
|
||||||
|
assertAbilities(player, true, true, true, true);
|
||||||
|
player.setGameMode(GameMode.ADVENTURE);
|
||||||
|
assertAbilities(player, false, false, false, false);
|
||||||
|
player.setGameMode(GameMode.SURVIVAL);
|
||||||
|
assertAbilities(player, false, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertAbilities(Player player, boolean isInvulnerable, boolean isFlying, boolean isAllowFlying,
|
||||||
|
boolean isInstantBreak) {
|
||||||
|
assertEquals(isInvulnerable, player.isInvulnerable());
|
||||||
|
assertEquals(isFlying, player.isFlying());
|
||||||
|
assertEquals(isAllowFlying, player.isAllowFlying());
|
||||||
|
assertEquals(isInstantBreak, player.isInstantBreak());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void playerJoinPackets(Env env) {
|
||||||
|
var instance = env.createFlatInstance();
|
||||||
|
var connection = env.createConnection();
|
||||||
|
|
||||||
|
final var packets = List.of(
|
||||||
|
JoinGamePacket.class, ServerDifficultyPacket.class, SpawnPositionPacket.class,
|
||||||
|
DeclareCommandsPacket.class, EntityPropertiesPacket.class, EntityStatusPacket.class,
|
||||||
|
UpdateHealthPacket.class, PlayerAbilitiesPacket.class
|
||||||
|
);
|
||||||
|
final List<TestConnection.PacketTracker<?>> trackers = new ArrayList<>();
|
||||||
|
for (var packet : packets) {
|
||||||
|
trackers.add(connection.trackIncoming(packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
var trackerAll = connection.trackIncoming(ServerPacket.class);
|
||||||
|
|
||||||
|
var player = connection.connect(instance, new Pos(0, 40, 0)).join();
|
||||||
|
assertEquals(instance, player.getInstance());
|
||||||
|
assertEquals(new Pos(0, 40, 0), player.getPosition());
|
||||||
|
|
||||||
|
for (var tracker : trackers) {
|
||||||
|
assertEquals(1, tracker.collect().size());
|
||||||
|
}
|
||||||
|
assertTrue(trackerAll.collect().size() > packets.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to see whether the packets from Player#refreshPlayer are sent
|
||||||
|
* when changing dimensions
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void refreshPlayerTest(Env env) {
|
||||||
|
final int TEST_PERMISSION_LEVEL = 2;
|
||||||
|
final var testDimension = DimensionType.builder(NamespaceID.from("minestom:test_dimension")).build();
|
||||||
|
env.process().dimension().addDimension(testDimension);
|
||||||
|
|
||||||
|
var instance = env.createFlatInstance();
|
||||||
|
var instance2 = env.process().instance().createInstanceContainer(testDimension);
|
||||||
|
|
||||||
|
var connection = env.createConnection();
|
||||||
|
var player = connection.connect(instance, new Pos(0, 42, 0)).join();
|
||||||
|
assertEquals(instance, player.getInstance());
|
||||||
|
|
||||||
|
var tracker1 = connection.trackIncoming(UpdateHealthPacket.class);
|
||||||
|
var tracker2 = connection.trackIncoming(SetExperiencePacket.class);
|
||||||
|
var trackerStatus = connection.trackIncoming(EntityStatusPacket.class);
|
||||||
|
var tracker4 = connection.trackIncoming(PlayerAbilitiesPacket.class);
|
||||||
|
|
||||||
|
player.setPermissionLevel(TEST_PERMISSION_LEVEL);
|
||||||
|
|
||||||
|
// #join may cause the thread to hang as scheduled for the next tick when initially in a pool
|
||||||
|
Assertions.assertTimeout(Duration.ofSeconds(2), () -> player.setInstance(instance2).join());
|
||||||
|
assertEquals(instance2, player.getInstance());
|
||||||
|
|
||||||
|
assertEquals(1, tracker1.collect().size());
|
||||||
|
assertEquals(1, tracker2.collect().size());
|
||||||
|
assertEquals(2, trackerStatus.collect().size());
|
||||||
|
assertEquals(1, tracker4.collect().size());
|
||||||
|
|
||||||
|
// Ensure that the player was sent the permission levels
|
||||||
|
for (var statusPacket : trackerStatus.collect()) {
|
||||||
|
assertEquals(player.getEntityId(), statusPacket.entityId());
|
||||||
|
assertEquals(24 + TEST_PERMISSION_LEVEL, statusPacket.status()); // TODO: Remove magic value of 24
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user