This commit is contained in:
2025-08-19 17:12:45 +06:00
parent 2f62ffd59c
commit 2cf37f4e0a
10 changed files with 255 additions and 141 deletions

View File

@@ -31,6 +31,12 @@ project(LuaVox VERSION 0.0 DESCRIPTION "LuaVox Description")
add_library(luavox_common INTERFACE) add_library(luavox_common INTERFACE)
target_compile_features(luavox_common INTERFACE cxx_std_23) 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_CXX_COMPILER_ID}" MATCHES "GNU") if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
target_compile_options(luavox_common INTERFACE -fcoroutines) target_compile_options(luavox_common INTERFACE -fcoroutines)
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
@@ -151,15 +157,38 @@ FetchContent_MakeAvailable(sqlite3)
target_link_libraries(luavox_common INTERFACE SQLite::SQLite3) target_link_libraries(luavox_common INTERFACE SQLite::SQLite3)
# Static Assets # Static Assets
file(GLOB_RECURSE ASSETS RELATIVE "${PROJECT_SOURCE_DIR}/assets" "assets/*.*") find_package(Python3 REQUIRED)
file(GLOB_RECURSE ASSETS_A "${PROJECT_SOURCE_DIR}/assets" "assets/*.*") set(ASSETS_DIR "${PROJECT_SOURCE_DIR}/assets")
add_custom_command(OUTPUT assets.o resources.cpp INPUT ${ASSETS_A} file(GLOB_RECURSE ASSETS_LIST RELATIVE "${ASSETS_DIR}" "${ASSETS_DIR}/*.*")
COMMAND cd ${CMAKE_CURRENT_BINARY_DIR} && ${CMAKE_CURRENT_SOURCE_DIR}/Src/assets.py ${ASSETS}
COMMAND cd "${CMAKE_CURRENT_SOURCE_DIR}/assets" && ld -r -b binary -o '${CMAKE_CURRENT_BINARY_DIR}/assets.o' ${ASSETS}
COMMAND objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents ${CMAKE_CURRENT_BINARY_DIR}/assets.o ${CMAKE_CURRENT_BINARY_DIR}/assets.o)
set_source_files_properties(assets.o PROPERTIES EXTERNAL_OBJECT true GENERATED true) set(ASSETS_O "${CMAKE_CURRENT_BINARY_DIR}/assets.o")
add_library(assets STATIC resources.cpp assets.o) set(ASSETS_LD_O "${CMAKE_CURRENT_BINARY_DIR}/assets_ld.o")
set(RESOURCES_CPP "${CMAKE_CURRENT_BINARY_DIR}/resources.cpp")
set(ASSETS_ABS)
foreach(asset IN LISTS ASSETS_LIST)
list(APPEND ASSETS_ABS "${ASSETS_DIR}/${asset}")
endforeach()
add_custom_command(
OUTPUT ${ASSETS_O} ${RESOURCES_CPP}
DEPENDS ${ASSETS_ABS}
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/Src/assets.py
"${RESOURCES_CPP}"
${ASSETS_LIST}
COMMAND ${CMAKE_COMMAND} -E chdir "${CMAKE_CURRENT_SOURCE_DIR}/assets" ld -r -b binary -o "${ASSETS_LD_O}" ${ASSETS_LIST}
COMMAND ${CMAKE_OBJCOPY}
-O elf64-x86-64
--rename-section .data=.rodata,alloc,load,readonly,data,contents
${ASSETS_LD_O}
${ASSETS_O}
COMMENT "Embedding assets: generating resources.cpp and assets.o"
VERBATIM
)
set_source_files_properties(${RESOURCES_CPP} PROPERTIES GENERATED true)
set_source_files_properties(${ASSETS_O} PROPERTIES EXTERNAL_OBJECT true GENERATED true)
add_library(assets STATIC ${RESOURCES_CPP} ${ASSETS_O})
set_target_properties(assets PROPERTIES LINKER_LANGUAGE C) set_target_properties(assets PROPERTIES LINKER_LANGUAGE C)
target_link_libraries(luavox_common INTERFACE assets) target_link_libraries(luavox_common INTERFACE assets)

View File

