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

This commit is contained in:
nossr50
2021-03-16 14:18:09 -07:00
28 changed files with 1779 additions and 2993 deletions

View File

@ -22,7 +22,7 @@ public class DatabaseAPI {
* @return true if the player exists in the DB, false if they do not
*/
public boolean doesPlayerExistInDB(UUID uuid) {
PlayerProfile playerProfile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid);
PlayerProfile playerProfile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid, null);
return playerProfile.isLoaded();
}

File diff suppressed because it is too large Load Diff

View File

@ -58,7 +58,7 @@ public class ConvertDatabaseCommand implements CommandExecutor {
}
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
PlayerProfile profile = oldDatabase.queryPlayerDataByUUID(player.getUniqueId());
PlayerProfile profile = oldDatabase.queryPlayerDataByUUID(player.getUniqueId(), null);
if(profile == null)
continue;

View File

@ -23,7 +23,7 @@ public class DatabaseRemovePlayerCommand implements TabExecutor {
String playerName = CommandUtils.getMatchedPlayerName(args[0]);
if (mcMMO.getUserManager().queryPlayer(playerName) == null
&& CommandUtils.hasNoProfile(sender, mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, false))) {
&& CommandUtils.hasNoProfile(sender, mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName))) {
sender.sendMessage(LocaleLoader.getString("Commands.Offline"));
return true;
}

View File

