diff --git a/patches/api/Add-Player-Client-Options-API.patch b/patches/api/Add-Player-Client-Options-API.patch index d022138b4d..7f3518c2aa 100644 --- a/patches/api/Add-Player-Client-Options-API.patch +++ b/patches/api/Add-Player-Client-Options-API.patch @@ -26,8 +26,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static final ClientOption LOCALE = new ClientOption<>(String.class); + public static final ClientOption MAIN_HAND = new ClientOption<>(MainHand.class); + public static final ClientOption VIEW_DISTANCE = new ClientOption<>(Integer.class); -+ public static final ClientOption ALLOW_SERVER_LISTINGS = new ClientOption<>(Boolean.class); + public static final ClientOption TEXT_FILTERING_ENABLED = new ClientOption<>(Boolean.class); ++ public static final ClientOption ALLOW_SERVER_LISTINGS = new ClientOption<>(Boolean.class); ++ public static final ClientOption PARTICLE_VISIBILITY = new ClientOption<>(ParticleVisibility.class); + + private final Class type; + @@ -60,6 +61,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return "options.chat.visibility." + this.name; + } + } ++ ++ public enum ParticleVisibility implements Translatable { ++ ALL("all"), ++ DECREASED("decreased"), ++ MINIMAL("minimal"); ++ ++ public static final Index NAMES = Index.create(ParticleVisibility.class, particleVisibility -> particleVisibility.name); ++ private final String name; ++ ++ ParticleVisibility(final String name) { ++ this.name = name; ++ } ++ ++ @Override ++ public String translationKey() { ++ return "options.particles." + this.name; ++ } ++ } +} diff --git a/src/main/java/com/destroystokyo/paper/SkinParts.java b/src/main/java/com/destroystokyo/paper/SkinParts.java new file mode 100644 @@ -97,6 +116,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + +import com.destroystokyo.paper.ClientOption; +import com.destroystokyo.paper.ClientOption.ChatVisibility; ++import com.destroystokyo.paper.ClientOption.ParticleVisibility; +import com.destroystokyo.paper.SkinParts; +import java.util.Map; +import org.bukkit.entity.Player; @@ -122,6 +142,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + private final MainHand mainHand; + private final boolean allowsServerListings; + private final boolean textFilteringEnabled; ++ private final ParticleVisibility particleVisibility; + + @Deprecated + public PlayerClientOptionsChangeEvent(final Player player, final String locale, final int viewDistance, final ChatVisibility chatVisibility, final boolean chatColors, final SkinParts skinParts, final MainHand mainHand) { @@ -134,6 +155,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.mainHand = mainHand; + this.allowsServerListings = false; + this.textFilteringEnabled = false; ++ this.particleVisibility = ParticleVisibility.ALL; + } + + @ApiStatus.Internal @@ -148,6 +170,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.mainHand = (MainHand) options.get(ClientOption.MAIN_HAND); + this.allowsServerListings = (boolean) options.get(ClientOption.ALLOW_SERVER_LISTINGS); + this.textFilteringEnabled = (boolean) options.get(ClientOption.TEXT_FILTERING_ENABLED); ++ this.particleVisibility = (ParticleVisibility) options.get(ClientOption.PARTICLE_VISIBILITY); + } + + public String getLocale() { @@ -198,6 +221,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.mainHand != this.player.getClientOption(ClientOption.MAIN_HAND); + } + ++ public boolean hasTextFilteringEnabled() { ++ return this.textFilteringEnabled; ++ } ++ ++ public boolean hasTextFilteringChanged() { ++ return this.textFilteringEnabled != this.player.getClientOption(ClientOption.TEXT_FILTERING_ENABLED); ++ } ++ + public boolean allowsServerListings() { + return this.allowsServerListings; + } @@ -206,12 +237,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.allowsServerListings != this.player.getClientOption(ClientOption.ALLOW_SERVER_LISTINGS); + } + -+ public boolean hasTextFilteringEnabled() { -+ return this.textFilteringEnabled; ++ public ParticleVisibility getParticleVisibility() { ++ return this.particleVisibility; + } + -+ public boolean hasTextFilteringChanged() { -+ return this.textFilteringEnabled != this.player.getClientOption(ClientOption.TEXT_FILTERING_ENABLED); ++ public boolean hasParticleVisibilityChanged() { ++ return this.particleVisibility != this.player.getClientOption(ClientOption.PARTICLE_VISIBILITY); + } + + @Override diff --git a/patches/server/Add-methods-to-get-translation-keys.patch b/patches/server/Add-methods-to-get-translation-keys.patch index 28bd0adfaf..bbee336f52 100644 --- a/patches/server/Add-methods-to-get-translation-keys.patch +++ b/patches/server/Add-methods-to-get-translation-keys.patch @@ -139,23 +139,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import com.destroystokyo.paper.ClientOption; +import java.util.Locale; +import java.util.Map; -+import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.resources.ResourceKey; -+import net.minecraft.resources.ResourceLocation; + import net.minecraft.server.level.ParticleStatus; import net.minecraft.world.entity.player.ChatVisiblity; +import net.minecraft.world.flag.FeatureFlags; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.biome.Biome; - import org.bukkit.Difficulty; ++import org.bukkit.Difficulty; +import org.bukkit.FireworkEffect; +import org.bukkit.GameMode; +import org.bukkit.GameRule; -+import org.bukkit.MusicInstrument; +import org.bukkit.attribute.Attribute; +import org.bukkit.craftbukkit.CraftWorld; -+import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.support.RegistryHelper; +import org.bukkit.support.environment.AllFeatures; import org.junit.jupiter.api.Assertions; @@ -167,7 +164,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Test @@ -0,0 +0,0 @@ public class TranslationKeyTest { - Assertions.assertEquals(ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey(), chatVisibility + "'s translation key doesn't match"); + Assertions.assertEquals(ParticleStatus.valueOf(particleVisibility.name()).getKey(), particleVisibility.translationKey(), particleVisibility + "'s translation key doesn't match"); } } + diff --git a/patches/server/Implement-Player-Client-Options-API.patch b/patches/server/Implement-Player-Client-Options-API.patch index 9f6c0e5ad8..94cf30a03c 100644 --- a/patches/server/Implement-Player-Client-Options-API.patch +++ b/patches/server/Implement-Player-Client-Options-API.patch @@ -5,6 +5,7 @@ Subject: [PATCH] Implement Player Client Options API == AT == public net.minecraft.world.entity.player.Player DATA_PLAYER_MODE_CUSTOMISATION +public net.minecraft.server.level.ServerPlayer particleStatus diff --git a/src/main/java/com/destroystokyo/paper/PaperSkinParts.java b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java new file mode 100644 @@ -100,26 +101,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start @@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - } } -+ // Paper start - Client option API -+ private java.util.Map, ?> getClientOptionMap(String locale, int viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility chatVisibility, boolean chatColors, com.destroystokyo.paper.PaperSkinParts skinParts, org.bukkit.inventory.MainHand mainHand, boolean allowsServerListing, boolean textFilteringEnabled) { -+ java.util.Map, Object> map = new java.util.HashMap<>(); -+ map.put(com.destroystokyo.paper.ClientOption.LOCALE, locale); -+ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, viewDistance); -+ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, chatVisibility); -+ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, chatColors); -+ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, skinParts); -+ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, mainHand); -+ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, allowsServerListing); -+ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, textFilteringEnabled); -+ return map; -+ } -+ // Paper end -+ public void updateOptions(ClientInformation clientOptions) { -+ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(getBukkitEntity(), getClientOptionMap(clientOptions.language(), clientOptions.viewDistance(), com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(clientOptions.chatVisibility().name()), clientOptions.chatColors(), new com.destroystokyo.paper.PaperSkinParts(clientOptions.modelCustomisation()), clientOptions.mainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT, clientOptions.allowsListing(), clientOptions.textFilteringEnabled())).callEvent(); // Paper - settings event ++ // Paper start - settings event ++ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(this.getBukkitEntity(), Util.make(new java.util.IdentityHashMap<>(), map -> { ++ map.put(com.destroystokyo.paper.ClientOption.LOCALE, clientOptions.language()); ++ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, clientOptions.viewDistance()); ++ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(clientOptions.chatVisibility().name())); ++ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, clientOptions.chatColors()); ++ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, new com.destroystokyo.paper.PaperSkinParts(clientOptions.modelCustomisation())); ++ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, clientOptions.mainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT); ++ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, clientOptions.textFilteringEnabled()); ++ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, clientOptions.allowsListing()); ++ map.put(com.destroystokyo.paper.ClientOption.PARTICLE_VISIBILITY, com.destroystokyo.paper.ClientOption.ParticleVisibility.valueOf(clientOptions.particleStatus().name())); ++ })).callEvent(); ++ // Paper end - settings event // CraftBukkit start if (this.getMainArm() != clientOptions.mainHand()) { PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), this.getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT); @@ -147,21 +144,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + @Override + public T getClientOption(com.destroystokyo.paper.ClientOption type) { + if (com.destroystokyo.paper.ClientOption.SKIN_PARTS == type) { -+ return type.getType().cast(new com.destroystokyo.paper.PaperSkinParts(getHandle().getEntityData().get(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION))); ++ return type.getType().cast(new com.destroystokyo.paper.PaperSkinParts(this.getHandle().getEntityData().get(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION))); + } else if (com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED == type) { -+ return type.getType().cast(getHandle().canChatInColor()); ++ return type.getType().cast(this.getHandle().canChatInColor()); + } else if (com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY == type) { -+ return type.getType().cast(getHandle().getChatVisibility() == null ? com.destroystokyo.paper.ClientOption.ChatVisibility.UNKNOWN : com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(getHandle().getChatVisibility().name())); ++ return type.getType().cast(this.getHandle().getChatVisibility() == null ? com.destroystokyo.paper.ClientOption.ChatVisibility.UNKNOWN : com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(this.getHandle().getChatVisibility().name())); + } else if (com.destroystokyo.paper.ClientOption.LOCALE == type) { -+ return type.getType().cast(getLocale()); ++ return type.getType().cast(this.getLocale()); + } else if (com.destroystokyo.paper.ClientOption.MAIN_HAND == type) { -+ return type.getType().cast(getMainHand()); ++ return type.getType().cast(this.getMainHand()); + } else if (com.destroystokyo.paper.ClientOption.VIEW_DISTANCE == type) { -+ return type.getType().cast(getClientViewDistance()); -+ } else if (com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS == type) { -+ return type.getType().cast(getHandle().allowsListing()); ++ return type.getType().cast(this.getClientViewDistance()); + } else if (com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED == type) { -+ return type.getType().cast(getHandle().isTextFilteringEnabled()); ++ return type.getType().cast(this.getHandle().isTextFilteringEnabled()); ++ } else if (com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS == type) { ++ return type.getType().cast(this.getHandle().allowsListing()); ++ } else if (com.destroystokyo.paper.ClientOption.PARTICLE_VISIBILITY == type) { ++ return type.getType().cast(com.destroystokyo.paper.ClientOption.ParticleVisibility.valueOf(this.getHandle().particleStatus.name())); + } + throw new RuntimeException("Unknown settings type"); + } @@ -177,8 +176,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +package io.papermc.paper.world; + +import com.destroystokyo.paper.ClientOption; ++import net.minecraft.server.level.ParticleStatus; +import net.minecraft.world.entity.player.ChatVisiblity; -+import org.bukkit.Difficulty; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + @@ -191,4 +190,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + Assertions.assertEquals(ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey(), chatVisibility + "'s translation key doesn't match"); + } + } ++ ++ @Test ++ public void testParticleVisibilityKeys() { ++ for (ClientOption.ParticleVisibility particleVisibility : ClientOption.ParticleVisibility.values()) { ++ Assertions.assertEquals(ParticleStatus.valueOf(particleVisibility.name()).getKey(), particleVisibility.translationKey(), particleVisibility + "'s translation key doesn't match"); ++ } ++ } +}