- net.Indyuce.mmocore.lib
+ me.vagdedes.spartan
SpartanAPI
1.0
system
diff --git a/src/main/java/net/Indyuce/mmocore/MMOCore.java b/src/main/java/net/Indyuce/mmocore/MMOCore.java
index 6705044c..63d35289 100644
--- a/src/main/java/net/Indyuce/mmocore/MMOCore.java
+++ b/src/main/java/net/Indyuce/mmocore/MMOCore.java
@@ -225,7 +225,7 @@ public class MMOCore extends LuminePlugin {
}
/*
- * resource regeneration. must check if entity is dead otherwise regen will make
+ * Resource regeneration. Must check if entity is dead otherwise regen will make
* the 'respawn' button glitched plus HURT entity effect bug
*/
new BukkitRunnable() {
@@ -240,7 +240,7 @@ public class MMOCore extends LuminePlugin {
}.runTaskTimer(MMOCore.plugin, 100, 20);
/*
- * clean active loot chests every 5 minutes. cannot register this runnable in
+ * Clean active loot chests every 5 minutes. Cannot register this runnable in
* the loot chest manager because it is instanced when the plugin loads
*/
new BukkitRunnable() {
@@ -255,7 +255,7 @@ public class MMOCore extends LuminePlugin {
* Stamina Addon...This should prevent a couple error reports produced by people
* not reading the installation guide...
*/
- if (Bukkit.getPluginManager().getPlugin("MMOItemsMana") != null) {
+ if (Bukkit.getPluginManager().getPlugin("MMOMana") != null) {
getLogger().log(Level.SEVERE, ChatColor.DARK_RED + "MMOCore is not meant to be used with MMOItems ManaAndStamina");
getLogger().log(Level.SEVERE, ChatColor.DARK_RED + "Please read the installation guide!");
Bukkit.broadcastMessage(ChatColor.DARK_RED + "[MMOCore] MMOCore is not meant to be used with MMOItems ManaAndStamina");
@@ -297,20 +297,16 @@ public class MMOCore extends LuminePlugin {
Bukkit.getPluginManager().registerEvents(new PlayerCollectStats(), this);
/*
- * initialize player data from all online players. this is very important to do
+ * Initialize player data from all online players. This is very important to do
* that after registering all the professses otherwise the player datas can't
* recognize what profess the player has and professes will be lost
*/
Bukkit.getOnlinePlayers().forEach(player -> dataProvider.getDataManager().setup(player.getUniqueId()));
- /*
- * load guild data after loading player data
- */
+ // load guild data after loading player data
dataProvider.getGuildManager().load();
- /*
- * commands
- */
+ // Command
try {
final Field bukkitCommandMap = Bukkit.getServer().getClass().getDeclaredField("commandMap");
diff --git a/src/main/java/net/Indyuce/mmocore/api/event/AsyncPlayerDataLoadEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/AsyncPlayerDataLoadEvent.java
new file mode 100644
index 00000000..e2ff20fa
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/api/event/AsyncPlayerDataLoadEvent.java
@@ -0,0 +1,27 @@
+package net.Indyuce.mmocore.api.event;
+
+import net.Indyuce.mmocore.api.player.PlayerData;
+import org.bukkit.event.HandlerList;
+
+public class AsyncPlayerDataLoadEvent extends PlayerDataEvent {
+ private static final HandlerList handlers = new HandlerList();
+
+ /**
+ * Called when a player data is being loaded into the game.
+ * This event is called async.
+ *
+ * @param playerData Player data being loaded
+ */
+ public AsyncPlayerDataLoadEvent(PlayerData playerData) {
+ super(playerData);
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/api/event/PlayerAttributeUseEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/PlayerAttributeUseEvent.java
index eb9e63b4..45c53a4b 100644
--- a/src/main/java/net/Indyuce/mmocore/api/event/PlayerAttributeUseEvent.java
+++ b/src/main/java/net/Indyuce/mmocore/api/event/PlayerAttributeUseEvent.java
@@ -1,15 +1,29 @@
package net.Indyuce.mmocore.api.event;
import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import org.bukkit.event.HandlerList;
-public class PlayerAttributeUseEvent extends PlayerDataEvent{
+public class PlayerAttributeUseEvent extends PlayerDataEvent {
private static final HandlerList handlers = new HandlerList();
- public PlayerAttributeUseEvent(PlayerData playerData) {
+ private final PlayerAttribute attribute;
+
+ /**
+ * Called when a player increases an attribute using the attribute viewer GUI
+ *
+ * @param playerData PLayer increasing his attribute
+ * @param attribute Attribute being increased
+ */
+ public PlayerAttributeUseEvent(PlayerData playerData, PlayerAttribute attribute) {
super(playerData);
+
+ this.attribute = attribute;
}
+ public PlayerAttribute getAttribute() {
+ return attribute;
+ }
@Override
public HandlerList getHandlers() {
diff --git a/src/main/java/net/Indyuce/mmocore/api/event/PlayerCombatEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/PlayerCombatEvent.java
index 2f93b885..6bdde032 100644
--- a/src/main/java/net/Indyuce/mmocore/api/event/PlayerCombatEvent.java
+++ b/src/main/java/net/Indyuce/mmocore/api/event/PlayerCombatEvent.java
@@ -1,30 +1,36 @@
package net.Indyuce.mmocore.api.event;
+import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.event.HandlerList;
-import net.Indyuce.mmocore.api.player.PlayerData;
-
public class PlayerCombatEvent extends PlayerDataEvent {
- private static final HandlerList handlers = new HandlerList();
+ private static final HandlerList handlers = new HandlerList();
- private final boolean enter;
+ private final boolean enter;
- public PlayerCombatEvent(PlayerData playerData, boolean enter) {
- super(playerData);
+ /**
+ * Called when a player either enters or leaves combat
+ * by dealing damage to, or being hit by another entity
+ *
+ * @param playerData Player interacting
+ * @param enter If the player is entering combt
+ */
+ public PlayerCombatEvent(PlayerData playerData, boolean enter) {
+ super(playerData);
- this.enter = enter;
- }
+ this.enter = enter;
+ }
- public boolean entersCombat() {
- return enter;
- }
+ public boolean entersCombat() {
+ return enter;
+ }
- @Override
- public HandlerList getHandlers() {
- return handlers;
- }
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
- public static HandlerList getHandlerList() {
- return handlers;
- }
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/api/event/PlayerDataLoadEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/PlayerDataLoadEvent.java
index 69fa797e..96ca55a2 100644
--- a/src/main/java/net/Indyuce/mmocore/api/event/PlayerDataLoadEvent.java
+++ b/src/main/java/net/Indyuce/mmocore/api/event/PlayerDataLoadEvent.java
@@ -1,22 +1,30 @@
package net.Indyuce.mmocore.api.event;
+import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.event.HandlerList;
-import net.Indyuce.mmocore.api.player.PlayerData;
-
+/**
+ * @deprecated Use {@link AsyncPlayerDataLoadEvent} instead
+ */
+@Deprecated
public class PlayerDataLoadEvent extends PlayerDataEvent {
- private static final HandlerList handlers = new HandlerList();
+ private static final HandlerList handlers = new HandlerList();
- public PlayerDataLoadEvent(PlayerData playerData) {
- super(playerData);
- }
+ /**
+ * Called when a player data is being loaded into the game.
+ *
+ * @param playerData Player data being loaded
+ */
+ public PlayerDataLoadEvent(PlayerData playerData) {
+ super(playerData);
+ }
- @Override
- public HandlerList getHandlers() {
- return handlers;
- }
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
- public static HandlerList getHandlerList() {
- return handlers;
- }
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/api/event/PlayerPostCastSkillEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/PlayerPostCastSkillEvent.java
index 88e59905..8270e463 100644
--- a/src/main/java/net/Indyuce/mmocore/api/event/PlayerPostCastSkillEvent.java
+++ b/src/main/java/net/Indyuce/mmocore/api/event/PlayerPostCastSkillEvent.java
@@ -1,44 +1,48 @@
package net.Indyuce.mmocore.api.event;
-import org.bukkit.event.HandlerList;
-
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
import net.Indyuce.mmocore.api.skill.SkillResult;
+import org.bukkit.event.HandlerList;
public class PlayerPostCastSkillEvent extends PlayerDataEvent {
- private static final HandlerList handlers = new HandlerList();
+ private static final HandlerList handlers = new HandlerList();
- private final SkillInfo skill;
- private final SkillResult result;
- private final boolean successful;
+ private final SkillInfo skill;
+ private final SkillResult result;
- public PlayerPostCastSkillEvent(PlayerData playerData, SkillInfo skill, SkillResult result, boolean successful) {
- super(playerData);
-
- this.skill = skill;
- this.result = result;
- this.successful = successful;
- }
+ /**
+ * Called right after a player casts a skill.
+ *
+ * @param playerData Player casting the skill
+ * @param skill Skill being cast
+ * @param result SKill casting result
+ */
+ public PlayerPostCastSkillEvent(PlayerData playerData, SkillInfo skill, SkillResult result) {
+ super(playerData);
- public SkillInfo getCast() {
- return skill;
- }
+ this.skill = skill;
+ this.result = result;
+ }
- public SkillResult getResult() {
- return result;
- }
-
- public boolean wasSuccessful() {
- return successful;
- }
+ public SkillInfo getCast() {
+ return skill;
+ }
- @Override
- public HandlerList getHandlers() {
- return handlers;
- }
+ public SkillResult getResult() {
+ return result;
+ }
- public static HandlerList getHandlerList() {
- return handlers;
- }
+ public boolean wasSuccessful() {
+ return result.isSuccessful();
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/api/event/PlayerPreCastSkillEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/PlayerPreCastSkillEvent.java
index b1665959..19f48876 100644
--- a/src/main/java/net/Indyuce/mmocore/api/event/PlayerPreCastSkillEvent.java
+++ b/src/main/java/net/Indyuce/mmocore/api/event/PlayerPreCastSkillEvent.java
@@ -1,44 +1,50 @@
package net.Indyuce.mmocore.api.event;
-import org.bukkit.event.Cancellable;
-import org.bukkit.event.HandlerList;
-
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
public class PlayerPreCastSkillEvent extends PlayerDataEvent implements Cancellable {
- private static final HandlerList handlers = new HandlerList();
+ private static final HandlerList handlers = new HandlerList();
- private final SkillInfo skill;
+ private final SkillInfo skill;
- private boolean cancelled;
+ private boolean cancelled;
- public PlayerPreCastSkillEvent(PlayerData playerData, SkillInfo skill) {
- super(playerData);
-
- this.skill = skill;
- }
+ /**
+ * Called right before a player casts a skill. This occurs before
+ * checking for mana, stamina costs and ability cooldown.
+ *
+ * @param playerData Player casting the skill
+ * @param skill Skill being cast
+ */
+ public PlayerPreCastSkillEvent(PlayerData playerData, SkillInfo skill) {
+ super(playerData);
- public SkillInfo getCast() {
- return skill;
- }
+ this.skill = skill;
+ }
- @Override
- public boolean isCancelled() {
- return cancelled;
- }
+ public SkillInfo getCast() {
+ return skill;
+ }
- @Override
- public void setCancelled(boolean value) {
- cancelled = value;
- }
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
- @Override
- public HandlerList getHandlers() {
- return handlers;
- }
+ @Override
+ public void setCancelled(boolean value) {
+ cancelled = value;
+ }
- public static HandlerList getHandlerList() {
- return handlers;
- }
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/api/loot/LootChest.java b/src/main/java/net/Indyuce/mmocore/api/loot/LootChest.java
index 4d242d58..ce489cdc 100644
--- a/src/main/java/net/Indyuce/mmocore/api/loot/LootChest.java
+++ b/src/main/java/net/Indyuce/mmocore/api/loot/LootChest.java
@@ -1,5 +1,7 @@
package net.Indyuce.mmocore.api.loot;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.manager.SoundManager;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
@@ -9,97 +11,98 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.manager.SoundManager;
-
public class LootChest {
- private final ChestTier tier;
- private final LootChestRegion region;
- private final ReplacedBlock block;
- private final BukkitRunnable effectRunnable;
- private final long date = System.currentTimeMillis();
+ private final ChestTier tier;
+ private final LootChestRegion region;
+ private final ReplacedBlock block;
+ private final BukkitRunnable effectRunnable;
+ private final long date = System.currentTimeMillis();
- /*
- * instance generated when a loot chest is placed (as a bukkit block), and
- * used to save the data of the block which has been replaced (can replace
- * non-solid blocks)
- */
- public LootChest(ChestTier tier, LootChestRegion region, Block block) {
- this.tier = tier;
- this.region = region;
- this.block = new ReplacedBlock(block);
- this.effectRunnable = tier.hasEffect() ? tier.getEffect().startNewRunnable(block.getLocation().add(.5, .5, .5)) : null;
- }
+ /**
+ * Called when a loot chest is placed as a Bukkit block, and used
+ * to save the data of the block which has been replaced.
+ *
+ * A placed drop chest may only replace non solid blocks like grass
+ * or levels..
+ */
+ public LootChest(ChestTier tier, LootChestRegion region, Block block) {
+ this.tier = tier;
+ this.region = region;
+ this.block = new ReplacedBlock(block);
+ this.effectRunnable = tier.hasEffect() ? tier.getEffect().startNewRunnable(block.getLocation().add(.5, .5, .5)) : null;
+ }
- public ChestTier getTier() {
- return tier;
- }
+ public ChestTier getTier() {
+ return tier;
+ }
- public ReplacedBlock getBlock() {
- return block;
- }
+ public ReplacedBlock getBlock() {
+ return block;
+ }
- public LootChestRegion getRegion() {
- return region;
- }
+ public LootChestRegion getRegion() {
+ return region;
+ }
- public boolean hasPlayerNearby() {
- for (Player player : block.loc.getWorld().getPlayers())
- if (player.getLocation().distanceSquared(block.loc) < 625)
- return true;
- return false;
- }
+ public boolean hasPlayerNearby() {
+ for (Player player : block.loc.getWorld().getPlayers())
+ if (player.getLocation().distanceSquared(block.loc) < 625)
+ return true;
+ return false;
+ }
- public boolean shouldExpire() {
- return System.currentTimeMillis() - date > MMOCore.plugin.configManager.lootChestExpireTime;
- }
+ public boolean shouldExpire() {
+ return System.currentTimeMillis() - date > MMOCore.plugin.configManager.lootChestExpireTime;
+ }
- public void unregister(boolean player) {
+ /**
+ * @param player If a player just the chest. It's set to false
+ * when a loot chest expires or when MMOCore disables.
+ */
+ public void unregister(boolean player) {
- /*
- * if a player is responsible of closing the chest, close it with sound
- */
- if (player) {
- MMOCore.plugin.soundManager.play(block.loc.getBlock(), SoundManager.SoundEvent.CLOSE_LOOT_CHEST);
- block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.clone().add(.5, .5, .5), 16, 0, 0, 0, .5);
- MMOCore.plugin.lootChests.unregister(this);
- }
+ // If a player is responsible of closing the chest, close it with sound
+ if (player) {
+ MMOCore.plugin.soundManager.play(block.loc.getBlock(), SoundManager.SoundEvent.CLOSE_LOOT_CHEST);
+ block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.clone().add(.5, .5, .5), 16, 0, 0, 0, .5);
+ MMOCore.plugin.lootChests.unregister(this);
+ }
- /*
- * must clean block inventory before replacing block otherwise loots fly
- * off and accumulate on the ground (+during dev phase)
- */
- else
- ((Chest) block.loc.getBlock().getState()).getBlockInventory().clear();
+ /*
+ * Must clean block inventory before replacing block otherwise loots fly
+ * off and accumulate on the ground (+during dev phase)
+ */
+ else
+ ((Chest) block.loc.getBlock().getState()).getBlockInventory().clear();
- block.restore();
- if (effectRunnable != null)
- effectRunnable.cancel();
- }
+ block.restore();
+ if (effectRunnable != null)
+ effectRunnable.cancel();
+ }
- public static class ReplacedBlock {
- private final Material material;
- private final BlockData data;
- private final Location loc;
+ public static class ReplacedBlock {
+ private final Material material;
+ private final BlockData data;
+ private final Location loc;
- public ReplacedBlock(Block block) {
- this.material = block.getType();
- this.data = block.getBlockData();
- this.loc = block.getLocation();
- }
+ public ReplacedBlock(Block block) {
+ this.material = block.getType();
+ this.data = block.getBlockData();
+ this.loc = block.getLocation();
+ }
- public Location getLocoation() {
- return loc;
- }
+ public Location getLocoation() {
+ return loc;
+ }
- public boolean matches(Location loc) {
- return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getBlockX() == loc.getBlockX() && this.loc.getBlockY() == loc.getBlockY()
- && this.loc.getBlockZ() == loc.getBlockZ();
- }
+ public boolean matches(Location loc) {
+ return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getBlockX() == loc.getBlockX() && this.loc.getBlockY() == loc.getBlockY()
+ && this.loc.getBlockZ() == loc.getBlockZ();
+ }
- public void restore() {
- loc.getBlock().setType(material);
- loc.getBlock().setBlockData(data);
- }
- }
+ public void restore() {
+ loc.getBlock().setType(material);
+ loc.getBlock().setBlockData(data);
+ }
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
index d366de27..85892f65 100644
--- a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
+++ b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
@@ -43,758 +43,785 @@ import java.util.logging.Level;
public class PlayerData extends OfflinePlayerData {
- /*
- * is updated everytime the player joins the server. it is kept when the
- * player is offline so the plugin can use #isOnline to check if the player
- * is online
- */
- private final MMOPlayerData mmoData;
-
- /*
- * 'profess' can be null, you need to retrieve the player class using the
- * getProfess() method which should never return null if the plugin is
- * configured right
- */
- private PlayerClass profess;
- private int level, experience, classPoints, skillPoints, attributePoints, attributeReallocationPoints;// skillReallocationPoints,
- private double mana, stamina, stellium;
- private Party party;
- private Guild guild;
-
- private final PlayerQuests questData;
- private final PlayerStats playerStats;
- private final List friends = new ArrayList<>();
- private final Set waypoints = new HashSet<>();
- private final Map skills = new HashMap<>();
- private final List boundSkills = new ArrayList<>();
- private final PlayerProfessions collectSkills = new PlayerProfessions(this);
- private final PlayerSkillData skillData = new PlayerSkillData(this);
- private final PlayerAttributes attributes = new PlayerAttributes(this);
- private final Map classSlots = new HashMap<>();
-
- private long lastWaypoint, lastFriendRequest, actionBarTimeOut, lastLootChest;
-
- /*
- * NON-FINAL player data stuff made public to facilitate field change
- */
- public int skillGuiDisplayOffset;
- public SkillCasting skillCasting;
- public boolean nocd;
- public CombatRunnable combat;
-
- private boolean fullyLoaded = false;
-
- public PlayerData(MMOPlayerData mmoData) {
- super(mmoData.getUniqueId());
-
- this.mmoData = mmoData;
- this.playerStats = new PlayerStats(this);
- this.questData = new PlayerQuests(this);
- }
-
- /*
- * update all references after /mmocore reload so there can be garbage
- * collection with old plugin objects like class or skill instances.
- */
- public void update() {
-
- try {
- profess = profess == null ? null : MMOCore.plugin.classManager.get(profess.getId());
- } catch (NullPointerException exception) {
- MMOCore.log(Level.SEVERE, "[Userdata] Could not find class " + getProfess().getId() + " while refreshing player data.");
- }
-
- int j = 0;
- while (j < boundSkills.size())
- try {
- boundSkills.set(j, getProfess().getSkill(boundSkills.get(j).getSkill()));
- j++;
- } catch (NullPointerException npe1) {
- boundSkills.remove(j);
- try {
- MMOCore.log(Level.SEVERE, "[Userdata] Could not find skill " + boundSkills.get(j).getSkill().getId() + " in class "
- + getProfess().getId() + " while refreshing player data.");
- } catch (NullPointerException npe2) {
- MMOCore.log(Level.SEVERE,
- "[Userdata] Could not find unidentified skill in class " + getProfess().getId() + " while refreshing player data.");
- }
- }
- }
-
- public MMOPlayerData getMMOPlayerData() {
- return mmoData;
- }
-
- public List getFriends() {
- return friends;
- }
-
- public PlayerProfessions getCollectionSkills() {
- return collectSkills;
- }
-
- public PlayerQuests getQuestData() {
- return questData;
- }
-
- public Player getPlayer() {
- return mmoData.getPlayer();
- }
-
- @Override
- public long getLastLogin() {
- return mmoData.getLastLogin();
- }
-
- public long getLastFriendRequest() {
- return lastFriendRequest;
- }
-
- @Override
- public int getLevel() {
- return Math.max(1, level);
- }
-
- public Party getParty() {
- return party;
- }
-
- public boolean hasGuild() {
- return guild != null;
- }
-
- public Guild getGuild() {
- return guild;
- }
-
- public int getClassPoints() {
- return classPoints;
- }
-
- public int getSkillPoints() {
- return skillPoints;
- }
-
- /*
- * returns level up needed in order to level up
- */
- public int getLevelUpExperience() {
- return getProfess().getExpCurve().getExperience(getLevel() + 1);
- }
-
- // public int getSkillReallocationPoints() {
- // return skillReallocationPoints;
- // }
-
- public int getAttributePoints() {
- return attributePoints;
- }
-
- public int getAttributeReallocationPoints() {
- return attributeReallocationPoints;
- }
-
- public boolean isOnline() {
- return mmoData.isOnline();
- }
-
- public boolean hasParty() {
- return party != null;
- }
-
- public boolean inGuild() {
- return guild != null;
- }
-
- // public boolean isOnline() {
- // return player.isOnline();
- // }
-
- public void setLevel(int level) {
- this.level = Math.max(1, level);
- getStats().updateStats();
- }
-
- public void takeLevels(int value) {
- this.level = Math.max(1, level - value);
- getStats().updateStats();
- }
-
- public void giveLevels(int value, EXPSource source) {
- int total = 0;
- while (value-- > 0)
- total += getProfess().getExpCurve().getExperience(getLevel() + value + 1);
- giveExperience(total, source);
- }
-
- public void setExperience(int value) {
- experience = Math.max(0, value);
- refreshVanillaExp();
- }
-
- public void refreshVanillaExp() {
- if (MMOCore.plugin.configManager.overrideVanillaExp) {
- if (!isOnline())
- return;
- getPlayer().setLevel(getLevel());
- getPlayer().setExp(Math.max(0, Math.min(1, (float) experience / (float) getLevelUpExperience())));
- }
- }
-
- // public void setSkillReallocationPoints(int value) {
- // skillReallocationPoints = Math.max(0, value);
- // }
-
- public void setAttributePoints(int value) {
- attributePoints = Math.max(0, value);
- }
-
- public void setAttributeReallocationPoints(int value) {
- attributeReallocationPoints = Math.max(0, value);
- }
-
- public void setSkillPoints(int value) {
- skillPoints = Math.max(0, value);
- }
-
- public void setClassPoints(int value) {
- classPoints = Math.max(0, value);
- }
-
- public boolean hasSavedClass(PlayerClass profess) {
- return classSlots.containsKey(profess.getId());
- }
-
- public Set getSavedClasses() {
- return classSlots.keySet();
- }
-
- public SavedClassInformation getClassInfo(PlayerClass profess) {
- return getClassInfo(profess.getId());
- }
-
- public SavedClassInformation getClassInfo(String profess) {
- return classSlots.get(profess);
- }
-
- public void applyClassInfo(PlayerClass profess, SavedClassInformation info) {
- classSlots.put(profess.getId(), info);
- }
-
- public void unloadClassInfo(PlayerClass profess) {
- classSlots.remove(profess.getId());
- }
-
- public Set getWaypoints() {
- return waypoints;
- }
-
- public boolean hasWaypoint(Waypoint waypoint) {
- return waypoint.isDefault() || waypoints.contains(waypoint.getId());
- }
-
- public void unlockWaypoint(Waypoint waypoint) {
- waypoints.add(waypoint.getId());
- }
-
- public long getWaypointCooldown() {
- return Math.max(0, lastWaypoint + 5000 - System.currentTimeMillis());
- }
-
- /*
- * handles the per-player loot chest cooldown. that is to reduce the risk of
- * spawning multiple chests in a row around the same player which could
- * break the gameplay
- */
- public boolean canSpawnLootChest() {
- return lastLootChest + MMOCore.plugin.configManager.lootChestPlayerCooldown < System.currentTimeMillis();
- }
-
- public void applyLootChestCooldown() {
- lastLootChest = System.currentTimeMillis();
- }
-
- public void heal(double heal) {
- if (!isOnline())
- return;
- double newest = Math.max(0, Math.min(getPlayer().getHealth() + heal, getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()));
- if (getPlayer().getHealth() == newest)
- return;
-
- PlayerRegenResourceEvent event = new PlayerRegenResourceEvent(this, PlayerResource.HEALTH, heal);
- Bukkit.getPluginManager().callEvent(event);
- if (event.isCancelled())
- return;
-
- getPlayer().setHealth(newest);
- }
-
- public void addFriend(UUID uuid) {
- friends.add(uuid);
- }
-
- @Override
- public void removeFriend(UUID uuid) {
- friends.remove(uuid);
- }
-
- @Override
- public boolean hasFriend(UUID uuid) {
- return friends.contains(uuid);
- }
-
- public void setParty(Party party) {
- this.party = party;
- }
-
- public void setGuild(Guild guild) {
- this.guild = guild;
- }
-
- public void log(Level level, String message) {
- MMOCore.plugin.getLogger().log(level, "[Userdata:" + (isOnline() ? getPlayer().getName() : "Offline Player") + "] " + message);
- }
-
- public void setLastFriendRequest(long ms) {
- lastFriendRequest = Math.max(0, ms);
- }
-
- public void sendFriendRequest(PlayerData target) {
- if (!isOnline() || !target.isOnline())
- return;
- setLastFriendRequest(System.currentTimeMillis());
-
- FriendRequest request = new FriendRequest(this, target);
- new ConfigMessage("friend-request").addPlaceholders("player", getPlayer().getName(), "uuid", request.getUniqueId().toString())
- .sendAsJSon(target.getPlayer());
- MMOCore.plugin.requestManager.registerRequest(request);
- }
-
- public void warp(Waypoint waypoint) {
-
- /*
- * this cooldown is only used internally to make sure the player is not
- * spamming waypoints. there is no need to reset it when resetting the
- * player waypoints data
- */
- lastWaypoint = System.currentTimeMillis();
-
- giveStellium(-waypoint.getStelliumCost());
-
- if (!isOnline())
- return;
- new BukkitRunnable() {
- final int x = getPlayer().getLocation().getBlockX();
- final int y = getPlayer().getLocation().getBlockY();
- final int z = getPlayer().getLocation().getBlockZ();
- int t;
-
- public void run() {
- if (!isOnline())
- return;
- if (getPlayer().getLocation().getBlockX() != x || getPlayer().getLocation().getBlockY() != y
- || getPlayer().getLocation().getBlockZ() != z) {
- MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.WARP_CANCELLED);
- MMOCore.plugin.configManager.getSimpleMessage("warping-canceled").send(getPlayer());
- giveStellium(waypoint.getStelliumCost());
- cancel();
- return;
- }
-
- MMOCore.plugin.configManager.getSimpleMessage("warping-comencing", "left", "" + ((120 - t) / 20)).send(getPlayer());
- if (t++ >= 100) {
- getPlayer().teleport(waypoint.getLocation());
- getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 1, false, false));
- MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.WARP_TELEPORT);
- cancel();
- return;
- }
-
- MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.WARP_CHARGE, 1, (float) (t / Math.PI * .015 + .5));
- double r = Math.sin((double) t / 100 * Math.PI);
- for (double j = 0; j < Math.PI * 2; j += Math.PI / 4)
- getPlayer().getLocation().getWorld().spawnParticle(Particle.REDSTONE,
- getPlayer().getLocation().add(Math.cos((double) t / 20 + j) * r, (double) t / 50, Math.sin((double) t / 20 + j) * r), 1,
- new Particle.DustOptions(Color.PURPLE, 1.25f));
- }
- }.runTaskTimer(MMOCore.plugin, 0, 1);
- }
-
- public boolean hasReachedMaxLevel() {
- return getProfess().getMaxLevel() > 0 && getLevel() >= getProfess().getMaxLevel();
- }
-
- public void giveExperience(int value, EXPSource source) {
- giveExperience(value, source, null);
- }
-
- /**
- * Called when giving experience to a player
- *
- * @param value Experience to give the player
- * @param source How the player earned experience
- * @param hologramLocation Location used to display the hologram. If it's null, no
- * hologram will be displayed
- */
- public void giveExperience(int value, EXPSource source, @Nullable Location hologramLocation) {
- if (hasReachedMaxLevel()) {
- setExperience(0);
- return;
- }
-
- /*
- * Handle experience hologram
- */
- if (hologramLocation != null && isOnline() && MMOCore.plugin.hasHolograms())
- MMOCore.plugin.hologramSupport.displayIndicator(hologramLocation.add(.5, 1.5, .5),
- MMOCore.plugin.configManager.getSimpleMessage("exp-hologram", "exp", "" + value).message(), getPlayer());
-
- value = MMOCore.plugin.boosterManager.calculateExp(null, value);
- value *= 1 + getStats().getStat(StatType.ADDITIONAL_EXPERIENCE) / 100;
-
- PlayerExperienceGainEvent event = new PlayerExperienceGainEvent(this, value, source);
- Bukkit.getPluginManager().callEvent(event);
- if (event.isCancelled())
- return;
-
- experience += event.getExperience();
-
- int oldLevel = level, needed;
- while (experience >= (needed = getLevelUpExperience())) {
-
- if (hasReachedMaxLevel()) {
- experience = 0;
- break;
- }
-
- experience -= needed;
- level = getLevel() + 1;
- }
-
- if (level > oldLevel) {
- Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(this, null, oldLevel, level));
- if (isOnline()) {
- new ConfigMessage("level-up").addPlaceholders("level", "" + level).send(getPlayer());
- MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.LEVEL_UP);
- new SmallParticleEffect(getPlayer(), Particle.SPELL_INSTANT);
- }
- getStats().updateStats();
- }
-
- refreshVanillaExp();
- }
-
- public int getExperience() {
- return experience;
- }
-
- @Override
- public PlayerClass getProfess() {
- return profess == null ? MMOCore.plugin.classManager.getDefaultClass() : profess;
- }
-
- public void giveMana(double amount) {
- double newest = Math.max(0, Math.min(getStats().getStat(StatType.MAX_MANA), mana + amount));
- if (mana == newest)
- return;
-
- PlayerRegenResourceEvent event = new PlayerRegenResourceEvent(this, PlayerResource.MANA, amount);
- Bukkit.getPluginManager().callEvent(event);
- if (event.isCancelled())
- return;
-
- mana = newest;
- }
-
- public void giveStamina(double amount) {
- double newest = Math.max(0, Math.min(getStats().getStat(StatType.MAX_STAMINA), stamina + amount));
- if (stamina == newest)
- return;
-
- PlayerRegenResourceEvent event = new PlayerRegenResourceEvent(this, PlayerResource.STAMINA, amount);
- Bukkit.getPluginManager().callEvent(event);
- if (event.isCancelled())
- return;
-
- stamina = newest;
-
- }
-
- public void giveStellium(double amount) {
- double newest = Math.max(0, Math.min(getStats().getStat(StatType.MAX_STELLIUM), stellium + amount));
- if (stellium == newest)
- return;
-
- PlayerRegenResourceEvent event = new PlayerRegenResourceEvent(this, PlayerResource.STELLIUM, amount);
- Bukkit.getPluginManager().callEvent(event);
- if (event.isCancelled())
- return;
-
- stellium = newest;
- }
-
- public double getMana() {
- return mana;
- }
-
- public double getStamina() {
- return stamina;
- }
-
- public double getStellium() {
- return stellium;
- }
-
- public PlayerStats getStats() {
- return playerStats;
- }
-
- public PlayerAttributes getAttributes() {
- return attributes;
- }
-
- public void setMana(double amount) {
- mana = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_MANA)));
- }
-
- public void setStamina(double amount) {
- stamina = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_STAMINA)));
- }
-
- public void setStellium(double amount) {
- stellium = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_STELLIUM)));
- }
-
- public boolean isFullyLoaded() {
- return fullyLoaded;
- }
-
- public void setFullyLoaded() {
- this.fullyLoaded = true;
- }
-
- public boolean isCasting() {
- return skillCasting != null;
- }
-
- /*
- * returns if the action bar is not being used to display anything else and
- * if the general info action bar can be displayed
- */
- public boolean canSeeActionBar() {
- return actionBarTimeOut < System.currentTimeMillis();
- }
-
- public void setActionBarTimeOut(long timeOut) {
- actionBarTimeOut = System.currentTimeMillis() + (timeOut * 50);
- }
-
- public void displayActionBar(String message) {
- if (!isOnline())
- return;
- setActionBarTimeOut(MMOCore.plugin.actionBarManager.getTimeOut());
- getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
- }
-
- @Deprecated
- public void setAttribute(PlayerAttribute attribute, int value) {
- setAttribute(attribute.getId(), value);
- }
-
- @Deprecated
- public void setAttribute(String id, int value) {
- attributes.setBaseAttribute(id, value);
- }
-
- @Deprecated
- public Map mapAttributePoints() {
- return getAttributes().mapPoints();
- }
-
- public int getSkillLevel(Skill skill) {
- return skills.getOrDefault(skill.getId(), 1);
- }
-
- public void setSkillLevel(Skill skill, int level) {
- setSkillLevel(skill.getId(), level);
- }
-
- public void setSkillLevel(String skill, int level) {
- skills.put(skill, level);
- }
-
- public void resetSkillLevel(String skill) {
- skills.remove(skill);
- }
-
- /*
- * better use getProfess().findSkill(skill).isPresent()
- */
- @Deprecated
- public boolean hasSkillUnlocked(Skill skill) {
- return getProfess().hasSkill(skill.getId()) && hasSkillUnlocked(getProfess().getSkill(skill.getId()));
- }
-
- /*
- * (bug fix) any skill, when the player has the right level is instantly
- * unlocked, therefore one must NOT check if the player has unlocked the
- * skill by checking if the skills map contains the skill id as key. this
- * only checks if the player has spent any skill point.
- */
- public boolean hasSkillUnlocked(SkillInfo info) {
- return getLevel() >= info.getUnlockLevel();
- }
-
- public Map mapSkillLevels() {
- return new HashMap<>(skills);
- }
-
- public void giveClassPoints(int value) {
- setClassPoints(classPoints + value);
- }
-
- public void giveSkillPoints(int value) {
- setSkillPoints(skillPoints + value);
- }
-
- public void giveAttributePoints(int value) {
- setAttributePoints(attributePoints + value);
- }
-
- // public void giveSkillReallocationPoints(int value) {
- // setSkillReallocationPoints(skillReallocationPoints + value);
- // }
-
- public void giveAttributeReallocationPoints(int value) {
- setAttributeReallocationPoints(attributeReallocationPoints + value);
- }
-
- public PlayerSkillData getSkillData() {
- return skillData;
- }
-
- public void setClass(PlayerClass profess) {
- this.profess = profess;
-
- // for (Iterator iterator = boundSkills.iterator();
- // iterator.hasNext();)
- // if (!getProfess().hasSkill(iterator.next().getSkill()))
- // iterator.remove();
-
- getStats().updateStats();
- }
-
- public boolean hasSkillBound(int slot) {
- return slot < boundSkills.size();
- }
-
- public SkillInfo getBoundSkill(int slot) {
- return slot >= boundSkills.size() ? null : boundSkills.get(slot);
- }
-
- public void setBoundSkill(int slot, SkillInfo skill) {
- if (boundSkills.size() < 6)
- boundSkills.add(skill);
- else
- boundSkills.set(slot, skill);
- }
-
- public void unbindSkill(int slot) {
- boundSkills.remove(slot);
- }
-
- public List getBoundSkills() {
- return boundSkills;
- }
-
- public boolean isInCombat() {
- return combat != null;
- }
-
- public boolean canChooseSubclass() {
- for (Subclass subclass : getProfess().getSubclasses())
- if (getLevel() >= subclass.getLevel())
- return true;
- return false;
- }
-
- public void updateCombat() {
- if (isInCombat())
- combat.update();
- else
- combat = new CombatRunnable(this);
- }
-
- public SkillResult cast(Skill skill) {
- return cast(getProfess().getSkill(skill));
- }
-
- public SkillResult cast(SkillInfo skill) {
-
- PlayerPreCastSkillEvent preEvent = new PlayerPreCastSkillEvent(this, skill);
- Bukkit.getPluginManager().callEvent(preEvent);
- if (preEvent.isCancelled())
- return new SkillResult(this, skill, CancelReason.OTHER);
-
- /*
- * skill, mana stamina aand cooldown requirements are all calculated in
- * the SkillResult instances. this cast(SkillResult) method only applies
- * cooldown, reduces mana and/or stamina and send messages
- */
- SkillResult cast = skill.getSkill().whenCast(this, skill);
- if (!cast.isSuccessful()) {
- if (!skill.getSkill().isPassive() && isOnline()) {
- if (cast.getCancelReason() == CancelReason.LOCKED)
- MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-skill").send(getPlayer());
-
- if (cast.getCancelReason() == CancelReason.MANA)
- MMOCore.plugin.configManager.getSimpleMessage("casting.no-mana").send(getPlayer());
-
- if (cast.getCancelReason() == CancelReason.STAMINA)
- MMOCore.plugin.configManager.getSimpleMessage("casting.no-stamina").send(getPlayer());
-
- if (cast.getCancelReason() == CancelReason.COOLDOWN)
- MMOCore.plugin.configManager.getSimpleMessage("casting.on-cooldown").send(getPlayer());
- }
-
- PlayerPostCastSkillEvent postEvent = new PlayerPostCastSkillEvent(this, skill, cast, false);
- Bukkit.getPluginManager().callEvent(postEvent);
- return cast;
- }
-
- if (!nocd) {
- double flatCooldownReduction = Math.max(0, Math.min(1, getStats().getStat(StatType.COOLDOWN_REDUCTION) / 100));
- flatCooldownReduction *= flatCooldownReduction > 0 ? skill.getModifier("cooldown", getSkillLevel(skill.getSkill())) * 1000 : 0;
-
- skillData.setLastCast(cast.getSkill(), System.currentTimeMillis() - (long) flatCooldownReduction);
- giveMana(-cast.getManaCost());
- giveStamina(-cast.getStaminaCost());
- }
-
- PlayerPostCastSkillEvent postEvent = new PlayerPostCastSkillEvent(this, skill, cast, true);
- Bukkit.getPluginManager().callEvent(postEvent);
- return cast;
- }
-
- @Override
- public int hashCode() {
- return mmoData.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof PlayerData && ((PlayerData) obj).getUniqueId().equals(getUniqueId());
- }
-
- public static PlayerData get(OfflinePlayer player) {
- return get(player.getUniqueId());
- }
-
- public static PlayerData get(UUID uuid) {
- return MMOCore.plugin.dataProvider.getDataManager().get(uuid);
- }
-
- public static Collection getAll() {
- return MMOCore.plugin.dataProvider.getDataManager().getLoaded();
- }
+ /**
+ * Corresponds to the MythicLib player data. It is used to keep
+ * track of the Player instance corresponding to that player data,
+ * as well as other things like the last time the player logged in/out
+ */
+ private final MMOPlayerData mmoData;
+
+ /**
+ * Can be null, the {@link #getProfess()} method will return the
+ * player class, or the default one if this field is null.
+ */
+ @Nullable
+ private PlayerClass profess;
+ private int level, experience, classPoints, skillPoints, attributePoints, attributeReallocationPoints;// skillReallocationPoints,
+ private double mana, stamina, stellium;
+ private Party party;
+ private Guild guild;
+
+ private final PlayerQuests questData;
+ private final PlayerStats playerStats;
+ private final List friends = new ArrayList<>();
+ private final Set waypoints = new HashSet<>();
+ private final Map skills = new HashMap<>();
+ private final List boundSkills = new ArrayList<>();
+ private final PlayerProfessions collectSkills = new PlayerProfessions(this);
+ private final PlayerSkillData skillData = new PlayerSkillData(this);
+ private final PlayerAttributes attributes = new PlayerAttributes(this);
+ private final Map classSlots = new HashMap<>();
+
+ private long lastWaypoint, lastFriendRequest, actionBarTimeOut, lastLootChest;
+
+ // NON-FINAL player data stuff made public to facilitate field change
+ public int skillGuiDisplayOffset;
+ public SkillCasting skillCasting;
+ public boolean nocd;
+ public CombatRunnable combat;
+
+ /**
+ * Player data is stored in the data map before it's actually fully loaded
+ * so that external plugins don't necessarily have to listen to the PlayerDataLoadEvent.
+ */
+ private boolean fullyLoaded = false;
+
+ public PlayerData(MMOPlayerData mmoData) {
+ super(mmoData.getUniqueId());
+
+ this.mmoData = mmoData;
+ this.playerStats = new PlayerStats(this);
+ this.questData = new PlayerQuests(this);
+ }
+
+ /**
+ * Update all references after /mmocore reload so there can be garbage
+ * collection with old plugin objects like class or skill instances.
+ */
+ public void update() {
+
+ try {
+ profess = profess == null ? null : MMOCore.plugin.classManager.get(profess.getId());
+ } catch (NullPointerException exception) {
+ MMOCore.log(Level.SEVERE, "[Userdata] Could not find class " + getProfess().getId() + " while refreshing player data.");
+ }
+
+ int j = 0;
+ while (j < boundSkills.size())
+ try {
+ boundSkills.set(j, getProfess().getSkill(boundSkills.get(j).getSkill()));
+ j++;
+ } catch (NullPointerException npe1) {
+ boundSkills.remove(j);
+ try {
+ MMOCore.log(Level.SEVERE, "[Userdata] Could not find skill " + boundSkills.get(j).getSkill().getId() + " in class "
+ + getProfess().getId() + " while refreshing player data.");
+ } catch (NullPointerException npe2) {
+ MMOCore.log(Level.SEVERE,
+ "[Userdata] Could not find unidentified skill in class " + getProfess().getId() + " while refreshing player data.");
+ }
+ }
+ }
+
+ public MMOPlayerData getMMOPlayerData() {
+ return mmoData;
+ }
+
+ public List getFriends() {
+ return friends;
+ }
+
+ public PlayerProfessions getCollectionSkills() {
+ return collectSkills;
+ }
+
+ public PlayerQuests getQuestData() {
+ return questData;
+ }
+
+ public Player getPlayer() {
+ return mmoData.getPlayer();
+ }
+
+ @Override
+ public long getLastLogin() {
+ return mmoData.getLastLogin();
+ }
+
+ public long getLastFriendRequest() {
+ return lastFriendRequest;
+ }
+
+ @Override
+ public int getLevel() {
+ return Math.max(1, level);
+ }
+
+ public Party getParty() {
+ return party;
+ }
+
+ public boolean hasGuild() {
+ return guild != null;
+ }
+
+ public Guild getGuild() {
+ return guild;
+ }
+
+ public int getClassPoints() {
+ return classPoints;
+ }
+
+ public int getSkillPoints() {
+ return skillPoints;
+ }
+
+ /**
+ * @return Experience needed in order to reach next level
+ */
+ public int getLevelUpExperience() {
+ return getProfess().getExpCurve().getExperience(getLevel() + 1);
+ }
+
+ // public int getSkillReallocationPoints() {
+ // return skillReallocationPoints;
+ // }
+
+ public int getAttributePoints() {
+ return attributePoints;
+ }
+
+ public int getAttributeReallocationPoints() {
+ return attributeReallocationPoints;
+ }
+
+ public boolean isOnline() {
+ return mmoData.isOnline();
+ }
+
+ public boolean hasParty() {
+ return party != null;
+ }
+
+ public boolean inGuild() {
+ return guild != null;
+ }
+
+ public void setLevel(int level) {
+ this.level = Math.max(1, level);
+ getStats().updateStats();
+ }
+
+ public void takeLevels(int value) {
+ this.level = Math.max(1, level - value);
+ getStats().updateStats();
+ }
+
+ public void giveLevels(int value, EXPSource source) {
+ int total = 0;
+ while (value-- > 0)
+ total += getProfess().getExpCurve().getExperience(getLevel() + value + 1);
+ giveExperience(total, source);
+ }
+
+ public void setExperience(int value) {
+ experience = Math.max(0, value);
+ refreshVanillaExp();
+ }
+
+ /**
+ * Class experience can be displayed on the player's exp bar.
+ * This updates the exp bar to display the player class level and exp.
+ */
+ public void refreshVanillaExp() {
+ if (!isOnline() || !MMOCore.plugin.configManager.overrideVanillaExp)
+ return;
+
+ getPlayer().setLevel(getLevel());
+ getPlayer().setExp(Math.max(0, Math.min(1, (float) experience / (float) getLevelUpExperience())));
+ }
+
+ // public void setSkillReallocationPoints(int value) {
+ // skillReallocationPoints = Math.max(0, value);
+ // }
+
+ public void setAttributePoints(int value) {
+ attributePoints = Math.max(0, value);
+ }
+
+ public void setAttributeReallocationPoints(int value) {
+ attributeReallocationPoints = Math.max(0, value);
+ }
+
+ public void setSkillPoints(int value) {
+ skillPoints = Math.max(0, value);
+ }
+
+ public void setClassPoints(int value) {
+ classPoints = Math.max(0, value);
+ }
+
+ public boolean hasSavedClass(PlayerClass profess) {
+ return classSlots.containsKey(profess.getId());
+ }
+
+ public Set getSavedClasses() {
+ return classSlots.keySet();
+ }
+
+ public SavedClassInformation getClassInfo(PlayerClass profess) {
+ return getClassInfo(profess.getId());
+ }
+
+ public SavedClassInformation getClassInfo(String profess) {
+ return classSlots.get(profess);
+ }
+
+ public void applyClassInfo(PlayerClass profess, SavedClassInformation info) {
+ classSlots.put(profess.getId(), info);
+ }
+
+ public void unloadClassInfo(PlayerClass profess) {
+ classSlots.remove(profess.getId());
+ }
+
+ public Set getWaypoints() {
+ return waypoints;
+ }
+
+ public boolean hasWaypoint(Waypoint waypoint) {
+ return waypoint.isDefault() || waypoints.contains(waypoint.getId());
+ }
+
+ public void unlockWaypoint(Waypoint waypoint) {
+ waypoints.add(waypoint.getId());
+ }
+
+ public long getWaypointCooldown() {
+ return Math.max(0, lastWaypoint + 5000 - System.currentTimeMillis());
+ }
+
+ /**
+ * Handles the per-player loot chest cooldown system. That is to
+ * reduce the rik of spawning multiple loot chests around the same
+ * player in a row, which could be game breaking.
+ *
+ * @return If a random chest can spawn around that player
+ */
+ public boolean canSpawnLootChest() {
+ return lastLootChest + MMOCore.plugin.configManager.lootChestPlayerCooldown < System.currentTimeMillis();
+ }
+
+ public void applyLootChestCooldown() {
+ lastLootChest = System.currentTimeMillis();
+ }
+
+ public void heal(double heal) {
+ if (!isOnline())
+ return;
+ double newest = Math.max(0, Math.min(getPlayer().getHealth() + heal, getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()));
+ if (getPlayer().getHealth() == newest)
+ return;
+
+ PlayerRegenResourceEvent event = new PlayerRegenResourceEvent(this, PlayerResource.HEALTH, heal);
+ Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled())
+ return;
+
+ getPlayer().setHealth(newest);
+ }
+
+ public void addFriend(UUID uuid) {
+ friends.add(uuid);
+ }
+
+ @Override
+ public void removeFriend(UUID uuid) {
+ friends.remove(uuid);
+ }
+
+ @Override
+ public boolean hasFriend(UUID uuid) {
+ return friends.contains(uuid);
+ }
+
+ public void setParty(Party party) {
+ this.party = party;
+ }
+
+ public void setGuild(Guild guild) {
+ this.guild = guild;
+ }
+
+ public void log(Level level, String message) {
+ MMOCore.plugin.getLogger().log(level, "[Userdata:" + (isOnline() ? getPlayer().getName() : "Offline Player") + "] " + message);
+ }
+
+ public void setLastFriendRequest(long ms) {
+ lastFriendRequest = Math.max(0, ms);
+ }
+
+ public void sendFriendRequest(PlayerData target) {
+ if (!isOnline() || !target.isOnline())
+ return;
+ setLastFriendRequest(System.currentTimeMillis());
+
+ FriendRequest request = new FriendRequest(this, target);
+ new ConfigMessage("friend-request").addPlaceholders("player", getPlayer().getName(), "uuid", request.getUniqueId().toString())
+ .sendAsJSon(target.getPlayer());
+ MMOCore.plugin.requestManager.registerRequest(request);
+ }
+
+ public void warp(Waypoint waypoint) {
+ if (!isOnline())
+ return;
+
+ /*
+ * This cooldown is only used internally to make sure the player is not
+ * spamming waypoints. There is no need to reset it when resetting the
+ * player waypoints data
+ */
+ lastWaypoint = System.currentTimeMillis();
+
+ giveStellium(-waypoint.getStelliumCost());
+
+ new BukkitRunnable() {
+ final int x = getPlayer().getLocation().getBlockX();
+ final int y = getPlayer().getLocation().getBlockY();
+ final int z = getPlayer().getLocation().getBlockZ();
+ int t;
+
+ public void run() {
+ if (!isOnline())
+ return;
+ if (getPlayer().getLocation().getBlockX() != x || getPlayer().getLocation().getBlockY() != y
+ || getPlayer().getLocation().getBlockZ() != z) {
+ MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.WARP_CANCELLED);
+ MMOCore.plugin.configManager.getSimpleMessage("warping-canceled").send(getPlayer());
+ giveStellium(waypoint.getStelliumCost());
+ cancel();
+ return;
+ }
+
+ MMOCore.plugin.configManager.getSimpleMessage("warping-comencing", "left", "" + ((120 - t) / 20)).send(getPlayer());
+ if (t++ >= 100) {
+ getPlayer().teleport(waypoint.getLocation());
+ getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 1, false, false));
+ MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.WARP_TELEPORT);
+ cancel();
+ return;
+ }
+
+ MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.WARP_CHARGE, 1, (float) (t / Math.PI * .015 + .5));
+ double r = Math.sin((double) t / 100 * Math.PI);
+ for (double j = 0; j < Math.PI * 2; j += Math.PI / 4)
+ getPlayer().getLocation().getWorld().spawnParticle(Particle.REDSTONE,
+ getPlayer().getLocation().add(Math.cos((double) t / 20 + j) * r, (double) t / 50, Math.sin((double) t / 20 + j) * r), 1,
+ new Particle.DustOptions(Color.PURPLE, 1.25f));
+ }
+ }.runTaskTimer(MMOCore.plugin, 0, 1);
+ }
+
+ public boolean hasReachedMaxLevel() {
+ return getProfess().getMaxLevel() > 0 && getLevel() >= getProfess().getMaxLevel();
+ }
+
+ /**
+ * Gives experience without displaying an EXP hologram around the player
+ *
+ * @param value Experience to give the player
+ * @param source How the player earned experience
+ */
+ public void giveExperience(int value, EXPSource source) {
+ giveExperience(value, source, null);
+ }
+
+ /**
+ * Called when giving experience to a player
+ *
+ * @param value Experience to give the player
+ * @param source How the player earned experience
+ * @param hologramLocation Location used to display the hologram. If it's null, no
+ * hologram will be displayed
+ */
+ public void giveExperience(int value, EXPSource source, @Nullable Location hologramLocation) {
+ if (hasReachedMaxLevel()) {
+ setExperience(0);
+ return;
+ }
+
+ // Experience hologram
+ if (hologramLocation != null && isOnline() && MMOCore.plugin.hasHolograms())
+ MMOCore.plugin.hologramSupport.displayIndicator(hologramLocation.add(.5, 1.5, .5),
+ MMOCore.plugin.configManager.getSimpleMessage("exp-hologram", "exp", "" + value).message(), getPlayer());
+
+ value = MMOCore.plugin.boosterManager.calculateExp(null, value);
+ value *= 1 + getStats().getStat(StatType.ADDITIONAL_EXPERIENCE) / 100;
+
+ PlayerExperienceGainEvent event = new PlayerExperienceGainEvent(this, value, source);
+ Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled())
+ return;
+
+ experience += event.getExperience();
+
+ // Calculate the player's next level
+ int oldLevel = level, needed;
+ while (experience >= (needed = getLevelUpExperience())) {
+
+ if (hasReachedMaxLevel()) {
+ experience = 0;
+ break;
+ }
+
+ experience -= needed;
+ level = getLevel() + 1;
+ }
+
+ if (level > oldLevel) {
+ Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(this, null, oldLevel, level));
+ if (isOnline()) {
+ new ConfigMessage("level-up").addPlaceholders("level", "" + level).send(getPlayer());
+ MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.LEVEL_UP);
+ new SmallParticleEffect(getPlayer(), Particle.SPELL_INSTANT);
+ }
+ getStats().updateStats();
+ }
+
+ refreshVanillaExp();
+ }
+
+ public int getExperience() {
+ return experience;
+ }
+
+ @Override
+ public PlayerClass getProfess() {
+ return profess == null ? MMOCore.plugin.classManager.getDefaultClass() : profess;
+ }
+
+ public void giveMana(double amount) {
+ double newest = Math.max(0, Math.min(getStats().getStat(StatType.MAX_MANA), mana + amount));
+ if (mana == newest)
+ return;
+
+ PlayerRegenResourceEvent event = new PlayerRegenResourceEvent(this, PlayerResource.MANA, amount);
+ Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled())
+ return;
+
+ mana = newest;
+ }
+
+ public void giveStamina(double amount) {
+ double newest = Math.max(0, Math.min(getStats().getStat(StatType.MAX_STAMINA), stamina + amount));
+ if (stamina == newest)
+ return;
+
+ PlayerRegenResourceEvent event = new PlayerRegenResourceEvent(this, PlayerResource.STAMINA, amount);
+ Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled())
+ return;
+
+ stamina = newest;
+
+ }
+
+ public void giveStellium(double amount) {
+ double newest = Math.max(0, Math.min(getStats().getStat(StatType.MAX_STELLIUM), stellium + amount));
+ if (stellium == newest)
+ return;
+
+ PlayerRegenResourceEvent event = new PlayerRegenResourceEvent(this, PlayerResource.STELLIUM, amount);
+ Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled())
+ return;
+
+ stellium = newest;
+ }
+
+ public double getMana() {
+ return mana;
+ }
+
+ public double getStamina() {
+ return stamina;
+ }
+
+ public double getStellium() {
+ return stellium;
+ }
+
+ public PlayerStats getStats() {
+ return playerStats;
+ }
+
+ public PlayerAttributes getAttributes() {
+ return attributes;
+ }
+
+ public void setMana(double amount) {
+ mana = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_MANA)));
+ }
+
+ public void setStamina(double amount) {
+ stamina = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_STAMINA)));
+ }
+
+ public void setStellium(double amount) {
+ stellium = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_STELLIUM)));
+ }
+
+ public boolean isFullyLoaded() {
+ return fullyLoaded;
+ }
+
+ public void setFullyLoaded() {
+ this.fullyLoaded = true;
+ }
+
+ public boolean isCasting() {
+ return skillCasting != null;
+ }
+
+ /**
+ * @return If the action bar is not being used to display anything else
+ * i.e if the "general info" action bar can be displayed
+ */
+ public boolean canSeeActionBar() {
+ return actionBarTimeOut < System.currentTimeMillis();
+ }
+
+ /**
+ * @param timeOut Delay during which the general info action bar
+ * will not be displayed to the player
+ */
+ public void setActionBarTimeOut(long timeOut) {
+ actionBarTimeOut = System.currentTimeMillis() + (timeOut * 50);
+ }
+
+ public void displayActionBar(String message) {
+ if (!isOnline())
+ return;
+
+ setActionBarTimeOut(MMOCore.plugin.actionBarManager.getTimeOut());
+ getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
+ }
+
+ @Deprecated
+ public void setAttribute(PlayerAttribute attribute, int value) {
+ setAttribute(attribute.getId(), value);
+ }
+
+ @Deprecated
+ public void setAttribute(String id, int value) {
+ attributes.setBaseAttribute(id, value);
+ }
+
+ @Deprecated
+ public Map mapAttributePoints() {
+ return getAttributes().mapPoints();
+ }
+
+ public int getSkillLevel(Skill skill) {
+ return skills.getOrDefault(skill.getId(), 1);
+ }
+
+ public void setSkillLevel(Skill skill, int level) {
+ setSkillLevel(skill.getId(), level);
+ }
+
+ public void setSkillLevel(String skill, int level) {
+ skills.put(skill, level);
+ }
+
+ public void resetSkillLevel(String skill) {
+ skills.remove(skill);
+ }
+
+ /*
+ * better use getProfess().findSkill(skill).isPresent()
+ */
+ @Deprecated
+ public boolean hasSkillUnlocked(Skill skill) {
+ return getProfess().hasSkill(skill.getId()) && hasSkillUnlocked(getProfess().getSkill(skill.getId()));
+ }
+
+ /**
+ * Checks for the player's level and compares it to the skill unlock level.
+ *
+ * Any skill, when the player has the right level is instantly
+ * unlocked, therefore one must NOT check if the player has unlocked the
+ * skill by checking if the skills map contains the skill id as key. This
+ * only checks if the player has spent any skill point.
+ *
+ * @return If the player unlocked the skill
+ */
+ public boolean hasSkillUnlocked(SkillInfo info) {
+ return getLevel() >= info.getUnlockLevel();
+ }
+
+ public Map mapSkillLevels() {
+ return new HashMap<>(skills);
+ }
+
+ public void giveClassPoints(int value) {
+ setClassPoints(classPoints + value);
+ }
+
+ public void giveSkillPoints(int value) {
+ setSkillPoints(skillPoints + value);
+ }
+
+ public void giveAttributePoints(int value) {
+ setAttributePoints(attributePoints + value);
+ }
+
+ // public void giveSkillReallocationPoints(int value) {
+ // setSkillReallocationPoints(skillReallocationPoints + value);
+ // }
+
+ public void giveAttributeReallocationPoints(int value) {
+ setAttributeReallocationPoints(attributeReallocationPoints + value);
+ }
+
+ public PlayerSkillData getSkillData() {
+ return skillData;
+ }
+
+ public void setClass(PlayerClass profess) {
+ this.profess = profess;
+
+ // for (Iterator iterator = boundSkills.iterator();
+ // iterator.hasNext();)
+ // if (!getProfess().hasSkill(iterator.next().getSkill()))
+ // iterator.remove();
+
+ getStats().updateStats();
+ }
+
+ public boolean hasSkillBound(int slot) {
+ return slot < boundSkills.size();
+ }
+
+ public SkillInfo getBoundSkill(int slot) {
+ return slot >= boundSkills.size() ? null : boundSkills.get(slot);
+ }
+
+ public void setBoundSkill(int slot, SkillInfo skill) {
+ if (boundSkills.size() < 6)
+ boundSkills.add(skill);
+ else
+ boundSkills.set(slot, skill);
+ }
+
+ public void unbindSkill(int slot) {
+ boundSkills.remove(slot);
+ }
+
+ public List getBoundSkills() {
+ return boundSkills;
+ }
+
+ public boolean isInCombat() {
+ return combat != null;
+ }
+
+ /**
+ * Loops through all the subclasses available to the player and
+ * checks if they could potentially upgrade to one of these
+ *
+ * @return If the player can change its current class to
+ * a subclass
+ */
+ public boolean canChooseSubclass() {
+ for (Subclass subclass : getProfess().getSubclasses())
+ if (getLevel() >= subclass.getLevel())
+ return true;
+ return false;
+ }
+
+ /**
+ * Everytime a player does a combat action, like taking
+ * or dealing damage to an entity, this method is called.
+ */
+ public void updateCombat() {
+ if (isInCombat())
+ combat.update();
+ else
+ combat = new CombatRunnable(this);
+ }
+
+ public SkillResult cast(Skill skill) {
+ return cast(getProfess().getSkill(skill));
+ }
+
+ public SkillResult cast(SkillInfo skill) {
+
+ PlayerPreCastSkillEvent preEvent = new PlayerPreCastSkillEvent(this, skill);
+ Bukkit.getPluginManager().callEvent(preEvent);
+ if (preEvent.isCancelled())
+ return new SkillResult(this, skill, CancelReason.OTHER);
+
+ // Check for mana/stamina/cooldown and cast skill
+ SkillResult cast = skill.getSkill().whenCast(this, skill);
+
+ // Send failure messages
+ if (!cast.isSuccessful()) {
+ if (!skill.getSkill().isPassive() && isOnline()) {
+ if (cast.getCancelReason() == CancelReason.LOCKED)
+ MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-skill").send(getPlayer());
+
+ if (cast.getCancelReason() == CancelReason.MANA)
+ MMOCore.plugin.configManager.getSimpleMessage("casting.no-mana").send(getPlayer());
+
+ if (cast.getCancelReason() == CancelReason.STAMINA)
+ MMOCore.plugin.configManager.getSimpleMessage("casting.no-stamina").send(getPlayer());
+
+ if (cast.getCancelReason() == CancelReason.COOLDOWN)
+ MMOCore.plugin.configManager.getSimpleMessage("casting.on-cooldown").send(getPlayer());
+ }
+
+ PlayerPostCastSkillEvent postEvent = new PlayerPostCastSkillEvent(this, skill, cast);
+ Bukkit.getPluginManager().callEvent(postEvent);
+ return cast;
+ }
+
+ // Apply cooldown, mana and stamina costs
+ if (!nocd) {
+ double flatCooldownReduction = Math.max(0, Math.min(1, getStats().getStat(StatType.COOLDOWN_REDUCTION) / 100));
+ flatCooldownReduction *= flatCooldownReduction > 0 ? skill.getModifier("cooldown", getSkillLevel(skill.getSkill())) * 1000 : 0;
+
+ skillData.setLastCast(cast.getSkill(), System.currentTimeMillis() - (long) flatCooldownReduction);
+ giveMana(-cast.getManaCost());
+ giveStamina(-cast.getStaminaCost());
+ }
+
+ PlayerPostCastSkillEvent postEvent = new PlayerPostCastSkillEvent(this, skill, cast);
+ Bukkit.getPluginManager().callEvent(postEvent);
+ return cast;
+ }
+
+ @Override
+ public int hashCode() {
+ return mmoData.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof PlayerData && ((PlayerData) obj).getUniqueId().equals(getUniqueId());
+ }
+
+ public static PlayerData get(OfflinePlayer player) {
+ return get(player.getUniqueId());
+ }
+
+ public static PlayerData get(UUID uuid) {
+ return MMOCore.plugin.dataProvider.getDataManager().get(uuid);
+ }
+
+ public static Collection getAll() {
+ return MMOCore.plugin.dataProvider.getDataManager().getLoaded();
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java b/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java
index 1943a3bb..a4862325 100644
--- a/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java
+++ b/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java
@@ -42,7 +42,7 @@ public class AttributeView extends EditableInventory {
}
public GeneratedInventory newInventory(PlayerData data) {
- return new SkillViewerInventory(data, this);
+ return new AttributeViewerInventory(data, this);
}
public static class AttributeItem extends InventoryPlaceholderItem {
@@ -74,8 +74,8 @@ public class AttributeView extends EditableInventory {
}
}
- public class SkillViewerInventory extends GeneratedInventory {
- public SkillViewerInventory(PlayerData playerData, EditableInventory editable) {
+ public class AttributeViewerInventory extends GeneratedInventory {
+ public AttributeViewerInventory(PlayerData playerData, EditableInventory editable) {
super(playerData, editable);
}
@@ -130,7 +130,7 @@ public class AttributeView extends EditableInventory {
MMOCore.plugin.configManager.getSimpleMessage("attribute-level-up", "attribute", attribute.getName(), "level", "" + ins.getBase()).send(player);
MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.LEVEL_ATTRIBUTE);
- PlayerAttributeUseEvent playerAttributeUseEvent = new PlayerAttributeUseEvent(playerData);
+ PlayerAttributeUseEvent playerAttributeUseEvent = new PlayerAttributeUseEvent(playerData, attribute);
Bukkit.getServer().getPluginManager().callEvent(playerAttributeUseEvent);
open();
diff --git a/src/main/java/net/Indyuce/mmocore/listener/PlayerListener.java b/src/main/java/net/Indyuce/mmocore/listener/PlayerListener.java
index b76518fb..73c5eafc 100644
--- a/src/main/java/net/Indyuce/mmocore/listener/PlayerListener.java
+++ b/src/main/java/net/Indyuce/mmocore/listener/PlayerListener.java
@@ -1,6 +1,11 @@
package net.Indyuce.mmocore.listener;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.event.PlayerRegenResourceEvent;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
+import net.Indyuce.mmocore.gui.api.PluginInventory;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
@@ -12,97 +17,71 @@ import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
-import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.event.PlayerRegenResourceEvent;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
-import net.Indyuce.mmocore.gui.api.PluginInventory;
import org.bukkit.scheduler.BukkitRunnable;
public class PlayerListener implements Listener {
- /*
- We load our player data.
+ // Player data loading
+ @EventHandler(priority = EventPriority.NORMAL)
+ public void playerLoadingEvent(PlayerJoinEvent event) {
+ MMOCore.plugin.dataProvider.getDataManager().setup(event.getPlayer().getUniqueId());
+ }
+
+ // Register custom inventory clicks
+ @EventHandler
+ public void b(InventoryClickEvent event) {
+ if (event.getInventory().getHolder() instanceof PluginInventory)
+ ((PluginInventory) event.getInventory().getHolder()).whenClicked(event);
+ }
+
+ // Register custom inventory close effect
+ @EventHandler
+ public void c(InventoryCloseEvent event) {
+ if (event.getInventory().getHolder() instanceof PluginInventory)
+ ((PluginInventory) event.getInventory().getHolder()).whenClosed(event);
+ }
+
+ /**
+ * Updates the player's combat log data every time he hits an entity, or
+ * gets hit by an entity or a projectile sent by another entity
*/
- @EventHandler(priority = EventPriority.NORMAL)
- public void playerLoadingEvent(PlayerJoinEvent e) {
- new BukkitRunnable() {
- @Override
- public void run() {
- MMOCore.plugin.dataProvider.getDataManager().setup(e.getPlayer().getUniqueId());
- }
- }.runTaskAsynchronously(MMOCore.plugin);
- }
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
+ public void d(EntityDamageByEntityEvent event) {
+ if (event.getEntity() instanceof Player && !event.getEntity().hasMetadata("NPC"))
+ PlayerData.get((Player) event.getEntity()).updateCombat();
- /*
- * custom inventories register
- */
- @EventHandler
- public void b(InventoryClickEvent event) {
- if (event.getInventory().getHolder() instanceof PluginInventory)
- ((PluginInventory) event.getInventory().getHolder()).whenClicked(event);
- }
+ if (event.getDamager() instanceof Player && !event.getDamager().hasMetadata("NPC"))
+ PlayerData.get((Player) event.getDamager()).updateCombat();
- @EventHandler
- public void c(InventoryCloseEvent event) {
- if (event.getInventory().getHolder() instanceof PluginInventory)
- ((PluginInventory) event.getInventory().getHolder()).whenClosed(event);
- }
+ if (event.getDamager() instanceof Projectile && ((Projectile) event.getDamager()).getShooter() instanceof Player)
+ if (!((Player) ((Projectile) event.getDamager()).getShooter()).hasMetadata("NPC"))
+ PlayerData.get((Player) ((Projectile) event.getDamager()).getShooter()).updateCombat();
+ }
- /*
- * updates the player's combat log data every time he hits an entity, or
- * gets hit by an entity or a projectile sent by another entity. updates
- * this stuff on LOW level so other plugins can check if the player just
- * entered combat
- */
- @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
- public void d(EntityDamageByEntityEvent event) {
- if (event.getEntity() instanceof Player && !event.getEntity().hasMetadata("NPC"))
- PlayerData.get((Player) event.getEntity()).updateCombat();
+ @EventHandler
+ public void e(PlayerQuitEvent event) {
+ PlayerData playerData = PlayerData.get(event.getPlayer());
+ if (playerData.hasParty())
+ playerData.getParty().removeMember(playerData);
- if (event.getDamager() instanceof Player && !event.getDamager().hasMetadata("NPC"))
- PlayerData.get((Player) event.getDamager()).updateCombat();
+ MMOCore.plugin.dataProvider.getDataManager().remove(playerData);
+ }
- if (event.getDamager() instanceof Projectile && ((Projectile) event.getDamager()).getShooter() instanceof Player)
- if (!((Player) ((Projectile) event.getDamager()).getShooter()).hasMetadata("NPC"))
- PlayerData.get((Player) ((Projectile) event.getDamager()).getShooter()).updateCombat();
- }
-
- @EventHandler
- public void e(PlayerQuitEvent event) {
- PlayerData playerData = PlayerData.get(event.getPlayer());
- if (playerData.hasParty())
- playerData.getParty().removeMember(playerData);
-
- MMOCore.plugin.dataProvider.getDataManager().remove(playerData);
- }
-
- /*
- * reset skill data when leaving combat
- */
- // @EventHandler
- // public void f(PlayerCombatEvent event) {
- // if (!event.entersCombat())
- // event.getData().getSkillData().resetData();
- // }
-
- /*
- * Warning: this really is not the best way to interface with MMOCore
- * generation. Use instead PlayerRegenResourceEvent to be able to access
- * directly the PlayerData without an extra map lookup.
- */
- @Deprecated
- @EventHandler(priority = EventPriority.HIGH)
- public void g(PlayerRegenResourceEvent event) {
- if (event.getResource() == PlayerResource.HEALTH) {
- EntityRegainHealthEvent bukkitEvent = new EntityRegainHealthEvent(event.getPlayer(), event.getAmount(), RegainReason.CUSTOM);
- Bukkit.getPluginManager().callEvent(bukkitEvent);
- event.setCancelled(bukkitEvent.isCancelled());
- event.setAmount(bukkitEvent.getAmount());
- }
- }
+ /**
+ * Warning: this really is not the best way to interface with MMOCore
+ * generation. Use instead PlayerRegenResourceEvent to be able to access
+ * directly the PlayerData without an extra map lookup.
+ */
+ @Deprecated
+ @EventHandler(priority = EventPriority.HIGH)
+ public void g(PlayerRegenResourceEvent event) {
+ if (event.getResource() == PlayerResource.HEALTH) {
+ EntityRegainHealthEvent bukkitEvent = new EntityRegainHealthEvent(event.getPlayer(), event.getAmount(), RegainReason.CUSTOM);
+ Bukkit.getPluginManager().callEvent(bukkitEvent);
+ event.setCancelled(bukkitEvent.isCancelled());
+ event.setAmount(bukkitEvent.getAmount());
+ }
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/manager/data/PlayerDataManager.java b/src/main/java/net/Indyuce/mmocore/manager/data/PlayerDataManager.java
index 656b0448..607841d0 100644
--- a/src/main/java/net/Indyuce/mmocore/manager/data/PlayerDataManager.java
+++ b/src/main/java/net/Indyuce/mmocore/manager/data/PlayerDataManager.java
@@ -1,127 +1,168 @@
package net.Indyuce.mmocore.manager.data;
-import java.util.*;
-
-import org.bukkit.Bukkit;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.configuration.ConfigurationSection;
-
+import io.lumine.mythic.lib.api.player.MMOPlayerData;
import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.event.AsyncPlayerDataLoadEvent;
import net.Indyuce.mmocore.api.event.PlayerDataLoadEvent;
import net.Indyuce.mmocore.api.player.OfflinePlayerData;
import net.Indyuce.mmocore.api.player.PlayerData;
-import io.lumine.mythic.lib.api.player.MMOPlayerData;
-import org.bukkit.scheduler.BukkitRunnable;
+import org.apache.commons.lang.Validate;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.configuration.ConfigurationSection;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
public abstract class PlayerDataManager {
- private final static Map data = Collections.synchronizedMap(new HashMap<>());
+ private final static Map data = Collections.synchronizedMap(new HashMap<>());
- private DefaultPlayerData defaultData = new DefaultPlayerData(1, 0, 0, 0, 0);
+ private DefaultPlayerData defaultData = new DefaultPlayerData(1, 0, 0, 0, 0);
- public PlayerData get(OfflinePlayer player) {
- return get(player.getUniqueId());
- }
+ public PlayerData get(OfflinePlayer player) {
+ return get(player.getUniqueId());
+ }
- public PlayerData get(UUID uuid) {
- return data.getOrDefault(uuid, setup(uuid));
- }
+ /**
+ * Gets the player data, or throws an exception if not found.
+ * The player data should be loaded when the player logs in
+ * so it's really bad practice to setup the player data if it's not loaded.
+ *
+ * @param uuid Player UUID
+ * @return Player data, if it's loaded
+ */
+ public PlayerData get(UUID uuid) {
+ Validate.isTrue(data.containsKey(uuid), "Player data is not loaded");
+ return data.get(uuid);
+ }
- public void remove(UUID uuid) {
- data.remove(uuid);
- }
+ public void remove(UUID uuid) {
+ data.remove(uuid);
+ }
- public abstract OfflinePlayerData getOffline(UUID uuid);
+ /**
+ * Offline player data is used to handle processes like friend removal
+ * which can still occur if one of the two players is offline.
+ *
+ * Unlike {@link #get(UUID)} this method never returns a null instance
+ *
+ * @param uuid Player unique id
+ * @return Offline player data
+ */
+ @NotNull
+ public abstract OfflinePlayerData getOffline(UUID uuid);
- public PlayerData setup(UUID uniqueId) {
- return data.compute(uniqueId, (uuid, searchData) -> {
- if (searchData == null) {
- PlayerData playerData = new PlayerData(MMOPlayerData.get(uniqueId));
+ /**
+ * Called when a player logs in, loading the player data inside the map.
+ *
+ * For YAML configs or SQL databases, data is loaded as not to overload
+ * the main thread with SQL requests. Therefore, the player data returned
+ * by that method, when the player joined for the first time, is not
+ * fully loaded YET.
+ *
+ * @param uniqueId Player UUID
+ * @return The loaded player data.
+ */
+ public PlayerData setup(UUID uniqueId) {
- loadData(playerData);
- playerData.getStats().updateStats();
+ // Load player data if it does not exist
+ if (!data.containsKey(uniqueId)) {
+ PlayerData newData = new PlayerData(MMOPlayerData.get(uniqueId));
- // We call the player data load event. TODO: Convert this event to async.
- new BukkitRunnable() {
- @Override
- public void run() {
- Bukkit.getPluginManager().callEvent(new PlayerDataLoadEvent(playerData));
- }
- }.runTask(MMOCore.plugin);
+ // Schedule async data loading
+ Bukkit.getScheduler().runTaskAsynchronously(MMOCore.plugin, () -> {
+ loadData(newData);
+ newData.getStats().updateStats();
+ Bukkit.getPluginManager().callEvent(new AsyncPlayerDataLoadEvent(newData));
+ Bukkit.getScheduler().runTask(MMOCore.plugin, () -> Bukkit.getPluginManager().callEvent(new PlayerDataLoadEvent(newData)));
+ });
- return playerData;
- } else return searchData;
+ // Update data map
+ data.put(uniqueId, newData);
- });
- }
+ return newData;
+ }
+ return data.get(uniqueId);
+ }
- public DefaultPlayerData getDefaultData() {
- return defaultData;
- }
+ public DefaultPlayerData getDefaultData() {
+ return defaultData;
+ }
- public void loadDefaultData(ConfigurationSection config) {
- defaultData = new DefaultPlayerData(config);
- }
+ public void loadDefaultData(ConfigurationSection config) {
+ defaultData = new DefaultPlayerData(config);
+ }
- public boolean isLoaded(UUID uuid) {
- return data.containsKey(uuid);
- }
+ public boolean isLoaded(UUID uuid) {
+ return data.containsKey(uuid);
+ }
- public Collection getLoaded() {
- return data.values();
- }
+ public Collection getLoaded() {
+ return data.values();
+ }
- public abstract void loadData(PlayerData data);
+ /**
+ * Called when player data must be loaded from database or config.
+ *
+ * @param data Player data to load
+ */
+ public abstract void loadData(PlayerData data);
- public abstract void saveData(PlayerData data);
+ /**
+ * Called when player data must be saved in configs or database.
+ *
+ * @param data Player data to save
+ */
+ public abstract void saveData(PlayerData data);
- public abstract void remove(PlayerData data);
+ public abstract void remove(PlayerData data);
- public static class DefaultPlayerData {
- private final int level, classPoints, skillPoints, attributePoints, attrReallocPoints;
+ public static class DefaultPlayerData {
+ private final int level, classPoints, skillPoints, attributePoints, attrReallocPoints;
- public DefaultPlayerData(ConfigurationSection config) {
- level = config.getInt("level", 1);
- classPoints = config.getInt("class-points");
- skillPoints = config.getInt("skill-points");
- attributePoints = config.getInt("attribute-points");
- attrReallocPoints = config.getInt("attribute-realloc-points");
- }
+ public DefaultPlayerData(ConfigurationSection config) {
+ level = config.getInt("level", 1);
+ classPoints = config.getInt("class-points");
+ skillPoints = config.getInt("skill-points");
+ attributePoints = config.getInt("attribute-points");
+ attrReallocPoints = config.getInt("attribute-realloc-points");
+ }
- public DefaultPlayerData(int level, int classPoints, int skillPoints, int attributePoints, int attrReallocPoints) {
- this.level = level;
- this.classPoints = classPoints;
- this.skillPoints = skillPoints;
- this.attributePoints = attributePoints;
- this.attrReallocPoints = attrReallocPoints;
- }
+ public DefaultPlayerData(int level, int classPoints, int skillPoints, int attributePoints, int attrReallocPoints) {
+ this.level = level;
+ this.classPoints = classPoints;
+ this.skillPoints = skillPoints;
+ this.attributePoints = attributePoints;
+ this.attrReallocPoints = attrReallocPoints;
+ }
- public int getLevel() {
- return level;
- }
+ public int getLevel() {
+ return level;
+ }
- public int getSkillPoints() {
- return skillPoints;
- }
+ public int getSkillPoints() {
+ return skillPoints;
+ }
- public int getClassPoints() {
- return classPoints;
- }
+ public int getClassPoints() {
+ return classPoints;
+ }
- public int getAttrReallocPoints() {
- return attrReallocPoints;
- }
+ public int getAttrReallocPoints() {
+ return attrReallocPoints;
+ }
- public int getAttributePoints() {
- return attributePoints;
- }
+ public int getAttributePoints() {
+ return attributePoints;
+ }
- public void apply(PlayerData player) {
- player.setLevel(level);
- player.setClassPoints(classPoints);
- player.setSkillPoints(skillPoints);
- player.setAttributePoints(attributePoints);
- player.setAttributeReallocationPoints(attrReallocPoints);
- }
- }
+ public void apply(PlayerData player) {
+ player.setLevel(level);
+ player.setClassPoints(classPoints);
+ player.setSkillPoints(skillPoints);
+ player.setAttributePoints(attributePoints);
+ player.setAttributeReallocationPoints(attrReallocPoints);
+ }
+ }
}