diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java
index 25d675e..ca77fbf 100644
--- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java
+++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java
@@ -53,12 +53,11 @@ public class ExtendedAEPlus {
// 注册到Forge事件总线
MinecraftForge.EVENT_BUS.register(this);
MinecraftForge.EVENT_BUS.addListener(ExtendedAEPlus::onLevelLoad);
- // 注册通用配置
- ModConfig.init();
- // 注册 InfinityBigIntegerCellInventory 的事件监听(tick flush 与停止时 flush)
+ // 注册每秒合并持久化队列的事件监听(Server tick end + stopping)
MinecraftForge.EVENT_BUS.addListener(InfinityBigIntegerCellInventory::onServerTick);
MinecraftForge.EVENT_BUS.addListener(InfinityBigIntegerCellInventory::onServerStopping);
-// ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigs.COMMON_SPEC);
+ // 注册通用配置
+ ModConfig.init();
}
/**
@@ -120,7 +119,8 @@ public class ExtendedAEPlus {
// 在世界加载时注册/加载 SavedData
private static void onLevelLoad(LevelEvent.Load event) {
if (event.getLevel() instanceof ServerLevel serverLevel) {
- InfinityStorageManager.getForLevel(serverLevel);
+ // 初始化自定义的文件 I/O 存储管理器
+ InfinityStorageManager.INSTANCE.initFromWorld(serverLevel);
}
}
}
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 2cbb417..d23c236 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
@@ -24,10 +24,10 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.DecimalFormat;
+import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
-import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
/**
* InfinityBigIntegerCellInventory
*
@@ -48,6 +48,8 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 待持久化队列(用于 debounce:在服务器 tick 中合并持久化)
private static final ConcurrentLinkedQueue PENDING_PERSIST = new ConcurrentLinkedQueue<>();
+ // 用于按 tick 计数,每 20 tick(约 1 秒)触发一次合并写入
+ private static int TICK_COUNTER = 0;
// 数字格式化对象,保留两位小数(复用以减少对象分配)
private static final DecimalFormat DF = new DecimalFormat("#.##");
@@ -59,8 +61,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
private Object2ObjectMap storedMap = null;
// 标记是否已持久化到 SavedData
private boolean isPersisted = true;
- // 缓存的总存储量,避免每次调用进行全表扫描
- private BigInteger totalStored = BigInteger.ZERO;
+
/**
* 私有构造器:通过 createInventory 工厂方法调用
@@ -70,59 +71,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
*/
private InfinityBigIntegerCellInventory(ItemStack stack, ISaveProvider saveProvider) {
this.stack = stack;
- container = saveProvider;
- // 不在构造时创建 storedMap,推迟到实际访问或首次写入时初始化
+ this.container = saveProvider;
this.storedMap = null;
- }
-
- // 创建存储单元库存实例的静态方法
- static InfinityBigIntegerCellInventory createInventory(ItemStack stack, ISaveProvider saveProvider) {
- if (stack.getItem() instanceof InfinityBigIntegerCellItem) {
- return new InfinityBigIntegerCellInventory(stack, saveProvider);
- }
- return null;
- }
-
- // 获取全局存储实例
- private static InfinityStorageManager getStorageInstance() {
- 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) {
- 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());
- }
+ initData();
}
// 将 BigInteger 格式化为带单位的字符串,保留两位小数
@@ -142,14 +93,24 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
return DF.format(bd.doubleValue()) + units[idx];
}
+ // 创建存储单元库存实例的静态方法
+ static InfinityBigIntegerCellInventory createInventory(ItemStack stack, ISaveProvider saveProvider) {
+ return new InfinityBigIntegerCellInventory(stack, saveProvider);
+ }
+
+ private void initData() {
+ if (!hasUUID()) {
+ getCellStoredMap();
+ }
+ }
+
// 获取当前存储单元的数据存储对象
private InfinityDataStorage getCellStorage() {
if (this.getUUID() == null) {
// 如果没有UUID,返回空存储
return InfinityDataStorage.EMPTY;
} else {
- // 否则获取或创建对应UUID的存储
- return getStorageInstance().getOrCreateCell(getUUID());
+ return InfinityStorageManager.INSTANCE.getOrCreateCell(this.getUUID());
}
}
@@ -176,34 +137,37 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 判断物品堆栈是否有UUID
public boolean hasUUID() {
- return stack.hasTag() && stack.getOrCreateTag().contains("uuid");
+ return this.stack.hasTag() && this.stack.getOrCreateTag().contains("uuid");
}
// 获取物品堆栈的UUID
public UUID getUUID() {
- if (this.hasUUID())
- return stack.getOrCreateTag().getUUID("uuid");
- else
+ if (this.hasUUID()) {
+ return this.stack.getOrCreateTag().getUUID("uuid");
+ } else {
return null;
+ }
}
// 获取或初始化存储映射
private Object2ObjectMap getCellStoredMap() {
- if (storedMap == null) {
- storedMap = new Object2ObjectOpenHashMap<>();
+ if (this.storedMap == null) {
+ this.storedMap = new Object2ObjectOpenHashMap<>();
this.loadCellStoredMap();
}
- return storedMap;
+ return this.storedMap;
}
// 从存储中加载物品映射
private void loadCellStoredMap() {
boolean corruptedTag = false; // 标记数据是否损坏
- if (!stack.hasTag()) return;
+ if (!this.stack.hasTag())
+ return;
ListTag keys = this.getCellStorage().keys;
ListTag amounts = this.getCellStorage().amounts;
- int len = Math.min(keys.size(), amounts.size());
- for (int i = 0; i < len; i++) {
+
+
+ for (int i = 0; i < amounts.size(); i++) {
AEKey key = AEKey.fromTagGeneric(keys.getCompound(i));
CompoundTag amtTag = amounts.getCompound(i);
try {
@@ -221,15 +185,13 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
corruptedTag = true;
} else {
// storedMap 已在 getCellStoredMap() 中初始化,直接使用字段以避免额外方法开销
- storedMap.put(key, amount);
- // 更新缓存的总数
- totalStored = totalStored.add(amount);
+ getCellStoredMap().put(key, amount);
}
} catch (NumberFormatException ex) {
corruptedTag = true;
}
}
- // 如果有损坏,保存修正后的数据
+ // 如果有损坏,尝试保存修正后的数据;若全局管理器尚未就绪则保守处理
if (corruptedTag) {
this.saveChanges();
}
@@ -238,14 +200,37 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 标记数据需要保存,并通知容器或直接持久化
private void saveChanges() {
// 标记为未持久化,交由容器或延迟任务合并写入以减少 I/O
- isPersisted = false;
- if (container != null) {
- // 当存在容器时,优先让容器统一处理持久化
- container.saveChanges();
- } else {
- // 如果没有容器,入队等待服务器 tick 在主线程统一持久化,避免频繁 I/O
- if (!PENDING_PERSIST.contains(this)) {
- PENDING_PERSIST.offer(this);
+ this.isPersisted = false;
+ // 将本实例加入待处理队列(去重)
+ if (!PENDING_PERSIST.contains(this)) {
+ PENDING_PERSIST.add(this);
+ }
+ if (this.container != null) {
+ // 当存在容器时,仍然通知容器以便 AE2 在合并时回调 persist()
+ this.container.saveChanges();
+ }
+ }
+
+ /**
+ * 每个服务器 tick 调用一次,用于按秒合并并执行待持久化项的 persist()
+ */
+ public static void onServerTick(TickEvent.ServerTickEvent event) {
+ if (event.phase != TickEvent.Phase.END) return;
+ TICK_COUNTER++;
+ if (TICK_COUNTER % 20 != 0) return; // 每 20 tick(约 1 秒)执行一次
+ onServerStopping(null);
+ }
+
+ /**
+ * 在服务器停止时强制刷新所有待持久化项
+ */
+ public static void onServerStopping(ServerStoppingEvent event) {
+ InfinityBigIntegerCellInventory inv;
+ while ((inv = PENDING_PERSIST.poll()) != null) {
+ try {
+ inv.persist();
+ } catch (Exception e) {
+ e.printStackTrace();
}
}
}
@@ -287,20 +272,25 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 持久化存储单元数据到全局存储
@Override
public void persist() {
- if (this.isPersisted)
+ if (this.isPersisted) {
return;
+ }
Object2ObjectMap map = this.getCellStoredMap();
if (map.isEmpty()) {
- // 如果存储为空,移除UUID和全局存储中的数据
+ // 如果存储为空,保守处理:写回空的 persisted 数据但不要从 ItemStack 上移除 uuid
if (this.hasUUID()) {
- getStorageInstance().removeCell(getUUID());
- if (stack.getTag() != null) {
- stack.getTag().remove("uuid");
- // 移除缓存的 total 字段
- stack.getTag().remove("total");
+ // 如果存储为空,移除UUID和全局存储中的数据,并清理缓存的 types/total
+ if (hasUUID()) {
+ InfinityStorageManager.INSTANCE.removeCell(getUUID());
+ if (this.stack.getTag() != null) {
+ this.stack.getTag().remove("uuid");
+ this.stack.getTag().remove("types");
+ this.stack.getTag().remove("total");
+ }
+ initData();
}
+ return;
}
- return;
}
// 构建要保存的Key和数量列表(混合表示:long 或 string)
ListTag amountTags = new ListTag();
@@ -318,42 +308,58 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
amountTags.add(amt);
}
}
- // 如果没有Key,更新为空存储,否则保存数据
if (keys.isEmpty()) {
- getStorageInstance().updateCell(this.getUUID(), new InfinityDataStorage());
+ InfinityStorageManager.INSTANCE.updateCell(this.getUUID(), new InfinityDataStorage());
+ // 清理缓存
+ if (this.stack.getTag() != null) {
+ this.stack.getTag().remove("types");
+ this.stack.getTag().remove("total");
+ }
} else {
// amounts 现在为 CompoundTag 列表
- getStorageInstance().modifyCell(this.getUUID(), keys, amountTags);
- }
- // 将缓存的 totalStored 同步到 ItemStack 的 NBT,优先使用 long
- if (stack.getOrCreateTag() != null) {
- if (totalStored.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0) {
- stack.getOrCreateTag().putLong("total", totalStored.longValue());
- } else {
- stack.getOrCreateTag().putString("total", totalStored.toString());
+ InfinityStorageManager.INSTANCE.modifyCell(this.getUUID(), keys, amountTags);
+ // 缓存类型数量与总量到 ItemStack 的 NBT,避免每次 tooltip 或展示时重新统计
+ try {
+ if (this.stack.getTag() == null) {
+ this.stack.setTag(new CompoundTag());
+ }
+ int typesCount = keys.size();
+ this.stack.getOrCreateTag().putInt("types", typesCount);
+ BigInteger total = BigInteger.ZERO;
+ for (Map.Entry e : map.object2ObjectEntrySet()) {
+ BigInteger v = e.getValue();
+ if (v.compareTo(BigInteger.ZERO) > 0) {
+ total = total.add(v);
+ }
+ }
+ if (total.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0) {
+ this.stack.getOrCreateTag().putLong("total", total.longValue());
+ } else {
+ this.stack.getOrCreateTag().putString("total", total.toString());
+ }
+ } catch (Exception ignored) {
}
- // 将当前已存储的不同物品种类数缓存到 NBT(键名: "types"),用于客户端 tooltip 显示
- int typesCount = this.getCellStoredMap().size();
- stack.getOrCreateTag().putInt("types", typesCount);
}
- isPersisted = true;
+ this.isPersisted = true;
}
// 插入物品到存储单元
@Override
public long insert(AEKey what, long amount, Actionable mode, IActionSource source) {
// 数量为0或类型不匹配直接返回
- if (amount == 0)
+ if (amount == 0) {
return 0;
+ }
// 不允许存储无限单元自身
- if (what instanceof AEItemKey itemKey && itemKey.getItem() instanceof InfinityBigIntegerCellItem)
+ if (what instanceof AEItemKey itemKey && itemKey.getItem() instanceof InfinityBigIntegerCellItem) {
return 0;
- // 如果没有UUID,生成UUID并初始化存储
+ }
+ // 如果没有UUID,生成UUID并初始化存储(延迟创建全局存储以避免在 manager 未就绪时 NPE)
if (!this.hasUUID()) {
- stack.getOrCreateTag().putUUID("uuid", UUID.randomUUID());
- getStorageInstance().getOrCreateCell(getUUID());
+ this.stack.getOrCreateTag().putUUID("uuid", UUID.randomUUID());
+ InfinityStorageManager.INSTANCE.getOrCreateCell(getUUID());
// 确保 storedMap 初始化并从持久层加载数据
- this.getCellStoredMap();
+ loadCellStoredMap();
}
Object2ObjectMap map = this.getCellStoredMap();
BigInteger currentAmount = map.getOrDefault(what, BigInteger.ZERO);
@@ -361,8 +367,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 实际插入,更新数量并保存
BigInteger newAmount = currentAmount.add(BigInteger.valueOf(amount));
map.put(what, newAmount);
- // 更新 cached total
- totalStored = totalStored.add(BigInteger.valueOf(amount));
this.saveChanges();
}
return amount;
@@ -383,11 +387,8 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
} else {
ret = currentAmount.longValue();
}
- if (mode == Actionable.MODULATE) {
+ if (mode == appeng.api.config.Actionable.MODULATE) {
map.remove(what);
- // 更新 cached total
- // 如果 currentAmount 大于 Long.MAX_VALUE,totalStored 减去 currentAmount 会保留大整数
- totalStored = totalStored.subtract(currentAmount);
this.saveChanges();
}
return ret;
@@ -395,8 +396,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 提取部分
if (mode == Actionable.MODULATE) {
map.put(what, currentAmount.subtract(requested));
- // 更新 cached total
- totalStored = totalStored.subtract(requested);
this.saveChanges();
}
return amount;
@@ -404,10 +403,4 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
}
return 0;
}
-
- // 获取存储单元内所有物品的总数量(格式化字符串)
- public String getTotalStorage() {
- // 使用缓存的 totalStored,避免每次全表扫描
- return formatBigInteger(totalStored);
- }
}
diff --git a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java
index dde5b96..f76df19 100644
--- a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java
+++ b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java
@@ -1,7 +1,6 @@
package com.extendedae_plus.ae.items;
import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellInventory;
-import com.google.common.base.Preconditions;
import net.minecraft.ChatFormatting;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.LongTag;
@@ -14,7 +13,6 @@ import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
-import java.math.BigInteger;
import java.util.List;
public class InfinityBigIntegerCellItem extends Item {
@@ -39,15 +37,14 @@ public class InfinityBigIntegerCellItem extends Item {
tooltip.add(Component.translatable("tooltip.extendedae_plus.infinity_biginteger_cell.summon1"));
tooltip.add(Component.translatable("tooltip.extendedae_plus.infinity_biginteger_cell.summon2"));
- Preconditions.checkArgument(stack.getItem() == this);
- // 仅在 ItemStack 自身存在 UUID 时显示 UUID,避免触发持久化或加载逻辑
+ // 优先使用 ItemStack 的 NBT 缓存信息显示 tooltip(客户端不应触发世界 I/O)
CompoundTag tag = stack.getTag();
if (tag != null && tag.contains("uuid")) {
String uuidStr = tag.getUUID("uuid").toString();
tooltip.add(
Component.literal("UUID: ").withStyle(ChatFormatting.GRAY).append(Component.literal(uuidStr).withStyle(ChatFormatting.YELLOW))
);
- // 读取并显示已缓存的种类数量(types),表示当前存储了多少种不同的 AEKey
+ // types 表示缓存的种类数
if (tag.contains("types")) {
try {
int types = tag.getInt("types");
@@ -55,27 +52,25 @@ public class InfinityBigIntegerCellItem extends Item {
Component.literal("Types: ").withStyle(ChatFormatting.GRAY).append(Component.literal(String.valueOf(types)).withStyle(ChatFormatting.GREEN))
);
} catch (Exception ignored) {
- // ignore malformed value
}
}
- // 读取并显示已缓存的 total(支持 long 或 string),使用格式化函数展示友好单位
+ // total 支持 long 或 string 两种表现形式
if (tag.contains("total")) {
- BigInteger total = BigInteger.ZERO;
- Tag t = tag.get("total");
try {
+ java.math.BigInteger total;
+ Tag t = tag.get("total");
if (t instanceof LongTag) {
- total = BigInteger.valueOf(tag.getLong("total"));
+ total = java.math.BigInteger.valueOf(tag.getLong("total"));
} else {
String s = tag.getString("total");
- total = new BigInteger(s);
+ total = new java.math.BigInteger(s);
}
+ String formatted = InfinityBigIntegerCellInventory.formatBigInteger(total);
+ tooltip.add(
+ Component.literal("Byte: ").withStyle(ChatFormatting.GRAY).append(Component.literal(formatted).withStyle(ChatFormatting.AQUA))
+ );
} catch (Exception ignored) {
- // 解析失败保持为 0
}
- String formatted = InfinityBigIntegerCellInventory.formatBigInteger(total);
- tooltip.add(
- Component.literal("Byte: ").withStyle(ChatFormatting.GRAY).append(Component.literal(formatted).withStyle(ChatFormatting.AQUA))
- );
}
}
}
diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java
index 4ef9036..71ec86a 100644
--- a/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java
+++ b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java
@@ -44,8 +44,8 @@ public class InfinityDataStorage {
*/
public CompoundTag serializeNBT() {
CompoundTag nbt = new CompoundTag();
- nbt.put("keys", keys);
- nbt.put("amounts", amounts);
+ nbt.put("keys", this.keys);
+ nbt.put("amounts", this.amounts);
return nbt;
}
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 e24a5ab..9aa2f64 100644
--- a/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java
+++ b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java
@@ -1,11 +1,18 @@
package com.extendedae_plus.util.storage;
+import com.extendedae_plus.ExtendedAEPlus;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
+import net.minecraft.nbt.NbtIo;
+import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerLevel;
-import net.minecraft.world.level.saveddata.SavedData;
-import org.jetbrains.annotations.NotNull;
+import net.minecraft.world.level.storage.LevelResource;
+import org.jetbrains.annotations.Nullable;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@@ -13,88 +20,89 @@ import java.util.UUID;
/**
* InfinityStorageManager
*
- * 世界级别的持久化容器,集中管理所有 InfinityBigInteger 存储单元的序列化数据。
- * 功能要点:
- * - 在世界加载时从存档恢复所有 cell 的数据
- * - 提供按 UUID 获取/创建单个 cell 的数据容器
- * - 在世界保存时将内存数据打包为 NBT 写回存档
+ * 替代之前基于 SavedData 的实现,本类使用手动文件 I/O 在 world 目录下保存 NBT 数据,
+ * 以避免依赖 Minecraft 的 SavedData 机制。
+ * 数据保持与之前兼容的 NBT 结构:根 Compound 包含 "list" => ListTag of Compound { uuid, data }
*/
-public class InfinityStorageManager extends SavedData {
+public class InfinityStorageManager {
+
+ public static final String FILE_NAME = "eap_infinity_biginteger_cells.dat";
/**
- * SavedData 文件名常量
- */
- public static final String FILE_NAME = "eap_infinity_biginteger_cells";
- /**
- * 全局单例实例(在世界加载时由 InfiniteBigIntegerStorageCell.onLevelLoad 填充)
- */
- public static InfinityStorageManager INSTANCE = null;
- /**
- * UUID -> 数据 的内存映射
+ * 全局单例,由 mod 在 world load 时初始化
*/
+ public static volatile InfinityStorageManager INSTANCE = new InfinityStorageManager();
+
private final Map cells = new HashMap<>();
- public InfinityStorageManager() {
- setDirty();
+ private Path saveFilePath = null;
+
+ private InfinityStorageManager() {}
+
+ /**
+ * 初始化并从 world 保存目录加载数据;若文件不存在则保持空状态
+ */
+ public void initFromWorld(@Nullable ServerLevel serverLevel) {
+ if (serverLevel == null) return;
+ try {
+ File worldFolder = serverLevel.getServer().getWorldPath(LevelResource.ROOT).toFile();
+ // 保存到 world// 文件夹下,避免与其它 mod 冲突
+ File modDir = new File(worldFolder, ExtendedAEPlus.MODID);
+ if (!modDir.exists()) {
+ modDir.mkdirs();
+ }
+ this.saveFilePath = new File(modDir, FILE_NAME).toPath();
+ if (Files.exists(this.saveFilePath)) {
+ CompoundTag root = NbtIo.readCompressed(this.saveFilePath.toFile());
+ ListTag cellList = root.getList("list", Tag.TAG_COMPOUND);
+ for (int i = 0; i < cellList.size(); i++) {
+ CompoundTag cell = cellList.getCompound(i);
+ this.cells.put(cell.getUUID("uuid"), InfinityDataStorage.loadFromNBT(cell.getCompound("data")));
+ }
+ }
+ } catch (IOException e) {
+ // 读取失败保持空,并打印栈追踪以便调试
+ e.printStackTrace();
+ }
}
/**
- * 从 NBT 构造:用于在世界加载时从存档恢复数据
+ * 保存当前内存数据到文件(会覆盖已有文件)
*/
- public InfinityStorageManager(CompoundTag nbt) {
- ListTag cellList = nbt.getList("list", CompoundTag.TAG_COMPOUND);
- for (int i = 0; i < cellList.size(); i++) {
- CompoundTag cell = cellList.getCompound(i);
- cells.put(cell.getUUID("uuid"), InfinityDataStorage.loadFromNBT(cell.getCompound("data")));
+ public synchronized void saveToFile() {
+ if (this.saveFilePath == null)
+ return;
+ try {
+ CompoundTag root = new CompoundTag();
+ ListTag cellList = new ListTag();
+ for (Map.Entry entry : this.cells.entrySet()) {
+ CompoundTag cell = new CompoundTag();
+ cell.putUUID("uuid", entry.getKey());
+ cell.put("data", entry.getValue().serializeNBT());
+ cellList.add(cell);
+ }
+ root.put("list", cellList);
+ // 使用压缩写入以节省空间
+ NbtIo.writeCompressed(root, this.saveFilePath.toFile());
+ } catch (IOException e) {
+ e.printStackTrace();
}
- setDirty();
}
- /**
- * 根据给定的 ServerLevel 获取或创建该世界对应的 SavedData 实例并缓存到 INSTANCE
- */
- public static InfinityStorageManager getForLevel(ServerLevel level) {
- if (INSTANCE == null && level != null) {
- INSTANCE = level.getDataStorage().computeIfAbsent(InfinityStorageManager::new, InfinityStorageManager::new, FILE_NAME);
- }
- return INSTANCE;
- }
-
- @Override
- public @NotNull CompoundTag save(@NotNull CompoundTag nbt) {
- // 将内存中的所有 cell 序列化为一个 ListTag
- ListTag cellList = new ListTag();
- for (Map.Entry entry : cells.entrySet()) {
- CompoundTag cell = new CompoundTag();
- cell.putUUID("uuid", entry.getKey());
- cell.put("data", entry.getValue().serializeNBT());
- cellList.add(cell);
- }
- nbt.put("list", cellList);
- return nbt;
- }
-
- /**
- * 更新或添加某个 UUID 对应的数据并标记为脏(需要保存)
- */
public void updateCell(UUID uuid, InfinityDataStorage infinityDataStorage) {
- cells.put(uuid, infinityDataStorage);
- setDirty();
+ this.cells.put(uuid, infinityDataStorage);
+ saveToFile();
}
- /**
- * 获取或创建某个 UUID 对应的数据容器
- */
public InfinityDataStorage getOrCreateCell(UUID uuid) {
- if (!cells.containsKey(uuid)) {
- updateCell(uuid, new InfinityDataStorage());
+ if (!this.cells.containsKey(uuid)) {
+ InfinityDataStorage newCell = new InfinityDataStorage();
+ this.cells.put(uuid, newCell);
+ saveToFile();
}
- return cells.get(uuid);
+ return this.cells.get(uuid);
}
- /**
- * 修改某个 UUID 对应的键与数量列表并保存(新的签名,stackAmounts 为 ListTag 字符串列表)
- */
public void modifyCell(UUID cellID, ListTag stackKeys, ListTag stackAmounts) {
InfinityDataStorage cellToModify = getOrCreateCell(cellID);
if (stackKeys != null && stackAmounts != null) {
@@ -104,11 +112,8 @@ public class InfinityStorageManager extends SavedData {
updateCell(cellID, cellToModify);
}
- /**
- * 删除某个 UUID 的持久化记录并标记为脏
- */
public void removeCell(UUID uuid) {
- cells.remove(uuid);
- setDirty();
+ this.cells.remove(uuid);
+ saveToFile();
}
}