Advertisement
Guest User

Untitled

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