Master Angler reworked

This commit is contained in:
nossr50 2020-11-09 16:46:52 -08:00
parent f4f6abd9d5
commit ba7e235e64
30 changed files with 715 additions and 437 deletions

View File

@ -1,13 +1,32 @@
Version 2.1.155
Master Angler now has 8 ranks
Master Angler is now supported by the latest builds of Spigot on 1.16.4
Wolves will now earn a lot more XP from combat than before (Wolves are going to be tweaked a lot in the near future)
Fixed a bug where Spectral Arrow awarded too much XP
Fixed a bug where party members other than the party leader had names that weren't properly hex colored
Added 'Skills.Fishing.MasterAngler.Tick_Reduction_Per_Rank.Min_Wait' to advanced.yml
Added 'Skills.Fishing.MasterAngler.Tick_Reduction_Per_Rank.Max_Wait' to advanced.yml
Added 'Skills.Fishing.MasterAngler.Boat_Tick_Reduction.Max_Wait' to advanced.yml
Added 'Skills.Fishing.MasterAngler.Boat_Tick_Reduction.Min_Wait' to advanced.yml
Added 'Skills.Fishing.MasterAngler.Tick_Reduction_Caps.Min_Wait' to advanced.yml
Added 'Skills.Fishing.MasterAngler.Tick_Reduction_Caps.Max_Wait' to advanced.yml
Removed Skills.Fishing.MasterAngler.BoatModifier from advanced.yml
Removed Skills.Fishing.MasterAngler.BoatModifier from advanced.yml
Optimized party/admin chat a bit
Added some misc safeguards against possible NPEs
Added some debug output when fishing if mmodebug is on
(API) Removed AbstractPlayerAuthor#getComponentDisplayName
(API) Removed AbstractPlayerAuthor#getComponentUserName
(API) Removed Author#getAuthoredComponentName
NOTES:
Master Angler won't work if you aren't on 1.16.4, the truth is it hasn't worked for a very long time. The Spigot API related to it has been broken since years and years ago, they finally updated the API but its only in the newest builds of Spigot.
If you are on something that doesn't support the new Master Angler that skill will be missing when you type /fishing
The boat bonus for master angler is static and doesn't improve when leveling master angler
The configurable reduction tick stuff for master angler is multiplied by the rank level when determining the final bonus (use /mmodebug when fishing to see some details)
Removed some unnecessary API, we aren't a chat plugin so these things shouldn't be here.
Master Angler stacks with the Lure enchant
Slowly adding Nullability annotations to the codebase
Version 2.1.154
Hex colors are now supported in Party & Admin chat

View File

@ -243,7 +243,7 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.14.4-R0.1-SNAPSHOT</version>
<version>1.16.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>

View File

