mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-06 16:37:38 +01:00
hollow-cube/add-gamemodechangeevent-and-fix-game-profile (#43)
* Resolve some todos and add connection.setProfile to EncryptionResponsePacket * Add PlayerGameModeChangeEvent (cherry picked from commit1514d8ac1f
) * Add unit tests (cherry picked from commit9685e74f3b
) --------- Co-authored-by: GreatWyrm <alecmusante@gmail.com> Co-authored-by: NxDs <7994264+NxDs@users.noreply.github.com> (cherry picked from commit2c567696ac
)
This commit is contained in:
parent
6d3690a660
commit
edf7b870c7
@ -1378,8 +1378,18 @@ 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
|
||||||
|
* @return true if the gamemode was changed successfully, false otherwise (cancelled by event)
|
||||||
*/
|
*/
|
||||||
public void setGameMode(@NotNull GameMode gameMode) {
|
public boolean setGameMode(@NotNull GameMode gameMode) {
|
||||||
|
PlayerGameModeChangeEvent playerGameModeChangeEvent = new PlayerGameModeChangeEvent(this, gameMode);
|
||||||
|
EventDispatcher.call(playerGameModeChangeEvent);
|
||||||
|
if (playerGameModeChangeEvent.isCancelled()) {
|
||||||
|
// Abort
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gameMode = playerGameModeChangeEvent.getNewGameMode();
|
||||||
|
|
||||||
this.gameMode = gameMode;
|
this.gameMode = gameMode;
|
||||||
// Condition to prevent sending the packets before spawning the player
|
// Condition to prevent sending the packets before spawning the player
|
||||||
if (isActive()) {
|
if (isActive()) {
|
||||||
@ -1411,6 +1421,8 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
if (isActive()) {
|
if (isActive()) {
|
||||||
refreshAbilities();
|
refreshAbilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package net.minestom.server.event.player;
|
||||||
|
|
||||||
|
import net.minestom.server.entity.GameMode;
|
||||||
|
import net.minestom.server.entity.Player;
|
||||||
|
import net.minestom.server.event.trait.CancellableEvent;
|
||||||
|
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the gamemode of a player is being modified.
|
||||||
|
*/
|
||||||
|
public class PlayerGameModeChangeEvent implements PlayerInstanceEvent, CancellableEvent {
|
||||||
|
|
||||||
|
private final Player player;
|
||||||
|
private GameMode newGameMode;
|
||||||
|
|
||||||
|
private boolean cancelled;
|
||||||
|
|
||||||
|
public PlayerGameModeChangeEvent(@NotNull Player player, @NotNull GameMode newGameMode) {
|
||||||
|
this.player = player;
|
||||||
|
this.newGameMode = newGameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the target gamemode.
|
||||||
|
*
|
||||||
|
* @return the target gamemode
|
||||||
|
*/
|
||||||
|
public @NotNull GameMode getNewGameMode() {
|
||||||
|
return newGameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the target gamemode.
|
||||||
|
*
|
||||||
|
* @param newGameMode the new target gamemode
|
||||||
|
*/
|
||||||
|
public void setNewGameMode(@NotNull GameMode newGameMode) {
|
||||||
|
this.newGameMode = newGameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancel) {
|
||||||
|
this.cancelled = cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,15 @@
|
|||||||
package net.minestom.server.network.packet.client.login;
|
package net.minestom.server.network.packet.client.login;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.extras.MojangAuth;
|
import net.minestom.server.extras.MojangAuth;
|
||||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||||
import net.minestom.server.network.NetworkBuffer;
|
import net.minestom.server.network.NetworkBuffer;
|
||||||
import net.minestom.server.network.packet.client.ClientPreplayPacket;
|
import net.minestom.server.network.packet.client.ClientPreplayPacket;
|
||||||
|
import net.minestom.server.network.player.GameProfile;
|
||||||
import net.minestom.server.network.player.PlayerConnection;
|
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.async.AsyncUtils;
|
import net.minestom.server.utils.async.AsyncUtils;
|
||||||
@ -20,7 +23,9 @@ import java.net.http.HttpClient;
|
|||||||
import java.net.http.HttpRequest;
|
import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY;
|
import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY;
|
||||||
@ -72,14 +77,22 @@ public record EncryptionResponsePacket(byte[] sharedSecret,
|
|||||||
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).whenComplete((response, throwable) -> {
|
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).whenComplete((response, throwable) -> {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
MinecraftServer.getExceptionManager().handleException(throwable);
|
MinecraftServer.getExceptionManager().handleException(throwable);
|
||||||
//todo disconnect with reason
|
if (socketConnection.getPlayer() != null) {
|
||||||
|
socketConnection.getPlayer().kick(Component.text("Failed to contact Mojang's Session Servers (Are they down?)"));
|
||||||
|
} else {
|
||||||
|
socketConnection.disconnect();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final JsonObject gameProfile = GSON.fromJson(response.body(), JsonObject.class);
|
final JsonObject gameProfile = GSON.fromJson(response.body(), JsonObject.class);
|
||||||
if (gameProfile == null) {
|
if (gameProfile == null) {
|
||||||
// Invalid response
|
// Invalid response
|
||||||
//todo disconnect with reason
|
if (socketConnection.getPlayer() != null) {
|
||||||
|
socketConnection.getPlayer().kick(Component.text("Failed to get data from Mojang's Session Servers (Are they down?)"));
|
||||||
|
} else {
|
||||||
|
socketConnection.disconnect();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
socketConnection.setEncryptionKey(getSecretKey());
|
socketConnection.setEncryptionKey(getSecretKey());
|
||||||
@ -89,6 +102,12 @@ public record EncryptionResponsePacket(byte[] sharedSecret,
|
|||||||
|
|
||||||
MinecraftServer.LOGGER.info("UUID of player {} is {}", loginUsername, profileUUID);
|
MinecraftServer.LOGGER.info("UUID of player {} is {}", loginUsername, profileUUID);
|
||||||
CONNECTION_MANAGER.startPlayState(connection, profileUUID, profileName, true);
|
CONNECTION_MANAGER.startPlayState(connection, profileUUID, profileName, true);
|
||||||
|
List<GameProfile.Property> propertyList = new ArrayList<>();
|
||||||
|
for (JsonElement element : gameProfile.get("properties").getAsJsonArray()) {
|
||||||
|
JsonObject object = element.getAsJsonObject();
|
||||||
|
propertyList.add(new GameProfile.Property(object.get("name").getAsString(), object.get("value").getAsString(), object.get("signature").getAsString()));
|
||||||
|
}
|
||||||
|
socketConnection.UNSAFE_setProfile(new GameProfile(profileUUID, profileName, propertyList));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
MinecraftServer.getExceptionManager().handleException(e);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package net.minestom.server.entity.player;
|
package net.minestom.server.entity.player;
|
||||||
|
|
||||||
|
import net.minestom.server.event.player.PlayerGameModeChangeEvent;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minestom.server.entity.damage.DamageType;
|
import net.minestom.server.entity.damage.DamageType;
|
||||||
import net.minestom.server.message.ChatMessageType;
|
import net.minestom.server.message.ChatMessageType;
|
||||||
import net.minestom.server.network.packet.client.play.ClientSettingsPacket;
|
import net.minestom.server.network.packet.client.play.ClientSettingsPacket;
|
||||||
|
import net.minestom.server.event.player.PlayerGameModeChangeEvent;
|
||||||
import net.minestom.testing.Collector;
|
import net.minestom.testing.Collector;
|
||||||
import net.minestom.testing.Env;
|
import net.minestom.testing.Env;
|
||||||
import net.minestom.testing.EnvTest;
|
import net.minestom.testing.EnvTest;
|
||||||
@ -27,7 +29,8 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||||||
public class PlayerIntegrationTest {
|
public class PlayerIntegrationTest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test to see whether player abilities are updated correctly when changing gamemodes
|
* Test to see whether player abilities are updated correctly and events
|
||||||
|
* are handled properly when changing gamemode.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void gamemodeTest(Env env) {
|
public void gamemodeTest(Env env) {
|
||||||
@ -36,16 +39,38 @@ public class PlayerIntegrationTest {
|
|||||||
var player = connection.connect(instance, new Pos(0, 42, 0)).join();
|
var player = connection.connect(instance, new Pos(0, 42, 0)).join();
|
||||||
assertEquals(instance, player.getInstance());
|
assertEquals(instance, player.getInstance());
|
||||||
|
|
||||||
player.setGameMode(GameMode.CREATIVE);
|
// Abilities
|
||||||
assertAbilities(player, true, false, true, true);
|
{
|
||||||
player.setGameMode(GameMode.SPECTATOR);
|
player.setGameMode(GameMode.CREATIVE);
|
||||||
assertAbilities(player, true, true, true, false);
|
assertAbilities(player, true, false, true, true);
|
||||||
player.setGameMode(GameMode.CREATIVE);
|
player.setGameMode(GameMode.SPECTATOR);
|
||||||
assertAbilities(player, true, true, true, true);
|
assertAbilities(player, true, true, true, false);
|
||||||
player.setGameMode(GameMode.ADVENTURE);
|
player.setGameMode(GameMode.CREATIVE);
|
||||||
assertAbilities(player, false, false, false, false);
|
assertAbilities(player, true, true, true, true);
|
||||||
player.setGameMode(GameMode.SURVIVAL);
|
player.setGameMode(GameMode.ADVENTURE);
|
||||||
assertAbilities(player, false, false, false, false);
|
assertAbilities(player, false, false, false, false);
|
||||||
|
player.setGameMode(GameMode.SURVIVAL);
|
||||||
|
assertAbilities(player, false, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var listener = env.listen(PlayerGameModeChangeEvent.class);
|
||||||
|
// Normal change
|
||||||
|
{
|
||||||
|
listener.followup();
|
||||||
|
assertTrue(player.setGameMode(GameMode.ADVENTURE));
|
||||||
|
}
|
||||||
|
// Change target gamemode event
|
||||||
|
{
|
||||||
|
listener.followup(event -> event.setNewGameMode(GameMode.SPECTATOR));
|
||||||
|
assertTrue(player.setGameMode(GameMode.CREATIVE));
|
||||||
|
assertEquals(GameMode.SPECTATOR, player.getGameMode());
|
||||||
|
}
|
||||||
|
// Cancel event
|
||||||
|
{
|
||||||
|
listener.followup(event -> event.setCancelled(true));
|
||||||
|
assertFalse(player.setGameMode(GameMode.CREATIVE));
|
||||||
|
assertEquals(GameMode.SPECTATOR, player.getGameMode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -165,7 +190,7 @@ public class PlayerIntegrationTest {
|
|||||||
|
|
||||||
assertNull(player.getDeathLocation());
|
assertNull(player.getDeathLocation());
|
||||||
player.damage(DamageType.VOID, 30);
|
player.damage(DamageType.VOID, 30);
|
||||||
|
|
||||||
assertNotNull(player.getDeathLocation());
|
assertNotNull(player.getDeathLocation());
|
||||||
assertEquals(dimensionNamespace, player.getDeathLocation().dimension());
|
assertEquals(dimensionNamespace, player.getDeathLocation().dimension());
|
||||||
assertEquals(5, player.getDeathLocation().position().x());
|
assertEquals(5, player.getDeathLocation().position().x());
|
||||||
|
Loading…
Reference in New Issue
Block a user