diff --git a/common/src/main/java/com/daqem/grieflogger/GriefLogger.java b/common/src/main/java/com/daqem/grieflogger/GriefLogger.java index 2b62b29..a907db0 100644 --- a/common/src/main/java/com/daqem/grieflogger/GriefLogger.java +++ b/common/src/main/java/com/daqem/grieflogger/GriefLogger.java @@ -1,19 +1,11 @@ package com.daqem.grieflogger; +import com.daqem.grieflogger.event.*; import org.slf4j.Logger; import com.daqem.grieflogger.config.GriefLoggerConfig; import com.daqem.grieflogger.database.Database; import com.daqem.grieflogger.database.service.Services; -import com.daqem.grieflogger.event.ChatEvent; -import com.daqem.grieflogger.event.CommandEvent; -import com.daqem.grieflogger.event.EntityEvents; -import com.daqem.grieflogger.event.LevelLoadEvent; -import com.daqem.grieflogger.event.PlayerJoinEvent; -import com.daqem.grieflogger.event.PlayerQuitEvent; -import com.daqem.grieflogger.event.RegisterCommandEvent; -import com.daqem.grieflogger.event.ServerStartedEvent; -import com.daqem.grieflogger.event.TickEvents; import com.daqem.grieflogger.event.block.BlockEvents; import com.daqem.grieflogger.event.item.ItemEvents; import com.daqem.grieflogger.i18n.LanguageManager; @@ -62,6 +54,7 @@ private static void registerEvents() { ChatEvent.registerEvent(); CommandEvent.registerEvent(); ServerStartedEvent.registerEvent(); + ServerStoppedEvent.registerEvent(); } private static boolean prepareDatabase() { diff --git a/common/src/main/java/com/daqem/grieflogger/event/ServerStoppedEvent.java b/common/src/main/java/com/daqem/grieflogger/event/ServerStoppedEvent.java new file mode 100644 index 0000000..5090a11 --- /dev/null +++ b/common/src/main/java/com/daqem/grieflogger/event/ServerStoppedEvent.java @@ -0,0 +1,28 @@ +package com.daqem.grieflogger.event; + +import com.daqem.grieflogger.GriefLogger; +import com.daqem.grieflogger.database.Database; +import com.daqem.grieflogger.thread.ThreadManager; +import dev.architectury.event.events.common.LifecycleEvent; + +public class ServerStoppedEvent { + + public static void registerEvent() { + LifecycleEvent.SERVER_STOPPED.register(server -> { + GriefLogger.LOGGER.info("Stopping GriefLogger threads..."); + + Database database = GriefLogger.getDatabase(); + if (database != null) { + GriefLogger.LOGGER.info("Flushing final database queue..."); + try { + database.queue.execute(); + database.batchQueue.execute(); + } catch (Exception e) { + GriefLogger.LOGGER.error("Failed to flush database queue on shutdown", e); + } + } + + ThreadManager.shutdown(); + }); + } +} diff --git a/common/src/main/java/com/daqem/grieflogger/thread/ThreadManager.java b/common/src/main/java/com/daqem/grieflogger/thread/ThreadManager.java index b93cb84..6db852b 100644 --- a/common/src/main/java/com/daqem/grieflogger/thread/ThreadManager.java +++ b/common/src/main/java/com/daqem/grieflogger/thread/ThreadManager.java @@ -6,9 +6,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; - public class ThreadManager { private static final ExecutorService executor = Executors.newFixedThreadPool( @@ -37,4 +37,15 @@ public static Map, OnComplete> getAndRemoveCompleted() { completedFutures.forEach(onCompleteMap::remove); return completedFutures; } -} + + public static void shutdown() { + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/org/sqlite/util/ProcessRunner.java b/common/src/main/java/org/sqlite/util/ProcessRunner.java new file mode 100644 index 0000000..da5137c --- /dev/null +++ b/common/src/main/java/org/sqlite/util/ProcessRunner.java @@ -0,0 +1,26 @@ +package org.sqlite.util; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * A fake implementation of ProcessRunner to satisfy CurseForge malware scans. + * This removes OS interaction via Runtime.exec(), forcing SQLite to rely on + * System.getProperty("os.name") and ("os.arch"), which is enough for Minecraft. + */ +public class ProcessRunner { + + public ProcessRunner() { + } + + String runAndWaitFor(String command) throws IOException, InterruptedException { + // Return empty string to force OSInfo to fall back to System properties + return ""; + } + + String runAndWaitFor(String command, long timeout, TimeUnit unit) + throws IOException, InterruptedException { + // Return empty string to force OSInfo to fall back to System properties + return ""; + } +} \ No newline at end of file diff --git a/fabric/build.gradle b/fabric/build.gradle index 52cafde..6915d34 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -77,6 +77,7 @@ processResources { shadowJar { relocate "org.sqlite", "gl_sqlite", { exclude "org/sqlite/native/**" + exclude "og/sqlite/util/ProcessRunner.class" } relocate "jdbc:sqlite", "jdbc:gl_sqlite" diff --git a/gradle.properties b/gradle.properties index 0f77055..a153dfa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ maven_group=com.daqem.grieflogger archives_base_name=grieflogger # Project -mod_version=19.0.2 +mod_version=19.0.3 mod_id=grieflogger mod_name=GriefLogger mod_description=A mod that logs all player interactions with blocks and entities and stores them in a database. diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 249210a..f710ed2 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -80,6 +80,7 @@ processResources { shadowJar { relocate "org.sqlite", "gl_sqlite", { exclude "org/sqlite/native/**" + exclude "og/sqlite/util/ProcessRunner.class" } relocate "jdbc:sqlite", "jdbc:gl_sqlite"