mirror of
				https://github.com/mcMMO-Dev/mcMMO.git
				synced 2025-10-22 05:53:43 +02:00 
			
		
		
		
	mcMMO should no longer lose a few minutes of player data from shutting
down the server
This commit is contained in:
		| @@ -1,3 +1,6 @@ | |||||||
|  | Version 2.1.69 | ||||||
|  |     Fixed a few places where mcMMO would not save player data immediately which may cause players to lose a few minutes of progress | ||||||
|  |  | ||||||
| Version 2.1.68 | Version 2.1.68 | ||||||
|     Updated Japanese locale (thanks Snake) |     Updated Japanese locale (thanks Snake) | ||||||
|     Fixed a bug where consuming food in the off hand did not trigger the Diet abilities |     Fixed a bug where consuming food in the off hand did not trigger the Diet abilities | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|     <groupId>com.gmail.nossr50.mcMMO</groupId> |     <groupId>com.gmail.nossr50.mcMMO</groupId> | ||||||
|     <artifactId>mcMMO</artifactId> |     <artifactId>mcMMO</artifactId> | ||||||
|     <version>2.1.68</version> |     <version>2.1.69-SNAPSHOT</version> | ||||||
|     <name>mcMMO</name> |     <name>mcMMO</name> | ||||||
|     <url>https://github.com/mcMMO-Dev/mcMMO</url> |     <url>https://github.com/mcMMO-Dev/mcMMO</url> | ||||||
|     <scm> |     <scm> | ||||||
|   | |||||||
| @@ -1102,7 +1102,7 @@ public final class ExperienceAPI { | |||||||
|         PlayerProfile profile = getOfflineProfile(playerUniqueId); |         PlayerProfile profile = getOfflineProfile(playerUniqueId); | ||||||
|  |  | ||||||
|         profile.addXp(skill, XP); |         profile.addXp(skill, XP); | ||||||
|         profile.save(); |         profile.save(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Deprecated |     @Deprecated | ||||||
|   | |||||||
| @@ -100,9 +100,10 @@ public class McMMOPlayer { | |||||||
|  |  | ||||||
|     private boolean isUsingUnarmed; |     private boolean isUsingUnarmed; | ||||||
|     private final FixedMetadataValue playerMetadata; |     private final FixedMetadataValue playerMetadata; | ||||||
|  |     private String playerName; | ||||||
|  |  | ||||||
|     public McMMOPlayer(Player player, PlayerProfile profile) { |     public McMMOPlayer(Player player, PlayerProfile profile) { | ||||||
|         String playerName = player.getName(); |         this.playerName = player.getName(); | ||||||
|         UUID uuid = player.getUniqueId(); |         UUID uuid = player.getUniqueId(); | ||||||
|  |  | ||||||
|         this.player = player; |         this.player = player; | ||||||
| @@ -140,6 +141,10 @@ public class McMMOPlayer { | |||||||
|         experienceBarManager = new ExperienceBarManager(this); |         experienceBarManager = new ExperienceBarManager(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public String getPlayerName() { | ||||||
|  |         return playerName; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /*public void hideXpBar(PrimarySkillType primarySkillType) |     /*public void hideXpBar(PrimarySkillType primarySkillType) | ||||||
|     { |     { | ||||||
|         experienceBarManager.hideExperienceBar(primarySkillType); |         experienceBarManager.hideExperienceBar(primarySkillType); | ||||||
| @@ -995,7 +1000,7 @@ public class McMMOPlayer { | |||||||
|         BleedTimerTask.bleedOut(thisPlayer); |         BleedTimerTask.bleedOut(thisPlayer); | ||||||
|  |  | ||||||
|         if (syncSave) { |         if (syncSave) { | ||||||
|             getProfile().save(); |             getProfile().save(true); | ||||||
|         } else { |         } else { | ||||||
|             getProfile().scheduleAsyncSave(); |             getProfile().scheduleAsyncSave(); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -92,14 +92,23 @@ public class PlayerProfile { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void scheduleAsyncSave() { |     public void scheduleAsyncSave() { | ||||||
|         new PlayerProfileSaveTask(this).runTaskAsynchronously(mcMMO.p); |         new PlayerProfileSaveTask(this, false).runTaskAsynchronously(mcMMO.p); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void scheduleSyncSave() { | ||||||
|  |         new PlayerProfileSaveTask(this, true).runTask(mcMMO.p); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void scheduleAsyncSaveDelay() { |     public void scheduleAsyncSaveDelay() { | ||||||
|         new PlayerProfileSaveTask(this).runTaskLaterAsynchronously(mcMMO.p, 20); |         new PlayerProfileSaveTask(this, false).runTaskLaterAsynchronously(mcMMO.p, 20); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void save() { |     @Deprecated | ||||||
|  |     public void scheduleSyncSaveDelay() { | ||||||
|  |         new PlayerProfileSaveTask(this, true).runTaskLater(mcMMO.p, 20); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void save(boolean useSync) { | ||||||
|         if (!changed || !loaded) { |         if (!changed || !loaded) { | ||||||
|             saveAttempts = 0; |             saveAttempts = 0; | ||||||
|             return; |             return; | ||||||
| @@ -121,7 +130,12 @@ public class PlayerProfile { | |||||||
|             if(saveAttempts < 10) |             if(saveAttempts < 10) | ||||||
|             { |             { | ||||||
|                 saveAttempts++; |                 saveAttempts++; | ||||||
|  |  | ||||||
|  |                 if(useSync) | ||||||
|  |                     scheduleSyncSave(); //Execute sync saves immediately | ||||||
|  |                 else | ||||||
|                     scheduleAsyncSaveDelay(); |                     scheduleAsyncSaveDelay(); | ||||||
|  |  | ||||||
|                 return; |                 return; | ||||||
|             } else { |             } else { | ||||||
|                 mcMMO.p.getLogger().severe("mcMMO has failed to save the profile for " |                 mcMMO.p.getLogger().severe("mcMMO has failed to save the profile for " | ||||||
| @@ -144,7 +158,7 @@ public class PlayerProfile { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setUniqueId(UUID uuid) { |     public void setUniqueId(UUID uuid) { | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         this.uuid = uuid; |         this.uuid = uuid; | ||||||
|     } |     } | ||||||
| @@ -162,17 +176,24 @@ public class PlayerProfile { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setMobHealthbarType(MobHealthbarType mobHealthbarType) { |     public void setMobHealthbarType(MobHealthbarType mobHealthbarType) { | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         this.mobHealthbarType = mobHealthbarType; |         this.mobHealthbarType = mobHealthbarType; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Marks the profile as "dirty" which flags a profile to be saved in the next save operation | ||||||
|  |      */ | ||||||
|  |     public void markProfileDirty() { | ||||||
|  |         changed = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public int getScoreboardTipsShown() { |     public int getScoreboardTipsShown() { | ||||||
|         return scoreboardTipsShown; |         return scoreboardTipsShown; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setScoreboardTipsShown(int scoreboardTipsShown) { |     public void setScoreboardTipsShown(int scoreboardTipsShown) { | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         this.scoreboardTipsShown = scoreboardTipsShown; |         this.scoreboardTipsShown = scoreboardTipsShown; | ||||||
|     } |     } | ||||||
| @@ -188,12 +209,12 @@ public class PlayerProfile { | |||||||
|     public int getChimaerWingDATS() { return uniquePlayerData.get(UniqueDataType.CHIMAERA_WING_DATS);} |     public int getChimaerWingDATS() { return uniquePlayerData.get(UniqueDataType.CHIMAERA_WING_DATS);} | ||||||
|  |  | ||||||
|     protected void setChimaeraWingDATS(int DATS) { |     protected void setChimaeraWingDATS(int DATS) { | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|         uniquePlayerData.put(UniqueDataType.CHIMAERA_WING_DATS, DATS); |         uniquePlayerData.put(UniqueDataType.CHIMAERA_WING_DATS, DATS); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setUniqueData(UniqueDataType uniqueDataType, int newData) { |     public void setUniqueData(UniqueDataType uniqueDataType, int newData) { | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|         uniquePlayerData.put(uniqueDataType, newData); |         uniquePlayerData.put(uniqueDataType, newData); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -216,7 +237,7 @@ public class PlayerProfile { | |||||||
|      * @param DATS the DATS of the ability |      * @param DATS the DATS of the ability | ||||||
|      */ |      */ | ||||||
|     protected void setAbilityDATS(SuperAbilityType ability, long DATS) { |     protected void setAbilityDATS(SuperAbilityType ability, long DATS) { | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         abilityDATS.put(ability, (int) (DATS * .001D)); |         abilityDATS.put(ability, (int) (DATS * .001D)); | ||||||
|     } |     } | ||||||
| @@ -225,7 +246,7 @@ public class PlayerProfile { | |||||||
|      * Reset all ability cooldowns. |      * Reset all ability cooldowns. | ||||||
|      */ |      */ | ||||||
|     protected void resetCooldowns() { |     protected void resetCooldowns() { | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         for (SuperAbilityType ability : abilityDATS.keySet()) { |         for (SuperAbilityType ability : abilityDATS.keySet()) { | ||||||
|             abilityDATS.put(ability, 0); |             abilityDATS.put(ability, 0); | ||||||
| @@ -253,7 +274,7 @@ public class PlayerProfile { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         skillsXp.put(skill, xpLevel); |         skillsXp.put(skill, xpLevel); | ||||||
|     } |     } | ||||||
| @@ -261,7 +282,7 @@ public class PlayerProfile { | |||||||
|     protected float levelUp(PrimarySkillType skill) { |     protected float levelUp(PrimarySkillType skill) { | ||||||
|         float xpRemoved = getXpToLevel(skill); |         float xpRemoved = getXpToLevel(skill); | ||||||
|  |  | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         skills.put(skill, skills.get(skill) + 1); |         skills.put(skill, skills.get(skill) + 1); | ||||||
|         skillsXp.put(skill, skillsXp.get(skill) - xpRemoved); |         skillsXp.put(skill, skillsXp.get(skill) - xpRemoved); | ||||||
| @@ -280,7 +301,7 @@ public class PlayerProfile { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         skillsXp.put(skill, skillsXp.get(skill) - xp); |         skillsXp.put(skill, skillsXp.get(skill) - xp); | ||||||
|     } |     } | ||||||
| @@ -290,7 +311,7 @@ public class PlayerProfile { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         skillsXp.put(skill, skillsXp.get(skill) - xp); |         skillsXp.put(skill, skillsXp.get(skill) - xp); | ||||||
|     } |     } | ||||||
| @@ -306,7 +327,7 @@ public class PlayerProfile { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         //Don't allow levels to be negative |         //Don't allow levels to be negative | ||||||
|         if(level < 0) |         if(level < 0) | ||||||
| @@ -333,7 +354,7 @@ public class PlayerProfile { | |||||||
|      * @param xp Number of experience to add |      * @param xp Number of experience to add | ||||||
|      */ |      */ | ||||||
|     public void addXp(PrimarySkillType skill, float xp) { |     public void addXp(PrimarySkillType skill, float xp) { | ||||||
|         changed = true; |         markProfileDirty(); | ||||||
|  |  | ||||||
|         if (skill.isChildSkill()) { |         if (skill.isChildSkill()) { | ||||||
|             Set<PrimarySkillType> parentSkills = FamilyTree.getParents(skill); |             Set<PrimarySkillType> parentSkills = FamilyTree.getParents(skill); | ||||||
|   | |||||||
| @@ -318,9 +318,9 @@ public class mcMMO extends JavaPlugin { | |||||||
|     @Override |     @Override | ||||||
|     public void onDisable() { |     public void onDisable() { | ||||||
|         try { |         try { | ||||||
|             Alchemy.finishAllBrews();   // Finish all partially complete AlchemyBrewTasks to prevent vanilla brewing continuation on restart |  | ||||||
|             UserManager.saveAll();      // Make sure to save player information if the server shuts down |             UserManager.saveAll();      // Make sure to save player information if the server shuts down | ||||||
|             UserManager.clearAll(); |             UserManager.clearAll(); | ||||||
|  |             Alchemy.finishAllBrews();   // Finish all partially complete AlchemyBrewTasks to prevent vanilla brewing continuation on restart | ||||||
|             PartyManager.saveParties(); // Save our parties |             PartyManager.saveParties(); // Save our parties | ||||||
|  |  | ||||||
|             //TODO: Needed? |             //TODO: Needed? | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ public class SaveTimerTask extends BukkitRunnable { | |||||||
|         int count = 1; |         int count = 1; | ||||||
|  |  | ||||||
|         for (McMMOPlayer mcMMOPlayer : UserManager.getPlayers()) { |         for (McMMOPlayer mcMMOPlayer : UserManager.getPlayers()) { | ||||||
|             new PlayerProfileSaveTask(mcMMOPlayer.getProfile()).runTaskLaterAsynchronously(mcMMO.p, count); |             new PlayerProfileSaveTask(mcMMOPlayer.getProfile(), false).runTaskLaterAsynchronously(mcMMO.p, count); | ||||||
|             count++; |             count++; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,13 +5,15 @@ import org.bukkit.scheduler.BukkitRunnable; | |||||||
|  |  | ||||||
| public class PlayerProfileSaveTask extends BukkitRunnable { | public class PlayerProfileSaveTask extends BukkitRunnable { | ||||||
|     private PlayerProfile playerProfile; |     private PlayerProfile playerProfile; | ||||||
|  |     private boolean isSync; | ||||||
|  |  | ||||||
|     public PlayerProfileSaveTask(PlayerProfile playerProfile) { |     public PlayerProfileSaveTask(PlayerProfile playerProfile, boolean isSync) { | ||||||
|         this.playerProfile = playerProfile; |         this.playerProfile = playerProfile; | ||||||
|  |         this.isSync = isSync; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void run() { |     public void run() { | ||||||
|         playerProfile.save(); |         playerProfile.save(isSync); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,10 +10,15 @@ import org.bukkit.metadata.FixedMetadataValue; | |||||||
|  |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
|  | import java.util.HashSet; | ||||||
|  |  | ||||||
| public final class UserManager { | public final class UserManager { | ||||||
|  |  | ||||||
|     private UserManager() {} |     private static HashSet<McMMOPlayer> playerDataSet; //Used to track players for sync saves on shutdown | ||||||
|  |  | ||||||
|  |     private UserManager() { | ||||||
|  |         playerDataSet = new HashSet<>(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Track a new user. |      * Track a new user. | ||||||
| @@ -22,6 +27,11 @@ public final class UserManager { | |||||||
|      */ |      */ | ||||||
|     public static void track(McMMOPlayer mcMMOPlayer) { |     public static void track(McMMOPlayer mcMMOPlayer) { | ||||||
|         mcMMOPlayer.getPlayer().setMetadata(mcMMO.playerDataKey, new FixedMetadataValue(mcMMO.p, mcMMOPlayer)); |         mcMMOPlayer.getPlayer().setMetadata(mcMMO.playerDataKey, new FixedMetadataValue(mcMMO.p, mcMMOPlayer)); | ||||||
|  |         playerDataSet.add(mcMMOPlayer); //for sync saves on shutdown | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static void cleanupPlayer(McMMOPlayer mcMMOPlayer) { | ||||||
|  |         playerDataSet.remove(mcMMOPlayer); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -30,7 +40,9 @@ public final class UserManager { | |||||||
|      * @param player The Player object |      * @param player The Player object | ||||||
|      */ |      */ | ||||||
|     public static void remove(Player player) { |     public static void remove(Player player) { | ||||||
|  |         McMMOPlayer mcMMOPlayer = getPlayer(player); | ||||||
|         player.removeMetadata(mcMMO.playerDataKey, mcMMO.p); |         player.removeMetadata(mcMMO.playerDataKey, mcMMO.p); | ||||||
|  |         playerDataSet.remove(mcMMOPlayer); //Clear sync save tracking | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -40,25 +52,31 @@ public final class UserManager { | |||||||
|         for (Player player : mcMMO.p.getServer().getOnlinePlayers()) { |         for (Player player : mcMMO.p.getServer().getOnlinePlayers()) { | ||||||
|             remove(player); |             remove(player); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         playerDataSet.clear(); //Clear sync save tracking | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Save all users ON THIS THREAD. |      * Save all users ON THIS THREAD. | ||||||
|      */ |      */ | ||||||
|     public static void saveAll() { |     public static void saveAll() { | ||||||
|         ImmutableList<Player> onlinePlayers = ImmutableList.copyOf(mcMMO.p.getServer().getOnlinePlayers()); |         ImmutableList<McMMOPlayer> trackedSyncData = ImmutableList.copyOf(playerDataSet); | ||||||
|         mcMMO.p.debug("Saving mcMMOPlayers... (" + onlinePlayers.size() + ")"); |  | ||||||
|  |  | ||||||
|         for (Player player : onlinePlayers) { |         mcMMO.p.getLogger().info("Saving mcMMOPlayers... (" + trackedSyncData.size() + ")"); | ||||||
|  |  | ||||||
|  |         for (McMMOPlayer playerData : trackedSyncData) { | ||||||
|             try |             try | ||||||
|             { |             { | ||||||
|                 getPlayer(player).getProfile().save(); |                 mcMMO.p.getLogger().info("Saving data for player: "+playerData.getPlayerName()); | ||||||
|  |                 playerData.getProfile().save(true); | ||||||
|             } |             } | ||||||
|             catch (Exception e) |             catch (Exception e) | ||||||
|             { |             { | ||||||
|                 mcMMO.p.getLogger().warning("Could not save mcMMO player data for player: " + player.getName()); |                 mcMMO.p.getLogger().warning("Could not save mcMMO player data for player: " + playerData.getPlayerName()); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         mcMMO.p.getLogger().info("Finished save operation for "+trackedSyncData.size()+" players!"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static Collection<McMMOPlayer> getPlayers() { |     public static Collection<McMMOPlayer> getPlayers() { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 nossr50
					nossr50