@ -1,21 +1,18 @@
package com.gmail.nossr50.commands.skills;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.config.treasure.TreasureConfig;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.treasure.Rarity;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.skills.fishing.Fishing;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.fishing.FishingManager;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.text.StringUtils;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import java.util.ArrayList;
@ -26,9 +23,7 @@ public class FishingCommand extends SkillCommand {
private String shakeChance;
private String shakeChanceLucky;
private int fishermansDietRank;
private String biteChance;
private String trapTreasure;
private String commonTreasure;
private String uncommonTreasure;
private String rareTreasure;
@ -45,6 +40,8 @@ public class FishingCommand extends SkillCommand {
private boolean canMasterAngler;
private boolean canIceFish;
private String maMinWaitTime, maMaxWaitTime;
public FishingCommand() {
super(PrimarySkillType.FISHING);
}
@ -94,25 +91,8 @@ public class FishingCommand extends SkillCommand {
// MASTER ANGLER
if (canMasterAngler) {
double rawBiteChance = 1.0 / (player.getWorld().hasStorm() ? 300 : 500);
Location location = fishingManager.getHookLocation();
if (location == null) {
location = player.getLocation();
}
if (Fishing.masterAnglerBiomes.contains(location.getBlock().getBiome())) {
rawBiteChance = rawBiteChance * AdvancedConfig.getInstance().getMasterAnglerBiomeModifier();
}
if (player.isInsideVehicle() && player.getVehicle().getType() == EntityType.BOAT) {
rawBiteChance = rawBiteChance * AdvancedConfig.getInstance().getMasterAnglerBoatModifier();
}
double luckyModifier = Permissions.lucky(player, PrimarySkillType.FISHING) ? 1.333D : 1.0D;
biteChance = percent.format((rawBiteChance * 100.0D) * luckyModifier);
maMinWaitTime = StringUtils.ticksToSeconds(fishingManager.getMasterAnglerTickMinWaitReduction(RankUtils.getRank(player, SubSkillType.FISHING_MASTER_ANGLER), false));
maMaxWaitTime = StringUtils.ticksToSeconds(fishingManager.getMasterAnglerTickMaxWaitReduction(RankUtils.getRank(player, SubSkillType.FISHING_MASTER_ANGLER), false));
}
}
@ -122,7 +102,7 @@ public class FishingCommand extends SkillCommand {
canMagicHunt = canUseSubskill(player, SubSkillType.FISHING_MAGIC_HUNTER) && canUseSubskill(player, SubSkillType.FISHING_TREASURE_HUNTER);
canShake = canUseSubskill(player, SubSkillType.FISHING_SHAKE);
canFishermansDiet = canUseSubskill(player, SubSkillType.FISHING_FISHERMANS_DIET);
canMasterAngler = canUseSubskill(player, SubSkillType.FISHING_MASTER_ANGLER);
canMasterAngler = mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null && canUseSubskill(player, SubSkillType.FISHING_MASTER_ANGLER);
canIceFish = canUseSubskill(player, SubSkillType.FISHING_ICE_FISHING);
}
@ -143,8 +123,13 @@ public class FishingCommand extends SkillCommand {
}
if (canMasterAngler) {
//TODO: Update this with more details
messages.add(getStatMessage(false, true, SubSkillType.FISHING_MASTER_ANGLER, biteChance));
messages.add(getStatMessage(false,true,
SubSkillType.FISHING_MASTER_ANGLER,
maMinWaitTime));
messages.add(getStatMessage(true,true,
SubSkillType.FISHING_MASTER_ANGLER,
maMaxWaitTime));
}
if (canShake) {

View File

@ -721,6 +721,12 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
public double getShakeChance(int rank) { return config.getDouble("Skills.Fishing.ShakeChance.Rank_" + rank); }
public int getFishingVanillaXPModifier(int rank) { return config.getInt("Skills.Fishing.VanillaXPMultiplier.Rank_" + rank); }
public int getFishingReductionMinWaitTicks() { return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Per_Rank.Min_Wait", 10);}
public int getFishingReductionMaxWaitTicks() { return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Per_Rank.Max_Wait", 30);}
public int getFishingBoatReductionMinWaitTicks() { return config.getInt("Skills.Fishing.MasterAngler.Boat_Tick_Reduction.Min_Wait", 10);}
public int getFishingBoatReductionMaxWaitTicks() { return config.getInt("Skills.Fishing.MasterAngler.Boat_Tick_Reduction.Max_Wait", 30);}
public int getFishingReductionMinWaitCap() { return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Caps.Min_Wait", 40);}
public int getFishingReductionMaxWaitCap() { return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Caps.Max_Wait", 100);}
public int getFishermanDietRankChange() { return config.getInt("Skills.Fishing.FishermansDiet.RankChange", 200); }
/*public int getIceFishingUnlockLevel() { return config.getInt("Skills.Fishing.IceFishing.UnlockLevel", 50); }

View File

@ -38,7 +38,7 @@ public enum SubSkillType {
FISHING_FISHERMANS_DIET(5),
FISHING_ICE_FISHING(1),
FISHING_MAGIC_HUNTER(1),
FISHING_MASTER_ANGLER(1),
FISHING_MASTER_ANGLER(8),
FISHING_TREASURE_HUNTER(8),
FISHING_SHAKE(1),

View File

@ -0,0 +1,21 @@
package com.gmail.nossr50.runnables.skills;
import com.gmail.nossr50.skills.fishing.FishingManager;
import org.bukkit.entity.FishHook;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
public class MasterAnglerTask extends BukkitRunnable {
private final @NotNull FishHook fishHook;
private final @NotNull FishingManager fishingManager;
public MasterAnglerTask(@NotNull FishHook fishHook, @NotNull FishingManager fishingManager) {
this.fishHook = fishHook;
this.fishingManager = fishingManager;
}
@Override
public void run() {
fishingManager.processMasterAngler(fishHook);
}
}

View File

@ -9,20 +9,20 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
public abstract class SkillManager {
protected McMMOPlayer mcMMOPlayer;
protected McMMOPlayer mmoPlayer;
protected PrimarySkillType skill;
public SkillManager(McMMOPlayer mcMMOPlayer, PrimarySkillType skill) {
this.mcMMOPlayer = mcMMOPlayer;
public SkillManager(McMMOPlayer mmoPlayer, PrimarySkillType skill) {
this.mmoPlayer = mmoPlayer;
this.skill = skill;
}
public Player getPlayer() {
return mcMMOPlayer.getPlayer();
return mmoPlayer.getPlayer();
}
public int getSkillLevel() {
return mcMMOPlayer.getSkillLevel(skill);
return mmoPlayer.getSkillLevel(skill);
}
/**
@ -33,7 +33,7 @@ public abstract class SkillManager {
*/
@Deprecated
public void applyXpGain(float xp, XPGainReason xpGainReason) {
mcMMOPlayer.beginXpGain(skill, xp, xpGainReason, XPGainSource.SELF);
mmoPlayer.beginXpGain(skill, xp, xpGainReason, XPGainSource.SELF);
}
/**
@ -43,7 +43,7 @@ public abstract class SkillManager {
* @param xpGainSource the source of the XP
*/
public void applyXpGain(float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) {
mcMMOPlayer.beginXpGain(skill, xp, xpGainReason, xpGainSource);
mmoPlayer.beginXpGain(skill, xp, xpGainReason, xpGainSource);
}
public XPGainReason getXPGainReason(LivingEntity target, Entity damager) {

View File

@ -91,11 +91,11 @@ public class AcrobaticsManager extends SkillManager {
if (!isFatal(modifiedDamage) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ACROBATICS_DODGE, player)) {
ParticleEffectUtils.playDodgeEffect(player);
if (mcMMOPlayer.useChatNotifications()) {
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Combat.Proc");
}
if (SkillUtils.cooldownExpired(mcMMOPlayer.getRespawnATS(), Misc.PLAYER_RESPAWN_COOLDOWN_SECONDS)) {
if (SkillUtils.cooldownExpired(mmoPlayer.getRespawnATS(), Misc.PLAYER_RESPAWN_COOLDOWN_SECONDS)) {
if(!(attacker instanceof Player)) {
//Check to see how many dodge XP rewards this mob has handed out
if(attacker.hasMetadata(mcMMO.DODGE_TRACKER) && ExperienceConfig.getInstance().isAcrobaticsExploitingPrevented()) {

View File

@ -57,9 +57,13 @@ public class ArcheryManager extends SkillManager {
if(!arrow.hasMetadata(mcMMO.arrowDistanceKey))
return arrow.getLocation().distance(target.getLocation());
Location firedLocation = (Location) arrow.getMetadata(mcMMO.arrowDistanceKey).get(0).value();
Location targetLocation = target.getLocation();
if(firedLocation == null || firedLocation.getWorld() == null)
return 1;
if (firedLocation.getWorld() != targetLocation.getWorld()) {
return 1;
}
@ -100,7 +104,7 @@ public class ArcheryManager extends SkillManager {
NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Combat.TouchedFuzzy");
}
if (mcMMOPlayer.useChatNotifications()) {
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.TargetDazed");
}

View File

@ -57,18 +57,18 @@ public class AxesManager extends SkillManager {
if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_SKULL_SPLITTER))
return false;
return target.isValid() && mcMMOPlayer.getAbilityMode(SuperAbilityType.SKULL_SPLITTER) && Permissions.skullSplitter(getPlayer());
return target.isValid() && mmoPlayer.getAbilityMode(SuperAbilityType.SKULL_SPLITTER) && Permissions.skullSplitter(getPlayer());
}
public boolean canActivateAbility() {
return mcMMOPlayer.getToolPreparationMode(ToolType.AXE) && Permissions.skullSplitter(getPlayer());
return mmoPlayer.getToolPreparationMode(ToolType.AXE) && Permissions.skullSplitter(getPlayer());
}
/**
* Handle the effects of the Axe Mastery ability
*/
public double axeMastery() {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer(), mcMMOPlayer.getAttackStrength())) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer(), mmoPlayer.getAttackStrength())) {
return 0;
}
@ -82,13 +82,13 @@ public class AxesManager extends SkillManager {
* @param damage The amount of damage initially dealt by the event
*/
public double criticalHit(LivingEntity target, double damage) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.AXES_CRITICAL_STRIKES, getPlayer(), mcMMOPlayer.getAttackStrength())) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.AXES_CRITICAL_STRIKES, getPlayer(), mmoPlayer.getAttackStrength())) {
return 0;
}
Player player = getPlayer();
if (mcMMOPlayer.useChatNotifications()) {
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.CriticalHit");
}
@ -118,7 +118,7 @@ public class AxesManager extends SkillManager {
for (ItemStack armor : target.getEquipment().getArmorContents()) {
if (armor != null && ItemUtils.isArmor(armor)) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer(), mcMMOPlayer.getAttackStrength())) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer(), mmoPlayer.getAttackStrength())) {
SkillUtils.handleDurabilityChange(armor, durabilityDamage, 1);
}
}
@ -136,7 +136,7 @@ public class AxesManager extends SkillManager {
*/
public double greaterImpact(LivingEntity target) {
//static chance (3rd param)
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_GREATER_IMPACT, getPlayer(), mcMMOPlayer.getAttackStrength())) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_GREATER_IMPACT, getPlayer(), mmoPlayer.getAttackStrength())) {
return 0;
}
@ -145,7 +145,7 @@ public class AxesManager extends SkillManager {
ParticleEffectUtils.playGreaterImpactEffect(target);
target.setVelocity(player.getLocation().getDirection().normalize().multiply(Axes.greaterImpactKnockbackMultiplier));
if (mcMMOPlayer.useChatNotifications()) {
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.GI.Proc");
}

View File

@ -18,8 +18,10 @@ import com.gmail.nossr50.events.skills.fishing.McMMOPlayerFishingTreasureEvent;
import com.gmail.nossr50.events.skills.fishing.McMMOPlayerShakeEvent;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.runnables.skills.MasterAnglerTask;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.*;
import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.random.RandomChanceSkillStatic;
import com.gmail.nossr50.util.random.RandomChanceUtil;
@ -28,6 +30,7 @@ import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import com.gmail.nossr50.util.sounds.SoundManager;
import com.gmail.nossr50.util.sounds.SoundType;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
@ -40,6 +43,7 @@ import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@ -67,7 +71,7 @@ public class FishingManager extends SkillManager {
}
public boolean canMasterAngler() {
return getSkillLevel() >= RankUtils.getUnlockLevel(SubSkillType.FISHING_MASTER_ANGLER) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_MASTER_ANGLER);
return mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null && getSkillLevel() >= RankUtils.getUnlockLevel(SubSkillType.FISHING_MASTER_ANGLER) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_MASTER_ANGLER);
}
public void setFishingRodCastTimestamp()
@ -243,24 +247,109 @@ public class FishingManager extends SkillManager {
EventUtils.callFakeFishEvent(getPlayer(), hook);
}
public void masterAngler(FishHook hook) {
Player player = getPlayer();
Location location = hook.getLocation();
double biteChance = hook.getBiteChance();
hookLocation = location;
if (Fishing.masterAnglerBiomes.contains(location.getBlock().getBiome())) {
biteChance = biteChance * AdvancedConfig.getInstance().getMasterAnglerBiomeModifier();
public void masterAngler(@NotNull FishHook hook) {
new MasterAnglerTask(hook, this).runTaskLater(mcMMO.p, 0); //We run later to get the lure bonus applied
}
if (player.isInsideVehicle() && player.getVehicle().getType() == EntityType.BOAT) {
biteChance = biteChance * AdvancedConfig.getInstance().getMasterAnglerBoatModifier();
/**
* Processes master angler
* Reduced tick time on fish hook, etc
* @param fishHook target fish hook
*/
public void processMasterAngler(@NotNull FishHook fishHook) {
MasterAnglerCompatibilityLayer masterAnglerCompatibilityLayer = (MasterAnglerCompatibilityLayer) mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer();
if(masterAnglerCompatibilityLayer != null) {
int maxWaitTicks = masterAnglerCompatibilityLayer.getMaxWaitTime(fishHook);
int minWaitTicks = masterAnglerCompatibilityLayer.getMinWaitTime(fishHook);
int masterAnglerRank = RankUtils.getRank(mmoPlayer, SubSkillType.FISHING_MASTER_ANGLER);
boolean boatBonus = isInBoat();
int minWaitReduction = getMasterAnglerTickMinWaitReduction(masterAnglerRank, boatBonus);
int maxWaitReduction = getMasterAnglerTickMaxWaitReduction(masterAnglerRank, boatBonus);
//Ticks for minWait and maxWait never go below this value
int bonusCapMin = AdvancedConfig.getInstance().getFishingReductionMinWaitCap();
int bonusCapMax = AdvancedConfig.getInstance().getFishingReductionMaxWaitCap();
int reducedMinWaitTime = getReducedTicks(minWaitTicks, minWaitReduction, bonusCapMin);
int reducedMaxWaitTime = getReducedTicks(maxWaitTicks, maxWaitReduction, bonusCapMax);
if(mmoPlayer.isDebugMode()) {
mmoPlayer.getPlayer().sendMessage(ChatColor.GOLD + "Master Angler Debug");
mmoPlayer.getPlayer().sendMessage("ALLOW STACK WITH LURE: " + masterAnglerCompatibilityLayer.getApplyLure(fishHook));
mmoPlayer.getPlayer().sendMessage("MIN TICK REDUCTION: " + minWaitReduction);
mmoPlayer.getPlayer().sendMessage("MAX TICK REDUCTION: " + maxWaitReduction);
mmoPlayer.getPlayer().sendMessage("BOAT BONUS: " + boatBonus);
if(boatBonus) {
mmoPlayer.getPlayer().sendMessage("BOAT MAX TICK REDUCTION: " + maxWaitReduction);
mmoPlayer.getPlayer().sendMessage("BOAT MIN TICK REDUCTION: " + maxWaitReduction);
}
hook.setBiteChance(Math.min(biteChance, 1.0));
mmoPlayer.getPlayer().sendMessage("");
mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "BEFORE MASTER ANGLER WAS APPLIED");
mmoPlayer.getPlayer().sendMessage("Original Max Wait Ticks: " + maxWaitTicks);
mmoPlayer.getPlayer().sendMessage("Original Min Wait Ticks: " + minWaitTicks);
mmoPlayer.getPlayer().sendMessage("");
mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "AFTER MASTER ANGLER WAS APPLIED");
mmoPlayer.getPlayer().sendMessage("Current Max Wait Ticks: " + reducedMaxWaitTime);
mmoPlayer.getPlayer().sendMessage("Current Min Wait Ticks: " + reducedMinWaitTime);
mmoPlayer.getPlayer().sendMessage("");
mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "Caps / Limits (edit in advanced.yml)");
mmoPlayer.getPlayer().sendMessage("Lowest possible max wait ticks " + bonusCapMax);
mmoPlayer.getPlayer().sendMessage("Lowest possible min wait ticks " + bonusCapMin);
}
masterAnglerCompatibilityLayer.setMaxWaitTime(fishHook, reducedMaxWaitTime);
masterAnglerCompatibilityLayer.setMinWaitTime(fishHook, reducedMinWaitTime);
}
}
public int getReducedTicks(int ticks, int totalBonus, int tickBounds) {
return Math.max(tickBounds, ticks - totalBonus);
}
public boolean isInBoat() {
return mmoPlayer.getPlayer().isInsideVehicle() && mmoPlayer.getPlayer().getVehicle() instanceof Boat;
}
public int getMasterAnglerTickMaxWaitReduction(int masterAnglerRank, boolean boatBonus) {
int totalBonus = AdvancedConfig.getInstance().getFishingReductionMaxWaitTicks() * masterAnglerRank;
if(boatBonus) {
totalBonus += getFishingBoatMaxWaitReduction();
}
return totalBonus;
}
public int getMasterAnglerTickMinWaitReduction(int masterAnglerRank, boolean boatBonus) {
int totalBonus = AdvancedConfig.getInstance().getFishingReductionMinWaitTicks() * masterAnglerRank;
if(boatBonus) {
totalBonus += getFishingBoatMinWaitReduction();
}
return totalBonus;
}
public int getFishingBoatMinWaitReduction() {
return AdvancedConfig.getInstance().getFishingBoatReductionMinWaitTicks();
}
public int getFishingBoatMaxWaitReduction() {
return AdvancedConfig.getInstance().getFishingBoatReductionMaxWaitTicks();
}
public boolean isMagicHunterEnabled()
{
return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.FISHING_MAGIC_HUNTER)

