Skip to content

Commit

Permalink
Merge pull request #26 from Artillex-Studios/backup-limits
Browse files Browse the repository at this point in the history
Add backup limiting
  • Loading branch information
BenceX100 authored Oct 12, 2024
2 parents dc42da5 + b62b258 commit 33160ed
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.artillexstudios.axinventoryrestore.api;

import com.artillexstudios.axinventoryrestore.AxInventoryRestore;
import com.artillexstudios.axinventoryrestore.utils.BackupLimiter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -9,5 +10,6 @@ public class AxInventoryRestoreAPI {

public static void saveInventory(@NotNull Player player, @NotNull String category, @Nullable String extraInfo) {
AxInventoryRestore.getDB().saveInventory(player, category, extraInfo);
BackupLimiter.tryLimit(player.getUniqueId(), category, category);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.artillexstudios.axinventoryrestore.guis.MainGui;
import com.artillexstudios.axinventoryrestore.queue.Priority;
import com.artillexstudios.axinventoryrestore.schedulers.AutoBackupScheduler;
import com.artillexstudios.axinventoryrestore.utils.BackupLimiter;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
Expand Down Expand Up @@ -101,6 +102,7 @@ public void save(CommandSender sender, Player player) {
final String cause = MESSAGES.getString("manual-created-by").replace("%player%", sender.getName());

AxInventoryRestore.getDB().saveInventory(player, "MANUAL", cause);
BackupLimiter.tryLimit(player.getUniqueId(), "manual", "MANUAL");
MESSAGEUTILS.sendLang(sender, "manual-backup", Map.of("%player%", player.getName()));
}

Expand All @@ -111,6 +113,7 @@ public void saveall(CommandSender sender) {

for (Player pl : Bukkit.getOnlinePlayers()) {
AxInventoryRestore.getDB().saveInventory(pl, "MANUAL", cause);
BackupLimiter.tryLimit(pl.getUniqueId(), "manual", "MANUAL");
}

MESSAGEUTILS.sendLang(sender, "manual-backup-all");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ public interface Database {

ItemStack[] getItemsFromBackup(int backupId);

// Null reason is any reason
int getSaves(UUID uuid, @Nullable String reason);

// Null reason is any reason
void removeLastSaves(UUID uuid, @Nullable String reason, int amount);

void fetchRestoreRequests(@NotNull UUID uuid);

void removeRestoreRequest(int restoreId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand All @@ -44,6 +45,7 @@ public abstract class Base implements Database {
private final HashBiMap<Integer, UUID> uuidCache = HashBiMap.create();
private final HashBiMap<Integer, String> reasonCache = HashBiMap.create();
private final HashBiMap<Integer, String> worldCache = HashBiMap.create();
private long lastClear = 0;

public abstract Connection getConnection();

Expand Down Expand Up @@ -591,6 +593,63 @@ public ItemStack[] getItemsFromBackup(int backupId) {
return null;
}

@Override
public int getSaves(UUID uuid, @Nullable String reason) {
String noReason = "SELECT COUNT(*) FROM axir_backups WHERE userId = ?;";
String withReason = "SELECT COUNT(*) FROM axir_backups WHERE userId = ? AND reasonId = ?;";
try (Connection connection = getConnection(); PreparedStatement statement = connection.prepareStatement(reason == null ? noReason : withReason)) {
statement.setInt(1, getUserId(uuid));
if (reason != null) {
statement.setInt(2, getReasonId(reason));
}
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return resultSet.getInt(1);
}

return 0;
}
} catch (SQLException exception) {
log.error("An unexpected error occurred while getting save-count for {}!", uuid, exception);
return -1;
}
}

@Override
public void removeLastSaves(UUID uuid, @Nullable String reason, int amount) {
final String noReason = "DELETE FROM axir_backups WHERE id IN (SELECT id FROM axir_backups WHERE userId = ? ORDER BY time ASC LIMIT ?);";
final String withReason = "DELETE FROM axir_backups WHERE id IN (SELECT id FROM axir_backups WHERE userId = ? AND reasonId = ? ORDER BY time ASC LIMIT ?);";
try (Connection connection = getConnection(); PreparedStatement statement = connection.prepareStatement(reason == null ? noReason : withReason)) {
if (reason == null) {
statement.setInt(1, getUserId(uuid));
statement.setInt(2, amount);
} else {
statement.setInt(1, getUserId(uuid));
statement.setInt(2, getReasonId(reason));
statement.setInt(3, amount);
}
statement.executeUpdate();
} catch (SQLException exception) {
log.error("An unexpected error occurred while removing last save for {}!", uuid, exception);
}

clean();
}

private void clean() {
if (System.currentTimeMillis() - lastClear < Duration.ofSeconds(60).toMillis()) {
return;
}
lastClear = System.currentTimeMillis();

final String sql2 = "DELETE FROM axir_storage WHERE id not IN (SELECT inventoryId FROM axir_backups WHERE inventoryId IS NOT NULL);";
try (Connection conn = getConnection(); PreparedStatement stmt = conn.prepareStatement(sql2)) {
stmt.executeUpdate();
} catch (SQLException exception) {
log.error("An unexpected error occurred while cleaning up!", exception);
}
}

@Override
public void fetchRestoreRequests(@NotNull UUID uuid) {
if (AxInventoryRestore.getDiscordAddon() == null) return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.artillexstudios.axinventoryrestore.listeners.impl;

import com.artillexstudios.axinventoryrestore.AxInventoryRestore;
import com.artillexstudios.axinventoryrestore.utils.BackupLimiter;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
Expand All @@ -25,5 +26,6 @@ public void onClose(@NotNull InventoryCloseEvent event) {
if (!CONFIG.getBoolean("enabled-backups.container-close", true)) return;
final String cause = event.getInventory().getType().name();
AxInventoryRestore.getDB().saveInventory((Player) event.getPlayer(), "CONTAINER_CLOSE", cause);
BackupLimiter.tryLimit(event.getPlayer().getUniqueId(), "container-close", "CONTAINER_CLOSE");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.artillexstudios.axinventoryrestore.listeners.impl;

import com.artillexstudios.axinventoryrestore.AxInventoryRestore;
import com.artillexstudios.axinventoryrestore.utils.BackupLimiter;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
Expand All @@ -23,5 +24,6 @@ public void onDeath(@NotNull PlayerDeathEvent event) {
}

AxInventoryRestore.getDB().saveInventory(player, "DEATH", cause);
BackupLimiter.tryLimit(player.getUniqueId(), "death", "DEATH");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.artillexstudios.axinventoryrestore.listeners.impl;

import com.artillexstudios.axinventoryrestore.AxInventoryRestore;
import com.artillexstudios.axinventoryrestore.utils.BackupLimiter;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
Expand All @@ -17,5 +18,6 @@ public void onClose(@NotNull InventoryCloseEvent event) {
if (event.getInventory().getType() != InventoryType.ENDER_CHEST) return;
if (!CONFIG.getBoolean("enabled-backups.ender-chest", true)) return;
AxInventoryRestore.getDB().saveInventory(event.getPlayer().getEnderChest().getStorageContents(), (Player) event.getPlayer(), "ENDER_CHEST", null);
BackupLimiter.tryLimit(event.getPlayer().getUniqueId(), "ender-chest", "ENDER_CHEST");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.artillexstudios.axinventoryrestore.listeners.impl;

import com.artillexstudios.axinventoryrestore.AxInventoryRestore;
import com.artillexstudios.axinventoryrestore.utils.BackupLimiter;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
Expand All @@ -18,5 +19,6 @@ public void onJoin(@NotNull PlayerJoinEvent event) {
AxInventoryRestore.getDB().fetchRestoreRequests(event.getPlayer().getUniqueId());
});
AxInventoryRestore.getDB().saveInventory(event.getPlayer(), "JOIN", null);
BackupLimiter.tryLimit(event.getPlayer().getUniqueId(), "join", "JOIN");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.artillexstudios.axinventoryrestore.listeners.impl;

import com.artillexstudios.axinventoryrestore.AxInventoryRestore;
import com.artillexstudios.axinventoryrestore.utils.BackupLimiter;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
Expand All @@ -14,5 +15,6 @@ public class QuitListener implements Listener {
public void onQuit(@NotNull PlayerQuitEvent event) {
if (!CONFIG.getBoolean("enabled-backups.quit", true)) return;
AxInventoryRestore.getDB().saveInventory(event.getPlayer(), "QUIT", null);
BackupLimiter.tryLimit(event.getPlayer().getUniqueId(), "quit", "QUIT");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.artillexstudios.axinventoryrestore.listeners.impl;

import com.artillexstudios.axinventoryrestore.AxInventoryRestore;
import com.artillexstudios.axinventoryrestore.utils.BackupLimiter;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
Expand All @@ -15,5 +16,6 @@ public void onQuit(@NotNull PlayerChangedWorldEvent event) {
if (!CONFIG.getBoolean("enabled-backups.world-change", true)) return;
final String cause = event.getFrom().getName() + " -> " + event.getPlayer().getWorld().getName();
AxInventoryRestore.getDB().saveInventory(event.getPlayer(), "WORLD_CHANGE", cause);
BackupLimiter.tryLimit(event.getPlayer().getUniqueId(), "world-change", "WORLD_CHANGE");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.artillexstudios.axinventoryrestore.schedulers;

import com.artillexstudios.axinventoryrestore.AxInventoryRestore;
import com.artillexstudios.axinventoryrestore.utils.BackupLimiter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

Expand Down Expand Up @@ -32,6 +33,7 @@ public static void start() {
future = executor.scheduleAtFixedRate(() -> {
for (Player player : Bukkit.getOnlinePlayers()) {
AxInventoryRestore.getDB().saveInventory(player, "AUTOMATIC", null);
BackupLimiter.tryLimit(player.getUniqueId(), "automatic", "AUTOMATIC");
}
}, backupTime, backupTime, TimeUnit.SECONDS);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.artillexstudios.axinventoryrestore.utils;

import com.artillexstudios.axinventoryrestore.AxInventoryRestore;

import java.util.UUID;

public class BackupLimiter {

public static void tryLimit(UUID uuid, String reason, String reason2) {
AxInventoryRestore.getThreadedQueue().submit(() -> {
int withReason = AxInventoryRestore.CONFIG.getInt("save-limits." + reason);
if (withReason != -1) {
int saves = AxInventoryRestore.getDB().getSaves(uuid, reason2);
int difference = withReason - saves;
if (difference <= 0) {
AxInventoryRestore.getDB().removeLastSaves(uuid, reason2, difference * (-1));
}
}

int total = AxInventoryRestore.CONFIG.getInt("save-limits.total");
if (total != -1) {
int saves = AxInventoryRestore.getDB().getSaves(uuid, null);
int difference = total - saves;
if (difference <= 0) {
AxInventoryRestore.getDB().removeLastSaves(uuid, null, difference * (-1));
}
}
});
}
}
16 changes: 15 additions & 1 deletion src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@ enabled-backups:
world-change: true
container-close: true

# how many saves should we allow per player in these categories?
# set to -1 to allow unlimited
# you can add your own categories here, that you save to via the api
save-limits:
ender-chest: -1
death: -1
join: -1
quit: -1
world-change: -1
container-close: -1
manual: -1
automatic: -1
total: -1

# check out the discord.yml for more info
enable-discord-addon: false

Expand All @@ -62,4 +76,4 @@ update-notifier:
on-join: true

# do not change this
version: 6
version: 7

0 comments on commit 33160ed

Please sign in to comment.