diff --git a/src/main/java/com/azuredoom/levelingcore/LevelingCore.java b/src/main/java/com/azuredoom/levelingcore/LevelingCore.java index ed5a42d..d3ef498 100644 --- a/src/main/java/com/azuredoom/levelingcore/LevelingCore.java +++ b/src/main/java/com/azuredoom/levelingcore/LevelingCore.java @@ -46,6 +46,7 @@ import com.azuredoom.levelingcore.level.xp.XPValues; import com.azuredoom.levelingcore.systems.damage.MobDamageFilter; import com.azuredoom.levelingcore.systems.damage.PlayerDamageFilter; +import com.azuredoom.levelingcore.systems.equipment.EquipBlockManager; import com.azuredoom.levelingcore.systems.level.LevelDownTickingSystem; import com.azuredoom.levelingcore.systems.level.LevelUpTickingSystem; import com.azuredoom.levelingcore.systems.level.MobLevelSystem; @@ -108,6 +109,8 @@ public class LevelingCore extends JavaPlugin { public static final MobLevelPersistence mobLevelPersistence = new MobLevelPersistence(); + public static final EquipBlockManager equipBlockManager = new EquipBlockManager(); + /** * Constructs a new {@code LevelingCore} instance and initializes the core components of the leveling system. This * constructor takes a non-null {@link JavaPluginInit} object to set up the necessary dependencies and @@ -208,6 +211,8 @@ public boolean cancel(boolean mayInterruptIfRunning) { }; this.getTaskRegistry().registerTask(task); LevelingCore.mobLevelPersistence.load(); + if (LevelingCore.getConfig().get().isEnableItemLevelRestriction()) + LevelingCore.equipBlockManager.start(); } /** @@ -220,6 +225,8 @@ public boolean cancel(boolean mayInterruptIfRunning) { @Override protected void shutdown() { LevelingCore.mobLevelPersistence.save(); + if (LevelingCore.getConfig().get().isEnableItemLevelRestriction()) + LevelingCore.equipBlockManager.shutdown(); super.shutdown(); LOGGER.at(Level.INFO).log("Leveling Core shutting down"); try { diff --git a/src/main/java/com/azuredoom/levelingcore/systems/equipment/EquipBlockManager.java b/src/main/java/com/azuredoom/levelingcore/systems/equipment/EquipBlockManager.java new file mode 100644 index 0000000..408dbb1 --- /dev/null +++ b/src/main/java/com/azuredoom/levelingcore/systems/equipment/EquipBlockManager.java @@ -0,0 +1,143 @@ +package com.azuredoom.levelingcore.systems.equipment; + +import com.hypixel.hytale.event.EventRegistration; +import com.hypixel.hytale.server.core.entity.entities.Player; +import com.hypixel.hytale.server.core.event.events.entity.LivingEntityInventoryChangeEvent; +import com.hypixel.hytale.server.core.inventory.Inventory; +import com.hypixel.hytale.server.core.inventory.ItemStack; +import com.hypixel.hytale.server.core.inventory.container.ItemContainer; +import com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction; +import com.hypixel.hytale.server.core.inventory.transaction.ListTransaction; +import com.hypixel.hytale.server.core.inventory.transaction.MoveTransaction; +import com.hypixel.hytale.server.core.inventory.transaction.MoveType; +import com.hypixel.hytale.server.core.inventory.transaction.SlotTransaction; +import com.hypixel.hytale.server.core.inventory.transaction.Transaction; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.azuredoom.levelingcore.LevelingCore; +import com.azuredoom.levelingcore.lang.CommandLang; + +public class EquipBlockManager { + + @Nullable + private volatile EventRegistration inventoryChangeRegistration; + + private volatile boolean restoringArmor = false; + + public void start() { + if (inventoryChangeRegistration == null || !inventoryChangeRegistration.isRegistered()) { + inventoryChangeRegistration = LevelingCore.getInstance() + .getEventRegistry() + .registerGlobal(LivingEntityInventoryChangeEvent.class, this::onInventoryChange); + } + } + + public void shutdown() { + EventRegistration inventoryRegistration = inventoryChangeRegistration; + if (inventoryRegistration != null && inventoryRegistration.isRegistered()) { + inventoryRegistration.unregister(); + } + inventoryChangeRegistration = null; + } + + private void onInventoryChange(@Nonnull LivingEntityInventoryChangeEvent event) { + if (!(event.getEntity() instanceof Player player)) { + return; + } + + if (restoringArmor) { + return; + } + + Inventory inventory = player.getInventory(); + ItemContainer armorContainer = inventory.getArmor(); + if (armorContainer == null) { + return; + } + + ItemContainer changedContainer = event.getItemContainer(); + if (changedContainer == null || changedContainer != armorContainer) { + return; + } + + Transaction transaction = event.getTransaction(); + if (transaction == null) { + return; + } + + List returnToInventory = new ArrayList<>(); + restoringArmor = true; + try { + rollbackArmorTransaction(player, armorContainer, transaction, returnToInventory); + + for (ItemStack stack : returnToInventory) { + if (stack != null && !ItemStack.isEmpty(stack)) { + inventory.getCombinedHotbarFirst().addItemStack(stack); + } + } + } finally { + restoringArmor = false; + } + } + + private void rollbackArmorTransaction( + @Nonnull Player player, + @Nonnull ItemContainer armorContainer, + @Nullable Transaction transaction, + @Nonnull List returnedItems + ) { + if (transaction == null || !transaction.succeeded()) { + return; + } + + if (transaction instanceof MoveTransaction moveTransaction) { + if (moveTransaction.getMoveType() == MoveType.MOVE_TO_SELF) { + rollbackArmorTransaction(player, armorContainer, moveTransaction.getAddTransaction(), returnedItems); + } + return; + } + + if (transaction instanceof ListTransaction listTransaction) { + for (Transaction nested : listTransaction.getList()) { + rollbackArmorTransaction(player, armorContainer, nested, returnedItems); + } + return; + } + + if (transaction instanceof ItemStackTransaction itemStackTransaction) { + for (SlotTransaction slotTransaction : itemStackTransaction.getSlotTransactions()) { + rollbackArmorTransaction(player, armorContainer, slotTransaction, returnedItems); + } + return; + } + + if (transaction instanceof SlotTransaction slotTransaction) { + ItemStack after = slotTransaction.getSlotAfter(); + if (after == null || ItemStack.isEmpty(after)) { + return; + } + + String itemId = after.getItemId(); + Integer levelRestriction = LevelingCore.itemLevelMapping.getOrDefault(itemId, null); + Integer playerLevel = LevelingCore.getLevelService().getLevel(player.getUuid()); + if (levelRestriction == null) + return; + + if (playerLevel >= levelRestriction) + return; + + player.sendMessage( + CommandLang.LEVEL_REQUIRED.param("requiredlevel", levelRestriction) + .param("itemid", itemId) + .param("level", playerLevel) + ); + + armorContainer.setItemStackForSlot(slotTransaction.getSlot(), slotTransaction.getSlotBefore(), false); + returnedItems.add(after); + } + } +}