EnderStorage API

提供给其他 mod 集成的核心入口:EnderStorageManager、EnderStoragePlugin、EnderStorageDyeTool、AbstractEnderStorage 与频率↔颜色换算工具。

基本信息

组件 类 路径
Manager EnderStorageManager codechicken.enderstorage.api.EnderStorageManager
抽象存储 AbstractEnderStorage codechicken.enderstorage.api.AbstractEnderStorage
Plugin 接口 EnderStoragePlugin codechicken.enderstorage.api.EnderStoragePlugin
染料工具 EnderStorageDyeTool codechicken.enderstorage.api.EnderStorageDyeTool
存储事件 EnderStorageStoredEvent codechicken.enderstorage.event.EnderStorageStoredEvent

EnderStorageManager(核心管理器)

  • 双实例:服务端 serverManager 与客户端 clientManager,通过 instance(boolean client) 区分。
  • 内部维护三张表:
    • storageMap: Map<String, AbstractEnderStorage>(key = freq + "|" + owner + "|" + type)
    • storageList: Map<String, List<AbstractEnderStorage>>(按 type 分类的列表,用于客户端广播)
    • dirtyStorage: LinkedList<AbstractEnderStorage>(待持久化对象)
  • 通过 EnderStorageSaveHandler 在 WorldEvent.Load/Save 上自动加载/保存;保存使用 DimensionManager.getCurrentSaveRootDirectory()/EnderStorage/data{1,2}.dat + lock.dat 三个文件的双缓冲模式(lock.dat 记录上一次写入的文件编号)。
  • getStorage(owner, freq, type) 懒加载:owner == null 强制写为 "global";首次访问创建 EnderStoragePlugin.createEnderStorage 实例,并尝试从 saveTag 中 loadFromTag。
  • setStorage(owner, freq, type, nbt) 用 NBT 覆盖已有实例或创建新实例。
  • cleanStorage(owner, type) 把 owner 在指定 type 下的所有存储清空(item 清空 ItemStack 数组;liquid 把 tank.Amount 设为 0)。
  • requestSave(storage) 把脏存储加入 dirtyStorage,下一次 save(false) 触发时由 EnderStorageSaveHandler.onWorldSave 写入磁盘。

频率↔颜色换算

// 颜色 → 频率(freq = (c1<<8) + (c2<<4) + c3)
public static int getFreqFromColours(int colour1, int colour2, int colour3)
public static int getFreqFromColours(int[] colours)

// 频率 → 颜色(0 = 高 4-bit / 1 = 中 4-bit / 2 = 低 4-bit)
public static int getColourFromFreq(int freq, int colour)
public static int[] getColoursFromFreq(int freq)

colour1/2/3 与 colour=0/1/2 顺序一致(高位先)。染色 blockEnderStorage.onBlockActivated 中读取并写入 freq 的对应分量。

插件注册

public static void registerPlugin(EnderStoragePlugin plugin)
public static void loadConfig(ConfigFile config2)

init 时机依次:registerPlugin(new EnderItemStoragePlugin()) → registerPlugin(new EnderLiquidStoragePlugin())。新插件必须实现 EnderStoragePlugin 接口才能挂入。

EnderStoragePlugin 接口

public AbstractEnderStorage createEnderStorage(EnderStorageManager manager, String owner, int freq);
public String identifer();                                       // "item" / "liquid"
public void sendClientInfo(EntityPlayer player, List<AbstractEnderStorage> list);
public void loadConfig(ConfigTag tag);
  • identifer() 返回字符串用于 storageMap / storageList 的 key。
  • sendClientInfo 在玩家登录/切换维度时调用;item 插件实现为"对所有打开中的 EnderItemStorage 广播 openCount",liquid 插件为空实现(液体走 TankSynchroniser)。
  • loadConfig 读取 ConfigFile 中 <identifier> 子分组。

AbstractEnderStorage(抽象存储)

