summaryrefslogtreewikicommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/net/tylermurphy/hideAndSeek/Main.java61
-rw-r--r--src/main/java/net/tylermurphy/hideAndSeek/game/Board.java2
-rw-r--r--src/main/java/net/tylermurphy/hideAndSeek/game/Disguiser.java67
-rw-r--r--src/main/java/net/tylermurphy/hideAndSeek/game/EntityHider.java282
-rw-r--r--src/main/java/net/tylermurphy/hideAndSeek/game/PlayerLoader.java3
-rw-r--r--src/main/java/net/tylermurphy/hideAndSeek/game/listener/DamageHandler.java3
-rw-r--r--src/main/java/net/tylermurphy/hideAndSeek/game/listener/DisguiseHandler.java212
-rw-r--r--src/main/java/net/tylermurphy/hideAndSeek/game/util/Disguise.java143
8 files changed, 658 insertions, 115 deletions
diff --git a/src/main/java/net/tylermurphy/hideAndSeek/Main.java b/src/main/java/net/tylermurphy/hideAndSeek/Main.java
index dc36752..9a589ae 100644
--- a/src/main/java/net/tylermurphy/hideAndSeek/Main.java
+++ b/src/main/java/net/tylermurphy/hideAndSeek/Main.java
@@ -23,12 +23,9 @@ import net.tylermurphy.hideAndSeek.configuration.Config;
import net.tylermurphy.hideAndSeek.configuration.Items;
import net.tylermurphy.hideAndSeek.configuration.Localization;
import net.tylermurphy.hideAndSeek.database.Database;
-import net.tylermurphy.hideAndSeek.game.Board;
-import net.tylermurphy.hideAndSeek.game.Disguiser;
-import net.tylermurphy.hideAndSeek.game.PlayerLoader;
+import net.tylermurphy.hideAndSeek.game.*;
import net.tylermurphy.hideAndSeek.game.util.Status;
import net.tylermurphy.hideAndSeek.util.CommandHandler;
-import net.tylermurphy.hideAndSeek.game.Game;
import net.tylermurphy.hideAndSeek.game.listener.*;
import net.tylermurphy.hideAndSeek.util.PAPIExpansion;
import net.tylermurphy.hideAndSeek.util.TabCompleter;
@@ -55,46 +52,23 @@ public class Main extends JavaPlugin implements Listener {
private static Main instance;
private static int version;
- private final Database database;
- private final Board board;
- private final Disguiser disguiser;
-
+ private Database database;
+ private Board board;
+ private Disguiser disguiser;
+ private EntityHider entityHider;
private Game game;
- public Main() {
- super();
- onConstructed();
- board = new Board();
- database = new Database();
- disguiser = new Disguiser();
- }
-
- protected Main(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
- super(loader, description, dataFolder, file);
- onConstructed();
- board = new Board();
- database = new Database();
- disguiser = new Disguiser();
- }
-
- private void onConstructed(){
-
- instance = this;
-
- Matcher matcher = Pattern.compile("MC: \\d\\.(\\d+)").matcher(Bukkit.getVersion());
- if (matcher.find()) {
- version = Integer.parseInt(matcher.group(1));
- } else {
- throw new IllegalArgumentException("Failed to parse server version from: " + Bukkit.getVersion());
- }
-
+ public void onEnable() {
+ Main.instance = this;
Config.loadConfig();
Localization.loadLocalization();
Items.loadItems();
- }
-
- public void onEnable() {
+ this.updateVersion();
+ this.board = new Board();
+ this.database = new Database();
+ this.disguiser = new Disguiser();
+ this.entityHider = new EntityHider(this, EntityHider.Policy.BLACKLIST);
this.registerListeners();
CommandHandler.registerCommands();
@@ -142,6 +116,15 @@ public class Main extends JavaPlugin implements Listener {
getServer().getPluginManager().registerEvents(new PlayerHandler(), this);
getServer().getPluginManager().registerEvents(new RespawnHandler(), this);
}
+
+ private void updateVersion(){
+ Matcher matcher = Pattern.compile("MC: \\d\\.(\\d+)").matcher(Bukkit.getVersion());
+ if (matcher.find()) {
+ version = Integer.parseInt(matcher.group(1));
+ } else {
+ throw new IllegalArgumentException("Failed to parse server version from: " + Bukkit.getVersion());
+ }
+ }
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
return CommandHandler.handleCommand(sender, args);
@@ -173,6 +156,8 @@ public class Main extends JavaPlugin implements Listener {
public Disguiser getDisguiser() { return disguiser; }
+ public EntityHider getEntityHider() { return entityHider; }
+
public boolean supports(int v){
return version >= v;
}
diff --git a/src/main/java/net/tylermurphy/hideAndSeek/game/Board.java b/src/main/java/net/tylermurphy/hideAndSeek/game/Board.java
index c6aaaf5..050faa8 100644
--- a/src/main/java/net/tylermurphy/hideAndSeek/game/Board.java
+++ b/src/main/java/net/tylermurphy/hideAndSeek/game/Board.java
@@ -401,6 +401,8 @@ class CustomBoard {
hiderTeam.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.NEVER);
seekerTeam.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.NEVER);
}
+ hiderTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
+ seekerTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
} else {
if (nameTagsVisible) {
hiderTeam.setNameTagVisibility(NameTagVisibility.HIDE_FOR_OTHER_TEAMS);
diff --git a/src/main/java/net/tylermurphy/hideAndSeek/game/Disguiser.java b/src/main/java/net/tylermurphy/hideAndSeek/game/Disguiser.java
index b4f70ad..a8ac441 100644
--- a/src/main/java/net/tylermurphy/hideAndSeek/game/Disguiser.java
+++ b/src/main/java/net/tylermurphy/hideAndSeek/game/Disguiser.java
@@ -1,62 +1,69 @@
package net.tylermurphy.hideAndSeek.game;
+import net.tylermurphy.hideAndSeek.game.util.Disguise;
+import org.bukkit.Location;
import org.bukkit.Material;
-import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Player;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
+import org.bukkit.util.BlockVector;
+import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
+import java.util.Vector;
public class Disguiser {
- private final Map<Player, FallingBlock> blocks;
+ private final Map<Player, Disguise> disguises;
public Disguiser(){
- this.blocks = new HashMap<>();
+ this.disguises = new HashMap<>();
}
- public FallingBlock getBlock(Player player){
- return blocks.get(player);
+ public Disguise getDisguise(Player player){
+ return disguises.get(player);
}
- public boolean contains(FallingBlock block) { return blocks.containsValue(block); }
+ public boolean disguised(Player player) { return disguises.containsKey(player); }
- public boolean disguised(Player player) { return blocks.containsKey(player); }
+ @Nullable
+ public Disguise getByEntityID(int ID){
+ return disguises.values().stream().filter(disguise -> disguise.getEntityID() == ID).findFirst().orElse(null);
+ }
+
+ @Nullable
+ public Disguise getByBlockLocation(BlockVector loc){
+ return disguises.values().stream().filter(disguise -> {
+ if(disguise.getSolidLocation() == null) return false;
+ return disguise.getSolidLocation().toVector().toBlockVector() == loc;
+ }).findFirst().orElse(null);
+ }
public void check(){
- for(Map.Entry<Player, FallingBlock> set : blocks.entrySet()){
+ for(Map.Entry<Player, Disguise> set : disguises.entrySet()){
+ Disguise disguise = set.getValue();
Player player = set.getKey();
- FallingBlock block = set.getValue();
- if(block.isDead()){
- block.remove();
- FallingBlock replacement = player.getLocation().getWorld().spawnFallingBlock(player.getLocation(), block.getMaterial(), (byte)0);
- replacement.setGravity(false);
- replacement.setDropItem(false);
- blocks.put(player, replacement);
+ if(!player.isOnline()) {
+ disguise.remove();
+ disguises.remove(player);
+ } else {
+ disguise.update();
}
}
}
public void disguise(Player player, Material material){
- if(blocks.containsKey(player)){
- FallingBlock block = blocks.get(player);
- block.remove();
+ if(disguises.containsKey(player)){
+ disguises.get(player).remove();
}
- FallingBlock block = player.getLocation().getWorld().spawnFallingBlock(player.getLocation(), material, (byte)0);
- block.setGravity(false);
- block.setDropItem(false);
- blocks.put(player, block);
- player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 1000000, 0,false, false));
+ Disguise disguise = new Disguise(player, material);
+ disguises.put(player, disguise);
}
public void reveal(Player player){
- if(!blocks.containsKey(player)) return;
- FallingBlock block = blocks.get(player);
- block.remove();
- blocks.remove(player);
- player.removePotionEffect(PotionEffectType.INVISIBILITY);
+ if(disguises.containsKey(player))
+ disguises.get(player).remove();
+ disguises.remove(player);
}
}
diff --git a/src/main/java/net/tylermurphy/hideAndSeek/game/EntityHider.java b/src/main/java/net/tylermurphy/hideAndSeek/game/EntityHider.java
new file mode 100644
index 0000000..9dcb0ab
--- /dev/null
+++ b/src/main/java/net/tylermurphy/hideAndSeek/game/EntityHider.java
@@ -0,0 +1,282 @@
+package net.tylermurphy.hideAndSeek.game;
+
+import static com.comphenix.protocol.PacketType.Play.Server.*;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.Map;
+
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDeathEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.world.ChunkUnloadEvent;
+import org.bukkit.plugin.Plugin;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.ProtocolManager;
+import com.comphenix.protocol.events.PacketAdapter;
+import com.comphenix.protocol.events.PacketContainer;
+import com.comphenix.protocol.events.PacketEvent;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+
+public class EntityHider implements Listener {
+ protected Table<Integer, Integer, Boolean> observerEntityMap = HashBasedTable.create();
+
+ private static final PacketType[] ENTITY_PACKETS = {
+ ENTITY_EQUIPMENT, BED, ANIMATION, NAMED_ENTITY_SPAWN,
+ COLLECT, SPAWN_ENTITY, SPAWN_ENTITY_LIVING, SPAWN_ENTITY_PAINTING, SPAWN_ENTITY_EXPERIENCE_ORB,
+ ENTITY_VELOCITY, REL_ENTITY_MOVE, ENTITY_LOOK, ENTITY_MOVE_LOOK, ENTITY_MOVE_LOOK,
+ ENTITY_TELEPORT, ENTITY_HEAD_ROTATION, ENTITY_STATUS, ATTACH_ENTITY, ENTITY_METADATA,
+ ENTITY_EFFECT, REMOVE_ENTITY_EFFECT, BLOCK_BREAK_ANIMATION
+ };
+
+ public enum Policy {
+ WHITELIST,
+ BLACKLIST,
+ }
+
+ private ProtocolManager manager;
+
+ private final Listener bukkitListener;
+ private final PacketAdapter protocolListener;
+
+ protected final Policy policy;
+
+ public EntityHider(Plugin plugin, Policy policy) {
+ Preconditions.checkNotNull(plugin, "plugin cannot be NULL.");
+
+ // Save policy
+ this.policy = policy;
+ this.manager = ProtocolLibrary.getProtocolManager();
+
+ // Register events and packet listener
+ plugin.getServer().getPluginManager().registerEvents(
+ bukkitListener = constructBukkit(), plugin);
+ manager.addPacketListener(
+ protocolListener = constructProtocol(plugin));
+ }
+
+ /**
+ * Set the visibility status of a given entity for a particular observer.
+ * @param observer - the observer player.
+ * @param entityID - ID of the entity that will be hidden or made visible.
+ * @param visible - TRUE if the entity should be made visible, FALSE if not.
+ * @return TRUE if the entity was visible before this method call, FALSE otherwise.
+ */
+ protected boolean setVisibility(Player observer, int entityID, boolean visible) {
+ switch (policy) {
+ case BLACKLIST:
+ // Non-membership means they are visible
+ return !setMembership(observer, entityID, !visible);
+ case WHITELIST:
+ return setMembership(observer, entityID, visible);
+ default :
+ throw new IllegalArgumentException("Unknown policy: " + policy);
+ }
+ }
+
+ /**
+ * Add or remove the given entity and observer entry from the table.
+ * @param observer - the player observer.
+ * @param entityID - ID of the entity.
+ * @param member - TRUE if they should be present in the table, FALSE otherwise.
+ * @return TRUE if they already were present, FALSE otherwise.
+ */
+ protected boolean setMembership(Player observer, int entityID, boolean member) {
+ if (member) {
+ return observerEntityMap.put(observer.getEntityId(), entityID, true) != null;
+ } else {
+ return observerEntityMap.remove(observer.getEntityId(), entityID) != null;
+ }
+ }
+
+ /**
+ * Determine if the given entity and observer is present in the table.
+ * @param observer - the player observer.
+ * @param entityID - ID of the entity.
+ * @return TRUE if they are present, FALSE otherwise.
+ */
+ protected boolean getMembership(Player observer, int entityID) {
+ return observerEntityMap.contains(observer.getEntityId(), entityID);
+ }
+
+ /**
+ * Determine if a given entity is visible for a particular observer.
+ * @param observer - the observer player.
+ * @param entityID - ID of the entity that we are testing for visibility.
+ * @return TRUE if the entity is visible, FALSE otherwise.
+ */
+ protected boolean isVisible(Player observer, int entityID) {
+ // If we are using a whitelist, presence means visibility - if not, the opposite is the case
+ boolean presence = getMembership(observer, entityID);
+
+ return (policy == Policy.WHITELIST) == presence;
+ }
+
+ /**
+ * Remove the given entity from the underlying map.
+ * @param entity - the entity to remove.
+ */
+ protected void removeEntity(Entity entity) {
+ int entityID = entity.getEntityId();
+
+ for (Map<Integer, Boolean> maps : observerEntityMap.rowMap().values()) {
+ maps.remove(entityID);
+ }
+ }
+
+ /**
+ * Invoked when a player logs out.
+ * @param player - the player that jused logged out.
+ */
+ protected void removePlayer(Player player) {
+ // Cleanup
+ observerEntityMap.rowMap().remove(player.getEntityId());
+ }
+
+ /**
+ * Construct the Bukkit event listener.
+ * @return Our listener.
+ */
+ private Listener constructBukkit() {
+ return new Listener() {
+ @EventHandler
+ public void onEntityDeath(EntityDeathEvent e) {
+ removeEntity(e.getEntity());
+ }
+
+ @EventHandler
+ public void onChunkUnload(ChunkUnloadEvent e) {
+ for (Entity entity : e.getChunk().getEntities()) {
+ removeEntity(entity);
+ }
+ }
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent e) {
+ removePlayer(e.getPlayer());
+ }
+ };
+ }
+
+ /**
+ * Construct the packet listener that will be used to intercept every entity-related packet.
+ * @param plugin - the parent plugin.
+ * @return The packet listener.
+ */
+ private PacketAdapter constructProtocol(Plugin plugin) {
+ return new PacketAdapter(plugin, ENTITY_PACKETS) {
+ @Override
+ public void onPacketSending(PacketEvent event) {
+ int entityID = event.getPacket().getIntegers().read(0);
+
+ // See if this packet should be cancelled
+ if (!isVisible(event.getPlayer(), entityID)) {
+ event.setCancelled(true);
+ }
+ }
+ };
+ }
+
+ /**
+ * Toggle the visibility status of an entity for a player.
+ * <p>
+ * If the entity is visible, it will be hidden. If it is hidden, it will become visible.
+ * @param observer - the player observer.
+ * @param entity - the entity to toggle.
+ * @return TRUE if the entity was visible before, FALSE otherwise.
+ */
+ public final boolean toggleEntity(Player observer, Entity entity) {
+ if (isVisible(observer, entity.getEntityId())) {
+ return hideEntity(observer, entity);
+ } else {
+ return !showEntity(observer, entity);
+ }
+ }
+
+ /**
+ * Allow the observer to see an entity that was previously hidden.
+ * @param observer - the observer.
+ * @param entity - the entity to show.
+ * @return TRUE if the entity was hidden before, FALSE otherwise.
+ */
+ public final boolean showEntity(Player observer, Entity entity) {
+ validate(observer, entity);
+ boolean hiddenBefore = !setVisibility(observer, entity.getEntityId(), true);
+
+ // Resend packets
+ if (manager != null && hiddenBefore) {
+ manager.updateEntity(entity, Arrays.asList(observer));
+ }
+ return hiddenBefore;
+ }
+
+ /**
+ * Prevent the observer from seeing a given entity.
+ * @param observer - the player observer.
+ * @param entity - the entity to hide.
+ * @return TRUE if the entity was previously visible, FALSE otherwise.
+ */
+ public final boolean hideEntity(Player observer, Entity entity) {
+ validate(observer, entity);
+ boolean visibleBefore = setVisibility(observer, entity.getEntityId(), false);
+
+ if (visibleBefore) {
+ PacketContainer destroyEntity = new PacketContainer(ENTITY_DESTROY);
+ try {
+ destroyEntity.getIntegerArrays().write(0, new int[]{entity.getEntityId()});
+ } catch (Exception e){ return false; }
+ // Make the entity disappear
+ try {
+ manager.sendServerPacket(observer, destroyEntity);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException("Cannot send server packet.", e);
+ }
+ }
+ return visibleBefore;
+ }
+
+ /**
+ * Determine if the given entity has been hidden from an observer.
+ * <p>
+ * Note that the entity may very well be occluded or out of range from the perspective
+ * of the observer. This method simply checks if an entity has been completely hidden
+ * for that observer.
+ * @param observer - the observer.
+ * @param entity - the entity that may be hidden.
+ * @return TRUE if the player may see the entity, FALSE if the entity has been hidden.
+ */
+ public final boolean canSee(Player observer, Entity entity) {
+ validate(observer, entity);
+
+ return isVisible(observer, entity.getEntityId());
+ }
+
+ private void validate(Player observer, Entity entity) {
+ Preconditions.checkNotNull(observer, "observer cannot be NULL.");
+ Preconditions.checkNotNull(entity, "entity cannot be NULL.");
+ }
+
+ /**
+ * Retrieve the current visibility policy.
+ * @return The current visibility policy.
+ */
+ public Policy getPolicy() {
+ return policy;
+ }
+
+ public void close() {
+ if (manager != null) {
+ HandlerList.unregisterAll(bukkitListener);
+ manager.removePacketListener(protocolListener);
+ manager = null;
+ }
+ }
+}
diff --git a/src/main/java/net/tylermurphy/hideAndSeek/game/PlayerLoader.java b/src/main/java/net/tylermurphy/hideAndSeek/game/PlayerLoader.java
index 2ddfeca..0447111 100644
--- a/src/main/java/net/tylermurphy/hideAndSeek/game/PlayerLoader.java
+++ b/src/main/java/net/tylermurphy/hideAndSeek/game/PlayerLoader.java
@@ -99,6 +99,7 @@ public class PlayerLoader {
public static void unloadPlayer(Player player){
player.setGameMode(GameMode.ADVENTURE);
player.getInventory().clear();
+ Main.getInstance().getDisguiser().reveal(player);
for(PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
}
@@ -135,6 +136,8 @@ public class PlayerLoader {
player.setGameMode(GameMode.ADVENTURE);
player.getInventory().clear();
for(PotionEffect effect : player.getActivePotionEffects()) {
+ Main.getInstance().getLogger().severe(player.getName() + " " + effect.getType());
+ if(effect.getType().getName().equals("INVISIBILITY") && Main.getInstance().getDisguiser().disguised(player)) continue;
player.removePotionEffect(effect.getType());
}
player.setFoodLevel(20);
diff --git a/src/main/java/net/tylermurphy/hideAndSeek/game/listener/DamageHandler.java b/src/main/java/net/tylermurphy/hideAndSeek/game/listener/DamageHandler.java
index f09e112..cb4cba5 100644
--- a/src/main/java/net/tylermurphy/hideAndSeek/game/listener/DamageHandler.java
+++ b/src/main/java/net/tylermurphy/hideAndSeek/game/listener/DamageHandler.java
@@ -25,10 +25,8 @@ public class DamageHandler implements Listener {
@EventHandler(priority = EventPriority.HIGHEST)
public void onEntityDamage(EntityDamageEvent event) {
-
Board board = Main.getInstance().getBoard();
Game game = Main.getInstance().getGame();
-
// If you are not a player, get out of here
if (!(event.getEntity() instanceof Player)) return;
// Define variables
@@ -46,6 +44,7 @@ public class DamageHandler implements Listener {
}
// Makes sure that if there was an attacking player, that the event is allowed for the game
if (attacker != null) {
+ System.out.println(event.getFinalDamage() + " " + player.getDisplayName() + " " + attacker.getDisplayName());
// Cancel if one player is in the game but other isn't
if ((board.contains(player) && !board.contains(attacker)) || (!board.contains(player) && board.contains(attacker))) {
event.setCancelled(true);
diff --git a/src/main/java/net/tylermurphy/hideAndSeek/game/listener/DisguiseHandler.java b/src/main/java/net/tylermurphy/hideAndSeek/game/listener/DisguiseHandler.java
index e3eb341..af58f91 100644
--- a/src/main/java/net/tylermurphy/hideAndSeek/game/listener/DisguiseHandler.java
+++ b/src/main/java/net/tylermurphy/hideAndSeek/game/listener/DisguiseHandler.java
@@ -1,78 +1,200 @@
package net.tylermurphy.hideAndSeek.game.listener;
-import com.comphenix.protocol.PacketType;
+import static com.comphenix.protocol.PacketType.Play.Client.*;
+
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
+import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
+import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.wrappers.BlockPosition;
+import com.cryptomorin.xseries.XMaterial;
import net.tylermurphy.hideAndSeek.Main;
+import net.tylermurphy.hideAndSeek.game.util.Disguise;
import org.bukkit.Bukkit;
import org.bukkit.Location;
-import org.bukkit.entity.FallingBlock;
+import org.bukkit.Material;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.util.BlockVector;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
+import java.util.ArrayList;
+import java.util.List;
public class DisguiseHandler implements Listener {
private static final ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
+ private final PacketAdapter packetListener;
- private final Map<UUID,Location> locations = new HashMap<>();
- private final Map<UUID,Long> times = new HashMap<>();
+ public DisguiseHandler(){
+ packetListener = createProtocol();
+ protocolManager.addPacketListener(packetListener);
+ }
@EventHandler(priority = EventPriority.HIGHEST)
public void onMove(PlayerMoveEvent event) {
- checkStandingStill(event.getPlayer());
- FallingBlock block = Main.getInstance().getDisguiser().getBlock(event.getPlayer());
- if(block == null) return;
- UUID uuid = event.getPlayer().getUniqueId();
- boolean finalFixLocation = times.containsKey(uuid) && new Date().getTime()-times.get(uuid) > 1000;
- Bukkit.getOnlinePlayers().forEach(player -> {
- teleportEntity(player, block, event.getPlayer().getLocation(), finalFixLocation);
- });
+ final Disguise disguise = Main.getInstance().getDisguiser().getDisguise(event.getPlayer());
+ if(disguise == null) return;
+ final Location lastLocation = event.getPlayer().getLocation();
+ Bukkit.getScheduler().scheduleSyncDelayedTask(Main.getInstance(), () -> {
+ final Location currentLocation = event.getPlayer().getLocation();
+ if(lastLocation.getWorld() != currentLocation.getWorld()) return;
+ double distance = lastLocation.distance(currentLocation);
+ disguise.setSolidify(distance < .1);
+ }, 40L);
+ if(event.getFrom().distance(event.getTo()) > .1)
+ disguise.setSolidify(false);
+ }
+
+// @EventHandler(priority = EventPriority.MONITOR)
+// public void onInteract(PlayerInteractEvent event) {
+// Action action = event.getAction();
+// Player player = event.getPlayer();
+// Block block = event.
+// }
+
+ private PacketAdapter createProtocol(){
+ return new PacketAdapter(Main.getInstance(), USE_ITEM, USE_ENTITY) {
+
+ @Override
+ public void onPacketReceiving(PacketEvent event){
+ PacketContainer packet = event.getPacket();
+ Player player = event.getPlayer();
+// if(!Main.getInstance().getBoard().isSeeker(player)) return;
+ if(packet.getType() == USE_ITEM) {
+ System.out.print("\nUse Item: ");
+ BlockPosition data;
+ try { data = packet.getBlockPositionModifier().read(0); }
+ catch (Exception e) { return; }
+ System.out.print(data + " ");
+ BlockVector loc = new BlockVector(data.getX(), data.getY(), data.getZ());
+ System.out.print(loc + " ");
+ Disguise disguise = Main.getInstance().getDisguiser().getByBlockLocation(loc);
+ System.out.print("FOUND");
+ handleAttack(disguise, player);
+ } else if(packet.getType() == USE_ENTITY) {
+ System.out.print("\nUse Entity: ");
+ int id = packet.getIntegers().read(0);
+ System.out.print(id + " ");
+ Disguise disguise = Main.getInstance().getDisguiser().getByEntityID(id);
+ System.out.print("FOUND");
+ handleAttack(disguise, player);
+ }
+ }
+
+ };
}
- private void checkStandingStill(Player player){
- UUID uuid = player.getUniqueId();
- Location lastLoc = locations.get(uuid);
- Location currentLoc = player.getLocation();
- if(lastLoc == null) lastLoc = currentLoc;
- double distance = lastLoc.distance(currentLoc);
- if(distance < .05){
- if(!times.containsKey(uuid))
- times.put(uuid, new Date().getTime());
+ private final List<Player> debounce = new ArrayList<>();
+
+ private void handleAttack(Disguise disguise, Player seeker){
+
+ double amount;
+ if(Main.getInstance().supports(9)) {
+ amount = seeker.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).getValue();
} else {
- times.remove(uuid);
+ amount = getItemDamageValue(seeker.getItemInHand(), disguise.getPlayer(), seeker);
}
- locations.put(uuid, currentLoc);
+
+ if(disguise == null) return;
+ disguise.setSolidify(false);
+ if(debounce.contains(disguise.getPlayer())) return;
+ debounce.add(disguise.getPlayer());
+ Bukkit.getScheduler().scheduleSyncDelayedTask(Main.getInstance(), () -> {
+ EntityDamageByEntityEvent event =
+ new EntityDamageByEntityEvent(seeker, disguise.getPlayer(), EntityDamageEvent.DamageCause.ENTITY_ATTACK, amount);
+ event.setDamage(amount);
+ disguise.getPlayer().setLastDamageCause(event);
+ Main.getInstance().getServer().getPluginManager().callEvent(event);
+ if(!event.isCancelled()){
+ disguise.getPlayer().damage(amount);
+ disguise.getPlayer().setVelocity(seeker.getLocation().getDirection().setY(.2).multiply(1));
+ }
+
+ }, 0);
+ Bukkit.getScheduler().scheduleSyncDelayedTask(Main.getInstance(), () -> debounce.remove(disguise.getPlayer()), 10);
}
- private void teleportEntity(Player player, FallingBlock block, Location location, boolean fixLocation) {
- PacketContainer packet = protocolManager.createPacket(PacketType.Play.Server.ENTITY_TELEPORT);
- packet.getModifier().writeDefaults();
- packet.getIntegers().write(0, block.getEntityId());
- if(fixLocation){
- packet.getDoubles().write(0, Math.round(location.getX()+.5)-.5);
- packet.getDoubles().write(1, (double)Math.round(location.getY()));
- packet.getDoubles().write(2, Math.round(location.getZ()+.5)-.5);
- } else {
- packet.getDoubles().write(0, location.getX());
- packet.getDoubles().write(1, location.getY());
- packet.getDoubles().write(2, location.getZ());
+ private int getItemDamageValue(ItemStack is, Player damaged, Player attacker) {
+ double damageValue = 0;
+ if (is != null) {
+ if (is.getType() == XMaterial.WOODEN_SWORD.parseMaterial()) {
+ damageValue = 5;
+ } else if (is.getType() == Material.STONE_SWORD) {
+ damageValue = 6;
+ } else if (is.getType() == Material.IRON_SWORD) {
+ damageValue = 7;
+ } else if (is.getType() == Material.DIAMOND_SWORD) {
+ damageValue = 8;
+ } else {
+ damageValue = 1;
+ }
+ damageValue += is.getEnchantmentLevel(Enchantment.DAMAGE_ALL);
}
- try {
- protocolManager.sendServerPacket(player, packet);
- } catch (InvocationTargetException e) {
- e.printStackTrace();
+ if (damaged != null) {
+ Inventory i = damaged.getInventory();
+ Material helmet = i.getItem(39).getType();
+ Material chestplate = i.getItem(40).getType();
+ Material leggings = i.getItem(41).getType();
+ Material boots = i.getItem(42).getType();
+ if (helmet == Material.LEATHER_HELMET)
+ damageValue -= (0.5 / 1.5);
+ // value shown at bar above the health bar / 1.5
+ else if (helmet == Material.CHAINMAIL_HELMET
+ || helmet == Material.IRON_HELMET
+ || helmet == Material.DIAMOND_HELMET
+ || helmet == XMaterial.GOLDEN_HELMET.parseMaterial())
+ damageValue -= (1 / 1.5);
+
+ if (chestplate == Material.LEATHER_CHESTPLATE)
+ damageValue -= (1.0);
+ else if (chestplate == Material.CHAINMAIL_CHESTPLATE
+ || chestplate == XMaterial.GOLDEN_CHESTPLATE.parseMaterial())
+ damageValue -= (2.5 / 1.5);
+ else if (chestplate == Material.IRON_CHESTPLATE)
+ damageValue -= (3 / 1.5);
+ else if (chestplate == Material.DIAMOND_CHESTPLATE)
+ damageValue -= (4 / 1.5);
+
+ if (leggings == Material.LEATHER_LEGGINGS)
+ damageValue -= (1 / 1.5);
+ else if (leggings == XMaterial.GOLDEN_LEGGINGS.parseMaterial())
+ damageValue -= (1.0);
+ else if (leggings == Material.CHAINMAIL_LEGGINGS)
+ damageValue -= (2 / 1.5);
+ else if (leggings == Material.IRON_LEGGINGS)
+ damageValue -= (2.5 / 1.5);
+ else if (leggings == Material.DIAMOND_LEGGINGS)
+ damageValue -= (3 / 1.5);
+
+ if (boots == Material.LEATHER_BOOTS
+ || boots == XMaterial.GOLDEN_BOOTS.parseMaterial()
+ || boots == Material.CHAINMAIL_BOOTS)
+ damageValue -= (0.5 / 1.5);
+ else if (boots == Material.IRON_BOOTS)
+ damageValue -= (1 / 1.5);
+ else if (boots == Material.DIAMOND_BOOTS)
+ damageValue -= (1.0);
+ }
+
+ for (PotionEffect effect : attacker.getActivePotionEffects()){
+ if (effect.getType() == PotionEffectType.HARM) {
+ damageValue += effect.getAmplifier()*1.5;
+ }
}
- }
+ return (int) Math.round(Math.max(damageValue, 0.0));
+ }
}
diff --git a/src/main/java/net/tylermurphy/hideAndSeek/game/util/Disguise.java b/src/main/java/net/tylermurphy/hideAndSeek/game/util/Disguise.java
new file mode 100644
index 0000000..691037b
--- /dev/null
+++ b/src/main/java/net/tylermurphy/hideAndSeek/game/util/Disguise.java
@@ -0,0 +1,143 @@
+package net.tylermurphy.hideAndSeek.game.util;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.ProtocolManager;
+import com.comphenix.protocol.events.PacketContainer;
+import com.comphenix.protocol.wrappers.BlockPosition;
+import com.comphenix.protocol.wrappers.WrappedBlockData;
+import net.tylermurphy.hideAndSeek.Main;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.entity.FallingBlock;
+import org.bukkit.entity.Player;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.reflect.InvocationTargetException;
+
+public class Disguise {
+
+ private static final ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
+
+ final Player hider;
+ final Material material;
+ FallingBlock entity;
+ Location solidLocation;
+ boolean solid, solidify;
+
+ public Disguise(Player player, Material material){
+ this.hider = player;
+ this.material = material;
+ this.solid = false;
+ respawnEntity();
+ player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 1000000, 0,false, false));
+ }
+
+ public void remove(){
+ if(entity != null)
+ entity.remove();
+ if(solid)
+ sendBlockUpdate(Material.AIR);
+ hider.removePotionEffect(PotionEffectType.INVISIBILITY);
+ }
+
+ @Nullable
+ public Location getSolidLocation() {
+ return solidLocation;
+ }
+
+ public int getEntityID() {
+ if(entity == null) return -1;
+ return entity.getEntityId();
+ }
+
+ public Player getPlayer() {
+ return hider;
+ }
+
+ public boolean isSolid(){
+ return solid;
+ }
+
+ public void update(){
+
+ if(entity == null || entity.isDead()){
+ if(entity != null) entity.remove();
+ respawnEntity();
+ }
+
+ if(solidify){
+ if(!solid)
+ solidLocation = hider.getLocation().getBlock().getLocation();
+ solid = true;
+ sendBlockUpdate(material);
+ } else if(solid){
+ solid = false;
+ sendBlockUpdate(Material.AIR);
+ }
+ sendToggleFallingBlock(!solid);
+ sendFallingBlockUpdate();
+ }
+
+ public void setSolidify(boolean value){
+ this.solidify = value;
+ }
+
+ private void sendBlockUpdate(Material material){
+ final PacketContainer packet = protocolManager.createPacket(PacketType.Play.Server.BLOCK_CHANGE);
+ packet.getModifier().writeDefaults();
+ packet.getBlockPositionModifier().write(0, new BlockPosition(solidLocation.toVector()));
+ packet.getBlockData().write(0, WrappedBlockData.createData(material));
+ Bukkit.getOnlinePlayers().forEach(receiver -> {
+ if(receiver == hider) return;
+ try {
+ protocolManager.sendServerPacket(receiver, packet);
+ } catch (InvocationTargetException ignored) {}
+ });
+ }
+
+ private void sendFallingBlockUpdate() {
+ if(entity == null || entity.isDead()){
+ if(entity != null) entity.remove();
+ respawnEntity();
+ }
+ final PacketContainer packet = protocolManager.createPacket(PacketType.Play.Server.ENTITY_TELEPORT);
+ Location location = hider.getLocation();
+ packet.getModifier().writeDefaults();
+ packet.getIntegers().write(0, entity.getEntityId());
+ if(solid){
+ packet.getDoubles().write(0, Math.round(location.getX()+.5)-.5);
+ packet.getDoubles().write(1, (double)Math.round(location.getY()));
+ packet.getDoubles().write(2, Math.round(location.getZ()+.5)-.5);
+ } else {
+ packet.getDoubles().write(0, location.getX());
+ packet.getDoubles().write(1, location.getY());
+ packet.getDoubles().write(2, location.getZ());
+ }
+ Bukkit.getOnlinePlayers().forEach(receiver -> {
+ try {
+ protocolManager.sendServerPacket(receiver, packet);
+ } catch (InvocationTargetException ignored) {}
+ });
+ }
+
+ private void sendToggleFallingBlock(boolean show){
+ Bukkit.getOnlinePlayers().forEach(receiver -> {
+ if(receiver == hider) return;
+ if(show)
+ Main.getInstance().getEntityHider().showEntity(receiver, entity);
+ else
+ Main.getInstance().getEntityHider().hideEntity(receiver, entity);
+ });
+ }
+
+ private void respawnEntity(){
+ entity = hider.getLocation().getWorld().spawnFallingBlock(hider.getLocation(), material, (byte)0);
+ entity.setGravity(false);
+ entity.setDropItem(false);
+ }
+
+} \ No newline at end of file