mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2024-11-26 07:06:45 +01:00
SQLDatabaseManager optimizations, async profile loading -t00thpick1, zreed
This commit changes our shared connection into a connection pool utility to prevent thread locks from multiple actions attempting to access the database at the same time. In additon, profile loading has been moved off the main thread at login time, to allieviate the performance issues caused by it. Fixes #2138, Fixes #2119, Fixes #1982, Fixes #1953
This commit is contained in:
parent
c10525ada9
commit
857e12b96e
@ -10,6 +10,7 @@ Key:
|
||||
Version 1.5.01-dev
|
||||
+ Added new child skill; Salvage
|
||||
+ Added UUID support!
|
||||
+ Added SQL connection pooling and async loading!
|
||||
+ Added new feature to Herbalism. Instantly-regrown crops are protected from being broken for 1 second
|
||||
+ Added option to config.yml to show the /mcstats scoreboard automatically after logging in
|
||||
+ Added option to config.yml for Alchemy. Skills.Alchemy.Prevent_Hopper_Transfer_Bottles
|
||||
|
15
pom.xml
15
pom.xml
@ -76,6 +76,8 @@
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>com.turt2live.metrics:MetricsExtension</include>
|
||||
<include>commons-logging:commons-logging</include>
|
||||
<include>net.snaq:dbpool</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<relocations>
|
||||
@ -83,6 +85,14 @@
|
||||
<pattern>com.turt2live.metrics</pattern>
|
||||
<shadedPattern>com.gmail.nossr50.metrics.mcstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.apache.commons.logging</pattern>
|
||||
<shadedPattern>com.gmail.nossr50.commons.logging</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>net.snaq</pattern>
|
||||
<shadedPattern>com.gmail.nossr50.dbpool</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
@ -136,6 +146,11 @@
|
||||
<artifactId>MetricsExtension</artifactId>
|
||||
<version>0.0.5-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.snaq</groupId>
|
||||
<artifactId>dbpool</artifactId>
|
||||
<version>5.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
|
@ -930,7 +930,7 @@ public final class ExperienceAPI {
|
||||
}
|
||||
|
||||
private static PlayerProfile getOfflineProfile(UUID uuid) {
|
||||
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, false);
|
||||
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid);
|
||||
|
||||
if (!profile.isLoaded()) {
|
||||
throw new InvalidPlayerException();
|
||||
@ -942,7 +942,7 @@ public final class ExperienceAPI {
|
||||
@Deprecated
|
||||
private static PlayerProfile getOfflineProfile(String playerName) {
|
||||
UUID uuid = mcMMO.p.getServer().getOfflinePlayer(playerName).getUniqueId();
|
||||
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, false);
|
||||
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid);
|
||||
|
||||
if (!profile.isLoaded()) {
|
||||
throw new InvalidPlayerException();
|
||||
|
@ -12,6 +12,7 @@ import com.gmail.nossr50.datatypes.database.DatabaseType;
|
||||
import com.gmail.nossr50.datatypes.player.PlayerProfile;
|
||||
import com.gmail.nossr50.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.runnables.database.DatabaseConversionTask;
|
||||
import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
|
||||
import com.gmail.nossr50.util.player.UserManager;
|
||||
|
||||
public class ConvertDatabaseCommand implements CommandExecutor {
|
||||
@ -55,13 +56,13 @@ public class ConvertDatabaseCommand implements CommandExecutor {
|
||||
UserManager.clearAll();
|
||||
|
||||
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
|
||||
PlayerProfile profile = oldDatabase.loadPlayerProfile(player.getUniqueId(), false);
|
||||
PlayerProfile profile = oldDatabase.loadPlayerProfile(player.getUniqueId());
|
||||
|
||||
if (profile.isLoaded()) {
|
||||
mcMMO.getDatabaseManager().saveUser(profile);
|
||||
}
|
||||
|
||||
UserManager.addUser(player);
|
||||
new PlayerProfileLoadingTask(player).runTaskTimerAsynchronously(mcMMO.p, 1, 20); // 1 Tick delay to ensure the player is marked as online before we begin loading
|
||||
}
|
||||
|
||||
new DatabaseConversionTask(oldDatabase, sender, previousType.toString(), newType.toString()).runTaskAsynchronously(mcMMO.p);
|
||||
|
@ -9,6 +9,7 @@ import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.datatypes.experience.FormulaType;
|
||||
import com.gmail.nossr50.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.runnables.database.FormulaConversionTask;
|
||||
import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
|
||||
import com.gmail.nossr50.util.player.UserManager;
|
||||
|
||||
public class ConvertExperienceCommand implements CommandExecutor {
|
||||
@ -37,7 +38,7 @@ public class ConvertExperienceCommand implements CommandExecutor {
|
||||
new FormulaConversionTask(sender, newType).runTaskLater(mcMMO.p, 1);
|
||||
|
||||
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
|
||||
UserManager.addUser(player);
|
||||
new PlayerProfileLoadingTask(player).runTaskTimerAsynchronously(mcMMO.p, 1, 20); // 1 Tick delay to ensure the player is marked as online before we begin loading
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -232,6 +232,7 @@ public class Config extends AutoUpdateConfigLoader {
|
||||
/* General Settings */
|
||||
public String getLocale() { return config.getString("General.Locale", "en_us"); }
|
||||
public boolean getMOTDEnabled() { return config.getBoolean("General.MOTD_Enabled", true); }
|
||||
public boolean getShowProfileLoadedMessage() { return config.getBoolean("General.Show_Profile_Loaded", true); }
|
||||
public boolean getDonateMessageEnabled() { return config.getBoolean("Commands.mcmmo.Donate_Message", true); }
|
||||
public int getSaveInterval() { return config.getInt("General.Save_Interval", 10); }
|
||||
public boolean getStatsTrackingEnabled() { return config.getBoolean("General.Stats_Tracking", true); }
|
||||
@ -313,6 +314,8 @@ public class Config extends AutoUpdateConfigLoader {
|
||||
public int getMySQLServerPort() { return config.getInt("MySQL.Server.Port", 3306); }
|
||||
public String getMySQLServerName() { return config.getString("MySQL.Server.Address", "localhost"); }
|
||||
public String getMySQLUserPassword() { return getStringIncludingInts("MySQL.Database.User_Password"); }
|
||||
public int getMySQLMaxConnections() { return config.getInt("MySQL.Database.MaxConnections"); }
|
||||
public int getMySQLMaxPoolSize() { return config.getInt("MySQL.Database.MaxPoolSize"); }
|
||||
|
||||
private String getStringIncludingInts(String key) {
|
||||
String str = config.getString(key);
|
||||
|
@ -73,7 +73,7 @@ public interface DatabaseManager {
|
||||
/**
|
||||
* Load a player from the database.
|
||||
*
|
||||
* @deprecated replaced by {@link #loadPlayerProfile(UUID uuid, boolean createNew)}
|
||||
* @deprecated replaced by {@link #loadPlayerProfile(String playerName, UUID uuid, boolean createNew)}
|
||||
*
|
||||
* @param playerName The name of the player to load from the database
|
||||
* @param createNew Whether to create a new record if the player is not
|
||||
@ -88,12 +88,9 @@ public interface DatabaseManager {
|
||||
* Load a player from the database.
|
||||
*
|
||||
* @param uuid The uuid of the player to load from the database
|
||||
* @param createNew Whether to create a new record if the player is not
|
||||
* found
|
||||
* @return The player's data, or an unloaded PlayerProfile if not found
|
||||
* and createNew is false
|
||||
*/
|
||||
public PlayerProfile loadPlayerProfile(UUID uuid, boolean createNew);
|
||||
public PlayerProfile loadPlayerProfile(UUID uuid);
|
||||
|
||||
/**
|
||||
* Load a player from the database. Attempt to use uuid, fall back on playername
|
||||
@ -132,4 +129,9 @@ public interface DatabaseManager {
|
||||
* @return The type of database
|
||||
*/
|
||||
public DatabaseType getDatabaseType();
|
||||
|
||||
/**
|
||||
* Called when the plugin disables
|
||||
*/
|
||||
public void onDisable();
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.gmail.nossr50.database;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
@ -10,6 +9,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -98,8 +98,22 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
tryClose(out);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,8 +178,22 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
tryClose(out);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,8 +231,22 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
tryClose(out);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,8 +336,22 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
tryClose(out);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -311,7 +367,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
public Map<SkillType, Integer> readRank(String playerName) {
|
||||
updateLeaderboards();
|
||||
|
||||
Map<SkillType, Integer> skills = new HashMap<SkillType, Integer>();
|
||||
Map<SkillType, Integer> skills = new EnumMap<SkillType, Integer>(SkillType.class);
|
||||
|
||||
for (SkillType skill : SkillType.NON_CHILD_SKILLS) {
|
||||
skills.put(skill, getPlayerRank(playerName, playerStatHash.get(skill)));
|
||||
@ -381,18 +437,25 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
tryClose(out);
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public PlayerProfile loadPlayerProfile(String playerName, boolean create) {
|
||||
return loadPlayerProfile(playerName, "", create);
|
||||
return loadPlayerProfile(playerName, "", false);
|
||||
}
|
||||
|
||||
public PlayerProfile loadPlayerProfile(UUID uuid, boolean create) {
|
||||
return loadPlayerProfile("", uuid.toString(), create);
|
||||
public PlayerProfile loadPlayerProfile(UUID uuid) {
|
||||
return loadPlayerProfile("", uuid.toString(), false);
|
||||
}
|
||||
|
||||
public PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean create) {
|
||||
@ -448,7 +511,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -491,7 +554,14 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -532,8 +602,22 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
tryClose(out);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -573,8 +657,22 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
tryClose(out);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,7 +699,14 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return users;
|
||||
@ -671,7 +776,14 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " during user " + playerName + " (Are you sure you formatted it correctly?) " + e.toString());
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -897,8 +1009,22 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
|
||||
}
|
||||
finally {
|
||||
tryClose(in);
|
||||
tryClose(out);
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -923,18 +1049,6 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void tryClose(Closeable c) {
|
||||
if (c == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
c.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Integer getPlayerRank(String playerName, List<PlayerStat> statsList) {
|
||||
if (statsList == null) {
|
||||
return null;
|
||||
@ -967,8 +1081,8 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
|
||||
private PlayerProfile loadFromLine(String[] character) {
|
||||
Map<SkillType, Integer> skills = getSkillMapFromLine(character); // Skill levels
|
||||
Map<SkillType, Float> skillsXp = new HashMap<SkillType, Float>(); // Skill & XP
|
||||
Map<AbilityType, Integer> skillsDATS = new HashMap<AbilityType, Integer>(); // Ability & Cooldown
|
||||
Map<SkillType, Float> skillsXp = new EnumMap<SkillType, Float>(SkillType.class); // Skill & XP
|
||||
Map<AbilityType, Integer> skillsDATS = new EnumMap<AbilityType, Integer>(AbilityType.class); // Ability & Cooldown
|
||||
MobHealthbarType mobHealthbarType;
|
||||
|
||||
// TODO on updates, put new values in a try{} ?
|
||||
@ -1019,7 +1133,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
}
|
||||
|
||||
private Map<SkillType, Integer> getSkillMapFromLine(String[] character) {
|
||||
Map<SkillType, Integer> skills = new HashMap<SkillType, Integer>(); // Skill & Level
|
||||
Map<SkillType, Integer> skills = new EnumMap<SkillType, Integer>(SkillType.class); // Skill & Level
|
||||
|
||||
skills.put(SkillType.TAMING, Integer.valueOf(character[24]));
|
||||
skills.put(SkillType.MINING, Integer.valueOf(character[1]));
|
||||
@ -1041,4 +1155,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
|
||||
public DatabaseType getDatabaseType() {
|
||||
return DatabaseType.FLATFILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() { }
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,12 +7,10 @@ import java.util.UUID;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.config.AdvancedConfig;
|
||||
@ -93,13 +91,13 @@ public class McMMOPlayer {
|
||||
private boolean isUsingUnarmed;
|
||||
private final FixedMetadataValue playerMetadata;
|
||||
|
||||
public McMMOPlayer(Player player) {
|
||||
public McMMOPlayer(Player player, PlayerProfile profile) {
|
||||
String playerName = player.getName();
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
this.player = player;
|
||||
playerMetadata = new FixedMetadataValue(mcMMO.p, playerName);
|
||||
profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, uuid, true);
|
||||
this.profile = profile;
|
||||
party = PartyManager.getPlayerParty(playerName);
|
||||
ptpRecord = new PartyTeleportRecord();
|
||||
|
||||
@ -130,70 +128,6 @@ public class McMMOPlayer {
|
||||
for (ToolType toolType : ToolType.values()) {
|
||||
toolMode.put(toolType, false);
|
||||
}
|
||||
|
||||
if (!profile.isLoaded()) {
|
||||
mcMMO.p.getLogger().warning("Unable to load the PlayerProfile for " + playerName + ". Will retry over the next several seconds.");
|
||||
new RetryProfileLoadingTask().runTaskTimerAsynchronously(mcMMO.p, 11L, 31L);
|
||||
}
|
||||
}
|
||||
|
||||
private class RetryProfileLoadingTask extends BukkitRunnable {
|
||||
private static final int MAX_TRIES = 5;
|
||||
private final String playerName = McMMOPlayer.this.player.getName();
|
||||
private final UUID uniqueId = McMMOPlayer.this.player.getUniqueId();
|
||||
private int attempt = 0;
|
||||
|
||||
// WARNING: ASYNC TASK
|
||||
// DO NOT MODIFY THE McMMOPLAYER FROM THIS CODE
|
||||
@Override
|
||||
public void run() {
|
||||
// Quit if they logged out
|
||||
if (!player.isOnline()) {
|
||||
mcMMO.p.getLogger().info("Aborting profile loading recovery for " + playerName + " - player logged out");
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the message that we're doing the recovery
|
||||
if (attempt == 0) {
|
||||
player.sendMessage(LocaleLoader.getString("Recovery.Notice"));
|
||||
}
|
||||
|
||||
// Increment attempt counter and try
|
||||
attempt++;
|
||||
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uniqueId, true);
|
||||
// If successful, schedule the apply
|
||||
if (profile.isLoaded()) {
|
||||
new ApplySuccessfulProfile(profile).runTask(mcMMO.p);
|
||||
player.sendMessage(LocaleLoader.getString("Recovery.Success"));
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've failed five times, give up
|
||||
if (attempt >= MAX_TRIES) {
|
||||
mcMMO.p.getLogger().severe("Giving up on attempting to load the PlayerProfile for " + playerName);
|
||||
mcMMO.p.getServer().broadcast(LocaleLoader.getString("Recovery.AdminFailureNotice", playerName), Server.BROADCAST_CHANNEL_ADMINISTRATIVE);
|
||||
player.sendMessage(LocaleLoader.getString("Recovery.Failure").split("\n"));
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ApplySuccessfulProfile extends BukkitRunnable {
|
||||
private final PlayerProfile profile;
|
||||
|
||||
private ApplySuccessfulProfile(PlayerProfile profile) {
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
// Synchronized task
|
||||
// No database access permitted
|
||||
@Override
|
||||
public void run() {
|
||||
McMMOPlayer.this.profile = profile;
|
||||
}
|
||||
}
|
||||
|
||||
public AcrobaticsManager getAcrobaticsManager() {
|
||||
|
@ -41,7 +41,7 @@ import com.gmail.nossr50.datatypes.skills.AbilityType;
|
||||
import com.gmail.nossr50.datatypes.skills.SkillType;
|
||||
import com.gmail.nossr50.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.party.ShareHandler;
|
||||
import com.gmail.nossr50.runnables.commands.McScoreboardKeepTask;
|
||||
import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
|
||||
import com.gmail.nossr50.runnables.skills.BleedTimerTask;
|
||||
import com.gmail.nossr50.skills.fishing.FishingManager;
|
||||
import com.gmail.nossr50.skills.herbalism.HerbalismManager;
|
||||
@ -387,9 +387,7 @@ public class PlayerListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
McMMOPlayer mcMMOPlayer = UserManager.addUser(player);
|
||||
mcMMOPlayer.actualizeRespawnATS();
|
||||
ScoreboardManager.setupPlayer(player);
|
||||
new PlayerProfileLoadingTask(player).runTaskTimerAsynchronously(mcMMO.p, 1, 20); // 1 Tick delay to ensure the player is marked as online before we begin loading
|
||||
|
||||
if (Config.getInstance().getMOTDEnabled() && Permissions.motd(player)) {
|
||||
Motd.displayAll(player);
|
||||
@ -403,11 +401,6 @@ public class PlayerListener implements Listener {
|
||||
player.sendMessage(LocaleLoader.getString("UpdateChecker.Outdated"));
|
||||
player.sendMessage(LocaleLoader.getString("UpdateChecker.NewAvailable"));
|
||||
}
|
||||
|
||||
if (Config.getInstance().getShowStatsAfterLogin()) {
|
||||
ScoreboardManager.enablePlayerStatsScoreboard(player);
|
||||
new McScoreboardKeepTask(player).runTaskLater(mcMMO.p, 1 * Misc.TICK_CONVERSION_FACTOR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,6 +38,7 @@ import com.gmail.nossr50.runnables.UpdaterResultAsyncTask;
|
||||
import com.gmail.nossr50.runnables.backups.CleanBackupsTask;
|
||||
import com.gmail.nossr50.runnables.database.UserPurgeTask;
|
||||
import com.gmail.nossr50.runnables.party.PartyAutoKickTask;
|
||||
import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
|
||||
import com.gmail.nossr50.runnables.player.PowerLevelUpdatingTask;
|
||||
import com.gmail.nossr50.runnables.skills.BleedTimerTask;
|
||||
import com.gmail.nossr50.skills.alchemy.Alchemy;
|
||||
@ -167,8 +168,7 @@ public class mcMMO extends JavaPlugin {
|
||||
holidayManager = new HolidayManager();
|
||||
|
||||
for (Player player : getServer().getOnlinePlayers()) {
|
||||
UserManager.addUser(player); // In case of reload add all users back into UserManager
|
||||
ScoreboardManager.setupPlayer(player);
|
||||
new PlayerProfileLoadingTask(player).runTaskTimerAsynchronously(mcMMO.p, 1, 20); // 1 Tick delay to ensure the player is marked as online before we begin loading
|
||||
}
|
||||
|
||||
debug("Version " + getDescription().getVersion() + " is enabled!");
|
||||
@ -242,6 +242,7 @@ public class mcMMO extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
databaseManager.onDisable();
|
||||
debug("Was disabled."); // How informative!
|
||||
}
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
package com.gmail.nossr50.runnables.database;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.gmail.nossr50.database.SQLDatabaseManager;
|
||||
|
||||
/**
|
||||
* This task is in charge of sending a MySQL ping over the MySQL connection
|
||||
* every hour to prevent the connection from timing out and losing players'
|
||||
* data when they join.
|
||||
* <p/>
|
||||
* A WeakReference is used to keep the database instance, because
|
||||
* {@link com.gmail.nossr50.commands.database.ConvertDatabaseCommand database
|
||||
* conversion} may create a SQLDatabaseManager that will be thrown out. If a
|
||||
* normal reference was used, the conversion would cause a combined data and
|
||||
* resource leak through this task.
|
||||
*/
|
||||
public class SQLDatabaseKeepaliveTask extends BukkitRunnable {
|
||||
WeakReference<SQLDatabaseManager> databaseInstance;
|
||||
|
||||
public SQLDatabaseKeepaliveTask(SQLDatabaseManager dbman) {
|
||||
databaseInstance = new WeakReference<SQLDatabaseManager>(dbman);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
SQLDatabaseManager dbman = databaseInstance.get();
|
||||
if (dbman != null) {
|
||||
dbman.checkConnected();
|
||||
}
|
||||
else {
|
||||
// This happens when the database was started for a conversion,
|
||||
// or discarded by its creator for any other reason. If this code
|
||||
// was not present, we would leak the connection resources.
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package com.gmail.nossr50.runnables.database;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.database.SQLDatabaseManager;
|
||||
import com.gmail.nossr50.util.player.UserManager;
|
||||
|
||||
public class SQLReconnectTask extends BukkitRunnable {
|
||||
@Override
|
||||
public void run() {
|
||||
if (((SQLDatabaseManager) mcMMO.getDatabaseManager()).checkConnected()) {
|
||||
UserManager.saveAll(); // Save all profiles
|
||||
UserManager.clearAll(); // Clear the profiles
|
||||
|
||||
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
|
||||
UserManager.addUser(player); // Add in new profiles, forcing them to 'load' again from MySQL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package com.gmail.nossr50.runnables.database;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.util.uuid.UUIDFetcher;
|
||||
|
||||
public class UUIDFetcherRunnable extends BukkitRunnable {
|
||||
private List<String> names;
|
||||
|
||||
public UUIDFetcherRunnable(List<String> names) {
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
public UUIDFetcherRunnable(String name) {
|
||||
this.names = new ArrayList<String>();
|
||||
this.names.add(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Map<String, UUID> returns = new UUIDFetcher(this.names).call();
|
||||
new CacheReturnedNames(returns).runTask(mcMMO.p);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private class CacheReturnedNames extends BukkitRunnable {
|
||||
private Map<String, UUID> returns;
|
||||
|
||||
public CacheReturnedNames(Map<String, UUID> returns) {
|
||||
this.returns = returns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (Entry<String, UUID> entry : this.returns.entrySet()) {
|
||||
mcMMO.getDatabaseManager().saveUserUUID(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package com.gmail.nossr50.runnables.player;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.config.Config;
|
||||
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
|
||||
import com.gmail.nossr50.datatypes.player.PlayerProfile;
|
||||
import com.gmail.nossr50.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.runnables.commands.McScoreboardKeepTask;
|
||||
import com.gmail.nossr50.util.Misc;
|
||||
import com.gmail.nossr50.util.player.UserManager;
|
||||
import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
|
||||
|
||||
public class PlayerProfileLoadingTask extends BukkitRunnable {
|
||||
private static final int MAX_TRIES = 5;
|
||||
private final Player player;
|
||||
private int attempt = 0;
|
||||
private ReentrantLock lock = new ReentrantLock();
|
||||
private boolean cancelled = false;
|
||||
|
||||
public PlayerProfileLoadingTask(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
// WARNING: ASYNC TASK
|
||||
// DO NOT MODIFY THE McMMOPLAYER FROM THIS CODE
|
||||
@Override
|
||||
public void run() {
|
||||
lock.lock();
|
||||
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Quit if they logged out
|
||||
if (!player.isOnline()) {
|
||||
mcMMO.p.getLogger().info("Aborting profile loading recovery for " + player.getName() + " - player logged out");
|
||||
this.cancel();
|
||||
cancelled = true;
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
// Increment attempt counter and try
|
||||
attempt++;
|
||||
|
||||
PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player.getName(), player.getUniqueId(), true);
|
||||
// If successful, schedule the apply
|
||||
if (profile.isLoaded()) {
|
||||
new ApplySuccessfulProfile(profile).runTask(mcMMO.p);
|
||||
this.cancel();
|
||||
cancelled = true;
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've failed five times, give up
|
||||
if (attempt >= MAX_TRIES) {
|
||||
mcMMO.p.getLogger().severe("Giving up on attempting to load the PlayerProfile for " + player.getName());
|
||||
mcMMO.p.getServer().broadcast(LocaleLoader.getString("Profile.Loading.AdminFailureNotice", player.getName()), Server.BROADCAST_CHANNEL_ADMINISTRATIVE);
|
||||
player.sendMessage(LocaleLoader.getString("Profile.Loading.Failure").split("\n"));
|
||||
this.cancel();
|
||||
cancelled = true;
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
private class ApplySuccessfulProfile extends BukkitRunnable {
|
||||
private final PlayerProfile profile;
|
||||
|
||||
private ApplySuccessfulProfile(PlayerProfile profile) {
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
// Synchronized task
|
||||
// No database access permitted
|
||||
@Override
|
||||
public void run() {
|
||||
if (!player.isOnline()) {
|
||||
mcMMO.p.getLogger().info("Aborting profile loading recovery for " + player.getName() + " - player logged out");
|
||||
return;
|
||||
}
|
||||
|
||||
McMMOPlayer mcMMOPlayer = new McMMOPlayer(player, profile);
|
||||
UserManager.track(mcMMOPlayer);
|
||||
mcMMOPlayer.actualizeRespawnATS();
|
||||
ScoreboardManager.setupPlayer(player);
|
||||
|
||||
if (Config.getInstance().getShowProfileLoadedMessage()) {
|
||||
player.sendMessage(LocaleLoader.getString("Profile.Loading.Success"));
|
||||
}
|
||||
|
||||
if (Config.getInstance().getShowStatsAfterLogin()) {
|
||||
ScoreboardManager.enablePlayerStatsScoreboard(player);
|
||||
new McScoreboardKeepTask(player).runTaskLater(mcMMO.p, 1 * Misc.TICK_CONVERSION_FACTOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.events.items.McMMOItemSpawnEvent;
|
||||
import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
|
||||
import com.gmail.nossr50.util.player.UserManager;
|
||||
|
||||
public final class Misc {
|
||||
@ -112,7 +113,7 @@ public final class Misc {
|
||||
|
||||
if (player != null) {
|
||||
UserManager.remove(player);
|
||||
UserManager.addUser(player);
|
||||
new PlayerProfileLoadingTask(player).runTaskTimerAsynchronously(mcMMO.p, 1, 20); // 1 Tick delay to ensure the player is marked as online before we begin loading
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,16 +18,12 @@ public final class UserManager {
|
||||
private UserManager() {}
|
||||
|
||||
/**
|
||||
* Add a new user.
|
||||
* Track a new user.
|
||||
*
|
||||
* @param player The player to create a user record for
|
||||
* @return the player's {@link McMMOPlayer} object
|
||||
* @param mcMMOPlayer the player profile to start tracking
|
||||
*/
|
||||
public static McMMOPlayer addUser(Player player) {
|
||||
McMMOPlayer mcMMOPlayer = new McMMOPlayer(player);
|
||||
player.setMetadata(mcMMO.playerDataKey, new FixedMetadataValue(mcMMO.p, mcMMOPlayer));
|
||||
|
||||
return mcMMOPlayer;
|
||||
public static void track(McMMOPlayer mcMMOPlayer) {
|
||||
mcMMOPlayer.getPlayer().setMetadata(mcMMO.playerDataKey, new FixedMetadataValue(mcMMO.p, mcMMOPlayer));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,6 +10,8 @@
|
||||
General:
|
||||
Locale: en_US
|
||||
MOTD_Enabled: true
|
||||
# Send a message to the player when his profile was successfully loaded
|
||||
Show_Profile_Loaded: false
|
||||
# Amount of time (in minutes) to wait between saves of player information
|
||||
Save_Interval: 10
|
||||
# Allow mcMMO to report on basic anonymous usage
|
||||
@ -122,6 +124,12 @@ MySQL:
|
||||
User_Password: UserPassword
|
||||
Name: DataBaseName
|
||||
TablePrefix: mcmmo_
|
||||
# This setting is the max simultaneous mysql connections allowed at a time, needs to be
|
||||
# high enough to support multiple player logins in quick succession
|
||||
MaxConnections: 30
|
||||
# This setting is the max size of the pool of cached connections that we hold available
|
||||
# at any given time
|
||||
MaxPoolSize: 20
|
||||
Server:
|
||||
Port: 3306
|
||||
Address: localhost
|
||||
|
@ -960,7 +960,6 @@ Scoreboard.Misc.Cooldown=[[LIGHT_PURPLE]]Cooldown
|
||||
Scoreboard.Misc.Overall=[[GOLD]]Overall
|
||||
|
||||
#DATABASE RECOVERY
|
||||
Recovery.Notice=[[RED]]Notice: mcMMO was [[DARK_RED]]unable to load your data.[[RED]] Retrying 5 times...
|
||||
Recovery.Success=[[GREEN]]Success! Your mcMMO data was loaded.
|
||||
Recovery.Failure=[[RED]]mcMMO still cannot load your data. You may want to [[AQUA]]contact the server owner.\n[[YELLOW]]You can still play on the server, but you will have [[BOLD]]no mcMMO levels[[YELLOW]] and any XP you get [[BOLD]]will not be saved[[YELLOW]].
|
||||
Recovery.AdminFailureNotice=[[DARK_RED]][A][[RED]] mcMMO was unable to load the player data for [[YELLOW]]{0}[[RED]]. [[LIGHT_PURPLE]]Please inspect your database setup.
|
||||
Profile.Loading.Success=[[GREEN]]Your mcMMO profile has been loaded.
|
||||
Profile.Loading.Failure=[[RED]]mcMMO still cannot load your data. You may want to [[AQUA]]contact the server owner.\n[[YELLOW]]You can still play on the server, but you will have [[BOLD]]no mcMMO levels[[YELLOW]] and any XP you get [[BOLD]]will not be saved[[YELLOW]].
|
||||
Profile.Loading.AdminFailureNotice=[[DARK_RED]][A][[RED]] mcMMO was unable to load the player data for [[YELLOW]]{0}[[RED]]. [[LIGHT_PURPLE]]Please inspect your database setup.
|
||||
|
Loading…
Reference in New Issue
Block a user