Преглед на файлове

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

nossr50 преди 6 години
родител
ревизия
8b2d1eb1d8

+ 12 - 0
Changelog.txt

@@ -170,6 +170,18 @@ Version 2.2.0
     Added API method to grab the level cap of a skill by its PrimarySkillType ENUM definition
     Added API method to check if a skill was being level capped
     Added 'UndefinedSkillBehaviour' for trying to use a method that has no behaviour defined for the provided skill
+Version 2.1.82
+    Added new WG flag 'mcmmo-hardcore' if set to negative players will not be penalized by hardcore mode (if hardcore mode is enabled) it defaults to true
+    Added proper error handling when loading parties file
+    Fixed an error that could occur when using mcrank on an offline player
+    You can now use mcrank on offline players by default
+    You can now use inspect on offline players by default
+    Removed the offline inspect/mcrank permissions
+    Updated Chinese locale (thanks to the user named 89009332 from github)
+    Added some redundancy checks when loading profiles (NPC checks to be specific)
+
+    NOTES:
+    There were reasons to prevent inspecting offline players in the past, I don't see any reason for them anymore so I've removed the restriction.
 
 Version 2.1.81
     Fixed a bug where Arrow Deflect would never trigger outside of PVP

+ 0 - 3
src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java

@@ -35,9 +35,6 @@ public class InspectCommand implements TabExecutor {
                         return true;
                     }
 
-                    if (CommandUtils.inspectOffline(sender, profile, Permissions.inspectOffline(sender))) {
-                        return true;
-                    }
 
                     if (mcMMO.getScoreboardSettings().getScoreboardsEnabled() && sender instanceof Player
                             && mcMMO.getScoreboardSettings().getConfigSectionScoreboardTypes().getConfigSectionInspectBoard().isUseThisBoard()) {

+ 0 - 2
src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java

@@ -63,8 +63,6 @@ public class McrankCommand implements TabExecutor {
                     if (CommandUtils.tooFar(sender, player, Permissions.mcrankFar(sender))) {
                         return true;
                     }
-                } else if (CommandUtils.inspectOffline(sender, mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false), Permissions.mcrankOffline(sender))) {
-                    return true;
                 }
 
                 display(sender, playerName);

+ 1 - 0
src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java

@@ -23,6 +23,7 @@ import com.gmail.nossr50.util.StringUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.google.common.collect.ImmutableList;
 import org.bukkit.Color;
+import org.bukkit.OfflinePlayer;
 import org.bukkit.entity.Entity;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Tameable;

+ 6 - 6
src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -306,7 +306,7 @@ public class EntityListener implements Listener {
         }
         */
 