@ -1,14 +1,13 @@
package com.gmail.nossr50.commands.experience;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.commands.CommandUtils;
import com.gmail.nossr50.util.player.UserManager;
import com.google.common.collect.ImmutableList;
import com.neetgames.mcmmo.player.MMOPlayer;
import com.neetgames.mcmmo.player.OnlineMMOPlayer;
import com.neetgames.mcmmo.skill.RootSkill;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@ -16,7 +15,6 @@ import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@ -25,7 +23,7 @@ import java.util.UUID;
public abstract class ExperienceCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
RootSkill rootSkill;
PrimarySkillType skill;
if(args.length < 2) {
return false;
@ -46,27 +44,27 @@ public abstract class ExperienceCommand implements TabExecutor {
return true;
}
rootSkill = mcMMO.p.getSkillRegister().getSkill(args[0]);
skill = PrimarySkillType.getSkill(args[0]);
if (args[1].equalsIgnoreCase("all")) {
rootSkill = null;
skill = null;
}
if (rootSkill != null && rootSkill.isChildSkill()) {
if (skill != null && skill.isChildSkill())
{
sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill"));
return true;
}
//Profile not loaded
Player player = (Player) sender;
OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
if(mmoPlayer == null) {
if(UserManager.getPlayer(sender.getName()) == null)
{
sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
return true;
}
editValues(mmoPlayer, rootSkill, Integer.parseInt(args[1]), isSilent(args));
editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), skill, Integer.parseInt(args[1]), isSilent(args));
return true;
} else if((args.length == 3 && !isSilent(args))
|| (args.length == 4 && isSilent(args))) {
@ -79,13 +77,13 @@ public abstract class ExperienceCommand implements TabExecutor {
return true;
}
rootSkill = mcMMO.p.getSkillRegister().getSkill(args[1]);
skill = PrimarySkillType.getSkill(args[1]);
if (args[1].equalsIgnoreCase("all")) {
rootSkill = null;
skill = null;
}
if (rootSkill != null && rootSkill.isChildSkill())
if (skill != null && skill.isChildSkill())
{
sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill"));
return true;
@ -94,25 +92,31 @@ public abstract class ExperienceCommand implements TabExecutor {
int value = Integer.parseInt(args[2]);
String playerName = CommandUtils.getMatchedPlayerName(args[0]);
OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(playerName);
McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName);
// If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
if (mmoPlayer == null) {
// If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
if (mcMMOPlayer == null) {
UUID uuid = null;
OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(playerName);
if (player != null) {
uuid = player.getUniqueId();
}
PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, uuid, false);
OfflinePlayer offlinePlayer = mcMMO.p.getServer().getOfflinePlayer(playerName);
PlayerProfile profile;
if (CommandUtils.hasNoProfile(sender, profile)) {
return true;
uuid = offlinePlayer.getUniqueId();
profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, null);
//Check loading by UUID
if (CommandUtils.unloadedProfile(sender, profile)) {
//Check loading by name
profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName);
if(CommandUtils.unloadedProfile(sender, profile)) {
return true;
}
}
editValues(null, profile, rootSkill, value, isSilent(args));
editValues(null, profile, skill, value, isSilent(args));
}
else {
editValues(Misc.adaptPlayer(mmoPlayer), mcMMOPlayer.getProfile(), rootSkill, value, isSilent(args));
editValues(mcMMOPlayer.getPlayer(), mcMMOPlayer.getProfile(), skill, value, isSilent(args));
}
handleSenderMessage(sender, playerName, skill);
@ -148,27 +152,27 @@ public abstract class ExperienceCommand implements TabExecutor {
protected abstract boolean permissionsCheckSelf(CommandSender sender);
protected abstract boolean permissionsCheckOthers(CommandSender sender);
protected abstract void handleCommand(Player player, PlayerProfile profile, RootSkill rootSkill, int value);
protected abstract void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill, int value);
protected abstract void handlePlayerMessageAll(Player player, int value, boolean isSilent);
protected abstract void handlePlayerMessageSkill(Player player, int value, RootSkill rootSkill, boolean isSilent);
protected abstract void handlePlayerMessageSkill(Player player, int value, PrimarySkillType skill, boolean isSilent);
private boolean validateArguments(CommandSender sender, String skillName, String value) {
return !(CommandUtils.isInvalidInteger(sender, value) || (!skillName.equalsIgnoreCase("all") && CommandUtils.isInvalidSkill(sender, skillName)));
}
protected static void handleSenderMessage(CommandSender sender, String playerName, RootSkill rootSkill) {
if (rootSkill == null) {
protected static void handleSenderMessage(CommandSender sender, String playerName, PrimarySkillType skill) {
if (skill == null) {
sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName));
}
else {
sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", rootSkill.getName(), playerName));
sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName));
}
}
protected void editValues(@NotNull MMOPlayer mmoPlayer, @Nullable RootSkill rootSkill, int value, boolean isSilent) {
if (primarySkillType == null) {
for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) {
handleCommand(player, profile, type, value);
protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill, int value, boolean isSilent) {
if (skill == null) {
for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) {
handleCommand(player, profile, primarySkillType, value);
}
if (player != null) {
@ -176,10 +180,10 @@ public abstract class ExperienceCommand implements TabExecutor {
}
}
else {
handleCommand(player, profile, primarySkillType, value);
handleCommand(player, profile, skill, value);
if (player != null) {
handlePlayerMessageSkill(player, value, primarySkillType, isSilent);
handlePlayerMessageSkill(player, value, skill, isSilent);
}
}
}

View File

@ -1,14 +1,16 @@
package com.gmail.nossr50.commands.experience;
import com.gmail.nossr50.datatypes.experience.XPGainReason;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.EventUtils;
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 com.neetgames.mcmmo.player.OnlineMMOPlayer;
import com.neetgames.mcmmo.skill.RootSkill;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@ -28,7 +30,7 @@ import java.util.UUID;
public class SkillresetCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
RootSkill rootSkill;
PrimarySkillType skill;
switch (args.length) {
case 1:
if (CommandUtils.noConsoleUsage(sender)) {
@ -45,14 +47,13 @@ public class SkillresetCommand implements TabExecutor {
}
if (args[0].equalsIgnoreCase("all")) {
rootSkill = null;
skill = null;
}
else {
rootSkill = mcMMO.p.getSkillRegister().getSkill(args[0]);
skill = PrimarySkillType.getSkill(args[0]);
}
editValues((Player) sender, mcMMO.getUserManager().queryPlayer(player)
, skill);
editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), skill);
return true;
case 2:
@ -66,32 +67,38 @@ public class SkillresetCommand implements TabExecutor {
}
if (args[1].equalsIgnoreCase("all")) {
rootSkill = null;
skill = null;
}
else {
rootSkill = mcMMO.p.getSkillRegister().getSkill(args[1]);
skill = PrimarySkillType.getSkill(args[1]);
}
String playerName = CommandUtils.getMatchedPlayerName(args[0]);
OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(playerName);
McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName);
// If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
if (mmoPlayer == null) {
// If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
if (mcMMOPlayer == null) {
UUID uuid = null;
OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(playerName);
if (player != null) {
uuid = player.getUniqueId();
}
PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, uuid, false);
uuid = player.getUniqueId();
if (CommandUtils.hasNoProfile(sender, profile)) {
return true;
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName);
//Check loading by UUID
if (CommandUtils.unloadedProfile(sender, profile)) {
//Didn't find it by UUID so try to find it by name
profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName);
//Check if it was present in DB
if(CommandUtils.unloadedProfile(sender, profile)) {
return true;
}
}
editValues(null, profile, skill);
}
else {
editValues(Misc.adaptPlayer(mmoPlayer), mmoPlayer, skill);
editValues(mcMMOPlayer.getPlayer(), mcMMOPlayer.getProfile(), skill);
}
handleSenderMessage(sender, playerName, skill);
@ -115,18 +122,18 @@ public class SkillresetCommand implements TabExecutor {
}
}
protected void handleCommand(Player player, PlayerProfile profile, RootSkill rootSkill) {
int levelsRemoved = profile.getSkillLevel(rootSkill);
float xpRemoved = profile.getSkillXpLevelRaw(rootSkill);
protected void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill) {
int levelsRemoved = profile.getSkillLevel(skill);
float xpRemoved = profile.getSkillXpLevelRaw(skill);
profile.modifySkill(rootSkill, 0);
profile.modifySkill(skill, 0);
if (player == null) {
profile.scheduleAsyncSave();
return;
}
EventUtils.tryLevelChangeEvent(player, rootSkill, levelsRemoved, xpRemoved, false, XPGainReason.COMMAND);
EventUtils.tryLevelChangeEvent(player, skill, levelsRemoved, xpRemoved, false, XPGainReason.COMMAND);
}
protected boolean permissionsCheckSelf(CommandSender sender) {
@ -141,26 +148,26 @@ public class SkillresetCommand implements TabExecutor {
player.sendMessage(LocaleLoader.getString("Commands.Reset.All"));
}
protected void handlePlayerMessageSkill(Player player, RootSkill rootSkill) {
player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", rootSkill.getName()));
protected void handlePlayerMessageSkill(Player player, PrimarySkillType skill) {
player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", skill.getName()));
}
private boolean validateArguments(CommandSender sender, String skillName) {
return skillName.equalsIgnoreCase("all") || !CommandUtils.isInvalidSkill(sender, skillName);
}
protected static void handleSenderMessage(CommandSender sender, String playerName, RootSkill rootSkill) {
if (rootSkill == null) {
protected static void handleSenderMessage(CommandSender sender, String playerName, PrimarySkillType skill) {
if (skill == null) {
sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName));
}
else {
sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", rootSkill.getName(), playerName));
sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName));
}
}
protected void editValues(Player player, PlayerProfile profile, RootSkill rootSkill) {
if (rootSkill == null) {
for (RootSkill rootSkill : PrimarySkillType.NON_CHILD_SKILLS) {
protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill) {
if (skill == null) {
for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) {
handleCommand(player, profile, primarySkillType);
}

View File

@ -1,15 +1,16 @@
package com.gmail.nossr50.commands.player;
import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.commands.CommandUtils;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
import com.google.common.collect.ImmutableList;
import com.neetgames.mcmmo.skill.RootSkill;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
@ -25,19 +26,15 @@ public class InspectCommand implements TabExecutor {
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length == 1) {
String playerName = CommandUtils.getMatchedPlayerName(args[0]);
McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName);
PlayerProfile playerProfile = mcMMO.getUserManager().queryPlayer(playerName);
Player targetPlayer = Bukkit.getPlayer(playerName);
// If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
if (mcMMOPlayer == null) {
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); // Temporary Profile
if(playerProfile == null) {
//TODO: Localize
sender.sendMessage("Data was not found in the database for the given player name!");
return true;
}
if(targetPlayer == null) {
//Target is offline
if (!CommandUtils.isLoaded(sender, profile)) {
return true;
}
if (Config.getInstance().getScoreboardsEnabled()
&& sender instanceof Player
@ -52,42 +49,48 @@ public class InspectCommand implements TabExecutor {
sender.sendMessage(LocaleLoader.getString("Inspect.OfflineStats", playerName));
sender.sendMessage(LocaleLoader.getString("Stats.Header.Gathering"));
for (RootSkill rootSkill : PrimarySkillType.GATHERING_SKILLS) {
for (PrimarySkillType skill : PrimarySkillType.GATHERING_SKILLS) {
sender.sendMessage(CommandUtils.displaySkill(profile, skill));
}
sender.sendMessage(LocaleLoader.getString("Stats.Header.Combat"));
for (RootSkill rootSkill : PrimarySkillType.COMBAT_SKILLS) {
for (PrimarySkillType skill : PrimarySkillType.COMBAT_SKILLS) {
sender.sendMessage(CommandUtils.displaySkill(profile, skill));
}
sender.sendMessage(LocaleLoader.getString("Stats.Header.Misc"));
for (RootSkill rootSkill : PrimarySkillType.MISC_SKILLS) {
for (PrimarySkillType skill : PrimarySkillType.MISC_SKILLS) {
sender.sendMessage(CommandUtils.displaySkill(profile, skill));
}
} else {
if (CommandUtils.hidden(sender, targetPlayer, Permissions.inspectHidden(sender))) {
sender.sendMessage(LocaleLoader.getString("Inspect.Offline"));
return true;
} else if (CommandUtils.tooFar(sender, targetPlayer, Permissions.inspectFar(sender))) {
} else {
Player target = mcMMOPlayer.getPlayer();
boolean isVanished = false;
if (CommandUtils.hidden(sender, target, Permissions.inspectHidden(sender))) {
isVanished = true;
}
//Only distance check players who are online and not vanished
if (!isVanished && CommandUtils.tooFar(sender, target, Permissions.inspectFar(sender))) {
return true;
}
if (Config.getInstance().getScoreboardsEnabled()
&& sender instanceof Player && Config.getInstance().getInspectUseBoard()) {
ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, playerProfile);
&& sender instanceof Player
&& Config.getInstance().getInspectUseBoard()) {
ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, mcMMOPlayer);
if (!Config.getInstance().getInspectUseChat()) {
return true;
}
}
sender.sendMessage(LocaleLoader.getString("Inspect.Stats", targetPlayer.getName()));
CommandUtils.printGatheringSkills(targetPlayer, sender);
CommandUtils.printCombatSkills(targetPlayer, sender);
CommandUtils.printMiscSkills(targetPlayer, sender);
sender.sendMessage(LocaleLoader.getString("Commands.PowerLevel", playerProfile.getExperienceHandler().getPowerLevel()));
sender.sendMessage(LocaleLoader.getString("Inspect.Stats", target.getName()));
CommandUtils.printGatheringSkills(target, sender);
CommandUtils.printCombatSkills(target, sender);
CommandUtils.printMiscSkills(target, sender);
sender.sendMessage(LocaleLoader.getString("Commands.PowerLevel", mcMMOPlayer.getPowerLevel()));
}
return true;

View File

@ -1,16 +1,11 @@
package com.gmail.nossr50.database;
import com.gmail.nossr50.api.exceptions.InvalidSkillException;
import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.datatypes.database.DatabaseType;
import com.gmail.nossr50.datatypes.database.PlayerStat;
import com.gmail.nossr50.datatypes.player.MMODataSnapshot;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.neetgames.mcmmo.exceptions.InvalidSkillException;
import com.neetgames.mcmmo.exceptions.ProfileRetrievalException;
import com.neetgames.mcmmo.player.MMOPlayerData;
import com.neetgames.mcmmo.skill.RootSkill;
import org.apache.commons.lang.NullArgumentException;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -39,35 +34,36 @@ public interface DatabaseManager {
* Remove a user from the database.
*
* @param playerName The name of the user to remove
* @param uuid uuid of player to remove, can be null
* @param uuid player UUID, can be null
* @return true if the user was successfully removed, false otherwise
*/
boolean removeUser(@NotNull String playerName, @Nullable UUID uuid);
boolean removeUser(String playerName, UUID uuid);
/**
* Removes any cache used for faster lookups
* Currently only used for SQL
* @param uuid target UUID to cleanup
*/
void removeCache(@NotNull UUID uuid);
void cleanupUser(UUID uuid);
/**
* Save a user to the database.
*
* @param mmoDataSnapshot Snapshot of player data to save
* @param profile The profile of the player to save
* @return true if successful, false on failure
*/
boolean saveUser(@NotNull MMODataSnapshot mmoDataSnapshot);
boolean saveUser(PlayerProfile profile);
/**
* Retrieve leaderboard info.
* Will never be null but it may be empty
*
* @param rootSkill The skill to retrieve info on
* @param skill The skill to retrieve info on
* @param pageNumber Which page in the leaderboards to retrieve
* @param statsPerPage The number of stats per page
* @return the requested leaderboard information
*/
@NotNull List<PlayerStat> readLeaderboard(@NotNull RootSkill rootSkill, int pageNumber, int statsPerPage) throws InvalidSkillException;
@NotNull List<PlayerStat> readLeaderboard(@Nullable PrimarySkillType skill, int pageNumber, int statsPerPage) throws InvalidSkillException;
/**
* Retrieve rank info into a HashMap from PrimarySkillType to the rank.
@ -78,74 +74,60 @@ public interface DatabaseManager {
* @param playerName The name of the user to retrieve the rankings for
* @return the requested rank information
*/
@NotNull Map<RootSkill, Integer> readRank(@NotNull String playerName);
Map<PrimarySkillType, Integer> readRank(String playerName);
/**
* Add a new user to the database.
* @param playerName The name of the player to be added to the database
*
* @param playerName The name of the player to be added to the database
* @param uuid The uuid of the player to be added to the database
*/
void insertNewUser(@NotNull String playerName, @NotNull UUID uuid) throws Exception;
void newUser(String playerName, UUID uuid);
@Nullable MMOPlayerData queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException;
@NotNull PlayerProfile newUser(@NotNull Player player);
/**
* Load player data (in the form of {@link PlayerProfile}) if player data exists
* Returns null if it doesn't
* Load a player from the database.
*
* @param playerName The name of the player to load from the database
* @return The player's data, or an unloaded PlayerProfile if not found
* and createNew is false
*/
@NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName);
/**
* Load a player from the database.
*
* @param uuid The uuid of the player to load from the database
* @param playerName the current player name for this player
* @return The player's data, or null if not found
* @return The player's data, or an unloaded PlayerProfile if not found
*/
@Nullable MMOPlayerData queryPlayerDataByUUID(@NotNull UUID uuid, @NotNull String playerName) throws ProfileRetrievalException, NullArgumentException;
/**
* Load player data (in the form of {@link PlayerProfile}) if player data exists
* Returns null if it doesn't
*
* @param playerName the current player name for this player
* @return The player's data, or null if not found
*/
@Nullable MMOPlayerData queryPlayerByName(@NotNull String playerName) throws ProfileRetrievalException;
/**
* This method queries the DB for player data for target player
* If it fails to find data for this player, or if it does find data but the data is corrupted,
* it will then proceed to make brand new data for the target player, which will be saved to the DB during the next save
*
* This method will return null for all other errors, which indicates a problem with the DB, in which case mcMMO
* will try to load the player data periodically, but that isn't handled in this method
*
* @param player target player
* @return {@link PlayerProfile} for the target player
*/
@Nullable MMOPlayerData initPlayerProfile(@NotNull Player player) throws Exception;
@NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName);
/**
* Get all users currently stored in the database.
*
* @return list of playernames
*/
@NotNull List<String> getStoredUsers();
List<String> getStoredUsers();
/**
* Convert all users from this database to the provided database using
* {@link #saveUser(MMODataSnapshot)}.
* {@link #saveUser(PlayerProfile)}.
*
* @param destination The DatabaseManager to save to
*/
void convertUsers(@NotNull DatabaseManager destination);
void convertUsers(DatabaseManager destination);
// boolean saveUserUUID(String userName, UUID uuid);
boolean saveUserUUID(String userName, UUID uuid);
// boolean saveUserUUIDs(Map<String, UUID> fetchedUUIDs);
boolean saveUserUUIDs(Map<String, UUID> fetchedUUIDs);
/**
* Retrieve the type of database in use. Custom databases should return CUSTOM.
*
* @return The type of database
*/
@NotNull DatabaseType getDatabaseType();
DatabaseType getDatabaseType();
/**
* Called when the plugin disables

View File

@ -33,6 +33,9 @@ import java.util.concurrent.locks.ReentrantLock;
public final class SQLDatabaseManager extends AbstractDatabaseManager {
private static final String ALL_QUERY_VERSION = "total";
public static final String MOBHEALTHBAR_VARCHAR = "VARCHAR(50)";
public static final String UUID_VARCHAR = "VARCHAR(36)";
public static final String USER_VARCHAR = "VARCHAR(40)";
private final String tablePrefix = Config.getInstance().getMySQLTablePrefix();
private final Map<UUID, Integer> cachedUserIDs = new HashMap<>();
@ -45,6 +48,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
private final ReentrantLock massUpdateLock = new ReentrantLock();
private final String CHARSET_SQL = "utf8mb4"; //This is compliant with UTF-8 while "utf8" is not, confusing but this is how it is.
protected SQLDatabaseManager() {
String connectionString = "jdbc:mysql://" + Config.getInstance().getMySQLServerName()
+ ":" + Config.getInstance().getMySQLServerPort() + "/" + Config.getInstance().getMySQLDatabaseName();
@ -565,6 +570,24 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
}
}
@Override
public @NotNull PlayerProfile newUser(@NotNull Player player) {
try {
Connection connection = getConnection(PoolIdentifier.SAVE);
int id = newUser(connection, player.getName(), player.getUniqueId());
if (id == -1) {
return new PlayerProfile(player.getName(), player.getUniqueId(), false);
} else {
return loadPlayerProfile(player.getUniqueId(), player.getName());
}
} catch (SQLException e) {
e.printStackTrace();
}
return new PlayerProfile(player.getName(), player.getUniqueId(), false);
}
private int newUser(Connection connection, String playerName, UUID uuid) {
ResultSet resultSet = null;
PreparedStatement statement = null;
@ -603,11 +626,26 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
return -1;
}
public @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName) {
try {
return loadPlayerFromDB(null, playerName);
} catch (RuntimeException e) {
e.printStackTrace();
return new PlayerProfile(playerName, false);
}
}
public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) {
return loadPlayerFromDB(uuid, playerName);
@Override
public @Nullable MMOPlayerData queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException {
return loadPlayerProfile(player, player.getName(), player.getUniqueId());
}
private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String playerName) throws RuntimeException {
if(uuid == null && playerName == null) {
throw new RuntimeException("Error looking up player, both UUID and playerName are null and one must not be.");
}
@Override
public @Nullable MMOPlayerData queryPlayerDataByUUID(@NotNull UUID uuid, @NotNull String playerName) throws ProfileRetrievalException, NullArgumentException {
return loadPlayerProfile(null, playerName, uuid);
@ -623,15 +661,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
int id = getUserID(connection, playerName, playerUUID);
if (id == -1) {
// There is no such user
if (player != null) {
id = newUser(connection, playerName, playerUUID);
if (id == -1) {
return null;
}
} else {
return null;
}
// There is no such user
return new PlayerProfile(playerName, false);
}
// There is such a user
writeMissingRows(connection, id);
@ -648,7 +679,10 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
resultSet.close();
statement.close();
if (!playerName.isEmpty() && !playerName.equalsIgnoreCase(name) && playerUUID != null) {
if (playerName != null
&& !playerName.isEmpty()
&& !playerName.equalsIgnoreCase(name)
&& playerUUID != null) {
statement = connection.prepareStatement(
"UPDATE `" + tablePrefix + "users` "
+ "SET user = ? "
@ -685,10 +719,11 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
tryClose(connection);
}
return null;
//Return empty profile
return new PlayerProfile(playerName, false);
}
public void convertUsers(@NotNull DatabaseManager destination) {
public void convertUsers(DatabaseManager destination) {
PreparedStatement statement = null;
Connection connection = null;
ResultSet resultSet = null;
@ -867,7 +902,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
+ "`lastlogin` int(32) unsigned NOT NULL,"
+ "PRIMARY KEY (`id`),"
+ "INDEX(`user`(20) ASC),"
+ "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;");
+ "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=" + CHARSET_SQL + " AUTO_INCREMENT=1;");
tryClose(createStatement);
}
tryClose(resultSet);
@ -881,7 +916,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
+ "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "',"
+ "`scoreboardtips` int(10) NOT NULL DEFAULT '0',"
+ "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=latin1;");
+ "DEFAULT CHARSET=" + CHARSET_SQL + ";");
tryClose(createStatement);
}
tryClose(resultSet);
@ -908,7 +943,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
+ "`tridents` int(32) unsigned NOT NULL DEFAULT '0',"
+ "`crossbows` int(32) unsigned NOT NULL DEFAULT '0',"
+ "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=latin1;");
+ "DEFAULT CHARSET=" + CHARSET_SQL + ";");
tryClose(createStatement);
}
tryClose(resultSet);
@ -936,7 +971,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
+ "`crossbows` int(10) unsigned NOT NULL DEFAULT '0',"
+ "`total` int(10) unsigned NOT NULL DEFAULT '0',"
+ "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=latin1;");
+ "DEFAULT CHARSET=" + CHARSET_SQL + ";");
tryClose(createStatement);
}
tryClose(resultSet);
@ -1010,7 +1045,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
+ "`view_tridents` varchar(40) NOT NULL DEFAULT 'NORMAL',"
+ "`view_crossbows` varchar(40) NOT NULL DEFAULT 'NORMAL',"
+ "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=latin1;");
+ "DEFAULT CHARSET=" + CHARSET_SQL + ";");
tryClose(createStatement);
}
tryClose(resultSet);
@ -1135,6 +1170,11 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
case ADD_UNIQUE_PLAYER_DATA:
checkUpgradeAddUniqueChimaeraWing(statement);
break;
case SQL_CHARSET_UTF8MB4:
updateCharacterSet(statement);
break;
case ADD_SQL_2_2:
checkUpgradeAddTridentsAndCrossbowsSQL(statement);
break;
@ -1142,8 +1182,6 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
break;
}
mcMMO.getUpgradeManager().setUpgradeCompleted(upgrade);
}
catch (SQLException ex) {
printErrors(ex);
@ -1358,6 +1396,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
statement.execute("ALTER TABLE `" + tablePrefix + "users` "
+ "DROP INDEX `user`,"
+ "ADD INDEX `user` (`user`(20) ASC)");
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_NAME_UNIQUENESS);
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
@ -1385,6 +1424,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
private void checkUpgradeAddAlchemy(final Statement statement) throws SQLException {
try {
statement.executeQuery("SELECT `alchemy` FROM `" + tablePrefix + "skills` LIMIT 1");
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_ALCHEMY);
}
catch (SQLException ex) {
mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Alchemy...");
@ -1396,6 +1436,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
private void checkUpgradeAddBlastMiningCooldown(final Statement statement) throws SQLException {
try {
statement.executeQuery("SELECT `blast_mining` FROM `" + tablePrefix + "cooldowns` LIMIT 1");
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_BLAST_MINING_COOLDOWN);
}
catch (SQLException ex) {
mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Blast Mining...");
@ -1406,6 +1447,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
private void checkUpgradeAddUniqueChimaeraWing(final Statement statement) throws SQLException {
try {
statement.executeQuery("SELECT `chimaera_wing` FROM `" + tablePrefix + "cooldowns` LIMIT 1");
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UNIQUE_PLAYER_DATA);
}
catch (SQLException ex) {
mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Chimaera Wing...");
@ -1416,6 +1458,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
private void checkUpgradeAddFishing(final Statement statement) throws SQLException {
try {
statement.executeQuery("SELECT `fishing` FROM `" + tablePrefix + "skills` LIMIT 1");
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_FISHING);
}
catch (SQLException ex) {
mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Fishing...");
@ -1427,6 +1470,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
private void checkUpgradeAddMobHealthbars(final Statement statement) throws SQLException {
try {
statement.executeQuery("SELECT `mobhealthbar` FROM `" + tablePrefix + "huds` LIMIT 1");
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_MOB_HEALTHBARS);
}
catch (SQLException ex) {
mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for mob healthbars...");
@ -1437,6 +1481,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
private void checkUpgradeAddScoreboardTips(final Statement statement) throws SQLException {
try {
statement.executeQuery("SELECT `scoreboardtips` FROM `" + tablePrefix + "huds` LIMIT 1");
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SCOREBOARD_TIPS);
}
catch (SQLException ex) {
mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for scoreboard tips...");
@ -1465,6 +1510,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
}
}
}
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SQL_INDEXES);
}
catch (SQLException ex) {
printErrors(ex);
@ -1494,7 +1541,11 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
mcMMO.p.getLogger().info("Adding UUIDs to mcMMO MySQL user table...");
statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD `uuid` varchar(36) NULL DEFAULT NULL");
statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD UNIQUE INDEX `uuid` (`uuid`) USING BTREE");
new GetUUIDUpdatesRequired().runTaskLaterAsynchronously(mcMMO.p, 100); // wait until after first purge
}
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS);
}
catch (SQLException ex) {
printErrors(ex);
@ -1502,8 +1553,6 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
finally {
tryClose(resultSet);
}
new GetUUIDUpdatesRequired().runTaskLaterAsynchronously(mcMMO.p, 100); // wait until after first purge
}
private class GetUUIDUpdatesRequired extends BukkitRunnable {
@ -1561,6 +1610,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
mcMMO.p.getLogger().info("Removing party name from users table...");
statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` DROP COLUMN `party`");
}
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SQL_PARTY_NAMES);
}
catch (SQLException ex) {
printErrors(ex);
@ -1596,6 +1647,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD INDEX `idx_total` (`total`) USING BTREE");
connection.commit();
}
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SKILL_TOTAL);
}
catch (SQLException ex) {
printErrors(ex);
@ -1627,6 +1680,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
mcMMO.p.getLogger().info("Removing Spout HUD type from huds table...");
statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` DROP COLUMN `hudtype`");
}
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SPOUT);
}
catch (SQLException ex) {
printErrors(ex);
@ -1740,6 +1795,69 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager {
}
}
private void updateCharacterSet(@NotNull Statement statement) {
//TODO: Could check the tables for being latin1 before executing queries but it seems moot because it is likely the same computational effort
/*
The following columns were set to use latin1 historically (now utf8mb4)
column user in <tablePrefix>users
column uuid in <tablePrefix>users
column mobhealthbar in <tablePrefix>huds
*/
//Alter users table
mcMMO.p.getLogger().info("SQL Converting tables from latin1 to utf8mb4");
//Update "user" column
try {
mcMMO.p.getLogger().info("Updating user column to new encoding");
statement.executeUpdate(getUpdateUserInUsersTableSQLQuery());
//Update "uuid" column
mcMMO.p.getLogger().info("Updating user column to new encoding");
statement.executeUpdate(getUpdateUUIDInUsersTableSQLQuery());
//Update "mobhealthbar" column
mcMMO.p.getLogger().info("Updating mobhealthbar column to new encoding");
statement.executeUpdate(getUpdateMobHealthBarInHudsTableSQLQuery());
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.SQL_CHARSET_UTF8MB4);
} catch (SQLException e) {
e.printStackTrace();
}
}
@NotNull
private String getUpdateUserInUsersTableSQLQuery() {
return "ALTER TABLE\n" +
" " + tablePrefix + "users\n" +
" CHANGE user user\n" +
" " + USER_VARCHAR + "\n" +
" CHARACTER SET utf8mb4\n" +
" COLLATE utf8mb4_unicode_ci;";
}
@NotNull
private String getUpdateUUIDInUsersTableSQLQuery() {
return "ALTER TABLE\n" +
" " + tablePrefix + "users\n" +
" CHANGE uuid uuid\n" +
" " + UUID_VARCHAR + "\n" +
" CHARACTER SET utf8mb4\n" +
" COLLATE utf8mb4_unicode_ci;";
}
@NotNull
private String getUpdateMobHealthBarInHudsTableSQLQuery() {
return "ALTER TABLE\n" +
" " + tablePrefix + "huds\n" +
" CHANGE mobhealthbar mobhealthbar\n" +
" " + MOBHEALTHBAR_VARCHAR + "\n" +
" CHARACTER SET utf8mb4\n" +
" COLLATE utf8mb4_unicode_ci;";
}
@Override
public void removeCache(@NotNull UUID uuid) {
cachedUserIDs.remove(uuid);

View File

@ -17,5 +17,6 @@ public enum UpgradeType {
ADD_SQL_2_2,
FIX_SPELLING_NETHERITE_SALVAGE,
FIX_SPELLING_NETHERITE_REPAIR,
FIX_NETHERITE_SALVAGE_QUANTITIES
FIX_NETHERITE_SALVAGE_QUANTITIES,
SQL_CHARSET_UTF8MB4
}

View File

@ -0,0 +1,41 @@
package com.gmail.nossr50.events;
import org.bukkit.entity.Item;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public class McMMOReplaceVanillaTreasureEvent extends Event {
private @NotNull ItemStack replacementItemStack;
private final @NotNull Item originalItem;
public McMMOReplaceVanillaTreasureEvent(@NotNull Item originalItem, @NotNull ItemStack replacementItemStack) {
this.originalItem = originalItem;
this.replacementItemStack = replacementItemStack;
}
/** Rest of file is required boilerplate for custom events **/
private static final @NotNull HandlerList handlers = new HandlerList();
@Override
public @NotNull HandlerList getHandlers() {
return handlers;
}
public static @NotNull HandlerList getHandlerList() {
return handlers;
}
public @NotNull ItemStack getReplacementItemStack() {
return replacementItemStack;
}
public void setReplacementItemStack(@NotNull ItemStack replacementItemStack) {
this.replacementItemStack = replacementItemStack;
}
public @NotNull Item getOriginalItem() {
return originalItem;
}
}

View File

@ -616,6 +616,7 @@ public class EntityListener implements Listener {
switch (cause) {
case CONTACT:
case FIRE:
case HOT_FLOOR:
case LAVA:
if (tamingManager.canUseEnvironmentallyAware()) {
tamingManager.processEnvironmentallyAware(wolf, event.getDamage());

View File

@ -8,6 +8,9 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.neetgames.mcmmo.player.OnlineMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
import com.gmail.nossr50.events.McMMOReplaceVanillaTreasureEvent;
import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.party.ShareHandler;
@ -258,7 +261,7 @@ public class PlayerListener implements Listener {
*
* @param event The event to modify
*/
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onPlayerFishHighest(PlayerFishEvent event) {
/* WORLD BLACKLIST CHECK */
if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld()))
@ -292,12 +295,20 @@ public class PlayerListener implements Listener {
if(event.getCaught() != null) {
Item fishingCatch = (Item) event.getCaught();
if (Config.getInstance(). getFishingOverrideTreasures() &&
if (Config.getInstance().getFishingOverrideTreasures() &&
fishingCatch.getItemStack().getType() != Material.SALMON &&
fishingCatch.getItemStack().getType() != Material.COD &&
fishingCatch.getItemStack().getType() != Material.TROPICAL_FISH &&
fishingCatch.getItemStack().getType() != Material.PUFFERFISH) {
fishingCatch.setItemStack(new ItemStack(Material.SALMON, 1));
ItemStack replacementCatch = new ItemStack(Material.SALMON, 1);
McMMOReplaceVanillaTreasureEvent replaceVanillaTreasureEvent = new McMMOReplaceVanillaTreasureEvent(fishingCatch, replacementCatch);
Bukkit.getPluginManager().callEvent(replaceVanillaTreasureEvent);
//Replace
replacementCatch = replaceVanillaTreasureEvent.getReplacementItemStack();
fishingCatch.setItemStack(replacementCatch);
}
if (Permissions.vanillaXpBoost(player, PrimarySkillType.FISHING)) {

View File

@ -615,7 +615,11 @@ public class mcMMO extends JavaPlugin {
private void scheduleTasks() {
// Periodic save timer (Saves every 10 minutes by default)
long saveIntervalTicks = Config.getInstance().getSaveInterval() * 1200;
long second = 20;
long minute = second * 60;
long saveIntervalTicks = Math.max(minute, Config.getInstance().getSaveInterval() * minute);
new SaveTimerTask().runTaskTimer(this, saveIntervalTicks, saveIntervalTicks);
// Cleanup the backups folder

View File

@ -31,7 +31,7 @@ public class FormulaConversionTask extends BukkitRunnable {
// If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
if (mmoPlayer == null) {
profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, false);
profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName);
if (!profile.isLoaded()) {
mcMMO.p.debug("Profile not loaded.");

View File

@ -99,7 +99,7 @@ public class UUIDUpdateAsyncTask implements Runnable {
position += batch.size();
plugin.getLogger().info(String.format("Conversion progress: %d/%d users", position, userNames.size()));
if (position == userNames.size()) {
if (position +1 >= userNames.size()) {
mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS);
awaiter.countDown();
plugin.getLogger().info("UUID checks completed");

View File

@ -2,12 +2,13 @@ package com.gmail.nossr50.runnables.player;
import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.neetgames.mcmmo.player.MMOPlayerData;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.runnables.commands.McScoreboardKeepTask;
import com.gmail.nossr50.util.EventUtils;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
import org.bukkit.Server;
import org.bukkit.entity.Player;
@ -41,40 +42,46 @@ public class PlayerProfileLoadingTask extends BukkitRunnable {
return;
}
try {
MMOPlayerData mmoPlayerData = mcMMO.getDatabaseManager().queryPlayerDataByPlayer(player);
McMMOPlayer mmoPlayer = new McMMOPlayer(player, player.getUniqueId(), player.getName());
new ApplySuccessfulProfile(new McMMOPlayer(player, )).runTask(mcMMO.p);
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player.getUniqueId(), player.getName());
if(!profile.isLoaded()) {
mcMMO.p.getLogger().info("Creating new data for player: "+player.getName());
//Profile isn't loaded so add as new user
profile = mcMMO.getDatabaseManager().newUser(player);
}
// If successful, schedule the apply
if (profile.isLoaded()) {
new ApplySuccessfulProfile(new McMMOPlayer(player, profile)).runTask(mcMMO.p);
EventUtils.callPlayerProfileLoadEvent(player, profile);
return;
} catch () {
// Print errors to console/logs if we're failing at least 2 times in a row to load the profile
if (attempt >= 3)
{
//Log the error
mcMMO.p.getLogger().severe(LocaleLoader.getString("Profile.Loading.FailureNotice",
player.getName(), String.valueOf(attempt)));
//Notify the admins
mcMMO.p.getServer().broadcast(LocaleLoader.getString("Profile.Loading.FailureNotice", player.getName()), Server.BROADCAST_CHANNEL_ADMINISTRATIVE);
//Notify the player
player.sendMessage(LocaleLoader.getString("Profile.Loading.FailurePlayer", String.valueOf(attempt)).split("\n"));
}
// Increment attempt counter and try
attempt++;
new PlayerProfileLoadingTask(player, attempt).runTaskLaterAsynchronously(mcMMO.p, (100 + (attempt * 100)));
}
// Print errors to console/logs if we're failing at least 2 times in a row to load the profile
if (attempt >= 3)
{
//Log the error
mcMMO.p.getLogger().severe(LocaleLoader.getString("Profile.Loading.FailureNotice",
player.getName(), String.valueOf(attempt)));
//Notify the admins
mcMMO.p.getServer().broadcast(LocaleLoader.getString("Profile.Loading.FailureNotice", player.getName()), Server.BROADCAST_CHANNEL_ADMINISTRATIVE);
//Notify the player
player.sendMessage(LocaleLoader.getString("Profile.Loading.FailurePlayer", String.valueOf(attempt)).split("\n"));
}
// Increment attempt counter and try
attempt++;
new PlayerProfileLoadingTask(player, attempt).runTaskLaterAsynchronously(mcMMO.p, (100 + (attempt * 100)));
}
private class ApplySuccessfulProfile extends BukkitRunnable {
private final McMMOPlayer mmoPlayer;
private final McMMOPlayer mcMMOPlayer;
private ApplySuccessfulProfile(McMMOPlayer mmoPlayer) {
this.mmoPlayer = mmoPlayer;
private ApplySuccessfulProfile(McMMOPlayer mcMMOPlayer) {
this.mcMMOPlayer = mcMMOPlayer;
}
// Synchronized task
@ -86,8 +93,9 @@ public class PlayerProfileLoadingTask extends BukkitRunnable {
return;
}
mcMMO.getUserManager().track(mmoPlayer);
mmoPlayer.actualizeRespawnATS();
mcMMOPlayer.setupPartyData();
UserManager.track(mcMMOPlayer);
mcMMOPlayer.actualizeRespawnATS();
if (Config.getInstance().getScoreboardsEnabled()) {
ScoreboardManager.setupPlayer(player);

View File

@ -138,7 +138,7 @@ public class SmeltingManager extends SkillManager {
ItemStack furnaceResult = furnaceInventory.getResult();
if(furnaceResult == null)
return false;
return true; //This actually means there is nothing yet in the resulting item slot, which means it should always be okay to double smelt
int resultAmount = furnaceResult.getAmount(); //Amount before double smelt
int itemLimit = furnaceResult.getMaxStackSize();

View File

@ -344,6 +344,22 @@ public class ScoreboardManager {
}
}
public static void enablePlayerInspectScoreboard(@NotNull Player player, @NotNull McMMOPlayer targetMcMMOPlayer) {
ScoreboardWrapper wrapper = getWrapper(player);
if(wrapper == null) {
setupPlayer(player);
wrapper = getWrapper(player);
}
if(wrapper != null) {
wrapper.setOldScoreboard();
wrapper.setTypeInspectStats(targetMcMMOPlayer);
changeScoreboard(wrapper, Config.getInstance().getInspectScoreboardTime());
}
}
public static void enablePlayerCooldownScoreboard(Player player) {
ScoreboardWrapper wrapper = getWrapper(player);

View File

@ -24,6 +24,7 @@ import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Score;
import org.bukkit.scoreboard.Scoreboard;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
@ -321,6 +322,17 @@ public class ScoreboardWrapper {
loadObjective(LocaleLoader.getString("Scoreboard.Header.PlayerInspect", targetPlayer));
}
public void setTypeInspectStats(@NotNull McMMOPlayer mcMMOPlayer) {
this.sidebarType = SidebarType.STATS_BOARD;
targetPlayer = mcMMOPlayer.getPlayer().getName();
targetProfile = mcMMOPlayer.getProfile();
targetSkill = null;
leaderboardPage = -1;
loadObjective(LocaleLoader.getString("Scoreboard.Header.PlayerInspect", targetPlayer));
}
public void setTypeCooldowns() {
this.sidebarType = SidebarType.COOLDOWNS_BOARD;

View File

@ -16,9 +16,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
public class TextUtils {
private static @Nullable LegacyComponentSerializer customLegacySerializer;
private TextUtils() {
// We don't want any instances of this class.
}
/**
* Makes a single component from an array of components, can optionally add prefixes and suffixes to come before and after each component
* @param componentsArray target array

View File

@ -11,7 +11,7 @@ public class UpgradeManager extends ConfigLoader {
private final Set<UpgradeType> setNeededUpgrades;
public UpgradeManager() {
super("upgrades.yml");
super("upgrades_overhaul.yml"); //overhaul is added so we don't have any issues with classic
setNeededUpgrades = EnumSet.allOf(UpgradeType.class);

View File

@ -17,7 +17,7 @@ Acrobatics.SubSkill.GracefulRoll.Name = Anmutiges Abrollen
Acrobatics.SubSkill.Roll.Chance = Chance abzurollen: &e{0}
Acrobatics.SubSkill.Roll.Description = Lande gezielt, um deinen Fallschaden zu reduzieren.
Acrobatics.SubSkill.Roll.GraceChance = Chance anmutig abzurollen: &e{0}
Acrobatics.SubSkill.Roll.Mechanics = &7Abrollen ist eine aktive F\u00E4higkeit mit einem passiven Teil. Immer, wenn du Fallschaden nimmst, gibt es eine Chance, dass der Schaden reduziert wird, je nachdem wie hoch dein Akrobatik-Level ist. Auf Level 50 hast du eine &e{0}%&7 Chance, den Schaden zu reduzieren bzw. &e{1}%&7 wenn Anmutiges Abrollen aktiviert wird. Die Erfolgschance steigt linear bis Level &e{2}&7, auf welchem es seinen maximalen Wert erreicht. Jedes Akrobatik-Level gibt dir eine &e{3}%&7 Chance zum erfolgreichen Abrollen. H\u00E4ltst du im Fall die Duck-Taste (standardm\u00E4\u00DFig Shift), aktivierst du Anmutiges Abrollen, welches den Fallschaden um noch mehr Schaden reduzieren oder sogar komplett verhindern kann. Normales Abrollen wird maximal &c{4}&7 Schaden verhindern, Anmutiges Abrollen bis zu &a{5}&7.
Acrobatics.SubSkill.Roll.Mechanics = &7Abrollen ist eine aktive F\u00E4higkeit mit einem passiven Teil. Immer, wenn du Fallschaden nimmst, gibt es eine Chance, dass der Schaden reduziert wird, je nachdem wie hoch dein Akrobatik-Level ist. Auf Level 50 hast du eine &e{0}%&7 Chance, den Schaden zu reduzieren bzw. &e{1}%&7 wenn Anmutiges Abrollen aktiviert wird. Die Erfolgschance steigt linear bis Level &e{2}&7, auf welchem es seinen maximalen Wert erreicht. Jedes Akrobatik-Level gibt dir eine &e{3}%&7 Chance zum erfolgreichen Abrollen. H\u00E4ltst du im Fall die Duck-Taste (standardm\u00E4\u00DFig Shift), aktivierst du Anmutiges Abrollen, welches den Fallschaden auf noch weniger Schaden reduzieren oder sogar komplett verhindern kann. Normales Abrollen wird maximal &c{4}&7 Schaden verhindern, Anmutiges Abrollen bis zu &a{5}&7.
Acrobatics.SubSkill.Roll.Name = Abrollen
Acrobatics.SubSkill.Roll.Stat = Chance abzurollen
Acrobatics.SubSkill.Roll.Stat.Extra = Chance anmutig abzurollen
@ -62,7 +62,7 @@ Axes.Ability.Lower = &7&o**Du senkst deine Axt.**
Axes.Ability.Ready = &a&o**Du hebst deine Axt...**
Axes.Ability.Ready.Extra = &3Du &6hebst&3 deine Axt. &7({0} ist f\u00FCr {1}s pausiert)
Axes.Combat.CritStruck = &cDu wurdest &4schwer &cverwundet!
Axes.Combat.CriticalHit = &4&Kritischer Treffer!
Axes.Combat.CriticalHit = &4Kritischer Treffer!
Axes.Combat.GI.Proc = &a**Du landest einen &2gewaltigen &aSchlag**
Axes.Combat.GI.Struck = &a&o**Von einem Wuchtschlag getroffen**
Axes.Combat.SS.Struck = &a&o**Von einem Sch\u00E4delspalter getroffen**
@ -233,7 +233,7 @@ Commands.Party.PartyFull.InviteAccept = Du kannst der Party &a{0}&c nicht beitre
Commands.Party.Quit = &a- Verlasse deine aktuelle Party.
Commands.Party.Rename = &7Party Name wurde zu &f{0} &7ver\u00E4ndert
Commands.Party.SetSharing = &7Party {0} teilen: &3{1}
Commands.Party.ShareMode = &8Teilen Modus:
Commands.Party.ShareMode = &8Teilen-Modus:
Commands.Party.Status = &8Name: &f{0} {1} &8Level: &3{2}
Commands.Party.Status.Alliance = &8Verb\u00FCndeter: &f{0}
Commands.Party.Teleport = &a- Teleportiere dich zu Partymitgliedern.
@ -242,7 +242,7 @@ Commands.Party.ToggleShareCategory = &7Party Item teilen f\u00FCr&6{0} &7wurde &
Commands.Party.UnlockedFeatures = &8Freigeschaltete Features: &7&o{0}
Commands.Party1 = &a- Erstelle eine neue Party.
Commands.Party2 = &a- Tritt der Party eines Spielers bei.
Commands.PowerLevel = &4GESAMT LEVEL: &a{0}
Commands.PowerLevel = &4Gesamtlevel: &a{0}
Commands.PowerLevel.Capped = &4Gesamtlevel: &a{0} &4H\u00F6chstlevel: &e{1}
Commands.PowerLevel.Leaderboard = --mcMMO&9 Power-Level &eBestenliste--
Commands.Reset = &a- Setze ein Skilllevel auf 0
@ -262,14 +262,14 @@ Commands.Skill.ChildSkill = Unterskills sind f\u00FCr diesen Befehl nicht benutz
Commands.Skill.Invalid = Das ist kein g\u00FCltiger Skillname!
Commands.Skill.Leaderboard = --mcMMO &9{0}&e Bestenliste--
Commands.SkillInfo = &a- Detaillierte Informationen zu einem Skill.
Commands.Stats = &a- Zeige deine Skill Statistiken.
Commands.Stats = &a- Zeige deine Skill-Statistiken.
Commands.Stats.Self.Overhaul = Statistiken
Commands.ToggleAbility = &a- Schalte F\u00E4higkeiten-Aktivierung mit Rechtsklick an oder aus.
Commands.Usage.0 = &cDie korrekte Verwendung ist /{0}
Commands.Usage.1 = &cDie korrekte Verwendung ist /{0} {1}
Commands.Usage.2 = &cDie korrekte Verwendung ist /{0} {1} {2}
Commands.Usage.3 = &cDie korrekte Verwendung ist /{0} {1} {2} {3}
Commands.Usage.3.XP = &cDie korrekte Verwendung ist /{0} {1} {2} {3}&7 (Du kannst auch -s an das Ende des Befehls hinzuf\u00FC"gen, damit der Spieler nicht benachrichtigt wird.)
Commands.Usage.3.XP = &cDie korrekte Verwendung ist /{0} {1} {2} {3}&7 (Du kannst auch -s an das Ende des Befehls hinzuf\u00FCgen, damit der Spieler nicht benachrichtigt wird.)
Commands.Usage.FullClassName = Klassenname
Commands.Usage.Level = Level
Commands.Usage.Message = Nachricht
@ -285,7 +285,7 @@ Commands.XPBar.DisableAll = &6Alle mcMMO Erfahrungsleisten wurden deaktiviert, b
Commands.XPBar.Reset = &6Die Erfahrungsleisten-Einstellungen f\u00FCr mcMMO wurden zur\u00FCckgesetzt.
Commands.XPBar.SettingChanged = &6Die Erfahrungsleisten-Einstellungen f\u00FCr &a{0}&6 wurden gesetzt auf: &a{1}
Commands.XPBar.Usage = Die korrekte Verwendung ist /mmoxpbar <skillname | reset> <show | hide>
Commands.XPGain = &8XP ZUWACHS: &f{0}
Commands.XPGain = &8XP-Zuwachs: &f{0}
Commands.XPGain.Acrobatics = Fallen
Commands.XPGain.Alchemy = Tr\u00E4nke brauen
Commands.XPGain.Archery = Monster angreifen
@ -379,12 +379,12 @@ Excavation.SubSkill.GigaDrillBreaker.Description = Dreifache Droprate, dreifache
Excavation.SubSkill.GigaDrillBreaker.Name = Gigabohrer
Excavation.SubSkill.GigaDrillBreaker.Stat = Gigabohrer-Dauer
Fishing.Ability.Info = Zauberj\u00E4ger: &7 **Verbessert sich mit Schatzj\u00E4ger-Rang**
Fishing.Ability.Info = Zauberj\u00E4ger: &7**Verbessert sich mit Schatzj\u00E4ger-Rang**
Fishing.Ability.Locked.0 = Gesperrt bis Level {0}!
Fishing.Ability.Locked.1 = Gesperrt bis Level {0}!
Fishing.Ability.Locked.2 = Gesperrt bis Level {0}!
Fishing.Ability.TH.Boom = &c&lDeine Angelschnur hat sich in einer &4&lSeemine &c&lverfangen!
Fishing.Ability.TH.MagicFound = &bDu f\u00FChlst etwas Magisches in diesem Fang...
Fishing.Ability.TH.MagicFound = &bDu f\u00FChlst etwas Magisches an diesem Fang...
Fishing.Ability.TH.Poison = &7Irgendetwas stinkt hier...
Fishing.Chance.Raining = &9Regen-Bonus
Fishing.Exhausting = &c&oUnsachgem\u00E4\u00DFe Nutzung der Angelrute f\u00FChrt zu Erm\u00FCdung und Abnutzen der Rute.
@ -557,7 +557,7 @@ Inspect.OfflineStats = mcMMO Stats f\u00FCr Offline-Spieler &e{0}
Inspect.Stats = &amcMMO Stats f\u00FCr &e{0}
Inspect.TooFar = Du bist zu weit entfernt um den Spieler zu inspizieren!
Item.ChimaeraWing.Fail = &c**CHIMAERA FL\u00DCGEL GESCHEITERT!**
Item.ChimaeraWing.Fail = &c**Chimaera Fl\u00FCgel gescheitert!**
Item.ChimaeraWing.Lore = &7Teleportiert dich zu deinem Bett.
Item.ChimaeraWing.Name = Chimaera Fl\u00FCgel
Item.ChimaeraWing.NotEnough = Du ben\u00F6tigst &e{0}&c weitere &6{1}&c!
@ -595,7 +595,7 @@ JSON.JWrapper.Perks.Lucky = {0}% Bessere Chancen
JSON.JWrapper.Target.Block = Block
JSON.JWrapper.Target.Player = Spieler
JSON.JWrapper.Target.Type = Zieltyp:
JSON.LevelRequirement = Level Voraussetzung
JSON.LevelRequirement = Level-Voraussetzung
JSON.Locked = -=[NICHT VERF\u00DCGBAR]=-
JSON.Mining = Bergbau
JSON.Notification.SuperAbility = {0}
@ -610,7 +610,7 @@ JSON.Type.Passive = Passiv
JSON.Type.SuperAbility = Superf\u00E4higkeit
JSON.URL.Discord = Der offizielle (englische) mcMMO Discord Server!
JSON.URL.Patreon = Unterst\u00FCtze die Entwicklung von mcMMO \u00FCber nossr50's Patreon!
JSON.URL.Spigot = Die offizielle mcmmo Spigot Seite
JSON.URL.Spigot = Die offizielle mcMMO Spigot-Seite.
JSON.URL.Translation = \u00DCbersetze mcMMO in andere Sprachen!
JSON.URL.Website = Die offizielle mcMMO Website!
JSON.URL.Wiki = Das offizielle mcMMO Wiki!
@ -666,7 +666,7 @@ Mining.SubSkill.SuperBreaker.Stat = Superbrecher L\u00E4nge
Notifications.Admin.Format.Others = &6(&amcMMO &3Admin&6) &7{0}
Notifications.Admin.Format.Self = &6(&amcMMO&6) &7{0}
Notifications.Admin.XPRate.End.Others = {0} &7hat das Bonuserfahrungs-Event beendet
Notifications.Admin.XPRate.End.Others = {0} &7hat das Bonuserfahrungs-Event beendet.
Notifications.Admin.XPRate.End.Self = &7Du hast das Bonuserfahrungs-Event beendet.
Notifications.Admin.XPRate.Start.Others = {0} &7hat ein Bonuserfahrungs-Event mit einem Faktor von {1}x gestartet.
Notifications.Admin.XPRate.Start.Self = &7Du hast den globalen Erfahrungsraten-Multiplikator auf &6{0}x&7 gesetzt.
@ -715,7 +715,7 @@ Party.Help.0 = &cDie korrekte Benutzung ist &3{0} <spieler> [passwort].
Party.Help.1 = &cUm eine Gruppe zu erstellen, nutze &3{0} <gruppenname> [gruppenpasswort].
Party.Help.10 = &cNutze &3{0} &cum Erfahrungsteilung mit Mitgliedern zu aktivieren.
Party.Help.2 = &cNutze &3{0} &cf\u00FCr mehr Informationen.
Party.Help.3 = &cNutze &3{0} <spieler> [passwort] &czum beitreten oder &3{1} &czum verlassen.
Party.Help.3 = &cNutze &3{0} <spieler> [passwort] &czum Beitreten oder &3{1} &czum Verlassen.
Party.Help.4 = &cUm deine Gruppe zu sperren oder entsperren, nutze &3{0}.
Party.Help.5 = &cUm deine Gruppe per Passwort zu sch\u00FCtzen, nutze &3{0} <passwort>.
Party.Help.6 = &cUm einen Spieler aus deiner Gruppe zu entfernen, nutze &3{0} <spieler>.
@ -823,7 +823,7 @@ Repair.SubSkill.StoneRepair.Description = Repariere Stein-Werkzeuge.
Repair.SubSkill.StoneRepair.Name = Stein-Reparatur ({0}+ SKILL)
Repair.SubSkill.SuperRepair.Description = Doppelte Effektivit\u00E4t.
Repair.SubSkill.SuperRepair.Name = Super-Reparatur
Repair.SubSkill.SuperRepair.Stat = Chance auf Superreparatur
Repair.SubSkill.SuperRepair.Stat = Chance auf Super-Reparatur
Salvage.Ability.Bonus.0 = Fortgeschrittenes Verwerten
Salvage.Ability.Bonus.1 = Max Ertrag {0} Item zerst\u00F6rt
@ -845,7 +845,7 @@ Salvage.Skills.Success = &aItem verwertet!
Salvage.Skills.TooDamaged = &4Das Item ist zu besch\u00E4digt um verwertet zu werden.
Salvage.SubSkill.ArcaneSalvage.Description = Extrahiere Verzauberungen aus Items.
Salvage.SubSkill.ArcaneSalvage.Name = Magische Bergung
Salvage.SubSkill.ArcaneSalvage.Stat = Magische Bergung: &eRank {0}/{1}
Salvage.SubSkill.ArcaneSalvage.Stat = Magische Bergung: &eRang {0}/{1}
Salvage.SubSkill.ScrapCollector.Description = Verschrotte einen Gegenstand, um Materialien zur\u00FCckzugewinnen; eine perfekte Verschrottung erfordert Gl\u00FCck und Geschick.
Salvage.SubSkill.ScrapCollector.Name = Schrottsammler
Salvage.SubSkill.ScrapCollector.Stat = Schrottsammler: &aVerschrotte bis zu &e{0}&a Gegenst\u00E4nde. Hierbei spielt Gl\u00FCck eine gewisse Rolle.
@ -856,13 +856,13 @@ Scoreboard.Header.PlayerCooldowns = mcMMO Abklingzeiten
Scoreboard.Header.PlayerInspect = mcMMO Stats: {0}
Scoreboard.Header.PlayerRank = mcMMO Bestenlisten
Scoreboard.Header.PlayerStats = mcMMO Stats
Scoreboard.Header.PowerLevel = Gesamt Level
Scoreboard.Header.PowerLevel = Gesamt-Level
Scoreboard.Misc.Ability = F\u00E4higkeit
Scoreboard.Misc.Cooldown = &dAbklingzeit
Scoreboard.Misc.CurrentXP = &aAktuelle XP
Scoreboard.Misc.Level = &3Level
Scoreboard.Misc.Overall = &6Insgesamt
Scoreboard.Misc.PowerLevel = &6Gesamt Level
Scoreboard.Misc.PowerLevel = &6Gesamt-Level
Scoreboard.Misc.RemainingXP = Verbliebene XP
Server.ConsoleName = &e[Server]
@ -884,9 +884,9 @@ Skills.TooTired = Du bist zu m\u00FCde um diese F\u00E4higkeit zu verwenden. &e(
Skills.TooTired.Extra = &6{0} &eSuperf\u00E4higkeit CDs - {1}
Skills.TooTired.Named = &7(&6{0}&e {1}s&7)
Smelting.Ability.Locked.0 = Gesperrt bis {0}+ Skill (XP BOOST)
Smelting.Ability.Locked.1 = Gesperrt bis {0}+ Skill (SCHMELZTIEGEL)
Smelting.Effect.4 = Vanilla XP Boost
Smelting.Ability.Locked.0 = Gesperrt bis {0}+ Skill (XP-Boost)
Smelting.Ability.Locked.1 = Gesperrt bis {0}+ Skill (Schmelztiegel)
Smelting.Effect.4 = Vanilla XP-Boost
Smelting.Effect.5 = Erh\u00F6ht die erhaltene Erfahrung beim Schmelzen.
Smelting.Listener = Schmelzen:
Smelting.SkillName = Schmelzen
@ -895,7 +895,7 @@ Smelting.SubSkill.FluxMining.Name = Schmelztiegel
Smelting.SubSkill.FluxMining.Stat = Schmelztiegel Chance
Smelting.SubSkill.FuelEfficiency.Description = Erh\u00F6he die Brenndauer des Brennstoffes in \u00D6fen.
Smelting.SubSkill.FuelEfficiency.Name = Brennstoff Effizienz
Smelting.SubSkill.FuelEfficiency.Stat = Brennstoff Effizienz Multiplikator: &e{0}x
Smelting.SubSkill.FuelEfficiency.Stat = Brennstoff Effizienz-Multiplikator: &e{0}x
Smelting.SubSkill.SecondSmelt.Description = Verdoppelt den Ertrag beim Schmelzen.
Smelting.SubSkill.SecondSmelt.Name = Extra Schmelzung
Smelting.SubSkill.SecondSmelt.Stat = Extra Schmelzung Chance
@ -906,12 +906,12 @@ Smelting.SubSkill.UnderstandingTheArt.Stat = Vanilla Erfahrungsmultiplikator: &e
Stats.Header.Combat = &6-=Kampfskills=-
Stats.Header.Gathering = &6-=Sammelskills=-
Stats.Header.Misc = &6-=Weitere Skills=-
Stats.Own.Stats = &aSkill Statistik
Stats.Own.Stats = &aSkill-Statistik
Swords.Ability.Lower = &7&o**Du senkst dein Sschwert.**
Swords.Ability.Lower = &7&o**Du senkst dein Schwert.**
Swords.Ability.Ready = &a&o**Du hebst dein Schwert...**
Swords.Combat.Bleeding = &a**Gegner blutet**
Swords.Combat.Bleeding.Started = &4 Du blutest!
Swords.Combat.Bleeding.Started = &4Du blutest!
Swords.Combat.Bleeding.Stopped = &7Das Bluten hat &aaufgeh\u00F6rt&7!
Swords.Combat.Counter.Hit = &4Treffer durch Gegenangriff!
Swords.Combat.Countered = &a**Gegenangriff**
@ -920,7 +920,7 @@ Swords.Combat.SS.Struck = &4Getroffen von S\u00E4gezahnschlag!
Swords.Effect.4 = S\u00E4gezahnschlag, Blutung+
Swords.Effect.5 = {0} Ticks Blutung
Swords.Listener = Schwert:
Swords.SkillName = Sschwert
Swords.SkillName = Schwert
Swords.Skills.SS.Off = &a&o**S\u00E4gezahnschlag abgenutzt**
Swords.Skills.SS.On = &a&o**S\u00E4gezahnschlag aktiviert**
Swords.Skills.SS.Other.Off = {0}s &cS\u00E4gezahnschlag&a ist &aabgenutzt.
@ -983,7 +983,7 @@ Taming.SubSkill.Pummel.Name = Pummel
Taming.SubSkill.Pummel.TargetMessage = Du wurdest von einem Wolf zur\u00FCckgeschlagen!
Taming.SubSkill.SharpenedClaws.Description = Schadens-Bonus
Taming.SubSkill.SharpenedClaws.Name = Gesch\u00E4rfte Krallen
Taming.SubSkill.ShockProof.Description = Reduktion von Explosions-Schaden.
Taming.SubSkill.ShockProof.Description = Reduktion von Explosionsschaden.
Taming.SubSkill.ShockProof.Name = Schock-Sicher
Taming.SubSkill.ThickFur.Description = Verminderter Schaden, Feuer-Resistenz
Taming.SubSkill.ThickFur.Name = Dicker Pelz
@ -1030,7 +1030,7 @@ Unarmed.SubSkill.SteelArmStyle.Description = Verst\u00E4rkt deinen Arm mit der Z
Unarmed.SubSkill.SteelArmStyle.Name = St\u00E4hlerner Arm
Unarmed.SubSkill.UnarmedLimitBreak.Description = Durchbreche deine Grenzen!
Unarmed.SubSkill.UnarmedLimitBreak.Name = \u00DCberwindung
Unarmed.SubSkill.UnarmedLimitBreak.Stat = Bonus Schaden durch \u00DCberwindung
Unarmed.SubSkill.UnarmedLimitBreak.Stat = Bonus-Schaden durch \u00DCberwindung
UpdateChecker.NewAvailable = Eine neue Version von mcMMO ist auf Spigot erh\u00E4ltlich!
UpdateChecker.Outdated = Du verwendest eine veraltete mcMMO Version!
@ -1088,9 +1088,9 @@ XPBar.Woodcutting = Holzf\u00E4llen Level: &6{0}
XPRate.Event = &6Es findet derzeit ein Skill-Event statt! Du bekommst aktuell &c{0} &6mal so viel Erfahrung f\u00FCr deine Skills wie normal!
mcMMO.Description = &3\u00DCber das &emcMMO&3 Projekt:,&6mcMMO ist ein &copen source&6 RPG mod erstellt in Februar 2011&6von &9nossr50&6. Das Ziel ist es ein qualitatives RPG Erlebnis zu liefern.,&3Tips:,&6 - &aNutze &c/mcmmo help&a um Befehle zu sehen &6,- &aNutze &c/skillname&a f\u00FCr detaillierte Skill Infos,&3Entwickler:,&6 - &anossr50 &9(Erfinder & Projektleitung),&6 - &aGJ &9(Fr\u00FChere Projektleitung),&6 - &aNuclearW &9(Entwickler),&6 - &abm01 &9(Entwickler),&6 - &aTfT_02 &9(Entwickler),&6 - &aGlitchfinder &9(Entwickler),&6 - &at00thpick1 &9(Entwickler),&6 - &alumis31 &9 (Urspr\u00FCngliche Deutsche \u00DCbersetzung),&6 - &aOverCrave &9 (Neue Deutsche \u00DCbersetzung & \u00DCberarbeitung),&3N\u00FCtzliche Links:,&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 Bug Reporting,&6 - &ahttps://discord.gg/EJGVanb &6 Offizieller Discord (Englisch)
mcMMO.Description = &3\u00DCber das &emcMMO&3 Projekt: &6mcMMO ist ein &copen source&6 RPG-Mod erstellt im Februar 2011 &6von &9nossr50&6. Das Ziel ist es ein qualitatives RPG Erlebnis zu liefern. &3Tipps:&6 - &aNutze &c/mcmmo help&a um Befehle zu sehen, &6 - &aNutze &c/skillname&a f\u00FCr detaillierte Skill Infos, &3Entwickler:&6 - &anossr50 &9(Erfinder & Projektleitung),&6 - &aGJ &9(Fr\u00FChere Projektleitung),&6 - &aNuclearW &9(Entwickler),&6 - &abm01 &9(Entwickler),&6 - &aTfT_02 &9(Entwickler),&6 - &aGlitchfinder &9(Entwickler),&6 - &at00thpick1 &9(Entwickler),&6 - &alumis31 &9(Urspr\u00FCngliche Deutsche \u00DCbersetzung),&6 - &aOverCrave &9(Neue Deutsche \u00DCbersetzung & \u00DCberarbeitung),&6 - &aAnseba &9(\u00DCberarbeitung Deutsche \u00DCbersetzung), &3N\u00FCtzliche Links:&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 Bug Reporting,&6 - &ahttps://discord.gg/EJGVanb &6 Offizieller Discord (Englisch)
mcMMO.Description.FormerDevs = &3Ehemalige Entwickler: &aGJ, NuclearW, bm01, TfT_02, Glitchfinder
mcMMO.NoInvites = &cDu hast zurzeit keine Einladungen
mcMMO.NoInvites = &cDu hast zurzeit keine Einladungen.
mcMMO.NoPermission = &4Unzureichende Berechtigungen.
mcMMO.NoSkillNote = &8Wenn du keinen Zugriff auf einen Skill hast wird er hier nicht angezeigt.
mcMMO.Template.Prefix = &6(&amcMMO&6) &7{0}

View File

@ -12,3 +12,4 @@ Upgrades_Finished:
FIX_NETHERITE_SALVAGE_QUANTITIES: false
ADD_SQL_2_2: false
ADD_UUIDS: false
SQL_CHARSET_UTF8MB4: false

View File

@ -0,0 +1,32 @@
package com.gmail.nossr50.util.text;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import org.junit.Assert;
import org.junit.Test;
/**
* This Unit Test checks if Adventure was set up correctly and works as expected.
* Normally we can rely on this to be the case. However sometimes our dependencies
* lack so far behind that things stop working correctly.
* This test ensures that basic functionality is guaranteed to work as we would expect.
*
* See https://github.com/mcMMO-Dev/mcMMO/pull/4446
*
*/
public class TextUtilsTest {
@Test
public void testColorizeText() {
String inputText = "&4This text should be red.";
/*
* If this method raises an exception, we know Adventure is not set up correctly.
* This will also make the test fail and warn us about it.
*/
TextComponent component = TextUtils.colorizeText(inputText);
Assert.assertEquals("Looks like Adventure is not working correctly.",
NamedTextColor.DARK_RED, component.color());
}
}