forked from Upstream/mmocore
New capacity
and shuffle
option for block/fishing drop tables
This commit is contained in:
parent
5759f78924
commit
b80cda490c
@ -84,6 +84,7 @@ public class BlockInfo {
|
|||||||
return table != null;
|
return table != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public List<ItemStack> collectDrops(LootBuilder builder) {
|
public List<ItemStack> collectDrops(LootBuilder builder) {
|
||||||
return table != null ? table.collect(builder) : new ArrayList<>();
|
return table != null ? table.collect(builder) : new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package net.Indyuce.mmocore.loot;
|
package net.Indyuce.mmocore.loot;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class LootBuilder {
|
public class LootBuilder {
|
||||||
private final PlayerData player;
|
private final PlayerData player;
|
||||||
@ -12,18 +13,22 @@ public class LootBuilder {
|
|||||||
|
|
||||||
private double capacity;
|
private double capacity;
|
||||||
|
|
||||||
|
public static double DEFAULT_CAPACITY = 100;
|
||||||
|
|
||||||
|
public LootBuilder(PlayerData player) {
|
||||||
|
this(player, DEFAULT_CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to create loot from a drop table
|
* Used to create loot from a drop table
|
||||||
*
|
*
|
||||||
* @param player
|
* @param player Player looting
|
||||||
* Player looting
|
* @param capacity Capacity is the maximum amount of item weight generated using
|
||||||
* @param capacity
|
|
||||||
* Capacity is the maximum amount of item weight generated using
|
|
||||||
* this table. If capacity is set to 10, this table cannot drop
|
* this table. If capacity is set to 10, this table cannot drop
|
||||||
* an item with 5 weight and another with 6 weight at the saeme
|
* an item with 5 weight and another with 6 weight at the saeme
|
||||||
* time.
|
* time.
|
||||||
*/
|
*/
|
||||||
public LootBuilder(PlayerData player, double capacity) {
|
public LootBuilder(@NotNull PlayerData player, double capacity) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.Indyuce.mmocore.loot;
|
package net.Indyuce.mmocore.loot;
|
||||||
|
|
||||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||||
|
import net.Indyuce.mmocore.loot.droptable.dropitem.DropItem;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -17,23 +18,24 @@ public class RandomWeightedRoll<T extends Weighted> {
|
|||||||
private final T rolled;
|
private final T rolled;
|
||||||
|
|
||||||
private static final Random RANDOM = new Random();
|
private static final Random RANDOM = new Random();
|
||||||
private static final double CHANCE_COEFFICIENT = 7. / 100;
|
|
||||||
|
|
||||||
public RandomWeightedRoll(PlayerData player, Collection<T> collection, double chanceWeight) {
|
public RandomWeightedRoll(PlayerData player, Collection<T> collection, double chanceWeight) {
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
|
|
||||||
double partialSum = 0;
|
double partialSum = 0;
|
||||||
final double randomCoefficient = RANDOM.nextDouble(), chance = chanceWeight * player.getStats().getStat("CHANCE"), sum = weightedSum(chance);
|
final double randomCoefficient = RANDOM.nextDouble(),
|
||||||
|
effectiveLuck = DropItem.CHANCE_FACTOR * chanceWeight * player.getStats().getStat("CHANCE"),
|
||||||
|
sum = weightedSum(effectiveLuck);
|
||||||
|
|
||||||
for (T item : collection) {
|
for (T item : collection) {
|
||||||
partialSum += computeRealWeight(item, chance);
|
partialSum += computeRealWeight(item, effectiveLuck);
|
||||||
if (partialSum >= randomCoefficient * sum) {
|
if (partialSum >= randomCoefficient * sum) {
|
||||||
rolled = item;
|
rolled = item;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException("Could not roll item, the chance is :"+chance);
|
throw new RuntimeException("Could not roll item, effective luck is " + effectiveLuck);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,10 +49,10 @@ public class RandomWeightedRoll<T extends Weighted> {
|
|||||||
return rolled;
|
return rolled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double weightedSum(double chance) {
|
private double weightedSum(double effectiveLuck) {
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
for (T item : collection)
|
for (T item : collection)
|
||||||
sum += computeRealWeight(item, chance);
|
sum += computeRealWeight(item, effectiveLuck);
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,8 +64,8 @@ public class RandomWeightedRoll<T extends Weighted> {
|
|||||||
*
|
*
|
||||||
* @return The real weight of an item considering the player's chance stat.
|
* @return The real weight of an item considering the player's chance stat.
|
||||||
*/
|
*/
|
||||||
private double computeRealWeight(T item, double chance) {
|
private double computeRealWeight(T item, double effectiveLuck) {
|
||||||
return Math.pow(item.getWeight(), 1 / Math.pow(1 + CHANCE_COEFFICIENT * chance, 1. / 3.));
|
return Math.pow(item.getWeight(), Math.pow(1 + effectiveLuck, -DropItem.CHANCE_POWER));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,27 +1,34 @@
|
|||||||
package net.Indyuce.mmocore.loot.chest;
|
package net.Indyuce.mmocore.loot.chest;
|
||||||
|
|
||||||
import io.lumine.mythic.lib.api.math.ScalingFormula;
|
import io.lumine.mythic.lib.api.math.ScalingFormula;
|
||||||
|
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
|
||||||
import net.Indyuce.mmocore.MMOCore;
|
import net.Indyuce.mmocore.MMOCore;
|
||||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||||
import net.Indyuce.mmocore.loot.Weighted;
|
import net.Indyuce.mmocore.loot.Weighted;
|
||||||
import net.Indyuce.mmocore.loot.droptable.DropTable;
|
import net.Indyuce.mmocore.loot.droptable.DropTable;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class ChestTier implements Weighted {
|
public class ChestTier implements Weighted {
|
||||||
private final TierEffect effect;
|
private final TierEffect effect;
|
||||||
|
// TODO Capacity should be inherent to drop table
|
||||||
|
// TODO make capacity any numeric formula, parsed with a player
|
||||||
|
@BackwardsCompatibility(version = "1.12.1")
|
||||||
|
@Nullable
|
||||||
private final ScalingFormula capacity;
|
private final ScalingFormula capacity;
|
||||||
private final DropTable table;
|
private final DropTable table;
|
||||||
private final double chance;
|
private final double chance;
|
||||||
|
|
||||||
public ChestTier(ConfigurationSection config) {
|
public ChestTier(ConfigurationSection config) {
|
||||||
effect = config.isConfigurationSection("effect") ? new TierEffect(config.getConfigurationSection("effect")) : null;
|
effect = config.isConfigurationSection("effect") ? new TierEffect(config.getConfigurationSection("effect")) : null;
|
||||||
capacity = new ScalingFormula(config.get("capacity"));
|
capacity = config.contains("capacity") ? new ScalingFormula(config.get("capacity")) : null;
|
||||||
chance = config.getDouble("chance");
|
chance = config.getDouble("chance");
|
||||||
table = MMOCore.plugin.dropTableManager.loadDropTable(config.get("drops"));
|
table = MMOCore.plugin.dropTableManager.loadDropTable(config.get("drops"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public double rollCapacity(PlayerData player) {
|
public double rollCapacity(@NotNull PlayerData player) {
|
||||||
return capacity.calculate(player.getLevel());
|
return capacity == null ? table.getCapacity() : capacity.calculate(player.getLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getChance() {
|
public double getChance() {
|
||||||
@ -33,6 +40,7 @@ public class ChestTier implements Weighted {
|
|||||||
return chance;
|
return chance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public DropTable getDropTable() {
|
public DropTable getDropTable() {
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
@ -13,15 +13,17 @@ 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;
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class DropTable implements PreloadedObject {
|
public class DropTable implements PreloadedObject {
|
||||||
private final String id;
|
private final String id;
|
||||||
private final Set<DropItem> drops = new LinkedHashSet<>();
|
private final double capacity;
|
||||||
private final Set<Condition> conditions = new LinkedHashSet<>();
|
private final boolean shuffle;
|
||||||
|
private final List<DropItem> drops = new ArrayList<>();
|
||||||
|
private final List<Condition> conditions = new ArrayList<>();
|
||||||
|
|
||||||
private final PostLoadAction postLoadAction;
|
private final PostLoadAction postLoadAction;
|
||||||
|
|
||||||
@ -30,11 +32,16 @@ public class DropTable implements PreloadedObject {
|
|||||||
this.postLoadAction.cacheConfig(config);
|
this.postLoadAction.cacheConfig(config);
|
||||||
|
|
||||||
this.id = config.getName();
|
this.id = config.getName();
|
||||||
|
this.shuffle = config.getBoolean("shuffle");
|
||||||
|
this.capacity = config.getDouble("capacity", LootBuilder.DEFAULT_CAPACITY);
|
||||||
|
Validate.isTrue(capacity >= 0, "Capacity must be positive");
|
||||||
}
|
}
|
||||||
|
|
||||||
public DropTable(String id) {
|
public DropTable(String id) {
|
||||||
this.postLoadAction = generatePostLoadAction();
|
this.postLoadAction = generatePostLoadAction();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.capacity = 100;
|
||||||
|
this.shuffle = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PostLoadAction generatePostLoadAction() {
|
private PostLoadAction generatePostLoadAction() {
|
||||||
@ -76,13 +83,27 @@ public class DropTable implements PreloadedObject {
|
|||||||
drops.add(item);
|
drops.add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<DropItem> getDrops() {
|
public double getCapacity() {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public List<DropItem> getDrops() {
|
||||||
return drops;
|
return drops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public List<ItemStack> collect(LootBuilder builder) {
|
public List<ItemStack> collect(LootBuilder builder) {
|
||||||
|
|
||||||
for (DropItem item : drops)
|
// Shuffle items?
|
||||||
|
final List<DropItem> items;
|
||||||
|
if (shuffle) {
|
||||||
|
items = new ArrayList<>(drops);
|
||||||
|
Collections.shuffle(items);
|
||||||
|
} else items = drops;
|
||||||
|
|
||||||
|
// Collect items
|
||||||
|
for (DropItem item : items)
|
||||||
if (item.rollChance(builder.getEntity()) && builder.getCapacity() >= item.getWeight()) {
|
if (item.rollChance(builder.getEntity()) && builder.getCapacity() >= item.getWeight()) {
|
||||||
item.collect(builder);
|
item.collect(builder);
|
||||||
builder.reduceCapacity(item.getWeight());
|
builder.reduceCapacity(item.getWeight());
|
||||||
@ -91,7 +112,8 @@ public class DropTable implements PreloadedObject {
|
|||||||
return builder.getLoot();
|
return builder.getLoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Condition> getConditions() {
|
@NotNull
|
||||||
|
public List<Condition> getConditions() {
|
||||||
return conditions;
|
return conditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,8 +14,6 @@ public abstract class DropItem {
|
|||||||
private final double chance, weight;
|
private final double chance, weight;
|
||||||
private final RandomAmount amount;
|
private final RandomAmount amount;
|
||||||
|
|
||||||
private static final double CHANCE_COEFFICIENT = 7. / 100;
|
|
||||||
|
|
||||||
public DropItem(MMOLineConfig config) {
|
public DropItem(MMOLineConfig config) {
|
||||||
chance = config.args().length > 0 ? Double.parseDouble(config.args()[0]) : 1;
|
chance = config.args().length > 0 ? Double.parseDouble(config.args()[0]) : 1;
|
||||||
amount = config.args().length > 1 ? new RandomAmount(config.args()[1]) : new RandomAmount(1, 1);
|
amount = config.args().length > 1 ? new RandomAmount(config.args()[1]) : new RandomAmount(1, 1);
|
||||||
@ -38,16 +36,14 @@ public abstract class DropItem {
|
|||||||
return amount.calculateInt();
|
return amount.calculateInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// TODO make it configurable
|
||||||
* CHANCE stat = 0 | tier chances are unchanged
|
@Deprecated
|
||||||
* CHANCE stat = +inf | uniform law for any drop item
|
public static final double CHANCE_FACTOR = 7. / 100, CHANCE_POWER = 0.33333333333;
|
||||||
* CHANCE stat = 100 | all tier chances are taken their square root
|
|
||||||
*
|
|
||||||
* @return The real weight of an item considering the player's CHANCE stat.
|
|
||||||
*/
|
|
||||||
public boolean rollChance(PlayerData player) {
|
public boolean rollChance(PlayerData player) {
|
||||||
double value = random.nextDouble();
|
final double effectiveLuck = CHANCE_FACTOR * MMOCore.plugin.configManager.dropItemsChanceWeight * player.getStats().getStat("CHANCE");
|
||||||
return value < Math.pow(chance, 1 / Math.pow(1 + CHANCE_COEFFICIENT * MMOCore.plugin.configManager.dropItemsChanceWeight* player.getStats().getStat("CHANCE"), 1.0 / 3.0));
|
final double randomValue = random.nextDouble();
|
||||||
|
return randomValue < Math.pow(chance, Math.pow(1 + effectiveLuck, CHANCE_POWER));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void collect(LootBuilder builder);
|
public abstract void collect(LootBuilder builder);
|
||||||
|
@ -87,7 +87,7 @@ public class BlockListener implements Listener {
|
|||||||
|
|
||||||
// Find the block drops
|
// Find the block drops
|
||||||
boolean conditionsMet = !info.hasDropTable() || info.getDropTable().areConditionsMet(new ConditionInstance(player));
|
boolean conditionsMet = !info.hasDropTable() || info.getDropTable().areConditionsMet(new ConditionInstance(player));
|
||||||
List<ItemStack> drops = conditionsMet && info.hasDropTable() ? info.getDropTable().collect(new LootBuilder(PlayerData.get(player), 0)) : new ArrayList<>();
|
List<ItemStack> drops = conditionsMet && info.hasDropTable() ? info.getDropTable().collect(new LootBuilder(PlayerData.get(player), info.getDropTable().getCapacity())) : new ArrayList<>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calls the event and listen for cancel & for drops changes... also
|
* Calls the event and listen for cancel & for drops changes... also
|
||||||
|
@ -170,7 +170,7 @@ public class FishingListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find looted item
|
// Find looted item
|
||||||
ItemStack collect = caught.collect(new LootBuilder(playerData, 0));
|
ItemStack collect = caught.collect(new LootBuilder(playerData));
|
||||||
if (collect == null) {
|
if (collect == null) {
|
||||||
hook.getWorld().spawnParticle(VParticle.SMOKE.get(), location, 24, 0, 0, 0, .08);
|
hook.getWorld().spawnParticle(VParticle.SMOKE.get(), location, 24, 0, 0, 0, .08);
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user