refactor: PlayerController
This commit is contained in:
parent
b3ae8484a2
commit
4e696520b6
@ -11,5 +11,7 @@
|
|||||||
"light-passing": true,
|
"light-passing": true,
|
||||||
"sky-light-passing": true,
|
"sky-light-passing": true,
|
||||||
"size": [1, 2, 1],
|
"size": [1, 2, 1],
|
||||||
"rotation": "pipe"
|
"rotation": "pipe",
|
||||||
|
"model": "aabb",
|
||||||
|
"hitbox": [0.0, 0.0, 0.8, 1.0, 2.0, 0.2]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,16 +137,14 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat
|
|||||||
def.model = BlockModel::custom;
|
def.model = BlockModel::custom;
|
||||||
if (root->has("model-primitives")) {
|
if (root->has("model-primitives")) {
|
||||||
loadCustomBlockModel(def, root->map("model-primitives"));
|
loadCustomBlockModel(def, root->map("model-primitives"));
|
||||||
}
|
} else {
|
||||||
else {
|
logger.error() << name << ": no 'model-primitives' found";
|
||||||
std::cerr << "ERROR occured while block "
|
|
||||||
<< name << " parsed: no \"model-primitives\" found" << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (model == "X") def.model = BlockModel::xsprite;
|
else if (model == "X") def.model = BlockModel::xsprite;
|
||||||
else if (model == "none") def.model = BlockModel::none;
|
else if (model == "none") def.model = BlockModel::none;
|
||||||
else {
|
else {
|
||||||
std::cerr << "unknown model " << model << std::endl;
|
logger.error() << "unknown model " << model;
|
||||||
def.model = BlockModel::none;
|
def.model = BlockModel::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,12 +154,12 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat
|
|||||||
std::string profile = "none";
|
std::string profile = "none";
|
||||||
root->str("rotation", profile);
|
root->str("rotation", profile);
|
||||||
def.rotatable = profile != "none";
|
def.rotatable = profile != "none";
|
||||||
if (profile == "pipe") {
|
if (profile == BlockRotProfile::PIPE_NAME) {
|
||||||
def.rotations = BlockRotProfile::PIPE;
|
def.rotations = BlockRotProfile::PIPE;
|
||||||
} else if (profile == "pane") {
|
} else if (profile == BlockRotProfile::PANE_NAME) {
|
||||||
def.rotations = BlockRotProfile::PANE;
|
def.rotations = BlockRotProfile::PANE;
|
||||||
} else if (profile != "none") {
|
} else if (profile != "none") {
|
||||||
std::cerr << "unknown rotation profile " << profile << std::endl;
|
logger.error() << "unknown rotation profile " << profile;
|
||||||
def.rotatable = false;
|
def.rotatable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +185,6 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat
|
|||||||
def.hitboxes = { AABB() };
|
def.hitboxes = { AABB() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// block light emission [r, g, b] where r,g,b in range [0..15]
|
// block light emission [r, g, b] where r,g,b in range [0..15]
|
||||||
if (auto emissionarr = root->list("emission")) {
|
if (auto emissionarr = root->list("emission")) {
|
||||||
def.emission[0] = emissionarr->num(0);
|
def.emission[0] = emissionarr->num(0);
|
||||||
@ -288,7 +285,7 @@ void ContentLoader::loadItem(ItemDef& def, const std::string& name, const fs::pa
|
|||||||
} else if (iconTypeStr == "sprite") {
|
} else if (iconTypeStr == "sprite") {
|
||||||
def.iconType = item_icon_type::sprite;
|
def.iconType = item_icon_type::sprite;
|
||||||
} else if (iconTypeStr.length()){
|
} else if (iconTypeStr.length()){
|
||||||
std::cerr << "unknown icon type" << iconTypeStr << std::endl;
|
logger.error() << name << ": unknown icon type" << iconTypeStr;
|
||||||
}
|
}
|
||||||
root->str("icon", def.icon);
|
root->str("icon", def.icon);
|
||||||
root->str("placing-block", def.placingBlock);
|
root->str("placing-block", def.placingBlock);
|
||||||
|
|||||||
@ -31,13 +31,6 @@ static std::shared_ptr<Label> create_label(wstringsupplier supplier) {
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t T>
|
|
||||||
inline std::wstring to_string(std::bitset<T> bs) {
|
|
||||||
std::wstringstream ss;
|
|
||||||
ss << bs;
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<UINode> create_debug_panel(
|
std::shared_ptr<UINode> create_debug_panel(
|
||||||
Engine* engine,
|
Engine* engine,
|
||||||
Level* level,
|
Level* level,
|
||||||
@ -82,37 +75,26 @@ std::shared_ptr<UINode> create_debug_panel(
|
|||||||
L" visible: "+std::to_wstring(level->chunks->visible);
|
L" visible: "+std::to_wstring(level->chunks->visible);
|
||||||
}));
|
}));
|
||||||
panel->add(create_label([=](){
|
panel->add(create_label([=](){
|
||||||
|
const auto& vox = player->selection.vox;
|
||||||
std::wstringstream stream;
|
std::wstringstream stream;
|
||||||
stream << "r:" << player->selectedVoxel.state.rotation << " s:"
|
stream << "r:" << vox.state.rotation << " s:"
|
||||||
<< std::bitset<3>(player->selectedVoxel.state.segment) << " u:"
|
<< std::bitset<3>(vox.state.segment) << " u:"
|
||||||
<< std::bitset<8>(player->selectedVoxel.state.userbits);
|
<< std::bitset<8>(vox.state.userbits);
|
||||||
if (player->selectedVoxel.id == BLOCK_VOID) {
|
if (vox.id == BLOCK_VOID) {
|
||||||
return std::wstring {L"block: -"};
|
return std::wstring {L"block: -"};
|
||||||
} else {
|
} else {
|
||||||
return L"block: "+std::to_wstring(player->selectedVoxel.id)+
|
return L"block: "+std::to_wstring(vox.id)+
|
||||||
L" "+stream.str();
|
L" "+stream.str();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
panel->add(create_label([=](){
|
panel->add(create_label([=](){
|
||||||
auto* indices = level->content->getIndices();
|
auto* indices = level->content->getIndices();
|
||||||
if (auto def = indices->getBlockDef(player->selectedVoxel.id)) {
|
if (auto def = indices->getBlockDef(player->selection.vox.id)) {
|
||||||
return L"name: " + util::str2wstr_utf8(def->name);
|
return L"name: " + util::str2wstr_utf8(def->name);
|
||||||
} else {
|
} else {
|
||||||
return std::wstring {L"name: void"};
|
return std::wstring {L"name: void"};
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
panel->add(create_label([=](){
|
|
||||||
auto* indices = level->content->getIndices();
|
|
||||||
if (auto def = indices->getBlockDef(player->selectedVoxel.id)) {
|
|
||||||
return L"light: " + to_string(std::bitset<16>(level->chunks->getLight(
|
|
||||||
player->actualSelectedBlockPosition.x,
|
|
||||||
player->actualSelectedBlockPosition.y,
|
|
||||||
player->actualSelectedBlockPosition.z
|
|
||||||
)));
|
|
||||||
} else {
|
|
||||||
return std::wstring {L"no light: -"};
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
panel->add(create_label([=](){
|
panel->add(create_label([=](){
|
||||||
return L"seed: "+std::to_wstring(level->getWorld()->getSeed());
|
return L"seed: "+std::to_wstring(level->getWorld()->getSeed());
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -195,15 +195,16 @@ void WorldRenderer::renderLevel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WorldRenderer::renderBlockSelection(Camera* camera, Shader* linesShader) {
|
void WorldRenderer::renderBlockSelection(Camera* camera, Shader* linesShader) {
|
||||||
|
const auto& selection = player->selection;
|
||||||
auto indices = level->content->getIndices();
|
auto indices = level->content->getIndices();
|
||||||
blockid_t id = PlayerController::selectedBlockId;
|
blockid_t id = selection.vox.id;
|
||||||
auto block = indices->getBlockDef(id);
|
auto block = indices->getBlockDef(id);
|
||||||
const glm::ivec3 pos = player->selectedBlockPosition;
|
const glm::ivec3 pos = player->selection.position;
|
||||||
const glm::vec3 point = PlayerController::selectedPointPosition;
|
const glm::vec3 point = selection.hitPosition;
|
||||||
const glm::vec3 norm = PlayerController::selectedBlockNormal;
|
const glm::vec3 norm = selection.normal;
|
||||||
|
|
||||||
const std::vector<AABB>& hitboxes = block->rotatable
|
const std::vector<AABB>& hitboxes = block->rotatable
|
||||||
? block->rt.hitboxes[PlayerController::selectedBlockRotation]
|
? block->rt.hitboxes[selection.vox.state.rotation]
|
||||||
: block->hitboxes;
|
: block->hitboxes;
|
||||||
|
|
||||||
linesShader->use();
|
linesShader->use();
|
||||||
@ -305,7 +306,7 @@ void WorldRenderer::draw(
|
|||||||
ctx.setCullFace(true);
|
ctx.setCullFace(true);
|
||||||
renderLevel(ctx, camera, settings);
|
renderLevel(ctx, camera, settings);
|
||||||
// Selected block
|
// Selected block
|
||||||
if (PlayerController::selectedBlockId != -1 && hudVisible){
|
if (player->selection.vox.id != BLOCK_VOID && hudVisible){
|
||||||
renderBlockSelection(camera, linesShader);
|
renderBlockSelection(camera, linesShader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -168,11 +168,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(
|
PlayerController::PlayerController(
|
||||||
Level* level,
|
Level* level,
|
||||||
const EngineSettings& settings,
|
const EngineSettings& settings,
|
||||||
@ -250,8 +245,8 @@ void PlayerController::update(float delta, bool input, bool pause) {
|
|||||||
if (input) {
|
if (input) {
|
||||||
updateInteraction();
|
updateInteraction();
|
||||||
} else {
|
} else {
|
||||||
selectedBlockId = -1;
|
player->selection.vox.id = BLOCK_VOID;
|
||||||
selectedBlockRotation = 0;
|
player->selection.vox.state.rotation = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,25 +329,11 @@ static void pick_block(ContentIndices* indices, Chunks* chunks, Player* player,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor this nesting nest
|
voxel* PlayerController::updateSelection(float maxDistance) {
|
||||||
void PlayerController::updateInteraction(){
|
|
||||||
auto indices = level->content->getIndices();
|
auto indices = level->content->getIndices();
|
||||||
Chunks* chunks = level->chunks.get();
|
auto chunks = level->chunks.get();
|
||||||
Lighting* lighting = level->lighting.get();
|
auto camera = player->camera.get();
|
||||||
Camera* camera = player->camera.get();
|
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 = 10.0f;
|
|
||||||
if (xkey) {
|
|
||||||
maxDistance *= 20.0f;
|
|
||||||
}
|
|
||||||
auto inventory = player->getInventory();
|
|
||||||
const ItemStack& stack = inventory->getSlot(player->getChosenSlot());
|
|
||||||
ItemDef* item = indices->getItemDef(stack.getItemId());
|
|
||||||
|
|
||||||
glm::vec3 end;
|
glm::vec3 end;
|
||||||
glm::ivec3 iend;
|
glm::ivec3 iend;
|
||||||
@ -363,46 +344,113 @@ void PlayerController::updateInteraction(){
|
|||||||
maxDistance,
|
maxDistance,
|
||||||
end, norm, iend
|
end, norm, iend
|
||||||
);
|
);
|
||||||
if (vox != nullptr) {
|
if (vox == nullptr) {
|
||||||
|
selection.vox = {BLOCK_VOID, {}};
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
blockstate selectedState = vox->state;
|
blockstate selectedState = vox->state;
|
||||||
player->selectedVoxel = *vox;
|
selection.vox = *vox;
|
||||||
selectedBlockId = vox->id;
|
selection.actualPosition = iend;
|
||||||
selectedBlockRotation = vox->state.rotation;
|
|
||||||
player->actualSelectedBlockPosition = iend;
|
|
||||||
if (selectedState.segment) {
|
if (selectedState.segment) {
|
||||||
iend = chunks->seekOrigin(
|
iend = chunks->seekOrigin(
|
||||||
iend, indices->getBlockDef(selectedBlockId), selectedState
|
iend, indices->getBlockDef(selection.vox.id), selectedState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
player->selectedBlockPosition = iend;
|
selection.position = iend;
|
||||||
selectedPointPosition = end;
|
selection.hitPosition = end;
|
||||||
selectedBlockNormal = norm;
|
selection.normal = norm;
|
||||||
int x = iend.x;
|
return vox;
|
||||||
int y = iend.y;
|
}
|
||||||
int z = iend.z;
|
|
||||||
|
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();
|
||||||
|
|
||||||
Block* def = indices->getBlockDef(item->rt.placingBlock);
|
|
||||||
blockstate state {};
|
blockstate state {};
|
||||||
state.rotation = determine_rotation(def, norm, camera->dir);
|
state.rotation = determine_rotation(def, selection.normal, camera->dir);
|
||||||
|
|
||||||
if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) {
|
if (!input.shift && target->rt.funcsset.oninteract) {
|
||||||
if (scripting::on_item_break_block(player.get(), item, x, y, z)) {
|
if (scripting::on_block_interact(player.get(), target, selection.position)) {
|
||||||
return;
|
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;
|
||||||
|
|
||||||
Block* target = indices->getBlockDef(vox->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) {
|
||||||
|
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){
|
if (lclick && target->breakable){
|
||||||
onBlockInteraction(
|
onBlockInteraction(
|
||||||
glm::ivec3(x, y, z), target,
|
iend, target,
|
||||||
BlockInteraction::destruction
|
BlockInteraction::destruction
|
||||||
);
|
);
|
||||||
blocksController->breakBlock(player.get(), target, x, y, z);
|
blocksController->breakBlock(player.get(), target, iend.x, iend.y, iend.z);
|
||||||
}
|
}
|
||||||
if (rclick && !input.shift) {
|
if (rclick && !input.shift) {
|
||||||
bool preventDefault = false;
|
bool preventDefault = false;
|
||||||
if (item->rt.funcsset.on_use_on_block) {
|
if (item->rt.funcsset.on_use_on_block) {
|
||||||
preventDefault = scripting::on_item_use_on_block(player.get(), item, x, y, z);
|
preventDefault = scripting::on_item_use_on_block(
|
||||||
|
player.get(), item, iend.x, iend.y, iend.z
|
||||||
|
);
|
||||||
} else if (item->rt.funcsset.on_use) {
|
} else if (item->rt.funcsset.on_use) {
|
||||||
preventDefault = scripting::on_item_use(player.get(), item);
|
preventDefault = scripting::on_item_use(player.get(), item);
|
||||||
}
|
}
|
||||||
@ -410,57 +458,13 @@ void PlayerController::updateInteraction(){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
auto def = indices->getBlockDef(item->rt.placingBlock);
|
||||||
if (def && rclick) {
|
if (def && rclick) {
|
||||||
iend = player->actualSelectedBlockPosition;
|
processRightClick(def, target);
|
||||||
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;
|
|
||||||
x = iend.x;
|
|
||||||
y = iend.y;
|
|
||||||
z = iend.z;
|
|
||||||
}
|
|
||||||
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)) {
|
if (Events::jactive(BIND_PLAYER_PICK)) {
|
||||||
pick_block(indices, chunks, player.get(), x, y, z);
|
auto coord = selection.actualPosition;
|
||||||
}
|
pick_block(indices, chunks, player.get(), coord.x, coord.y, coord.z);
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -76,12 +76,10 @@ class PlayerController {
|
|||||||
float stepsTimer = 0.0f;
|
float stepsTimer = 0.0f;
|
||||||
void onFootstep();
|
void onFootstep();
|
||||||
void updateFootsteps(float delta);
|
void updateFootsteps(float delta);
|
||||||
public:
|
void processRightClick(Block* def, Block* target);
|
||||||
static glm::ivec3 selectedBlockNormal;
|
|
||||||
static glm::vec3 selectedPointPosition;
|
|
||||||
static int selectedBlockId;
|
|
||||||
static int selectedBlockRotation;
|
|
||||||
|
|
||||||
|
voxel* updateSelection(float maxDistance);
|
||||||
|
public:
|
||||||
PlayerController(
|
PlayerController(
|
||||||
Level* level,
|
Level* level,
|
||||||
const EngineSettings& settings,
|
const EngineSettings& settings,
|
||||||
|
|||||||
@ -134,10 +134,10 @@ static int l_player_set_noclip(lua_State* L) {
|
|||||||
|
|
||||||
static int l_player_get_selected_block(lua_State* L) {
|
static int l_player_get_selected_block(lua_State* L) {
|
||||||
if (auto player = get_player(L, 1)) {
|
if (auto player = get_player(L, 1)) {
|
||||||
if (player->selectedVoxel.id == BLOCK_VOID) {
|
if (player->selection.vox.id == BLOCK_VOID) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const glm::ivec3 pos = player->selectedBlockPosition;
|
const glm::ivec3 pos = player->selection.position;
|
||||||
lua_pushinteger(L, pos.x);
|
lua_pushinteger(L, pos.x);
|
||||||
lua_pushinteger(L, pos.y);
|
lua_pushinteger(L, pos.y);
|
||||||
lua_pushinteger(L, pos.z);
|
lua_pushinteger(L, pos.z);
|
||||||
|
|||||||
@ -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";
|
std::string name = block->name + ".interact";
|
||||||
return state->emit_event(name, [x, y, z, player] (lua::LuaState* state) {
|
return state->emit_event(name, [pos, player] (lua::LuaState* state) {
|
||||||
state->pushivec3(x, y, z);
|
state->pushivec3(pos.x, pos.y, pos.z);
|
||||||
state->pushinteger(player->getId());
|
state->pushinteger(player->getId());
|
||||||
return 4;
|
return 4;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -58,7 +58,7 @@ namespace scripting {
|
|||||||
void random_update_block(const Block* block, int x, int y, int z);
|
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_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);
|
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
|
/// @brief Called on RMB click with the item selected
|
||||||
/// @return true if prevents default action
|
/// @return true if prevents default action
|
||||||
|
|||||||
@ -32,6 +32,14 @@ struct PlayerInput {
|
|||||||
bool flight : 1;
|
bool flight : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BlockSelection {
|
||||||
|
voxel vox {0, {}};
|
||||||
|
glm::ivec3 position {};
|
||||||
|
glm::ivec3 actualPosition {};
|
||||||
|
glm::ivec3 normal {};
|
||||||
|
glm::vec3 hitPosition;
|
||||||
|
};
|
||||||
|
|
||||||
class Player : public Object, public Serializable {
|
class Player : public Object, public Serializable {
|
||||||
float speed;
|
float speed;
|
||||||
int chosenSlot;
|
int chosenSlot;
|
||||||
@ -44,10 +52,8 @@ public:
|
|||||||
std::shared_ptr<Camera> currentCamera;
|
std::shared_ptr<Camera> currentCamera;
|
||||||
std::unique_ptr<Hitbox> hitbox;
|
std::unique_ptr<Hitbox> hitbox;
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
voxel selectedVoxel {0, {}};
|
|
||||||
glm::vec3 cam {};
|
glm::vec3 cam {};
|
||||||
glm::ivec3 selectedBlockPosition {};
|
BlockSelection selection {};
|
||||||
glm::ivec3 actualSelectedBlockPosition {};
|
|
||||||
|
|
||||||
Player(glm::vec3 position, float speed, std::shared_ptr<Inventory> inv);
|
Player(glm::vec3 position, float speed, std::shared_ptr<Inventory> inv);
|
||||||
~Player();
|
~Player();
|
||||||
|
|||||||
@ -62,6 +62,9 @@ struct BlockRotProfile {
|
|||||||
|
|
||||||
/// @brief Doors, signs and other panes
|
/// @brief Doors, signs and other panes
|
||||||
static const BlockRotProfile PANE;
|
static const BlockRotProfile PANE;
|
||||||
|
|
||||||
|
static inline std::string PIPE_NAME = "pipe";
|
||||||
|
static inline std::string PANE_NAME = "pane";
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class BlockModel {
|
enum class BlockModel {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ Chunks::Chunks(
|
|||||||
WorldFiles* wfile,
|
WorldFiles* wfile,
|
||||||
LevelEvents* events,
|
LevelEvents* events,
|
||||||
const Content* content
|
const Content* content
|
||||||
) : contentIds(content->getIndices()),
|
) : indices(content->getIndices()),
|
||||||
chunks(w*d),
|
chunks(w*d),
|
||||||
chunksSecond(w*d),
|
chunksSecond(w*d),
|
||||||
w(w), d(d), ox(ox), oz(oz),
|
w(w), d(d), ox(ox), oz(oz),
|
||||||
@ -65,7 +65,7 @@ const AABB* Chunks::isObstacleAt(float x, float y, float z){
|
|||||||
return ∅
|
return ∅
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const Block* def = contentIds->getBlockDef(v->id);
|
const Block* def = indices->getBlockDef(v->id);
|
||||||
if (def->obstacle) {
|
if (def->obstacle) {
|
||||||
const auto& boxes = def->rotatable
|
const auto& boxes = def->rotatable
|
||||||
? def->rt.hitboxes[v->state.rotation]
|
? def->rt.hitboxes[v->state.rotation]
|
||||||
@ -83,21 +83,21 @@ bool Chunks::isSolidBlock(int32_t x, int32_t y, int32_t z) {
|
|||||||
voxel* v = get(x, y, z);
|
voxel* v = get(x, y, z);
|
||||||
if (v == nullptr)
|
if (v == nullptr)
|
||||||
return false;
|
return false;
|
||||||
return contentIds->getBlockDef(v->id)->rt.solid;
|
return indices->getBlockDef(v->id)->rt.solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Chunks::isReplaceableBlock(int32_t x, int32_t y, int32_t z) {
|
bool Chunks::isReplaceableBlock(int32_t x, int32_t y, int32_t z) {
|
||||||
voxel* v = get(x, y, z);
|
voxel* v = get(x, y, z);
|
||||||
if (v == nullptr)
|
if (v == nullptr)
|
||||||
return false;
|
return false;
|
||||||
return contentIds->getBlockDef(v->id)->replaceable;
|
return indices->getBlockDef(v->id)->replaceable;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Chunks::isObstacleBlock(int32_t x, int32_t y, int32_t z) {
|
bool Chunks::isObstacleBlock(int32_t x, int32_t y, int32_t z) {
|
||||||
voxel* v = get(x, y, z);
|
voxel* v = get(x, y, z);
|
||||||
if (v == nullptr)
|
if (v == nullptr)
|
||||||
return false;
|
return false;
|
||||||
return contentIds->getBlockDef(v->id)->obstacle;
|
return indices->getBlockDef(v->id)->obstacle;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubyte Chunks::getLight(int32_t x, int32_t y, int32_t z, int channel){
|
ubyte Chunks::getLight(int32_t x, int32_t y, int32_t z, int channel){
|
||||||
@ -218,6 +218,33 @@ void Chunks::repairSegments(const Block* def, blockstate state, int x, int y, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Chunks::checkReplaceability(const Block* def, blockstate state, glm::ivec3 origin) {
|
||||||
|
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++) {
|
||||||
|
blockstate segState = state;
|
||||||
|
segState.segment = ((sx > 0) | ((sy > 0) << 1) | ((sz > 0) << 2));
|
||||||
|
|
||||||
|
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->getBlockDef(vox->id);
|
||||||
|
if (!target->replaceable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state) {
|
void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state) {
|
||||||
if (y < 0 || y >= CHUNK_H) {
|
if (y < 0 || y >= CHUNK_H) {
|
||||||
return;
|
return;
|
||||||
@ -240,7 +267,7 @@ void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state)
|
|||||||
|
|
||||||
// block finalization
|
// block finalization
|
||||||
voxel& vox = chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx];
|
voxel& vox = chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx];
|
||||||
auto prevdef = contentIds->getBlockDef(vox.id);
|
auto prevdef = indices->getBlockDef(vox.id);
|
||||||
if (prevdef->inventorySize == 0) {
|
if (prevdef->inventorySize == 0) {
|
||||||
chunk->removeBlockInventory(lx, y, lz);
|
chunk->removeBlockInventory(lx, y, lz);
|
||||||
}
|
}
|
||||||
@ -249,7 +276,7 @@ void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// block initialization
|
// block initialization
|
||||||
auto newdef = contentIds->getBlockDef(id);
|
auto newdef = indices->getBlockDef(id);
|
||||||
vox.id = id;
|
vox.id = id;
|
||||||
vox.state = state;
|
vox.state = state;
|
||||||
chunk->setModifiedAndUnsaved();
|
chunk->setModifiedAndUnsaved();
|
||||||
@ -318,7 +345,7 @@ voxel* Chunks::rayCast(
|
|||||||
if (voxel == nullptr){
|
if (voxel == nullptr){
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const Block* def = contentIds->getBlockDef(voxel->id);
|
const auto def = indices->getBlockDef(voxel->id);
|
||||||
if (def->selectable){
|
if (def->selectable){
|
||||||
end.x = px + t * dx;
|
end.x = px + t * dx;
|
||||||
end.y = py + t * dy;
|
end.y = py + t * dy;
|
||||||
@ -442,7 +469,7 @@ glm::vec3 Chunks::rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDis
|
|||||||
if (voxel == nullptr) {
|
if (voxel == nullptr) {
|
||||||
return glm::vec3(px + t * dx, py + t * dy, pz + t * dz);
|
return glm::vec3(px + t * dx, py + t * dy, pz + t * dz);
|
||||||
}
|
}
|
||||||
const Block* def = contentIds->getBlockDef(voxel->id);
|
const auto def = indices->getBlockDef(voxel->id);
|
||||||
if (def->obstacle) {
|
if (def->obstacle) {
|
||||||
if (!def->rt.solid) {
|
if (!def->rt.solid) {
|
||||||
const std::vector<AABB>& hitboxes = def->rotatable
|
const std::vector<AABB>& hitboxes = def->rotatable
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class Block;
|
|||||||
|
|
||||||
/* Player-centred chunks matrix */
|
/* Player-centred chunks matrix */
|
||||||
class Chunks {
|
class Chunks {
|
||||||
const ContentIndices* const contentIds;
|
const ContentIndices* const indices;
|
||||||
|
|
||||||
void eraseSegments(const Block* def, blockstate state, int x, int y, int z);
|
void eraseSegments(const Block* def, blockstate state, int x, int y, int z);
|
||||||
void repairSegments(const Block* def, blockstate state, int x, int y, int z);
|
void repairSegments(const Block* def, blockstate state, int x, int y, int z);
|
||||||
@ -40,6 +40,7 @@ public:
|
|||||||
WorldFiles* worldFiles, LevelEvents* events, const Content* content);
|
WorldFiles* worldFiles, LevelEvents* events, const Content* content);
|
||||||
~Chunks() = default;
|
~Chunks() = default;
|
||||||
|
|
||||||
|
bool checkReplaceability(const Block* def, blockstate state, glm::ivec3 coord);
|
||||||
bool putChunk(const std::shared_ptr<Chunk>& chunk);
|
bool putChunk(const std::shared_ptr<Chunk>& chunk);
|
||||||
|
|
||||||
Chunk* getChunk(int32_t x, int32_t z);
|
Chunk* getChunk(int32_t x, int32_t z);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user