diff --git a/dev/tests/perftest.lua b/dev/tests/perftest.lua new file mode 100644 index 00000000..a1cc3cc6 --- /dev/null +++ b/dev/tests/perftest.lua @@ -0,0 +1,12 @@ +app.set_setting("chunks.load-distance", 3) +app.set_setting("chunks.load-speed", 16) + +app.reconfig_packs({"base"}, {}) +app.new_world("demo", "2019", "core:default") + +local pid = player.create("A") +assert(player.get_name(pid) == "A") +app.tick() + +timeit(1e7, block.get, 0, 0, 0) +timeit(1e7, block.set, 0, 0, 0, 6) diff --git a/doc/en/scripting/builtins/libapp.md b/doc/en/scripting/builtins/libapp.md index 6b1d8e60..a0a17970 100644 --- a/doc/en/scripting/builtins/libapp.md +++ b/doc/en/scripting/builtins/libapp.md @@ -83,6 +83,12 @@ app.reopen_world() Reopens the world. +```lua +app.save_world() +``` + +Saves the world. + ```lua app.close_world( -- save the world before closing diff --git a/doc/ru/scripting/builtins/libapp.md b/doc/ru/scripting/builtins/libapp.md index 1cf067a2..a30a96e4 100644 --- a/doc/ru/scripting/builtins/libapp.md +++ b/doc/ru/scripting/builtins/libapp.md @@ -83,6 +83,12 @@ app.reopen_world() Переоткрывает мир. +```lua +app.save_world() +``` + +Сохраняет мир. + ```lua app.close_world( -- сохранить мир перед закрытием diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 7900e1c8..714725d0 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -27,6 +27,7 @@ if app then app.script = __VC_SCRIPT_NAME app.new_world = core.new_world app.open_world = core.open_world + app.save_world = core.save_world app.close_world = core.close_world app.reopen_world = core.reopen_world app.delete_world = core.delete_world diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index af15df21..37944694 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -63,6 +63,15 @@ static int l_reopen_world(lua::State*) { return 0; } +/// @brief Save world +static int l_save_world(lua::State* L) { + if (controller == nullptr) { + throw std::runtime_error("no world open"); + } + controller->saveWorld(); + return 0; +} + /// @brief Close world /// @param flag Save world (bool) static int l_close_world(lua::State* L) { @@ -246,6 +255,7 @@ const luaL_Reg corelib[] = { {"new_world", lua::wrap}, {"open_world", lua::wrap}, {"reopen_world", lua::wrap}, + {"save_world", lua::wrap}, {"close_world", lua::wrap}, {"delete_world", lua::wrap}, {"reconfig_packs", lua::wrap}, diff --git a/src/voxels/Chunk.hpp b/src/voxels/Chunk.hpp index 94011d40..55cdac21 100644 --- a/src/voxels/Chunk.hpp +++ b/src/voxels/Chunk.hpp @@ -8,6 +8,7 @@ #include "constants.hpp" #include "lighting/Lightmap.hpp" #include "util/SmallHeap.hpp" +#include "maths/aabb.hpp" #include "voxel.hpp" inline constexpr int CHUNK_DATA_LEN = CHUNK_VOL * 4; @@ -75,4 +76,11 @@ public: bool decode(const ubyte* data); static void convert(ubyte* data, const ContentReport* report); + + AABB getAABB() const { + return AABB( + glm::vec3(x * CHUNK_W, -INFINITY, z * CHUNK_D), + glm::vec3((x + 1) * CHUNK_W, INFINITY, (z + 1) * CHUNK_D) + ); + } }; diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index a85be528..d82a6b04 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -24,6 +24,10 @@ GlobalChunks::GlobalChunks(Level* level) chunksMap.max_load_factor(CHUNKS_MAP_MAX_LOAD_FACTOR); } +void GlobalChunks::setOnUnload(consumer onUnload) { + this->onUnload = std::move(onUnload); +} + std::shared_ptr GlobalChunks::fetch(int x, int z) { const auto& found = chunksMap.find(keyfrom(x, z)); if (found == chunksMap.end()) { @@ -160,6 +164,9 @@ void GlobalChunks::decref(Chunk* chunk) { ekey.pos[0] = chunk->x; ekey.pos[1] = chunk->z; + if (onUnload) { + onUnload(*chunk); + } save(chunk); chunksMap.erase(ekey.key); refCounters.erase(found); @@ -170,17 +177,11 @@ void GlobalChunks::save(Chunk* chunk) { if (chunk == nullptr) { return; } - AABB aabb( - glm::vec3(chunk->x * CHUNK_W, -INFINITY, chunk->z * CHUNK_D), - glm::vec3( - (chunk->x + 1) * CHUNK_W, INFINITY, (chunk->z + 1) * CHUNK_D - ) - ); + AABB aabb = chunk->getAABB(); auto entities = level->entities->getAllInside(aabb); auto root = dv::object(); root["data"] = level->entities->serialize(entities); if (!entities.empty()) { - level->entities->despawn(std::move(entities)); chunk->flags.entities = true; } level->getWorld()->wfile->getRegions().put( diff --git a/src/voxels/GlobalChunks.hpp b/src/voxels/GlobalChunks.hpp index b4bb45e9..862f6c70 100644 --- a/src/voxels/GlobalChunks.hpp +++ b/src/voxels/GlobalChunks.hpp @@ -8,6 +8,7 @@ #include #include "voxel.hpp" +#include "delegates.hpp" class Chunk; class Level; @@ -30,10 +31,14 @@ class GlobalChunks { std::unordered_map> chunksMap; std::unordered_map> pinnedChunks; std::unordered_map refCounters; + + consumer onUnload; public: GlobalChunks(Level* level); ~GlobalChunks() = default; + void setOnUnload(consumer onUnload); + std::shared_ptr fetch(int x, int z); std::shared_ptr create(int x, int z); diff --git a/src/world/Level.cpp b/src/world/Level.cpp index 28a8dab5..2276e9aa 100644 --- a/src/world/Level.cpp +++ b/src/world/Level.cpp @@ -58,6 +58,10 @@ Level::Level( events->listen(LevelEventType::EVT_CHUNK_HIDDEN, [this](LevelEventType, Chunk* chunk) { chunks->decref(chunk); }); + chunks->setOnUnload([this](const Chunk& chunk) { + AABB aabb = chunk.getAABB(); + entities->despawn(entities->getAllInside(aabb)); + }); inventories = std::make_unique(*this); }