Kernel 管理运行时实体、实体结构、静态配置和地图实例。业务模块通过 kernel_module 创建、查找和销毁实体,通过 entity 访问字段、表格和容器。
模块与数据模型
| 对象 / 模块 | 用途 | 主要接口 |
|---|---|---|
class_meta_module |
加载实体与配置的结构定义,管理类事件回调 | find_meta()、find_static_meta()、add_class_call_back() |
config_module |
按配置 ID 查找已加载的静态数据 | find_static_entity() |
map_module |
创建地图和实例,维护实例内实体列表 | create_map()、create_map_instance()、get_inst_entity_list() |
kernel_module |
管理实体及其事件,转换实体数据 | create_entity()、get_entity()、destroy_entity()、entity_to_db_data() |
entity |
运行时数据:字段、表格、容器和空间位置 | get_int32()、set_int32()、find_table()、find_container() |
static_entity |
从资源文件加载的配置记录 | get_config_id()、get_int32()、get_string() |
实体结构和配置值是两类数据:结构定义字段名称、类型、索引与属性;静态配置为配置 ID 提供具体值;运行时实体拥有独立的 ID 和可修改数据。
资源加载
元数据模块在 init() 中加载 resource/meta/config_class.config 和 resource/meta/entity_class.config。这两个文件引用具体的结构文件;配置结构还可指定数据资源文件。config_module 在 post_init() 中按元数据加载静态记录。
业务代码应在框架完成相应初始化后查询配置。创建运行时实体前,需要存在对应类结构、地图和地图实例。类事件回调应在目标实体创建前注册。模块接入方式见创建模块。
创建和查找实体
以下函数用于已加载 Kernel 插件的进程。map_id 由应用分配;create_map() 会创建编号为 0 的默认实例。示例使用已有的 Player 结构,不加载配置记录,也不写入业务字段。
#include <memory>
#include "ark/kernel/data_list_impl.hpp"
#include "ark/kernel/kernel_module.hpp"
#include "ark/kernel/map_module.hpp"
#include "ark/meta_define.hpp"
#include "ark/plugin_manager.hpp"
std::shared_ptr<ark::entity> create_player(ark::plugin_manager& manager, int map_id) {
auto* kernel = manager.find_module<ark::kernel_module>();
auto* maps = manager.find_module<ark::map_module>();
if (kernel == nullptr || maps == nullptr)
{
return nullptr;
}
if (!maps->exist_map(map_id) && !maps->create_map(map_id))
{
return nullptr;
}
ark::data_list_impl args;
return kernel->create_entity(ark::null_guid, map_id, 0, ark::entity_meta_player::self_name(), 0, args);
}create_entity() 返回 nullptr 表示创建失败,例如类结构、地图或实例不存在,实体 ID 重复,或参数数量不符合要求。传入 null_guid 时由 Guid 模块生成 ID;初始化参数按「值、字段索引」成对排列;本例传入空参数列表。已有实体可用 get_entity(id) 查询,用 exist(id) 检查,用 destroy_entity(id) 请求销毁。
持有 shared_ptr<entity> 不等于实体仍在 Kernel 中注册。销毁后不要继续将外部保存的指针当作有效业务实体;需要时按 ID 重新查询。
配置默认值与初始化参数
config_id > 0 时,配置记录必须存在且与实体类匹配。配置为未指定的字段提供默认值,合法的 args 覆盖同一字段;显式传入 0 或空字符串也会覆盖配置值。同一字段在合法参数中重复出现时,最后一个值生效。实体数据独立于配置记录,修改实体不会修改原配置。
参数按 (value, uint32_t field_index) 成对排列:先加入值,再用 add_u_int() 加入字段索引。索引必须来自已加载的实体结构,值类型必须与字段类型完全一致;不要依赖隐式转换。
下面使用声明为 int32 的 Player.level 和 string 的 Player.name,显式将等级设为 0、名称设为空字符串,其余字段保留配置默认值。调用前,目标地图、实例和对应的 Player 配置记录必须存在。
#include <memory>
#include "ark/kernel/data_list_impl.hpp"
#include "ark/kernel/kernel_module.hpp"
#include "ark/meta_define.hpp"
std::shared_ptr<ark::entity> create_configured_player(
ark::kernel_module& kernel, int map_id, int instance_id, ark::id_type config_id) {
ark::data_list_impl args;
args.add_int(0);
args.add_u_int(ark::entity_meta_player::level_index());
args.add_string("");
args.add_u_int(ark::entity_meta_player::name_index());
return kernel.create_entity(
ark::null_guid, map_id, instance_id, ark::entity_meta_player::self_name(), config_id, args);
}配置默认值与参数值在第一个类事件 entity_evt_pre_load_data 前就已就绪。create_container_entity() 没有 args 参数,按配置初始化;create_entity(protobuf_data) 从保存的数据恢复,不自动合并配置默认值。
访问字段、表格和配置
字段读写属于 entity,可以使用字段名称或元数据索引。类型应与结构定义一致;不要用数值返回值判断实体或字段是否存在。
#include <cstdint>
#include <string>
#include "ark/kernel/kernel_module.hpp"
bool set_int32_field(ark::kernel_module& kernel, const ark::guid_t& id, const std::string& field, std::int32_t value) {
auto object = kernel.get_entity(id);
if (object == nullptr || object->get_node_type(field) != ark::data_type::dt_int32)
{
return false;
}
return object->set_int32(field, value);
}| 数据类型 | 访问方式 |
|---|---|
| 单值字段 | entity::get_bool()、get_int32()、get_int64()、get_string()、get_guid() 等;写入使用对应的 set_*() |
| 表格 | entity::find_table() 返回 table*;使用 find_row() / add_row() 获取 row*,再按列名称或索引读写 |
| 容器 | entity::find_container() 获取容器;kernel_module::create_container_entity() 创建容器内实体 |
| 静态配置 | config_module::find_static_entity(config_id) 返回 shared_ptr<static_entity>;检查空值后按已知字段类型读取 |
table* 和 row* 是借用指针,不独立拥有实体数据。表格删除行、清空表格或销毁所属实体后,不要继续使用相关指针。
注册事件
可以按类注册创建 / 销毁事件、字段变化、表格变化和容器操作,也可以为单个实体注册业务事件。公共类事件通过 add_common_class_event() 注册。
#include <string>
#include "ark/kernel/kernel_module.hpp"
class entity_observer
{
public:
bool attach(ark::kernel_module& kernel, const std::string& class_name) {
return kernel.add_class_call_back(class_name, this, &entity_observer::on_class_event);
}
private:
int on_class_event(
const ark::guid_t& id, const std::string& class_name, ark::entity_event event, const ark::data_list& args) {
if (event == ark::entity_event::entity_evt_data_finished)
{
// Handle the entity after its creation stages complete.
}
return 0;
}
};注册保存了对象指针;entity_observer 必须在回调可能执行期间一直有效。不要使用创建后立即离开作用域的局部对象注册成员回调。当前接口未提供对应的公开注销方法。
普通 create_entity() 的类事件按以下顺序同步分发:
| 阶段 | entity_event |
|---|---|
| 加载前 | entity_evt_pre_load_data |
| 加载 | entity_evt_load_data |
| 应用数据前 | entity_evt_pre_effect_data |
| 应用数据 | entity_evt_effect_data |
| 应用数据后 | entity_evt_post_effect_data |
| 数据阶段完成 | entity_evt_data_finished |
entity_evt_all_finished 由应用按需显式触发,不是上述创建函数自动发送的阶段。正常实体销毁时先分发 entity_evt_pre_destroy,再分发 entity_evt_destroy。
字段和表格回调分别使用 add_node_call_back()、add_table_call_back();参数包含实体 ID、变化位置以及旧值 / 新值。do_event(id, event_id, args) 用于分发单实体业务事件。回调参数和优先级以公开头文件签名为准。
地图与数据转换
地图按 map_id 区分,每张地图可以创建多个实例。create_map_instance() 成功时返回实例 ID,失败返回 -1。switch_map() 将已有实体移到目标实例;目标地图和实例必须事先存在。
地图模块提供实体列表与在线数量查询。它不提供完整的可见范围管理(AOI);九宫格、空间索引和业务广播范围需要由应用实现。get_max_online_count() 当前是固定返回值,不应作为部署容量上限或容量测试结论。
entity_to_db_data() 将实体转换为 ark::protobuf::protobuf_db_entity,对应的 create_entity(protobuf_data) 重载用于恢复。entity_node_to_protobuf_data() 和 entity_table_to_protobuf_data() 可按数据掩码转换部分字段。转换不等于写入数据库;持久化、版本兼容和恢复后的业务校验由应用负责。