diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index 6a84267..25d675e 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -3,6 +3,7 @@ package com.extendedae_plus; import appeng.api.storage.StorageCells; import appeng.menu.locator.MenuLocators; import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellHandler; +import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellInventory; import com.extendedae_plus.client.ClientRegistrar; import com.extendedae_plus.config.ModConfig; import com.extendedae_plus.init.*; @@ -54,6 +55,9 @@ public class ExtendedAEPlus { MinecraftForge.EVENT_BUS.addListener(ExtendedAEPlus::onLevelLoad); // 注册通用配置 ModConfig.init(); + // 注册 InfinityBigIntegerCellInventory 的事件监听(tick flush 与停止时 flush) + MinecraftForge.EVENT_BUS.addListener(InfinityBigIntegerCellInventory::onServerTick); + MinecraftForge.EVENT_BUS.addListener(InfinityBigIntegerCellInventory::onServerStopping); // ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigs.COMMON_SPEC); } 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 d46cf2d..2cbb417 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 @@ -17,8 +17,8 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.TickEvent; +import net.minecraftforge.event.server.ServerStoppingEvent; import java.math.BigDecimal; import java.math.BigInteger; @@ -27,6 +27,7 @@ import java.text.DecimalFormat; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; +import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; /** * InfinityBigIntegerCellInventory *
@@ -50,15 +51,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 数字格式化对象,保留两位小数(复用以减少对象分配)
private static final DecimalFormat DF = new DecimalFormat("#.##");
- static {
- // 在类加载时注册服务器 tick 监听器,用于在主线程合并写入
- try {
- MinecraftForge.EVENT_BUS.addListener(InfinityBigIntegerCellInventory::onServerTick);
- } catch (Throwable ignored) {
- // 保守降级:若注册失败,不阻塞实例化
- }
- }
-
// 关联的 ItemStack(含可能的 uuid NBT)
private final ItemStack stack;
// AE2 提供的保存提供者,用于在容器中批量保存时触发回调
@@ -97,7 +89,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
}
// 服务器 tick 回调:合并并执行待持久化项
- private static void onServerTick(TickEvent.ServerTickEvent event) {
+ public static void onServerTick(TickEvent.ServerTickEvent event) {
if (event.phase != TickEvent.Phase.END) return;
InfinityBigIntegerCellInventory inv;
// 处理本次 tick 中的全部待持久化项
@@ -107,11 +99,32 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
inv.persist();
}
} catch (Throwable ignored) {
- // 忽略单项错误,继续处理其余队列
+ LOGGER.info("InfinityBigIntegerCellInventory onServerTick error: {}", ignored.getMessage());
}
}
}
+ // 在服务器停止时被调用,立即强制持久化队列中的所有实例
+ public static void onServerStopping(ServerStoppingEvent event) {
+ 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) {
// 使用局部 DF(非线程安全),但 Minecraft 通常在主线程运行
@@ -240,12 +253,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 获取所有可用的物品堆栈及其数量
@Override
public void getAvailableStacks(KeyCounter out) {
- // 使用饱和(saturating)加法将 BigInteger 值转换为 long 并安全地累加到 KeyCounter 中。
- // 问题背景:当同一物品存在于多个 cell 中,AE2 的 KeyCounter 使用 long 来记录数量,
- // 若简单将单个 cell 的超长值截断为 Long.MAX_VALUE 并直接 add,多个 cell 的合并会导致
- // 原本代表 "大于 long" 的值被重复添加而导致读取异常。解决方案:每次向 KeyCounter 添加前,
- // 先读取当前计数器中的已有值(long),并使用 BigInteger 做饱和加法后再写回为 long,避免中间溢出。
-
BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE);
Object2ObjectMap