move setRotation, checkReplaceability, raycast logic to the blocks_agent
This commit is contained in:
parent
c7c2fe29d2
commit
fb3f201dfc
@ -98,7 +98,9 @@ static int l_set(lua::State* L) {
|
|||||||
if (static_cast<size_t>(id) >= indices->blocks.count()) {
|
if (static_cast<size_t>(id) >= indices->blocks.count()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!level->chunks->get(x, y, z)) {
|
int cx = floordiv<CHUNK_W>(x);
|
||||||
|
int cz = floordiv<CHUNK_D>(z);
|
||||||
|
if (!blocks_agent::get_chunk(*level->chunksStorage, cx, cz)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
blocks_agent::set(*level->chunksStorage, x, y, z, id, int2blockstate(state));
|
blocks_agent::set(*level->chunksStorage, x, y, z, id, int2blockstate(state));
|
||||||
@ -183,7 +185,7 @@ static int l_set_rotation(lua::State* L) {
|
|||||||
auto y = lua::tointeger(L, 2);
|
auto y = lua::tointeger(L, 2);
|
||||||
auto z = lua::tointeger(L, 3);
|
auto z = lua::tointeger(L, 3);
|
||||||
auto value = lua::tointeger(L, 4);
|
auto value = lua::tointeger(L, 4);
|
||||||
level->chunks->setRotation(x, y, z, value);
|
blocks_agent::set_rotation(*level->chunksStorage, x, y, z, value);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +236,9 @@ static int l_get_user_bits(lua::State* L) {
|
|||||||
auto origin = blocks_agent::seek_origin(
|
auto origin = blocks_agent::seek_origin(
|
||||||
*level->chunksStorage, {x, y, z}, def, vox->state
|
*level->chunksStorage, {x, y, z}, def, vox->state
|
||||||
);
|
);
|
||||||
vox = level->chunks->get(origin.x, origin.y, origin.z);
|
vox = blocks_agent::get(
|
||||||
|
*level->chunksStorage, origin.x, origin.y, origin.z
|
||||||
|
);
|
||||||
if (vox == nullptr) {
|
if (vox == nullptr) {
|
||||||
return lua::pushinteger(L, 0);
|
return lua::pushinteger(L, 0);
|
||||||
}
|
}
|
||||||
@ -245,6 +249,7 @@ static int l_get_user_bits(lua::State* L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int l_set_user_bits(lua::State* L) {
|
static int l_set_user_bits(lua::State* L) {
|
||||||
|
auto& chunks = *level->chunksStorage;
|
||||||
auto x = lua::tointeger(L, 1);
|
auto x = lua::tointeger(L, 1);
|
||||||
auto y = lua::tointeger(L, 2);
|
auto y = lua::tointeger(L, 2);
|
||||||
auto z = lua::tointeger(L, 3);
|
auto z = lua::tointeger(L, 3);
|
||||||
@ -254,18 +259,19 @@ static int l_set_user_bits(lua::State* L) {
|
|||||||
size_t mask = ((1 << bits) - 1) << offset;
|
size_t mask = ((1 << bits) - 1) << offset;
|
||||||
auto value = (lua::tointeger(L, 6) << offset) & mask;
|
auto value = (lua::tointeger(L, 6) << offset) & mask;
|
||||||
|
|
||||||
auto chunk = level->chunks->getChunkByVoxel(x, y, z);
|
int cx = floordiv<CHUNK_W>(x);
|
||||||
if (chunk == nullptr) {
|
int cz = floordiv<CHUNK_D>(z);
|
||||||
return 0;
|
auto chunk = blocks_agent::get_chunk(chunks, cx, cz);
|
||||||
}
|
if (chunk == nullptr || y < 0 || y >= CHUNK_H) {
|
||||||
auto vox = level->chunks->get(x, y, z);
|
|
||||||
if (vox == nullptr) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int lx = x - cx * CHUNK_W;
|
||||||
|
int lz = z - cz * CHUNK_D;
|
||||||
|
auto vox = &chunk->voxels[vox_index(lx, y, lz)];
|
||||||
const auto& def = content->getIndices()->blocks.require(vox->id);
|
const auto& def = content->getIndices()->blocks.require(vox->id);
|
||||||
if (def.rt.extended) {
|
if (def.rt.extended) {
|
||||||
auto origin = level->chunks->seekOrigin({x, y, z}, def, vox->state);
|
auto origin = blocks_agent::seek_origin(chunks, {x, y, z}, def, vox->state);
|
||||||
vox = level->chunks->get(origin);
|
vox = blocks_agent::get(chunks, origin.x, origin.y, origin.z);
|
||||||
if (vox == nullptr) {
|
if (vox == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -410,8 +416,15 @@ static int l_raycast(lua::State* L) {
|
|||||||
glm::vec3 end;
|
glm::vec3 end;
|
||||||
glm::ivec3 normal;
|
glm::ivec3 normal;
|
||||||
glm::ivec3 iend;
|
glm::ivec3 iend;
|
||||||
if (auto voxel = level->chunks->rayCast(
|
if (auto voxel = blocks_agent::raycast(
|
||||||
start, dir, maxDistance, end, normal, iend, filteredBlocks
|
*level->chunksStorage,
|
||||||
|
start,
|
||||||
|
dir,
|
||||||
|
maxDistance,
|
||||||
|
end,
|
||||||
|
normal,
|
||||||
|
iend,
|
||||||
|
filteredBlocks
|
||||||
)) {
|
)) {
|
||||||
if (lua::gettop(L) >= 4 && !lua::isnil(L, 4)) {
|
if (lua::gettop(L) >= 4 && !lua::isnil(L, 4)) {
|
||||||
lua::pushvalue(L, 4);
|
lua::pushvalue(L, 4);
|
||||||
|
|||||||
@ -181,109 +181,17 @@ bool Chunks::checkReplaceability(
|
|||||||
const glm::ivec3& origin,
|
const glm::ivec3& origin,
|
||||||
blockid_t ignore
|
blockid_t ignore
|
||||||
) {
|
) {
|
||||||
const auto& rotation = def.rotations.variants[state.rotation];
|
return blocks_agent::check_replaceability(*this, def, state, origin, ignore);
|
||||||
const auto size = def.size;
|
|
||||||
for (int sy = 0; sy < size.y; sy++) {
|
|
||||||
for (int sz = 0; sz < size.z; sz++) {
|
|
||||||
for (int sx = 0; sx < size.x; sx++) {
|
|
||||||
auto pos = origin;
|
|
||||||
pos += rotation.axisX * sx;
|
|
||||||
pos += rotation.axisY * sy;
|
|
||||||
pos += rotation.axisZ * sz;
|
|
||||||
if (auto vox = get(pos.x, pos.y, pos.z)) {
|
|
||||||
auto& target = indices->blocks.require(vox->id);
|
|
||||||
if (!target.replaceable && vox->id != ignore) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunks::setRotationExtended(
|
void Chunks::setRotationExtended(
|
||||||
const Block& def, blockstate state, const glm::ivec3& origin, uint8_t index
|
const Block& def, blockstate state, const glm::ivec3& origin, uint8_t index
|
||||||
) {
|
) {
|
||||||
auto newstate = state;
|
blocks_agent::set_rotation_extended(*this, def, state, origin, index);
|
||||||
newstate.rotation = index;
|
|
||||||
|
|
||||||
// unable to rotate block (cause: obstacles)
|
|
||||||
if (!checkReplaceability(def, newstate, origin, def.rt.id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& rotation = def.rotations.variants[index];
|
|
||||||
const auto size = def.size;
|
|
||||||
std::vector<glm::ivec3> segmentBlocks;
|
|
||||||
|
|
||||||
for (int sy = 0; sy < size.y; sy++) {
|
|
||||||
for (int sz = 0; sz < size.z; sz++) {
|
|
||||||
for (int sx = 0; sx < size.x; sx++) {
|
|
||||||
auto pos = origin;
|
|
||||||
pos += rotation.axisX * sx;
|
|
||||||
pos += rotation.axisY * sy;
|
|
||||||
pos += rotation.axisZ * sz;
|
|
||||||
|
|
||||||
blockstate segState = newstate;
|
|
||||||
segState.segment = blocks_agent::segment_to_int(sx, sy, sz);
|
|
||||||
|
|
||||||
auto vox = get(pos);
|
|
||||||
// checked for nullptr by checkReplaceability
|
|
||||||
if (vox->id != def.rt.id) {
|
|
||||||
set(pos.x, pos.y, pos.z, def.rt.id, segState);
|
|
||||||
} else {
|
|
||||||
vox->state = segState;
|
|
||||||
auto chunk = getChunkByVoxel(pos.x, pos.y, pos.z);
|
|
||||||
assert(chunk != nullptr);
|
|
||||||
chunk->setModifiedAndUnsaved();
|
|
||||||
segmentBlocks.emplace_back(pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto& prevRotation = def.rotations.variants[state.rotation];
|
|
||||||
for (int sy = 0; sy < size.y; sy++) {
|
|
||||||
for (int sz = 0; sz < size.z; sz++) {
|
|
||||||
for (int sx = 0; sx < size.x; sx++) {
|
|
||||||
auto pos = origin;
|
|
||||||
pos += prevRotation.axisX * sx;
|
|
||||||
pos += prevRotation.axisY * sy;
|
|
||||||
pos += prevRotation.axisZ * sz;
|
|
||||||
if (std::find(
|
|
||||||
segmentBlocks.begin(), segmentBlocks.end(), pos
|
|
||||||
) == segmentBlocks.end()) {
|
|
||||||
set(pos.x, pos.y, pos.z, 0, {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunks::setRotation(int32_t x, int32_t y, int32_t z, uint8_t index) {
|
void Chunks::setRotation(int32_t x, int32_t y, int32_t z, uint8_t index) {
|
||||||
if (index >= BlockRotProfile::MAX_COUNT) {
|
return blocks_agent::set_rotation(*this, x, y, z, index);
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto vox = get(x, y, z);
|
|
||||||
if (vox == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto& def = indices->blocks.require(vox->id);
|
|
||||||
if (!def.rotatable || vox->state.rotation == index) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (def.rt.extended) {
|
|
||||||
auto origin = seekOrigin({x, y, z}, def, vox->state);
|
|
||||||
vox = get(origin);
|
|
||||||
setRotationExtended(def, vox->state, origin, index);
|
|
||||||
} else {
|
|
||||||
vox->state.rotation = index;
|
|
||||||
auto chunk = getChunkByVoxel(x, y, z);
|
|
||||||
assert(chunk != nullptr);
|
|
||||||
chunk->setModifiedAndUnsaved();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunks::set(
|
void Chunks::set(
|
||||||
@ -301,134 +209,9 @@ voxel* Chunks::rayCast(
|
|||||||
glm::ivec3& iend,
|
glm::ivec3& iend,
|
||||||
std::set<blockid_t> filter
|
std::set<blockid_t> filter
|
||||||
) const {
|
) const {
|
||||||
float px = start.x;
|
return blocks_agent::raycast(
|
||||||
float py = start.y;
|
*this, start, dir, maxDist, end, norm, iend, std::move(filter)
|
||||||
float pz = start.z;
|
);
|
||||||
|
|
||||||
float dx = dir.x;
|
|
||||||
float dy = dir.y;
|
|
||||||
float dz = dir.z;
|
|
||||||
|
|
||||||
float t = 0.0f;
|
|
||||||
int ix = std::floor(px);
|
|
||||||
int iy = std::floor(py);
|
|
||||||
int iz = std::floor(pz);
|
|
||||||
|
|
||||||
int stepx = (dx > 0.0f) ? 1 : -1;
|
|
||||||
int stepy = (dy > 0.0f) ? 1 : -1;
|
|
||||||
int stepz = (dz > 0.0f) ? 1 : -1;
|
|
||||||
|
|
||||||
constexpr float infinity = std::numeric_limits<float>::infinity();
|
|
||||||
constexpr float epsilon = 1e-6f; // 0.000001
|
|
||||||
float txDelta = (std::fabs(dx) < epsilon) ? infinity : std::fabs(1.0f / dx);
|
|
||||||
float tyDelta = (std::fabs(dy) < epsilon) ? infinity : std::fabs(1.0f / dy);
|
|
||||||
float tzDelta = (std::fabs(dz) < epsilon) ? infinity : std::fabs(1.0f / dz);
|
|
||||||
|
|
||||||
float xdist = (stepx > 0) ? (ix + 1 - px) : (px - ix);
|
|
||||||
float ydist = (stepy > 0) ? (iy + 1 - py) : (py - iy);
|
|
||||||
float zdist = (stepz > 0) ? (iz + 1 - pz) : (pz - iz);
|
|
||||||
|
|
||||||
float txMax = (txDelta < infinity) ? txDelta * xdist : infinity;
|
|
||||||
float tyMax = (tyDelta < infinity) ? tyDelta * ydist : infinity;
|
|
||||||
float tzMax = (tzDelta < infinity) ? tzDelta * zdist : infinity;
|
|
||||||
|
|
||||||
int steppedIndex = -1;
|
|
||||||
|
|
||||||
while (t <= maxDist) {
|
|
||||||
voxel* voxel = get(ix, iy, iz);
|
|
||||||
if (voxel == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& def = indices->blocks.require(voxel->id);
|
|
||||||
if ((filter.empty() && def.selectable) ||
|
|
||||||
(!filter.empty() && filter.find(def.rt.id) == filter.end())) {
|
|
||||||
end.x = px + t * dx;
|
|
||||||
end.y = py + t * dy;
|
|
||||||
end.z = pz + t * dz;
|
|
||||||
iend.x = ix;
|
|
||||||
iend.y = iy;
|
|
||||||
iend.z = iz;
|
|
||||||
|
|
||||||
if (!def.rt.solid) {
|
|
||||||
const std::vector<AABB>& hitboxes =
|
|
||||||
def.rotatable ? def.rt.hitboxes[voxel->state.rotation]
|
|
||||||
: def.hitboxes;
|
|
||||||
|
|
||||||
scalar_t distance = maxDist;
|
|
||||||
Ray ray(start, dir);
|
|
||||||
|
|
||||||
bool hit = false;
|
|
||||||
|
|
||||||
glm::vec3 offset {};
|
|
||||||
if (voxel->state.segment) {
|
|
||||||
offset = seekOrigin(iend, def, voxel->state) - iend;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto box : hitboxes) {
|
|
||||||
box.a += offset;
|
|
||||||
box.b += offset;
|
|
||||||
scalar_t boxDistance;
|
|
||||||
glm::ivec3 boxNorm;
|
|
||||||
if (ray.intersectAABB(
|
|
||||||
iend, box, maxDist, boxNorm, boxDistance
|
|
||||||
) > RayRelation::None &&
|
|
||||||
boxDistance < distance) {
|
|
||||||
hit = true;
|
|
||||||
distance = boxDistance;
|
|
||||||
norm = boxNorm;
|
|
||||||
end = start + (dir * glm::vec3(distance));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit) return voxel;
|
|
||||||
} else {
|
|
||||||
iend.x = ix;
|
|
||||||
iend.y = iy;
|
|
||||||
iend.z = iz;
|
|
||||||
|
|
||||||
norm.x = norm.y = norm.z = 0;
|
|
||||||
if (steppedIndex == 0) norm.x = -stepx;
|
|
||||||
if (steppedIndex == 1) norm.y = -stepy;
|
|
||||||
if (steppedIndex == 2) norm.z = -stepz;
|
|
||||||
return voxel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (txMax < tyMax) {
|
|
||||||
if (txMax < tzMax) {
|
|
||||||
ix += stepx;
|
|
||||||
t = txMax;
|
|
||||||
txMax += txDelta;
|
|
||||||
steppedIndex = 0;
|
|
||||||
} else {
|
|
||||||
iz += stepz;
|
|
||||||
t = tzMax;
|
|
||||||
tzMax += tzDelta;
|
|
||||||
steppedIndex = 2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (tyMax < tzMax) {
|
|
||||||
iy += stepy;
|
|
||||||
t = tyMax;
|
|
||||||
tyMax += tyDelta;
|
|
||||||
steppedIndex = 1;
|
|
||||||
} else {
|
|
||||||
iz += stepz;
|
|
||||||
t = tzMax;
|
|
||||||
tzMax += tzDelta;
|
|
||||||
steppedIndex = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iend.x = ix;
|
|
||||||
iend.y = iy;
|
|
||||||
iend.z = iz;
|
|
||||||
|
|
||||||
end.x = px + t * dx;
|
|
||||||
end.y = py + t * dy;
|
|
||||||
end.z = pz + t * dz;
|
|
||||||
norm.x = norm.y = norm.z = 0;
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Chunks::rayCastToObstacle(
|
glm::vec3 Chunks::rayCastToObstacle(
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
#include "blocks_agent.hpp"
|
#include "blocks_agent.hpp"
|
||||||
|
|
||||||
|
#include "maths/rays.hpp"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
using namespace blocks_agent;
|
using namespace blocks_agent;
|
||||||
|
|
||||||
template <class Storage>
|
template <class Storage>
|
||||||
@ -93,3 +97,171 @@ void blocks_agent::set(
|
|||||||
) {
|
) {
|
||||||
set_block(chunks, x, y, z, id, state);
|
set_block(chunks, x, y, z, id, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Storage>
|
||||||
|
static inline voxel* raycast_blocks(
|
||||||
|
const Storage& chunks,
|
||||||
|
const glm::vec3& start,
|
||||||
|
const glm::vec3& dir,
|
||||||
|
float maxDist,
|
||||||
|
glm::vec3& end,
|
||||||
|
glm::ivec3& norm,
|
||||||
|
glm::ivec3& iend,
|
||||||
|
std::set<blockid_t> filter
|
||||||
|
) {
|
||||||
|
const auto& blocks = chunks.getContentIndices().blocks;
|
||||||
|
float px = start.x;
|
||||||
|
float py = start.y;
|
||||||
|
float pz = start.z;
|
||||||
|
|
||||||
|
float dx = dir.x;
|
||||||
|
float dy = dir.y;
|
||||||
|
float dz = dir.z;
|
||||||
|
|
||||||
|
float t = 0.0f;
|
||||||
|
int ix = std::floor(px);
|
||||||
|
int iy = std::floor(py);
|
||||||
|
int iz = std::floor(pz);
|
||||||
|
|
||||||
|
int stepx = (dx > 0.0f) ? 1 : -1;
|
||||||
|
int stepy = (dy > 0.0f) ? 1 : -1;
|
||||||
|
int stepz = (dz > 0.0f) ? 1 : -1;
|
||||||
|
|
||||||
|
constexpr float infinity = std::numeric_limits<float>::infinity();
|
||||||
|
constexpr float epsilon = 1e-6f; // 0.000001
|
||||||
|
float txDelta = (std::fabs(dx) < epsilon) ? infinity : std::fabs(1.0f / dx);
|
||||||
|
float tyDelta = (std::fabs(dy) < epsilon) ? infinity : std::fabs(1.0f / dy);
|
||||||
|
float tzDelta = (std::fabs(dz) < epsilon) ? infinity : std::fabs(1.0f / dz);
|
||||||
|
|
||||||
|
float xdist = (stepx > 0) ? (ix + 1 - px) : (px - ix);
|
||||||
|
float ydist = (stepy > 0) ? (iy + 1 - py) : (py - iy);
|
||||||
|
float zdist = (stepz > 0) ? (iz + 1 - pz) : (pz - iz);
|
||||||
|
|
||||||
|
float txMax = (txDelta < infinity) ? txDelta * xdist : infinity;
|
||||||
|
float tyMax = (tyDelta < infinity) ? tyDelta * ydist : infinity;
|
||||||
|
float tzMax = (tzDelta < infinity) ? tzDelta * zdist : infinity;
|
||||||
|
|
||||||
|
int steppedIndex = -1;
|
||||||
|
|
||||||
|
while (t <= maxDist) {
|
||||||
|
voxel* voxel = get(chunks, ix, iy, iz);
|
||||||
|
if (voxel == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& def = blocks.require(voxel->id);
|
||||||
|
if ((filter.empty() && def.selectable) ||
|
||||||
|
(!filter.empty() && filter.find(def.rt.id) == filter.end())) {
|
||||||
|
end.x = px + t * dx;
|
||||||
|
end.y = py + t * dy;
|
||||||
|
end.z = pz + t * dz;
|
||||||
|
iend.x = ix;
|
||||||
|
iend.y = iy;
|
||||||
|
iend.z = iz;
|
||||||
|
|
||||||
|
if (!def.rt.solid) {
|
||||||
|
const std::vector<AABB>& hitboxes =
|
||||||
|
def.rotatable ? def.rt.hitboxes[voxel->state.rotation]
|
||||||
|
: def.hitboxes;
|
||||||
|
|
||||||
|
scalar_t distance = maxDist;
|
||||||
|
Ray ray(start, dir);
|
||||||
|
|
||||||
|
bool hit = false;
|
||||||
|
|
||||||
|
glm::vec3 offset {};
|
||||||
|
if (voxel->state.segment) {
|
||||||
|
offset = seek_origin(chunks, iend, def, voxel->state) - iend;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto box : hitboxes) {
|
||||||
|
box.a += offset;
|
||||||
|
box.b += offset;
|
||||||
|
scalar_t boxDistance;
|
||||||
|
glm::ivec3 boxNorm;
|
||||||
|
if (ray.intersectAABB(
|
||||||
|
iend, box, maxDist, boxNorm, boxDistance
|
||||||
|
) > RayRelation::None &&
|
||||||
|
boxDistance < distance) {
|
||||||
|
hit = true;
|
||||||
|
distance = boxDistance;
|
||||||
|
norm = boxNorm;
|
||||||
|
end = start + (dir * glm::vec3(distance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hit) return voxel;
|
||||||
|
} else {
|
||||||
|
iend.x = ix;
|
||||||
|
iend.y = iy;
|
||||||
|
iend.z = iz;
|
||||||
|
|
||||||
|
norm.x = norm.y = norm.z = 0;
|
||||||
|
if (steppedIndex == 0) norm.x = -stepx;
|
||||||
|
if (steppedIndex == 1) norm.y = -stepy;
|
||||||
|
if (steppedIndex == 2) norm.z = -stepz;
|
||||||
|
return voxel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (txMax < tyMax) {
|
||||||
|
if (txMax < tzMax) {
|
||||||
|
ix += stepx;
|
||||||
|
t = txMax;
|
||||||
|
txMax += txDelta;
|
||||||
|
steppedIndex = 0;
|
||||||
|
} else {
|
||||||
|
iz += stepz;
|
||||||
|
t = tzMax;
|
||||||
|
tzMax += tzDelta;
|
||||||
|
steppedIndex = 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tyMax < tzMax) {
|
||||||
|
iy += stepy;
|
||||||
|
t = tyMax;
|
||||||
|
tyMax += tyDelta;
|
||||||
|
steppedIndex = 1;
|
||||||
|
} else {
|
||||||
|
iz += stepz;
|
||||||
|
t = tzMax;
|
||||||
|
tzMax += tzDelta;
|
||||||
|
steppedIndex = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iend.x = ix;
|
||||||
|
iend.y = iy;
|
||||||
|
iend.z = iz;
|
||||||
|
|
||||||
|
end.x = px + t * dx;
|
||||||
|
end.y = py + t * dy;
|
||||||
|
end.z = pz + t * dz;
|
||||||
|
norm.x = norm.y = norm.z = 0;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
voxel* blocks_agent::raycast(
|
||||||
|
const Chunks& chunks,
|
||||||
|
const glm::vec3& start,
|
||||||
|
const glm::vec3& dir,
|
||||||
|
float maxDist,
|
||||||
|
glm::vec3& end,
|
||||||
|
glm::ivec3& norm,
|
||||||
|
glm::ivec3& iend,
|
||||||
|
std::set<blockid_t> filter
|
||||||
|
) {
|
||||||
|
return raycast_blocks(chunks, start, dir, maxDist, end, norm, iend, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
voxel* blocks_agent::raycast(
|
||||||
|
const GlobalChunks& chunks,
|
||||||
|
const glm::vec3& start,
|
||||||
|
const glm::vec3& dir,
|
||||||
|
float maxDist,
|
||||||
|
glm::vec3& end,
|
||||||
|
glm::ivec3& norm,
|
||||||
|
glm::ivec3& iend,
|
||||||
|
std::set<blockid_t> filter
|
||||||
|
) {
|
||||||
|
return raycast_blocks(chunks, start, dir, maxDist, end, norm, iend, filter);
|
||||||
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "maths/voxmaths.hpp"
|
#include "maths/voxmaths.hpp"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
@ -160,4 +161,158 @@ inline glm::ivec3 seek_origin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Storage>
|
||||||
|
inline bool check_replaceability(
|
||||||
|
const Storage& chunks,
|
||||||
|
const Block& def,
|
||||||
|
blockstate state,
|
||||||
|
const glm::ivec3& origin,
|
||||||
|
blockid_t ignore
|
||||||
|
) {
|
||||||
|
const auto& blocks = chunks.getContentIndices().blocks;
|
||||||
|
const auto& rotation = def.rotations.variants[state.rotation];
|
||||||
|
const auto size = def.size;
|
||||||
|
for (int sy = 0; sy < size.y; sy++) {
|
||||||
|
for (int sz = 0; sz < size.z; sz++) {
|
||||||
|
for (int sx = 0; sx < size.x; sx++) {
|
||||||
|
auto pos = origin;
|
||||||
|
pos += rotation.axisX * sx;
|
||||||
|
pos += rotation.axisY * sy;
|
||||||
|
pos += rotation.axisZ * sz;
|
||||||
|
if (auto vox = get(chunks, pos.x, pos.y, pos.z)) {
|
||||||
|
auto& target = blocks.require(vox->id);
|
||||||
|
if (!target.replaceable && vox->id != ignore) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Set rotation to an extended block
|
||||||
|
/// @tparam Storage chunks storage
|
||||||
|
/// @param def block definition
|
||||||
|
/// @param state current block state
|
||||||
|
/// @param origin extended block origin
|
||||||
|
/// @param index target rotation index
|
||||||
|
template <class Storage>
|
||||||
|
inline void set_rotation_extended(
|
||||||
|
Storage& chunks,
|
||||||
|
const Block& def,
|
||||||
|
blockstate state,
|
||||||
|
const glm::ivec3& origin,
|
||||||
|
uint8_t index
|
||||||
|
) {
|
||||||
|
auto newstate = state;
|
||||||
|
newstate.rotation = index;
|
||||||
|
|
||||||
|
// unable to rotate block (cause: obstacles)
|
||||||
|
if (!check_replaceability(chunks, def, newstate, origin, def.rt.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& rotation = def.rotations.variants[index];
|
||||||
|
const auto size = def.size;
|
||||||
|
std::vector<glm::ivec3> segmentBlocks;
|
||||||
|
|
||||||
|
for (int sy = 0; sy < size.y; sy++) {
|
||||||
|
for (int sz = 0; sz < size.z; sz++) {
|
||||||
|
for (int sx = 0; sx < size.x; sx++) {
|
||||||
|
auto pos = origin;
|
||||||
|
pos += rotation.axisX * sx;
|
||||||
|
pos += rotation.axisY * sy;
|
||||||
|
pos += rotation.axisZ * sz;
|
||||||
|
|
||||||
|
blockstate segState = newstate;
|
||||||
|
segState.segment = segment_to_int(sx, sy, sz);
|
||||||
|
|
||||||
|
auto vox = get(chunks, pos.x, pos.y, pos.z);
|
||||||
|
// checked for nullptr by checkReplaceability
|
||||||
|
if (vox->id != def.rt.id) {
|
||||||
|
set(chunks, pos.x, pos.y, pos.z, def.rt.id, segState);
|
||||||
|
} else {
|
||||||
|
vox->state = segState;
|
||||||
|
int cx = floordiv<CHUNK_W>(pos.x);
|
||||||
|
int cz = floordiv<CHUNK_D>(pos.z);
|
||||||
|
auto chunk = get_chunk(chunks, cx, cz);
|
||||||
|
assert(chunk != nullptr);
|
||||||
|
chunk->setModifiedAndUnsaved();
|
||||||
|
segmentBlocks.emplace_back(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto& prevRotation = def.rotations.variants[state.rotation];
|
||||||
|
for (int sy = 0; sy < size.y; sy++) {
|
||||||
|
for (int sz = 0; sz < size.z; sz++) {
|
||||||
|
for (int sx = 0; sx < size.x; sx++) {
|
||||||
|
auto pos = origin;
|
||||||
|
pos += prevRotation.axisX * sx;
|
||||||
|
pos += prevRotation.axisY * sy;
|
||||||
|
pos += prevRotation.axisZ * sz;
|
||||||
|
if (std::find(
|
||||||
|
segmentBlocks.begin(), segmentBlocks.end(), pos
|
||||||
|
) == segmentBlocks.end()) {
|
||||||
|
set(chunks, pos.x, pos.y, pos.z, 0, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Storage>
|
||||||
|
inline void set_rotation(
|
||||||
|
Storage& chunks, int32_t x, int32_t y, int32_t z, uint8_t index
|
||||||
|
) {
|
||||||
|
if (index >= BlockRotProfile::MAX_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto vox = get(chunks, x, y, z);
|
||||||
|
if (vox == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& def = chunks.getContentIndices().blocks.require(vox->id);
|
||||||
|
if (!def.rotatable || vox->state.rotation == index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (def.rt.extended) {
|
||||||
|
auto origin = seek_origin(chunks, {x, y, z}, def, vox->state);
|
||||||
|
vox = get(chunks, origin.x, origin.y, origin.z);
|
||||||
|
set_rotation_extended(chunks, def, vox->state, origin, index);
|
||||||
|
} else {
|
||||||
|
vox->state.rotation = index;
|
||||||
|
int cx = floordiv<CHUNK_W>(x);
|
||||||
|
int cz = floordiv<CHUNK_D>(z);
|
||||||
|
auto chunk = get_chunk(chunks, cx, cz);
|
||||||
|
assert(chunk != nullptr);
|
||||||
|
chunk->setModifiedAndUnsaved();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
voxel* raycast(
|
||||||
|
const Chunks& chunks,
|
||||||
|
const glm::vec3& start,
|
||||||
|
const glm::vec3& dir,
|
||||||
|
float maxDist,
|
||||||
|
glm::vec3& end,
|
||||||
|
glm::ivec3& norm,
|
||||||
|
glm::ivec3& iend,
|
||||||
|
std::set<blockid_t> filter
|
||||||
|
);
|
||||||
|
|
||||||
|
voxel* raycast(
|
||||||
|
const GlobalChunks& chunks,
|
||||||
|
const glm::vec3& start,
|
||||||
|
const glm::vec3& dir,
|
||||||
|
float maxDist,
|
||||||
|
glm::vec3& end,
|
||||||
|
glm::ivec3& norm,
|
||||||
|
glm::ivec3& iend,
|
||||||
|
std::set<blockid_t> filter
|
||||||
|
);
|
||||||
|
|
||||||
} // blocks_agent
|
} // blocks_agent
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user