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;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.player.TemporaryPlayerData;
import io.lumine.mythic.lib.player.cooldown.CooldownMap;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
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.PlayerLevelUpEvent;
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.util.Closable;
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.ExperienceObject;
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.ExperienceTable;
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.provided.Party;
import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.waypoint.WaypointOption;
import net.md_5.bungee.api.ChatMessageType;
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
* the player. This can be used by other plugins by
* implementing the {@link Unlockable} interface
* the player. This is used for:
* - waypoints
* - skills
*
* @see {@link Unlockable}
*/
@ -289,8 +288,11 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return guild != null;
}
/**
* @return If the item is unlocked by the player
*/
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
*/
public boolean unlock(Unlockable unlockable) {
throw new RuntimeException("Not implemented yet");
return unlockedItems.add(unlockable.getUnlockNamespacedKey());
}
public void setLevel(int level) {

View File

@ -1,16 +1,20 @@
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.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 {
@EventHandler
public void a(InventoryCloseEvent event) {
public void expireOnClose(InventoryCloseEvent event) {
if (!(event.getInventory().getHolder() instanceof Chest))
return;
@ -19,4 +23,14 @@ public class LootableChestsListener implements Listener {
if (lootChest != null)
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.api.SoundEvent;
import net.Indyuce.mmocore.util.item.HashableLocation;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
@ -52,7 +53,7 @@ public class LootChest {
public boolean hasPlayerNearby() {
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 false;
}
@ -78,8 +79,8 @@ public class LootChest {
// If a player is responsible of closing the chest, close it with sound
if (player) {
MMOCore.plugin.soundManager.getSound(SoundEvent.CLOSE_LOOT_CHEST).playAt(block.loc);
block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.clone().add(.5, .5, .5), 16, 0, 0, 0, .5);
MMOCore.plugin.soundManager.getSound(SoundEvent.CLOSE_LOOT_CHEST).playAt(block.loc.bukkit());
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)
*/
else
((Chest) block.loc.getBlock().getState()).getBlockInventory().clear();
((Chest) block.loc.bukkit().getBlock().getState()).getBlockInventory().clear();
block.restore();
if (effectRunnable != null)
@ -97,22 +98,28 @@ public class LootChest {
public static class ReplacedBlock {
private final Material material;
private final BlockData data;
private final Location loc;
private final HashableLocation loc;
public ReplacedBlock(Block block) {
this.material = block.getType();
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) {
return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getBlockX() == loc.getBlockX() && this.loc.getBlockY() == loc.getBlockY()
&& this.loc.getBlockZ() == loc.getBlockZ();
return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getX() == loc.getBlockX() && this.loc.getY() == loc.getBlockY()
&& this.loc.getZ() == loc.getBlockZ();
}
public void restore() {
loc.getBlock().setType(material);
loc.getBlock().setBlockData(data);
Block block = loc.bukkit().getBlock();
block.setType(material);
block.setBlockData(data);
}
}
}

View File

@ -1,24 +1,27 @@
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.api.ConfigFile;
import net.Indyuce.mmocore.loot.chest.LootChest;
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.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 {
/**
* 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
@ -42,26 +45,21 @@ public class LootChestManager implements MMOCoreManager {
return regions.values();
}
public Set<LootChest> getActive() {
return active;
public Collection<LootChest> getActive() {
return active.values();
}
public void register(LootChest chest) {
active.add(chest);
active.put(chest.getBlock().getLocation(), chest);
}
public void unregister(LootChest chest) {
active.remove(chest);
active.remove(chest.getBlock().getLocation());
}
@Nullable
public LootChest getChest(Location loc) {
for (LootChest chest : active)
if (chest.getBlock().matches(loc))
return chest;
return null;
return active.get(new HashableLocation(loc));
}
@Override
@ -80,6 +78,5 @@ public class LootChestManager implements MMOCoreManager {
MMOCore.plugin.getLogger().log(Level.WARNING,
"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;
/**
* Some item that can be unlocked. ALl unlockable are saved in the same list in
* the player data. This useful list can be used for:
* Some item that can be unlocked. All unlockables are saved in the
* same list in the player data. This useful list can be used for:
* - waypoints
* - skill tree nodes
* - skills using skill books? TODO
@ -15,8 +15,8 @@ import net.Indyuce.mmocore.api.player.PlayerData;
public interface Unlockable {
/**
* Format being used is the minecraft's default
* namespaced key format, e.g "skill_tree:strength_1_5"
* Format being used is the minecraft's default namespaced
* key format, e.g "skill_tree:strength_1_5" for readability
*/
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.modifier.ModifierSource;
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.util.math.formula.IntegerLinearValue;
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 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
* 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 net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.player.Unlockable;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@ -15,7 +16,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
public class RegisteredSkill {
public class RegisteredSkill implements Unlockable {
private final SkillHandler<?> handler;
private final String name;
private final Map<String, LinearValue> defaultModifiers = new HashMap<>();
@ -45,6 +46,11 @@ public class RegisteredSkill {
this.triggerType = triggerType;
}
@Override
public String getUnlockNamespacedKey() {
return "registered_skill:" + handler.getId().toLowerCase();
}
public SkillHandler<?> getHandler() {
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);
}
}