mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2025-01-05 06:57:35 +01:00
Item equip detection, basic stats recalculation & events
This commit is contained in:
parent
4f5192975d
commit
8180ff00cb
@ -1,4 +1,4 @@
|
||||
package net.Indyuce.mmoitems.api.event;
|
||||
package net.Indyuce.mmoitems.api.event.inventory;
|
||||
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
|
||||
@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RefreshInventoryEvent extends Event {
|
||||
public class MMOInventoryRefreshEvent extends Event {
|
||||
|
||||
@NotNull final List<EquippedItem> itemsToEquip;
|
||||
@NotNull public List<EquippedItem> getItemsToEquip() { return itemsToEquip; }
|
||||
@ -27,7 +27,7 @@ public class RefreshInventoryEvent extends Event {
|
||||
@NotNull final Player player;
|
||||
@NotNull final PlayerData playerData;
|
||||
|
||||
public RefreshInventoryEvent(@NotNull List<EquippedItem> itemsToEquip, @NotNull Player player, @NotNull PlayerData playerData) {
|
||||
public MMOInventoryRefreshEvent(@NotNull List<EquippedItem> itemsToEquip, @NotNull Player player, @NotNull PlayerData playerData) {
|
||||
this.itemsToEquip = itemsToEquip;
|
||||
this.player = player;
|
||||
this.playerData = playerData;
|
@ -0,0 +1,42 @@
|
||||
package net.Indyuce.mmoitems.api.event.inventory;
|
||||
|
||||
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class MMOItemEquipEvent extends Event {
|
||||
|
||||
private final int oldHashcode;
|
||||
private final int newHashcode;
|
||||
private final @Nullable EquippedItem oldItem;
|
||||
private final @Nullable EquippedItem newItem;
|
||||
|
||||
public MMOItemEquipEvent(int oldHashcode, int newHashcode, @Nullable EquippedItem oldItem, @Nullable EquippedItem newItem) {
|
||||
this.oldHashcode = oldHashcode;
|
||||
this.newHashcode = newHashcode;
|
||||
this.oldItem = oldItem;
|
||||
this.newItem = newItem;
|
||||
}
|
||||
|
||||
public int getOldHashcode() {
|
||||
return oldHashcode;
|
||||
}
|
||||
|
||||
public int getNewHashcode() {
|
||||
return newHashcode;
|
||||
}
|
||||
|
||||
public @Nullable EquippedItem getOldItem() {
|
||||
return oldItem;
|
||||
}
|
||||
|
||||
public @Nullable EquippedItem getNewItem() {
|
||||
return newItem;
|
||||
}
|
||||
|
||||
@NotNull static final HandlerList handlers = new HandlerList();
|
||||
@NotNull public HandlerList getHandlers() { return handlers; }
|
||||
@NotNull public static HandlerList getHandlerList() { return handlers; }
|
||||
}
|
@ -15,7 +15,7 @@ import net.Indyuce.mmoitems.api.ConfigFile;
|
||||
import net.Indyuce.mmoitems.api.ItemSet;
|
||||
import net.Indyuce.mmoitems.api.ItemSet.SetBonuses;
|
||||
import net.Indyuce.mmoitems.api.crafting.CraftingStatus;
|
||||
import net.Indyuce.mmoitems.api.event.RefreshInventoryEvent;
|
||||
import net.Indyuce.mmoitems.api.event.inventory.MMOInventoryRefreshEvent;
|
||||
import net.Indyuce.mmoitems.api.interaction.Tool;
|
||||
import net.Indyuce.mmoitems.api.item.ItemReference;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
|
||||
@ -212,7 +212,7 @@ public class PlayerData {
|
||||
}
|
||||
|
||||
// Call Bukkit event
|
||||
Bukkit.getPluginManager().callEvent(new RefreshInventoryEvent(inventory.equipped(), getPlayer(), this));
|
||||
Bukkit.getPluginManager().callEvent(new MMOInventoryRefreshEvent(inventory.equipped(), getPlayer(), this));
|
||||
|
||||
for (EquippedItem equipped : inventory.equipped()) {
|
||||
final VolatileMMOItem item = equipped.getCached();
|
||||
@ -355,6 +355,10 @@ public class PlayerData {
|
||||
return permanentEffects.values();
|
||||
}
|
||||
|
||||
public Map<PotionEffectType, PotionEffect> getPermanentPotionEffectsMap() {
|
||||
return permanentEffects;
|
||||
}
|
||||
|
||||
public PlayerStats getStats() {
|
||||
return stats;
|
||||
}
|
||||
@ -406,6 +410,22 @@ public class PlayerData {
|
||||
return mmoData.getCooldownMap().getInfo(ref).getRemaining() / 1000d;
|
||||
}
|
||||
|
||||
public @NotNull Set<ParticleRunnable> getItemParticles() {
|
||||
return itemParticles;
|
||||
}
|
||||
|
||||
public @Nullable ParticleRunnable getOverridingItemParticles() {
|
||||
return overridingItemParticles;
|
||||
}
|
||||
|
||||
public void resetOverridingItemParticles() {
|
||||
overridingItemParticles = null;
|
||||
}
|
||||
|
||||
public @NotNull Set<String> permissions() {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PlayerData get(@NotNull OfflinePlayer player) {
|
||||
return get(player.getUniqueId());
|
||||
|
@ -64,7 +64,7 @@ public class PlayerStats {
|
||||
// The index of the mmoitem stat modifier being added
|
||||
int index = 0;
|
||||
|
||||
for (EquippedItem item : playerData.getInventory().getEquipped()) {
|
||||
for (EquippedItem item : playerData.getInventory().equipped()) {
|
||||
double value = item.getNBT().getStat(stat.getId());
|
||||
|
||||
if (value != 0) {
|
||||
|
@ -64,7 +64,6 @@ public abstract class EquippedItem {
|
||||
* @return If item placement is legal
|
||||
*/
|
||||
public boolean isPlacementLegal() {
|
||||
|
||||
// Vanilla items are ignored
|
||||
final @Nullable String typeFormat = item.getString("MMOITEMS_ITEM_TYPE");
|
||||
if (typeFormat == null)
|
||||
|
@ -1,14 +1,24 @@
|
||||
package net.Indyuce.mmoitems.comp.inventory;
|
||||
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.player.modifier.ModifierSource;
|
||||
import io.lumine.mythic.lib.player.skill.PassiveSkill;
|
||||
import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.event.inventory.MMOItemEquipEvent;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
|
||||
import net.Indyuce.mmoitems.comp.inventory.model.SlotEquippedItem;
|
||||
import net.Indyuce.mmoitems.stat.data.*;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -17,36 +27,182 @@ import java.util.Map;
|
||||
*
|
||||
* @author Roch Blondiaux (Kiwix).
|
||||
*/
|
||||
public class PlayerInventoryUpdater extends BukkitRunnable {
|
||||
public class PlayerInventoryUpdater implements Runnable {
|
||||
|
||||
private final PlayerData data;
|
||||
private final Map<EquipmentSlot, Integer> lastHashCodes = new HashMap<>();
|
||||
private final Map<Integer, Integer> lastHashCodes = new HashMap<>();
|
||||
private final Map<Integer, SlotEquippedItem> CACHE = new HashMap<>();
|
||||
|
||||
private boolean running;
|
||||
|
||||
public PlayerInventoryUpdater(PlayerData data) {
|
||||
this.data = data;
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Current equipment
|
||||
MMOItems.plugin.getInventory().inventory(data.getPlayer())
|
||||
if (!this.running)
|
||||
return;
|
||||
if (!this.data.isOnline()) {
|
||||
this.stop();
|
||||
return;
|
||||
}
|
||||
MMOItems.plugin.getInventory()
|
||||
.inventory(data.getPlayer())
|
||||
.stream()
|
||||
.filter(item -> item instanceof SlotEquippedItem)
|
||||
.map(item -> (SlotEquippedItem) item)
|
||||
.filter(this::needsUpdate)
|
||||
.forEach(equippedItem -> {
|
||||
Bukkit.broadcastMessage("Updating " + equippedItem.getNBT().getItem().getType());
|
||||
.forEach(eItem -> {
|
||||
final int currentHashcode = lastHashCodes.getOrDefault(eItem.getSlotNumber(), -99);
|
||||
final int newHashcode = isEmpty(eItem) ? -1 : eItem.hashCode();
|
||||
final SlotEquippedItem oldItem = CACHE.get(currentHashcode);
|
||||
|
||||
// Call item equip event
|
||||
Bukkit.getPluginManager().callEvent(new MMOItemEquipEvent(currentHashcode, newHashcode, oldItem, eItem));
|
||||
|
||||
// Remove all old item attributes & effects
|
||||
if (oldItem != null && !isEmpty(oldItem)) {
|
||||
final MMOItem mmoItem = oldItem.getCached().clone();
|
||||
|
||||
// Potion effects
|
||||
if (mmoItem.hasData(ItemStats.PERM_EFFECTS))
|
||||
((PotionEffectListData) mmoItem.getData(ItemStats.PERM_EFFECTS))
|
||||
.getEffects()
|
||||
.forEach(effect -> this.data.getPermanentPotionEffectsMap().remove(effect.getType(), effect.toEffect()));
|
||||
|
||||
// Item particles
|
||||
if (mmoItem.hasData(ItemStats.ITEM_PARTICLES)) {
|
||||
ParticleData particleData = (ParticleData) mmoItem.getData(ItemStats.ITEM_PARTICLES);
|
||||
|
||||
if (particleData.getType().hasPriority()) {
|
||||
if (this.data.getOverridingItemParticles() != null
|
||||
&& this.data.getOverridingItemParticles().getParticleData().equals(particleData)) {
|
||||
this.data.getOverridingItemParticles().cancel();
|
||||
this.data.resetOverridingItemParticles();
|
||||
}
|
||||
} else {
|
||||
this.data.getItemParticles()
|
||||
.stream()
|
||||
.filter(particleRunnable -> particleRunnable.getParticleData().equals(particleData))
|
||||
.forEach(BukkitRunnable::cancel);
|
||||
this.data.getItemParticles().removeIf(BukkitRunnable::isCancelled);
|
||||
}
|
||||
}
|
||||
|
||||
// Permissions
|
||||
if (MMOItems.plugin.hasPermissions() && mmoItem.hasData(ItemStats.GRANTED_PERMISSIONS)) {
|
||||
final Permission perms = MMOItems.plugin.getVault().getPermissions();
|
||||
List<String> permissions = new ArrayList<>(((StringListData) mmoItem.getData(ItemStats.GRANTED_PERMISSIONS)).getList());
|
||||
permissions.forEach(s -> {
|
||||
this.data.permissions().remove(s);
|
||||
if (perms.has(this.data.getPlayer(), s))
|
||||
perms.playerRemove(this.data.getPlayer(), s);
|
||||
});
|
||||
}
|
||||
|
||||
// Abilities
|
||||
// TODO: find a solution for that:
|
||||
// Idea 1: cache ability uuid and remove it from the map
|
||||
// if (mmoItem.hasData(ItemStats.ABILITIES)) {
|
||||
// ModifierSource modSource = oldItem.getCached().getType().getModifierSource();
|
||||
// ((AbilityListData) mmoItem.getData(ItemStats.ABILITIES))
|
||||
// .getAbilities()
|
||||
// .forEach(abilityData -> this.data.getMMOPlayerData()
|
||||
// .getPassiveSkillMap()
|
||||
// .getModifiers()
|
||||
// .removeIf(passiveSkill -> passiveSkill.getSource().equals(modSource)
|
||||
// && passiveSkill.getType().equals(abilityData.getTrigger())));
|
||||
// }
|
||||
}
|
||||
|
||||
// Check if the new item is empty
|
||||
if (isEmpty(eItem))
|
||||
return;
|
||||
|
||||
// Check if item is legal
|
||||
if (!eItem.isPlacementLegal() || !this.data.getRPG().canUse(eItem.getNBT(), false, false)) {
|
||||
if (!eItem.isPlacementLegal())
|
||||
MMOItems.log("Illegal item placement detected.");
|
||||
else
|
||||
MMOItems.log("Illegal item usage detected.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache new item hashcode & item
|
||||
cache(eItem);
|
||||
|
||||
// Add item to MMO inventory
|
||||
this.data.getInventory().addItem(eItem);
|
||||
|
||||
// Add all new item attributes & effects
|
||||
final MMOItem mmoItem = eItem.getCached().clone();
|
||||
final EquipmentSlot equipmentSlot = eItem.getSlot();
|
||||
|
||||
// Abilities
|
||||
if (mmoItem.hasData(ItemStats.ABILITIES)) {
|
||||
for (AbilityData abilityData : ((AbilityListData) mmoItem.getData(ItemStats.ABILITIES)).getAbilities()) {
|
||||
ModifierSource modSource = eItem.getCached().getType().getModifierSource();
|
||||
this.data.getMMOPlayerData().getPassiveSkillMap().addModifier(new PassiveSkill("MMOItemsItem", abilityData, equipmentSlot, modSource));
|
||||
}
|
||||
}
|
||||
|
||||
// Modifier application rules
|
||||
final ModifierSource source = mmoItem.getType().getModifierSource();
|
||||
if (!EquipmentSlot.MAIN_HAND.isCompatible(source, equipmentSlot))
|
||||
return;
|
||||
|
||||
// Apply permanent potion effects
|
||||
if (mmoItem.hasData(ItemStats.PERM_EFFECTS))
|
||||
((PotionEffectListData) mmoItem.getData(ItemStats.PERM_EFFECTS))
|
||||
.getEffects()
|
||||
.stream()
|
||||
.filter(potionEffectData -> this.data.getPermanentPotionEffectAmplifier(potionEffectData.getType()) < potionEffectData.getLevel() - 1)
|
||||
.forEach(effect -> this.data.getPermanentPotionEffectsMap().put(effect.getType(), effect.toEffect()));
|
||||
|
||||
if (MMOItems.plugin.hasPermissions() && mmoItem.hasData(ItemStats.GRANTED_PERMISSIONS)) {
|
||||
final Permission perms = MMOItems.plugin.getVault().getPermissions();
|
||||
this.data.permissions().addAll(((StringListData) mmoItem.getData(ItemStats.GRANTED_PERMISSIONS)).getList());
|
||||
this.data.permissions()
|
||||
.stream()
|
||||
.filter(s -> !perms.has(this.data.getPlayer(), s))
|
||||
.forEach(perm -> perms.playerAdd(this.data.getPlayer(), perm));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
// TODO: Call inventory refresh event
|
||||
// Bukkit.getPluginManager().callEvent(new MMOInventoryRefreshEvent(inventory.equipped(), getPlayer(), this));
|
||||
}
|
||||
|
||||
private boolean needsUpdate(@Nullable EquippedItem item) {
|
||||
if (isEmpty(item))
|
||||
return true;
|
||||
int hash = item.getNBT().hashCode();
|
||||
boolean result = lastHashCodes.getOrDefault(item.getSlot(), 0) != hash;
|
||||
lastHashCodes.put(item.getSlot(), hash);
|
||||
return result;
|
||||
private boolean needsUpdate(@NotNull SlotEquippedItem item) {
|
||||
return !lastHashCodes.containsKey(item.getSlotNumber()) || lastHashCodes.get(item.getSlotNumber()) != (isEmpty(item) ? -1 : item.hashCode());
|
||||
}
|
||||
|
||||
private boolean isEmpty(@Nullable EquippedItem item) {
|
||||
return item == null || item.getNBT().getItem().getType().isAir();
|
||||
private void cache(@NotNull SlotEquippedItem item) {
|
||||
final int hashCode = isEmpty(item) ? -1 : item.hashCode();
|
||||
lastHashCodes.put(item.getSlotNumber(), hashCode);
|
||||
CACHE.put(hashCode, item);
|
||||
item.cacheItem();
|
||||
}
|
||||
|
||||
private boolean isEmpty(@Nullable SlotEquippedItem item) {
|
||||
return item == null || item.getNBT() == null || item.getNBT().getItem() == null || item.getNBT().getItem().getType().isAir();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package net.Indyuce.mmoitems.comp.inventory.model;
|
||||
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
|
||||
import net.Indyuce.mmoitems.comp.inventory.PlayerInventoryUpdater;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
@ -16,10 +18,13 @@ import java.util.*;
|
||||
public class PlayerMMOInventory {
|
||||
|
||||
private final UUID uniqueId;
|
||||
private final PlayerData data;
|
||||
private final Map<EquippedItem, Integer> content = new HashMap<>();
|
||||
|
||||
public PlayerMMOInventory(@NotNull PlayerData data) {
|
||||
this.uniqueId = data.getUniqueId();
|
||||
this.data = data;
|
||||
this.updater = new PlayerInventoryUpdater(data);
|
||||
}
|
||||
|
||||
public void addItem(@NotNull EquippedItem item) {
|
||||
@ -65,4 +70,17 @@ public class PlayerMMOInventory {
|
||||
public int hashCode() {
|
||||
return Objects.hash(uniqueId, content.keySet());
|
||||
}
|
||||
|
||||
// Old weird code
|
||||
@Deprecated
|
||||
public void scheduleUpdate() {
|
||||
MMOItems.log("PlayerMMOInventory#scheduleUpdate called!");
|
||||
}
|
||||
|
||||
private final PlayerInventoryUpdater updater;
|
||||
@Deprecated
|
||||
public void updateCheck(){
|
||||
this.updater.run();
|
||||
// MMOItems.log("PlayerMMOInventory#updateCheck called!");
|
||||
}
|
||||
}
|
||||
|
@ -63,4 +63,31 @@ public class SlotEquippedItem extends EquippedItem {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public ItemStack getItem() {
|
||||
switch (getSlotNumber()) {
|
||||
case -106:
|
||||
return getPlayer().getInventory().getItemInOffHand();
|
||||
case -7:
|
||||
return getPlayer().getInventory().getItemInMainHand();
|
||||
case 103:
|
||||
return getPlayer().getInventory().getHelmet();
|
||||
case 102:
|
||||
return getPlayer().getInventory().getChestplate();
|
||||
case 101:
|
||||
return getPlayer().getInventory().getLeggings();
|
||||
case 100:
|
||||
return getPlayer().getInventory().getBoots();
|
||||
default:
|
||||
return getPlayer().getInventory().getItem(getSlotNumber());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int accumulator = 0;
|
||||
accumulator ^= getSlot().hashCode();
|
||||
accumulator ^= getItem().hashCode();
|
||||
return accumulator;
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,28 @@
|
||||
package net.Indyuce.mmoitems.particle.api;
|
||||
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.stat.data.ParticleData;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
public abstract class ParticleRunnable extends BukkitRunnable {
|
||||
protected final ParticleData particle;
|
||||
protected final PlayerData player;
|
||||
|
||||
public ParticleRunnable(ParticleData particle, PlayerData player) {
|
||||
this.particle = particle;
|
||||
this.player = player;
|
||||
}
|
||||
protected final ParticleData particle;
|
||||
protected final PlayerData player;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if(!player.isOnline()) return;
|
||||
createParticles();
|
||||
}
|
||||
|
||||
public abstract void createParticles();
|
||||
public ParticleRunnable(ParticleData particle, PlayerData player) {
|
||||
this.particle = particle;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!player.isOnline()) return;
|
||||
createParticles();
|
||||
}
|
||||
|
||||
public abstract void createParticles();
|
||||
|
||||
public ParticleData getParticleData() {
|
||||
return particle;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user