+ * Copyright (C) Kristian S. Strangeland
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.comphenix.packetwrapper;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.events.PacketContainer;
+import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.wrappers.WrappedDataValue;
+import java.util.List;
+import org.bukkit.World;
+import org.bukkit.entity.Entity;
+
+public class WrapperPlayServerEntityMetadata extends AbstractPacket {
+ public static final PacketType TYPE =
+ PacketType.Play.Server.ENTITY_METADATA;
+
+ public WrapperPlayServerEntityMetadata() {
+ super(new PacketContainer(TYPE), TYPE);
+ handle.getModifier().writeDefaults();
+ }
+
+ public WrapperPlayServerEntityMetadata(PacketContainer packet) {
+ super(packet, TYPE);
+ }
+
+ /**
+ * Retrieve Entity ID.
+ *
+ * Notes: entity's ID
+ *
+ * @return The current Entity ID
+ */
+ public int getEntityID() {
+ return handle.getIntegers().read(0);
+ }
+
+ /**
+ * Set Entity ID.
+ *
+ * @param value - new value.
+ */
+ public void setEntityID(int value) {
+ handle.getIntegers().write(0, value);
+ }
+
+ /**
+ * Retrieve the entity of the painting that will be spawned.
+ *
+ * @param world - the current world of the entity.
+ * @return The spawned entity.
+ */
+ public Entity getEntity(World world) {
+ return handle.getEntityModifier(world).read(0);
+ }
+
+ /**
+ * Retrieve the entity of the painting that will be spawned.
+ *
+ * @param event - the packet event.
+ * @return The spawned entity.
+ */
+ public Entity getEntity(PacketEvent event) {
+ return getEntity(event.getPlayer().getWorld());
+ }
+
+ /**
+ * Retrieve Metadata.
+ *
+ * @return The current Metadata
+ */
+ public List getMetadata() {
+ return handle.getDataValueCollectionModifier().read(0);
+ }
+
+ /**
+ * Set Metadata.
+ *
+ * @param value - new value.
+ */
+ public void setMetadata(List value) {
+ handle.getDataValueCollectionModifier().write(0, value);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/hielkemaps/serverplugin/Main.java b/src/main/java/io/github/hielkemaps/serverplugin/Main.java
index e0ad68b..cc4c633 100644
--- a/src/main/java/io/github/hielkemaps/serverplugin/Main.java
+++ b/src/main/java/io/github/hielkemaps/serverplugin/Main.java
@@ -1,5 +1,6 @@
package io.github.hielkemaps.serverplugin;
+import com.comphenix.protocol.ProtocolLibrary;
import dev.jorel.commandapi.CommandAPI;
import io.github.hielkemaps.serverplugin.commands.*;
import io.github.hielkemaps.serverplugin.events.EventListener;
@@ -9,6 +10,7 @@
import net.kyori.adventure.text.format.TextColor;
import org.black_ixx.playerpoints.PlayerPoints;
import org.black_ixx.playerpoints.PlayerPointsAPI;
+import io.github.hielkemaps.serverplugin.events.PacketListener;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Sound;
@@ -56,6 +58,8 @@ public void onEnable() {
pointsAPI = PlayerPoints.getInstance().getAPI();
loadConfig();
+
+ ProtocolLibrary.getProtocolManager().addPacketListener(new PacketListener(this));
}
public static void loadConfig() {
@@ -77,6 +81,9 @@ public static void loadConfig() {
if (!disabledCommands.contains("highscores")) new Highscores();
else CommandAPI.unregister("highscores");
+ if(!disabledCommands.contains("player_visibility")) new PlayerVisibility();
+ else CommandAPI.unregister("player_visibility");
+
Bukkit.getOnlinePlayers().forEach(CommandAPI::updateRequirements);
}
diff --git a/src/main/java/io/github/hielkemaps/serverplugin/PlayerVisibilityOption.java b/src/main/java/io/github/hielkemaps/serverplugin/PlayerVisibilityOption.java
new file mode 100644
index 0000000..39bc360
--- /dev/null
+++ b/src/main/java/io/github/hielkemaps/serverplugin/PlayerVisibilityOption.java
@@ -0,0 +1,6 @@
+package io.github.hielkemaps.serverplugin;
+
+public enum PlayerVisibilityOption {
+
+ VISIBLE, INVISIBLE, GHOST;
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/hielkemaps/serverplugin/commands/PlayerVisibility.java b/src/main/java/io/github/hielkemaps/serverplugin/commands/PlayerVisibility.java
new file mode 100644
index 0000000..4c643a9
--- /dev/null
+++ b/src/main/java/io/github/hielkemaps/serverplugin/commands/PlayerVisibility.java
@@ -0,0 +1,30 @@
+package io.github.hielkemaps.serverplugin.commands;
+
+import dev.jorel.commandapi.CommandAPICommand;
+import io.github.hielkemaps.serverplugin.PlayerVisibilityOption;
+import io.github.hielkemaps.serverplugin.wrapper.PlayerManager;
+
+public class PlayerVisibility {
+
+ public PlayerVisibility() {
+ new CommandAPICommand("player_visibility")
+ .withAliases("playervisibility", "pv")
+
+ .withSubcommand(new CommandAPICommand("visible")
+ .executesPlayer((p, args) -> {
+ PlayerManager.getPlayer(p.getUniqueId()).setVisibilityOption(PlayerVisibilityOption.VISIBLE);
+ }))
+
+ .withSubcommand(new CommandAPICommand("invisible")
+ .executesPlayer((p, args) -> {
+ PlayerManager.getPlayer(p.getUniqueId()).setVisibilityOption(PlayerVisibilityOption.INVISIBLE);
+ }))
+
+ .withSubcommand(new CommandAPICommand("ghost")
+ .executesPlayer((p, args) -> {
+ PlayerManager.getPlayer(p.getUniqueId()).setVisibilityOption(PlayerVisibilityOption.GHOST);
+ }))
+
+ .register();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/hielkemaps/serverplugin/events/EventListener.java b/src/main/java/io/github/hielkemaps/serverplugin/events/EventListener.java
index 0d08600..cb2b5e1 100644
--- a/src/main/java/io/github/hielkemaps/serverplugin/events/EventListener.java
+++ b/src/main/java/io/github/hielkemaps/serverplugin/events/EventListener.java
@@ -2,7 +2,11 @@
import dev.jorel.commandapi.CommandAPI;
import io.github.hielkemaps.serverplugin.Main;
+import io.github.hielkemaps.serverplugin.PlayerVisibilityOption;
import io.github.hielkemaps.serverplugin.wrapper.PlayerManager;
+import io.github.hielkemaps.serverplugin.wrapper.PlayerWrapper;
+import java.util.Collection;
+import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
@@ -16,9 +20,6 @@
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
-import java.util.Collection;
-import java.util.Set;
-
public class EventListener implements Listener {
Set flowerpots;
@@ -59,6 +60,30 @@ public void onJoin(PlayerJoinEvent e) {
onlinePlayers.forEach(CommandAPI::updateRequirements);
}
}
+
+ PlayerWrapper player = PlayerManager.getPlayer(e.getPlayer().getUniqueId());
+
+ for (Player other : Bukkit.getOnlinePlayers()) {
+ if (!other.getUniqueId().equals(e.getPlayer().getUniqueId())) {
+ PlayerWrapper wrapper = PlayerManager.getPlayer(other.getUniqueId());
+
+ // If the other player has players invisible, hide the new player
+ if (wrapper.getVisibilityOption() == PlayerVisibilityOption.INVISIBLE) {
+ other.hidePlayer(Main.getInstance(), e.getPlayer());
+ } else {
+ other.showPlayer(Main.getInstance(), e.getPlayer());
+ }
+
+ // If the new player has players invisible, hide the other player
+ if (player.getVisibilityOption() == PlayerVisibilityOption.INVISIBLE) {
+ e.getPlayer().hidePlayer(Main.getInstance(), other);
+ } else {
+ e.getPlayer().showPlayer(Main.getInstance(), other);
+ }
+
+ // Don't need to handle ghost players here, as it is handled by the PacketListener
+ }
+ }
}
@EventHandler
diff --git a/src/main/java/io/github/hielkemaps/serverplugin/events/PacketListener.java b/src/main/java/io/github/hielkemaps/serverplugin/events/PacketListener.java
new file mode 100644
index 0000000..95eac7c
--- /dev/null
+++ b/src/main/java/io/github/hielkemaps/serverplugin/events/PacketListener.java
@@ -0,0 +1,70 @@
+package io.github.hielkemaps.serverplugin.events;
+
+import com.comphenix.packetwrapper.WrapperPlayServerEntityMetadata;
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.events.PacketAdapter;
+import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.wrappers.WrappedDataValue;
+import com.comphenix.protocol.wrappers.WrappedDataWatcher;
+import com.comphenix.protocol.wrappers.WrappedWatchableObject;
+import com.google.common.collect.Lists;
+import io.github.hielkemaps.serverplugin.PlayerVisibilityOption;
+import io.github.hielkemaps.serverplugin.wrapper.PlayerManager;
+import io.github.hielkemaps.serverplugin.wrapper.PlayerWrapper;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+public class PacketListener extends PacketAdapter {
+
+ public PacketListener(Plugin plugin) {
+ super(plugin, PacketType.Play.Server.ENTITY_METADATA);
+ }
+
+ @Override
+ public void onPacketSending(final PacketEvent event) {
+ PlayerWrapper player = PlayerManager.getPlayer(event.getPlayer().getUniqueId());
+
+ WrapperPlayServerEntityMetadata packet = new WrapperPlayServerEntityMetadata(event.getPacket());
+ Entity entity = packet.getEntity(event);
+
+ // Check if the entity is a player and if it is not the player that is sending the packet
+ if (entity instanceof Player) {
+ if (!entity.getUniqueId().equals(event.getPlayer().getUniqueId())) {
+ for (WrappedDataValue watchedObject : packet.getMetadata()) {
+
+ // Index 0 is the bitmask that contains the visibility flag (0x20)
+ if (watchedObject.getIndex() == 0) {
+ if (player.getVisibilityOption() == PlayerVisibilityOption.GHOST) {
+ if (((byte) watchedObject.getValue() & 0x20) != 0x20) {
+ WrapperPlayServerEntityMetadata newPacket = new WrapperPlayServerEntityMetadata();
+ newPacket.setMetadata(Lists.newArrayList(
+ new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) ((byte) watchedObject.getRawValue() | 0x20))
+ ));
+
+ newPacket.setEntityID(packet.getEntityID());
+ newPacket.sendPacket(event.getPlayer());
+
+ event.setCancelled(true);
+ }
+ } else {
+ if (((byte) watchedObject.getRawValue() & 0x20) == 0x20) {
+ WrapperPlayServerEntityMetadata newPacket = new WrapperPlayServerEntityMetadata();
+ newPacket.setMetadata(Lists.newArrayList(
+ new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) ((byte) watchedObject.getRawValue() & (0xFF - 0x20)))
+ ));
+
+ newPacket.setEntityID(packet.getEntityID());
+ newPacket.sendPacket(event.getPlayer());
+
+ event.setCancelled(true);
+ }
+ }
+
+ return;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/hielkemaps/serverplugin/wrapper/PlayerWrapper.java b/src/main/java/io/github/hielkemaps/serverplugin/wrapper/PlayerWrapper.java
index 0c1e406..50d68fc 100644
--- a/src/main/java/io/github/hielkemaps/serverplugin/wrapper/PlayerWrapper.java
+++ b/src/main/java/io/github/hielkemaps/serverplugin/wrapper/PlayerWrapper.java
@@ -1,7 +1,17 @@
package io.github.hielkemaps.serverplugin.wrapper;
+import com.comphenix.packetwrapper.WrapperPlayServerEntityMetadata;
+import com.comphenix.protocol.wrappers.WrappedDataValue;
+import com.comphenix.protocol.wrappers.WrappedDataWatcher;
+import com.google.common.collect.Lists;
import dev.jorel.commandapi.CommandAPI;
+import io.github.hielkemaps.serverplugin.Main;
+import io.github.hielkemaps.serverplugin.PlayerVisibilityOption;
+import java.util.List;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.TextColor;
import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.util.HashSet;
@@ -14,6 +24,8 @@ public class PlayerWrapper {
private final Set outgoing = new HashSet<>();
private boolean getCoins = true;
+ private PlayerVisibilityOption visibilityOption = PlayerVisibilityOption.VISIBLE;
+
public PlayerWrapper(UUID uuid) {
this.uuid = uuid;
}
@@ -76,9 +88,68 @@ public void clearOutgoing() {
}
public void updateRequirements() {
- Player player = Bukkit.getPlayer(this.uuid);
+ Player player = getPlayer();
if (player != null) {
CommandAPI.updateRequirements(player);
}
}
+
+ public Player getPlayer() {
+ return Bukkit.getPlayer(this.uuid);
+ }
+
+ public PlayerVisibilityOption getVisibilityOption() {
+ return this.visibilityOption;
+ }
+
+ public void setVisibilityOption(PlayerVisibilityOption option) {
+ Player player = getPlayer();
+
+ if (player != null) {
+ if (this.visibilityOption == option) {
+ player.sendMessage(Component.text("Players are already set to " + option.toString().toLowerCase() + "!").color(TextColor.fromHexString("#FF0000")));
+ return;
+ }
+
+ this.visibilityOption = option;
+
+ switch (option) {
+ case VISIBLE -> {
+ List data = Lists.newArrayList(new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0));
+
+ for (Player other : Bukkit.getOnlinePlayers()) {
+ if (!other.getUniqueId().equals(uuid)) {
+ player.showPlayer(Main.getInstance(), other);
+
+ WrapperPlayServerEntityMetadata packet = new WrapperPlayServerEntityMetadata();
+ packet.setEntityID(other.getEntityId());
+ packet.setMetadata(data);
+ packet.sendPacket(player);
+ }
+ }
+ }
+ case GHOST -> {
+ List data = Lists.newArrayList(new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 20));
+
+ for (Player other : Bukkit.getOnlinePlayers()) {
+ if (!other.getUniqueId().equals(uuid)) {
+ player.showPlayer(Main.getInstance(), other);
+
+ WrapperPlayServerEntityMetadata packet = new WrapperPlayServerEntityMetadata();
+ packet.setEntityID(other.getEntityId());
+ packet.setMetadata(data);
+ packet.sendPacket(player);
+ }
+ }
+ }
+ case INVISIBLE -> {
+ for (Player other : Bukkit.getOnlinePlayers()) {
+ if (!other.getUniqueId().equals(uuid)) {
+ player.hidePlayer(Main.getInstance(), other);
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index a596297..5fe05df 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -3,4 +3,4 @@ main: io.github.hielkemaps.serverplugin.Main
version: 1.1.2
author: Hielke
api-version: '1.20'
-depend: [CommandAPI,PlayerPoints]
\ No newline at end of file
+depend: [CommandAPI,PlayerPoints,ProtocolLib]
\ No newline at end of file
diff --git a/target/classes/io/github/hielkemaps/serverplugin/Main.class b/target/classes/io/github/hielkemaps/serverplugin/Main.class
index 02748aa..d0914e3 100644
Binary files a/target/classes/io/github/hielkemaps/serverplugin/Main.class and b/target/classes/io/github/hielkemaps/serverplugin/Main.class differ
diff --git a/target/classes/io/github/hielkemaps/serverplugin/commands/Highscores.class b/target/classes/io/github/hielkemaps/serverplugin/commands/Highscores.class
index 4a2b386..85e41b4 100644
Binary files a/target/classes/io/github/hielkemaps/serverplugin/commands/Highscores.class and b/target/classes/io/github/hielkemaps/serverplugin/commands/Highscores.class differ
diff --git a/target/classes/io/github/hielkemaps/serverplugin/commands/Hub.class b/target/classes/io/github/hielkemaps/serverplugin/commands/Hub.class
index fc88796..804b144 100644
Binary files a/target/classes/io/github/hielkemaps/serverplugin/commands/Hub.class and b/target/classes/io/github/hielkemaps/serverplugin/commands/Hub.class differ
diff --git a/target/classes/io/github/hielkemaps/serverplugin/commands/Spectate.class b/target/classes/io/github/hielkemaps/serverplugin/commands/Spectate.class
index a0b6e7f..be798da 100644
Binary files a/target/classes/io/github/hielkemaps/serverplugin/commands/Spectate.class and b/target/classes/io/github/hielkemaps/serverplugin/commands/Spectate.class differ
diff --git a/target/classes/io/github/hielkemaps/serverplugin/commands/Tpa.class b/target/classes/io/github/hielkemaps/serverplugin/commands/Tpa.class
index 97914b8..527fe2b 100644
Binary files a/target/classes/io/github/hielkemaps/serverplugin/commands/Tpa.class and b/target/classes/io/github/hielkemaps/serverplugin/commands/Tpa.class differ
diff --git a/target/classes/io/github/hielkemaps/serverplugin/events/EventListener.class b/target/classes/io/github/hielkemaps/serverplugin/events/EventListener.class
index fd19d76..b82fecd 100644
Binary files a/target/classes/io/github/hielkemaps/serverplugin/events/EventListener.class and b/target/classes/io/github/hielkemaps/serverplugin/events/EventListener.class differ
diff --git a/target/classes/io/github/hielkemaps/serverplugin/objects/ScorePair.class b/target/classes/io/github/hielkemaps/serverplugin/objects/ScorePair.class
index 6c919f8..1337e4e 100644
Binary files a/target/classes/io/github/hielkemaps/serverplugin/objects/ScorePair.class and b/target/classes/io/github/hielkemaps/serverplugin/objects/ScorePair.class differ
diff --git a/target/classes/io/github/hielkemaps/serverplugin/wrapper/PlayerManager.class b/target/classes/io/github/hielkemaps/serverplugin/wrapper/PlayerManager.class
index b92e204..d1d0217 100644
Binary files a/target/classes/io/github/hielkemaps/serverplugin/wrapper/PlayerManager.class and b/target/classes/io/github/hielkemaps/serverplugin/wrapper/PlayerManager.class differ
diff --git a/target/classes/io/github/hielkemaps/serverplugin/wrapper/PlayerWrapper.class b/target/classes/io/github/hielkemaps/serverplugin/wrapper/PlayerWrapper.class
index 4063213..eeb3692 100644
Binary files a/target/classes/io/github/hielkemaps/serverplugin/wrapper/PlayerWrapper.class and b/target/classes/io/github/hielkemaps/serverplugin/wrapper/PlayerWrapper.class differ
diff --git a/target/classes/plugin.yml b/target/classes/plugin.yml
index e41cabf..d1d59ac 100644
--- a/target/classes/plugin.yml
+++ b/target/classes/plugin.yml
@@ -3,4 +3,4 @@ main: io.github.hielkemaps.serverplugin.Main
version: 1.1.0
author: Hielke
api-version: '1.20'
-depend: [CommandAPI,PlayerPoints]
\ No newline at end of file
+depend: [CommandAPI,PlayerPoints,ProtocolLib]
diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties
index 3dce227..b801228 100644
--- a/target/maven-archiver/pom.properties
+++ b/target/maven-archiver/pom.properties
@@ -1,5 +1,5 @@
#Generated by Maven
-#Tue Jul 25 15:47:51 CST 2023
+#Thu Jan 11 16:52:17 GMT 2024
groupId=io.github.hielkemaps
artifactId=ServerPlugin
-version=1.1.0
+version=1.1.2
diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
index 2765363..05afe29 100644
--- a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
+++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -1,10 +1,16 @@
io\github\hielkemaps\serverplugin\wrapper\PlayerManager.class
-io\github\hielkemaps\serverplugin\commands\Hub.class
+io\github\hielkemaps\serverplugin\events\PacketListener.class
io\github\hielkemaps\serverplugin\wrapper\PlayerWrapper.class
io\github\hielkemaps\serverplugin\commands\Highscores.class
io\github\hielkemaps\serverplugin\commands\Spectate.class
-io\github\hielkemaps\serverplugin\Main.class
+com\comphenix\packetwrapper\WrapperPlayServerEntityMetadata.class
io\github\hielkemaps\serverplugin\objects\ScorePair.class
io\github\hielkemaps\serverplugin\events\EventListener.class
-io\github\hielkemaps\serverplugin\commands\ReloadConfig.class
io\github\hielkemaps\serverplugin\commands\Tpa.class
+io\github\hielkemaps\serverplugin\PlayerVisibilityOption.class
+io\github\hielkemaps\serverplugin\wrapper\PlayerWrapper$1.class
+io\github\hielkemaps\serverplugin\commands\Hub.class
+io\github\hielkemaps\serverplugin\commands\PlayerVisibility.class
+io\github\hielkemaps\serverplugin\Main.class
+io\github\hielkemaps\serverplugin\commands\ReloadConfig.class
+com\comphenix\packetwrapper\AbstractPacket.class