From 5ddc31e20462a0587c62cf45288c67c498cba3d6 Mon Sep 17 00:00:00 2001 From: AdamYuan Date: Wed, 1 Nov 2023 16:17:03 +0800 Subject: [PATCH] generalize liquid, better liquid mesh, liquid path detection --- block/block/flowing_water.hpp | 168 +-------------- block/block/public/Liquid.hpp | 311 +++++++++++++++++++++++++--- block/block/public/Water.hpp | 15 ++ block/block/water.hpp | 15 +- block/include/block/BlockEvent.hpp | 4 +- client/src/ChunkUpdateBlockTask.cpp | 12 +- 6 files changed, 306 insertions(+), 219 deletions(-) create mode 100644 block/block/public/Water.hpp diff --git a/block/block/flowing_water.hpp b/block/block/flowing_water.hpp index 4b8e443..4f78b4f 100644 --- a/block/block/flowing_water.hpp +++ b/block/block/flowing_water.hpp @@ -1,168 +1,4 @@ #pragma once -#include "public/Liquid.hpp" -#include "public/Trait.hpp" +#include "public/Water.hpp" -#include - -inline static constexpr uint8_t get_flowing_water_height(BlockMeta variant) { return std::max(variant * 2, 1); } - -template -inline static constexpr void flowing_water_mesh_gen(const Block *neighbours, BlockMeshFace *p_out_faces, - uint32_t *p_out_face_count, BlockTexture p_out_textures[6], - bool *p_dynamic_texture) { - const auto get_nei_height = [](Block block) -> uint8_t { - return block.GetID() == kWater - ? 16 - : (block.GetID() == kFlowingWater ? get_flowing_water_height(block.GetMeta()) : 0); - }; - uint8_t nhs[] = - { - get_nei_height(neighbours[0]), get_nei_height(neighbours[1]), get_nei_height(neighbours[2]), - get_nei_height(neighbours[3]), get_nei_height(neighbours[4]), get_nei_height(neighbours[5]), - get_nei_height(neighbours[6]), get_nei_height(neighbours[7]), - }, - nb = get_flowing_water_height(Variant); - - // 0 1 2 - // 3 4 - // 5 6 7 - // - // 0 1 - // 2 3 - // #define N4(a, b, c) ((nb + nhs[a] + nhs[b] + nhs[c]) / (bool(nhs[a]) + bool(nhs[b]) + bool(nhs[c]) + 1)) -#define N4(a, b, c) std::max(std::max(nb, nhs[a]), std::max(nhs[b], nhs[c])) - uint8_t h0 = N4(0, 1, 3); - uint8_t h1 = N4(1, 2, 4); - uint8_t h2 = N4(3, 5, 6); - uint8_t h3 = N4(4, 6, 7); -#undef N4 - - *p_dynamic_texture = true; - if (h0 == 16 && h1 == 16 && h2 == 16 && h3 == 16) { - *p_out_face_count = 0; - std::fill(p_out_textures, p_out_textures + 6, BlockTextures::kWater); - } else { - *p_out_face_count = 1; - p_out_faces[0] = BlockMeshFace{ - 1, - BlockFaces::kTop, - BlockFaces::kTop, - {BlockTextures::kWater}, - { - {(uint8_t)0, h0, (uint8_t)0}, - {(uint8_t)0, h2, (uint8_t)16}, - {(uint8_t)16, h3, (uint8_t)16}, - {(uint8_t)16, h1, (uint8_t)0}, - }, - }; - bool left_full = h0 == 16 && h2 == 16; - bool right_full = h1 == 16 && h3 == 16; - bool front_full = h2 == 16 && h3 == 16; - bool back_full = h0 == 16 && h1 == 16; - if (!left_full && neighbours[3].GetID() != kWater && neighbours[3].GetID() != kFlowingWater) { - p_out_faces[(*p_out_face_count)++] = BlockMeshFace{ - 0, - BlockFaces::kLeft, - BlockFaces::kLeft, - {BlockTextures::kWater}, - { - {(uint8_t)0, h0, (uint8_t)0}, - {(uint8_t)0, (uint8_t)0, (uint8_t)0}, - {(uint8_t)0, (uint8_t)0, (uint8_t)16}, - {(uint8_t)0, h2, (uint8_t)16}, - }, - }; - } - if (!right_full && neighbours[4].GetID() != kWater && neighbours[4].GetID() != kFlowingWater) { - p_out_faces[(*p_out_face_count)++] = BlockMeshFace{ - 0, - BlockFaces::kRight, - BlockFaces::kRight, - {BlockTextures::kWater}, - { - {(uint8_t)16, (uint8_t)0, (uint8_t)0}, - {(uint8_t)16, h1, (uint8_t)0}, - {(uint8_t)16, h3, (uint8_t)16}, - {(uint8_t)16, (uint8_t)0, (uint8_t)16}, - }, - }; - } - if (!back_full && neighbours[1].GetID() != kWater && neighbours[1].GetID() != kFlowingWater) { - p_out_faces[(*p_out_face_count)++] = BlockMeshFace{ - 2, - BlockFaces::kBack, - BlockFaces::kBack, - {BlockTextures::kWater}, - { - {(uint8_t)0, (uint8_t)0, (uint8_t)0}, - {(uint8_t)0, h0, (uint8_t)0}, - {(uint8_t)16, h1, (uint8_t)0}, - {(uint8_t)16, (uint8_t)0, (uint8_t)0}, - }, - }; - } - if (!front_full && neighbours[6].GetID() != kWater && neighbours[6].GetID() != kFlowingWater) { - p_out_faces[(*p_out_face_count)++] = BlockMeshFace{ - 2, - BlockFaces::kFront, - BlockFaces::kFront, - {BlockTextures::kWater}, - { - {(uint8_t)0, h2, (uint8_t)16}, - {(uint8_t)0, (uint8_t)0, (uint8_t)16}, - {(uint8_t)16, (uint8_t)0, (uint8_t)16}, - {(uint8_t)16, h3, (uint8_t)16}, - }, - }; - } - p_out_textures[BlockFaces::kTop] = BlockTextures::kNone; - p_out_textures[BlockFaces::kLeft] = left_full ? BlockTextures::kWater : BlockTextures::kNone; - p_out_textures[BlockFaces::kRight] = right_full ? BlockTextures::kWater : BlockTextures::kNone; - p_out_textures[BlockFaces::kFront] = front_full ? BlockTextures::kWater : BlockTextures::kNone; - p_out_textures[BlockFaces::kBack] = back_full ? BlockTextures::kWater : BlockTextures::kNone; - p_out_textures[BlockFaces::kBottom] = BlockTextures::kWater; - } -} - -template -inline static constexpr BlockMesh kFlowingWaterMesh = { - {}, - 0, - {{{0, 0, 0}, {16, get_flowing_water_height(Variant), 16}}}, - 1, - flowing_water_mesh_gen, - { - glm::i8vec3{-1, 0, -1}, - glm::i8vec3{0, 0, -1}, - glm::i8vec3{1, 0, -1}, - glm::i8vec3{-1, 0, 0}, - glm::i8vec3{1, 0, 0}, - glm::i8vec3{-1, 0, 1}, - glm::i8vec3{0, 0, 1}, - glm::i8vec3{1, 0, 1}, - }, - 8u, -}; - -template <> struct BlockTrait { - inline static constexpr uint8_t kVariants = 9; - inline static constexpr uint8_t kVariantBits = std::countr_zero(std::bit_ceil(kVariants)); - inline static constexpr uint8_t kTransforms = 0; - inline static constexpr uint8_t kTransformBits = std::countr_zero(std::bit_ceil(kTransforms)); - - template inline static constexpr BlockProperty TransformProperty(BlockProperty property) { - return property; - } - - template inline static constexpr BlockProperty GetProperty() { - return { - "Flowing Water", - BLOCK_TEXTURE_BOT_SIDE_TOP(BlockTextures::kWater, BlockTextures::kNone, BlockTextures::kNone), - BlockTransparency::kSemiTransparent, - (LightLvl)0, - BlockCollision::kWater, - &kFlowingWaterMesh, - &kLiquidEvent, - }; - } -}; +template <> struct BlockTrait : public LiquidFlowTrait {}; diff --git a/block/block/public/Liquid.hpp b/block/block/public/Liquid.hpp index 302bbfc..fe758b6 100644 --- a/block/block/public/Liquid.hpp +++ b/block/block/public/Liquid.hpp @@ -1,78 +1,139 @@ #pragma once +#include "Trait.hpp" #include -#include +#include +#include namespace hc::block { +template +concept LiquidConcept = requires(T t) { + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; + requires std::same_as; +}; -template -inline static void on_liquid_update(const Block *p_neighbours, Block *p_out_set_blocks, BlockExtraGetBlockFunc) { - // TODO: Improve this +template +inline static void on_liquid_update(const Block *p_neighbours, Block *p_out_set_blocks, + std::function extra_get_block_func) { Block blk = p_neighbours[6]; - const auto is_source = [p_neighbours](int i = 6) { return p_neighbours[i].GetID() == SourceID; }; - const auto is_flow = [p_neighbours](int i = 6) { return p_neighbours[i].GetID() == FlowID; }; + const auto is_source = [p_neighbours](int i = 6) { return p_neighbours[i].GetID() == Config::kSourceID; }; + const auto is_flow = [p_neighbours](int i = 6) { return p_neighbours[i].GetID() == Config::kFlowID; }; const auto is_liquid = [p_neighbours, &is_source, &is_flow](int i = 6) { return is_source(i) || is_flow(i); }; const auto is_wall = [p_neighbours, &is_liquid](int i = 6) { - return p_neighbours[i].GetID() != Blocks::kAir && !is_liquid(i); + return Config::IsObstacle(p_neighbours[i]) && !is_liquid(i); + }; + const auto is_wall_blk = [](Block blk) { + return Config::IsObstacle(blk) && blk.GetID() != Config::kSourceID && blk.GetID() != Config::kFlowID; }; const auto get_lvl = [p_neighbours, &is_source, &is_flow](int i = 6) -> int8_t { - return is_source(i) ? FlowDistance : (is_flow(i) ? p_neighbours[i].GetMeta() : -1); + return is_source(i) ? Config::kFlowDistance : (is_flow(i) ? p_neighbours[i].GetMeta() : -1); }; if (!is_liquid()) return; // Flow -> Source - /* if (!is_source() && is_source(BlockFaces::kLeft) && is_source(BlockFaces::kRight) && is_source(BlockFaces::kBack) - && is_source(BlockFaces::kFront)) { p_out_set_blocks[(*p_out_set_block_count)++] = {6, SourceID}; return; - } */ + if constexpr (Config::kRegenerateSource) { + if (!is_source() && uint32_t(is_source(BlockFaces::kLeft) + is_source(BlockFaces::kRight) + + is_source(BlockFaces::kBack) + is_source(BlockFaces::kFront)) >= 2) { + p_out_set_blocks[6] = Config::kSourceID; + return; + } + } int8_t lvl = get_lvl(); + int8_t lvl_left = get_lvl(BlockFaces::kLeft), lvl_right = get_lvl(BlockFaces::kRight), + lvl_back = get_lvl(BlockFaces::kBack), lvl_front = get_lvl(BlockFaces::kFront); + // Down Shrink - if (!is_liquid(BlockFaces::kTop)) { + if (!is_liquid(BlockFaces::kTop) && is_flow()) { if (!is_liquid(BlockFaces::kLeft) && !is_liquid(BlockFaces::kRight) && !is_liquid(BlockFaces::kBack) && - !is_liquid(BlockFaces::kFront) && !is_source()) { + !is_liquid(BlockFaces::kFront)) { p_out_set_blocks[6] = Blocks::kAir; return; - } else if (is_flow() && lvl == FlowDistance) { - p_out_set_blocks[6] = Blocks::kAir; + } else if (lvl == Config::kFlowDistance) { + if (is_wall(BlockFaces::kBottom)) { + auto max_lvl = std::max(std::max(lvl_left, lvl_right), std::max(lvl_back, lvl_front)); + Block new_blk = max_lvl == 0 ? Blocks::kAir : Block{Config::kFlowID, BlockMeta(max_lvl - 1), 0}; + p_out_set_blocks[6] = new_blk; + } else + p_out_set_blocks[6] = Blocks::kAir; return; } } // Shrink - int8_t lvl_left = get_lvl(BlockFaces::kLeft), lvl_right = get_lvl(BlockFaces::kRight), - lvl_back = get_lvl(BlockFaces::kBack), lvl_front = get_lvl(BlockFaces::kFront); - if (is_flow() && lvl < FlowDistance && (~lvl)) { - if (lvl >= lvl_left && lvl >= lvl_right && lvl >= lvl_back && lvl >= lvl_front) { - Block new_blk = lvl == 0 ? Blocks::kAir : Block{FlowID, BlockMeta(lvl - 1), 0}; + if (is_flow() && lvl < Config::kFlowDistance && lvl >= lvl_left && lvl >= lvl_right && lvl >= lvl_back && + lvl >= lvl_front) { + auto max_lvl = std::max(std::max(lvl_left, lvl_right), std::max(lvl_back, lvl_front)); + if (~max_lvl) { + Block new_blk = max_lvl == 0 ? Blocks::kAir : Block{Config::kFlowID, BlockMeta(max_lvl - 1), 0}; p_out_set_blocks[6] = new_blk; - return; } + return; } - if (is_wall(BlockFaces::kBottom)) { + if (is_wall(BlockFaces::kBottom) || is_source(BlockFaces::kBottom)) { // Spread if (lvl > 0) { - if (!is_wall(BlockFaces::kLeft) && lvl > lvl_left + 1) - p_out_set_blocks[BlockFaces::kLeft] = Block{FlowID, BlockMeta(lvl - 1), 0}; - if (!is_wall(BlockFaces::kRight) && lvl > lvl_right + 1) - p_out_set_blocks[BlockFaces::kRight] = Block{FlowID, BlockMeta(lvl - 1), 0}; - if (!is_wall(BlockFaces::kBack) && lvl > lvl_back + 1) - p_out_set_blocks[BlockFaces::kBack] = Block{FlowID, BlockMeta(lvl - 1), 0}; - if (!is_wall(BlockFaces::kFront) && lvl > lvl_front + 1) - p_out_set_blocks[BlockFaces::kFront] = Block{FlowID, BlockMeta(lvl - 1), 0}; + static_assert(Config::kDetectDistance <= Config::kFlowDistance); + + const auto detect_length = [&is_wall_blk, &is_wall, &is_source, + &extra_get_block_func](BlockFace dir) -> uint32_t { + int8_t axis = dir >> 1, delta = 1 - ((dir & 1) << 1); + glm::i8vec3 cur = {}, gnd = {0, -1, 0}; + + cur[axis] += delta, gnd[axis] += delta; + if (is_wall(dir) || is_source(dir)) + return -1; // mark + else if (!is_wall_blk(extra_get_block_func(gnd))) + return 1; + + for (uint32_t i = 1; i < Config::kDetectDistance; ++i) { + cur[axis] += delta, gnd[axis] += delta; + auto cur_blk = extra_get_block_func(cur); + if (is_wall_blk(cur_blk) || cur_blk.GetID() == Config::kSourceID) + return Config::kDetectDistance + 1; + else if (!is_wall_blk(extra_get_block_func(gnd))) + return i + 1; + } + return Config::kDetectDistance + 1; + }; + uint32_t len_left = detect_length(BlockFaces::kLeft), len_right = detect_length(BlockFaces::kRight), + len_back = detect_length(BlockFaces::kBack), len_front = detect_length(BlockFaces::kFront); + + uint32_t len_min = std::min(std::min(len_left, len_right), std::min(len_back, len_front)); + + if ((~len_left) && lvl > lvl_left + 1 && len_left == len_min) + p_out_set_blocks[BlockFaces::kLeft] = Block{Config::kFlowID, BlockMeta(lvl - 1), 0}; + if ((~len_right) && lvl > lvl_right + 1 && len_right == len_min) + p_out_set_blocks[BlockFaces::kRight] = Block{Config::kFlowID, BlockMeta(lvl - 1), 0}; + if ((~len_back) && lvl > lvl_back + 1 && len_back == len_min) + p_out_set_blocks[BlockFaces::kBack] = Block{Config::kFlowID, BlockMeta(lvl - 1), 0}; + if ((~len_front) && lvl > lvl_front + 1 && len_front == len_min) + p_out_set_blocks[BlockFaces::kFront] = Block{Config::kFlowID, BlockMeta(lvl - 1), 0}; } } else if (!is_source(BlockFaces::kBottom)) { // Down Propagation - p_out_set_blocks[BlockFaces::kBottom] = Block{FlowID, FlowDistance, 0}; + p_out_set_blocks[BlockFaces::kBottom] = Block{Config::kFlowID, Config::kFlowDistance, 0}; } } -template +template inline static BlockEvent kLiquidEvent = { - FlowTickInterval, + Config::kFlowTickInterval, { glm::i8vec3{1, 0, 0}, glm::i8vec3{-1, 0, 0}, @@ -83,7 +144,189 @@ inline static BlockEvent kLiquidEvent = { glm::i8vec3{0, 0, 0}, }, 7u, - on_liquid_update, + on_liquid_update, +}; + +template inline static constexpr uint8_t get_flow_height(BlockMeta variant) { + static_assert(16 % Config::kFlowDistance == 0); + return std::max(variant * (16 / Config::kFlowDistance), 1u); +} + +template +inline static constexpr void flow_mesh_gen(const Block *neighbours, BlockMeshFace *p_out_faces, + uint32_t *p_out_face_count, texture::BlockTexture p_out_textures[6], + bool *p_dynamic_texture) { + // 0 1 + // 2 3 + uint8_t h0, h1, h2, h3; + { + const auto get_nei_height = [](Block block) -> int8_t { + return block.GetID() == Config::kSourceID + ? 16 + : (block.GetID() == Config::kFlowID ? get_flow_height(block.GetMeta()) + : (Config::IsObstacle(block) ? -1 : 0)); + }; + int8_t nhs[] = + { + get_nei_height(neighbours[0]), get_nei_height(neighbours[1]), get_nei_height(neighbours[2]), + get_nei_height(neighbours[3]), get_nei_height(neighbours[4]), get_nei_height(neighbours[5]), + get_nei_height(neighbours[6]), get_nei_height(neighbours[7]), + }, + nb = get_flow_height(Variant); + + // 0 1 2 + // 3 4 + // 5 6 7 + const auto get_vh = [&nhs, nb](uint32_t a, uint32_t b, uint32_t c) -> uint8_t { + uint8_t mx = std::max(std::max(nb, nhs[a]), std::max(nhs[b], nhs[c])); + if (mx != 16 && (nb == 0) + (nhs[a] == 0) + (nhs[b] == 0) + (nhs[c] == 0) >= 3) + return 0; + return mx; + }; + h0 = get_vh(0, 1, 3); + h1 = get_vh(1, 2, 4); + h2 = get_vh(3, 5, 6); + h3 = get_vh(4, 6, 7); + } + + *p_dynamic_texture = true; + if (h0 == 16 && h1 == 16 && h2 == 16 && h3 == 16) { + *p_out_face_count = 0; + std::fill(p_out_textures, p_out_textures + 6, Config::kFlowTex); + } else { + *p_out_face_count = 1; + p_out_faces[0] = BlockMeshFace{ + 1, + BlockFaces::kTop, + BlockFaces::kTop, + {Config::kFlowTex}, + { + {(uint8_t)0, h0, (uint8_t)0}, + {(uint8_t)0, h2, (uint8_t)16}, + {(uint8_t)16, h3, (uint8_t)16}, + {(uint8_t)16, h1, (uint8_t)0}, + }, + }; + bool left_full = h0 == 16 && h2 == 16, left_empty = h0 == 0 && h2 == 0; + bool right_full = h1 == 16 && h3 == 16, right_empty = h1 == 0 && h3 == 0; + bool front_full = h2 == 16 && h3 == 16, front_empty = h2 == 0 && h3 == 0; + bool back_full = h0 == 16 && h1 == 16, back_empty = h0 == 0 && h1 == 0; + if (!left_full && !left_empty && neighbours[3].GetID() != Config::kSourceID && + neighbours[3].GetID() != Config::kFlowID) { + p_out_faces[(*p_out_face_count)++] = BlockMeshFace{ + 0, + BlockFaces::kLeft, + BlockFaces::kLeft, + {Config::kFlowTex}, + { + {(uint8_t)0, h0, (uint8_t)0}, + {(uint8_t)0, (uint8_t)0, (uint8_t)0}, + {(uint8_t)0, (uint8_t)0, (uint8_t)16}, + {(uint8_t)0, h2, (uint8_t)16}, + }, + }; + } + if (!right_full && !right_empty && neighbours[4].GetID() != Config::kSourceID && + neighbours[4].GetID() != Config::kFlowID) { + p_out_faces[(*p_out_face_count)++] = BlockMeshFace{ + 0, + BlockFaces::kRight, + BlockFaces::kRight, + {Config::kFlowTex}, + { + {(uint8_t)16, (uint8_t)0, (uint8_t)0}, + {(uint8_t)16, h1, (uint8_t)0}, + {(uint8_t)16, h3, (uint8_t)16}, + {(uint8_t)16, (uint8_t)0, (uint8_t)16}, + }, + }; + } + if (!back_full && !back_empty && neighbours[1].GetID() != Config::kSourceID && + neighbours[1].GetID() != Config::kFlowID) { + p_out_faces[(*p_out_face_count)++] = BlockMeshFace{ + 2, + BlockFaces::kBack, + BlockFaces::kBack, + {Config::kFlowTex}, + { + {(uint8_t)0, (uint8_t)0, (uint8_t)0}, + {(uint8_t)0, h0, (uint8_t)0}, + {(uint8_t)16, h1, (uint8_t)0}, + {(uint8_t)16, (uint8_t)0, (uint8_t)0}, + }, + }; + } + if (!front_full && !front_empty && neighbours[6].GetID() != Config::kSourceID && + neighbours[6].GetID() != Config::kFlowID) { + p_out_faces[(*p_out_face_count)++] = BlockMeshFace{ + 2, + BlockFaces::kFront, + BlockFaces::kFront, + {Config::kFlowTex}, + { + {(uint8_t)0, h2, (uint8_t)16}, + {(uint8_t)0, (uint8_t)0, (uint8_t)16}, + {(uint8_t)16, (uint8_t)0, (uint8_t)16}, + {(uint8_t)16, h3, (uint8_t)16}, + }, + }; + } + p_out_textures[BlockFaces::kTop] = texture::BlockTextures::kNone; + p_out_textures[BlockFaces::kLeft] = left_full ? Config::kFlowTex : texture::BlockTextures::kNone; + p_out_textures[BlockFaces::kRight] = right_full ? Config::kFlowTex : texture::BlockTextures::kNone; + p_out_textures[BlockFaces::kFront] = front_full ? Config::kFlowTex : texture::BlockTextures::kNone; + p_out_textures[BlockFaces::kBack] = back_full ? Config::kFlowTex : texture::BlockTextures::kNone; + p_out_textures[BlockFaces::kBottom] = Config::kFlowTex; + } +} + +template +inline static constexpr BlockMesh kLiquidFlowMesh = { + {}, + 0, + {{{0, 0, 0}, {16, get_flow_height(Variant), 16}}}, + 1, + flow_mesh_gen, + { + glm::i8vec3{-1, 0, -1}, + glm::i8vec3{0, 0, -1}, + glm::i8vec3{1, 0, -1}, + glm::i8vec3{-1, 0, 0}, + glm::i8vec3{1, 0, 0}, + glm::i8vec3{-1, 0, 1}, + glm::i8vec3{0, 0, 1}, + glm::i8vec3{1, 0, 1}, + }, + 8u, +}; + +template struct LiquidFlowTrait { + inline static constexpr uint8_t kVariants = Config::kFlowDistance + 1; + inline static constexpr uint8_t kVariantBits = std::countr_zero(std::bit_ceil(kVariants)); + inline static constexpr uint8_t kTransforms = 0; + inline static constexpr uint8_t kTransformBits = std::countr_zero(std::bit_ceil(kTransforms)); + + template inline static constexpr BlockProperty TransformProperty(BlockProperty property) { + return property; + } + + template inline static constexpr BlockProperty GetProperty() { + return { + Config::kFlowName, {}, + Config::kTransparency, Config::kLightLvl, + BlockCollision::kWater, &kLiquidFlowMesh, + &kLiquidEvent, + }; + } +}; + +template struct LiquidSourceTrait : public SingleBlockTrait { + constexpr static BlockProperty kProperty = { + Config::kSourceName, BLOCK_TEXTURE_SAME(Config::kSourceTex), + Config::kTransparency, Config::kLightLvl, + BlockCollision::kWater, nullptr, + &kLiquidEvent, + }; }; } // namespace hc::block diff --git a/block/block/public/Water.hpp b/block/block/public/Water.hpp new file mode 100644 index 0000000..6fb68a9 --- /dev/null +++ b/block/block/public/Water.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "Liquid.hpp" + +struct WaterTrait { + inline static constexpr BlockID kSourceID = kWater, kFlowID = kFlowingWater; + inline static constexpr const char *kSourceName = "Water", *kFlowName = "Flowing Water"; + inline static constexpr uint32_t kFlowDistance = 8, kDetectDistance = 6, kFlowTickInterval = 5; + inline static constexpr bool kRegenerateSource = true; + inline static constexpr BlockTexID kSourceTex = BlockTextures::kWater, kFlowTex = BlockTextures::kWater; + inline static constexpr BlockTransparency kTransparency = BlockTransparency::kSemiTransparent; + inline static constexpr LightLvl kLightLvl = 0; + inline static bool IsObstacle(Block blk) { return blk.GetID() != kAir; } +}; +static_assert(LiquidConcept); \ No newline at end of file diff --git a/block/block/water.hpp b/block/block/water.hpp index 1babd2f..5c6e579 100644 --- a/block/block/water.hpp +++ b/block/block/water.hpp @@ -1,15 +1,4 @@ #pragma once -#include "public/Liquid.hpp" -#include "public/Trait.hpp" +#include "public/Water.hpp" -template <> struct BlockTrait : public SingleBlockTrait { - constexpr static BlockProperty kProperty = { - "Water", - BLOCK_TEXTURE_SAME(BlockTextures::kWater), - BlockTransparency::kSemiTransparent, - (LightLvl)0, - BlockCollision::kWater, - nullptr, - &kLiquidEvent, - }; -}; +template <> struct BlockTrait : public LiquidSourceTrait {}; diff --git a/block/include/block/BlockEvent.hpp b/block/include/block/BlockEvent.hpp index 8653c52..928d545 100644 --- a/block/include/block/BlockEvent.hpp +++ b/block/include/block/BlockEvent.hpp @@ -1,13 +1,13 @@ #pragma once #include "BlockFace.hpp" +#include namespace hc::block { class Block; -using BlockExtraGetBlockFunc = Block (*)(glm::i8vec3); -using BlockOnUpdateFunc = void (*)(const Block *, Block *, BlockExtraGetBlockFunc); +using BlockOnUpdateFunc = void (*)(const Block *, Block *, std::function); constexpr uint32_t kBlockUpdateMaxNeighbours = 32; struct BlockEvent { diff --git a/client/src/ChunkUpdateBlockTask.cpp b/client/src/ChunkUpdateBlockTask.cpp index d5a8de2..4f75e14 100644 --- a/client/src/ChunkUpdateBlockTask.cpp +++ b/client/src/ChunkUpdateBlockTask.cpp @@ -58,18 +58,22 @@ void ChunkTaskRunner::Run(ChunkTaskPool *p_task_poo std::vector> set_blocks[27]; - for (const auto &update : data.GetUpdates()) { - const auto *p_blk_event = chunk->GetBlock(update.x, update.y, update.z).GetEvent(); + for (const auto &update_pos : data.GetUpdates()) { + const auto *p_blk_event = chunk->GetBlock(update_pos.x, update_pos.y, update_pos.z).GetEvent(); if (!p_blk_event || !p_blk_event->on_update_func) continue; for (uint32_t i = 0; i < p_blk_event->update_neighbour_count; ++i) { - InnerPos3 pos = update + p_blk_event->update_neighbours[i]; + InnerPos3 pos = update_pos + p_blk_event->update_neighbours[i]; m_update_neighbour_pos[i] = pos; m_update_neighbours[i] = get_block(pos.x, pos.y, pos.z); } std::copy(m_update_neighbours, m_update_neighbours + p_blk_event->update_neighbour_count, m_update_set_blocks); - p_blk_event->on_update_func(m_update_neighbours, m_update_set_blocks, nullptr); + p_blk_event->on_update_func(m_update_neighbours, m_update_set_blocks, + [&update_pos, &get_block](glm::i8vec3 pos) { + pos += update_pos; + return get_block(pos.x, pos.y, pos.z); + }); for (uint32_t i = 0; i < p_blk_event->update_neighbour_count; ++i) { block::Block set_blk = m_update_set_blocks[i]; if (set_blk == m_update_neighbours[i])