fix: 回退无限磁盘修改至上一版本,再次修复,添加版本号
This commit is contained in:
parent
49b0ef0726
commit
ba79d0e31a
|
|
@ -16,6 +16,8 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
|||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.server.ServerStoppingEvent;
|
||||
|
|
@ -23,7 +25,6 @@ import net.minecraftforge.event.server.ServerStoppingEvent;
|
|||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
|
|
@ -48,8 +49,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
|
|||
|
||||
// 待持久化队列(用于 debounce:在服务器 tick 中合并持久化)
|
||||
private static final ConcurrentLinkedQueue<InfinityBigIntegerCellInventory> PENDING_PERSIST = new ConcurrentLinkedQueue<>();
|
||||
// 数字格式化对象,保留两位小数(复用以减少对象分配)
|
||||
private static final DecimalFormat DF = new DecimalFormat("#.##");
|
||||
// 数字格式化对象:改为方法局部以避免静态非线程安全问题
|
||||
|
||||
// 关联的 ItemStack(含可能的 uuid NBT)
|
||||
private final ItemStack stack;
|
||||
|
|
@ -106,6 +106,17 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
|
|||
|
||||
// 在服务器停止时被调用,立即强制持久化队列中的所有实例
|
||||
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 {
|
||||
|
|
@ -116,7 +127,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
|
|||
LOGGER.info("InfinityBigIntegerCellInventory onServerStopping error1: {}", ignored.getMessage());
|
||||
}
|
||||
}
|
||||
// 额外尝试将全局存储管理器标记为脏以确保 SavedData 被写回(在单人模式下可能直接由系统触发)
|
||||
// 将全局存储管理器标记为脏以确保 SavedData 被写回
|
||||
try {
|
||||
var stor = getStorageInstance();
|
||||
if (stor != null) stor.setDirty();
|
||||
|
|
@ -127,7 +138,8 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
|
|||
|
||||
// 将 BigInteger 格式化为带单位的字符串,保留两位小数
|
||||
public static String formatBigInteger(BigInteger number) {
|
||||
// 使用局部 DF(非线程安全),但 Minecraft 通常在主线程运行
|
||||
// 使用方法局部的 DecimalFormat,避免静态共享的非线程安全问题
|
||||
java.text.DecimalFormat df = new java.text.DecimalFormat("#.##");
|
||||
BigDecimal bd = new BigDecimal(number);
|
||||
BigDecimal thousand = new BigDecimal(1000);
|
||||
String[] units = new String[]{"", "K", "M", "G", "T", "P", "E", "Z", "Y"};
|
||||
|
|
@ -139,17 +151,23 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
|
|||
if (idx == 0) {
|
||||
return bd.setScale(0, RoundingMode.DOWN).toPlainString();
|
||||
}
|
||||
return DF.format(bd.doubleValue()) + units[idx];
|
||||
return df.format(bd.doubleValue()) + units[idx];
|
||||
}
|
||||
|
||||
// 获取当前存储单元的数据存储对象
|
||||
private InfinityDataStorage getCellStorage() {
|
||||
if (this.getUUID() == null) {
|
||||
// 如果没有UUID,返回空存储
|
||||
return InfinityDataStorage.EMPTY;
|
||||
// 如果没有UUID,返回空存储(返回新实例以避免共享可变状态)
|
||||
return InfinityDataStorage.empty();
|
||||
} else {
|
||||
// 在访问全局 SavedData 之前做防御性检查,避免在客户端或尚未初始化的情况下 NPE
|
||||
InfinityStorageManager mgr = getStorageInstance();
|
||||
if (mgr == null) {
|
||||
// SavedData 尚未就绪,视为空存储(返回新实例以避免共享可变状态)
|
||||
return InfinityDataStorage.empty();
|
||||
}
|
||||
// 否则获取或创建对应UUID的存储
|
||||
return getStorageInstance().getOrCreateCell(getUUID());
|
||||
return mgr.getOrCreateCell(getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -200,8 +218,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
|
|||
private void loadCellStoredMap() {
|
||||
boolean corruptedTag = false; // 标记数据是否损坏
|
||||
if (!stack.hasTag()) return;
|
||||
ListTag keys = this.getCellStorage().keys;
|
||||
ListTag amounts = this.getCellStorage().amounts;
|
||||
InfinityDataStorage storage = this.getCellStorage();
|
||||
ListTag keys = storage.keys;
|
||||
ListTag amounts = storage.amounts;
|
||||
int len = Math.min(keys.size(), amounts.size());
|
||||
for (int i = 0; i < len; i++) {
|
||||
AEKey key = AEKey.fromTagGeneric(keys.getCompound(i));
|
||||
|
|
@ -233,6 +252,12 @@ 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) {
|
||||
}
|
||||
}
|
||||
|
||||
// 标记数据需要保存,并通知容器或直接持久化
|
||||
|
|
@ -289,16 +314,32 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
|
|||
public void persist() {
|
||||
if (this.isPersisted)
|
||||
return;
|
||||
// 若全局存储管理器尚未就绪,重新入队并在未来 tick 重试
|
||||
InfinityStorageManager mgr = getStorageInstance();
|
||||
if (mgr == null) {
|
||||
try {
|
||||
var id = this.getUUID();
|
||||
LOGGER.info("Persist deferred for cell {}: storage manager not ready", id);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
if (!PENDING_PERSIST.contains(this)) {
|
||||
PENDING_PERSIST.offer(this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Object2ObjectMap<AEKey, BigInteger> map = this.getCellStoredMap();
|
||||
if (map.isEmpty()) {
|
||||
// 如果存储为空,移除UUID和全局存储中的数据
|
||||
if (this.hasUUID()) {
|
||||
getStorageInstance().removeCell(getUUID());
|
||||
mgr.removeCell(getUUID());
|
||||
if (stack.getTag() != null) {
|
||||
stack.getTag().remove("uuid");
|
||||
// 移除缓存的 total 字段
|
||||
stack.getTag().remove("total");
|
||||
}
|
||||
// 标记为已持久化,避免重复尝试
|
||||
isPersisted = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -320,10 +361,10 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
|
|||
}
|
||||
// 如果没有Key,更新为空存储,否则保存数据
|
||||
if (keys.isEmpty()) {
|
||||
getStorageInstance().updateCell(this.getUUID(), new InfinityDataStorage());
|
||||
mgr.updateCell(this.getUUID(), new InfinityDataStorage());
|
||||
} else {
|
||||
// amounts 现在为 CompoundTag 列表
|
||||
getStorageInstance().modifyCell(this.getUUID(), keys, amountTags);
|
||||
mgr.modifyCell(this.getUUID(), keys, amountTags);
|
||||
}
|
||||
// 将缓存的 totalStored 同步到 ItemStack 的 NBT,优先使用 long
|
||||
if (stack.getOrCreateTag() != null) {
|
||||
|
|
@ -337,6 +378,12 @@ 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) {
|
||||
}
|
||||
}
|
||||
|
||||
// 插入物品到存储单元
|
||||
|
|
@ -348,12 +395,19 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
|
|||
// 不允许存储无限单元自身
|
||||
if (what instanceof AEItemKey itemKey && itemKey.getItem() instanceof InfinityBigIntegerCellItem)
|
||||
return 0;
|
||||
// 如果没有UUID,生成UUID并初始化存储
|
||||
// 如果没有UUID,尝试在服务器端且存储管理器已就绪时生成UUID并初始化存储
|
||||
if (!this.hasUUID()) {
|
||||
stack.getOrCreateTag().putUUID("uuid", UUID.randomUUID());
|
||||
getStorageInstance().getOrCreateCell(getUUID());
|
||||
// 确保 storedMap 初始化并从持久层加载数据
|
||||
this.getCellStoredMap();
|
||||
InfinityStorageManager mgr = getStorageInstance();
|
||||
// 仅在 SavedData 已就绪(通常在服务器端)时创建 UUID 并注册持久化存储
|
||||
if (mgr != null) {
|
||||
stack.getOrCreateTag().putUUID("uuid", UUID.randomUUID());
|
||||
mgr.getOrCreateCell(getUUID());
|
||||
// 确保 storedMap 初始化并从持久层加载数据
|
||||
this.getCellStoredMap();
|
||||
} else {
|
||||
// SavedData 未就绪:把插入作为本地内存操作(不生成 UUID,不持久化),确保 storedMap 初始化以容纳临时数据
|
||||
this.getCellStoredMap();
|
||||
}
|
||||
}
|
||||
Object2ObjectMap<AEKey, BigInteger> map = this.getCellStoredMap();
|
||||
BigInteger currentAmount = map.getOrDefault(what, BigInteger.ZERO);
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@ import net.minecraft.nbt.Tag;
|
|||
*/
|
||||
public class InfinityDataStorage {
|
||||
|
||||
/** 空实例(表示没有数据) */
|
||||
public static final InfinityDataStorage EMPTY = new InfinityDataStorage();
|
||||
/** 空实例的访问器(返回新实例以避免共享可变状态) */
|
||||
public static InfinityDataStorage empty() {
|
||||
return new InfinityDataStorage();
|
||||
}
|
||||
|
||||
/** 序列化的键列表(NBT ListTag,元素为 CompoundTag) */
|
||||
public ListTag keys;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
|
||||
|
||||
/**
|
||||
* InfinityStorageManager
|
||||
* <p>
|
||||
|
|
@ -21,6 +23,10 @@ import java.util.UUID;
|
|||
*/
|
||||
public class InfinityStorageManager extends SavedData {
|
||||
|
||||
// 当前磁盘格式版本号,增加字段用于向后/向前兼容
|
||||
private static final int FORMAT_VERSION = 1;
|
||||
|
||||
|
||||
/**
|
||||
* SavedData 文件名常量
|
||||
*/
|
||||
|
|
@ -42,10 +48,18 @@ public class InfinityStorageManager extends SavedData {
|
|||
* 从 NBT 构造:用于在世界加载时从存档恢复数据
|
||||
*/
|
||||
public InfinityStorageManager(CompoundTag nbt) {
|
||||
// 读取格式版本,缺省视为 1(兼容旧档)
|
||||
int version = nbt.contains("format_version") ? nbt.getInt("format_version") : 1;
|
||||
LOGGER.info("Loading InfinityStorageManager format_version={}", version);
|
||||
|
||||
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")));
|
||||
java.util.UUID uuid = cell.getUUID("uuid");
|
||||
CompoundTag dataTag = cell.getCompound("data");
|
||||
InfinityDataStorage data = InfinityDataStorage.loadFromNBT(dataTag);
|
||||
cells.put(uuid, data);
|
||||
LOGGER.info("Loaded InfinityDataStorage for uuid {}: keys={}, amounts={}", uuid, data.keys.size(), data.amounts.size());
|
||||
}
|
||||
setDirty();
|
||||
}
|
||||
|
|
@ -71,6 +85,8 @@ public class InfinityStorageManager extends SavedData {
|
|||
cellList.add(cell);
|
||||
}
|
||||
nbt.put("list", cellList);
|
||||
// 写入当前格式版本号,便于未来迁移与兼容判断
|
||||
nbt.putInt("format_version", FORMAT_VERSION);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user