diff --git a/doc/en/scripting/builtins/libhud.md b/doc/en/scripting/builtins/libhud.md index 4beb5d93..963e428c 100644 --- a/doc/en/scripting/builtins/libhud.md +++ b/doc/en/scripting/builtins/libhud.md @@ -24,7 +24,9 @@ hud.open_block(x: int, y: int, z: int) -> int, str ```lua -- Show overlay with layout specified. -- Shows player inventory also if playerinv is true. -hud.show_overlay(layoutid: str, playerinv: bool) +-- Using `args` you can specify an array of parameter values ​​that will be passed +-- to on_open of the overlay being shown. +hud.show_overlay(layoutid: str, playerinv: bool, [optional] args: table) -- Add element to the screen. -- The element will be removed on world close only. diff --git a/doc/en/scripting/builtins/libplayer.md b/doc/en/scripting/builtins/libplayer.md index 4ef892dd..99482c68 100644 --- a/doc/en/scripting/builtins/libplayer.md +++ b/doc/en/scripting/builtins/libplayer.md @@ -56,12 +56,26 @@ player.set_noclip(bool) Getter and setter for player noclip mode (collisions disabled) +```lua +player.is_infinite_items() -> bool +player.set_infinite_items(bool) +``` + +Getter and setter for infinite items (not removed from inventory after use) + +```lua +player.is_instant_destruction() -> bool +player.set_instant_destruction(bool) +``` + +Getter and setter for instant destruction of blocks when the `player.destroy` binding is activated. + ``` lua player.set_spawnpoint(playerid: int, x: number, y: number, z: number) player.get_spawnpoint(playerid: int) -> number, number, number ``` -Point setter and getter added by player +Spawn point setter and getter ```lua player.get_selected_block(playerid: int) -> x,y,z diff --git a/doc/en/scripting/events.md b/doc/en/scripting/events.md index ccc61673..8dcd1a06 100644 --- a/doc/en/scripting/events.md +++ b/doc/en/scripting/events.md @@ -38,7 +38,13 @@ Called on random block update (grass growth) function on_blocks_tick(tps: int) ``` -Called tps (20) times per second. +Called tps (20) times per second. Use 1/tps instead of `time.delta()`. + +```lua +function on_player_tick(playerid: int, tps: int) +``` + +Called tps (20) times per second. Use 1/tps instead of `time.delta()`. ## Item events diff --git a/doc/ru/scripting/builtins/libhud.md b/doc/ru/scripting/builtins/libhud.md index ae5a69c3..4bf14d99 100644 --- a/doc/ru/scripting/builtins/libhud.md +++ b/doc/ru/scripting/builtins/libhud.md @@ -25,7 +25,9 @@ hud.open_block(x: int, y: int, z: int) -> int, str ```lua -- Показывает элемент в режиме оверлея. -- Также показывает инвентарь игрока, если playerinv - **true**. -hud.show_overlay(layoutid: str, playerinv: bool) +-- Через args можно указать массив значений параметров, что будут переданы +-- в on_open показываемого оверлея. +hud.show_overlay(layoutid: str, playerinv: bool, [опционально] args: table) -- Добавляет постоянный элемент на экран. Элемент не удаляется при -- закрытии инвентаря. Чтобы не перекрывать затенение в режиме diff --git a/doc/ru/scripting/builtins/libplayer.md b/doc/ru/scripting/builtins/libplayer.md index bd2e8f65..179e6b18 100644 --- a/doc/ru/scripting/builtins/libplayer.md +++ b/doc/ru/scripting/builtins/libplayer.md @@ -56,6 +56,20 @@ player.set_noclip(bool) Геттер и сеттер noclip режима (выключенная коллизия игрока) +```lua +player.is_infinite_items() -> bool +player.set_infinite_items(bool) +``` + +Геттер и сеттер бесконечных предметов (не удаляются из инвентаря при использовании) + +```lua +player.is_instant_destruction() -> bool +player.set_instant_destruction(bool) +``` + +Геттер и сеттер мнгновенного разрушения блоков при активации привязки `player.destroy`. + ```lua player.set_spawnpoint(playerid: int, x: number, y: number, z: number) player.get_spawnpoint(playerid: int) -> number, number, number diff --git a/doc/ru/scripting/events.md b/doc/ru/scripting/events.md index 31c958fc..6d908459 100644 --- a/doc/ru/scripting/events.md +++ b/doc/ru/scripting/events.md @@ -38,7 +38,13 @@ function on_random_update(x, y, z) function on_blocks_tick(tps: int) ``` -Вызывается tps (20) раз в секунду +Вызывается tps (20) раз в секунду. Используйте 1/tps вместо `time.delta()`. + +```lua +function on_player_tick(playerid: int, tps: int) +``` + +Вызывается tps (20) раз в секунду. Используйте 1/tps вместо `time.delta()`. ## События предметов diff --git a/res/content/base/preload.json b/res/content/base/preload.json index 33f38f36..56b9896e 100644 --- a/res/content/base/preload.json +++ b/res/content/base/preload.json @@ -1,4 +1,7 @@ { + "atlases": [ + {"name": "cracks", "type": "separate"} + ], "sounds": [ "blocks/door_open", "blocks/door_close", diff --git a/res/content/base/textures/cracks/cracks_0.png b/res/content/base/textures/cracks/cracks_0.png new file mode 100644 index 00000000..84d56c43 Binary files /dev/null and b/res/content/base/textures/cracks/cracks_0.png differ diff --git a/res/content/base/textures/cracks/cracks_1.png b/res/content/base/textures/cracks/cracks_1.png new file mode 100644 index 00000000..40bd0ce8 Binary files /dev/null and b/res/content/base/textures/cracks/cracks_1.png differ diff --git a/res/content/base/textures/cracks/cracks_10.png b/res/content/base/textures/cracks/cracks_10.png new file mode 100644 index 00000000..8253dd6d Binary files /dev/null and b/res/content/base/textures/cracks/cracks_10.png differ diff --git a/res/content/base/textures/cracks/cracks_2.png b/res/content/base/textures/cracks/cracks_2.png new file mode 100644 index 00000000..d13052d2 Binary files /dev/null and b/res/content/base/textures/cracks/cracks_2.png differ diff --git a/res/content/base/textures/cracks/cracks_3.png b/res/content/base/textures/cracks/cracks_3.png new file mode 100644 index 00000000..40275992 Binary files /dev/null and b/res/content/base/textures/cracks/cracks_3.png differ diff --git a/res/content/base/textures/cracks/cracks_4.png b/res/content/base/textures/cracks/cracks_4.png new file mode 100644 index 00000000..ced0d189 Binary files /dev/null and b/res/content/base/textures/cracks/cracks_4.png differ diff --git a/res/content/base/textures/cracks/cracks_5.png b/res/content/base/textures/cracks/cracks_5.png new file mode 100644 index 00000000..3db95bf4 Binary files /dev/null and b/res/content/base/textures/cracks/cracks_5.png differ diff --git a/res/content/base/textures/cracks/cracks_6.png b/res/content/base/textures/cracks/cracks_6.png new file mode 100644 index 00000000..1eda5a64 Binary files /dev/null and b/res/content/base/textures/cracks/cracks_6.png differ diff --git a/res/content/base/textures/cracks/cracks_7.png b/res/content/base/textures/cracks/cracks_7.png new file mode 100644 index 00000000..a9b9092d Binary files /dev/null and b/res/content/base/textures/cracks/cracks_7.png differ diff --git a/res/content/base/textures/cracks/cracks_8.png b/res/content/base/textures/cracks/cracks_8.png new file mode 100644 index 00000000..79669ab1 Binary files /dev/null and b/res/content/base/textures/cracks/cracks_8.png differ diff --git a/res/content/base/textures/cracks/cracks_9.png b/res/content/base/textures/cracks/cracks_9.png new file mode 100644 index 00000000..18eb1a53 Binary files /dev/null and b/res/content/base/textures/cracks/cracks_9.png differ diff --git a/res/layouts/console.xml.lua b/res/layouts/console.xml.lua index 679645b7..7d4c2771 100644 --- a/res/layouts/console.xml.lua +++ b/res/layouts/console.xml.lua @@ -202,9 +202,8 @@ function on_open(mode) debug=document.s_debug }, function (mode) set_mode(mode) - end, "console") - end - if mode then + end, mode or "console") + elseif mode then modes:set(mode) end end diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 7fc726f8..2c48bdfc 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -269,7 +269,7 @@ function _rules.clear() _rules.create("allow-cheats", true) end -function __vc_create_hud_rules() +function __vc_on_hud_open() _rules.create("allow-content-access", hud._is_content_access(), function(value) hud._set_content_access(value) input.set_enabled("player.pick", value) @@ -295,6 +295,14 @@ function __vc_create_hud_rules() _rules.create("allow-debug-cheats", true, function(value) hud._set_debug_cheats(value) end) + input.add_callback("devtools.console", function() + if hud.is_paused() then + return + end + time.post_runnable(function() + hud.show_overlay("core:console", false, {"console"}) + end) + end) end local RULES_FILE = "world:rules.toml" diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index 924c235f..14479c7d 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -292,6 +292,10 @@ function __load_script(path, nocache) end function require(path) + if not string.find(path, ':') then + local prefix, _ = parse_path(debug.getinfo(2).source) + return require(prefix..':'..path) + end local prefix, file = parse_path(path) return __load_script(prefix..":modules/"..file..".lua") end diff --git a/res/shaders/entity.glslf b/res/shaders/entity.glslf index 5da4142c..143b3eaa 100644 --- a/res/shaders/entity.glslf +++ b/res/shaders/entity.glslf @@ -9,6 +9,7 @@ uniform samplerCube u_cubemap; uniform vec3 u_fogColor; uniform float u_fogFactor; uniform float u_fogCurve; +uniform bool u_alphaClip; void main() { vec3 fogColor = texture(u_cubemap, a_dir).rgb; @@ -16,7 +17,7 @@ void main() { float depth = (a_distance/256.0); float alpha = a_color.a * tex_color.a; // anyway it's any alpha-test alternative required - if (alpha < 0.5f) + if (alpha < (u_alphaClip ? 0.5f : 0.2f)) discard; f_color = mix(a_color * tex_color, vec4(fogColor,1.0), min(1.0, pow(depth*u_fogFactor, u_fogCurve))); diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 142934d1..d3806157 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -43,7 +43,11 @@ void AssetsLoader::add( const std::string& alias, std::shared_ptr settings ) { + if (enqueued.find({tag, alias}) != enqueued.end()){ + return; + } entries.push(aloader_entry {tag, filename, alias, std::move(settings)}); + enqueued.insert({tag, alias}); } bool AssetsLoader::hasNext() const { @@ -148,6 +152,16 @@ void AssetsLoader::processPreload( std::make_shared(map.at("keep-pcm").get(keepPCM))); break; } + case AssetType::ATLAS: { + std::string typeName = "atlas"; + map.at("type").get(typeName); + auto type = AtlasType::ATLAS; + if (typeName == "separate") { + type = AtlasType::SEPARATE; + } + add(tag, path, name, std::make_shared(type)); + break; + } default: add(tag, path, name); break; diff --git a/src/assets/AssetsLoader.hpp b/src/assets/AssetsLoader.hpp index 2321f9a3..cd6db950 100644 --- a/src/assets/AssetsLoader.hpp +++ b/src/assets/AssetsLoader.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,17 @@ struct SoundCfg : AssetCfg { } }; +enum class AtlasType { + ATLAS, SEPARATE +}; + +struct AtlasCfg : AssetCfg { + AtlasType type; + + AtlasCfg(AtlasType type) : type(type) { + } +}; + using aloader_func = std::function< assetload:: postfunc(AssetsLoader*, const ResPaths*, const std::string&, const std::string&, std::shared_ptr)>; @@ -52,6 +64,7 @@ class AssetsLoader { Assets* assets; std::map loaders; std::queue entries; + std::set> enqueued; const ResPaths* paths; void tryAddSound(const std::string& name); diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index ce8b65c9..813d1c87 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -103,12 +103,25 @@ static bool append_atlas(AtlasBuilder& atlas, const fs::path& file) { } assetload::postfunc assetload::atlas( - AssetsLoader*, + AssetsLoader* loader, const ResPaths* paths, const std::string& directory, const std::string& name, - const std::shared_ptr& + const std::shared_ptr& config ) { + auto atlasConfig = std::dynamic_pointer_cast(config); + if (atlasConfig && atlasConfig->type == AtlasType::SEPARATE) { + for (const auto& file : paths->listdir(directory)) { + if (!imageio::is_read_supported(file.extension().u8string())) + continue; + loader->add( + AssetType::TEXTURE, + directory + "/" + file.stem().u8string(), + name + "/" + file.stem().u8string() + ); + } + return [](auto){}; + } AtlasBuilder builder; for (const auto& file : paths->listdir(directory)) { if (!imageio::is_read_supported(file.extension().u8string())) continue; diff --git a/src/content/ContentPack.hpp b/src/content/ContentPack.hpp index 9d25d752..b790d0e7 100644 --- a/src/content/ContentPack.hpp +++ b/src/content/ContentPack.hpp @@ -99,6 +99,7 @@ struct world_funcs_set { bool onblockplaced : 1; bool onblockbroken : 1; bool onblockinteract : 1; + bool onplayertick : 1; }; class ContentPackRuntime { diff --git a/src/core_defs.hpp b/src/core_defs.hpp index 4a02cac9..9f26b1c8 100644 --- a/src/core_defs.hpp +++ b/src/core_defs.hpp @@ -10,7 +10,6 @@ inline const std::string CORE_STRUCT_AIR = "core:struct_air"; inline const std::string TEXTURE_NOTFOUND = "notfound"; // built-in bindings -inline const std::string BIND_DEVTOOLS_CONSOLE = "devtools.console"; inline const std::string BIND_CHUNKS_RELOAD = "chunks.reload"; inline const std::string BIND_MOVE_FORWARD = "movement.forward"; inline const std::string BIND_MOVE_BACK = "movement.back"; diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 889b102f..cc9c54d0 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -229,17 +229,9 @@ void Hud::processInput(bool visible) { setPause(true); } } - if (!pause && Events::jactive(BIND_DEVTOOLS_CONSOLE)) { - showOverlay( - assets->get("core:console"), - false, - std::string("console") - ); - } if (!Window::isFocused() && !pause && !isInventoryOpen()) { setPause(true); } - if (!pause && visible && Events::jactive(BIND_HUD_INVENTORY)) { if (inventoryOpen) { closeInventory(); @@ -470,7 +462,7 @@ void Hud::showExchangeSlot() { } void Hud::showOverlay( - UiDocument* doc, bool playerInventory, const dv::value& arg + UiDocument* doc, bool playerInventory, const dv::value& args ) { if (isInventoryOpen()) { closeInventory(); @@ -483,7 +475,7 @@ void Hud::showOverlay( inventoryOpen = true; } add(HudElement(hud_element_mode::inventory_bound, doc, secondUI, false), - arg); + args); } void Hud::openPermanent(UiDocument* doc) { @@ -515,13 +507,18 @@ void Hud::closeInventory() { cleanup(); } -void Hud::add(const HudElement& element, const dv::value& arg) { +void Hud::add(const HudElement& element, const dv::value& argsArray) { gui->add(element.getNode()); auto document = element.getDocument(); if (document) { auto invview = std::dynamic_pointer_cast(element.getNode()); auto inventory = invview ? invview->getInventory() : nullptr; - std::vector args {arg}; + std::vector args; + if (argsArray != nullptr) { + for (const auto& arg : argsArray) { + args.push_back(arg); + } + } args.emplace_back(inventory ? inventory.get()->getId() : 0); for (int i = 0; i < 3; i++) { args.emplace_back(static_cast(blockPos[i])); diff --git a/src/graphics/render/BlockWrapsRenderer.cpp b/src/graphics/render/BlockWrapsRenderer.cpp new file mode 100644 index 00000000..ddb93d3a --- /dev/null +++ b/src/graphics/render/BlockWrapsRenderer.cpp @@ -0,0 +1,108 @@ +#include "BlockWrapsRenderer.hpp" + +#include "assets/Assets.hpp" +#include "assets/assets_util.hpp" +#include "constants.hpp" +#include "content/Content.hpp" +#include "graphics/core/Atlas.hpp" +#include "graphics/core/Shader.hpp" +#include "graphics/core/DrawContext.hpp" +#include "graphics/render/MainBatch.hpp" +#include "objects/Player.hpp" +#include "voxels/Block.hpp" +#include "voxels/Chunks.hpp" +#include "window/Window.hpp" +#include "world/Level.hpp" + +BlockWrapsRenderer::BlockWrapsRenderer(const Assets& assets, const Level& level) + : assets(assets), level(level), batch(std::make_unique(1024)) { +} + +BlockWrapsRenderer::~BlockWrapsRenderer() = default; + +void BlockWrapsRenderer::draw(const BlockWrapper& wrapper) { + const auto& chunks = *level.chunks; + + auto textureRegion = util::get_texture_region(assets, wrapper.texture, ""); + + auto& shader = assets.require("entity"); + shader.use(); + shader.uniform1i("u_alphaClip", false); + + const UVRegion& cracksRegion = textureRegion.region; + UVRegion regions[6] { + cracksRegion, cracksRegion, cracksRegion, + cracksRegion, cracksRegion, cracksRegion + }; + batch->setTexture(textureRegion.texture); + + const voxel* vox = chunks.get(wrapper.position); + if (vox == nullptr) { + return; + } + if (vox->id != BLOCK_VOID) { + const auto& def = + level.content->getIndices()->blocks.require(vox->id); + switch (def.model) { + case BlockModel::block: + batch->cube( + glm::vec3(wrapper.position) + glm::vec3(0.5f), + glm::vec3(1.01f), + regions, + glm::vec4(0), + false + ); + break; + case BlockModel::aabb: { + const auto& aabb = def.rt.hitboxes[vox->state.rotation].at(0); + const auto& size = aabb.size(); + regions[0].scale(size.z, size.y); + regions[1].scale(size.z, size.y); + regions[2].scale(size.x, size.z); + regions[3].scale(size.x, size.z); + regions[4].scale(size.x, size.y); + regions[5].scale(size.x, size.y); + batch->cube( + glm::vec3(wrapper.position) + aabb.center(), + size * glm::vec3(1.01f), + regions, + glm::vec4(0), + false + ); + break; + } + default: + break; + } + } +} + +void BlockWrapsRenderer::draw(const DrawContext& pctx, const Player& player) { + auto ctx = pctx.sub(); + for (const auto& [_, wrapper] : wrappers) { + draw(*wrapper); + } + batch->flush(); +} + +u64id_t BlockWrapsRenderer::add( + const glm::ivec3& position, const std::string& texture +) { + u64id_t id = nextWrapper++; + wrappers[id] = std::make_unique( + BlockWrapper {position, texture} + ); + return id; +} + +BlockWrapper* BlockWrapsRenderer::get(u64id_t id) const { + const auto& found = wrappers.find(id); + if (found == wrappers.end()) { + return nullptr; + } + return found->second.get(); +} + +void BlockWrapsRenderer::remove(u64id_t id) { + wrappers.erase(id); +} diff --git a/src/graphics/render/BlockWrapsRenderer.hpp b/src/graphics/render/BlockWrapsRenderer.hpp new file mode 100644 index 00000000..728e664a --- /dev/null +++ b/src/graphics/render/BlockWrapsRenderer.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +#include "MainBatch.hpp" +#include "typedefs.hpp" + +class Assets; +class Player; +class Level; +class DrawContext; + +struct BlockWrapper { + glm::ivec3 position; + std::string texture; +}; + +class BlockWrapsRenderer { + const Assets& assets; + const Level& level; + std::unique_ptr batch; + + std::unordered_map> wrappers; + u64id_t nextWrapper = 1; + + void draw(const BlockWrapper& wrapper); +public: + BlockWrapsRenderer(const Assets& assets, const Level& level); + ~BlockWrapsRenderer(); + + void draw(const DrawContext& ctx, const Player& player); + + u64id_t add(const glm::ivec3& position, const std::string& texture); + + BlockWrapper* get(u64id_t id) const; + + void remove(u64id_t id); +}; diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index d3686a86..78ed45bf 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -236,6 +236,7 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { const auto& cameraPos = camera.position; const auto& atlas = assets.require("blocks"); + shader.use(); atlas.getTexture()->bind(); shader.uniformMatrix("u_model", glm::mat4(1.0f)); shader.uniform1i("u_alphaClip", false); diff --git a/src/graphics/render/MainBatch.cpp b/src/graphics/render/MainBatch.cpp index e3a87db7..a440a43b 100644 --- a/src/graphics/render/MainBatch.cpp +++ b/src/graphics/render/MainBatch.cpp @@ -97,38 +97,38 @@ void MainBatch::cube( const glm::vec3 Z(0.0f, 0.0f, 1.0f); quad( - coord + glm::vec3(0.0f, 0.0f, 0.0f), + coord + Z * size.z * 0.5f, X, Y, glm::vec2(size.x, size.y), (shading ? do_tint(0.8) * tint : tint), glm::vec3(1.0f), texfaces[5] ); quad( - coord + glm::vec3(size.x, 0.0f, -size.z), + coord - Z * size.z * 0.5f, -X, Y, glm::vec2(size.x, size.y), - (shading ? do_tint(0.8) * tint : tint), + (shading ? do_tint(0.9f) * tint : tint), glm::vec3(1.0f), texfaces[4] ); quad( - coord + glm::vec3(0.0f, size.y, 0.0f), - X, -Z, glm::vec2(size.x, size.z), + coord + Y * size.y * 0.5f, + -X, Z, glm::vec2(size.x, size.z), (shading ? do_tint(1.0f) * tint : tint), glm::vec3(1.0f), texfaces[3] ); quad( - coord + glm::vec3(0.0f, 0.0f, -size.z), + coord - Y * size.y * 0.5f, X, Z, glm::vec2(size.x, size.z), (shading ? do_tint(0.7f) * tint : tint), glm::vec3(1.0f), texfaces[2] ); quad( - coord + glm::vec3(0.0f, 0.0f, -size.z), - Z, Y, glm::vec2(size.z, size.y), - (shading ? do_tint(0.9f) * tint : tint), - glm::vec3(1.0f), texfaces[0] + coord + X * size.x * 0.5f, + -Z, Y, glm::vec2(size.z, size.y), + (shading ? do_tint(0.8f) * tint : tint), + glm::vec3(1.0f), texfaces[1] ); quad( - coord + glm::vec3(size.x, 0.0f, 0.0f), - -Z, Y, glm::vec2(size.z, size.y), + coord - X * size.x * 0.5f, + Z, Y, glm::vec2(size.z, size.y), (shading ? do_tint(0.9f) * tint : tint), glm::vec3(1.0f), texfaces[1] ); diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 0593305d..7084d2de 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -41,6 +41,7 @@ #include "graphics/core/Shader.hpp" #include "graphics/core/Texture.hpp" #include "graphics/core/Font.hpp" +#include "BlockWrapsRenderer.hpp" #include "ParticlesRenderer.hpp" #include "TextsRenderer.hpp" #include "ChunksRenderer.hpp" @@ -80,7 +81,8 @@ WorldRenderer::WorldRenderer( *frustumCulling, frontend.getContentGfxCache(), engine->getSettings() - )) { + )), + blockWraps(std::make_unique(assets, level)) { auto& settings = engine->getSettings(); level.events->listen( EVT_CHUNK_HIDDEN, @@ -153,6 +155,7 @@ void WorldRenderer::renderLevel( frustumCulling->update(camera.getProjView()); } + entityShader.uniform1i("u_alphaClip", true); level.entities->render( assets, *modelBatch, @@ -169,6 +172,7 @@ void WorldRenderer::renderLevel( setupWorldShader(shader, camera, settings, fogFactor); chunks->drawChunks(camera, shader); + blockWraps->draw(ctx, *player); if (hudVisible) { renderLines(camera, linesShader, ctx); diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index b94694bd..c3ea72f1 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -17,6 +17,7 @@ class Batch3D; class LineBatch; class ChunksRenderer; class ParticlesRenderer; +class BlockWrapsRenderer; class GuidesRenderer; class TextsRenderer; class Shader; @@ -68,6 +69,7 @@ class WorldRenderer { public: std::unique_ptr texts; std::unique_ptr particles; + std::unique_ptr blockWraps; static bool showChunkBorders; static bool showEntitiesDebug; diff --git a/src/logic/BlocksController.cpp b/src/logic/BlocksController.cpp index b0362fd9..01679546 100644 --- a/src/logic/BlocksController.cpp +++ b/src/logic/BlocksController.cpp @@ -14,10 +14,10 @@ #include "world/Level.hpp" #include "world/World.hpp" -BlocksController::BlocksController(Level* level, uint padding) +BlocksController::BlocksController(const Level& level, uint padding) : level(level), - chunks(level->chunks.get()), - lighting(level->lighting.get()), + chunks(*level.chunks), + lighting(*level.lighting), randTickClock(20, 3), blocksTickClock(20, 1), worldTickClock(20, 1), @@ -34,8 +34,8 @@ void BlocksController::updateSides(int x, int y, int z) { } void BlocksController::updateSides(int x, int y, int z, int w, int h, int d) { - voxel* vox = chunks->get(x, y, z); - const auto& def = level->content->getIndices()->blocks.require(vox->id); + voxel* vox = chunks.get(x, y, z); + const auto& def = level.content->getIndices()->blocks.require(vox->id); const auto& rot = def.rotations.variants[vox->state.rotation]; const auto& xaxis = rot.axisX; const auto& yaxis = rot.axisY; @@ -62,8 +62,8 @@ void BlocksController::breakBlock( onBlockInteraction( player, glm::ivec3(x, y, z), def, BlockInteraction::destruction ); - chunks->set(x, y, z, 0, {}); - lighting->onBlockSet(x, y, z, 0); + chunks.set(x, y, z, 0, {}); + lighting.onBlockSet(x, y, z, 0); scripting::on_block_broken(player, def, glm::ivec3(x, y, z)); if (def.rt.extended) { updateSides(x, y, z , def.size.x, def.size.y, def.size.z); @@ -78,8 +78,8 @@ void BlocksController::placeBlock( onBlockInteraction( player, glm::ivec3(x, y, z), def, BlockInteraction::placing ); - chunks->set(x, y, z, def.rt.id, state); - lighting->onBlockSet(x, y, z, def.rt.id); + chunks.set(x, y, z, def.rt.id, state); + lighting.onBlockSet(x, y, z, def.rt.id); scripting::on_block_placed(player, def, glm::ivec3(x, y, z)); if (def.rt.extended) { updateSides(x, y, z , def.size.x, def.size.y, def.size.z); @@ -89,12 +89,12 @@ void BlocksController::placeBlock( } void BlocksController::updateBlock(int x, int y, int z) { - voxel* vox = chunks->get(x, y, z); + voxel* vox = chunks.get(x, y, z); if (vox == nullptr) return; - const auto& def = level->content->getIndices()->blocks.require(vox->id); + const auto& def = level.content->getIndices()->blocks.require(vox->id); if (def.grounded) { const auto& vec = get_ground_direction(def, vox->state.rotation); - if (!chunks->isSolidBlock(x + vec.x, y + vec.y, z + vec.z)) { + if (!chunks.isSolidBlock(x + vec.x, y + vec.y, z + vec.z)) { breakBlock(nullptr, def, x, y, z); return; } @@ -117,12 +117,11 @@ void BlocksController::update(float delta) { } void BlocksController::onBlocksTick(int tickid, int parts) { - auto content = level->content; - auto indices = content->getIndices(); + const auto& indices = level.content->getIndices()->blocks; int tickRate = blocksTickClock.getTickRate(); - for (size_t id = 0; id < indices->blocks.count(); id++) { + for (size_t id = 0; id < indices.count(); id++) { if ((id + tickid) % parts != 0) continue; - auto& def = indices->blocks.require(id); + auto& def = indices.require(id); auto interval = def.tickInterval; if (def.rt.funcsset.onblockstick && tickid / parts % interval == 0) { scripting::on_blocks_tick(def, tickRate / interval); @@ -155,9 +154,9 @@ void BlocksController::randomTick( } void BlocksController::randomTick(int tickid, int parts) { - auto indices = level->content->getIndices(); - int width = chunks->getWidth(); - int height = chunks->getHeight(); + auto indices = level.content->getIndices(); + int width = chunks.getWidth(); + int height = chunks.getHeight(); int segments = 4; for (uint z = padding; z < height - padding; z++) { @@ -166,7 +165,7 @@ void BlocksController::randomTick(int tickid, int parts) { if ((index + tickid) % parts != 0) { continue; } - auto& chunk = chunks->getChunks()[index]; + auto& chunk = chunks.getChunks()[index]; if (chunk == nullptr || !chunk->flags.lighted) { continue; } @@ -176,7 +175,7 @@ void BlocksController::randomTick(int tickid, int parts) { } int64_t BlocksController::createBlockInventory(int x, int y, int z) { - auto chunk = chunks->getChunkByVoxel(x, y, z); + auto chunk = chunks.getChunkByVoxel(x, y, z); if (chunk == nullptr) { return 0; } @@ -184,21 +183,20 @@ int64_t BlocksController::createBlockInventory(int x, int y, int z) { int lz = z - chunk->z * CHUNK_D; auto inv = chunk->getBlockInventory(lx, y, lz); if (inv == nullptr) { - auto indices = level->content->getIndices(); - auto& def = - indices->blocks.require(chunk->voxels[vox_index(lx, y, lz)].id); + const auto& indices = level.content->getIndices()->blocks; + auto& def = indices.require(chunk->voxels[vox_index(lx, y, lz)].id); int invsize = def.inventorySize; if (invsize == 0) { return 0; } - inv = level->inventories->create(invsize); + inv = level.inventories->create(invsize); chunk->addBlockInventory(inv, lx, y, lz); } return inv->getId(); } void BlocksController::bindInventory(int64_t invid, int x, int y, int z) { - auto chunk = chunks->getChunkByVoxel(x, y, z); + auto chunk = chunks.getChunkByVoxel(x, y, z); if (chunk == nullptr) { throw std::runtime_error("block does not exists"); } @@ -207,11 +205,11 @@ void BlocksController::bindInventory(int64_t invid, int x, int y, int z) { } int lx = x - chunk->x * CHUNK_W; int lz = z - chunk->z * CHUNK_D; - chunk->addBlockInventory(level->inventories->get(invid), lx, y, lz); + chunk->addBlockInventory(level.inventories->get(invid), lx, y, lz); } void BlocksController::unbindInventory(int x, int y, int z) { - auto chunk = chunks->getChunkByVoxel(x, y, z); + auto chunk = chunks.getChunkByVoxel(x, y, z); if (chunk == nullptr) { throw std::runtime_error("block does not exists"); } diff --git a/src/logic/BlocksController.hpp b/src/logic/BlocksController.hpp index 86bbe395..0937b3f7 100644 --- a/src/logic/BlocksController.hpp +++ b/src/logic/BlocksController.hpp @@ -24,9 +24,9 @@ using on_block_interaction = std::function< /// BlocksController manages block updates and data (inventories, metadata) class BlocksController { - Level* level; - Chunks* chunks; - Lighting* lighting; + const Level& level; + Chunks& chunks; + Lighting& lighting; util::Clock randTickClock; util::Clock blocksTickClock; util::Clock worldTickClock; @@ -34,7 +34,7 @@ class BlocksController { FastRandom random {}; std::vector blockInteractionCallbacks; public: - BlocksController(Level* level, uint padding); + BlocksController(const Level& level, uint padding); void updateSides(int x, int y, int z); void updateSides(int x, int y, int z, int w, int h, int d); diff --git a/src/logic/ChunksController.cpp b/src/logic/ChunksController.cpp index 07492f29..f61a2755 100644 --- a/src/logic/ChunksController.cpp +++ b/src/logic/ChunksController.cpp @@ -22,15 +22,15 @@ const uint MAX_WORK_PER_FRAME = 128; const uint MIN_SURROUNDING = 9; -ChunksController::ChunksController(Level* level, uint padding) +ChunksController::ChunksController(Level& level, uint padding) : level(level), - chunks(level->chunks.get()), - lighting(level->lighting.get()), + chunks(*level.chunks), + lighting(*level.lighting), padding(padding), generator(std::make_unique( - level->content->generators.require(level->getWorld()->getGenerator()), - level->content, - level->getWorld()->getSeed() + level.content->generators.require(level.getWorld()->getGenerator()), + level.content, + level.getWorld()->getSeed() )) {} ChunksController::~ChunksController() = default; @@ -56,8 +56,8 @@ void ChunksController::update( } bool ChunksController::loadVisible() { - int sizeX = chunks->getWidth(); - int sizeY = chunks->getHeight(); + int sizeX = chunks.getWidth(); + int sizeY = chunks.getHeight(); int nearX = 0; int nearZ = 0; @@ -66,7 +66,7 @@ bool ChunksController::loadVisible() { for (uint z = padding; z < sizeY - padding; z++) { for (uint x = padding; x < sizeX - padding; x++) { int index = z * sizeX + x; - auto& chunk = chunks->getChunks()[index]; + auto& chunk = chunks.getChunks()[index]; if (chunk != nullptr) { if (chunk->flags.loaded && !chunk->flags.lighted) { if (buildLights(chunk)) { @@ -87,12 +87,12 @@ bool ChunksController::loadVisible() { } } - const auto& chunk = chunks->getChunks()[nearZ * sizeX + nearX]; + const auto& chunk = chunks.getChunks()[nearZ * sizeX + nearX]; if (chunk != nullptr || !assigned) { return false; } - int offsetX = chunks->getOffsetX(); - int offsetY = chunks->getOffsetY(); + int offsetX = chunks.getOffsetX(); + int offsetY = chunks.getOffsetY(); createChunk(nearX + offsetX, nearZ + offsetY); return true; } @@ -101,15 +101,15 @@ bool ChunksController::buildLights(const std::shared_ptr& chunk) { int surrounding = 0; for (int oz = -1; oz <= 1; oz++) { for (int ox = -1; ox <= 1; ox++) { - if (chunks->getChunk(chunk->x + ox, chunk->z + oz)) surrounding++; + if (chunks.getChunk(chunk->x + ox, chunk->z + oz)) surrounding++; } } if (surrounding == MIN_SURROUNDING) { bool lightsCache = chunk->flags.loadedLights; if (!lightsCache) { - lighting->buildSkyLight(chunk->x, chunk->z); + lighting.buildSkyLight(chunk->x, chunk->z); } - lighting->onChunkLoaded(chunk->x, chunk->z, !lightsCache); + lighting.onChunkLoaded(chunk->x, chunk->z, !lightsCache); chunk->flags.lighted = true; return true; } @@ -117,8 +117,8 @@ bool ChunksController::buildLights(const std::shared_ptr& chunk) { } void ChunksController::createChunk(int x, int z) { - auto chunk = level->chunksStorage->create(x, z); - chunks->putChunk(chunk); + auto chunk = level.chunksStorage->create(x, z); + chunks.putChunk(chunk); auto& chunkFlags = chunk->flags; if (!chunkFlags.loaded) { @@ -128,7 +128,7 @@ void ChunksController::createChunk(int x, int z) { chunk->updateHeights(); if (!chunkFlags.loadedLights) { - Lighting::prebuildSkyLight(chunk.get(), level->content->getIndices()); + Lighting::prebuildSkyLight(chunk.get(), level.content->getIndices()); } chunkFlags.loaded = true; chunkFlags.ready = true; diff --git a/src/logic/ChunksController.hpp b/src/logic/ChunksController.hpp index 8566ee1b..e9f1ab62 100644 --- a/src/logic/ChunksController.hpp +++ b/src/logic/ChunksController.hpp @@ -13,9 +13,9 @@ class WorldGenerator; /// @brief ChunksController manages chunks dynamic loading/unloading class ChunksController { private: - Level* level; - Chunks* chunks; - Lighting* lighting; + Level& level; + Chunks& chunks; + Lighting& lighting; uint padding; std::unique_ptr generator; @@ -24,7 +24,7 @@ private: bool buildLights(const std::shared_ptr& chunk); void createChunk(int x, int y); public: - ChunksController(Level* level, uint padding); + ChunksController(Level& level, uint padding); ~ChunksController(); /// @param maxDuration milliseconds reserved for chunks loading diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index 2cd491d4..bd8af15c 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -16,14 +16,14 @@ static debug::Logger logger("level-control"); -LevelController::LevelController(Engine* engine, std::unique_ptr level) +LevelController::LevelController(Engine* engine, std::unique_ptr levelPtr) : settings(engine->getSettings()), - level(std::move(level)), + level(std::move(levelPtr)), blocks(std::make_unique( - this->level.get(), settings.chunks.padding.get() + *level, settings.chunks.padding.get() )), chunks(std::make_unique( - this->level.get(), settings.chunks.padding.get() + *level, settings.chunks.padding.get() )), player(std::make_unique( settings, this->level.get(), blocks.get() diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 57af3c13..0ad5ef6b 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -195,7 +195,8 @@ PlayerController::PlayerController( : settings(settings), level(level), player(level->getObject(0)), camControl(player, settings.camera), - blocksController(blocksController) { + blocksController(blocksController), + playerTickClock(20, 3) { } void PlayerController::onFootstep(const Hitbox& hitbox) { @@ -249,6 +250,13 @@ void PlayerController::update(float delta, bool input, bool pause) { resetKeyboard(); } updatePlayer(delta); + + if (playerTickClock.update(delta)) { + if (player->getId() % playerTickClock.getParts() == + playerTickClock.getPart()) { + scripting::on_player_tick(player.get(), playerTickClock.getTickRate()); + } + } } } @@ -302,7 +310,7 @@ void PlayerController::updatePlayer(float delta) { } static int determine_rotation( - const Block* def, const glm::ivec3& norm, glm::vec3& camDir + const Block* def, const glm::ivec3& norm, const glm::vec3& camDir ) { if (def && def->rotatable) { const std::string& name = def->rotations.name; @@ -461,6 +469,10 @@ void PlayerController::processRightClick(const Block& def, const Block& target) } } if (chosenBlock != vox->id && chosenBlock) { + if (!player->isInfiniteItems()) { + auto& slot = player->getInventory()->getSlot(player->getChosenSlot()); + slot.setCount(slot.getCount()-1); + } blocksController->placeBlock( player.get(), def, state, coord.x, coord.y, coord.z ); @@ -522,16 +534,18 @@ void PlayerController::updateInteraction(float delta) { auto iend = selection.position; if (lclick && !input.shift && item.rt.funcsset.on_block_break_by) { if (scripting::on_item_break_block( - player.get(), item, iend.x, iend.y, iend.z - )) { + player.get(), item, iend.x, iend.y, iend.z + )) { return; } } auto& target = indices->blocks.require(vox->id); - if (lclick && target.breakable) { - blocksController->breakBlock( - player.get(), target, iend.x, iend.y, iend.z - ); + if (lclick) { + if (player->isInstantDestruction() && target.breakable) { + blocksController->breakBlock( + player.get(), target, iend.x, iend.y, iend.z + ); + } } if (rclick && !input.shift) { bool preventDefault = false; diff --git a/src/logic/PlayerController.hpp b/src/logic/PlayerController.hpp index 6affa43d..3fe3decf 100644 --- a/src/logic/PlayerController.hpp +++ b/src/logic/PlayerController.hpp @@ -5,6 +5,7 @@ #include #include "objects/Player.hpp" +#include "util/Clock.hpp" class Engine; class Camera; @@ -53,6 +54,7 @@ class PlayerController { PlayerInput input {}; CameraControl camControl; BlocksController* blocksController; + util::Clock playerTickClock; float interactionTimer = 0.0f; void updateKeyboard(); diff --git a/src/logic/scripting/lua/libs/api_lua.hpp b/src/logic/scripting/lua/libs/api_lua.hpp index b0edba79..12df1d66 100644 --- a/src/logic/scripting/lua/libs/api_lua.hpp +++ b/src/logic/scripting/lua/libs/api_lua.hpp @@ -18,6 +18,7 @@ extern const luaL_Reg audiolib[]; extern const luaL_Reg base64lib[]; extern const luaL_Reg bjsonlib[]; extern const luaL_Reg blocklib[]; +extern const luaL_Reg blockwrapslib[]; // gfx.blockwraps extern const luaL_Reg cameralib[]; extern const luaL_Reg consolelib[]; extern const luaL_Reg corelib[]; @@ -32,10 +33,10 @@ extern const luaL_Reg itemlib[]; extern const luaL_Reg jsonlib[]; extern const luaL_Reg mat4lib[]; extern const luaL_Reg packlib[]; -extern const luaL_Reg particleslib[]; +extern const luaL_Reg particleslib[]; // gfx.particles extern const luaL_Reg playerlib[]; extern const luaL_Reg quatlib[]; -extern const luaL_Reg text3dlib[]; +extern const luaL_Reg text3dlib[]; // gfx.text3d extern const luaL_Reg timelib[]; extern const luaL_Reg tomllib[]; extern const luaL_Reg utf8lib[]; diff --git a/src/logic/scripting/lua/libs/libblockwraps.cpp b/src/logic/scripting/lua/libs/libblockwraps.cpp new file mode 100644 index 00000000..fec1c5d7 --- /dev/null +++ b/src/logic/scripting/lua/libs/libblockwraps.cpp @@ -0,0 +1,43 @@ +#include "api_lua.hpp" + +#include "logic/scripting/scripting_hud.hpp" +#include "graphics/render/WorldRenderer.hpp" +#include "graphics/render/BlockWrapsRenderer.hpp" + +using namespace scripting; + +static int l_wrap(lua::State* L) { + auto position = lua::tovec3(L, 1); + std::string texture = lua::require_string(L, 2); + + return lua::pushinteger( + L, renderer->blockWraps->add(position, std::move(texture)) + ); +} + +static int l_unwrap(lua::State* L) { + renderer->blockWraps->remove(lua::tointeger(L, 1)); + return 0; +} + +static int l_set_pos(lua::State* L) { + if (auto wrapper = renderer->blockWraps->get(lua::tointeger(L, 1))) { + wrapper->position = lua::tovec3(L, 2); + } + return 0; +} + +static int l_set_texture(lua::State* L) { + if (auto wrapper = renderer->blockWraps->get(lua::tointeger(L, 1))) { + wrapper->texture = lua::require_string(L, 2); + } + return 0; +} + +const luaL_Reg blockwrapslib[] = { + {"wrap", lua::wrap}, + {"unwrap", lua::wrap}, + {"set_pos", lua::wrap}, + {"set_texture", lua::wrap}, + {NULL, NULL} +}; diff --git a/src/logic/scripting/lua/libs/libhud.cpp b/src/logic/scripting/lua/libs/libhud.cpp index 17e1211a..460cf66b 100644 --- a/src/logic/scripting/lua/libs/libhud.cpp +++ b/src/logic/scripting/lua/libs/libhud.cpp @@ -98,7 +98,8 @@ static int l_show_overlay(lua::State* L) { if (layout == nullptr) { throw std::runtime_error("there is no ui layout " + util::quote(name)); } - hud->showOverlay(layout, playerInventory); + auto args = lua::tovalue(L, 3); + hud->showOverlay(layout, playerInventory, std::move(args)); return 0; } @@ -188,4 +189,5 @@ const luaL_Reg hudlib[] = { {"_is_content_access", lua::wrap}, {"_set_content_access", lua::wrap}, {"_set_debug_cheats", lua::wrap}, - {NULL, NULL}}; + {NULL, NULL} +}; diff --git a/src/logic/scripting/lua/libs/libplayer.cpp b/src/logic/scripting/lua/libs/libplayer.cpp index 0d0a7223..18b29405 100644 --- a/src/logic/scripting/lua/libs/libplayer.cpp +++ b/src/logic/scripting/lua/libs/libplayer.cpp @@ -128,6 +128,34 @@ static int l_set_noclip(lua::State* L) { return 0; } +static int l_is_infinite_items(lua::State* L) { + if (auto player = get_player(L, 1)) { + return lua::pushboolean(L, player->isInfiniteItems()); + } + return 0; +} + +static int l_set_infinite_items(lua::State* L) { + if (auto player = get_player(L, 1)) { + player->setInfiniteItems(lua::toboolean(L, 2)); + } + return 0; +} + +static int l_is_instant_destruction(lua::State* L) { + if (auto player = get_player(L, 1)) { + return lua::pushboolean(L, player->isInstantDestruction()); + } + return 0; +} + +static int l_set_instant_destruction(lua::State* L) { + if (auto player = get_player(L, 1)) { + player->setInstantDestruction(lua::toboolean(L, 2)); + } + return 0; +} + static int l_get_selected_block(lua::State* L) { if (auto player = get_player(L, 1)) { if (player->selection.vox.id == BLOCK_VOID) { @@ -220,6 +248,10 @@ const luaL_Reg playerlib[] = { {"set_flight", lua::wrap}, {"is_noclip", lua::wrap}, {"set_noclip", lua::wrap}, + {"is_infinite_items", lua::wrap}, + {"set_infinite_items", lua::wrap}, + {"is_instant_destruction", lua::wrap}, + {"set_instant_destruction", lua::wrap}, {"get_selected_block", lua::wrap}, {"get_selected_entity", lua::wrap}, {"set_spawnpoint", lua::wrap}, @@ -228,4 +260,5 @@ const luaL_Reg playerlib[] = { {"set_entity", lua::wrap}, {"get_camera", lua::wrap}, {"set_camera", lua::wrap}, - {NULL, NULL}}; + {NULL, NULL} +}; diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 3f3161ae..f0082a3c 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -323,6 +323,21 @@ bool scripting::on_block_interact( } } +void scripting::on_player_tick(Player* player, int tps) { + auto args = [=](lua::State* L) { + lua::pushinteger(L, player ? player->getId() : -1); + lua::pushinteger(L, tps); + return 2; + }; + for (auto& [packid, pack] : content->getPacks()) { + if (pack->worldfuncsset.onplayertick) { + lua::emit_event( + lua::get_main_state(), packid + ":.playertick", args + ); + } + } +} + bool scripting::on_item_use(Player* player, const ItemDef& item) { std::string name = item.name + ".use"; return lua::emit_event( @@ -724,6 +739,8 @@ void scripting::load_world_script( register_event(env, "on_block_broken", prefix + ":.blockbroken"); funcsset.onblockinteract = register_event(env, "on_block_interact", prefix + ":.blockinteract"); + funcsset.onplayertick = + register_event(env, "on_player_tick", prefix + ":.playertick"); } void scripting::load_layout_script( diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index c103a97a..ca0ea433 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -73,6 +73,7 @@ namespace scripting { Player* player, const Block& block, const glm::ivec3& pos ); bool on_block_interact(Player* player, const Block& block, const glm::ivec3& pos); + void on_player_tick(Player* player, int tps); /// @brief Called on RMB click with the item selected /// @return true if prevents default action diff --git a/src/logic/scripting/scripting_hud.cpp b/src/logic/scripting/scripting_hud.cpp index a7be1892..7adb5076 100644 --- a/src/logic/scripting/scripting_hud.cpp +++ b/src/logic/scripting/scripting_hud.cpp @@ -32,12 +32,13 @@ void scripting::on_frontend_init(Hud* hud, WorldRenderer* renderer) { auto L = lua::get_main_state(); lua::openlib(L, "hud", hudlib); + lua::openlib(L, "gfx", "blockwraps", blockwrapslib); lua::openlib(L, "gfx", "particles", particleslib); lua::openlib(L, "gfx", "text3d", text3dlib); load_script("hud_classes.lua"); - if (lua::getglobal(L, "__vc_create_hud_rules")) { + if (lua::getglobal(L, "__vc_on_hud_open")) { lua::call_nothrow(L, 0, 0); } diff --git a/src/maths/UVRegion.hpp b/src/maths/UVRegion.hpp index 75b0ab6b..019c8760 100644 --- a/src/maths/UVRegion.hpp +++ b/src/maths/UVRegion.hpp @@ -40,4 +40,15 @@ struct UVRegion { float h = getHeight(); return glm::vec2(u1 + uv.x * w, v1 + uv.y * h); } + + void scale(float x, float y) { + float w = getWidth(); + float h = getHeight(); + float cx = (u1 + u2) * 0.5f; + float cy = (v1 + v2) * 0.5f; + u1 = cx - w * 0.5f * x; + v1 = cy - h * 0.5f * y; + u2 = cx + w * 0.5f * x; + v2 = cy + h * 0.5f * y; + } }; diff --git a/src/objects/Player.cpp b/src/objects/Player.cpp index 5b925f58..5c2a2b85 100644 --- a/src/objects/Player.cpp +++ b/src/objects/Player.cpp @@ -240,6 +240,22 @@ void Player::setNoclip(bool flag) { this->noclip = flag; } +bool Player::isInfiniteItems() const { + return infiniteItems; +} + +void Player::setInfiniteItems(bool flag) { + infiniteItems = flag; +} + +bool Player::isInstantDestruction() const { + return instantDestruction; +} + +void Player::setInstantDestruction(bool flag) { + instantDestruction = flag; +} + entityid_t Player::getEntity() const { return eid; } @@ -273,6 +289,8 @@ dv::value Player::serialize() const { root["flight"] = flight; root["noclip"] = noclip; + root["infinite-items"] = infiniteItems; + root["instant-destruction"] = instantDestruction; root["chosen-slot"] = chosenSlot; root["entity"] = eid; root["inventory"] = inventory->serialize(); @@ -300,6 +318,9 @@ void Player::deserialize(const dv::value& src) { flight = src["flight"].asBoolean(); noclip = src["noclip"].asBoolean(); + src.at("infinite-items").get(infiniteItems); + src.at("instant-destruction").get(instantDestruction); + setChosenSlot(src["chosen-slot"].asInteger()); eid = src["entity"].asNumber(); diff --git a/src/objects/Player.hpp b/src/objects/Player.hpp index 985aba55..2badd9dc 100644 --- a/src/objects/Player.hpp +++ b/src/objects/Player.hpp @@ -49,6 +49,8 @@ class Player : public Object, public Serializable { std::shared_ptr inventory; bool flight = false; bool noclip = false; + bool infiniteItems = true; + bool instantDestruction = true; entityid_t eid; entityid_t selectedEid; public: @@ -86,6 +88,12 @@ public: bool isNoclip() const; void setNoclip(bool flag); + bool isInfiniteItems() const; + void setInfiniteItems(bool flag); + + bool isInstantDestruction() const; + void setInstantDestruction(bool flag); + entityid_t getEntity() const; void setEntity(entityid_t eid); diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index c27ed9e7..0942550e 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -438,7 +438,7 @@ voxel* Chunks::rayCast( glm::ivec3& norm, glm::ivec3& iend, std::set filter -) { +) const { float px = start.x; float py = start.y; float pz = start.z; @@ -571,7 +571,7 @@ voxel* Chunks::rayCast( glm::vec3 Chunks::rayCastToObstacle( const glm::vec3& start, const glm::vec3& dir, float maxDist -) { +) const { const float px = start.x; const float py = start.y; const float pz = start.z; diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index 38a5be8c..01648301 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -102,11 +102,11 @@ public: glm::ivec3& norm, glm::ivec3& iend, std::set filter = {} - ); + ) const; glm::vec3 rayCastToObstacle( const glm::vec3& start, const glm::vec3& dir, float maxDist - ); + ) const; const AABB* isObstacleAt(float x, float y, float z) const; diff --git a/src/world/Level.hpp b/src/world/Level.hpp index c88a1617..767844cf 100644 --- a/src/world/Level.hpp +++ b/src/world/Level.hpp @@ -72,7 +72,7 @@ public: } template - std::shared_ptr getObject(uint64_t id) { + std::shared_ptr getObject(uint64_t id) const { static_assert( std::is_base_of::value, "T must be a derived of Object class"