fix extended block grounding (new block property)

This commit is contained in:
clasher113 2026-02-28 18:31:15 +02:00
parent 0cc8c70a17
commit 0b7dc14f55
7 changed files with 111 additions and 8 deletions

View file

@ -241,6 +241,15 @@ Number of block inventory slots. Default - 0 (no inventory).
Array of three integers. Default value is `[1, 1, 1]`. Array of three integers. Default value is `[1, 1, 1]`.
### *grounding-behaviour*
Defines the behavior of the extended grounded block. Available behavior options:
- "partial" - at least one segment must be grounded (default)
- "complete" - all segments must be grounded
- "origin" - origin segment must be grounded
## Block fields ## Block fields
Block fields allow you to write more data unique to a specified voxel than the user bits allow. Block fields allow you to write more data unique to a specified voxel than the user bits allow.

View file

@ -247,6 +247,14 @@
Массив из трех целых чисел. Значение по-умолчанию - `[1, 1, 1]`. Массив из трех целых чисел. Значение по-умолчанию - `[1, 1, 1]`.
### Поведение приземленности - *grounding-behaviour*
Определяет поведение расширенного приземленного блока. Доступные варианты поведения:
- "partial" - как минимум один сегмент блока должен быть приземленным (по-умолчанию)
- "complete" - все сегменты блока должны быть приземленными
- "origin" - главный сегмент должен быть приземленным
## Поля блока ## Поля блока
Поля блоков позволяет записывать больше уникальных для конкретного блока данных, чем это позволяют пользовательские биты. Поля блоков позволяет записывать больше уникальных для конкретного блока данных, чем это позволяют пользовательские биты.

View file

@ -206,6 +206,15 @@ template<> void ContentUnitLoader<Block>::loadUnit(
def.defaults.model.type = BlockModelType::AABB; def.defaults.model.type = BlockModelType::AABB;
def.hitboxes = {AABB(def.size)}; def.hitboxes = {AABB(def.size)};
} }
// grounding behaviour
if (root.has("grounding-behaviour")) {
std::string groundingBehaviourName = GroundingBehaviourMeta.getNameString(def.groundingBehaviour);
root.at("grounding-behaviour").get(groundingBehaviourName);
if (!GroundingBehaviourMeta.getItem(groundingBehaviourName, def.groundingBehaviour)) {
logger.error() << "unknown grounding behaviour: " << groundingBehaviourName;
}
}
} }
// primitive properties // primitive properties

View file

@ -106,10 +106,17 @@ void BlocksController::updateBlock(int x, int y, int z) {
if (vox == nullptr) return; 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) { if (def.grounded) {
const auto& vec = get_ground_direction(def, vox->state.rotation); if (def.rt.extended) {
if (!blocks_agent::is_solid_at(chunks, x + vec.x, y + vec.y, z + vec.z)) { auto origin = blocks_agent::seek_origin(chunks, {x, y, z}, def, vox->state);
breakBlock(nullptr, def, x, y, z); if (!blocks_agent::check_grounding(chunks, def, vox->state.rotation, origin)) {
return; breakBlock(nullptr, def, origin.x, origin.y, origin.z);
return;
}
} else {
if (!blocks_agent::check_grounding(chunks, def, vox->state.rotation, {x, y, z})) {
breakBlock(nullptr, def, x, y, z);
return;
}
} }
} }
if (def.rt.funcsset.update) { if (def.rt.funcsset.update) {

View file

@ -22,6 +22,7 @@
#include "scripting/scripting.hpp" #include "scripting/scripting.hpp"
#include "settings.hpp" #include "settings.hpp"
#include "voxels/Block.hpp" #include "voxels/Block.hpp"
#include "voxels/blocks_agent.hpp"
#include "voxels/Chunks.hpp" #include "voxels/Chunks.hpp"
#include "voxels/voxel.hpp" #include "voxels/voxel.hpp"
#include "window/Camera.hpp" #include "window/Camera.hpp"
@ -448,10 +449,7 @@ void PlayerController::processRightClick(
return; return;
} }
if (def.grounded) { if (def.grounded) {
const auto& vec = get_ground_direction(def, state.rotation); if (!blocks_agent::check_grounding(chunks, def, state.rotation, coord)) {
if (!chunks.isSolidBlock(
coord.x + vec.x, coord.y + vec.y, coord.z + vec.z
)) {
return; return;
} }
} }

View file

@ -140,6 +140,22 @@ VC_ENUM_METADATA(CullingMode)
{"disabled", CullingMode::DISABLED}, {"disabled", CullingMode::DISABLED},
VC_ENUM_END VC_ENUM_END
/// @brief Grounding behaviour for extended blocks
enum class GroundingBehaviour : uint8_t {
/// @brief at least one segment must be grounded
PARTIAL,
/// @brief all segments must be grounded
COMPLETE,
/// @brief origin segment must be grounded
ORIGIN
};
VC_ENUM_METADATA(GroundingBehaviour)
{"partial", GroundingBehaviour::PARTIAL},
{"complete", GroundingBehaviour::COMPLETE},
{"origin", GroundingBehaviour::ORIGIN},
VC_ENUM_END
/// @brief Common kit of block properties applied to groups of blocks /// @brief Common kit of block properties applied to groups of blocks
struct BlockMaterial : Serializable { struct BlockMaterial : Serializable {
std::string name; std::string name;
@ -239,6 +255,9 @@ public:
/// @brief Explicitly overriding 'solid' property if true assigned /// @brief Explicitly overriding 'solid' property if true assigned
bool explictlySolid = false; bool explictlySolid = false;
/// @brief Grounding behaviour
GroundingBehaviour groundingBehaviour = GroundingBehaviour::PARTIAL;
/// @brief Set of block physical hitboxes /// @brief Set of block physical hitboxes
std::vector<AABB> hitboxes {AABB()}; std::vector<AABB> hitboxes {AABB()};

View file

@ -494,4 +494,57 @@ inline const AABB* is_obstacle_at(const Storage& chunks, float x, float y, float
return nullptr; return nullptr;
} }
/// @brief Check block grounding
/// @tparam Storage chunks storage class
/// @param chunks chunks storage
/// @param def block definition
/// @param rotationIndex target block rotation index
/// @param origin target block origin
/// @return true if grounded
template <class Storage>
inline bool check_grounding(
const Storage& chunks,
const Block& def,
uint8_t rotationIndex,
const glm::ivec3& origin
) {
const auto& vec = get_ground_direction(def, rotationIndex);
if (def.rt.extended) {
const auto& rotation = def.rotations.variants[rotationIndex];
if (def.groundingBehaviour == GroundingBehaviour::PARTIAL) {
for (int sz = 0; sz < def.size.z; sz++) {
for (int sx = 0; sx < def.size.x; sx++) {
auto pos = origin;
pos += rotation.axes[0] * sx;
pos += rotation.axes[2] * sz;
if (blocks_agent::is_solid_at(chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z)) {
return true;
}
}
}
return false;
}
else if (def.groundingBehaviour == GroundingBehaviour::COMPLETE) {
for (int sz = 0; sz < def.size.z; sz++) {
for (int sx = 0; sx < def.size.x; sx++) {
auto pos = origin;
pos += rotation.axes[0] * sx;
pos += rotation.axes[2] * sz;
if (!blocks_agent::is_solid_at(chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z)) {
return false;
}
}
}
return true;
}
else if (def.groundingBehaviour == GroundingBehaviour::ORIGIN) {
return blocks_agent::is_solid_at(chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z);
}
}
return blocks_agent::is_solid_at(chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z);
}
} // blocks_agent } // blocks_agent