diff --git a/Changelog.txt b/Changelog.txt index 4d45a0f9a..71afaa7ab 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -114,6 +114,7 @@ Version 2.1.0 ! (Skills) Shake now uses a rank system ! (Skills) Flux Mining now uses a rank system ! (Skills) Removed traps from fishing + ! (Kraken) Removed everything involving the kraken = (Skills) Shake now sends custom damage types for better nocheat compat ! (Config) Unarmed.IronArm in advanced.yml is now Unarmed.IronArmStyle ! (Config) Unarmed.Deflect in advanced.yml is now Unarmed.ArrowDeflect diff --git a/src/main/java/com/gmail/nossr50/commands/KrakenCommand.java b/src/main/java/com/gmail/nossr50/commands/KrakenCommand.java deleted file mode 100644 index ca0aab11e..000000000 --- a/src/main/java/com/gmail/nossr50/commands/KrakenCommand.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.gmail.nossr50.commands; - -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.commands.CommandUtils; -import com.gmail.nossr50.util.player.UserManager; -import com.google.common.collect.ImmutableList; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.bukkit.util.StringUtil; - -import java.util.ArrayList; -import java.util.List; - -public class KrakenCommand implements TabExecutor { - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - switch (args.length) { - case 0: - if (CommandUtils.noConsoleUsage(sender)) { - return true; - } - - if (!Permissions.kraken(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - if (!CommandUtils.hasPlayerDataKey(sender)) { - return true; - } - - UserManager.getPlayer(sender.getName()).getFishingManager().unleashTheKraken(); - return true; - - case 1: - if (!Permissions.krakenOthers(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - String playerName = CommandUtils.getMatchedPlayerName(args[0]); - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(playerName); - - if (!CommandUtils.checkPlayerExistence(sender, playerName, mcMMOPlayer)) { - return true; - } - - mcMMOPlayer.getFishingManager().unleashTheKraken(); - return true; - - default: - return false; - } - } - - @Override - public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { - switch (args.length) { - case 1: - List playerNames = CommandUtils.getOnlinePlayerNames(sender); - return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList(playerNames.size())); - default: - return ImmutableList.of(); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java index d44fd0698..37fe92f67 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.archery.Archery; import com.gmail.nossr50.util.TextComponentFactory; -import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillActivationType; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.entity.Player; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java index 5bbcb140f..59ce4f09f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java @@ -3,7 +3,6 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.skills.unarmed.Unarmed; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.TextComponentFactory; import com.gmail.nossr50.util.player.UserManager; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 4d7fa85ec..554c8f824 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -15,7 +15,6 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.RandomChanceExecution; import com.gmail.nossr50.util.random.RandomChanceSkill; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.PerksUtils; diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 09e66bf6e..5f2864b8f 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -12,7 +12,6 @@ import com.gmail.nossr50.events.fake.FakeEntityDamageEvent; import com.gmail.nossr50.events.fake.FakeEntityTameEvent; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; -import com.gmail.nossr50.runnables.skills.BleedTimerTask; import com.gmail.nossr50.skills.archery.Archery; import com.gmail.nossr50.skills.fishing.Fishing; import com.gmail.nossr50.skills.mining.BlastMining; diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 9e92a98b6..63d668774 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -252,11 +252,6 @@ public class PlayerListener implements Listener { FishingManager fishingManager = UserManager.getPlayer(player).getFishingManager(); switch (event.getState()) { - case FISHING: - if (!Permissions.krakenBypass(player)) { - event.setCancelled(fishingManager.exploitPrevention()); - } - return; case CAUGHT_FISH: //TODO Update to new API once available! Waiting for case CAUGHT_TREASURE: Item fishingCatch = (Item) event.getCaught(); diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/KrakenAttackTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/KrakenAttackTask.java deleted file mode 100644 index 68d4b71b5..000000000 --- a/src/main/java/com/gmail/nossr50/runnables/skills/KrakenAttackTask.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.gmail.nossr50.runnables.skills; - -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.util.sounds.SoundManager; -import com.gmail.nossr50.util.sounds.SoundType; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; - -public class KrakenAttackTask extends BukkitRunnable { - private LivingEntity kraken; - private Player player; - private Location location; - private final boolean GLOBAL_EFFECTS = AdvancedConfig.getInstance().getKrakenGlobalEffectsEnabled(); - private final String DEFEAT_MESSAGE = AdvancedConfig.getInstance().getPlayerDefeatMessage(); - private final String ESCAPE_MESSAGE = AdvancedConfig.getInstance().getPlayerEscapeMessage(); - - public KrakenAttackTask(LivingEntity kraken2, Player player) { - this.kraken = kraken2; - this.player = player; - } - - public KrakenAttackTask(LivingEntity kraken2, Player player, Location location) { - this.kraken = kraken2; - this.player = player; - this.location = location; - } - - @Override - public void run() { - if (location != null) { - Location playerLocation = player.getLocation(); - - if (player.isValid() && playerLocation.getBlock().isLiquid()) { - World world = player.getWorld(); - - krakenAttack(playerLocation, world); - } - else { - player.sendMessage(AdvancedConfig.getInstance().getPlayerEscapeMessage()); - player.resetPlayerWeather(); - cancel(); - } - - return; - } - - if (!kraken.isValid()) { - if (!DEFEAT_MESSAGE.isEmpty()) { - player.sendMessage(DEFEAT_MESSAGE); - } - - player.resetPlayerWeather(); - cancel(); - } - - if (player.isValid()) { - Location location = player.getLocation(); - - if (!location.getBlock().isLiquid() && AdvancedConfig.getInstance().getKrakenEscapeAllowed()) { - if (!ESCAPE_MESSAGE.isEmpty()) { - player.sendMessage(AdvancedConfig.getInstance().getPlayerEscapeMessage()); - } - - kraken.remove(); - player.resetPlayerWeather(); - cancel(); - return; - } - - World world = player.getWorld(); - - kraken.teleport(player); - krakenAttack(location, world); - } - else { - kraken.remove(); - cancel(); - } - } - - private void krakenAttack(Location playerLocation, World world) { - player.damage(AdvancedConfig.getInstance().getKrakenAttackDamage(), kraken); - - if (GLOBAL_EFFECTS) { - SoundManager.worldSendSound(world, location, SoundType.KRAKEN); - world.strikeLightningEffect(playerLocation); - } - else { - SoundManager.sendSound(player, playerLocation, SoundType.KRAKEN); - world.createExplosion(playerLocation.getX(), playerLocation.getY(), playerLocation.getZ(), 0F, false, false); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java index 68d828b88..56b1bc6c2 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java @@ -9,8 +9,6 @@ import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.random.RandomChanceSkillStatic; -import com.gmail.nossr50.util.random.RandomChanceStatic; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Location; diff --git a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java index 589b206c5..42d5c474c 100644 --- a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java @@ -17,28 +17,22 @@ import com.gmail.nossr50.events.skills.fishing.McMMOPlayerFishingTreasureEvent; import com.gmail.nossr50.events.skills.fishing.McMMOPlayerShakeEvent; import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillRandomCheckEvent; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.runnables.skills.KrakenAttackTask; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.skills.CombatUtils; 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.*; +import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.SkullMeta; -import org.bukkit.potion.Potion; -import org.bukkit.potion.PotionType; -import org.bukkit.util.Vector; import java.util.*; @@ -63,93 +57,7 @@ public class FishingManager extends SkillManager { return getSkillLevel() >= RankUtils.getUnlockLevel(SubSkillType.FISHING_MASTER_ANGLER) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_MASTER_ANGLER); } - public boolean unleashTheKraken() { - return unleashTheKraken(true); - } - - private boolean unleashTheKraken(boolean forceSpawn) { - if (!forceSpawn && (fishingTries < AdvancedConfig.getInstance().getKrakenTriesBeforeRelease() || fishingTries <= Misc.getRandom().nextInt(200))) { - return false; - } - - Player player = getPlayer(); - World world = player.getWorld(); - - player.setPlayerWeather(WeatherType.DOWNFALL); - - Entity vehicle = player.getVehicle(); - - if (vehicle != null && vehicle.getType() == EntityType.BOAT) { - vehicle.eject(); - vehicle.remove(); - } - - player.teleport(player.getTargetBlock(null, 100).getLocation(), TeleportCause.PLUGIN); - - String unleashMessage = AdvancedConfig.getInstance().getPlayerUnleashMessage(); - - if (!unleashMessage.isEmpty()) { - //TODO: Strange that this pull strings from the config of all places... - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, unleashMessage); - } - - Location location = player.getLocation(); - boolean globalEffectsEnabled = AdvancedConfig.getInstance().getKrakenGlobalEffectsEnabled(); - - if (globalEffectsEnabled) { - world.strikeLightningEffect(location); - world.strikeLightningEffect(location); - world.strikeLightningEffect(location); - - SoundManager.worldSendSound(world, location, SoundType.KRAKEN); - mcMMO.p.getServer().broadcastMessage(ChatColor.RED + AdvancedConfig.getInstance().getServerUnleashMessage().replace("(PLAYER)", player.getDisplayName())); - } - else { - world.createExplosion(location.getX(), location.getY(), location.getZ(), 0F, false, false); - world.createExplosion(location.getX(), location.getY(), location.getZ(), 0F, false, false); - world.createExplosion(location.getX(), location.getY(), location.getZ(), 0F, false, false); - - SoundManager.sendSound(player, location, SoundType.KRAKEN); - } - - if (player.getInventory().getItemInMainHand().getType() == Material.FISHING_ROD) { - player.getInventory().setItemInMainHand(null); - } - else if (player.getInventory().getItemInOffHand().getType() == Material.FISHING_ROD) { - player.getInventory().setItemInOffHand(null); - } - - LivingEntity kraken = (LivingEntity) world.spawnEntity(player.getEyeLocation(), (Misc.getRandom().nextInt(100) == 0 ? EntityType.CHICKEN : EntityType.SQUID)); - kraken.setCustomName(AdvancedConfig.getInstance().getKrakenName()); - - if (!kraken.isValid()) { - int attackInterval = AdvancedConfig.getInstance().getKrakenAttackInterval() * Misc.TICK_CONVERSION_FACTOR; - new KrakenAttackTask(kraken, player, player.getLocation()).runTaskTimer(mcMMO.p, attackInterval, attackInterval); - - if (!forceSpawn) { - fishingTries = 0; - } - - return true; - } - - kraken.setMaxHealth(AdvancedConfig.getInstance().getKrakenHealth()); - kraken.setHealth(kraken.getMaxHealth()); - - int attackInterval = AdvancedConfig.getInstance().getKrakenAttackInterval() * Misc.TICK_CONVERSION_FACTOR; - new KrakenAttackTask(kraken, player).runTaskTimer(mcMMO.p, attackInterval, attackInterval); - - if (!forceSpawn) { - fishingTries = 0; - } - - return true; - } - public boolean exploitPrevention() { - if (!AdvancedConfig.getInstance().getKrakenEnabled()) { - return false; - } Block targetBlock = getPlayer().getTargetBlock(BlockUtils.getTransparentBlocks(), 100); @@ -160,16 +68,11 @@ public class FishingManager extends SkillManager { long currentTime = System.currentTimeMillis(); boolean hasFished = (currentTime < fishingTimestamp + FISHING_COOLDOWN_SECONDS); - fishingTries = hasFished ? fishingTries + 1 : Math.max(fishingTries - 1, 0); fishingTimestamp = currentTime; Location targetLocation = targetBlock.getLocation(); boolean sameTarget = (fishingTarget != null && fishingTarget.equals(targetLocation)); - - fishingTries = sameTarget ? fishingTries + 1 : Math.max(fishingTries - 1, 0); - fishingTarget = targetLocation; - - return unleashTheKraken(false); + return hasFished && sameTarget; } public boolean canIceFish(Block block) { @@ -501,36 +404,6 @@ public class FishingManager extends SkillManager { return treasure; } - private void handleTraps() { - Player player = getPlayer(); - - if (Permissions.trapsBypass(player)) { - return; - } - - if (Misc.getRandom().nextBoolean()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Fishing.Ability.TH.Boom"); - - TNTPrimed tnt = (TNTPrimed) player.getWorld().spawnEntity(fishingCatch.getLocation(), EntityType.PRIMED_TNT); - fishingCatch.setPassenger(tnt); - - Vector velocity = fishingCatch.getVelocity(); - double magnitude = velocity.length(); - fishingCatch.setVelocity(velocity.multiply((magnitude + 1) / magnitude)); - - tnt.setMetadata(mcMMO.tntsafeMetadataKey, mcMMO.metadataValue); - tnt.setFuseTicks(3 * Misc.TICK_CONVERSION_FACTOR); - } - else { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Fishing.Ability.TH.Poison"); - - ThrownPotion thrownPotion = player.getWorld().spawn(fishingCatch.getLocation(), ThrownPotion.class); - thrownPotion.setItem(new Potion(PotionType.POISON).splash().toItemStack(1)); - - fishingCatch.setPassenger(thrownPotion); - } - } - /** * Process the Magic Hunter ability * diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 545428665..d05de745b 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -391,15 +391,6 @@ public final class CommandRegistrationManager { command.setExecutor(new McscoreboardCommand()); } - private static void registerKrakenCommand() { - PluginCommand command = mcMMO.p.getCommand("kraken"); - command.setDescription("Unleash the kraken!"); //TODO: Localize - command.setPermission("mcmmo.commands.kraken;mcmmo.commands.kraken.others"); - command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "kraken", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); - command.setExecutor(new KrakenCommand()); - } - private static void registerMcImportCommand() { PluginCommand command = mcMMO.p.getCommand("mcimport"); command.setDescription("Import mod config files"); //TODO: Localize @@ -413,7 +404,6 @@ public final class CommandRegistrationManager { // Generic Commands registerMmoInfoCommand(); registerMcImportCommand(); - registerKrakenCommand(); registerMcabilityCommand(); registerMcgodCommand(); registerMcChatSpyCommand(); diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index dac472ae9..2475a5109 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -6,9 +6,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent; import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillRandomCheckEvent; -import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; -import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.SkillActivationType; import org.bukkit.entity.Player; diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index 27d7f007d..ef5155f20 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -657,25 +657,3 @@ Style: Italics: false Underline: false Color: GREEN - - - - -# -# Customize the kraken! -### -Kraken: - Enabled: true - Tries_Before_Release: 50 - Health: 50.0 - Name: The Kraken - Attack_Interval_Seconds: 1 - Attack_Damage: 1.0 - Global_Effects: false - Allow_Escaping: false - Unleashed_Message: - Server: (PLAYER) has unleashed the kraken! - Player: THE KRAKEN HAS BEEN UNLEASHED! - Defeated_Message: - Escape: You have escaped from the kraken! - Killed: You have slain the kraken! diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 8898ce802..e44d77584 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -164,10 +164,6 @@ commands: aliases: [mcsb] description: Manage your mcMMO Scoreboard permission: mcmmo.commands.mcscoreboard - kraken: - aliases: [mckraken] - description: Unleash the kraken! - permission: mcmmo.commands.kraken mcfools: aliases: [macho, jumping, throwing, wrecking, crafting, walking, swimming, falling, climbing, flying, diving, piggy] description: Deploy jokes @@ -699,8 +695,6 @@ permissions: mcmmo.bypass.partylimit: true mcmmo.bypass.arcanebypass: true mcmmo.bypass.hardcoremode: true - mcmmo.bypass.kraken: true - mcmmo.bypass.fishingtraps: true mcmmo.commands.inspect.far: true mcmmo.commands.inspect.hidden: true mcmmo.commands.inspect.offline: true @@ -713,12 +707,6 @@ permissions: mcmmo.bypass.hardcoremode: default: false description: Allows user to bypass negative penalties of Hardcore mode - mcmmo.bypass.kraken: - default: false - description: Allows user to bypass the effects of the exploit prevention when Fishing - mcmmo.bypass.fishingtraps: - default: false - description: Allows user to bypass finding traps when Fishing mcmmo.chat.*: default: false description: Implies all mcmmo.chat permissions. (Warning, contains adminchat) @@ -788,8 +776,6 @@ permissions: mcmmo.commands.inspect.far: true mcmmo.commands.inspect.hidden: true mcmmo.commands.inspect.offline: true - mcmmo.commands.kraken: true - mcmmo.commands.kraken.others: true mcmmo.commands.mcability.others: true mcmmo.commands.mcconvert.all: true mcmmo.commands.mcchatspy: true @@ -869,10 +855,6 @@ permissions: description: Allows access to the inspect command for hidden players mcmmo.commands.inspect.offline: description: Allows access to the inspect command for offline players - mcmmo.commands.kraken: - description: Allows access to the kraken command - mcmmo.commands.kraken.others: - description: Allows access to the kraken command for other players mcmmo.commands.mcability: description: Allows access to the mcability command mcmmo.commands.mcability.others: