Loot chest O(1) lookup time

This commit is contained in:
Indyuce 2022-05-22 16:49:53 +02:00
parent 13c0469594
commit a7e3f9554f
9 changed files with 202 additions and 93 deletions

View File

@ -1,15 +1,11 @@
package net.Indyuce.mmocore.api.player; package net.Indyuce.mmocore.api.player;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.MMOPlayerData; import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.player.TemporaryPlayerData; import io.lumine.mythic.lib.player.TemporaryPlayerData;
import io.lumine.mythic.lib.player.cooldown.CooldownMap; import io.lumine.mythic.lib.player.cooldown.CooldownMap;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.waypoint.CostType;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.api.event.PlayerExperienceGainEvent; import net.Indyuce.mmocore.api.event.PlayerExperienceGainEvent;
import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent; import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent; import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
@ -25,7 +21,6 @@ import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.quest.PlayerQuests; import net.Indyuce.mmocore.api.quest.PlayerQuests;
import net.Indyuce.mmocore.api.util.Closable; import net.Indyuce.mmocore.api.util.Closable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import net.Indyuce.mmocore.experience.EXPSource; import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.ExperienceTableClaimer; import net.Indyuce.mmocore.experience.ExperienceTableClaimer;
@ -33,11 +28,14 @@ import net.Indyuce.mmocore.experience.PlayerProfessions;
import net.Indyuce.mmocore.experience.droptable.ExperienceItem; import net.Indyuce.mmocore.experience.droptable.ExperienceItem;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import net.Indyuce.mmocore.party.AbstractParty; import net.Indyuce.mmocore.party.AbstractParty;
import net.Indyuce.mmocore.party.provided.Party; import net.Indyuce.mmocore.party.provided.Party;
import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill; import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler; import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.waypoint.WaypointOption; import net.Indyuce.mmocore.waypoint.WaypointOption;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
@ -88,8 +86,9 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
/** /**
* Saves all the items that have been unlocked so far by * Saves all the items that have been unlocked so far by
* the player. This can be used by other plugins by * the player. This is used for:
* implementing the {@link Unlockable} interface * - waypoints
* - skills
* *
* @see {@link Unlockable} * @see {@link Unlockable}
*/ */
@ -289,8 +288,11 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return guild != null; return guild != null;
} }
/**
* @return If the item is unlocked by the player
*/
public boolean hasUnlocked(Unlockable unlockable) { public boolean hasUnlocked(Unlockable unlockable) {
throw new RuntimeException("Not implemented yet"); return unlockedItems.contains(unlockable.getUnlockNamespacedKey());
} }
/** /**
@ -299,7 +301,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
* @return If the item was already unlocked when calling this method * @return If the item was already unlocked when calling this method
*/ */
public boolean unlock(Unlockable unlockable) { public boolean unlock(Unlockable unlockable) {
throw new RuntimeException("Not implemented yet"); return unlockedItems.add(unlockable.getUnlockNamespacedKey());
} }
public void setLevel(int level) { public void setLevel(int level) {

View File

@ -1,16 +1,20 @@
package net.Indyuce.mmocore.listener; package net.Indyuce.mmocore.listener;
import org.bukkit.block.Chest;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCloseEvent;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.loot.chest.LootChest; import net.Indyuce.mmocore.loot.chest.LootChest;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
public class LootableChestsListener implements Listener { public class LootableChestsListener implements Listener {
@EventHandler @EventHandler
public void a(InventoryCloseEvent event) { public void expireOnClose(InventoryCloseEvent event) {
if (!(event.getInventory().getHolder() instanceof Chest)) if (!(event.getInventory().getHolder() instanceof Chest))
return; return;
@ -19,4 +23,14 @@ public class LootableChestsListener implements Listener {
if (lootChest != null) if (lootChest != null)
lootChest.expire(true); lootChest.expire(true);
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
public void noBreaking(BlockBreakEvent event) {
Block block = event.getBlock();
if (block.getType() == Material.CHEST) {
LootChest lootChest = MMOCore.plugin.lootChests.getChest(block.getLocation());
if (lootChest != null)
event.setCancelled(true);
}
}
} }

View File

@ -2,6 +2,7 @@ package net.Indyuce.mmocore.loot.chest;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.util.item.HashableLocation;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@ -52,7 +53,7 @@ public class LootChest {
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.bukkit()) < 625)
return true; return true;
return false; return false;
} }
@ -78,8 +79,8 @@ public class LootChest {
// 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) { if (player) {
MMOCore.plugin.soundManager.getSound(SoundEvent.CLOSE_LOOT_CHEST).playAt(block.loc); MMOCore.plugin.soundManager.getSound(SoundEvent.CLOSE_LOOT_CHEST).playAt(block.loc.bukkit());
block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.clone().add(.5, .5, .5), 16, 0, 0, 0, .5); block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.bukkit().add(.5, .5, .5), 16, 0, 0, 0, .5);
} }
/* /*
@ -87,7 +88,7 @@ public class LootChest {
* 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.bukkit().getBlock().getState()).getBlockInventory().clear();
block.restore(); block.restore();
if (effectRunnable != null) if (effectRunnable != null)
@ -97,22 +98,28 @@ public class LootChest {
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 HashableLocation 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 = new HashableLocation(block.getLocation());
} }
public HashableLocation getLocation() {
return loc;
}
@Deprecated
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.getX() == loc.getBlockX() && this.loc.getY() == loc.getBlockY()
&& this.loc.getBlockZ() == loc.getBlockZ(); && this.loc.getZ() == loc.getBlockZ();
} }
public void restore() { public void restore() {
loc.getBlock().setType(material); Block block = loc.bukkit().getBlock();
loc.getBlock().setBlockData(data); block.setType(material);
block.setBlockData(data);
} }
} }
} }

View File

@ -1,24 +1,27 @@
package net.Indyuce.mmocore.manager; package net.Indyuce.mmocore.manager;
import java.util.*;
import java.util.logging.Level;
import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigFile; import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.loot.chest.LootChest; import net.Indyuce.mmocore.loot.chest.LootChest;
import net.Indyuce.mmocore.loot.chest.LootChestRegion; import net.Indyuce.mmocore.loot.chest.LootChestRegion;
import net.Indyuce.mmocore.util.item.HashableLocation;
import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
public class LootChestManager implements MMOCoreManager { public class LootChestManager implements MMOCoreManager {
/** /**
* Active loot chests in the server * Active loot chests in the server
*/ */
private final Set<LootChest> active = new HashSet<>(); private final Map<HashableLocation, LootChest> active = new HashMap<>();
/** /**
* Registered loot chest regions * Registered loot chest regions
@ -42,26 +45,21 @@ public class LootChestManager implements MMOCoreManager {
return regions.values(); return regions.values();
} }
public Set<LootChest> getActive() { public Collection<LootChest> getActive() {
return active; return active.values();
} }
public void register(LootChest chest) { public void register(LootChest chest) {
active.add(chest); active.put(chest.getBlock().getLocation(), chest);
} }
public void unregister(LootChest chest) { public void unregister(LootChest chest) {
active.remove(chest); active.remove(chest.getBlock().getLocation());
} }
@Nullable @Nullable
public LootChest getChest(Location loc) { public LootChest getChest(Location loc) {
return active.get(new HashableLocation(loc));
for (LootChest chest : active)
if (chest.getBlock().matches(loc))
return chest;
return null;
} }
@Override @Override
@ -80,6 +78,5 @@ public class LootChestManager implements MMOCoreManager {
MMOCore.plugin.getLogger().log(Level.WARNING, MMOCore.plugin.getLogger().log(Level.WARNING,
"An error occured while trying to load loot chest region '" + key + "': " + exception.getMessage()); "An error occured while trying to load loot chest region '" + key + "': " + exception.getMessage());
} }
} }
} }

View File

@ -3,8 +3,8 @@ package net.Indyuce.mmocore.player;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
/** /**
* Some item that can be unlocked. ALl unlockable are saved in the same list in * Some item that can be unlocked. All unlockables are saved in the
* the player data. This useful list can be used for: * same list in the player data. This useful list can be used for:
* - waypoints * - waypoints
* - skill tree nodes * - skill tree nodes
* - skills using skill books? TODO * - skills using skill books? TODO
@ -15,8 +15,8 @@ import net.Indyuce.mmocore.api.player.PlayerData;
public interface Unlockable { public interface Unlockable {
/** /**
* Format being used is the minecraft's default * Format being used is the minecraft's default namespaced
* namespaced key format, e.g "skill_tree:strength_1_5" * key format, e.g "skill_tree:strength_1_5" for readability
*/ */
String getUnlockNamespacedKey(); String getUnlockNamespacedKey();
} }

