1
mirror of https://github.com/Shiewk/SModeration.git synced 2026-04-28 05:54:16 +02:00

Add gzip-compressed saving and loading system

This commit is contained in:
Shy
2024-06-09 10:55:32 +02:00
parent deee125e88
commit 9e59bae857
5 changed files with 137 additions and 15 deletions
@@ -8,24 +8,31 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import static org.bukkit.Bukkit.getPluginManager;
public final class SModeration extends JavaPlugin {
public static final PunishmentContainer container = new PunishmentContainer();
public static ComponentLogger LOGGER = null;
public static SModeration PLUGIN = null;
public static File SAVE_FILE = null;
public static final TextColor PRIMARY_COLOR = TextColor.color(212, 0, 255);
public static final TextColor SECONDARY_COLOR = TextColor.color(52, 143, 255);
public static final TextColor INACTIVE_COLOR = NamedTextColor.GRAY;
public static final TextComponent CHAT_PREFIX = Component.text("SM \u00BB ").color(SECONDARY_COLOR);
public static final TextComponent CHAT_PREFIX = Component.text("SM \u00BB ").color(PRIMARY_COLOR);
@Override
public void onLoad() {
LOGGER = getComponentLogger();
PLUGIN = this;
SAVE_FILE = new File(this.getDataFolder().getAbsolutePath() + "/container.gz");
}
@Override
@@ -67,5 +74,12 @@ public final class SModeration extends JavaPlugin {
assert unban != null;
unban.setExecutor(new UnbanCommand());
unban.setTabCompleter(new UnbanCommand());
container.load(SAVE_FILE);
}
@Override
public void onDisable() {
SModeration.container.save(SModeration.SAVE_FILE);
}
}
@@ -12,6 +12,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.world.WorldSaveEvent;
import static de.shiewk.smoderation.SModeration.CHAT_PREFIX;
@@ -59,4 +60,11 @@ public class PunishmentListener implements Listener {
}
}
}
@EventHandler
public void onWorldSave(WorldSaveEvent event){
if (event.getWorld().equals(Bukkit.getServer().getWorlds().get(0))){
SModeration.container.save(SModeration.SAVE_FILE);
}
}
}
@@ -9,7 +9,10 @@ import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import java.nio.ByteBuffer;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import static de.shiewk.smoderation.SModeration.*;
@@ -25,12 +28,41 @@ public class Punishment {
private UUID undoneBy;
public Punishment(PunishmentType type, long time, long until, UUID by, UUID to, String reason) {
this(type, time, until, by, to, reason, null);
}
private Punishment(PunishmentType type, long time, long until, UUID by, UUID to, String reason, UUID undoneBy) {
this.type = type;
this.time = time;
this.until = until;
this.by = by;
this.to = to;
this.reason = reason;
this.undoneBy = undoneBy;
}
private static byte[] readStreamInternal(InputStream stream, int len) throws IOException {
final byte[] bytes = stream.readNBytes(len);
if (bytes.length != len){
throw new EOFException("Stream has ended before enough bytes were read");
}
return bytes;
}
public static Punishment load(InputStream in) throws IOException {
PunishmentType type = PunishmentType.values()[ByteUtil.bytesToInt(readStreamInternal(in, 4))];
long time = ByteUtil.bytesToLong(readStreamInternal(in, 8));
long until = ByteUtil.bytesToLong(readStreamInternal(in, 8));
UUID by = ByteUtil.bytesToUuid(readStreamInternal(in, 16));
UUID to = ByteUtil.bytesToUuid(readStreamInternal(in, 16));
int reasonLen = ByteUtil.bytesToInt(readStreamInternal(in, 4));
String reason = new String(readStreamInternal(in, reasonLen));
UUID undoneBy = null;
boolean undone = in.read() == 1;
if (undone){
undoneBy = ByteUtil.bytesToUuid(readStreamInternal(in, 16));
}
return new Punishment(type, time, until, by, to, reason, undoneBy);
}
public boolean wasUndone(){
@@ -66,21 +98,19 @@ public class Punishment {
private static final int BUFFER_LENGTH = 56;
public byte[] toBytes(){
public void writeBytes(OutputStream stream) throws IOException {
stream.write(ByteUtil.intToBytes(type.ordinal()));
stream.write(ByteUtil.longToBytes(time));
stream.write(ByteUtil.longToBytes(until));
stream.write(ByteUtil.uuidToBytes(by));
stream.write(ByteUtil.uuidToBytes(to));
final byte[] reasonBytes = reason.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_LENGTH + reasonBytes.length + (undoneBy != null ? 17 : 1));
buffer.putInt(0, type.ordinal());
buffer.putLong(4, time);
buffer.putLong(12, until);
buffer.put(20, ByteUtil.uuidToBytes(by));
buffer.put(36, ByteUtil.uuidToBytes(to));
buffer.putInt(40, reason.length());
buffer.put(44, reasonBytes);
buffer.put(44+reasonBytes.length, undoneBy != null ? (byte) 1 : (byte) 0);
if (undoneBy != null){
buffer.put(44+reasonBytes.length+1, ByteUtil.uuidToBytes(undoneBy));
stream.write(ByteUtil.intToBytes(reasonBytes.length));
stream.write(reasonBytes);
stream.write(wasUndone() ? 1 : 0);
if (wasUndone()){
stream.write(ByteUtil.uuidToBytes(undoneBy));
}
return buffer.array();
}
private Component undoMessage(){
@@ -1,17 +1,22 @@
package de.shiewk.smoderation.storage;
import de.shiewk.smoderation.SModeration;
import de.shiewk.smoderation.punishments.Punishment;
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class PunishmentContainer {
@@ -68,4 +73,54 @@ public class PunishmentContainer {
public ArrayList<Punishment> copy() {
return new ArrayList<>(punishments);
}
public void load(File file){
final ComponentLogger logger = SModeration.LOGGER;
try {
logger.info("Loading from {}", file.getPath());
if (!file.isFile()){
logger.warn("The file does not exist.");
} else {
try (FileInputStream fin = new FileInputStream(file)){
GZIPInputStream gzin = new GZIPInputStream(fin);
while (gzin.available() > 0){
add(Punishment.load(gzin));
}
}
logger.info("Successfully loaded {} items.", punishments.size());
}
} catch (EOFException e) {
logger.error("The file was not correctly saved, {} items could be recovered!", this.punishments.size());
} catch (IOException e){
logger.error("An error occurred while loading: {}", e.toString());
for (StackTraceElement stackTraceElement : e.getStackTrace()) {
logger.error(stackTraceElement.toString());
}
}
}
public void save(File file) {
final ComponentLogger logger = SModeration.LOGGER;
try {
logger.info("Saving to {}", file.getPath());
if (!file.isFile()){
file.mkdirs();
file.delete();
file.createNewFile();
}
try (FileOutputStream outputStream = new FileOutputStream(file)) {
GZIPOutputStream gzout = new GZIPOutputStream(outputStream);
for (Punishment punishment : copy()) {
punishment.writeBytes(gzout);
}
gzout.close();
}
logger.info("Successfully saved.");
} catch (IOException e){
logger.error("An error occurred while saving: {}", e.toString());
for (StackTraceElement stackTraceElement : e.getStackTrace()) {
logger.error(stackTraceElement.toString());
}
}
}
}
@@ -42,4 +42,19 @@ public abstract class ByteUtil {
long m = bytesToLong(new byte[]{ i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7] });
return new UUID(m, l);
}
public static int bytesToInt(byte[] bytes) {
if (bytes.length != 4){
throw new IllegalArgumentException("length must be 4");
}
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.put(0, bytes);
return buffer.getInt(0);
}
public static byte[] intToBytes(int value) {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.putInt(value);
return buffer.array();
}
}