diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerLifecycleEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerLifecycleEvents.java index abd971e850..769d8e9b96 100644 --- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerLifecycleEvents.java +++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerLifecycleEvents.java @@ -107,6 +107,24 @@ private ServerLifecycleEvents() { } }); + /** + * Called before a Minecraft server begins saving data. + */ + public static final Event BEFORE_SAVE = EventFactory.createArrayBacked(BeforeSave.class, callbacks -> (server, flush, force) -> { + for (BeforeSave callback : callbacks) { + callback.onBeforeSave(server, flush, force); + } + }); + + /** + * Called after a Minecraft server finishes saving data. + */ + public static final Event AFTER_SAVE = EventFactory.createArrayBacked(AfterSave.class, callbacks -> (server, flush, force) -> { + for (AfterSave callback : callbacks) { + callback.onAfterSave(server, flush, force); + } + }); + @FunctionalInterface public interface ServerStarting { void onServerStarting(MinecraftServer server); @@ -160,4 +178,28 @@ public interface EndDataPackReload { */ void endDataPackReload(MinecraftServer server, LifecycledResourceManager resourceManager, boolean success); } + + @FunctionalInterface + public interface BeforeSave { + /** + * Called before a Minecraft server begins saving data. + * + * @param server the server + * @param flush is true when all chunks are being written to disk, server will likely freeze during this time + * @param force whether servers that have save-off set should save + */ + void onBeforeSave(MinecraftServer server, boolean flush, boolean force); + } + + @FunctionalInterface + public interface AfterSave { + /** + * Called before a Minecraft server begins saving data. + * + * @param server the server + * @param flush is true when all chunks are being written to disk, server will likely freeze during this time + * @param force whether servers that have save-off set should save + */ + void onAfterSave(MinecraftServer server, boolean flush, boolean force); + } } diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/MinecraftServerMixin.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/MinecraftServerMixin.java index 04cffbe7e3..2dcbce66e3 100644 --- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/MinecraftServerMixin.java +++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/MinecraftServerMixin.java @@ -101,4 +101,14 @@ private void endResourceReload(Collection collection, CallbackInfoReturn return value; }, (MinecraftServer) (Object) this); } + + @Inject(method = "save", at = @At("HEAD")) + private void startSave(boolean suppressLogs, boolean flush, boolean force, CallbackInfoReturnable cir) { + ServerLifecycleEvents.BEFORE_SAVE.invoker().onBeforeSave((MinecraftServer) (Object) this, flush, force); + } + + @Inject(method = "save", at = @At("TAIL")) + private void endSave(boolean suppressLogs, boolean flush, boolean force, CallbackInfoReturnable cir) { + ServerLifecycleEvents.AFTER_SAVE.invoker().onAfterSave((MinecraftServer) (Object) this, flush, force); + } } diff --git a/fabric-lifecycle-events-v1/src/testmod/java/net/fabricmc/fabric/test/event/lifecycle/ServerLifecycleTests.java b/fabric-lifecycle-events-v1/src/testmod/java/net/fabricmc/fabric/test/event/lifecycle/ServerLifecycleTests.java index 3294bd2548..ea1e236fc8 100644 --- a/fabric-lifecycle-events-v1/src/testmod/java/net/fabricmc/fabric/test/event/lifecycle/ServerLifecycleTests.java +++ b/fabric-lifecycle-events-v1/src/testmod/java/net/fabricmc/fabric/test/event/lifecycle/ServerLifecycleTests.java @@ -54,5 +54,13 @@ public void onInitialize() { ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.register((player, joined) -> { LOGGER.info("SyncDataPackContents received for {}", joined ? "join" : "reload"); }); + + ServerLifecycleEvents.BEFORE_SAVE.register((server, flush, force) -> { + LOGGER.info("Starting Save with settings: Flush:{} Force:{}", flush, force); + }); + + ServerLifecycleEvents.AFTER_SAVE.register((server, flush, force) -> { + LOGGER.info("Save Finished with settings: Flush:{} Force:{}", flush, force); + }); } }