From d6ac6e8045dcb54a61f478ab61d0cfab84df526c Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Sat, 20 Sep 2025 16:29:46 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=BF=9B=E4=B8=80=E6=AD=A5=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E6=B8=B8=E6=88=8F=E5=9C=A8=E7=89=B9=E6=AE=8A=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E6=83=85=E5=86=B5=E4=B8=8B=E8=83=BD=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E6=95=B0=E6=8D=AE=EF=BC=8C=E5=A6=82Alt=20F4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../InfinityBigIntegerCellInventory.java | 144 ++++++++++-------- .../util/storage/InfinityStorageManager.java | 19 +++ 3 files changed, 104 insertions(+), 61 deletions(-) diff --git a/gradle.properties b/gradle.properties index 32815b9..2c5731e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G loom.platform = forge # Mod properties -mod_version = 1.4.2-fix +mod_version = 1.4.2-fix1 maven_group = com.extendedae_plus archives_name = extendedae_plus diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java index e678dfc..efbf16b 100644 --- a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java @@ -21,6 +21,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.ItemStack; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.server.ServerStoppingEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; import java.math.BigDecimal; import java.math.BigInteger; @@ -88,54 +89,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell { return InfinityStorageManager.INSTANCE; } - // 服务器 tick 回调:合并并执行待持久化项 - public static void onServerTick(TickEvent.ServerTickEvent event) { - if (event.phase != TickEvent.Phase.END) return; - InfinityBigIntegerCellInventory inv; - // 处理本次 tick 中的全部待持久化项 - while ((inv = PENDING_PERSIST.poll()) != null) { - try { - if (!inv.isPersisted) { - inv.persist(); - } - } catch (Throwable ignored) { - LOGGER.info("InfinityBigIntegerCellInventory onServerTick error: {}", ignored.getMessage()); - } - } - } - - // 在服务器停止时被调用,立即强制持久化队列中的所有实例 - public static void onServerStopping(ServerStoppingEvent event) { - // 尝试在服务端停止流程开始时初始化 SavedData(确保 INSTANCE 可用以便后续持久化) - try { - MinecraftServer server = event.getServer(); - if (server != null) { - for (ServerLevel level : server.getAllLevels()) { - InfinityStorageManager.getForLevel(level); - } - } - } catch (Throwable ignored) { - } - - InfinityBigIntegerCellInventory inv; - while ((inv = PENDING_PERSIST.poll()) != null) { - try { - if (!inv.isPersisted) { - inv.persist(); - } - } catch (Throwable ignored) { - LOGGER.info("InfinityBigIntegerCellInventory onServerStopping error1: {}", ignored.getMessage()); - } - } - // 将全局存储管理器标记为脏以确保 SavedData 被写回 - try { - var stor = getStorageInstance(); - if (stor != null) stor.setDirty(); - } catch (Throwable ignored) { - LOGGER.info("InfinityBigIntegerCellInventory onServerStopping error2: {}", ignored.getMessage()); - } - } - // 将 BigInteger 格式化为带单位的字符串,保留两位小数 public static String formatBigInteger(BigInteger number) { // 使用方法局部的 DecimalFormat,避免静态共享的非线程安全问题 @@ -252,12 +205,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell { if (corruptedTag) { this.saveChanges(); } - // 打印加载后的摘要日志 - try { - var uuid = this.getUUID(); - LOGGER.info("Loaded cell {}: types={}, totalCached={}", uuid, this.getCellStoredMap().size(), this.getTotalStorage()); - } catch (Throwable ignored) { - } } // 标记数据需要保存,并通知容器或直接持久化 @@ -378,12 +325,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell { stack.getOrCreateTag().putInt("types", typesCount); } isPersisted = true; - // 打印持久化摘要日志 - try { - var uuid = this.getUUID(); - LOGGER.info("Persisted cell {}: types={}, totalCached={}", uuid, this.getCellStoredMap().size(), this.getTotalStorage()); - } catch (Throwable ignored) { - } } // 插入物品到存储单元 @@ -464,4 +405,87 @@ public class InfinityBigIntegerCellInventory implements StorageCell { // 使用缓存的 totalStored,避免每次全表扫描 return formatBigInteger(totalStored); } + + /** 定时 tick 保存计数器 */ + private static int SAVE_TICK_COUNTER = 0; + + /** tick 间隔,单位为服务器 tick(20 tick ≈ 1 秒) */ + private static final int SAVE_TICK_INTERVAL = 20; // 约30秒 + + /** 服务器 tick 事件:处理队列并定时保存 */ + @SubscribeEvent + public static void onServerTick(TickEvent.ServerTickEvent event) { + if (event.phase != TickEvent.Phase.END) return; + + // 处理待持久化队列 + InfinityBigIntegerCellInventory inv; + while ((inv = PENDING_PERSIST.poll()) != null) { + try { + if (!inv.isPersisted) { + inv.persist(); + } + } catch (Throwable ex) { + LOGGER.info("InfinityBigIntegerCellInventory onServerTick error: {}", ex.getMessage()); + } + } + + // 定时标记全局存储为脏 + try { + if (++SAVE_TICK_COUNTER >= SAVE_TICK_INTERVAL) { + SAVE_TICK_COUNTER = 0; + if (InfinityStorageManager.INSTANCE != null) { + InfinityStorageManager.INSTANCE.setDirty(); + } + } + } catch (Throwable ex) { + LOGGER.info("InfinityBigIntegerCellInventory tick dirty set error: {}", ex.getMessage()); + } + } + + // 在服务器停止时被调用,立即强制持久化队列中的所有实例 + @SubscribeEvent + public static void onServerStopping(ServerStoppingEvent event) { + // 尝试在服务端停止流程开始时初始化 SavedData(确保 INSTANCE 可用以便后续持久化) + try { + MinecraftServer server = event.getServer(); + if (server != null) { + for (ServerLevel level : server.getAllLevels()) { + InfinityStorageManager.getForLevel(level); + } + } + } catch (Throwable ignored) { + LOGGER.info("InfinityBigIntegerCellInventory onServerStopping init error: {}", ignored.getMessage()); + } + + InfinityBigIntegerCellInventory inv; + while ((inv = PENDING_PERSIST.poll()) != null) { + try { + if (!inv.isPersisted) { + inv.persist(); + } + } catch (Throwable ex) { + LOGGER.info("InfinityBigIntegerCellInventory onServerStopping persist error: {}", ex.getMessage()); } + } + + // 强制写回磁盘,确保直接关闭游戏也能保存 + try { + InfinityStorageManager mgr = InfinityStorageManager.INSTANCE; + if (mgr != null) { + MinecraftServer server = event.getServer(); + if (server != null) { + for (ServerLevel level : server.getAllLevels()) { + try { + mgr.forceSaveAll(level); + LOGGER.info("Stop forceSaveAll for level {}", level.dimension().location()); + } catch (Throwable ex) { + LOGGER.info("InfinityBigIntegerCellInventory forceSaveAll error for level {}: {}", + level.dimension().location(), ex.getMessage()); + } + } + } + } + } catch (Throwable ex) { + LOGGER.info("InfinityBigIntegerCellInventory onServerStopping forceSaveAll error: {}", ex.getMessage()); + } + } } diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java index 24bbe28..5f8f3fe 100644 --- a/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java @@ -189,4 +189,23 @@ public class InfinityStorageManager extends SavedData { cells.remove(uuid); setDirty(); } + + /** + * 强制将内存中的所有 InfinityDataStorage 写入磁盘 + * 可在服务器停止或 tick 中调用,确保数据不会丢失 + */ + public void forceSaveAll(ServerLevel level) { + try { + if (level != null) { + this.setDirty(); + CompoundTag nbt = new CompoundTag(); + this.save(nbt); + File file = level.getServer().getWorldPath(new LevelResource("data")) + .resolve(FILE_NAME + ".dat").toFile(); + NbtIo.writeCompressed(nbt, file); + } + } catch (Throwable ex) { + LOGGER.info("InfinityStorageManager forceSaveAll error: {}", ex.getMessage()); + } + } }