Skip to content

数据同步 (CPDC) ​

CrossPlatformDataContainer -- 纵向(Server↔Client)对象级 KV 数据容器,支持同步与本地持久化。

前置知识

需要了解 网络系统 的 Wrapper 类型。横向跨服同步请查看 ServerSync。

Quick Start ​

kotlin
val key = ResourceIdWrapper.of("myplugin", "player_level")

// 服务端写入 SYNC 数据 -> 自动同步到客户端
cpdc.setInt(key, 10)

// 任一端读取
val level = cpdc.getInt(key) ?: 1

API Reference ​

CrossPersistentPlatformDataContainer ​

方法参数返回值说明
getBoolean(key)ResourceIdWrapperBoolean?读取布尔值
getInt(key)ResourceIdWrapperInt?读取整数
getLong(key)ResourceIdWrapperLong?读取长整数
getDouble(key)ResourceIdWrapperDouble?读取双精度浮点
getString(key)ResourceIdWrapperString?读取字符串
getBytes(key)ResourceIdWrapperByteArray?读取字节数组
getObject(key)ResourceIdWrapperAny?读取对象
getKeys()—Set<ResourceIdWrapper>获取所有键
setBoolean(key, value)ResourceIdWrapper, Boolean—写入布尔值
setInt(key, value)ResourceIdWrapper, Int—写入整数
setLong(key, value)ResourceIdWrapper, Long—写入长整数
setDouble(key, value)ResourceIdWrapper, Double—写入双精度浮点
setString(key, value)ResourceIdWrapper, String—写入字符串
setBytes(key, value)ResourceIdWrapper, ByteArray—写入字节数组
setObject(key, value)ResourceIdWrapper, Any—写入对象
remove(key)ResourceIdWrapper—删除键

CrossPlatformDataScope ​

值说明
LOCAL本端持久化,每个端独立存储,不同步
SYNC服务端权威同步,自动推送到客户端

获取 CPDC 容器 ​

Forge 客户端:

目标类型方法签名
物品ItemStack.getCrossPlatformDataContainer(scope)
实体Entity.getCrossPlatformDataContainer(scope)
区块LevelChunk.getCrossPlatformDataContainer(scope)
方块BlockPos.getCrossPlatformDataContainer(level, scope)
槽位物品AbstractContainerMenu.getCrossPlatformDataContainer(slotIndex, scope)
BUIServerAPI 存储getBUILocalStorageContainer(storeId)

Spigot 服务端:

目标类型方法签名
物品ItemStack.getCrossPlatformPersistentDataContainer(scope)
实体Entity.getCrossPlatformPersistentDataContainer(scope)
区块Chunk.getCrossPlatformPersistentDataContainer(scope)
方块Block.getCrossPlatformPersistentDataContainer(scope)

数据值类型 ​

类型Kotlin 类说明
BoolCrossPlatformDataValue.Bool布尔值
Int32CrossPlatformDataValue.Int3232 位整数
Int64CrossPlatformDataValue.Int6464 位整数
Float64CrossPlatformDataValue.Float64双精度浮点
TextCrossPlatformDataValue.Text字符串
BytesCrossPlatformDataValue.Bytes字节数组
ObjectCrossPlatformDataValue.Object序列化对象(含 typeHint)

作用域详解 ​

LOCAL - 本地数据 ​

仅在当前端存储,不同步。

使用场景: 临时缓存、客户端 UI 状态、服务端内部状态。

kotlin
// 客户端:存储 UI 偏好
val cpdc = entity.getCrossPlatformDataContainer(CrossPlatformDataScope.LOCAL)
cpdc.setBoolean(showHudKey, true)

SYNC - 同步数据 ​

服务端是权威,写入后自动同步到客户端。

使用场景: 需要双端访问的数据、UI 显示数据、游戏状态。

kotlin
// 服务端写入
val cpdc = entity.getCrossPlatformPersistentDataContainer(CrossPlatformDataScope.SYNC)
cpdc.setInt(levelKey, 10)
// -> 自动同步到客户端,客户端读取即可获得最新值

同步流程 ​

完整示例 ​

kotlin
// === 服务端(Spigot) ===
import com.behemiron.engine.spigot.util.crossplatform.*

@Service
class ItemDataService {
    private val rarityKey = ResourceIdWrapper.of("mygame", "rarity")
    private val levelKey = ResourceIdWrapper.of("mygame", "level")
    private val cacheKey = ResourceIdWrapper.of("mygame", "last_check")

    // 设置物品品质(SYNC -> 客户端可读取用于 UI 显示)
    fun setItemRarity(item: ItemStack, rarity: String) {
        val cpdc = item.getCrossPlatformPersistentDataContainer(CrossPlatformDataScope.SYNC)
        cpdc.setString(rarityKey, rarity)
        cpdc.setInt(levelKey, calculateLevel(rarity))
    }

    // 服务端内部缓存(LOCAL -> 仅服务端可见)
    fun markChecked(entity: Entity) {
        val cpdc = entity.getCrossPlatformPersistentDataContainer(CrossPlatformDataScope.LOCAL)
        cpdc.setLong(cacheKey, System.currentTimeMillis())
    }
}

// === 客户端(Forge) ===
import com.behemiron.engine.forge.util.crossplatform.*

class ItemTooltipRenderer {
    private val rarityKey = ResourceIdWrapper.of("mygame", "rarity")

    // 读取服务端同步过来的品质数据
    fun getRarity(itemStack: ItemStack): String {
        val cpdc = itemStack.getCrossPlatformDataContainer(CrossPlatformDataScope.SYNC)
        return cpdc.getString(rarityKey) ?: "common"
    }
}

注意事项

  • 物品 SYNC 写入限制:直接对 ItemStack 获取的 SYNC 容器是只读的。要写入物品的 SYNC 数据,必须通过 AbstractContainerMenu.getCrossPlatformDataContainer(slotIndex, SYNC) 使用槽位寻址。
  • 使用命名空间作为 key 前缀(ResourceIdWrapper.of("myplugin", "xxx")),避免与其他插件冲突。
  • 避免滥用 setObject,序列化开销较大,优先使用具体类型方法。
  • 对于多个数据变更,尽量批量提交以减少同步开销。