Mineplex/GOD DAMN COSMETICS/treasure/reward/TreasureRewardManager.java
Daniel Waggner 38a20f98c2 Removed Files
These two directories contain code that was removed from the src and dependencies of the compiled files. They were removed due to being either a. unnecessary or b. a royal pain in my booty.
2021-05-23 18:13:37 -07:00

296 lines
9.2 KiB
Java

package mineplex.core.treasure.reward;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.bukkit.entity.Player;
import mineplex.core.MiniPlugin;
import mineplex.core.ReflectivelyCreateMiniPlugin;
import mineplex.core.common.util.UtilMath;
import mineplex.core.common.weight.WeightSet;
import mineplex.core.reward.Reward;
import mineplex.core.reward.rewards.RankReward;
import mineplex.core.reward.rewards.TreasureShardReward;
import mineplex.core.treasure.types.Treasure;
/**
* This manager serves as a random reward generator.
* A lot of this was adapted from the previous reward manager, so if you've come here to
* fix something then prepare yourself for a shock.
*/
@ReflectivelyCreateMiniPlugin
public class TreasureRewardManager extends MiniPlugin
{
/**
* For all the reward algorithms, if a condition cannot be met within {@value} iterations then it gives up.
* {@value} is a very generous threshold and most likely, unless due to error, each one should complete in one
* or two iterations.
*/
private static final int MAX_ATTEMPTS = 40;
private final Map<Treasure, Map<RewardRarity, WeightSet<Reward>>> _rewardPoolMap;
private TreasureRewardManager()
{
super("Treasure Rewards");
_rewardPoolMap = new HashMap<>();
}
/**
* Adds a reward into the pool for a particular chest type.
*
* @param treasure The {@link Treasure}'s pool you want to add the reward to.
* @param reward The {@link Reward} you want to add to the pool.
* @param weight The weight of the reward, bigger weight, more probable to be picked.
*/
public void addReward(Treasure treasure, Reward reward, int weight)
{
// Populate the map if absent
_rewardPoolMap.computeIfAbsent(treasure, k -> new HashMap<>());
// Populate the inner map if absent
Map<RewardRarity, WeightSet<Reward>> map = _rewardPoolMap.get(treasure);
map.computeIfAbsent(reward.getRarity(), k -> new WeightSet<>());
// Add the reward to the WeightSet
map.get(reward.getRarity()).add(weight, reward);
}
/**
* Returns whether or not a player has all the items within a chest's pool
*
* @param player The player you want to checl.
* @param treasure The {@link Treasure} you want to search through the pool of.
* @return a boolean value of if the player has all the items within a chest's pool.
*/
public boolean hasAllItems(Player player, Treasure treasure)
{
Map<RewardRarity, WeightSet<Reward>> rewardMap = _rewardPoolMap.get(treasure);
// Null entry, programmer error
return rewardMap == null || getOwnedItems(player, treasure) == getTotalItems(treasure);
}
/**
* Returns the number of items a player owns within a chest's pool
*
* @param player The player you want to check.
* @param treasure The {@link Treasure} you want to search through the pool of.
* @return an integer value of the amount of items the player has within a chest's pool.
*/
public int getOwnedItems(Player player, Treasure treasure)
{
Map<RewardRarity, WeightSet<Reward>> rewardMap = _rewardPoolMap.get(treasure);
// Null entry, programmer error
if (rewardMap == null)
{
return 0;
}
int owned = 0;
// Check every reward
for (WeightSet<Reward> weightSet : rewardMap.values())
{
for (Reward reward : weightSet.elements())
{
// If the player cannot be given that reward
if (!reward.canGiveReward(player))
{
owned++;
}
}
}
return owned;
}
/**
* Returns the total number of items within a chest's pool.
*
* @param treasure The {@link Treasure} you want to search through the pool of.
* @return an integer value of the amount of items the chest has within it's pool.
*/
public int getTotalItems(Treasure treasure)
{
Map<RewardRarity, WeightSet<Reward>> rewardMap = _rewardPoolMap.get(treasure);
// Null entry, programmer error
if (rewardMap == null)
{
return 0;
}
int amount = 0;
// Check every reward
for (WeightSet<Reward> weightSet : rewardMap.values())
{
amount += weightSet.elements().size();
}
return amount;
}
/**
* Returns a list of random rewards that can be awarded to a player.
*
* @param player The player you want to give the rewards to.
* @param treasure The {@link Treasure} you want to search through the pool of.
* @return A {@link List} the size of {@link Treasure#getRewardsPerChest()} and with the contents of random rewards
* that can be given to the player or null if an error has occurred.
*/
public List<Reward> getRewards(Player player, Treasure treasure)
{
Map<RewardRarity, WeightSet<Reward>> rewardMap = _rewardPoolMap.get(treasure);
// Null entry, programmer error
if (rewardMap == null)
{
return null;
}
// The list of rewards that will be returned
List<Reward> rewards = new ArrayList<>(treasure.getRewardsPerChest());
// These variables here are used to ensure that each chest opening will always contain at least one uncommon
// but never more than one mythical.
boolean hasUncommon = false;
boolean hasMythical = false;
int attempts = 0;
for (int i = 0; i < treasure.getRewardsPerChest(); i++)
{
attempts++;
Reward reward = nextReward(player, treasure, rewardMap, i, hasUncommon, hasMythical);
// If the reward was null then the reward could not have been given to the player
if (reward == null)
{
// At this point if it has taken 20+ attempts to find a reward and it's still null, then there seems to
// be a problem with the chest's pool or a programmer error.
if (attempts > MAX_ATTEMPTS)
{
return null;
}
// We run the loop again
i--;
continue;
}
RewardRarity rarity = reward.getRarity();
// If the reward is as or more uncommon than an uncommon
if (rarity.ordinal() >= RewardRarity.UNCOMMON.ordinal())
{
hasUncommon = true;
}
// If the reward is as more uncommon than an mythical
if (rarity.ordinal() >= RewardRarity.MYTHICAL.ordinal())
{
hasMythical = true;
}
// Add the reward to our list of rewards
rewards.add(reward);
}
// Due to the last reward always being an uncommon or better, we swap it randomly with another element as to
// appear more random.
Collections.swap(rewards, rewards.size() - 1, UtilMath.r(rewards.size()));
return rewards;
}
/**
* This determines the rarity of the reward.
*
* @param player The player you want to give the reward to.
* @param treasure The {@link Treasure} you want to search through the pool of.
* @param rewardMap The map of rarities and weights.
* @param index The current index of this reward, for example the first chest to open will have an index of 0, second 1 etc...
* @param hasUncommon Does the current list of rewards contain an uncommon or better?
* @param hasMythical Does the current list of rewards contain a mythical or better?
* @return A random reward that can be given to the player or null if not or an error has occurred.
*/
private Reward nextReward(Player player, Treasure treasure, Map<RewardRarity, WeightSet<Reward>> rewardMap, int index, boolean hasUncommon, boolean hasMythical)
{
RewardRarity rarity = treasure.getRewardType().generateRarity();
int attempts = 0;
// If the reward list already contains a mythical, keep trying until it isn't one
while (attempts++ < MAX_ATTEMPTS && hasMythical && rarity == RewardRarity.MYTHICAL)
{
rarity = treasure.getRewardType().generateRarity();
}
// If we are on the last reward and there hasn't been an uncommon then make sure this reward is uncommon
// Additional duplicates check is needed as chests without duplicates can only contain rare or above.
if (!hasUncommon && treasure.isDuplicates() && treasure.getRewardsPerChest() > 1 && index == treasure.getRewardsPerChest() - 1)
{
rarity = RewardRarity.UNCOMMON;
}
WeightSet<Reward> rewardSet = rewardMap.get(rarity);
// Null entry, programmer error
if (rewardSet == null || rewardSet.elements().isEmpty())
{
return null;
}
// If the chest doesn't give duplicates
if (!treasure.isDuplicates())
{
// Clone the set as we modify it below
rewardSet = new WeightSet<>(rewardSet);
// Remove all elements if they cannot be given to a player
rewardSet.removeIf(rewardWeight -> !rewardWeight.getValue().canGiveReward(player));
}
// Nothing for this rarity
if (rewardSet.elements().isEmpty())
{
return null;
}
return nextReward(player, treasure, rewardSet);
}
/**
* This determines the actual reward.
*
* @param player The player you want to give the reward to.
* @param treasure The {@link Treasure} you want to search through the pool of.
* @param rewardSet The set of reward weights.
* @return A random reward that can be given to the player or null if not or an error has occurred.
*/
private Reward nextReward(Player player, Treasure treasure, WeightSet<Reward> rewardSet)
{
// Get a random reward
Reward reward = rewardSet.generateRandom();
// If the chest can award duplicates and the player cannot be given the reward, give a shard reward instead.
if (!reward.canGiveReward(player))
{
if (reward instanceof RankReward)
{
return null;
}
else if (treasure.isDuplicates())
{
return new TreasureShardReward(reward, reward.getRarity());
}
}
return reward;
}
}