public final EnderStorageManager manager;
public final int freq;
public final String owner;

public void setDirty();           // 标记 + manager.requestSave + changeCount++
public void setClean();
public int getChangeCount();      // 客户端每 tick 用 changeCount 判断是否需要同步
public abstract String type();
public abstract NBTTagCompound saveToTag();
public abstract void loadFromTag(NBTTagCompound tag);
  • 脏标记 + 变更计数:服务端的 setDirty 会调用 manager.requestSave;客户端 setDirty 直接 return。
  • changeCount 在客户端用来判断"是否要把 TileEntity 标记为需要 update(worldObj.func_147453_f)",由 TileFrequencyOwner.updateEntity 每 tick 轮询。

EnderStorageDyeTool(染料工具接口)

public interface EnderStorageDyeTool {
    int getDye(ItemStack itemStack);                  // 返回 0–15 的染料颜色;-1 表示此物品不提供染料
    default void expendToolUse(ItemStack itemStack) {} // 默认无操作;mod 可在此消耗耐久/EU/etc
}

集成流程(BlockEnderStorage.onBlockActivated subHit 1–3):

  1. EnderStorageRecipe.getDyeType(item) 先尝试 Items.dye、dyeBlack/…/od 列表;
  2. 然后尝试 item instanceof EnderStorageDyeTool,调 getDye(item);
  3. 命中后修改 freq 对应分量;创造模式不消耗,否则调用 ((EnderStorageDyeTool) item.getItem()).expendToolUse(item)。

接口 Javadoc 明确说明:仅对已放置的 Ender Chest / Tank 有效——合成配方中的"染色"路径不走 EnderStorageDyeTool。

EnderStorageStoredEvent(事件)

public static final int TYPE_ITEM   = 1;
public static final int TYPE_LIQUID = 2;

public final boolean global;   // true=global, false=player-owned
public final int type;         // TYPE_ITEM / TYPE_LIQUID

由 EnderStorageCPH.handlePacket 在收到服务器 type=7 包后通过 MinecraftForge.EVENT_BUS.post(new EnderStorageStoredEvent(global, type)) 触发,第三方 mod 可监听以在"玩家完整库存清单下发"后做缓存/UI 更新。

网络包(channel = "ES")

type 方向 含义
1 S→C TileEntity description(handleTilePacket)
1 C→S TankSynchroniser.handleVisiblityPacket
2 S→C 打开 GUI(EnderItemStorage.openClientGui)
2 C→S 请求完整库存清单(sendStorageStored)
3 S→C 箱子开/关状态(setClientOpen)
4 S→C 液体同步(TankSynchroniser.syncClient)
5/6 S↔C Ender Tank 液体/压力状态(TileEnderTank.sync)
7 S→C 完整 (freqs, owner, type) 清单(updateStorage + 触发 EnderStorageStoredEvent)

第三方 mod 集成示例

// 自定义 EnderStorage 插件(不通过 EnderStorageManager.registerPlugin 在 init 时机注册,
// 可在 mod 自己的 FMLInitializationEvent 中注册):
public class MyStoragePlugin implements EnderStoragePlugin {
    @Override public AbstractEnderStorage createEnderStorage(EnderStorageManager m, String o, int f) {
        return new MyEnderStorage(m, o, f);
    }
    @Override public String identifer() { return "mytype"; }
    @Override public void sendClientInfo(EntityPlayer p, List<AbstractEnderStorage> list) {}
    @Override public void loadConfig(ConfigTag tag) {}
}
EnderStorageManager.registerPlugin(new MyStoragePlugin());

// 自定义染料工具:
public class MyDyeTool extends Item implements EnderStorageDyeTool {
    @Override public int getDye(ItemStack s) { return s.getItemDamage() & 0xF; }
    @Override public void expendToolUse(ItemStack s) { s.setItemDamage(s.getItemDamage() + 1); }
}

相关条目