fix:回退无限存储元件修复

This commit is contained in:
C-H716 2025-09-16 22:02:13 +08:00
parent 3039add611
commit d316c5f039
3 changed files with 24 additions and 93 deletions

View File

@ -26,7 +26,6 @@ import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* InfinityBigIntegerCellInventory
@ -92,9 +91,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
return null;
}
// 获取全局存储实例尽量安全地获取任意已注册的世界实例
// 获取全局存储实例
private static InfinityStorageManager getStorageInstance() {
return InfinityStorageManager.getAnyInstance();
return InfinityStorageManager.INSTANCE;
}
// 服务器 tick 回调合并并执行待持久化项
@ -134,12 +133,10 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
private InfinityDataStorage getCellStorage() {
if (this.getUUID() == null) {
// 如果没有UUID返回空存储
return InfinityDataStorage.empty();
return InfinityDataStorage.EMPTY;
} else {
// 否则获取或创建对应UUID的存储若管理器不可用则返回空存储以避免 NPE
InfinityStorageManager mgr = getStorageInstance();
if (mgr == null) return InfinityDataStorage.empty();
return mgr.getOrCreateCell(getUUID());
// 否则获取或创建对应UUID的存储
return getStorageInstance().getOrCreateCell(getUUID());
}
}
@ -190,11 +187,8 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
private void loadCellStoredMap() {
boolean corruptedTag = false; // 标记数据是否损坏
if (!stack.hasTag()) return;
// 在加载前重置缓存避免重复累计
totalStored = BigInteger.ZERO;
InfinityDataStorage storage = this.getCellStorage();
ListTag keys = storage.getKeys();
ListTag amounts = storage.getAmounts();
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++) {
AEKey key = AEKey.fromTagGeneric(keys.getCompound(i));
@ -229,8 +223,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
}
// 标记数据需要保存并通知容器或直接持久化
private final AtomicBoolean queued = new AtomicBoolean(false);
private void saveChanges() {
// 标记为未持久化交由容器或延迟任务合并写入以减少 I/O
isPersisted = false;
@ -239,7 +231,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
container.saveChanges();
} else {
// 如果没有容器入队等待服务器 tick 在主线程统一持久化避免频繁 I/O
if (queued.compareAndSet(false, true)) {
if (!PENDING_PERSIST.contains(this)) {
PENDING_PERSIST.offer(this);
}
}
@ -266,21 +258,13 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
if (map.isEmpty()) {
// 如果存储为空移除UUID和全局存储中的数据
if (this.hasUUID()) {
InfinityStorageManager mgr = getStorageInstance();
if (mgr != null) mgr.removeCell(getUUID());
getStorageInstance().removeCell(getUUID());
if (stack.getTag() != null) {
stack.getTag().remove("uuid");
// 移除缓存的 total 字段
stack.getTag().remove("total");
}
// 清理 queued 标志并标记已持久化
queued.set(false);
isPersisted = true;
return;
}
// UUID 且为空不需要做额外操作但确保已标记为已持久化
queued.set(false);
isPersisted = true;
return;
}
// 构建要保存的Key和数量列表混合表示long string
@ -300,16 +284,11 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
}
}
// 如果没有Key更新为空存储否则保存数据
InfinityStorageManager mgr = getStorageInstance();
if (mgr == null) {
// 无可用存储管理器跳过持久化保留内存状态
if (keys.isEmpty()) {
getStorageInstance().updateCell(this.getUUID(), new InfinityDataStorage());
} else {
if (keys.isEmpty()) {
mgr.updateCell(this.getUUID(), new InfinityDataStorage());
} else {
// amounts 现在为 CompoundTag 列表
mgr.modifyCell(this.getUUID(), keys, amountTags);
}
// amounts 现在为 CompoundTag 列表
getStorageInstance().modifyCell(this.getUUID(), keys, amountTags);
}
// 将缓存的 totalStored 同步到 ItemStack NBT优先使用 long
if (stack.getOrCreateTag() != null) {
@ -320,8 +299,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
}
}
isPersisted = true;
// 持久化完成后清除 queued 标志
queued.set(false);
}
// 插入物品到存储单元

View File

