Merge pull request #237 from MihailRis/extended-blocks

Extended blocks
This commit is contained in:
MihailRis
2024-06-10 19:10:54 +03:00
committed by GitHub
29 changed files with 764 additions and 382 deletions
+6 -3
View File
@@ -130,11 +130,13 @@ void BlocksController::randomTick(int tickid, int parts) {
for (uint z = padding; z < d-padding; z++){
for (uint x = padding; x < w-padding; x++){
int index = z * w + x;
if ((index + tickid) % parts != 0)
if ((index + tickid) % parts != 0) {
continue;
}
auto& chunk = chunks->chunks[index];
if (chunk == nullptr || !chunk->flags.lighted)
if (chunk == nullptr || !chunk->flags.lighted) {
continue;
}
for (int s = 0; s < segments; s++) {
for (int i = 0; i < 4; i++) {
int bx = random.rand() % CHUNK_W;
@@ -146,7 +148,8 @@ void BlocksController::randomTick(int tickid, int parts) {
scripting::random_update_block(
block,
chunk->x * CHUNK_W + bx, by,
chunk->z * CHUNK_D + bz);
chunk->z * CHUNK_D + bz
);
}
}
}
+131 -111
View File
@@ -170,11 +170,6 @@ void CameraControl::update(const PlayerInput& input, float delta, Chunks* chunks
}
}
glm::vec3 PlayerController::selectedPointPosition;
glm::ivec3 PlayerController::selectedBlockNormal;
int PlayerController::selectedBlockId = -1;
int PlayerController::selectedBlockRotation = 0;
PlayerController::PlayerController(
Level* level,
const EngineSettings& settings,
@@ -252,8 +247,8 @@ void PlayerController::update(float delta, bool input, bool pause) {
if (input) {
updateInteraction();
} else {
selectedBlockId = -1;
selectedBlockRotation = 0;
player->selection.vox.id = BLOCK_VOID;
player->selection.vox.state.rotation = 0;
}
}
@@ -295,7 +290,7 @@ void PlayerController::updateControls(float delta){
player->updateInput(level, input, delta);
}
static int determine_rotation(Block* def, glm::ivec3& norm, glm::vec3& camDir) {
static int determine_rotation(Block* def, const glm::ivec3& norm, glm::vec3& camDir) {
if (def && def->rotatable){
const std::string& name = def->rotations.name;
if (name == "pipe") {
@@ -336,25 +331,11 @@ static void pick_block(ContentIndices* indices, Chunks* chunks, Player* player,
}
}
// TODO: refactor this nesting nest
void PlayerController::updateInteraction(){
voxel* PlayerController::updateSelection(float maxDistance) {
auto indices = level->content->getIndices();
Chunks* chunks = level->chunks.get();
Lighting* lighting = level->lighting.get();
Camera* camera = player->camera.get();
bool xkey = Events::pressed(keycode::X);
bool lclick = Events::jactive(BIND_PLAYER_ATTACK) ||
(xkey && Events::active(BIND_PLAYER_ATTACK));
bool rclick = Events::jactive(BIND_PLAYER_BUILD) ||
(xkey && Events::active(BIND_PLAYER_BUILD));
float maxDistance = 10.0f;
if (xkey) {
maxDistance *= 20.0f;
}
auto inventory = player->getInventory();
const ItemStack& stack = inventory->getSlot(player->getChosenSlot());
ItemDef* item = indices->getItemDef(stack.getItemId());
auto chunks = level->chunks.get();
auto camera = player->camera.get();
auto& selection = player->selection;
glm::vec3 end;
glm::ivec3 iend;
@@ -365,95 +346,134 @@ void PlayerController::updateInteraction(){
maxDistance,
end, norm, iend
);
if (vox != nullptr) {
player->selectedVoxel = *vox;
selectedBlockId = vox->id;
selectedBlockRotation = vox->state.rotation;
player->selectedBlockPosition = iend;
selectedPointPosition = end;
selectedBlockNormal = norm;
int x = iend.x;
int y = iend.y;
int z = iend.z;
Block* def = indices->getBlockDef(item->rt.placingBlock);
blockstate state {};
state.rotation = determine_rotation(def, norm, camera->dir);
if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) {
if (scripting::on_item_break_block(player.get(), item, x, y, z))
return;
}
Block* target = indices->getBlockDef(vox->id);
if (lclick && target->breakable){
onBlockInteraction(
glm::ivec3(x, y, z), target,
BlockInteraction::destruction
);
blocksController->breakBlock(player.get(), target, x, y, z);
}
if (rclick && !input.shift) {
bool preventDefault = false;
if (item->rt.funcsset.on_use_on_block) {
preventDefault = scripting::on_item_use_on_block(player.get(), item, x, y, z);
} else if (item->rt.funcsset.on_use) {
preventDefault = scripting::on_item_use(player.get(), item);
}
if (preventDefault) {
return;
}
}
if (def && rclick){
if (!input.shift && target->rt.funcsset.oninteract) {
if (scripting::on_block_interact(player.get(), target, x, y, z))
return;
}
if (!target->replaceable){
x = (iend.x)+(norm.x);
y = (iend.y)+(norm.y);
z = (iend.z)+(norm.z);
} else {
if (def->rotations.name == "pipe") {
state.rotation = BLOCK_DIR_UP;
}
}
vox = chunks->get(x, y, z);
blockid_t chosenBlock = def->rt.id;
if (vox && (target = indices->getBlockDef(vox->id))->replaceable) {
if (!level->physics->isBlockInside(x,y,z,def,state, player->hitbox.get())
|| !def->obstacle){
if (def->grounded && !chunks->isSolidBlock(x, y-1, z)) {
chosenBlock = 0;
}
if (chosenBlock != vox->id && chosenBlock) {
onBlockInteraction(
glm::ivec3(x, y, z), def,
BlockInteraction::placing
);
chunks->set(x, y, z, chosenBlock, state);
lighting->onBlockSet(x,y,z, chosenBlock);
if (def->rt.funcsset.onplaced) {
scripting::on_block_placed(player.get(), def, x, y, z);
}
blocksController->updateSides(x, y, z);
}
}
}
}
if (Events::jactive(BIND_PLAYER_PICK)) {
pick_block(indices, chunks, player.get(), x, y, z);
if (vox == nullptr) {
selection.vox = {BLOCK_VOID, {}};
return nullptr;
}
blockstate selectedState = vox->state;
selection.vox = *vox;
selection.actualPosition = iend;
if (selectedState.segment) {
selection.position = chunks->seekOrigin(
iend, indices->getBlockDef(selection.vox.id), selectedState
);
auto origin = chunks->get(iend);
if (origin && origin->id != vox->id) {
chunks->set(iend.x, iend.y, iend.z, 0, {});
return updateSelection(maxDistance);
}
} else {
selectedBlockId = -1;
selectedBlockRotation = 0;
player->selectedVoxel.id = BLOCK_VOID;
if (rclick) {
if (item->rt.funcsset.on_use) {
scripting::on_item_use(player.get(), item);
}
selection.position = iend;
}
selection.hitPosition = end;
selection.normal = norm;
return vox;
}
void PlayerController::processRightClick(Block* def, Block* target) {
const auto& selection = player->selection;
auto chunks = level->chunks.get();
auto camera = player->camera.get();
auto lighting = level->lighting.get();
blockstate state {};
state.rotation = determine_rotation(def, selection.normal, camera->dir);
if (!input.shift && target->rt.funcsset.oninteract) {
if (scripting::on_block_interact(player.get(), target, selection.position)) {
return;
}
}
auto coord = selection.actualPosition;
if (!target->replaceable){
coord += selection.normal;
} else if (def->rotations.name == BlockRotProfile::PIPE_NAME) {
state.rotation = BLOCK_DIR_UP;
}
blockid_t chosenBlock = def->rt.id;
if (def->obstacle && level->physics->isBlockInside(
coord.x, coord.y, coord.z, def,state, player->hitbox.get())) {
return;
}
auto vox = chunks->get(coord);
if (vox == nullptr) {
return;
}
if (!chunks->checkReplaceability(def, state, coord)) {
return;
}
if (def->grounded && !chunks->isSolidBlock(coord.x, coord.y-1, coord.z)) {
return;
}
if (chosenBlock != vox->id && chosenBlock) {
onBlockInteraction(coord, def, BlockInteraction::placing);
chunks->set(coord.x, coord.y, coord.z, chosenBlock, state);
lighting->onBlockSet(coord.x, coord.y, coord.z, chosenBlock);
if (def->rt.funcsset.onplaced) {
scripting::on_block_placed(player.get(), def, coord.x, coord.y, coord.z);
}
blocksController->updateSides(coord.x, coord.y, coord.z);
}
}
void PlayerController::updateInteraction() {
auto indices = level->content->getIndices();
auto chunks = level->chunks.get();
const auto& selection = player->selection;
bool xkey = Events::pressed(keycode::X);
bool lclick = Events::jactive(BIND_PLAYER_ATTACK) || (xkey && Events::active(BIND_PLAYER_ATTACK));
bool rclick = Events::jactive(BIND_PLAYER_BUILD) || (xkey && Events::active(BIND_PLAYER_BUILD));
float maxDistance = xkey ? 200.0f : 10.0f;
auto inventory = player->getInventory();
const ItemStack& stack = inventory->getSlot(player->getChosenSlot());
ItemDef* item = indices->getItemDef(stack.getItemId());
auto vox = updateSelection(maxDistance);
if (vox == nullptr) {
if (rclick && item->rt.funcsset.on_use) {
scripting::on_item_use(player.get(), item);
}
return;
}
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)) {
return;
}
}
auto target = indices->getBlockDef(vox->id);
if (lclick && target->breakable){
onBlockInteraction(
iend, target,
BlockInteraction::destruction
);
blocksController->breakBlock(player.get(), target, iend.x, iend.y, iend.z);
}
if (rclick && !input.shift) {
bool preventDefault = false;
if (item->rt.funcsset.on_use_on_block) {
preventDefault = scripting::on_item_use_on_block(
player.get(), item, iend.x, iend.y, iend.z
);
} else if (item->rt.funcsset.on_use) {
preventDefault = scripting::on_item_use(player.get(), item);
}
if (preventDefault) {
return;
}
}
auto def = indices->getBlockDef(item->rt.placingBlock);
if (def && rclick) {
processRightClick(def, target);
}
if (Events::jactive(BIND_PLAYER_PICK)) {
auto coord = selection.actualPosition;
pick_block(indices, chunks, player.get(), coord.x, coord.y, coord.z);
}
}
Player* PlayerController::getPlayer() {
+3 -5
View File
@@ -76,12 +76,10 @@ class PlayerController {
float stepsTimer = 0.0f;
void onFootstep();
void updateFootsteps(float delta);
public:
static glm::ivec3 selectedBlockNormal;
static glm::vec3 selectedPointPosition;
static int selectedBlockId;
static int selectedBlockRotation;
void processRightClick(Block* def, Block* target);
voxel* updateSelection(float maxDistance);
public:
PlayerController(
Level* level,
const EngineSettings& settings,
+92 -58
View File
@@ -13,29 +13,32 @@
#include "../../../content/Content.hpp"
#include "../../../logic/BlocksController.hpp"
int l_block_name(lua_State* L) {
static Block* require_block(lua_State* L) {
auto indices = scripting::content->getIndices();
lua_Integer id = lua_tointeger(L, 1);
if (static_cast<size_t>(id) >= indices->countBlockDefs()) {
return 0;
return nullptr;
}
auto def = indices->getBlockDef(id);
lua_pushstring(L, def->name.c_str());
return 1;
return indices->getBlockDef(id);
}
int l_block_material(lua_State* L) {
auto indices = scripting::content->getIndices();
lua_Integer id = lua_tointeger(L, 1);
if (static_cast<size_t>(id) >= indices->countBlockDefs()) {
return 0;
static int l_name(lua_State* L) {
if (auto def = require_block(L)) {
lua_pushstring(L, def->name.c_str());
return 1;
}
auto def = indices->getBlockDef(id);
lua_pushstring(L, def->material.c_str());
return 1;
return 0;
}
int l_is_solid_at(lua_State* L) {
static int l_material(lua_State* L) {
if (auto def = require_block(L)) {
lua_pushstring(L, def->material.c_str());
return 1;
}
return 0;
}
static int l_is_solid_at(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -44,18 +47,53 @@ int l_is_solid_at(lua_State* L) {
return 1;
}
int l_blocks_count(lua_State* L) {
static int l_count(lua_State* L) {
lua_pushinteger(L, scripting::indices->countBlockDefs());
return 1;
}
int l_block_index(lua_State* L) {
static int l_index(lua_State* L) {
std::string name = lua_tostring(L, 1);
lua_pushinteger(L, scripting::content->requireBlock(name).rt.id);
return 1;
}
int l_set_block(lua_State* L) {
static int l_is_extended(lua_State* L) {
if (auto def = require_block(L)) {
lua_pushboolean(L, def->rt.extended);
return 1;
}
return 0;
}
static int l_get_size(lua_State* L) {
if (auto def = require_block(L)) {
return lua::pushivec3(L, def->size.x, def->size.y, def->size.z);
}
return 0;
}
static int l_is_segment(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
auto vox = scripting::level->chunks->get(x, y, z);
lua_pushboolean(L, vox->state.segment);
return 1;
}
static int l_seek_origin(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
auto vox = scripting::level->chunks->get(x, y, z);
auto def = scripting::indices->getBlockDef(vox->id);
return lua::pushivec3(L, scripting::level->chunks->seekOrigin({x, y, z}, def, vox->state));
}
static int l_set(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -76,7 +114,7 @@ int l_set_block(lua_State* L) {
return 0;
}
int l_get_block(lua_State* L) {
static int l_get(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -86,7 +124,7 @@ int l_get_block(lua_State* L) {
return 1;
}
int l_get_block_x(lua_State* L) {
static int l_get_x(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -103,7 +141,7 @@ int l_get_block_x(lua_State* L) {
}
}
int l_get_block_y(lua_State* L) {
static int l_get_y(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -120,7 +158,7 @@ int l_get_block_y(lua_State* L) {
}
}
int l_get_block_z(lua_State* L) {
static int l_get_z(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -137,7 +175,7 @@ int l_get_block_z(lua_State* L) {
}
}
int l_get_block_rotation(lua_State* L) {
static int l_get_rotation(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -147,21 +185,16 @@ int l_get_block_rotation(lua_State* L) {
return 1;
}
int l_set_block_rotation(lua_State* L) {
static int l_set_rotation(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
lua_Integer value = lua_tointeger(L, 4);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return 0;
}
vox->state.rotation = value;
scripting::level->chunks->getChunkByVoxel(x, y, z)->setModifiedAndUnsaved();
scripting::level->chunks->setRotation(x, y, z, value);
return 0;
}
int l_get_block_states(lua_State* L) {
static int l_get_states(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -171,7 +204,7 @@ int l_get_block_states(lua_State* L) {
return 1;
}
int l_set_block_states(lua_State* L) {
static int l_set_states(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -187,7 +220,7 @@ int l_set_block_states(lua_State* L) {
return 0;
}
int l_get_block_user_bits(lua_State* L) {
static int l_get_user_bits(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -205,7 +238,7 @@ int l_get_block_user_bits(lua_State* L) {
return 1;
}
int l_set_block_user_bits(lua_State* L) {
static int l_set_user_bits(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -228,7 +261,7 @@ int l_set_block_user_bits(lua_State* L) {
return 0;
}
int l_is_replaceable_at(lua_State* L) {
static int l_is_replaceable_at(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3);
@@ -237,35 +270,36 @@ int l_is_replaceable_at(lua_State* L) {
return 1;
}
int l_block_caption(lua_State* L) {
auto indices = scripting::content->getIndices();
lua_Integer id = lua_tointeger(L, 1);
if (static_cast<size_t>(id) >= indices->countBlockDefs()) {
return 0;
static int l_caption(lua_State* L) {
if (auto def = require_block(L)) {
lua_pushstring(L, def->caption.c_str());
return 1;
}
auto def = indices->getBlockDef(id);
lua_pushstring(L, def->caption.c_str());
return 1;
return 0;
}
const luaL_Reg blocklib [] = {
{"index", lua_wrap_errors<l_block_index>},
{"name", lua_wrap_errors<l_block_name>},
{"material", lua_wrap_errors<l_block_material>},
{"caption", lua_wrap_errors<l_block_caption>},
{"defs_count", lua_wrap_errors<l_blocks_count>},
{"index", lua_wrap_errors<l_index>},
{"name", lua_wrap_errors<l_name>},
{"material", lua_wrap_errors<l_material>},
{"caption", lua_wrap_errors<l_caption>},
{"defs_count", lua_wrap_errors<l_count>},
{"is_solid_at", lua_wrap_errors<l_is_solid_at>},
{"is_replaceable_at", lua_wrap_errors<l_is_replaceable_at>},
{"set", lua_wrap_errors<l_set_block>},
{"get", lua_wrap_errors<l_get_block>},
{"get_X", lua_wrap_errors<l_get_block_x>},
{"get_Y", lua_wrap_errors<l_get_block_y>},
{"get_Z", lua_wrap_errors<l_get_block_z>},
{"get_states", lua_wrap_errors<l_get_block_states>},
{"set_states", lua_wrap_errors<l_set_block_states>},
{"get_rotation", lua_wrap_errors<l_get_block_rotation>},
{"set_rotation", lua_wrap_errors<l_set_block_rotation>},
{"get_user_bits", lua_wrap_errors<l_get_block_user_bits>},
{"set_user_bits", lua_wrap_errors<l_set_block_user_bits>},
{"set", lua_wrap_errors<l_set>},
{"get", lua_wrap_errors<l_get>},
{"get_X", lua_wrap_errors<l_get_x>},
{"get_Y", lua_wrap_errors<l_get_y>},
{"get_Z", lua_wrap_errors<l_get_z>},
{"get_states", lua_wrap_errors<l_get_states>},
{"set_states", lua_wrap_errors<l_set_states>},
{"get_rotation", lua_wrap_errors<l_get_rotation>},
{"set_rotation", lua_wrap_errors<l_set_rotation>},
{"get_user_bits", lua_wrap_errors<l_get_user_bits>},
{"set_user_bits", lua_wrap_errors<l_set_user_bits>},
{"is_extended", lua_wrap_errors<l_is_extended>},
{"get_size", lua_wrap_errors<l_get_size>},
{"is_segment", lua_wrap_errors<l_is_segment>},
{"seek_origin", lua_wrap_errors<l_seek_origin>},
{NULL, NULL}
};
+2 -2
View File
@@ -134,10 +134,10 @@ static int l_player_set_noclip(lua_State* L) {
static int l_player_get_selected_block(lua_State* L) {
if (auto player = get_player(L, 1)) {
if (player->selectedVoxel.id == BLOCK_VOID) {
if (player->selection.vox.id == BLOCK_VOID) {
return 0;
}
const glm::ivec3 pos = player->selectedBlockPosition;
const glm::ivec3 pos = player->selection.position;
lua_pushinteger(L, pos.x);
lua_pushinteger(L, pos.y);
lua_pushinteger(L, pos.z);
+7
View File
@@ -21,6 +21,13 @@ namespace lua {
return 3;
}
inline int pushivec3(lua_State* L, glm::ivec3 vec) {
lua_pushinteger(L, vec.x);
lua_pushinteger(L, vec.y);
lua_pushinteger(L, vec.z);
return 3;
}
inline int pushvec3(lua_State* L, glm::vec3 vec) {
lua_pushnumber(L, vec.x);
lua_pushnumber(L, vec.y);
+3 -3
View File
@@ -192,10 +192,10 @@ void scripting::on_block_broken(Player* player, const Block* block, int x, int y
});
}
bool scripting::on_block_interact(Player* player, const Block* block, int x, int y, int z) {
bool scripting::on_block_interact(Player* player, const Block* block, glm::ivec3 pos) {
std::string name = block->name + ".interact";
return state->emit_event(name, [x, y, z, player] (lua::LuaState* state) {
state->pushivec3(x, y, z);
return state->emit_event(name, [pos, player] (lua::LuaState* state) {
state->pushivec3(pos.x, pos.y, pos.z);
state->pushinteger(player->getId());
return 4;
});
+1 -1
View File
@@ -58,7 +58,7 @@ namespace scripting {
void random_update_block(const Block* block, int x, int y, int z);
void on_block_placed(Player* player, const Block* block, int x, int y, int z);
void on_block_broken(Player* player, const Block* block, int x, int y, int z);
bool on_block_interact(Player* player, const Block* block, int x, int y, int z);
bool on_block_interact(Player* player, const Block* block, glm::ivec3 pos);
/// @brief Called on RMB click with the item selected
/// @return true if prevents default action