PLayer data now loaded async on player join

This commit is contained in:
Jules 2021-07-25 15:06:07 +02:00
parent 4da75c0864
commit 9cbc951fad
13 changed files with 1226 additions and 1115 deletions

12
pom.xml
View File

@ -172,7 +172,7 @@
<!-- Local repo --> <!-- Local repo -->
<dependency> <dependency>
<groupId>net.Indyuce.mmocore.lib</groupId> <groupId>com.bekvon.bukkit.residence</groupId>
<artifactId>Residence</artifactId> <artifactId>Residence</artifactId>
<version>4.8.7.2</version> <version>4.8.7.2</version>
<scope>system</scope> <scope>system</scope>
@ -180,7 +180,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.Indyuce.mmocore.lib</groupId> <groupId>com.Zrips.CMI</groupId>
<artifactId>CMI</artifactId> <artifactId>CMI</artifactId>
<version>8.6.5.0</version> <version>8.6.5.0</version>
<scope>system</scope> <scope>system</scope>
@ -188,7 +188,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.Indyuce.mmocore.lib</groupId> <groupId>com.sainttx.holograms</groupId>
<artifactId>Holograms</artifactId> <artifactId>Holograms</artifactId>
<version>2.9.1</version> <version>2.9.1</version>
<scope>system</scope> <scope>system</scope>
@ -196,7 +196,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.Indyuce.mmocore.lib</groupId> <groupId>com.gmail.filoghost</groupId>
<artifactId>HolographicDisplays</artifactId> <artifactId>HolographicDisplays</artifactId>
<version>2.4.6</version> <version>2.4.6</version>
<scope>system</scope> <scope>system</scope>
@ -204,7 +204,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.Indyuce.mmocore.lib</groupId> <groupId>net.citizensnpcs</groupId>
<artifactId>Citizens</artifactId> <artifactId>Citizens</artifactId>
<version>2.0.25</version> <version>2.0.25</version>
<scope>system</scope> <scope>system</scope>
@ -212,7 +212,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.Indyuce.mmocore.lib</groupId> <groupId>me.vagdedes.spartan</groupId>
<artifactId>SpartanAPI</artifactId> <artifactId>SpartanAPI</artifactId>
<version>1.0</version> <version>1.0</version>
<scope>system</scope> <scope>system</scope>

View File

@ -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 * the 'respawn' button glitched plus HURT entity effect bug
*/ */
new BukkitRunnable() { new BukkitRunnable() {
@ -240,7 +240,7 @@ public class MMOCore extends LuminePlugin {
}.runTaskTimer(MMOCore.plugin, 100, 20); }.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 * the loot chest manager because it is instanced when the plugin loads
*/ */
new BukkitRunnable() { new BukkitRunnable() {
@ -255,7 +255,7 @@ public class MMOCore extends LuminePlugin {
* Stamina Addon...This should prevent a couple error reports produced by people * Stamina Addon...This should prevent a couple error reports produced by people
* not reading the installation guide... * 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 + "MMOCore is not meant to be used with MMOItems ManaAndStamina");
getLogger().log(Level.SEVERE, ChatColor.DARK_RED + "Please read the installation guide!"); 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"); 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); 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 * that after registering all the professses otherwise the player datas can't
* recognize what profess the player has and professes will be lost * recognize what profess the player has and professes will be lost
*/ */
Bukkit.getOnlinePlayers().forEach(player -> dataProvider.getDataManager().setup(player.getUniqueId())); 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(); dataProvider.getGuildManager().load();
/* // Command
* commands
*/
try { try {
final Field bukkitCommandMap = Bukkit.getServer().getClass().getDeclaredField("commandMap"); final Field bukkitCommandMap = Bukkit.getServer().getClass().getDeclaredField("commandMap");

View File

@ -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;
}
}

View File

@ -1,15 +1,29 @@
package net.Indyuce.mmocore.api.event; package net.Indyuce.mmocore.api.event;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
public class PlayerAttributeUseEvent extends PlayerDataEvent{ public class PlayerAttributeUseEvent extends PlayerDataEvent {
private static final HandlerList handlers = new HandlerList(); 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); super(playerData);
this.attribute = attribute;
} }
public PlayerAttribute getAttribute() {
return attribute;
}
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {

View File

@ -1,30 +1,36 @@
package net.Indyuce.mmocore.api.event; package net.Indyuce.mmocore.api.event;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import net.Indyuce.mmocore.api.player.PlayerData;
public class PlayerCombatEvent extends PlayerDataEvent { 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() { public boolean entersCombat() {
return enter; return enter;
} }
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;
} }
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
} }