View File

@ -80,15 +80,15 @@ public class HerbalismManager extends SkillManager {
}
public boolean canGreenTerraBlock(BlockState blockState) {
return mcMMOPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA) && BlockUtils.canMakeMossy(blockState);
return mmoPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA) && BlockUtils.canMakeMossy(blockState);
}
public boolean canActivateAbility() {
return mcMMOPlayer.getToolPreparationMode(ToolType.HOE) && Permissions.greenTerra(getPlayer());
return mmoPlayer.getToolPreparationMode(ToolType.HOE) && Permissions.greenTerra(getPlayer());
}
public boolean isGreenTerraActive() {
return mcMMOPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA);
return mmoPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA);
}
/**
@ -242,7 +242,7 @@ public class HerbalismManager extends SkillManager {
if(delayedChorusBlocks.size() > 0) {
//Check XP for chorus blocks
DelayedHerbalismXPCheckTask delayedHerbalismXPCheckTask = new DelayedHerbalismXPCheckTask(mcMMOPlayer, delayedChorusBlocks);
DelayedHerbalismXPCheckTask delayedHerbalismXPCheckTask = new DelayedHerbalismXPCheckTask(mmoPlayer, delayedChorusBlocks);
//Large delay because the tree takes a while to break
delayedHerbalismXPCheckTask.runTaskLater(mcMMO.p, 20); //Calculate Chorus XP + Bonus Drops 1 tick later
@ -330,7 +330,7 @@ public class HerbalismManager extends SkillManager {
public void markForBonusDrops(BlockState brokenPlantState) {
//Add metadata to mark this block for double or triple drops
boolean awardTriple = mcMMOPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA);
boolean awardTriple = mmoPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA);
BlockUtils.markDropsAsBonus(brokenPlantState, awardTriple);
}
@ -387,8 +387,8 @@ public class HerbalismManager extends SkillManager {
}
}
if(mcMMOPlayer.isDebugMode()) {
mcMMOPlayer.getPlayer().sendMessage("Plants processed: "+brokenPlants.size());
if(mmoPlayer.isDebugMode()) {
mmoPlayer.getPlayer().sendMessage("Plants processed: "+brokenPlants.size());
}
//Reward XP
@ -438,9 +438,9 @@ public class HerbalismManager extends SkillManager {
}
}
if(mcMMOPlayer.isDebugMode()) {
mcMMOPlayer.getPlayer().sendMessage("Chorus Plants checked for XP: "+brokenPlants.size());
mcMMOPlayer.getPlayer().sendMessage("Valid Chorus Plant XP Gains: "+blocksGivingXP);
if(mmoPlayer.isDebugMode()) {
mmoPlayer.getPlayer().sendMessage("Chorus Plants checked for XP: "+brokenPlants.size());
mmoPlayer.getPlayer().sendMessage("Valid Chorus Plant XP Gains: "+blocksGivingXP);
}
//Reward XP

View File

@ -82,7 +82,7 @@ public class MiningManager extends SkillManager {
return;
}
if (mcMMOPlayer.getAbilityMode(skill.getAbility())) {
if (mmoPlayer.getAbilityMode(skill.getAbility())) {
SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), Config.getInstance().getAbilityToolDamage());
}
@ -96,7 +96,7 @@ public class MiningManager extends SkillManager {
//TODO: Make this readable
if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS, true)) {
boolean useTriple = mcMMOPlayer.getAbilityMode(skill.getAbility()) && AdvancedConfig.getInstance().getAllowMiningTripleDrops();
boolean useTriple = mmoPlayer.getAbilityMode(skill.getAbility()) && AdvancedConfig.getInstance().getAllowMiningTripleDrops();
BlockUtils.markDropsAsBonus(blockState, useTriple);
}
}
@ -119,13 +119,13 @@ public class MiningManager extends SkillManager {
NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, "Mining.Blast.Boom");
//player.sendMessage(LocaleLoader.getString("Mining.Blast.Boom"));
tnt.setMetadata(mcMMO.tntMetadataKey, mcMMOPlayer.getPlayerMetadata());
tnt.setMetadata(mcMMO.tntMetadataKey, mmoPlayer.getPlayerMetadata());
tnt.setFuseTicks(0);
targetBlock.setType(Material.AIR);
mcMMOPlayer.setAbilityDATS(SuperAbilityType.BLAST_MINING, System.currentTimeMillis());
mcMMOPlayer.setAbilityInformed(SuperAbilityType.BLAST_MINING, false);
new AbilityCooldownTask(mcMMOPlayer, SuperAbilityType.BLAST_MINING).runTaskLater(mcMMO.p, SuperAbilityType.BLAST_MINING.getCooldown() * Misc.TICK_CONVERSION_FACTOR);
mmoPlayer.setAbilityDATS(SuperAbilityType.BLAST_MINING, System.currentTimeMillis());
mmoPlayer.setAbilityInformed(SuperAbilityType.BLAST_MINING, false);
new AbilityCooldownTask(mmoPlayer, SuperAbilityType.BLAST_MINING).runTaskLater(mcMMO.p, SuperAbilityType.BLAST_MINING.getCooldown() * Misc.TICK_CONVERSION_FACTOR);
}
/**
@ -311,7 +311,7 @@ public class MiningManager extends SkillManager {
}
private boolean blastMiningCooldownOver() {
int timeRemaining = mcMMOPlayer.calculateTimeRemaining(SuperAbilityType.BLAST_MINING);
int timeRemaining = mmoPlayer.calculateTimeRemaining(SuperAbilityType.BLAST_MINING);
if (timeRemaining > 0) {
//getPlayer().sendMessage(LocaleLoader.getString("Skills.TooTired", timeRemaining));

View File

@ -29,7 +29,7 @@ public class SwordsManager extends SkillManager {
}
public boolean canActivateAbility() {
return mcMMOPlayer.getToolPreparationMode(ToolType.SWORD) && Permissions.serratedStrikes(getPlayer());
return mmoPlayer.getToolPreparationMode(ToolType.SWORD) && Permissions.serratedStrikes(getPlayer());
}
public boolean canUseStab() {
@ -51,7 +51,7 @@ public class SwordsManager extends SkillManager {
if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.SWORDS_SERRATED_STRIKES))
return false;
return mcMMOPlayer.getAbilityMode(SuperAbilityType.SERRATED_STRIKES);
return mmoPlayer.getAbilityMode(SuperAbilityType.SERRATED_STRIKES);
}
/**
@ -60,7 +60,7 @@ public class SwordsManager extends SkillManager {
* @param target The defending entity
*/
public void ruptureCheck(LivingEntity target) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_RUPTURE, getPlayer(), this.mcMMOPlayer.getAttackStrength())) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_RUPTURE, getPlayer(), this.mmoPlayer.getAttackStrength())) {
if (target instanceof Player) {
Player defender = (Player) target;
@ -77,7 +77,7 @@ public class SwordsManager extends SkillManager {
BleedTimerTask.add(target, getPlayer(), getRuptureBleedTicks(), RankUtils.getRank(getPlayer(), SubSkillType.SWORDS_RUPTURE), getToolTier(getPlayer().getInventory().getItemInMainHand()));
if (mcMMOPlayer.useChatNotifications()) {
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding");
}
}

View File

@ -33,7 +33,7 @@ public class UnarmedManager extends SkillManager {
}
public boolean canActivateAbility() {
return mcMMOPlayer.getToolPreparationMode(ToolType.FISTS) && Permissions.berserk(getPlayer());
return mmoPlayer.getToolPreparationMode(ToolType.FISTS) && Permissions.berserk(getPlayer());
}
public boolean canUseSteelArm() {
@ -44,7 +44,7 @@ public class UnarmedManager extends SkillManager {
}
public boolean canUseBerserk() {
return mcMMOPlayer.getAbilityMode(SuperAbilityType.BERSERK);
return mmoPlayer.getAbilityMode(SuperAbilityType.BERSERK);
}
public boolean canDisarm(LivingEntity target) {
@ -102,7 +102,7 @@ public class UnarmedManager extends SkillManager {
* @param defender The defending player
*/
public void disarmCheck(Player defender) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_DISARM, getPlayer(), mcMMOPlayer.getAttackStrength()) && !hasIronGrip(defender)) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_DISARM, getPlayer(), mmoPlayer.getAttackStrength()) && !hasIronGrip(defender)) {
if (EventUtils.callDisarmEvent(defender).isCancelled()) {
return;
}
@ -139,7 +139,7 @@ public class UnarmedManager extends SkillManager {
* @param damage The amount of damage initially dealt by the event
*/
public double berserkDamage(double damage) {
damage = ((damage * Unarmed.berserkDamageModifier) * mcMMOPlayer.getAttackStrength()) - damage;
damage = ((damage * Unarmed.berserkDamageModifier) * mmoPlayer.getAttackStrength()) - damage;
return damage;
}

View File

@ -63,7 +63,7 @@ public class WoodcuttingManager extends SkillManager {
}
public boolean canUseTreeFeller(ItemStack heldItem) {
return mcMMOPlayer.getAbilityMode(SuperAbilityType.TREE_FELLER)
return mmoPlayer.getAbilityMode(SuperAbilityType.TREE_FELLER)
&& ItemUtils.isAxe(heldItem);
}

View File

@ -8,10 +8,13 @@ import com.gmail.nossr50.util.compat.layers.bungee.BungeeModernSerializerCompati
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;
@ -21,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
@ -31,6 +35,7 @@ public class CompatibilityManager {
// private PlayerAttackCooldownExploitPreventionLayer playerAttackCooldownExploitPreventionLayer;
private AbstractPersistentDataLayer persistentDataLayer;
private AbstractBungeeSerializerCompatibilityLayer bungeeSerializerCompatibilityLayer;
private AbstractMasterAnglerCompatibility masterAnglerCompatibility;
public CompatibilityManager(MinecraftGameVersion minecraftGameVersion) {
mcMMO.p.getLogger().info("Loading compatibility layers...");
@ -49,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
}
}
@ -64,16 +65,39 @@ 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() {
@ -145,11 +169,6 @@ public class CompatibilityManager {
return NMSVersion.UNSUPPORTED;
}
// public PlayerAttackCooldownExploitPreventionLayer getPlayerAttackCooldownExploitPreventionLayer() {
// return playerAttackCooldownExploitPreventionLayer;
// }
public AbstractBungeeSerializerCompatibilityLayer getBungeeSerializerCompatibilityLayer() {
return bungeeSerializerCompatibilityLayer;
}
@ -157,4 +176,8 @@ public class CompatibilityManager {
public AbstractPersistentDataLayer getPersistentDataLayer() {
return persistentDataLayer;
}
public @Nullable AbstractMasterAnglerCompatibility getMasterAnglerCompatibilityLayer() {
return masterAnglerCompatibility;
}
}

View File

@ -1,7 +1,7 @@
package com.gmail.nossr50.util.compat;
public enum CompatibilityType {
PLAYER_ATTACK_COOLDOWN_EXPLOIT_PREVENTION,
PERSISTENT_DATA,
BUNGEE_SERIALIZER
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,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

@ -27,6 +27,8 @@ import com.gmail.nossr50.util.player.UserManager;
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;
@ -48,12 +50,12 @@ public final class CombatUtils {
private CombatUtils() {}
private static AbstractPersistentDataLayer getPersistentData() {
private static @NotNull AbstractPersistentDataLayer getPersistentData() {
return mcMMO.getCompatibilityManager().getPersistentDataLayer();
}
//Likely.. because who knows what plugins are throwing around
public static boolean isDamageLikelyFromNormalCombat(DamageCause damageCause) {
public static boolean isDamageLikelyFromNormalCombat(@NotNull DamageCause damageCause) {
switch (damageCause) {
case ENTITY_ATTACK:
case ENTITY_SWEEP_ATTACK:
@ -64,12 +66,11 @@ public final class CombatUtils {
}
}
public static boolean hasWeakenedDamage(LivingEntity livingEntity) {
public static boolean hasWeakenedDamage(@NotNull LivingEntity livingEntity) {
return livingEntity.hasPotionEffect(PotionEffectType.WEAKNESS);
}
private static void processSwordCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event) {
private static void processSwordCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) {
return;
}
@ -119,43 +120,19 @@ public final class CombatUtils {
printFinalDamageDebug(player, event, mcMMOPlayer);
}
private static void printFinalDamageDebug(@NotNull Player player, @NotNull EntityDamageByEntityEvent event, @NotNull McMMOPlayer mcMMOPlayer, @Nullable String... extraInfoLines) {
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);
}
}
}
}
// 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 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;
}
@ -207,7 +184,7 @@ public final class CombatUtils {
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;
}
@ -251,7 +228,7 @@ public final class CombatUtils {
printFinalDamageDebug(player, event, mcMMOPlayer);
}
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;
@ -280,12 +257,12 @@ public final class CombatUtils {
}
applyScaledModifiers(initialDamage, finalDamage, event);
processCombatXP(mcMMOPlayer, target, PrimarySkillType.TAMING);
processCombatXP(mcMMOPlayer, target, PrimarySkillType.TAMING, 3);
}
}
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 mcMMOPlayer = UserManager.getPlayer(player);
@ -339,7 +316,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();
@ -469,7 +446,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");
@ -488,7 +465,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));
@ -505,7 +482,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) {
@ -524,7 +501,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()) {
@ -541,7 +518,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());
}
@ -550,7 +527,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);
@ -566,7 +543,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);
}
@ -578,7 +555,7 @@ 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);
}
@ -606,7 +583,7 @@ 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;
}
@ -623,7 +600,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;
}
@ -649,19 +626,19 @@ public final class CombatUtils {
processingNoInvulnDamage = false;
}
public static void removeIgnoreDamageMetadata(LivingEntity target) {
public static void removeIgnoreDamageMetadata(@NotNull LivingEntity target) {
target.removeMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY, mcMMO.p);
}
public static void applyIgnoreDamageMetadata(LivingEntity target) {
public static void applyIgnoreDamageMetadata(@NotNull LivingEntity target) {
target.setMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY, mcMMO.metadataValue);
}
public static boolean hasIgnoreDamageMetadata(LivingEntity target) {
public static boolean hasIgnoreDamageMetadata(@NotNull LivingEntity target) {
return target.getMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY).size() != 0;
}
public static void dealNoInvulnerabilityTickDamageRupture(LivingEntity target, double damage, Entity attacker, int toolTier) {
public static void dealNoInvulnerabilityTickDamageRupture(@NotNull LivingEntity target, double damage, Entity attacker, int toolTier) {
if (target.isDead()) {
return;
}
@ -706,7 +683,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);
@ -754,7 +731,7 @@ public final class CombatUtils {
* @param target The defending entity
* @param primarySkillType The skill being used
*/
public static void processCombatXP(McMMOPlayer mcMMOPlayer, LivingEntity target, PrimarySkillType primarySkillType) {
public static void processCombatXP(@NotNull McMMOPlayer mcMMOPlayer, LivingEntity target, PrimarySkillType primarySkillType) {
processCombatXP(mcMMOPlayer, target, primarySkillType, 1.0);
}
@ -766,7 +743,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 mcMMOPlayer, LivingEntity target, PrimarySkillType primarySkillType, double multiplier) {
public static void processCombatXP(@NotNull McMMOPlayer mcMMOPlayer, LivingEntity target, PrimarySkillType primarySkillType, double multiplier) {
double baseXP = 0;
XPGainReason xpGainReason;
@ -849,7 +826,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;
@ -879,10 +856,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);
}
}
@ -897,7 +876,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.
@ -912,7 +891,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();
@ -927,12 +906,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()) {
@ -942,27 +921,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);
@ -973,7 +952,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));
@ -982,7 +961,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()) {
@ -997,7 +976,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;
@ -1025,7 +1004,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)) {
@ -1052,7 +1031,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;
}
@ -1069,4 +1048,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

