Let the PlayerData load before trying to update items on player join

- Fixes a NPE on the players first join with items that need updated
This commit is contained in:
HexedHero 2021-10-26 04:49:05 +00:00
parent 279b008122
commit 6e2fb4c19d
2 changed files with 191 additions and 190 deletions

View File

@ -1,188 +1,188 @@
package net.Indyuce.mmoitems.listener; package net.Indyuce.mmoitems.listener;
import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.NBTItem; import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot; import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.utils.Schedulers; import io.lumine.mythic.utils.Schedulers;
import io.lumine.mythic.utils.events.extra.ArmorEquipEvent; import io.lumine.mythic.utils.events.extra.ArmorEquipEvent;
import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.MMOUtils; import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.ability.Ability.CastingMode; import net.Indyuce.mmoitems.ability.Ability.CastingMode;
import net.Indyuce.mmoitems.api.SoulboundInfo; import net.Indyuce.mmoitems.api.SoulboundInfo;
import net.Indyuce.mmoitems.api.Type; import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.interaction.util.InteractItem; import net.Indyuce.mmoitems.api.interaction.util.InteractItem;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon; import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.player.PlayerData; import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.player.RPGPlayer; import net.Indyuce.mmoitems.api.player.RPGPlayer;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Trident; import org.bukkit.entity.Trident;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.Action; import org.bukkit.event.block.Action;
import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.event.player.*; import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
public class PlayerListener implements Listener { public class PlayerListener implements Listener {
private final Map<Player, ArrayList<ItemStack>> deathItems = new HashMap<>(); private final Map<Player, ArrayList<ItemStack>> deathItems = new HashMap<>();
@EventHandler @EventHandler(priority = EventPriority.NORMAL)
public void loadPlayerData(PlayerJoinEvent event) { public void loadPlayerData(PlayerJoinEvent event) {
MMOItems.plugin.getRecipes().refreshRecipeBook(event.getPlayer()); MMOItems.plugin.getRecipes().refreshRecipeBook(event.getPlayer());
PlayerData.load(event.getPlayer()); PlayerData.load(event.getPlayer());
} }
@EventHandler(priority = EventPriority.HIGH) @EventHandler(priority = EventPriority.HIGH)
public void savePlayerData(PlayerQuitEvent event) { public void savePlayerData(PlayerQuitEvent event) {
PlayerData.get(event.getPlayer()).save(); PlayerData.get(event.getPlayer()).save();
} }
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void castWhenHitAbilities(EntityDamageByEntityEvent event) { public void castWhenHitAbilities(EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof Player) || event.getEntity().hasMetadata("NPC")) if (!(event.getEntity() instanceof Player) || event.getEntity().hasMetadata("NPC"))
return; return;
LivingEntity damager = MMOUtils.getDamager(event); LivingEntity damager = MMOUtils.getDamager(event);
if (damager == null) if (damager == null)
return; return;
Player player = (Player) event.getEntity(); Player player = (Player) event.getEntity();
PlayerData.get(player).castAbilities(damager, CastingMode.WHEN_HIT); PlayerData.get(player).castAbilities(damager, CastingMode.WHEN_HIT);
} }
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void castWhenSneakAbilities(PlayerToggleSneakEvent event) { public void castWhenSneakAbilities(PlayerToggleSneakEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
PlayerData.get(player).castAbilities(null, CastingMode.SNEAK); PlayerData.get(player).castAbilities(null, CastingMode.SNEAK);
} }
@EventHandler(priority = EventPriority.LOW) @EventHandler(priority = EventPriority.LOW)
public void castClickAbilities(PlayerInteractEvent event) { public void castClickAbilities(PlayerInteractEvent event) {
if (event.getAction() == Action.PHYSICAL) if (event.getAction() == Action.PHYSICAL)
return; return;
Player player = event.getPlayer(); Player player = event.getPlayer();
boolean left = event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK; boolean left = event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK;
CastingMode castMode = player.isSneaking() ? (left ? CastingMode.SHIFT_LEFT_CLICK : CastingMode.SHIFT_RIGHT_CLICK) : (left ? CastingMode.LEFT_CLICK : CastingMode.RIGHT_CLICK); CastingMode castMode = player.isSneaking() ? (left ? CastingMode.SHIFT_LEFT_CLICK : CastingMode.SHIFT_RIGHT_CLICK) : (left ? CastingMode.LEFT_CLICK : CastingMode.RIGHT_CLICK);
PlayerData.get(player).castAbilities(null, castMode); PlayerData.get(player).castAbilities(null, castMode);
} }
/* /*
* Prevent players from dropping items which are bound to them with a * Prevent players from dropping items which are bound to them with a
* soulbound. Items are cached inside a map waiting for the player to * soulbound. Items are cached inside a map waiting for the player to
* respawn. If he does not respawn the items are dropped on the ground, this * respawn. If he does not respawn the items are dropped on the ground, this
* way there don't get lost * way there don't get lost
*/ */
@EventHandler(priority = EventPriority.HIGH) @EventHandler(priority = EventPriority.HIGH)
public void onDeath(PlayerDeathEvent event) { public void onDeath(PlayerDeathEvent event) {
if (event.getKeepInventory() || !MMOItems.plugin.getLanguage().keepSoulboundOnDeath) if (event.getKeepInventory() || !MMOItems.plugin.getLanguage().keepSoulboundOnDeath)
return; return;
Player player = event.getEntity(); Player player = event.getEntity();
SoulboundInfo soulboundInfo = new SoulboundInfo(player); SoulboundInfo soulboundInfo = new SoulboundInfo(player);
Iterator<ItemStack> iterator = event.getDrops().iterator(); Iterator<ItemStack> iterator = event.getDrops().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
ItemStack item = iterator.next(); ItemStack item = iterator.next();
NBTItem nbt = NBTItem.get(item); NBTItem nbt = NBTItem.get(item);
if (nbt.hasTag("MMOITEMS_DISABLE_DEATH_DROP") && nbt.getBoolean("MMOITEMS_DISABLE_DEATH_DROP")) { if (nbt.hasTag("MMOITEMS_DISABLE_DEATH_DROP") && nbt.getBoolean("MMOITEMS_DISABLE_DEATH_DROP")) {
iterator.remove(); iterator.remove();
if (!deathItems.containsKey(player)) if (!deathItems.containsKey(player))
deathItems.put(player, new ArrayList<>()); deathItems.put(player, new ArrayList<>());
deathItems.get(player).add(item); deathItems.get(player).add(item);
} }
/* /*
* not a perfect check but it's very sufficient and so we avoid * not a perfect check but it's very sufficient and so we avoid
* using a JsonParser followed by map checkups in the SoulboundData * using a JsonParser followed by map checkups in the SoulboundData
* constructor * constructor
*/ */
else if (nbt.hasTag("MMOITEMS_SOULBOUND") && nbt.getString("MMOITEMS_SOULBOUND").contains(player.getUniqueId().toString())) { else if (nbt.hasTag("MMOITEMS_SOULBOUND") && nbt.getString("MMOITEMS_SOULBOUND").contains(player.getUniqueId().toString())) {
iterator.remove(); iterator.remove();
soulboundInfo.add(item); soulboundInfo.add(item);
} }
} }
if (soulboundInfo.hasItems()) if (soulboundInfo.hasItems())
soulboundInfo.setup(); soulboundInfo.setup();
} }
@EventHandler @EventHandler
public void onRespawn(PlayerRespawnEvent event) { public void onRespawn(PlayerRespawnEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (MMOItems.plugin.getLanguage().keepSoulboundOnDeath) if (MMOItems.plugin.getLanguage().keepSoulboundOnDeath)
SoulboundInfo.read(player); SoulboundInfo.read(player);
if (deathItems.containsKey(player)) { if (deathItems.containsKey(player)) {
Schedulers.sync().runLater(() -> { Schedulers.sync().runLater(() -> {
player.getInventory().addItem(deathItems.get(player).toArray(new ItemStack[0])); player.getInventory().addItem(deathItems.get(player).toArray(new ItemStack[0]));
deathItems.remove(player); deathItems.remove(player);
}, 10); }, 10);
} }
} }
@EventHandler @EventHandler
public void onArmorEquip(ArmorEquipEvent event) { public void onArmorEquip(ArmorEquipEvent event) {
Player p = event.getPlayer(); Player p = event.getPlayer();
RPGPlayer rpgPlayer = PlayerData.get(p.getUniqueId()).getRPG(); RPGPlayer rpgPlayer = PlayerData.get(p.getUniqueId()).getRPG();
NBTItem item = NBTItem.get(event.getNewArmorPiece()); NBTItem item = NBTItem.get(event.getNewArmorPiece());
if (!rpgPlayer.canUse(item, true)) if (!rpgPlayer.canUse(item, true))
event.setCancelled(true); event.setCancelled(true);
} }
/** /**
* This handler listens to ALL trident shootings, including both * This handler listens to ALL trident shootings, including both
* custom tridents from MMOItems AND vanilla tridents, since MMOItems * custom tridents from MMOItems AND vanilla tridents, since MMOItems
* needs to apply on-hit effects like crits, elemental damage... even * needs to apply on-hit effects like crits, elemental damage... even
* if the player is using a vanilla trident. * if the player is using a vanilla trident.
* <p> * <p>
* Fixing commit 6cf6f741 * Fixing commit 6cf6f741
*/ */
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void registerTridents(ProjectileLaunchEvent event) { public void registerTridents(ProjectileLaunchEvent event) {
if (!(event.getEntity() instanceof Trident) || !(event.getEntity().getShooter() instanceof Player)) if (!(event.getEntity() instanceof Trident) || !(event.getEntity().getShooter() instanceof Player))
return; return;
InteractItem item = new InteractItem((Player) event.getEntity().getShooter(), Material.TRIDENT); InteractItem item = new InteractItem((Player) event.getEntity().getShooter(), Material.TRIDENT);
if (!item.hasItem()) if (!item.hasItem())
return; return;
NBTItem nbtItem = MythicLib.plugin.getVersion().getWrapper().getNBTItem(item.getItem()); NBTItem nbtItem = MythicLib.plugin.getVersion().getWrapper().getNBTItem(item.getItem());
Type type = Type.get(nbtItem.getType()); Type type = Type.get(nbtItem.getType());
PlayerData playerData = PlayerData.get((Player) event.getEntity().getShooter()); PlayerData playerData = PlayerData.get((Player) event.getEntity().getShooter());
if (type != null) { if (type != null) {
Weapon weapon = new Weapon(playerData, nbtItem); Weapon weapon = new Weapon(playerData, nbtItem);
if (!weapon.checkItemRequirements() || !weapon.applyWeaponCosts()) { if (!weapon.checkItemRequirements() || !weapon.applyWeaponCosts()) {
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
} }
MMOItems.plugin.getEntities().registerCustomProjectile(nbtItem, playerData.getStats().newTemporary(EquipmentSlot.fromBukkit(item.getSlot())), event.getEntity(), type != null); MMOItems.plugin.getEntities().registerCustomProjectile(nbtItem, playerData.getStats().newTemporary(EquipmentSlot.fromBukkit(item.getSlot())), event.getEntity(), type != null);
} }
/** /**
* Fixes an issue where quickly swapping items in hand just * Fixes an issue where quickly swapping items in hand just
* does not update the player's inventory which can make the * does not update the player's inventory which can make the
* player cast abilities or attacks with not the correct stats * player cast abilities or attacks with not the correct stats
*/ */
@EventHandler @EventHandler
public void registerInventoryUpdates(PlayerSwapHandItemsEvent event) { public void registerInventoryUpdates(PlayerSwapHandItemsEvent event) {
PlayerData.get(event.getPlayer()).updateInventory(); PlayerData.get(event.getPlayer()).updateInventory();
} }
} }

View File

@ -14,6 +14,7 @@ import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
@ -56,7 +57,7 @@ public class UpdaterManager implements Listener {
/** /**
* Updates a player inventory when joining * Updates a player inventory when joining
*/ */
@EventHandler @EventHandler(priority = EventPriority.HIGH)
public void updateOnJoin(PlayerJoinEvent event) { public void updateOnJoin(PlayerJoinEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
@ -183,4 +184,4 @@ public class UpdaterManager implements Listener {
return name().toLowerCase().replace("_", "-").substring(5); return name().toLowerCase().replace("_", "-").substring(5);
} }
} }
} }