Merge pull request #68 in MIN/mineplex from clans_custom_gear to clans-beta
* commit '17fbd42b9cda97a34fae52d73e733c4da24d3128': Fix bug where a players inventory was not properly updated after switching to SURVIVAL mode, causing CustomGear items to remain unhidden an JSON encoded. Fix offensive skill exploit where players could swap hotbar slots quickly and keep their original offensive spell casting for a large damage and speed advantage (running and attacking). Fix bug edge-case where outgoing slot packets were being missed, causing players CustomGear items to improperly display encoded JSON data instead of a user-friendly item description.
This commit is contained in:
commit
739440a2a3
@ -15,6 +15,7 @@ public class UtilItem
|
||||
private static final Material[] FOOD_LIST = { Material.APPLE, Material.BAKED_POTATO, Material.BREAD, Material.CARROT, Material.CARROT_ITEM, Material.COOKED_CHICKEN,
|
||||
Material.COOKED_FISH, Material.GRILLED_PORK, Material.COOKIE, Material.GOLDEN_APPLE, Material.GOLDEN_CARROT, Material.MELON, Material.MUSHROOM_SOUP, Material.POISONOUS_POTATO,
|
||||
Material.PUMPKIN_PIE, Material.RAW_BEEF, Material.RAW_CHICKEN, Material.RAW_FISH, Material.PORK, Material.ROTTEN_FLESH, Material.SPIDER_EYE, Material.COOKED_BEEF};
|
||||
private static final Material[] SWORD_LIST = { Material.WOOD_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.STONE_SWORD, Material.DIAMOND_SWORD };
|
||||
|
||||
public static LinkedList<ItemContainer> matchItem(Player caller, String items, boolean inform)
|
||||
{
|
||||
@ -166,4 +167,23 @@ public class UtilItem
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isSword(ItemStack item)
|
||||
{
|
||||
return item != null && isSword(item.getType());
|
||||
}
|
||||
|
||||
public static boolean isSword(Material material)
|
||||
{
|
||||
for (Material sword : SWORD_LIST)
|
||||
{
|
||||
if (sword.equals(material))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -29,6 +30,12 @@ import org.bukkit.util.Vector;
|
||||
public class UtilPlayer
|
||||
{
|
||||
private static Random RANDOM = new Random();
|
||||
|
||||
// A mapping of player names (Keys) to the system time when they last changed active Hotbar Slot
|
||||
private static Map<String, Long> _hotbarUpdates = new HashMap<String, Long>();
|
||||
|
||||
// The amount of time (in milliseconds) after changin hotbars that you can block
|
||||
public static final long BLOCKING_HOTBAR_DELAY = 100;
|
||||
|
||||
private static boolean hasIntersection(Vector3D p1, Vector3D p2, Vector3D min, Vector3D max)
|
||||
{
|
||||
@ -159,6 +166,30 @@ public class UtilPlayer
|
||||
return hit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player - the player to be checked for blocking status
|
||||
* @return true, if the {@code player} is blocking and has not recently
|
||||
* changed hotbar slots (within {@value BLOCKING_HOTBAR_DELAY} milliseconds), false otherwise.
|
||||
*/
|
||||
public static boolean isBlocking(Player player)
|
||||
{
|
||||
String name = player.getName();
|
||||
long lastUpdate = _hotbarUpdates.containsKey(name) ? _hotbarUpdates.get(name) : 0;;
|
||||
long duration = System.currentTimeMillis() - lastUpdate;
|
||||
|
||||
return player.isBlocking() && UtilItem.isSword(player.getItemInHand())
|
||||
&& duration >= BLOCKING_HOTBAR_DELAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the {@code player} as having changed hotbar slots.
|
||||
* @param player - the player to be marked
|
||||
*/
|
||||
public static void onHotbarChange(Player player)
|
||||
{
|
||||
_hotbarUpdates.put(player.getName(), System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* AviodAllies doesn't work. Leaving as a param as it sounds like something you may want in the future.
|
||||
*/
|
||||
|
@ -15,7 +15,7 @@ public enum ObserverSettings
|
||||
|
||||
public static EnumSet<ObserverSettings> getSettings(Rank rank)
|
||||
{
|
||||
if (rank.Has(Rank.DEVELOPER))
|
||||
if (rank.has(Rank.DEVELOPER))
|
||||
return EnumSet.of(CAN_OPEN_CHESTS);
|
||||
|
||||
return EnumSet.noneOf(ObserverSettings.class);
|
||||
|
@ -134,7 +134,7 @@ public abstract class ShopBase<PluginType extends MiniPlugin> implements Listene
|
||||
|
||||
if (page.matchesInventory(event.getInventory()))
|
||||
{
|
||||
_playerPageMap.get(event.getWhoClicked().getName()).playerClicked(event);
|
||||
page.playerClicked(event);
|
||||
|
||||
if (event.getRawSlot() < page.getSize())
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
package mineplex.game.clans.items;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -40,6 +40,7 @@ import mineplex.serverdata.serialization.RuntimeTypeAdapterFactory;
|
||||
import mineplex.serverdata.servers.ServerManager;
|
||||
import net.minecraft.server.v1_7_R4.Packet;
|
||||
import net.minecraft.server.v1_7_R4.PacketPlayOutSetSlot;
|
||||
import net.minecraft.server.v1_7_R4.PacketPlayOutWindowItems;
|
||||
import net.minecraft.util.com.google.common.collect.Sets;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
@ -432,34 +433,45 @@ public class GearManager extends MiniPlugin implements IPacketHandler, Runnable
|
||||
Packet packet = packetInfo.getPacket();
|
||||
|
||||
if (packet instanceof PacketPlayOutSetSlot)
|
||||
{
|
||||
{
|
||||
PacketPlayOutSetSlot slotPacket = (PacketPlayOutSetSlot) packet;
|
||||
|
||||
net.minecraft.server.v1_7_R4.ItemStack original = slotPacket.c;
|
||||
CraftItemStack originalItem = CraftItemStack.asCraftMirror(original);
|
||||
ItemMeta originalMeta = originalItem.getItemMeta();
|
||||
|
||||
if (originalMeta == null || originalMeta.getLore() == null) return; // No need to modify item packets with no lore
|
||||
|
||||
List<String> lore = new ArrayList<String>();
|
||||
|
||||
for (String line : originalMeta.getLore())
|
||||
{
|
||||
if (!line.startsWith(ITEM_SERIALIZATION_TAG)) // Remove serialization lines from out-going lore
|
||||
{
|
||||
lore.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
net.minecraft.server.v1_7_R4.ItemStack newItem = CraftItemStack.asNMSCopy(originalItem);
|
||||
CraftItemStack newCopy = CraftItemStack.asCraftMirror(newItem);
|
||||
ItemMeta newMeta = newCopy.getItemMeta();
|
||||
newMeta.setLore(lore);
|
||||
newCopy.setItemMeta(newMeta);
|
||||
slotPacket.c = newItem;
|
||||
//CraftItemStack.setItemMeta(slotPacket.c, meta);
|
||||
// TODO: Modify spigot build so that slotPacket's itemstack lore can be modified
|
||||
// to 'hide' json-encoded lore from players.
|
||||
slotPacket.c = maskItem(slotPacket.c); // Mask all out-going item packets
|
||||
}
|
||||
else if (packet instanceof PacketPlayOutWindowItems)
|
||||
{
|
||||
PacketPlayOutWindowItems itemsPacket = (PacketPlayOutWindowItems) packet;
|
||||
|
||||
for (int i = 0; i < itemsPacket.b.length; i++)
|
||||
{
|
||||
itemsPacket.b[i] = maskItem(itemsPacket.b[i]); // Mask all out-going item packets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private net.minecraft.server.v1_7_R4.ItemStack maskItem(net.minecraft.server.v1_7_R4.ItemStack item)
|
||||
{
|
||||
if (item == null) return null; // Cannot mask a null item
|
||||
|
||||
CraftItemStack originalItem = CraftItemStack.asCraftMirror(item);
|
||||
ItemMeta originalMeta = originalItem.getItemMeta();
|
||||
|
||||
if (originalMeta == null || originalMeta.getLore() == null) return item; // No need to modify item packets with no lore
|
||||
|
||||
List<String> lore = new ArrayList<String>();
|
||||
|
||||
for (String line : originalMeta.getLore())
|
||||
{
|
||||
if (!line.startsWith(ITEM_SERIALIZATION_TAG)) // Remove serialization lines from out-going lore
|
||||
{
|
||||
lore.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
net.minecraft.server.v1_7_R4.ItemStack newItem = CraftItemStack.asNMSCopy(originalItem);
|
||||
CraftItemStack newCopy = CraftItemStack.asCraftMirror(newItem);
|
||||
ItemMeta newMeta = newCopy.getItemMeta();
|
||||
newMeta.setLore(lore);
|
||||
newCopy.setItemMeta(newMeta);
|
||||
return newItem;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import mineplex.game.clans.items.attributes.ItemAttribute;
|
||||
import mineplex.minecraft.game.core.damage.CustomDamageEvent;
|
||||
import net.minecraft.server.v1_7_R4.Material;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -44,7 +45,7 @@ public class ItemListener implements Listener
|
||||
_plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onGamemodeChange(PlayerGameModeChangeEvent event)
|
||||
{
|
||||
if (event.getNewGameMode() == GameMode.CREATIVE) // Entering creative mode
|
||||
@ -54,6 +55,17 @@ public class ItemListener implements Listener
|
||||
else if (event.getPlayer().getGameMode() == GameMode.CREATIVE) // Exiting creative mode
|
||||
{
|
||||
GearManager.getInstance().removeCreativePlayer(event.getPlayer());
|
||||
|
||||
// Update/refresh the players inventory in 5 ticks once they're in survival mode again
|
||||
final Player player = event.getPlayer();
|
||||
Bukkit.getScheduler().runTaskLater(_plugin, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
player.updateInventory();
|
||||
}
|
||||
}, 5l);
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,21 +175,6 @@ public class ItemListener implements Listener
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event)
|
||||
{
|
||||
// Prevent players from equipping armour items in hand (prevents lore-breaking bug)
|
||||
ItemStack itemInHand = event.getItem();
|
||||
if (isArmour(itemInHand))
|
||||
{
|
||||
Action action = event.getAction();
|
||||
boolean rightClick = action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK;
|
||||
|
||||
if (rightClick)
|
||||
{
|
||||
event.setCancelled(true);
|
||||
GearManager.notify(event.getPlayer(), "You must manually equip armour!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Activate weapon interact abilities
|
||||
PlayerGear playerGear = getGear(event.getPlayer());
|
||||
playerGear.onInteract(event);
|
||||
|
@ -58,6 +58,7 @@ public class GearCommand extends CommandBase<GearManager>
|
||||
}
|
||||
else
|
||||
{
|
||||
caller.updateInventory();
|
||||
//caller.setFoodLevel(10);
|
||||
//return;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public class Evade extends SkillActive
|
||||
if (!_active.contains(cur))
|
||||
continue;
|
||||
|
||||
if (!cur.isBlocking())
|
||||
if (!UtilPlayer.isBlocking(cur))
|
||||
{
|
||||
_active.remove(cur);
|
||||
continue;
|
||||
|
@ -143,7 +143,7 @@ public class Illusion extends SkillActive
|
||||
Skeleton skel = _active.get(cur);
|
||||
|
||||
if (Factory.Condition().GetActiveCondition(cur, ConditionType.CLOAK) == null ||
|
||||
!cur.isBlocking() ||
|
||||
!UtilPlayer.isBlocking(cur) ||
|
||||
!Factory.Energy().Use(cur, GetName(), 0.625 - (getLevel(cur) * 0.025), true, true) ||
|
||||
skel == null ||
|
||||
!skel.isValid())
|
||||
|
@ -201,7 +201,7 @@ public class BlockToss extends SkillCharge implements IThrown
|
||||
}
|
||||
|
||||
//Throw
|
||||
if (!cur.isBlocking())
|
||||
if (!UtilPlayer.isBlocking(cur))
|
||||
throwSet.add(cur);
|
||||
|
||||
//Charged Tick
|
||||
|
@ -293,7 +293,7 @@ public class DwarfToss extends SkillActive
|
||||
}
|
||||
|
||||
//Expire
|
||||
if (!cur.isBlocking() || System.currentTimeMillis() - _time.get(cur) > 5000)
|
||||
if (!UtilPlayer.isBlocking(cur) || System.currentTimeMillis() - _time.get(cur) > 5000)
|
||||
{
|
||||
throwSet.add(cur);
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public class FleshHook extends SkillActiveCharge implements IThrown
|
||||
if (level == 0) return;
|
||||
|
||||
//Add Charge
|
||||
if (cur.isBlocking())
|
||||
if (UtilPlayer.isBlocking(cur))
|
||||
{
|
||||
Charge(cur);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import mineplex.minecraft.game.classcombat.Class.IPvpClass.ClassType;
|
||||
@ -87,7 +88,7 @@ public class Blizzard extends SkillActive
|
||||
{
|
||||
_active.add(player);
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void Energy(UpdateEvent event)
|
||||
{
|
||||
@ -99,7 +100,7 @@ public class Blizzard extends SkillActive
|
||||
if (!_active.contains(cur))
|
||||
continue;
|
||||
|
||||
if (!cur.isBlocking())
|
||||
if (!UtilPlayer.isBlocking(cur))
|
||||
{
|
||||
_active.remove(cur);
|
||||
continue;
|
||||
@ -134,7 +135,7 @@ public class Blizzard extends SkillActive
|
||||
if (!_active.contains(cur))
|
||||
continue;
|
||||
|
||||
if (!cur.isBlocking())
|
||||
if (!UtilPlayer.isBlocking(cur))
|
||||
{
|
||||
_active.remove(cur);
|
||||
continue;
|
||||
|
@ -85,7 +85,7 @@ public class Inferno extends SkillActive
|
||||
if (!_active.contains(cur))
|
||||
continue;
|
||||
|
||||
if (!cur.isBlocking())
|
||||
if (!UtilPlayer.isBlocking(cur))
|
||||
{
|
||||
_active.remove(cur);
|
||||
continue;
|
||||
|
@ -75,7 +75,7 @@ public class Magnetize extends SkillActive
|
||||
if (!_active.contains(cur))
|
||||
continue;
|
||||
|
||||
if (!cur.isBlocking())
|
||||
if (!UtilPlayer.isBlocking(cur))
|
||||
{
|
||||
_active.remove(cur);
|
||||
continue;
|
||||
|
@ -146,7 +146,7 @@ public class Rupture extends SkillActiveCharge
|
||||
if (level == 0) return;
|
||||
|
||||
//Add Charge
|
||||
if (!cur.isBlocking())
|
||||
if (!UtilPlayer.isBlocking(cur))
|
||||
DoRupture(cur);
|
||||
|
||||
else
|
||||
|
@ -6,8 +6,8 @@ import java.util.Set;
|
||||
|
||||
import mineplex.core.common.util.C;
|
||||
import mineplex.core.common.util.NautHashMap;
|
||||
|
||||
import mineplex.core.common.util.UtilGear;
|
||||
import mineplex.core.common.util.UtilPlayer;
|
||||
import mineplex.core.common.util.UtilTextBottom;
|
||||
import mineplex.minecraft.game.classcombat.Class.IPvpClass.ClassType;
|
||||
import mineplex.minecraft.game.classcombat.Skill.repository.token.SkillToken;
|
||||
@ -20,6 +20,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public abstract class Skill implements ISkill, Listener
|
||||
@ -292,6 +293,17 @@ public abstract class Skill implements ISkill, Listener
|
||||
{
|
||||
Reset(event.getEntity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger {@link UtilPlayer#onHotbarChange(Player)} to appropriately check
|
||||
* if players are blocking.
|
||||
* @param event
|
||||
*/
|
||||
@EventHandler
|
||||
public void onHotbarChange(PlayerItemHeldEvent event)
|
||||
{
|
||||
UtilPlayer.onHotbarChange(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public final void Quit(PlayerQuitEvent event)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package mineplex.minecraft.game.classcombat.Skill;
|
||||
|
||||
import mineplex.core.common.util.UtilEnt;
|
||||
import mineplex.core.common.util.UtilPlayer;
|
||||
import mineplex.core.recharge.Recharge;
|
||||
import mineplex.core.updater.UpdateType;
|
||||
import mineplex.core.updater.event.UpdateEvent;
|
||||
@ -51,8 +52,8 @@ public abstract class SkillChargeSword extends SkillCharge implements Listener
|
||||
for (Player cur : GetUsers())
|
||||
{
|
||||
//Charge
|
||||
if (cur.isBlocking())
|
||||
{
|
||||
if (UtilPlayer.isBlocking(cur))
|
||||
{
|
||||
//Flags
|
||||
if (!_canChargeInAir && !UtilEnt.isGrounded(cur))
|
||||
continue;
|
||||
|
Loading…
Reference in New Issue
Block a user