diff --git a/CMakeLists.txt b/CMakeLists.txt index b0afd13..0b1d21d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,11 +31,11 @@ project(LuaVox VERSION 0.0 DESCRIPTION "LuaVox Description") add_library(luavox_common INTERFACE) target_compile_features(luavox_common INTERFACE cxx_std_23) -# if(CMAKE_BUILD_TYPE STREQUAL "Debug") -# target_compile_options(luavox_common INTERFACE -fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=all) -# target_link_options(luavox_common INTERFACE -fsanitize=address,undefined) -# set(ENV{ASAN_OPTIONS} detect_leaks=0) -# endif() +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_options(luavox_common INTERFACE -fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=all) + target_link_options(luavox_common INTERFACE -fsanitize=address,undefined) + set(ENV{ASAN_OPTIONS} detect_leaks=0) +endif() if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") target_compile_options(luavox_common INTERFACE -fcoroutines) diff --git a/Src/Common/Abstract.cpp b/Src/Common/Abstract.cpp index 094da2d..cc93823 100644 --- a/Src/Common/Abstract.cpp +++ b/Src/Common/Abstract.cpp @@ -1440,7 +1440,7 @@ std::pair textures_val = profile.try_at("textures")) { @@ -1745,13 +1744,22 @@ PreparedModel::PreparedModel(const std::string_view modid, const js::object& pro for(const js::value& sub_val : subModels) { SubModel result; - const js::object& sub = sub_val.as_object(); - auto [domain, key] = parseDomainKey((std::string) sub.at("path").as_string(), modid); - result.Domain = std::move(domain); - result.Key = std::move(key); - if(boost::system::result scene_val = profile.try_at("scene")) - result.Scene = scene_val->to_number(); + if(auto path = sub_val.try_as_string()) { + auto [domain, key] = parseDomainKey((std::string) path.value(), modid); + result.Domain = std::move(domain); + result.Key = std::move(key); + } else { + const js::object& sub = sub_val.as_object(); + auto [domain, key] = parseDomainKey((std::string) sub.at("path").as_string(), modid); + result.Domain = std::move(domain); + result.Key = std::move(key); + + if(boost::system::result scene_val = profile.try_at("scene")) + result.Scene = scene_val->to_number(); + } + + SubModels.emplace_back(std::move(result)); } } } diff --git a/Src/Common/Abstract.hpp b/Src/Common/Abstract.hpp index e7488cf..05a0f67 100644 --- a/Src/Common/Abstract.hpp +++ b/Src/Common/Abstract.hpp @@ -673,7 +673,7 @@ enum struct TexturePipelineCMD : uint8_t { using Hash_t = std::array; inline std::pair parseDomainKey(const std::string& value, const std::string_view defaultDomain = "core") { - auto regResult = TOS::Str::match(value, "(?:([\\w\\d_]+):)?([\\w\\d_]+)"); + auto regResult = TOS::Str::match(value, "(?:([\\w\\d_]+):)?([\\w\\d/_.]+)"); if(!regResult) MAKE_ERROR("Недействительный домен:ключ"); diff --git a/Src/Server/AssetsManager.cpp b/Src/Server/AssetsManager.cpp index 6bef01c..da03036 100644 --- a/Src/Server/AssetsManager.cpp +++ b/Src/Server/AssetsManager.cpp @@ -115,18 +115,20 @@ void AssetsManager::loadResourceFromFile_Model(ResourceChangeObj& out, const std Resource res(path); std::filesystem::file_time_type ftt = fs::last_write_time(path); PreparedModel pmc; + + auto extension = path.extension(); - if(path.extension() == "json") { + if(extension == ".json") { js::object obj = js::parse(std::string_view((const char*) res.data(), res.size())).as_object(); LV::PreparedModel pm(domain, obj); std::u8string data = pm.dump(); pmc = PreparedModel(domain, pm); out.NewOrChange[(int) EnumAssets::Model][domain].emplace_back(key, Resource((const uint8_t*) data.data(), data.size()), ftt); - } else if(path.extension() == "gltf") { + } else if(extension == ".gltf") { js::object obj = js::parse(std::string_view((const char*) res.data(), res.size())).as_object(); pmc = PreparedModel(domain, obj); out.NewOrChange[(int) EnumAssets::Model][domain].emplace_back(key, res, ftt); - } else if(path.extension() == "glb") { + } else if(extension == ".glb") { pmc = PreparedModel(domain, res); out.NewOrChange[(int) EnumAssets::Model][domain].emplace_back(key, res, ftt); } else { @@ -251,7 +253,7 @@ std::tuple&> AssetsManager:: uint32_t pos = entry.Empty._Find_first(); entry.Empty.reset(pos); - if(entry.Empty._Find_first() == entry.Empty.size()) + if(entry.Empty._Find_next(pos) == entry.Empty.size()) entry.IsFull = true; id = index*TableEntry::ChunkSize + pos; @@ -262,6 +264,7 @@ std::tuple&> AssetsManager:: table.emplace_back(std::make_unique>()); id = (table.size()-1)*TableEntry::ChunkSize; data = &table.back()->Entries[0]; + table.back()->Empty.reset(0); // Расширяем таблицу с ресурсами, если необходимо if(type == EnumAssets::Nodestate) @@ -517,8 +520,8 @@ AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const std::vector models; - for(auto& [domain, key] : value.ModelToLocalId) { - models.push_back(lock->getId(EnumAssets::Model, domain, key)); + for(auto& [domain2, key2] : value.ModelToLocalId) { + models.push_back(lock->getId(EnumAssets::Model, domain2, key2)); } { @@ -542,14 +545,18 @@ AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const ResourceId resId = lock->getId(EnumAssets::Model, domain, key); ModelDependency deps; - for(auto& [domain, list] : value.ModelDependencies) { - ResourceId subResId = lock->getId(EnumAssets::Model, domain, key); - deps.ModelDeps.push_back(subResId); + for(auto& [domain2, list] : value.ModelDependencies) { + for(const std::string& key2 : list) { + ResourceId subResId = lock->getId(EnumAssets::Model, domain2, key2); + deps.ModelDeps.push_back(subResId); + } } - for(auto& [domain, list] : value.TextureDependencies) { - ResourceId subResId = lock->getId(EnumAssets::Texture, domain, key); - deps.TextureDeps.push_back(subResId); + for(auto& [domain2, list] : value.TextureDependencies) { + for(const std::string& key2 : list) { + ResourceId subResId = lock->getId(EnumAssets::Texture, domain2, key2); + deps.TextureDeps.push_back(subResId); + } } lock->Table_Model[resId / TableEntry::ChunkSize] @@ -574,7 +581,8 @@ AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const } // Вычисляем зависимости - std::function calcDeps = [&](AssetsModel resId, ModelDependency& entry) { + std::function calcDeps; + calcDeps = [&](AssetsModel resId, ModelDependency& entry) { for(AssetsModel subResId : entry.ModelDeps) { auto& model = lock->Table_Model[subResId / TableEntry::ChunkSize] ->Entries[subResId % TableEntry::ChunkSize]; @@ -582,6 +590,14 @@ AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const if(!model) continue; + if(resId == subResId) { + const auto object1 = lock->getResource(EnumAssets::Model, resId); + const auto object2 = lock->getResource(EnumAssets::Model, subResId); + LOG.warn() << "В моделе " << std::get<1>(*object1) << ':' << std::get<2>(*object1) + << " обнаружена циклическая зависимость с самой собою"; + continue; + } + if(!model->Ready) calcDeps(subResId, *model); diff --git a/Src/Server/AssetsManager.hpp b/Src/Server/AssetsManager.hpp index 4e140c9..047f4d7 100644 --- a/Src/Server/AssetsManager.hpp +++ b/Src/Server/AssetsManager.hpp @@ -229,7 +229,7 @@ public: getNodeDependency(const std::string& domain, const std::string& key) { auto lock = LocalObj.lock(); - AssetsNodestate nodestateId = lock->getId(EnumAssets::Nodestate, domain, key); + AssetsNodestate nodestateId = lock->getId(EnumAssets::Nodestate, domain, key+".json"); std::vector models; std::vector textures; diff --git a/Src/Server/GameServer.cpp b/Src/Server/GameServer.cpp index aef64fe..b876ac7 100644 --- a/Src/Server/GameServer.cpp +++ b/Src/Server/GameServer.cpp @@ -1444,13 +1444,13 @@ void GameServer::init(fs::path worldPath) { { sol::table t = LuaMainState.create_table(); - Content.CM.registerBase(EnumDefContent::Node, "core", "test0", t); - Content.CM.registerBase(EnumDefContent::Node, "core", "test1", t); - Content.CM.registerBase(EnumDefContent::Node, "core", "test2", t); - Content.CM.registerBase(EnumDefContent::Node, "core", "test3", t); - Content.CM.registerBase(EnumDefContent::Node, "core", "test4", t); - Content.CM.registerBase(EnumDefContent::Node, "core", "test5", t); - Content.CM.registerBase(EnumDefContent::World, "core", "devel_world", t); + Content.CM.registerBase(EnumDefContent::Node, "test", "test0", t); + Content.CM.registerBase(EnumDefContent::Node, "test", "test1", t); + Content.CM.registerBase(EnumDefContent::Node, "test", "test2", t); + Content.CM.registerBase(EnumDefContent::Node, "test", "test3", t); + Content.CM.registerBase(EnumDefContent::Node, "test", "test4", t); + Content.CM.registerBase(EnumDefContent::Node, "test", "test5", t); + Content.CM.registerBase(EnumDefContent::World, "test", "devel_world", t); } initLuaPre(); @@ -1513,15 +1513,15 @@ void GameServer::prerun() { } void GameServer::run() { - { - IWorldSaveBackend::TickSyncInfo_In in; - for(int x = -1; x <= 1; x++) - for(int y = -1; y <= 1; y++) - for(int z = -1; z <= 1; z++) - in.Load[0].push_back(Pos::GlobalChunk(x, y, z)); + // { + // IWorldSaveBackend::TickSyncInfo_In in; + // for(int x = -1; x <= 1; x++) + // for(int y = -1; y <= 1; y++) + // for(int z = -1; z <= 1; z++) + // in.Load[0].push_back(Pos::GlobalChunk(x, y, z)); - stepGeneratorAndLuaAsync(SaveBackend.World->tickSync(std::move(in))); - } + // stepGeneratorAndLuaAsync(SaveBackend.World->tickSync(std::move(in))); + // } while(true) { ((uint32_t&) Game.AfterStartTime) += (uint32_t) (CurrentTickDuration*256); @@ -2467,13 +2467,20 @@ void GameServer::stepSyncContent() { } for(std::shared_ptr& remoteClient : Game.RemoteClients) { - remoteClient->informateAssets(resources); - remoteClient->informateDefVoxel(voxels); - remoteClient->informateDefNode(nodes); - remoteClient->informateDefWorld(worlds); - remoteClient->informateDefPortal(portals); - remoteClient->informateDefEntity(entities); - remoteClient->informateDefItem(items); + if(!resources.empty()) + remoteClient->informateAssets(resources); + if(!voxels.empty()) + remoteClient->informateDefVoxel(voxels); + if(!nodes.empty()) + remoteClient->informateDefNode(nodes); + if(!worlds.empty()) + remoteClient->informateDefWorld(worlds); + if(!portals.empty()) + remoteClient->informateDefPortal(portals); + if(!entities.empty()) + remoteClient->informateDefEntity(entities); + if(!items.empty()) + remoteClient->informateDefItem(items); }