主题
数据同步
Behemiron 提供 CrossPlatformDataContainer (CPDC) 系统,用于在服务端和客户端之间同步数据或在各端存储 KV 型持久化数据
概念导图
CPDC 接口
基本 API
CPDC 使用 ResourceIdWrapper 作为键,提供类型化的读写方法:
kotlin
interface CrossPersistentPlatformDataContainer {
val scope: CrossPlatformDataScope
// 读取
fun getBoolean(key: ResourceIdWrapper): Boolean?
fun getInt(key: ResourceIdWrapper): Int?
fun getLong(key: ResourceIdWrapper): Long?
fun getDouble(key: ResourceIdWrapper): Double?
fun getString(key: ResourceIdWrapper): String?
fun getBytes(key: ResourceIdWrapper): ByteArray?
fun getObject(key: ResourceIdWrapper): Any?
fun getKeys(): Set<ResourceIdWrapper>
// 写入
fun setBoolean(key: ResourceIdWrapper, value: Boolean)
fun setInt(key: ResourceIdWrapper, value: Int)
fun setLong(key: ResourceIdWrapper, value: Long)
fun setDouble(key: ResourceIdWrapper, value: Double)
fun setString(key: ResourceIdWrapper, value: String)
fun setBytes(key: ResourceIdWrapper, value: ByteArray)
fun setObject(key: ResourceIdWrapper, value: Any)
fun remove(key: ResourceIdWrapper)
}使用示例
kotlin
// 创建键
val levelKey = ResourceIdWrapper.of("myplugin", "player_level")
val nameKey = ResourceIdWrapper.of("myplugin", "display_name")
// 写入数据
cpdc.setInt(levelKey, 10)
cpdc.setString(nameKey, "Hero")
// 读取数据
val level = cpdc.getInt(levelKey) ?: 1
val name = cpdc.getString(nameKey) ?: "Unknown"
// 删除数据
cpdc.remove(levelKey)
// 获取所有键
val allKeys = cpdc.getKeys()获取 CPDC 容器
通过扩展函数从平台对象获取 CPDC 容器。
Forge 客户端
kotlin
import com.behemiron.engine.forge.util.crossplatform.*
// 物品
val itemCpdc = itemStack.getCrossPlatformDataContainer(CrossPlatformDataScope.SYNC)
// 实体
val entityCpdc = entity.getCrossPlatformDataContainer(CrossPlatformDataScope.SYNC)
// 区块
val chunkCpdc = levelChunk.getCrossPlatformDataContainer(CrossPlatformDataScope.LOCAL)
// 方块(需要 Level)
val blockCpdc = blockPos.getCrossPlatformDataContainer(level, CrossPlatformDataScope.SYNC)
// 区块坐标(需要 Level)
val chunkPosCpdc = chunkPos.getCrossPlatformDataContainer(level, CrossPlatformDataScope.LOCAL)
// 容器槽位物品(支持 SYNC 写入)
val slotCpdc = menu.getCrossPlatformDataContainer(slotIndex, CrossPlatformDataScope.SYNC)
// BUI LocalStorage
val storageCpdc = getBUILocalStorageContainer("my_template_id")物品 SYNC 写入
直接对 ItemStack 获取的 SYNC 容器是只读的。要写入物品的 SYNC 数据,必须通过 AbstractContainerMenu.getCrossPlatformDataContainer(slotIndex, SYNC) 使用槽位寻址。
Spigot 服务端
kotlin
import com.behemiron.engine.spigot.util.crossplatform.*
// 物品
val itemCpdc = itemStack.getCrossPlatformPersistentDataContainer(CrossPlatformDataScope.SYNC)
// 实体
val entityCpdc = entity.getCrossPlatformPersistentDataContainer(CrossPlatformDataScope.SYNC)
// 区块
val chunkCpdc = chunk.getCrossPlatformPersistentDataContainer(CrossPlatformDataScope.LOCAL)
// 方块
val blockCpdc = block.getCrossPlatformPersistentDataContainer(CrossPlatformDataScope.SYNC)扩展函数一览
| 目标类型 | Forge 方法 | Spigot 方法 |
|---|---|---|
| 物品 | ItemStack.getCrossPlatformDataContainer(scope) | ItemStack.getCrossPlatformPersistentDataContainer(scope) |
| 实体 | Entity.getCrossPlatformDataContainer(scope) | Entity.getCrossPlatformPersistentDataContainer(scope) |
| 区块 | LevelChunk.getCrossPlatformDataContainer(scope) | Chunk.getCrossPlatformPersistentDataContainer(scope) |
| 方块 | BlockPos.getCrossPlatformDataContainer(level, scope) | Block.getCrossPlatformPersistentDataContainer(scope) |
| 槽位 | AbstractContainerMenu.getCrossPlatformDataContainer(slotIndex, scope) | - |
| 存储 | getBUILocalStorageContainer(storeId) | - |
作用域
CrossPlatformDataScope
kotlin
enum class CrossPlatformDataScope {
/** 本端持久化(每个端独立存储) */
LOCAL,
/** 服务端权威同步(服务端是权威,同步到客户端) */
SYNC
}LOCAL - 本地数据
仅在当前端存储,不同步:
kotlin
// 服务端的 LOCAL 数据只在服务端可见
// 客户端的 LOCAL 数据只在客户端可见使用场景:
- 临时缓存
- 客户端 UI 状态
- 服务端内部状态
SYNC - 同步数据
服务端是权威,自动同步到客户端:
kotlin
// 服务端修改 SYNC 数据
cpdc.setInt(key, 100)
// 数据自动同步到客户端使用场景:
- 需要双端访问的数据
- UI 显示所需的数据
- 游戏状态
数据值类型
kotlin
sealed interface CrossPlatformDataValue {
data class Bool(val value: Boolean) : CrossPlatformDataValue
data class Int32(val value: Int) : CrossPlatformDataValue
data class Int64(val value: Long) : CrossPlatformDataValue
data class Float64(val value: Double) : CrossPlatformDataValue
data class Text(val value: String) : CrossPlatformDataValue
data class Bytes(val value: ByteArray) : CrossPlatformDataValue
data class Object(val bytes: ByteArray, val typeHint: String?) : CrossPlatformDataValue
}最佳实践
1. 使用命名空间
kotlin
// ✅ 推荐:使用命名空间
val key = ResourceIdWrapper.of("myplugin", "player_level")
// ❌ 不推荐:不使用命名空间可能冲突
val key = ResourceIdWrapper.of("minecraft", "level")2. 选择正确的作用域
kotlin
// UI 显示需要 -> SYNC
cpdc.setString(displayNameKey, "Hero") // scope = SYNC
// 仅服务端内部使用 -> LOCAL
cpdc.setLong(lastCalculationKey, timestamp) // scope = LOCAL3. 使用合适的数据类型
kotlin
// ✅ 使用具体类型方法
cpdc.setInt(countKey, 100)
cpdc.setString(nameKey, "Player")
// ❌ 避免滥用 Object 类型
cpdc.setObject(dataKey, complexObject) // 序列化开销大4. 批量操作
对于多个数据变更,尽量批量提交以减少同步开销。