CushyPro

Untitled

Oct 15th, 2018
255
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.49 KB | None | 0 0
  1. package Me.CushyPro.KRKEvent;
  2.  
  3. import static com.comphenix.protocol.Packets.Server.*;
  4.  
  5. import java.lang.reflect.InvocationTargetException;
  6. import java.util.Arrays;
  7. import java.util.Map;
  8.  
  9. import org.bukkit.entity.Entity;
  10. import org.bukkit.entity.Player;
  11. import org.bukkit.event.EventHandler;
  12. import org.bukkit.event.HandlerList;
  13. import org.bukkit.event.Listener;
  14. import org.bukkit.event.entity.EntityDeathEvent;
  15. import org.bukkit.event.player.PlayerQuitEvent;
  16. import org.bukkit.event.world.ChunkUnloadEvent;
  17. import org.bukkit.plugin.Plugin;
  18.  
  19. import com.comphenix.protocol.ProtocolLibrary;
  20. import com.comphenix.protocol.ProtocolManager;
  21. import com.comphenix.protocol.events.ConnectionSide;
  22. import com.comphenix.protocol.events.PacketAdapter;
  23. import com.comphenix.protocol.events.PacketContainer;
  24. import com.comphenix.protocol.events.PacketEvent;
  25. import com.google.common.base.Preconditions;
  26. import com.google.common.collect.HashBasedTable;
  27. import com.google.common.collect.Table;
  28.  
  29. public class EntityHider implements Listener {
  30.     protected Table<Integer, Integer, Boolean> observerEntityMap = HashBasedTable.create();
  31.  
  32.     // Packets that update remote player entities
  33.     @SuppressWarnings("deprecation")
  34.     private static final Integer[] ENTITY_PACKETS = { ENTITY_EQUIPMENT, ENTITY_LOCATION_ACTION, ARM_ANIMATION,
  35.             NAMED_ENTITY_SPAWN, COLLECT, VEHICLE_SPAWN, MOB_SPAWN, ENTITY_PAINTING, ADD_EXP_ORB, ENTITY_VELOCITY,
  36.             REL_ENTITY_MOVE, ENTITY_LOOK, REL_ENTITY_MOVE_LOOK, REL_ENTITY_MOVE_LOOK, ENTITY_TELEPORT,
  37.             ENTITY_HEAD_ROTATION, ENTITY_STATUS, ATTACH_ENTITY, ENTITY_METADATA, MOB_EFFECT, REMOVE_MOB_EFFECT,
  38.             BLOCK_BREAK_ANIMATION
  39.  
  40.             // We don't handle DESTROY_ENTITY though
  41.     };
  42.  
  43.     /**
  44.      * The current entity visibility policy.
  45.      *
  46.      * @author Kristian
  47.      */
  48.     public enum Policy {
  49.         /**
  50.          * All entities are invisible by default. Only entities specifically made
  51.          * visible may be seen.
  52.          */
  53.         WHITELIST,
  54.  
  55.         /**
  56.          * All entities are visible by default. An entity can only be hidden explicitly.
  57.          */
  58.         BLACKLIST,
  59.     }
  60.  
  61.     private ProtocolManager manager;
  62.  
  63.     // Listeners
  64.     private Listener bukkitListener;
  65.     private PacketAdapter protocolListener;
  66.  
  67.     // Current policy
  68.     protected final Policy policy;
  69.  
  70.     /**
  71.      * Construct a new entity hider.
  72.      *
  73.      * @param plugin
  74.      *            - the plugin that controls this entity hider.
  75.      * @param policy
  76.      *            - the default visibility policy.
  77.      */
  78.     public EntityHider(Plugin plugin, Policy policy) {
  79.         Preconditions.checkNotNull(plugin, "plugin cannot be NULL.");
  80.  
  81.         // Save policy
  82.         this.policy = policy;
  83.         this.manager = ProtocolLibrary.getProtocolManager();
  84.  
  85.         // Register events and packet listener
  86.         plugin.getServer().getPluginManager().registerEvents(bukkitListener = constructBukkit(), plugin);
  87.         manager.addPacketListener(protocolListener = constructProtocol(plugin));
  88.     }
  89.  
  90.     /**
  91.      * Set the visibility status of a given entity for a particular observer.
  92.      *
  93.      * @param observer
  94.      *            - the observer player.
  95.      * @param entity
  96.      *            - ID of the entity that will be hidden or made visible.
  97.      * @param visible
  98.      *            - TRUE if the entity should be made visible, FALSE if not.
  99.      * @return TRUE if the entity was visible before this method call, FALSE
  100.      *         otherwise.
  101.      */
  102.     protected boolean setVisibility(Player observer, int entityID, boolean visible) {
  103.         switch (policy) {
  104.         case BLACKLIST:
  105.             // Non-membership means they are visible
  106.             return !setMembership(observer, entityID, !visible);
  107.         case WHITELIST:
  108.             return setMembership(observer, entityID, visible);
  109.         default:
  110.             throw new IllegalArgumentException("Unknown policy: " + policy);
  111.         }
  112.     }
  113.  
  114.     /**
  115.      * Add or remove the given entity and observer entry from the table.
  116.      *
  117.      * @param observer
  118.      *            - the player observer.
  119.      * @param entityID
  120.      *            - ID of the entity.
  121.      * @param member
  122.      *            - TRUE if they should be present in the table, FALSE otherwise.
  123.      * @return TRUE if they already were present, FALSE otherwise.
  124.      */
  125.     // Helper method
  126.     protected boolean setMembership(Player observer, int entityID, boolean member) {
  127.         if (member) {
  128.             return observerEntityMap.put(observer.getEntityId(), entityID, true) != null;
  129.         } else {
  130.             return observerEntityMap.remove(observer.getEntityId(), entityID) != null;
  131.         }
  132.     }
  133.  
  134.     /**
  135.      * Determine if the given entity and observer is present in the table.
  136.      *
  137.      * @param observer
  138.      *            - the player observer.
  139.      * @param entityID
  140.      *            - ID of the entity.
  141.      * @return TRUE if they are present, FALSE otherwise.
  142.      */
  143.     protected boolean getMembership(Player observer, int entityID) {
  144.         return observerEntityMap.contains(observer.getEntityId(), entityID);
  145.     }
  146.  
  147.     /**
  148.      * Determine if a given entity is visible for a particular observer.
  149.      *
  150.      * @param observer
  151.      *            - the observer player.
  152.      * @param entityID
  153.      *            - ID of the entity that we are testing for visibility.
  154.      * @return TRUE if the entity is visible, FALSE otherwise.
  155.      */
  156.     protected boolean isVisible(Player observer, int entityID) {
  157.         // If we are using a whitelist, presence means visibility - if not, the opposite
  158.         // is the case
  159.         boolean presence = getMembership(observer, entityID);
  160.  
  161.         return policy == Policy.WHITELIST ? presence : !presence;
  162.     }
  163.  
  164.     /**
  165.      * Remove the given entity from the underlying map.
  166.      *
  167.      * @param entity
  168.      *            - the entity to remove.
  169.      * @param destroyed
  170.      *            - TRUE if the entity was killed, FALSE if it is merely unloading.
  171.      */
  172.     protected void removeEntity(Entity entity, boolean destroyed) {
  173.         int entityID = entity.getEntityId();
  174.  
  175.         for (Map<Integer, Boolean> maps : observerEntityMap.rowMap().values()) {
  176.             maps.remove(entityID);
  177.         }
  178.     }
  179.  
  180.     /**
  181.      * Invoked when a player logs out.
  182.      *
  183.      * @param player
  184.      *            - the player that jused logged out.
  185.      */
  186.     protected void removePlayer(Player player) {
  187.         // Cleanup
  188.         observerEntityMap.rowMap().remove(player.getEntityId());
  189.     }
  190.  
  191.     /**
  192.      * Construct the Bukkit event listener.
  193.      *
  194.      * @return Our listener.
  195.      */
  196.     private Listener constructBukkit() {
  197.         return new Listener() {
  198.             @EventHandler
  199.             public void onEntityDeath(EntityDeathEvent e) {
  200.                 removeEntity(e.getEntity(), true);
  201.             }
  202.  
  203.             @EventHandler
  204.             public void onChunkUnload(ChunkUnloadEvent e) {
  205.                 for (Entity entity : e.getChunk().getEntities()) {
  206.                     removeEntity(entity, false);
  207.                 }
  208.             }
  209.  
  210.             @EventHandler
  211.             public void onPlayerQuit(PlayerQuitEvent e) {
  212.                 removePlayer(e.getPlayer());
  213.             }
  214.         };
  215.     }
  216.  
  217.     /**
  218.      * Construct the packet listener that will be used to intercept every
  219.      * entity-related packet.
  220.      *
  221.      * @param plugin
  222.      *            - the parent plugin.
  223.      * @return The packet listener.
  224.      */
  225.     @SuppressWarnings("deprecation")
  226.     private PacketAdapter constructProtocol(Plugin plugin) {
  227.         return new PacketAdapter(plugin, ConnectionSide.SERVER_SIDE, ENTITY_PACKETS) {
  228.             @Override
  229.             public void onPacketSending(PacketEvent event) {
  230.                 int entityID = event.getPacket().getIntegers().read(0);
  231.  
  232.                 // See if this packet should be cancelled
  233.                 if (!isVisible(event.getPlayer(), entityID)) {
  234.                     event.setCancelled(true);
  235.                 }
  236.             }
  237.         };
  238.     }
  239.  
  240.     /**
  241.      * Toggle the visibility status of an entity for a player.
  242.      * <p>
  243.      * If the entity is visible, it will be hidden. If it is hidden, it will become
  244.      * visible.
  245.      *
  246.      * @param observer
  247.      *            - the player observer.
  248.      * @param entity
  249.      *            - the entity to toggle.
  250.      * @return TRUE if the entity was visible before, FALSE otherwise.
  251.      */
  252.     public final boolean toggleEntity(Player observer, Entity entity) {
  253.         if (isVisible(observer, entity.getEntityId())) {
  254.             return hideEntity(observer, entity);
  255.         } else {
  256.             return !showEntity(observer, entity);
  257.         }
  258.     }
  259.  
  260.     /**
  261.      * Allow the observer to see an entity that was previously hidden.
  262.      *
  263.      * @param observer
  264.      *            - the observer.
  265.      * @param entity
  266.      *            - the entity to show.
  267.      * @return TRUE if the entity was hidden before, FALSE otherwise.
  268.      */
  269.     public final boolean showEntity(Player observer, Entity entity) {
  270.         validate(observer, entity);
  271.         boolean hiddenBefore = !setVisibility(observer, entity.getEntityId(), true);
  272.  
  273.         // Resend packets
  274.         if (manager != null && hiddenBefore) {
  275.             manager.updateEntity(entity, Arrays.asList(observer));
  276.         }
  277.         return hiddenBefore;
  278.     }
  279.  
  280.     /**
  281.      * Prevent the observer from seeing a given entity.
  282.      *
  283.      * @param observer
  284.      *            - the player observer.
  285.      * @param entity
  286.      *            - the entity to hide.
  287.      * @return TRUE if the entity was previously visible, FALSE otherwise.
  288.      */
  289.     @SuppressWarnings("deprecation")
  290.     public final boolean hideEntity(Player observer, Entity entity) {
  291.         validate(observer, entity);
  292.         boolean visibleBefore = setVisibility(observer, entity.getEntityId(), false);
  293.  
  294.         if (visibleBefore) {
  295.             PacketContainer destroyEntity = new PacketContainer(DESTROY_ENTITY);
  296.             destroyEntity.getIntegerArrays().write(0, new int[] { entity.getEntityId() });
  297.  
  298.             // Make the entity disappear
  299.             try {
  300.                 manager.sendServerPacket(observer, destroyEntity);
  301.             } catch (InvocationTargetException e) {
  302.                 throw new RuntimeException("Cannot send server packet.", e);
  303.             }
  304.         }
  305.         return visibleBefore;
  306.     }
  307.  
  308.     /**
  309.      * Determine if the given entity has been hidden from an observer.
  310.      * <p>
  311.      * Note that the entity may very well be occluded or out of range from the
  312.      * perspective of the observer. This method simply checks if an entity has been
  313.      * completely hidden for that observer.
  314.      *
  315.      * @param observer
  316.      *            - the observer.
  317.      * @param entity
  318.      *            - the entity that may be hidden.
  319.      * @return TRUE if the player may see the entity, FALSE if the entity has been
  320.      *         hidden.
  321.      */
  322.     public final boolean canSee(Player observer, Entity entity) {
  323.         validate(observer, entity);
  324.  
  325.         return isVisible(observer, entity.getEntityId());
  326.     }
  327.  
  328.     // For valdiating the input parameters
  329.     private void validate(Player observer, Entity entity) {
  330.         Preconditions.checkNotNull(observer, "observer cannot be NULL.");
  331.         Preconditions.checkNotNull(entity, "entity cannot be NULL.");
  332.     }
  333.  
  334.     /**
  335.      * Retrieve the current visibility policy.
  336.      *
  337.      * @return The current visibility policy.
  338.      */
  339.     public Policy getPolicy() {
  340.         return policy;
  341.     }
  342.  
  343.     public void close() {
  344.         if (manager != null) {
  345.             HandlerList.unregisterAll(bukkitListener);
  346.             manager.removePacketListener(protocolListener);
  347.             manager = null;
  348.         }
  349.     }
  350. }
Advertisement
Add Comment
Please, Sign In to add comment