From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Samsuik Date: Tue, 21 Sep 2021 23:54:25 +0100 Subject: [PATCH] Visibility API and Command diff --git a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java index 3b08454cf7411d12bb33225df59800bd73312123..22676ec7a7ae9494b198e5e65e6be6d32e0feb85 100644 --- a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java +++ b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java @@ -2,6 +2,9 @@ package me.samsuik.sakura.command; import io.papermc.paper.command.PaperPluginsCommand; import me.samsuik.sakura.command.subcommands.ConfigCommand; +import me.samsuik.sakura.command.subcommands.FPSCommand; +import me.samsuik.sakura.command.subcommands.VisualCommand; +import me.samsuik.sakura.player.visibility.Visibility; import net.minecraft.server.MinecraftServer; import org.bukkit.command.Command; @@ -14,6 +17,10 @@ public final class SakuraCommands { static { COMMANDS.put("sakura", new SakuraCommand("sakura")); COMMANDS.put("config", new ConfigCommand("config")); + COMMANDS.put("fps", new FPSCommand("fps")); + COMMANDS.put("tntvisibility", new VisualCommand(Visibility.Setting.TNT_VISIBILITY, "tnttoggle")); + COMMANDS.put("sandvisibility", new VisualCommand(Visibility.Setting.SAND_VISIBILITY, "sandtoggle")); + COMMANDS.put("minimal", new VisualCommand(Visibility.Setting.MINIMAL, "minimaltnt", "tntlag")); } public static void registerCommands(final MinecraftServer server) { diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..aa5ddf696b09226a0bd3d967d2ac2b11fc2deb32 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java @@ -0,0 +1,26 @@ +package me.samsuik.sakura.command.subcommands; + +import me.samsuik.sakura.command.BaseSubCommand; +import me.samsuik.sakura.player.visibility.VisibilityGUI; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; + +@DefaultQualifier(NonNull.class) +public final class FPSCommand extends BaseSubCommand { + + private final VisibilityGUI VISIBILITY_GUI = new VisibilityGUI(); + + public FPSCommand(String name) { + super(name); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (sender instanceof Player player) { + VISIBILITY_GUI.showTo(player); + } + } + +} diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..148a583279333eeb3e5db16652623082cd5e0e60 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java @@ -0,0 +1,45 @@ +package me.samsuik.sakura.command.subcommands; + +import me.samsuik.sakura.command.BaseSubCommand; +import me.samsuik.sakura.configuration.GlobalConfiguration; +import me.samsuik.sakura.player.visibility.Visibility; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; + +import java.util.Arrays; + +@DefaultQualifier(NonNull.class) +public final class VisualCommand extends BaseSubCommand { + + private final Visibility.Setting type; + + public VisualCommand(Visibility.Setting type, String... aliases) { + super(type.basicName()); + this.setAliases(Arrays.asList(aliases)); + this.type = type; + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (!(sender instanceof Player player)) { + return; + } + + var visibility = player.getVisibility(); + + // Toggle clicked setting visibility + visibility.toggle(type); + + // Send message to player + var state = visibility.isEnabled(type) ? "Enabled" : "Disabled"; + player.sendMessage(MiniMessage.miniMessage().deserialize(GlobalConfiguration.get().fps.message, + Placeholder.unparsed("name", type.friendlyName()), + Placeholder.unparsed("state", state)) + ); + } + +} diff --git a/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGUI.java b/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGUI.java new file mode 100644 index 0000000000000000000000000000000000000000..6f74429456e78f17fa3e4426d9d9b5f008d8df42 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGUI.java @@ -0,0 +1,123 @@ +package me.samsuik.sakura.player.visibility; + +import me.samsuik.sakura.configuration.GlobalConfiguration; +import me.samsuik.sakura.player.gui.ItemIcon; +import me.samsuik.sakura.player.gui.PlayerGUI; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.function.BiFunction; + +public final class VisibilityGUI extends PlayerGUI { + + private static final BiFunction CREATE_INVENTORY = (player, holder) -> { + Inventory inventory = Bukkit.createInventory(holder, 45, Component.text("FPS GUI")); + + for (int i = 0; i < inventory.getSize(); ++i) { + int column = i % 9; + int row = (i + 1) / 9; + + Material background = column > 0 && column < 8 ? (row > 0 && row < 4 || column > 1 && column < 7) + ? Material.matchMaterial(GlobalConfiguration.get().fps.material) + : Material.WHITE_STAINED_GLASS_PANE + : Material.BLACK_STAINED_GLASS_PANE; + + ItemStack itemstack = new ItemStack(background); + ItemMeta meta = itemstack.getItemMeta(); + meta.displayName(Component.space()); + itemstack.setItemMeta(meta); + + inventory.setItem(i, itemstack); + } + + return inventory; + }; + + public VisibilityGUI() { + super(CREATE_INVENTORY); + } + + @Override + protected void register() { + registerFPSIcon(Visibility.Setting.TNT_VISIBILITY, 12); + registerFPSIcon(Visibility.Setting.SAND_VISIBILITY, 14); + registerFPSIcon(Visibility.Setting.MINIMAL, 13); + registerFPSIcon(Visibility.Setting.SPAWNERS, 20); + // ...22 + registerFPSIcon(Visibility.Setting.EXPLOSIONS, 24); + registerFPSIcon(Visibility.Setting.PISTONS, 30); + registerFPSIcon(Visibility.Setting.REDSTONE, 31); + registerFPSIcon(Visibility.Setting.ENCHANTMENT_GLINT, 32); + + registerIcon(new ItemIcon(player -> { + Visibility.State state = player.getVisibility().getState(); + ItemStack itemstack = new ItemStack(state.material()); + + itemstack.editMeta(meta -> { + Component title = Component.text("Toggle all", state.colour()); + + // italic is default + title = title.decoration(TextDecoration.ITALIC, false); + + meta.displayName(title.append(Component.space()) + .append(Component.text(state.title(), NamedTextColor.GRAY))); + }); + + return itemstack; + }, player -> { + player.getVisibility().toggleAll(); + // refresh icons after toggling + this.refresh(player); + }, 26)); + } + + private void registerFPSIcon(Visibility.Setting setting, int slot) { + registerIcon(new ItemIcon(player -> { + Visibility visibility = player.getVisibility(); + ItemStack itemstack = new ItemStack(setting.material()); + + itemstack.editMeta(meta -> { + // Get the current state as a string + String state = visibility.isEnabled(setting) ? "Enabled" : "Disabled"; + + // Friendly name as a component + Component title = Component.text(setting.friendlyName(), setting.colour()); + + // Display names are italic by default + title = title.decoration(TextDecoration.ITALIC, false); + + // Set the display name + meta.displayName(title.append(Component.space()) + .append(Component.text(state, NamedTextColor.GRAY))); + }); + + return itemstack; + }, player -> { + Visibility visibility = player.getVisibility(); + + // Toggle clicked setting visibility + visibility.toggle(setting); + + // Get the current state as a string + String state = visibility.isEnabled(setting) ? "Enabled" : "Disabled"; + + // Send message to player + player.sendRichMessage(GlobalConfiguration.get().fps.message, + Placeholder.unparsed("name", setting.friendlyName()), + Placeholder.unparsed("state", state) + ); + + // Update toggle all icon + this.refreshSlot(player, 26); + }, slot)); + } + +} diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java index 1a37654aff9a9c86c9f7af10a1cf721371f0c5ec..82644b34a77dc5e5af38260b7b07b3ec9aceae33 100644 --- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java +++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java @@ -19,7 +19,7 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet public public ClientboundSectionBlocksUpdatePacket(SectionPos sectionPos, ShortSet positions, LevelChunkSection section) { this.sectionPos = sectionPos; diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index aae93a7f1b7c7744e4cd354b6d070d4f2d4d8843..dd5994f65ef31a41d0f4f06f4990078d4c20a450 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1799,6 +1799,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop recreatePacket(Packet packet) { + me.samsuik.sakura.player.visibility.Visibility visibility = this.player.visibility; + if (packet instanceof ClientboundSetEquipmentPacket equipment && visibility.isToggled(Setting.ENCHANTMENT_GLINT)) { + java.util.List> slots = new java.util.ArrayList<>(); + + for (int i = 0; i < equipment.getSlots().size(); i++) { + Pair pair = equipment.getSlots().get(i); + ItemStack itemstack = pair.getSecond(); + + if (itemstack.isEnchanted()) { + ItemStack copy = itemstack.copy(); + copy.remove(DataComponents.ENCHANTMENTS); + itemstack = copy; + } + + slots.add(new Pair<>(pair.getFirst(), itemstack)); + } + + packet = new ClientboundSetEquipmentPacket(equipment.getEntity(), slots); + } else if (packet instanceof ClientboundBlockEntityDataPacket blockdata + && visibility.isToggled(Setting.SPAWNERS) + && this.player.level().getBlockIfLoaded(blockdata.getPos()) == Blocks.SPAWNER) { + packet = new ClientboundBlockUpdatePacket(blockdata.getPos(), Blocks.BLACK_STAINED_GLASS.defaultBlockState()); + } else if (packet instanceof ClientboundBlockUpdatePacket updatePacket) { + if (visibility.isToggled(Setting.SPAWNERS) && updatePacket.blockState.getBlock() == Blocks.SPAWNER) { + packet = new ClientboundBlockUpdatePacket(updatePacket.getPos(), Blocks.BLACK_STAINED_GLASS.defaultBlockState()); + } else if (visibility.isToggled(Setting.REDSTONE) + && (updatePacket.blockState.getBlock() instanceof DiodeBlock + || updatePacket.blockState.getBlock() instanceof RedStoneWireBlock)) { + return null; + } else if (visibility.isToggled(Setting.PISTONS) + && (updatePacket.blockState.getBlock() instanceof PistonBaseBlock + || updatePacket.blockState.getBlock() instanceof PistonHeadBlock)) { + return null; + } + } else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionPacket) { + for (net.minecraft.world.level.block.state.BlockState state : sectionPacket.states) { + if (visibility.isToggled(Setting.REDSTONE) + && (state.getBlock() instanceof DiodeBlock + || state.getBlock() instanceof RedStoneWireBlock)) { + return null; + } else if (visibility.isToggled(Setting.PISTONS) + && (state.getBlock() instanceof PistonBaseBlock + || state.getBlock() instanceof PistonHeadBlock)) { + return null; + } + } + } else if (packet instanceof ClientboundBlockEventPacket blockevent + && visibility.isToggled(Setting.PISTONS) + && (blockevent.getBlock() instanceof PistonBaseBlock + || blockevent.getBlock() instanceof PistonHeadBlock)) { + return null; + } + + return packet; + } + // Sakura end - visibility api + public CraftPlayer getCraftPlayer() { return (this.player == null) ? null : (CraftPlayer) this.player.getBukkitEntity(); // CraftBukkit end @@ -300,6 +376,12 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack ClientboundSetDefaultSpawnPositionPacket packet6 = (ClientboundSetDefaultSpawnPositionPacket) packet; this.player.compassTarget = CraftLocation.toBukkit(packet6.pos, this.getCraftPlayer().getWorld()); } + // Sakura start - visibility api + if (this.player.visibility.isModified()) { + packet = this.recreatePacket(packet); + if (packet == null) return; + } + // Sakura end - visibility api // CraftBukkit end if (packet.isTerminal()) { this.close(); @@ -313,8 +395,11 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack CrashReport crashreport = CrashReport.forThrowable(throwable, "Sending packet"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Packet being sent"); + // Sakura start - this has to be effectively final as we're modifying the packet above + var packetFinal = packet; crashreportsystemdetails.setDetail("Packet class", () -> { - return packet.getClass().getCanonicalName(); + return packetFinal.getClass().getCanonicalName(); + // Sakura end }); throw new ReportedException(crashreport); } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index dd0610104822bee532542c87ecc9cd16ccf3c216..e513380ae2988d466056fcedc7529b363544337e 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -3172,6 +3172,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl event.setCancelled(cancelled); AbstractContainerMenu oldContainer = this.player.containerMenu; // SPIGOT-1224 + me.samsuik.sakura.player.gui.PlayerGUI.onWindowClick(event); // Sakura - visibility gui this.cserver.getPluginManager().callEvent(event); if (this.player.containerMenu != oldContainer) { return; diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 7ef9f67d27cc240191dd5d07e8dcf5fbdebe1049..c33e325d7eb4584986de338f966a79e868ef300e 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -568,6 +568,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public boolean updatingSectionStatus = false; // Paper end + // Sakura start - visibility api and command + public boolean isPrimedTNT; + public boolean isFallingBlock; + // Sakura end - visibility api and command public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java index d504d10fbe45dfe3f2f3d08d2473df6cd18f6dcf..28b8efdd224e4dbb32f3eac1c9e2c512e2695dc8 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -74,6 +74,7 @@ public class FallingBlockEntity extends Entity { this.blockState = Blocks.SAND.defaultBlockState(); this.dropItem = true; this.fallDamageMax = 40; + this.isFallingBlock = true; // Sakura } public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) { diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java index f1f352ec0e51f5db59254841a06c176c5a876fc9..dace8dc0c051ce9355d878154466ee3a548a3832 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java @@ -37,6 +37,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { public PrimedTnt(EntityType type, Level world) { super(type, world); this.blocksBuilding = true; + this.isPrimedTNT = true; // Sakura } public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) { diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 1059530bb6f817352c8304f6a1544aeb5ac14b30..5a43957309019bec27b9624e5268d6a8c50c165d 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -217,6 +217,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public abstract ResourceKey getTypeKey(); + public final it.unimi.dsi.fastutil.longs.Long2IntMap minimalTNT = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(); // Sakura - visibility api + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, Supplier sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files // Paper - create paper world config; Async-Anti-Xray: Pass executor this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 32c3c2c6b2eaa90b149d9b425341e75b85bd9764..549d4c45d072e95b741ceb79779cd8fac65bf185 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -543,6 +543,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.getHandle().displayName = name == null ? this.getName() : name; } + // Sakura start - visiblity api + @Override + public me.samsuik.sakura.player.visibility.Visibility getVisibility() { + return getHandle().visibility; + } + // Sakura end + // Paper start @Override public void playerListName(net.kyori.adventure.text.Component name) {