View File

@ -4,6 +4,7 @@ import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.player.cooldown.CooldownObject; import io.lumine.mythic.lib.player.cooldown.CooldownObject;
import io.lumine.mythic.lib.player.modifier.ModifierSource; import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.skill.PassiveSkill; import io.lumine.mythic.lib.player.skill.PassiveSkill;
import io.lumine.mythic.lib.skill.custom.condition.Condition;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.math.formula.IntegerLinearValue; import net.Indyuce.mmocore.api.util.math.formula.IntegerLinearValue;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue; import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
@ -17,6 +18,9 @@ public class ClassSkill implements CooldownObject {
private final int unlockLevel, maxSkillLevel; private final int unlockLevel, maxSkillLevel;
private final Map<String, LinearValue> modifiers = new HashMap<>(); private final Map<String, LinearValue> modifiers = new HashMap<>();
@Deprecated
private final Set<Condition> unlockConditions = new HashSet<>();
/** /**
* Class used to save information about skills IN A CLASS CONTEXT i.e at * Class used to save information about skills IN A CLASS CONTEXT i.e at
* which level the skill can be unlocked, etc. * which level the skill can be unlocked, etc.

View File

@ -5,6 +5,7 @@ import io.lumine.mythic.lib.skill.handler.SkillHandler;
import io.lumine.mythic.lib.skill.trigger.TriggerType; import io.lumine.mythic.lib.skill.trigger.TriggerType;
import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue; import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.player.Unlockable;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -15,7 +16,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
public class RegisteredSkill { public class RegisteredSkill implements Unlockable {
private final SkillHandler<?> handler; private final SkillHandler<?> handler;
private final String name; private final String name;
private final Map<String, LinearValue> defaultModifiers = new HashMap<>(); private final Map<String, LinearValue> defaultModifiers = new HashMap<>();
@ -45,6 +46,11 @@ public class RegisteredSkill {
this.triggerType = triggerType; this.triggerType = triggerType;
} }
@Override
public String getUnlockNamespacedKey() {
return "registered_skill:" + handler.getId().toLowerCase();
}
public SkillHandler<?> getHandler() { public SkillHandler<?> getHandler() {
return handler; return handler;
} }

View File

@ -0,0 +1,28 @@
package net.Indyuce.mmocore.tree.modifier;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.modifier.PlayerModifier;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import org.apache.commons.lang.NotImplementedException;
public class UnlockSkillModifier extends PlayerModifier {
private RegisteredSkill unlocked = null;
public UnlockSkillModifier(String key, EquipmentSlot slot, ModifierSource source) {
super(key, slot, source);
}
@Override
public void register(MMOPlayerData mmoPlayerData) {
PlayerData playerData = PlayerData.get(mmoPlayerData.getUniqueId());
// playerData.unlock(unlocked);
}
@Override
public void unregister(MMOPlayerData mmoPlayerData) {
throw new NotImplementedException("");
}
}

View File

@ -0,0 +1,51 @@
package net.Indyuce.mmocore.util.item;
import org.bukkit.Location;
import org.bukkit.World;
import java.util.Objects;
public class HashableLocation {
private final World world;
private final int x, y, z;
public HashableLocation(Location loc) {
this.world = loc.getWorld();
this.x = loc.getBlockX();
this.y = loc.getBlockY();
this.z = loc.getBlockZ();
}
public World getWorld() {
return world;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public Location bukkit() {
return new Location(world, x, y, z);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HashableLocation that = (HashableLocation) o;
return x == that.x && y == that.y && z == that.z && world.equals(that.world);
}
@Override
public int hashCode() {
return Objects.hash(world, x, y, z);
}
}