Merge branch 'master' of github.com:mcMMO-Dev/mcMMO into tridentsxbows

This commit is contained in:
nossr50
2020-11-11 16:42:53 -08:00
197 changed files with 11978 additions and 9566 deletions

View File

@@ -67,7 +67,7 @@ public final class BlockUtils {
* @return true if the block awards XP, false otherwise
*/
public static boolean shouldBeWatched(BlockState blockState) {
return affectedByGigaDrillBreaker(blockState) || affectedByGreenTerra(blockState) || affectedBySuperBreaker(blockState) || isLog(blockState)
return affectedByGigaDrillBreaker(blockState) || affectedByGreenTerra(blockState) || affectedBySuperBreaker(blockState) || hasWoodcuttingXP(blockState)
|| Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType())
|| Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.EXCAVATION, blockState.getType())
|| Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType())
@@ -208,10 +208,8 @@ public final class BlockUtils {
* @param blockState The {@link BlockState} of the block to check
* @return true if the block is a log, false otherwise
*/
public static boolean isLog(BlockState blockState) {
if (ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.WOODCUTTING, blockState.getBlockData()))
return true;
return mcMMO.getModManager().isCustomLog(blockState);
public static boolean hasWoodcuttingXP(BlockState blockState) {
return ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.WOODCUTTING, blockState.getBlockData());
}
/**
@@ -220,8 +218,12 @@ public final class BlockUtils {
* @param blockState The {@link BlockState} of the block to check
* @return true if the block is a leaf, false otherwise
*/
public static boolean isLeaves(BlockState blockState) {
return mcMMO.getMaterialMapStore().isLeavesWhiteListed(blockState.getType());
public static boolean isNonWoodPartOfTree(BlockState blockState) {
return mcMMO.getMaterialMapStore().isTreeFellerDestructible(blockState.getType());
}
public static boolean isNonWoodPartOfTree(Material material) {
return mcMMO.getMaterialMapStore().isTreeFellerDestructible(material);
}
/**
@@ -330,4 +332,8 @@ public final class BlockUtils {
}
return true;
}
public static boolean isPartOfTree(Block rayCast) {
return hasWoodcuttingXP(rayCast.getState()) || isNonWoodPartOfTree(rayCast.getType());
}
}

View File

@@ -43,7 +43,9 @@ import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
@@ -51,10 +53,30 @@ import java.util.Map;
/**
* This class is meant to help make event related code less boilerplate
*/
public class EventUtils {
public final class EventUtils {
/**
* This is a static utility class, therefore we don't want any instances of
* this class. Making the constructor private prevents accidents like that.
*/
private EventUtils() {}
/*
* Quality of Life methods
*/
/**
* This is a simple check to see if an {@link Event} is fake or not.
* {@link FakeEvent FakeEvents} should not be processed like normally and maybe even
* be ignored by other {@link Plugin plugins} completely.
*
* @param event The {@link Event} in question
* @return Whether this {@link Event} has been faked by mcMMO and should not be processed normally.
*/
public static boolean isFakeEvent(@NotNull Event event) {
return event instanceof FakeEvent;
}
/**
* Checks to see if damage is from natural sources
* This cannot be used to determine if damage is from vanilla MC, it just checks to see if the damage is from a complex behaviour in mcMMO such as bleed.
@@ -62,16 +84,17 @@ public class EventUtils {
* @param event this event
* @return true if damage is NOT from an unnatural mcMMO skill (such as bleed DOTs)
*/
public static boolean isDamageFromMcMMOComplexBehaviour(Event event) {
public static boolean isDamageFromMcMMOComplexBehaviour(@NotNull Event event) {
return event instanceof FakeEntityDamageEvent;
}
/**
* This little method is just to make the code more readable
*
* @param entity target entity
* @return the associated McMMOPlayer for this entity
*/
public static McMMOPlayer getMcMMOPlayer(Entity entity)
public static McMMOPlayer getMcMMOPlayer(@NotNull Entity entity)
{
return mcMMO.getUserManager().queryMcMMOPlayer((Player)entity);
}
@@ -89,7 +112,7 @@ public class EventUtils {
* @param entityDamageEvent
* @return
*/
public static boolean isRealPlayerDamaged(EntityDamageEvent entityDamageEvent)
public static boolean isRealPlayerDamaged(@NotNull EntityDamageEvent entityDamageEvent)
{
//Make sure the damage is above 0
double damage = entityDamageEvent.getFinalDamage();
@@ -144,14 +167,14 @@ public class EventUtils {
* Others
*/
public static McMMOPlayerAbilityActivateEvent callPlayerAbilityActivateEvent(Player player, PrimarySkillType skill) {
public static @NotNull McMMOPlayerAbilityActivateEvent callPlayerAbilityActivateEvent(@NotNull Player player, @NotNull PrimarySkillType skill) {
McMMOPlayerAbilityActivateEvent event = new McMMOPlayerAbilityActivateEvent(player, skill);
mcMMO.p.getServer().getPluginManager().callEvent(event);
return event;
}
public static McMMOPlayerProfileLoadEvent callPlayerProfileLoadEvent(Player player, PlayerProfile profile){
public static @NotNull McMMOPlayerProfileLoadEvent callPlayerProfileLoadEvent(@NotNull Player player, @NotNull PlayerProfile profile){
McMMOPlayerProfileLoadEvent event = new McMMOPlayerProfileLoadEvent(player, profile);
mcMMO.p.getServer().getPluginManager().callEvent(event);

View File

@@ -10,6 +10,7 @@ import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.sounds.SoundManager;
import com.gmail.nossr50.util.sounds.SoundType;
import com.gmail.nossr50.util.text.StringUtils;
import com.google.common.collect.ImmutableList;
import org.bukkit.ChatColor;
import org.bukkit.Color;

View File

@@ -20,6 +20,10 @@ import java.util.List;
import static org.bukkit.Material.AIR;
public final class ItemUtils {
/**
* This is a static utility class, therefore we don't want any instances of
* this class. Making the constructor private prevents accidents like that.
*/
private ItemUtils() {}
/**

View File

@@ -1,6 +1,7 @@
package com.gmail.nossr50.util;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.HashSet;
@@ -15,54 +16,54 @@ import java.util.Locale;
*/
public class MaterialMapStore {
private HashSet<String> abilityBlackList;
private HashSet<String> toolBlackList;
private HashSet<String> mossyWhiteList;
private HashSet<String> leavesWhiteList;
private HashSet<String> herbalismAbilityBlackList;
private HashSet<String> blockCrackerWhiteList;
private HashSet<String> canMakeShroomyWhiteList;
private HashSet<String> multiBlockPlant;
private HashSet<String> foodItemWhiteList;
private HashSet<String> glassBlocks;
private final @NotNull HashSet<String> abilityBlackList;
private final @NotNull HashSet<String> toolBlackList;
private final @NotNull HashSet<String> mossyWhiteList;
private final @NotNull HashSet<String> treeFellerDestructibleWhiteList;
private final @NotNull HashSet<String> herbalismAbilityBlackList;
private final @NotNull HashSet<String> blockCrackerWhiteList;
private final @NotNull HashSet<String> canMakeShroomyWhiteList;
private final @NotNull HashSet<String> multiBlockPlant;
private final @NotNull HashSet<String> foodItemWhiteList;
private final @NotNull HashSet<String> glassBlocks;
private HashSet<String> netheriteArmor;
private HashSet<String> netheriteTools;
private HashSet<String> woodTools;
private HashSet<String> stoneTools;
private HashSet<String> leatherArmor;
private HashSet<String> ironArmor;
private HashSet<String> ironTools;
private HashSet<String> stringTools;
private HashSet<String> goldArmor;
private HashSet<String> goldTools;
private HashSet<String> chainmailArmor;
private HashSet<String> diamondArmor;
private HashSet<String> diamondTools;
private HashSet<String> armors;
private final @NotNull HashSet<String> netheriteArmor;
private final @NotNull HashSet<String> netheriteTools;
private final @NotNull HashSet<String> woodTools;
private final @NotNull HashSet<String> stoneTools;
private final @NotNull HashSet<String> leatherArmor;
private final @NotNull HashSet<String> ironArmor;
private final @NotNull HashSet<String> ironTools;
private final @NotNull HashSet<String> stringTools;
private final @NotNull HashSet<String> goldArmor;
private final @NotNull HashSet<String> goldTools;
private final @NotNull HashSet<String> chainmailArmor;
private final @NotNull HashSet<String> diamondArmor;
private final @NotNull HashSet<String> diamondTools;
private final @NotNull HashSet<String> armors;
private HashSet<String> swords;
private HashSet<String> axes;
private HashSet<String> hoes;
private HashSet<String> shovels;
private HashSet<String> pickAxes;
private HashSet<String> tridents;
private HashSet<String> bows;
private HashSet<String> xbows;
private HashSet<String> tools;
private final @NotNull HashSet<String> swords;
private final @NotNull HashSet<String> axes;
private final @NotNull HashSet<String> hoes;
private final @NotNull HashSet<String> shovels;
private final @NotNull HashSet<String> pickAxes;
private final @NotNull HashSet<String> tridents;
private final @NotNull HashSet<String> bows;
private final @NotNull HashSet<String> xbows;
private final @NotNull HashSet<String> tools;
private HashSet<String> enchantables;
private final @NotNull HashSet<String> enchantables;
private HashSet<String> ores;
private final @NotNull HashSet<String> ores;
private HashMap<String, Integer> tierValue;
private final @NotNull HashMap<String, Integer> tierValue;
public MaterialMapStore()
{
abilityBlackList = new HashSet<>();
toolBlackList = new HashSet<>();
mossyWhiteList = new HashSet<>();
leavesWhiteList = new HashSet<>();
treeFellerDestructibleWhiteList = new HashSet<>();
herbalismAbilityBlackList = new HashSet<>();
blockCrackerWhiteList = new HashSet<>();
canMakeShroomyWhiteList = new HashSet<>();
@@ -105,57 +106,12 @@ public class MaterialMapStore {
fillVanillaMaterialRegisters();
}
public boolean isMultiBlockPlant(Material material)
{
return multiBlockPlant.contains(material.getKey().getKey());
}
public boolean isAbilityActivationBlackListed(Material material)
{
return abilityBlackList.contains(material.getKey().getKey());
}
public boolean isToolActivationBlackListed(Material material)
{
return toolBlackList.contains(material.getKey().getKey());
}
public boolean isToolActivationBlackListed(String blockId)
{
return toolBlackList.contains(blockId);
}
public boolean isMossyWhiteListed(Material material)
{
return mossyWhiteList.contains(material.getKey().getKey());
}
public boolean isLeavesWhiteListed(Material material)
{
return leavesWhiteList.contains(material.getKey().getKey());
}
public boolean isHerbalismAbilityWhiteListed(Material material)
{
return herbalismAbilityBlackList.contains(material.getKey().getKey());
}
public boolean isBlockCrackerWhiteListed(Material material)
{
return blockCrackerWhiteList.contains(material.getKey().getKey());
}
public boolean isShroomyWhiteListed(Material material)
{
return canMakeShroomyWhiteList.contains(material.getKey().getKey());
}
private void fillVanillaMaterialRegisters()
{
fillAbilityBlackList();
fillToolBlackList();
fillMossyWhiteList();
fillLeavesWhiteList();
fillTreeFellerDestructibleWhiteList();
fillHerbalismAbilityBlackList();
fillBlockCrackerWhiteList();
fillShroomyWhiteList();
@@ -170,6 +126,45 @@ public class MaterialMapStore {
fillTierMap();
}
public boolean isMultiBlockPlant(@NotNull Material material) {
return multiBlockPlant.contains(material.getKey().getKey());
}
public boolean isAbilityActivationBlackListed(@NotNull Material material)
{
return abilityBlackList.contains(material.getKey().getKey());
}
public boolean isToolActivationBlackListed(@NotNull Material material)
{
return toolBlackList.contains(material.getKey().getKey());
}
public boolean isToolActivationBlackListed(String blockId)
{
return toolBlackList.contains(blockId);
}
public boolean isMossyWhiteListed(@NotNull Material material) {
return mossyWhiteList.contains(material.getKey().getKey());
}
public boolean isTreeFellerDestructible(@NotNull Material material) {
return treeFellerDestructibleWhiteList.contains(material.getKey().getKey());
}
public boolean isHerbalismAbilityWhiteListed(@NotNull Material material) {
return herbalismAbilityBlackList.contains(material.getKey().getKey());
}
public boolean isBlockCrackerWhiteListed(@NotNull Material material) {
return blockCrackerWhiteList.contains(material.getKey().getKey());
}
public boolean isShroomyWhiteListed(@NotNull Material material) {
return canMakeShroomyWhiteList.contains(material.getKey().getKey());
}
private void fillTierMap() {
for(String id : leatherArmor) {
tierValue.put(id, 1);
@@ -430,26 +425,7 @@ public class MaterialMapStore {
ironTools.add("iron_shovel");
//Used for repair, remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in 2.2
//TODO: Remove in config update
ironTools.add("bucket");
ironTools.add("flint_and_steel");
ironTools.add("shears");
@@ -567,7 +543,7 @@ public class MaterialMapStore {
* @param material target material
* @return true if it is used for armor
*/
public boolean isArmor(Material material) {
public boolean isArmor(@NotNull Material material) {
return isArmor(material.getKey().getKey());
}
@@ -576,220 +552,207 @@ public class MaterialMapStore {
* @param id target item id
* @return true if the item id matches armor
*/
public boolean isArmor(String id) {
public boolean isArmor(@NotNull String id) {
return armors.contains(id);
}
public boolean isTool(Material material) {
public boolean isTool(@NotNull Material material) {
return isTool(material.getKey().getKey());
}
public boolean isTool(String id) {
public boolean isTool(@NotNull String id) {
return tools.contains(id);
}
public boolean isEnchantable(Material material) {
public boolean isEnchantable(@NotNull Material material) {
return isEnchantable(material.getKey().getKey());
}
public boolean isEnchantable(String id) {
public boolean isEnchantable(@NotNull String id) {
return enchantables.contains(id);
}
public boolean isOre(Material material) {
public boolean isOre(@NotNull Material material) {
return isOre(material.getKey().getKey());
}
public boolean isOre(String id) {
public boolean isOre(@NotNull String id) {
return ores.contains(id);
}
public boolean isBow(Material material) {
public boolean isBow(@NotNull Material material) {
return isBow(material.getKey().getKey());
}
public boolean isBow(String id) {
public boolean isBow(@NotNull String id) {
return bows.contains(id);
}
public boolean isCrossbow(Material material) {
public boolean isCrossbow(@NotNull Material material) {
return isCrossbow(material.getKey().getKey());
}
public boolean isCrossbow(String id) {
public boolean isCrossbow(@NotNull String id) {
return xbows.contains(id);
}
public boolean isLeatherArmor(Material material) {
public boolean isLeatherArmor(@NotNull Material material) {
return isLeatherArmor(material.getKey().getKey());
}
public boolean isLeatherArmor(String id) {
public boolean isLeatherArmor(@NotNull String id) {
return leatherArmor.contains(id);
}
public boolean isIronArmor(Material material) {
public boolean isIronArmor(@NotNull Material material) {
return isIronArmor(material.getKey().getKey());
}
public boolean isIronArmor(String id) {
public boolean isIronArmor(@NotNull String id) {
return ironArmor.contains(id);
}
public boolean isGoldArmor(Material material) {
public boolean isGoldArmor(@NotNull Material material) {
return isGoldArmor(material.getKey().getKey());
}
public boolean isGoldArmor(String id) {
public boolean isGoldArmor(@NotNull String id) {
return goldArmor.contains(id);
}
public boolean isDiamondArmor(Material material) {
public boolean isDiamondArmor(@NotNull Material material) {
return isDiamondArmor(material.getKey().getKey());
}
public boolean isDiamondArmor(String id) {
public boolean isDiamondArmor(@NotNull String id) {
return diamondArmor.contains(id);
}
public boolean isChainmailArmor(Material material) {
public boolean isChainmailArmor(@NotNull Material material) {
return isChainmailArmor(material.getKey().getKey());
}
public boolean isChainmailArmor(String id) {
public boolean isChainmailArmor(@NotNull String id) {
return chainmailArmor.contains(id);
}
public boolean isNetheriteArmor(Material material) {
public boolean isNetheriteArmor(@NotNull Material material) {
return isNetheriteArmor(material.getKey().getKey());
}
public boolean isNetheriteArmor(String id) {
public boolean isNetheriteArmor(@NotNull String id) {
return netheriteArmor.contains(id);
}
public boolean isWoodTool(Material material) {
public boolean isWoodTool(@NotNull Material material) {
return isWoodTool(material.getKey().getKey());
}
public boolean isWoodTool(String id) {
public boolean isWoodTool(@NotNull String id) {
return woodTools.contains(id);
}
public boolean isStoneTool(Material material) {
public boolean isStoneTool(@NotNull Material material) {
return isStoneTool(material.getKey().getKey());
}
public boolean isStoneTool(String id) {
public boolean isStoneTool(@NotNull String id) {
return stoneTools.contains(id);
}
public boolean isIronTool(Material material) {
public boolean isIronTool(@NotNull Material material) {
return isIronTool(material.getKey().getKey());
}
public boolean isIronTool(String id) {
public boolean isIronTool(@NotNull String id) {
return ironTools.contains(id);
}
public boolean isGoldTool(Material material) {
public boolean isGoldTool(@NotNull Material material) {
return isGoldTool(material.getKey().getKey());
}
public boolean isGoldTool(String id) {
public boolean isGoldTool(@NotNull String id) {
return goldTools.contains(id);
}
public boolean isDiamondTool(Material material) {
public boolean isDiamondTool(@NotNull Material material) {
return isDiamondTool(material.getKey().getKey());
}
public boolean isDiamondTool(String id) {
public boolean isDiamondTool(@NotNull String id) {
return diamondTools.contains(id);
}
public boolean isTrident(Material material) { return isTrident(material.getKey().getKey()); }
public boolean isTrident(@NotNull Material material) { return isTrident(material.getKey().getKey()); }
public boolean isTrident(String id) { return tridents.contains(id); }
public boolean isTrident(@NotNull String id) { return tridents.contains(id); }
public boolean isSword(Material material) {
public boolean isSword(@NotNull Material material) {
return isSword(material.getKey().getKey());
}
public boolean isSword(String id) {
public boolean isSword(@NotNull String id) {
return swords.contains(id);
}
public boolean isAxe(Material material) {
public boolean isAxe(@NotNull Material material) {
return isAxe(material.getKey().getKey());
}
public boolean isAxe(String id) {
public boolean isAxe(@NotNull String id) {
return axes.contains(id);
}
public boolean isPickAxe(Material material) {
public boolean isPickAxe(@NotNull Material material) {
return isPickAxe(material.getKey().getKey());
}
public boolean isPickAxe(String id) {
public boolean isPickAxe(@NotNull String id) {
return pickAxes.contains(id);
}
public boolean isShovel(Material material) {
public boolean isShovel(@NotNull Material material) {
return isShovel(material.getKey().getKey());
}
public boolean isShovel(String id) {
public boolean isShovel(@NotNull String id) {
return shovels.contains(id);
}
public boolean isHoe(Material material) {
public boolean isHoe(@NotNull Material material) {
return isHoe(material.getKey().getKey());
}
public boolean isHoe(String id) {
public boolean isHoe(@NotNull String id) {
return hoes.contains(id);
}
public boolean isNetheriteTool(Material material) {
public boolean isNetheriteTool(@NotNull Material material) {
return isNetheriteTool(material.getKey().getKey());
}
public boolean isNetheriteTool(String id) {
public boolean isNetheriteTool(@NotNull String id) {
return netheriteTools.contains(id);
}
public boolean isStringTool(Material material) {
public boolean isStringTool(@NotNull Material material) {
return isStringTool(material.getKey().getKey());
}
public boolean isStringTool(String id) {
public boolean isStringTool(@NotNull String id) {
return stringTools.contains(id);
}
public boolean isGlass(Material material) {
public boolean isGlass(@NotNull Material material) {
return glassBlocks.contains(material.getKey().getKey());
}
public boolean isFood(Material material) {
public boolean isFood(@NotNull Material material) {
return foodItemWhiteList.contains(material.getKey().getKey());
}
private void fillMultiBlockPlantSet()
{
//Single Block Plants
// plantBlockSet.add("melon");
// plantBlockSet.add("pumpkin");
// plantBlockSet.add("potatoes");
// plantBlockSet.add("carrots");
// plantBlockSet.add("beetroots");
// plantBlockSet.add("nether_wart");
// plantBlockSet.add("grass");
// plantBlockSet.add("fern");
// plantBlockSet.add("large_fern");
private void fillMultiBlockPlantSet() {
//Multi-Block Plants
multiBlockPlant.add("cactus");
multiBlockPlant.add("chorus_plant");
@@ -805,15 +768,13 @@ public class MaterialMapStore {
multiBlockPlant.add("twisted_vines_plant");
}
private void fillShroomyWhiteList()
{
private void fillShroomyWhiteList() {
canMakeShroomyWhiteList.add("dirt");
canMakeShroomyWhiteList.add("grass");
canMakeShroomyWhiteList.add("grass_path");
}
private void fillBlockCrackerWhiteList()
{
private void fillBlockCrackerWhiteList() {
blockCrackerWhiteList.add("stone_bricks");
blockCrackerWhiteList.add("infested_stone_bricks");
@@ -827,16 +788,18 @@ public class MaterialMapStore {
herbalismAbilityBlackList.add("farmland");
}
private void fillLeavesWhiteList()
private void fillTreeFellerDestructibleWhiteList()
{
leavesWhiteList.add("oak_leaves");
leavesWhiteList.add("acacia_leaves");
leavesWhiteList.add("birch_leaves");
leavesWhiteList.add("dark_oak_leaves");
leavesWhiteList.add("jungle_leaves");
leavesWhiteList.add("spruce_leaves");
leavesWhiteList.add("nether_wart_block");
leavesWhiteList.add("warped_wart_block");
treeFellerDestructibleWhiteList.add("oak_leaves");
treeFellerDestructibleWhiteList.add("acacia_leaves");
treeFellerDestructibleWhiteList.add("birch_leaves");
treeFellerDestructibleWhiteList.add("dark_oak_leaves");
treeFellerDestructibleWhiteList.add("jungle_leaves");
treeFellerDestructibleWhiteList.add("spruce_leaves");
treeFellerDestructibleWhiteList.add("nether_wart_block");
treeFellerDestructibleWhiteList.add("warped_wart_block");
treeFellerDestructibleWhiteList.add("brown_mushroom_block");
treeFellerDestructibleWhiteList.add("red_mushroom_block");
}
private void fillMossyWhiteList()
@@ -1115,24 +1078,24 @@ public class MaterialMapStore {
toolBlackList.add("respawn_anchor");
}
public HashSet<String> getNetheriteArmor() {
public @NotNull HashSet<String> getNetheriteArmor() {
return netheriteArmor;
}
public HashSet<String> getNetheriteTools() {
public @NotNull HashSet<String> getNetheriteTools() {
return netheriteTools;
}
public int getTier(Material material) {
public int getTier(@NotNull Material material) {
return getTier(material.getKey().getKey());
}
public int getTier(String id) {
public int getTier(@NotNull String id) {
return tierValue.getOrDefault(id, 1); //1 for unknown items
}
private void addToHashSet(String string, HashSet<String> stringHashSet)
private void addToHashSet(@NotNull String string, @NotNull HashSet<String> stringHashSet)
{
stringHashSet.add(string.toLowerCase(Locale.ENGLISH));
}

View File

@@ -1,5 +1,7 @@
package com.gmail.nossr50.util;
import com.gmail.nossr50.api.ItemSpawnReason;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.events.items.McMMOItemSpawnEvent;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
@@ -9,7 +11,10 @@ import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.entity.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Locale;
@@ -17,7 +22,7 @@ import java.util.Random;
import java.util.Set;
public final class Misc {
private static final Random random = new Random();
private static final @NotNull Random random = new Random();
public static final int TIME_CONVERSION_FACTOR = 1000;
public static final int TICK_CONVERSION_FACTOR = 20;
@@ -36,7 +41,7 @@ public final class Misc {
public static final float LEVELUP_PITCH = 0.5F; // Reduced to differentiate between vanilla level-up
public static final float LEVELUP_VOLUME = 0.75F * Config.getInstance().getMasterVolume(); // Use max volume always*/
public static final Set<String> modNames = ImmutableSet.of("LOTR", "BUILDCRAFT", "ENDERIO", "ENHANCEDBIOMES", "IC2", "METALLURGY", "FORESTRY", "GALACTICRAFT", "RAILCRAFT", "TWILIGHTFOREST", "THAUMCRAFT", "GRAVESTONEMOD", "GROWTHCRAFT", "ARCTICMOBS", "DEMONMOBS", "INFERNOMOBS", "SWAMPMOBS", "MARICULTURE", "MINESTRAPPOLATION");
public static final @NotNull Set<String> modNames = ImmutableSet.of("LOTR", "BUILDCRAFT", "ENDERIO", "ENHANCEDBIOMES", "IC2", "METALLURGY", "FORESTRY", "GALACTICRAFT", "RAILCRAFT", "TWILIGHTFOREST", "THAUMCRAFT", "GRAVESTONEMOD", "GROWTHCRAFT", "ARCTICMOBS", "DEMONMOBS", "INFERNOMOBS", "SWAMPMOBS", "MARICULTURE", "MINESTRAPPOLATION");
private Misc() {}
@@ -53,7 +58,7 @@ public final class Misc {
* @param entity target entity
* @return true if the entity is not a Villager and is not a "NPC"
*/
public static boolean isNPCEntityExcludingVillagers(Entity entity) {
public static boolean isNPCEntityExcludingVillagers(@NotNull Entity entity) {
return (!isVillager(entity)
&& isNPCIncludingVillagers(entity)); //Compatibility with some mod..
}
@@ -72,7 +77,7 @@ public final class Misc {
return entityType.equalsIgnoreCase("wandering_trader") || entity instanceof Villager;
}
public static boolean isNPCIncludingVillagers(Entity entity) {
public static boolean isNPCIncludingVillagers(@Nullable Entity entity) {
return (entity == null
|| (hasNPCMetadataTag(entity))
|| (isNPCClassType(entity))
@@ -87,7 +92,7 @@ public final class Misc {
* @param maxDistance The max distance apart
* @return true if the distance between {@code first} and {@code second} is less than {@code maxDistance}, false otherwise
*/
public static boolean isNear(Location first, Location second, double maxDistance) {
public static boolean isNear(@NotNull Location first, @NotNull Location second, double maxDistance) {
return (first.getWorld() == second.getWorld()) && (first.distanceSquared(second) < (maxDistance * maxDistance) || maxDistance == 0);
}
@@ -101,9 +106,25 @@ public final class Misc {
return blockState.getLocation().add(0.5, 0.5, 0.5);
}
public static void dropItems(Location location, Collection<ItemStack> drops) {
public static void spawnItemsFromCollection(@NotNull Location location, @NotNull Collection<ItemStack> drops, @NotNull ItemSpawnReason itemSpawnReason) {
for (ItemStack drop : drops) {
dropItem(location, drop);
spawnItem(location, drop, itemSpawnReason);
}
}
/**
* Drops only the first n items in a collection
* Size should always be a positive integer above 0
*
* @param location target drop location
* @param drops collection to iterate over
* @param sizeLimit the number of drops to process
*/
public static void spawnItemsFromCollection(@NotNull Location location, @NotNull Collection<ItemStack> drops, @NotNull ItemSpawnReason itemSpawnReason, int sizeLimit) {
ItemStack[] arrayDrops = drops.toArray(new ItemStack[0]);
for(int i = 0; i < sizeLimit-1; i++) {
spawnItem(location, arrayDrops[i], itemSpawnReason);
}
}
@@ -114,9 +135,9 @@ public final class Misc {
* @param is The items to drop
* @param quantity The amount of items to drop
*/
public static void dropItems(Location location, ItemStack is, int quantity) {
public static void spawnItems(@NotNull Location location, @NotNull ItemStack is, int quantity, @NotNull ItemSpawnReason itemSpawnReason) {
for (int i = 0; i < quantity; i++) {
dropItem(location, is);
spawnItem(location, is, itemSpawnReason);
}
}
@@ -125,15 +146,16 @@ public final class Misc {
*
* @param location The location to drop the item at
* @param itemStack The item to drop
* @param itemSpawnReason the reason for the item drop
* @return Dropped Item entity or null if invalid or cancelled
*/
public static Item dropItem(Location location, ItemStack itemStack) {
if (itemStack.getType() == Material.AIR) {
public static @Nullable Item spawnItem(@NotNull Location location, @NotNull ItemStack itemStack, @NotNull ItemSpawnReason itemSpawnReason) {
if (itemStack.getType() == Material.AIR || location.getWorld() == null) {
return null;
}
// We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event.
McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack);
McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack, itemSpawnReason);
mcMMO.p.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
@@ -148,22 +170,23 @@ public final class Misc {
*
* @param location The location to drop the item at
* @param itemStack The item to drop
* @param itemSpawnReason the reason for the item drop
* @return Dropped Item entity or null if invalid or cancelled
*/
public static Item dropItem(Location location, ItemStack itemStack, int count) {
if (itemStack.getType() == Material.AIR) {
public static @Nullable Item spawnItemNaturally(@NotNull Location location, @NotNull ItemStack itemStack, @NotNull ItemSpawnReason itemSpawnReason) {
if (itemStack.getType() == Material.AIR || location.getWorld() == null) {
return null;
}
// We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event.
McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack);
McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack, itemSpawnReason);
mcMMO.p.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return null;
}
return location.getWorld().dropItem(location, itemStack);
return location.getWorld().dropItemNaturally(location, itemStack);
}
/**
@@ -174,9 +197,9 @@ public final class Misc {
* @param speed the speed that the item should travel
* @param quantity The amount of items to drop
*/
public static void spawnItemsTowardsLocation(Location fromLocation, Location toLocation, ItemStack is, int quantity, double speed) {
public static void spawnItemsTowardsLocation(@NotNull Location fromLocation, @NotNull Location toLocation, @NotNull ItemStack is, int quantity, double speed, @NotNull ItemSpawnReason itemSpawnReason) {
for (int i = 0; i < quantity; i++) {
spawnItemTowardsLocation(fromLocation, toLocation, is, speed);
spawnItemTowardsLocation(fromLocation, toLocation, is, speed, itemSpawnReason);
}
}
@@ -190,7 +213,7 @@ public final class Misc {
* @param speed the speed that the item should travel
* @return Dropped Item entity or null if invalid or cancelled
*/
public static Item spawnItemTowardsLocation(Location fromLocation, Location toLocation, ItemStack itemToSpawn, double speed) {
public static @Nullable Item spawnItemTowardsLocation(@NotNull Location fromLocation, @NotNull Location toLocation, @NotNull ItemStack itemToSpawn, double speed, @NotNull ItemSpawnReason itemSpawnReason) {
if (itemToSpawn.getType() == Material.AIR) {
return null;
}
@@ -200,12 +223,15 @@ public final class Misc {
Location spawnLocation = fromLocation.clone();
Location targetLocation = toLocation.clone();
if(spawnLocation.getWorld() == null)
return null;
// We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event.
McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(spawnLocation, clonedItem);
McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(spawnLocation, clonedItem, itemSpawnReason);
mcMMO.p.getServer().getPluginManager().callEvent(event);
//Something cancelled the event so back out
if (event.isCancelled() || event.getItemStack() == null) {
if (event.isCancelled()) {
return null;
}
@@ -223,7 +249,7 @@ public final class Misc {
return spawnedItem;
}
public static void profileCleanup(String playerName) {
public static void profileCleanup(@NotNull String playerName) {
Player player = mcMMO.p.getServer().getPlayerExact(playerName);
if (player != null) {
@@ -238,7 +264,7 @@ public final class Misc {
}
}
public static String getModName(String materialName) {
public static String getModName(@NotNull String materialName) {
for (String mod : modNames) {
if (materialName.contains(mod)) {
return mod;
@@ -257,7 +283,7 @@ public final class Misc {
/**
* Gets a random location near the specified location
*/
public static Location getLocationOffset(Location location, double strength) {
public static Location getLocationOffset(@NotNull Location location, double strength) {
double blockX = location.getBlockX();
double blockZ = location.getBlockZ();
@@ -271,7 +297,50 @@ public final class Misc {
return new Location(location.getWorld(), blockX, location.getY(), blockZ);
}
public static Random getRandom() {
public static @NotNull Random getRandom() {
return random;
}
/**
* Whether or not a player is the party leader of a party
*
* @param mmoPlayer target player
* @return true if the player is the party leader
*/
public static boolean isPartyLeader(@NotNull McMMOPlayer mmoPlayer) {
return mmoPlayer.getParty().getLeader().getUniqueId().equals(mmoPlayer.getPlayer().getUniqueId());
}
// public static void spawnExperienceOrb(@NotNull Location location, int orbAmount, int experienceValue) {
// for (int i = 0; i < orbAmount; i++) {
// new SpawnOrbTask(location, experienceValue).runTaskLater(mcMMO.p, 20);
// }
// }
public static void spawnExperienceOrb(@NotNull Location location, int experienceValue) {
if(location.getWorld() == null)
return;
ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld().spawnEntity(location, EntityType.EXPERIENCE_ORB);
experienceOrb.setExperience(experienceValue);
}
private static class SpawnOrbTask extends BukkitRunnable {
private final Location location;
private int orbExpValue;
private SpawnOrbTask(Location location, int orbExpValue) {
this.location = location;
this.orbExpValue = orbExpValue;
}
@Override
public void run() {
if(location == null || location.getWorld() == null)
return;
ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld().spawnEntity(location, EntityType.EXPERIENCE_ORB);
experienceOrb.setExperience(orbExpValue);
}
}
}

View File

@@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.MobHealthBarType;
import com.gmail.nossr50.datatypes.meta.OldName;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.runnables.MobHealthDisplayUpdaterTask;
import com.gmail.nossr50.util.text.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;

View File

@@ -136,10 +136,6 @@ public class ModManager {
return Config.getInstance().getBlockModsEnabled() && customLogs.contains(state.getType());
}
public boolean isCustomLeaf(BlockState state) {
return Config.getInstance().getBlockModsEnabled() && customLeaves.contains(state.getType());
}
public boolean isCustomAbilityBlock(BlockState state) {
return Config.getInstance().getBlockModsEnabled() && customAbilityBlocks.contains(state.getType());
}

View File

@@ -39,6 +39,7 @@ public final class Permissions {
/* CHAT */
public static boolean partyChat(Permissible permissible) { return permissible.hasPermission("mcmmo.chat.partychat"); }
public static boolean adminChat(Permissible permissible) { return permissible.hasPermission("mcmmo.chat.adminchat"); }
public static boolean colorChat(Permissible permissible) { return permissible.hasPermission("mcmmo.chat.colors"); }
/*
* COMMANDS

View File

@@ -0,0 +1,34 @@
package com.gmail.nossr50.util;
import com.gmail.nossr50.mcMMO;
import org.bukkit.entity.LivingEntity;
public class TransientMetadataTools {
private final mcMMO pluginRef;
public TransientMetadataTools(mcMMO pluginRef) {
this.pluginRef = pluginRef;
}
public void cleanAllMobMetadata(LivingEntity livingEntity) {
//Since its not written anywhere, apparently the GC won't touch objects with metadata still present on them
if (livingEntity.hasMetadata(mcMMO.customNameKey)) {
livingEntity.setCustomName(livingEntity.getMetadata(mcMMO.customNameKey).get(0).asString());
livingEntity.removeMetadata(mcMMO.customNameKey, pluginRef);
}
//Involved in changing mob names to hearts
if (livingEntity.hasMetadata(mcMMO.customVisibleKey)) {
livingEntity.setCustomNameVisible(livingEntity.getMetadata(mcMMO.customVisibleKey).get(0).asBoolean());
livingEntity.removeMetadata(mcMMO.customVisibleKey, pluginRef);
}
//Gets assigned to endermen, potentially doesn't get cleared before this point
if(livingEntity.hasMetadata(mcMMO.travelingBlock)) {
livingEntity.removeMetadata(mcMMO.travelingBlock, pluginRef);
}
//Cleanup mob metadata
mcMMO.getCompatibilityManager().getPersistentDataLayer().removeMobFlags(livingEntity);
}
}

View File

@@ -4,9 +4,7 @@ import com.gmail.nossr50.commands.*;
import com.gmail.nossr50.commands.admin.CompatibilityCommand;
import com.gmail.nossr50.commands.admin.McmmoReloadLocaleCommand;
import com.gmail.nossr50.commands.admin.PlayerDebugCommand;
import com.gmail.nossr50.commands.chat.AdminChatCommand;
import com.gmail.nossr50.commands.chat.McChatSpy;
import com.gmail.nossr50.commands.chat.PartyChatCommand;
import com.gmail.nossr50.commands.database.McpurgeCommand;
import com.gmail.nossr50.commands.database.DatabaseRemovePlayerCommand;
import com.gmail.nossr50.commands.database.MmoshowdbCommand;
@@ -24,7 +22,7 @@ import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.StringUtils;
import com.gmail.nossr50.util.text.StringUtils;
import org.bukkit.command.PluginCommand;
import java.util.ArrayList;
@@ -129,7 +127,7 @@ public final class CommandRegistrationManager {
command.setDescription(LocaleLoader.getString("Commands.Description.addlevels"));
command.setPermission("mcmmo.commands.addlevels;mcmmo.commands.addlevels.others");
command.setPermissionMessage(permissionsMessage);
command.setUsage(LocaleLoader.getString("Commands.Usage.3", "addlevels", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", "<" + LocaleLoader.getString("Commands.Usage.Level") + ">"));
command.setUsage(LocaleLoader.getString("Commands.Usage.3.XP", "addlevels", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", "<" + LocaleLoader.getString("Commands.Usage.Level") + ">"));
command.setExecutor(new AddlevelsCommand());
}
@@ -138,7 +136,7 @@ public final class CommandRegistrationManager {
command.setDescription(LocaleLoader.getString("Commands.Description.addxp"));
command.setPermission("mcmmo.commands.addxp;mcmmo.commands.addxp.others");
command.setPermissionMessage(permissionsMessage);
command.setUsage(LocaleLoader.getString("Commands.Usage.3", "addxp", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", "<" + LocaleLoader.getString("Commands.Usage.XP") + ">"));
command.setUsage(LocaleLoader.getString("Commands.Usage.3.XP", "addxp", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", "<" + LocaleLoader.getString("Commands.Usage.XP") + ">"));
command.setExecutor(new AddxpCommand());
}
@@ -192,7 +190,7 @@ public final class CommandRegistrationManager {
command.setDescription(LocaleLoader.getString("Commands.Description.mmoedit"));
command.setPermission("mcmmo.commands.mmoedit;mcmmo.commands.mmoedit.others");
command.setPermissionMessage(permissionsMessage);
command.setUsage(LocaleLoader.getString("Commands.Usage.3", "mmoedit", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", "<" + LocaleLoader.getString("Commands.Usage.Level") + ">"));
command.setUsage(LocaleLoader.getString("Commands.Usage.3.XP", "mmoedit", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", "<" + LocaleLoader.getString("Commands.Usage.Level") + ">"));
command.setExecutor(new MmoeditCommand());
}
@@ -320,27 +318,27 @@ public final class CommandRegistrationManager {
command.setExecutor(new McconvertCommand());
}
private static void registerAdminChatCommand() {
PluginCommand command = mcMMO.p.getCommand("adminchat");
command.setDescription(LocaleLoader.getString("Commands.Description.adminchat"));
command.setPermission("mcmmo.chat.adminchat");
command.setPermissionMessage(permissionsMessage);
command.setUsage(LocaleLoader.getString("Commands.Usage.0", "adminchat"));
command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "<on|off>"));
command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">"));
command.setExecutor(new AdminChatCommand());
}
// private static void registerAdminChatCommand() {
// PluginCommand command = mcMMO.p.getCommand("adminchat");
// command.setDescription(LocaleLoader.getString("Commands.Description.adminchat"));
// command.setPermission("mcmmo.chat.adminchat");
// command.setPermissionMessage(permissionsMessage);
// command.setUsage(LocaleLoader.getString("Commands.Usage.0", "adminchat"));
// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "<on|off>"));
// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">"));
// command.setExecutor(new AdminChatCommand());
// }
private static void registerPartyChatCommand() {
PluginCommand command = mcMMO.p.getCommand("partychat");
command.setDescription(LocaleLoader.getString("Commands.Description.partychat"));
command.setPermission("mcmmo.chat.partychat;mcmmo.commands.party");
command.setPermissionMessage(permissionsMessage);
command.setUsage(LocaleLoader.getString("Commands.Usage.0", "partychat"));
command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "<on|off>"));
command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">"));
command.setExecutor(new PartyChatCommand());
}
// private static void registerPartyChatCommand() {
// PluginCommand command = mcMMO.p.getCommand("partychat");
// command.setDescription(LocaleLoader.getString("Commands.Description.partychat"));
// command.setPermission("mcmmo.chat.partychat;mcmmo.commands.party");
// command.setPermissionMessage(permissionsMessage);
// command.setUsage(LocaleLoader.getString("Commands.Usage.0", "partychat"));
// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "<on|off>"));
// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">"));
// command.setExecutor(new PartyChatCommand());
// }
private static void registerPartyCommand() {
PluginCommand command = mcMMO.p.getCommand("party");
@@ -460,10 +458,6 @@ public final class CommandRegistrationManager {
registerMHDCommand();
registerXprateCommand();
// Chat Commands
registerPartyChatCommand();
registerAdminChatCommand();
// Database Commands
registerMcpurgeCommand();
registerMcremoveCommand();

View File

@@ -7,8 +7,9 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.StringUtils;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.skills.SkillUtils;
import com.gmail.nossr50.util.text.StringUtils;
import com.google.common.collect.ImmutableList;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
@@ -72,7 +73,7 @@ public final class CommandUtils {
*
* @param sender CommandSender who used the command
* @param playerName name of the target player
* @param McMMOPlayer mmoPlayer object of the target player
* @param mcMMOPlayer object of the target player
*
* @return true if the player is online and a valid mmoPlayer object was found
*/

View File

@@ -2,14 +2,19 @@ package com.gmail.nossr50.util.compat;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.StringUtils;
import com.gmail.nossr50.util.compat.layers.attackcooldown.PlayerAttackCooldownExploitPreventionLayer;
import com.gmail.nossr50.util.compat.layers.bungee.AbstractBungeeSerializerCompatibilityLayer;
import com.gmail.nossr50.util.compat.layers.bungee.BungeeLegacySerializerCompatibilityLayer;
import com.gmail.nossr50.util.compat.layers.bungee.BungeeModernSerializerCompatibilityLayer;
import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataLayer_1_13;
import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataLayer_1_14;
import com.gmail.nossr50.util.compat.layers.skills.AbstractMasterAnglerCompatibility;
import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer;
import com.gmail.nossr50.util.nms.NMSVersion;
import com.gmail.nossr50.util.platform.MinecraftGameVersion;
import com.gmail.nossr50.util.text.StringUtils;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
@@ -19,6 +24,7 @@ import java.util.HashMap;
* In 2.2 we are switching to modules and that will clean things up significantly
*
*/
//TODO: I need to rewrite this crap
public class CompatibilityManager {
private HashMap<CompatibilityType, Boolean> supportedLayers;
private boolean isFullyCompatibleServerSoftware = true; //true if all compatibility layers load successfully
@@ -26,8 +32,10 @@ public class CompatibilityManager {
private final NMSVersion nmsVersion;
/* Compatibility Layers */
private PlayerAttackCooldownExploitPreventionLayer playerAttackCooldownExploitPreventionLayer;
// private PlayerAttackCooldownExploitPreventionLayer playerAttackCooldownExploitPreventionLayer;
private AbstractPersistentDataLayer persistentDataLayer;
private AbstractBungeeSerializerCompatibilityLayer bungeeSerializerCompatibilityLayer;
private AbstractMasterAnglerCompatibility masterAnglerCompatibility;
public CompatibilityManager(MinecraftGameVersion minecraftGameVersion) {
mcMMO.p.getLogger().info("Loading compatibility layers...");
@@ -46,10 +54,6 @@ public class CompatibilityManager {
supportedLayers = new HashMap<>(); //Init map
for(CompatibilityType compatibilityType : CompatibilityType.values()) {
//TODO: Remove later
if(compatibilityType == CompatibilityType.PLAYER_ATTACK_COOLDOWN_EXPLOIT_PREVENTION)
continue;
supportedLayers.put(compatibilityType, false); //All layers are set to false when initialized
}
}
@@ -60,10 +64,42 @@ public class CompatibilityManager {
*/
private void initCompatibilityLayers() {
initPersistentDataLayer();
initBungeeSerializerLayer();
initMasterAnglerLayer();
isFullyCompatibleServerSoftware = true;
}
private void initMasterAnglerLayer() {
if(minecraftGameVersion.getMinorVersion().asInt() >= 16 || minecraftGameVersion.getMajorVersion().asInt() >= 2) {
if(hasNewFishingHookAPI()) {
masterAnglerCompatibility = new MasterAnglerCompatibilityLayer();
}
} else {
masterAnglerCompatibility = null;
}
}
private boolean hasNewFishingHookAPI() {
try {
Class<?> checkForClass = Class.forName("org.bukkit.entity.FishHook");
checkForClass.getMethod("getMinWaitTime");
return true;
} catch (ClassNotFoundException | NoSuchMethodException e) {
return false;
}
}
private void initBungeeSerializerLayer() {
if(minecraftGameVersion.getMinorVersion().asInt() >= 16) {
bungeeSerializerCompatibilityLayer = new BungeeModernSerializerCompatibilityLayer();
} else {
bungeeSerializerCompatibilityLayer = new BungeeLegacySerializerCompatibilityLayer();
}
supportedLayers.put(CompatibilityType.BUNGEE_SERIALIZER, true);
}
private void initPersistentDataLayer() {
if(minecraftGameVersion.getMinorVersion().asInt() >= 14 || minecraftGameVersion.getMajorVersion().asInt() >= 2) {
@@ -124,6 +160,8 @@ public class CompatibilityManager {
return NMSVersion.NMS_1_16_2;
} else if(minecraftGameVersion.getPatchVersion().asInt() == 3) {
return NMSVersion.NMS_1_16_3;
} else if(minecraftGameVersion.getPatchVersion().asInt() >= 4) {
return NMSVersion.NMS_1_16_4;
}
}
}
@@ -131,11 +169,15 @@ public class CompatibilityManager {
return NMSVersion.UNSUPPORTED;
}
public PlayerAttackCooldownExploitPreventionLayer getPlayerAttackCooldownExploitPreventionLayer() {
return playerAttackCooldownExploitPreventionLayer;
public AbstractBungeeSerializerCompatibilityLayer getBungeeSerializerCompatibilityLayer() {
return bungeeSerializerCompatibilityLayer;
}
public AbstractPersistentDataLayer getPersistentDataLayer() {
return persistentDataLayer;
}
public @Nullable AbstractMasterAnglerCompatibility getMasterAnglerCompatibilityLayer() {
return masterAnglerCompatibility;
}
}

View File

@@ -1,6 +1,7 @@
package com.gmail.nossr50.util.compat;
public enum CompatibilityType {
PLAYER_ATTACK_COOLDOWN_EXPLOIT_PREVENTION,
PERSISTENT_DATA
PERSISTENT_DATA,
BUNGEE_SERIALIZER,
MASTER_ANGLER,
}

View File

@@ -1,32 +1,32 @@
package com.gmail.nossr50.util.compat.layers.attackcooldown;
import com.gmail.nossr50.util.nms.NMSVersion;
import org.bukkit.entity.Player;
import java.lang.reflect.InvocationTargetException;
public class DummyPlayerAttackCooldownExploitPreventionLayer extends PlayerAttackCooldownExploitPreventionLayer {
public DummyPlayerAttackCooldownExploitPreventionLayer() {
super(NMSVersion.UNSUPPORTED);
}
@Override
public boolean initializeLayer() {
return noErrorsOnInitialize;
}
@Override
public float getAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
return 1.0F; //Always full strength
}
@Override
public float getCooldownValue(Player player) throws InvocationTargetException, IllegalAccessException {
return 0F;
}
@Override
public void resetAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
//Do nothing
}
}
//package com.gmail.nossr50.util.compat.layers.attackcooldown;
//
//import com.gmail.nossr50.util.nms.NMSVersion;
//import org.bukkit.entity.Player;
//
//import java.lang.reflect.InvocationTargetException;
//
//public class DummyPlayerAttackCooldownExploitPreventionLayer extends PlayerAttackCooldownExploitPreventionLayer {
// public DummyPlayerAttackCooldownExploitPreventionLayer() {
// super(NMSVersion.UNSUPPORTED);
// }
//
// @Override
// public boolean initializeLayer() {
// return noErrorsOnInitialize;
// }
//
// @Override
// public float getAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
// return 1.0F; //Always full strength
// }
//
// @Override
// public float getCooldownValue(Player player) throws InvocationTargetException, IllegalAccessException {
// return 0F;
// }
//
// @Override
// public void resetAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
// //Do nothing
// }
//}

View File

@@ -1,202 +1,202 @@
package com.gmail.nossr50.util.compat.layers.attackcooldown;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.compat.layers.AbstractNMSCompatibilityLayer;
import com.gmail.nossr50.util.nms.NMSConstants;
import com.gmail.nossr50.util.nms.NMSVersion;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
*
* These classes are a band-aid solution for adding NMS support into 2.1.XXX
* In 2.2 we are switching to modules and that will clean things up significantly
*
*/
public class PlayerAttackCooldownExploitPreventionLayer extends AbstractNMSCompatibilityLayer implements PlayerAttackCooldownMethods{
private final String cbNMSVersionPath;
protected Class<?> craftPlayerClass;
protected Class<?> entityHumanClass;
protected Method playerAttackCooldownMethod;
protected Method playerAttackStrengthMethod;
protected Method resetPlayerAttackCooldownMethod;
protected Method getHandleMethod;
public PlayerAttackCooldownExploitPreventionLayer(@NotNull NMSVersion nmsVersion) {
super(nmsVersion);
mcMMO.p.getLogger().info("Loading Compatibility Layer... (Player Attack Cooldown Exploit Prevention)");
if(!isCompatibleWithMinecraftVersion()) {
mcMMO.p.getLogger().severe("this version of mcMMO does not support NMS for this version of Minecraft, try updating mcMMO or updating Minecraft. Not all versions of Minecraft will have NMS support built into mcMMO.");
cbNMSVersionPath = "";
} else {
if(NMSConstants.getCraftBukkitVersionPath(nmsVersion) != null) {
cbNMSVersionPath = NMSConstants.getCraftBukkitVersionPath(nmsVersion);
noErrorsOnInitialize = initializeLayer();
if(noErrorsOnInitialize) {
mcMMO.p.getLogger().info("Successfully Loaded Compatibility Layer! (Player Attack Cooldown Exploit Prevention)");
}
} else {
mcMMO.p.getLogger().info("Failed to load - CL (Player Attack Cooldown Exploit Prevention) Could not find CB NMS path for CL");
flagErrorsDuringStartup();
mcMMO.p.getLogger().warning("Could not wire NMS package path for CraftBukkit!");
cbNMSVersionPath = "";
}
}
}
private boolean isCompatibleWithMinecraftVersion() {
switch(nmsVersion) {
case NMS_1_13_2:
case NMS_1_14_4:
case NMS_1_15_2:
case NMS_1_16_1:
return true;
default:
return false;
}
}
/**
* Cache all reflection methods/types/classes needed for the NMS of this CompatibilityLayer
* @param cooldownMethodName the cooldown method name
* @param attackStrengthMethodName the attack strength method name
* @param resetAttackCooldownMethodName the reset attack cooldown method name
* @param getHandleMethodName the get handle method name
* @return true if NMS was successfully wired
*/
public boolean wireNMS(@NotNull String cooldownMethodName, @NotNull String attackStrengthMethodName, @NotNull String resetAttackCooldownMethodName, @NotNull String getHandleMethodName) {
entityHumanClass = initEntityHumanClass();
craftPlayerClass = initCraftPlayerClass();
try {
this.playerAttackCooldownMethod = entityHumanClass.getMethod(cooldownMethodName);
this.playerAttackStrengthMethod = entityHumanClass.getMethod(attackStrengthMethodName, float.class);
this.resetPlayerAttackCooldownMethod = entityHumanClass.getMethod(resetAttackCooldownMethodName);
if (craftPlayerClass != null) {
this.getHandleMethod = craftPlayerClass.getMethod(getHandleMethodName);
} else {
return false;
}
return true;
} catch (NoSuchMethodException e) {
flagErrorsDuringStartup();
e.printStackTrace();
return false;
}
}
/**
* Get the cached player attack cooldown method
* @return the cached player attack cooldown method
*/
private @Nullable Method getPlayerAttackCooldownMethod() {
return playerAttackCooldownMethod;
}
/**
* Get the cached player attack strength method
* @return the cached player attack strength method
*/
private @Nullable Method getPlayerAttackStrengthMethod() {
return playerAttackStrengthMethod;
}
/**
* Get the cached player attack cooldown reset method
* @return the cached player attack cooldown reset method
*/
private @Nullable Method getResetPlayerAttackCooldownMethod() {
return resetPlayerAttackCooldownMethod;
}
/**
* Grab the CraftPlayer class type from NMS
* @return the CraftPlayer class type from NMS
*/
private @Nullable Class<?> initCraftPlayerClass() {
try {
return Class.forName(NMSConstants.getCraftPlayerClassPath(cbNMSVersionPath));
} catch (ClassNotFoundException e) {
flagErrorsDuringStartup();
e.printStackTrace();
return null;
}
}
/**
* Grab the EntityHuman class type from NMS
* @return the EntityHuman class type from NMS
*/
private @Nullable Class<?> initEntityHumanClass() {
try {
return Class.forName(NMSConstants.getEntityHumanClassPath(cbNMSVersionPath));
} catch (ClassNotFoundException e) {
flagErrorsDuringStartup();
e.printStackTrace();
return null;
}
}
private void flagErrorsDuringStartup() {
noErrorsOnInitialize = false;
}
/**
* Grabs the attack strength for a player
* Should be noted that as of today there is no way to capture a players current attack strength in spigot when they attack an entity outside of network packet listening
* @param player target player
* @return the float value of the player's attack strength
*/
@Override
public float getAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
Object craftPlayer = craftPlayerClass.cast(player);
Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
return (float) playerAttackStrengthMethod.invoke(entityHuman, 0F); //Add no adjustment ticks
}
@Override
public float getCooldownValue(Player player) throws InvocationTargetException, IllegalAccessException {
Object craftPlayer = craftPlayerClass.cast(player);
Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
return (float) playerAttackCooldownMethod.invoke(entityHuman); //Add no adjustment ticks
}
@Override
public void resetAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
Object craftPlayer = craftPlayerClass.cast(player);
Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
resetPlayerAttackCooldownMethod.invoke(entityHuman);
}
@Override
public boolean initializeLayer() {
switch(nmsVersion) {
case NMS_1_12_2:
return wireNMS("dr", "n", "ds", "getHandle");
case NMS_1_13_2:
return wireNMS("dG", "r", "dH", "getHandle");
case NMS_1_14_4:
return wireNMS("dY", "s", "dZ", "getHandle");
case NMS_1_15_2:
return wireNMS("ex", "s", "ey", "getHandle");
case NMS_1_16_1:
return wireNMS("eR", "getAttackCooldown", "resetAttackCooldown", "getHandle");
default:
break;
}
return false;
}
}
//package com.gmail.nossr50.util.compat.layers.attackcooldown;
//
//import com.gmail.nossr50.mcMMO;
//import com.gmail.nossr50.util.compat.layers.AbstractNMSCompatibilityLayer;
//import com.gmail.nossr50.util.nms.NMSConstants;
//import com.gmail.nossr50.util.nms.NMSVersion;
//import org.bukkit.entity.Player;
//import org.jetbrains.annotations.NotNull;
//import org.jetbrains.annotations.Nullable;
//
//import java.lang.reflect.InvocationTargetException;
//import java.lang.reflect.Method;
//
///**
// *
// * These classes are a band-aid solution for adding NMS support into 2.1.XXX
// * In 2.2 we are switching to modules and that will clean things up significantly
// *
// */
//public class PlayerAttackCooldownExploitPreventionLayer extends AbstractNMSCompatibilityLayer implements PlayerAttackCooldownMethods{
//
// private final String cbNMSVersionPath;
//
// protected Class<?> craftPlayerClass;
// protected Class<?> entityHumanClass;
//
// protected Method playerAttackCooldownMethod;
// protected Method playerAttackStrengthMethod;
// protected Method resetPlayerAttackCooldownMethod;
// protected Method getHandleMethod;
//
// public PlayerAttackCooldownExploitPreventionLayer(@NotNull NMSVersion nmsVersion) {
// super(nmsVersion);
// mcMMO.p.getLogger().info("Loading Compatibility Layer... (Player Attack Cooldown Exploit Prevention)");
// if(!isCompatibleWithMinecraftVersion()) {
// mcMMO.p.getLogger().severe("this version of mcMMO does not support NMS for this version of Minecraft, try updating mcMMO or updating Minecraft. Not all versions of Minecraft will have NMS support built into mcMMO.");
// cbNMSVersionPath = "";
// } else {
// if(NMSConstants.getCraftBukkitVersionPath(nmsVersion) != null) {
// cbNMSVersionPath = NMSConstants.getCraftBukkitVersionPath(nmsVersion);
// noErrorsOnInitialize = initializeLayer();
//
// if(noErrorsOnInitialize) {
// mcMMO.p.getLogger().info("Successfully Loaded Compatibility Layer! (Player Attack Cooldown Exploit Prevention)");
// }
// } else {
// mcMMO.p.getLogger().info("Failed to load - CL (Player Attack Cooldown Exploit Prevention) Could not find CB NMS path for CL");
// flagErrorsDuringStartup();
// mcMMO.p.getLogger().warning("Could not wire NMS package path for CraftBukkit!");
// cbNMSVersionPath = "";
// }
// }
// }
//
// private boolean isCompatibleWithMinecraftVersion() {
// switch(nmsVersion) {
// case NMS_1_13_2:
// case NMS_1_14_4:
// case NMS_1_15_2:
// case NMS_1_16_1:
// return true;
// default:
// return false;
// }
//
// }
//
// /**
// * Cache all reflection methods/types/classes needed for the NMS of this CompatibilityLayer
// * @param cooldownMethodName the cooldown method name
// * @param attackStrengthMethodName the attack strength method name
// * @param resetAttackCooldownMethodName the reset attack cooldown method name
// * @param getHandleMethodName the get handle method name
// * @return true if NMS was successfully wired
// */
// public boolean wireNMS(@NotNull String cooldownMethodName, @NotNull String attackStrengthMethodName, @NotNull String resetAttackCooldownMethodName, @NotNull String getHandleMethodName) {
// entityHumanClass = initEntityHumanClass();
// craftPlayerClass = initCraftPlayerClass();
//
// try {
// this.playerAttackCooldownMethod = entityHumanClass.getMethod(cooldownMethodName);
// this.playerAttackStrengthMethod = entityHumanClass.getMethod(attackStrengthMethodName, float.class);
// this.resetPlayerAttackCooldownMethod = entityHumanClass.getMethod(resetAttackCooldownMethodName);
// if (craftPlayerClass != null) {
// this.getHandleMethod = craftPlayerClass.getMethod(getHandleMethodName);
// } else {
// return false;
// }
// return true;
// } catch (NoSuchMethodException e) {
// flagErrorsDuringStartup();
// e.printStackTrace();
// return false;
// }
// }
//
// /**
// * Get the cached player attack cooldown method
// * @return the cached player attack cooldown method
// */
// private @Nullable Method getPlayerAttackCooldownMethod() {
// return playerAttackCooldownMethod;
// }
//
// /**
// * Get the cached player attack strength method
// * @return the cached player attack strength method
// */
// private @Nullable Method getPlayerAttackStrengthMethod() {
// return playerAttackStrengthMethod;
// }
//
// /**
// * Get the cached player attack cooldown reset method
// * @return the cached player attack cooldown reset method
// */
// private @Nullable Method getResetPlayerAttackCooldownMethod() {
// return resetPlayerAttackCooldownMethod;
// }
//
// /**
// * Grab the CraftPlayer class type from NMS
// * @return the CraftPlayer class type from NMS
// */
// private @Nullable Class<?> initCraftPlayerClass() {
// try {
// return Class.forName(NMSConstants.getCraftPlayerClassPath(cbNMSVersionPath));
// } catch (ClassNotFoundException e) {
// flagErrorsDuringStartup();
// e.printStackTrace();
// return null;
// }
// }
//
// /**
// * Grab the EntityHuman class type from NMS
// * @return the EntityHuman class type from NMS
// */
// private @Nullable Class<?> initEntityHumanClass() {
// try {
// return Class.forName(NMSConstants.getEntityHumanClassPath(cbNMSVersionPath));
// } catch (ClassNotFoundException e) {
// flagErrorsDuringStartup();
// e.printStackTrace();
// return null;
// }
// }
//
// private void flagErrorsDuringStartup() {
// noErrorsOnInitialize = false;
// }
//
// /**
// * Grabs the attack strength for a player
// * Should be noted that as of today there is no way to capture a players current attack strength in spigot when they attack an entity outside of network packet listening
// * @param player target player
// * @return the float value of the player's attack strength
// */
// @Override
// public float getAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
//
// return (float) playerAttackStrengthMethod.invoke(entityHuman, 0F); //Add no adjustment ticks
// }
//
// @Override
// public float getCooldownValue(Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
//
// return (float) playerAttackCooldownMethod.invoke(entityHuman); //Add no adjustment ticks
// }
//
// @Override
// public void resetAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
//
// resetPlayerAttackCooldownMethod.invoke(entityHuman);
// }
//
// @Override
// public boolean initializeLayer() {
// switch(nmsVersion) {
// case NMS_1_12_2:
// return wireNMS("dr", "n", "ds", "getHandle");
// case NMS_1_13_2:
// return wireNMS("dG", "r", "dH", "getHandle");
// case NMS_1_14_4:
// return wireNMS("dY", "s", "dZ", "getHandle");
// case NMS_1_15_2:
// return wireNMS("ex", "s", "ey", "getHandle");
// case NMS_1_16_1:
// return wireNMS("eR", "getAttackCooldown", "resetAttackCooldown", "getHandle");
// default:
// break;
// }
//
// return false;
// }
//}

View File

@@ -1,19 +1,19 @@
package com.gmail.nossr50.util.compat.layers.attackcooldown;
import org.bukkit.entity.Player;
import java.lang.reflect.InvocationTargetException;
public interface PlayerAttackCooldownMethods {
/**
* Grabs the attack strength for a player
* Should be noted that as of today there is no way to capture a players current attack strength in spigot when they attack an entity outside of network packet listening
* @param player target player
* @return the float value of the player's attack strength
*/
float getAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException;
float getCooldownValue(Player player) throws InvocationTargetException, IllegalAccessException;
void resetAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException;
}
//package com.gmail.nossr50.util.compat.layers.attackcooldown;
//
//import org.bukkit.entity.Player;
//
//import java.lang.reflect.InvocationTargetException;
//
//public interface PlayerAttackCooldownMethods {
// /**
// * Grabs the attack strength for a player
// * Should be noted that as of today there is no way to capture a players current attack strength in spigot when they attack an entity outside of network packet listening
// * @param player target player
// * @return the float value of the player's attack strength
// */
// float getAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException;
//
// float getCooldownValue(Player player) throws InvocationTargetException, IllegalAccessException;
//
// void resetAttackStrength(Player player) throws InvocationTargetException, IllegalAccessException;
//}

View File

@@ -0,0 +1,11 @@
package com.gmail.nossr50.util.compat.layers.bungee;
import net.kyori.adventure.text.Component;
import net.md_5.bungee.api.chat.BaseComponent;
import org.checkerframework.checker.nullness.qual.NonNull;
public abstract class AbstractBungeeSerializerCompatibilityLayer {
public abstract @NonNull Component deserialize(final @NonNull BaseComponent @NonNull[] input);
}

View File

@@ -0,0 +1,13 @@
package com.gmail.nossr50.util.compat.layers.bungee;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
import org.checkerframework.checker.nullness.qual.NonNull;
public class BungeeLegacySerializerCompatibilityLayer extends AbstractBungeeSerializerCompatibilityLayer {
@Override
public @NonNull Component deserialize(@NonNull BaseComponent @NonNull [] input) {
return BungeeComponentSerializer.legacy().deserialize(input);
}
}

View File

@@ -0,0 +1,13 @@
package com.gmail.nossr50.util.compat.layers.bungee;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
import org.checkerframework.checker.nullness.qual.NonNull;
public class BungeeModernSerializerCompatibilityLayer extends AbstractBungeeSerializerCompatibilityLayer {
@Override
public @NonNull Component deserialize(@NonNull BaseComponent @NonNull [] input) {
return BungeeComponentSerializer.get().deserialize(input);
}
}

View File

@@ -4,6 +4,7 @@ import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.compat.layers.AbstractCompatibilityLayer;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Furnace;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
@@ -14,19 +15,114 @@ import java.util.UUID;
public abstract class AbstractPersistentDataLayer extends AbstractCompatibilityLayer {
public static final String LEGACY_ABILITY_TOOL_LORE = "mcMMO Ability Tool";
public final NamespacedKey superAbilityBoosted;
public final String SUPER_ABILITY_BOOSTED = "super_ability_boosted";
protected final @NotNull NamespacedKey NSK_SUPER_ABILITY_BOOSTED_ITEM;
protected final @NotNull NamespacedKey NSK_MOB_SPAWNER_MOB;
protected final @NotNull NamespacedKey NSK_EGG_MOB;
protected final @NotNull NamespacedKey NSK_NETHER_GATE_MOB;
protected final @NotNull NamespacedKey NSK_COTW_SUMMONED_MOB;
protected final @NotNull NamespacedKey NSK_PLAYER_BRED_MOB;
protected final @NotNull NamespacedKey NSK_PLAYER_TAMED_MOB;
protected final @NotNull NamespacedKey NSK_VILLAGER_TRADE_ORIGIN_ITEM;
protected final @NotNull NamespacedKey NSK_EXPLOITED_ENDERMEN;
//Never change these constants
public final @NotNull String STR_SUPER_ABILITY_BOOSTED_ITEM = "super_ability_boosted";
public final @NotNull String STR_MOB_SPAWNER_MOB = "mcmmo_mob_spawner_mob";
public final @NotNull String STR_EGG_MOB = "mcmmo_egg_mob";
public final @NotNull String STR_NETHER_PORTAL_MOB = "mcmmo_nethergate_mob";
public final @NotNull String STR_COTW_SUMMONED_MOB = "mcmmo_cotw_summoned_mob";
public final @NotNull String STR_PLAYER_BRED_MOB = "mcmmo_player_bred_mob";
public final @NotNull String STR_PLAYER_TAMED_MOB = "mcmmo_player_tamed_mob";
public final @NotNull String STR_VILLAGER_TRADE_ORIGIN_ITEM = "mcmmo_villager_trade_origin_item";
public final @NotNull String STR_EXPLOITED_ENDERMEN = "mcmmo_exploited_endermen";
/*
* Don't modify these keys
*/
public final @NotNull String STR_FURNACE_UUID_MOST_SIG = "furnace_uuid_most_sig";
public final @NotNull String STR_FURNACE_UUID_LEAST_SIG = "furnace_uuid_least_sig";
protected final @NotNull NamespacedKey NSK_FURNACE_UUID_MOST_SIG;
protected final @NotNull NamespacedKey NSK_FURNACE_UUID_LEAST_SIG;
public final @NotNull String LEGACY_ABILITY_TOOL_LORE = "mcMMO Ability Tool";
protected static final byte SIMPLE_FLAG_VALUE = (byte) 0x1;
public AbstractPersistentDataLayer() {
superAbilityBoosted = getNamespacedKey(SUPER_ABILITY_BOOSTED);
NSK_SUPER_ABILITY_BOOSTED_ITEM = getNamespacedKey(STR_SUPER_ABILITY_BOOSTED_ITEM);
NSK_MOB_SPAWNER_MOB = getNamespacedKey(STR_MOB_SPAWNER_MOB);
NSK_EGG_MOB = getNamespacedKey(STR_EGG_MOB);
NSK_NETHER_GATE_MOB = getNamespacedKey(STR_NETHER_PORTAL_MOB);
NSK_COTW_SUMMONED_MOB = getNamespacedKey(STR_COTW_SUMMONED_MOB);
NSK_PLAYER_BRED_MOB = getNamespacedKey(STR_PLAYER_BRED_MOB);
NSK_PLAYER_TAMED_MOB = getNamespacedKey(STR_PLAYER_TAMED_MOB);
NSK_VILLAGER_TRADE_ORIGIN_ITEM = getNamespacedKey(STR_VILLAGER_TRADE_ORIGIN_ITEM);
NSK_EXPLOITED_ENDERMEN = getNamespacedKey(STR_EXPLOITED_ENDERMEN);
NSK_FURNACE_UUID_MOST_SIG = getNamespacedKey(STR_FURNACE_UUID_MOST_SIG);
NSK_FURNACE_UUID_LEAST_SIG = getNamespacedKey(STR_FURNACE_UUID_LEAST_SIG);
initializeLayer();
}
public @NotNull NamespacedKey getNamespacedKey(@NotNull String key) {
/**
* Helper method to simplify generating namespaced keys
* @param key the {@link String} value of the key
* @return the generated {@link NamespacedKey}
*/
private @NotNull NamespacedKey getNamespacedKey(@NotNull String key) {
return new NamespacedKey(mcMMO.p, key);
}
/**
* Whether or not a target {@link LivingEntity} has a specific mcMMO mob flags
* @param flag the type of mob flag to check for
* @param livingEntity the living entity to check for metadata
* @return true if the mob has metadata values for target {@link MobMetaFlagType}
*/
public abstract boolean hasMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity);
/**
* Whether or not a target {@link LivingEntity} has any mcMMO mob flags
* @param livingEntity the living entity to check for metadata
* @return true if the mob has any mcMMO mob related metadata values
*/
public abstract boolean hasMobFlags(@NotNull LivingEntity livingEntity);
/**
* Copies all mcMMO mob flags from one {@link LivingEntity} to another {@link LivingEntity}
* This does not clear existing mcMMO mob flags on the target
* @param sourceEntity entity to copy from
* @param targetEntity entity to copy to
*/
public abstract void addMobFlags(@NotNull LivingEntity sourceEntity, @NotNull LivingEntity targetEntity);
/**
* Adds a mob flag to a {@link LivingEntity} which effectively acts a true/false boolean
* Existence of the flag can be considered a true value, non-existence can be considered false for all intents and purposes
* @param flag the desired flag to assign
* @param livingEntity the target living entity
*/
public abstract void flagMetadata(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity);
/**
* Removes a specific mob flag from target {@link LivingEntity}
* @param flag desired flag to remove
* @param livingEntity the target living entity
*/
public abstract void removeMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity);
/**
* Remove all mcMMO related mob flags from the target {@link LivingEntity}
* @param livingEntity target entity
*/
public void removeMobFlags(@NotNull LivingEntity livingEntity) {
for(MobMetaFlagType flag : MobMetaFlagType.values()) {
removeMobFlag(flag, livingEntity);
}
}
public abstract @Nullable UUID getFurnaceOwner(@NotNull Furnace furnace);
public abstract void setFurnaceOwner(@NotNull Furnace furnace, @NotNull UUID uuid);
@@ -39,7 +135,7 @@ public abstract class AbstractPersistentDataLayer extends AbstractCompatibilityL
public abstract void removeBonusDigSpeedOnSuperAbilityTool(@NotNull ItemStack itemStack);
public boolean isLegacyAbilityTool(ItemStack itemStack) {
public boolean isLegacyAbilityTool(@NotNull ItemStack itemStack) {
ItemMeta itemMeta = itemStack.getItemMeta();
if(itemMeta == null)
@@ -53,7 +149,7 @@ public abstract class AbstractPersistentDataLayer extends AbstractCompatibilityL
return lore.contains(LEGACY_ABILITY_TOOL_LORE);
}
public static String getLegacyAbilityToolLore() {
public @NotNull String getLegacyAbilityToolLore() {
return LEGACY_ABILITY_TOOL_LORE;
}
}

View File

@@ -0,0 +1,11 @@
package com.gmail.nossr50.util.compat.layers.persistentdata;
public enum MobMetaFlagType {
MOB_SPAWNER_MOB,
EGG_MOB,
NETHER_PORTAL_MOB,
COTW_SUMMONED_MOB,
PLAYER_BRED_MOB,
PLAYER_TAMED_MOB,
EXPLOITED_ENDERMEN,
}

View File

@@ -1,9 +1,11 @@
package com.gmail.nossr50.util.compat.layers.persistentdata;
import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister;
import com.gmail.nossr50.datatypes.meta.UUIDMeta;
import com.gmail.nossr50.mcMMO;
import org.bukkit.block.Furnace;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
@@ -11,6 +13,7 @@ import org.bukkit.inventory.meta.tags.ItemTagType;
import org.bukkit.metadata.Metadatable;
import org.jetbrains.annotations.NotNull;
import java.util.EnumMap;
import java.util.UUID;
/**
@@ -18,19 +21,94 @@ import java.util.UUID;
*/
public class SpigotPersistentDataLayer_1_13 extends AbstractPersistentDataLayer {
private final String FURNACE_OWNER_METADATA_KEY = "mcMMO_furnace_owner";
private final @NotNull String KEY_FURNACE_OWNER = "mcMMO_furnace_owner";
private final @NotNull EnumMap<MobMetaFlagType, String> mobFlagKeyMap;
public SpigotPersistentDataLayer_1_13() {
mobFlagKeyMap = new EnumMap<>(MobMetaFlagType.class);
initMobFlagKeyMap();
}
@Override
public boolean initializeLayer() {
return true;
}
private void initMobFlagKeyMap() throws IncompleteNamespacedKeyRegister {
for(MobMetaFlagType flagType : MobMetaFlagType.values()) {
switch(flagType) {
case MOB_SPAWNER_MOB:
mobFlagKeyMap.put(flagType, STR_MOB_SPAWNER_MOB);
break;
case EGG_MOB:
mobFlagKeyMap.put(flagType, STR_EGG_MOB);
break;
case NETHER_PORTAL_MOB:
mobFlagKeyMap.put(flagType, STR_NETHER_PORTAL_MOB);
break;
case COTW_SUMMONED_MOB:
mobFlagKeyMap.put(flagType, STR_COTW_SUMMONED_MOB);
break;
case PLAYER_BRED_MOB:
mobFlagKeyMap.put(flagType, STR_PLAYER_BRED_MOB);
break;
case PLAYER_TAMED_MOB:
mobFlagKeyMap.put(flagType, STR_PLAYER_TAMED_MOB);
break;
case EXPLOITED_ENDERMEN:
mobFlagKeyMap.put(flagType, STR_EXPLOITED_ENDERMEN);
break;
default:
throw new IncompleteNamespacedKeyRegister("Missing flag register for: "+flagType.toString());
}
}
}
@Override
public boolean hasMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
return livingEntity.hasMetadata(mobFlagKeyMap.get(flag));
}
@Override
public boolean hasMobFlags(@NotNull LivingEntity livingEntity) {
for(String currentKey : mobFlagKeyMap.values()) {
if(livingEntity.hasMetadata(currentKey)) {
return true;
}
}
return false;
}
@Override
public void addMobFlags(@NotNull LivingEntity sourceEntity, @NotNull LivingEntity targetEntity) {
for(MobMetaFlagType flag : MobMetaFlagType.values()) {
if(hasMobFlag(flag, sourceEntity)) {
flagMetadata(flag, targetEntity);
}
}
}
@Override
public void flagMetadata(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
if(!hasMobFlag(flag, livingEntity)) {
livingEntity.setMetadata(mobFlagKeyMap.get(flag), mcMMO.metadataValue);
}
}
@Override
public void removeMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
if(hasMobFlag(flag, livingEntity)) {
livingEntity.removeMetadata(mobFlagKeyMap.get(flag), mcMMO.p);
}
}
@Override
public UUID getFurnaceOwner(@NotNull Furnace furnace) {
Metadatable metadatable = (Metadatable) furnace;
if(metadatable.getMetadata(FURNACE_OWNER_METADATA_KEY).size() > 0) {
UUIDMeta uuidMeta = (UUIDMeta) metadatable.getMetadata(FURNACE_OWNER_METADATA_KEY).get(0);
if(metadatable.getMetadata(KEY_FURNACE_OWNER).size() > 0) {
UUIDMeta uuidMeta = (UUIDMeta) metadatable.getMetadata(KEY_FURNACE_OWNER).get(0);
return (UUID) uuidMeta.value();
} else {
return null;
@@ -41,11 +119,11 @@ public class SpigotPersistentDataLayer_1_13 extends AbstractPersistentDataLayer
public void setFurnaceOwner(@NotNull Furnace furnace, @NotNull UUID uuid) {
Metadatable metadatable = (Metadatable) furnace;
if(metadatable.getMetadata(FURNACE_OWNER_METADATA_KEY).size() > 0) {
metadatable.removeMetadata(FURNACE_OWNER_METADATA_KEY, mcMMO.p);
if(metadatable.getMetadata(KEY_FURNACE_OWNER).size() > 0) {
metadatable.removeMetadata(KEY_FURNACE_OWNER, mcMMO.p);
}
metadatable.setMetadata(FURNACE_OWNER_METADATA_KEY, new UUIDMeta(mcMMO.p, uuid));
metadatable.setMetadata(KEY_FURNACE_OWNER, new UUIDMeta(mcMMO.p, uuid));
}
@Override
@@ -57,7 +135,7 @@ public class SpigotPersistentDataLayer_1_13 extends AbstractPersistentDataLayer
return;
}
itemMeta.getCustomTagContainer().setCustomTag(superAbilityBoosted, ItemTagType.INTEGER, originalDigSpeed);
itemMeta.getCustomTagContainer().setCustomTag(NSK_SUPER_ABILITY_BOOSTED_ITEM, ItemTagType.INTEGER, originalDigSpeed);
itemStack.setItemMeta(itemMeta);
}
@@ -69,7 +147,7 @@ public class SpigotPersistentDataLayer_1_13 extends AbstractPersistentDataLayer
return false;
CustomItemTagContainer tagContainer = itemMeta.getCustomTagContainer();
return tagContainer.hasCustomTag(superAbilityBoosted, ItemTagType.INTEGER);
return tagContainer.hasCustomTag(NSK_SUPER_ABILITY_BOOSTED_ITEM, ItemTagType.INTEGER);
}
@Override
@@ -81,8 +159,8 @@ public class SpigotPersistentDataLayer_1_13 extends AbstractPersistentDataLayer
CustomItemTagContainer tagContainer = itemMeta.getCustomTagContainer();
if(tagContainer.hasCustomTag(superAbilityBoosted , ItemTagType.INTEGER)) {
return tagContainer.getCustomTag(superAbilityBoosted, ItemTagType.INTEGER);
if(tagContainer.hasCustomTag(NSK_SUPER_ABILITY_BOOSTED_ITEM, ItemTagType.INTEGER)) {
return tagContainer.getCustomTag(NSK_SUPER_ABILITY_BOOSTED_ITEM, ItemTagType.INTEGER);
} else {
return 0;
}

View File

@@ -1,9 +1,12 @@
package com.gmail.nossr50.util.compat.layers.persistentdata;
import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister;
import com.gmail.nossr50.config.PersistentDataConfig;
import com.gmail.nossr50.mcMMO;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Furnace;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
@@ -12,28 +15,109 @@ import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.EnumMap;
import java.util.UUID;
public class SpigotPersistentDataLayer_1_14 extends AbstractPersistentDataLayer {
/*
* Don't modify these keys
*/
public static final String FURNACE_UUID_MOST_SIG = "furnace_uuid_most_sig";
public static final String FURNACE_UUID_LEAST_SIG = "furnace_uuid_least_sig";
private final @NotNull EnumMap<MobMetaFlagType, NamespacedKey> mobFlagKeyMap;
private final @NotNull SpigotPersistentDataLayer_1_13 transientLayer;
private NamespacedKey furnaceOwner_MostSig_Key;
private NamespacedKey furnaceOwner_LeastSig_Key;
public SpigotPersistentDataLayer_1_14() {
mobFlagKeyMap = new EnumMap<>(MobMetaFlagType.class);
initMobFlagKeyMap();
transientLayer = new SpigotPersistentDataLayer_1_13(); //For disabled persistent types
}
@Override
public boolean initializeLayer() {
initNamespacedKeys();
return true;
}
private void initNamespacedKeys() {
furnaceOwner_MostSig_Key = getNamespacedKey(FURNACE_UUID_MOST_SIG);
furnaceOwner_LeastSig_Key = getNamespacedKey(FURNACE_UUID_LEAST_SIG);
/**
* Registers the namespaced keys required by the API (CB/Spigot)
*/
private void initMobFlagKeyMap() throws IncompleteNamespacedKeyRegister {
for(MobMetaFlagType mobMetaFlagType : MobMetaFlagType.values()) {
switch(mobMetaFlagType) {
case MOB_SPAWNER_MOB:
mobFlagKeyMap.put(mobMetaFlagType, NSK_MOB_SPAWNER_MOB);
break;
case EGG_MOB:
mobFlagKeyMap.put(mobMetaFlagType, NSK_EGG_MOB);
break;
case NETHER_PORTAL_MOB:
mobFlagKeyMap.put(mobMetaFlagType, NSK_NETHER_GATE_MOB);
break;
case COTW_SUMMONED_MOB:
mobFlagKeyMap.put(mobMetaFlagType, NSK_COTW_SUMMONED_MOB);
break;
case PLAYER_BRED_MOB:
mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_BRED_MOB);
break;
case EXPLOITED_ENDERMEN:
mobFlagKeyMap.put(mobMetaFlagType, NSK_EXPLOITED_ENDERMEN);
break;
case PLAYER_TAMED_MOB:
mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_TAMED_MOB);
break;
default:
throw new IncompleteNamespacedKeyRegister("missing namespaced key register for type: "+ mobMetaFlagType.toString());
}
}
}
@Override
public boolean hasMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
if(PersistentDataConfig.getInstance().isMobPersistent(flag)) {
return livingEntity.getPersistentDataContainer().has(mobFlagKeyMap.get(flag), PersistentDataType.BYTE);
} else {
return transientLayer.hasMobFlag(flag, livingEntity);
}
}
@Override
public boolean hasMobFlags(@NotNull LivingEntity livingEntity) {
for(MobMetaFlagType currentFlag : MobMetaFlagType.values()) {
if(hasMobFlag(currentFlag, livingEntity)) {
return true;
}
}
return false;
}
@Override
public void addMobFlags(@NotNull LivingEntity sourceEntity, @NotNull LivingEntity targetEntity) {
for(MobMetaFlagType flag : MobMetaFlagType.values()) {
if(hasMobFlag(flag, sourceEntity)) {
flagMetadata(flag, targetEntity);
}
}
}
@Override
public void flagMetadata(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
if(PersistentDataConfig.getInstance().isMobPersistent(flag)) {
if(!hasMobFlag(flag, livingEntity)) {
PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer();
persistentDataContainer.set(mobFlagKeyMap.get(flag), PersistentDataType.BYTE, SIMPLE_FLAG_VALUE);
}
} else {
transientLayer.flagMetadata(flag, livingEntity);
}
}
@Override
public void removeMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
if(PersistentDataConfig.getInstance().isMobPersistent(flag)) {
if(hasMobFlag(flag, livingEntity)) {
PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer();
persistentDataContainer.remove(mobFlagKeyMap.get(flag));
}
} else {
transientLayer.removeMobFlag(flag, livingEntity);
}
}
@Override
@@ -42,8 +126,8 @@ public class SpigotPersistentDataLayer_1_14 extends AbstractPersistentDataLayer
PersistentDataContainer dataContainer = ((PersistentDataHolder) furnace).getPersistentDataContainer();
//Too lazy to make a custom data type for this stuff
Long mostSigBits = dataContainer.get(furnaceOwner_MostSig_Key, PersistentDataType.LONG);
Long leastSigBits = dataContainer.get(furnaceOwner_LeastSig_Key, PersistentDataType.LONG);
Long mostSigBits = dataContainer.get(NSK_FURNACE_UUID_MOST_SIG, PersistentDataType.LONG);
Long leastSigBits = dataContainer.get(NSK_FURNACE_UUID_LEAST_SIG, PersistentDataType.LONG);
if(mostSigBits != null && leastSigBits != null) {
return new UUID(mostSigBits, leastSigBits);
@@ -56,8 +140,8 @@ public class SpigotPersistentDataLayer_1_14 extends AbstractPersistentDataLayer
public void setFurnaceOwner(@NotNull Furnace furnace, @NotNull UUID uuid) {
PersistentDataContainer dataContainer = ((PersistentDataHolder) furnace).getPersistentDataContainer();
dataContainer.set(furnaceOwner_MostSig_Key, PersistentDataType.LONG, uuid.getMostSignificantBits());
dataContainer.set(furnaceOwner_LeastSig_Key, PersistentDataType.LONG, uuid.getLeastSignificantBits());
dataContainer.set(NSK_FURNACE_UUID_MOST_SIG, PersistentDataType.LONG, uuid.getMostSignificantBits());
dataContainer.set(NSK_FURNACE_UUID_LEAST_SIG, PersistentDataType.LONG, uuid.getLeastSignificantBits());
furnace.update();
}
@@ -72,7 +156,7 @@ public class SpigotPersistentDataLayer_1_14 extends AbstractPersistentDataLayer
ItemMeta itemMeta = itemStack.getItemMeta();
PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
dataContainer.set(superAbilityBoosted, PersistentDataType.INTEGER, originalDigSpeed);
dataContainer.set(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER, originalDigSpeed);
itemStack.setItemMeta(itemMeta);
}
@@ -87,7 +171,7 @@ public class SpigotPersistentDataLayer_1_14 extends AbstractPersistentDataLayer
PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
//If this value isn't null, then the tool can be considered dig speed boosted
Integer boostValue = dataContainer.get(superAbilityBoosted, PersistentDataType.INTEGER);
Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER);
return boostValue != null;
}
@@ -102,12 +186,12 @@ public class SpigotPersistentDataLayer_1_14 extends AbstractPersistentDataLayer
PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
if(dataContainer.get(superAbilityBoosted, PersistentDataType.INTEGER) == null) {
if(dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER) == null) {
mcMMO.p.getLogger().severe("Value should never be null for a boosted item");
return 0;
} else {
//Too lazy to make a custom data type for this stuff
Integer boostValue = dataContainer.get(superAbilityBoosted, PersistentDataType.INTEGER);
Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER);
return Math.max(boostValue, 0);
}
}
@@ -127,7 +211,7 @@ public class SpigotPersistentDataLayer_1_14 extends AbstractPersistentDataLayer
}
PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
dataContainer.remove(superAbilityBoosted); //Remove persistent data
dataContainer.remove(NSK_SUPER_ABILITY_BOOSTED_ITEM); //Remove persistent data
//TODO: needed?
itemStack.setItemMeta(itemMeta);

View File

@@ -0,0 +1,6 @@
package com.gmail.nossr50.util.compat.layers.skills;
import com.gmail.nossr50.util.compat.layers.AbstractCompatibilityLayer;
public abstract class AbstractMasterAnglerCompatibility extends AbstractCompatibilityLayer {
}

View File

@@ -0,0 +1,91 @@
package com.gmail.nossr50.util.compat.layers.skills;
import org.bukkit.entity.FishHook;
import org.jetbrains.annotations.NotNull;
public class MasterAnglerCompatibilityLayer extends AbstractMasterAnglerCompatibility {
@Override
public boolean initializeLayer() {
return true;
}
/**
* Get the minimum number of ticks one has to wait for a fish biting.
* <p>
* The default is 100 ticks (5 seconds).<br>
* Note that this is before applying lure.
*
* @return Minimum number of ticks one has to wait for a fish biting
*/
public int getMinWaitTime(@NotNull FishHook fishHook) {
return fishHook.getMinWaitTime();
}
/**
* Set the minimum number of ticks one has to wait for a fish biting.
* <p>
* The default is 100 ticks (5 seconds).<br>
* Note that this is before applying lure.
*
* @param minWaitTime Minimum number of ticks one has to wait for a fish
* biting
*/
public void setMinWaitTime(@NotNull FishHook fishHook, int minWaitTime) {
fishHook.setMinWaitTime(minWaitTime);
}
/**
* Get the maximum number of ticks one has to wait for a fish biting.
* <p>
* The default is 600 ticks (30 seconds).<br>
* Note that this is before applying lure.
*
* @return Maximum number of ticks one has to wait for a fish biting
*/
public int getMaxWaitTime(@NotNull FishHook fishHook) {
return fishHook.getMaxWaitTime();
}
/**
* Set the maximum number of ticks one has to wait for a fish biting.
* <p>
* The default is 600 ticks (30 seconds).<br>
* Note that this is before applying lure.
*
* @param maxWaitTime Maximum number of ticks one has to wait for a fish
* biting
*/
public void setMaxWaitTime(@NotNull FishHook fishHook, int maxWaitTime) {
fishHook.setMaxWaitTime(maxWaitTime);
}
/**
* Get whether the lure enchantment should be applied to reduce the wait
* time.
* <p>
* The default is true.<br>
* Lure reduces the wait time by 100 ticks (5 seconds) for each level of the
* enchantment.
*
* @return Whether the lure enchantment should be applied to reduce the wait
* time
*/
public boolean getApplyLure(@NotNull FishHook fishHook) {
return fishHook.getApplyLure();
}
/**
* Set whether the lure enchantment should be applied to reduce the wait
* time.
* <p>
* The default is true.<br>
* Lure reduces the wait time by 100 ticks (5 seconds) for each level of the
* enchantment.
*
* @param applyLure Whether the lure enchantment should be applied to reduce
* the wait time
*/
public void setApplyLure(@NotNull FishHook fishHook, boolean applyLure) {
fishHook.setApplyLure(applyLure);
}
}

View File

@@ -4,8 +4,8 @@ import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.datatypes.player.PersistentPlayerData;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.util.StringUtils;
import com.gmail.nossr50.util.player.PlayerLevelUtils;
import com.gmail.nossr50.util.text.StringUtils;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;

View File

@@ -1,10 +1,14 @@
package com.gmail.nossr50.util.input;
import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.datatypes.interactions.NotificationType;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.herbalism.HerbalismManager;
import com.gmail.nossr50.skills.mining.MiningManager;
@@ -12,6 +16,7 @@ import com.gmail.nossr50.skills.taming.TamingManager;
import com.gmail.nossr50.util.BlockUtils;
import com.gmail.nossr50.util.ChimaeraWing;
import com.gmail.nossr50.util.EventUtils;
import com.gmail.nossr50.util.player.NotificationManager;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -186,6 +191,53 @@ public class AbilityActivationProcessor {
}
}
public void processAxeToolMessages() {
Block rayCast = player.getTargetBlock(null, 100);
/*
* IF BOTH TREE FELLER & SKULL SPLITTER ARE ON CD
*/
if(isAbilityOnCooldown(SuperAbilityType.TREE_FELLER) && isAbilityOnCooldown(SuperAbilityType.SKULL_SPLITTER)) {
tooTiredMultiple(PrimarySkillType.WOODCUTTING, SubSkillType.WOODCUTTING_TREE_FELLER, SuperAbilityType.TREE_FELLER, SubSkillType.AXES_SKULL_SPLITTER, SuperAbilityType.SKULL_SPLITTER);
/*
* IF TREE FELLER IS ON CD
* AND PLAYER IS LOOKING AT TREE
*/
} else if(isAbilityOnCooldown(SuperAbilityType.TREE_FELLER)
&& BlockUtils.isPartOfTree(rayCast)) {
raiseToolWithCooldowns(SubSkillType.WOODCUTTING_TREE_FELLER, SuperAbilityType.TREE_FELLER);
/*
* IF SKULL SPLITTER IS ON CD
*/
} else if(isAbilityOnCooldown(SuperAbilityType.SKULL_SPLITTER)) {
raiseToolWithCooldowns(SubSkillType.AXES_SKULL_SPLITTER, SuperAbilityType.SKULL_SPLITTER);
} else {
NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, ToolType.AXE.getRaiseTool());
}
}
private void tooTiredMultiple(PrimarySkillType primarySkillType, SubSkillType aSubSkill, SuperAbilityType aSuperAbility, SubSkillType bSubSkill, SuperAbilityType bSuperAbility) {
String aSuperAbilityCD = LocaleLoader.getString("Skills.TooTired.Named", aSubSkill.getLocaleName(), String.valueOf(calculateTimeRemaining(aSuperAbility)));
String bSuperAbilityCD = LocaleLoader.getString("Skills.TooTired.Named", bSubSkill.getLocaleName(), String.valueOf(calculateTimeRemaining(bSuperAbility)));
String allCDStr = aSuperAbilityCD + ", " + bSuperAbilityCD;
NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, "Skills.TooTired.Extra",
primarySkillType.getName(),
allCDStr);
}
private void raiseToolWithCooldowns(SubSkillType subSkillType, SuperAbilityType superAbilityType) {
NotificationManager.sendPlayerInformation(player, NotificationType.TOOL,
"Axes.Ability.Ready.Extra",
subSkillType.getLocaleName(),
String.valueOf(calculateTimeRemaining(superAbilityType)));
}
public boolean isAbilityOnCooldown(SuperAbilityType ability) {
return !getAbilityMode(ability) && calculateTimeRemaining(ability) > 0;
}
private SuperAbilityManager getSuperAbilityManager() {
return mmoPlayer.getSuperAbilityManager();
}

View File

@@ -84,6 +84,45 @@ public class SuperAbilityManager {
* Woodcutting & Axes need to be treated differently.
* Basically the tool always needs to ready and we check to see if the cooldown is over when the user takes action
*/
/*
* Woodcutting & Axes need to be treated differently.
* Basically the tool always needs to ready and we check to see if the cooldown is over when the user takes action
*/
//TODO: Convert this later
if (mmoPlayer.getAbilityActivationProcessor().isHoldingTool() && !isAbilityToolPrimed(tool)) {
if (skill != PrimarySkillType.WOODCUTTING && skill != PrimarySkillType.AXES) {
int timeRemaining = calculateTimeRemaining(ability);
if (isAbilityOnCooldown(ability)) {
NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining));
return;
}
}
if (Config.getInstance().getAbilityMessagesEnabled()) {
/*
*
* IF THE TOOL IS AN AXE
*
*/
if(tool == ToolType.AXE) {
processAxeToolMessages();
} else {
NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, tool.getRaiseTool());
}
//Send Sound
SoundManager.sendSound(player, player.getLocation(), SoundType.TOOL_READY);
}
setToolPreparationMode(tool, true);
new ToolLowerTask(this, tool).runTaskLater(mcMMO.p, 4 * Misc.TICK_CONVERSION_FACTOR);
}
//TODO: Older code below
if (mmoPlayer.getAbilityActivationProcessor().isHoldingTool() && !isAbilityToolPrimed(tool)) {
if (skill != PrimarySkillType.WOODCUTTING && skill != PrimarySkillType.AXES) {
int timeRemaining = calculateTimeRemaining(ability);

View File

@@ -20,6 +20,7 @@ public enum NMSVersion {
NMS_1_16_1("1.16.1"),
NMS_1_16_2("1.16.2"),
NMS_1_16_3("1.16.3"),
NMS_1_16_4("1.16.4"),
//Version not known to this build of mcMMO
UNSUPPORTED("unsupported");

View File

@@ -10,13 +10,14 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.events.skills.McMMOPlayerNotificationEvent;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.McMMOMessageType;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.TextComponentFactory;
import com.gmail.nossr50.util.sounds.SoundManager;
import com.gmail.nossr50.util.sounds.SoundType;
import com.gmail.nossr50.util.text.McMMOMessageType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@@ -115,10 +116,10 @@ public class NotificationManager {
if(customEvent.isMessageAlsoBeingSentToChat())
{
//Send copy to chat system
audience.sendMessage(customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
audience.sendMessage(Identity.nil(), customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
}
} else {
audience.sendMessage(customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
audience.sendMessage(Identity.nil(), customEvent.getNotificationTextComponent(), MessageType.SYSTEM);
}
}
@@ -165,7 +166,7 @@ public class NotificationManager {
return;
//CHAT MESSAGE
mcMMO.getAudiences().player(mmoPlayer.getPlayer()).sendMessage(TextComponentFactory.getSubSkillUnlockedNotificationComponents(mmoPlayer.getPlayer(), subSkillType));
mcMMO.getAudiences().player(mmoPlayer.getPlayer()).sendMessage(Identity.nil(), TextComponentFactory.getSubSkillUnlockedNotificationComponents(mmoPlayer.getPlayer(), subSkillType));
//Unlock Sound Effect
SoundManager.sendCategorizedSound(mmoPlayer.getPlayer(), mmoPlayer.getPlayer().getLocation(), SoundType.SKILL_UNLOCKED, SoundCategory.MASTER);

View File

@@ -10,6 +10,7 @@ import com.gmail.nossr50.util.EventUtils;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.skills.SkillActivationType;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.text.DecimalFormat;
import java.util.concurrent.ThreadLocalRandom;
@@ -314,7 +315,7 @@ public class RandomChanceUtil
return isActivationSuccessful(skillActivationType, abstractSubSkill.getSubSkillType(), player);
}
public static String[] calculateAbilityDisplayValues(SkillActivationType skillActivationType, Player player, SubSkillType subSkillType) {
public static String[] calculateAbilityDisplayValues(@NotNull SkillActivationType skillActivationType, @NotNull Player player, @NotNull SubSkillType subSkillType) {
double successChance = getActivationChance(skillActivationType, subSkillType, player);
String[] displayValues = new String[2];

View File

@@ -466,8 +466,8 @@ public class ScoreboardWrapper {
// Special-Case: Mining has two abilities, both with cooldowns
Score cooldownSB = sidebarObjective.getScore(ScoreboardManager.abilityLabelsSkill.get(SuperAbilityType.SUPER_BREAKER));
Score cooldownBM = sidebarObjective.getScore(ScoreboardManager.abilityLabelsSkill.get(SuperAbilityType.BLAST_MINING));
int secondsSB = Math.max(mmoPlayer.calculateTimeRemaining(SuperAbilityType.SUPER_BREAKER), 0);
int secondsBM = Math.max(mmoPlayer.calculateTimeRemaining(SuperAbilityType.BLAST_MINING), 0);
int secondsSB = Math.max(mmoPlayer.getCooldownSeconds(SuperAbilityType.SUPER_BREAKER), 0);
int secondsBM = Math.max(mmoPlayer.getCooldownSeconds(SuperAbilityType.BLAST_MINING), 0);
cooldownSB.setScore(secondsSB);
cooldownBM.setScore(secondsBM);
@@ -477,7 +477,7 @@ public class ScoreboardWrapper {
else {
SuperAbilityType ability = targetSkill.getSuperAbilityType();
Score cooldown = sidebarObjective.getScore(ScoreboardManager.abilityLabelsSkill.get(ability));
int seconds = Math.max(mmoPlayer.calculateTimeRemaining(ability), 0);
int seconds = Math.max(mmoPlayer.getCooldownSeconds(ability), 0);
cooldown.setScore(seconds);
@@ -497,7 +497,7 @@ public class ScoreboardWrapper {
boolean anyCooldownsActive = false;
for (SuperAbilityType ability : SuperAbilityType.values()) {
int seconds = Math.max(mmoPlayer.calculateTimeRemaining(ability), 0);
int seconds = Math.max(mmoPlayer.getCooldownSeconds(ability), 0);
if (seconds != 0) {
anyCooldownsActive = true;

View File

@@ -21,10 +21,14 @@ import com.gmail.nossr50.skills.taming.TamingManager;
import com.gmail.nossr50.skills.tridents.TridentManager;
import com.gmail.nossr50.skills.unarmed.UnarmedManager;
import com.gmail.nossr50.util.*;
import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
import com.gmail.nossr50.util.player.NotificationManager;
import com.google.common.collect.ImmutableMap;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.*;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
@@ -32,7 +36,10 @@ import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityDamageEvent.DamageModifier;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.projectiles.ProjectileSource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.EnumMap;
import java.util.HashMap;
@@ -40,9 +47,30 @@ import java.util.List;
import java.util.Map;
public final class CombatUtils {
private CombatUtils() {}
private static void processSwordCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event) {
private static @NotNull AbstractPersistentDataLayer getPersistentData() {
return mcMMO.getCompatibilityManager().getPersistentDataLayer();
}
//Likely.. because who knows what plugins are throwing around
public static boolean isDamageLikelyFromNormalCombat(@NotNull DamageCause damageCause) {
switch (damageCause) {
case ENTITY_ATTACK:
case ENTITY_SWEEP_ATTACK:
case PROJECTILE:
return true;
default:
return false;
}
}
public static boolean hasWeakenedDamage(@NotNull LivingEntity livingEntity) {
return livingEntity.hasPotionEffect(PotionEffectType.WEAKNESS);
}
private static void processSwordCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) {
return;
}
@@ -88,6 +116,8 @@ public final class CombatUtils {
applyScaledModifiers(initialDamage, finalDamage, event);
processCombatXP(mmoPlayer, target, PrimarySkillType.SWORDS);
printFinalDamageDebug(player, event, mcMMOPlayer);
}
public static void processTridentCombat(LivingEntity target, Player player, EntityDamageByEntityEvent entityDamageByEntityEvent) {
@@ -110,32 +140,19 @@ public final class CombatUtils {
}
// public static void strengthDebug(Player player) {
// BukkitPlatform bukkitPlatform = (BukkitPlatform) mcMMO.getPlatformManager().getPlatform();
// Bukkit.broadcastMessage("Strength: "+bukkitPlatform.getPlayerAttackStrength(player));
//
// Bukkit.getScheduler().scheduleSyncDelayedTask(mcMMO.p, () -> {
// Bukkit.broadcastMessage("1 Tick Delay: " + bukkitPlatform.getPlayerAttackStrength(player));
// }, 1);
//
// Bukkit.getScheduler().scheduleSyncDelayedTask(mcMMO.p, () -> {
// Bukkit.broadcastMessage("5 Tick Delay: " + bukkitPlatform.getPlayerAttackStrength(player));
// }, 5);
//
// Bukkit.getScheduler().scheduleSyncDelayedTask(mcMMO.p, () -> {
// Bukkit.broadcastMessage("80 Tick Delay: " + bukkitPlatform.getPlayerAttackStrength(player));
// }, 20 * 4);
//
// Bukkit.broadcastMessage("");
//
//// if(isPlayerFullStrength(player)) {
//// Bukkit.broadcastMessage("Full Strength!");
//// } else {
//// Bukkit.broadcastMessage("Not full strength!");
//// }
// }
private static void printFinalDamageDebug(@NotNull Player player, @NotNull EntityDamageByEntityEvent event, @NotNull McMMOPlayer mcMMOPlayer, @Nullable String @Nullable ... extraInfoLines) {
if(mcMMOPlayer.isDebugMode()) {
player.sendMessage("Final Damage value after mcMMO modifiers: "+ event.getFinalDamage());
if(extraInfoLines != null) {
for(String str : extraInfoLines) {
if(str != null)
player.sendMessage(str);
}
}
}
}
private static void processAxeCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event) {
private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) {
return;
}
@@ -183,9 +200,11 @@ public final class CombatUtils {
applyScaledModifiers(initialDamage, finalDamage, event);
processCombatXP(mmoPlayer, target, PrimarySkillType.AXES);
printFinalDamageDebug(player, event, mcMMOPlayer);
}
private static void processUnarmedCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event) {
private static void processUnarmedCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) {
return;
}
@@ -206,8 +225,7 @@ public final class CombatUtils {
mmoPlayer.getSuperAbilityManager().checkAbilityActivation(PrimarySkillType.UNARMED);
}
//Only execute bonuses if the player is not spamming
if (unarmedManager.canUseIronArm()) {
if (unarmedManager.canUseSteelArm()) {
finalDamage+=(unarmedManager.calculateSteelArmStyleDamage() * mmoPlayer.getAttackStrength());
}
@@ -226,9 +244,11 @@ public final class CombatUtils {
applyScaledModifiers(initialDamage, finalDamage, event);
processCombatXP(mmoPlayer, target, PrimarySkillType.UNARMED);
printFinalDamageDebug(player, event, mmoPlayer);
}
private static void processTamingCombat(LivingEntity target, Player master, Wolf wolf, EntityDamageByEntityEvent event) {
private static void processTamingCombat(@NotNull LivingEntity target, @Nullable Player master, @NotNull Wolf wolf, @NotNull EntityDamageByEntityEvent event) {
double initialDamage = event.getDamage();
double finalDamage = initialDamage;
@@ -262,7 +282,7 @@ public final class CombatUtils {
}
private static void processArcheryCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event, Projectile arrow) {
private static void processArcheryCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event, @NotNull Projectile arrow) {
double initialDamage = event.getDamage();
McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
@@ -301,6 +321,13 @@ public final class CombatUtils {
// forceMultiplier = arrow.getMetadata(mcMMO.bowForceKey).get(0).asDouble();
applyScaledModifiers(initialDamage, finalDamage, event);
printFinalDamageDebug(player, event, mmoPlayer,
"Distance Multiplier: "+distanceMultiplier,
"Force Multiplier: "+forceMultiplier,
"Initial Damage: "+initialDamage,
"Final Damage: "+finalDamage);
processCombatXP(mmoPlayer, target, PrimarySkillType.ARCHERY, distanceMultiplier);
}
@@ -337,6 +364,13 @@ public final class CombatUtils {
double distanceMultiplier = crossbowManager.distanceXpBonusMultiplier(target, arrow);
applyScaledModifiers(initialDamage, finalDamage, event);
// printFinalDamageDebug(player, event, mcMMOPlayer,
// "Distance Multiplier: "+distanceMultiplier,
// "Force Multiplier: "+forceMultiplier,
// "Initial Damage: "+initialDamage,
// "Final Damage: "+finalDamage);
processCombatXP(mmoPlayer, target, PrimarySkillType.CROSSBOWS, distanceMultiplier);
}
@@ -345,7 +379,7 @@ public final class CombatUtils {
*
* @param event The event to run the combat checks on.
*/
public static void processCombatAttack(EntityDamageByEntityEvent event, Entity painSourceRoot, LivingEntity target) {
public static void processCombatAttack(@NotNull EntityDamageByEntityEvent event, @NotNull Entity painSourceRoot, @NotNull LivingEntity target) {
Entity painSource = event.getDamager();
EntityType entityType = painSource.getType();
@@ -459,8 +493,6 @@ public final class CombatUtils {
ProjectileSource projectileShooter = arrow.getShooter();
//Determine if the arrow belongs to a bow or xbow
if (projectileShooter instanceof Player) {
Player player = (Player) projectileShooter;
@@ -481,7 +513,6 @@ public final class CombatUtils {
}
}
if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.TAMING.getPermissions(player)) {
McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
@@ -508,7 +539,7 @@ public final class CombatUtils {
* This cleans up names from displaying in chat as hearts
* @param entity target entity
*/
public static void fixNames(LivingEntity entity)
public static void fixNames(@NotNull LivingEntity entity)
{
List<MetadataValue> metadataValue = entity.getMetadata("mcMMO_oldName");
@@ -527,7 +558,7 @@ public final class CombatUtils {
* @param subSkillType the specific limit break skill for calculations
* @return the RAW damage bonus from Limit Break which is applied before reductions
*/
public static int getLimitBreakDamage(Player attacker, LivingEntity defender, SubSkillType subSkillType) {
public static int getLimitBreakDamage(@NotNull Player attacker, @NotNull LivingEntity defender, @NotNull SubSkillType subSkillType) {
if(defender instanceof Player) {
Player playerDefender = (Player) defender;
return getLimitBreakDamageAgainstQuality(attacker, subSkillType, getArmorQualityLevel(playerDefender));
@@ -544,7 +575,7 @@ public final class CombatUtils {
* @param armorQualityLevel Armor quality level
* @return the RAW damage boost after its been mutated by armor quality
*/
public static int getLimitBreakDamageAgainstQuality(Player attacker, SubSkillType subSkillType, int armorQualityLevel) {
public static int getLimitBreakDamageAgainstQuality(@NotNull Player attacker, @NotNull SubSkillType subSkillType, int armorQualityLevel) {
int rawDamageBoost = RankUtils.getRank(attacker, subSkillType);
if(armorQualityLevel <= 4) {
@@ -563,7 +594,7 @@ public final class CombatUtils {
* @param defender target defending player
* @return the armor quality of the defending player
*/
public static int getArmorQualityLevel(Player defender) {
public static int getArmorQualityLevel(@NotNull Player defender) {
int armorQualityLevel = 0;
for(ItemStack itemStack : defender.getInventory().getArmorContents()) {
@@ -580,7 +611,7 @@ public final class CombatUtils {
* @param itemStack target item stack
* @return the armor quality of a specific Item Stack
*/
private static int getArmorQuality(ItemStack itemStack) {
private static int getArmorQuality(@NotNull ItemStack itemStack) {
return mcMMO.getMaterialMapStore().getTier(itemStack.getType().getKey().getKey());
}
@@ -589,7 +620,7 @@ public final class CombatUtils {
* @param player target entity
* @return true if the player has access to the limit break
*/
public static boolean canUseLimitBreak(Player player, LivingEntity target, SubSkillType subSkillType) {
public static boolean canUseLimitBreak(@NotNull Player player, LivingEntity target, @NotNull SubSkillType subSkillType) {
if(target instanceof Player || AdvancedConfig.getInstance().canApplyLimitBreakPVE()) {
return RankUtils.hasUnlockedSubskill(player, subSkillType)
&& Permissions.isSubSkillEnabled(player, subSkillType);
@@ -605,7 +636,7 @@ public final class CombatUtils {
* @param damage Amount of damage to attempt to do
*/
@Deprecated
public static void dealDamage(LivingEntity target, double damage) {
public static void dealDamage(@NotNull LivingEntity target, double damage) {
dealDamage(target, damage, DamageCause.CUSTOM, null);
}
@@ -617,25 +648,25 @@ public final class CombatUtils {
* @param attacker Player to pass to event as damager
*/
@Deprecated
public static void dealDamage(LivingEntity target, double damage, LivingEntity attacker) {
public static void dealDamage(@NotNull LivingEntity target, double damage, @NotNull LivingEntity attacker) {
dealDamage(target, damage, DamageCause.CUSTOM, attacker);
}
/**
* Attempt to damage target for value dmg with reason ENTITY_ATTACK with damager attacker
*
* @param target LivingEntity which to attempt to damage
* @param damage Amount of damage to attempt to do
* @param attacker Player to pass to event as damager
*/
public static void dealDamage(LivingEntity target, double damage, Map<DamageModifier, Double> modifiers, LivingEntity attacker) {
if (target.isDead()) {
return;
}
// Aren't we applying the damage twice????
target.damage(getFakeDamageFinalResult(attacker, target, damage, modifiers));
}
// /**
// * Attempt to damage target for value dmg with reason ENTITY_ATTACK with damager attacker
// *
// * @param target LivingEntity which to attempt to damage
// * @param damage Amount of damage to attempt to do
// * @param attacker Player to pass to event as damager
// */
// public static void dealDamage(LivingEntity target, double damage, Map<DamageModifier, Double> modifiers, LivingEntity attacker) {
// if (target.isDead()) {
// return;
// }
//
// // Aren't we applying the damage twice????
// target.damage(getFakeDamageFinalResult(attacker, target, damage, modifiers));
// }
/**
* Attempt to damage target for value dmg with reason ENTITY_ATTACK with damager attacker
@@ -645,13 +676,16 @@ public final class CombatUtils {
* @param attacker Player to pass to event as damager
*/
@Deprecated
public static void dealDamage(LivingEntity target, double damage, DamageCause cause, Entity attacker) {
public static void dealDamage(@NotNull LivingEntity target, double damage, @NotNull DamageCause cause, @Nullable Entity attacker) {
if (target.isDead()) {
return;
}
if(canDamage(attacker, target, cause, damage))
if(canDamage(attacker, target, cause, damage)) {
applyIgnoreDamageMetadata(target);
target.damage(damage);
removeIgnoreDamageMetadata(target);
}
}
private static boolean processingNoInvulnDamage;
@@ -659,7 +693,7 @@ public final class CombatUtils {
return processingNoInvulnDamage;
}
public static void dealNoInvulnerabilityTickDamage(LivingEntity target, double damage, Entity attacker) {
public static void dealNoInvulnerabilityTickDamage(@NotNull LivingEntity target, double damage, Entity attacker) {
if (target.isDead()) {
return;
}
@@ -670,56 +704,39 @@ public final class CombatUtils {
// cause do have issues around plugin observability. This is not a perfect solution, but it appears to be the best one here
// We also set no damage ticks to 0, to ensure that damage is applied for this case, and reset it back to the original value
// Snapshot current state so we can pop up properly
boolean wasMetaSet = target.getMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY).size() != 0;
boolean wasMetaSet = hasIgnoreDamageMetadata(target);
boolean wasProcessing = processingNoInvulnDamage;
// set markers
processingNoInvulnDamage = true;
target.setMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY, mcMMO.metadataValue);
applyIgnoreDamageMetadata(target);
int noDamageTicks = target.getNoDamageTicks();
target.setNoDamageTicks(0);
target.damage(damage, attacker);
target.setNoDamageTicks(noDamageTicks);
if (!wasMetaSet)
target.removeMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY, mcMMO.p);
removeIgnoreDamageMetadata(target);
if (!wasProcessing)
processingNoInvulnDamage = false;
}
public static void dealNoInvulnerabilityTickDamageRupture(LivingEntity target, double damage, Entity attacker, int toolTier) {
public static void removeIgnoreDamageMetadata(@NotNull LivingEntity target) {
target.removeMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY, mcMMO.p);
}
public static void applyIgnoreDamageMetadata(@NotNull LivingEntity target) {
target.setMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY, mcMMO.metadataValue);
}
public static boolean hasIgnoreDamageMetadata(@NotNull LivingEntity target) {
return target.getMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY).size() != 0;
}
public static void dealNoInvulnerabilityTickDamageRupture(@NotNull LivingEntity target, double damage, Entity attacker, int toolTier) {
if (target.isDead()) {
return;
}
dealNoInvulnerabilityTickDamage(target, damage, attacker);
// //IFrame storage
//// int noDamageTicks = target.getNoDamageTicks();
//
//// String debug = "BLEED DMG RESULT: INC DMG:"+damage+", HP-Before:"+target.getHealth()+", HP-After:";
//
//// double incDmg = getFakeDamageFinalResult(attacker, target, DamageCause.ENTITY_ATTACK, damage);
//
//// double newHealth = Math.max(0, target.getHealth() - incDmg);
//
// //Don't kill things with a stone or wooden weapon
//// if(toolTier < 3 && newHealth == 0)
//// return;
//
// target.setMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY, mcMMO.metadataValue);
//
// if(newHealth == 0 && !(target instanceof Player))
// {
// target.damage(99999, attacker);
// }
// else
// {
//// Vector beforeRuptureVec = new Vector(target.getVelocity().getX(), target.getVelocity().getY(), target.getVelocity().getZ()); ;
// target.damage(damage, attacker);
//// debug+=target.getHealth();
// Bukkit.broadcastMessage(debug);
//// target.setNoDamageTicks(noDamageTicks); //Do not add additional IFrames
//// target.setVelocity(beforeRuptureVec);
// }
}
/**
@@ -730,7 +747,7 @@ public final class CombatUtils {
* @param damage The initial damage amount
* @param type The type of skill being used
*/
public static void applyAbilityAoE(Player attacker, LivingEntity target, double damage, Map<DamageModifier, Double> modifiers, PrimarySkillType type) {
public static void applyAbilityAoE(@NotNull Player attacker, @NotNull LivingEntity target, double damage, Map<DamageModifier, Double> modifiers, @NotNull PrimarySkillType type) {
int numberOfTargets = getTier(attacker.getInventory().getItemInMainHand()); // The higher the weapon tier, the more targets you hit
double damageAmount = Math.max(damage, 1);
@@ -778,7 +795,7 @@ public final class CombatUtils {
* @param target The defending entity
* @param primarySkillType The skill being used
*/
public static void processCombatXP(McMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType) {
public static void processCombatXP(@NotNull McMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType) {
processCombatXP(mmoPlayer, target, primarySkillType, 1.0);
}
@@ -790,7 +807,7 @@ public final class CombatUtils {
* @param primarySkillType The skill being used
* @param multiplier final XP result will be multiplied by this
*/
public static void processCombatXP(McMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType, double multiplier) {
public static void processCombatXP(@NotNull McMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType, double multiplier) {
double baseXP = 0;
XPGainReason xpGainReason;
@@ -841,19 +858,22 @@ public final class CombatUtils {
}
}
if (target.hasMetadata(mcMMO.entityMetadataKey)
//Epic Spawners compatibility
|| target.hasMetadata("ES")) {
if(getPersistentData().hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, target)) {
baseXP = 0;
} else if(getPersistentData().hasMobFlag(MobMetaFlagType.MOB_SPAWNER_MOB, target) || target.hasMetadata("ES")) {
baseXP *= ExperienceConfig.getInstance().getSpawnedMobXpMultiplier();
}
if (target.hasMetadata(mcMMO.bredMetadataKey)) {
} else if(getPersistentData().hasMobFlag(MobMetaFlagType.NETHER_PORTAL_MOB, target)) {
baseXP *= ExperienceConfig.getInstance().getNetherPortalXpMultiplier();
} else if(getPersistentData().hasMobFlag(MobMetaFlagType.EGG_MOB, target)) {
baseXP *= ExperienceConfig.getInstance().getEggXpMultiplier();
} else if (getPersistentData().hasMobFlag(MobMetaFlagType.PLAYER_BRED_MOB, target)) {
baseXP *= ExperienceConfig.getInstance().getBredMobXpMultiplier();
} else if(getPersistentData().hasMobFlag(MobMetaFlagType.PLAYER_TAMED_MOB, target)) {
baseXP *= ExperienceConfig.getInstance().getTamedMobXpMultiplier();
}
xpGainReason = XPGainReason.PVE;
baseXP *= 10;
xpGainReason = XPGainReason.PVE;
}
baseXP *= multiplier;
@@ -870,7 +890,7 @@ public final class CombatUtils {
* @param entity The defending Entity
* @return true if the Entity should be damaged, false otherwise.
*/
private static boolean shouldBeAffected(Player player, Entity entity) {
private static boolean shouldBeAffected(@NotNull Player player, @NotNull Entity entity) {
if (entity instanceof Player) {
Player defender = (Player) entity;
@@ -900,10 +920,12 @@ public final class CombatUtils {
return getFakeDamageFinalResult(player, entity, 1.0) != 0;
}
else if (entity instanceof Tameable) {
if (isFriendlyPet(player, (Tameable) entity)) {
Tameable tameableEntity = (Tameable) entity;
if (isFriendlyPet(player, tameableEntity)) {
// isFriendlyPet ensures that the Tameable is: Tamed, owned by a player, and the owner is in the same party
// So we can make some assumptions here, about our casting and our check
Player owner = (Player) ((Tameable) entity).getOwner();
Player owner = (Player) tameableEntity.getOwner();
return Permissions.friendlyFire(player) && Permissions.friendlyFire(owner);
}
}
@@ -918,7 +940,7 @@ public final class CombatUtils {
* @param eventDamage The damage from the event the entity is involved in
* @return true if the entity is invincible, false otherwise
*/
public static boolean isInvincible(LivingEntity entity, double eventDamage) {
public static boolean isInvincible(@NotNull LivingEntity entity, double eventDamage) {
/*
* So apparently if you do more damage to a LivingEntity than its last damage int you bypass the invincibility.
* So yeah, this is for that.
@@ -933,7 +955,7 @@ public final class CombatUtils {
* @param pet The entity to check.
* @return true if the entity is friendly, false otherwise
*/
public static boolean isFriendlyPet(Player attacker, Tameable pet) {
public static boolean isFriendlyPet(@NotNull Player attacker, @NotNull Tameable pet) {
if (pet.isTamed()) {
AnimalTamer tamer = pet.getOwner();
@@ -948,12 +970,12 @@ public final class CombatUtils {
}
@Deprecated
public static double getFakeDamageFinalResult(Entity attacker, Entity target, double damage) {
public static double getFakeDamageFinalResult(@Nullable Entity attacker, @NotNull Entity target, double damage) {
return getFakeDamageFinalResult(attacker, target, DamageCause.ENTITY_ATTACK, new EnumMap<>(ImmutableMap.of(DamageModifier.BASE, damage)));
}
@Deprecated
public static double getFakeDamageFinalResult(Entity attacker, Entity target, DamageCause damageCause, double damage) {
public static double getFakeDamageFinalResult(@Nullable Entity attacker, @NotNull Entity target, @NotNull DamageCause damageCause, double damage) {
EntityDamageEvent damageEvent = sendEntityDamageEvent(attacker, target, damageCause, damage);
if (damageEvent.isCancelled()) {
@@ -963,27 +985,27 @@ public final class CombatUtils {
return damageEvent.getFinalDamage();
}
public static boolean canDamage(Entity attacker, Entity target, DamageCause damageCause, double damage) {
public static boolean canDamage(@NotNull Entity attacker, @NotNull Entity target, @NotNull DamageCause damageCause, double damage) {
EntityDamageEvent damageEvent = sendEntityDamageEvent(attacker, target, damageCause, damage);
return !damageEvent.isCancelled();
}
public static EntityDamageEvent sendEntityDamageEvent(Entity attacker, Entity target, DamageCause damageCause, double damage) {
public static @NotNull EntityDamageEvent sendEntityDamageEvent(@Nullable Entity attacker, @NotNull Entity target, @NotNull DamageCause damageCause, double damage) {
EntityDamageEvent damageEvent = attacker == null ? new FakeEntityDamageEvent(target, damageCause, damage) : new FakeEntityDamageByEntityEvent(attacker, target, damageCause, damage);
mcMMO.p.getServer().getPluginManager().callEvent(damageEvent);
return damageEvent;
}
public static double getFakeDamageFinalResult(Entity attacker, Entity target, Map<DamageModifier, Double> modifiers) {
public static double getFakeDamageFinalResult(@Nullable Entity attacker, @NotNull Entity target, @NotNull Map<DamageModifier, Double> modifiers) {
return getFakeDamageFinalResult(attacker, target, DamageCause.ENTITY_ATTACK, modifiers);
}
public static double getFakeDamageFinalResult(Entity attacker, Entity target, double damage, Map<DamageModifier, Double> modifiers) {
public static double getFakeDamageFinalResult(@Nullable Entity attacker, @NotNull Entity target, double damage, @NotNull Map<DamageModifier, Double> modifiers) {
return getFakeDamageFinalResult(attacker, target, DamageCause.ENTITY_ATTACK, getScaledModifiers(damage, modifiers));
}
public static double getFakeDamageFinalResult(Entity attacker, Entity target, DamageCause cause, Map<DamageModifier, Double> modifiers) {
public static double getFakeDamageFinalResult(@Nullable Entity attacker, @NotNull Entity target, @NotNull DamageCause cause, @NotNull Map<DamageModifier, Double> modifiers) {
EntityDamageEvent damageEvent = attacker == null ? new FakeEntityDamageEvent(target, cause, modifiers) : new FakeEntityDamageByEntityEvent(attacker, target, cause, modifiers);
mcMMO.p.getServer().getPluginManager().callEvent(damageEvent);
@@ -994,7 +1016,7 @@ public final class CombatUtils {
return damageEvent.getFinalDamage();
}
private static Map<DamageModifier, Double> getModifiers(EntityDamageEvent event) {
private static @NotNull Map<DamageModifier, Double> getModifiers(@NotNull EntityDamageEvent event) {
Map<DamageModifier, Double> modifiers = new HashMap<>();
for (DamageModifier modifier : DamageModifier.values()) {
modifiers.put(modifier, event.getDamage(modifier));
@@ -1003,7 +1025,7 @@ public final class CombatUtils {
return modifiers;
}
private static Map<DamageModifier, Double> getScaledModifiers(double damage, Map<DamageModifier, Double> modifiers) {
private static @NotNull Map<DamageModifier, Double> getScaledModifiers(double damage, @NotNull Map<DamageModifier, Double> modifiers) {
Map<DamageModifier, Double> scaledModifiers = new HashMap<>();
for (DamageModifier modifier : modifiers.keySet()) {
@@ -1018,7 +1040,7 @@ public final class CombatUtils {
return scaledModifiers;
}
public static EntityDamageByEntityEvent applyScaledModifiers(double initialDamage, double finalDamage, EntityDamageByEntityEvent event) {
public static @NotNull EntityDamageByEntityEvent applyScaledModifiers(double initialDamage, double finalDamage, @NotNull EntityDamageByEntityEvent event) {
// No additional damage
if (initialDamage == finalDamage) {
return event;
@@ -1046,7 +1068,7 @@ public final class CombatUtils {
* @param inHand The item to check the tier of
* @return the tier of the item
*/
private static int getTier(ItemStack inHand) {
private static int getTier(@NotNull ItemStack inHand) {
int tier = 0;
if (ItemUtils.isWoodTool(inHand)) {
@@ -1073,7 +1095,7 @@ public final class CombatUtils {
return tier;
}
public static void handleHealthbars(Entity attacker, LivingEntity target, double damage, mcMMO plugin) {
public static void handleHealthbars(@NotNull Entity attacker, @NotNull LivingEntity target, double damage, @NotNull mcMMO plugin) {
if (!(attacker instanceof Player)) {
return;
}
@@ -1090,4 +1112,13 @@ public final class CombatUtils {
MobHealthbarUtils.handleMobHealthbars(target, damage, plugin);
}
public static void modifyMoveSpeed(@NotNull LivingEntity livingEntity, double multiplier) {
AttributeInstance attributeInstance = livingEntity.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
if(attributeInstance != null) {
double normalSpeed = attributeInstance.getBaseValue();
attributeInstance.setBaseValue(normalSpeed * multiplier);
}
}
}

View File

@@ -6,6 +6,7 @@ import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.Permissions;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class PerksUtils {
private static final int LUCKY_SKILL_ACTIVATION_CHANCE = 75;
@@ -27,7 +28,7 @@ public final class PerksUtils {
return cooldown;
}
public static int handleActivationPerks(Player player, int ticks, int maxTicks) {
public static int handleActivationPerks(@NotNull Player player, int ticks, int maxTicks) {
if (maxTicks != 0) {
ticks = Math.min(ticks, maxTicks);
}

View File

@@ -11,6 +11,7 @@ import com.gmail.nossr50.runnables.skills.SkillUnlockNotificationTask;
import com.gmail.nossr50.util.Permissions;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
@@ -22,14 +23,14 @@ public class RankUtils {
*
* @param plugin plugin instance ref
* @param mmoPlayer target player
* @param primarySkillType
* @param primarySkillType target skill
* @param newLevel the new level of this skill
*/
public static void executeSkillUnlockNotifications(Plugin plugin, McMMOPlayer mmoPlayer, PrimarySkillType primarySkillType, int newLevel)
public static void executeSkillUnlockNotifications(@NotNull Plugin plugin, @NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, int newLevel)
{
for(SubSkillType subSkillType : primarySkillType.getSkillAbilities())
{
int playerRankInSkill = getRank(mmoPlayer.getPlayer(), subSkillType);
int playerRankInSkill = getRank(mmoPlayer, subSkillType);
HashMap<Integer, Integer> innerMap = subSkillRanks.get(subSkillType.toString());
@@ -59,7 +60,7 @@ public class RankUtils {
}
/* NEW SYSTEM */
private static void addRanks(AbstractSubSkill abstractSubSkill)
private static void addRanks(@NotNull AbstractSubSkill abstractSubSkill)
{
//Fill out the rank array
for(int i = 0; i < abstractSubSkill.getNumRanks(); i++)
@@ -72,8 +73,7 @@ public class RankUtils {
}
}
private static void addRanks(SubSkillType subSkillType)
{
private static void addRanks(@NotNull SubSkillType subSkillType) {
//Fill out the rank array
for(int i = 0; i < subSkillType.getNumRanks(); i++)
{
@@ -88,8 +88,7 @@ public class RankUtils {
/**
* Populates the ranks for every skill we know about
*/
public static void populateRanks()
{
public static void populateRanks() {
for(SubSkillType subSkillType : SubSkillType.values())
{
addRanks(subSkillType);
@@ -103,13 +102,13 @@ public class RankUtils {
/**
* Returns whether or not the player has unlocked the first rank in target subskill
* @param player the player
* @param mmoPlayer the player
* @param subSkillType the target subskill
* @return true if the player has at least one rank in the skill
*/
public static boolean hasUnlockedSubskill(Player player, SubSkillType subSkillType)
public static boolean hasUnlockedSubskill(@NotNull McMMOPlayer mmoPlayer, @NotNull SubSkillType subSkillType)
{
int curRank = getRank(player, subSkillType);
int curRank = getRank(mmoPlayer, subSkillType);
//-1 means the skill has no unlockable levels and is therefor unlocked
return curRank == -1 || curRank >= 1;
@@ -117,13 +116,13 @@ public class RankUtils {
/**
* Returns whether or not the player has unlocked the first rank in target subskill
* @param player the player
* @param mmoPlayer the player
* @param abstractSubSkill the target subskill
* @return true if the player has at least one rank in the skill
*/
public static boolean hasUnlockedSubskill(Player player, AbstractSubSkill abstractSubSkill)
public static boolean hasUnlockedSubskill(@NotNull McMMOPlayer mmoPlayer, @NotNull AbstractSubSkill abstractSubSkill)
{
int curRank = getRank(player, abstractSubSkill);
int curRank = getRank(mmoPlayer, abstractSubSkill);
//-1 means the skill has no unlockable levels and is therefor unlocked
return curRank == -1 || curRank >= 1;
@@ -132,34 +131,45 @@ public class RankUtils {
/**
* Returns whether or not the player has reached the specified rank in target subskill
* @param rank the target rank
* @param player the player
* @param mmoPlayer the player
* @param subSkillType the target subskill
* @return true if the player is at least that rank in this subskill
*/
public static boolean hasReachedRank(int rank, Player player, SubSkillType subSkillType)
public static boolean hasReachedRank(int rank, @NotNull McMMOPlayer mmoPlayer, @NotNull SubSkillType subSkillType)
{
return getRank(player, subSkillType) >= rank;
return getRank(mmoPlayer, subSkillType) >= rank;
}
/**
* Returns whether or not the player has reached the specified rank in target subskill
* @param rank the target rank
* @param player the player
* @param mmoPlayer the player
* @param abstractSubSkill the target subskill
* @return true if the player is at least that rank in this subskill
*/
public static boolean hasReachedRank(int rank, Player player, AbstractSubSkill abstractSubSkill)
public static boolean hasReachedRank(int rank, @NotNull McMMOPlayer mmoPlayer, @NotNull AbstractSubSkill abstractSubSkill)
{
return getRank(player, abstractSubSkill) >= rank;
return getRank(mmoPlayer, abstractSubSkill) >= rank;
}
// /**
// * Gets the current rank of the subskill for the player
// * @param mmoPlayer The player in question
// * @param subSkillType Target subskill
// * @return The rank the player currently has achieved in this skill. -1 for skills without ranks.
// */
// public static int getRank(Player player, SubSkillType subSkillType)
// {
// return getRank(mmoPlayer.getPlayer(), subSkillType);
// }
/**
* Gets the current rank of the subskill for the player
* @param player The player in question
* @param mmoPlayer The player in question
* @param subSkillType Target subskill
* @return The rank the player currently has achieved in this skill. -1 for skills without ranks.
*/
public static int getRank(Player player, SubSkillType subSkillType)
public static int getRank(@NotNull McMMOPlayer mmoPlayer, @NotNull SubSkillType subSkillType)
{
String skillName = subSkillType.toString();
int numRanks = subSkillType.getNumRanks();
@@ -176,11 +186,8 @@ public class RankUtils {
//Get our rank map
HashMap<Integer, Integer> rankMap = subSkillRanks.get(skillName);
if(mcMMO.getUserManager().getPlayer(player) == null)
return 0;
//Skill level of parent skill
int currentSkillLevel = mcMMO.getUserManager().getPlayer(player).getSkillLevel(subSkillType.getParentSkill());
int currentSkillLevel = mmoPlayer.getExperienceManager().getSkillLevel(subSkillType.getParentSkill());
for(int i = 0; i < numRanks; i++)
{
@@ -202,11 +209,11 @@ public class RankUtils {
/**
* Gets the current rank of the subskill for the player
* @param player The player in question
* @param mmoPlayer The player in question
* @param abstractSubSkill Target subskill
* @return The rank the player currently has achieved in this skill. -1 for skills without ranks.
*/
public static int getRank(Player player, AbstractSubSkill abstractSubSkill)
public static int getRank(@NotNull McMMOPlayer mmoPlayer, @NotNull AbstractSubSkill abstractSubSkill)
{
String skillName = abstractSubSkill.getConfigKeyName();
int numRanks = abstractSubSkill.getNumRanks();
@@ -223,11 +230,8 @@ public class RankUtils {
//Get our rank map
HashMap<Integer, Integer> rankMap = subSkillRanks.get(skillName);
if(mcMMO.getUserManager().getPlayer(player) == null)
return 0;
//Skill level of parent skill
int currentSkillLevel = mcMMO.getUserManager().getPlayer(player).getSkillLevel(abstractSubSkill.getPrimarySkill());
int currentSkillLevel = mmoPlayer.getExperienceManager().getSkillLevel(abstractSubSkill.getPrimarySkill());
for(int i = 0; i < numRanks; i++)
{
@@ -252,7 +256,7 @@ public class RankUtils {
* @param abstractSubSkill The subskill to add ranks for
* @param rank The rank to add
*/
private static void addRank(AbstractSubSkill abstractSubSkill, int rank)
private static void addRank(@NotNull AbstractSubSkill abstractSubSkill, int rank)
{
initMaps(abstractSubSkill.getConfigKeyName());
@@ -262,7 +266,7 @@ public class RankUtils {
}
@Deprecated
private static void addRank(SubSkillType subSkillType, int rank)
private static void addRank(@NotNull SubSkillType subSkillType, int rank)
{
initMaps(subSkillType.toString());
@@ -271,7 +275,7 @@ public class RankUtils {
rankMap.put(rank, getRankUnlockLevel(subSkillType, rank));
}
private static void initMaps(String s) {
private static void initMaps(@NotNull String s) {
if (subSkillRanks == null)
subSkillRanks = new HashMap<>();
@@ -302,12 +306,12 @@ public class RankUtils {
* @return The level at which this rank unlocks
*/
@Deprecated
public static int getRankUnlockLevel(SubSkillType subSkillType, int rank)
public static int getRankUnlockLevel(@NotNull SubSkillType subSkillType, int rank)
{
return RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, rank);
}
public static int getRankUnlockLevel(AbstractSubSkill abstractSubSkill, int rank)
public static int getRankUnlockLevel(@NotNull AbstractSubSkill abstractSubSkill, int rank)
{
return RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, rank);
}
@@ -317,7 +321,7 @@ public class RankUtils {
* @param subSkillType target subskill
* @return The unlock requirements for rank 1 in this skill
*/
public static int getUnlockLevel(SubSkillType subSkillType)
public static int getUnlockLevel(@NotNull SubSkillType subSkillType)
{
return RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1);
}
@@ -327,7 +331,7 @@ public class RankUtils {
* @param abstractSubSkill target subskill
* @return The unlock requirements for rank 1 in this skill
*/
public static int getUnlockLevel(AbstractSubSkill abstractSubSkill)
public static int getUnlockLevel(@NotNull AbstractSubSkill abstractSubSkill)
{
return RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1);
}
@@ -337,12 +341,12 @@ public class RankUtils {
* @param subSkillType target subskill
* @return the last rank of a subskill
*/
public static int getHighestRank(SubSkillType subSkillType)
public static int getHighestRank(@NotNull SubSkillType subSkillType)
{
return subSkillType.getNumRanks();
}
public static String getHighestRankStr(SubSkillType subSkillType)
public static String getHighestRankStr(@NotNull SubSkillType subSkillType)
{
return String.valueOf(subSkillType.getNumRanks());
}
@@ -352,18 +356,18 @@ public class RankUtils {
* @param abstractSubSkill target subskill
* @return the last rank of a subskill
*/
public static int getHighestRank(AbstractSubSkill abstractSubSkill)
public static int getHighestRank(@NotNull AbstractSubSkill abstractSubSkill)
{
return abstractSubSkill.getNumRanks();
}
public static int getSuperAbilityUnlockRequirement(SuperAbilityType superAbilityType)
public static int getSuperAbilityUnlockRequirement(@NotNull SuperAbilityType superAbilityType)
{
return getRankUnlockLevel(superAbilityType.getSubSkillTypeDefinition(), 1);
}
public static boolean isPlayerMaxRankInSubSkill(Player player, SubSkillType subSkillType) {
int playerRank = getRank(player, subSkillType);
public static boolean isPlayerMaxRankInSubSkill(@NotNull McMMOPlayer mmoPlayer, SubSkillType subSkillType) {
int playerRank = getRank(mmoPlayer, subSkillType);
int highestRank = getHighestRank(subSkillType);
return playerRank == highestRank;

View File

@@ -14,10 +14,11 @@ import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.ItemUtils;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.StringUtils;
import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
import com.gmail.nossr50.util.experience.MMOExperienceBarManager;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.text.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -35,7 +36,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
public class SkillUtils {
public final class SkillUtils {
/**
* This is a static utility class, therefore we don't want any instances of
* this class. Making the constructor private prevents accidents like that.
*/
private SkillUtils() {}
public static void applyXpGain(McMMOPlayer mmoPlayer, PrimarySkillType primarySkillType, float xp, XPGainReason xpGainReason) {
mmoPlayer.getExperienceManager().beginXpGain(mmoPlayer.getPlayer(), primarySkillType, xp, xpGainReason, XPGainSource.SELF);
@@ -228,10 +234,8 @@ public class SkillUtils {
if(compatLayer.isLegacyAbilityTool(itemStack)) {
ItemMeta itemMeta = itemStack.getItemMeta();
//TODO: can be optimized
if(itemMeta.hasEnchant(Enchantment.DIG_SPEED)) {
itemMeta.removeEnchant(Enchantment.DIG_SPEED);
}
// This is safe to call without prior checks.
itemMeta.removeEnchant(Enchantment.DIG_SPEED);
itemStack.setItemMeta(itemMeta);
ItemUtils.removeAbilityLore(itemStack);
@@ -275,7 +279,8 @@ public class SkillUtils {
return false;
}
protected static Material getRepairAndSalvageItem(ItemStack inHand) {
@Nullable
public static Material getRepairAndSalvageItem(@NotNull ItemStack inHand) {
if (ItemUtils.isDiamondTool(inHand) || ItemUtils.isDiamondArmor(inHand)) {
return Material.DIAMOND;
}

View File

@@ -1,13 +1,15 @@
package com.gmail.nossr50.util;
package com.gmail.nossr50.util.text;
import java.util.function.BiConsumer;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import java.util.function.BiConsumer;
public enum McMMOMessageType {
ACTION_BAR(Audience::sendActionBar),
SYSTEM((audience, message) -> audience.sendMessage(message, MessageType.SYSTEM));
SYSTEM((audience, message) -> audience.sendMessage(Identity.nil(), message, MessageType.SYSTEM));
private final BiConsumer<Audience, Component> sender;

View File

@@ -1,4 +1,4 @@
package com.gmail.nossr50.util;
package com.gmail.nossr50.util.text;
import com.gmail.nossr50.datatypes.party.PartyFeature;
import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
@@ -6,11 +6,16 @@ import org.bukkit.Material;
import org.bukkit.block.data.Ageable;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
import java.text.DecimalFormat;
import java.util.Locale;
public class StringUtils {
protected static DecimalFormat percent = new DecimalFormat("##0.00%");
protected static DecimalFormat shortDecimal = new DecimalFormat("##0.0");
/**
* Gets a capitalized version of the target string.
*
@@ -22,6 +27,30 @@ public class StringUtils {
return target.substring(0, 1).toUpperCase() + target.substring(1).toLowerCase(Locale.ENGLISH);
}
public static String ticksToSeconds(double ticks) {
return shortDecimal.format(ticks / 20);
}
/**
* Creates a string from an array skipping the first n elements
* @param args the array to iterate over when forming the string
* @param index the amount of elements to skip over
* @return the "trimmed" string
*/
public static String buildStringAfterNthElement(@NotNull String @NotNull []args, int index) {
StringBuilder trimMessage = new StringBuilder();
for (int i = index; i < args.length; i++) {
if(i + 1 >= args.length)
trimMessage.append(args[i]);
else
trimMessage.append(args[i]).append(" ");
}
return trimMessage.toString();
}
public static String getPrettyItemString(Material material) {
return createPrettyString(material.toString());
}

View File

@@ -1,4 +1,4 @@
package com.gmail.nossr50.util;
package com.gmail.nossr50.util.text;
import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.config.RankConfig;
@@ -10,20 +10,20 @@ import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill;
import com.gmail.nossr50.listeners.InteractionManager;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.skills.RankUtils;
import java.util.concurrent.atomic.AtomicReference;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentBuilder;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@@ -43,7 +43,7 @@ public class TextComponentFactory {
public static TextComponent getNotificationMultipleValues(String localeKey, String... values)
{
String preColoredString = LocaleLoader.getString(localeKey, (Object[]) values);
return TextComponent.of(preColoredString);
return Component.text(preColoredString);
}
public static Component getNotificationTextComponentFromLocale(String localeKey)
@@ -53,13 +53,13 @@ public class TextComponentFactory {
public static Component getNotificationLevelUpTextComponent(PrimarySkillType skill, int levelsGained, int currentLevel)
{
return TextComponent.of(LocaleLoader.getString("Overhaul.Levelup", LocaleLoader.getString("Overhaul.Name."+StringUtils.getCapitalized(skill.toString())), levelsGained, currentLevel));
return Component.text(LocaleLoader.getString("Overhaul.Levelup", LocaleLoader.getString("Overhaul.Name."+ StringUtils.getCapitalized(skill.toString())), levelsGained, currentLevel));
}
private static TextComponent getNotificationTextComponent(String text)
{
//textComponent.setColor(getNotificationColor(notificationType));
return TextComponent.of(text);
return Component.text(text);
}
public static void sendPlayerSubSkillWikiLink(Player player, String subskillformatted)
@@ -67,29 +67,29 @@ public class TextComponentFactory {
if(!Config.getInstance().getUrlLinksEnabled())
return;
TextComponent.Builder wikiLinkComponent = TextComponent.builder(LocaleLoader.getString("Overhaul.mcMMO.MmoInfo.Wiki"));
TextComponent.Builder wikiLinkComponent = Component.text().content(LocaleLoader.getString("Overhaul.mcMMO.MmoInfo.Wiki"));
wikiLinkComponent.decoration(TextDecoration.UNDERLINED, true);
String wikiUrl = "https://mcmmo.org/wiki/"+subskillformatted;
wikiLinkComponent.clickEvent(ClickEvent.openUrl(wikiUrl));
TextComponent.Builder componentBuilder = TextComponent.builder(subskillformatted).append("\n").append(wikiUrl).color(NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, true);
TextComponent.Builder componentBuilder = Component.text().content(subskillformatted).append(Component.newline()).append(Component.text(wikiUrl)).color(NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, true);
wikiLinkComponent.hoverEvent(HoverEvent.showText(componentBuilder.build()));
mcMMO.getAudiences().player(player).sendMessage(wikiLinkComponent, MessageType.SYSTEM);
mcMMO.getAudiences().player(player).sendMessage(Identity.nil(), wikiLinkComponent, MessageType.SYSTEM);
}
public static void sendPlayerUrlHeader(Player player) {
TextComponent prefix = TextComponent.of(LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Prefix") + " ");
TextComponent prefix = Component.text(LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Prefix") + " ");
/*prefix.setColor(ChatColor.DARK_AQUA);*/
TextComponent suffix = TextComponent.of(" "+LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Suffix"));
TextComponent suffix = Component.text(" "+LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Suffix"));
/*suffix.setColor(ChatColor.DARK_AQUA);*/
TextComponent emptySpace = TextComponent.space();
TextComponent emptySpace = Component.space();
mcMMO.getAudiences().player(player).sendMessage(TextComponent.ofChildren(
mcMMO.getAudiences().player(player).sendMessage(Identity.nil(),TextComponent.ofChildren(
prefix,
getWebLinkTextComponent(McMMOWebLinks.WEBSITE),
emptySpace,
@@ -106,46 +106,32 @@ public class TextComponentFactory {
), MessageType.SYSTEM);
}
public static void sendPlayerSubSkillList(Player player, List<Component> textComponents)
{
TextComponent emptySpace = TextComponent.space();
AtomicReference<Component> messageToSend = new AtomicReference<>();
int newLineCount = 0; //Hacky solution to wordwrap problems
/**
* Sends a player a bunch of text components that represent a list of sub-skills
* Styling and formatting is applied before sending the messages
*
* @param player target player
* @param subSkillComponents the text components representing the sub-skills by name
*/
public static void sendPlayerSubSkillList(@NotNull Player player, @NotNull List<Component> subSkillComponents) {
final Audience audience = mcMMO.getAudiences().player(player);
for (Component textComponent : textComponents) {
//Don't send more than 3 subskills per line to avoid MOST wordwrap problems
if(newLineCount > 2)
{
Component toSend = messageToSend.get();
if (toSend != null) {
audience.sendMessage(toSend.append(emptySpace));
}
messageToSend.set(null);
newLineCount = 0;
}
//Style the skills into @links
final String originalTxt = textComponent instanceof TextComponent ? ((TextComponent) textComponent).content() : "";
//@ Signs, done for style
Component space = Component.space();
TextComponent atSignComponent = Component.text(LocaleLoader.getString("JSON.Hover.AtSymbolSkills"));
TextComponent.Builder stylizedText = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolSkills"));
addChild(stylizedText, originalTxt);
//Only send 3 sub-skills per line
Component[][] splitSubSkills = TextUtils.splitComponentsIntoGroups(subSkillComponents, 3);
ArrayList<Component> individualLinesToSend = new ArrayList<>();
if(textComponent.hoverEvent() != null)
stylizedText.hoverEvent(textComponent.hoverEvent());
if(textComponent.clickEvent() != null)
stylizedText.clickEvent(textComponent.clickEvent());
messageToSend.set(stylizedText.build().append(emptySpace));
newLineCount++;
//Create each line
for (Component[] componentArray : splitSubSkills) {
individualLinesToSend.add(TextUtils.fromArray(componentArray, atSignComponent, space));
}
Component toSend = messageToSend.get();
if (toSend != null) {
audience.sendMessage(toSend.append(emptySpace));
//Send each group
for(Component curLine : individualLinesToSend) {
audience.sendMessage(Identity.nil(), curLine);
}
}
@@ -156,100 +142,88 @@ public class TextComponentFactory {
switch(webLinks)
{
case WEBSITE:
webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
addChild(webTextComponent, "Web");
webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
TextUtils.addChildWebComponent(webTextComponent, "Web");
webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWebsite));
break;
case SPIGOT:
webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
addChild(webTextComponent, "Spigot");
webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
TextUtils.addChildWebComponent(webTextComponent, "Spigot");
webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlSpigot));
break;
case DISCORD:
webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
addChild(webTextComponent, "Discord");
webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
TextUtils.addChildWebComponent(webTextComponent, "Discord");
webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlDiscord));
break;
case PATREON:
webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
addChild(webTextComponent, "Patreon");
webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
TextUtils.addChildWebComponent(webTextComponent, "Patreon");
webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlPatreon));
break;
case WIKI:
webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
addChild(webTextComponent, "Wiki");
webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
TextUtils.addChildWebComponent(webTextComponent, "Wiki");
webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWiki));
break;
case HELP_TRANSLATE:
webTextComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
addChild(webTextComponent, "Lang");
webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL"));
TextUtils.addChildWebComponent(webTextComponent, "Lang");
webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlTranslate));
break;
default:
webTextComponent = TextComponent.builder("NOT DEFINED");
webTextComponent = Component.text().content("NOT DEFINED");
}
addNewHoverComponentToTextComponent(webTextComponent, getUrlHoverEvent(webLinks));
TextUtils.addNewHoverComponentToTextComponent(webTextComponent, getUrlHoverEvent(webLinks));
webTextComponent.insertion(webLinks.getUrl());
return webTextComponent.build();
}
private static void addChild(Component webTextComponent, String childName) {
TextComponent childComponent = TextComponent.of(childName);
childComponent.color(NamedTextColor.BLUE);
webTextComponent.append(childComponent);
}
private static void addChild(ComponentBuilder<?, ?> webTextComponent, String childName) {
TextComponent childComponent = TextComponent.of(childName);
childComponent.color(NamedTextColor.BLUE);
webTextComponent.append(childComponent);
}
private static Component getUrlHoverEvent(McMMOWebLinks webLinks)
{
TextComponent.Builder componentBuilder = TextComponent.builder(webLinks.getNiceTitle());
TextComponent.Builder componentBuilder = Component.text().content(webLinks.getNiceTitle());
switch(webLinks)
{
case WEBSITE:
addUrlHeaderHover(webLinks, componentBuilder);
componentBuilder.append("\n\n");
componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append(TextComponent.of("\nDev Blogs, and information related to mcMMO can be found here", NamedTextColor.GRAY));
componentBuilder.append(Component.newline()).append(Component.newline());
componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append(Component.text("\nDev Blogs, and information related to mcMMO can be found here", NamedTextColor.GRAY));
break;
case SPIGOT:
addUrlHeaderHover(webLinks, componentBuilder);
componentBuilder.append("\n\n");
componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append(TextComponent.of("\nI post regularly in the discussion thread here!", NamedTextColor.GRAY));
componentBuilder.append(Component.newline()).append(Component.newline());
componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append(Component.text("\nI post regularly in the discussion thread here!", NamedTextColor.GRAY));
break;
case PATREON:
addUrlHeaderHover(webLinks, componentBuilder);
componentBuilder.append("\n\n");
componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append("\n");
componentBuilder.append(TextComponent.of("Show support by buying me a coffee :)", NamedTextColor.GRAY));
componentBuilder.append(Component.newline()).append(Component.newline());
componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append(Component.newline());
componentBuilder.append(Component.text("Show support by buying me a coffee :)", NamedTextColor.GRAY));
break;
case WIKI:
addUrlHeaderHover(webLinks, componentBuilder);
componentBuilder.append("\n\n");
componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append("\n");
componentBuilder.append(TextComponent.of("I'm looking for more wiki staff, contact me on our discord!", NamedTextColor.DARK_GRAY));
componentBuilder.append(Component.newline()).append(Component.newline());
componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append(Component.newline());
componentBuilder.append(Component.text("I'm looking for more wiki staff, contact me on our discord!", NamedTextColor.DARK_GRAY));
break;
case DISCORD:
addUrlHeaderHover(webLinks, componentBuilder);
componentBuilder.append("\n\n");
componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append(Component.newline()).append(Component.newline());
componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
break;
case HELP_TRANSLATE:
addUrlHeaderHover(webLinks, componentBuilder);
componentBuilder.append("\n\n");
componentBuilder.append(TextComponent.of(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append("\n");
componentBuilder.append(TextComponent.of("You can use this website to help translate mcMMO into your language!" +
componentBuilder.append(Component.newline()).append(Component.newline());
componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN));
componentBuilder.append(Component.newline());
componentBuilder.append(Component.text("You can use this website to help translate mcMMO into your language!" +
"\nIf you want to know more contact me in discord.", NamedTextColor.DARK_GRAY));
}
@@ -257,8 +231,8 @@ public class TextComponentFactory {
}
private static void addUrlHeaderHover(McMMOWebLinks webLinks, TextComponent.Builder componentBuilder) {
componentBuilder.append("\n");
componentBuilder.append(TextComponent.of(webLinks.getUrl(), NamedTextColor.GRAY, TextDecoration.ITALIC));
componentBuilder.append(Component.newline());
componentBuilder.append(Component.text(webLinks.getUrl(), NamedTextColor.GRAY, TextDecoration.ITALIC));
}
private static ClickEvent getUrlClickEvent(String url)
@@ -276,7 +250,7 @@ public class TextComponentFactory {
TextComponent.Builder textComponent = initNewSkillTextComponent(player, skillName, subSkillType, skillUnlocked);
//Hover Event
addNewHoverComponentToTextComponent(textComponent, getSubSkillHoverComponent(player, subSkillType));
TextUtils.addNewHoverComponentToTextComponent(textComponent, getSubSkillHoverComponent(player, subSkillType));
//Insertion
textComponent.insertion(skillName);
@@ -284,10 +258,6 @@ public class TextComponentFactory {
return textComponent.build();
}
private static void addNewHoverComponentToTextComponent(TextComponent.Builder textComponent, Component baseComponent) {
textComponent.hoverEvent(HoverEvent.showText(baseComponent));
}
private static TextComponent getSubSkillTextComponent(Player player, AbstractSubSkill abstractSubSkill)
{
//String key = abstractSubSkill.getConfigKeyName();
@@ -301,7 +271,7 @@ public class TextComponentFactory {
TextComponent.Builder textComponent = initNewSkillTextComponent(player, skillName, subSkillType, skillUnlocked);
//Hover Event
addNewHoverComponentToTextComponent(textComponent, getSubSkillHoverComponent(player, abstractSubSkill));
TextUtils.addNewHoverComponentToTextComponent(textComponent, getSubSkillHoverComponent(player, abstractSubSkill));
//Insertion
textComponent.insertion(skillName);
@@ -313,14 +283,14 @@ public class TextComponentFactory {
TextComponent.Builder textComponent;
if (skillUnlocked) {
if (RankUtils.getHighestRank(subSkillType) == RankUtils.getRank(player, subSkillType) && subSkillType.getNumRanks() > 1)
textComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.MaxRankSkillName", skillName));
textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.MaxRankSkillName", skillName));
else
textComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.SkillName", skillName));
textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.SkillName", skillName));
textComponent.clickEvent(ClickEvent.runCommand("/mmoinfo " + subSkillType.getNiceNameNoSpaces(subSkillType)));
} else {
textComponent = TextComponent.builder(LocaleLoader.getString("JSON.Hover.Mystery",
textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.Mystery",
String.valueOf(RankUtils.getUnlockLevel(subSkillType))));
textComponent.clickEvent(ClickEvent.runCommand("/mmoinfo ???"));
@@ -384,12 +354,12 @@ public class TextComponentFactory {
addRanked(ccRank, ccCurRank, ccPossessive, ccCurRank, componentBuilder, abstractSubSkill.getNumRanks(), RankUtils.getRank(player, abstractSubSkill), nextRank);
componentBuilder.append(LocaleLoader.getString("JSON.DescriptionHeader"));
componentBuilder.append("\n").append(abstractSubSkill.getDescription()).append("\n");
componentBuilder.append(Component.text(LocaleLoader.getString("JSON.DescriptionHeader")));
componentBuilder.append(Component.newline()).append(Component.text(abstractSubSkill.getDescription())).append(Component.newline());
//Empty line
componentBuilder.append("\n").decoration(TextDecoration.BOLD, false);
componentBuilder.append("\n");
componentBuilder.append(Component.newline()).decoration(TextDecoration.BOLD, false);
componentBuilder.append(Component.newline());
//Finally, add details to the tooltip
abstractSubSkill.addStats(componentBuilder, player);
@@ -412,19 +382,19 @@ public class TextComponentFactory {
}
private static TextComponent.Builder getNewComponentBuilder(String skillName) {
TextComponent.Builder componentBuilder = TextComponent.builder(skillName);
componentBuilder.append("\n");
TextComponent.Builder componentBuilder = Component.text().content(skillName);
componentBuilder.append(Component.newline());
return componentBuilder;
}
private static void addRanked(TextColor ccRank, TextColor ccCurRank, TextColor ccPossessive, TextColor ccNumRanks, TextComponent.Builder componentBuilder, int numRanks, int rank, int nextRank) {
if (numRanks > 0) {
//Rank: x
componentBuilder.append(LocaleLoader.getString("JSON.Hover.Rank", String.valueOf(rank))).append("\n");
componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Hover.Rank", String.valueOf(rank)))).append(Component.newline());
//Next Rank: x
if(nextRank > rank)
componentBuilder.append(LocaleLoader.getString("JSON.Hover.NextRank", String.valueOf(nextRank))).append("\n");
componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Hover.NextRank", String.valueOf(nextRank)))).append(Component.newline());
/*componentBuilder.append(" " + LocaleLoader.getString("JSON.RankPossesive") + " ").color(ccPossessive);
componentBuilder.append(String.valueOf(numRanks)).color(ccNumRanks);*/
@@ -433,20 +403,20 @@ public class TextComponentFactory {
private static void addLocked(SubSkillType subSkillType, TextColor ccLocked, TextColor ccLevelRequirement, TextColor ccLevelRequired, TextComponent.Builder componentBuilder) {
addLocked(ccLocked, ccLevelRequirement, componentBuilder);
componentBuilder.append(TextComponent.of(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1)), ccLevelRequired));
//componentBuilder.append("\n");
componentBuilder.append(Component.text(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1)), ccLevelRequired));
//componentBuilder.append(Component.newline());
}
private static void addLocked(AbstractSubSkill abstractSubSkill, TextColor ccLocked, TextColor ccLevelRequirement, TextColor ccLevelRequired, TextComponent.Builder componentBuilder) {
addLocked(ccLocked, ccLevelRequirement, componentBuilder);
componentBuilder.append(TextComponent.of(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1)), ccLevelRequired));
//componentBuilder.append("\n");
componentBuilder.append(Component.text(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1)), ccLevelRequired));
//componentBuilder.append(Component.newline());
}
private static void addLocked(TextColor ccLocked, TextColor ccLevelRequirement, TextComponent.Builder componentBuilder) {
componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.Locked"), ccLocked, TextDecoration.BOLD));
componentBuilder.append("\n").append("\n");
componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.LevelRequirement") + ": ", ccLevelRequirement));
componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Locked"), ccLocked, TextDecoration.BOLD));
componentBuilder.append(Component.newline()).append(Component.newline());
componentBuilder.append(Component.text(LocaleLoader.getString("JSON.LevelRequirement") + ": ", ccLevelRequirement));
}
@Deprecated
@@ -492,11 +462,11 @@ public class TextComponentFactory {
}
componentBuilder.append("\n");
componentBuilder.append(LocaleLoader.getString("JSON.DescriptionHeader"));
componentBuilder.append(Component.newline());
componentBuilder.append(Component.text(LocaleLoader.getString("JSON.DescriptionHeader")));
componentBuilder.color(ccDescriptionHeader);
componentBuilder.append("\n");
componentBuilder.append(subSkillType.getLocaleDescription());
componentBuilder.append(Component.newline());
componentBuilder.append(Component.text(subSkillType.getLocaleDescription()));
componentBuilder.color(ccDescription);
}
@@ -507,15 +477,15 @@ public class TextComponentFactory {
{
if(abstractSubSkill.isSuperAbility())
{
componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.Type.SuperAbility"), NamedTextColor.LIGHT_PURPLE, TextDecoration.BOLD));
componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Type.SuperAbility"), NamedTextColor.LIGHT_PURPLE, TextDecoration.BOLD));
} else if(abstractSubSkill.isActiveUse())
{
componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.Type.Active"), NamedTextColor.DARK_RED, TextDecoration.BOLD));
componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Type.Active"), NamedTextColor.DARK_RED, TextDecoration.BOLD));
} else {
componentBuilder.append(TextComponent.of(LocaleLoader.getString("JSON.Type.Passive"), NamedTextColor.GREEN, TextDecoration.BOLD));
componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Type.Passive"), NamedTextColor.GREEN, TextDecoration.BOLD));
}
componentBuilder.append("\n");
componentBuilder.append(Component.newline());
}
public static void getSubSkillTextComponents(Player player, List<Component> textComponents, PrimarySkillType parentSkill) {
@@ -523,6 +493,11 @@ public class TextComponentFactory {
{
if(subSkillType.getParentSkill() == parentSkill)
{
//TODO: Hacky rewrite later
//Only some versions of MC have this skill
if(subSkillType == SubSkillType.FISHING_MASTER_ANGLER && mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() == null)
continue;
if(Permissions.isSubSkillEnabled(player, subSkillType))
{
if(!InteractionManager.hasSubSkill(subSkillType))
@@ -544,7 +519,7 @@ public class TextComponentFactory {
public static TextComponent getSubSkillUnlockedNotificationComponents(Player player, SubSkillType subSkillType)
{
TextComponent.Builder unlockMessage = TextComponent.builder(LocaleLoader.getString("JSON.SkillUnlockMessage", subSkillType.getLocaleName(), RankUtils.getRank(player, subSkillType)));
TextComponent.Builder unlockMessage = Component.text().content(LocaleLoader.getString("JSON.SkillUnlockMessage", subSkillType.getLocaleName(), RankUtils.getRank(player, subSkillType)));
unlockMessage.hoverEvent(HoverEvent.showText(getSubSkillHoverComponent(player, subSkillType)));
unlockMessage.clickEvent(ClickEvent.runCommand("/"+subSkillType.getParentSkill().toString().toLowerCase(Locale.ENGLISH)));
return unlockMessage.build();

View File

@@ -0,0 +1,131 @@
package com.gmail.nossr50.util.text;
import com.gmail.nossr50.mcMMO;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentBuilder;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class TextUtils {
private static @Nullable LegacyComponentSerializer customLegacySerializer;
/**
* Makes a single component from an array of components, can optionally add prefixes and suffixes to come before and after each component
* @param componentsArray target array
* @return a component with optional styling built from an array
*/
static @NotNull Component fromArray(@NotNull Component[] componentsArray, @Nullable Component prefixComponent, @Nullable Component suffixComponent) {
TextComponent.Builder componentBuilder = Component.text();
for(Component component : componentsArray) {
if(component == null) //Individual elements can be null
continue;
if(prefixComponent != null)
componentBuilder.append(prefixComponent);
componentBuilder.append(component);
if(suffixComponent != null)
componentBuilder.append(suffixComponent);
}
return componentBuilder.build();
}
/**
* Takes a list of components and splits them into arrays each with a maximum element limit
* Individual elements in [][X] may be null
*
* @param components target component list
* @param groupsSize maximum size per array
* @return a 2D array with components split into groups
*/
static @NotNull Component[][] splitComponentsIntoGroups(@NotNull List<Component> components, int groupsSize) {
int groupCount = (int) Math.ceil((double) components.size() / (double) groupsSize);
Component[][] splitGroups = new Component[groupCount][groupsSize];
int groupsFinished = 0;
while (groupsFinished < groupCount) {
//Fill group with members
for(int i = 0; i < groupsSize; i++) {
int indexOfPotentialMember = i + (groupsFinished * 3); //Groups don't always fill all members neatly
//Some groups won't have entirely non-null elements
if(indexOfPotentialMember > components.size()-1) {
break;
}
Component potentialMember = components.get(indexOfPotentialMember);
//Make sure the potential member exists because of rounding
if(potentialMember != null) {
splitGroups[groupsFinished][i] = potentialMember;
}
}
//Another group is finished
groupsFinished++;
}
return splitGroups;
}
static void addChildWebComponent(@NotNull ComponentBuilder<?, ?> webTextComponent, @NotNull String childName) {
TextComponent childComponent = Component.text(childName).color(NamedTextColor.BLUE);
webTextComponent.append(childComponent);
}
static void addNewHoverComponentToTextComponent(@NotNull TextComponent.Builder textComponent, @NotNull Component baseComponent) {
textComponent.hoverEvent(HoverEvent.showText(baseComponent));
}
public static BaseComponent[] convertToBungeeComponent(@NotNull String displayName) {
return net.md_5.bungee.api.chat.TextComponent.fromLegacyText(displayName);
}
public static @NotNull TextComponent ofBungeeComponents(@NotNull BaseComponent[] bungeeName) {
return TextComponent.ofChildren(mcMMO.getCompatibilityManager().getBungeeSerializerCompatibilityLayer().deserialize(bungeeName));
}
public static @NotNull TextComponent ofBungeeRawStrings(@NotNull String bungeeRawString) {
return ofBungeeComponents(convertToBungeeComponent(bungeeRawString));
}
public static @NotNull TextComponent ofLegacyTextRaw(@NotNull String rawString) {
return LegacyComponentSerializer.legacySection().deserialize(rawString);
}
public static @NotNull TextComponent colorizeText(String rawtext) {
if(customLegacySerializer == null) {
customLegacySerializer = getSerializer();
}
return customLegacySerializer.deserialize(rawtext);
}
@NotNull
private static LegacyComponentSerializer getSerializer() {
return LegacyComponentSerializer.builder().hexColors().useUnusualXRepeatedCharacterHexFormat().character('&').hexCharacter('#').build();
}
public static @NotNull String sanitizeForSerializer(@NotNull String string) {
if(customLegacySerializer == null) {
customLegacySerializer = getSerializer();
}
TextComponent componentForm = ofLegacyTextRaw(string);
return customLegacySerializer.serialize(componentForm);
}
}