@ -154,6 +154,17 @@ public class RankUtils {
return getRank(player, 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(McMMOPlayer mmoPlayer, SubSkillType subSkillType)
{
return getRank(mmoPlayer.getPlayer(), subSkillType);
}
/**
* Gets the current rank of the subskill for the player
* @param player The player in question

View File

@ -8,10 +8,14 @@ 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.
*
@ -23,6 +27,11 @@ 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) + "s";
}
/**
* Creates a string from an array skipping the first n elements
* @param args the array to iterate over when forming the string

View File

@ -493,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))

View File

@ -231,10 +231,16 @@ Skills:
RankChange: 20
MasterAngler:
# BoatMultiplier: Catch rate is multiplied by this modifier
# BiomeModifier: Catch rate is multiplied by this modifier
BoatModifier: 2.0
BiomeModifier: 2.0
Boat_Tick_Reduction:
Min_Wait: 10
Max_Wait: 30
Tick_Reduction_Per_Rank:
Min_Wait: 10
Max_Wait: 30
Tick_Reduction_Caps:
# Don't modify these two unless you fully understand what you are doing
Min_Wait: 40
Max_Wait: 100
#
# Settings for Herbalism
###

View File

@ -251,8 +251,9 @@ Fishing.SubSkill.FishermansDiet.Name=Fisherman's Diet
Fishing.SubSkill.FishermansDiet.Description=Improves hunger restored from fished foods
Fishing.SubSkill.FishermansDiet.Stat=Fisherman's Diet:&a Rank {0}
Fishing.SubSkill.MasterAngler.Name=Master Angler
Fishing.SubSkill.MasterAngler.Description=Improves chance of getting a bite while fishing
Fishing.SubSkill.MasterAngler.Stat=Added Bite Chance at your current location: &a+{0}
Fishing.SubSkill.MasterAngler.Description=Fish are caught more frequently
Fishing.SubSkill.MasterAngler.Stat=Fishing minimum wait time bonus: &a-{0} seconds
Fishing.SubSkill.MasterAngler.Stat.Extra=Fishing maximum wait time bonus: &a-{0} seconds
Fishing.SubSkill.IceFishing.Name=Ice Fishing
Fishing.SubSkill.IceFishing.Description=Allows you to fish in icy biomes
Fishing.SubSkill.IceFishing.Stat=Ice Fishing
@ -896,7 +897,7 @@ Guides.Excavation.Section.5=&3Notes about Excavation:\n&eExcavation drops are co
Guides.Fishing.Section.0=&3About Fishing:\n&eWith the Fishing skill, Fishing is exciting again!\n&eFind hidden treasures, and shake items off mobs.\n\n&3XP GAIN:\n&eCatch fish.
Guides.Fishing.Section.1=&3How does Treasure Hunter work?\n&eThis ability allows you to find treasure from fishing \n&ewith a small chance of the items being enchanted.\n&eEvery possible treasure for Fishing has a chance\n&eto drop on any level. It depends however\n&ewhat the rarity of the item is how often it will drop.\n&eThe higher your Fishing skill is, the better\n&eyour chances are to find better treasures.
Guides.Fishing.Section.2=&3How does Ice Fishing work?\n&eThis passive skill allows you to fish in ice lakes!\n&eCast your fishing rod in an ice lake and the ability will\n&ecreate a small hole in the ice to fish in.
Guides.Fishing.Section.3=&3How does Master Angler work?\n&eThis passive skill increases the bite chance while fishing.\n&eWhen you've unlocked this ability, fishing while in\n&ea boat or when an ocean biome doubles the bite chance.
Guides.Fishing.Section.3=&3How does Master Angler work?\n&eThis passive skill increases the bite chance while fishing.\n&eWhen you've unlocked this ability, fishing while in\n&ea boat improves odds of catching a fish.
Guides.Fishing.Section.4=&3How does Shake work?\n&eThis active ability allows you to shake items loose from mobs\n&eby hooking them with the fishing rod. \n&eMobs will drop items they would normally drop on death.\n&eIt is also possible to acquire mob skulls, which are normally \n&eunobtainable in survival mode.
Guides.Fishing.Section.5=&3How does Fisherman's Diet work?\n&eThis passive skill increases the amount of hunger restored \n&efrom eating fish.
Guides.Fishing.Section.6=&3Notes about Fishing:\n&eFishing drops are completely customizable,\n&eso results vary server to server.

View File

@ -410,9 +410,23 @@ Fishing:
Rank_1: 150
MasterAngler:
Standard:
Rank_1: 50
Rank_1: 1
Rank_2: 20
Rank_3: 30
Rank_4: 40
Rank_5: 60
Rank_6: 70
Rank_7: 80
Rank_8: 90
RetroMode:
Rank_1: 500
Rank_1: 1
Rank_2: 200
Rank_3: 300
Rank_4: 400
Rank_5: 600
Rank_6: 700
Rank_7: 800
Rank_8: 900
IceFishing:
Standard:
Rank_1: 5