Async user loading/saving :D

This commit is contained in:
Harry5573OP 2014-05-18 19:22:12 +01:00
parent ead716ef0d
commit 2f74d53dbe
7 changed files with 269 additions and 229 deletions

View File

@ -37,9 +37,8 @@ public interface DatabaseManager {
* Save a user to the database. * Save a user to the database.
* *
* @param profile The profile of the player to save * @param profile The profile of the player to save
* @return true if successful, false on failure
*/ */
public boolean saveUser(PlayerProfile profile); public void saveUser(PlayerProfile profile);
/** /**
* Retrieve leaderboard info. * Retrieve leaderboard info.

View File

@ -206,7 +206,10 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
return worked; return worked;
} }
public boolean saveUser(PlayerProfile profile) { public void saveUser(final PlayerProfile profile) {
mcMMO.p.getServer().getScheduler().runTaskAsynchronously(mcMMO.p, new Runnable() {
@Override
public void run() {
String playerName = profile.getPlayerName(); String playerName = profile.getPlayerName();
BufferedReader in = null; BufferedReader in = null;
@ -225,8 +228,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
// Read the line in and copy it to the output it's not the player we want to edit // Read the line in and copy it to the output it's not the player we want to edit
if (!line.split(":")[0].equalsIgnoreCase(playerName)) { if (!line.split(":")[0].equalsIgnoreCase(playerName)) {
writer.append(line).append("\r\n"); writer.append(line).append("\r\n");
} } else {
else {
// Otherwise write the new player information // Otherwise write the new player information
writer.append(playerName).append(":"); writer.append(playerName).append(":");
writer.append(profile.getSkillLevel(SkillType.MINING)).append(":"); writer.append(profile.getSkillLevel(SkillType.MINING)).append(":");
@ -277,18 +279,18 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
// Write the new file // Write the new file
out = new FileWriter(usersFilePath); out = new FileWriter(usersFilePath);
out.write(writer.toString()); out.write(writer.toString());
return true; return;
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return false; return;
} } finally {
finally {
tryClose(in); tryClose(in);
tryClose(out); tryClose(out);
} }
} }
} }
});
}
public List<PlayerStat> readLeaderboard(SkillType skill, int pageNumber, int statsPerPage) { public List<PlayerStat> readLeaderboard(SkillType skill, int pageNumber, int statsPerPage) {
updateLeaderboards(); updateLeaderboards();

View File

@ -115,25 +115,27 @@ public final class SQLDatabaseManager implements DatabaseManager {
return success; return success;
} }
public boolean saveUser(PlayerProfile profile) { public void saveUser(final PlayerProfile profile) {
if (!checkConnected()) { if (!checkConnected()) {
return false; return;
} }
mcMMO.p.getServer().getScheduler().runTaskAsynchronously(mcMMO.p, new Runnable() {
@Override
public void run() {
int userId = readId(profile.getPlayerName()); int userId = readId(profile.getPlayerName());
if (userId == -1) { if (userId == -1) {
newUser(profile.getPlayerName()); newUser(profile.getPlayerName());
userId = readId(profile.getPlayerName()); userId = readId(profile.getPlayerName());
if (userId == -1) { if (userId == -1) {
return false; return;
} }
} }
boolean success = true;
MobHealthbarType mobHealthbarType = profile.getMobHealthbarType(); MobHealthbarType mobHealthbarType = profile.getMobHealthbarType();
success &= saveLogin(userId, ((int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR))); saveLogin(userId, ((int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)));
success &= saveHuds(userId, (mobHealthbarType == null ? Config.getInstance().getMobHealthbarDefault().toString() : mobHealthbarType.toString())); saveHuds(userId, (mobHealthbarType == null ? Config.getInstance().getMobHealthbarDefault().toString() : mobHealthbarType.toString()));
success &= saveLongs( saveLongs(
"UPDATE " + tablePrefix + "cooldowns SET " "UPDATE " + tablePrefix + "cooldowns SET "
+ " mining = ?, woodcutting = ?, unarmed = ?" + " mining = ?, woodcutting = ?, unarmed = ?"
+ ", herbalism = ?, excavation = ?, swords = ?" + ", herbalism = ?, excavation = ?, swords = ?"
@ -147,7 +149,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
profile.getAbilityDATS(AbilityType.SERRATED_STRIKES), profile.getAbilityDATS(AbilityType.SERRATED_STRIKES),
profile.getAbilityDATS(AbilityType.SKULL_SPLITTER), profile.getAbilityDATS(AbilityType.SKULL_SPLITTER),
profile.getAbilityDATS(AbilityType.BLAST_MINING)); profile.getAbilityDATS(AbilityType.BLAST_MINING));
success &= saveIntegers( saveIntegers(
"UPDATE " + tablePrefix + "skills SET " "UPDATE " + tablePrefix + "skills SET "
+ " taming = ?, mining = ?, repair = ?, woodcutting = ?" + " taming = ?, mining = ?, repair = ?, woodcutting = ?"
+ ", unarmed = ?, herbalism = ?, excavation = ?" + ", unarmed = ?, herbalism = ?, excavation = ?"
@ -167,7 +169,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
profile.getSkillLevel(SkillType.FISHING), profile.getSkillLevel(SkillType.FISHING),
profile.getSkillLevel(SkillType.ALCHEMY), profile.getSkillLevel(SkillType.ALCHEMY),
userId); userId);
success &= saveIntegers( saveIntegers(
"UPDATE " + tablePrefix + "experience SET " "UPDATE " + tablePrefix + "experience SET "
+ " taming = ?, mining = ?, repair = ?, woodcutting = ?" + " taming = ?, mining = ?, repair = ?, woodcutting = ?"
+ ", unarmed = ?, herbalism = ?, excavation = ?" + ", unarmed = ?, herbalism = ?, excavation = ?"
@ -187,7 +189,9 @@ public final class SQLDatabaseManager implements DatabaseManager {
profile.getSkillXpLevel(SkillType.FISHING), profile.getSkillXpLevel(SkillType.FISHING),
profile.getSkillXpLevel(SkillType.ALCHEMY), profile.getSkillXpLevel(SkillType.ALCHEMY),
userId); userId);
return success; return;
}
});
} }
public List<PlayerStat> readLeaderboard(SkillType skill, int pageNumber, int statsPerPage) { public List<PlayerStat> readLeaderboard(SkillType skill, int pageNumber, int statsPerPage) {
@ -351,7 +355,9 @@ public final class SQLDatabaseManager implements DatabaseManager {
return loadPlayerProfile(playerName, create, true); return loadPlayerProfile(playerName, create, true);
} }
private PlayerProfile loadPlayerProfile(String playerName, boolean create, boolean retry) { private PlayerProfile loadPlayerProfile(String playerName, boolean create, boolean retry) {
if (!checkConnected()) { if (!checkConnected()) {
return new PlayerProfile(playerName, false); // return fake profile if not connected return new PlayerProfile(playerName, false); // return fake profile if not connected
} }
@ -458,15 +464,13 @@ public final class SQLDatabaseManager implements DatabaseManager {
resultSet.next(); resultSet.next();
destination.saveUser(loadFromResult(playerName, resultSet)); destination.saveUser(loadFromResult(playerName, resultSet));
resultSet.close(); resultSet.close();
} } catch (SQLException e) {
catch (SQLException e) {
// Ignore // Ignore
} }
convertedUsers++; convertedUsers++;
Misc.printProgress(convertedUsers, progressInterval, startMillis); Misc.printProgress(convertedUsers, progressInterval, startMillis);
} }
} } catch (SQLException e) {
catch (SQLException e) {
printErrors(e); printErrors(e);
} }
finally { finally {

View File

@ -1,19 +1,5 @@
package com.gmail.nossr50.datatypes.player; package com.gmail.nossr50.datatypes.player;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
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; import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.experience.ExperienceConfig;
@ -26,6 +12,7 @@ import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.datatypes.skills.ToolType; import com.gmail.nossr50.datatypes.skills.ToolType;
import com.gmail.nossr50.datatypes.skills.XPGainReason; import com.gmail.nossr50.datatypes.skills.XPGainReason;
import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.party.PartyManager;
import com.gmail.nossr50.party.ShareHandler; import com.gmail.nossr50.party.ShareHandler;
import com.gmail.nossr50.runnables.skills.AbilityDisableTask; import com.gmail.nossr50.runnables.skills.AbilityDisableTask;
@ -53,14 +40,27 @@ import com.gmail.nossr50.util.StringUtils;
import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.skills.ParticleEffectUtils;
import com.gmail.nossr50.util.skills.PerksUtils; import com.gmail.nossr50.util.skills.PerksUtils;
import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.skills.SkillUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
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;
public class McMMOPlayer { public class McMMOPlayer {
private Player player; private Player player;
private PlayerProfile profile; private PlayerProfile playerProfile;
private final Map<SkillType, SkillManager> skillManagers = new HashMap<SkillType, SkillManager>(); private final ConcurrentHashMap<SkillType, SkillManager> skillManagers = new ConcurrentHashMap<SkillType, SkillManager>();
private Party party; private Party party;
private Party invite; private Party invite;
@ -91,12 +91,26 @@ public class McMMOPlayer {
private boolean isUsingUnarmed; private boolean isUsingUnarmed;
private final FixedMetadataValue playerMetadata; private final FixedMetadataValue playerMetadata;
public interface Callback {
public void done(String playerName, PlayerProfile profile);
}
public Callback pendingCallback;
public McMMOPlayer(Player player) { public McMMOPlayer(Player player) {
String playerName = player.getName(); final String playerName = player.getName();
this.player = player; this.player = player;
playerMetadata = new FixedMetadataValue(mcMMO.p, playerName); playerMetadata = new FixedMetadataValue(mcMMO.p, playerName);
profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, true);
//Fake the profile
playerProfile = new PlayerProfile(playerName, false);
pendingCallback = new Callback() {
public void done(String playerName, PlayerProfile p) {
playerProfile = p;
party = PartyManager.getPlayerParty(playerName); party = PartyManager.getPlayerParty(playerName);
ptpRecord = new PartyTeleportRecord(); ptpRecord = new PartyTeleportRecord();
@ -107,12 +121,26 @@ public class McMMOPlayer {
*/ */
try { try {
for (SkillType skillType : SkillType.values()) { for (SkillType skillType : SkillType.values()) {
skillManagers.put(skillType, skillType.getManagerClass().getConstructor(McMMOPlayer.class).newInstance(this)); skillManagers.put(skillType, skillType.getManagerClass().getConstructor(McMMOPlayer.class).newInstance(McMMOPlayer.this));
} }
} } catch (IllegalAccessException e) {
catch (Exception e) {
e.printStackTrace();
mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p); mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p);
e.printStackTrace();
} catch (IllegalArgumentException e) {
mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p);
e.printStackTrace();
} catch (InstantiationException e) {
mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p);
e.printStackTrace();
} catch (NoSuchMethodException e) {
mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p);
e.printStackTrace();
} catch (SecurityException e) {
mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p);
e.printStackTrace();
} catch (InvocationTargetException e) {
mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p);
e.printStackTrace();
} }
for (AbilityType abilityType : AbilityType.values()) { for (AbilityType abilityType : AbilityType.values()) {
@ -124,11 +152,20 @@ public class McMMOPlayer {
toolMode.put(toolType, false); toolMode.put(toolType, false);
} }
if (!profile.isLoaded()) { if (!playerProfile.isLoaded()) {
mcMMO.p.getLogger().warning("Unable to load the PlayerProfile for " + playerName + ". Will retry over the next several seconds."); mcMMO.p.getLogger().log(Level.WARNING, "Unable to load the PlayerProfile for {0}. Will retry over the next several seconds.", playerName);
new RetryProfileLoadingTask().runTaskTimerAsynchronously(mcMMO.p, 11L, 31L); new RetryProfileLoadingTask().runTaskTimerAsynchronously(mcMMO.p, 11L, 31L);
} }
} }
};
mcMMO.p.getServer().getScheduler().runTaskAsynchronously(mcMMO.p, new Runnable() {
@Override
public void run() {
pendingCallback.done(playerName, mcMMO.getDatabaseManager().loadPlayerProfile(playerName, true));
}
});
}
private class RetryProfileLoadingTask extends BukkitRunnable { private class RetryProfileLoadingTask extends BukkitRunnable {
private static final int MAX_TRIES = 5; private static final int MAX_TRIES = 5;
@ -184,7 +221,7 @@ public class McMMOPlayer {
// No database access permitted // No database access permitted
@Override @Override
public void run() { public void run() {
McMMOPlayer.this.profile = profile; McMMOPlayer.this.playerProfile = profile;
} }
} }
@ -548,7 +585,7 @@ public class McMMOPlayer {
break; break;
} }
xpRemoved += profile.levelUp(skillType); xpRemoved += playerProfile.levelUp(skillType);
levelsGained++; levelsGained++;
} }
@ -572,7 +609,7 @@ public class McMMOPlayer {
} }
public PlayerProfile getProfile() { public PlayerProfile getProfile() {
return profile; return playerProfile;
} }
/* /*
@ -798,7 +835,7 @@ public class McMMOPlayer {
SkillUtils.sendSkillMessage(player, ability.getAbilityPlayer(player)); SkillUtils.sendSkillMessage(player, ability.getAbilityPlayer(player));
// Enable the ability // Enable the ability
profile.setAbilityDATS(ability, System.currentTimeMillis() + (ticks * Misc.TIME_CONVERSION_FACTOR)); playerProfile.setAbilityDATS(ability, System.currentTimeMillis() + (ticks * Misc.TIME_CONVERSION_FACTOR));
setAbilityMode(ability, true); setAbilityMode(ability, true);
if (ability == AbilityType.SUPER_BREAKER || ability == AbilityType.GIGA_DRILL_BREAKER) { if (ability == AbilityType.SUPER_BREAKER || ability == AbilityType.GIGA_DRILL_BREAKER) {
@ -863,7 +900,7 @@ public class McMMOPlayer {
* @return the number of seconds remaining before the cooldown expires * @return the number of seconds remaining before the cooldown expires
*/ */
public int calculateTimeRemaining(AbilityType ability) { public int calculateTimeRemaining(AbilityType ability) {
long deactivatedTimestamp = profile.getAbilityDATS(ability) * Misc.TIME_CONVERSION_FACTOR; long deactivatedTimestamp = playerProfile.getAbilityDATS(ability) * Misc.TIME_CONVERSION_FACTOR;
return (int) (((deactivatedTimestamp + (PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TIME_CONVERSION_FACTOR)) - System.currentTimeMillis()) / Misc.TIME_CONVERSION_FACTOR); return (int) (((deactivatedTimestamp + (PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TIME_CONVERSION_FACTOR)) - System.currentTimeMillis()) / Misc.TIME_CONVERSION_FACTOR);
} }
@ -875,47 +912,47 @@ public class McMMOPlayer {
* These functions are wrapped from PlayerProfile so that we don't always have to store it alongside the McMMOPlayer object. * These functions are wrapped from PlayerProfile so that we don't always have to store it alongside the McMMOPlayer object.
*/ */
public int getSkillLevel(SkillType skill) { public int getSkillLevel(SkillType skill) {
return profile.getSkillLevel(skill); return playerProfile.getSkillLevel(skill);
} }
public float getSkillXpLevelRaw(SkillType skill) { public float getSkillXpLevelRaw(SkillType skill) {
return profile.getSkillXpLevelRaw(skill); return playerProfile.getSkillXpLevelRaw(skill);
} }
public int getSkillXpLevel(SkillType skill) { public int getSkillXpLevel(SkillType skill) {
return profile.getSkillXpLevel(skill); return playerProfile.getSkillXpLevel(skill);
} }
public void setSkillXpLevel(SkillType skill, float xpLevel) { public void setSkillXpLevel(SkillType skill, float xpLevel) {
profile.setSkillXpLevel(skill, xpLevel); playerProfile.setSkillXpLevel(skill, xpLevel);
} }
public int getXpToLevel(SkillType skill) { public int getXpToLevel(SkillType skill) {
return profile.getXpToLevel(skill); return playerProfile.getXpToLevel(skill);
} }
public void removeXp(SkillType skill, int xp) { public void removeXp(SkillType skill, int xp) {
profile.removeXp(skill, xp); playerProfile.removeXp(skill, xp);
} }
public void modifySkill(SkillType skill, int level) { public void modifySkill(SkillType skill, int level) {
profile.modifySkill(skill, level); playerProfile.modifySkill(skill, level);
} }
public void addLevels(SkillType skill, int levels) { public void addLevels(SkillType skill, int levels) {
profile.addLevels(skill, levels); playerProfile.addLevels(skill, levels);
} }
public void addXp(SkillType skill, float xp) { public void addXp(SkillType skill, float xp) {
profile.addXp(skill, xp); playerProfile.addXp(skill, xp);
} }
public void setAbilityDATS(AbilityType ability, long DATS) { public void setAbilityDATS(AbilityType ability, long DATS) {
profile.setAbilityDATS(ability, DATS); playerProfile.setAbilityDATS(ability, DATS);
} }
public void resetCooldowns() { public void resetCooldowns() {
profile.resetCooldowns(); playerProfile.resetCooldowns();
} }
public FixedMetadataValue getPlayerMetadata() { public FixedMetadataValue getPlayerMetadata() {

View File

@ -65,11 +65,8 @@ public class PlayerProfile {
return; return;
} }
changed = !mcMMO.getDatabaseManager().saveUser(new PlayerProfile(playerName, ImmutableMap.copyOf(skills), ImmutableMap.copyOf(skillsXp), ImmutableMap.copyOf(abilityDATS), mobHealthbarType)); mcMMO.getDatabaseManager().saveUser(new PlayerProfile(playerName, ImmutableMap.copyOf(skills), ImmutableMap.copyOf(skillsXp), ImmutableMap.copyOf(abilityDATS), mobHealthbarType));
changed = false;
if (changed) {
mcMMO.p.getLogger().warning("PlayerProfile for " + playerName + " failed to save");
}
} }
public String getPlayerName() { public String getPlayerName() {

View File

@ -344,9 +344,9 @@ public class PlayerListener implements Listener {
/** /**
* Monitor PlayerQuitEvents. * Monitor PlayerQuitEvents.
* <p> * <p>
* These events are monitored for the purpose of resetting player * These events are monitored for the purpose of resetting player variables
* variables and other garbage collection tasks that must take place when * and other garbage collection tasks that must take place when a player
* a player exits the server. * exits the server.
* *
* @param event The event to monitor * @param event The event to monitor
*/ */
@ -407,7 +407,7 @@ public class PlayerListener implements Listener {
} }
} }
/** /**e
* Monitor PlayerRespawnEvents. * Monitor PlayerRespawnEvents.
* <p> * <p>
* These events are monitored for the purpose of setting the * These events are monitored for the purpose of setting the

View File

@ -1,16 +1,17 @@
package com.gmail.nossr50.skills.alchemy; package com.gmail.nossr50.skills.alchemy;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.runnables.skills.AlchemyBrewTask;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.bukkit.Location; import org.bukkit.Location;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.runnables.skills.AlchemyBrewTask;
public final class Alchemy { public final class Alchemy {
public enum Tier { public enum Tier {
EIGHT(8), EIGHT(8),
@ -53,7 +54,7 @@ public final class Alchemy {
public static double catalysisMinSpeed = AdvancedConfig.getInstance().getCatalysisMinSpeed(); public static double catalysisMinSpeed = AdvancedConfig.getInstance().getCatalysisMinSpeed();
public static double catalysisMaxSpeed = AdvancedConfig.getInstance().getCatalysisMaxSpeed(); public static double catalysisMaxSpeed = AdvancedConfig.getInstance().getCatalysisMaxSpeed();
public static Map<Location, AlchemyBrewTask> brewingStandMap = new HashMap<Location, AlchemyBrewTask>(); public static ConcurrentMap<Location, AlchemyBrewTask> brewingStandMap = new ConcurrentHashMap<Location, AlchemyBrewTask>();
private Alchemy() {} private Alchemy() {}