-        if (Misc.isNPCEntity(defender) || !defender.isValid() || !(defender instanceof LivingEntity)) {
+        if (Misc.isNPCEntityExcludingVillagers(defender) || !defender.isValid() || !(defender instanceof LivingEntity)) {
             return;
         }
 
@@ -316,7 +316,7 @@ public class EntityListener implements Listener {
             return;
         }
 
-        if (Misc.isNPCEntity(attacker)) {
+        if (Misc.isNPCEntityExcludingVillagers(attacker)) {
             return;
         }
 
@@ -440,7 +440,7 @@ public class EntityListener implements Listener {
         }
         */
 
-        if (Misc.isNPCEntity(entity) || !entity.isValid() || !(entity instanceof LivingEntity)) {
+        if (Misc.isNPCEntityExcludingVillagers(entity) || !entity.isValid() || !(entity instanceof LivingEntity)) {
             return;
         }
 
@@ -570,7 +570,7 @@ public class EntityListener implements Listener {
 
         LivingEntity entity = event.getEntity();
 
-        if (Misc.isNPCEntity(entity)) {
+        if (Misc.isNPCEntityExcludingVillagers(entity)) {
             return;
         }
 
@@ -602,7 +602,7 @@ public class EntityListener implements Listener {
 
         LivingEntity entity = event.getEntity();
 
-        if (Misc.isNPCEntity(entity)) {
+        if (Misc.isNPCEntityExcludingVillagers(entity)) {
             return;
         }
 
@@ -885,7 +885,7 @@ public class EntityListener implements Listener {
 
         LivingEntity entity = event.getEntity();
 
-        if (!UserManager.hasPlayerDataKey(player) || Misc.isNPCEntity(entity) || entity.hasMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY)) {
+        if (!UserManager.hasPlayerDataKey(player) || Misc.isNPCEntityExcludingVillagers(entity) || entity.hasMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY)) {
             return;
         }
 

+ 1 - 5
src/main/java/com/gmail/nossr50/listeners/PlayerListener.java

@@ -511,10 +511,6 @@ public class PlayerListener implements Listener {
     public void onPlayerJoin(PlayerJoinEvent event) {
         Player player = event.getPlayer();
 
-        if (Misc.isNPCEntity(player)) {
-            return;
-        }
-
         //Delay loading for 3 seconds in case the player has a save task running, its hacky but it should do the trick
         new PlayerProfileLoadingTask(player).runTaskLaterAsynchronously(mcMMO.p, 60);
 
@@ -840,7 +836,7 @@ public class PlayerListener implements Listener {
     public void onPlayerChat(AsyncPlayerChatEvent event) {
         Player player = event.getPlayer();
 
-        if (Misc.isNPCEntity(player) || !UserManager.hasPlayerDataKey(player)) {
+        if (Misc.isNPCEntityExcludingVillagers(player) || !UserManager.hasPlayerDataKey(player)) {
             return;
         }
 

+ 34 - 26
src/main/java/com/gmail/nossr50/party/PartyManager.java

@@ -610,45 +610,53 @@ public final class PartyManager {
             return;
         }*/
 
-        YamlConfiguration partiesFile = YamlConfiguration.loadConfiguration(partyFile);
+        try {
+            YamlConfiguration partiesFile;
+            partiesFile = YamlConfiguration.loadConfiguration(partyFile);
 
-        ArrayList<Party> hasAlly = new ArrayList<>();
+            ArrayList<Party> hasAlly = new ArrayList<Party>();
 
-        for (String partyName : partiesFile.getConfigurationSection("").getKeys(false)) {
-            Party party = new Party(partyName);
+            for (String partyName : partiesFile.getConfigurationSection("").getKeys(false)) {
+                Party party = new Party(partyName);
 
-            String[] leaderSplit = partiesFile.getString(partyName + ".Leader").split("[|]");
-            party.setLeader(new PartyLeader(UUID.fromString(leaderSplit[0]), leaderSplit[1]));
-            party.setPassword(partiesFile.getString(partyName + ".Password"));
-            party.setLocked(partiesFile.getBoolean(partyName + ".Locked"));
-            party.setLevel(partiesFile.getInt(partyName + ".Level"));
-            party.setXp(partiesFile.getInt(partyName + ".Xp"));
+                String[] leaderSplit = partiesFile.getString(partyName + ".Leader").split("[|]");
+                party.setLeader(new PartyLeader(UUID.fromString(leaderSplit[0]), leaderSplit[1]));
+                party.setPassword(partiesFile.getString(partyName + ".Password"));
+                party.setLocked(partiesFile.getBoolean(partyName + ".Locked"));
+                party.setLevel(partiesFile.getInt(partyName + ".Level"));
+                party.setXp(partiesFile.getInt(partyName + ".Xp"));
 
-            if (partiesFile.getString(partyName + ".Ally") != null) {
-                hasAlly.add(party);
-            }
+                if (partiesFile.getString(partyName + ".Ally") != null) {
+                    hasAlly.add(party);
+                }
 
-            party.setXpShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ExpShareMode", "NONE")));
-            party.setItemShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ItemShareMode", "NONE")));
+                party.setXpShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ExpShareMode", "NONE")));
+                party.setItemShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ItemShareMode", "NONE")));
 
-            for (ItemShareType itemShareType : ItemShareType.values()) {
-                party.setSharingDrops(itemShareType, partiesFile.getBoolean(partyName + ".ItemShareType." + itemShareType.toString(), true));
+                for (ItemShareType itemShareType : ItemShareType.values()) {
+                    party.setSharingDrops(itemShareType, partiesFile.getBoolean(partyName + ".ItemShareType." + itemShareType.toString(), true));
+                }
+
+                LinkedHashMap<UUID, String> members = party.getMembers();
+
+                for (String memberEntry : partiesFile.getStringList(partyName + ".Members")) {
+                    String[] memberSplit = memberEntry.split("[|]");
+                    members.put(UUID.fromString(memberSplit[0]), memberSplit[1]);
+                }
+
+                parties.add(party);
             }
 
-            LinkedHashMap<UUID, String> members = party.getMembers();
+            mcMMO.p.debug("Loaded (" + parties.size() + ") Parties...");
 
-            for (String memberEntry : partiesFile.getStringList(partyName + ".Members")) {
-                String[] memberSplit = memberEntry.split("[|]");
-                members.put(UUID.fromString(memberSplit[0]), memberSplit[1]);
+            for (Party party : hasAlly) {
+                party.setAlly(PartyManager.getParty(partiesFile.getString(party.getName() + ".Ally")));
             }
 
-            parties.add(party);
+        } catch (Exception e) {
+            e.printStackTrace();
         }
-        mcMMO.p.debug("Loaded (" + parties.size() + ") Parties...");
 
-        for (Party party : hasAlly) {
-            party.setAlly(PartyManager.getParty(partiesFile.getString(party.getName() + ".Ally")));
-        }
     }
 
     /**

+ 4 - 4
src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java

@@ -41,16 +41,16 @@ public class McrankCommandDisplayTask extends BukkitRunnable {
     }
 
     private void displayChat() {
-        Player player = mcMMO.p.getServer().getPlayerExact(playerName);
+//        Player player = mcMMO.p.getServer().getPlayerExact(playerName);
         Integer rank;
 
         sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Heading"));
         sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName));
 
         for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) {
-            if (!skill.getPermissions(player)) {
-                continue;
-            }
+//            if (!skill.getPermissions(player)) {
+//                continue;
+//            }
 
             rank = skills.get(skill);
             sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", skill.getName(), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank)));

+ 5 - 0
src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java

@@ -29,6 +29,11 @@ public class PlayerProfileLoadingTask extends BukkitRunnable {
     // DO NOT MODIFY THE McMMOPLAYER FROM THIS CODE
     @Override
     public void run() {
+
+        if (Misc.isNPCIncludingVillagers(player)) {
+            return;
+        }
+
         // Quit if they logged out
         if (!player.isOnline()) {
             mcMMO.p.getLogger().info("Aborting profile loading recovery for " + player.getName() + " - player logged out");

+ 1 - 1
src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java

@@ -169,7 +169,7 @@ public class UnarmedManager extends SkillManager {
      * @return true if the defender was not disarmed, false otherwise
      */
     private boolean hasIronGrip(Player defender) {
-        if (!Misc.isNPCEntity(defender) && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP)
+        if (!Misc.isNPCEntityExcludingVillagers(defender) && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP)
                 && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_IRON_GRIP, getPlayer())) {
             mcMMO.getNotificationManager().sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Defender");
             mcMMO.getNotificationManager().sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker");

+ 1 - 1
src/main/java/com/gmail/nossr50/util/EventUtils.java

@@ -123,7 +123,7 @@ public class EventUtils {
         Entity entity = entityDamageEvent.getEntity();
 
         //Check to make sure the entity is not an NPC
-        if (Misc.isNPCEntity(entity))
+        if(Misc.isNPCEntityExcludingVillagers(entity))
             return false;
 
         if (!entity.isValid() || !(entity instanceof LivingEntity)) {

+ 16 - 0
src/main/java/com/gmail/nossr50/util/HardcoreManager.java

@@ -5,6 +5,8 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.worldguard.WorldGuardManager;
+import com.gmail.nossr50.worldguard.WorldGuardUtils;
 import org.bukkit.entity.Player;
 
 import java.util.HashMap;
@@ -14,6 +16,13 @@ public final class HardcoreManager {
     }
 
     public static void invokeStatPenalty(Player player) {
+
+        if(WorldGuardUtils.isWorldGuardLoaded()) {
+            if(!WorldGuardManager.getInstance().hasHardcoreFlag(player)) {
+                return;
+            }
+        }
+
         double statLossPercentage = mcMMO.getConfigManager().getConfigHardcore().getDeathPenalty().getPenaltyPercentage();
         int levelThreshold = mcMMO.getConfigManager().getConfigHardcore().getDeathPenalty().getLevelThreshold();
 
@@ -59,6 +68,13 @@ public final class HardcoreManager {
     }
 
     public static void invokeVampirism(Player killer, Player victim) {
+
+        if(WorldGuardUtils.isWorldGuardLoaded()) {
+            if(!WorldGuardManager.getInstance().hasHardcoreFlag(killer) || !WorldGuardManager.getInstance().hasHardcoreFlag(victim)) {
+                return;
+            }
+        }
+
         double vampirismStatLeechPercentage = mcMMO.getConfigManager().getConfigHardcore().getVampirism().getPenaltyPercentage();
         int levelThreshold = mcMMO.getConfigManager().getConfigHardcore().getVampirism().getLevelThreshold();
 

+ 8 - 1
src/main/java/com/gmail/nossr50/util/Misc.java

@@ -37,13 +37,20 @@ public final class Misc {
     private Misc() {
     }
 
-    public static boolean isNPCEntity(Entity entity) {
+    public static boolean isNPCEntityExcludingVillagers(Entity entity) {
         return (entity == null
                 || (entity.hasMetadata("NPC") && !(entity instanceof Villager))
                 || (entity instanceof NPC && !(entity instanceof Villager))
                 || entity.getClass().getName().equalsIgnoreCase("cofh.entity.PlayerFake"));
     }
 
+    public static boolean isNPCIncludingVillagers(Player entity) {
+        return (entity == null
+                || (entity.hasMetadata("NPC"))
+                || (entity instanceof NPC)
+                || entity.getClass().getName().equalsIgnoreCase("cofh.entity.PlayerFake"));
+    }
+
     /**
      * Determine if two locations are near each other.
      *

+ 0 - 13
src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java

@@ -34,19 +34,6 @@ public final class CommandUtils {
         return true;
     }
 
-    public static boolean inspectOffline(CommandSender sender, PlayerProfile profile, boolean hasPermission) {
-        if (unloadedProfile(sender, profile)) {
-            return true;
-        }
-
-        if (!hasPermission && !mcMMO.getConfigManager().getConfigCommands().isAllowInspectOnOfflinePlayers()) {
-            sender.sendMessage(LocaleLoader.getString("Inspect.Offline"));
-            return true;
-        }
-
-        return false;
-    }
-
     public static boolean tooFar(CommandSender sender, Player target, boolean hasPermission) {
         if (sender instanceof Player
                 && mcMMO.getConfigManager().getConfigCommands().isLimitInspectRange()

+ 6 - 6
src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java

@@ -240,7 +240,7 @@ public final class CombatUtils {
         EntityType entityType = damager.getType();
 
         if (target instanceof Player) {
-            if (Misc.isNPCEntity(target)) {
+            if (Misc.isNPCEntityExcludingVillagers(target)) {
                 return;
             }
 
@@ -325,7 +325,7 @@ public final class CombatUtils {
             if (tamer instanceof Player && PrimarySkillType.TAMING.shouldProcess(target)) {
                 Player master = (Player) tamer;
 
-                if (!Misc.isNPCEntity(master) && PrimarySkillType.TAMING.getPermissions(master)) {
+                if (!Misc.isNPCEntityExcludingVillagers(master) && PrimarySkillType.TAMING.getPermissions(master)) {
                     processTamingCombat(target, master, wolf, event);
                 }
             }
@@ -336,11 +336,11 @@ public final class CombatUtils {
             if (projectileSource instanceof Player && PrimarySkillType.ARCHERY.shouldProcess(target)) {
                 Player player = (Player) projectileSource;
 
-                if (!Misc.isNPCEntity(player) && PrimarySkillType.ARCHERY.getPermissions(player)) {
+                if (!Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.ARCHERY.getPermissions(player)) {
                     processArcheryCombat(target, player, event, arrow);
                 }
 
-                if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntity(player) && PrimarySkillType.TAMING.getPermissions(player)) {
+                if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.TAMING.getPermissions(player)) {
                     McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
                     TamingManager tamingManager = mcMMOPlayer.getTamingManager();
                     tamingManager.attackTarget(target);
@@ -508,7 +508,7 @@ public final class CombatUtils {
                 break;
             }
 
-            if (Misc.isNPCEntity(entity) || !(entity instanceof LivingEntity) || !shouldBeAffected(attacker, entity)) {
+            if (Misc.isNPCEntityExcludingVillagers(entity) || !(entity instanceof LivingEntity) || !shouldBeAffected(attacker, entity)) {
                 continue;
             }
 
@@ -830,7 +830,7 @@ public final class CombatUtils {
 
         Player player = (Player) attacker;
 
-        if (Misc.isNPCEntity(player) || Misc.isNPCEntity(target)) {
+        if (Misc.isNPCEntityExcludingVillagers(player) || Misc.isNPCEntityExcludingVillagers(target)) {
             return;
         }
 

+ 1 - 0
src/main/java/com/gmail/nossr50/worldguard/WorldGuardFlags.java

@@ -6,4 +6,5 @@ public class WorldGuardFlags {
     // StateFlag with the name "my-custom-flag", which defaults to "allow"
     public static final StateFlag MCMMO_ENABLE_WG_FLAG = new StateFlag("mcmmo", true);
     public static final StateFlag MCMMO_XP_WG_FLAG = new StateFlag("mcmmo-xp", true);
+    public static final StateFlag MCMMO_HARDCORE_WG_FLAG = new StateFlag("mcmmo-hardcore", true);
 }

+ 18 - 0
src/main/java/com/gmail/nossr50/worldguard/WorldGuardManager.java

@@ -61,6 +61,23 @@ public class WorldGuardManager {
         return query.testState(loc, WorldGuardPlugin.inst().wrapPlayer(player), WorldGuardFlags.MCMMO_XP_WG_FLAG);
     }
 
+    public boolean hasHardcoreFlag(Player player)
+    {
+        if(player == null)
+            return false;
+
+        BukkitPlayer localPlayer = BukkitAdapter.adapt(player);
+        com.sk89q.worldedit.util.Location loc = localPlayer.getLocation();
+
+        //WorldGuardPlugin worldGuard = getWorldGuard();
+        RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
+        RegionQuery query = container.createQuery();
+
+        //ApplicableRegionSet set = query.getApplicableRegions(loc);
+
+        return query.testState(loc, WorldGuardPlugin.inst().wrapPlayer(player), WorldGuardFlags.MCMMO_HARDCORE_WG_FLAG);
+    }
+
     private WorldGuardPlugin getWorldGuard() {
         Plugin plugin = getServer().getPluginManager().getPlugin("WorldGuard");
 
@@ -84,6 +101,7 @@ public class WorldGuardManager {
             registry.register(WorldGuardFlags.MCMMO_XP_WG_FLAG);*/
             registry.register(WorldGuardFlags.MCMMO_ENABLE_WG_FLAG);
             registry.register(WorldGuardFlags.MCMMO_XP_WG_FLAG);
+            registry.register(WorldGuardFlags.MCMMO_HARDCORE_WG_FLAG);
             System.out.println("mcMMO has registered WG flags successfully!");
         } catch (FlagConflictException e) {
             e.printStackTrace();

+ 4 - 1
src/main/resources/locale/locale_zh_CN.properties

@@ -219,7 +219,7 @@ Excavation.Skills.GigaDrillBreaker.Refresh=[[GREEN]]\u4f60\u7684 [[YELLOW]]\u66b
 Excavation.Skills.GigaDrillBreaker.Other.Off=\u66b4\u8d70\u94bb\u5934[[GREEN]] \u7ed3\u675f\u4e86,\u8fdb\u5165\u51b7\u5374 [[YELLOW]]{0}
 Excavation.Skills.GigaDrillBreaker.Other.On=[[GREEN]]{0}[[DARK_GREEN]] \u4f7f\u7528\u4e86 [[RED]]\u66b4\u8d70\u94bb\u5934!
 #\u9493\u9c7c
-Fishing.Scarcity=[[YELLOW]]&o\u8be5\u533a\u57df\u5df2\u7ecf\u8fc7\u5ea6\u6355\u635e, \u8bf7\u6362\u4e00\u4e2a\u65b0\u533a\u57df\u518d\u5c1d\u8bd5.
+Fishing.ScarcityTip=[[YELLOW]]&o\u8be5\u533a\u57df\u5df2\u7ecf\u8fc7\u5ea6\u6355\u635e, \u8bf7\u6362\u4e00\u4e2a\u65b0\u533a\u57df\u518d\u5c1d\u8bd5,\u8bf7\u5230\u81f3\u5c11 {0} \u7684\u65b9\u5757\u4ee5\u5916.
 Fishing.Scared=[[GRAY]]&o\u4e71\u52a8\u4f1a\u5413\u8dd1\u9c7c!
 Fishing.Exhausting=[[RED]]&o\u4e0d\u6b63\u5f53\u4f7f\u7528\u9c7c\u7aff\u4f1a\u52a0\u5267\u8010\u4e45\u7684\u635f\u8017!
 Fishing.LowResources=[[GRAY]]\u4f60\u89c9\u5f97\u8fd9\u5757\u533a\u57df\u4f3c\u4e4e\u6ca1\u6709\u591a\u5c11\u9c7c\u4e86.
@@ -365,6 +365,9 @@ Repair.Arcane.Perfect=[[GREEN]]\u4f60\u6210\u529f\u5730\u4fdd\u7559\u4e86\u8fd9\
 Salvage.Pretty.Name=\u5206\u89e3
 Salvage.SubSkill.UnderstandingTheArt.Name=\u5206\u89e3\u7cbe\u901a
 Salvage.SubSkill.UnderstandingTheArt.Description=\u4f60\u4e0d\u53ea\u662f\u518d\u7ffb\u90bb\u5c45\u7684\u5783\u573e, \u4f60\u662f\u5728\u4fdd\u62a4\u73af\u5883.\n\u589e\u5f3a\u5206\u89e3\u7684\u5404\u79cd\u5c5e\u6027.
+Salvage.SubSkill.ScrapCollector.Name=\u5e9f\u6599\u56de\u6536
+Salvage.SubSkill.ScrapCollector.Description=\u4ece\u7269\u54c1\u4e2d\u5206\u89e3\u51fa\u6750\u6599, \u5b8c\u7f8e\u5206\u89e3\u53d6\u51b3\u4e8e\u6280\u80fd\u548c\u8fd0\u6c14.
+Salvage.SubSkill.ScrapCollector.Stat=\u5e9f\u6599\u56de\u6536: [[GREEN]]\u6700\u591a\u5206\u89e3\u51fa [[YELLOW]]{0}[[GREEN]] \u4e2a\u7269\u54c1. \u5360\u4e00\u4e9b\u8fd0\u6c14\u6210\u5206.
 Salvage.SubSkill.AdvancedSalvage.Name=\u8fdb\u9636\u5206\u89e3
 Salvage.SubSkill.AdvancedSalvage.Description=\u5206\u89e3\u635f\u574f\u7684\u7269\u54c1
 Salvage.SubSkill.ArcaneSalvage.Name=\u5965\u6570\u5206\u89e3

+ 0 - 8
src/main/resources/plugin.yml

@@ -707,7 +707,6 @@ permissions:
             mcmmo.bypass.hardcoremode: true
             mcmmo.commands.inspect.far: true
             mcmmo.commands.inspect.hidden: true
-            mcmmo.commands.inspect.offline: true
     mcmmo.bypass.partylimit:
         default: false
         description: Allows user to bypass party size limitations if present on the server
@@ -782,7 +781,6 @@ permissions:
             mcmmo.commands.defaults: true
             mcmmo.commands.inspect.far: true
             mcmmo.commands.inspect.hidden: true
-            mcmmo.commands.inspect.offline: true
             mcmmo.commands.mcability.others: true
             mcmmo.commands.mcconvert.all: true
             mcmmo.commands.mcchatspy: true
@@ -837,15 +835,12 @@ permissions:
             mcmmo.commands.inspect: true
             mcmmo.commands.inspect.far: true
             mcmmo.commands.inspect.hidden: true
-            mcmmo.commands.inspect.offline: true
     mcmmo.commands.inspect:
         description: Allows access to the inspect command
     mcmmo.commands.inspect.far:
         description: Allows access to the inspect command for far players
     mcmmo.commands.inspect.hidden:
         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.mcability:
         description: Allows access to the mcability command
     mcmmo.commands.mcability.others:
@@ -906,13 +901,10 @@ permissions:
         children:
             mcmmo.commands.mcrank.others: true
             mcmmo.commands.mcrank.others.far: true
-            mcmmo.commands.mcrank.others.offline: true
     mcmmo.commands.mcrank.others:
         description: Allows access to the mcrank command for other players
     mcmmo.commands.mcrank.others.far:
         description: Allows access to the mcrank command for far players
-    mcmmo.commands.mcrank.others.offline:
-        description: Allows access to the mcrank command for offline players
     mcmmo.commands.mcrefresh:
         description: Allows access to the mcrefresh command
     mcmmo.commands.mcrefresh.others: