From 017f3d54841d471d06c7defda6095593be739978 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 24 Mar 2023 12:50:49 +0100 Subject: [PATCH 1/6] Interpret ESM::Light::mSound as identifier not a path --- apps/openmw/mwlua/types/light.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwlua/types/light.cpp b/apps/openmw/mwlua/types/light.cpp index 3ec5f53c11..e43a876464 100644 --- a/apps/openmw/mwlua/types/light.cpp +++ b/apps/openmw/mwlua/types/light.cpp @@ -41,9 +41,8 @@ namespace MWLua record["icon"] = sol::readonly_property([vfs](const ESM::Light& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); - record["sound"] = sol::readonly_property([vfs](const ESM::Light& rec) -> std::string { - return Misc::ResourceHelpers::correctSoundPath(rec.mSound.getRefIdString(), vfs); - }); + record["sound"] + = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mSound.getRefIdString(); }); record["mwscript"] = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mScript.getRefIdString(); }); record["weight"] = sol::readonly_property([](const ESM::Light& rec) -> float { return rec.mData.mWeight; }); From a762624581189a41ec8db0103eb3dd6aaf2a6d10 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 3 Feb 2023 15:11:53 +0100 Subject: [PATCH 2/6] Reorganize and update benchmarks --- apps/benchmarks/CMakeLists.txt | 17 +---------------- apps/benchmarks/detournavigator/CMakeLists.txt | 15 +++++++++++++++ .../detournavigator/navmeshtilescache.cpp | 2 +- extern/CMakeLists.txt | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 apps/benchmarks/detournavigator/CMakeLists.txt diff --git a/apps/benchmarks/CMakeLists.txt b/apps/benchmarks/CMakeLists.txt index 18bc56ec60..6a23ac3b37 100644 --- a/apps/benchmarks/CMakeLists.txt +++ b/apps/benchmarks/CMakeLists.txt @@ -2,19 +2,4 @@ if(OPENMW_USE_SYSTEM_BENCHMARK) find_package(benchmark REQUIRED) endif() -openmw_add_executable(openmw_detournavigator_navmeshtilescache_benchmark detournavigator/navmeshtilescache.cpp) -target_compile_features(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE cxx_std_17) -target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark benchmark::benchmark components) - -if (UNIX AND NOT APPLE) - target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark ${CMAKE_THREAD_LIBS_INIT}) -endif() - -if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.16 AND MSVC) - target_precompile_headers(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE ) -endif() - -if (BUILD_WITH_CODE_COVERAGE) - target_compile_options(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE --coverage) - target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark gcov) -endif() +add_subdirectory(detournavigator) diff --git a/apps/benchmarks/detournavigator/CMakeLists.txt b/apps/benchmarks/detournavigator/CMakeLists.txt new file mode 100644 index 0000000000..198cf2bd3c --- /dev/null +++ b/apps/benchmarks/detournavigator/CMakeLists.txt @@ -0,0 +1,15 @@ +openmw_add_executable(openmw_detournavigator_navmeshtilescache_benchmark navmeshtilescache.cpp) +target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark benchmark::benchmark components) + +if (UNIX AND NOT APPLE) + target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark ${CMAKE_THREAD_LIBS_INIT}) +endif() + +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.16 AND MSVC) + target_precompile_headers(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE ) +endif() + +if (BUILD_WITH_CODE_COVERAGE) + target_compile_options(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE --coverage) + target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark gcov) +endif() diff --git a/apps/benchmarks/detournavigator/navmeshtilescache.cpp b/apps/benchmarks/detournavigator/navmeshtilescache.cpp index f1d024a25f..3be1c8762a 100644 --- a/apps/benchmarks/detournavigator/navmeshtilescache.cpp +++ b/apps/benchmarks/detournavigator/navmeshtilescache.cpp @@ -191,7 +191,7 @@ namespace generateKeys(std::back_inserter(keys), keys.size() * (100 - hitPercentage) / 100, random); std::size_t n = 0; - while (state.KeepRunning()) + for (auto _ : state) { const auto& key = keys[n++ % keys.size()]; const auto result = cache.get(key.mAgentBounds, key.mTilePosition, key.mRecastMesh); diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 5ce604c50b..33908c8caf 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -221,8 +221,8 @@ if (BUILD_BENCHMARKS AND NOT OPENMW_USE_SYSTEM_BENCHMARK) include(FetchContent) FetchContent_Declare(benchmark - URL https://github.com/google/benchmark/archive/refs/tags/v1.5.2.zip - URL_HASH SHA512=1146deca3b424703800933012ef75805d4657309d58b3484498bb51a99025bd405a69855a75af59c23fc3684bfa027224513999b8d7beaab3320c96fb6d6c540 + URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.zip + URL_HASH SHA512=bec4016263587a57648e02b094c69e838c0a21e16c3dcfc6f03100397ab8f95d5fab1f5fd0d7e0e8adbb8212fff1eb574581158fdda1fa7fd6ff12762154b0cc SOURCE_DIR fetched/benchmark ) FetchContent_MakeAvailableExcludeFromAll(benchmark) From 30fd8c9d2325d0455b945b6797c5c3b9fa1db213 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 24 Mar 2023 23:29:21 +0100 Subject: [PATCH 3/6] Add benchmarks for RefId serialization and deserialization --- .gitlab-ci.yml | 1 + apps/benchmarks/CMakeLists.txt | 1 + apps/benchmarks/esm/CMakeLists.txt | 15 ++++++ apps/benchmarks/esm/benchrefid.cpp | 82 ++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 apps/benchmarks/esm/CMakeLists.txt create mode 100644 apps/benchmarks/esm/benchrefid.cpp diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8ef6c5db4b..16a420a8c8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,6 +50,7 @@ variables: - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw_test_suite --gtest_output="xml:openmw_tests.xml"; fi - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw-cs-tests --gtest_output="xml:openmw_cs_tests.xml"; fi - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_detournavigator_navmeshtilescache_benchmark; fi + - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_esm_refid_benchmark; fi - ccache -s - df -h - if [[ "${BUILD_WITH_CODE_COVERAGE}" ]]; then gcovr --xml-pretty --exclude-unreachable-branches --print-summary --root "${CI_PROJECT_DIR}" -j $(nproc) -o ../coverage.xml; fi diff --git a/apps/benchmarks/CMakeLists.txt b/apps/benchmarks/CMakeLists.txt index 6a23ac3b37..971a1ecd25 100644 --- a/apps/benchmarks/CMakeLists.txt +++ b/apps/benchmarks/CMakeLists.txt @@ -3,3 +3,4 @@ if(OPENMW_USE_SYSTEM_BENCHMARK) endif() add_subdirectory(detournavigator) +add_subdirectory(esm) diff --git a/apps/benchmarks/esm/CMakeLists.txt b/apps/benchmarks/esm/CMakeLists.txt new file mode 100644 index 0000000000..e7ecfff41b --- /dev/null +++ b/apps/benchmarks/esm/CMakeLists.txt @@ -0,0 +1,15 @@ +openmw_add_executable(openmw_esm_refid_benchmark benchrefid.cpp) +target_link_libraries(openmw_esm_refid_benchmark benchmark::benchmark components) + +if (UNIX AND NOT APPLE) + target_link_libraries(openmw_esm_refid_benchmark ${CMAKE_THREAD_LIBS_INIT}) +endif() + +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.16 AND MSVC) + target_precompile_headers(openmw_esm_refid_benchmark PRIVATE ) +endif() + +if (BUILD_WITH_CODE_COVERAGE) + target_compile_options(openmw_esm_refid_benchmark PRIVATE --coverage) + target_link_libraries(openmw_esm_refid_benchmark gcov) +endif() diff --git a/apps/benchmarks/esm/benchrefid.cpp b/apps/benchmarks/esm/benchrefid.cpp new file mode 100644 index 0000000000..6b76740602 --- /dev/null +++ b/apps/benchmarks/esm/benchrefid.cpp @@ -0,0 +1,82 @@ +#include + +#include "components/esm/refid.hpp" + +#include +#include +#include +#include +#include + +namespace +{ + constexpr std::size_t refIdsCount = 64 * 1024; + + template + std::string generateText(std::size_t size, Random& random) + { + std::uniform_int_distribution distribution('A', 'z'); + std::string result; + result.reserve(size); + std::generate_n(std::back_inserter(result), size, [&] { return distribution(random); }); + return result; + } + + template + std::vector generateStringRefIds(std::size_t size, Random& random) + { + std::vector result; + result.reserve(refIdsCount); + std::generate_n( + std::back_inserter(result), refIdsCount, [&] { return ESM::StringRefId(generateText(size, random)); }); + return result; + } + + template + std::vector generateSerializedRefIds(const std::vector& generated, Serialize&& serialize) + { + std::vector result; + result.reserve(generated.size()); + for (ESM::RefId refId : generated) + result.push_back(serialize(refId)); + return result; + } + + template + std::vector generateSerializedStringRefIds(std::size_t size, Random& random, Serialize&& serialize) + { + return generateSerializedRefIds(generateStringRefIds(size, random), serialize); + } + + void serializeRefId(benchmark::State& state) + { + std::minstd_rand random; + std::vector refIds = generateStringRefIds(state.range(0), random); + std::size_t i = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(refIds[i].serialize()); + if (++i >= refIds.size()) + i = 0; + } + } + + void deserializeRefId(benchmark::State& state) + { + std::minstd_rand random; + std::vector serializedRefIds + = generateSerializedStringRefIds(state.range(0), random, [](ESM::RefId v) { return v.serialize(); }); + std::size_t i = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(ESM::RefId::deserialize(serializedRefIds[i])); + if (++i >= serializedRefIds.size()) + i = 0; + } + } +} + +BENCHMARK(serializeRefId)->RangeMultiplier(4)->Range(8, 64); +BENCHMARK(deserializeRefId)->RangeMultiplier(4)->Range(8, 64); + +BENCHMARK_MAIN(); From 33a59a9342cfb8c740780ece0da51ae37a9fe9fb Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 24 Mar 2023 11:20:37 +0100 Subject: [PATCH 4/6] Use ESM::RefId::toDebugString to convert record to string in Lua --- apps/openmw/mwlua/localscripts.cpp | 6 +++--- apps/openmw/mwlua/types/activator.cpp | 2 +- apps/openmw/mwlua/types/apparatus.cpp | 2 +- apps/openmw/mwlua/types/armor.cpp | 2 +- apps/openmw/mwlua/types/book.cpp | 2 +- apps/openmw/mwlua/types/clothing.cpp | 2 +- apps/openmw/mwlua/types/container.cpp | 2 +- apps/openmw/mwlua/types/creature.cpp | 2 +- apps/openmw/mwlua/types/door.cpp | 2 +- apps/openmw/mwlua/types/ingredient.cpp | 2 +- apps/openmw/mwlua/types/light.cpp | 2 +- apps/openmw/mwlua/types/lockpick.cpp | 2 +- apps/openmw/mwlua/types/misc.cpp | 2 +- apps/openmw/mwlua/types/npc.cpp | 2 +- apps/openmw/mwlua/types/potion.cpp | 2 +- apps/openmw/mwlua/types/probe.cpp | 2 +- apps/openmw/mwlua/types/repair.cpp | 2 +- apps/openmw/mwlua/types/static.cpp | 2 +- apps/openmw/mwlua/types/weapon.cpp | 2 +- 19 files changed, 21 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 1b9984fc66..5d43374ea2 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -83,7 +83,7 @@ namespace MWLua sol::usertype mwscript = context.mLua->sol().new_usertype("LocalMWScript"); mwscript[sol::meta_function::to_string] = [](const LocalMWScript& s) { - return s.mSelf.ptr().getRefData().getLocals().getScriptId().getRefIdString(); + return s.mSelf.ptr().getRefData().getLocals().getScriptId().toDebugString(); }; mwscript[sol::meta_function::index] = [](const LocalMWScript& s, std::string_view var) { MWScript::Locals& locals = s.mSelf.ptr().getRefData().getLocals(); @@ -92,8 +92,8 @@ namespace MWLua mwscript[sol::meta_function::new_index] = [](const LocalMWScript& s, std::string_view var, double val) { MWScript::Locals& locals = s.mSelf.ptr().getRefData().getLocals(); if (!locals.setVar(locals.getScriptId(), Misc::StringUtils::lowerCase(var), val)) - throw std::runtime_error("No variable \"" + std::string(var) + "\" in mwscript \"" - + locals.getScriptId().getRefIdString() + "\""); + throw std::runtime_error( + "No variable \"" + std::string(var) + "\" in mwscript " + locals.getScriptId().toDebugString()); }; using AiPackage = MWMechanics::AiPackage; diff --git a/apps/openmw/mwlua/types/activator.cpp b/apps/openmw/mwlua/types/activator.cpp index 569149aabd..f598cc91b0 100644 --- a/apps/openmw/mwlua/types/activator.cpp +++ b/apps/openmw/mwlua/types/activator.cpp @@ -32,7 +32,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Activator"); record[sol::meta_function::to_string] - = [](const ESM::Activator& rec) { return "ESM3_Activator[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Activator& rec) { return "ESM3_Activator[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/apparatus.cpp b/apps/openmw/mwlua/types/apparatus.cpp index 405f254658..956e4a7e64 100644 --- a/apps/openmw/mwlua/types/apparatus.cpp +++ b/apps/openmw/mwlua/types/apparatus.cpp @@ -39,7 +39,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Apparatus"); record[sol::meta_function::to_string] - = [](const ESM::Apparatus& rec) { return "ESM3_Apparatus[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Apparatus& rec) { return "ESM3_Apparatus[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/armor.cpp b/apps/openmw/mwlua/types/armor.cpp index 0145e6dc74..94e7eae892 100644 --- a/apps/openmw/mwlua/types/armor.cpp +++ b/apps/openmw/mwlua/types/armor.cpp @@ -45,7 +45,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Armor"); record[sol::meta_function::to_string] - = [](const ESM::Armor& rec) -> std::string { return "ESM3_Armor[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Armor& rec) -> std::string { return "ESM3_Armor[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/book.cpp b/apps/openmw/mwlua/types/book.cpp index 1c6b17a5d8..3fdd978bfd 100644 --- a/apps/openmw/mwlua/types/book.cpp +++ b/apps/openmw/mwlua/types/book.cpp @@ -40,7 +40,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Book"); record[sol::meta_function::to_string] - = [](const ESM::Book& rec) { return "ESM3_Book[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Book& rec) { return "ESM3_Book[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/clothing.cpp b/apps/openmw/mwlua/types/clothing.cpp index b6110fb90d..3775c3a657 100644 --- a/apps/openmw/mwlua/types/clothing.cpp +++ b/apps/openmw/mwlua/types/clothing.cpp @@ -45,7 +45,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Clothing"); record[sol::meta_function::to_string] - = [](const ESM::Clothing& rec) -> std::string { return "ESM3_Clothing[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Clothing& rec) -> std::string { return "ESM3_Clothing[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Clothing& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Clothing& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/container.cpp b/apps/openmw/mwlua/types/container.cpp index 3300f50f7a..c1d675f63b 100644 --- a/apps/openmw/mwlua/types/container.cpp +++ b/apps/openmw/mwlua/types/container.cpp @@ -57,7 +57,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Container"); record[sol::meta_function::to_string] = [](const ESM::Container& rec) -> std::string { - return "ESM3_Container[" + rec.mId.getRefIdString() + "]"; + return "ESM3_Container[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mId.getRefIdString(); }); diff --git a/apps/openmw/mwlua/types/creature.cpp b/apps/openmw/mwlua/types/creature.cpp index e4df984ef6..234a32078f 100644 --- a/apps/openmw/mwlua/types/creature.cpp +++ b/apps/openmw/mwlua/types/creature.cpp @@ -32,7 +32,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Creature"); record[sol::meta_function::to_string] - = [](const ESM::Creature& rec) { return "ESM3_Creature[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Creature& rec) { return "ESM3_Creature[" + rec.mId.toDebugString() + "]"; }; record["name"] = sol::readonly_property([](const ESM::Creature& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Creature& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); diff --git a/apps/openmw/mwlua/types/door.cpp b/apps/openmw/mwlua/types/door.cpp index d44c604822..a7a780cba9 100644 --- a/apps/openmw/mwlua/types/door.cpp +++ b/apps/openmw/mwlua/types/door.cpp @@ -52,7 +52,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Door"); record[sol::meta_function::to_string] - = [](const ESM::Door& rec) -> std::string { return "ESM3_Door[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Door& rec) -> std::string { return "ESM3_Door[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/ingredient.cpp b/apps/openmw/mwlua/types/ingredient.cpp index a3cf1479ab..0a9de4d170 100644 --- a/apps/openmw/mwlua/types/ingredient.cpp +++ b/apps/openmw/mwlua/types/ingredient.cpp @@ -33,7 +33,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype(("ESM3_Ingredient")); record[sol::meta_function::to_string] - = [](const ESM::Ingredient& rec) { return "ESM3_Ingredient[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Ingredient& rec) { return "ESM3_Ingredient[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property( [](const ESM::Ingredient& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/light.cpp b/apps/openmw/mwlua/types/light.cpp index e43a876464..c18add7790 100644 --- a/apps/openmw/mwlua/types/light.cpp +++ b/apps/openmw/mwlua/types/light.cpp @@ -31,7 +31,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Light"); record[sol::meta_function::to_string] - = [](const ESM::Light& rec) -> std::string { return "ESM3_Light[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Light& rec) -> std::string { return "ESM3_Light[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/lockpick.cpp b/apps/openmw/mwlua/types/lockpick.cpp index f77327d391..333d137d20 100644 --- a/apps/openmw/mwlua/types/lockpick.cpp +++ b/apps/openmw/mwlua/types/lockpick.cpp @@ -32,7 +32,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Lockpick"); record[sol::meta_function::to_string] - = [](const ESM::Lockpick& rec) { return "ESM3_Lockpick[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Lockpick& rec) { return "ESM3_Lockpick[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/misc.cpp b/apps/openmw/mwlua/types/misc.cpp index 43c9180362..19214ddb3c 100644 --- a/apps/openmw/mwlua/types/misc.cpp +++ b/apps/openmw/mwlua/types/misc.cpp @@ -33,7 +33,7 @@ namespace MWLua sol::usertype record = context.mLua->sol().new_usertype("ESM3_Miscellaneous"); record[sol::meta_function::to_string] - = [](const ESM::Miscellaneous& rec) { return "ESM3_Miscellaneous[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Miscellaneous& rec) { return "ESM3_Miscellaneous[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property( [](const ESM::Miscellaneous& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/npc.cpp b/apps/openmw/mwlua/types/npc.cpp index 6105c2dc96..a0a20dcd26 100644 --- a/apps/openmw/mwlua/types/npc.cpp +++ b/apps/openmw/mwlua/types/npc.cpp @@ -33,7 +33,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_NPC"); record[sol::meta_function::to_string] - = [](const ESM::NPC& rec) { return "ESM3_NPC[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::NPC& rec) { return "ESM3_NPC[" + rec.mId.toDebugString() + "]"; }; record["name"] = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mName; }); record["race"] = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mRace.getRefIdString(); }); diff --git a/apps/openmw/mwlua/types/potion.cpp b/apps/openmw/mwlua/types/potion.cpp index 07f1b62a4d..4b6c23bd35 100644 --- a/apps/openmw/mwlua/types/potion.cpp +++ b/apps/openmw/mwlua/types/potion.cpp @@ -32,7 +32,7 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Potion"); record[sol::meta_function::to_string] - = [](const ESM::Potion& rec) { return "ESM3_Potion[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Potion& rec) { return "ESM3_Potion[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/probe.cpp b/apps/openmw/mwlua/types/probe.cpp index 8189d73548..06200f9538 100644 --- a/apps/openmw/mwlua/types/probe.cpp +++ b/apps/openmw/mwlua/types/probe.cpp @@ -31,7 +31,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Probe"); record[sol::meta_function::to_string] - = [](const ESM::Probe& rec) { return "ESM3_Probe[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Probe& rec) { return "ESM3_Probe[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/repair.cpp b/apps/openmw/mwlua/types/repair.cpp index 159f21fab1..ca5d9bd223 100644 --- a/apps/openmw/mwlua/types/repair.cpp +++ b/apps/openmw/mwlua/types/repair.cpp @@ -32,7 +32,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Repair"); record[sol::meta_function::to_string] - = [](const ESM::Repair& rec) { return "ESM3_Repair[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Repair& rec) { return "ESM3_Repair[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mName; }); diff --git a/apps/openmw/mwlua/types/static.cpp b/apps/openmw/mwlua/types/static.cpp index ad7962dd61..ff1cc5a812 100644 --- a/apps/openmw/mwlua/types/static.cpp +++ b/apps/openmw/mwlua/types/static.cpp @@ -32,7 +32,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Static"); record[sol::meta_function::to_string] - = [](const ESM::Static& rec) -> std::string { return "ESM3_Static[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Static& rec) -> std::string { return "ESM3_Static[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Static& rec) -> std::string { return rec.mId.getRefIdString(); }); record["model"] = sol::readonly_property([vfs](const ESM::Static& rec) -> std::string { diff --git a/apps/openmw/mwlua/types/weapon.cpp b/apps/openmw/mwlua/types/weapon.cpp index e5cf2d6c45..bfd2167824 100644 --- a/apps/openmw/mwlua/types/weapon.cpp +++ b/apps/openmw/mwlua/types/weapon.cpp @@ -49,7 +49,7 @@ namespace MWLua }); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Weapon"); record[sol::meta_function::to_string] - = [](const ESM::Weapon& rec) -> std::string { return "ESM3_Weapon[" + rec.mId.getRefIdString() + "]"; }; + = [](const ESM::Weapon& rec) -> std::string { return "ESM3_Weapon[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mId.getRefIdString(); }); record["name"] = sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mName; }); From ca9c55ac26c09917d6ea8c6efcdceaf3b2c2729d Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 24 Mar 2023 12:31:37 +0100 Subject: [PATCH 5/6] Use common function to add record binding --- apps/openmw/mwlua/types/activator.cpp | 9 ++------- apps/openmw/mwlua/types/apparatus.cpp | 9 ++------- apps/openmw/mwlua/types/armor.cpp | 8 ++------ apps/openmw/mwlua/types/book.cpp | 8 ++------ apps/openmw/mwlua/types/clothing.cpp | 9 ++------- apps/openmw/mwlua/types/container.cpp | 9 ++------- apps/openmw/mwlua/types/creature.cpp | 9 ++------- apps/openmw/mwlua/types/door.cpp | 8 ++------ apps/openmw/mwlua/types/ingredient.cpp | 9 ++------- apps/openmw/mwlua/types/light.cpp | 8 ++------ apps/openmw/mwlua/types/lockpick.cpp | 9 ++------- apps/openmw/mwlua/types/misc.cpp | 9 ++------- apps/openmw/mwlua/types/npc.cpp | 8 ++------ apps/openmw/mwlua/types/potion.cpp | 8 +------- apps/openmw/mwlua/types/probe.cpp | 8 ++------ apps/openmw/mwlua/types/repair.cpp | 9 ++------- apps/openmw/mwlua/types/static.cpp | 9 ++------- apps/openmw/mwlua/types/types.hpp | 15 +++++++++++++++ apps/openmw/mwlua/types/weapon.cpp | 9 ++------- 19 files changed, 50 insertions(+), 120 deletions(-) diff --git a/apps/openmw/mwlua/types/activator.cpp b/apps/openmw/mwlua/types/activator.cpp index f598cc91b0..936d438361 100644 --- a/apps/openmw/mwlua/types/activator.cpp +++ b/apps/openmw/mwlua/types/activator.cpp @@ -23,13 +23,8 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - activator["record"] = sol::overload( - [](const Object& obj) -> const ESM::Activator* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Activator* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(activator); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Activator"); record[sol::meta_function::to_string] = [](const ESM::Activator& rec) { return "ESM3_Activator[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/apparatus.cpp b/apps/openmw/mwlua/types/apparatus.cpp index 956e4a7e64..d4be3776bf 100644 --- a/apps/openmw/mwlua/types/apparatus.cpp +++ b/apps/openmw/mwlua/types/apparatus.cpp @@ -30,13 +30,8 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - apparatus["record"] = sol::overload( - [](const Object& obj) -> const ESM::Apparatus* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Apparatus* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(apparatus); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Apparatus"); record[sol::meta_function::to_string] = [](const ESM::Apparatus& rec) { return "ESM3_Apparatus[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/armor.cpp b/apps/openmw/mwlua/types/armor.cpp index 94e7eae892..e112139ba7 100644 --- a/apps/openmw/mwlua/types/armor.cpp +++ b/apps/openmw/mwlua/types/armor.cpp @@ -37,12 +37,8 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store = &MWBase::Environment::get().getWorld()->getStore().get(); - armor["record"] - = sol::overload([](const Object& obj) -> const ESM::Armor* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Armor* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(armor); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Armor"); record[sol::meta_function::to_string] = [](const ESM::Armor& rec) -> std::string { return "ESM3_Armor[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/book.cpp b/apps/openmw/mwlua/types/book.cpp index 3fdd978bfd..defc70d50c 100644 --- a/apps/openmw/mwlua/types/book.cpp +++ b/apps/openmw/mwlua/types/book.cpp @@ -32,12 +32,8 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store = &MWBase::Environment::get().getWorld()->getStore().get(); - book["record"] - = sol::overload([](const Object& obj) -> const ESM::Book* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Book* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(book); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Book"); record[sol::meta_function::to_string] = [](const ESM::Book& rec) { return "ESM3_Book[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/clothing.cpp b/apps/openmw/mwlua/types/clothing.cpp index 3775c3a657..c5169440cb 100644 --- a/apps/openmw/mwlua/types/clothing.cpp +++ b/apps/openmw/mwlua/types/clothing.cpp @@ -36,13 +36,8 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - clothing["record"] = sol::overload( - [](const Object& obj) -> const ESM::Clothing* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Clothing* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(clothing); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Clothing"); record[sol::meta_function::to_string] = [](const ESM::Clothing& rec) -> std::string { return "ESM3_Clothing[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/container.cpp b/apps/openmw/mwlua/types/container.cpp index c1d675f63b..76616eef54 100644 --- a/apps/openmw/mwlua/types/container.cpp +++ b/apps/openmw/mwlua/types/container.cpp @@ -48,13 +48,8 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - container["record"] = sol::overload( - [](const Object& obj) -> const ESM::Container* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Container* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(container); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Container"); record[sol::meta_function::to_string] = [](const ESM::Container& rec) -> std::string { return "ESM3_Container[" + rec.mId.toDebugString() + "]"; diff --git a/apps/openmw/mwlua/types/creature.cpp b/apps/openmw/mwlua/types/creature.cpp index 234a32078f..3691b7912d 100644 --- a/apps/openmw/mwlua/types/creature.cpp +++ b/apps/openmw/mwlua/types/creature.cpp @@ -23,13 +23,8 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - creature["record"] = sol::overload( - [](const Object& obj) -> const ESM::Creature* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Creature* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(creature); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Creature"); record[sol::meta_function::to_string] = [](const ESM::Creature& rec) { return "ESM3_Creature[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/door.cpp b/apps/openmw/mwlua/types/door.cpp index a7a780cba9..cf2880886e 100644 --- a/apps/openmw/mwlua/types/door.cpp +++ b/apps/openmw/mwlua/types/door.cpp @@ -44,12 +44,8 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store = &MWBase::Environment::get().getWorld()->getStore().get(); - door["record"] - = sol::overload([](const Object& obj) -> const ESM::Door* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Door* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(door); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Door"); record[sol::meta_function::to_string] = [](const ESM::Door& rec) -> std::string { return "ESM3_Door[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/ingredient.cpp b/apps/openmw/mwlua/types/ingredient.cpp index 0a9de4d170..8534526922 100644 --- a/apps/openmw/mwlua/types/ingredient.cpp +++ b/apps/openmw/mwlua/types/ingredient.cpp @@ -24,13 +24,8 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - ingredient["record"] = sol::overload( - [](const Object& obj) -> const ESM::Ingredient* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordID) -> const ESM::Ingredient* { - return store->find(ESM::RefId::stringRefId(recordID)); - }); + addRecordFunctionBinding(ingredient); + sol::usertype record = context.mLua->sol().new_usertype(("ESM3_Ingredient")); record[sol::meta_function::to_string] = [](const ESM::Ingredient& rec) { return "ESM3_Ingredient[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/light.cpp b/apps/openmw/mwlua/types/light.cpp index c18add7790..512eda3e33 100644 --- a/apps/openmw/mwlua/types/light.cpp +++ b/apps/openmw/mwlua/types/light.cpp @@ -23,12 +23,8 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store = &MWBase::Environment::get().getWorld()->getStore().get(); - light["record"] - = sol::overload([](const Object& obj) -> const ESM::Light* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Light* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(light); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Light"); record[sol::meta_function::to_string] = [](const ESM::Light& rec) -> std::string { return "ESM3_Light[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/lockpick.cpp b/apps/openmw/mwlua/types/lockpick.cpp index 333d137d20..133f228bb5 100644 --- a/apps/openmw/mwlua/types/lockpick.cpp +++ b/apps/openmw/mwlua/types/lockpick.cpp @@ -23,13 +23,8 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - lockpick["record"] = sol::overload( - [](const Object& obj) -> const ESM::Lockpick* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Lockpick* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(lockpick); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Lockpick"); record[sol::meta_function::to_string] = [](const ESM::Lockpick& rec) { return "ESM3_Lockpick[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/misc.cpp b/apps/openmw/mwlua/types/misc.cpp index 19214ddb3c..e25bf85b36 100644 --- a/apps/openmw/mwlua/types/misc.cpp +++ b/apps/openmw/mwlua/types/misc.cpp @@ -23,13 +23,8 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - miscellaneous["record"] = sol::overload( - [](const Object& obj) -> const ESM::Miscellaneous* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Miscellaneous* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(miscellaneous); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Miscellaneous"); record[sol::meta_function::to_string] diff --git a/apps/openmw/mwlua/types/npc.cpp b/apps/openmw/mwlua/types/npc.cpp index a0a20dcd26..0691aed27d 100644 --- a/apps/openmw/mwlua/types/npc.cpp +++ b/apps/openmw/mwlua/types/npc.cpp @@ -25,12 +25,8 @@ namespace MWLua { addNpcStatsBindings(npc, context); - const MWWorld::Store* store = &MWBase::Environment::get().getWorld()->getStore().get(); - npc["record"] - = sol::overload([](const Object& obj) -> const ESM::NPC* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::NPC* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(npc); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_NPC"); record[sol::meta_function::to_string] = [](const ESM::NPC& rec) { return "ESM3_NPC[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/potion.cpp b/apps/openmw/mwlua/types/potion.cpp index 4b6c23bd35..43bb29308d 100644 --- a/apps/openmw/mwlua/types/potion.cpp +++ b/apps/openmw/mwlua/types/potion.cpp @@ -21,13 +21,7 @@ namespace MWLua { void addPotionBindings(sol::table potion, const Context& context) { - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - potion["record"] - = sol::overload([](const Object& obj) -> const ESM::Potion* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Potion* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(potion); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); sol::usertype record = context.mLua->sol().new_usertype("ESM3_Potion"); diff --git a/apps/openmw/mwlua/types/probe.cpp b/apps/openmw/mwlua/types/probe.cpp index 06200f9538..f1d72c6bcb 100644 --- a/apps/openmw/mwlua/types/probe.cpp +++ b/apps/openmw/mwlua/types/probe.cpp @@ -23,12 +23,8 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store = &MWBase::Environment::get().getWorld()->getStore().get(); - probe["record"] - = sol::overload([](const Object& obj) -> const ESM::Probe* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Probe* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(probe); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Probe"); record[sol::meta_function::to_string] = [](const ESM::Probe& rec) { return "ESM3_Probe[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/repair.cpp b/apps/openmw/mwlua/types/repair.cpp index ca5d9bd223..a1c04eca5a 100644 --- a/apps/openmw/mwlua/types/repair.cpp +++ b/apps/openmw/mwlua/types/repair.cpp @@ -23,13 +23,8 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - repair["record"] - = sol::overload([](const Object& obj) -> const ESM::Repair* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Repair* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(repair); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Repair"); record[sol::meta_function::to_string] = [](const ESM::Repair& rec) { return "ESM3_Repair[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/static.cpp b/apps/openmw/mwlua/types/static.cpp index ff1cc5a812..b69735e896 100644 --- a/apps/openmw/mwlua/types/static.cpp +++ b/apps/openmw/mwlua/types/static.cpp @@ -23,13 +23,8 @@ namespace MWLua { auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - stat["record"] - = sol::overload([](const Object& obj) -> const ESM::Static* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Static* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(stat); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Static"); record[sol::meta_function::to_string] = [](const ESM::Static& rec) -> std::string { return "ESM3_Static[" + rec.mId.toDebugString() + "]"; }; diff --git a/apps/openmw/mwlua/types/types.hpp b/apps/openmw/mwlua/types/types.hpp index 2ce6d3e9a2..8716c73eee 100644 --- a/apps/openmw/mwlua/types/types.hpp +++ b/apps/openmw/mwlua/types/types.hpp @@ -5,6 +5,11 @@ #include +#include "apps/openmw/mwbase/environment.hpp" +#include "apps/openmw/mwbase/world.hpp" +#include "apps/openmw/mwworld/esmstore.hpp" +#include "apps/openmw/mwworld/store.hpp" + #include "../context.hpp" namespace MWLua @@ -45,6 +50,16 @@ namespace MWLua void addClothingBindings(sol::table clothing, const Context& context); void addStaticBindings(sol::table stat, const Context& context); void addLightBindings(sol::table light, const Context& context); + + template + void addRecordFunctionBinding(sol::table table) + { + const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); + + table["record"] = sol::overload([](const Object& obj) -> const T* { return obj.ptr().get()->mBase; }, + [&store]( + const std::string& recordId) -> const T* { return store.find(ESM::RefId::stringRefId(recordId)); }); + } } #endif // MWLUA_TYPES_H diff --git a/apps/openmw/mwlua/types/weapon.cpp b/apps/openmw/mwlua/types/weapon.cpp index bfd2167824..de8ec1d392 100644 --- a/apps/openmw/mwlua/types/weapon.cpp +++ b/apps/openmw/mwlua/types/weapon.cpp @@ -40,13 +40,8 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); - const MWWorld::Store* store - = &MWBase::Environment::get().getWorld()->getStore().get(); - weapon["record"] - = sol::overload([](const Object& obj) -> const ESM::Weapon* { return obj.ptr().get()->mBase; }, - [store](const std::string& recordId) -> const ESM::Weapon* { - return store->find(ESM::RefId::stringRefId(recordId)); - }); + addRecordFunctionBinding(weapon); + sol::usertype record = context.mLua->sol().new_usertype("ESM3_Weapon"); record[sol::meta_function::to_string] = [](const ESM::Weapon& rec) -> std::string { return "ESM3_Weapon[" + rec.mId.toDebugString() + "]"; }; From b7fdca0fe65278af11f62941faba8a2c836244b3 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 24 Mar 2023 12:31:37 +0100 Subject: [PATCH 6/6] Use serialized ESM::RefId for Lua records --- apps/benchmarks/esm/benchrefid.cpp | 121 +++++++++++++++++++++++ apps/openmw/mwlua/cellbindings.cpp | 4 +- apps/openmw/mwlua/objectbindings.cpp | 2 +- apps/openmw/mwlua/types/activator.cpp | 4 +- apps/openmw/mwlua/types/apparatus.cpp | 4 +- apps/openmw/mwlua/types/armor.cpp | 8 +- apps/openmw/mwlua/types/book.cpp | 6 +- apps/openmw/mwlua/types/clothing.cpp | 6 +- apps/openmw/mwlua/types/container.cpp | 4 +- apps/openmw/mwlua/types/creature.cpp | 4 +- apps/openmw/mwlua/types/door.cpp | 8 +- apps/openmw/mwlua/types/ingredient.cpp | 6 +- apps/openmw/mwlua/types/light.cpp | 6 +- apps/openmw/mwlua/types/lockpick.cpp | 4 +- apps/openmw/mwlua/types/misc.cpp | 4 +- apps/openmw/mwlua/types/npc.cpp | 10 +- apps/openmw/mwlua/types/potion.cpp | 6 +- apps/openmw/mwlua/types/probe.cpp | 4 +- apps/openmw/mwlua/types/repair.cpp | 6 +- apps/openmw/mwlua/types/static.cpp | 2 +- apps/openmw/mwlua/types/types.cpp | 1 - apps/openmw/mwlua/types/types.hpp | 3 +- apps/openmw/mwlua/types/weapon.cpp | 8 +- apps/openmw_test_suite/esm/testrefid.cpp | 61 ++++++++++-- components/CMakeLists.txt | 1 + components/esm/formidrefid.cpp | 16 +-- components/esm/generatedrefid.cpp | 16 +-- components/esm/indexrefid.cpp | 23 +++-- components/esm/refid.cpp | 47 +++++++++ components/esm/refid.hpp | 8 +- components/esm/serializerefid.hpp | 64 ++++++++++++ components/esm/stringrefid.cpp | 4 +- 32 files changed, 383 insertions(+), 88 deletions(-) create mode 100644 components/esm/serializerefid.hpp diff --git a/apps/benchmarks/esm/benchrefid.cpp b/apps/benchmarks/esm/benchrefid.cpp index 6b76740602..c2cd41e093 100644 --- a/apps/benchmarks/esm/benchrefid.cpp +++ b/apps/benchmarks/esm/benchrefid.cpp @@ -48,6 +48,40 @@ namespace return generateSerializedRefIds(generateStringRefIds(size, random), serialize); } + template + std::vector generateIndexRefIds(Random& random) + { + std::vector result; + result.reserve(refIdsCount); + std::uniform_int_distribution distribution(0, std::numeric_limits::max()); + std::generate_n(std::back_inserter(result), refIdsCount, + [&] { return ESM::IndexRefId(ESM::REC_ARMO, distribution(random)); }); + return result; + } + + template + std::vector generateSerializedIndexRefIds(Random& random, Serialize&& serialize) + { + return generateSerializedRefIds(generateIndexRefIds(random), serialize); + } + + template + std::vector generateGeneratedRefIds(Random& random) + { + std::vector result; + result.reserve(refIdsCount); + std::uniform_int_distribution distribution(0, std::numeric_limits::max()); + std::generate_n( + std::back_inserter(result), refIdsCount, [&] { return ESM::GeneratedRefId(distribution(random)); }); + return result; + } + + template + std::vector generateSerializedGeneratedRefIds(Random& random, Serialize&& serialize) + { + return generateSerializedRefIds(generateGeneratedRefIds(random), serialize); + } + void serializeRefId(benchmark::State& state) { std::minstd_rand random; @@ -74,9 +108,96 @@ namespace i = 0; } } + + void serializeTextStringRefId(benchmark::State& state) + { + std::minstd_rand random; + std::vector refIds = generateStringRefIds(state.range(0), random); + std::size_t i = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(refIds[i].serializeText()); + if (++i >= refIds.size()) + i = 0; + } + } + + void deserializeTextStringRefId(benchmark::State& state) + { + std::minstd_rand random; + std::vector serializedRefIds + = generateSerializedStringRefIds(state.range(0), random, [](ESM::RefId v) { return v.serializeText(); }); + std::size_t i = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(ESM::RefId::deserializeText(serializedRefIds[i])); + if (++i >= serializedRefIds.size()) + i = 0; + } + } + + void serializeTextGeneratedRefId(benchmark::State& state) + { + std::minstd_rand random; + std::vector refIds = generateGeneratedRefIds(random); + std::size_t i = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(refIds[i].serializeText()); + if (++i >= refIds.size()) + i = 0; + } + } + + void deserializeTextGeneratedRefId(benchmark::State& state) + { + std::minstd_rand random; + std::vector serializedRefIds + = generateSerializedGeneratedRefIds(random, [](ESM::RefId v) { return v.serializeText(); }); + std::size_t i = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(ESM::RefId::deserializeText(serializedRefIds[i])); + if (++i >= serializedRefIds.size()) + i = 0; + } + } + + void serializeTextIndexRefId(benchmark::State& state) + { + std::minstd_rand random; + std::vector refIds = generateIndexRefIds(random); + std::size_t i = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(refIds[i].serializeText()); + if (++i >= refIds.size()) + i = 0; + } + } + + void deserializeTextIndexRefId(benchmark::State& state) + { + std::minstd_rand random; + std::vector serializedRefIds + = generateSerializedIndexRefIds(random, [](ESM::RefId v) { return v.serializeText(); }); + std::size_t i = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(ESM::RefId::deserializeText(serializedRefIds[i])); + if (++i >= serializedRefIds.size()) + i = 0; + } + } } BENCHMARK(serializeRefId)->RangeMultiplier(4)->Range(8, 64); BENCHMARK(deserializeRefId)->RangeMultiplier(4)->Range(8, 64); +BENCHMARK(serializeTextStringRefId)->RangeMultiplier(4)->Range(8, 64); +BENCHMARK(deserializeTextStringRefId)->RangeMultiplier(4)->Range(8, 64); +BENCHMARK(serializeTextGeneratedRefId); +BENCHMARK(deserializeTextGeneratedRefId); +BENCHMARK(serializeTextIndexRefId); +BENCHMARK(deserializeTextIndexRefId); BENCHMARK_MAIN(); diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index dc50a79eef..f144336fa0 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -40,8 +40,8 @@ namespace MWLua }; cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getNameId(); }); - cellT["region"] - = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getRegion().getRefIdString(); }); + cellT["region"] = sol::readonly_property( + [](const CellT& c) -> std::string { return c.mStore->getCell()->getRegion().serializeText(); }); cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); }); cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); }); cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); }); diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 5a7791c635..127d9b98e3 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -167,7 +167,7 @@ namespace MWLua { objectT["isValid"] = [](const ObjectT& o) { return !o.ptrOrNull().isEmpty(); }; objectT["recordId"] = sol::readonly_property( - [](const ObjectT& o) -> std::string { return o.ptr().getCellRef().getRefId().toDebugString(); }); + [](const ObjectT& o) -> std::string { return o.ptr().getCellRef().getRefId().serializeText(); }); objectT["cell"] = sol::readonly_property([](const ObjectT& o) -> sol::optional> { const MWWorld::Ptr& ptr = o.ptr(); if (ptr.isInCell()) diff --git a/apps/openmw/mwlua/types/activator.cpp b/apps/openmw/mwlua/types/activator.cpp index 936d438361..88cf4d0f29 100644 --- a/apps/openmw/mwlua/types/activator.cpp +++ b/apps/openmw/mwlua/types/activator.cpp @@ -29,12 +29,12 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Activator& rec) { return "ESM3_Activator[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Activator& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] = sol::readonly_property( - [](const ESM::Activator& rec) -> std::string { return rec.mScript.getRefIdString(); }); + [](const ESM::Activator& rec) -> std::string { return rec.mScript.serializeText(); }); } } diff --git a/apps/openmw/mwlua/types/apparatus.cpp b/apps/openmw/mwlua/types/apparatus.cpp index d4be3776bf..0747d97d4c 100644 --- a/apps/openmw/mwlua/types/apparatus.cpp +++ b/apps/openmw/mwlua/types/apparatus.cpp @@ -36,13 +36,13 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Apparatus& rec) { return "ESM3_Apparatus[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Apparatus& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] = sol::readonly_property( - [](const ESM::Apparatus& rec) -> std::string { return rec.mScript.getRefIdString(); }); + [](const ESM::Apparatus& rec) -> std::string { return rec.mScript.serializeText(); }); record["icon"] = sol::readonly_property([vfs](const ESM::Apparatus& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); diff --git a/apps/openmw/mwlua/types/armor.cpp b/apps/openmw/mwlua/types/armor.cpp index e112139ba7..7c5b477e10 100644 --- a/apps/openmw/mwlua/types/armor.cpp +++ b/apps/openmw/mwlua/types/armor.cpp @@ -43,7 +43,7 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Armor& rec) -> std::string { return "ESM3_Armor[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Armor& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); @@ -51,10 +51,10 @@ namespace MWLua record["icon"] = sol::readonly_property([vfs](const ESM::Armor& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); - record["enchant"] = sol::readonly_property( - [](const ESM::Armor& rec) -> std::string { return rec.mEnchant.getRefIdString(); }); + record["enchant"] + = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mEnchant.serializeText(); }); record["mwscript"] - = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mScript.getRefIdString(); }); + = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mScript.serializeText(); }); record["weight"] = sol::readonly_property([](const ESM::Armor& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Armor& rec) -> int { return rec.mData.mValue; }); record["type"] = sol::readonly_property([](const ESM::Armor& rec) -> int { return rec.mData.mType; }); diff --git a/apps/openmw/mwlua/types/book.cpp b/apps/openmw/mwlua/types/book.cpp index defc70d50c..02602bd6a7 100644 --- a/apps/openmw/mwlua/types/book.cpp +++ b/apps/openmw/mwlua/types/book.cpp @@ -38,19 +38,19 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Book& rec) { return "ESM3_Book[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Book& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] - = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mScript.getRefIdString(); }); + = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mScript.serializeText(); }); record["icon"] = sol::readonly_property([vfs](const ESM::Book& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); record["text"] = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mText; }); record["enchant"] - = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mEnchant.getRefIdString(); }); + = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mEnchant.serializeText(); }); record["isScroll"] = sol::readonly_property([](const ESM::Book& rec) -> bool { return rec.mData.mIsScroll; }); record["value"] = sol::readonly_property([](const ESM::Book& rec) -> int { return rec.mData.mValue; }); record["weight"] = sol::readonly_property([](const ESM::Book& rec) -> float { return rec.mData.mWeight; }); diff --git a/apps/openmw/mwlua/types/clothing.cpp b/apps/openmw/mwlua/types/clothing.cpp index c5169440cb..35634d5fc1 100644 --- a/apps/openmw/mwlua/types/clothing.cpp +++ b/apps/openmw/mwlua/types/clothing.cpp @@ -42,7 +42,7 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Clothing& rec) -> std::string { return "ESM3_Clothing[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Clothing& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Clothing& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Clothing& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Clothing& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); @@ -51,9 +51,9 @@ namespace MWLua return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); record["enchant"] = sol::readonly_property( - [](const ESM::Clothing& rec) -> std::string { return rec.mEnchant.getRefIdString(); }); + [](const ESM::Clothing& rec) -> std::string { return rec.mEnchant.serializeText(); }); record["mwscript"] = sol::readonly_property( - [](const ESM::Clothing& rec) -> std::string { return rec.mScript.getRefIdString(); }); + [](const ESM::Clothing& rec) -> std::string { return rec.mScript.serializeText(); }); record["weight"] = sol::readonly_property([](const ESM::Clothing& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Clothing& rec) -> int { return rec.mData.mValue; }); record["type"] = sol::readonly_property([](const ESM::Clothing& rec) -> int { return rec.mData.mType; }); diff --git a/apps/openmw/mwlua/types/container.cpp b/apps/openmw/mwlua/types/container.cpp index 76616eef54..cd6d2e3d24 100644 --- a/apps/openmw/mwlua/types/container.cpp +++ b/apps/openmw/mwlua/types/container.cpp @@ -55,13 +55,13 @@ namespace MWLua return "ESM3_Container[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Container& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] = sol::readonly_property( - [](const ESM::Container& rec) -> std::string { return rec.mScript.getRefIdString(); }); + [](const ESM::Container& rec) -> std::string { return rec.mScript.serializeText(); }); record["weight"] = sol::readonly_property([](const ESM::Container& rec) -> float { return rec.mWeight; }); } } diff --git a/apps/openmw/mwlua/types/creature.cpp b/apps/openmw/mwlua/types/creature.cpp index 3691b7912d..ecba2b7eba 100644 --- a/apps/openmw/mwlua/types/creature.cpp +++ b/apps/openmw/mwlua/types/creature.cpp @@ -33,8 +33,8 @@ namespace MWLua return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] = sol::readonly_property( - [](const ESM::Creature& rec) -> std::string { return rec.mScript.getRefIdString(); }); + [](const ESM::Creature& rec) -> std::string { return rec.mScript.serializeText(); }); record["baseCreature"] = sol::readonly_property( - [](const ESM::Creature& rec) -> std::string { return rec.mOriginal.getRefIdString(); }); + [](const ESM::Creature& rec) -> std::string { return rec.mOriginal.serializeText(); }); } } diff --git a/apps/openmw/mwlua/types/door.cpp b/apps/openmw/mwlua/types/door.cpp index cf2880886e..9473ddf565 100644 --- a/apps/openmw/mwlua/types/door.cpp +++ b/apps/openmw/mwlua/types/door.cpp @@ -50,17 +50,17 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Door& rec) -> std::string { return "ESM3_Door[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Door& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] - = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mScript.getRefIdString(); }); + = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mScript.serializeText(); }); record["openSound"] = sol::readonly_property( - [](const ESM::Door& rec) -> std::string { return rec.mOpenSound.getRefIdString(); }); + [](const ESM::Door& rec) -> std::string { return rec.mOpenSound.serializeText(); }); record["closeSound"] = sol::readonly_property( - [](const ESM::Door& rec) -> std::string { return rec.mCloseSound.getRefIdString(); }); + [](const ESM::Door& rec) -> std::string { return rec.mCloseSound.serializeText(); }); } } diff --git a/apps/openmw/mwlua/types/ingredient.cpp b/apps/openmw/mwlua/types/ingredient.cpp index 8534526922..ed66ec9a9b 100644 --- a/apps/openmw/mwlua/types/ingredient.cpp +++ b/apps/openmw/mwlua/types/ingredient.cpp @@ -29,14 +29,14 @@ namespace MWLua sol::usertype record = context.mLua->sol().new_usertype(("ESM3_Ingredient")); record[sol::meta_function::to_string] = [](const ESM::Ingredient& rec) { return "ESM3_Ingredient[" + rec.mId.toDebugString() + "]"; }; - record["id"] = sol::readonly_property( - [](const ESM::Ingredient& rec) -> std::string { return rec.mId.getRefIdString(); }); + record["id"] + = sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Ingredient& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] = sol::readonly_property( - [](const ESM::Ingredient& rec) -> std::string { return rec.mScript.getRefIdString(); }); + [](const ESM::Ingredient& rec) -> std::string { return rec.mScript.serializeText(); }); record["icon"] = sol::readonly_property([vfs](const ESM::Ingredient& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); diff --git a/apps/openmw/mwlua/types/light.cpp b/apps/openmw/mwlua/types/light.cpp index 512eda3e33..bc9630289b 100644 --- a/apps/openmw/mwlua/types/light.cpp +++ b/apps/openmw/mwlua/types/light.cpp @@ -29,7 +29,7 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Light& rec) -> std::string { return "ESM3_Light[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Light& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); @@ -38,9 +38,9 @@ namespace MWLua return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); record["sound"] - = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mSound.getRefIdString(); }); + = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mSound.serializeText(); }); record["mwscript"] - = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mScript.getRefIdString(); }); + = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mScript.serializeText(); }); record["weight"] = sol::readonly_property([](const ESM::Light& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mValue; }); record["duration"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mTime; }); diff --git a/apps/openmw/mwlua/types/lockpick.cpp b/apps/openmw/mwlua/types/lockpick.cpp index 133f228bb5..c5d9c6983d 100644 --- a/apps/openmw/mwlua/types/lockpick.cpp +++ b/apps/openmw/mwlua/types/lockpick.cpp @@ -29,13 +29,13 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Lockpick& rec) { return "ESM3_Lockpick[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Lockpick& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] = sol::readonly_property( - [](const ESM::Lockpick& rec) -> std::string { return rec.mScript.getRefIdString(); }); + [](const ESM::Lockpick& rec) -> std::string { return rec.mScript.serializeText(); }); record["icon"] = sol::readonly_property([vfs](const ESM::Lockpick& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); diff --git a/apps/openmw/mwlua/types/misc.cpp b/apps/openmw/mwlua/types/misc.cpp index e25bf85b36..7b0b5934ec 100644 --- a/apps/openmw/mwlua/types/misc.cpp +++ b/apps/openmw/mwlua/types/misc.cpp @@ -30,13 +30,13 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Miscellaneous& rec) { return "ESM3_Miscellaneous[" + rec.mId.toDebugString() + "]"; }; record["id"] = sol::readonly_property( - [](const ESM::Miscellaneous& rec) -> std::string { return rec.mId.getRefIdString(); }); + [](const ESM::Miscellaneous& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Miscellaneous& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] = sol::readonly_property( - [](const ESM::Miscellaneous& rec) -> std::string { return rec.mScript.getRefIdString(); }); + [](const ESM::Miscellaneous& rec) -> std::string { return rec.mScript.serializeText(); }); record["icon"] = sol::readonly_property([vfs](const ESM::Miscellaneous& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); diff --git a/apps/openmw/mwlua/types/npc.cpp b/apps/openmw/mwlua/types/npc.cpp index 0691aed27d..71d611f99c 100644 --- a/apps/openmw/mwlua/types/npc.cpp +++ b/apps/openmw/mwlua/types/npc.cpp @@ -32,15 +32,15 @@ namespace MWLua = [](const ESM::NPC& rec) { return "ESM3_NPC[" + rec.mId.toDebugString() + "]"; }; record["name"] = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mName; }); record["race"] - = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mRace.getRefIdString(); }); + = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mRace.serializeText(); }); record["class"] - = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mClass.getRefIdString(); }); + = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mClass.serializeText(); }); record["mwscript"] - = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mScript.getRefIdString(); }); + = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mScript.serializeText(); }); record["hair"] - = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHair.getRefIdString(); }); + = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHair.serializeText(); }); record["head"] - = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHead.getRefIdString(); }); + = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHead.serializeText(); }); // This function is game-specific, in future we should replace it with something more universal. npc["isWerewolf"] = [](const Object& o) { diff --git a/apps/openmw/mwlua/types/potion.cpp b/apps/openmw/mwlua/types/potion.cpp index 43bb29308d..36a6c523d9 100644 --- a/apps/openmw/mwlua/types/potion.cpp +++ b/apps/openmw/mwlua/types/potion.cpp @@ -28,7 +28,7 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Potion& rec) { return "ESM3_Potion[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Potion& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); @@ -36,8 +36,8 @@ namespace MWLua record["icon"] = sol::readonly_property([vfs](const ESM::Potion& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); - record["mwscript"] = sol::readonly_property( - [](const ESM::Potion& rec) -> std::string { return rec.mScript.getRefIdString(); }); + record["mwscript"] + = sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mScript.serializeText(); }); record["weight"] = sol::readonly_property([](const ESM::Potion& rec) -> float { return rec.mData.mWeight; }); record["value"] = sol::readonly_property([](const ESM::Potion& rec) -> int { return rec.mData.mValue; }); } diff --git a/apps/openmw/mwlua/types/probe.cpp b/apps/openmw/mwlua/types/probe.cpp index f1d72c6bcb..e042e4a0ab 100644 --- a/apps/openmw/mwlua/types/probe.cpp +++ b/apps/openmw/mwlua/types/probe.cpp @@ -29,13 +29,13 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Probe& rec) { return "ESM3_Probe[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Probe& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); record["mwscript"] - = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mScript.getRefIdString(); }); + = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mScript.serializeText(); }); record["icon"] = sol::readonly_property([vfs](const ESM::Probe& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); diff --git a/apps/openmw/mwlua/types/repair.cpp b/apps/openmw/mwlua/types/repair.cpp index a1c04eca5a..f38b7e2992 100644 --- a/apps/openmw/mwlua/types/repair.cpp +++ b/apps/openmw/mwlua/types/repair.cpp @@ -29,13 +29,13 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Repair& rec) { return "ESM3_Repair[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Repair& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); - record["mwscript"] = sol::readonly_property( - [](const ESM::Repair& rec) -> std::string { return rec.mScript.getRefIdString(); }); + record["mwscript"] + = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mScript.serializeText(); }); record["icon"] = sol::readonly_property([vfs](const ESM::Repair& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); diff --git a/apps/openmw/mwlua/types/static.cpp b/apps/openmw/mwlua/types/static.cpp index b69735e896..ad7ee6b640 100644 --- a/apps/openmw/mwlua/types/static.cpp +++ b/apps/openmw/mwlua/types/static.cpp @@ -29,7 +29,7 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Static& rec) -> std::string { return "ESM3_Static[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Static& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Static& rec) -> std::string { return rec.mId.serializeText(); }); record["model"] = sol::readonly_property([vfs](const ESM::Static& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); }); diff --git a/apps/openmw/mwlua/types/types.cpp b/apps/openmw/mwlua/types/types.cpp index 75cc072ce2..8b5fdba713 100644 --- a/apps/openmw/mwlua/types/types.cpp +++ b/apps/openmw/mwlua/types/types.cpp @@ -58,7 +58,6 @@ namespace MWLua { ESM::REC_PROB, ObjectTypeName::Probe }, { ESM::REC_REPA, ObjectTypeName::Repair }, }; - } unsigned int getLiveCellRefType(const MWWorld::LiveCellRefBase* ref) diff --git a/apps/openmw/mwlua/types/types.hpp b/apps/openmw/mwlua/types/types.hpp index 8716c73eee..498c5baa28 100644 --- a/apps/openmw/mwlua/types/types.hpp +++ b/apps/openmw/mwlua/types/types.hpp @@ -57,8 +57,7 @@ namespace MWLua const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); table["record"] = sol::overload([](const Object& obj) -> const T* { return obj.ptr().get()->mBase; }, - [&store]( - const std::string& recordId) -> const T* { return store.find(ESM::RefId::stringRefId(recordId)); }); + [&store](std::string_view id) -> const T* { return store.find(ESM::RefId::deserializeText(id)); }); } } diff --git a/apps/openmw/mwlua/types/weapon.cpp b/apps/openmw/mwlua/types/weapon.cpp index de8ec1d392..b333f4ef57 100644 --- a/apps/openmw/mwlua/types/weapon.cpp +++ b/apps/openmw/mwlua/types/weapon.cpp @@ -46,7 +46,7 @@ namespace MWLua record[sol::meta_function::to_string] = [](const ESM::Weapon& rec) -> std::string { return "ESM3_Weapon[" + rec.mId.toDebugString() + "]"; }; record["id"] - = sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mId.getRefIdString(); }); + = sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mId.serializeText(); }); record["name"] = sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mName; }); record["model"] = sol::readonly_property([vfs](const ESM::Weapon& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs); @@ -55,9 +55,9 @@ namespace MWLua return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); record["enchant"] = sol::readonly_property( - [](const ESM::Weapon& rec) -> std::string { return rec.mEnchant.getRefIdString(); }); - record["mwscript"] = sol::readonly_property( - [](const ESM::Weapon& rec) -> std::string { return rec.mScript.getRefIdString(); }); + [](const ESM::Weapon& rec) -> std::string { return rec.mEnchant.serializeText(); }); + record["mwscript"] + = sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mScript.serializeText(); }); record["isMagical"] = sol::readonly_property( [](const ESM::Weapon& rec) -> bool { return rec.mData.mFlags & ESM::Weapon::Magical; }); record["isSilver"] = sol::readonly_property( diff --git a/apps/openmw_test_suite/esm/testrefid.cpp b/apps/openmw_test_suite/esm/testrefid.cpp index 48262b3640..51dad424d0 100644 --- a/apps/openmw_test_suite/esm/testrefid.cpp +++ b/apps/openmw_test_suite/esm/testrefid.cpp @@ -211,9 +211,9 @@ namespace ESM { RefId(), std::string() }, { RefId::stringRefId("foo"), "foo" }, { RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), { 'a', 0, -1, '\n', '\t' } }, - { RefId::formIdRefId(42), "42" }, - { RefId::generated(42), "42" }, - { RefId::index(REC_ARMO, 42), "ARMO, 42" }, + { RefId::formIdRefId(42), "0x2a" }, + { RefId::generated(42), "0x2a" }, + { RefId::index(REC_ARMO, 42), "ARMO:0x2a" }, }; INSTANTIATE_TEST_SUITE_P(ESMRefIdToString, ESMRefIdToStringTest, ValuesIn(toStringParams)); @@ -240,15 +240,51 @@ namespace ESM const std::vector> toDebugStringParams = { { RefId(), "Empty{}" }, - { RefId::stringRefId("foo"), "String{foo}" }, - { RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), "String{a\\x0\\xFF\\xA\\x9}" }, - { RefId::formIdRefId(42), "FormId{42}" }, - { RefId::generated(42), "Generated{42}" }, - { RefId::index(REC_ARMO, 42), "Index{ARMO, 42}" }, + { RefId::stringRefId("foo"), "\"foo\"" }, + { RefId::stringRefId("BAR"), "\"BAR\"" }, + { RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), "\"a\\x0\\xFF\\xA\\x9\"" }, + { RefId::formIdRefId(42), "FormId:0x2a" }, + { RefId::generated(42), "Generated:0x2a" }, + { RefId::index(REC_ARMO, 42), "Index:ARMO:0x2a" }, }; INSTANTIATE_TEST_SUITE_P(ESMRefIdToDebugString, ESMRefIdToDebugStringTest, ValuesIn(toDebugStringParams)); + struct ESMRefIdTextTest : TestWithParam> + { + }; + + TEST_P(ESMRefIdTextTest, serializeTextShouldReturnString) + { + EXPECT_EQ(GetParam().first.serializeText(), GetParam().second); + } + + TEST_P(ESMRefIdTextTest, deserializeTextShouldReturnRefId) + { + EXPECT_EQ(RefId::deserializeText(GetParam().second), GetParam().first); + } + + const std::vector> serializedRefIds = { + { RefId(), "" }, + { RefId::stringRefId("foo"), "foo" }, + { RefId::stringRefId("BAR"), "bar" }, + { RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), { 'a', 0, -1, '\n', '\t' } }, + { RefId::formIdRefId(0), "FormId:0x0" }, + { RefId::formIdRefId(1), "FormId:0x1" }, + { RefId::formIdRefId(0x1f), "FormId:0x1f" }, + { RefId::formIdRefId(std::numeric_limits::max()), "FormId:0xffffffff" }, + { RefId::generated(0), "Generated:0x0" }, + { RefId::generated(1), "Generated:0x1" }, + { RefId::generated(0x1f), "Generated:0x1f" }, + { RefId::generated(std::numeric_limits::max()), "Generated:0xffffffffffffffff" }, + { RefId::index(REC_INGR, 0), "Index:INGR:0x0" }, + { RefId::index(REC_INGR, 1), "Index:INGR:0x1" }, + { RefId::index(REC_INGR, 0x1f), "Index:INGR:0x1f" }, + { RefId::index(REC_INGR, std::numeric_limits::max()), "Index:INGR:0xffffffff" }, + }; + + INSTANTIATE_TEST_SUITE_P(ESMRefIdText, ESMRefIdTextTest, ValuesIn(serializedRefIds)); + template RefId generateRefId(); @@ -295,7 +331,14 @@ namespace ESM EXPECT_EQ(RefId::deserialize(refId.serialize()), refId); } - REGISTER_TYPED_TEST_SUITE_P(ESMRefIdSerializeDeserializeTest, serializeThenDeserializeShouldProduceSameValue); + TYPED_TEST_P(ESMRefIdSerializeDeserializeTest, serializeTextThenDeserializeTextShouldProduceSameValue) + { + const RefId refId = generateRefId(); + EXPECT_EQ(RefId::deserializeText(refId.serializeText()), refId); + } + + REGISTER_TYPED_TEST_SUITE_P(ESMRefIdSerializeDeserializeTest, serializeThenDeserializeShouldProduceSameValue, + serializeTextThenDeserializeTextShouldProduceSameValue); using RefIdTypeParams = Types; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f62274d0e9..c64c7fed65 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -90,6 +90,7 @@ add_component_dir(esm attr common defs esmcommon records util luascripts format stringrefid generatedrefid indexrefid + serializerefid ) add_component_dir(fx pass technique lexer widgets stateupdater) diff --git a/components/esm/formidrefid.cpp b/components/esm/formidrefid.cpp index de430698e2..f4635f1a87 100644 --- a/components/esm/formidrefid.cpp +++ b/components/esm/formidrefid.cpp @@ -1,24 +1,28 @@ #include "formidrefid.hpp" +#include "serializerefid.hpp" + #include -#include namespace ESM { std::string FormIdRefId::toString() const { - return std::to_string(mValue); + std::string result; + result.resize(getIntegralSize(mValue) + 2, '\0'); + serializeIntegral(mValue, 0, result); + return result; } std::string FormIdRefId::toDebugString() const { - std::ostringstream stream; - stream << *this; - return stream.str(); + std::string result; + serializeRefIdValue(mValue, formIdRefIdPrefix, result); + return result; } std::ostream& operator<<(std::ostream& stream, FormIdRefId value) { - return stream << "FormId{" << value.mValue << '}'; + return stream << value.toDebugString(); } } diff --git a/components/esm/generatedrefid.cpp b/components/esm/generatedrefid.cpp index 434e04bc5f..03d9732107 100644 --- a/components/esm/generatedrefid.cpp +++ b/components/esm/generatedrefid.cpp @@ -1,24 +1,28 @@ #include "generatedrefid.hpp" +#include "serializerefid.hpp" + #include -#include namespace ESM { std::string GeneratedRefId::toString() const { - return std::to_string(mValue); + std::string result; + result.resize(getIntegralSize(mValue) + 2, '\0'); + serializeIntegral(mValue, 0, result); + return result; } std::string GeneratedRefId::toDebugString() const { - std::ostringstream stream; - stream << *this; - return stream.str(); + std::string result; + serializeRefIdValue(mValue, generatedRefIdPrefix, result); + return result; } std::ostream& operator<<(std::ostream& stream, GeneratedRefId value) { - return stream << "Generated{" << value.mValue << '}'; + return stream << value.toDebugString(); } } diff --git a/components/esm/indexrefid.cpp b/components/esm/indexrefid.cpp index 4a71b64662..ee99f10e68 100644 --- a/components/esm/indexrefid.cpp +++ b/components/esm/indexrefid.cpp @@ -1,26 +1,33 @@ #include "indexrefid.hpp" -#include -#include +#include "serializerefid.hpp" -#include "esmcommon.hpp" +#include namespace ESM { std::string IndexRefId::toString() const { - return ESM::NAME(mRecordType).toString() + ", " + std::to_string(mValue); + std::string result; + result.resize(sizeof(mRecordType) + getIntegralSize(mValue) + 3, '\0'); + std::memcpy(result.data(), &mRecordType, sizeof(mRecordType)); + result[sizeof(mRecordType)] = ':'; + serializeIntegral(mValue, sizeof(mRecordType) + 1, result); + return result; } std::string IndexRefId::toDebugString() const { - std::ostringstream stream; - stream << *this; - return stream.str(); + std::string result; + serializeRefIdPrefix(sizeof(mRecordType) + getIntegralSize(mValue) + 1, indexRefIdPrefix, result); + std::memcpy(result.data() + indexRefIdPrefix.size(), &mRecordType, sizeof(mRecordType)); + result[indexRefIdPrefix.size() + sizeof(mRecordType)] = ':'; + serializeIntegral(mValue, indexRefIdPrefix.size() + sizeof(mRecordType) + 1, result); + return result; } std::ostream& operator<<(std::ostream& stream, IndexRefId value) { - return stream << "Index{" << ESM::NAME(value.mRecordType).toStringView() << ", " << value.mValue << '}'; + return stream << value.toDebugString(); } } diff --git a/components/esm/refid.cpp b/components/esm/refid.cpp index 8d5cdfd5ab..d04ad4a845 100644 --- a/components/esm/refid.cpp +++ b/components/esm/refid.cpp @@ -1,8 +1,15 @@ #include "refid.hpp" +#include "serializerefid.hpp" + +#include "components/misc/strings/lower.hpp" + +#include #include #include #include +#include +#include namespace ESM { @@ -102,6 +109,19 @@ namespace ESM return false; } }; + + struct SerializeText + { + std::string operator()(ESM::EmptyRefId /*v*/) const { return std::string(); } + + std::string operator()(ESM::StringRefId v) const { return Misc::StringUtils::lowerCase(v.getValue()); } + + template + std::string operator()(const T& v) const + { + return v.toDebugString(); + } + }; } const RefId RefId::sEmpty = {}; @@ -193,4 +213,31 @@ namespace ESM std::memcpy(&result.mValue, value.data(), sizeof(result.mValue)); return result; } + + std::string RefId::serializeText() const + { + return std::visit(SerializeText{}, mValue); + } + + ESM::RefId RefId::deserializeText(std::string_view value) + { + if (value.empty()) + return ESM::RefId(); + + if (value.starts_with(formIdRefIdPrefix)) + return ESM::RefId::formIdRefId(deserializeIntegral(formIdRefIdPrefix.size(), value)); + + if (value.starts_with(generatedRefIdPrefix)) + return ESM::RefId::generated(deserializeIntegral(generatedRefIdPrefix.size(), value)); + + if (value.starts_with(indexRefIdPrefix)) + { + ESM::RecNameInts recordType{}; + std::memcpy(&recordType, value.data() + indexRefIdPrefix.size(), sizeof(recordType)); + return ESM::RefId::index(recordType, + deserializeIntegral(indexRefIdPrefix.size() + sizeof(recordType) + 1, value)); + } + + return ESM::RefId::stringRefId(value); + } } diff --git a/components/esm/refid.hpp b/components/esm/refid.hpp index dc90be5760..4a24839061 100644 --- a/components/esm/refid.hpp +++ b/components/esm/refid.hpp @@ -48,9 +48,12 @@ namespace ESM public: const static RefId sEmpty; - // Constructs RefId from a string containing byte by byte copy of RefId::mValue. + // Constructs RefId from a serialized string containing byte by byte copy of RefId::mValue. static ESM::RefId deserialize(std::string_view value); + // Constructs RefId from a serialized text. + static ESM::RefId deserializeText(std::string_view value); + // Constructs RefId from a string using a pointer to a static set of strings. static RefId stringRefId(std::string_view value); @@ -118,6 +121,9 @@ namespace ESM // Copy mValue byte by byte into a string. Use result only during within the same process. std::string serialize() const; + // Serialize into stable text format. + std::string serializeText() const; + friend constexpr bool operator==(const RefId& l, const RefId& r) { return l.mValue == r.mValue; } bool operator==(std::string_view rhs) const; diff --git a/components/esm/serializerefid.hpp b/components/esm/serializerefid.hpp new file mode 100644 index 0000000000..9f43511622 --- /dev/null +++ b/components/esm/serializerefid.hpp @@ -0,0 +1,64 @@ +#ifndef OPENMW_COMPONENTS_ESM_SERIALIZEREFID_HPP +#define OPENMW_COMPONENTS_ESM_SERIALIZEREFID_HPP + +#include +#include +#include +#include +#include + +namespace ESM +{ + constexpr std::string_view formIdRefIdPrefix = "FormId:"; + constexpr std::string_view generatedRefIdPrefix = "Generated:"; + constexpr std::string_view indexRefIdPrefix = "Index:"; + + template + std::size_t getIntegralSize(T value) + { + std::size_t result = sizeof(T) * 2; + while (true) + { + if (result == 1 || (value & static_cast(0xf) << ((result - 1) * 4)) != 0) + break; + --result; + } + return result; + } + + inline void serializeRefIdPrefix(std::size_t valueSize, std::string_view prefix, std::string& out) + { + out.resize(prefix.size() + valueSize + 2, '\0'); + std::memcpy(out.data(), prefix.data(), prefix.size()); + } + + template + void serializeIntegral(T value, std::size_t shift, std::string& out) + { + out[shift] = '0'; + out[shift + 1] = 'x'; + const auto r = std::to_chars(out.data() + shift + 2, out.data() + out.size(), value, 16); + if (r.ec != std::errc()) + throw std::system_error(std::make_error_code(r.ec), "Failed to serialize ESM::RefId integral value"); + } + + template + void serializeRefIdValue(T value, std::string_view prefix, std::string& out) + { + serializeRefIdPrefix(getIntegralSize(value), prefix, out); + serializeIntegral(value, prefix.size(), out); + } + + template + T deserializeIntegral(std::size_t shift, std::string_view value) + { + T result{}; + const auto r = std::from_chars(value.data() + shift + 2, value.data() + value.size(), result, 16); + if (r.ec != std::errc()) + throw std::system_error(std::make_error_code(r.ec), + "Failed to deserialize ESM::RefId integral value: \"" + std::string(value) + '"'); + return result; + } +} + +#endif diff --git a/components/esm/stringrefid.cpp b/components/esm/stringrefid.cpp index 22cf045a32..ad7d35903e 100644 --- a/components/esm/stringrefid.cpp +++ b/components/esm/stringrefid.cpp @@ -60,13 +60,13 @@ namespace ESM std::ostream& operator<<(std::ostream& stream, StringRefId value) { - stream << "String{"; + stream << '"'; for (char c : *value.mValue) if (std::isprint(c) && c != '\t' && c != '\n' && c != '\r') stream << c; else stream << "\\x" << std::hex << std::uppercase << static_cast(static_cast(c)); - return stream << '}'; + return stream << '"'; } std::string StringRefId::toDebugString() const