From 641bdc62587c4eb0dfc964f1e8eb48f037cc6fb6 Mon Sep 17 00:00:00 2001 From: nick Date: Mon, 26 Oct 2026 23:28:04 +0800 Subject: [PATCH] fix(kernel): update custom uint32 entity values --- docs/reference/kernel.md | 6 +++ docs/reference/kernel_CN.md | 6 +++ src/plugins/kernel/entity_impl.cpp | 9 +++- tests/app/typed_examples.cpp | 11 +++++ tests/core/entity_config_copy.cpp | 66 ++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) diff --git a/docs/reference/kernel.md b/docs/reference/kernel.md index 930ff4495..13440dc67 100644 --- a/docs/reference/kernel.md +++ b/docs/reference/kernel.md @@ -116,6 +116,12 @@ bool set_int32_field(ark::kernel_module& kernel, const ark::guid_t& id, const st `table*` and `row*` are borrowed pointers, with no independent ownership of entity data. Do not retain them after removing the row, clearing the table or destroying the owning entity. +### Custom unsigned values + +`entity::add_custom_u_int32(name, value)` creates a named runtime `uint32_t` value separate from schema fields. After creation, `set_custom_u_int32(name, value)` updates that value across the full range from `0` to `UINT32_MAX`; read it with `get_custom_u_int32(name)`. Setting a missing name or a name containing another scalar type returns `false` without creating data, converting its type or changing the existing value, in both Debug and Release builds. Use `find_custom_data()` to check existence; a stored zero is a valid value. + +`check-kernel-initialization` exercises these operations through the public `entity` interface, including other custom scalar controls. With applications, Kernel/Utility and examples enabled, `check-typed-examples` also verifies unsigned updates on entities created by the real Kernel/EntityOperations libraries. + ## Register events Class callbacks cover creation / destruction, field changes, table changes and container operations. Individual entities can also have application event handlers. Register common class callbacks with `add_common_class_event()`. diff --git a/docs/reference/kernel_CN.md b/docs/reference/kernel_CN.md index 5fde718df..5975ef513 100644 --- a/docs/reference/kernel_CN.md +++ b/docs/reference/kernel_CN.md @@ -116,6 +116,12 @@ bool set_int32_field(ark::kernel_module& kernel, const ark::guid_t& id, const st `table*` 和 `row*` 是借用指针,不独立拥有实体数据。表格删除行、清空表格或销毁所属实体后,不要继续使用相关指针。 +### 自定义无符号值 + +`entity::add_custom_u_int32(name, value)` 创建按名称访问的运行时 `uint32_t` 值,与元数据字段分开。创建后,`set_custom_u_int32(name, value)` 可在 `0` 到 `UINT32_MAX` 的完整范围内更新值,使用 `get_custom_u_int32(name)` 读取。名称不存在或对应其他标量类型时,设置操作在 Debug 和 Release 构建中均返回 `false`,不会创建数据、转换类型或修改已有值。使用 `find_custom_data()` 检查是否存在;已存储的零是有效值。 + +`check-kernel-initialization` 通过公开的 `entity` 接口验证这些操作,并检查其他自定义标量。启用应用、Kernel、Utility 和示例后,`check-typed-examples` 还会在真实 Kernel、EntityOperations 动态库创建的实体上验证无符号值更新。 + ## 注册事件 可以按类注册创建 / 销毁事件、字段变化、表格变化和容器操作,也可以为单个实体注册业务事件。公共类事件通过 `add_common_class_event()` 注册。 diff --git a/src/plugins/kernel/entity_impl.cpp b/src/plugins/kernel/entity_impl.cpp index b11ab3451..46ddae028 100644 --- a/src/plugins/kernel/entity_impl.cpp +++ b/src/plugins/kernel/entity_impl.cpp @@ -761,7 +761,14 @@ bool entity_impl::set_custom_int32(const std::string& name, const int32_t value) } bool entity_impl::set_custom_u_int32(const std::string& name, const uint32_t value) { - return false; + auto* data_ptr = custom_data_list_.find_value(name); + if (data_ptr == nullptr || data_ptr->get_type() != data_type::dt_uint32) + { + return false; + } + + data_ptr->set_u_int(value); + return true; } bool entity_impl::set_custom_int64(const std::string& name, const int64_t value) { diff --git a/tests/app/typed_examples.cpp b/tests/app/typed_examples.cpp index eb67fd063..e84be8e6e 100644 --- a/tests/app/typed_examples.cpp +++ b/tests/app/typed_examples.cpp @@ -1,8 +1,10 @@ // Copyright (c) 2026 OpenArkStudio. Licensed under Apache-2.0. See LICENSE. #include +#include #include #include #include +#include #include #include #include @@ -111,6 +113,15 @@ int main(int argc, char* argv[]) { require(gender == 1 || gender == 11, "Unexpected player gender"); edited += gender == 11; require(player->get_custom_int32("test") == 111, "Custom data initialization changed"); + require(player->add_custom_u_int32("unsigned_sequence", 0), "Custom uint32 creation failed"); + for (const auto value : {std::numeric_limits::max(), std::uint32_t{0}}) + { + require(player->set_custom_u_int32("unsigned_sequence", value) && + player->get_custom_u_int32("unsigned_sequence") == value, + "Public entity custom uint32 update failed through the real Kernel DSO"); + } + require(!player->set_custom_u_int32("test", 7) && player->get_custom_int32("test") == 111, + "Custom uint32 update changed a signed field"); auto* items = player->find_table(ark::entity_meta_player::items()); require(items && items->first() && items->first()->get_int64(ark::entity_meta_item_bag::guid_index()) == 1111, diff --git a/tests/core/entity_config_copy.cpp b/tests/core/entity_config_copy.cpp index d0606c705..fbda843b1 100644 --- a/tests/core/entity_config_copy.cpp +++ b/tests/core/entity_config_copy.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -412,3 +413,68 @@ TEST_CASE("container configuration zero and rejected configurations preserve cre CHECK(container->exist(empty->get_id())); CHECK(world.kernel.get_static_entity(99)->get_int32("level") == 13); } + +TEST_CASE("public entity custom uint32 updates preserve the full unsigned range") { + configured_world world; + const std::shared_ptr object = world.create(10, 0); + REQUIRE(object != nullptr); + REQUIRE(object->add_custom_u_int32("sequence", 0)); + CHECK(object->get_custom_u_int32("sequence") == 0); + for (const auto value : + {std::numeric_limits::max(), std::uint32_t{0x80000000}, std::uint32_t{1}, std::uint32_t{0}}) + { + REQUIRE(object->set_custom_u_int32("sequence", value)); + CHECK(object->get_custom_u_int32("sequence") == value); + CHECK(object->find_custom_data("sequence")); + } +} + +TEST_CASE("public entity custom uint32 rejects missing names without creating data") { + configured_world world; + const std::shared_ptr object = world.create(10, 0); + REQUIRE(object != nullptr); + CHECK_FALSE(object->find_custom_data("missing")); + CHECK_FALSE(object->set_custom_u_int32("missing", std::numeric_limits::max())); + CHECK_FALSE(object->find_custom_data("missing")); + REQUIRE(object->add_custom_u_int32("missing", 7)); + CHECK(object->get_custom_u_int32("missing") == 7); + REQUIRE(object->remove_custom_data("missing")); + CHECK_FALSE(object->set_custom_u_int32("missing", 0)); + CHECK_FALSE(object->find_custom_data("missing")); +} + +TEST_CASE("public entity custom uint32 rejects other scalar types without changing their values") { + configured_world world; + const std::shared_ptr object = world.create(10, 0); + REQUIRE(object != nullptr); + REQUIRE(object->add_custom_bool("boolean", true)); + REQUIRE(object->add_custom_int32("signed32", -17)); + REQUIRE(object->add_custom_int64("signed64", 4567890123LL)); + REQUIRE(object->add_custom_float("float", 1.25F)); + REQUIRE(object->add_custom_double("double", 2.5)); + REQUIRE(object->add_custom_string("string", "preserved")); + for (const auto* name : {"boolean", "signed32", "signed64", "float", "double", "string"}) + { + CHECK_FALSE(object->set_custom_u_int32(name, 0)); + CHECK_FALSE(object->set_custom_u_int32(name, std::numeric_limits::max())); + } + CHECK(object->get_custom_bool("boolean")); + CHECK(object->get_custom_int32("signed32") == -17); + CHECK(object->get_custom_int64("signed64") == 4567890123LL); + CHECK(object->get_custom_float("float") == 1.25F); + CHECK(object->get_custom_double("double") == 2.5); + CHECK(std::string(object->get_custom_string("string")) == "preserved"); + + REQUIRE(object->set_custom_bool("boolean", false)); + REQUIRE(object->set_custom_int32("signed32", 23)); + REQUIRE(object->set_custom_int64("signed64", -4567890123LL)); + REQUIRE(object->set_custom_float("float", 3.5F)); + REQUIRE(object->set_custom_double("double", 4.25)); + REQUIRE(object->set_custom_string("string", "updated")); + CHECK_FALSE(object->get_custom_bool("boolean")); + CHECK(object->get_custom_int32("signed32") == 23); + CHECK(object->get_custom_int64("signed64") == -4567890123LL); + CHECK(object->get_custom_float("float") == 3.5F); + CHECK(object->get_custom_double("double") == 4.25); + CHECK(std::string(object->get_custom_string("string")) == "updated"); +}