This commit is contained in:
Indyuce 2020-12-20 17:33:17 +01:00
parent 35b590fad6
commit 6b61c9dea4
8 changed files with 162 additions and 103 deletions

View File

@ -49,6 +49,7 @@ public class ItemStackBuilder {
*
* @param mmoitem The mmoitem you want to build
*/
@SuppressWarnings("unused")
public ItemStackBuilder(MMOItem mmoitem) {
this.mmoitem = mmoitem;

View File

@ -24,10 +24,12 @@ public class MMOItem implements ItemReference {
/**
* Constructor used to generate an ItemStack based on some stat data
*
* @param type The type of the item you want to create
* @param id The id of the item, make sure it is different from other
* existing items not to interfere with MI features like the
* dynamic item updater
* @param type
* The type of the item you want to create
* @param id
* The id of the item, make sure it is different from other
* existing items not to interfere with MI features like the
* dynamic item updater
*/
public MMOItem(Type type, String id) {
this.type = type;

View File

@ -17,9 +17,7 @@ import net.Indyuce.mmoitems.api.player.RPGPlayer;
* so this can be performance heavy
*
* @author cympe
*
*/
@SuppressWarnings("UnusedReturnValue")
public class TemplateExplorer {
private final Random random = new Random();
@ -40,19 +38,20 @@ public class TemplateExplorer {
public Optional<MMOItemTemplate> rollLoot() {
switch (count()) {
case 0:
return Optional.empty();
case 1:
return all.stream().findFirst();
default:
return all.stream().skip(random.nextInt(count())).findFirst();
case 0:
return Optional.empty();
case 1:
return all.stream().findFirst();
default:
return all.stream().skip(random.nextInt(count())).findFirst();
}
}
/**
* Util method to easily generate random MI loot
*
* @param player The player
* @param player
* The player
* @return Random item with random tier and item level which matches the
* player's level
*/

View File

@ -60,9 +60,9 @@ public class PlayerData {
private RPGPlayer rpgPlayer;
/*
* the inventory is all the items the player can actually use. items are cached
* here to check if the player's items changed, if so just update inventory
* TODO improve player inventory checkup method
* the inventory is all the items the player can actually use. items are
* cached here to check if the player's items changed, if so just update
* inventory TODO improve player inventory checkup method
*/
private ItemStack helmet = null, chestplate = null, leggings = null, boots = null, hand = null, offhand = null;
private final List<VolatileMMOItem> playerInventory = new ArrayList<>();
@ -74,8 +74,8 @@ public class PlayerData {
private final Map<CooldownType, Long> extraCooldowns = new HashMap<>();
/*
* specific stat calculation
* TODO compress it in Map<ItemStat, DynamicStatData>
* specific stat calculation TODO compress it in Map<ItemStat,
* DynamicStatData>
*/
private final Map<PotionEffectType, PotionEffect> permanentEffects = new HashMap<>();
private final Set<ParticleRunnable> itemParticles = new HashSet<>();
@ -104,7 +104,8 @@ public class PlayerData {
if (MMOItems.plugin.hasPermissions() && config.contains("permissions-from-items")) {
Permission perms = MMOItems.plugin.getVault().getPermissions();
config.getStringList("permissions-from-items").forEach(perm -> {
if (perms.has(getPlayer(), perm)) perms.playerRemove(getPlayer(), perm);
if (perms.has(getPlayer(), perm))
perms.playerRemove(getPlayer(), perm);
});
}
}
@ -149,9 +150,11 @@ public class PlayerData {
}
public void checkForInventoryUpdate() {
if (!mmoData.isOnline()) return;
if (!mmoData.isOnline())
return;
PlayerInventory inv = getPlayer().getInventory();
if (isNotSame(helmet, inv.getHelmet()) || isNotSame(chestplate, inv.getChestplate()) || isNotSame(leggings, inv.getLeggings()) || isNotSame(boots, inv.getBoots()) || isNotSame(hand, inv.getItemInMainHand()) || isNotSame(offhand, inv.getItemInOffHand()))
if (isNotSame(helmet, inv.getHelmet()) || isNotSame(chestplate, inv.getChestplate()) || isNotSame(leggings, inv.getLeggings())
|| isNotSame(boots, inv.getBoots()) || isNotSame(hand, inv.getItemInMainHand()) || isNotSame(offhand, inv.getItemInOffHand()))
updateInventory();
}
@ -165,7 +168,8 @@ public class PlayerData {
public void cancelRunnables() {
itemParticles.forEach(BukkitRunnable::cancel);
if (overridingItemParticles != null) overridingItemParticles.cancel();
if (overridingItemParticles != null)
overridingItemParticles.cancel();
}
/*
@ -173,14 +177,17 @@ public class PlayerData {
* one two handed item and one other item at the same time. this will
*/
public boolean areHandsFull() {
if (!mmoData.isOnline()) return false;
if (!mmoData.isOnline())
return false;
NBTItem main = MMOLib.plugin.getVersion().getWrapper().getNBTItem(getPlayer().getInventory().getItemInMainHand());
NBTItem off = MMOLib.plugin.getVersion().getWrapper().getNBTItem(getPlayer().getInventory().getItemInOffHand());
return (main.getBoolean("MMOITEMS_TWO_HANDED") && (off.getItem() != null && off.getItem().getType() != Material.AIR)) || (off.getBoolean("MMOITEMS_TWO_HANDED") && (main.getItem() != null && main.getItem().getType() != Material.AIR));
return (main.getBoolean("MMOITEMS_TWO_HANDED") && (off.getItem() != null && off.getItem().getType() != Material.AIR))
|| (off.getBoolean("MMOITEMS_TWO_HANDED") && (main.getItem() != null && main.getItem().getType() != Material.AIR));
}
public void updateInventory() {
if (!mmoData.isOnline()) return;
if (!mmoData.isOnline())
return;
/*
* very important, clear particle data AFTER canceling the runnable
* otherwise it cannot cancel and the runnable keeps going (severe)
@ -211,16 +218,19 @@ public class PlayerData {
NBTItem nbtItem = item.newNBTItem();
Type type = Type.get(nbtItem.getType());
if (type == null) continue;
if (type == null)
continue;
/*
* if the player is holding an item the wrong way i.e if the item is
* not in the right slot. intuitive methods with small exceptions
* like BOTH_HANDS and ANY
*/
if (!item.matches(type)) continue;
if (!item.matches(type))
continue;
if (!getRPG().canUse(nbtItem, false)) continue;
if (!getRPG().canUse(nbtItem, false))
continue;
playerInventory.add(new VolatileMMOItem(nbtItem));
}
@ -243,8 +253,10 @@ public class PlayerData {
ParticleData particleData = (ParticleData) item.getData(ItemStats.ITEM_PARTICLES);
if (particleData.getType().hasPriority()) {
if (overridingItemParticles == null) overridingItemParticles = particleData.start(this);
} else itemParticles.add(particleData.start(this));
if (overridingItemParticles == null)
overridingItemParticles = particleData.start(this);
} else
itemParticles.add(particleData.start(this));
}
/*
@ -254,9 +266,11 @@ public class PlayerData {
// if the item with the abilities is in the players offhand AND
// its disabled in the config then just move on, else add the
// ability
if (item.getNBT().getItem().equals(getPlayer().getInventory().getItemInOffHand()) && MMOItems.plugin.getConfig().getBoolean("disable-abilities-in-offhand")) {
if (item.getNBT().getItem().equals(getPlayer().getInventory().getItemInOffHand())
&& MMOItems.plugin.getConfig().getBoolean("disable-abilities-in-offhand")) {
continue;
} else itemAbilities.addAll(((AbilityListData) item.getData(ItemStats.ABILITIES)).getAbilities());
} else
itemAbilities.addAll(((AbilityListData) item.getData(ItemStats.ABILITIES)).getAbilities());
}
/*
@ -282,7 +296,8 @@ public class PlayerData {
for (VolatileMMOItem item : getMMOItems()) {
String tag = item.getNBT().getString("MMOITEMS_ITEM_SET");
ItemSet itemSet = MMOItems.plugin.getSets().get(tag);
if (itemSet == null) continue;
if (itemSet == null)
continue;
int nextInt = (sets.getOrDefault(itemSet, 0)) + 1;
sets.put(itemSet, nextInt);
@ -327,13 +342,15 @@ public class PlayerData {
}
public void updateStats() {
if (!mmoData.isOnline()) return;
if (!mmoData.isOnline())
return;
// perm effects
permanentEffects.keySet().forEach(effect -> getPlayer().addPotionEffect(permanentEffects.get(effect)));
// two handed
if (fullHands) getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 40, 1, true, false));
if (fullHands)
getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 40, 1, true, false));
}
public SetBonuses getSetBonuses() {
@ -370,7 +387,8 @@ public class PlayerData {
private boolean hasAbility(CastingMode castMode) {
for (AbilityData ability : itemAbilities)
if (ability.getCastingMode() == castMode) return true;
if (ability.getCastingMode() == castMode)
return true;
return false;
}
@ -381,24 +399,29 @@ public class PlayerData {
* performance improvement, do not cache the player stats into a
* CachedStats if the player has no ability on that cast mode
*/
if (!hasAbility(castMode)) return result;
if (!hasAbility(castMode))
return result;
return castAbilities(getStats().newTemporary(), target, result, castMode);
}
public ItemAttackResult castAbilities(CachedStats stats, LivingEntity target, ItemAttackResult result, CastingMode castMode) {
if (!mmoData.isOnline()) return result;
if (!mmoData.isOnline())
return result;
/*
* if ability has target, check for ability flag at location of target
* and make sure player can attack target. if ability has no target,
* check for WG flag at the caster location
*/
if (target == null ? !MMOItems.plugin.getFlags().isFlagAllowed(getPlayer(), CustomFlag.MI_ABILITIES) : !MMOItems.plugin.getFlags().isFlagAllowed(target.getLocation(), CustomFlag.MI_ABILITIES) || !MMOUtils.canDamage(getPlayer(), target))
if (target == null ? !MMOItems.plugin.getFlags().isFlagAllowed(getPlayer(), CustomFlag.MI_ABILITIES)
: !MMOItems.plugin.getFlags().isFlagAllowed(target.getLocation(), CustomFlag.MI_ABILITIES)
|| !MMOUtils.canDamage(getPlayer(), target))
return result.setSuccessful(false);
for (AbilityData ability : itemAbilities)
if (ability.getCastingMode() == castMode) cast(stats, target, result, ability);
if (ability.getCastingMode() == castMode)
cast(stats, target, result, ability);
return result;
}
@ -420,25 +443,31 @@ public class PlayerData {
public void cast(CachedStats stats, LivingEntity target, ItemAttackResult attack, AbilityData ability) {
AbilityUseEvent event = new AbilityUseEvent(this, ability, target);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) return;
if (event.isCancelled())
return;
if (!rpgPlayer.canCast(ability)) return;
if (!rpgPlayer.canCast(ability))
return;
/*
* check if ability can be cast (custom conditions)
*/
AbilityResult abilityResult = ability.getAbility().whenRan(stats, target, ability, attack);
if (!abilityResult.isSuccessful()) return;
if (!abilityResult.isSuccessful())
return;
/*
* the player can cast the ability, and it was successfully cast on its
* target, removes resources needed from the player
*/
if (ability.hasModifier("mana")) rpgPlayer.giveMana(-abilityResult.getModifier("mana"));
if (ability.hasModifier("stamina")) rpgPlayer.giveStamina(-abilityResult.getModifier("stamina"));
if (ability.hasModifier("mana"))
rpgPlayer.giveMana(-abilityResult.getModifier("mana"));
if (ability.hasModifier("stamina"))
rpgPlayer.giveStamina(-abilityResult.getModifier("stamina"));
double cooldown = abilityResult.getModifier("cooldown") * (1 - Math.min(.8, stats.getStat(ItemStats.COOLDOWN_REDUCTION) / 100));
if (cooldown > 0) applyAbilityCooldown(ability.getAbility(), cooldown);
if (cooldown > 0)
applyAbilityCooldown(ability.getAbility(), cooldown);
/*
* finally cast the ability (BUG FIX) cooldown MUST be applied BEFORE
@ -502,7 +531,8 @@ public class PlayerData {
}
public static PlayerData get(UUID uuid) {
if (PlayerData.data.containsKey(uuid)) return data.get(uuid);
if (PlayerData.data.containsKey(uuid))
return data.get(uuid);
return new PlayerData(MMOPlayerData.get(uuid));
}
@ -513,13 +543,15 @@ public class PlayerData {
public static void load(Player player) {
/*
* Double check they are online, for some reason even if this is fired
* from the join event the player can be offline if they left in the same tick or something.
* from the join event the player can be offline if they left in the
* same tick or something.
*/
if (!player.isOnline() || data.containsKey(player.getUniqueId())) return;
if (!player.isOnline() || data.containsKey(player.getUniqueId()))
return;
PlayerData newData = PlayerData.get(player.getUniqueId());
/*
* update the cached RPGPlayer in case of any major
* change in the player data of other rpg plugins
* update the cached RPGPlayer in case of any major change in the player
* data of other rpg plugins
*/
newData.rpgPlayer = MMOItems.plugin.getRPG().getInfo(newData);
/* cache the playerdata */

View File

@ -1,7 +1,5 @@
package net.Indyuce.mmoitems.command;
import net.mmogroup.mmolib.MMOLib;
import net.mmogroup.mmolib.api.item.NBTItem;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@ -20,7 +18,7 @@ public class UpdateItemCommand implements CommandExecutor {
Player player = (Player) sender;
if (args.length < 1 || !player.hasPermission("mmoitems.admin")) {
NBTItem item = MMOLib.plugin.getVersion().getWrapper().getNBTItem(player.getInventory().getItemInMainHand());
// NBTItem item = MMOLib.plugin.getVersion().getWrapper().getNBTItem(player.getInventory().getItemInMainHand());
// for items generated before 2.0
/*if (!item.hasTag("MMOITEMS_ITEM_TYPE")) {

View File

@ -27,8 +27,8 @@ public class TemplateManager implements Reloadable {
private final TemplateMap<MMOItemTemplate> templates = new TemplateMap<>();
/*
* bank of item modifiers which can be used anywhere in generation templates to
* make item generation easier.
* bank of item modifiers which can be used anywhere in generation templates
* to make item generation easier.
*/
private final Map<String, TemplateModifier> modifiers = new HashMap<>();
@ -53,9 +53,9 @@ public class TemplateManager implements Reloadable {
/**
* Used in class constructors to easily
*
* @param type The item type
* @param id The item ID
* @return MMOItem template if it exists, or throws an IAE otherwise
* @param type The item type
* @param id The item ID
* @return MMOItem template if it exists, or throws an IAE otherwise
*/
public MMOItemTemplate getTemplateOrThrow(Type type, String id) {
Validate.isTrue(hasTemplate(type, id), "Could not find a template with ID '" + id + "'");
@ -78,9 +78,9 @@ public class TemplateManager implements Reloadable {
}
/**
* Unregisters a template from mmoitem registery. Must be used when an item is
* removed from the config files. Also disables the dynamic updater for that
* item
* Unregisters a template from mmoitem registery. Must be used when an item
* is removed from the config files. Also disables the dynamic updater for
* that item
*
* @param type The item type
* @param id The item ID
@ -90,8 +90,8 @@ public class TemplateManager implements Reloadable {
}
/**
* Unregisters a template from mmoitem registery and clears it from the config
* file
* Unregisters a template from mmoitem registery and clears it from the
* config file
*
* @param type The item type
* @param id The item ID
@ -109,8 +109,8 @@ public class TemplateManager implements Reloadable {
* method unregisters the current template and loads it again from the
* configuration file.
*
* Can also be used right after creating a template after the config file has
* been initialized in order to load the newly created item
* Can also be used right after creating a template after the config file
* has been initialized in order to load the newly created item
*
* @param type The item type
* @param id The item ID
@ -120,22 +120,21 @@ public class TemplateManager implements Reloadable {
templates.removeValue(type, id);
try {
MMOItemTemplate template = new MMOItemTemplate(type,
type.getConfigFile().getConfig().getConfigurationSection(id));
MMOItemTemplate template = new MMOItemTemplate(type, type.getConfigFile().getConfig().getConfigurationSection(id));
template.postLoad();
registerTemplate(template);
return template;
} catch (IllegalArgumentException exception) {
MMOItems.plugin.getLogger().log(Level.INFO, "An error occured while trying to reload item gen template '"
+ id + "': " + exception.getMessage());
MMOItems.plugin.getLogger().log(Level.INFO,
"An error occured while trying to reload item gen template '" + id + "': " + exception.getMessage());
return null;
}
}
/**
* @return Collects all existing mmoitem templates into a set so that it can be
* filtered afterwards to generate random loot
* @return Collects all existing mmoitem templates into a set so that it can
* be filtered afterwards to generate random loot
*/
public Collection<MMOItemTemplate> collectTemplates() {
return templates.collectValues();
@ -168,10 +167,11 @@ public class TemplateManager implements Reloadable {
}
/**
* @param playerLevel Input player level
* @return Generates a randomly chosen item level. The level spread (editable in
* the main config file) corresponding to the standard deviation of a
* gaussian distribution centered on the player level (input)
* @param playerLevel Input player level
* @return Generates a randomly chosen item level. The level
* spread (editable in the main config file)
* corresponding to the standard deviation of a gaussian
* distribution centered on the player level (input)
*/
public int rollLevel(int playerLevel) {
double spread = MMOItems.plugin.getLanguage().levelSpread;
@ -184,7 +184,6 @@ public class TemplateManager implements Reloadable {
return (int) found;
}
/**
* Templates must be loaded whenever MMOItems enables so that other plugins
* like MMOCore can load template references in drop items or other objects.

View File

@ -1,5 +1,16 @@
package net.Indyuce.mmoitems.stat.type;
import java.text.DecimalFormat;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.api.edition.StatEdition;
@ -15,15 +26,6 @@ import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.data.type.UpgradeInfo;
import net.mmogroup.mmolib.api.item.ItemTag;
import net.mmogroup.mmolib.api.util.AltChar;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.text.DecimalFormat;
import java.util.List;
public class DoubleStat extends ItemStat implements Upgradable {
private static final DecimalFormat digit = new DecimalFormat("0.####");
@ -36,6 +38,13 @@ public class DoubleStat extends ItemStat implements Upgradable {
super(id, mat, name, lore, types, materials);
}
/**
* @return If this stat supports negatives stat values
*/
public boolean handleNegativeStats() {
return true;
}
@Override
public RandomStatData whenInitialized(Object object) {
@ -51,16 +60,15 @@ public class DoubleStat extends ItemStat implements Upgradable {
@Override
public void whenApplied(ItemStackBuilder item, StatData data) {
double value = ((DoubleData) data).getValue();
// If value is not allowed to be negative it will not
// apply the stat or the lore.
if (value < 0 && !canNegative())
if (value < 0 && !handleNegativeStats())
return;
// If the value is 0 the lore will not be applied
// but the stat will still be added to the nbt
if (value != 0)
item.getLore().insert(getPath(), formatNumericStat(value, "#", new StatFormat("##").format(value)));
item.addItemTag(new ItemTag(getNBTPath(), value));
item.addItemTag(new ItemTag(getNBTPath(), value));
}
@Override
@ -72,18 +80,44 @@ public class DoubleStat extends ItemStat implements Upgradable {
return;
}
new StatEdition(inv, this).enable("Write in the chat the numeric value you want.",
"Second Format: {Base} {Scaling Value} {Spread} {Max Spread}");
"Second Format: {Base} {Scaling Value} {Spread} {Max Spread}", "Third Format: {Min Value} -> {Max Value}");
}
@Override
public void whenInput(EditionInventory inv, String message, Object... info) {
String[] split = message.split(" ");
double base = MMOUtils.parseDouble(split[0]);
double scale = split.length > 1 ? MMOUtils.parseDouble(split[1]) : 0;
double spread = split.length > 2 ? MMOUtils.parseDouble(split[2]) : 0;
double maxSpread = split.length > 3 ? MMOUtils.parseDouble(split[3]) : 0;
double base, scale, spread, maxSpread;
// save as number
/**
* Supports the old RANGE formula with a minimum and a maximum value and
* automatically makes the conversion to the newest system. This way
* users can keep using the old system if they don't want to adapt to
* the complex gaussian stat calculation
*/
if (message.contains("->")) {
String[] split = message.replace(" ", "").split(Pattern.quote("->"));
Validate.isTrue(split.length > 1, "You must specif two (both min and max) values");
double min = Double.parseDouble(split[0]), max = Double.parseDouble(split[1]);
Validate.isTrue(max > min, "Max value must be greater than min value");
base = MMOUtils.truncation(min == -max ? (max - min) * .05 : (min + max) / 2, 3);
scale = 0; // No scale
maxSpread = MMOUtils.truncation((max - min) / (2 * base), 3);
spread = MMOUtils.truncation(.8 * maxSpread, 3);
}
/**
* Newest system with gaussian values calculation
*/
else {
String[] split = message.split(" ");
base = MMOUtils.parseDouble(split[0]);
scale = split.length > 1 ? MMOUtils.parseDouble(split[1]) : 0;
spread = split.length > 2 ? MMOUtils.parseDouble(split[2]) : 0;
maxSpread = split.length > 3 ? MMOUtils.parseDouble(split[3]) : 0;
}
// Save as a flat formula
if (scale == 0 && spread == 0 && maxSpread == 0)
inv.getEditedSection().set(getPath(), base);

View File

@ -210,10 +210,4 @@ public abstract class ItemStat {
String str = MMOItems.plugin.getLanguage().getStatFormat(path);
return str == null ? "<TranslationNotFound:" + path + ">" : str;
}
// Sets if the double value is allowed to be
// a negative.
public boolean canNegative() {
return true;
}
}