├── src └── main │ ├── java │ └── com │ │ └── planetgallium │ │ ├── database │ │ ├── DataType.java │ │ ├── TopEntry.java │ │ ├── Field.java │ │ ├── Record.java │ │ └── Database.java │ │ └── kitpvp │ │ ├── menu │ │ ├── KitHolder.java │ │ ├── PreviewHolder.java │ │ ├── RefillMenu.java │ │ ├── KitMenu.java │ │ └── PreviewMenu.java │ │ ├── api │ │ ├── PlayerSelectKitEvent.java │ │ ├── PlayerLevelUpEvent.java │ │ ├── PlayerAbilityEvent.java │ │ ├── EventListener.java │ │ ├── Ability.java │ │ └── Kit.java │ │ ├── game │ │ ├── Menus.java │ │ ├── Leaderboards.java │ │ ├── Cooldowns.java │ │ ├── Leaderboard.java │ │ ├── Utilities.java │ │ ├── KillStreaks.java │ │ ├── Abilities.java │ │ ├── Infoboard.java │ │ ├── Stats.java │ │ └── Arena.java │ │ ├── util │ │ ├── PlayerData.java │ │ ├── CacheManager.java │ │ ├── Menu.java │ │ ├── WorldGuardFlag.java │ │ ├── WorldGuardAPI.java │ │ ├── Cooldown.java │ │ ├── Updater.java │ │ ├── Placeholders.java │ │ ├── Resource.java │ │ └── Resources.java │ │ ├── listener │ │ ├── ChatListener.java │ │ ├── LeaveListener.java │ │ ├── HitListener.java │ │ ├── JoinListener.java │ │ ├── AttackListener.java │ │ ├── AbilityListener.java │ │ ├── TrackerListener.java │ │ ├── SoupListener.java │ │ ├── ArrowListener.java │ │ ├── MenuListener.java │ │ ├── SignListener.java │ │ └── ArenaListener.java │ │ ├── command │ │ └── AliasCommand.java │ │ ├── Game.java │ │ └── item │ │ └── AttributeWriter.java │ └── resources │ ├── abilities │ ├── ExampleAbility2.yml │ ├── SpeedBoost.yml │ ├── HealthPack.yml │ ├── Stampede.yml │ └── ExampleAbility.yml │ ├── plugin.yml │ ├── scoreboard.yml │ ├── kits │ ├── Fighter.yml │ ├── Tank.yml │ ├── Thunderbolt.yml │ ├── Ninja.yml │ ├── Archer.yml │ ├── Rhino.yml │ ├── Witch.yml │ ├── Vampire.yml │ ├── Kangaroo.yml │ ├── Warper.yml │ ├── Bomber.yml │ ├── Trickster.yml │ ├── Soldier.yml │ └── Example.yml │ ├── signs.yml │ ├── killstreaks.yml │ ├── abilities.yml │ ├── messages.yml │ ├── config.yml │ ├── levels.yml │ └── menu.yml ├── .github ├── ISSUE_TEMPLATE │ ├── report-a-bug.md │ └── ask-for-assistance.md └── CONTRIBUTING.md ├── README.md ├── .gitignore └── pom.xml /src/main/java/com/planetgallium/database/DataType.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.database; 2 | 3 | public enum DataType { 4 | FIXED_STRING, 5 | STRING, 6 | INTEGER, 7 | FLOAT 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/abilities/ExampleAbility2.yml: -------------------------------------------------------------------------------- 1 | Activator: 2 | Name: '&aSecond Ability Item &7(Unlimited custom abilities per kit!)' 3 | Material: GOLD_INGOT 4 | Message: 5 | Message: '%prefix% &7KitPvP supports &aunlimited &7custom kits and each with &aunlimited &7custom abilities!' -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/menu/KitHolder.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.menu; 2 | 3 | import org.bukkit.inventory.Inventory; 4 | import org.bukkit.inventory.InventoryHolder; 5 | 6 | public class KitHolder implements InventoryHolder { 7 | 8 | @Override 9 | public Inventory getInventory() { return null; } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/menu/PreviewHolder.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.menu; 2 | 3 | import org.bukkit.inventory.Inventory; 4 | import org.bukkit.inventory.InventoryHolder; 5 | 6 | public class PreviewHolder implements InventoryHolder { 7 | 8 | @Override 9 | public Inventory getInventory() { return null; } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/abilities/SpeedBoost.yml: -------------------------------------------------------------------------------- 1 | Activator: 2 | Name: '&aSpeed Boost &7(Right Click)' 3 | Material: FEATHER 4 | Cooldown: 5 | Cooldown: '40S' 6 | Message: 7 | Message: '%prefix% &7You have used a &bSpeed Boost&7.' 8 | Sound: 9 | Sound: ZOMBIE_IDLE 10 | Pitch: 1 11 | Volume: 1 12 | Effects: 13 | SPEED: 14 | Amplifier: 7 15 | Duration: 10 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/report-a-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Report a bug 3 | about: Create a KitPvP bug report 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Description of the bug** 11 | 12 | 13 | **Screenshot of /kp debug** 14 | 15 | 16 | **Additional screenshots or video (if applicable)** 17 | 18 | 19 | **Pastebin.com of any relevant .yml files (if applicable)** 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ask-for-assistance.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Ask for assistance 3 | about: Need help with the plugin or need to ask a question? 4 | title: '' 5 | labels: help wanted 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Problem** 11 | 12 | 13 | **What I have tried** 14 | 15 | 16 | **Screenshot of /kp debug** 17 | 18 | 19 | **Any additional information (copy of config files, screenshots, videos, etc.)** 20 | -------------------------------------------------------------------------------- /src/main/resources/abilities/HealthPack.yml: -------------------------------------------------------------------------------- 1 | Activator: 2 | Name: '&aHealth Pack &7(Right Click)' 3 | Material: ENDER_CHEST 4 | Cooldown: 5 | Cooldown: '30S' 6 | Message: 7 | Message: '%prefix% &7You have used a &bHealth Pack&7.' 8 | Sound: 9 | Sound: ANVIL_USE 10 | Pitch: 1 11 | Volume: 1 12 | Effects: 13 | SPEED: 14 | Amplifier: 2 15 | Duration: 10 16 | REGENERATION: 17 | Amplifier: 2 18 | Duration: 10 -------------------------------------------------------------------------------- /src/main/resources/abilities/Stampede.yml: -------------------------------------------------------------------------------- 1 | Activator: 2 | Name: '&aStampede &7(Right Click)' 3 | Material: FIREWORK_STAR 4 | Cooldown: 5 | Cooldown: '60S' 6 | Message: 7 | Message: '%prefix% &7You have used your ability.' 8 | Sound: 9 | Sound: HORSE_ANGRY 10 | Pitch: 0 11 | Volume: 1 12 | Effects: 13 | SPEED: 14 | Level: 3 15 | Duration: 5 16 | REGENERATION: 17 | Level: 3 18 | Duration: 5 19 | INCREASE_DAMAGE: 20 | Level: 2 21 | Duration: 5 22 | NIGHT_VISION: 23 | Level: 1 24 | Duration: 5 -------------------------------------------------------------------------------- /src/main/resources/abilities/ExampleAbility.yml: -------------------------------------------------------------------------------- 1 | Activator: 2 | Name: '&aAbility Item' 3 | Material: EMERALD 4 | Cooldown: 5 | Cooldown: '10S' 6 | Message: 7 | Message: '%prefix% &7This is an example ability message.' 8 | Sound: 9 | Sound: NOTE_PLING 10 | Pitch: 1 11 | Volume: 1 12 | Effects: 13 | SPEED: 14 | Amplifier: 5 15 | Duration: 10 16 | Commands: 17 | - 'console: say Hi %player%, this is an example console command that can be run when you use your ability.' 18 | - 'player: me This is an example player command that can be run when you use your ability.' -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: KitPvP 2 | author: Cervinakuy 3 | main: com.planetgallium.kitpvp.Game 4 | version: 2.2.5 5 | description: The ultimate all-in-one KitPvP plugin. 6 | website: https://www.spigotmc.org/resources/27107/ 7 | softdepend: [PlaceholderAPI, WorldGuard] 8 | api-version: 1.13 9 | 10 | commands: 11 | kitpvp: 12 | description: Main command. 13 | aliases: [kp, kit-pvp] 14 | ckit: 15 | description: Select a kit. 16 | cspawn: 17 | description: Teleports you to the spawn. 18 | ckits: 19 | description: View all available kits. 20 | cstats: 21 | description: View your stats. -------------------------------------------------------------------------------- /src/main/resources/scoreboard.yml: -------------------------------------------------------------------------------- 1 | # To learn more about customizing the Scoreboard, please 2 | # visit the scoreboard.yml documentation on GitHub: 3 | # https://github.com/cervinakuy/KitPvP/wiki/scoreboard.yml 4 | 5 | Scoreboard: 6 | General: 7 | Title: '&0 &r&b&lKIT-PVP &0' 8 | Enabled: true 9 | Lines: 10 | - ' ' 11 | - '&e&lStats' 12 | - '&aName: &f%player%' 13 | - '&aKills: &f%kills%' 14 | - '&aDeaths: &f%deaths%' 15 | - '&aK/D Ratio: &f%kd%' 16 | - ' ' 17 | - '&6&lLevel' 18 | - '&aLevel: &f%level%/%max_level%' 19 | - '&aExperience: &f%xp%/%max_xp%' 20 | - ' ' 21 | - '&c&lKill Streak' 22 | - '&f%streak% Kills' 23 | - ' ' 24 | - '&ewww.myserver.com' -------------------------------------------------------------------------------- /src/main/resources/kits/Fighter.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.fighter 3 | Cooldown: 0 4 | Level: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Fighter Helmet' 9 | Material: IRON_HELMET 10 | Chestplate: 11 | Name: '&7Fighter Chestplate' 12 | Material: IRON_CHESTPLATE 13 | Leggings: 14 | Name: '&7Fighter Leggings' 15 | Material: IRON_LEGGINGS 16 | Boots: 17 | Name: '&7Fighter Boots' 18 | Material: IRON_BOOTS 19 | Items: 20 | 0: 21 | Name: '&aFighter''s Sword' 22 | Material: IRON_SWORD 23 | 1: 24 | Name: '&aHealth Pack &7(Right Click)' 25 | Material: ENDER_CHEST 26 | 8: 27 | Name: '&aPlayer Tracker &7(Right Click)' 28 | Material: COMPASS 29 | Fill: 30 | Name: '&aRegenerative Soup &7(Right Click)' 31 | Material: MUSHROOM_SOUP -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Process 4 | If you submit a pull request, please make **1** singular pull request per major change. Do not submit one huge pull request that includes many changes. If an individual change is not approved, this will block your entire pull request from being merged. 5 | 6 | Your commits should also be descriptive, properly labeled, and contained. Do not have generic commit labels (e.g. "Improvements", "Changes"), and do not submit commits that include changes outside of the scope of the commit label (e.g. "Fix death messages not showing for players killed by ender dragon" commit label, but commit also touches unrelated kit ability logic). 7 | 8 | If you have identified an issue within the plugin and have limited Java experience, 9 | please consider [submitting an issue](https://github.com/cervinakuy/KitPvP/issues) instead. 10 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/api/PlayerSelectKitEvent.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.api; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Event; 5 | import org.bukkit.event.HandlerList; 6 | 7 | public class PlayerSelectKitEvent extends Event { 8 | 9 | private static final HandlerList HANDLERS = new HandlerList(); 10 | 11 | private final Player player; 12 | private final Kit kit; 13 | 14 | public PlayerSelectKitEvent(Player player, Kit kit) { 15 | this.player = player; 16 | this.kit = kit; 17 | } 18 | 19 | public Player getPlayer() { return player; } 20 | 21 | public Kit getKit() { return kit; } 22 | 23 | public HandlerList getHandlers() { return HANDLERS; } 24 | 25 | public String getEventName() { return "PlayerSelectKitEvent"; } 26 | 27 | public static HandlerList getHandlerList() { return HANDLERS; } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/api/PlayerLevelUpEvent.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.api; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Event; 5 | import org.bukkit.event.HandlerList; 6 | 7 | public class PlayerLevelUpEvent extends Event { 8 | 9 | private static final HandlerList HANDLERS = new HandlerList(); 10 | 11 | private final Player player; 12 | private final int level; 13 | 14 | public PlayerLevelUpEvent(Player player, int level) { 15 | this.player = player; 16 | this.level = level; 17 | } 18 | 19 | public Player getPlayer() { return player; } 20 | 21 | public int getLevel() { return level; } 22 | 23 | public HandlerList getHandlers() { return HANDLERS; } 24 | 25 | public String getEventName() { return "PlayerLevelUpEvent"; } 26 | 27 | public static HandlerList getHandlerList() { return HANDLERS; } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/Menus.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import com.planetgallium.kitpvp.menu.KitMenu; 4 | import com.planetgallium.kitpvp.menu.PreviewMenu; 5 | import com.planetgallium.kitpvp.menu.RefillMenu; 6 | import com.planetgallium.kitpvp.util.Resources; 7 | 8 | public class Menus { 9 | 10 | private final KitMenu kitMenu; 11 | private final PreviewMenu previewMenu; 12 | private final RefillMenu refillMenu; 13 | 14 | public Menus(Resources resources) { 15 | this.kitMenu = new KitMenu(resources); 16 | this.previewMenu = new PreviewMenu(); 17 | this.refillMenu = new RefillMenu(resources); 18 | } 19 | 20 | public KitMenu getKitMenu() { return kitMenu; } 21 | 22 | public PreviewMenu getPreviewMenu() { return previewMenu; } 23 | 24 | public RefillMenu getRefillMenu() { return refillMenu; } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/kits/Tank.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.tank 3 | Cooldown: 0 4 | Level: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Tank Helmet' 9 | Material: IRON_HELMET 10 | Chestplate: 11 | Name: '&7Tank Chestplate' 12 | Material: DIAMOND_CHESTPLATE 13 | Leggings: 14 | Name: '&7Tank Leggings' 15 | Material: DIAMOND_LEGGINGS 16 | Boots: 17 | Name: '&7Tank Boots' 18 | Material: IRON_BOOTS 19 | Items: 20 | 0: 21 | Name: '&aTank''s Sword' 22 | Material: IRON_SWORD 23 | 1: 24 | Name: '&aSpeed Boost &7(Right Click)' 25 | Material: FEATHER 26 | 8: 27 | Name: '&aPlayer Tracker &7(Right Click)' 28 | Material: COMPASS 29 | Fill: 30 | Name: '&aRegenerative Soup &7(Right Click)' 31 | Material: MUSHROOM_SOUP 32 | Effects: 33 | SLOW: 34 | Amplifier: 2 35 | Duration: -1 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![image](https://i.imgur.com/3MpRXfn.png) 2 | 3 | # KitPvP 4 | The all-in-one battle plugin featuring custom kits, custom abilities, leaderboards, levels, kill streaks, and more. 5 | 6 | ## Support 7 | We use GitHub for plugin support, bug tracking, and any other topics related to KitPvP. 8 | 9 | Prior to contacting us via the below links, please ensure you have fully read the [KitPvP Wiki](https://github.com/cervinakuy/KitPvP/wiki). 10 | 11 | The below links require being logged into a GitHub account. 12 | * [Ask a question](https://github.com/cervinakuy/KitPvP/issues/new?assignees=&labels=help+wanted&template=ask-for-assistance.md&title=) 13 | * [Report a bug](https://github.com/cervinakuy/KitPvP/issues/new?assignees=&labels=bug&template=report-a-bug.md&title=) 14 | 15 | ## Quick Links 16 | * [Plugin Page](https://www.spigotmc.org/resources/27107/) 17 | * [Wiki](https://github.com/cervinakuy/KitPvP/wiki) -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/database/TopEntry.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.database; 2 | 3 | public class TopEntry implements Comparable { 4 | 5 | private final String identifier; 6 | private int value; 7 | 8 | public TopEntry(String identifier, int value) { 9 | this.identifier = identifier; 10 | this.value = value; 11 | } 12 | 13 | @Override 14 | public int compareTo(TopEntry otherEntry) { 15 | if (this.getValue() < otherEntry.getValue()) { 16 | return 1; 17 | } else if (this.getValue() > otherEntry.getValue()) { 18 | return -1; 19 | } 20 | return 0; // if they're equal, will return 0 21 | } 22 | 23 | public void setValue(int newValue) { this.value = newValue; } 24 | 25 | public String getIdentifier() { return identifier; } 26 | 27 | public int getValue() { return value; } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | /target 19 | /dependency-reduced-pom.xml 20 | 21 | # intellij 22 | *.iml 23 | *.ipr 24 | *.iws 25 | .idea/ 26 | 27 | # External tool builders 28 | .externalToolBuilders/ 29 | 30 | # Locally stored "Eclipse launch configurations" 31 | *.launch 32 | 33 | # CDT-specific 34 | .cproject 35 | 36 | # PDT-specific 37 | .buildpath 38 | 39 | ############ 40 | ## Windows 41 | ############ 42 | 43 | # Windows image file caches 44 | Thumbs.db 45 | 46 | # Folder config file 47 | Desktop.ini 48 | 49 | # Installer logs 50 | pip-log.txt 51 | 52 | # Unit test / coverage reports 53 | .coverage 54 | .tox 55 | 56 | #Translations 57 | *.mo 58 | 59 | #Mr Developer 60 | .mr.developer.cfg 61 | 62 | # Mac crap 63 | .DS_Store -------------------------------------------------------------------------------- /src/main/resources/kits/Thunderbolt.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.thunderbolt 3 | Level: 0 4 | Cooldown: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Thunderbolt Helmet' 9 | Material: LEATHER_HELMET 10 | Dye: 11 | Red: 224 12 | Green: 249 13 | Blue: 0 14 | Chestplate: 15 | Name: '&7Thunderbolt Chestplate' 16 | Material: GOLD_CHESTPLATE 17 | Leggings: 18 | Name: '&7Thunderbolt Leggings' 19 | Material: GOLD_LEGGINGS 20 | Boots: 21 | Name: '&7Thunderbolt Boots' 22 | Material: GOLD_BOOTS 23 | Items: 24 | 0: 25 | Name: '&aThunderbolt''s Sword' 26 | Material: GOLD_SWORD 27 | 1: 28 | Name: '&aLightning Strike &7(Click Player)' 29 | Material: BLAZE_ROD 30 | Amount: 3 31 | 8: 32 | Name: '&aPlayer Tracker &7(Right Click)' 33 | Material: COMPASS 34 | Fill: 35 | Name: '&aRegenerative Soup &7(Right Click)' 36 | Material: MUSHROOM_SOUP -------------------------------------------------------------------------------- /src/main/resources/signs.yml: -------------------------------------------------------------------------------- 1 | # To learn how to create signs, please 2 | # visit the signs.yml documentation on GitHub: 3 | # https://github.com/cervinakuy/KitPvP/wiki/signs.yml 4 | 5 | Signs: 6 | Kit: 7 | Line-1: '&7[&b&lKIT-PVP&7]' 8 | Line-2: '&1Click to select' 9 | Line-3: '&1%kit% kit' 10 | Line-4: ' ' 11 | Clear: 12 | Line-1: '&7[&b&lKIT-PVP&7]' 13 | Line-2: '&1Click to clear' 14 | Line-3: '&1your current kit' 15 | Line-4: ' ' 16 | Menu: 17 | Line-1: '&7[&b&lKIT-PVP&7]' 18 | Line-2: '&1Click to open' 19 | Line-3: '&1the kit selector' 20 | Line-4: ' ' 21 | Stats: 22 | Line-1: '&7[&b&lKIT-PVP&7]' 23 | Line-2: '&1Click to view' 24 | Line-3: '&1your stats' 25 | Line-4: ' ' 26 | Refill: 27 | Line-1: '&7[&b&lKIT-PVP&7]' 28 | Line-2: '&1Click to refill' 29 | Line-3: '&1your soups' 30 | Line-4: ' ' 31 | Arena: 32 | Line-1: '&7[&b&lKIT-PVP&7]' 33 | Line-2: '&1Click to teleport' 34 | Line-3: '&1to &1%arena% &1arena' 35 | Line-4: ' ' -------------------------------------------------------------------------------- /src/main/resources/kits/Ninja.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.ninja 3 | Level: 0 4 | Cooldown: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Ninja Helmet' 9 | Material: LEATHER_HELMET 10 | Dye: 11 | Red: 0 12 | Green: 0 13 | Blue: 0 14 | Chestplate: 15 | Name: '&7Ninja Chestplate' 16 | Material: CHAINMAIL_CHESTPLATE 17 | Leggings: 18 | Name: '&7Ninja Leggings' 19 | Material: CHAINMAIL_LEGGINGS 20 | Boots: 21 | Name: '&7Ninja Boots' 22 | Material: CHAINMAIL_BOOTS 23 | Items: 24 | 0: 25 | Name: '&aNinja''s Sword' 26 | Material: IRON_SWORD 27 | 1: 28 | Name: '&aVanish Stars &7(Right Click)' 29 | Material: NETHER_STAR 30 | Amount: 3 31 | 8: 32 | Name: '&aPlayer Tracker &7(Right Click)' 33 | Material: COMPASS 34 | Fill: 35 | Name: '&aRegenerative Soup &7(Right Click)' 36 | Material: MUSHROOM_SOUP 37 | Effects: 38 | SPEED: 39 | Amplifier: 1 40 | Duration: -1 -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/menu/RefillMenu.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.menu; 2 | 3 | import com.planetgallium.kitpvp.util.Menu; 4 | import com.planetgallium.kitpvp.util.Resources; 5 | import com.planetgallium.kitpvp.util.Toolkit; 6 | import org.bukkit.Material; 7 | import org.bukkit.entity.Player; 8 | 9 | import java.util.List; 10 | 11 | public class RefillMenu { 12 | 13 | private final Resources resources; 14 | private Menu menu; 15 | 16 | public RefillMenu(Resources resources) { 17 | this.resources = resources; 18 | } 19 | 20 | private void create() { 21 | this.menu = new Menu("Refill", null, 54); 22 | 23 | for (int i = 0; i < menu.getSize(); i++) { 24 | menu.addItem(resources.getConfig().fetchString("Soups.Name"), 25 | Toolkit.safeMaterial("MUSHROOM_STEW"), 26 | resources.getConfig().getStringList("Soups.Lore"), i); 27 | } 28 | } 29 | 30 | public void open(Player p) { 31 | create(); 32 | menu.openMenu(p); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/resources/kits/Archer.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.archer 3 | Cooldown: 0 4 | Level: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Archer Helmet' 9 | Material: CHAINMAIL_HELMET 10 | Chestplate: 11 | Name: '&7Archer Chestplate' 12 | Material: CHAINMAIL_CHESTPLATE 13 | Leggings: 14 | Name: '&7Archer Leggings' 15 | Material: CHAINMAIL_LEGGINGS 16 | Boots: 17 | Name: '&7Archer Boots' 18 | Material: CHAINMAIL_BOOTS 19 | Items: 20 | 0: 21 | Name: '&aArcher''s Sword' 22 | Material: STONE_SWORD 23 | 1: 24 | Name: '&aArcher''s Bow' 25 | Material: BOW 26 | 2: 27 | Name: '&aFire Arrows &cOFF &7(Right Click)' 28 | Material: SLIME_BALL 29 | Amount: 10 30 | 7: 31 | Name: '&aArcher''s Arrows &7(+1 arrow each successful shot)' 32 | Material: ARROW 33 | Amount: 64 34 | 8: 35 | Name: '&aPlayer Tracker &7(Right Click)' 36 | Material: COMPASS 37 | Fill: 38 | Name: '&aRegenerative Soup &7(Right Click)' 39 | Material: MUSHROOM_SOUP -------------------------------------------------------------------------------- /src/main/resources/kits/Rhino.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.rhino 3 | Cooldown: 0 4 | Level: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Rhino Helmet' 9 | Material: DIAMOND_HELMET 10 | Chestplate: 11 | Name: '&7Rhino Chestplate' 12 | Material: LEATHER_CHESTPLATE 13 | Amount: 1 14 | Dye: 15 | Red: 76 16 | Green: 76 17 | Blue: 76 18 | Leggings: 19 | Name: '&7Rhino Leggings' 20 | Material: LEATHER_LEGGINGS 21 | Amount: 1 22 | Dye: 23 | Red: 76 24 | Green: 76 25 | Blue: 76 26 | Boots: 27 | Name: '&7Rhino Boots' 28 | Material: LEATHER_BOOTS 29 | Amount: 1 30 | Dye: 31 | Red: 76 32 | Green: 76 33 | Blue: 76 34 | Items: 35 | 0: 36 | Name: '&aRhino''s Sword' 37 | Material: IRON_SWORD 38 | 1: 39 | Name: '&aStampede &7(Right Click)' 40 | Material: FIREWORK_STAR 41 | 8: 42 | Name: '&aPlayer Tracker &7(Right Click)' 43 | Material: COMPASS 44 | Fill: 45 | Name: '&aRegenerative Soup &7(Right Click)' 46 | Material: MUSHROOM_SOUP -------------------------------------------------------------------------------- /src/main/resources/kits/Witch.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.witch 3 | Level: 0 4 | Cooldown: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Witch Helmet' 9 | Material: LEATHER_HELMET 10 | Dye: 11 | Red: 139 12 | Green: 0 13 | Blue: 139 14 | Chestplate: 15 | Name: '&7Witch Chestplate' 16 | Material: LEATHER_CHESTPLATE 17 | Dye: 18 | Red: 139 19 | Green: 0 20 | Blue: 139 21 | Leggings: 22 | Name: '&7Witch Leggings' 23 | Material: LEATHER_LEGGINGS 24 | Dye: 25 | Red: 139 26 | Green: 0 27 | Blue: 139 28 | Boots: 29 | Name: '&7Witch Boots' 30 | Material: LEATHER_BOOTS 31 | Dye: 32 | Red: 139 33 | Green: 0 34 | Blue: 139 35 | Items: 36 | 0: 37 | Name: '&aWitch''s Sword' 38 | Material: IRON_SWORD 39 | 1: 40 | Name: '&aPotion Switcher &7(Right Click)' 41 | Material: GLASS_BOTTLE 42 | 8: 43 | Name: '&aPlayer Tracker &7(Right Click)' 44 | Material: COMPASS 45 | Fill: 46 | Name: '&aRegenerative Soup &7(Right Click)' 47 | Material: MUSHROOM_SOUP -------------------------------------------------------------------------------- /src/main/resources/kits/Vampire.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.vampire 3 | Level: 0 4 | Cooldown: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Vampire Helmet' 9 | Material: LEATHER_HELMET 10 | Dye: 11 | Red: 252 12 | Green: 45 13 | Blue: 59 14 | Chestplate: 15 | Name: '&7Vampire Chestplate' 16 | Material: LEATHER_CHESTPLATE 17 | Dye: 18 | Red: 0 19 | Green: 0 20 | Blue: 0 21 | Leggings: 22 | Name: '&7Vampire Leggings' 23 | Material: LEATHER_LEGGINGS 24 | Dye: 25 | Red: 0 26 | Green: 0 27 | Blue: 0 28 | Boots: 29 | Name: '&7Vampire Boots' 30 | Material: LEATHER_BOOTS 31 | Dye: 32 | Red: 252 33 | Green: 45 34 | Blue: 59 35 | Items: 36 | 0: 37 | Name: '&aVampire''s Sword' 38 | Material: IRON_SWORD 39 | 1: 40 | Name: '&aBlood Suckers &7(Click Player)' 41 | Material: GHAST_TEAR 42 | Amount: 5 43 | 8: 44 | Name: '&aPlayer Tracker &7(Right Click)' 45 | Material: COMPASS 46 | Fill: 47 | Name: '&aRegenerative Soup &7(Right Click)' 48 | Material: MUSHROOM_SOUP -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/api/PlayerAbilityEvent.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.api; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Event; 5 | import org.bukkit.event.HandlerList; 6 | import org.bukkit.event.player.PlayerInteractEvent; 7 | 8 | public class PlayerAbilityEvent extends Event { 9 | 10 | private static final HandlerList HANDLERS = new HandlerList(); 11 | 12 | private final Player player; 13 | private final Ability ability; 14 | private final PlayerInteractEvent originalInteractionEvent; 15 | 16 | public PlayerAbilityEvent(Player player, Ability ability, PlayerInteractEvent originalInteractionEvent) { 17 | this.player = player; 18 | this.ability = ability; 19 | this.originalInteractionEvent = originalInteractionEvent; 20 | } 21 | 22 | public Player getPlayer() { return player; } 23 | 24 | public Ability getAbility() { return ability; } 25 | 26 | public HandlerList getHandlers() { return HANDLERS; } 27 | 28 | public String getEventName() { return "PlayerAbilityEvent"; } 29 | 30 | public PlayerInteractEvent getOriginalInteractionEvent() { return originalInteractionEvent; } 31 | 32 | public static HandlerList getHandlerList() { return HANDLERS; } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/PlayerData.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class PlayerData { 7 | 8 | private final Map data; 9 | private final Map kitCooldowns; 10 | 11 | public PlayerData(int kills, int deaths, int experience, int level) { 12 | this.data = new HashMap<>(); 13 | this.kitCooldowns = new HashMap<>(); 14 | 15 | data.put("kills", kills); 16 | data.put("deaths", deaths); 17 | data.put("experience", experience); 18 | data.put("level", level); 19 | } 20 | 21 | public void setData(String identifier, int value) { 22 | data.put(identifier, value); 23 | } 24 | 25 | public void addKitCooldown(String kitName, long timeKitLastUsed) { kitCooldowns.put(kitName, timeKitLastUsed); } 26 | 27 | public int getData(String identifier) { 28 | return data.get(identifier); 29 | } 30 | 31 | public long getTimeKitLastUsed(String kitName) { return kitCooldowns.get(kitName); } 32 | 33 | public Map getKitCooldowns() { return kitCooldowns; } 34 | 35 | public Map getData() { return data; } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/kits/Kangaroo.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.kangaroo 3 | Level: 0 4 | Cooldown: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Kangaroo Helmet' 9 | Material: LEATHER_HELMET 10 | Dye: 11 | Red: 165 12 | Green: 42 13 | Blue: 42 14 | Chestplate: 15 | Name: '&7Kangaroo Chestplate' 16 | Material: LEATHER_CHESTPLATE 17 | Dye: 18 | Red: 165 19 | Green: 42 20 | Blue: 42 21 | Leggings: 22 | Name: '&7Kangaroo Leggings' 23 | Material: LEATHER_LEGGINGS 24 | Dye: 25 | Red: 165 26 | Green: 42 27 | Blue: 42 28 | Boots: 29 | Name: '&7Kangaroo Boots' 30 | Material: LEATHER_BOOTS 31 | Dye: 32 | Red: 165 33 | Green: 42 34 | Blue: 42 35 | Items: 36 | 0: 37 | Name: '&aKangaroo''s Sword' 38 | Material: IRON_SWORD 39 | 1: 40 | Name: '&aLauncher &7(Right Click)' 41 | Material: SADDLE 42 | Amount: 3 43 | 8: 44 | Name: '&aPlayer Tracker &7(Right Click)' 45 | Material: COMPASS 46 | Fill: 47 | Name: '&aRegenerative Soup &7(Right Click)' 48 | Material: MUSHROOM_SOUP 49 | Effects: 50 | JUMP: 51 | Amplifier: 2 52 | Duration: -1 -------------------------------------------------------------------------------- /src/main/resources/kits/Warper.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.warper 3 | Level: 0 4 | Cooldown: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Warper Helmet' 9 | Material: LEATHER_HELMET 10 | Dye: 11 | Red: 0 12 | Green: 0 13 | Blue: 0 14 | Chestplate: 15 | Name: '&7Warper Chestplate' 16 | Material: LEATHER_CHESTPLATE 17 | Dye: 18 | Red: 0 19 | Green: 0 20 | Blue: 0 21 | Leggings: 22 | Name: '&7Warper Leggings' 23 | Material: LEATHER_LEGGINGS 24 | Dye: 25 | Red: 0 26 | Green: 0 27 | Blue: 0 28 | Boots: 29 | Name: '&7Warper Boots' 30 | Material: LEATHER_BOOTS 31 | Dye: 32 | Red: 0 33 | Green: 0 34 | Blue: 0 35 | Items: 36 | 0: 37 | Name: '&aWarper''s Sword' 38 | Material: IRON_SWORD 39 | 1: 40 | Name: '&aEnder Pearls' 41 | Material: ENDER_PEARL 42 | Amount: 4 43 | 2: 44 | Name: '&aNearest Player Teleporter &7(Right Click)' 45 | Material: EYE_OF_ENDER 46 | Amount: 3 47 | 8: 48 | Name: '&aPlayer Tracker &7(Right Click)' 49 | Material: COMPASS 50 | Fill: 51 | Name: '&aRegenerative Soup &7(Right Click)' 52 | Material: MUSHROOM_SOUP -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/ChatListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.planetgallium.kitpvp.game.Arena; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.EventHandler; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.event.player.AsyncPlayerChatEvent; 8 | 9 | import com.planetgallium.kitpvp.Game; 10 | import com.planetgallium.kitpvp.util.Resources; 11 | import com.planetgallium.kitpvp.util.Toolkit; 12 | 13 | public class ChatListener implements Listener { 14 | 15 | private final Arena arena; 16 | private final Resources resources; 17 | 18 | public ChatListener(Game plugin) { 19 | this.arena = plugin.getArena(); 20 | this.resources = plugin.getResources(); 21 | } 22 | 23 | @EventHandler 24 | public void onChat(AsyncPlayerChatEvent e) { 25 | if (resources.getConfig().getBoolean("Chat.Enabled") && Toolkit.inArena(e.getPlayer())) { 26 | Player p = e.getPlayer(); 27 | String levelPrefix = arena.getUtilities().getPlayerLevelPrefix(p.getName()); 28 | 29 | String format = resources.getConfig().fetchString("Chat.Format") 30 | .replace("%player%", "%s") 31 | .replace("%message%", "%s") 32 | .replace("%level%", levelPrefix); 33 | 34 | e.setFormat(Toolkit.addPlaceholdersIfPossible(p, format)); 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/kits/Bomber.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.bomber 3 | Cooldown: 0 4 | Level: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Bomber Helmet' 9 | Material: LEATHER_HELMET 10 | Dye: 11 | Red: 252 12 | Green: 45 13 | Blue: 59 14 | Chestplate: 15 | Name: '&7Bomber Chestplate' 16 | Material: LEATHER_CHESTPLATE 17 | Dye: 18 | Red: 252 19 | Green: 45 20 | Blue: 59 21 | Leggings: 22 | Name: '&7Bomber Leggings' 23 | Material: LEATHER_LEGGINGS 24 | Dye: 25 | Red: 252 26 | Green: 45 27 | Blue: 59 28 | Boots: 29 | Name: '&7Bomber Boots' 30 | Material: LEATHER_BOOTS 31 | Dye: 32 | Red: 252 33 | Green: 45 34 | Blue: 59 35 | Items: 36 | 0: 37 | Name: '&aBomber''s Sword' 38 | Material: IRON_SWORD 39 | 1: 40 | Name: '&aThrowable TNT &7(Right Click)' 41 | Material: TNT 42 | Amount: 16 43 | 2: 44 | Name: '&aTNT Trail &7(Right Click)' 45 | Material: COAL 46 | Amount: 3 47 | 8: 48 | Name: '&aPlayer Tracker &7(Right Click)' 49 | Material: COMPASS 50 | Fill: 51 | Name: '&aRegenerative Soup &7(Right Click)' 52 | Material: MUSHROOM_SOUP 53 | Effects: 54 | SPEED: 55 | Amplifier: 2 56 | Duration: -1 -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/menu/KitMenu.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.menu; 2 | 3 | import com.planetgallium.kitpvp.util.*; 4 | import org.bukkit.Material; 5 | import org.bukkit.configuration.ConfigurationSection; 6 | import org.bukkit.entity.Player; 7 | 8 | import java.util.List; 9 | 10 | public class KitMenu { 11 | 12 | private Menu menu; 13 | private final Resources resources; 14 | 15 | public KitMenu(Resources resources) { 16 | this.resources = resources; 17 | // rebuildCache(); 18 | } 19 | 20 | private void create() { 21 | this.menu = new Menu(resources.getMenu().fetchString("Menu.General.Title"), new KitHolder(), resources.getMenu().getInt("Menu.General.Size")); 22 | 23 | ConfigurationSection section = resources.getMenu().getConfigurationSection("Menu.Items"); 24 | 25 | for (String slot : section.getKeys(false)) { 26 | String itemPath = "Menu.Items." + slot; 27 | 28 | String name = resources.getMenu().fetchString(itemPath + ".Name"); 29 | Material material = Toolkit.safeMaterial(resources.getMenu().fetchString(itemPath + ".Material")); 30 | List lore = resources.getMenu().getStringList(itemPath + ".Lore"); 31 | 32 | menu.addItem(name, material, lore, Integer.parseInt(slot)); 33 | } 34 | } 35 | 36 | // public void rebuildCache() { 37 | // create(); 38 | // } 39 | 40 | public void open(Player p) { 41 | create(); 42 | menu.openMenu(p); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/LeaveListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.planetgallium.kitpvp.util.Toolkit; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.EventHandler; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.event.player.PlayerChangedWorldEvent; 8 | import org.bukkit.event.player.PlayerQuitEvent; 9 | 10 | import com.planetgallium.kitpvp.Game; 11 | import com.planetgallium.kitpvp.game.Arena; 12 | 13 | public class LeaveListener implements Listener { 14 | 15 | private final Game plugin; 16 | private final Arena arena; 17 | 18 | public LeaveListener(Game plugin) { 19 | this.plugin = plugin; 20 | this.arena = plugin.getArena(); 21 | } 22 | 23 | @EventHandler 24 | public void onLeave(PlayerQuitEvent e) { 25 | Player p = e.getPlayer(); 26 | if (Toolkit.inArena(p)) { 27 | arena.deletePlayer(p); 28 | } 29 | } 30 | 31 | @EventHandler 32 | public void onWorldChange(PlayerChangedWorldEvent e) { 33 | if (Toolkit.inArena(e.getFrom())) { // if they left from a kitpvp arena 34 | Player p = e.getPlayer(); 35 | 36 | if (plugin.getConfig().getBoolean("Arena.ClearInventoryOnLeave")) { 37 | p.getInventory().clear(); 38 | p.getInventory().setArmorContents(null); 39 | } 40 | 41 | arena.removePlayer(p); 42 | // no need to clear stats from cache; that will be done on player quit above 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/resources/kits/Trickster.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.trickster 3 | Level: 0 4 | Cooldown: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Trickster Helmet' 9 | Material: LEATHER_HELMET 10 | Dye: 11 | Red: 22 12 | Green: 156 13 | Blue: 156 14 | Enchantments: 15 | thorns: 1 16 | Chestplate: 17 | Material: DIAMOND_CHESTPLATE 18 | Name: '&7Trickster Chestplate' 19 | Enchantments: 20 | thorns: 1 21 | Leggings: 22 | Name: '&7Trickster Leggings' 23 | Material: LEATHER_LEGGINGS 24 | Dye: 25 | Red: 22 26 | Green: 156 27 | Blue: 156 28 | Enchantments: 29 | thorns: 1 30 | Boots: 31 | Name: '&7Trickster Boots' 32 | Material: LEATHER_BOOTS 33 | Dye: 34 | Red: 22 35 | Green: 156 36 | Blue: 156 37 | Enchantments: 38 | thorns: 1 39 | Items: 40 | 0: 41 | Name: '&7Trickster''s Sword' 42 | Material: STONE_SWORD 43 | Enchantments: 44 | knockback: 2 45 | 1: 46 | Name: '&7Trickster''s Fishing Rod' 47 | Material: FISHING_ROD 48 | 2: 49 | Name: '&aSwitcher Pellets &7(Right Click)' 50 | Material: EGG 51 | Amount: 4 52 | 8: 53 | Name: '&aPlayer Tracker &7(Right Click)' 54 | Material: COMPASS 55 | Fill: 56 | Name: '&aRegenerative Soup &7(Right Click)' 57 | Material: MUSHROOM_SOUP 58 | -------------------------------------------------------------------------------- /src/main/resources/kits/Soldier.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.soldier 3 | Level: 0 4 | Cooldown: 0 5 | Inventory: 6 | Armor: 7 | Helmet: 8 | Name: '&7Soldier Helmet' 9 | Material: LEATHER_HELMET 10 | Dye: 11 | Red: 77 12 | Green: 175 13 | Blue: 123 14 | Chestplate: 15 | Name: '&7Soldier Chestplate' 16 | Material: CHAINMAIL_CHESTPLATE 17 | Dye: 18 | Red: 77 19 | Green: 175 20 | Blue: 123 21 | Leggings: 22 | Name: '&7Soldier Leggings' 23 | Material: LEATHER_LEGGINGS 24 | Dye: 25 | Red: 77 26 | Green: 175 27 | Blue: 123 28 | Boots: 29 | Name: '&7Soldier Boots' 30 | Material: LEATHER_BOOTS 31 | Dye: 32 | Red: 77 33 | Green: 175 34 | Blue: 123 35 | Items: 36 | 0: 37 | Name: '&aSoldier''s Sword' 38 | Material: STONE_SWORD 39 | 1: 40 | Name: '&aSoldier''s Bow' 41 | Material: BOW 42 | 2: 43 | Name: '&aSoldier''s Fishing Rod' 44 | Material: FISHING_ROD 45 | 3: 46 | Name: '&aGun &7(Right Click)' 47 | Material: IRON_HOE 48 | Amount: 5 49 | 7: 50 | Name: '&aSoldier''s Arrows &7(+1 arrow each successful shot)' 51 | Material: ARROW 52 | Amount: 32 53 | 8: 54 | Name: '&aPlayer Tracker &7(Right Click)' 55 | Material: COMPASS 56 | Fill: 57 | Name: '&aRegenerative Soup &7(Right Click)' 58 | Material: MUSHROOM_SOUP -------------------------------------------------------------------------------- /src/main/resources/killstreaks.yml: -------------------------------------------------------------------------------- 1 | # To learn all the options available with killstreaks, please 2 | # visit the killstreaks.yml documentation on GitHub: 3 | # https://github.com/cervinakuy/KitPvP/wiki/killstreaks.yml 4 | 5 | KillStreaks: 6 | 3: 7 | Sound: 8 | Sound: ENDERDRAGON_GROWL 9 | Pitch: 1 10 | Message: 11 | Message: '%prefix% &b%player% &7is on a killstreak of &b%streak% Kills&7.' 12 | 6: 13 | Title: 14 | Title: '&c&lKill Streak' 15 | Subtitle: '&6%player% &7is on a &6%streak% &7kill streak.' 16 | Sound: 17 | Sound: ENDERDRAGON_GROWL 18 | Pitch: 1 19 | Message: 20 | Message: '%prefix% &b%player% &7is on a killstreak of &b%streak% Kills&7.' 21 | 10: 22 | Title: 23 | Title: '&c&lKill Streak' 24 | Subtitle: '&6%player% &7is on a &6%streak% &7kill streak.' 25 | Sound: 26 | Sound: ENDERDRAGON_GROWL 27 | Pitch: 1 28 | Message: 29 | Message: '%prefix% &b%player% &7is on a killstreak of &b%streak% Kills&7.' 30 | Commands: 31 | - 'console: give %player% gold_ingot 1' 32 | EndStreaks: 33 | 3: 34 | Sound: 35 | Sound: ENDERDRAGON_GROWL 36 | Pitch: 1 37 | Message: 38 | Message: '%prefix% &b%player% &7lost their streak of &b%streak% Kills&7.' 39 | 6: 40 | Title: 41 | Title: '&c&lKill Streak' 42 | Subtitle: '&6%player% &7lost their streak of &6%streak%&7.' 43 | Sound: 44 | Sound: ENDERDRAGON_GROWL 45 | Pitch: 1 46 | Message: 47 | Message: '%prefix% &b%player% &7lost their streak of &b%streak% Kills&7.' -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/HitListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.cryptomorin.xseries.XSound; 4 | import com.planetgallium.kitpvp.Game; 5 | import com.planetgallium.kitpvp.game.Arena; 6 | import com.planetgallium.kitpvp.util.Resource; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.EventHandler; 9 | import org.bukkit.event.Listener; 10 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 11 | import com.planetgallium.kitpvp.util.Toolkit; 12 | 13 | public class HitListener implements Listener { 14 | 15 | private final Arena arena; 16 | private final Resource config; 17 | private final XSound.Record hitSound; 18 | 19 | public HitListener(Game plugin) { 20 | this.arena = plugin.getArena(); 21 | this.config = plugin.getResources().getConfig(); 22 | 23 | String soundString = config.fetchString("Combat.HitSound.Sound") + ", 1, " + config.getInt("Combat.HitSound.Pitch"); 24 | this.hitSound = XSound.parse(soundString); 25 | } 26 | 27 | @EventHandler 28 | public void onHit(EntityDamageByEntityEvent e) { 29 | if (e.getEntity() instanceof Player && e.getDamager() instanceof Player) { 30 | Player damager = (Player) e.getDamager(); 31 | Player damagedPlayer = (Player) e.getEntity(); 32 | 33 | if (Toolkit.inArena(damagedPlayer)) { 34 | arena.getHitCache().put(damagedPlayer.getName(), damager.getName()); 35 | 36 | if (config.getBoolean("Combat.HitSound.Enabled")) { 37 | hitSound.soundPlayer().forPlayers(damagedPlayer, damager); 38 | } 39 | } 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/Leaderboards.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import com.planetgallium.database.TopEntry; 4 | import com.planetgallium.kitpvp.Game; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class Leaderboards { 10 | 11 | private final Map leaderboards; 12 | 13 | public Leaderboards(Game plugin) { 14 | Infobase database = plugin.getDatabase(); 15 | this.leaderboards = new HashMap<>(); 16 | 17 | leaderboards.put("kills", 18 | new Leaderboard("kills", database.getTopNStats("kills", 25), 25)); 19 | leaderboards.put("deaths", 20 | new Leaderboard("deaths", database.getTopNStats("deaths", 25), 25)); 21 | leaderboards.put("level", 22 | new Leaderboard("level", database.getTopNStats("level", 25), 25)); 23 | } 24 | 25 | public void updateRankings(String leaderboardName, TopEntry newEntry) { 26 | if (isValidLeaderboardName(leaderboardName)) { 27 | leaderboards.get(leaderboardName).updateRankings(newEntry); 28 | } 29 | } 30 | 31 | public TopEntry getTopN(String leaderboardName, int rank) { 32 | if (isValidLeaderboardName(leaderboardName)) { 33 | return leaderboards.get(leaderboardName).getNRanking(rank); 34 | } 35 | return new TopEntry("NAN", -1); 36 | } 37 | 38 | private boolean isValidLeaderboardName(String leaderboardName) { 39 | return leaderboardName.equals("kills") || leaderboardName.equals("deaths") || leaderboardName.equals("level"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/CacheManager.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | import com.planetgallium.kitpvp.api.Kit; 4 | 5 | import java.util.*; 6 | 7 | public class CacheManager { 8 | 9 | private static final Map usernameToUUID = new HashMap<>(); 10 | private static final Map kitCache = new HashMap<>(); 11 | private static final Map previewMenuCache = new HashMap<>(); 12 | private static final Map> abilityCooldowns = new HashMap<>(); 13 | private static final Map statsCache = new HashMap<>(); 14 | private static final Set potionSwitcherUsers = new HashSet<>(); 15 | 16 | public static Map getUUIDCache() { return usernameToUUID; } 17 | 18 | public static Map getKitCache() { return kitCache; } 19 | 20 | public static Map getPreviewMenuCache() { return previewMenuCache; } 21 | 22 | public static Map getStatsCache() { return statsCache; } 23 | 24 | public static Set getPotionSwitcherUsers() { return potionSwitcherUsers; } 25 | 26 | public static Map getPlayerAbilityCooldowns(String username) { 27 | if (!abilityCooldowns.containsKey(username)) { 28 | abilityCooldowns.put(username, new HashMap<>()); 29 | } 30 | return abilityCooldowns.get(username); 31 | } 32 | 33 | public static void clearCaches() { 34 | kitCache.clear(); 35 | previewMenuCache.clear(); 36 | abilityCooldowns.clear(); 37 | // stats, usernameToUUID, and cache isn't here as of right now 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/command/AliasCommand.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.command; 2 | 3 | import com.planetgallium.kitpvp.Game; 4 | import com.planetgallium.kitpvp.util.Resource; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.Listener; 8 | import org.bukkit.event.player.PlayerCommandPreprocessEvent; 9 | 10 | public class AliasCommand implements Listener { 11 | 12 | private final Resource config; 13 | 14 | public AliasCommand(Game plugin) { 15 | this.config = plugin.getResources().getConfig(); 16 | } 17 | 18 | @EventHandler 19 | public void onCommand(PlayerCommandPreprocessEvent e) { 20 | Player p = e.getPlayer(); 21 | String message = e.getMessage(); 22 | 23 | String[] words = message.split(" "); 24 | 25 | if (message.equals("/spawn") && config.getBoolean("Commands.Alias.Spawn")) { 26 | e.setCancelled(true); 27 | p.performCommand("kp spawn"); 28 | 29 | } else if (message.equals("/kits") && config.getBoolean("Commands.Alias.Kits")) { 30 | e.setCancelled(true); 31 | p.performCommand("kp kits"); 32 | 33 | } else if (message.startsWith("/kit") && config.getBoolean("Commands.Alias.Kit")) { 34 | if (words.length == 1) { 35 | e.setCancelled(true); 36 | p.performCommand("kp kit"); 37 | } else if (words.length == 2) { 38 | e.setCancelled(true); 39 | p.performCommand("kp kit " + words[1]); 40 | } 41 | 42 | } else if (message.startsWith("/stats") && config.getBoolean("Commands.Alias.Stats")) { 43 | if (words.length == 1) { 44 | e.setCancelled(true); 45 | p.performCommand("kp stats"); 46 | } else if (words.length == 2) { 47 | e.setCancelled(true); 48 | p.performCommand("kp stats " + words[1]); 49 | } 50 | } 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/database/Field.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.database; 2 | 3 | // aka "column" 4 | public class Field { 5 | 6 | private final String name; 7 | private final DataType dataType; 8 | private int limit; 9 | private Object value; 10 | 11 | public Field(String name, DataType dataType) { 12 | this.name = name; 13 | this.dataType = dataType; 14 | } 15 | 16 | public Field(String name, DataType dataType, Object value) { 17 | this(name, dataType); 18 | this.value = value; 19 | } 20 | 21 | public Field(String name, DataType dataType, Object value, int limit) { 22 | this(name, dataType, value); 23 | this.limit = limit; 24 | } 25 | 26 | public Field(String name, DataType dataType, int limitOrValue) { 27 | // NOTE: this is a "double-constructor", can work for int data types and strings, but doing different things 28 | this(name, dataType); 29 | if (dataType == DataType.INTEGER || dataType == DataType.FLOAT) { 30 | this.value = limitOrValue; 31 | } else if (dataType == DataType.STRING || dataType == DataType.FIXED_STRING) { 32 | this.limit = limitOrValue; 33 | } 34 | } 35 | 36 | public String getSQLDataType() { 37 | switch (this.dataType) { 38 | case FIXED_STRING: return "CHAR"; 39 | case STRING: return "VARCHAR"; 40 | case INTEGER: return "INT"; 41 | case FLOAT: return "FLOAT"; 42 | } 43 | return null; 44 | } 45 | 46 | public String getName() { return name; } 47 | 48 | public DataType getDataType() { return dataType; } 49 | 50 | public int getLimit() { return limit; } 51 | 52 | public Object getValue() { return value; } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/api/EventListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.api; 2 | 3 | import com.planetgallium.kitpvp.Game; 4 | import com.planetgallium.kitpvp.util.Resources; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.block.Action; 10 | import org.bukkit.event.player.PlayerInteractEvent; 11 | import org.bukkit.inventory.ItemStack; 12 | 13 | import com.planetgallium.kitpvp.game.Arena; 14 | import com.planetgallium.kitpvp.util.Toolkit;; 15 | 16 | public class EventListener implements Listener { 17 | 18 | private final Resources resources; 19 | private final Arena arena; 20 | 21 | public EventListener(Game plugin) { 22 | this.resources = plugin.getResources(); 23 | this.arena = plugin.getArena(); 24 | } 25 | 26 | @EventHandler 27 | public void onAbility(PlayerInteractEvent e) { 28 | if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) { 29 | if (Toolkit.inArena(e.getPlayer())) { 30 | Player p = e.getPlayer(); 31 | ItemStack currentItem = Toolkit.getHandItemForInteraction(e); 32 | 33 | if (resources.getConfig().getBoolean("Arena.AbilitiesRequireKit") && 34 | !arena.getKits().playerHasKit(p.getName())) { 35 | return; // if "AbilitiesRequireKit" true, and player does not have kit, return 36 | } 37 | 38 | if (currentItem.hasItemMeta() && currentItem.getItemMeta().hasDisplayName()) { 39 | Ability abilityResult = arena.getAbilities().getAbilityByActivator(currentItem); 40 | 41 | if (abilityResult != null) { 42 | Bukkit.getPluginManager().callEvent(new PlayerAbilityEvent(p, abilityResult, e)); 43 | e.setCancelled(true); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/database/Record.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.database; 2 | 3 | import java.util.*; 4 | 5 | // aka a "row" or "line" in a table 6 | public class Record { 7 | 8 | private final List fields; 9 | 10 | public Record() { 11 | this.fields = new ArrayList<>(); 12 | } 13 | 14 | public Record(Field ... fields) { 15 | this.fields = new ArrayList<>(); 16 | this.fields.addAll(Arrays.asList(fields)); 17 | } 18 | 19 | /** 20 | * Adds data to a row. If a column is already present, its data will 21 | * be updated. 22 | */ 23 | public void addOrUpdateData(String columnName, DataType dataType, Object data) { 24 | Field field = new Field(columnName, dataType, data); 25 | int fieldIndex = getFieldIndexByName(columnName); 26 | if (fieldIndex == -1) { 27 | this.fields.add(field); 28 | } else { 29 | this.fields.set(fieldIndex, field); 30 | } 31 | } 32 | 33 | public Object getFieldValue(String fieldName) { 34 | Field field = getFieldByName(fieldName); 35 | if (field != null) { 36 | return field.getValue(); 37 | } 38 | return null; 39 | } 40 | 41 | private int getFieldIndexByName(String fieldName) { 42 | for (int i = 0; i < this.fields.size(); i++) { 43 | if (fields.get(i).getName().equals(fieldName)) { 44 | return i; 45 | } 46 | } 47 | return -1; 48 | } 49 | 50 | private Field getFieldByName(String fieldName) { 51 | int fieldIndex = getFieldIndexByName(fieldName); 52 | if (fieldIndex != -1) { 53 | return this.fields.get(fieldIndex); 54 | } 55 | return null; 56 | } 57 | 58 | public List getFields() { return fields; } 59 | 60 | public List getFieldsWithoutPrimaryKey() { return fields.subList(1, fields.size()); } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/Menu.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | import java.util.List; 4 | 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.Material; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.inventory.Inventory; 9 | import org.bukkit.inventory.InventoryHolder; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.bukkit.inventory.meta.ItemMeta; 12 | 13 | public class Menu { 14 | 15 | private final String title; 16 | private final int size; 17 | private final Inventory menu; 18 | private final InventoryHolder owner; 19 | 20 | public Menu(String title, InventoryHolder owner, int size) { 21 | this.menu = Bukkit.createInventory(owner, size, Toolkit.translate(title)); 22 | this.title = title; 23 | this.size = size; 24 | this.owner = owner; 25 | } 26 | 27 | public void addItem(String name, Material material, List lore, int slot) { 28 | ItemStack item = new ItemStack(material); 29 | ItemMeta meta = item.getItemMeta(); 30 | 31 | lore = Toolkit.colorizeList(lore); 32 | 33 | meta.setDisplayName(Toolkit.translate(name)); 34 | meta.setLore(lore); 35 | item.setItemMeta(meta); 36 | 37 | menu.setItem(slot, item); 38 | } 39 | 40 | public void addItem(String name, Material material, List lore, int amount, int slot) { 41 | ItemStack item = new ItemStack(material); 42 | ItemMeta meta = item.getItemMeta(); 43 | 44 | lore = Toolkit.colorizeList(lore); 45 | 46 | meta.setDisplayName(Toolkit.translate(name)); 47 | meta.setLore(lore); 48 | item.setAmount(amount > 0 ? amount : 1); 49 | item.setItemMeta(meta); 50 | 51 | menu.setItem(slot, item); 52 | } 53 | 54 | public void setItem(ItemStack item, int slot) { 55 | menu.setItem(slot, item); 56 | } 57 | 58 | public void openMenu(Player p) { 59 | p.openInventory(menu); 60 | } 61 | 62 | public void closeMenu(Player p) { 63 | p.closeInventory(); 64 | } 65 | 66 | public ItemStack getSlot(int slot) { return menu.getItem(slot); } 67 | 68 | public String getTitle() { return title; } 69 | 70 | public InventoryHolder getOwner() { return owner; } 71 | 72 | public int getSize() { return size; } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/JoinListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.planetgallium.kitpvp.util.Resource; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.EventHandler; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.event.player.PlayerChangedWorldEvent; 8 | import org.bukkit.event.player.PlayerJoinEvent; 9 | 10 | import com.planetgallium.kitpvp.Game; 11 | import com.planetgallium.kitpvp.game.Arena; 12 | import com.planetgallium.kitpvp.util.Toolkit; 13 | 14 | public class JoinListener implements Listener { 15 | 16 | private final Game plugin; 17 | private final Arena arena; 18 | private final Resource config; 19 | 20 | public JoinListener(Game plugin) { 21 | this.plugin = plugin; 22 | this.arena = plugin.getArena(); 23 | this.config = plugin.getResources().getConfig(); 24 | } 25 | 26 | @EventHandler 27 | public void onJoin(PlayerJoinEvent e) { 28 | Player p = e.getPlayer(); 29 | 30 | // Update checker 31 | if (plugin.needsUpdate()) { 32 | if (p.isOp()) { 33 | p.sendMessage(Toolkit.translate("&7[&b&lKIT-PVP&7] &aAn update was found: v" + 34 | plugin.getUpdateVersion() + " https://www.spigotmc.org/resources/27107/")); 35 | } 36 | } 37 | 38 | arena.getStats().createPlayer(p); 39 | 40 | if (p.getName().equals("cervinakuy")) { 41 | e.setJoinMessage(Toolkit.translate("&7[&b&lKIT-PVP&7] &7The Developer of &bKitPvP" + 42 | " &7has joined the server.")); 43 | } 44 | 45 | if (Toolkit.inArena(p)) { 46 | if (config.getBoolean("Arena.ClearInventoryOnJoin")) { 47 | p.getInventory().clear(); 48 | p.getInventory().setArmorContents(null); 49 | } 50 | 51 | arena.addPlayer(p, config.getBoolean("Arena.ToSpawnOnJoin"), 52 | config.getBoolean("Arena.GiveItemsOnJoin")); 53 | } 54 | } 55 | 56 | @EventHandler 57 | public void onWorldChange(PlayerChangedWorldEvent e) { 58 | Player p = e.getPlayer(); 59 | 60 | if (Toolkit.inArena(p)) { 61 | if (config.getBoolean("Arena.ClearInventoryOnJoin")) { 62 | p.getInventory().clear(); 63 | p.getInventory().setArmorContents(null); 64 | } 65 | 66 | arena.addPlayer(p, config.getBoolean("Arena.ToSpawnOnJoin"), 67 | config.getBoolean("Arena.GiveItemsOnJoin")); 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/AttackListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.planetgallium.kitpvp.game.Kits; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.EventHandler; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 8 | import org.bukkit.event.entity.EntityDamageEvent; 9 | import org.bukkit.event.entity.EntityDamageEvent.DamageCause; 10 | 11 | import com.planetgallium.kitpvp.Game; 12 | import com.planetgallium.kitpvp.util.Resources; 13 | import com.planetgallium.kitpvp.util.Toolkit; 14 | 15 | public class AttackListener implements Listener { 16 | 17 | private final Resources resources; 18 | private final Kits kits; 19 | 20 | public AttackListener(Game plugin) { 21 | this.resources = plugin.getResources(); 22 | this.kits = plugin.getArena().getKits(); 23 | } 24 | 25 | @EventHandler 26 | public void onDamageDealt(EntityDamageByEntityEvent e) { 27 | if (e.getEntity() instanceof Player && e.getDamager() instanceof Player) { 28 | Player damagedPlayer = (Player) e.getEntity(); 29 | Player damager = (Player) e.getDamager(); 30 | 31 | if (Toolkit.inArena(damagedPlayer) && !damagedPlayer.hasMetadata("NPC")) { 32 | if (resources.getConfig().getBoolean("Arena.NoKitProtection")) { 33 | if (!kits.playerHasKit(damagedPlayer.getName())) { 34 | damager.sendMessage(resources.getMessages().fetchString("Messages.Error.Invincible")); 35 | e.setCancelled(true); 36 | } 37 | 38 | if (kits.playerHasKit(damagedPlayer.getName()) && !kits.playerHasKit(damager.getName())) { 39 | damager.sendMessage(resources.getMessages().fetchString("Messages.Error.Kit")); 40 | e.setCancelled(true); 41 | } 42 | } 43 | } 44 | } 45 | } 46 | 47 | @EventHandler 48 | public void onDamage(EntityDamageEvent e) { 49 | if (e.getEntity() instanceof Player) { 50 | Player damagedPlayer = (Player) e.getEntity(); 51 | 52 | if (Toolkit.inArena(damagedPlayer)) { 53 | if (resources.getConfig().getBoolean("Arena.NoKitProtection")) { 54 | if (!kits.playerHasKit(damagedPlayer.getName())) { 55 | if (e.getCause() != DamageCause.VOID) { 56 | e.setCancelled(true); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/AbilityListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.planetgallium.kitpvp.Game; 4 | import com.planetgallium.kitpvp.api.Ability; 5 | import com.planetgallium.kitpvp.util.Cooldown; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.inventory.ItemStack; 10 | import com.planetgallium.kitpvp.api.PlayerAbilityEvent; 11 | import com.planetgallium.kitpvp.game.Arena; 12 | import com.planetgallium.kitpvp.util.Resources; 13 | import com.planetgallium.kitpvp.util.Toolkit; 14 | 15 | public class AbilityListener implements Listener { 16 | 17 | private final Arena arena; 18 | private final Resources resources; 19 | 20 | public AbilityListener(Game plugin) { 21 | this.arena = plugin.getArena(); 22 | this.resources = plugin.getResources(); 23 | } 24 | 25 | @EventHandler 26 | public void onAbility(PlayerAbilityEvent e) { 27 | Player p = e.getPlayer(); 28 | 29 | if (!arena.getUtilities().isCombatActionPermittedInRegion(p)) { 30 | return; 31 | } 32 | 33 | Ability ability = e.getAbility(); 34 | 35 | String abilityPermission = "kp.ability." + ability.getName().toLowerCase(); 36 | if (!p.hasPermission(abilityPermission)) { 37 | p.sendMessage(resources.getMessages().fetchString("Messages.General.Permission") 38 | .replace("%permission%", abilityPermission)); 39 | return; 40 | } 41 | 42 | Cooldown cooldownRemaining = arena.getCooldowns().getRemainingCooldown(p, ability); 43 | if (cooldownRemaining.toSeconds() > 0) { 44 | p.sendMessage(resources.getMessages().fetchString("Messages.Error.CooldownAbility") 45 | .replace("%cooldown%", cooldownRemaining.formatted(false))); 46 | return; 47 | } 48 | 49 | if (ability.getMessage() != null) 50 | p.sendMessage(Toolkit.translate(ability.getMessage())); 51 | 52 | if (ability.getSound() != null) 53 | p.playSound(p.getLocation(), ability.getSound(), ability.getSoundVolume(), ability.getSoundPitch()); 54 | 55 | if (ability.getEffects().size() > 0) 56 | ability.getEffects().forEach(p::addPotionEffect); 57 | 58 | if (ability.getCommands().size() > 0) 59 | Toolkit.runCommands(p, ability.getCommands(), "none", "none"); 60 | 61 | if (ability.getCooldown() == null) { 62 | ItemStack abilityItem = Toolkit.getHandItemForInteraction(e.getOriginalInteractionEvent()); 63 | abilityItem.setAmount(abilityItem.getAmount() - 1); 64 | } else { 65 | arena.getCooldowns().setAbilityCooldown(p.getName(), ability.getName()); 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/Cooldowns.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import com.planetgallium.kitpvp.Game; 4 | import com.planetgallium.kitpvp.api.Ability; 5 | import com.planetgallium.kitpvp.api.Kit; 6 | import com.planetgallium.kitpvp.util.CacheManager; 7 | import com.planetgallium.kitpvp.util.Cooldown; 8 | import org.bukkit.entity.Player; 9 | 10 | import java.util.Map; 11 | 12 | public class Cooldowns { 13 | 14 | private final Stats stats; 15 | private final Infobase database; 16 | 17 | public Cooldowns(Game plugin, Arena arena) { 18 | this.stats = arena.getStats(); 19 | this.database = plugin.getDatabase(); 20 | } 21 | 22 | public void setAbilityCooldown(String playerName, String abilityName) { 23 | CacheManager.getPlayerAbilityCooldowns(playerName).put(abilityName, (System.currentTimeMillis() / 1000)); 24 | } 25 | 26 | public void clearPlayerAbilityCooldowns(String playerName) { 27 | CacheManager.getPlayerAbilityCooldowns(playerName).clear(); 28 | } 29 | 30 | public void setKitCooldown(String username, String kitName) { 31 | long timeKitLastUsed = System.currentTimeMillis() / 1000; 32 | stats.getOrCreateStatsCache(username).addKitCooldown(kitName, timeKitLastUsed); 33 | } 34 | 35 | public Cooldown getRemainingCooldown(Player p, Object type) { 36 | long currentTimeSeconds = (System.currentTimeMillis() / 1000); 37 | int timeLastUsedSeconds = 0; 38 | int actionCooldownSeconds = 0; 39 | Cooldown noCooldown = new Cooldown(0, 0, 0, 0); 40 | 41 | if (type instanceof Kit) { 42 | 43 | Kit kit = (Kit) type; 44 | if (kit.getCooldown() == null) return noCooldown; 45 | 46 | Object timeLastUsedResult = database.getData(kit.getName() + "_cooldowns", "last_used", p.getName()); 47 | if (timeLastUsedResult != null) { 48 | timeLastUsedSeconds = (int) timeLastUsedResult; 49 | } else { 50 | return noCooldown; 51 | } 52 | actionCooldownSeconds = kit.getCooldown().toSeconds(); 53 | 54 | } else if (type instanceof Ability) { 55 | 56 | Ability ability = (Ability) type; 57 | if (ability.getCooldown() == null || 58 | !CacheManager.getPlayerAbilityCooldowns(p.getName()).containsKey(ability.getName())) 59 | return noCooldown; 60 | 61 | timeLastUsedSeconds = CacheManager.getPlayerAbilityCooldowns(p.getName()).get(ability.getName()).intValue(); 62 | actionCooldownSeconds = ability.getCooldown().toSeconds(); 63 | 64 | } 65 | 66 | int cooldownRemainingSeconds = (int) (timeLastUsedSeconds + actionCooldownSeconds - currentTimeSeconds); 67 | return new Cooldown(cooldownRemainingSeconds); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/resources/kits/Example.yml: -------------------------------------------------------------------------------- 1 | Kit: 2 | Permission: kp.kit.example 3 | Level: 0 4 | Cooldown: 1D:12H:10M:30S 5 | Health: 6 6 | Inventory: 7 | Armor: 8 | Helmet: 9 | Name: '&aSkull Item' 10 | Lore: 11 | - '&7This is a player skull' 12 | - '&7which can automatically' 13 | - '&7be detected and saved' 14 | - '&7when using /kp create' 15 | Material: SKULL_ITEM 16 | Skull: cervinakuy 17 | Chestplate: 18 | Name: '&aDyed Item' 19 | Lore: 20 | - '&7This is a dyed item which' 21 | - '&7can include over 16 million' 22 | - '&7different color combinations' 23 | Material: LEATHER_CHESTPLATE 24 | Dye: 25 | Red: 127 26 | Green: 63 27 | Blue: 178 28 | Leggings: 29 | Name: '&aEnchanted Item' 30 | Lore: 31 | - '&7This is an enchanted' 32 | - '&7item which can support' 33 | - '&7an unlimited amount of' 34 | - '&7enchantments and can bypass' 35 | - '&7vanilla enchantment limits.' 36 | Material: IRON_LEGGINGS 37 | Enchantments: 38 | DEPTH_STRIDER: 10 39 | Boots: 40 | Name: '&aItem' 41 | Lore: 42 | - '&7This is just a regular item.' 43 | Material: GOLD_BOOTS 44 | Items: 45 | 0: 46 | Name: '&aCustomized Item' 47 | Lore: 48 | - '&3This is an item with a custom' 49 | - '&cname and lore.' 50 | Material: PAPER 51 | 1: 52 | Name: '&aDamaged Item' 53 | Lore: 54 | - '&7This is a damaged item' 55 | Durability: 10 56 | Material: GOLD_PICKAXE 57 | 2: 58 | Name: '&aPotion Item' 59 | Lore: 60 | - '&7This is a regular potion item' 61 | - '&7Splash potions are also supported' 62 | Material: POTION 63 | Type: POTION 64 | Effects: 65 | JUMP: 66 | Amplifier: 1 67 | Duration: 45 68 | 7: 69 | Name: '&aAbility Item' 70 | Lore: 71 | - '&7This is an ability item' 72 | - '&7which can support messages,' 73 | - '&7sounds, potion effects,' 74 | - '&7and commands when right-clicked.' 75 | - '&7It must be customized in' 76 | - '&7the kit file.' 77 | Material: EMERALD 78 | 8: 79 | Name: '&aSecond Ability Item &7(Unlimited custom abilities per kit!)' 80 | Material: GOLD_INGOT 81 | Amount: 3 82 | Fill: 83 | Name: '&aFill Item' 84 | Lore: 85 | - '&7This is a fill item which' 86 | - '&7can fill up any blank slots' 87 | - '&7in a kit. You must customize' 88 | - '&7this in the kit file.' 89 | Material: COOKIE 90 | Commands: 91 | - 'console: say These commands can optionally be included in your kit file' 92 | - 'console: say to be run when the kit is selected' -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/WorldGuardFlag.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | import com.sk89q.worldguard.protection.flags.Flags; 4 | import com.sk89q.worldguard.protection.flags.StateFlag; 5 | 6 | public enum WorldGuardFlag { 7 | PASSTHROUGH, 8 | BUILD, 9 | BLOCK_BREAK, 10 | BLOCK_PLACE, 11 | USE, 12 | INTEERACT, 13 | DAMAGE_ANIMALS, 14 | PVP, 15 | SLEEP, 16 | TNT, 17 | CHEST_ACCESS, 18 | PLACE_VEHICLE, 19 | DESTROY_VEHICLE, 20 | LIGHTER, 21 | RIDE, 22 | POTION_SPLASH, 23 | ITEM_FRAME_ROTATE, 24 | TRAMPLE_BLOCKS, 25 | ITEM_PICKUP, 26 | ITEM_DROP, 27 | EXP_DROPS, 28 | MOB_DAMAGE, 29 | CREEPER_EXPLOSION, 30 | ENDERDRAGON_BLOCK_DAMAGE, 31 | GHAST_FIREBALL, 32 | FIREWORK_DAMAGE, 33 | OTHER_EXPLOSION, 34 | WITHER_DAMAGE, 35 | ENDER_BUILD, 36 | SNOWMAN_TRAILS, 37 | RAVAGER_RAVAGE, 38 | ENTITY_PAINTING_DESTROY, 39 | ENTITY_ITEM_FAME_DESTROY, 40 | MOB_SPAWNING, 41 | DENY_SPAWN, 42 | PISTONS, 43 | FIRE_SPREAD, 44 | LAVA_FIRE, 45 | LIGHTNING, 46 | SNOW_FALL, 47 | SNOW_MELT, 48 | ICE_FORM, 49 | ICE_MELT, 50 | FROSTED_ICE_MELT, 51 | FROSTED_ICE_FORM, 52 | MUSHROOMS, 53 | LEAF_DECAY, 54 | GRASS_SPREAD, 55 | MYCELIUM_SPREAD, 56 | VINE_GROWTH, 57 | CROP_GROWTH, 58 | SOIL_DRY, 59 | WATER_FLOW, 60 | LAVA_FLOW, 61 | WEATHER_LOCK, 62 | TIME_LOCK, 63 | SEND_CHAT, 64 | RECEIVE_CHAT, 65 | BLOCKED_CMDS, 66 | ALLOWED_CMDS, 67 | TELE_LOC, 68 | SPAWN_LOC, 69 | INVINCIBILITY, 70 | FALL_DAMAGE, 71 | ENTRY, 72 | EXIT, 73 | EXIT_OVERRIDE, 74 | EXIT_VIA_TELEPORT, 75 | ENDERPEARL, 76 | CHORUS_TELEPORT, 77 | GREET_MESSAGE, 78 | FAREWELL_MESSAGE, 79 | GREET_TITLE, 80 | FAREWELL_TITLE, 81 | NOTIFY_ENTER, 82 | NOTIFY_LEAVE, 83 | GAME_MODE, 84 | HEAL_DECAY, 85 | HEAL_AMOUNT, 86 | MIN_HEAL, 87 | MAX_HEAL, 88 | FEED_DELAY, 89 | FEED_AMOUNT, 90 | MIN_FOOD, 91 | MAX_FOOD, 92 | DENY_MESSAGE, 93 | ENTRY_DENY_MESSAGE, 94 | EXIT_DENY_MESSAGE; 95 | 96 | private final byte version = WorldGuardAPI.getInstance().version; 97 | private StateFlag flag; 98 | 99 | public StateFlag getFlag() { 100 | if (flag != null) 101 | return flag; 102 | 103 | String flagName = name(); 104 | 105 | try { 106 | Class flagClass = version == 6 ? 107 | Class.forName("com.sk89q.worldguard.protection.flags.DefaultFlag") : Flags.class; 108 | flag = (StateFlag) flagClass.getDeclaredField(flagName).get(null); 109 | } catch (Exception e) { 110 | System.out.println("[KitPvP] Unsupported flag! WorldGuard version " + version + " ; flag " + flagName); 111 | e.printStackTrace(); 112 | } 113 | 114 | return flag; 115 | } 116 | 117 | } -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/WorldGuardAPI.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | import com.sk89q.worldguard.LocalPlayer; 4 | import com.sk89q.worldguard.bukkit.WorldGuardPlugin; 5 | import com.sk89q.worldguard.protection.ApplicableRegionSet; 6 | import com.sk89q.worldguard.protection.flags.StateFlag; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.Location; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.plugin.Plugin; 11 | 12 | import java.lang.reflect.InvocationTargetException; 13 | 14 | public class WorldGuardAPI { 15 | 16 | /** 17 | * Adapted from: https://www.spigotmc.org/threads/worldguard-6-and-7-support.382130/ 18 | */ 19 | 20 | private static WorldGuardAPI instance; 21 | protected byte version; 22 | 23 | public static WorldGuardAPI getInstance() { 24 | if (instance == null) { 25 | instance = new WorldGuardAPI(); 26 | Plugin worldGuardPlugin = Bukkit.getPluginManager().getPlugin("WorldGuard"); 27 | String version = worldGuardPlugin != null && worldGuardPlugin.isEnabled() ? worldGuardPlugin.getDescription().getVersion() : null; 28 | instance.version = (byte) (version != null ? version.startsWith("6") ? 6 : 7 : -1); 29 | } 30 | return instance; 31 | } 32 | 33 | public boolean allows(Player player, StateFlag...flags) { 34 | Location location = player.getLocation(); 35 | return version == -1 || version == 6 ? allowsWg6(player, location, flags) : allowsWg7(player, location, flags); 36 | } 37 | 38 | private boolean allowsWg6(Player player, Location location, StateFlag...flags) { 39 | LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player); 40 | 41 | com.sk89q.worldguard.protection.managers.RegionManager regionManager = com.sk89q.worldguard.bukkit.WGBukkit.getRegionManager(location.getWorld()); 42 | com.sk89q.worldguard.protection.ApplicableRegionSet regionSet = null; 43 | 44 | try { 45 | regionSet = (ApplicableRegionSet) regionManager.getClass().getMethod("getApplicableRegions", Location.class).invoke(regionManager, location); 46 | } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { 47 | e.printStackTrace(); 48 | } 49 | 50 | for (StateFlag flag : flags) { 51 | if (regionSet.queryState(localPlayer, flag) == StateFlag.State.DENY) { 52 | return false; 53 | } 54 | } 55 | 56 | return true; 57 | } 58 | 59 | private boolean allowsWg7(Player player, Location location, StateFlag...flags) { 60 | com.sk89q.worldguard.protection.regions.RegionContainer container = com.sk89q.worldguard.WorldGuard.getInstance().getPlatform().getRegionContainer(); 61 | com.sk89q.worldguard.protection.regions.RegionQuery query = container.createQuery(); 62 | ApplicableRegionSet regionSet = query.getApplicableRegions(com.sk89q.worldedit.bukkit.BukkitAdapter.adapt(location)); 63 | 64 | return regionSet.testState(WorldGuardPlugin.inst().wrapPlayer(player), flags); 65 | } 66 | 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/TrackerListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.planetgallium.kitpvp.game.Arena; 4 | import com.planetgallium.kitpvp.util.Resources; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.Listener; 8 | import org.bukkit.event.player.PlayerItemHeldEvent; 9 | import org.bukkit.inventory.ItemStack; 10 | import org.bukkit.inventory.meta.ItemMeta; 11 | import org.bukkit.scheduler.BukkitRunnable; 12 | 13 | import com.planetgallium.kitpvp.Game; 14 | import com.planetgallium.kitpvp.util.Toolkit; 15 | 16 | public class TrackerListener implements Listener { 17 | 18 | private final Game plugin; 19 | private final Arena arena; 20 | private final Resources resources; 21 | 22 | public TrackerListener(Game plugin) { 23 | this.plugin = plugin; 24 | this.arena = plugin.getArena(); 25 | this.resources = plugin.getResources(); 26 | } 27 | 28 | @EventHandler 29 | public void onCompassHeld(PlayerItemHeldEvent e) { 30 | if (!Toolkit.inArena(e.getPlayer())) { 31 | return; 32 | } 33 | 34 | Player p = e.getPlayer(); 35 | ItemStack itemHeld = p.getInventory().getItem(e.getNewSlot()); 36 | 37 | if (itemHeld != null && Toolkit.hasMatchingMaterial(itemHeld, "COMPASS")) { 38 | 39 | new BukkitRunnable() { 40 | @Override 41 | public void run() { 42 | // if the player using the compass leaves the server or no longer has a kit 43 | if (!p.isOnline() || !arena.getKits().playerHasKit(p.getName())) { 44 | cancel(); 45 | return; 46 | } 47 | 48 | if (resources.getConfig().getBoolean("PlayerTracker.RefreshOnlyWhenHeld")) { 49 | if (!Toolkit.eitherHandHasMaterial(p, "COMPASS")) { 50 | cancel(); 51 | return; 52 | } 53 | } 54 | 55 | String[] nearestPlayerData = null; 56 | if (p.getWorld().getPlayers().size() == 1) { 57 | cancel(); 58 | } else { 59 | nearestPlayerData = Toolkit.getNearestPlayer(p, 60 | resources.getConfig().getInt("PlayerTracker.TrackBelowY")); 61 | } 62 | 63 | updateTrackingCompass(p, itemHeld, nearestPlayerData); 64 | } 65 | }.runTaskTimer(plugin, 0L, 20L); 66 | } 67 | } 68 | 69 | private void updateTrackingCompass(Player player, ItemStack compass, String[] nearestPlayerData) { 70 | ItemMeta compassMeta = compass.getItemMeta(); 71 | 72 | if (nearestPlayerData != null) { 73 | Player nearestPlayer = Toolkit.getPlayer(player.getWorld(), nearestPlayerData[0]); 74 | double nearestPlayerDistance = Toolkit.round(Double.parseDouble(nearestPlayerData[1]), 1); 75 | 76 | if (nearestPlayer != null && nearestPlayer.isOnline()) { 77 | compassMeta.setDisplayName(resources.getConfig().fetchString("PlayerTracker.Message") 78 | .replace("%nearestplayer%", nearestPlayer.getName()) 79 | .replace("%distance%", String.valueOf(nearestPlayerDistance))); 80 | player.setCompassTarget(nearestPlayer.getLocation()); 81 | } 82 | } else { 83 | compassMeta.setDisplayName(resources.getConfig().fetchString("PlayerTracker.NoneOnline")); 84 | } 85 | 86 | compass.setItemMeta(compassMeta); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/menu/PreviewMenu.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.menu; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.cryptomorin.xseries.XMaterial; 7 | import com.planetgallium.kitpvp.api.Kit; 8 | import com.planetgallium.kitpvp.util.CacheManager; 9 | import com.planetgallium.kitpvp.util.Resources; 10 | import org.bukkit.entity.Player; 11 | 12 | import com.planetgallium.kitpvp.util.Menu; 13 | import org.bukkit.potion.PotionEffect; 14 | 15 | public class PreviewMenu { 16 | 17 | private Menu create(Kit kit, Resources resources) { 18 | String previewMenuTitle = resources.getMessages().fetchString("Messages.Other.PreviewMenuTitle") 19 | .replace("%kit%", kit.getName()); 20 | Menu previewMenu = new Menu(previewMenuTitle, new PreviewHolder(), 54); 21 | 22 | // ARMOR // 23 | 24 | if (kit.getHelmet() != null) 25 | previewMenu.setItem(kit.getHelmet(), 0); 26 | 27 | if (kit.getChestplate() != null) 28 | previewMenu.setItem(kit.getChestplate(), 1); 29 | 30 | if (kit.getLeggings() != null) 31 | previewMenu.setItem(kit.getLeggings(), 2); 32 | 33 | if (kit.getBoots() != null) 34 | previewMenu.setItem(kit.getBoots(), 3); 35 | 36 | // POTION EFFECTS // 37 | 38 | List effectsLore = new ArrayList<>(); 39 | 40 | for (PotionEffect effect : kit.getEffects()) { 41 | String type = effect.getType().getName(); 42 | int amplifierNonZeroBased = effect.getAmplifier() + 1; 43 | int durationSeconds = effect.getDuration() / 20; 44 | 45 | effectsLore.add("&7- " + type + " " + amplifierNonZeroBased + " (" + (durationSeconds > 10000 ? "Infinite" : (durationSeconds + "s")) + ")"); 46 | } 47 | 48 | if (kit.getEffects().size() == 0) { 49 | effectsLore.add("&7None"); 50 | } 51 | 52 | String menuPotionEffectsItemName = 53 | resources.getMessages().fetchString("Messages.Other.PreviewMenuPotionEffectsItemName"); 54 | previewMenu.addItem(menuPotionEffectsItemName, XMaterial.BREWING_STAND.parseMaterial(), effectsLore, 4); 55 | 56 | // HOTBAR // 57 | 58 | for (int i = 0; i < 9; i++) { 59 | if (kit.getInventory().containsKey(i)) { 60 | previewMenu.setItem(kit.getInventory().get(i), (45 + i)); 61 | } 62 | } 63 | 64 | // ITEMS // 65 | 66 | for (int i = 9; i < 36; i++) { 67 | if (kit.getInventory().containsKey(i)) { 68 | previewMenu.setItem(kit.getInventory().get(i), (9 + i)); 69 | } 70 | } 71 | 72 | // FILL // 73 | 74 | if (kit.getFill() != null) { 75 | for (int i = 18; i < 54; i++) { 76 | if (previewMenu.getSlot(i) == null) { 77 | previewMenu.setItem(kit.getFill(), i); 78 | } 79 | } 80 | } 81 | 82 | String menuBackArrowItemName = 83 | resources.getMessages().fetchString("Messages.Other.PreviewMenuBackArrowItemName"); 84 | previewMenu.addItem(menuBackArrowItemName, XMaterial.ARROW.parseMaterial(), new ArrayList<>(), 8); 85 | 86 | CacheManager.getPreviewMenuCache().put(kit.getName(), previewMenu); 87 | 88 | return previewMenu; 89 | } 90 | 91 | public void open(Player p, Kit kit, Resources resources) { 92 | Menu previewMenu = CacheManager.getPreviewMenuCache().containsKey(kit.getName()) ? 93 | CacheManager.getPreviewMenuCache().get(kit.getName()) : create(kit, resources); 94 | 95 | previewMenu.openMenu(p); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/resources/abilities.yml: -------------------------------------------------------------------------------- 1 | # To learn more about abilities, please 2 | # visit the abilities.yml documentation on GitHub: 3 | # https://github.com/cervinakuy/KitPvP/wiki/abilities.yml 4 | 5 | Abilities: 6 | Archer: 7 | Item: 8 | Fire: '&aFire Arrows &eON &7(Right Click)' 9 | NoFire: '&aFire Arrows &cOFF &7(Right Click)' 10 | Amount: 10 11 | Message: 12 | Fire: '%prefix% &bFire Arrows &7are now &eON&7.' 13 | NoFire: '%prefix% &bFire Arrows &7are now &cOFF&7.' 14 | Enabled: true 15 | Sound: 16 | Sound: GHAST_FIREBALL 17 | Pitch: 1 18 | Enabled: true 19 | Soldier: 20 | Item: 21 | Name: '&aGun &7(Right Click)' 22 | Amount: 5 23 | Sound: 24 | Sound: EXPLODE 25 | Pitch: 1 26 | Enabled: true 27 | Bomber: 28 | Item: 29 | Name: '&aTNT Trail &7(Right Click)' 30 | Amount: 3 31 | Message: 32 | Message: '%prefix% &7You have used a &bTNT Trail&7.' 33 | Enabled: true 34 | Sound: 35 | Sound: FIZZ 36 | Pitch: 1 37 | Enabled: true 38 | Kangaroo: 39 | Item: 40 | Name: '&aLauncher &7(Right Click)' 41 | Amount: 3 42 | Message: 43 | Message: '%prefix% &7You have used a &bLauncher&7.' 44 | Enabled: false 45 | Sound: 46 | Sound: BAT_TAKEOFF 47 | Pitch: 1 48 | Enabled: true 49 | Warper: 50 | Item: 51 | Name: '&aNearest Player Teleporter &7(Right Click)' 52 | Amount: 3 53 | Message: 54 | Message: '%prefix% &7You have used a &bNearest Player Teleporter&7.' 55 | Enabled: true 56 | Sound: 57 | Sound: ENDERMAN_TELEPORT 58 | Pitch: 1 59 | Enabled: true 60 | Witch: 61 | Item: 62 | Name: '&aPotion Switcher &7(Right Click)' 63 | Message: 64 | Message: '%prefix% &7You now have a new potion.' 65 | Enabled: true 66 | Sound: 67 | Sound: ITEM_PICKUP 68 | Pitch: 1 69 | Enabled: true 70 | Ninja: 71 | Item: 72 | Name: '&aVanish Stars &7(Right Click)' 73 | Amount: 3 74 | Message: 75 | Message: '%prefix% &7You have used a &bVanish Star&7.' 76 | Enabled: true 77 | Sound: 78 | Sound: CREEPER_HISS 79 | Pitch: 1 80 | Enabled: true 81 | Thunderbolt: 82 | Item: 83 | Name: '&aLightning Strike &7(Click Player)' 84 | Amount: 3 85 | Message: 86 | Message: '%prefix% &7You have used a &bLighting Strike &7on &b%player%&7.' 87 | Enabled: true 88 | Sound: 89 | Sound: AMBIENCE_THUNDER 90 | Pitch: 1 91 | Enabled: true 92 | Vampire: 93 | Item: 94 | Name: '&aBlood Suckers &7(Click Player)' 95 | Amount: 3 96 | Message: 97 | Message: '%prefix% &7You have sucked the blood of &b%player%&7. &c+ 3 Health' 98 | Enabled: true 99 | Sound: 100 | Sound: BAT_HURT 101 | Pitch: 1 102 | Enabled: true 103 | Trickster: 104 | Item: 105 | Name: '&aSwitcher Pellets &7(Right Click)' 106 | Amount: 4 107 | Message: 108 | Message: '%prefix% &7You have switched places with &b%player%&7.' 109 | Enabled: true 110 | Sound: 111 | Sound: ENDERMAN_TELEPORT 112 | Pitch: 1 113 | Enabled: true 114 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/Cooldown.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | public class Cooldown { 4 | 5 | private int days; 6 | private int hours; 7 | private int minutes; 8 | private int seconds; 9 | 10 | public Cooldown(int days, int hours, int minutes, int seconds) { 11 | this.days = days; 12 | this.hours = hours; 13 | this.minutes = minutes; 14 | this.seconds = seconds; 15 | } 16 | 17 | public Cooldown(int seconds) { 18 | if (seconds / 86400 > 0) { 19 | this.days = seconds / 86400; 20 | seconds -= (days * 86400); 21 | } 22 | 23 | if (seconds / 3600 > 0) { 24 | this.hours = seconds / 3600; 25 | seconds -= (hours * 3600); 26 | } 27 | 28 | if (seconds / 60 > 0) { 29 | this.minutes = seconds / 60; 30 | seconds -= (minutes * 60); 31 | } 32 | 33 | if (seconds > 0) { 34 | this.seconds = seconds; 35 | } 36 | } 37 | 38 | public Cooldown(String formattedCooldown) { 39 | String[] units = formattedCooldown.split(":"); 40 | 41 | for (int i = 0; i < units.length; i++) { 42 | if (units[i].toUpperCase().endsWith("D")) { 43 | days = Integer.parseInt(units[i].split("D")[0]); 44 | } else if (units[i].toUpperCase().endsWith("H")) { 45 | hours = Integer.parseInt(units[i].split("H")[0]); 46 | } else if (units[i].toUpperCase().endsWith("M")) { 47 | minutes = Integer.parseInt(units[i].split("M")[0]); 48 | } else if (units[i].toUpperCase().endsWith("S")) { 49 | seconds = Integer.parseInt(units[i].split("S")[0]); 50 | } 51 | } 52 | } 53 | 54 | public String formatted(boolean condensed) { 55 | if (condensed) { 56 | String condensedCooldown = ""; 57 | 58 | if (getDays() != 0) condensedCooldown += getDays() + "D:"; 59 | if (getHours() != 0) condensedCooldown += getHours() + "H:"; 60 | if (getMinutes() != 0) condensedCooldown += getMinutes() + "M:"; 61 | if (getSeconds() != 0) condensedCooldown += getSeconds() + "S:"; 62 | 63 | if (condensedCooldown.endsWith(":")) { 64 | condensedCooldown = condensedCooldown.substring(0, condensedCooldown.length() - 1); 65 | } else if (condensedCooldown.equals("")) { 66 | condensedCooldown = null; 67 | } 68 | 69 | return condensedCooldown; 70 | } else { 71 | String longCooldown = ""; 72 | 73 | if (getDays() != 0) longCooldown += (getDays() + " days "); 74 | if (getHours() != 0) longCooldown += (getHours() + " hours "); 75 | if (getMinutes() != 0) longCooldown += (getMinutes() + " minutes "); 76 | if (getSeconds() != 0) longCooldown += (getSeconds() + " seconds"); 77 | 78 | if (longCooldown.length() > 0 && longCooldown.charAt(longCooldown.length() - 1) == ' ') { 79 | longCooldown = longCooldown.substring(0, longCooldown.length() - 1); 80 | } 81 | 82 | return longCooldown; 83 | } 84 | } 85 | 86 | public int toSeconds() { 87 | int daysToSeconds = days * 86400; 88 | int hoursToSeconds = hours * 3600; 89 | int minutesToSeconds = minutes * 60; 90 | return daysToSeconds + hoursToSeconds + minutesToSeconds + seconds; 91 | } 92 | 93 | public int getDays() { return days; } 94 | 95 | public int getHours() { return hours; } 96 | 97 | public int getMinutes() { return minutes; } 98 | 99 | public int getSeconds() { return seconds; } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/SoupListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.planetgallium.kitpvp.util.*; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.EventHandler; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.event.block.Action; 8 | import org.bukkit.event.entity.PlayerDeathEvent; 9 | import org.bukkit.event.player.PlayerInteractEvent; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.bukkit.inventory.meta.ItemMeta; 12 | import org.bukkit.scheduler.BukkitRunnable; 13 | 14 | import com.planetgallium.kitpvp.Game; 15 | 16 | public class SoupListener implements Listener { 17 | 18 | private final Game plugin; 19 | private final Resource config; 20 | 21 | public SoupListener(Game plugin) { 22 | this.plugin = plugin; 23 | this.config = plugin.getResources().getConfig(); 24 | } 25 | 26 | @EventHandler 27 | public void onPlayerDeath(PlayerDeathEvent e) { 28 | Player victim = e.getEntity(); 29 | 30 | if (!Toolkit.inArena(victim)) { 31 | return; 32 | } 33 | 34 | if (victim.getKiller() != null && config.getBoolean("Kill.SoupReward.Enabled")) { 35 | Player killer = victim.getKiller(); 36 | 37 | if (!killer.hasPermission("kp.soupreturn")) { 38 | return; 39 | } 40 | 41 | new BukkitRunnable() { 42 | @Override 43 | public void run() { 44 | if (killer.isOnline()) { 45 | insertSoupRewardToInventory(killer); 46 | } 47 | } 48 | }.runTaskLater(plugin, config.getInt("Kill.SoupReward.Delay") * 20L); 49 | } 50 | } 51 | 52 | private void insertSoupRewardToInventory(Player killer) { 53 | for (int i = config.getInt("Kill.SoupReward.Amount"); i > 0; i--) { 54 | if (killer.getInventory().firstEmpty() == -1) { 55 | killer.sendMessage(config.fetchString("Kill.SoupReward.NoSpace") 56 | .replace("%amount%", String.valueOf(i))); 57 | break; 58 | } else { 59 | killer.getInventory().addItem(buildSoup()); 60 | } 61 | } 62 | } 63 | 64 | @EventHandler 65 | public void onSoupUse(PlayerInteractEvent e) { 66 | if (!config.getBoolean("Soups.Enabled")) { 67 | return; 68 | } 69 | 70 | Player p = e.getPlayer(); 71 | 72 | if (Toolkit.inArena(p) && 73 | (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK)) { 74 | if (Toolkit.hasMatchingMaterial(Toolkit.getHandItemForInteraction(e), "MUSHROOM_STEW")) { 75 | e.setCancelled(true); 76 | 77 | if (p.getHealth() < 20.0) { 78 | int soupBoost = plugin.getConfig().getInt("Soups.RegenAmount"); 79 | 80 | p.setHealth(Math.min(p.getHealth() + (double) soupBoost, 20.0)); 81 | 82 | Toolkit.playSoundToPlayer(p, config.fetchString("Soups.Sound"), 83 | config.getInt("Soups.Pitch")); 84 | Toolkit.setHandItemForInteraction(e,config.getBoolean("Soups.RemoveAfterUse") ? 85 | Toolkit.safeItemStack("AIR") : Toolkit.safeItemStack("BOWL")); 86 | } 87 | } 88 | } 89 | } 90 | 91 | private ItemStack buildSoup() { 92 | ItemStack soup = Toolkit.safeItemStack("MUSHROOM_STEW"); 93 | ItemMeta soupMeta = soup.getItemMeta(); 94 | 95 | soupMeta.setDisplayName(config.fetchString("Soups.Name")); 96 | soupMeta.setLore(config.getStringList("Soups.Lore")); 97 | 98 | soup.setItemMeta(soupMeta); 99 | return soup; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/ArrowListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.cryptomorin.xseries.XMaterial; 4 | import com.planetgallium.kitpvp.util.Resource; 5 | import org.bukkit.Material; 6 | import org.bukkit.entity.Arrow; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.EventHandler; 9 | import org.bukkit.event.Listener; 10 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 11 | import org.bukkit.inventory.ItemStack; 12 | import org.bukkit.scheduler.BukkitRunnable; 13 | 14 | import com.planetgallium.kitpvp.Game; 15 | import com.planetgallium.kitpvp.util.Toolkit; 16 | 17 | public class ArrowListener implements Listener { 18 | 19 | private final Game plugin; 20 | private final Resource config; 21 | 22 | public ArrowListener(Game plugin) { 23 | this.plugin = plugin; 24 | this.config = plugin.getResources().getConfig(); 25 | } 26 | 27 | @EventHandler 28 | public void onArrowHit(EntityDamageByEntityEvent e) { 29 | if (Toolkit.inArena(e.getEntity()) && 30 | e.getEntity() instanceof Player && e.getDamager() instanceof Arrow) { 31 | Player damagedPlayer = (Player) e.getEntity(); 32 | Arrow arrow = (Arrow) e.getDamager(); 33 | 34 | if (arrow.getShooter() != null && arrow.getShooter() instanceof Player) { 35 | Player shooter = (Player) arrow.getShooter(); 36 | 37 | // make sure damaged player isn't shooter (self-hit) 38 | if (!damagedPlayer.getName().equals(shooter.getName())) { 39 | doArrowHitMessageIfEnabled(shooter, damagedPlayer); 40 | doArrowReturnIfEnabled(shooter, damagedPlayer); 41 | } 42 | } 43 | } 44 | } 45 | 46 | private void doArrowHitMessageIfEnabled(Player shooter, Player damagedPlayer) { 47 | if (config.getBoolean("Combat.ArrowHit.Enabled")) { 48 | new BukkitRunnable() { 49 | @Override 50 | public void run() { 51 | double health = Math.round(damagedPlayer.getHealth() * 10.0) / 10.0; 52 | 53 | if (shooter.hasPermission("kp.arrowmessage")) { 54 | if (health != 20.0) { 55 | shooter.sendMessage(config.fetchString("Combat.ArrowHit.Message").replace("%player%", damagedPlayer.getName()).replace("%health%", String.valueOf(health))); 56 | } 57 | } 58 | } 59 | }.runTaskLater(plugin, 2L); 60 | } 61 | } 62 | 63 | private void doArrowReturnIfEnabled(Player shooter, Player damagedPlayer) { 64 | if (config.getBoolean("Combat.ArrowReturn.Enabled")) { 65 | 66 | // Do not do arrow return if damagedPlayer does not have a kit (if NoKitProtection is enabled) 67 | if (config.getBoolean("Arena.NoKitProtection")) { 68 | if (!plugin.getArena().getKits().playerHasKit(damagedPlayer.getName())) { 69 | return; 70 | } 71 | } 72 | 73 | ItemStack arrowToAdd = new ItemStack(Material.ARROW, config.getInt("Combat.ArrowReturn.Count")); 74 | 75 | for (ItemStack items : shooter.getInventory().getContents()) { 76 | if (items != null && items.getType() == XMaterial.ARROW.parseMaterial() && items.getAmount() < 64) { 77 | 78 | if (shooter.hasPermission("kp.arrowreturn")) { 79 | shooter.getInventory().addItem(arrowToAdd); 80 | return; 81 | } 82 | } 83 | } 84 | 85 | if (shooter.getInventory().firstEmpty() == -1) { 86 | shooter.sendMessage(config.fetchString("Combat.ArrowReturn.NoSpace")); 87 | } else { 88 | shooter.getInventory().addItem(arrowToAdd); 89 | } 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/Leaderboard.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import com.planetgallium.database.TopEntry; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | public class Leaderboard { 10 | 11 | private final String name; 12 | private final List rankings; 13 | private final int maxSize; 14 | 15 | public Leaderboard(String name, List initialRankings, int maxSize) { 16 | this.name = name; 17 | this.rankings = initialRankings; 18 | this.maxSize = maxSize; 19 | } 20 | 21 | public void updateRankings(TopEntry playerEntry) { 22 | if (rankingsContainPlayer(playerEntry.getIdentifier())) { 23 | // Update the player's score if they are already in the leaderboard 24 | updatePlayerEntryInRanking(playerEntry); 25 | } else if (rankings.size() < maxSize || playerEntry.getValue() > rankings.get(rankings.size() - 1).getValue()) { 26 | // Add the new player if there's space, or they have a higher score than the lowest in the leaderboard 27 | if (rankings.size() == maxSize) { 28 | // Remove the lowest ranking player to make space for the new entry 29 | rankings.remove(rankings.size() - 1); 30 | } 31 | rankings.add(playerEntry); 32 | } 33 | sortRankings(); 34 | } 35 | 36 | // public void updateRankings(TopEntry playerEntry) { 37 | // if (rankings.size() < maxSize) { 38 | // rankings.add(playerEntry); 39 | // sortRankings(); 40 | // } else if (rankings.size() == maxSize) { 41 | // TopEntry lowestRankingPlayer = rankings.get(rankings.size() - 1); 42 | // if (playerEntry.getValue() > lowestRankingPlayer.getValue()) { 43 | // if (!rankingsContainPlayer(playerEntry.getIdentifier())) { 44 | // // remove lowest ranking player and add new better player 45 | // rankings.remove(rankings.size() - 1); 46 | // rankings.add(playerEntry); 47 | // } else { 48 | // // update ranking for player already in leaderboard 49 | // updatePlayerEntryInRanking(playerEntry); 50 | // } 51 | // sortRankings(); // resort in both above cases 52 | // } 53 | // } 54 | // } 55 | 56 | public TopEntry getNRanking(int n) { // n = 1 is top player 57 | if (n <= rankings.size() && n >= 1) { 58 | return rankings.get(n - 1); 59 | } 60 | return new TopEntry("N / A", 0); 61 | } 62 | 63 | private boolean rankingsContainPlayer(String username) { 64 | for (TopEntry entry : this.rankings) { 65 | if (entry.getIdentifier().equals(username)) { 66 | return true; 67 | } 68 | } 69 | return false; 70 | } 71 | 72 | private void updatePlayerEntryInRanking(TopEntry updatedEntry) { 73 | for (TopEntry entry : this.rankings) { 74 | if (entry.getIdentifier().equals(updatedEntry.getIdentifier())) { 75 | entry.setValue(updatedEntry.getValue()); 76 | return; 77 | } 78 | } 79 | } 80 | 81 | public void sortRankings() { 82 | Collections.sort(rankings); 83 | } 84 | 85 | public String getName() { return name; } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/Updater.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | import com.google.common.base.Preconditions; 4 | import com.google.common.io.Resources; 5 | import com.google.common.net.HttpHeaders; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.plugin.java.JavaPlugin; 8 | 9 | import javax.annotation.Nonnull; 10 | import javax.net.ssl.HttpsURLConnection; 11 | import java.io.IOException; 12 | import java.net.HttpURLConnection; 13 | import java.net.URL; 14 | import java.nio.charset.Charset; 15 | import java.util.Objects; 16 | import java.util.function.BiConsumer; 17 | 18 | public class Updater { 19 | 20 | public enum VersionResponse { 21 | LATEST, 22 | FOUND_NEW, 23 | UNAVAILABLE 24 | } 25 | 26 | private static final String SPIGOT_URL = "https://api.spigotmc.org/legacy/update.php?resource=%d"; 27 | 28 | private final JavaPlugin javaPlugin; 29 | 30 | private String currentVersion; 31 | private int resourceId = -1; 32 | private BiConsumer versionResponse; 33 | 34 | private Updater(@Nonnull JavaPlugin javaPlugin) { 35 | this.javaPlugin = Objects.requireNonNull(javaPlugin, "javaPlugin"); 36 | this.currentVersion = javaPlugin.getDescription().getVersion(); 37 | } 38 | 39 | public static Updater of(@Nonnull JavaPlugin javaPlugin) { 40 | return new Updater(javaPlugin); 41 | } 42 | 43 | public Updater currentVersion(@Nonnull String currentVersion) { 44 | this.currentVersion = currentVersion; 45 | return this; 46 | } 47 | 48 | public Updater resourceId(int resourceId) { 49 | this.resourceId = resourceId; 50 | return this; 51 | } 52 | 53 | public Updater handleResponse(@Nonnull BiConsumer versionResponse) { 54 | this.versionResponse = versionResponse; 55 | return this; 56 | } 57 | 58 | public void check() { 59 | Objects.requireNonNull(this.javaPlugin, "javaPlugin"); 60 | Objects.requireNonNull(this.currentVersion, "currentVersion"); 61 | Preconditions.checkState(this.resourceId != -1, "resource id not set"); 62 | Objects.requireNonNull(this.versionResponse, "versionResponse"); 63 | 64 | Bukkit.getScheduler().runTaskAsynchronously(this.javaPlugin, () -> { 65 | try { 66 | HttpURLConnection httpURLConnection = (HttpsURLConnection) new URL(String.format(SPIGOT_URL, 67 | this.resourceId)).openConnection(); 68 | httpURLConnection.setRequestMethod("GET"); 69 | httpURLConnection.setRequestProperty(HttpHeaders.USER_AGENT, "Mozilla/5.0"); 70 | 71 | String fetchedVersion = Resources.toString(httpURLConnection.getURL(), Charset.defaultCharset()); 72 | 73 | boolean latestVersion = fetchedVersion.equalsIgnoreCase(this.currentVersion); 74 | 75 | Bukkit.getScheduler().runTask(this.javaPlugin, () -> 76 | this.versionResponse.accept(latestVersion ? VersionResponse.LATEST : VersionResponse.FOUND_NEW, 77 | latestVersion ? this.currentVersion : fetchedVersion)); 78 | } catch (IOException exception) { 79 | exception.printStackTrace(); 80 | Bukkit.getScheduler().runTask(this.javaPlugin, () -> 81 | this.versionResponse.accept(VersionResponse.UNAVAILABLE, null)); 82 | } 83 | }); 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/Placeholders.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | import com.planetgallium.database.TopEntry; 4 | import com.planetgallium.kitpvp.Game; 5 | import org.apache.commons.lang.StringUtils; 6 | import org.bukkit.entity.Player; 7 | import com.planetgallium.kitpvp.game.Arena; 8 | 9 | import me.clip.placeholderapi.expansion.PlaceholderExpansion; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | public class Placeholders extends PlaceholderExpansion { 16 | 17 | private final Arena arena; 18 | private final Map placeholderAPItoBuiltIn; 19 | 20 | public Placeholders(Game plugin) { 21 | this.arena = plugin.getArena(); 22 | this.placeholderAPItoBuiltIn = new HashMap<>(); 23 | 24 | placeholderAPItoBuiltIn.put("stats_kills", "%kills%"); 25 | placeholderAPItoBuiltIn.put("stats_deaths", "%deaths%"); 26 | placeholderAPItoBuiltIn.put("stats_kd", "%kd%"); 27 | placeholderAPItoBuiltIn.put("stats_experience", "%xp%"); 28 | placeholderAPItoBuiltIn.put("stats_level", "%level%"); 29 | placeholderAPItoBuiltIn.put("player_killstreak", "%streak%"); 30 | placeholderAPItoBuiltIn.put("player_kit", "%kit%"); 31 | placeholderAPItoBuiltIn.put("max_level", "%max_level%"); 32 | placeholderAPItoBuiltIn.put("max_xp", "%max_xp%"); 33 | placeholderAPItoBuiltIn.put("level_prefix", "%level_prefix%"); 34 | } 35 | 36 | @Override 37 | public String onPlaceholderRequest(Player p, @NotNull String identifier) { 38 | if (identifier.contains("top")) { 39 | return handleLeaderboardPlaceholder(identifier); 40 | } 41 | 42 | if (p != null) { 43 | return translatePlaceholderAPIPlaceholders(identifier, p.getName()); 44 | } 45 | return null; 46 | } 47 | 48 | private String handleLeaderboardPlaceholder(String identifier) { 49 | String[] queries = identifier.split("_"); 50 | String topType = queries[1]; // ex: kills 51 | String topIdentifier = queries[2]; // ex: amount, player 52 | String possibleTopValue = queries[3]; // 1, 15 53 | int topValue = 1; // if number parsing fails, use top player 54 | 55 | if (StringUtils.isNumeric(possibleTopValue)) { 56 | topValue = Integer.parseInt(possibleTopValue); 57 | } else { 58 | Toolkit.printToConsole("%prefix% &cFailed to properly parse placeholder, " + 59 | "expected number but received: " + possibleTopValue); 60 | } 61 | 62 | TopEntry entry = arena.getLeaderboards().getTopN(topType, topValue); 63 | boolean isUsernamePlaceholder = topIdentifier.equals("player"); 64 | 65 | return isUsernamePlaceholder ? entry.getIdentifier() : String.valueOf(entry.getValue()); 66 | } 67 | 68 | public String translatePlaceholderAPIPlaceholders(String placeholderAPIIdentifier, String username) { 69 | if (placeholderAPItoBuiltIn.containsKey(placeholderAPIIdentifier)) { 70 | String toBuiltInPlaceholder = placeholderAPItoBuiltIn.get(placeholderAPIIdentifier); 71 | return arena.getUtilities().replaceBuiltInPlaceholdersIfPresent(toBuiltInPlaceholder, username); 72 | } else { 73 | Toolkit.printToConsole(String.format("&7[&b&lKIT-PVP&7] &cUnknown placeholder identifier [%s]. " + 74 | "Please see plugin page.", placeholderAPIIdentifier)); 75 | return "invalid-placeholder"; 76 | } 77 | } 78 | 79 | @Override 80 | public boolean canRegister() { return true; } 81 | 82 | @Override 83 | public boolean persist() { return true; } 84 | 85 | @Override 86 | public @NotNull String getAuthor() { return "Cervinakuy"; } 87 | 88 | @Override 89 | public @NotNull String getIdentifier() { return "kitpvp"; } 90 | 91 | @Override 92 | public @NotNull String getVersion() { return "1.0.0"; } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/database/Database.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.database; 2 | 3 | import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource; 4 | import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; 5 | import org.sqlite.SQLiteDataSource; 6 | 7 | import javax.sql.DataSource; 8 | import java.sql.Connection; 9 | import java.sql.PreparedStatement; 10 | import java.sql.SQLException; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public class Database { 15 | 16 | private DataSource dataSource; 17 | private final Map tables; 18 | 19 | public Database(String localDatabaseFileName) { 20 | this("none", -1, localDatabaseFileName, "none", "none"); 21 | } 22 | 23 | public Database(String host, int port, String database, String username, String password) { 24 | this.tables = new HashMap<>(); 25 | 26 | if (!host.equals("none")) { 27 | setupMySQL(host, port, database, username, password); 28 | } else { 29 | setupSQLite(database); 30 | } 31 | } 32 | 33 | private void setupMySQL(String host, int port, String database, String username, String password) { 34 | try { 35 | MysqlDataSource dataSource = new MysqlConnectionPoolDataSource(); // new MysqlDataSource(); 36 | dataSource.setServerName(host); 37 | dataSource.setPortNumber(port); 38 | dataSource.setCreateDatabaseIfNotExist(true); // idk 39 | dataSource.setDatabaseName(database); 40 | dataSource.setUser(username); 41 | dataSource.setPassword(password); 42 | 43 | this.dataSource = dataSource; 44 | 45 | testDatabaseConnection(); 46 | } catch (SQLException exception) { 47 | exception.printStackTrace(); 48 | System.out.println("[Database] Connection to MySQL database failed. Using SQLite instead..."); 49 | setupSQLite("storage.db"); 50 | } 51 | } 52 | 53 | private void setupSQLite(String databaseFileName) { 54 | SQLiteDataSource sqLiteDataSource = new SQLiteDataSource(); 55 | sqLiteDataSource.setUrl("jdbc:sqlite:" + databaseFileName); 56 | 57 | this.dataSource = sqLiteDataSource; 58 | } 59 | 60 | private void testDatabaseConnection() throws SQLException { 61 | try (Connection connection = dataSource.getConnection()) { 62 | if (!connection.isValid(1)) { 63 | throw new SQLException("Could not establish database connection"); 64 | } 65 | } 66 | 67 | } 68 | 69 | public Table createTable(String tableName, Record masterRecord) { 70 | Table table = new Table(dataSource, tableName, masterRecord); 71 | tables.put(tableName, table); 72 | return table; 73 | } 74 | 75 | public void deleteTable(String tableName) { 76 | Table table = tables.get(tableName); 77 | if (table == null) { 78 | System.out.printf("[Database] Failed to delete table %s; table not found\n", tableName); 79 | return; 80 | } 81 | 82 | String deleteTableQuery = Table.DELETE_TABLE_QUERY.replace("{table_name}", tableName); 83 | try (Connection connection = dataSource.getConnection() ; 84 | PreparedStatement statement = connection.prepareStatement(deleteTableQuery)) { 85 | statement.executeUpdate(); 86 | } catch (SQLException exception) { 87 | exception.printStackTrace(); 88 | } 89 | } 90 | 91 | public Table getTable(String tableName) { 92 | return tables.get(tableName); 93 | } 94 | 95 | public Map getTables() { return tables; } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/Resource.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | import java.io.*; 4 | import java.nio.file.Paths; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import com.planetgallium.kitpvp.Game; 9 | import org.bukkit.ChatColor; 10 | import org.bukkit.configuration.InvalidConfigurationException; 11 | import org.bukkit.configuration.file.YamlConfiguration; 12 | import org.bukkit.plugin.Plugin; 13 | 14 | public class Resource extends YamlConfiguration { 15 | 16 | private final String name; 17 | private final File file; 18 | private final List copyDefaultExemptions; 19 | 20 | private final Plugin plugin; 21 | private final String path; 22 | 23 | public Resource(Plugin plugin, String path) { 24 | this.plugin = plugin; 25 | this.path = path; 26 | 27 | this.file = new File(plugin.getDataFolder() + "/" + Paths.get(path)); 28 | this.name = Paths.get(path).getFileName().toString(); 29 | this.copyDefaultExemptions = new ArrayList<>(); 30 | } 31 | 32 | public void load() { 33 | if (!file.getParentFile().exists()) { 34 | file.getParentFile().mkdirs(); 35 | } 36 | 37 | if (!file.exists()) { 38 | if (plugin.getResource(path) == null) { 39 | try { 40 | file.createNewFile(); 41 | } catch (IOException e) { 42 | e.printStackTrace(); 43 | } 44 | } else { 45 | plugin.saveResource(path, true); 46 | } 47 | } 48 | 49 | try { 50 | super.load(file); 51 | } catch (IOException | InvalidConfigurationException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | 56 | public void copyDefaults() { 57 | Reader defaultConfigSearchResult = null; 58 | 59 | if (plugin.getResource(path) != null) { 60 | try { 61 | defaultConfigSearchResult = new InputStreamReader(plugin.getResource(path), "UTF8"); 62 | } catch (UnsupportedEncodingException e) { 63 | e.printStackTrace(); 64 | } 65 | } 66 | 67 | if (defaultConfigSearchResult != null) { 68 | YamlConfiguration defaultConfig = YamlConfiguration.loadConfiguration(defaultConfigSearchResult); 69 | 70 | for (String valuePath : defaultConfig.getValues(true).keySet()) { 71 | if (!contains(valuePath)) { 72 | if (!Toolkit.containsAnyThatStartWith(copyDefaultExemptions, valuePath)) { 73 | this.set(valuePath, defaultConfig.get(valuePath)); 74 | } 75 | } 76 | } 77 | save(); 78 | } 79 | } 80 | 81 | public void addCopyDefaultExemption(String path) { 82 | copyDefaultExemptions.add(path); 83 | } 84 | 85 | public void save() { 86 | try { 87 | super.save(file); 88 | } catch (IOException e) { 89 | e.printStackTrace(); 90 | } 91 | } 92 | 93 | @Override 94 | public String getString(String path) { 95 | Toolkit.printToConsole("%prefix% &cNote: Do not use legacy resource.getString, use resource.fetchString instead"); 96 | return super.getString(path); 97 | } 98 | 99 | public String fetchString(String path) { 100 | String string = super.getString(path); 101 | 102 | if (string != null) { 103 | string = ChatColor.translateAlternateColorCodes('&', 104 | string.replace("%prefix%", Game.getPrefix() == null ? "" : Game.getPrefix())); 105 | } else { 106 | string = "String not found"; 107 | Toolkit.printToConsole(String.format("&7[&b&lKIT-PVP&7] &cString with path %s was not found.", path)); 108 | } 109 | 110 | return string; 111 | } 112 | 113 | @Override 114 | public List getStringList(String path) { 115 | return Toolkit.colorizeList(super.getStringList(path)); 116 | } 117 | 118 | public String getName() { return name; } 119 | 120 | public File getFile() { return file; } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/api/Ability.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.api; 2 | 3 | import com.planetgallium.kitpvp.util.Cooldown; 4 | import com.planetgallium.kitpvp.util.Resource; 5 | import com.planetgallium.kitpvp.util.Toolkit; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.Sound; 8 | import org.bukkit.inventory.ItemStack; 9 | import org.bukkit.potion.PotionEffect; 10 | import org.bukkit.potion.PotionEffectType; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class Ability { 16 | 17 | private final String name; 18 | private ItemStack activator; 19 | private Cooldown cooldown; 20 | private String message; 21 | private Sound sound; 22 | private int soundPitch; 23 | private int soundVolume; 24 | private final List effects; 25 | private final List commands; 26 | 27 | public Ability(String name) { 28 | this.name = name; 29 | this.effects = new ArrayList<>(); 30 | this.commands = new ArrayList<>(); 31 | } 32 | 33 | public void setActivator(ItemStack activator) { 34 | this.activator = activator; 35 | } 36 | 37 | public void setCooldown(Cooldown cooldown) { 38 | this.cooldown = cooldown; 39 | } 40 | 41 | public void setMessage(String message) { 42 | this.message = message; 43 | } 44 | 45 | public void setSound(Sound sound, int pitch, int volume) { 46 | this.sound = sound; 47 | this.soundPitch = pitch; 48 | this.soundVolume = volume; 49 | } 50 | 51 | public void addEffect(PotionEffectType type, int amplifierNonZeroBased, int durationSeconds) { 52 | PotionEffect effect = new PotionEffect(type, Toolkit.parsePotionEffectDuration(durationSeconds), amplifierNonZeroBased - 1); 53 | effects.add(effect); 54 | } 55 | 56 | public void addCommand(String command) { 57 | commands.add(command); 58 | } 59 | 60 | public void toResource(Resource resource) { 61 | resource.set("Activator.Name", Toolkit.toNormalColorCodes(activator.getItemMeta().getDisplayName())); 62 | resource.set("Activator.Material", activator.getType().toString()); 63 | if (cooldown != null) { 64 | resource.set("Cooldown.Cooldown", cooldown.formatted(true)); 65 | } 66 | resource.set("Message.Message", message); 67 | resource.set("Sound.Sound", sound.toString()); 68 | resource.set("Sound.Pitch", soundPitch != 0 ? soundPitch : null); 69 | resource.set("Sound.Volume", soundVolume != 0 ? soundVolume : null); 70 | 71 | for (PotionEffect effect : effects) { 72 | String type = effect.getType().getName(); 73 | int amplifierNonZeroBased = effect.getAmplifier() + 1; 74 | int durationSeconds = effect.getDuration() / 20; 75 | 76 | resource.set("Effects." + type + ".Amplifier", amplifierNonZeroBased); 77 | resource.set("Effects." + type + ".Duration", durationSeconds); 78 | } 79 | 80 | resource.set("Commands", commands.toArray()); 81 | 82 | resource.save(); 83 | } 84 | 85 | public String getName() { return name; } 86 | 87 | public ItemStack getActivator() { return activator; } 88 | 89 | public Cooldown getCooldown() { return cooldown; } 90 | 91 | public String getMessage() { return message; } 92 | 93 | public Sound getSound() { return sound; } 94 | 95 | public int getSoundPitch() { return soundPitch; } 96 | 97 | public int getSoundVolume() { return soundVolume; } 98 | 99 | public List getEffects() { return effects; } 100 | 101 | public List getCommands() { return commands; } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/MenuListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.planetgallium.kitpvp.Game; 4 | import com.planetgallium.kitpvp.game.Arena; 5 | import com.planetgallium.kitpvp.menu.KitHolder; 6 | import com.planetgallium.kitpvp.menu.PreviewHolder; 7 | import com.planetgallium.kitpvp.util.Resource; 8 | import com.planetgallium.kitpvp.util.Toolkit; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.event.EventHandler; 11 | import org.bukkit.event.Listener; 12 | import org.bukkit.event.inventory.*; 13 | import org.bukkit.inventory.Inventory; 14 | import org.bukkit.scheduler.BukkitRunnable; 15 | 16 | public class MenuListener implements Listener { 17 | 18 | private final Game plugin; 19 | private final Arena arena; 20 | private final Resource config; 21 | private final Resource menuConfig; 22 | 23 | public MenuListener(Game plugin) { 24 | this.plugin = plugin; 25 | this.arena = plugin.getArena(); 26 | this.config = plugin.getResources().getConfig(); 27 | this.menuConfig = plugin.getResources().getMenu(); 28 | } 29 | 30 | @EventHandler 31 | public void onClick(InventoryClickEvent e) { 32 | if (e.getClickedInventory() != null) { 33 | Player p = (Player) e.getWhoClicked(); 34 | 35 | Inventory originInventory = e.getClickedInventory(); 36 | Inventory clickedInventory = e.getInventory(); 37 | 38 | // to prevent adding items into the inventory 39 | if (originInventory.getType() == InventoryType.PLAYER && clickedInventory.getType() == InventoryType.CHEST) { 40 | if (clickedInventory.getHolder() instanceof KitHolder || 41 | clickedInventory.getHolder() instanceof PreviewHolder) { 42 | e.setCancelled(true); 43 | return; 44 | } 45 | } 46 | 47 | if (e.getClickedInventory().getHolder() instanceof KitHolder) { 48 | 49 | Inventory openMenu = e.getClickedInventory(); 50 | String itemPath = "Menu.Items." + e.getSlot(); 51 | 52 | if (menuConfig.contains(itemPath)) { 53 | if (openMenu.getItem(e.getSlot()) != null) { 54 | e.setCancelled(true); 55 | p.closeInventory(); 56 | 57 | String clickType = e.getClick() == ClickType.LEFT ? "Left-Click" : "Right-Click"; 58 | 59 | if (menuConfig.contains(itemPath + ".Commands")) { 60 | new BukkitRunnable() { 61 | @Override 62 | public void run() { 63 | Toolkit.runCommands(p, 64 | menuConfig.getStringList(itemPath + ".Commands." + clickType), 65 | "none", "none"); 66 | } 67 | }.runTaskLater(plugin, 1L); 68 | } 69 | } 70 | } 71 | 72 | } else if (e.getClickedInventory().getHolder() instanceof PreviewHolder) { 73 | 74 | if (e.getSlot() == 8) { 75 | p.closeInventory(); 76 | 77 | new BukkitRunnable() { 78 | @Override 79 | public void run() { 80 | Toolkit.runCommands(p, config.getStringList("PreviewMenuBackArrowCommands"), "none", "none"); 81 | } 82 | }.runTaskLater(plugin, 1L); 83 | 84 | } else { 85 | e.setCancelled(true); 86 | } 87 | } 88 | } 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/resources/messages.yml: -------------------------------------------------------------------------------- 1 | Messages: 2 | General: 3 | Prefix: '&7[&b&lKIT-PVP&7]' 4 | Permission: '%prefix% &cYou do not have permission (%permission%).' 5 | Player: '%prefix% &cYou must be a player to perform this action.' 6 | Commands: 7 | Create: '%prefix% &7The kit &b%kit% &7has successfully been created.' 8 | Delete: '%prefix% &7The kit &b%kit% &7has successfully been deleted.' 9 | Kit: '%prefix% &7You have selected kit &b%kit%&7.' 10 | KitOther: '%prefix% &7Attempting to give &b%player% &7kit &b%kit%&7.' 11 | Kits: '%prefix% &bKits (case-sensitive): &7%kits%' 12 | Teleport: '%prefix% &7Teleported you to the spawn.' 13 | Teleporting: '%prefix% &7Teleporting, do not move.' 14 | Time: '%prefix% &7Teleporting you in &b%time% seconds&7.' 15 | Added: '%prefix% &7Successfully added spawn &b#%number% &7in arena &b&b%arena%&7.' 16 | Removed: '%prefix% &7Successfully removed the arena &b%arena%&7.' 17 | Reload: '%prefix% &7Successfully reloaded the configurations and cleared caches.' 18 | Cleared: '%prefix% &7Your kit has been cleared.' 19 | ClearedOther: '%prefix% &7You cleared &b%player%''s &7kit.' 20 | SetStats: '%prefix% &7Updated &b%player%''s &7stats to &b%amount% %type%&7.' 21 | Other: 22 | Needed: '%prefix% &cYou must be Level %level% to use that kit.' 23 | Level: '%prefix% &7Congratulations! You are now &bLevel %level%&7.' 24 | Sign: '%prefix% &7You have successfully created a sign.' 25 | Players: '%prefix% &cThere are no other players with a kit online.' 26 | NoKit: 'None' 27 | PreviewMenuTitle: 'Previewing: %kit%' 28 | PreviewMenuBackArrowItemName: '&cBack to Kits' 29 | PreviewMenuPotionEffectsItemName: '&a&lPotion Effects' 30 | OverflowItemsDropped: '%prefix% &b%number% &7kit items had no inventory space and were dropped on the ground.' 31 | Error: 32 | Player: '%prefix% &cYou must right-click on a player to activate this ability.' 33 | Arena: '%prefix% &cNo arena exists with name %arena%.' 34 | ExistsArena: '%prefix% &cThe specified arena does not exist.' 35 | Exists: '%prefix% &cThe specified kit already exists.' 36 | Lost: '%prefix% &cKit not found! Remember kit names are case-sensitive!' 37 | Arguments: '%prefix% Please specify more arguments in the command.' 38 | Kit: '%prefix% &cYou must select a kit before hitting players.' 39 | Moved: '%prefix% &cYou moved, teleportation cancelled.' 40 | Invincible: '%prefix% &cYou cannot hit that player because they have no kit.' 41 | Selected: '%prefix% &cYou have already selected a kit.' 42 | SelectedOther: '%prefix% &cThe specified player has already selected a kit.' 43 | Location: '%prefix% &cYou are not in the arena to perform this action.' 44 | KitInvalid: '%prefix% &cYou cannot perform this action because you have a kit selected.' 45 | CooldownKit: '%prefix% &cYou cannot select this kit for another %cooldown%.' 46 | CooldownAbility: '%prefix% &cYou cannot use this ability for another %cooldown%.' 47 | Offline: '%prefix% &cThe specified player could not be found.' 48 | Menu: '%prefix% &cFailed to automatically add to the menu, the menu may be full.' 49 | PVP: '%prefix% &cPVP is not permitted in this region.' 50 | InvalidType: '%prefix% &cInvalid type "%type%". Available types: %types%.' 51 | InvalidNumber: '%prefix% &cInvalid number "%number%".' 52 | OverflowItemsLost: '%prefix% &c%number% items could not fit in your inventory and were lost.' 53 | InvalidKitName: '%prefix% &cFailed to create kit due to invalid kit name (contains +, -)' 54 | Stats: 55 | Message: 56 | - '&7&m &r' 57 | - ' ' 58 | - ' &b&lStats for %player%' 59 | - ' &aLevel: &7%level%/%max_level%' 60 | - ' &aExperience: &7%xp%/%max_xp%' 61 | - ' &aKills: &7%kills%' 62 | - ' &aDeaths: &7%deaths%' 63 | - ' ' 64 | - '&7&m &r' 65 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # To learn more about the options available and their functionality, please 2 | # visit the config.yml documentation on GitHub: 3 | # https://github.com/cervinakuy/KitPvP/wiki/config.yml 4 | 5 | Items: 6 | Kits: 7 | Enabled: true 8 | Name: '&aKit Selector &7(Right Click)' 9 | Material: CHEST 10 | Slot: 0 11 | Menu: true 12 | Commands: [] 13 | Leave: 14 | Enabled: true 15 | Name: '&aReturn to Hub &7(Right Click)' 16 | Material: WATCH 17 | Slot: 8 18 | BungeeCord: 19 | Server: Hub 20 | Enabled: false 21 | Commands: [] 22 | Chat: 23 | Format: '%level% &e%player% &f%message%' 24 | Enabled: true 25 | Combat: 26 | HitSound: 27 | Sound: BLAZE_HIT 28 | Pitch: 1 29 | Enabled: true 30 | ArrowHit: 31 | Message: '%prefix% &b%player% &7is on &c%health%&7.' 32 | Enabled: true 33 | ArrowReturn: 34 | ItemName: '&eReturnable Arrow' 35 | NoSpace: '%prefix% &cYou must have at least one slot open in your inventory for you to receive your arrow for your successful shot.' 36 | Enabled: true 37 | Count: 2 38 | Kill: 39 | SoupReward: 40 | NoSpace: '%prefix% &c%amount% soups could not be added to your full inventory.' 41 | Amount: 1 42 | Delay: 0 43 | Enabled: true 44 | Commands: [] 45 | Death: 46 | Title: 47 | Title: '&c&lYOU DIED!' 48 | Subtitle: '&7You will respawn in %seconds% seconds.' 49 | Time: 5 50 | Message: '%prefix% &7Respawning...' 51 | Sound: 52 | Sound: AMBIENCE_THUNDER 53 | Pitch: 1 54 | Enabled: false 55 | Commands: [] 56 | Messages: 57 | Player: '%prefix% &b%victim% &7was killed by &b%killer% &7(&c%killer_health%&7).' 58 | Shot: '%prefix% &b%victim% &7was shot by &b%killer% &7(&c%killer_health%&7).' 59 | Fall: '%prefix% &b%victim% &7fell to their doom.' 60 | Void: '%prefix% &b%victim% &7died from the void.' 61 | Fire: '%prefix% &b%victim% &7died from fire.' 62 | Explosion: '%prefix% &b%victim% &7blew up.' 63 | Suicide: '%prefix% &b%victim% &7killed themselves.' 64 | Unknown: '%prefix% &b%victim% &7died.' 65 | Enabled: true 66 | Respawn: 67 | Commands: [] 68 | PlayerTracker: 69 | Name: '&aPlayer Tracker' 70 | Message: '&b&lTarget: &3%nearestplayer% &b&lDistance: &3%distance%' 71 | NoneOnline: '&cNo Players Online' 72 | TrackBelowY: 128 73 | RefreshOnlyWhenHeld: true 74 | Soups: 75 | Name: '&aRegenerative Soups &7(Right Click)' 76 | RegenAmount: 6 77 | RemoveAfterUse: true 78 | Lore: 79 | - '&7Use this item to regain health.' 80 | Sound: EAT 81 | Pitch: 1 82 | Enabled: true 83 | TNT: 84 | Name: '&aThrowable TNT &7(Right Click)' 85 | Enabled: true 86 | PreviewMenuBackArrowCommands: 87 | - 'player: kp menu' 88 | Commands: 89 | Alias: 90 | Spawn: false 91 | Kit: false 92 | Kits: false 93 | Stats: false 94 | Storage: 95 | Type: sqlite 96 | MySQL: 97 | Host: 127.0.0.1 98 | Port: 3306 99 | Database: kitpvp 100 | Username: root 101 | Password: password 102 | Arena: 103 | ClearPotionEffectsOnJoin: true 104 | ClearInventoryOnJoin: true 105 | ClearInventoryOnLeave: false 106 | ClearInventoryOnRespawn: true 107 | ClearInventoryOnKit: true 108 | ClearKitOnCommandSpawn: true 109 | PreventBlockBreaking: true 110 | PreventBlockPlacing: true 111 | PreventItemDropping: true 112 | PreventHunger: true 113 | PreventItemDurabilityDamage: false 114 | PreventChestOpen: true 115 | PreventFallDamage: false 116 | PreventDeathDrops: true 117 | PreventArenaSignUseWithKit: true 118 | KeepWeatherAtSunny: true 119 | GiveItemsOnClear: true 120 | GiveItemsOnRespawn: true 121 | GiveItemsOnJoin: true 122 | NoKitProtection: true 123 | FancyDeath: true 124 | ResetKillStreakOnLeave: true 125 | ToSpawnOnJoin: true 126 | DeathParticles: true 127 | AbilitiesRequireKit: true 128 | AddOverflowItemsOnKit: true 129 | DropRemainingOverflowItemsOnKit: true 130 | ResetMaxHealthOnDeath: true 131 | Other: 132 | AutomaticallyAddKitToMenu: true 133 | Spawn: 134 | Time: 5 135 | Enabled: true 136 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/Utilities.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import com.planetgallium.kitpvp.Game; 4 | import com.planetgallium.kitpvp.util.Resources; 5 | import com.planetgallium.kitpvp.util.WorldGuardAPI; 6 | import com.planetgallium.kitpvp.util.WorldGuardFlag; 7 | import me.clip.placeholderapi.PlaceholderAPI; 8 | import org.bukkit.entity.Player; 9 | 10 | public class Utilities { 11 | 12 | private final Game plugin; 13 | private final Arena arena; 14 | private final Resources resources; 15 | 16 | public Utilities(Game plugin, Arena arena) { 17 | this.plugin = plugin; 18 | this.arena = arena; 19 | this.resources = plugin.getResources(); 20 | } 21 | 22 | public String getPlayerLevelPrefix(String username) { 23 | String playerLevel = String.valueOf(arena.getStats().getStat("level", username)); 24 | return resources.getLevels().fetchString("Levels.Levels." + playerLevel + ".Prefix") 25 | .replace("%level%", playerLevel); 26 | } 27 | 28 | public String addPlaceholdersIfPossible(Player p, String text) { 29 | if (plugin.hasPlaceholderAPI()) { 30 | text = PlaceholderAPI.setPlaceholders(p, text); 31 | } 32 | 33 | return replaceBuiltInPlaceholdersIfPresent(text, p.getName()); 34 | } 35 | 36 | public String replaceBuiltInPlaceholdersIfPresent(String s, String username) { 37 | // The reason I'm doing all these if statements rather than a more concise code solution is to reduce 38 | // the amount of data that is unnecessarily fetched (ex by using .replace) to improve performance 39 | // no longer constantly fetching stats from database for EACH line of scoreboard on update and player join 40 | 41 | if (s.contains("%streak%")) { 42 | s = s.replace("%streak%", String.valueOf(arena.getKillStreaks().getStreak(username))); 43 | } 44 | 45 | if (s.contains("%player%")) { 46 | s = s.replace("%player%", username); 47 | } 48 | 49 | if (s.contains("%xp%")) { 50 | s = s.replace("%xp%", String.valueOf(arena.getStats().getStat("experience", username))); 51 | } 52 | 53 | if (s.contains("%level%")) { 54 | s = s.replace("%level%", String.valueOf(arena.getStats().getStat("level", username))); 55 | } 56 | 57 | if (s.contains("%level_prefix%")) { 58 | String levelPrefix = getPlayerLevelPrefix(username); 59 | s = s.replace("%level_prefix%", levelPrefix); 60 | } 61 | 62 | if (s.contains("%max_xp%")) { 63 | s = s.replace("%max_xp%", String.valueOf(arena.getStats().getRegularOrRelativeNeededExperience(username))); 64 | } 65 | 66 | if (s.contains("%max_level%")) { 67 | s = s.replace("%max_level%", 68 | String.valueOf(resources.getLevels().getInt("Levels.Options.Maximum-Level"))); 69 | } 70 | 71 | if (s.contains("%kd%")) { 72 | s = s.replace("%kd%", String.valueOf(arena.getStats().getKDRatio(username))); 73 | } 74 | 75 | if (s.contains("%kills%")) { 76 | s = s.replace("%kills%", String.valueOf(arena.getStats().getStat("kills", username))); 77 | } 78 | 79 | if (s.contains("%deaths%")) { 80 | s = s.replace("%deaths%", String.valueOf(arena.getStats().getStat("deaths", username))); 81 | } 82 | 83 | if (s.contains("%kit%")) { 84 | if (arena.getKits().getKitOfPlayer(username) != null) { 85 | s = s.replace("%kit%", arena.getKits().getKitOfPlayer(username).getName()); 86 | } else { 87 | s = s.replace("%kit%", "None"); 88 | } 89 | } 90 | 91 | return s; 92 | } 93 | 94 | public boolean isCombatActionPermittedInRegion(Player p) { 95 | if (plugin.hasWorldGuard()) { 96 | if (WorldGuardAPI.getInstance().allows(p, WorldGuardFlag.PVP.getFlag())) { 97 | return true; 98 | } 99 | 100 | p.sendMessage(resources.getMessages().fetchString("Messages.Error.PVP")); 101 | return false; 102 | } 103 | return true; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/KillStreaks.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import java.util.HashMap; 4 | 5 | import com.cryptomorin.xseries.messages.Titles; 6 | import com.planetgallium.kitpvp.util.*; 7 | import org.bukkit.Sound; 8 | import org.bukkit.World; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.event.EventHandler; 11 | import org.bukkit.event.Listener; 12 | import org.bukkit.event.entity.PlayerDeathEvent; 13 | import org.bukkit.event.player.PlayerJoinEvent; 14 | import org.bukkit.event.player.PlayerQuitEvent; 15 | 16 | public class KillStreaks implements Listener { 17 | 18 | private final Resources resources; 19 | private final Resource killConfig; 20 | private final HashMap kills; 21 | 22 | public KillStreaks(Resources resources) { 23 | this.resources = resources; 24 | this.killConfig = resources.getKillStreaks(); 25 | this.kills = new HashMap<>(); 26 | } 27 | 28 | @EventHandler 29 | public void onKill(PlayerDeathEvent e) { 30 | if (Toolkit.inArena(e.getEntity())) { 31 | Player damager = e.getEntity().getKiller(); 32 | Player damagedPlayer = e.getEntity(); 33 | 34 | if (damager != null && !damager.getName().equals(damagedPlayer.getName())) { 35 | kills.put(damager.getName(), getStreak(damager.getName()) + 1); 36 | runStreakCase("KillStreaks", damager); 37 | runStreakCase("EndStreaks", damagedPlayer); 38 | kills.put(damagedPlayer.getName(), 0); 39 | 40 | } else { 41 | kills.put(damagedPlayer.getName(), 0); 42 | runStreakCase("EndStreaks", damagedPlayer); 43 | } 44 | 45 | } 46 | } 47 | 48 | @EventHandler 49 | public void createStreak(PlayerJoinEvent e) { 50 | Player p = e.getPlayer(); 51 | 52 | if (!kills.containsKey(p.getName())) { 53 | kills.put(e.getPlayer().getName(), 0); 54 | } 55 | } 56 | 57 | @EventHandler 58 | public void removeStreak(PlayerQuitEvent e) { 59 | if (resources.getConfig().getBoolean("Arena.ResetKillStreakOnLeave")) { 60 | kills.put(e.getPlayer().getName(), 0); 61 | } 62 | } 63 | 64 | public void runStreakCase(String streakType, Player p) { 65 | String username = p.getName(); 66 | int streakNumber = getStreak(username); 67 | World world = p.getWorld(); 68 | 69 | String pathPrefix = streakType + "." + streakNumber; 70 | 71 | if (killConfig.contains(pathPrefix)) { 72 | 73 | // TITLE 74 | if (killConfig.contains(pathPrefix + ".Title")) { 75 | String title = killConfig.fetchString(pathPrefix + ".Title.Title") 76 | .replace("%player%", username) 77 | .replace("%streak%", String.valueOf(streakNumber)); 78 | String subtitle = killConfig.fetchString(pathPrefix + ".Title.Subtitle") 79 | .replace("%player%", username) 80 | .replace("%streak%", String.valueOf(streakNumber)); 81 | 82 | for (Player local : world.getPlayers()) { 83 | Titles.sendTitle(local, 20, 60, 20, title, subtitle); 84 | } 85 | } 86 | 87 | // SOUND 88 | if (killConfig.contains(pathPrefix + ".Sound")) { 89 | Sound sound = Toolkit.safeSound(killConfig.fetchString(pathPrefix + ".Sound.Sound")); 90 | int pitch = killConfig.getInt(pathPrefix + ".Sound.Pitch"); 91 | 92 | for (Player local : world.getPlayers()) { 93 | local.playSound(local.getLocation(), sound, 1, pitch); 94 | } 95 | } 96 | 97 | // MESSAGE 98 | if (killConfig.contains(pathPrefix + ".Message")) { 99 | String message = killConfig.fetchString(pathPrefix + ".Message.Message") 100 | .replace("%streak%", String.valueOf(streakNumber)) 101 | .replace("%player%", username); 102 | 103 | for (Player local : world.getPlayers()) { 104 | local.sendMessage(message); 105 | } 106 | } 107 | 108 | // COMMANDS 109 | if (killConfig.contains(pathPrefix + ".Commands")) { 110 | Toolkit.runCommands(p, killConfig.getStringList(pathPrefix + ".Commands"), 111 | "none", "none"); 112 | } 113 | 114 | } 115 | 116 | } 117 | 118 | public int getStreak(String username) { 119 | if (!kills.containsKey(username)) { 120 | kills.put(username, 0); 121 | } 122 | 123 | return kills.get(username); 124 | } 125 | 126 | public void resetStreak(Player p) { 127 | if (kills.containsKey(p.getName())) { 128 | runStreakCase("EndStreaks", p); 129 | kills.put(p.getName(), 0); 130 | } 131 | } 132 | 133 | public void setStreak(Player p, int streak) { 134 | kills.put(p.getName(), streak); 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/Abilities.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import com.planetgallium.kitpvp.Game; 4 | import com.planetgallium.kitpvp.api.Ability; 5 | import com.planetgallium.kitpvp.util.Cooldown; 6 | import com.planetgallium.kitpvp.util.Resource; 7 | import com.planetgallium.kitpvp.util.Resources; 8 | import com.planetgallium.kitpvp.util.Toolkit; 9 | import org.bukkit.Sound; 10 | import org.bukkit.configuration.ConfigurationSection; 11 | import org.bukkit.inventory.ItemStack; 12 | import org.bukkit.inventory.meta.ItemMeta; 13 | import org.bukkit.potion.PotionEffectType; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | public class Abilities { 19 | 20 | private final Resources resources; 21 | private final Map activatorDataToAbility; 22 | 23 | public Abilities(Game plugin) { 24 | this.resources = plugin.getResources(); 25 | this.activatorDataToAbility = new HashMap<>(); 26 | 27 | rebuildCache(); 28 | } 29 | 30 | public void rebuildCache() { 31 | for (Resource abilityResource : resources.getAbilityResources()) { 32 | Ability ability = getAbilityFromResource(abilityResource); 33 | AbilityActivatorMetaData activatorMetaData = new AbilityActivatorMetaData(ability.getActivator()); 34 | activatorDataToAbility.put(activatorMetaData, ability); 35 | } 36 | } 37 | 38 | public Ability getAbilityByActivator(ItemStack potentialActivator) { 39 | return activatorDataToAbility.get(new AbilityActivatorMetaData(potentialActivator)); 40 | } 41 | 42 | private Ability getAbilityFromResource(Resource resource) { 43 | Ability ability = new Ability(resource.getName()); 44 | 45 | // Activator 46 | ItemStack activator = Toolkit.safeItemStack(resource.fetchString("Activator.Material")); 47 | ItemMeta activatorMeta = activator.getItemMeta(); 48 | 49 | activatorMeta.setDisplayName(resource.fetchString("Activator.Name")); 50 | activator.setItemMeta(activatorMeta); 51 | 52 | ability.setActivator(activator); 53 | 54 | // Cooldown 55 | if (resource.contains("Cooldown")) { 56 | String formattedCooldown = resource.fetchString("Cooldown.Cooldown"); 57 | ability.setCooldown(new Cooldown(formattedCooldown)); 58 | } 59 | 60 | // Message 61 | if (resource.contains("Message")) { 62 | ability.setMessage(resource.fetchString("Message.Message")); 63 | } 64 | 65 | // Sound 66 | if (resource.contains("Sound")) { 67 | Sound abilitySound = Toolkit.safeSound(resource.fetchString("Sound.Sound")); 68 | int abilitySoundPitch = resource.getInt("Sound.Pitch"); 69 | int abilitySoundVolume = resource.getInt("Sound.Volume"); 70 | 71 | ability.setSound(abilitySound, abilitySoundPitch, abilitySoundVolume); 72 | } 73 | 74 | // Effects 75 | if (resource.contains("Effects")) { 76 | ConfigurationSection effectSection = resource.getConfigurationSection("Effects"); 77 | 78 | for (String effectName : effectSection.getKeys(false)) { 79 | PotionEffectType effectType = Toolkit.safePotionEffectType(effectName); 80 | int amplifier = resource.getInt("Effects." + effectName + ".Amplifier"); 81 | int duration = resource.getInt("Effects." + effectName + ".Duration"); 82 | 83 | ability.addEffect(effectType, amplifier, duration); 84 | } 85 | } 86 | 87 | // Commands 88 | if (resource.contains("Commands")) { 89 | for (String command : resource.getStringList("Commands")) { 90 | ability.addCommand(command); 91 | } 92 | } 93 | 94 | return ability; 95 | } 96 | 97 | public class AbilityActivatorMetaData { 98 | 99 | private final String materialName; 100 | private String displayName; 101 | 102 | public AbilityActivatorMetaData(ItemStack buildFromItem) { 103 | this.materialName = buildFromItem.getType().toString(); 104 | if (buildFromItem.hasItemMeta()) { 105 | ItemMeta itemMeta = buildFromItem.getItemMeta(); 106 | if (itemMeta.hasDisplayName()) { 107 | this.displayName = itemMeta.getDisplayName(); 108 | } 109 | } 110 | } 111 | 112 | @Override 113 | public boolean equals(Object otherObject) { 114 | if (otherObject instanceof AbilityActivatorMetaData) { 115 | AbilityActivatorMetaData otherAbilityData = (AbilityActivatorMetaData) otherObject; 116 | return this.displayName.equals(otherAbilityData.getDisplayName()) && 117 | this.materialName.equals(otherAbilityData.getMaterialName()); 118 | } 119 | return false; 120 | } 121 | 122 | @Override 123 | public int hashCode() { 124 | return this.displayName.hashCode() + this.materialName.hashCode(); 125 | } 126 | 127 | public String getDisplayName() { return displayName; } 128 | 129 | public String getMaterialName() { return materialName; } 130 | 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/Infoboard.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.planetgallium.kitpvp.util.Toolkit; 7 | import org.apache.commons.lang.StringUtils; 8 | import org.bukkit.ChatColor; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.scoreboard.DisplaySlot; 11 | import org.bukkit.scoreboard.Objective; 12 | import org.bukkit.scoreboard.Scoreboard; 13 | import org.bukkit.scoreboard.Team; 14 | 15 | import com.google.common.base.Preconditions; 16 | 17 | public class Infoboard { 18 | 19 | private List list; 20 | private Scoreboard scoreBoard; 21 | private Objective objective; 22 | private String tag; 23 | private int lastSentCount; 24 | 25 | public Infoboard(final Scoreboard scoreboard2, final String title) { 26 | this.list = new ArrayList(); 27 | this.tag = "PlaceHolder"; 28 | this.lastSentCount = -1; 29 | if (title.length() > 32) { 30 | Toolkit.printToConsole("&7[&b&lKIT-PVP&7] &cScoreboard title in scoreboard.yml is too long;" + 31 | " must be less than or equal to 32 characters. Scoreboard will not display."); 32 | } 33 | Preconditions.checkState(title.length() <= 32, (Object) "title cannot be more than 32 characters"); 34 | this.tag = ChatColor.translateAlternateColorCodes('&', title); 35 | this.scoreBoard = scoreboard2; 36 | (this.objective = this.getOrCreateObjective(this.tag)).setDisplaySlot(DisplaySlot.SIDEBAR); 37 | } 38 | 39 | public void add(String input) { 40 | input = ChatColor.translateAlternateColorCodes('&', input); 41 | 42 | ScoreboardText text = null; 43 | if (input.length() <= 16) { 44 | text = new ScoreboardText(input, ""); 45 | } 46 | else { 47 | String first = input.substring(0, 16); 48 | String second = input.substring(16, input.length()); 49 | if (first.endsWith(String.valueOf('§'))) { 50 | first = first.substring(0, first.length() - 1); 51 | second = String.valueOf(String.valueOf('§')) + second; 52 | } 53 | final String lastColors = ChatColor.getLastColors(first); 54 | second = String.valueOf(String.valueOf(lastColors)) + second; 55 | text = new ScoreboardText(first, StringUtils.left(second, 16)); 56 | } 57 | this.list.add(text); 58 | } 59 | 60 | public void clear() { 61 | this.list.clear(); 62 | } 63 | 64 | public void remove(final int index) { 65 | final String name = this.getNameForIndex(index); 66 | this.scoreBoard.resetScores(name); 67 | final Team team = this.getOrCreateTeam(String.valueOf(String.valueOf(ChatColor.stripColor(StringUtils.left(this.tag, 14)))) + index, index); 68 | team.unregister(); 69 | } 70 | 71 | public void update(final Player player) { 72 | player.setScoreboard(this.scoreBoard); 73 | for (int sentCount = 0; sentCount < this.list.size(); ++sentCount) { 74 | final Team i = this.getOrCreateTeam(String.valueOf(String.valueOf(ChatColor.stripColor(StringUtils.left(this.tag, 14)))) + sentCount, sentCount); 75 | final ScoreboardText str = this.list.get(this.list.size() - sentCount - 1); 76 | i.setPrefix(str.getLeft()); 77 | i.setSuffix(str.getRight()); 78 | this.objective.getScore(this.getNameForIndex(sentCount)).setScore(sentCount + 1); 79 | } 80 | if (this.lastSentCount != -1) { 81 | for (int sentCount = this.list.size(), var4 = 0; var4 < this.lastSentCount - sentCount; ++var4) { 82 | this.remove(sentCount + var4); 83 | } 84 | } 85 | this.lastSentCount = this.list.size(); 86 | } 87 | 88 | public Team getOrCreateTeam(final String team, final int i) { 89 | Team value = this.scoreBoard.getTeam(team); 90 | if (value == null) { 91 | value = this.scoreBoard.registerNewTeam(team); 92 | value.addEntry(this.getNameForIndex(i)); 93 | } 94 | return value; 95 | } 96 | 97 | public Objective getOrCreateObjective(final String objective) { 98 | Objective value = this.scoreBoard.getObjective("dummyhubobj"); 99 | if (value == null) { 100 | value = this.scoreBoard.registerNewObjective("dummyhubobj", "dummy"); 101 | } 102 | value.setDisplayName(objective); 103 | return value; 104 | } 105 | 106 | public String getNameForIndex(final int index) { 107 | return String.valueOf(String.valueOf(ChatColor.values()[index].toString())) + ChatColor.RESET; 108 | } 109 | 110 | private static class ScoreboardText 111 | { 112 | private String left; 113 | private String right; 114 | 115 | public ScoreboardText(final String left, final String right) { 116 | this.left = left; 117 | this.right = right; 118 | } 119 | 120 | public String getLeft() { 121 | return this.left; 122 | } 123 | 124 | public String getRight() { 125 | return this.right; 126 | } 127 | } 128 | 129 | /** 130 | * Added for testing purposes, not part of original class 131 | */ 132 | public void hide() { 133 | objective.setDisplaySlot(null); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/main/resources/levels.yml: -------------------------------------------------------------------------------- 1 | # To learn about what specific options here mean, please 2 | # visit the levels.yml documentation on GitHub: 3 | # https://github.com/cervinakuy/KitPvP/wiki/levels.yml 4 | 5 | Levels: 6 | Options: 7 | Experience-To-Level-Up: 100 8 | Experience-Given-On-Kill: 15 9 | Experience-Taken-On-Death: 5 10 | Minimum-Level: 0 11 | Maximum-Level: 100 12 | Commands-On-Level-Up: [] 13 | Levels: 14 | 0: 15 | Prefix: '&7Level %level%' 16 | 1: 17 | Prefix: '&7Level %level%' 18 | 2: 19 | Prefix: '&7Level %level%' 20 | 3: 21 | Prefix: '&7Level %level%' 22 | 4: 23 | Prefix: '&7Level %level%' 24 | 5: 25 | Prefix: '&7Level %level%' 26 | 6: 27 | Prefix: '&7Level %level%' 28 | 7: 29 | Prefix: '&7Level %level%' 30 | 8: 31 | Prefix: '&7Level %level%' 32 | 9: 33 | Prefix: '&7Level %level%' 34 | 10: 35 | Prefix: '&7Level %level%' 36 | Commands: 37 | - 'console: say Congratulations to %player% for reaching Level %level%!' 38 | - 'console: Commands on level can be edited via the levels.yml' 39 | Experience-To-Level-Up: 98 40 | 11: 41 | Prefix: '&7Level %level%' 42 | 12: 43 | Prefix: '&7Level %level%' 44 | 13: 45 | Prefix: '&7Level %level%' 46 | 14: 47 | Prefix: '&7Level %level%' 48 | 15: 49 | Prefix: '&7Level %level%' 50 | 16: 51 | Prefix: '&7Level %level%' 52 | 17: 53 | Prefix: '&7Level %level%' 54 | 18: 55 | Prefix: '&7Level %level%' 56 | 19: 57 | Prefix: '&7Level %level%' 58 | 20: 59 | Prefix: '&9Level %level%' 60 | 21: 61 | Prefix: '&9Level %level%' 62 | 22: 63 | Prefix: '&9Level %level%' 64 | 23: 65 | Prefix: '&9Level %level%' 66 | 24: 67 | Prefix: '&9Level %level%' 68 | 25: 69 | Prefix: '&9Level %level%' 70 | 26: 71 | Prefix: '&9Level %level%' 72 | 27: 73 | Prefix: '&9Level %level%' 74 | 28: 75 | Prefix: '&9Level %level%' 76 | 29: 77 | Prefix: '&9Level %level%' 78 | 30: 79 | Prefix: '&9Level %level%' 80 | 31: 81 | Prefix: '&9Level %level%' 82 | 32: 83 | Prefix: '&9Level %level%' 84 | 33: 85 | Prefix: '&9Level %level%' 86 | 34: 87 | Prefix: '&9Level %level%' 88 | 35: 89 | Prefix: '&9Level %level%' 90 | 36: 91 | Prefix: '&9Level %level%' 92 | 37: 93 | Prefix: '&9Level %level%' 94 | 38: 95 | Prefix: '&9Level %level%' 96 | 39: 97 | Prefix: '&9Level %level%' 98 | 40: 99 | Prefix: '&eLevel %level%' 100 | 41: 101 | Prefix: '&eLevel %level%' 102 | 42: 103 | Prefix: '&eLevel %level%' 104 | 43: 105 | Prefix: '&eLevel %level%' 106 | 44: 107 | Prefix: '&eLevel %level%' 108 | 45: 109 | Prefix: '&eLevel %level%' 110 | 46: 111 | Prefix: '&eLevel %level%' 112 | 47: 113 | Prefix: '&eLevel %level%' 114 | 48: 115 | Prefix: '&eLevel %level%' 116 | 49: 117 | Prefix: '&eLevel %level%' 118 | 50: 119 | Prefix: '&eLevel %level%' 120 | 51: 121 | Prefix: '&eLevel %level%' 122 | 52: 123 | Prefix: '&eLevel %level%' 124 | 53: 125 | Prefix: '&eLevel %level%' 126 | 54: 127 | Prefix: '&eLevel %level%' 128 | 55: 129 | Prefix: '&eLevel %level%' 130 | 56: 131 | Prefix: '&eLevel %level%' 132 | 57: 133 | Prefix: '&eLevel %level%' 134 | 58: 135 | Prefix: '&eLevel %level%' 136 | 59: 137 | Prefix: '&eLevel %level%' 138 | 60: 139 | Prefix: '&eLevel %level%' 140 | 61: 141 | Prefix: '&eLevel %level%' 142 | 62: 143 | Prefix: '&eLevel %level%' 144 | 63: 145 | Prefix: '&eLevel %level%' 146 | 64: 147 | Prefix: '&eLevel %level%' 148 | 65: 149 | Prefix: '&eLevel %level%' 150 | 66: 151 | Prefix: '&eLevel %level%' 152 | 67: 153 | Prefix: '&eLevel %level%' 154 | 68: 155 | Prefix: '&eLevel %level%' 156 | 69: 157 | Prefix: '&eLevel %level%' 158 | 70: 159 | Prefix: '&6Level %level%' 160 | 71: 161 | Prefix: '&6Level %level%' 162 | 72: 163 | Prefix: '&6Level %level%' 164 | 73: 165 | Prefix: '&6Level %level%' 166 | 74: 167 | Prefix: '&6Level %level%' 168 | 75: 169 | Prefix: '&6Level %level%' 170 | 76: 171 | Prefix: '&6Level %level%' 172 | 77: 173 | Prefix: '&6Level %level%' 174 | 78: 175 | Prefix: '&6Level %level%' 176 | 79: 177 | Prefix: '&6Level %level%' 178 | 80: 179 | Prefix: '&6Level %level%' 180 | 81: 181 | Prefix: '&6Level %level%' 182 | 82: 183 | Prefix: '&6Level %level%' 184 | 83: 185 | Prefix: '&6Level %level%' 186 | 84: 187 | Prefix: '&6Level %level%' 188 | 85: 189 | Prefix: '&6Level %level%' 190 | 86: 191 | Prefix: '&6Level %level%' 192 | 87: 193 | Prefix: '&6Level %level%' 194 | 88: 195 | Prefix: '&6Level %level%' 196 | 89: 197 | Prefix: '&6Level %level%' 198 | 90: 199 | Prefix: '&6Level %level%' 200 | 91: 201 | Prefix: '&6Level %level%' 202 | 92: 203 | Prefix: '&6Level %level%' 204 | 93: 205 | Prefix: '&6Level %level%' 206 | 94: 207 | Prefix: '&6Level %level%' 208 | 95: 209 | Prefix: '&6Level %level%' 210 | 96: 211 | Prefix: '&6Level %level%' 212 | 97: 213 | Prefix: '&6Level %level%' 214 | 98: 215 | Prefix: '&6Level %level%' 216 | 99: 217 | Prefix: '&6Level %level%' 218 | 100: 219 | Prefix: '&cLevel 100' 220 | Enabled: true -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/SignListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.planetgallium.kitpvp.Game; 4 | import com.planetgallium.kitpvp.game.Arena; 5 | import com.planetgallium.kitpvp.util.Resource; 6 | import com.planetgallium.kitpvp.util.Toolkit; 7 | import org.bukkit.ChatColor; 8 | import org.bukkit.block.Sign; 9 | import org.bukkit.configuration.ConfigurationSection; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.event.EventHandler; 12 | import org.bukkit.event.Listener; 13 | import org.bukkit.event.block.Action; 14 | import org.bukkit.event.block.SignChangeEvent; 15 | import org.bukkit.event.player.PlayerInteractEvent; 16 | 17 | import java.util.ArrayList; 18 | import java.util.Arrays; 19 | import java.util.List; 20 | 21 | public class SignListener implements Listener { 22 | 23 | private final Arena arena; 24 | private final Resource messages; 25 | private final Resource signs; 26 | private final List regularSignTypes; 27 | private final List customSignTypes; 28 | 29 | public SignListener(Game plugin) { 30 | this.arena = plugin.getArena(); 31 | this.messages = plugin.getResources().getMessages(); 32 | this.signs = plugin.getResources().getSigns(); 33 | this.regularSignTypes = new ArrayList<>(Arrays.asList("clear", "menu", "stats", "refill")); 34 | this.customSignTypes = new ArrayList<>(Arrays.asList("kit", "arena")); 35 | } 36 | 37 | @EventHandler 38 | public void onSignChange(SignChangeEvent e) { 39 | if (e.getLine(0) != null && e.getLine(0).equalsIgnoreCase("[KitPvP]")) { 40 | Player p = e.getPlayer(); 41 | String signType = e.getLine(1); 42 | 43 | if (regularSignTypes.contains(signType)) { 44 | renameSign(e, "Signs." + Toolkit.capitalizeFirstChar(signType), null, null); 45 | p.sendMessage(messages.fetchString("Messages.Other.Sign")); 46 | } else if (customSignTypes.contains(signType)) { 47 | String placeholderKey = "%" + signType + "%"; 48 | String placeholderValue = e.getLine(2); 49 | renameSign(e, "Signs." + Toolkit.capitalizeFirstChar(signType), placeholderKey, placeholderValue); 50 | p.sendMessage(messages.fetchString("Messages.Other.Sign")); 51 | } 52 | } 53 | } 54 | 55 | @EventHandler 56 | public void onSignUse(PlayerInteractEvent e) { 57 | // Logic behind this specific sign feature implementation: to avoid storing signs, most signs will 58 | // either match what is specified in the config 100%, or essentially 95%, where the other 5% may be one word 59 | // that is different (for instance a specified kit name, or arena name). 60 | // If there isn't a 100% match, a search for that one word delta will be started and subsequently used if found. 61 | 62 | if (e.getAction() == Action.RIGHT_CLICK_BLOCK) { 63 | if (e.getClickedBlock() != null && e.getClickedBlock().getState() instanceof Sign) { 64 | ConfigurationSection signsSection = signs.getConfigurationSection("Signs"); 65 | Sign sign = (Sign) e.getClickedBlock().getState(); 66 | Player p = e.getPlayer(); 67 | 68 | for (String signType : signsSection.getKeys(false)) { 69 | if (signType.equals("Locations")) break; 70 | 71 | List mismatchedLines = new ArrayList<>(); 72 | 73 | for (int i = 0; i < 3; i++) { 74 | String signLine = sign.getLine(i); 75 | String configSignLine = signs.fetchString("Signs." + signType + ".Line-" + (i + 1)); 76 | 77 | if (!signLine.equals(configSignLine)) { 78 | mismatchedLines.add(new String[]{configSignLine, signLine}); 79 | } 80 | } 81 | 82 | if (mismatchedLines.size() == 0) { // exact match 83 | executeSign(p, signType, null); 84 | e.setCancelled(true); // prevents sign editing on 1.20+ 85 | break; 86 | } else if (mismatchedLines.size() == 1) { // one line (line with kit name or arena name) doesn't match 87 | executeSign(p, signType, getWordDelta(mismatchedLines)); 88 | e.setCancelled(true); // prevents sign editing on 1.20+ 89 | break; 90 | } 91 | } 92 | } 93 | } 94 | } 95 | 96 | private void renameSign(SignChangeEvent e, String path, String placeholder, String placeholderValue) { 97 | for (int i = 0; i < 3; i++) { 98 | String line = signs.fetchString(path + ".Line-" + (i + 1)); 99 | 100 | if (placeholder != null && placeholderValue != null) 101 | line = line.replace(placeholder, placeholderValue); 102 | e.setLine(i, line); 103 | } 104 | } 105 | 106 | private String getWordDelta(List mismatchedLines) { 107 | List wordDelta = new ArrayList<>(); 108 | 109 | String rawConfigSignLine = ChatColor.stripColor(mismatchedLines.get(0)[0]); 110 | String rawSignLine = ChatColor.stripColor(mismatchedLines.get(0)[1]); 111 | 112 | String[] rawSignLineWords = rawSignLine.split(" "); 113 | String[] rawConfigSignLineWords = rawConfigSignLine.split(" "); 114 | 115 | for (int i = 0; i < rawConfigSignLineWords.length; i++) { 116 | String rawConfigSignWord = rawConfigSignLineWords[i]; 117 | String rawSignLineWord = rawSignLineWords[i]; 118 | 119 | if (!rawConfigSignWord.equals(rawSignLineWord)) { 120 | wordDelta.add(rawSignLineWord); 121 | } 122 | } 123 | 124 | // if too many words differ, sign is not a match, return null 125 | return wordDelta.size() > 1 ? null : wordDelta.get(0); 126 | } 127 | 128 | private void executeSign(Player p, String type, String placeholder) { 129 | switch (type.toLowerCase()) { 130 | case "refill": 131 | arena.getMenus().getRefillMenu().open(p); 132 | break; 133 | case "clear": case "menu": case "stats": 134 | p.performCommand("kp " + type); 135 | break; 136 | case "kit": 137 | String kitName = placeholder; 138 | p.performCommand("kp kit " + kitName); 139 | break; 140 | case "arena": 141 | String arenaName = placeholder; 142 | p.performCommand("kp arena " + arenaName); 143 | break; 144 | } 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/listener/ArenaListener.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.listener; 2 | 3 | import com.cryptomorin.xseries.XMaterial; 4 | import com.planetgallium.kitpvp.Game; 5 | import com.planetgallium.kitpvp.util.Resource; 6 | import org.bukkit.GameMode; 7 | import org.bukkit.entity.*; 8 | import org.bukkit.event.EventHandler; 9 | import org.bukkit.event.Listener; 10 | import org.bukkit.event.block.Action; 11 | import org.bukkit.event.block.BlockBreakEvent; 12 | import org.bukkit.event.block.BlockPlaceEvent; 13 | import org.bukkit.event.entity.*; 14 | import org.bukkit.event.entity.EntityDamageEvent.DamageCause; 15 | import org.bukkit.event.hanging.HangingBreakEvent; 16 | import org.bukkit.event.player.PlayerDropItemEvent; 17 | import org.bukkit.event.player.PlayerInteractEvent; 18 | import org.bukkit.event.player.PlayerItemDamageEvent; 19 | import org.bukkit.event.player.PlayerTeleportEvent; 20 | import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; 21 | import org.bukkit.event.weather.WeatherChangeEvent; 22 | import com.planetgallium.kitpvp.game.Arena; 23 | import com.planetgallium.kitpvp.util.Resources; 24 | import com.planetgallium.kitpvp.util.Toolkit; 25 | 26 | public class ArenaListener implements Listener { 27 | 28 | private final Arena arena; 29 | private final Resource config; 30 | 31 | public ArenaListener(Game plugin) { 32 | this.arena = plugin.getArena(); 33 | this.config = plugin.getResources().getConfig(); 34 | } 35 | 36 | @EventHandler 37 | public void onBreak(BlockBreakEvent e) { 38 | Player p = e.getPlayer(); 39 | 40 | if (Toolkit.inArena(p) && config.getBoolean("Arena.PreventBlockBreaking")) { 41 | e.setCancelled(!p.hasPermission("kp.arena.blockbreaking")); 42 | } 43 | } 44 | 45 | @EventHandler 46 | public void onPlace(BlockPlaceEvent e) { 47 | Player p = e.getPlayer(); 48 | 49 | if (Toolkit.inArena(p) && config.getBoolean("Arena.PreventBlockPlacing")) { 50 | e.setCancelled(!p.hasPermission("kp.arena.blockplacing")); 51 | } 52 | 53 | } 54 | 55 | @EventHandler 56 | public void onItemDamage(PlayerItemDamageEvent e) { 57 | if (Toolkit.inArena(e.getPlayer()) && config.getBoolean("Arena.PreventItemDurabilityDamage")) { 58 | e.setCancelled(true); 59 | } 60 | } 61 | 62 | @EventHandler 63 | public void onDrop(PlayerDropItemEvent e) { 64 | Player p = e.getPlayer(); 65 | 66 | if (Toolkit.inArena(p) && config.getBoolean("Arena.PreventItemDropping")) { 67 | e.setCancelled(!p.hasPermission("kp.arena.itemdropping")); 68 | } 69 | } 70 | 71 | @EventHandler 72 | public void onHunger(FoodLevelChangeEvent e) { 73 | Player p = (Player) e.getEntity(); 74 | 75 | if (Toolkit.inArena(p) && config.getBoolean("Arena.PreventHunger")) { 76 | e.setCancelled(true); 77 | } 78 | } 79 | 80 | @EventHandler 81 | public void onExplode(EntityExplodeEvent e) { 82 | if (Toolkit.inArena(e.getEntity()) && config.getBoolean("Arena.PreventBlockBreaking")) { 83 | if (e.getEntityType() == EntityType.PRIMED_TNT) { // enable TNT explosion animation 84 | e.blockList().clear(); 85 | e.setCancelled(false); 86 | return; 87 | } 88 | e.setCancelled(true); 89 | } 90 | } 91 | 92 | @EventHandler 93 | public void onEntityDamage(EntityDamageByEntityEvent e) { 94 | if (Toolkit.inArena(e.getEntity())) { 95 | 96 | if (e.getEntity() instanceof Player && e.getDamager() instanceof Projectile) { 97 | 98 | Player damagedPlayer = (Player) e.getEntity(); 99 | if (config.getBoolean("Arena.NoKitProtection")) { 100 | if (!arena.getKits().playerHasKit(damagedPlayer.getName())) { 101 | e.setCancelled(true); 102 | } 103 | } 104 | 105 | } else if (e.getEntity() instanceof Damageable) { 106 | 107 | if (e.getDamager().getType() == EntityType.PRIMED_TNT) { 108 | if (e.getEntity() instanceof ArmorStand || !(e.getEntity() instanceof LivingEntity)) { 109 | // for preventing breakage of paintings, item frames, etc. 110 | e.setCancelled(true); 111 | } 112 | } 113 | 114 | } 115 | } 116 | } 117 | 118 | @EventHandler 119 | public void onWeatherChange(WeatherChangeEvent e) { 120 | if (Toolkit.inArena(e.getWorld()) && config.getBoolean("Arena.KeepWeatherAtSunny")) { 121 | if (e.toWeatherState()) { 122 | e.setCancelled(true); 123 | e.getWorld().setStorm(false); 124 | e.getWorld().setThundering(false); 125 | e.getWorld().setWeatherDuration(0); 126 | } 127 | } 128 | } 129 | 130 | @EventHandler 131 | public void onExplosion(EntityDamageEvent e) { 132 | if (e.getEntity() instanceof Player) { 133 | Player damagedPlayer = (Player) e.getEntity(); 134 | 135 | if (Toolkit.inArena(damagedPlayer)) { 136 | 137 | if (e.getCause() == DamageCause.BLOCK_EXPLOSION || 138 | e.getCause() == DamageCause.ENTITY_EXPLOSION || 139 | e.getCause() == DamageCause.FIRE || 140 | e.getCause() == DamageCause.FIRE_TICK) { 141 | if (config.getBoolean("Arena.NoKitProtection")) { 142 | if (!arena.getKits().playerHasKit(damagedPlayer.getName())) { 143 | e.setCancelled(true); 144 | } 145 | } 146 | 147 | } else if (e.getCause() == DamageCause.FALL) { 148 | 149 | if (config.getBoolean("Arena.PreventFallDamage")) { 150 | e.setCancelled(true); 151 | // only canceling if preventing fall damage is enabled, this allows for WorldGuard to step in 152 | } 153 | 154 | } else if (damagedPlayer.getGameMode() == GameMode.SPECTATOR) { 155 | e.setCancelled(true); 156 | } 157 | } 158 | } 159 | } 160 | 161 | @EventHandler 162 | public void onInteract(PlayerInteractEvent e) { 163 | Player p = e.getPlayer(); 164 | 165 | if (Toolkit.inArena(p)) { 166 | if (e.getClickedBlock() != null) { 167 | if (e.getClickedBlock().getType() == XMaterial.CHEST.parseMaterial()) { 168 | if (e.getAction() == Action.RIGHT_CLICK_BLOCK) { 169 | if (config.getBoolean("Arena.PreventChestOpen")) { 170 | e.setCancelled(true); 171 | } 172 | } 173 | } 174 | } 175 | } 176 | } 177 | 178 | @EventHandler 179 | public void onHangingEntityBreakByTNT(HangingBreakEvent e) { 180 | if (Toolkit.inArena(e.getEntity())) { 181 | if (e.getCause() == HangingBreakEvent.RemoveCause.EXPLOSION) { 182 | e.setCancelled(true); 183 | } 184 | } 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/Game.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp; 2 | 3 | import com.planetgallium.kitpvp.game.Infobase; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.Listener; 8 | import org.bukkit.event.block.Action; 9 | import org.bukkit.event.player.PlayerInteractEvent; 10 | import org.bukkit.plugin.PluginManager; 11 | import org.bukkit.plugin.java.JavaPlugin; 12 | import org.bukkit.scheduler.BukkitRunnable; 13 | 14 | import com.google.common.io.ByteArrayDataOutput; 15 | import com.google.common.io.ByteStreams; 16 | import com.planetgallium.kitpvp.api.EventListener; 17 | import com.planetgallium.kitpvp.command.*; 18 | import com.planetgallium.kitpvp.game.Arena; 19 | import com.planetgallium.kitpvp.listener.*; 20 | import com.planetgallium.kitpvp.util.*; 21 | 22 | public class Game extends JavaPlugin implements Listener { 23 | 24 | private static Game instance; 25 | private static String prefix = "None"; 26 | 27 | private Arena arena; 28 | private Infobase database; 29 | private Resources resources; 30 | 31 | private String updateVersion = "Error"; 32 | private boolean needsUpdate = false; 33 | private boolean hasPlaceholderAPI = false; 34 | private boolean hasWorldGuard = false; 35 | 36 | @Override 37 | public void onEnable() { 38 | Toolkit.printToConsole("&7[&b&lKIT-PVP&7] &7Enabling &bKitPvP &7version &b" + this.getDescription().getVersion() + "&7..."); 39 | 40 | instance = this; 41 | resources = new Resources(this); 42 | prefix = resources.getMessages().fetchString("Messages.General.Prefix"); 43 | database = new Infobase(this); 44 | arena = new Arena(this, resources); 45 | 46 | PluginManager pm = Bukkit.getPluginManager(); 47 | pm.registerEvents(this, this); 48 | pm.registerEvents(new EventListener(this), this); 49 | pm.registerEvents(new ArenaListener(this), this); 50 | pm.registerEvents(new JoinListener(this), this); 51 | pm.registerEvents(new LeaveListener(this), this); 52 | pm.registerEvents(new ArrowListener(this), this); 53 | pm.registerEvents(new DeathListener(this), this); 54 | pm.registerEvents(new HitListener(this), this); 55 | pm.registerEvents(new AttackListener(this), this); 56 | pm.registerEvents(new ItemListener(this), this); 57 | pm.registerEvents(new SoupListener(this), this); 58 | pm.registerEvents(new ChatListener(this), this); 59 | pm.registerEvents(new SignListener(this), this); 60 | pm.registerEvents(new AliasCommand(this), this); 61 | pm.registerEvents(new AbilityListener(this), this); 62 | pm.registerEvents(new TrackerListener(this), this); 63 | pm.registerEvents(new MenuListener(this), this); 64 | pm.registerEvents(getArena().getKillStreaks(), this); 65 | 66 | getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); 67 | getCommand("kitpvp").setExecutor(new MainCommand(this)); 68 | 69 | new Metrics(this); 70 | 71 | new BukkitRunnable() { 72 | @Override 73 | public void run() { 74 | checkUpdate(); 75 | } 76 | }.runTaskAsynchronously(this); 77 | 78 | if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { 79 | Bukkit.getConsoleSender().sendMessage(Toolkit.translate("[&b&lKIT-PVP&7] &7Hooking into &bPlaceholderAPI&7...")); 80 | new Placeholders(this).register(); 81 | hasPlaceholderAPI = true; 82 | } 83 | 84 | if (Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) { 85 | Bukkit.getConsoleSender().sendMessage(Toolkit.translate("[&b&lKIT-PVP&7] &7Hooking into &bWorldGuard&7...")); 86 | hasWorldGuard = true; 87 | } 88 | 89 | populateUUIDCacheForOnlinePlayers(); 90 | 91 | Toolkit.printToConsole("&7[&b&lKIT-PVP&7] &aDone!"); 92 | } 93 | 94 | private void populateUUIDCacheForOnlinePlayers() { 95 | // populates UUID cache if there are players online when doing /reload to avoid a lot of errors related 96 | // to database and UUIDs 97 | if (Bukkit.getOnlinePlayers().size() > 0) { 98 | for (Player player : Bukkit.getOnlinePlayers()) { 99 | CacheManager.getUUIDCache().put(player.getName(), player.getUniqueId().toString()); 100 | } 101 | } 102 | } 103 | 104 | private void checkUpdate() { 105 | Updater.of(this).resourceId(27107).handleResponse((versionResponse, version) -> { 106 | switch (versionResponse) { 107 | case FOUND_NEW: 108 | Bukkit.getConsoleSender().sendMessage(Toolkit.translate("&7[&b&lKIT-PVP&7] &aNew version found! Please update to v" + version + " on the Spigot page.")); 109 | needsUpdate = true; 110 | updateVersion = version; 111 | break; 112 | case UNAVAILABLE: 113 | Bukkit.getConsoleSender().sendMessage(Toolkit.translate("&7[&b&lKIT-PVP&7] &cUnable to perform an update check.")); 114 | break; 115 | } 116 | }).check(); 117 | } 118 | 119 | @EventHandler 120 | public void onInteract(PlayerInteractEvent e) { 121 | Player p = e.getPlayer(); 122 | 123 | if (!resources.getConfig().contains("Items.Leave")) { 124 | return; 125 | } 126 | 127 | if (Toolkit.matchesConfigItem(Toolkit.getHandItemForInteraction(e), resources.getConfig(), "Items.Leave")) { 128 | if (resources.getConfig().getBoolean("Items.Leave.Enabled")) { 129 | if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) { 130 | if (resources.getConfig().getBoolean("Items.Leave.BungeeCord.Enabled")) { 131 | ByteArrayDataOutput out = ByteStreams.newDataOutput(); 132 | out.writeUTF("Connect"); 133 | 134 | String server = resources.getConfig().fetchString("Items.Leave.BungeeCord.Server"); 135 | 136 | out.writeUTF(server); 137 | p.sendPluginMessage(this, "BungeeCord", out.toByteArray()); 138 | } 139 | e.setCancelled(true); 140 | } 141 | } 142 | } 143 | } 144 | 145 | @Override 146 | public void onDisable() { 147 | // for players that haven't died and had their stats pushed 148 | // for (String username : CacheManager.getStatsCache().keySet()) { 149 | // arena.getStats().pushCachedStatsToDatabase(username); 150 | // } 151 | } 152 | 153 | public boolean hasPlaceholderAPI() { return hasPlaceholderAPI; } 154 | 155 | public boolean hasWorldGuard() { return hasWorldGuard; } 156 | 157 | public boolean needsUpdate() { return needsUpdate; } 158 | 159 | public String getUpdateVersion() { return updateVersion; } 160 | 161 | public static Game getInstance() { return instance; } 162 | 163 | public Arena getArena() { return arena; } 164 | 165 | public Infobase getDatabase() { return database; } 166 | 167 | public static String getPrefix() { return prefix; } 168 | 169 | public Resources getResources() { return resources; } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/Stats.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import com.cryptomorin.xseries.XSound; 4 | import com.planetgallium.database.TopEntry; 5 | import com.planetgallium.kitpvp.Game; 6 | import com.planetgallium.kitpvp.api.PlayerLevelUpEvent; 7 | import com.planetgallium.kitpvp.util.*; 8 | import org.bukkit.Bukkit; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.scheduler.BukkitRunnable; 11 | 12 | import java.util.List; 13 | 14 | public class Stats { 15 | 16 | private final Game plugin; 17 | private final Infobase database; 18 | private final Resources resources; 19 | private final Resource levels; 20 | private final Leaderboards leaderboards; 21 | 22 | public Stats(Game plugin, Arena arena) { 23 | this.plugin = plugin; 24 | this.database = plugin.getDatabase(); 25 | this.resources = plugin.getResources(); 26 | this.levels = plugin.getResources().getLevels(); 27 | this.leaderboards = arena.getLeaderboards(); 28 | } 29 | 30 | public void createPlayer(Player p) { 31 | CacheManager.getUUIDCache().put(p.getName(), p.getUniqueId().toString()); 32 | database.registerPlayerStats(p); 33 | } 34 | 35 | private boolean isPlayerRegistered(String username) { 36 | if (CacheManager.getStatsCache().containsKey(username)) { // try to use cache first to be faster 37 | return true; 38 | } 39 | return database.isPlayerRegistered(username); 40 | } 41 | 42 | public double getKDRatio(String username) { 43 | if (getStat("deaths", username) != 0) { 44 | double divided = (double) getStat("kills", username) / getStat("deaths", username); 45 | return Toolkit.round(divided, 2); 46 | } 47 | return 0.00; 48 | } 49 | 50 | public void removeExperience(String username, int amount) { 51 | if (levels.getBoolean("Levels.Levels.Enabled")) { 52 | int currentExperience = getStat("experience", username); 53 | setStat("experience", username, currentExperience >= amount ? currentExperience - amount : 0); 54 | } 55 | } 56 | 57 | public void addExperience(Player p, int experienceToAdd) { 58 | if (levels.getBoolean("Levels.Levels.Enabled")) { 59 | int currentExperience = getStat("experience", p.getName()); 60 | int newExperience = applyPossibleXPMultiplier(p, currentExperience + experienceToAdd); 61 | setStat("experience", p.getName(), newExperience); 62 | if (getStat("experience", p.getName()) >= getRegularOrRelativeNeededExperience(p.getName())) { 63 | levelUp(p); 64 | Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(p, getStat("level", p.getName()))); 65 | } 66 | } 67 | } 68 | 69 | private int applyPossibleXPMultiplier(Player p, int experience) { 70 | double xpMultiplier = Toolkit.getPermissionAmountDouble(p, "kp.xpmultiplier.", 1.0); 71 | return (int) (experience * xpMultiplier); 72 | } 73 | 74 | public void levelUp(Player p) { 75 | String username = p.getName(); 76 | 77 | if (getStat("level", username) < levels.getInt("Levels.Options.Maximum-Level")) { 78 | 79 | int newLevel = getStat("level", username) + 1; 80 | setStat("level", username, newLevel); 81 | setStat("experience", username, 0); 82 | 83 | List levelUpCommands = levels.getStringList("Levels.Commands-On-Level-Up"); 84 | Toolkit.runCommands(p, levelUpCommands, "%level%", String.valueOf(newLevel)); 85 | 86 | if (levels.contains("Levels.Levels." + newLevel + ".Commands")) { 87 | List commandsList = levels.getStringList("Levels.Levels." + newLevel + ".Commands"); 88 | Toolkit.runCommands(p, commandsList, "%level%", String.valueOf(newLevel)); 89 | } 90 | 91 | p.sendMessage(resources.getMessages().fetchString("Messages.Other.Level") 92 | .replace("%level%", String.valueOf(newLevel))); 93 | Toolkit.playSoundToPlayer(p, "ENTITY_PLAYER_LEVELUP", 1); 94 | 95 | } else { 96 | setStat("experience", username, 0); 97 | } 98 | } 99 | 100 | public void addToStat(String identifier, String username, int amount) { 101 | int updatedAmount = getStat(identifier, username) + amount; 102 | setStat(identifier, username, updatedAmount); 103 | } 104 | 105 | public void setStat(String identifier, String username, int data) { 106 | if (!isPlayerRegistered(username)) { 107 | return; 108 | } 109 | 110 | getOrCreateStatsCache(username).setData(identifier, data); 111 | leaderboards.updateRankings(identifier, new TopEntry(username, data)); 112 | } 113 | 114 | public void pushCachedStatsToDatabase(String username, boolean removeFromCacheAfter) { 115 | new BukkitRunnable() { 116 | @Override 117 | public void run() { 118 | if (!CacheManager.getStatsCache().containsKey(username)) { 119 | return; // nothing to push if stats cache is empty 120 | } 121 | 122 | database.setStatsData(username, getOrCreateStatsCache(username)); 123 | if (removeFromCacheAfter) { 124 | CacheManager.getStatsCache().remove(username); 125 | } 126 | } 127 | }.runTaskAsynchronously(plugin); 128 | } 129 | 130 | public int getStat(String identifier, String username) { 131 | if (!isPlayerRegistered(username)) { 132 | return -1; 133 | } 134 | 135 | return getOrCreateStatsCache(username).getData(identifier); 136 | } 137 | 138 | public PlayerData getOrCreateStatsCache(String username) { 139 | if (!isPlayerRegistered(username)) { 140 | return new PlayerData(-1, -1, -1, -1); 141 | } 142 | 143 | if (!CacheManager.getStatsCache().containsKey(username)) { 144 | CacheManager.getStatsCache().put(username, database.getStatsData(username)); 145 | } 146 | return CacheManager.getStatsCache().get(username); 147 | } 148 | 149 | public int getRegularOrRelativeNeededExperience(String username) { 150 | int level = getStat("level", username); 151 | 152 | if (levels.contains("Levels.Levels." + level + ".Experience-To-Level-Up")) { 153 | return levels.getInt("Levels.Levels." + level + ".Experience-To-Level-Up"); 154 | } 155 | return levels.getInt("Levels.Options.Experience-To-Level-Up"); 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/util/Resources.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.util; 2 | 3 | import java.io.File; 4 | import java.util.*; 5 | 6 | import com.planetgallium.kitpvp.Game; 7 | import com.planetgallium.kitpvp.api.Ability; 8 | 9 | public class Resources { 10 | 11 | private final Game plugin; 12 | private final Map kitToResource; 13 | private final Map abilityToResource; 14 | 15 | private final Resource config, abilities, killstreaks, 16 | levels, menu, messages, scoreboard, signs; 17 | 18 | public Resources(Game plugin) { 19 | this.plugin = plugin; 20 | this.kitToResource = new HashMap<>(); 21 | this.abilityToResource = new HashMap<>(); 22 | 23 | Toolkit.printToConsole("&7[&b&lKIT-PVP&7] &7Loading configuration files..."); 24 | this.config = new Resource(plugin, "config.yml"); 25 | this.abilities = new Resource(plugin, "abilities.yml"); 26 | this.killstreaks = new Resource(plugin, "killstreaks.yml"); 27 | this.levels = new Resource(plugin, "levels.yml"); 28 | this.menu = new Resource(plugin, "menu.yml"); 29 | this.messages = new Resource(plugin, "messages.yml"); 30 | this.scoreboard = new Resource(plugin, "scoreboard.yml"); 31 | this.signs = new Resource(plugin, "signs.yml"); 32 | 33 | if (!plugin.getDataFolder().exists()) { 34 | kitToResource.put("Fighter.yml", new Resource(plugin, "kits/Fighter.yml")); 35 | kitToResource.put("Archer.yml", new Resource(plugin, "kits/Archer.yml")); 36 | kitToResource.put("Tank.yml", new Resource(plugin, "kits/Tank.yml")); 37 | kitToResource.put("Soldier.yml", new Resource(plugin, "kits/Soldier.yml")); 38 | kitToResource.put("Bomber.yml", new Resource(plugin, "kits/Bomber.yml")); 39 | kitToResource.put("Kangaroo.yml", new Resource(plugin, "kits/Kangaroo.yml")); 40 | kitToResource.put("Warper.yml", new Resource(plugin, "kits/Warper.yml")); 41 | kitToResource.put("Witch.yml", new Resource(plugin, "kits/Witch.yml")); 42 | kitToResource.put("Ninja.yml", new Resource(plugin, "kits/Ninja.yml")); 43 | kitToResource.put("Thunderbolt.yml", new Resource(plugin, "kits/Thunderbolt.yml")); 44 | kitToResource.put("Vampire.yml", new Resource(plugin, "kits/Vampire.yml")); 45 | kitToResource.put("Rhino.yml", new Resource(plugin, "kits/Rhino.yml")); 46 | kitToResource.put("Example.yml", new Resource(plugin, "kits/Example.yml")); 47 | kitToResource.put("Trickster.yml", new Resource(plugin, "kits/Trickster.yml")); 48 | 49 | abilityToResource.put("HealthPack.yml", new Resource(plugin, "abilities/HealthPack.yml")); 50 | abilityToResource.put("ExampleAbility.yml", new Resource(plugin, "abilities/ExampleAbility.yml")); 51 | abilityToResource.put("ExampleAbility2.yml", new Resource(plugin, "abilities/ExampleAbility2.yml")); 52 | abilityToResource.put("SpeedBoost.yml", new Resource(plugin, "abilities/SpeedBoost.yml")); 53 | abilityToResource.put("Stampede.yml", new Resource(plugin, "abilities/Stampede.yml")); 54 | } 55 | 56 | Toolkit.printToConsole("&7[&b&lKIT-PVP&7] &7Loading kit files..."); 57 | load(); 58 | } 59 | 60 | public void load() { 61 | config.load(); 62 | abilities.load(); 63 | killstreaks.load(); 64 | levels.load(); 65 | menu.load(); 66 | messages.load(); 67 | scoreboard.load(); 68 | signs.load(); 69 | 70 | messages.addCopyDefaultExemption("Messages.Stats.Message"); 71 | messages.copyDefaults(); 72 | 73 | menu.addCopyDefaultExemption("Menu.Items"); 74 | menu.copyDefaults(); 75 | 76 | levels.addCopyDefaultExemption("Levels.Levels.10.Commands"); 77 | levels.addCopyDefaultExemption("Levels.Levels.10.Experience-To-Level-Up"); 78 | levels.copyDefaults(); 79 | 80 | scoreboard.addCopyDefaultExemption("Scoreboard.Lines"); 81 | scoreboard.copyDefaults(); 82 | 83 | config.addCopyDefaultExemption("Items.Kits.Commands"); 84 | config.addCopyDefaultExemption("Items.Leave.Commands"); 85 | config.copyDefaults(); 86 | 87 | abilities.copyDefaults(); 88 | signs.copyDefaults(); 89 | 90 | // load new kits & abilities that have been added through file system (when doing /kp reload) 91 | for (String fileName : getPluginDirectoryFiles("kits", true)) { 92 | if (!kitToResource.containsKey(fileName) && !fileName.startsWith(".")) { 93 | kitToResource.put(fileName, new Resource(plugin, "kits/" + fileName)); 94 | } 95 | } 96 | 97 | for (String fileName : getPluginDirectoryFiles("abilities", true)) { 98 | if (!abilityToResource.containsKey(fileName) && !fileName.startsWith(".")) { 99 | abilityToResource.put(fileName, new Resource(plugin, "abilities/" + fileName)); 100 | } 101 | } 102 | 103 | // Reload all kitName.yml, abilityName.yml 104 | kitToResource.values().forEach(Resource::load); 105 | abilityToResource.values().forEach(Resource::load); 106 | } 107 | 108 | public void reload() { 109 | load(); 110 | } 111 | 112 | public void addResource(String fileName, Resource resource) { 113 | kitToResource.put(fileName, resource); 114 | kitToResource.get(fileName).load(); 115 | } 116 | 117 | public void removeResource(String fileName) { 118 | kitToResource.get(fileName).getFile().delete(); 119 | kitToResource.remove(fileName); 120 | } 121 | 122 | public void addAbilityResource(Ability ability) { 123 | String abilityName = ability.getName(); 124 | Resource abilityResource = new Resource(plugin, "abilities/" + abilityName + ".yml"); 125 | ability.toResource(abilityResource); 126 | 127 | abilityToResource.put(abilityName, abilityResource); 128 | abilityToResource.get(abilityName).load(); 129 | } 130 | 131 | public Resource getKit(String kitName) { 132 | if (kitToResource.containsKey(kitName + ".yml")) { 133 | return kitToResource.get(kitName + ".yml"); 134 | } 135 | return null; 136 | } 137 | 138 | public List getPluginDirectoryFiles(String directoryName, boolean withFileEndings) { 139 | File folder = new File(plugin.getDataFolder().getAbsolutePath() + "/" + directoryName); 140 | List fileList = new ArrayList<>(); 141 | 142 | if (folder.exists() && folder.list() != null) { 143 | for (String fileName : folder.list()) { 144 | fileList.add(withFileEndings ? fileName : fileName.split(".yml")[0]); 145 | } 146 | } 147 | return fileList; 148 | } 149 | 150 | public Resource getConfig() { return config; } 151 | 152 | public Resource getAbilities() { return abilities; } 153 | 154 | public Resource getKillStreaks() { return killstreaks; } 155 | 156 | public Resource getLevels() { return levels; } 157 | 158 | public Resource getMenu() { return menu; } 159 | 160 | public Resource getMessages() { return messages; } 161 | 162 | public Resource getScoreboard() { return scoreboard; } 163 | 164 | public Resource getSigns() { return signs; } 165 | 166 | public Collection getAbilityResources() { return abilityToResource.values(); } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/game/Arena.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.game; 2 | 3 | import java.util.*; 4 | 5 | import com.planetgallium.kitpvp.util.*; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.GameMode; 8 | import org.bukkit.configuration.ConfigurationSection; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.bukkit.inventory.meta.ItemMeta; 12 | import org.bukkit.potion.PotionEffect; 13 | import org.bukkit.scoreboard.Scoreboard; 14 | 15 | import com.planetgallium.kitpvp.Game; 16 | 17 | public class Arena { 18 | 19 | private final Game plugin; 20 | private final Random random; 21 | 22 | private final Resources resources; 23 | private final Resource config; 24 | 25 | private final Map hitCache; 26 | 27 | private final Utilities utilties; 28 | private final Leaderboards leaderboards; 29 | private final Stats stats; 30 | private final Kits kits; 31 | private final Abilities abilities; 32 | private final KillStreaks killstreaks; 33 | private final Cooldowns cooldowns; 34 | private final Menus menus; 35 | 36 | public Arena(Game plugin, Resources resources) { 37 | this.plugin = plugin; 38 | this.random = new Random(); 39 | 40 | this.resources = resources; 41 | this.config = resources.getConfig(); 42 | 43 | this.hitCache = new HashMap<>(); 44 | 45 | this.utilties = new Utilities(plugin, this); 46 | this.leaderboards = new Leaderboards(plugin); 47 | this.stats = new Stats(plugin, this); 48 | this.kits = new Kits(plugin, this); 49 | this.abilities = new Abilities(plugin); 50 | this.killstreaks = new KillStreaks(resources); 51 | this.cooldowns = new Cooldowns(plugin, this); 52 | this.menus = new Menus(resources); 53 | } 54 | 55 | public void addPlayer(Player p, boolean toSpawn, boolean giveItems) { 56 | cooldowns.clearPlayerAbilityCooldowns(p.getName()); 57 | 58 | kits.resetPlayerKit(p.getName()); 59 | 60 | if (config.getBoolean("Arena.ResetKillStreakOnLeave")) { 61 | killstreaks.setStreak(p, 0); 62 | } 63 | 64 | if (config.getBoolean("Arena.ClearPotionEffectsOnJoin")) { 65 | for (PotionEffect effect : p.getActivePotionEffects()) { 66 | p.removePotionEffect(effect.getType()); 67 | } 68 | } 69 | 70 | if (p.getFireTicks() > 0) { 71 | p.setFireTicks(0); 72 | } 73 | 74 | p.setGameMode(GameMode.SURVIVAL); 75 | 76 | if (config.getBoolean("Arena.ResetMaxHealthOnDeath")) { 77 | Toolkit.setMaxHealth(p, 20); 78 | } 79 | 80 | if (config.getBoolean("Arena.FancyDeath")) { 81 | // p.setHealth(20.0); 82 | p.setHealth(Toolkit.getMaxHealth(p)); 83 | } 84 | 85 | p.setExp(0f); 86 | p.setFoodLevel(20); 87 | 88 | if (giveItems) { 89 | giveArenaItems(p); 90 | } 91 | 92 | if (toSpawn) { 93 | toSpawn(p, p.getWorld().getName()); 94 | } 95 | 96 | if (resources.getScoreboard().getBoolean("Scoreboard.General.Enabled")) { 97 | updateScoreboards(p, false); 98 | } 99 | } 100 | 101 | public void removePlayer(Player p) { 102 | CacheManager.getPlayerAbilityCooldowns(p.getName()).clear(); 103 | CacheManager.getPotionSwitcherUsers().remove(p.getName()); 104 | 105 | for (PotionEffect effect : p.getActivePotionEffects()) { 106 | p.removePotionEffect(effect.getType()); 107 | } 108 | 109 | kits.resetPlayerKit(p.getName()); 110 | 111 | if (config.getBoolean("Arena.ResetKillStreakOnLeave")) { 112 | getKillStreaks().resetStreak(p); 113 | } 114 | 115 | p.setExp(0f); 116 | p.setFoodLevel(20); 117 | 118 | if (resources.getScoreboard().getBoolean("Scoreboard.General.Enabled")) { 119 | updateScoreboards(p, true); 120 | } 121 | 122 | stats.pushCachedStatsToDatabase(p.getName(), false); // cached stats are pushed to database on death 123 | hitCache.remove(p.getName()); 124 | } 125 | 126 | public void deletePlayer(Player p) { 127 | if (config.getBoolean("Arena.ClearInventoryOnLeave")) { 128 | p.getInventory().clear(); 129 | p.getInventory().setArmorContents(null); 130 | } 131 | 132 | CacheManager.getPlayerAbilityCooldowns(p.getName()).clear(); 133 | hitCache.remove(p.getName()); 134 | stats.pushCachedStatsToDatabase(p.getName(), true); 135 | } 136 | 137 | public void giveArenaItems(Player p) { 138 | ConfigurationSection items = config.getConfigurationSection("Items"); 139 | 140 | for (String identifier : items.getKeys(false)) { 141 | String itemPath = "Items." + identifier; 142 | 143 | if (config.getBoolean(itemPath + ".Enabled")) { 144 | ItemStack item = Toolkit.safeItemStack(config.fetchString(itemPath + ".Material")); 145 | ItemMeta meta = item.getItemMeta(); 146 | 147 | meta.setDisplayName(config.fetchString(itemPath + ".Name")); 148 | meta.setLore(config.getStringList(itemPath + ".Lore")); 149 | 150 | item.setItemMeta(meta); 151 | 152 | p.getInventory().setItem(config.getInt(itemPath + ".Slot"), item); 153 | } 154 | } 155 | } 156 | 157 | public void toSpawn(Player p, String arenaName) { 158 | if (config.contains("Arenas." + arenaName)) { 159 | p.teleport(Toolkit.getLocationFromResource(config, 160 | "Arenas." + arenaName + "." + generateRandomArenaSpawn(arenaName))); 161 | } else { 162 | p.sendMessage(resources.getMessages().fetchString("Messages.Error.Arena") 163 | .replace("%arena%", arenaName)); 164 | } 165 | } 166 | 167 | public void updateScoreboards(Player p, boolean hide) { 168 | Scoreboard board = Bukkit.getScoreboardManager().getNewScoreboard(); 169 | String scoreboardTitle = utilties.addPlaceholdersIfPossible(p, 170 | resources.getScoreboard().fetchString("Scoreboard.General.Title")); 171 | Infoboard scoreboard = new Infoboard(board, scoreboardTitle); 172 | 173 | if (!hide) { 174 | for (String line : resources.getScoreboard().getStringList("Scoreboard.Lines")) { 175 | scoreboard.add(utilties.addPlaceholdersIfPossible(p, line)); 176 | } 177 | } else { 178 | scoreboard.hide(); 179 | } 180 | 181 | scoreboard.update(p); 182 | } 183 | 184 | public String generateRandomArenaSpawn(String arenaName) { 185 | ConfigurationSection section = config.getConfigurationSection("Arenas." + arenaName); 186 | List spawnKeys = new ArrayList<>(section.getKeys(false)); 187 | 188 | return spawnKeys.get(random.nextInt(spawnKeys.size())); 189 | } 190 | 191 | public Map getHitCache() { return hitCache; } 192 | 193 | public Stats getStats() { return stats; } 194 | 195 | public Utilities getUtilities() { return utilties; } 196 | 197 | public Leaderboards getLeaderboards() { return leaderboards; } 198 | 199 | public Kits getKits() { return kits; } 200 | 201 | public Abilities getAbilities() { return abilities; } 202 | 203 | public KillStreaks getKillStreaks() { return killstreaks; } 204 | 205 | public Cooldowns getCooldowns() { return cooldowns; } 206 | 207 | public Menus getMenus() { return menus; } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/item/AttributeWriter.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.item; 2 | 3 | import com.cryptomorin.xseries.XMaterial; 4 | import com.planetgallium.kitpvp.util.Resource; 5 | import com.planetgallium.kitpvp.util.Toolkit; 6 | import org.bukkit.enchantments.Enchantment; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.bukkit.inventory.meta.*; 9 | import org.bukkit.potion.Potion; 10 | import org.bukkit.potion.PotionData; 11 | import org.bukkit.potion.PotionEffect; 12 | 13 | public class AttributeWriter { 14 | 15 | // look into using XItemStack by Crypto 16 | 17 | public static void potionEffectToResource(Resource resource, String path, PotionEffect effect) { 18 | if (effect == null) return; 19 | 20 | int amplifierNonZeroBased = effect.getAmplifier() + 1; 21 | int durationSeconds = effect.getDuration() / 20; 22 | 23 | resource.set(path + "." + effect.getType().getName() + ".Amplifier", amplifierNonZeroBased); 24 | resource.set(path + "." + effect.getType().getName() + ".Duration", durationSeconds); 25 | resource.save(); 26 | } 27 | 28 | public static void itemStackToResource(Resource resource, String path, ItemStack item) { 29 | if (item == null || item.getType() == XMaterial.AIR.parseMaterial()) return; 30 | 31 | ItemMeta meta = item.getItemMeta(); 32 | 33 | resource.set(path + ".Name", meta.hasDisplayName() ? Toolkit.toNormalColorCodes(meta.getDisplayName()) : null); 34 | resource.set(path + ".Lore", Toolkit.toNormalColorCodes(meta.getLore())); 35 | resource.set(path + ".Material", item.getType().toString()); 36 | resource.set(path + ".Amount", item.getAmount() == 1 ? null : item.getAmount()); 37 | resource.save(); 38 | 39 | serializeDyedArmor(resource, item, path); 40 | serializeSkull(resource, item, path); 41 | serializeTippedArrows(resource, item, path); 42 | serializePotion(resource, item, path); 43 | serializeEnchantments(resource, item, path); 44 | serializeDurability(resource, item, path); 45 | } 46 | 47 | private static void serializeDyedArmor(Resource resource, ItemStack item, String path) { 48 | if (item.getType() == XMaterial.LEATHER_HELMET.parseMaterial() || 49 | item.getType() == XMaterial.LEATHER_CHESTPLATE.parseMaterial() || 50 | item.getType() == XMaterial.LEATHER_LEGGINGS.parseMaterial() || 51 | item.getType() == XMaterial.LEATHER_BOOTS.parseMaterial()) { 52 | 53 | LeatherArmorMeta dyedMeta = (LeatherArmorMeta) item.getItemMeta(); 54 | 55 | resource.set(path + ".Dye.Red", dyedMeta.getColor().getRed()); 56 | resource.set(path + ".Dye.Green", dyedMeta.getColor().getGreen()); 57 | resource.set(path + ".Dye.Blue", dyedMeta.getColor().getBlue()); 58 | resource.save(); 59 | } 60 | } 61 | 62 | private static void serializeSkull(Resource resource, ItemStack item, String path) { 63 | if (item.getType() == XMaterial.PLAYER_HEAD.parseMaterial()) { 64 | SkullMeta skullMeta = (SkullMeta) item.getItemMeta(); 65 | 66 | resource.set(path + ".Skull", skullMeta.getOwner()); 67 | resource.save(); 68 | } 69 | } 70 | 71 | private static void serializeTippedArrows(Resource resource, ItemStack item, String path) { 72 | if (Toolkit.versionToNumber() >= 19 && item.getType() == XMaterial.TIPPED_ARROW.parseMaterial()) { 73 | serializeEffects(resource, item, path); 74 | } 75 | } 76 | 77 | private static void serializeEffects(Resource resource, ItemStack item, String path) { 78 | PotionMeta meta = (PotionMeta) item.getItemMeta(); 79 | String effectPath = path + ".Effects"; 80 | 81 | if (meta.getCustomEffects().size() > 0) { 82 | for (PotionEffect effect : meta.getCustomEffects()) { 83 | resource.set(effectPath + "." + effect.getType().getName() + ".Amplifier", effect.getAmplifier() + 1); 84 | resource.set(effectPath + "." + effect.getType().getName() + ".Duration", effect.getDuration() / 20); 85 | resource.save(); 86 | } 87 | 88 | } else { 89 | 90 | if (Toolkit.versionToNumber() == 18) { 91 | Potion potionStack = Potion.fromItemStack(item); 92 | 93 | resource.set(path + ".Type", potionStack.isSplash() ? "SPLASH_POTION" : "POTION"); 94 | resource.save(); 95 | 96 | resource.set(path + ".Effects." + potionStack.getType() + ".Upgraded", potionStack.getLevel() > 0); 97 | resource.set(path + ".Effects." + potionStack.getType() + ".Extended", potionStack.hasExtendedDuration()); 98 | resource.save(); 99 | 100 | } else if (Toolkit.versionToNumber() >= 19) { 101 | PotionData data = meta.getBasePotionData(); 102 | 103 | String effectName = data.getType().getEffectType().getName(); 104 | resource.set(effectPath + "." + effectName + ".Upgraded", data.isUpgraded()); 105 | resource.set(effectPath + "." + effectName + ".Extended", data.isExtended()); 106 | resource.save(); 107 | } 108 | } 109 | } 110 | 111 | private static void serializePotion(Resource resource, ItemStack item, String path) { 112 | if (item.getType() == XMaterial.POTION.parseMaterial() || 113 | (Toolkit.versionToNumber() >= 19 && 114 | (item.getType() == XMaterial.SPLASH_POTION.parseMaterial() || 115 | item.getType() == XMaterial.LINGERING_POTION.parseMaterial()))) { 116 | serializeEffects(resource, item, path); 117 | } 118 | } 119 | 120 | private static void serializeEnchantments(Resource resource, ItemStack item, String path) { 121 | if (item.getEnchantments().size() > 0) { 122 | for (Enchantment enchantment : item.getEnchantments().keySet()) { 123 | String enchantmentName = Toolkit.versionToNumber() < 113 ? 124 | enchantment.getName() : enchantment.getKey().getKey(); 125 | resource.set(path + ".Enchantments." + enchantmentName.toUpperCase(), 126 | item.getEnchantments().get(enchantment)); 127 | resource.save(); 128 | } 129 | } 130 | } 131 | 132 | private static void serializeDurability(Resource resource, ItemStack item, String path) { 133 | if (Toolkit.versionToNumber() < 113) { 134 | if (item.getDurability() > 0 && 135 | item.getType() != XMaterial.PLAYER_HEAD.parseMaterial() && 136 | item.getType() != XMaterial.POTION.parseMaterial() && 137 | item.getType() != XMaterial.SPLASH_POTION.parseMaterial()) { 138 | 139 | resource.set(path + ".Durability", item.getDurability()); 140 | resource.save(); 141 | } 142 | 143 | } else if (Toolkit.versionToNumber() >= 113) { 144 | 145 | if (item.getItemMeta() instanceof Damageable && 146 | item.getType() != XMaterial.PLAYER_HEAD.parseMaterial() && 147 | item.getType() != XMaterial.POTION.parseMaterial() && 148 | item.getType() != XMaterial.SPLASH_POTION.parseMaterial()) { 149 | 150 | Damageable damagedMeta = (Damageable) item.getItemMeta(); 151 | 152 | if (damagedMeta.hasDamage()) { 153 | resource.set(path + ".Durability", damagedMeta.getDamage()); 154 | resource.save(); 155 | } 156 | } 157 | } 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.planetgallium 8 | KitPvP 9 | 2.2.2 10 | jar 11 | 12 | ${project.artifactId} 13 | 14 | 15 | UTF-8 16 | 17 | 18 | 19 | clean package 20 | ${project.artifactId}-${project.version} 21 | 22 | 23 | org.apache.maven.plugins 24 | maven-compiler-plugin 25 | 3.8.1 26 | 27 | 1.8 28 | 1.8 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-shade-plugin 35 | 3.2.1 36 | 37 | 38 | 39 | com.cryptomorin.xseries 40 | com.planetgallium.kitpvp 41 | 42 | 43 | com.mysql 44 | com.planetgallium.sql 45 | 46 | 47 | 48 | 49 | *:* 50 | 51 | com/cryptomorin/xseries/messages/ActionBar* 52 | com/cryptomorin/xseries/particles/* 53 | com/cryptomorin/xseries/NMSExtras* 54 | com/cryptomorin/xseries/NoteBlockMusic* 55 | com/cryptomorin/xseries/SkullUtils* 56 | com/cryptomorin/xseries/XBiome* 57 | com/cryptomorin/xseries/XBlock* 58 | com/cryptomorin/xseries/XEntity* 59 | com/cryptomorin/xseries/XItemStack* 60 | com/cryptomorin/xseries/XBlock* 61 | com/cryptomorin/xseries/XTag* 62 | com/cryptomorin/xseries/XWorldBorder* 63 | 64 | 65 | 66 | 67 | 68 | 69 | package 70 | 71 | shade 72 | 73 | 74 | false 75 | false 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | src/main/resources 84 | true 85 | 86 | 87 | 88 | 89 | 90 | 91 | dev 92 | 93 | false 94 | 95 | 96 | 97 | 98 | org.apache.maven.plugins 99 | maven-shade-plugin 100 | 101 | /Users/nico/Developer/Spigot/Latest/plugins/${project.artifactId}.jar 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | org.spigotmc 112 | spigot-api 113 | 1.20.4-R0.1-SNAPSHOT 114 | provided 115 | 116 | 117 | me.clip 118 | placeholderapi 119 | 2.11.0 120 | provided 121 | 122 | 123 | com.sk89q.worldguard 124 | worldguard-bukkit 125 | 7.0.0 126 | provided 127 | 128 | 129 | org.bstats 130 | bstats-bukkit 131 | 132 | 133 | 134 | 135 | com.sk89q.worldguard 136 | worldguard-legacy 137 | 6.2 138 | provided 139 | 140 | 141 | com.github.cryptomorin 142 | XSeries 143 | 13.2.0 144 | 145 | 146 | com.googlecode.json-simple 147 | json-simple 148 | 1.1.1 149 | provided 150 | 151 | 152 | com.google.code.findbugs 153 | jsr305 154 | 3.0.2 155 | provided 156 | 157 | 158 | mysql 159 | mysql-connector-java 160 | 5.1.44 161 | compile 162 | 163 | 164 | org.xerial 165 | sqlite-jdbc 166 | 3.36.0.3 167 | provided 168 | 169 | 170 | 171 | 172 | 173 | spigot-repo 174 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 175 | 176 | 177 | placeholderapi 178 | https://repo.extendedclip.com/content/repositories/placeholderapi/ 179 | 180 | 181 | sk89q-repo 182 | https://maven.enginehub.org/repo/ 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /src/main/resources/menu.yml: -------------------------------------------------------------------------------- 1 | # To learn more about customizing the menu, please 2 | # visit the menu.yml documentation on GitHub: 3 | # https://github.com/cervinakuy/KitPvP/wiki/menu.yml 4 | 5 | Menu: 6 | General: 7 | Title: 'Kits' 8 | Size: 54 9 | Items: 10 | 10: 11 | Name: '&a&lFighter Kit' 12 | Material: IRON_CHESTPLATE 13 | Lore: 14 | - '&6Ability: &7Rechargeable Health Pack' 15 | - ' ' 16 | - '&7- Iron Sword' 17 | - '&7- Iron Helmet' 18 | - '&7- Iron Chestplate' 19 | - '&7- Iron Leggings' 20 | - '&7- Iron Boots' 21 | - ' ' 22 | - '&eLeft-click to select.' 23 | - '&eRight-click to preview.' 24 | Commands: 25 | Left-Click: 26 | - 'player: kp kit Fighter' 27 | Right-Click: 28 | - 'player: kp preview Fighter' 29 | 11: 30 | Name: '&a&lArcher Kit' 31 | Material: BOW 32 | Lore: 33 | - '&6Ability: &710 Fire Arrows' 34 | - ' ' 35 | - '&7- Stone Sword' 36 | - '&7- Bow' 37 | - '&7- 64 Arrows' 38 | - '&7- Chain Helmet' 39 | - '&7- Chain Chestplate' 40 | - '&7- Chain Leggings' 41 | - '&7- Chain Boots' 42 | - ' ' 43 | - '&eLeft-click to select.' 44 | - '&eRight-click to preview.' 45 | Commands: 46 | Left-Click: 47 | - 'player: kp kit Archer' 48 | Right-Click: 49 | - 'player: kp preview Archer' 50 | 12: 51 | Name: '&a&lTank Kit' 52 | Material: DIAMOND 53 | Lore: 54 | - '&6Ability: &7Rechargeable Speed Boost' 55 | - ' ' 56 | - '&7- Iron Sword' 57 | - '&7- Diamond Helmet' 58 | - '&7- Diamond Chestplate' 59 | - '&7- Diamond Leggings' 60 | - '&7- Diamond Boots' 61 | - ' ' 62 | - '&eLeft-click to select.' 63 | - '&eRight-click to preview.' 64 | Commands: 65 | Left-Click: 66 | - 'player: kp kit Tank' 67 | Right-Click: 68 | - 'player: kp preview Tank' 69 | 13: 70 | Name: '&a&lSoldier Kit' 71 | Material: ARROW 72 | Lore: 73 | - '&6Ability: &7Gun with 5 ammo' 74 | - ' ' 75 | - '&7- Stone Sword' 76 | - '&7- Bow' 77 | - '&7- 32 Arrows' 78 | - '&7- Fishing Rod' 79 | - '&7- Leather Helmet' 80 | - '&7- Chain Chestplate' 81 | - '&7- Leather Leggings' 82 | - '&7- Leather Boots' 83 | - ' ' 84 | - '&eLeft-click to select.' 85 | - '&eRight-click to preview.' 86 | Commands: 87 | Left-Click: 88 | - 'player: kp kit Soldier' 89 | Right-Click: 90 | - 'player: kp preview Soldier' 91 | 14: 92 | Name: '&a&lBomber Kit' 93 | Material: TNT 94 | Lore: 95 | - '&6Ability: &73 TNT Trails' 96 | - ' ' 97 | - '&7- Iron Sword' 98 | - '&7- 16 TNT' 99 | - '&7- Leather Helmet' 100 | - '&7- Leather Chestplate' 101 | - '&7- Leather Leggings' 102 | - '&7- Leather Boots' 103 | - ' ' 104 | - '&eLeft-click to select.' 105 | - '&eRight-click to preview.' 106 | Commands: 107 | Left-Click: 108 | - 'player: kp kit Bomber' 109 | Right-Click: 110 | - 'player: kp preview Bomber' 111 | 15: 112 | Name: '&a&lKangaroo Kit' 113 | Material: SADDLE 114 | Lore: 115 | - '&6Ability: &73 Launchers' 116 | - ' ' 117 | - '&7- Iron Sword' 118 | - '&7- Leather Helmet' 119 | - '&7- Leather Chestplate' 120 | - '&7- Leather Leggings' 121 | - '&7- Leather Boots' 122 | - ' ' 123 | - '&eLeft-click to select.' 124 | - '&eRight-click to preview.' 125 | Commands: 126 | Left-Click: 127 | - 'player: kp kit Kangaroo' 128 | Right-Click: 129 | - 'player: kp preview Kangaroo' 130 | 16: 131 | Name: '&a&lWarper Kit' 132 | Material: ENDER_PEARL 133 | Lore: 134 | - '&6Ability: &73 Teleporters' 135 | - ' ' 136 | - '&7- Iron Sword' 137 | - '&7- 4 Ender Pearls' 138 | - '&7- Leather Helmet' 139 | - '&7- Leather Chestplate' 140 | - '&7- Leather Leggings' 141 | - '&7- Leather Boots' 142 | - ' ' 143 | - '&eLeft-click to select.' 144 | - '&eRight-click to preview.' 145 | Commands: 146 | Left-Click: 147 | - 'player: kp kit Warper' 148 | Right-Click: 149 | - 'player: kp preview Warper' 150 | 19: 151 | Name: '&a&lWitch Kit' 152 | Material: BREWING_STAND 153 | Slot: 19 154 | Lore: 155 | - '&6Ability: &7Infinite Potions' 156 | - ' ' 157 | - '&7- Iron Sword' 158 | - '&7- Leather Helmet' 159 | - '&7- Leather Chestplate' 160 | - '&7- Leather Leggings' 161 | - '&7- Leather Boots' 162 | - ' ' 163 | - '&eLeft-click to select.' 164 | - '&eRight-click to preview.' 165 | Commands: 166 | Left-Click: 167 | - 'player: kp kit Witch' 168 | Right-Click: 169 | - 'player: kp preview Witch' 170 | 20: 171 | Name: '&a&lNinja Kit' 172 | Material: NETHER_STAR 173 | Lore: 174 | - '&6Ability: &73 Vanish Stars' 175 | - ' ' 176 | - '&7- Wooden Sword' 177 | - '&7- Leather Helmet' 178 | - '&7- Chain Chestplate' 179 | - '&7- Chain Leggings' 180 | - '&7- Chain Boots' 181 | - ' ' 182 | - '&eLeft-click to select.' 183 | - '&eRight-click to preview.' 184 | Commands: 185 | Left-Click: 186 | - 'player: kp kit Ninja' 187 | Right-Click: 188 | - 'player: kp preview Ninja' 189 | 21: 190 | Name: '&a&lThunderbolt Kit' 191 | Material: BLAZE_POWDER 192 | Lore: 193 | - '&6Ability: &73 Lightning Strikes' 194 | - ' ' 195 | - '&7- Golden Sword' 196 | - '&7- Leather Helmet' 197 | - '&7- Golden Chestplate' 198 | - '&7- Golden Leggings' 199 | - '&7- Golden Boots' 200 | - ' ' 201 | - '&eLeft-click to select.' 202 | - '&eRight-click to preview.' 203 | Commands: 204 | Left-Click: 205 | - 'player: kp kit Thunderbolt' 206 | Right-Click: 207 | - 'player: kp preview Thunderbolt' 208 | 22: 209 | Name: '&a&lVampire Kit' 210 | Material: FERMENTED_SPIDER_EYE 211 | Lore: 212 | - '&6Ability: &73 Blood Suckers' 213 | - ' ' 214 | - '&7- Iron Sword' 215 | - '&7- Leather Helmet' 216 | - '&7- Leather Chestplate' 217 | - '&7- Leather Leggings' 218 | - '&7- Leather Boots' 219 | - ' ' 220 | - '&eLeft-click to select.' 221 | - '&eRight-click to preview.' 222 | Commands: 223 | Left-Click: 224 | - 'player: kp kit Vampire' 225 | Right-Click: 226 | - 'player: kp preview Vampire' 227 | 23: 228 | Name: '&a&lRhino Kit' 229 | Material: DIAMOND_HELMET 230 | Lore: 231 | - '&6Ability: &7Rechargeable Rhino Charge' 232 | - ' ' 233 | - '&7- Iron Sword' 234 | - '&7- Diamond Helmet' 235 | - '&7- Leather Chestplate' 236 | - '&7- Leather Leggings' 237 | - '&7- Leather Boots' 238 | - ' ' 239 | - '&eLeft-click to select.' 240 | - '&eRight-click to preview.' 241 | Commands: 242 | Left-Click: 243 | - 'player: kp kit Rhino' 244 | Right-Click: 245 | - 'player: kp preview Rhino' 246 | 24: 247 | Name: '&a&lTrickster Kit' 248 | Material: EGG 249 | Lore: 250 | - '&6Ability: &74 Switcher Pellets' 251 | - ' ' 252 | - '&7- Stone Sword' 253 | - '&7- Leather Helmet' 254 | - '&7- Diamond Chestplate' 255 | - '&7- Leather Leggings' 256 | - '&7- Leather Boots' 257 | - ' ' 258 | - '&eLeft-click to select.' 259 | - '&eRight-click to preview.' 260 | Commands: 261 | Left-Click: 262 | - 'player: kp kit Trickster' 263 | Right-Click: 264 | - 'player: kp preview Trickster' 265 | 25: 266 | Name: '&a&lExample Kit' 267 | Material: WOOD_SWORD 268 | Lore: 269 | - '&7This is the example of a custom' 270 | - '&7kit you can create using KitPvP.' 271 | - '&7You can make a custom kit using your' 272 | - '&7own inventory, potion effects, and enchantments' 273 | - '&7using /kp create kitName. Make sure to add it to' 274 | - '&7the menu.yml!' 275 | Commands: 276 | Left-Click: 277 | - 'player: kp kit Example' 278 | Right-Click: 279 | - 'player: kp preview Example' 280 | 40: 281 | Name: '&c&lClose' 282 | Material: BARRIER 283 | Lore: 284 | - '&7Click to close the Kit Menu.' 285 | Commands: [] -------------------------------------------------------------------------------- /src/main/java/com/planetgallium/kitpvp/api/Kit.java: -------------------------------------------------------------------------------- 1 | package com.planetgallium.kitpvp.api; 2 | 3 | import com.planetgallium.kitpvp.item.AttributeWriter; 4 | import com.planetgallium.kitpvp.util.Cooldown; 5 | import com.planetgallium.kitpvp.util.Resource; 6 | import com.planetgallium.kitpvp.util.Toolkit; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.inventory.ItemStack; 10 | import org.bukkit.potion.PotionEffect; 11 | import org.bukkit.potion.PotionEffectType; 12 | 13 | import java.util.ArrayList; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | public class Kit { 19 | 20 | private final String name; 21 | private String permission; 22 | private Cooldown cooldown; 23 | private int level; 24 | private int maxHealth; 25 | 26 | private final Map options; 27 | private final Map inventory; 28 | private final List effects; 29 | 30 | private ItemStack kitHelmet; 31 | private ItemStack kitChestplate; 32 | private ItemStack kitLeggings; 33 | private ItemStack kitBoots; 34 | private ItemStack offhand; 35 | private ItemStack fill; 36 | 37 | public Kit(String name) { 38 | this.name = name; 39 | this.options = new HashMap<>(); 40 | this.inventory = new HashMap<>(); 41 | this.effects = new ArrayList<>(); 42 | } 43 | 44 | public void setPermission(String permission) { 45 | this.permission = permission; 46 | } 47 | 48 | public void setCooldown(Cooldown cooldown) { 49 | this.cooldown = cooldown; 50 | } 51 | 52 | public void setLevel(int level) { 53 | this.level = level; 54 | } 55 | 56 | public void setMaxHealth(int health) { 57 | this.maxHealth = health; 58 | } 59 | 60 | public void setOption(String key, Object value) { 61 | // NOTE: using this strategy to pass data rather than using Resources class so 62 | // kit class can be used externally without needing access to Resources 63 | this.options.put(key, value); 64 | } 65 | 66 | public void setInventoryItem(int slot, ItemStack item) { 67 | inventory.put(slot, item); 68 | } 69 | 70 | public void addEffect(PotionEffectType type, int amplifierNonZeroBased, int durationSeconds) { 71 | PotionEffect effect = new PotionEffect(type, Toolkit.parsePotionEffectDuration(durationSeconds), 72 | amplifierNonZeroBased - 1); 73 | effects.add(effect); 74 | } 75 | 76 | public void setHelmet(ItemStack helmet) { 77 | this.kitHelmet = helmet; 78 | } 79 | 80 | public void setChestplate(ItemStack chestplate) { 81 | this.kitChestplate = chestplate; 82 | } 83 | 84 | public void setLeggings(ItemStack leggings) { 85 | this.kitLeggings = leggings; 86 | } 87 | 88 | public void setBoots(ItemStack boots) { 89 | this.kitBoots = boots; 90 | } 91 | 92 | public void setOffhand(ItemStack offhand) { 93 | this.offhand = offhand; 94 | } 95 | 96 | public void setFill(ItemStack fill) { 97 | this.fill = fill; 98 | } 99 | 100 | public void apply(Player player) { 101 | List overflowItems = new ArrayList<>(); 102 | boolean addOverflowItems = (Boolean) options.get("AddOverflowItemsOnKit"); 103 | 104 | if (kitHelmet != null) { 105 | if (player.getInventory().getHelmet() == null) { 106 | player.getInventory().setHelmet(kitHelmet); 107 | } else { 108 | overflowItems.add(kitHelmet); 109 | } 110 | } 111 | 112 | if (kitChestplate != null) { 113 | if (player.getInventory().getChestplate() == null) { 114 | player.getInventory().setChestplate(kitChestplate); 115 | } else { 116 | overflowItems.add(kitChestplate); 117 | } 118 | } 119 | 120 | if (kitLeggings != null) { 121 | if (player.getInventory().getLeggings() == null) { 122 | player.getInventory().setLeggings(kitLeggings); 123 | } else { 124 | overflowItems.add(kitLeggings); 125 | } 126 | } 127 | 128 | if (kitBoots != null) { 129 | if (player.getInventory().getBoots() == null) { 130 | player.getInventory().setBoots(kitBoots); 131 | } else { 132 | overflowItems.add(kitBoots); 133 | } 134 | } 135 | 136 | Toolkit.setMaxHealth(player, maxHealth); 137 | 138 | for (int i = 0; i < 36; i++) { 139 | if (addOverflowItems) { 140 | // if kit wants to put an item in slot i, but slot i in player inventory is already taken 141 | if (inventory.containsKey(i) && player.getInventory().getItem(i) != null) { 142 | overflowItems.add(inventory.get(i)); // add kit item to overflow items 143 | continue; // ignore this kit item, will be accounted for with giveOverflowItems 144 | } 145 | } 146 | 147 | if (inventory.get(i) != null) { 148 | player.getInventory().setItem(i, inventory.get(i)); 149 | } 150 | } 151 | 152 | if (offhand != null && Toolkit.versionToNumber() >= 19) { 153 | player.getInventory().setItemInOffHand(offhand); 154 | } 155 | 156 | if (addOverflowItems) { 157 | giveOverflowItems(player, overflowItems); 158 | } 159 | 160 | if (fill != null) { 161 | for (int i = 0; i < 36; i++) { 162 | if (player.getInventory().getItem(i) == null) { 163 | player.getInventory().setItem(i, fill); 164 | } 165 | } 166 | } 167 | 168 | effects.stream().forEach(effect -> player.addPotionEffect(effect)); 169 | } 170 | 171 | private void giveOverflowItems(Player p, List overflowItems) { 172 | for (int i = 0; i < 36; i++) { 173 | if (p.getInventory().getItem(i) == null) { // if empty slot found 174 | if (overflowItems.size() >= 1) { 175 | p.getInventory().setItem(i, overflowItems.get(0)); 176 | overflowItems.remove(0); 177 | } else { 178 | return; // if no overflow items left, return out of function 179 | } 180 | } 181 | } 182 | 183 | boolean dropRemainingOverflowItems = (Boolean) options.get("DropRemainingOverflowItemsOnKit"); 184 | 185 | if (dropRemainingOverflowItems) { 186 | for (ItemStack remainingOverflowItem : overflowItems) { 187 | p.getWorld().dropItem(p.getLocation(), remainingOverflowItem); 188 | } 189 | String overflowItemsDropMessage = (String) options.get("Message-OverflowItemsDropped"); 190 | p.sendMessage(overflowItemsDropMessage.replace("%number%", String.valueOf(overflowItems.size()))); 191 | } else { 192 | String overflowItemsLostMessage = (String) options.get("Message-OverflowItemsLost"); 193 | p.sendMessage(overflowItemsLostMessage.replace("%number%", String.valueOf(overflowItems.size()))); 194 | } 195 | } 196 | 197 | public void toResource(Resource resource) { 198 | resource.set("Kit.Permission", permission != null ? permission : "kp.kit." + name); 199 | resource.set("Kit.Cooldown", cooldown != null ? cooldown.formatted(true) : 0); 200 | resource.set("Kit.Level", level); 201 | resource.set("Kit.Health", maxHealth); 202 | resource.save(); 203 | 204 | AttributeWriter.itemStackToResource(resource, "Inventory.Armor.Helmet", kitHelmet); 205 | AttributeWriter.itemStackToResource(resource, "Inventory.Armor.Chestplate", kitChestplate); 206 | AttributeWriter.itemStackToResource(resource, "Inventory.Armor.Leggings", kitLeggings); 207 | AttributeWriter.itemStackToResource(resource, "Inventory.Armor.Boots", kitBoots); 208 | 209 | for (Integer slot : inventory.keySet()) { 210 | AttributeWriter.itemStackToResource(resource, "Inventory.Items." + slot, inventory.get(slot)); 211 | } 212 | 213 | AttributeWriter.itemStackToResource(resource, "Inventory.Items.Offhand", offhand); 214 | AttributeWriter.itemStackToResource(resource, "Inventory.Items.Fill", fill); 215 | 216 | for (PotionEffect effect : effects) { 217 | AttributeWriter.potionEffectToResource(resource, "Effects", effect); 218 | } 219 | 220 | resource.save(); 221 | } 222 | 223 | public String getName() { return name; } 224 | 225 | public String getPermission() { return permission; } 226 | 227 | public Cooldown getCooldown() { return cooldown; } 228 | 229 | public int getLevel() { return level; } 230 | 231 | public int getMaxHealth() { return maxHealth; } 232 | 233 | public Map getInventory() { return inventory; } 234 | 235 | public List getEffects() { return effects; } 236 | 237 | public ItemStack getHelmet() { return kitHelmet; } 238 | 239 | public ItemStack getChestplate() { return kitChestplate; } 240 | 241 | public ItemStack getLeggings() { return kitLeggings; } 242 | 243 | public ItemStack getBoots() { return kitBoots; } 244 | 245 | public ItemStack getFill() { return fill; } 246 | 247 | } 248 | --------------------------------------------------------------------------------