@@ -2226,18 +2226,23 @@ void Vulkan::gui_MainMenu() {
void Vulkan::gui_ConnectedToServer() { void Vulkan::gui_ConnectedToServer() {
if(Game.Session) { if(Game.Session) {
if(ImGui::Begin("MainMenu", nullptr, ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove))
if(!ImGui::Begin("MainMenu", nullptr, ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) {
return;
std::string text = std::to_string(ImGui::GetIO().Framerate); std::string text = std::to_string(ImGui::GetIO().Framerate);
ImGui::Text(text.c_str()); ImGui::Text(text.c_str());
if(ImGui::Button("Выйти")) {
Game.RSession->pushStage(EnumRenderStage::Shutdown);
Game.Session->shutdown(EnumDisconnect::ByInterface);
Game.RSession = nullptr;
Game.Session = nullptr;
}
ImGui::End(); ImGui::End();
}
if(Game.Session->isConnected()) if(Game.Session->isConnected())
return; return;
Game.RSession->pushStage(EnumRenderStage::Shutdown);
Game.RSession = nullptr; Game.RSession = nullptr;
Game.Session = nullptr; Game.Session = nullptr;
Game.ImGuiInterfaces.pop_back(); Game.ImGuiInterfaces.pop_back();

View File

@@ -1266,7 +1266,7 @@ void VulkanRenderSession::pushStage(EnumRenderStage stage) {
VKCTX->ThreadVertexObj.join(); VKCTX->ThreadVertexObj.join();
} }
std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(const std::vector<VoxelCube> cubes) { std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(const std::vector<VoxelCube>& cubes) {
std::vector<VoxelVertexPoint> out; std::vector<VoxelVertexPoint> out;
out.reserve(cubes.size()*6); out.reserve(cubes.size()*6);

View File

@@ -120,8 +120,7 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
} }
~ThreadVertexObj_t() { ~ThreadVertexObj_t() {
State.lock()->Stage = EnumRenderStage::Shutdown; assert(!Thread.joinable());
Thread.join();
if(CMDPool) if(CMDPool)
vkDestroyCommandPool(VkInst->Graphics.Device, CMDPool, nullptr); vkDestroyCommandPool(VkInst->Graphics.Device, CMDPool, nullptr);
@@ -355,7 +354,7 @@ public:
void drawWorld(GlobalTime gTime, float dTime, VkCommandBuffer drawCmd); void drawWorld(GlobalTime gTime, float dTime, VkCommandBuffer drawCmd);
void pushStage(EnumRenderStage stage); void pushStage(EnumRenderStage stage);
static std::vector<VoxelVertexPoint> generateMeshForVoxelChunks(const std::vector<VoxelCube> cubes); static std::vector<VoxelVertexPoint> generateMeshForVoxelChunks(const std::vector<VoxelCube>& cubes);
static std::vector<NodeVertexStatic> generateMeshForNodeChunks(const Node* nodes); static std::vector<NodeVertexStatic> generateMeshForNodeChunks(const Node* nodes);
private: private:

View File

@@ -823,4 +823,18 @@ std::u8string unCompressLinear(const std::u8string& data) {
return *(std::u8string*) &outString; return *(std::u8string*) &outString;
} }
PreparedNodeState::PreparedNodeState(const js::object& profile) {
for(auto& [key, value] : profile) {
}
}
PreparedNodeState::PreparedNodeState(const sol::table& profile) {
}
PreparedNodeState::PreparedNodeState(const std::u8string& data) {
}
} }

View File

@@ -9,10 +9,15 @@
#include <memory> #include <memory>
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include <type_traits> #include <type_traits>
#include <unordered_map>
#include <vector> #include <vector>
#include <boost/json.hpp>
namespace LV { namespace LV {
namespace js = boost::json;
namespace Pos { namespace Pos {
template<typename T, size_t BitsPerComponent> template<typename T, size_t BitsPerComponent>
@@ -498,40 +503,77 @@ enum struct TexturePipelineCMD : uint8_t {
}; };
/*
Хранит распаршенное определение состояний нод.
Не привязано ни к какому окружению.
*/
struct PreparedNodeState {
enum class Op {
Add, Sub, Mul, Div, Mod,
LT, LE, GT, GE, EQ, NE,
And, Or,
Pos, Neg, Not
};
struct Node {
struct Num { int v; };
struct Var { std::string name; };
struct Unary { Op op; uint16_t rhs; };
struct Binary { Op op; uint16_t lhs, rhs; };
std::variant<Num, Var, Unary, Binary> v;
};
struct Transformation {
int a; float b;
};
struct Model {
uint16_t Id;
bool UVLock = false;
std::vector<Transformation> Transforms;
};
struct VectorModel {
std::vector<Model> Models;
bool UVLock = false;
// Может добавить возможность использовать переменную рандома в трансформациях?
std::vector<Transformation> Transforms;
};
// Локальный идентификатор в именной ресурс
std::vector<std::pair<std::string, std::string>> ResourceToLocalId;
// Ноды выражений
std::vector<Node> Nodes;
// Условия -> вариации модели + веса
std::vector<
std::pair<uint16_t,
boost::container::small_vector<
std::pair<std::variant<Model, VectorModel>, uint16_t>,
1
>
>
> Routes;
PreparedNodeState(const js::object& profile);
PreparedNodeState(const sol::table& profile);
PreparedNodeState(const std::u8string& data);
PreparedNodeState() = default;
PreparedNodeState(const PreparedNodeState&) = default;
PreparedNodeState(PreparedNodeState&&) = default;
PreparedNodeState& operator=(const PreparedNodeState&) = default;
PreparedNodeState& operator=(PreparedNodeState&&) = default;
// Пишет в сжатый двоичный формат
std::u8string dump() const;
};
struct TexturePipeline { struct TexturePipeline {
std::vector<AssetsTexture> BinTextures; std::vector<AssetsTexture> BinTextures;
std::u8string Pipeline; std::u8string Pipeline;
}; };
struct DefVoxel_t {
};
struct DefNode_t {
enum struct EnumDrawType : uint8_t {
NoDraw, // Не рисуется
Simple, // Простая нода с текстурами на каждой стороне
} DrawType = EnumDrawType::Simple;
TexturePipeline Texs[6];
};
struct DefWorld_t {
};
struct DefPortal_t {
};
struct DefEntity_t {
};
struct DefItem_t {
};
using Hash_t = std::array<uint8_t, 32>; using Hash_t = std::array<uint8_t, 32>;
} }

View File

@@ -11,54 +11,54 @@
namespace LV::Server { namespace LV::Server {
AssetsManager::Resource AssetsManager::loadResourceFromFile(EnumAssets type, fs::path path) const { void AssetsManager::loadResourceFromFile(EnumAssets type, ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
switch(type) { switch(type) {
case EnumAssets::Nodestate: return loadResourceFromFile_Nodestate(path); case EnumAssets::Nodestate: loadResourceFromFile_Nodestate (out, domain, key, path); return;
case EnumAssets::Particle: return loadResourceFromFile_Particle(path); case EnumAssets::Particle: loadResourceFromFile_Particle (out, domain, key, path); return;
case EnumAssets::Animation: return loadResourceFromFile_Animation(path); case EnumAssets::Animation: loadResourceFromFile_Animation (out, domain, key, path); return;
case EnumAssets::Model: return loadResourceFromFile_Model(path); case EnumAssets::Model: loadResourceFromFile_Model (out, domain, key, path); return;
case EnumAssets::Texture: return loadResourceFromFile_Texture(path); case EnumAssets::Texture: loadResourceFromFile_Texture (out, domain, key, path); return;
case EnumAssets::Sound: return loadResourceFromFile_Sound(path); case EnumAssets::Sound: loadResourceFromFile_Sound (out, domain, key, path); return;
case EnumAssets::Font: return loadResourceFromFile_Font(path); case EnumAssets::Font: loadResourceFromFile_Font (out, domain, key, path); return;
default: default:
std::unreachable(); std::unreachable();
} }
} }
AssetsManager::Resource AssetsManager::loadResourceFromLua(EnumAssets type, const sol::table& profile) const { void AssetsManager::loadResourceFromLua(EnumAssets type, ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
switch(type) { switch(type) {
case EnumAssets::Nodestate: return loadResourceFromLua_Nodestate(profile); case EnumAssets::Nodestate: loadResourceFromLua_Nodestate(out, domain, key, profile); return;
case EnumAssets::Particle: return loadResourceFromLua_Particle(profile); case EnumAssets::Particle: loadResourceFromLua_Particle(out, domain, key, profile); return;
case EnumAssets::Animation: return loadResourceFromLua_Animation(profile); case EnumAssets::Animation: loadResourceFromLua_Animation(out, domain, key, profile); return;
case EnumAssets::Model: return loadResourceFromLua_Model(profile); case EnumAssets::Model: loadResourceFromLua_Model(out, domain, key, profile); return;
case EnumAssets::Texture: return loadResourceFromLua_Texture(profile); case EnumAssets::Texture: loadResourceFromLua_Texture(out, domain, key, profile); return;
case EnumAssets::Sound: return loadResourceFromLua_Sound(profile); case EnumAssets::Sound: loadResourceFromLua_Sound(out, domain, key, profile); return;
case EnumAssets::Font: return loadResourceFromLua_Font(profile); case EnumAssets::Font: loadResourceFromLua_Font(out, domain, key, profile); return;
default: default:
std::unreachable(); std::unreachable();
} }
} }
AssetsManager::Resource AssetsManager::loadResourceFromFile_Nodestate(fs::path path) const { void AssetsManager::loadResourceFromFile_Nodestate(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromFile_Particle(fs::path path) const { void AssetsManager::loadResourceFromFile_Particle(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromFile_Animation(fs::path path) const { void AssetsManager::loadResourceFromFile_Animation(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromFile_Model(fs::path path) const { void AssetsManager::loadResourceFromFile_Model(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
/* /*
json, obj, glTF json, obj, glTF
*/ */
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromFile_Texture(fs::path path) const { void AssetsManager::loadResourceFromFile_Texture(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
Resource res(path); Resource res(path);
if(res.size() < 8) if(res.size() < 8)
@@ -66,10 +66,14 @@ AssetsManager::Resource AssetsManager::loadResourceFromFile_Texture(fs::path pat
if(png_check_sig(reinterpret_cast<png_bytep>((unsigned char*) res.data()), 8)) { if(png_check_sig(reinterpret_cast<png_bytep>((unsigned char*) res.data()), 8)) {
// Это png // Это png
return res; fs::file_time_type lwt = fs::last_write_time(path);
out.NewOrChange[(int) EnumAssets::Texture][domain].emplace_back(key, res, lwt);
return;
} else if((int) res.data()[0] == 0xFF && (int) res.data()[1] == 0xD8) { } else if((int) res.data()[0] == 0xFF && (int) res.data()[1] == 0xD8) {
// Это jpeg // Это jpeg
return res; fs::file_time_type lwt = fs::last_write_time(path);
out.NewOrChange[(int) EnumAssets::Texture][domain].emplace_back(key, res, lwt);
return;
} else { } else {
MAKE_ERROR("Файл не является текстурой png или jpeg"); MAKE_ERROR("Файл не является текстурой png или jpeg");
} }
@@ -77,65 +81,72 @@ AssetsManager::Resource AssetsManager::loadResourceFromFile_Texture(fs::path pat
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromFile_Sound(fs::path path) const { void AssetsManager::loadResourceFromFile_Sound(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromFile_Font(fs::path path) const { void AssetsManager::loadResourceFromFile_Font(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromLua_Nodestate(const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Nodestate(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
return AssetsManager::Resource(*path); out.NewOrChange[(int) EnumAssets::Nodestate][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min());
return;
} }
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromLua_Particle(const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Particle(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
return AssetsManager::Resource(*path); out.NewOrChange[(int) EnumAssets::Particle][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min());
return;
} }
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromLua_Animation(const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Animation(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
return AssetsManager::Resource(*path); out.NewOrChange[(int) EnumAssets::Animation][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min());
return;
} }
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromLua_Model(const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Model(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
return AssetsManager::Resource(*path); out.NewOrChange[(int) EnumAssets::Model][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min());
return;
} }
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromLua_Texture(const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Texture(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
return AssetsManager::Resource(*path); out.NewOrChange[(int) EnumAssets::Texture][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min());
return;
} }
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromLua_Sound(const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Sound(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
return AssetsManager::Resource(*path); out.NewOrChange[(int) EnumAssets::Sound][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min());
return;
} }
std::unreachable(); std::unreachable();
} }
AssetsManager::Resource AssetsManager::loadResourceFromLua_Font(const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Font(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
return AssetsManager::Resource(*path); out.NewOrChange[(int) EnumAssets::Font][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min());
return;
} }
std::unreachable(); std::unreachable();
@@ -165,28 +176,28 @@ std::tuple<ResourceId, std::optional<AssetsManager::DataEntry>&> AssetsManager::
if(entry.Empty._Find_first() == entry.Empty.size()) if(entry.Empty._Find_first() == entry.Empty.size())
entry.IsFull = true; entry.IsFull = true;
id = index*TableEntry::ChunkSize + pos; id = index*TableEntry<DataEntry>::ChunkSize + pos;
data = &entry.Entries[pos]; data = &entry.Entries[pos];
} }
if(!data) { if(!data) {
table.emplace_back(std::make_unique<TableEntry>()); table.emplace_back(std::make_unique<TableEntry<DataEntry>>());
id = (table.size()-1)*TableEntry::ChunkSize; id = (table.size()-1)*TableEntry<DataEntry>::ChunkSize;
data = &table.back()->Entries[0]; data = &table.back()->Entries[0];
} }
return {id, *data}; return {id, *data};
} }
AssetsManager::Out_recheckResources AssetsManager::recheckResources(const AssetsRegister& info) { AssetsManager::ResourceChangeObj AssetsManager::recheckResources(const AssetsRegister& info) {
Out_recheckResources result; ResourceChangeObj result;
// Найти пропавшие ресурсы // Найти пропавшие ресурсы
for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) { for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) {
auto lock = LocalObj.lock(); auto lock = LocalObj.lock();
for(auto& [domain, resources] : lock->KeyToId[type]) { for(auto& [domain, resources] : lock->KeyToId[type]) {
for(auto& [key, id] : resources) { for(auto& [key, id] : resources) {
if(!lock->Table[type][id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]) if(!lock->Table[type][id / TableEntry<DataEntry>::ChunkSize]->Entries[id % TableEntry<DataEntry>::ChunkSize])
continue; continue;
bool exists = false; bool exists = false;
@@ -234,7 +245,6 @@ AssetsManager::Out_recheckResources AssetsManager::recheckResources(const Assets
// Найти новые или изменённые ресурсы // Найти новые или изменённые ресурсы
for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) { for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) {
for(auto& [domain, resources] : info.Custom[type]) { for(auto& [domain, resources] : info.Custom[type]) {
auto lock = LocalObj.lock(); auto lock = LocalObj.lock();
const auto& keyToId = lock->KeyToId[type]; const auto& keyToId = lock->KeyToId[type];
@@ -257,10 +267,10 @@ AssetsManager::Out_recheckResources AssetsManager::recheckResources(const Assets
continue; continue;
else if(iterDomain->second.contains(key)) { else if(iterDomain->second.contains(key)) {
// Ресурс уже есть, TODO: нужно проверить его изменение // Ресурс уже есть, TODO: нужно проверить его изменение
result.NewOrChange[type][domain].emplace_back(key, loadResourceFromFile((EnumAssets) type, "assets/null"), fs::file_time_type::min()); loadResourceFromFile((EnumAssets) type, result, domain, key, "assets/null");
} else { } else {
// Ресурс не был известен // Ресурс не был известен
result.NewOrChange[type][domain].emplace_back(key, loadResourceFromFile((EnumAssets) type, "assets/null"), fs::file_time_type::min()); loadResourceFromFile((EnumAssets) type, result, domain, key, "assets/null");
} }
findList.insert(key); findList.insert(key);
@@ -315,16 +325,15 @@ AssetsManager::Out_recheckResources AssetsManager::recheckResources(const Assets
else if(iterDomain != lock->KeyToId[type].end() && iterDomain->second.contains(key)) { else if(iterDomain != lock->KeyToId[type].end() && iterDomain->second.contains(key)) {
// Ресурс уже есть, TODO: нужно проверить его изменение // Ресурс уже есть, TODO: нужно проверить его изменение
ResourceId id = iterDomain->second.at(key); ResourceId id = iterDomain->second.at(key);
DataEntry& entry = *lock->Table[type][id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; DataEntry& entry = *lock->Table[type][id / TableEntry<DataEntry>::ChunkSize]->Entries[id % TableEntry<DataEntry>::ChunkSize];
fs::file_time_type lwt = fs::last_write_time(file); fs::file_time_type lwt = fs::last_write_time(file);
if(lwt != entry.FileChangeTime) if(lwt != entry.FileChangeTime)
// Будем считать что ресурс изменился // Будем считать что ресурс изменился
result.NewOrChange[type][domain].emplace_back(key, loadResourceFromFile((EnumAssets) type, file), lwt); loadResourceFromFile((EnumAssets) type, result, domain, key, file);
} else { } else {
// Ресурс не был известен // Ресурс не был известен
fs::file_time_type lwt = fs::last_write_time(file); loadResourceFromFile((EnumAssets) type, result, domain, key, file);
result.NewOrChange[type][domain].emplace_back(key, loadResourceFromFile((EnumAssets) type, file), lwt);
} }
findList.insert(key); findList.insert(key);
@@ -337,7 +346,7 @@ AssetsManager::Out_recheckResources AssetsManager::recheckResources(const Assets
return result; return result;
} }
AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const Out_recheckResources& orr) { AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const ResourceChangeObj& orr) {
// Потерянные и обновлённые идентификаторы // Потерянные и обновлённые идентификаторы
Out_applyResourceChange result; Out_applyResourceChange result;
@@ -362,8 +371,8 @@ AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const
// keyToIdDomain.erase(iter); // keyToIdDomain.erase(iter);
// lost[type].push_back(resId); // lost[type].push_back(resId);
uint32_t localId = resId % TableEntry::ChunkSize; uint32_t localId = resId % TableEntry<DataEntry>::ChunkSize;
auto& chunk = lock->Table[type][resId / TableEntry::ChunkSize]; auto& chunk = lock->Table[type][resId / TableEntry<DataEntry>::ChunkSize];
// chunk->IsFull = false; // chunk->IsFull = false;
// chunk->Empty.set(localId); // chunk->Empty.set(localId);
chunk->Entries[localId].reset(); chunk->Entries[localId].reset();
@@ -383,7 +392,7 @@ AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const
if(auto iterId = keyToIdDomain.find(key); iterId != keyToIdDomain.end()) { if(auto iterId = keyToIdDomain.find(key); iterId != keyToIdDomain.end()) {
id = iterId->second; id = iterId->second;
data = &lock->Table[(int) type][id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; data = &lock->Table[(int) type][id / TableEntry<DataEntry>::ChunkSize]->Entries[id % TableEntry<DataEntry>::ChunkSize];
} else { } else {
auto [_id, _data] = lock->nextId((EnumAssets) type); auto [_id, _data] = lock->nextId((EnumAssets) type);
id = _id; id = _id;

View File

@@ -16,6 +16,10 @@ namespace LV::Server {
namespace fs = std::filesystem; namespace fs = std::filesystem;
struct DefModel {
};
/* /*
Работает с ресурсами из папок assets. Работает с ресурсами из папок assets.
Использует папку server_cache/assets для хранения Использует папку server_cache/assets для хранения
@@ -56,6 +60,13 @@ public:
Hash_t hash() const { return In->Hash; } Hash_t hash() const { return In->Hash; }
}; };
struct ResourceChangeObj {
// Потерянные ресурсы
std::unordered_map<std::string, std::vector<std::string>> Lost[(int) EnumAssets::MAX_ENUM];
// Домен и ключ ресурса
std::unordered_map<std::string, std::vector<std::tuple<std::string, Resource, fs::file_time_type>>> NewOrChange[(int) EnumAssets::MAX_ENUM];
};
private: private:
// Данные об отслеживаемых файлах // Данные об отслеживаемых файлах
struct DataEntry { struct DataEntry {
@@ -65,6 +76,7 @@ private:
std::string Domain, Key; std::string Domain, Key;
}; };
template<typename T>
struct TableEntry { struct TableEntry {
static constexpr size_t ChunkSize = 4096; static constexpr size_t ChunkSize = 4096;
bool IsFull = false; bool IsFull = false;
@@ -78,7 +90,12 @@ private:
struct Local { struct Local {
// Связь ресурсов по идентификаторам // Связь ресурсов по идентификаторам
std::vector<std::unique_ptr<TableEntry>> Table[(int) EnumAssets::MAX_ENUM]; std::vector<std::unique_ptr<TableEntry<DataEntry>>> Table[(int) EnumAssets::MAX_ENUM];
// Распаршенные ресурсы, для использования сервером
std::vector<std::unique_ptr<TableEntry<DefNodeState>>> Table_NodeState;
std::vector<std::unique_ptr<TableEntry<DefModel>>> Table_Model;
// Связь домены -> {ключ -> идентификатор} // Связь домены -> {ключ -> идентификатор}
std::unordered_map<std::string, std::unordered_map<std::string, ResourceId>> KeyToId[(int) EnumAssets::MAX_ENUM]; std::unordered_map<std::string, std::unordered_map<std::string, ResourceId>> KeyToId[(int) EnumAssets::MAX_ENUM];
@@ -91,24 +108,24 @@ private:
Загрузка ресурса с файла. При необходимости приводится Загрузка ресурса с файла. При необходимости приводится
к внутреннему формату и сохраняется в кеше к внутреннему формату и сохраняется в кеше
*/ */
Resource loadResourceFromFile (EnumAssets type, fs::path path) const; void loadResourceFromFile (EnumAssets type, ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const;
Resource loadResourceFromLua (EnumAssets type, const sol::table& profile) const; void loadResourceFromLua (EnumAssets type, ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const;
Resource loadResourceFromFile_Nodestate (fs::path path) const; void loadResourceFromFile_Nodestate (ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const;
Resource loadResourceFromFile_Particle (fs::path path) const; void loadResourceFromFile_Particle (ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const;
Resource loadResourceFromFile_Animation (fs::path path) const; void loadResourceFromFile_Animation (ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const;
Resource loadResourceFromFile_Model (fs::path path) const; void loadResourceFromFile_Model (ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const;
Resource loadResourceFromFile_Texture (fs::path path) const; void loadResourceFromFile_Texture (ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const;
Resource loadResourceFromFile_Sound (fs::path path) const; void loadResourceFromFile_Sound (ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const;
Resource loadResourceFromFile_Font (fs::path path) const; void loadResourceFromFile_Font (ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const;
Resource loadResourceFromLua_Nodestate (const sol::table& profile) const; void loadResourceFromLua_Nodestate (ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const;
Resource loadResourceFromLua_Particle (const sol::table& profile) const; void loadResourceFromLua_Particle (ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const;
Resource loadResourceFromLua_Animation (const sol::table& profile) const; void loadResourceFromLua_Animation (ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const;
Resource loadResourceFromLua_Model (const sol::table& profile) const; void loadResourceFromLua_Model (ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const;
Resource loadResourceFromLua_Texture (const sol::table& profile) const; void loadResourceFromLua_Texture (ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const;
Resource loadResourceFromLua_Sound (const sol::table& profile) const; void loadResourceFromLua_Sound (ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const;
Resource loadResourceFromLua_Font (const sol::table& profile) const; void loadResourceFromLua_Font (ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const;
public: public:
AssetsManager(asio::io_context& ioc); AssetsManager(asio::io_context& ioc);
@@ -137,14 +154,7 @@ public:
std::unordered_map<std::string, std::unordered_map<std::string, void*>> Custom[(int) EnumAssets::MAX_ENUM]; std::unordered_map<std::string, std::unordered_map<std::string, void*>> Custom[(int) EnumAssets::MAX_ENUM];
}; };
struct Out_recheckResources { ResourceChangeObj recheckResources(const AssetsRegister&);
// Потерянные ресурсы
std::unordered_map<std::string, std::vector<std::string>> Lost[(int) EnumAssets::MAX_ENUM];
// Домен и ключ ресурса
std::unordered_map<std::string, std::vector<std::tuple<std::string, Resource, fs::file_time_type>>> NewOrChange[(int) EnumAssets::MAX_ENUM];
};
Out_recheckResources recheckResources(const AssetsRegister&);
/* /*
Применяет расчитанные изменения. Применяет расчитанные изменения.
@@ -155,7 +165,7 @@ public:
std::vector<std::pair<ResourceId, Resource>> NewOrChange[(int) EnumAssets::MAX_ENUM]; std::vector<std::pair<ResourceId, Resource>> NewOrChange[(int) EnumAssets::MAX_ENUM];
}; };
Out_applyResourceChange applyResourceChange(const Out_recheckResources& orr); Out_applyResourceChange applyResourceChange(const ResourceChangeObj& orr);
/* /*
Выдаёт идентификатор ресурса, даже если он не существует или был удалён. Выдаёт идентификатор ресурса, даже если он не существует или был удалён.
@@ -177,8 +187,8 @@ public:
std::optional<std::tuple<Resource, const std::string&, const std::string&>> getResource(EnumAssets type, ResourceId id) { std::optional<std::tuple<Resource, const std::string&, const std::string&>> getResource(EnumAssets type, ResourceId id) {
auto lock = LocalObj.lock(); auto lock = LocalObj.lock();
assert(id < lock->Table[(int) type].size()*TableEntry::ChunkSize); assert(id < lock->Table[(int) type].size()*TableEntry<DataEntry>::ChunkSize);
auto& value = lock->Table[(int) type][id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; auto& value = lock->Table[(int) type][id / TableEntry<DataEntry>::ChunkSize]->Entries[id % TableEntry<DataEntry>::ChunkSize];
if(value) if(value)
return {{value->Res, value->Domain, value->Key}}; return {{value->Res, value->Domain, value->Key}};
else else

View File

@@ -798,7 +798,7 @@ void RemoteClient::onUpdate() {
} }
std::vector<std::tuple<WorldId_t, Pos::Object, uint8_t>> RemoteClient::getViewPoints() { std::vector<std::tuple<WorldId_t, Pos::Object, uint8_t>> RemoteClient::getViewPoints() {
return {{0, CameraPos, 2}}; return {{0, CameraPos, 1}};
} }
} }

View File

@@ -2,22 +2,28 @@
import sys import sys
import re import re
output_file = "resources.cpp" if len(sys.argv) < 3:
with open(output_file, "w") as f: print("Usage: assets.py <output_cpp> <file1> [file2 ...]")
sys.exit(1)
output_cpp = sys.argv[1]
symbols = sys.argv[2:]
with open(output_cpp, "w") as f:
f.write("#include <unordered_map>\n#include <string>\n#include <tuple>\n\nextern \"C\" {\n") f.write("#include <unordered_map>\n#include <string>\n#include <tuple>\n\nextern \"C\" {\n")
for symbol in sys.argv[1:]: for symbol in symbols:
var_name = "_binary_" + re.sub('[^a-zA-Z0-9]', '_', symbol) var_name = "_binary_" + re.sub('[^a-zA-Z0-9]', '_', symbol)
f.write(f"\textern const char {var_name}_start[];\n\textern const char {var_name}_end[];\n") f.write(f"\textern const char {var_name}_start[];\n\textern const char {var_name}_end[];\n")
f.write("}") f.write("}\n\n")
f.write("\n\nstd::unordered_map<std::string, std::tuple<const char*, const char*>> _binary_assets_symbols = {\n") f.write("std::unordered_map<std::string, std::tuple<const char*, const char*>> _binary_assets_symbols = {\n")
for symbol in sys.argv[1:]: for symbol in symbols:
var_name = "_binary_" + re.sub('[^a-zA-Z0-9]', '_', symbol) var_name = "_binary_" + re.sub('[^a-zA-Z0-9]', '_', symbol)
f.write(f"\t{{\"{symbol}\", {{(const char*) &{var_name}_start, (const char*) &{var_name}_end}}}},\n") f.write(f"\t{{\"{symbol}\", {{(const char*) &{var_name}_start, (const char*) &{var_name}_end}}}},\n")
f.write("};\n") f.write("};\n")
print(f"File {output_file} is generated.") print(f"File {output_cpp} is generated.")