From 167549c9e8b15e3885a38162b7dfcdc3aeb73df0 Mon Sep 17 00:00:00 2001 From: Ty Sayers Date: Mon, 25 May 2015 14:22:06 -0400 Subject: [PATCH] Add implementation for variety of attribute and base attribute hierarchies, add in JSON encoding for itemstack-item pairing to hold stats and information about items without unintuitive print & parse methods. Temporarily disable donation related commands in DonationManager for testing, as it was presenting compilation issues. Introduce further implementation of LegendaryItems. Add various utility methods for JSON encoding (utilizes GSON). Fix various bugs seen in internal testing. --- .../core/donation/DonationManager.java | 7 +- Plugins/Mineplex.Game.Clans/.classpath | 1 + .../src/mineplex/game/clans/Clans.java | 5 +- .../mineplex/game/clans/clans/ChunkData.java | 28 ++ .../game/clans/clans/ClansUtility.java | 59 ++++- .../mineplex/game/clans/items/CustomItem.java | 113 +++++++-- .../game/clans/items/GearManager.java | 151 ++++++++++- .../game/clans/items/ItemListener.java | 27 ++ .../mineplex/game/clans/items/PlayerGear.java | 45 +++- .../clans/items/attributes/ItemAttribute.java | 6 + .../armor/FlatReductionAttribute.java | 1 + .../items/attributes/armor/LavaAttribute.java | 5 + .../attributes/armor/PaddedAttribute.java | 7 +- .../armor/PercentReductionAttribute.java | 2 +- .../attributes/armor/ProtectionAttribute.java | 5 + .../attributes/armor/ReinforcedAttribute.java | 5 + .../attributes/armor/SlantedAttribute.java | 5 + .../attributes/weapon/AttackAttribute.java | 2 + .../weapon/ConqueringAttribute.java | 6 + .../attributes/weapon/DamageAttribute.java | 1 + .../attributes/weapon/FlamingAttribute.java | 6 + .../attributes/weapon/FrostedAttribute.java | 16 +- .../attributes/weapon/HasteAttribute.java | 6 + .../attributes/weapon/HeavyAttribute.java | 1 + .../attributes/weapon/JaggedAttribute.java | 6 + .../attributes/weapon/SharpAttribute.java | 6 + .../attributes/weapon/VampiricAttribute.java | 6 + .../clans/items/commands/GearCommand.java | 34 +++ .../items/legendaries/AlligatorsTooth.java | 13 +- .../items/legendaries/GiantsBroadsword.java | 12 + .../items/legendaries/LegendaryItem.java | 8 + .../clans/items/legendaries/WindBlade.java | 20 +- .../game/clans/items/smelting/Smelter.java | 26 +- .../src/mineplex/serverdata/Utility.java | 2 + .../RuntimeTypeAdapterFactory.java | 240 ++++++++++++++++++ 35 files changed, 831 insertions(+), 52 deletions(-) create mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ChunkData.java create mode 100644 Plugins/Mineplex.ServerData/src/mineplex/serverdata/serialization/RuntimeTypeAdapterFactory.java diff --git a/Plugins/Mineplex.Core/src/mineplex/core/donation/DonationManager.java b/Plugins/Mineplex.Core/src/mineplex/core/donation/DonationManager.java index b8b2bf46b..fc4699c30 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/donation/DonationManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/donation/DonationManager.java @@ -40,9 +40,10 @@ public class DonationManager extends MiniDbClientPlugin @Override public void addCommands() { - addCommand(new GemCommand(this)); - addCommand(new CoinCommand(this)); - addCommand(new GoldCommand(this)); + // TODO: Re-add commands? Where are command implementations, seen as missing at the moment. + //addCommand(new GemCommand(this)); + //addCommand(new CoinCommand(this)); + //addCommand(new GoldCommand(this)); } @EventHandler diff --git a/Plugins/Mineplex.Game.Clans/.classpath b/Plugins/Mineplex.Game.Clans/.classpath index 075cca472..d60d74d9e 100644 --- a/Plugins/Mineplex.Game.Clans/.classpath +++ b/Plugins/Mineplex.Game.Clans/.classpath @@ -8,5 +8,6 @@ + diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java index d94fc39ae..24d34157c 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java @@ -17,6 +17,7 @@ import mineplex.core.itemstack.ItemStackFactory; import mineplex.core.memory.MemoryFix; import mineplex.core.message.MessageManager; import mineplex.core.monitor.LagMeter; +import mineplex.core.packethandler.PacketHandler; import mineplex.core.portal.Portal; import mineplex.core.preferences.PreferencesManager; import mineplex.core.punish.Punish; @@ -94,7 +95,9 @@ public class Clans extends JavaPlugin new BuildingShop(clans, _clientManager, _donationManager); new PvpShop(clans, _clientManager, _donationManager); - GearManager customGear = new GearManager(this); + // Enable custom-gear related managers + PacketHandler packetHandler = new PacketHandler(this); + GearManager customGear = new GearManager(this, packetHandler); //Updates getServer().getScheduler().scheduleSyncRepeatingTask(this, new Updater(this), 1, 1); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ChunkData.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ChunkData.java new file mode 100644 index 000000000..9eccb5170 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ChunkData.java @@ -0,0 +1,28 @@ +package mineplex.game.clans.clans; + +import org.bukkit.ChatColor; +import org.bukkit.Color; + +public class ChunkData +{ + + private int _x; + public int getX() { return _x; } + + private int _z; + public int getZ() { return _z; } + + private ChatColor _color; + public ChatColor getColor() { return _color; } + + private String _clanName; + public String getClanName() { return _clanName; } + + public ChunkData(int x, int z, ChatColor color, String clanName) + { + _x = x; + _z = z; + _color = color; + _clanName = clanName; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java index a9ac01df5..d6fa99f06 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java @@ -1,11 +1,15 @@ package mineplex.game.clans.clans; +import java.awt.Color; +import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; import java.util.Map.Entry; import org.bukkit.ChatColor; import org.bukkit.Chunk; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Player; import mineplex.core.common.util.C; @@ -33,7 +37,49 @@ public class ClansUtility ADMIN, SAFE } - + + /** + * + * @param location + * @param radius + * @return a 2D array of {@link ClanTerritory} with uniform dimension of ({@code radius} * 2 + 1). The region represented by + * the array of territories is centered on {@code location} chunk with a given chunk {@code radius}. + */ + public List getTerritory(Location location, int radius, ClanInfo surveyorClan) + { + World world = location.getWorld(); + Chunk chunk = location.getChunk(); + int chunkX = chunk.getX(); + int chunkZ = chunk.getZ(); + int width = radius*2 + 1; + + List chunks = new ArrayList(); + + for (int x = 0; x < width; x++) + { + for (int z = 0; z < width; z++) + { + int territoryX = chunkX - radius + x; + int territoryZ = chunkZ - radius + z; + ClanTerritory territory = getClaim(world.getChunkAt(territoryX, territoryZ)); + + if (territory != null) + { + ClanInfo clan = getOwner(territory); + String clanName = territory.Owner; + ClanRelation relationship = rel(surveyorClan, clan); + ChatColor color = relChatColor(relationship, false); + + ChunkData data = new ChunkData(territoryX, territoryZ, color, clanName); + + chunks.add(data); + } + } + } + + return chunks; + } + public ClanInfo searchClanPlayer(Player caller, String name, boolean inform) { //CLAN @@ -197,11 +243,16 @@ public class ClansUtility return clan.getHome().getChunk().equals(chunk); } - + + public ClanTerritory getClaim(Chunk chunk) + { + String chunkTag = UtilWorld.chunkToStr(chunk); + return Clans.getClaimMap().get(chunkTag); + } + public ClanTerritory getClaim(Location loc) { - String chunk = UtilWorld.chunkToStr(loc.getChunk()); - return Clans.getClaimMap().get(chunk); + return getClaim(loc.getChunk()); } public ClanTerritory getClaim(String chunk) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/CustomItem.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/CustomItem.java index 00eaaf444..f8bc27309 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/CustomItem.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/CustomItem.java @@ -4,12 +4,15 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.UUID; import mineplex.game.clans.items.attributes.ItemAttribute; +import org.bukkit.Material; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; /** * Represents a customizable wrapper for an {@link ItemStack}, enabling the possession @@ -20,11 +23,34 @@ import org.bukkit.inventory.ItemStack; public class CustomItem { - private ItemAttribute superPrefix; - private ItemAttribute prefix; - private ItemAttribute suffix; + private ItemAttribute _superPrefix; + public void setSuperPrefix(ItemAttribute attribute) { _superPrefix = attribute; } + + private ItemAttribute _prefix; + public void setPrefix(ItemAttribute attribute) { _prefix = attribute; } + + private ItemAttribute _suffix; + public void setSuffix(ItemAttribute attribute) { _suffix = attribute; } private String _displayName; + private String _description; + private Material _material; + + private String _uuid; + public String getUuid() { return _uuid; } + + public CustomItem(String displayName, String description, Material material) + { + _displayName = displayName; + _description = description; + _material = material; + _uuid = UUID.randomUUID().toString(); + } + + public CustomItem(Material material) + { + this(material.toString(), null, material); // TODO: Prettify item materal name + } /** * @return the name displayed to players for the item. @@ -34,19 +60,19 @@ public class CustomItem // Concatenate attribute prefixes/suffixes to display name. String display = _displayName; - if (prefix != null) + if (_prefix != null) { - display = prefix.getDisplayName() + " " + display; + display = _prefix.getDisplayName() + " " + display; } - if (superPrefix != null) + if (_superPrefix != null) { - display = superPrefix.getDisplayName() + " " + display; + display = _superPrefix.getDisplayName() + " " + display; } - if (suffix != null) + if (_suffix != null) { - display += " of " + suffix.getDisplayName(); + display += " of " + _suffix.getDisplayName(); } return display; @@ -54,22 +80,46 @@ public class CustomItem public List getLore() { + String serialization = GearManager.getItemSerialization(this); + List lore = new ArrayList(); - // TODO: Add decorative stat lore (and hidden json-encoding/uuid info) - lore.add("Custom stat lore string!"); + if (_description != null) + { + lore.add(_description); + } + + // Display attribute descriptions and stats in lore + for (ItemAttribute attribute : getAttributes()) + { + String attributeLine = attribute.getDisplayName() + " - " + attribute.getDescription(); + lore.add(attributeLine); + } + + // Tack on serialized JSON encoded line for utility purposes. (Not seen by user) + List serializedLines = new ArrayList(); + String[] seri = serialization.split("\n"); + for (String line : seri) + { + serializedLines.add(line); + } + lore.addAll(serializedLines); return lore; } - public ItemStack toItemStack() + public ItemStack toItemStack(int amount) { - // TODO: Generate an item stack representing this CustomItem - return null; + ItemStack item = new ItemStack(_material, amount); + update(item); + + // TODO: Add non-descript enchantment for glowing efect? + return item; } public void onInteract(PlayerInteractEvent event) { + System.out.println("Triggered interact!"); for (ItemAttribute attribute : getAttributes()) { attribute.onInteract(event); @@ -78,6 +128,7 @@ public class CustomItem public void onAttack(EntityDamageByEntityEvent event) { + System.out.println("Triggered attack!"); for (ItemAttribute attribute : getAttributes()) { attribute.onAttack(event); @@ -86,6 +137,7 @@ public class CustomItem public void onAttacked(EntityDamageByEntityEvent event) { + System.out.println("Triggered damage!"); for (ItemAttribute attribute : getAttributes()) { attribute.onAttacked(event); @@ -98,9 +150,36 @@ public class CustomItem public Set getAttributes() { Set attributes = new HashSet(); - attributes.add(superPrefix); - attributes.add(prefix); - attributes.add(suffix); + if (_superPrefix != null) attributes.add(_superPrefix); + if (_prefix != null) attributes.add(_prefix); + if (_suffix != null) attributes.add(_suffix); return attributes; } + + /** + * @param item - the item to check for a matching link + * @return true, if {@code item} matches this CustomItem via UUID, false otherwise. + */ + public boolean matches(CustomItem item) + { + return item.getUuid().equals(_uuid); + } + + /** + * Update {@code item} with the proper meta properties suited for this + * {@link CustomItem}. + * @param item - the item whose meta properties are being updated to become a version of this updated custom item. + */ + public void update(ItemStack item) + { + ItemMeta meta = item.getItemMeta(); + + String displayName = getDisplayName(); + List lore = getLore(); + + meta.setDisplayName(displayName); + meta.setLore(lore); + + item.setItemMeta(meta); + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/GearManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/GearManager.java index 267288b11..30ce2a183 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/GearManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/GearManager.java @@ -1,56 +1,101 @@ package mineplex.game.clans.items; import java.util.HashMap; +import java.util.List; import java.util.Map; import mineplex.core.MiniPlugin; import mineplex.core.account.CoreClientManager; +import mineplex.core.common.util.UtilServer; +import mineplex.core.packethandler.IPacketHandler; +import mineplex.core.packethandler.PacketHandler; +import mineplex.core.packethandler.PacketInfo; import mineplex.core.portal.TransferHandler; import mineplex.core.portal.Commands.SendCommand; import mineplex.core.portal.Commands.ServerCommand; +import mineplex.game.clans.items.attributes.ItemAttribute; +import mineplex.game.clans.items.attributes.weapon.FlamingAttribute; +import mineplex.game.clans.items.attributes.weapon.FrostedAttribute; +import mineplex.game.clans.items.attributes.weapon.SharpAttribute; import mineplex.game.clans.items.commands.GearCommand; import mineplex.game.clans.items.generation.Weight; import mineplex.game.clans.items.generation.WeightSet; +import mineplex.game.clans.items.legendaries.AlligatorsTooth; +import mineplex.game.clans.items.legendaries.WindBlade; +import mineplex.game.clans.items.smelting.SmeltingListener; import mineplex.serverdata.Region; import mineplex.serverdata.Utility; import mineplex.serverdata.commands.ServerCommandManager; import mineplex.serverdata.commands.TransferCommand; +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 org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.plugin.java.JavaPlugin; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + /** * Manages creation and retrieval of associated {@link PlayerGear}s with online players, as well * as offering methods for parsing and handling {@link CustomItem}s. * @author MrTwiggy * */ -public class GearManager extends MiniPlugin +public class GearManager extends MiniPlugin implements IPacketHandler { - + private static final String ITEM_SERIALIZATION_TAG = "-JSON-"; private static GearManager _instance; // Singleton instance + private Map playerGears; // Mapping of player names (key) to cached gear set (value). private WeightSet _attributeWeights; // Weightings for randomly selecting number of attributes (1, 2, 3) private WeightSet _itemWeights; // Weightings for randomly selecting item type (legendary/rare) private WeightSet _gearWeights; // Weightings for randomly selecting gear type (armour/weapon) + private static Gson _gson; - public GearManager(JavaPlugin plugin) + public GearManager(JavaPlugin plugin, PacketHandler packetHandler) { super("CustomGear", plugin); _instance = this; playerGears = new HashMap(); + // TODO: Introduce configurable non-hardcoded values for generation weights? _attributeWeights = new WeightSet(new Weight(3, 3), new Weight(20, 2), new Weight(77, 1)); _itemWeights = new WeightSet(new Weight(90, true), new Weight(10, false)); _itemWeights = new WeightSet(new Weight(50, true), new Weight(50, false)); System.out.println("-Testting-testing"); System.out.println(Utility.currentTimeSeconds()); + + // Register listeners + UtilServer.getServer().getPluginManager().registerEvents(new ItemListener(), getPlugin()); + UtilServer.getServer().getPluginManager().registerEvents(new SmeltingListener(), getPlugin()); + + // adding all different container classes with their flag + RuntimeTypeAdapterFactory typeFactory = RuntimeTypeAdapterFactory + .of(ItemAttribute.class, "AttributeType") + .registerSubtype(SharpAttribute.class) + .registerSubtype(FrostedAttribute.class) + .registerSubtype(FlamingAttribute.class); // TODO: Register all item attributes automatically + + RuntimeTypeAdapterFactory customItemType = RuntimeTypeAdapterFactory + .of(CustomItem.class, "ItemType") + .registerSubtype(AlligatorsTooth.class) + .registerSubtype(WindBlade.class); // TODO: Register all legendary weapons automatically + + GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapterFactory(typeFactory); + builder.registerTypeAdapterFactory(customItemType); + _gson = builder.create(); + + packetHandler.addPacketHandler(this); } @Override @@ -88,12 +133,94 @@ public class GearManager extends MiniPlugin public static CustomItem parseItem(ItemStack item) { - return null; // TODO: Parse CustomItem from hidden JSON-encoded lore string in item passed in + String serialization = getItemSerialization(item); + + if (serialization != null) + { + CustomItem customItem = deserialize(serialization); + return customItem; + } + + return null; // No serialization found in item's lore, not a custom item! } public static boolean isCustomItem(ItemStack item) { - return parseItem(item) != null; // TODO: Check for JSON-encoded lore string instead of deserializing? + return getItemSerialization(item) != null; + } + + public static String getItemSerialization(CustomItem customItem) + { + String tempSeri = serialize(customItem); + String serialization = ITEM_SERIALIZATION_TAG; + + for (int i = 0; i < tempSeri.length(); i++) + { + if (i % 40 == 39) + { + serialization += "\n"; + } + + serialization += tempSeri.charAt(i); + } + + return serialization; + } + + private static String getItemSerialization(ItemStack item) + { + if (item == null || item.getItemMeta() == null + || item.getItemMeta().getLore() == null) return null; + + ItemMeta meta = item.getItemMeta(); + + /*for (String lore : meta.getLore()) + { + if (lore.startsWith(ITEM_SERIALIZATION_TAG)) // Found serialization lore-line + { + int tagLength = ITEM_SERIALIZATION_TAG.length(); + String serialization = lore.substring(tagLength); + + return serialization; + } + }*/ + + // TODO: Implement packet intercepting to hide json encoded lore + List lore = meta.getLore(); + boolean serialized = false; + String serialization = ""; + for (int i = 0; i < lore.size(); i++) + { + String line = lore.get(i); + + if (line.startsWith(ITEM_SERIALIZATION_TAG)) + { + serialized = true; + serialization += line.substring(ITEM_SERIALIZATION_TAG.length()); + } + else if (serialized) + { + serialization += line; + } + } + + if (serialized) + { + return serialization; + } + + return null; // Unable to find any serialized lore lines, hence not a CustomItem. + } + + public static String serialize(CustomItem customItem) + { + return _gson.toJson(customItem); + } + + public static CustomItem deserialize(String serialization) + { + System.out.println("Serialization: " + serialization); + return _gson.fromJson(serialization, CustomItem.class); } /** @@ -103,4 +230,18 @@ public class GearManager extends MiniPlugin { return _instance; } + + @Override + public void handle(PacketInfo packetInfo) + { + Packet packet = packetInfo.getPacket(); + + if (packet instanceof PacketPlayOutSetSlot) + { + System.out.println("Item slot packet!"); + PacketPlayOutSetSlot slotPacket = (PacketPlayOutSetSlot) packet; + + + } + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/ItemListener.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/ItemListener.java index 4a619b961..521974557 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/ItemListener.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/ItemListener.java @@ -6,7 +6,9 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; /** * Listens for item-related trigger events and accordingly triggers appropriate @@ -17,6 +19,31 @@ import org.bukkit.event.player.PlayerInteractEvent; public class ItemListener implements Listener { + /** + * Handle players shuffling CustomItems around by properly updating + * and managing their movement. + * @param event + */ + @EventHandler + public void onInventoryClick(InventoryClickEvent event) + { + // TODO: Update any custom-items that are selected/moved to save proper stats if they + // TODO: are active. (IE: PlayerGear possesses it as armor slot or weapon) + } + + /** + * Handle updated CustomItem stats and lore upon player + * switching items. + * @param event + */ + @EventHandler + public void onItemHeldChanged(PlayerItemHeldEvent event) + { + Player player = event.getPlayer(); + PlayerGear gear = getGear(player); + + gear.onItemHeldChanged(event); + } /** * Handle the trigger of custom gear related effects and abilities. diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/PlayerGear.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/PlayerGear.java index 033b811f1..1ae4319ba 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/PlayerGear.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/PlayerGear.java @@ -7,7 +7,9 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; /** * PlayerGear caches and manages a players set of {@link CustomItem}s that @@ -17,7 +19,6 @@ import org.bukkit.inventory.ItemStack; */ public class PlayerGear { - private String _playerName; // Name of player who owns the gear // Cached custom item information for player's gear @@ -44,6 +45,14 @@ public class PlayerGear return Bukkit.getPlayer(_playerName); } + /** + * @return the {@link PlayerInventory} associated with the owner of this {@link PlayerGear}. + */ + public PlayerInventory getInventory() + { + return getPlayer().getInventory(); + } + /** * Trigger interact events for the set of equipped {@link CustomItem}s in gear set. * @param event - the triggering interact event @@ -80,6 +89,21 @@ public class PlayerGear } } + /** + * Update appropriate gear status and item lores. + * @param event - the triggering item held change event. + */ + public void onItemHeldChanged(PlayerItemHeldEvent event) + { + ItemStack item = getPlayer().getItemInHand(); + CustomItem weapon = getWeapon(); + + if (weapon != null) + { + weapon.update(item); // Update held-item's stats. + } + } + public CustomItem getWeapon() { ItemStack weaponItem = getPlayer().getInventory().getItemInHand(); @@ -146,11 +170,11 @@ public class PlayerGear public Set getGear() { Set items = new HashSet(); - items.add(getWeapon()); - items.add(getHelmet()); - items.add(getChestplate()); - items.add(getLeggings()); - items.add(getBoots()); + if (getWeapon() != null) items.add(getWeapon()); + if (getHelmet() != null) items.add(getHelmet()); + if (getChestplate() != null) items.add(getChestplate()); + if (getLeggings() != null) items.add(getLeggings()); + if (getBoots() != null) items.add(getBoots()); return items; } @@ -158,8 +182,13 @@ public class PlayerGear { if (customItem == null || item == null) return false; - // TODO: Implement more sophisticated match-checking that checks hidden UUID - return customItem.getDisplayName().equals(item.getItemMeta().getDisplayName()); + if (GearManager.isCustomItem(item)) + { + CustomItem customItem2 = GearManager.parseItem(item); + return customItem2.matches(customItem); + } + + return false; } private CustomItem parseItem(ItemStack item) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/ItemAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/ItemAttribute.java index e44ce1dd0..bf9443f7a 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/ItemAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/ItemAttribute.java @@ -18,6 +18,12 @@ public abstract class ItemAttribute * @return the attribute name display to players. */ public abstract String getDisplayName(); + + /** + * @return a user-friendly description of this attribute, entailing it's effects + * and current associated values. + */ + public String getDescription() { return "???IMPLEMENT"; } public void onInteract(PlayerInteractEvent event) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/FlatReductionAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/FlatReductionAttribute.java index f9b05e295..7df8fe1c5 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/FlatReductionAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/FlatReductionAttribute.java @@ -6,6 +6,7 @@ public abstract class FlatReductionAttribute extends ReductionAttribute { private double _reduction; + public double getFlatReduction() { return _reduction; } public FlatReductionAttribute(ValueDistribution reductionGen, ReductionConfig config) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/LavaAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/LavaAttribute.java index bdeb36575..4e8f8dc1a 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/LavaAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/LavaAttribute.java @@ -23,4 +23,9 @@ public class LavaAttribute extends PercentReductionAttribute return "Lava Forged"; } + @Override + public String getDescription() + { + return String.format("Reduce fire-related damage by %.2f percent.", getReductionPercent()); + } } \ No newline at end of file diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/PaddedAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/PaddedAttribute.java index 7f05bbcea..5c255a918 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/PaddedAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/PaddedAttribute.java @@ -21,5 +21,10 @@ public class PaddedAttribute extends FlatReductionAttribute { return "Padded"; } - + + @Override + public String getDescription() + { + return String.format("Reduce fall damage by %.2f half-hearts.", getFlatReduction()); + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/PercentReductionAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/PercentReductionAttribute.java index fdcc6ad61..aeee83b22 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/PercentReductionAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/PercentReductionAttribute.java @@ -4,8 +4,8 @@ import mineplex.game.clans.items.generation.ValueDistribution; public abstract class PercentReductionAttribute extends ReductionAttribute { - private double _reductionPercent; + public double getReductionPercent() { return _reductionPercent; } public PercentReductionAttribute(ValueDistribution reductionGen, ReductionConfig config) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/ProtectionAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/ProtectionAttribute.java index ff3995157..8903beb8a 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/ProtectionAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/ProtectionAttribute.java @@ -24,4 +24,9 @@ public class ProtectionAttribute extends FlatReductionAttribute return "Protection"; } + @Override + public String getDescription() + { + return String.format("Reduce incoming attack damage by %.2f half-hearts.", getFlatReduction()); + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/ReinforcedAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/ReinforcedAttribute.java index 177b9a42a..09cc76b99 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/ReinforcedAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/ReinforcedAttribute.java @@ -21,4 +21,9 @@ public class ReinforcedAttribute extends FlatReductionAttribute return "Reinforced"; } + @Override + public String getDescription() + { + return String.format("Reduce incoming enemy attacks by %.2f half-hearts.", getFlatReduction()); + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/SlantedAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/SlantedAttribute.java index f3e93f4f3..0618e473d 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/SlantedAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/armor/SlantedAttribute.java @@ -22,4 +22,9 @@ public class SlantedAttribute extends FlatReductionAttribute return "Slanted"; } + @Override + public String getDescription() + { + return String.format("Reduce arrow damage by %.2f half-hearts.", getFlatReduction()); + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/AttackAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/AttackAttribute.java index 3d98b1634..877dc6199 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/AttackAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/AttackAttribute.java @@ -15,6 +15,8 @@ public abstract class AttackAttribute extends ItemAttribute { private int _attackLimit; + public int getAttackLimit() { return _attackLimit; } + private int _attackCount; public AttackAttribute(int attackLimit) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/ConqueringAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/ConqueringAttribute.java index 7e61aa5ef..c3b57c04b 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/ConqueringAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/ConqueringAttribute.java @@ -21,6 +21,12 @@ public class ConqueringAttribute extends DamageAttribute return "Conquering"; // TODO: Fill in name } + @Override + public String getDescription() + { + return String.format("Deal an extra %.2f hearts of damage to mobs.", getBonusDamage()); + } + @Override public boolean grantBonusDamage(Entity entity) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/DamageAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/DamageAttribute.java index 2387c206d..301008ca0 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/DamageAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/DamageAttribute.java @@ -9,6 +9,7 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent; public abstract class DamageAttribute extends ItemAttribute { private double _bonusDamage; + public double getBonusDamage() { return _bonusDamage; } public DamageAttribute(ValueDistribution damageGen) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FlamingAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FlamingAttribute.java index 9a7b5f84c..c3b0f088d 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FlamingAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FlamingAttribute.java @@ -24,6 +24,12 @@ public class FlamingAttribute extends AttackAttribute return "Flaming"; // TODO: Fill in name } + @Override + public String getDescription() + { + return String.format("Enemies catch fire for %d ticks every %d attacks.", _fireDuration, getAttackLimit()); + } + @Override public void triggerAttack(Entity attacker, Entity defender) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FrostedAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FrostedAttribute.java index a1a6a70e9..aa4484b4f 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FrostedAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FrostedAttribute.java @@ -16,12 +16,11 @@ import org.bukkit.potion.PotionEffectType; */ public class FrostedAttribute extends ItemAttribute { - public final int TICKS_PER_SECOND = 20; // Number of ticks per second for in-game logic. private static ValueDistribution amountGen = generateDistribution(0, 3); // Value generator for slow amount range - private static ValueDistribution durationGen = generateDistribution(1, 3); // Value generator for slow duration range + private static ValueDistribution durationGen = generateDistribution(20, 60); // Value generator for slow duration range private int _slowAmount; // The slowness level/amplifier - private double _slowDuration; // The duration (in seconds) of slow effect + private int _slowDuration; // The duration (in ticks) of slow effect /** * Class constructor @@ -29,7 +28,7 @@ public class FrostedAttribute extends ItemAttribute public FrostedAttribute() { _slowAmount = amountGen.generateIntValue(); - _slowDuration = durationGen.generateValue(); + _slowDuration = durationGen.generateIntValue(); } @Override @@ -38,6 +37,12 @@ public class FrostedAttribute extends ItemAttribute return "Frosted"; } + @Override + public String getDescription() + { + return String.format("Apply slowness %d for %d ticks to enemies.", _slowAmount, _slowDuration); + } + @Override public void onAttacked(EntityDamageByEntityEvent event) { @@ -51,7 +56,6 @@ public class FrostedAttribute extends ItemAttribute private PotionEffect generateSlowEffect() { - int duration = (int) (_slowDuration / TICKS_PER_SECOND); - return new PotionEffect(PotionEffectType.SLOW, duration, _slowAmount); + return new PotionEffect(PotionEffectType.SLOW, _slowDuration, _slowAmount); } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HasteAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HasteAttribute.java index a23f7fe68..c694957cc 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HasteAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HasteAttribute.java @@ -32,6 +32,12 @@ public class HasteAttribute extends AttackAttribute return "Haste"; // TODO: Fill in name } + @Override + public String getDescription() + { + return String.format("Gain speed %d for %d ticks every %d attacks.", _speedAmount, _speedDuration, getAttackLimit()); + } + @Override public void triggerAttack(Entity attacker, Entity defender) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HeavyAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HeavyAttribute.java index 04d8c9758..338950352 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HeavyAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HeavyAttribute.java @@ -21,4 +21,5 @@ public class HeavyAttribute extends ItemAttribute return ""; // TODO: Fill in name } + } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/JaggedAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/JaggedAttribute.java index 51fc7c03b..0b9fcbc74 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/JaggedAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/JaggedAttribute.java @@ -21,6 +21,12 @@ public class JaggedAttribute extends AttackAttribute return "Jagged"; // TODO: Fill in name } + @Override + public String getDescription() + { + return String.format("Temporarily halt enemies every %d attacks.", getAttackLimit()); + } + @Override public void triggerAttack(Entity attacker, Entity defender) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/SharpAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/SharpAttribute.java index c03aec7a1..9413b79a6 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/SharpAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/SharpAttribute.java @@ -20,6 +20,12 @@ public class SharpAttribute extends DamageAttribute return "Sharp"; // TODO: Fill in name } + @Override + public String getDescription() + { + return String.format("Deal an extra %.2f damage.", getBonusDamage()); + } + @Override public boolean grantBonusDamage(Entity defender) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/VampiricAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/VampiricAttribute.java index d8fabe2a2..0bca99aaf 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/VampiricAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/VampiricAttribute.java @@ -24,6 +24,12 @@ public class VampiricAttribute extends ItemAttribute return "Vampiric"; // TODO: Fill in name } + @Override + public String getDescription() + { + return String.format("Heal yourself for %d percentage of damage dealt to enemy players.", _healPercent); + } + @Override public void onAttack(EntityDamageByEntityEvent event) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/commands/GearCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/commands/GearCommand.java index a15577860..3c22d4b79 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/commands/GearCommand.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/commands/GearCommand.java @@ -1,9 +1,13 @@ package mineplex.game.clans.items.commands; import java.util.ArrayList; +import java.util.List; import org.bukkit.Chunk; +import org.bukkit.Material; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import mineplex.core.command.CommandBase; import mineplex.core.common.Rank; @@ -22,7 +26,13 @@ import mineplex.game.clans.clans.ClanRole; import mineplex.game.clans.clans.ClansManager; import mineplex.game.clans.clans.ClansUtility.ClanRelation; import mineplex.game.clans.clans.ClientClan; +import mineplex.game.clans.items.CustomItem; import mineplex.game.clans.items.GearManager; +import mineplex.game.clans.items.attributes.weapon.FlamingAttribute; +import mineplex.game.clans.items.attributes.weapon.FrostedAttribute; +import mineplex.game.clans.items.attributes.weapon.SharpAttribute; +import mineplex.game.clans.items.legendaries.LegendaryItem; +import mineplex.game.clans.items.legendaries.WindBlade; public class GearCommand extends CommandBase { @@ -36,6 +46,30 @@ public class GearCommand extends CommandBase { UtilPlayer.message(caller, F.main("Gear", "Opening custom gear GUI!")); + if (caller.getItemInHand() != null && caller.getItemInHand().getType() != Material.AIR) + { + ItemStack item = caller.getItemInHand(); + ItemMeta meta = item.getItemMeta(); + List lore = meta.getLore(); + lore.set(0, "Test"); + meta.setLore(lore); + item.setItemMeta(meta); + System.out.println("aaaaaaa"); + return; + } + else + { + LegendaryItem legendary = new WindBlade(); + caller.setItemInHand(legendary.toItemStack(1)); + return; + } + + /*CustomItem customItem = new CustomItem(); + customItem.setPrefix(new FrostedAttribute()); + customItem.setSuperPrefix(new SharpAttribute()); + customItem.setSuffix(new FlamingAttribute()); + ItemStack sword = customItem.toItemStack(1); + caller.setItemInHand(sword);*/ // TODO: Open custom gear GUI here } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/AlligatorsTooth.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/AlligatorsTooth.java index c8767a955..3ce29f6a6 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/AlligatorsTooth.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/AlligatorsTooth.java @@ -3,19 +3,26 @@ package mineplex.game.clans.items.legendaries; import mineplex.game.clans.items.attributes.ItemAttribute; import mineplex.game.clans.items.generation.ValueDistribution; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.util.Vector; public class AlligatorsTooth extends LegendaryItem { - private static ValueDistribution damageGen = generateDistribution(1.0d, 5.0d); + private static ValueDistribution boostGen = generateDistribution(0.6d, 1.2d); + private static ValueDistribution damageGen = generateDistribution(1.0d, 6.0d); private double _damageBonus; + private double _swimSpeed; public AlligatorsTooth() { + super("Alligators Tooth", "Grants bonus damage in water and special ability to swim fast!", Material.RAW_FISH); + _damageBonus = damageGen.generateValue(); + _swimSpeed = boostGen.generateValue(); } @Override @@ -41,7 +48,9 @@ public class AlligatorsTooth extends LegendaryItem private void propelPlayer(Player player) { - // TODO: Propel player forward with 0.6 to 1.2 velocity + Vector direction = player.getLocation().getDirection().normalize(); + direction.multiply(_swimSpeed); + player.setVelocity(direction); } private boolean isInWater(Player player) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java index 33306ab82..9df21fdee 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java @@ -3,6 +3,7 @@ package mineplex.game.clans.items.legendaries; import java.util.HashSet; import java.util.Set; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.potion.PotionEffect; @@ -11,6 +12,11 @@ import org.bukkit.potion.PotionEffectType; public class GiantsBroadsword extends LegendaryItem { + public GiantsBroadsword() + { + super("Giants Broadsword", "Deal huge damage and block to gain defensive abilities!", Material.PAPER); + } + @Override public void update(Player wielder) { @@ -24,6 +30,12 @@ public class GiantsBroadsword extends LegendaryItem public void onAttack(EntityDamageByEntityEvent event, Player wielder) { // TODO: Buff knockback and damage values (What are specific values?) + // Chiss: Make 'em up + + double bonusDamage = 2.0d; // Too much? + event.setDamage(event.getDamage() + bonusDamage); + + // TODO: Apply knockback bonus using previous Clans Custom combat events } private void buffPlayer(Player player) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/LegendaryItem.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/LegendaryItem.java index 559273ff4..60db32a47 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/LegendaryItem.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/LegendaryItem.java @@ -1,5 +1,6 @@ package mineplex.game.clans.items.legendaries; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.event.entity.EntityDamageByEntityEvent; @@ -19,6 +20,13 @@ public class LegendaryItem extends CustomItem public LegendaryItem() { + this(null, null, null); // TODO: Never used, just to skip base implementation for testing. + } + + public LegendaryItem(String name, String description, Material material) + { + super(name, description, material); + _lastBlock = 0l; } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/WindBlade.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/WindBlade.java index 16ef9ee7d..c8d38f700 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/WindBlade.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/WindBlade.java @@ -3,34 +3,52 @@ package mineplex.game.clans.items.legendaries; import mineplex.game.clans.items.attributes.ItemAttribute; import mineplex.game.clans.items.generation.ValueDistribution; +import org.bukkit.Material; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.util.Vector; public class WindBlade extends LegendaryItem { + public static final double FLIGHT_VELOCITY = 0.25d; public static final int MAX_FLIGHT_TIME = 80; // Max flight of 80 ticks private long _flightTime; // Time (in ticks) since last touching ground and flying public WindBlade() { + super("Wind Blade", "Activate flying ability to take flight for 80 ticks before landing!", Material.STICK); // TODO: Configurable? + _flightTime = 0; } @Override public void update(Player wielder) { + Entity entity = (Entity) wielder; + + // Check if player is attempting to fly and activate if (isHoldingRightClick() && canPropel()) { propelPlayer(wielder); } + + // Check if player has touched down + if (entity.isOnGround()) + { + _flightTime = 0; + } } private void propelPlayer(Player player) { _flightTime++; - // TODO: Propel player forward with ??? velocity + Vector direction = player.getLocation().getDirection().normalize(); + direction.multiply(FLIGHT_VELOCITY); // Set velocity magnitude + + player.setVelocity(direction); } private boolean canPropel() diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/smelting/Smelter.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/smelting/Smelter.java index 92976abc6..7fb1195bc 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/smelting/Smelter.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/smelting/Smelter.java @@ -1,5 +1,7 @@ package mineplex.game.clans.items.smelting; +import mineplex.game.clans.items.GearManager; + import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -9,21 +11,32 @@ public class Smelter public static void smeltItemInHand(Player player) { - // Smelt item in hand for player ItemStack item = player.getInventory().getItemInHand(); - if (item != null) + if (isSmeltable(item)) { ItemStack returns = smeltItem(item); player.getInventory().setItemInHand(returns); } + + // TODO: Notify player of smelt success/failure? } public static ItemStack smeltItem(ItemStack item) { Material material = getSmeltedType(item.getType()); int maxAmount = getSmeltAmount(item.getType()); - int amount = maxAmount; // TODO: Determine proportional return on smelt depending on type/durability + int amount = maxAmount; + + if (!GearManager.isCustomItem(item)) + { + short maxDurability = item.getType().getMaxDurability(); + int durability = maxDurability - item.getDurability(); + double percent = durability / (double) maxDurability; + System.out.println("Durability: " + item.getDurability() + " -- max: " + item.getType().getMaxDurability() + " --- percent: " + percent); + amount = Math.max(1, (int) (maxAmount * percent)); + } + return new ItemStack(material, amount); } @@ -60,6 +73,13 @@ public class Smelter } } + private static boolean isSmeltable(ItemStack item) + { + if (item == null) return false; + + return getSmeltedType(item.getType()) != null; + } + private static Material getSmeltedType(Material itemType) { switch (itemType) diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Utility.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Utility.java index b848f99cd..8c0af1c99 100644 --- a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Utility.java +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Utility.java @@ -41,6 +41,8 @@ public class Utility */ public static T deserialize(String serializedData, Class type) { + if (serializedData == null) return null; + return _gson.fromJson(serializedData, type); } diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/serialization/RuntimeTypeAdapterFactory.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/serialization/RuntimeTypeAdapterFactory.java new file mode 100644 index 000000000..33dc2239e --- /dev/null +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/serialization/RuntimeTypeAdapterFactory.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mineplex.serverdata.serialization; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + *

Registering Types

+ * Create a {@code RuntimeTypeAdapter} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   RuntimeTypeAdapter shapeAdapter
+ *       = RuntimeTypeAdapter.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapter.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapter.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapter.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapter(Shape.class, shapeAdapter)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   RuntimeTypeAdapter shapeAdapter = RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap>(); + private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory(baseType, "type"); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final Map> labelToDelegate + = new LinkedHashMap>(); + final Map, TypeAdapter> subtypeToDelegate + = new LinkedHashMap, TypeAdapter>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override public R read(JsonReader in) throws IOException { + JsonElement jsonElement = Streams.parse(in); + JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + JsonObject clone = new JsonObject(); + clone.add(typeFieldName, new JsonPrimitive(label)); + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + Streams.write(clone, out); + } + }; + } +} \ No newline at end of file