From 14ae1a69c4743c060c5e5cea4f8b24a82c33632c Mon Sep 17 00:00:00 2001 From: riking Date: Sat, 5 Oct 2013 15:43:14 -0700 Subject: [PATCH] Attempt clean recovery from an unloaded PlayerProfile This change should cause McMMOPlayer to create a graceful recovery when the database is temporarily unavailable. When a McMMOPlayer is constructed and recieves an unloaded PlayerProfile, it schedules a task to re-attempt profile retrieval. This task can run for a maximum of 5 seconds, after which a second warning is printed indicating that it has given up (and a message given to the user). --- .../nossr50/datatypes/player/McMMOPlayer.java | 65 +++++++++++++++++++ .../resources/locale/locale_en_US.properties | 6 ++ 2 files changed, 71 insertions(+) diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index 04cd8db18..930182807 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -4,10 +4,13 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; +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; @@ -123,6 +126,68 @@ public class McMMOPlayer { toolMode.put(toolType, false); toolATS.put(toolType, 0); } + + 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 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(playerName, 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); + Bukkit.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() { diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 7f9b3958c..1a3b817a3 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -772,3 +772,9 @@ Scoreboard.Misc.Level=Level Scoreboard.Misc.CurrentXP=Current XP Scoreboard.Misc.RemainingXP=Remaining XP Scoreboard.Misc.Overall=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.