added ability to attack block in solid form, blocks now go solid
This commit is contained in:
parent
aa15931410
commit
361b97d414
8 changed files with 658 additions and 115 deletions
|
@ -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();
|
||||
|
@ -143,6 +117,15 @@ public class Main extends JavaPlugin implements Listener {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
282
src/main/java/net/tylermurphy/hideAndSeek/game/EntityHider.java
Normal file
282
src/main/java/net/tylermurphy/hideAndSeek/game/EntityHider.java
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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());
|
||||
// @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 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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue