From d72f588e17cb792a23321833b18ac71e779d6566 Mon Sep 17 00:00:00 2001 From: aromaa Date: Fri, 2 Jun 2023 22:28:09 +0200 Subject: [PATCH] Implement ChangeDataHolderEvent.ValueChange for GameMode Closes #3563 --- .../server/level/ServerPlayerBridge.java | 2 + .../provider/entity/ServerPlayerData.java | 2 +- .../core/server/level/ServerPlayerMixin.java | 50 ++++++++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/spongepowered/common/bridge/server/level/ServerPlayerBridge.java b/src/main/java/org/spongepowered/common/bridge/server/level/ServerPlayerBridge.java index 3d3c804d140..ad30aae6213 100644 --- a/src/main/java/org/spongepowered/common/bridge/server/level/ServerPlayerBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/server/level/ServerPlayerBridge.java @@ -108,4 +108,6 @@ public interface ServerPlayerBridge extends ServerPlayerEntityHealthScaleBridge void bridge$setSleepingIgnored(final boolean sleepingIgnored); + void bridge$setGameModeNoEvent(final GameType gameType); + } diff --git a/src/main/java/org/spongepowered/common/data/provider/entity/ServerPlayerData.java b/src/main/java/org/spongepowered/common/data/provider/entity/ServerPlayerData.java index c5d08399a47..78243c3d27e 100644 --- a/src/main/java/org/spongepowered/common/data/provider/entity/ServerPlayerData.java +++ b/src/main/java/org/spongepowered/common/data/provider/entity/ServerPlayerData.java @@ -71,7 +71,7 @@ public static void register(final DataProviderRegistrator registrator) { .asMutable(ServerPlayer.class) .create(Keys.GAME_MODE) .get(h -> (GameMode) (Object) h.gameMode.getGameModeForPlayer()) - .set((h, v) -> h.setGameMode((GameType) (Object) v)) + .set((h, v) -> ((ServerPlayerBridge) h).bridge$setGameModeNoEvent((GameType) (Object) v)) .create(Keys.PREVIOUS_GAME_MODE) .get(h -> (GameMode) (Object) h.gameMode.getPreviousGameModeForPlayer()) .create(Keys.SKIN_PROFILE_PROPERTY) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java index 831713b6c76..b2c084a1510 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerPlayerMixin.java @@ -65,6 +65,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.portal.PortalInfo; @@ -76,15 +77,21 @@ import org.spongepowered.api.Sponge; import org.spongepowered.api.adventure.Audiences; import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.data.DataHolder; +import org.spongepowered.api.data.DataTransactionResult; +import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.type.SkinPart; +import org.spongepowered.api.data.value.Value; import org.spongepowered.api.entity.living.Living; import org.spongepowered.api.entity.living.player.chat.ChatVisibility; +import org.spongepowered.api.entity.living.player.gamemode.GameMode; import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.event.Cause; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContextKeys; import org.spongepowered.api.event.SpongeEventFactory; import org.spongepowered.api.event.cause.entity.MovementTypes; +import org.spongepowered.api.event.data.ChangeDataHolderEvent; import org.spongepowered.api.event.entity.ChangeEntityWorldEvent; import org.spongepowered.api.event.entity.DestructEntityEvent; import org.spongepowered.api.event.entity.InteractEntityEvent; @@ -104,6 +111,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -134,6 +142,7 @@ import java.util.HashSet; import java.util.Locale; +import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -164,10 +173,9 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr @Shadow protected abstract void shadow$triggerDimensionChangeTriggers(ServerLevel serverworld); @Shadow public abstract void shadow$doCloseContainer(); @Shadow public abstract void shadow$setServerLevel(ServerLevel serverLevel); + @Shadow public abstract boolean shadow$setGameMode(GameType param0); // @formatter:on - - private net.minecraft.network.chat.@Nullable Component impl$connectionMessage; private Locale impl$language = Locales.DEFAULT; private Scoreboard impl$scoreboard = Sponge.game().server().serverScoreboard().get(); @@ -178,6 +186,7 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr private Set impl$skinParts = ImmutableSet.of(); private final PlayerOwnBorderListener impl$borderListener = new PlayerOwnBorderListener((net.minecraft.server.level.ServerPlayer) (Object) this); private boolean impl$sleepingIgnored; + private boolean impl$noGameModeEvent; @Override public net.minecraft.network.chat.@Nullable Component bridge$getConnectionMessageToSend() { @@ -828,4 +837,41 @@ public void sendMessage(final OutgoingChatMessage $$0, final boolean $$1, final protected void impl$updateHealthForUseFinish(final CallbackInfo ci) { this.bridge$refreshScaledHealth(); } + + @ModifyVariable(method = "setGameMode", at = @At(value = "HEAD"), argsOnly = true) + private GameType impl$setGameMode(final GameType value) { + if (!ShouldFire.CHANGE_DATA_HOLDER_EVENT_VALUE_CHANGE || Objects.equals(this.gameMode.getGameModeForPlayer(), value) || this.impl$noGameModeEvent) { + return value; + } + + final DataTransactionResult transaction = DataTransactionResult.builder() + .replace(Value.immutableOf(Keys.GAME_MODE, (GameMode) (Object) this.gameMode.getGameModeForPlayer())) + .success(Value.immutableOf(Keys.GAME_MODE, (GameMode) (Object) value)) + .result(DataTransactionResult.Type.SUCCESS) + .build(); + + final ChangeDataHolderEvent.ValueChange + event = + SpongeEventFactory.createChangeDataHolderEventValueChange(PhaseTracker.getCauseStackManager().currentCause(), transaction, (DataHolder.Mutable) this); + + Sponge.eventManager().post(event); + + if (event.isCancelled()) { + return this.gameMode.getGameModeForPlayer(); + } + + return (GameType) (Object) event.endResult().successfulValue(Keys.GAME_MODE) + .map(Value::get) + .orElse((GameMode) (Object) value); + } + + @Override + public void bridge$setGameModeNoEvent(final GameType gameType) { + try { + this.impl$noGameModeEvent = true; + this.shadow$setGameMode(gameType); + } finally { + this.impl$noGameModeEvent = false; + } + } }