View File

@ -1,22 +1,30 @@
package net.Indyuce.mmocore.api.event; package net.Indyuce.mmocore.api.event;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import net.Indyuce.mmocore.api.player.PlayerData; /**
* @deprecated Use {@link AsyncPlayerDataLoadEvent} instead
*/
@Deprecated
public class PlayerDataLoadEvent extends PlayerDataEvent { 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 @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;
} }
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
} }

View File

@ -1,44 +1,48 @@
package net.Indyuce.mmocore.api.event; package net.Indyuce.mmocore.api.event;
import org.bukkit.event.HandlerList;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.skill.Skill.SkillInfo; import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
import net.Indyuce.mmocore.api.skill.SkillResult; import net.Indyuce.mmocore.api.skill.SkillResult;
import org.bukkit.event.HandlerList;
public class PlayerPostCastSkillEvent extends PlayerDataEvent { 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 SkillInfo skill;
private final SkillResult result; private final SkillResult result;
private final boolean successful;
public PlayerPostCastSkillEvent(PlayerData playerData, SkillInfo skill, SkillResult result, boolean successful) { /**
super(playerData); * 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);
this.skill = skill; this.skill = skill;
this.result = result; this.result = result;
this.successful = successful; }
}
public SkillInfo getCast() { public SkillInfo getCast() {
return skill; return skill;
} }
public SkillResult getResult() { public SkillResult getResult() {
return result; return result;
} }
public boolean wasSuccessful() { public boolean wasSuccessful() {
return successful; return result.isSuccessful();
} }
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;
} }
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
} }

View File

@ -1,44 +1,50 @@
package net.Indyuce.mmocore.api.event; 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.player.PlayerData;
import net.Indyuce.mmocore.api.skill.Skill.SkillInfo; 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 { 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); * 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);
this.skill = skill; this.skill = skill;
} }
public SkillInfo getCast() { public SkillInfo getCast() {
return skill; return skill;
} }
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
return cancelled; return cancelled;
} }
@Override @Override
public void setCancelled(boolean value) { public void setCancelled(boolean value) {
cancelled = value; cancelled = value;
} }
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;
} }
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
} }

View File

@ -1,5 +1,7 @@
package net.Indyuce.mmocore.api.loot; package net.Indyuce.mmocore.api.loot;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.manager.SoundManager;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Particle; import org.bukkit.Particle;
@ -9,97 +11,98 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.manager.SoundManager;
public class LootChest { public class LootChest {
private final ChestTier tier; private final ChestTier tier;
private final LootChestRegion region; private final LootChestRegion region;
private final ReplacedBlock block; private final ReplacedBlock block;
private final BukkitRunnable effectRunnable; private final BukkitRunnable effectRunnable;
private final long date = System.currentTimeMillis(); private final long date = System.currentTimeMillis();
/* /**
* instance generated when a loot chest is placed (as a bukkit block), and * Called when a loot chest is placed as a Bukkit block, and used
* used to save the data of the block which has been replaced (can replace * to save the data of the block which has been replaced.
* non-solid blocks) * <p>
*/ * A placed drop chest may only replace non solid blocks like grass
public LootChest(ChestTier tier, LootChestRegion region, Block block) { * or levels..
this.tier = tier; */
this.region = region; public LootChest(ChestTier tier, LootChestRegion region, Block block) {
this.block = new ReplacedBlock(block); this.tier = tier;
this.effectRunnable = tier.hasEffect() ? tier.getEffect().startNewRunnable(block.getLocation().add(.5, .5, .5)) : null; 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() { public ChestTier getTier() {
return tier; return tier;
} }
public ReplacedBlock getBlock() { public ReplacedBlock getBlock() {
return block; return block;
} }
public LootChestRegion getRegion() { public LootChestRegion getRegion() {
return region; return region;
} }
public boolean hasPlayerNearby() { public boolean hasPlayerNearby() {
for (Player player : block.loc.getWorld().getPlayers()) for (Player player : block.loc.getWorld().getPlayers())
if (player.getLocation().distanceSquared(block.loc) < 625) if (player.getLocation().distanceSquared(block.loc) < 625)
return true; return true;
return false; return false;
} }
public boolean shouldExpire() { public boolean shouldExpire() {
return System.currentTimeMillis() - date > MMOCore.plugin.configManager.lootChestExpireTime; 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 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);
if (player) { block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.clone().add(.5, .5, .5), 16, 0, 0, 0, .5);
MMOCore.plugin.soundManager.play(block.loc.getBlock(), SoundManager.SoundEvent.CLOSE_LOOT_CHEST); MMOCore.plugin.lootChests.unregister(this);
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 * Must clean block inventory before replacing block otherwise loots fly
* off and accumulate on the ground (+during dev phase) * off and accumulate on the ground (+during dev phase)
*/ */
else else
((Chest) block.loc.getBlock().getState()).getBlockInventory().clear(); ((Chest) block.loc.getBlock().getState()).getBlockInventory().clear();
block.restore(); block.restore();
if (effectRunnable != null) if (effectRunnable != null)
effectRunnable.cancel(); effectRunnable.cancel();
} }
public static class ReplacedBlock { public static class ReplacedBlock {
private final Material material; private final Material material;
private final BlockData data; private final BlockData data;
private final Location loc; private final Location loc;
public ReplacedBlock(Block block) { public ReplacedBlock(Block block) {
this.material = block.getType(); this.material = block.getType();
this.data = block.getBlockData(); this.data = block.getBlockData();
this.loc = block.getLocation(); this.loc = block.getLocation();
} }
public Location getLocoation() { public Location getLocoation() {
return loc; return loc;
} }
public boolean matches(Location loc) { public boolean matches(Location loc) {
return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getBlockX() == loc.getBlockX() && this.loc.getBlockY() == loc.getBlockY() return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getBlockX() == loc.getBlockX() && this.loc.getBlockY() == loc.getBlockY()
&& this.loc.getBlockZ() == loc.getBlockZ(); && this.loc.getBlockZ() == loc.getBlockZ();
} }
public void restore() { public void restore() {
loc.getBlock().setType(material); loc.getBlock().setType(material);
loc.getBlock().setBlockData(data); loc.getBlock().setBlockData(data);
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@ public class AttributeView extends EditableInventory {
} }
public GeneratedInventory newInventory(PlayerData data) { public GeneratedInventory newInventory(PlayerData data) {
return new SkillViewerInventory(data, this); return new AttributeViewerInventory(data, this);
} }
public static class AttributeItem extends InventoryPlaceholderItem { public static class AttributeItem extends InventoryPlaceholderItem {
@ -74,8 +74,8 @@ public class AttributeView extends EditableInventory {
} }
} }
public class SkillViewerInventory extends GeneratedInventory { public class AttributeViewerInventory extends GeneratedInventory {
public SkillViewerInventory(PlayerData playerData, EditableInventory editable) { public AttributeViewerInventory(PlayerData playerData, EditableInventory editable) {
super(playerData, 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.configManager.getSimpleMessage("attribute-level-up", "attribute", attribute.getName(), "level", "" + ins.getBase()).send(player);
MMOCore.plugin.soundManager.play(getPlayer(), SoundManager.SoundEvent.LEVEL_ATTRIBUTE); 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); Bukkit.getServer().getPluginManager().callEvent(playerAttributeUseEvent);
open(); open();

View File

@ -1,6 +1,11 @@
package net.Indyuce.mmocore.listener; 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.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile; 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.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent; 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; import org.bukkit.scheduler.BukkitRunnable;
public class PlayerListener implements Listener { public class PlayerListener implements Listener {
/* // Player data loading
We load our player data. @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) @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void playerLoadingEvent(PlayerJoinEvent e) { public void d(EntityDamageByEntityEvent event) {
new BukkitRunnable() { if (event.getEntity() instanceof Player && !event.getEntity().hasMetadata("NPC"))
@Override PlayerData.get((Player) event.getEntity()).updateCombat();
public void run() {
MMOCore.plugin.dataProvider.getDataManager().setup(e.getPlayer().getUniqueId());
}
}.runTaskAsynchronously(MMOCore.plugin);
}
/* if (event.getDamager() instanceof Player && !event.getDamager().hasMetadata("NPC"))
* custom inventories register PlayerData.get((Player) event.getDamager()).updateCombat();
*/
@EventHandler
public void b(InventoryClickEvent event) {
if (event.getInventory().getHolder() instanceof PluginInventory)
((PluginInventory) event.getInventory().getHolder()).whenClicked(event);
}
@EventHandler if (event.getDamager() instanceof Projectile && ((Projectile) event.getDamager()).getShooter() instanceof Player)
public void c(InventoryCloseEvent event) { if (!((Player) ((Projectile) event.getDamager()).getShooter()).hasMetadata("NPC"))
if (event.getInventory().getHolder() instanceof PluginInventory) PlayerData.get((Player) ((Projectile) event.getDamager()).getShooter()).updateCombat();
((PluginInventory) event.getInventory().getHolder()).whenClosed(event); }
}
/* @EventHandler
* updates the player's combat log data every time he hits an entity, or public void e(PlayerQuitEvent event) {
* gets hit by an entity or a projectile sent by another entity. updates PlayerData playerData = PlayerData.get(event.getPlayer());
* this stuff on LOW level so other plugins can check if the player just if (playerData.hasParty())
* entered combat playerData.getParty().removeMember(playerData);
*/
@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();
if (event.getDamager() instanceof Player && !event.getDamager().hasMetadata("NPC")) MMOCore.plugin.dataProvider.getDataManager().remove(playerData);
PlayerData.get((Player) event.getDamager()).updateCombat(); }
if (event.getDamager() instanceof Projectile && ((Projectile) event.getDamager()).getShooter() instanceof Player) /**
if (!((Player) ((Projectile) event.getDamager()).getShooter()).hasMetadata("NPC")) * Warning: this really is not the best way to interface with MMOCore
PlayerData.get((Player) ((Projectile) event.getDamager()).getShooter()).updateCombat(); * generation. Use instead PlayerRegenResourceEvent to be able to access
} * directly the PlayerData without an extra map lookup.
*/
@EventHandler @Deprecated
public void e(PlayerQuitEvent event) { @EventHandler(priority = EventPriority.HIGH)
PlayerData playerData = PlayerData.get(event.getPlayer()); public void g(PlayerRegenResourceEvent event) {
if (playerData.hasParty()) if (event.getResource() == PlayerResource.HEALTH) {
playerData.getParty().removeMember(playerData); EntityRegainHealthEvent bukkitEvent = new EntityRegainHealthEvent(event.getPlayer(), event.getAmount(), RegainReason.CUSTOM);
Bukkit.getPluginManager().callEvent(bukkitEvent);
MMOCore.plugin.dataProvider.getDataManager().remove(playerData); event.setCancelled(bukkitEvent.isCancelled());
} event.setAmount(bukkitEvent.getAmount());
}
/* }
* 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());
}
}
} }

View File

@ -1,127 +1,168 @@
package net.Indyuce.mmocore.manager.data; package net.Indyuce.mmocore.manager.data;
import java.util.*; import io.lumine.mythic.lib.api.player.MMOPlayerData;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.ConfigurationSection;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.event.AsyncPlayerDataLoadEvent;
import net.Indyuce.mmocore.api.event.PlayerDataLoadEvent; import net.Indyuce.mmocore.api.event.PlayerDataLoadEvent;
import net.Indyuce.mmocore.api.player.OfflinePlayerData; import net.Indyuce.mmocore.api.player.OfflinePlayerData;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import io.lumine.mythic.lib.api.player.MMOPlayerData; import org.apache.commons.lang.Validate;
import org.bukkit.scheduler.BukkitRunnable; 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 { public abstract class PlayerDataManager {
private final static Map<UUID, PlayerData> data = Collections.synchronizedMap(new HashMap<>()); private final static Map<UUID, PlayerData> 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) { public PlayerData get(OfflinePlayer player) {
return get(player.getUniqueId()); 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) { public void remove(UUID uuid) {
data.remove(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.
* <p>
* 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) -> { * Called when a player logs in, loading the player data inside the map.
if (searchData == null) { * <p>
PlayerData playerData = new PlayerData(MMOPlayerData.get(uniqueId)); * 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); // Load player data if it does not exist
playerData.getStats().updateStats(); if (!data.containsKey(uniqueId)) {
PlayerData newData = new PlayerData(MMOPlayerData.get(uniqueId));
// We call the player data load event. TODO: Convert this event to async. // Schedule async data loading
new BukkitRunnable() { Bukkit.getScheduler().runTaskAsynchronously(MMOCore.plugin, () -> {
@Override loadData(newData);
public void run() { newData.getStats().updateStats();
Bukkit.getPluginManager().callEvent(new PlayerDataLoadEvent(playerData)); Bukkit.getPluginManager().callEvent(new AsyncPlayerDataLoadEvent(newData));
} Bukkit.getScheduler().runTask(MMOCore.plugin, () -> Bukkit.getPluginManager().callEvent(new PlayerDataLoadEvent(newData)));
}.runTask(MMOCore.plugin); });
return playerData; // Update data map
} else return searchData; data.put(uniqueId, newData);
}); return newData;
} }
return data.get(uniqueId);
}
public DefaultPlayerData getDefaultData() { public DefaultPlayerData getDefaultData() {
return defaultData; return defaultData;
} }
public void loadDefaultData(ConfigurationSection config) { public void loadDefaultData(ConfigurationSection config) {
defaultData = new DefaultPlayerData(config); defaultData = new DefaultPlayerData(config);
} }
public boolean isLoaded(UUID uuid) { public boolean isLoaded(UUID uuid) {
return data.containsKey(uuid); return data.containsKey(uuid);
} }
public Collection<PlayerData> getLoaded() { public Collection<PlayerData> getLoaded() {
return data.values(); 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 { public static class DefaultPlayerData {
private final int level, classPoints, skillPoints, attributePoints, attrReallocPoints; private final int level, classPoints, skillPoints, attributePoints, attrReallocPoints;
public DefaultPlayerData(ConfigurationSection config) { public DefaultPlayerData(ConfigurationSection config) {
level = config.getInt("level", 1); level = config.getInt("level", 1);
classPoints = config.getInt("class-points"); classPoints = config.getInt("class-points");
skillPoints = config.getInt("skill-points"); skillPoints = config.getInt("skill-points");
attributePoints = config.getInt("attribute-points"); attributePoints = config.getInt("attribute-points");
attrReallocPoints = config.getInt("attribute-realloc-points"); attrReallocPoints = config.getInt("attribute-realloc-points");
} }
public DefaultPlayerData(int level, int classPoints, int skillPoints, int attributePoints, int attrReallocPoints) { public DefaultPlayerData(int level, int classPoints, int skillPoints, int attributePoints, int attrReallocPoints) {
this.level = level; this.level = level;
this.classPoints = classPoints; this.classPoints = classPoints;
this.skillPoints = skillPoints; this.skillPoints = skillPoints;
this.attributePoints = attributePoints; this.attributePoints = attributePoints;
this.attrReallocPoints = attrReallocPoints; this.attrReallocPoints = attrReallocPoints;
} }
public int getLevel() { public int getLevel() {
return level; return level;
} }
public int getSkillPoints() { public int getSkillPoints() {
return skillPoints; return skillPoints;
} }
public int getClassPoints() { public int getClassPoints() {
return classPoints; return classPoints;
} }
public int getAttrReallocPoints() { public int getAttrReallocPoints() {
return attrReallocPoints; return attrReallocPoints;
} }
public int getAttributePoints() { public int getAttributePoints() {
return attributePoints; return attributePoints;
} }
public void apply(PlayerData player) { public void apply(PlayerData player) {
player.setLevel(level); player.setLevel(level);
player.setClassPoints(classPoints); player.setClassPoints(classPoints);
player.setSkillPoints(skillPoints); player.setSkillPoints(skillPoints);
player.setAttributePoints(attributePoints); player.setAttributePoints(attributePoints);
player.setAttributeReallocationPoints(attrReallocPoints); player.setAttributeReallocationPoints(attrReallocPoints);
} }
} }
} }