@ -18,17 +18,17 @@ import net.minecraft.nbt.Tag;
*/
public class InfinityDataStorage {
// 不再暴露可变的共享实例避免多个调用方修改同一 ListTag 导致交叉污染
private static final InfinityDataStorage TRUE_EMPTY = new InfinityDataStorage(new ListTag(), new ListTag());
/** 空实例(表示没有数据) */
public static final InfinityDataStorage EMPTY = new InfinityDataStorage();
/** 序列化的键列表NBT ListTag元素为 CompoundTag */
private ListTag keys;
public ListTag keys;
/**
* keys 对应的数量列表NBT ListTag元素为 CompoundTag
* - 若数量能放入 long CompoundTag 包含键 "l"(long)
* - 否则包含键 "s"(String) 存放 BigInteger 的字符串形式
*/
private ListTag amounts;
public ListTag amounts;
public InfinityDataStorage() {
this(new ListTag(), new ListTag());
@ -39,14 +39,6 @@ public class InfinityDataStorage {
this.amounts = amounts;
}
/**
* 返回一个空的不可共享实例调用方若需要可变副本请自行复制
*/
public static InfinityDataStorage empty() {
// 返回一个新的实例以避免共享可变对象被篡改
return new InfinityDataStorage(new ListTag(), new ListTag());
}
/**
* 将当前数据封装为 CompoundTag 以写入存档
*/
@ -66,20 +58,4 @@ public class InfinityDataStorage {
ListTag stackAmounts = nbt.getList("amounts", Tag.TAG_COMPOUND);
return new InfinityDataStorage(stackKeys, stackAmounts);
}
public ListTag getKeys() {
return keys;
}
public ListTag getAmounts() {
return amounts;
}
public void setKeys(ListTag keys) {
this.keys = keys;
}
public void setAmounts(ListTag amounts) {
this.amounts = amounts;
}
}

View File

@ -2,16 +2,13 @@ package com.extendedae_plus.util.storage;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.saveddata.SavedData;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* InfinityStorageManager
@ -29,9 +26,9 @@ public class InfinityStorageManager extends SavedData {
*/
public static final String FILE_NAME = "eap_infinity_biginteger_cells";
/**
* Per-world instances to avoid cross-world leakage. Keyed by world ResourceKey<Level>.
* 全局单例实例在世界加载时由 InfiniteBigIntegerStorageCell.onLevelLoad 填充
*/
private static final Map<ResourceKey<Level>, InfinityStorageManager> INSTANCES = new ConcurrentHashMap<>();
public static InfinityStorageManager INSTANCE = null;
/**
* UUID -> 数据 的内存映射
*/
@ -57,29 +54,10 @@ public class InfinityStorageManager extends SavedData {
* 根据给定的 ServerLevel 获取或创建该世界对应的 SavedData 实例并缓存到 INSTANCE
*/
public static InfinityStorageManager getForLevel(ServerLevel level) {
if (level == null) return null;
ResourceKey<Level> key = level.dimension();
InfinityStorageManager mgr = INSTANCES.get(key);
if (mgr == null) {
mgr = level.getDataStorage().computeIfAbsent(InfinityStorageManager::new, InfinityStorageManager::new, FILE_NAME);
INSTANCES.put(key, mgr);
if (INSTANCE == null && level != null) {
INSTANCE = level.getDataStorage().computeIfAbsent(InfinityStorageManager::new, InfinityStorageManager::new, FILE_NAME);
}
return mgr;
}
/**
* 返回任何现有实例作为无法访问 ServerLevel 的代码路径的安全回退
*/
public static InfinityStorageManager getAnyInstance() {
return INSTANCES.values().stream().findFirst().orElse(null);
}
/**
* 删除世界的实例在世界卸载时调用
*/
public static void removeForLevel(ServerLevel level) {
if (level == null) return;
INSTANCES.remove(level.dimension());
return INSTANCE;
}
@Override
@ -120,8 +98,8 @@ public class InfinityStorageManager extends SavedData {
public void modifyCell(UUID cellID, ListTag stackKeys, ListTag stackAmounts) {
InfinityDataStorage cellToModify = getOrCreateCell(cellID);
if (stackKeys != null && stackAmounts != null) {
cellToModify.setKeys(stackKeys);
cellToModify.setAmounts(stackAmounts);
cellToModify.keys = stackKeys;
cellToModify.amounts = stackAmounts;
}
updateCell(cellID, cellToModify);
}