diff --git a/src/main/java/net/Indyuce/mmocore/api/loot/ChestAlgorithmOptions.java b/src/main/java/net/Indyuce/mmocore/api/loot/ChestAlgorithmOptions.java index bd305605..ab98956e 100644 --- a/src/main/java/net/Indyuce/mmocore/api/loot/ChestAlgorithmOptions.java +++ b/src/main/java/net/Indyuce/mmocore/api/loot/ChestAlgorithmOptions.java @@ -25,7 +25,7 @@ public class ChestAlgorithmOptions { * finder algorithm. */ public ChestAlgorithmOptions(ConfigurationSection config) { - Validate.notNull(config, "Config cannot be nulm"); + Validate.notNull(config, "Config cannot be null"); minRange = config.getDouble("min-range", DEFAULT.minRange); maxRange = config.getDouble("max-range", DEFAULT.maxRange); diff --git a/src/main/java/net/Indyuce/mmocore/api/loot/LootChestRegion.java b/src/main/java/net/Indyuce/mmocore/api/loot/LootChestRegion.java index 586cffe3..2ffa6491 100644 --- a/src/main/java/net/Indyuce/mmocore/api/loot/LootChestRegion.java +++ b/src/main/java/net/Indyuce/mmocore/api/loot/LootChestRegion.java @@ -3,6 +3,7 @@ package net.Indyuce.mmocore.api.loot; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Optional; import java.util.Random; import java.util.Set; import java.util.logging.Level; @@ -109,6 +110,7 @@ public class LootChestRegion { } // TODO improve + // TODO stat to increase chance to get higher tiers? public ChestTier rollTier() { double s = 0; @@ -116,7 +118,6 @@ public class LootChestRegion { if (random.nextDouble() < tier.chance / (1 - s)) return tier; s += tier.chance; - } return tiers.stream().findAny().get(); @@ -166,4 +167,21 @@ public class LootChestRegion { private boolean isSuitable(Location loc) { return !loc.getBlock().getType().isSolid() && loc.clone().add(0, -1, 0).getBlock().getType().isSolid(); } + + public class LootChestRunnable extends BukkitRunnable { + private final LootChestRegion region; + + public LootChestRunnable(LootChestRegion region) { + this.region = region; + + runTaskTimer(MMOCore.plugin, region.getChestSpawnPeriod() * 20, region.getChestSpawnPeriod() * 20); + } + + @Override + public void run() { + Optional found = region.getBounds().getPlayers().filter(data -> data.canSpawnLootChest()).findAny(); + if (found.isPresent()) + region.spawnChest(found.get()); + } + } } diff --git a/src/main/java/net/Indyuce/mmocore/api/loot/LootChestRunnable.java b/src/main/java/net/Indyuce/mmocore/api/loot/LootChestRunnable.java deleted file mode 100644 index 7e341a08..00000000 --- a/src/main/java/net/Indyuce/mmocore/api/loot/LootChestRunnable.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.Indyuce.mmocore.api.loot; - -import java.util.Optional; - -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; - -import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.player.PlayerData; - -public class LootChestRunnable extends BukkitRunnable { - private final LootChestRegion region; - - public LootChestRunnable(LootChestRegion region) { - this.region = region; - - runTaskTimer(MMOCore.plugin, region.getChestSpawnPeriod() * 20, region.getChestSpawnPeriod() * 20); - } - - // TODO add option so that players cannot have more than X chests every X - // time - @Override - public void run() { - Optional found = region.getBounds().getPlayers().findAny(); - if (found.isPresent()) - region.spawnChest(PlayerData.get(found.get())); - } -} diff --git a/src/main/java/net/Indyuce/mmocore/api/loot/RegionBounds.java b/src/main/java/net/Indyuce/mmocore/api/loot/RegionBounds.java index c162aa37..8603ec5d 100644 --- a/src/main/java/net/Indyuce/mmocore/api/loot/RegionBounds.java +++ b/src/main/java/net/Indyuce/mmocore/api/loot/RegionBounds.java @@ -9,13 +9,19 @@ import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; +import net.Indyuce.mmocore.api.player.PlayerData; + public class RegionBounds { private final World world; private final int x1, z1, x2, z2; public RegionBounds(ConfigurationSection config) { Validate.notNull(config, "Could not load config"); - Validate.notNull(world = Bukkit.getWorld(config.getString("world")), "Could not find world " + config.getString("world")); + + String name = config.getString("world"); + Validate.notNull(name, "Could not find world name"); + Validate.notNull(world = Bukkit.getWorld(name), "Could not find world " + config.getString("world")); + x1 = Math.min(config.getInt("x1"), config.getInt("x2")); x2 = Math.max(config.getInt("x1"), config.getInt("x2")); @@ -33,8 +39,8 @@ public class RegionBounds { z2 = Math.max(loc1.getBlockZ(), loc2.getBlockZ()); } - public Stream getPlayers() { - return world.getPlayers().stream().filter(player -> isInRegion(player)); + public Stream getPlayers() { + return world.getPlayers().stream().filter(player -> isInRegion(player)).map(player -> PlayerData.get(player)); } public boolean isInRegion(Player player) { diff --git a/src/main/java/net/Indyuce/mmocore/api/player/CombatRunnable.java b/src/main/java/net/Indyuce/mmocore/api/player/CombatRunnable.java index 501853d3..572a6617 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/CombatRunnable.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/CombatRunnable.java @@ -25,7 +25,7 @@ public class CombatRunnable extends BukkitRunnable { @Override public void run() { - if (lastHit + (MMOCore.plugin.configManager.combatLogTimer * 1000) < System.currentTimeMillis()) { + if (lastHit + MMOCore.plugin.configManager.combatLogTimer < System.currentTimeMillis()) { Bukkit.getPluginManager().callEvent(new PlayerCombatEvent(player, false)); MMOCore.plugin.configManager.getSimpleMessage("leave-combat").send(player.getPlayer()); close(); diff --git a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java index db7943f6..3374d5e8 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java @@ -88,7 +88,7 @@ public class PlayerData extends OfflinePlayerData { private final PlayerAttributes attributes = new PlayerAttributes(this); private final Map classSlots = new HashMap<>(); - private long lastWaypoint, lastLogin, lastFriendRequest, actionBarTimeOut; + private long lastWaypoint, lastLogin, lastFriendRequest, actionBarTimeOut, lastLootChest; /* * NON-FINAL player data stuff made public to facilitate field change @@ -325,6 +325,19 @@ public class PlayerData extends OfflinePlayerData { return Math.max(0, lastWaypoint + 5000 - System.currentTimeMillis()); } + /* + * handles the per-player loot chest cooldown. that is to reduce the risk of + * spawning multiple chests in a row around the same player which could + * break the gameplay + */ + public boolean canSpawnLootChest() { + return lastLootChest + MMOCore.plugin.configManager.lootChestPlayerCooldown < System.currentTimeMillis(); + } + + public void applyLootChestCooldown() { + lastLootChest = System.currentTimeMillis(); + } + public void heal(double heal) { double newest = Math.max(0, Math.min(player.getHealth() + heal, player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue())); if (player.getHealth() == newest) @@ -723,7 +736,7 @@ public class PlayerData extends OfflinePlayerData { if (!skill.getSkill().isPassive()) { if (cast.getCancelReason() == CancelReason.LOCKED) MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-skill").send(player); - + if (cast.getCancelReason() == CancelReason.MANA) MMOCore.plugin.configManager.getSimpleMessage("casting.no-mana").send(player); diff --git a/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java b/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java index 9e6113fe..d018f919 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java @@ -28,7 +28,7 @@ public class ConfigManager { public double expPartyBuff, regenPartyBuff; public String partyChatPrefix, noSkillBoundPlaceholder; public ChatColor staminaFull, staminaHalf, staminaEmpty; - public int combatLogTimer, lootChestExpireTime; + public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown; public final DecimalFormatSymbols formatSymbols = new DecimalFormatSymbols(); public final DecimalFormat decimal = new DecimalFormat("0.#", formatSymbols), decimals = new DecimalFormat("0.##", formatSymbols); @@ -87,7 +87,7 @@ public class ConfigManager { loadDefaultFile("stats.yml"); loadDefaultFile("waypoints.yml"); loadDefaultFile("restrictions.yml"); - // loadDefaultFile("chests.yml"); + loadDefaultFile("loot-chests.yml"); loadDefaultFile("commands.yml"); loadDefaultFile("guilds.yml"); @@ -100,8 +100,9 @@ public class ConfigManager { chatInput = MMOCore.plugin.getConfig().getBoolean("use-chat-input"); partyChatPrefix = MMOCore.plugin.getConfig().getString("party.chat-prefix"); formatSymbols.setDecimalSeparator(getFirstChar(MMOCore.plugin.getConfig().getString("number-format.decimal-separator"), ',')); - combatLogTimer = MMOCore.plugin.getConfig().getInt("combat-log.timer"); - lootChestExpireTime = Math.max(MMOCore.plugin.getConfig().getInt("loot-chest-expire-time"), 1) * 1000; + combatLogTimer = MMOCore.plugin.getConfig().getInt("combat-log.timer") * 1000; + lootChestExpireTime = Math.max(MMOCore.plugin.getConfig().getInt("loot-chests.chest-expire-time"), 1) * 1000; + lootChestPlayerCooldown = MMOCore.plugin.getConfig().getInt("player-cooldown") * 1000; noSkillBoundPlaceholder = getSimpleMessage("no-skill-placeholder").message(); staminaFull = getColorOrDefault("stamina-whole", ChatColor.GREEN); @@ -176,10 +177,12 @@ public class ConfigManager { public boolean send(Player player) { String msg = hasPlaceholders ? MMOCore.plugin.placeholderParser.parse(player, message) : message; - + if (!msg.isEmpty()) { - if (actionbar) PlayerData.get(player.getUniqueId()).displayActionBar(msg); - else player.sendMessage(msg); + if (actionbar) + PlayerData.get(player.getUniqueId()).displayActionBar(msg); + else + player.sendMessage(msg); } return !msg.isEmpty(); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index d1c7d57e..a3b2cb47 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -7,13 +7,13 @@ auto-save: # MySQL Support mysql: - enabled: false - database: minecraft - host: localhost - port: 3306 - user: mmolover - pass: ILoveAria - flags: '?allowReconnect=true&useSSL=false' + enabled: false + database: minecraft + host: localhost + port: 3306 + user: mmolover + pass: ILoveAria + flags: '?allowReconnect=true&useSSL=false' # The list of all conditions which must be met for the # BLOCK REGEN and BLOCK RESTRICTIONS to apply. @@ -32,9 +32,15 @@ lootsplosion: offset: .2 height: .6 -# Time in seconds it takes for a loot chest to -# expire after it was spawned. 600 is 10 minutes. -loot-chest-expire-time: 600 +loot-chests: + + # Time in seconds it takes for a loot chest to + # expire after it was spawned. 600 is 10 minutes. + chest-expire-time: 600 + + # Interval in seconds before the same player + # spawns two loot chests in ANY region. + player-cooldown: 600 # Settings for the default action bar action-bar: @@ -110,7 +116,7 @@ use-chat-input: true # Prevents mobs spawned from spawners from giving XP points. prevent-spawner-xp: true -#Timer for combat log to expire (in seconds) +# Timer for combat log to expire (in seconds) combat-log: timer: 10 diff --git a/src/main/resources/default/chests.yml b/src/main/resources/default/chests.yml deleted file mode 100644 index 3826e9f0..00000000 --- a/src/main/resources/default/chests.yml +++ /dev/null @@ -1,24 +0,0 @@ - -'world 59 71 131': - - # Create directly your drop table here. - drop-table: - items: - - 'vanilla{type=DIAMOND} 1 1-3' - - 'gold{} .9 1-3' - - 'gold{} .9 1-3' - - 'gold{} .9 1-3' - - 'gold{} .9 1-3' - - 'gold{} .9 1-3' - - 'gold{} .9 1-3' - - 'note{min=1;max=10} .9 1-3' - - # Ticks the chest takes to appear again. - regen-time: 40 - - # The particle played every 4sec around the chest. - # Types available: helix|offset|galaxy - # Particle names here: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Particle.html - effect: - type: helix - particle: FLAME diff --git a/src/main/resources/default/loot-chests.yml b/src/main/resources/default/loot-chests.yml new file mode 100644 index 00000000..6c4be187 --- /dev/null +++ b/src/main/resources/default/loot-chests.yml @@ -0,0 +1,37 @@ + +sample-region: + + # Region boundaries + bounds: + world: world_name_here + x1: 32 + x2: -15 + z1: -419 + z2: -375 + + # Chest spawn period in seconds + spawn-period: 120 + + # Extra options for the random location algorithm + algorithm-options: + min-range: 8 # Min range from chest to player + max-range: 20 # Max range from chest to player + height: 15 # Maximum Y coord delta between the chest and player + iterations: 15 # Amount of random locations taken (tries) before canceling loot chest spawning + + tiers: + + # Some tier + normal: + + # Particle effect played around a spawned loot chest + effect: + type: OFFSET # Type of particle effect used + particle: FLAME # Particle used to play the effect + period: 60 # Plays the effect every 60 ticks + + capacity: 10 + chance: 1 + drops: + items: + - 'vanilla{type=DIAMOND}' \ No newline at end of file