From de904e4d56e8733d7cc060f3094264bf43f5e9af Mon Sep 17 00:00:00 2001 From: Koyorice Date: Fri, 13 Feb 2026 22:08:04 +0800 Subject: [PATCH] Add auto save support --- .../InventoryRollbackPlus.java | 16 +++++++++++ .../util/LegacyBackupConversionUtil.java | 2 ++ .../inventoryrollback/config/ConfigData.java | 20 ++++++++++++++ .../inventoryrollback/data/LogType.java | 1 + .../danjono/inventoryrollback/data/MySQL.java | 7 ++++- .../inventoryrollback/data/PlayerData.java | 2 ++ .../danjono/inventoryrollback/data/YAML.java | 9 +++++++ .../inventoryrollback/gui/Buttons.java | 27 +++++++++++++++++++ .../gui/menu/PlayerMenu.java | 8 +++++- src/main/resources/config.yml | 4 +++ src/main/resources/plugin.yml | 9 +++++++ 11 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/InventoryRollbackPlus.java b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/InventoryRollbackPlus.java index 7ca7e06..b8356b6 100644 --- a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/InventoryRollbackPlus.java +++ b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/InventoryRollbackPlus.java @@ -91,6 +91,9 @@ public void onEnable() { // Run after all plugin enable getServer().getScheduler().runTask(this, EventLogs::patchLowestHandlers); + // Auto Backups + scheduleAutoSave(ConfigData.getAutoSaveInterval()); + // PaperLib if (!PaperLib.isPaper()) { this.getLogger().info("----------------------------------------"); @@ -198,6 +201,19 @@ public void checkUpdate() { }); } + public void scheduleAutoSave(int interval) { + if (interval <= 0) return; + + getServer().getScheduler().runTaskTimer(this, () -> { + for (Player player : getServer().getOnlinePlayers()) { + if (player.hasPermission("inventoryrollbackplus.autosave")) { + new SaveInventory(player, LogType.AUTO, null, null) + .snapshotAndSave(player.getInventory(), player.getEnderChest(), true); + } + } + }, 0, interval * 20L); + } + public void initBStats() { bStats(); } diff --git a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/util/LegacyBackupConversionUtil.java b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/util/LegacyBackupConversionUtil.java index 84e3452..05d5e3c 100644 --- a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/util/LegacyBackupConversionUtil.java +++ b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/util/LegacyBackupConversionUtil.java @@ -40,6 +40,7 @@ public static void convertOldBackupData() { oldBackupTypeFolders.add(new File(oldBackupsRoot, "quits")); oldBackupTypeFolders.add(new File(oldBackupsRoot, "worldChanges")); oldBackupTypeFolders.add(new File(oldBackupsRoot, "force")); + oldBackupTypeFolders.add(new File(oldBackupsRoot, "auto")); int logTypeNumber = -1; List logTypes = new ArrayList<>(); @@ -48,6 +49,7 @@ public static void convertOldBackupData() { logTypes.add(LogType.QUIT); logTypes.add(LogType.WORLD_CHANGE); logTypes.add(LogType.FORCE); + logTypes.add(LogType.AUTO); for (File oldBackupFolder : oldBackupTypeFolders) { diff --git a/src/main/java/me/danjono/inventoryrollback/config/ConfigData.java b/src/main/java/me/danjono/inventoryrollback/config/ConfigData.java index 8213ceb..951f676 100644 --- a/src/main/java/me/danjono/inventoryrollback/config/ConfigData.java +++ b/src/main/java/me/danjono/inventoryrollback/config/ConfigData.java @@ -91,6 +91,7 @@ public String getName() { private static boolean allowOtherPluginEditDeathInventory; private static boolean restoreToPlayerButton; private static int backupLinesVisible; + private static int autoSaveInterval; private static boolean saveEmptyInventories; @@ -99,6 +100,7 @@ public String getName() { private static int maxSavesDeath; private static int maxSavesWorldChange; private static int maxSavesForce; + private static int maxSavesAuto; private static long timeZoneOffsetMillis; private static TimeZone timeZone; @@ -149,6 +151,7 @@ public void setVariables() { setAllowOtherPluginEditDeathInventory((boolean) getDefaultValue("allow-other-plugins-edit-death-inventory", false)); setRestoreToPlayerButton((boolean) getDefaultValue("restore-to-player-button", true)); setBackupLinesVisible((int) getDefaultValue("backup-lines-visible", 1)); + setAutoSaveInterval((int) getDefaultValue("auto-save-interval", 300)); setSaveEmptyInventories((boolean) getDefaultValue("save-empty-inventories", true)); setMaxSavesJoin((int) getDefaultValue("max-saves.join", 10)); @@ -156,6 +159,7 @@ public void setVariables() { setMaxSavesDeath((int) getDefaultValue("max-saves.death", 50)); setMaxSavesWorldChange((int) getDefaultValue("max-saves.world-change", 10)); setMaxSavesForce((int) getDefaultValue("max-saves.force", 10)); + setMaxSavesAuto((int) getDefaultValue("max-saves.auto", 50)); setTimeZone((String) getDefaultValue("time-zone", "GMT")); setTimeFormat((String) getDefaultValue("time-format", "dd/MM/yyyy HH:mm:ss a")); @@ -266,6 +270,10 @@ public static void setBackupLinesVisible(int value) { } } + public static void setAutoSaveInterval(int value) { + autoSaveInterval = value; + } + public static void setMaxSavesJoin(int value) { maxSavesJoin = value; } @@ -286,6 +294,10 @@ public static void setMaxSavesForce(int value) { maxSavesForce = value; } + public static void setMaxSavesAuto(int value) { + maxSavesAuto = value; + } + public static void setTimeZone(String zone) { try { // Allow UTC offsets @@ -416,6 +428,10 @@ public static int getBackupLinesVisible() { return backupLinesVisible; } + public static int getAutoSaveInterval() { + return autoSaveInterval; + } + public static int getMaxSavesJoin() { return maxSavesJoin; } @@ -436,6 +452,10 @@ public static int getMaxSavesForce() { return maxSavesForce; } + public static int getMaxSavesAuto() { + return maxSavesAuto; + } + public static long getTimeZoneOffsetMillis() { return timeZoneOffsetMillis; } diff --git a/src/main/java/me/danjono/inventoryrollback/data/LogType.java b/src/main/java/me/danjono/inventoryrollback/data/LogType.java index 4a0b19f..7b57f20 100644 --- a/src/main/java/me/danjono/inventoryrollback/data/LogType.java +++ b/src/main/java/me/danjono/inventoryrollback/data/LogType.java @@ -6,5 +6,6 @@ public enum LogType { DEATH, WORLD_CHANGE, FORCE, + AUTO, UNKNOWN; } diff --git a/src/main/java/me/danjono/inventoryrollback/data/MySQL.java b/src/main/java/me/danjono/inventoryrollback/data/MySQL.java index 080ce29..3ad2164 100644 --- a/src/main/java/me/danjono/inventoryrollback/data/MySQL.java +++ b/src/main/java/me/danjono/inventoryrollback/data/MySQL.java @@ -69,7 +69,8 @@ public enum BackupTable { JOIN(ConfigData.getMySQLTablePrefix() + "joins"), QUIT(ConfigData.getMySQLTablePrefix() + "quits"), WORLD_CHANGE(ConfigData.getMySQLTablePrefix() + "world_changes"), - FORCE(ConfigData.getMySQLTablePrefix() + "force_backups"); + FORCE(ConfigData.getMySQLTablePrefix() + "force_backups"), + AUTO(ConfigData.getMySQLTablePrefix() + "auto_backups"); private final String tableName; @@ -98,6 +99,7 @@ public static void convertYAMLToMySQL() { backupLocations.add(new File(backupArea, "quits")); backupLocations.add(new File(backupArea, "worldChanges")); backupLocations.add(new File(backupArea, "force")); + backupLocations.add(new File(backupArea, "auto")); List logTypeFiles = new ArrayList<>(); logTypeFiles.add(LogType.DEATH); @@ -105,6 +107,7 @@ public static void convertYAMLToMySQL() { logTypeFiles.add(LogType.QUIT); logTypeFiles.add(LogType.WORLD_CHANGE); logTypeFiles.add(LogType.FORCE); + logTypeFiles.add(LogType.AUTO); for (int i = 0; i < backupLocations.size(); i++) { File backupType = backupLocations.get(i); @@ -185,6 +188,8 @@ private BackupTable getBackupTable() { return BackupTable.WORLD_CHANGE; } else if (logType == LogType.FORCE) { return BackupTable.FORCE; + } else if (logType == LogType.AUTO) { + return BackupTable.AUTO; } else { throw new IllegalArgumentException("Unknown log type: " + logType); } diff --git a/src/main/java/me/danjono/inventoryrollback/data/PlayerData.java b/src/main/java/me/danjono/inventoryrollback/data/PlayerData.java index dd717b7..5369f71 100644 --- a/src/main/java/me/danjono/inventoryrollback/data/PlayerData.java +++ b/src/main/java/me/danjono/inventoryrollback/data/PlayerData.java @@ -452,6 +452,8 @@ public int getMaxSaves() { return ConfigData.getMaxSavesWorldChange(); } else if (logType == LogType.FORCE) { return ConfigData.getMaxSavesForce(); + } else if (logType == LogType.AUTO) { + return ConfigData.getMaxSavesAuto(); } diff --git a/src/main/java/me/danjono/inventoryrollback/data/YAML.java b/src/main/java/me/danjono/inventoryrollback/data/YAML.java index b05c2e4..dad3c08 100644 --- a/src/main/java/me/danjono/inventoryrollback/data/YAML.java +++ b/src/main/java/me/danjono/inventoryrollback/data/YAML.java @@ -84,6 +84,11 @@ public static void createStorageFolders() { File forceSavesFolder = new File(savesFolder, "force"); if(!forceSavesFolder.exists()) forceSavesFolder.mkdir(); + + //Create folder for auto saves + File autoSavesFolder = new File(savesFolder, "auto"); + if(!autoSavesFolder.exists()) + autoSavesFolder.mkdir(); } private static File getRootBackupsFolder() { @@ -103,6 +108,8 @@ private static File getBackupFolderForLogType(LogType backupLogType) { backupLocation = new File(backupLocation, "worldChanges"); } else if (backupLogType == LogType.FORCE) { backupLocation = new File(backupLocation, "force"); + } else if (backupLogType == LogType.AUTO) { + backupLocation = new File(backupLocation, "auto"); } return backupLocation; @@ -374,6 +381,7 @@ public static void convertOldBackupData() { backupLocations.add(new File(ConfigData.getFolderLocation(), "saves/quits")); backupLocations.add(new File(ConfigData.getFolderLocation(), "saves/worldChanges")); backupLocations.add(new File(ConfigData.getFolderLocation(), "saves/force")); + backupLocations.add(new File(ConfigData.getFolderLocation(), "saves/auto")); List logTypeFiles = new ArrayList<>(); int logTypeNumber = 0; @@ -382,6 +390,7 @@ public static void convertOldBackupData() { logTypeFiles.add(LogType.QUIT); logTypeFiles.add(LogType.WORLD_CHANGE); logTypeFiles.add(LogType.FORCE); + logTypeFiles.add(LogType.AUTO); for (File backupFolders : backupLocations) { if (!backupFolders.exists()) { diff --git a/src/main/java/me/danjono/inventoryrollback/gui/Buttons.java b/src/main/java/me/danjono/inventoryrollback/gui/Buttons.java index fe77426..16e5785 100644 --- a/src/main/java/me/danjono/inventoryrollback/gui/Buttons.java +++ b/src/main/java/me/danjono/inventoryrollback/gui/Buttons.java @@ -41,6 +41,7 @@ public class Buttons { private static final Material forceSave = Material.DIAMOND; + private static final Material autoSave = Material.NETHER_STAR; private static final Material pageSelector = InventoryRollbackPlus.getInstance().getVersion().greaterOrEqThan(BukkitVersion.v1_13_R1) ? @@ -97,6 +98,10 @@ public static Material getForceSaveLogIcon() { return forceSave; } + public static Material getAutoSaveLogIcon() { + return autoSave; + } + public static Material getPageSelectorIcon() { return pageSelector; } @@ -449,6 +454,28 @@ public ItemStack createForceSaveLogButton(LogType logType, List lore) { return item; } + public ItemStack createAutoSaveLogButton(LogType logType, List lore) { + ItemStack item = new ItemStack(getAutoSaveLogIcon()); + ItemMeta meta = item.getItemMeta(); + + assert meta != null; + if (lore != null) { + meta.setLore(lore); + } + + meta.setDisplayName(ChatColor.YELLOW + "Auto Saves"); + + item.setItemMeta(meta); + + CustomDataItemEditor nbt = CustomDataItemEditor.editItem(item); + + nbt.setString("uuid", uuid.toString()); + nbt.setString("logType", logType.name()); + item = nbt.setItemData(); + + return item; + } + public ItemStack playerHead(List lore, boolean setSkin) { if (uuid == null) return null; diff --git a/src/main/java/me/danjono/inventoryrollback/gui/menu/PlayerMenu.java b/src/main/java/me/danjono/inventoryrollback/gui/menu/PlayerMenu.java index 36408b7..df66b93 100644 --- a/src/main/java/me/danjono/inventoryrollback/gui/menu/PlayerMenu.java +++ b/src/main/java/me/danjono/inventoryrollback/gui/menu/PlayerMenu.java @@ -41,6 +41,7 @@ public void createInventory() { inventory.setItem(4, buttons.createQuitLogButton(LogType.QUIT, null)); inventory.setItem(5, buttons.createWorldChangeLogButton(LogType.WORLD_CHANGE, null)); inventory.setItem(6, buttons.createForceSaveLogButton(LogType.FORCE, null)); + inventory.setItem(7, buttons.createAutoSaveLogButton(LogType.AUTO, null)); } public Inventory getInventory() { @@ -71,12 +72,14 @@ public void getPlayerMenu() { PlayerData quitBackup = new PlayerData(uuid, LogType.QUIT, null); PlayerData worldChangeBackup = new PlayerData(uuid, LogType.WORLD_CHANGE, null); PlayerData forceSaveBackup = new PlayerData(uuid, LogType.FORCE, null); + PlayerData autoSaveBackup = new PlayerData(uuid, LogType.AUTO, null); if (!joinBackup.doesBackupTypeExist() && !quitBackup.doesBackupTypeExist() && !deathBackup.doesBackupTypeExist() && !worldChangeBackup.doesBackupTypeExist() - && !forceSaveBackup.doesBackupTypeExist()) { + && !forceSaveBackup.doesBackupTypeExist() + && !autoSaveBackup.doesBackupTypeExist()) { //No backups have been found for the player staff.sendMessage(MessageData.getPluginPrefix() + MessageData.getNoBackupError(offlinePlayer.getName())); @@ -98,6 +101,9 @@ public void getPlayerMenu() { List forceSaves = Arrays.asList(forceSaveBackup.getAmountOfBackups() + backupsAvailable); inventory.setItem(6, buttons.createForceSaveLogButton(LogType.FORCE, forceSaves)); + + List autoSaves = Arrays.asList(autoSaveBackup.getAmountOfBackups() + backupsAvailable); + inventory.setItem(7, buttons.createAutoSaveLogButton(LogType.AUTO, autoSaves)); } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7c07653..9049224 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -8,10 +8,14 @@ max-saves: death: 50 world-change: 10 force: 10 + auto: 50 ## Number of lines shown with backups on (Max: 5) backup-lines-visible: 4 +# Auto save backups interval in seconds. Set to -1 to disable. +auto-save-interval: 300 + ## Set folder path where the data is saved to. Set as "DEFAULT" to keep it in the plugin folder. folder-location: 'DEFAULT' diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9d56c25..08d29aa 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -27,6 +27,7 @@ permissions: inventoryrollbackplus.joinsave: true inventoryrollbackplus.leavesave: true inventoryrollbackplus.worldchangesave: true + inventoryrollbackplus.autosave: true inventoryrollbackplus.enable: true inventoryrollbackplus.disable: true inventoryrollbackplus.reload: true @@ -52,6 +53,9 @@ permissions: inventoryrollbackplus.worldchangesave: description: Player inventories will be saved when they change worlds. default: true + inventoryrollbackplus.autosave: + description: Player inventories will be saved when auto save timer. + default: true inventoryrollbackplus.enable: description: Grants access to enable the plugin globally. default: op @@ -111,6 +115,11 @@ permissions: default: false children: inventoryrollbackplus.worldchangesave: true + inventoryrollback.autosave: + description: Player inventories will be saved when auto save timer. + default: false + children: + inventoryrollbackplus.autosave: true inventoryrollback.enable: description: Grants access to enable the plugin globally. default: false