[BlockState] Added. First stop of block states.
This commit is contained in:
parent
0af7cd7d0e
commit
7750154b22
@ -263,6 +263,7 @@ Useful for flora, tallgrass, mushrooms, etc...
|
||||
Parameters:
|
||||
|
||||
- `pos` (`ivec3`): position of the block
|
||||
- `block` (`ServerBlock`): block definition
|
||||
- `player` (`ServerPlayer`): player that activated the block
|
||||
- `world` (`ServerWorld`): instance of the world
|
||||
- `client` (`Client`): client that activated the block
|
||||
@ -290,6 +291,7 @@ Parameters:
|
||||
Parameters:
|
||||
|
||||
- `pos` (`ivec3`): position of the block
|
||||
- `block` (`ServerBlock`): block definition
|
||||
- `chunk` (`ServerChunk`): current chunk
|
||||
- `world` (`ServerWorld`): instance of the world
|
||||
|
||||
|
@ -35,8 +35,8 @@ end)
|
||||
|
||||
Possible events:
|
||||
|
||||
- `BlockPlaced`: `funcion(pos, block, player, world, client, server)`
|
||||
- `BlockDigged`: `funcion(pos, block, player, world, client, server)`
|
||||
- `BlockPlaced`: `funcion(pos, block_state, player, world, client, server)`
|
||||
- `BlockDigged`: `funcion(pos, block_state, player, world, client, server)`
|
||||
- `BlockActivated`: `function(pos, block, player, world, client, server)`
|
||||
- `ItemActivated`: `function(pos, block, player, world, client, server)`
|
||||
- `PlayerConnected`: `function(pos, player, client, server)`
|
||||
|
@ -5,13 +5,10 @@
|
||||
## Block
|
||||
|
||||
- `u16 id()`
|
||||
- `u16 data()`
|
||||
- `string string_id()`
|
||||
- `string label()`
|
||||
- `string mod_name()`
|
||||
- `bool is_opaque()`
|
||||
- `ItemStack get_item_drop()`
|
||||
- `BlockParam param()`
|
||||
- `Block get_state()`
|
||||
|
||||
## BlockData
|
||||
|
||||
|
@ -208,7 +208,7 @@ mod:block {
|
||||
draw_type = "glass",
|
||||
is_opaque = false,
|
||||
|
||||
on_block_activated = function(pos, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
on_block_activated = function(pos, block, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
local dim = (player:dimension() + 1) % 2
|
||||
local pos = {
|
||||
x = math.floor(player:x()),
|
||||
@ -311,7 +311,7 @@ mod:block {
|
||||
name = "Redstone Lamp",
|
||||
tiles = "redstone_lamp_off.png",
|
||||
|
||||
on_block_activated = function(pos, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
on_block_activated = function(pos, block, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
local block = openminer.registry:get_block_from_string("default:redstone_lamp_on")
|
||||
world:set_block(pos.x, pos.y, pos.z, block:id())
|
||||
end
|
||||
@ -327,7 +327,7 @@ mod:block {
|
||||
ci_ignore = 1
|
||||
},
|
||||
|
||||
on_block_activated = function(pos, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
on_block_activated = function(pos, block, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
local block = openminer.registry:get_block_from_string("default:redstone_lamp_off")
|
||||
world:set_block(pos.x, pos.y, pos.z, block:id())
|
||||
end
|
||||
@ -356,11 +356,22 @@ mod:block {
|
||||
id = "seeds",
|
||||
name = "Seeds",
|
||||
tiles = "wheat_stage_0.png",
|
||||
alt_tiles = "wheat_stage_7.png",
|
||||
draw_type = "xshape",
|
||||
inventory_image = "seeds_wheat.png",
|
||||
hardness = 0,
|
||||
|
||||
bounding_box = {0, 0, 0, 1, 1, 1.0 / 16.0},
|
||||
|
||||
states = {
|
||||
[1] = { tiles = "wheat_stage_1.png", bounding_box = {0, 0, 0, 1, 1, 3.0 / 16.0}, },
|
||||
[2] = { tiles = "wheat_stage_2.png", bounding_box = {0, 0, 0, 1, 1, 5.0 / 16.0}, },
|
||||
[3] = { tiles = "wheat_stage_3.png", bounding_box = {0, 0, 0, 1, 1, 8.0 / 16.0}, },
|
||||
[4] = { tiles = "wheat_stage_4.png", bounding_box = {0, 0, 0, 1, 1, 10.0 / 16.0}, },
|
||||
[5] = { tiles = "wheat_stage_5.png", bounding_box = {0, 0, 0, 1, 1, 12.0 / 16.0}, },
|
||||
[6] = { tiles = "wheat_stage_6.png", bounding_box = {0, 0, 0, 1, 1, 14.0 / 16.0}, },
|
||||
[7] = { tiles = "wheat_stage_7.png", bounding_box = {0, 0, 0, 1, 1, 1}, },
|
||||
},
|
||||
|
||||
tick_randomly = true,
|
||||
tick_probability = 0.01,
|
||||
|
||||
@ -368,25 +379,20 @@ mod:block {
|
||||
world:add_block_data(pos.x, pos.y, pos.z, 0, 0)
|
||||
end,
|
||||
|
||||
on_tick = function(pos, chunk, world)
|
||||
local data = world:get_block_data(pos.x, pos.y, pos.z)
|
||||
if not data then return end
|
||||
|
||||
local growth_stage = data.meta:get_int("growth_stage") or 0
|
||||
if growth_stage < 7 then
|
||||
data.use_alt_tiles = true
|
||||
data.meta:set_int("growth_stage", 7)
|
||||
on_tick = function(pos, block, chunk, world)
|
||||
local block_param = world:get_block_param(pos.x, pos.y, pos.z)
|
||||
local current_state = block:param():get_param(BlockParam.State, block_param)
|
||||
if current_state < 7 then
|
||||
world:set_block_param(pos.x, pos.y, pos.z, current_state + 1)
|
||||
end
|
||||
end,
|
||||
|
||||
on_block_activated = function(pos, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
local data = world:get_block_data(pos.x, pos.y, pos.z)
|
||||
if not data then return end
|
||||
|
||||
local growth_stage = data.meta:get_int("growth_stage") or 0
|
||||
if growth_stage >= 7 then
|
||||
data.use_alt_tiles = false
|
||||
data.meta:set_int("growth_stage", 0)
|
||||
on_block_activated = function(pos, block, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
local block_param = world:get_block_param(pos.x, pos.y, pos.z)
|
||||
local current_state = block:param():get_param(BlockParam.State, block_param)
|
||||
if current_state >= 7 then
|
||||
world:set_block_param(pos.x, pos.y, pos.z,
|
||||
block:param():set_param(BlockParam.State, block_param, 0))
|
||||
|
||||
-- FIXME: It should drop the item if 'default:use_item_drops' is enabled
|
||||
local item_stack = ItemStack.new("default:wheat", 1)
|
||||
|
@ -66,7 +66,7 @@ mod:block {
|
||||
end
|
||||
end,
|
||||
|
||||
on_block_activated = function(pos, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
on_block_activated = function(pos, block, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
open_door(pos, world)
|
||||
open_door({x = pos.x, y = pos.y, z = pos.z - 1}, world)
|
||||
end
|
||||
|
@ -37,7 +37,7 @@ mod:block {
|
||||
world:add_block_data(pos.x, pos.y, pos.z, 3, 1)
|
||||
end,
|
||||
|
||||
on_block_activated = function(pos, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
on_block_activated = function(pos, block, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
local gui = LuaGUI.new()
|
||||
|
||||
gui:set_size(176, 166)
|
||||
@ -169,7 +169,7 @@ mod:block {
|
||||
gui:show(client)
|
||||
end,
|
||||
|
||||
on_tick = function(pos, chunk, world)
|
||||
on_tick = function(pos, block, chunk, world)
|
||||
local data = world:get_block_data(pos.x, pos.y, pos.z)
|
||||
if not data then return end
|
||||
|
||||
|
@ -35,7 +35,7 @@ mod:block {
|
||||
world:add_block_data(pos.x, pos.y, pos.z, 3, 3)
|
||||
end,
|
||||
|
||||
on_block_activated = function(pos, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
on_block_activated = function(pos, block, player, world, client, server, screen_width, screen_height, gui_scale)
|
||||
local gui = LuaGUI.new()
|
||||
|
||||
gui:set_size(176, 166)
|
||||
|
@ -136,11 +136,13 @@ void TextureAtlas::loadFromRegistry(const std::string &texturePack) {
|
||||
else
|
||||
path = "texturepacks/" + texturePack + "/blocks/";
|
||||
|
||||
const TilesDef &tiles = block->tiles();
|
||||
for (auto &textureFilename : tiles.textureFilenames())
|
||||
addFile(path, textureFilename);
|
||||
for (auto &textureFilename : tiles.altTextureFilenames())
|
||||
addFile(path, textureFilename);
|
||||
for (auto &state : block->states()) {
|
||||
const TilesDef &tiles = state.tiles();
|
||||
for (auto &textureFilename : tiles.textureFilenames())
|
||||
addFile(path, textureFilename);
|
||||
for (auto &textureFilename : tiles.altTextureFilenames())
|
||||
addFile(path, textureFilename);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &item : Registry::getInstance().items()) {
|
||||
|
@ -58,9 +58,11 @@ InventoryCube::InventoryCube(float size, bool isEntity)
|
||||
|
||||
using namespace BlockGeometry;
|
||||
|
||||
void InventoryCube::updateVertexBuffer(const Block &block) {
|
||||
void InventoryCube::updateVertexBuffer(const Block &block, u8 state) {
|
||||
if (!block.id()) return;
|
||||
|
||||
const BlockState &blockState = block.getState(state);
|
||||
|
||||
Vertex vertices[nFaces][nVertsPerFace];
|
||||
|
||||
glm::vec3 vertexPos[nVertsPerCube] {
|
||||
@ -75,7 +77,7 @@ void InventoryCube::updateVertexBuffer(const Block &block) {
|
||||
glm::vec3{m_size, m_size, m_size},
|
||||
};
|
||||
|
||||
const gk::FloatBox &boundingBox = block.boundingBox();
|
||||
const gk::FloatBox &boundingBox = blockState.boundingBox();
|
||||
|
||||
constexpr s8f faceValue[nFaces]{2, 2, 4, 4, 3, 3};
|
||||
|
||||
@ -86,7 +88,7 @@ void InventoryCube::updateVertexBuffer(const Block &block) {
|
||||
// U0V0 -> 3 2 <- U1V0
|
||||
// U0V1 -> 0 1 <- U1V1
|
||||
float U0, V0, U1, V1;
|
||||
if (block.drawType() == BlockDrawType::Cactus) {
|
||||
if (blockState.drawType() == BlockDrawType::Cactus) {
|
||||
U0 = 0.f;
|
||||
V0 = 0.f;
|
||||
U1 = 1.f;
|
||||
@ -101,10 +103,10 @@ void InventoryCube::updateVertexBuffer(const Block &block) {
|
||||
V1 = (f <= 3) ? 1.f - boundingBox.z : (f == 4) ? boundingBox.y + boundingBox.sizeY : 1.f - boundingBox.y;
|
||||
}
|
||||
|
||||
const gk::FloatRect &blockTexCoords = m_textureAtlas->getTexCoords(block.tiles().getTextureForFace(f));
|
||||
const gk::FloatRect &blockTexCoords = m_textureAtlas->getTexCoords(blockState.tiles().getTextureForFace(f));
|
||||
|
||||
for (u8f v = 0; v < nVertsPerFace; ++v) {
|
||||
if (block.drawType() == BlockDrawType::Cactus) {
|
||||
if (blockState.drawType() == BlockDrawType::Cactus) {
|
||||
vertices[f][v].coord3d[0] = vertexPos[cubeVerts[f][v]].x - boundingBox.x * faceNormals[f][0] * m_size;
|
||||
vertices[f][v].coord3d[1] = vertexPos[cubeVerts[f][v]].y - boundingBox.y * faceNormals[f][1] * m_size;
|
||||
vertices[f][v].coord3d[2] = vertexPos[cubeVerts[f][v]].z - boundingBox.z * faceNormals[f][2] * m_size;
|
||||
@ -121,7 +123,7 @@ void InventoryCube::updateVertexBuffer(const Block &block) {
|
||||
vertices[f][v].texCoord[0] = gk::qlerp(blockTexCoords.x, blockTexCoords.x + blockTexCoords.sizeX, U);
|
||||
vertices[f][v].texCoord[1] = gk::qlerp(blockTexCoords.y, blockTexCoords.y + blockTexCoords.sizeY, V);
|
||||
|
||||
const gk::Color &colorMultiplier = block.colorMultiplier();
|
||||
const gk::Color &colorMultiplier = blockState.colorMultiplier();
|
||||
vertices[f][v].color[0] = colorMultiplier.r;
|
||||
vertices[f][v].color[1] = colorMultiplier.g;
|
||||
vertices[f][v].color[2] = colorMultiplier.b;
|
||||
|
@ -38,7 +38,7 @@ class InventoryCube : public gk::Drawable, public gk::Transformable {
|
||||
public:
|
||||
InventoryCube(float size = 1.0f, bool isEntity = false);
|
||||
|
||||
void updateVertexBuffer(const Block &block);
|
||||
void updateVertexBuffer(const Block &block, u8 state = 0);
|
||||
|
||||
float size() const { return m_size; }
|
||||
|
||||
|
@ -42,12 +42,13 @@ ItemWidget::ItemWidget(Inventory &inventory, u16 x, u16 y, Widget *parent)
|
||||
void ItemWidget::update() {
|
||||
if (stack().item().isBlock()) {
|
||||
const Block &block = Registry::getInstance().getBlock(stack().item().id());
|
||||
if (block.drawType() != BlockDrawType::XShape && block.inventoryImage().empty()) {
|
||||
const BlockState &blockState = block.getState(0); // FIXME: Get state from item stack
|
||||
if (blockState.drawType() != BlockDrawType::XShape && blockState.inventoryImage().empty()) {
|
||||
m_cube.updateVertexBuffer(block);
|
||||
m_isImage = false;
|
||||
}
|
||||
else
|
||||
updateImage(&block);
|
||||
updateImage(&blockState);
|
||||
}
|
||||
else
|
||||
updateImage();
|
||||
@ -56,7 +57,7 @@ void ItemWidget::update() {
|
||||
m_text.setPosition(16 - 4 - 6 * floor(log10(stack().amount())), 16 - 6, 0);
|
||||
}
|
||||
|
||||
void ItemWidget::updateImage(const Block *block) {
|
||||
void ItemWidget::updateImage(const BlockState *blockState) {
|
||||
if (m_image.width() == 0) {
|
||||
m_image.load(m_textureAtlas.texture());
|
||||
m_image.setPosition(1, 1, 0);
|
||||
@ -67,8 +68,8 @@ void ItemWidget::updateImage(const Block *block) {
|
||||
m_image.setClipRect(clipRect.x, clipRect.y, clipRect.sizeX, clipRect.sizeY);
|
||||
m_image.setScale(16.0f / clipRect.sizeX, 16.0f / clipRect.sizeY);
|
||||
|
||||
if (block)
|
||||
m_image.setColor(block->colorMultiplier());
|
||||
if (blockState)
|
||||
m_image.setColor(blockState->colorMultiplier());
|
||||
|
||||
m_isImage = true;
|
||||
}
|
||||
|
@ -34,12 +34,14 @@
|
||||
#include "Text.hpp"
|
||||
#include "Widget.hpp"
|
||||
|
||||
class BlockState;
|
||||
|
||||
class ItemWidget : public Widget {
|
||||
public:
|
||||
ItemWidget(Inventory &inventory, u16 x, u16 y, Widget *parent = nullptr);
|
||||
|
||||
void update() override;
|
||||
void updateImage(const Block *block = nullptr);
|
||||
void updateImage(const BlockState *blockState = nullptr);
|
||||
|
||||
const ItemStack &stack() const { return m_inventory.getStack(m_x, m_y); }
|
||||
void setStack(const std::string &name, unsigned int amount = 1);
|
||||
|
@ -95,12 +95,14 @@ void BlockCursor::onEvent(const SDL_Event &event, const Hotbar &hotbar) {
|
||||
if (face == 5) --z;
|
||||
|
||||
// First, we check if the new block is not replacing another block
|
||||
u32 blockId = m_world.getBlock(x, y, z);
|
||||
const Block &block = Registry::getInstance().getBlock(blockId);
|
||||
if (!blockId || block.drawType() == BlockDrawType::Liquid) {
|
||||
// u32 blockId = m_world.getBlock(x, y, z);
|
||||
// const Block &block = Registry::getInstance().getBlock(blockId);
|
||||
const BlockState *blockState = m_world.getBlockState(x, y, z);
|
||||
if (blockState && (!blockState->block().id() || blockState->drawType() == BlockDrawType::Liquid)) {
|
||||
// Second, we check if the new block is not inside the player
|
||||
const Block &newBlock = Registry::getInstance().getBlock(hotbar.currentItem().id());
|
||||
gk::FloatBox boundingBox = newBlock.boundingBox() + gk::Vector3f(x - m_player.x(), y - m_player.y(), z - m_player.z());
|
||||
const BlockState &newBlockState = newBlock.getState(0); // FIXME: Get state from item stack
|
||||
gk::FloatBox boundingBox = newBlockState.boundingBox() + gk::Vector3f(x - m_player.x(), y - m_player.y(), z - m_player.z());
|
||||
gk::FloatBox playerBoundingBox = m_player.hitbox();
|
||||
if (!boundingBox.intersects(playerBoundingBox)) {
|
||||
u32 block = hotbar.currentItem().id();
|
||||
@ -137,12 +139,14 @@ void BlockCursor::update(const Hotbar &hotbar) {
|
||||
|
||||
m_selectedBlock = selectedBlock;
|
||||
|
||||
m_currentBlock = &Registry::getInstance().getBlock(m_world.getBlock(m_selectedBlock.x, m_selectedBlock.y, m_selectedBlock.z));
|
||||
m_currentBlock = m_world.getBlockState(m_selectedBlock.x, m_selectedBlock.y, m_selectedBlock.z);
|
||||
// if (block.boundingBox().intersects(FloatBox{m_selectedBlock.x, m_selectedBlock.y, m_selectedBlock.z, 1, 1, 1})) {
|
||||
// selectedBlockChanged = false;
|
||||
// m_selectedBlock.w = -1;
|
||||
// }
|
||||
|
||||
if (!m_currentBlock) return;
|
||||
|
||||
u32 ticks = gk::GameClock::getInstance().getTicks();
|
||||
|
||||
if (selectedBlockChanged)
|
||||
@ -167,7 +171,7 @@ void BlockCursor::update(const Hotbar &hotbar) {
|
||||
}
|
||||
}
|
||||
|
||||
u8f orientation = m_currentBlock->isRotatable() ? m_world.getData(selectedBlock.x, selectedBlock.y, selectedBlock.z) & 0x1F : 0;
|
||||
u8f orientation = m_currentBlock->block().isRotatable() ? m_world.getData(selectedBlock.x, selectedBlock.y, selectedBlock.z) & 0x1F : 0;
|
||||
|
||||
if (m_selectedBlock.w != -1)
|
||||
updateVertexBuffer(*m_currentBlock, orientation);
|
||||
@ -181,11 +185,11 @@ void BlockCursor::update(const Hotbar &hotbar) {
|
||||
|
||||
using namespace BlockGeometry;
|
||||
|
||||
void BlockCursor::updateVBOCoords(Vertex vertices[nFaces][nVertsPerFace], const Block &block,
|
||||
void BlockCursor::updateVBOCoords(Vertex vertices[nFaces][nVertsPerFace], const BlockState &blockState,
|
||||
float face, u8f orientation)
|
||||
{
|
||||
glm::vec3 bottomLeft{block.boundingBox().x, block.boundingBox().y, block.boundingBox().z};
|
||||
glm::vec3 topRight{block.boundingBox().sizeX, block.boundingBox().sizeY, block.boundingBox().sizeZ};
|
||||
glm::vec3 bottomLeft{blockState.boundingBox().x, blockState.boundingBox().y, blockState.boundingBox().z};
|
||||
glm::vec3 topRight{blockState.boundingBox().sizeX, blockState.boundingBox().sizeY, blockState.boundingBox().sizeZ};
|
||||
topRight += bottomLeft;
|
||||
|
||||
const glm::mat3 &orientMatrix = orientMatrices[orientation];
|
||||
@ -220,18 +224,18 @@ void BlockCursor::updateVBOCoords(Vertex vertices[nFaces][nVertsPerFace], const
|
||||
}
|
||||
}
|
||||
|
||||
void BlockCursor::updateVertexBuffer(const Block &block, u8f orientation) {
|
||||
void BlockCursor::updateVertexBuffer(const BlockState &blockState, u8f orientation) {
|
||||
Vertex vertices[nFaces][nVertsPerFace];
|
||||
updateVBOCoords(vertices, block, -1, orientation);
|
||||
updateVBOCoords(vertices, blockState, -1, orientation);
|
||||
|
||||
gk::VertexBuffer::bind(&m_vbo);
|
||||
m_vbo.setData(sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
gk::VertexBuffer::bind(nullptr);
|
||||
}
|
||||
|
||||
void BlockCursor::updateAnimationVertexBuffer(const Block &block, u8f orientation, int animationPos) {
|
||||
void BlockCursor::updateAnimationVertexBuffer(const BlockState &blockState, u8f orientation, int animationPos) {
|
||||
Vertex vertices[nFaces][nVertsPerFace];
|
||||
updateVBOCoords(vertices, block, -2, orientation);
|
||||
updateVBOCoords(vertices, blockState, -2, orientation);
|
||||
|
||||
GLfloat color[4] = {1, 1, 1, 0.5};
|
||||
for (u8f f = 0; f < nFaces; ++f)
|
||||
@ -301,9 +305,8 @@ glm::ivec4 BlockCursor::findSelectedBlock() const {
|
||||
s32f bestZ = s32f(floor(position.z));
|
||||
|
||||
// Deal with a degenerate case: camera in the middle of a block
|
||||
u32f blockID = m_world.getBlock(bestX, bestY, bestZ);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
if (blockID && block.drawType() != BlockDrawType::Liquid) {
|
||||
const BlockState *blockState = m_world.getBlockState(bestX, bestY, bestZ);
|
||||
if (blockState && blockState->block().id() && blockState->drawType() != BlockDrawType::Liquid) {
|
||||
// We're inside a node, therefore there's no face, but we still need
|
||||
// to return a valid block. We use face 6 for that. For rightclicks,
|
||||
// it should attempt to place the block on the same node clicked, and
|
||||
@ -320,9 +323,8 @@ glm::ivec4 BlockCursor::findSelectedBlock() const {
|
||||
if (double(bestX) == position.x && double(bestY) == position.y) {
|
||||
for (int y = -1; y <= 0; y++) {
|
||||
for (int x = -1; x <= 0; x++) {
|
||||
blockID = m_world.getBlock(bestX + x, bestY + y, bestZ);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
if (blockID && block.drawType() != BlockDrawType::Liquid) {
|
||||
const BlockState *blockState = m_world.getBlockState(bestX, bestY, bestZ);
|
||||
if (blockState && blockState->block().id() && blockState->drawType() != BlockDrawType::Liquid) {
|
||||
return glm::ivec4{bestX + x, bestY + y, bestZ, 6};
|
||||
}
|
||||
}
|
||||
|
@ -45,13 +45,13 @@ class BlockCursor : public gk::Drawable {
|
||||
|
||||
void update(const Hotbar &hotbar);
|
||||
|
||||
const Block *currentBlock() const { return m_currentBlock; }
|
||||
const BlockState *currentBlock() const { return m_currentBlock; }
|
||||
|
||||
private:
|
||||
void updateVertexBuffer(const Block &block, const u8f orientation);
|
||||
void updateAnimationVertexBuffer(const Block &block, const u8f orientation, int animationPos = -1);
|
||||
void updateVertexBuffer(const BlockState &blockState, const u8f orientation);
|
||||
void updateAnimationVertexBuffer(const BlockState &blockState, const u8f orientation, int animationPos = -1);
|
||||
void updateVBOCoords(Vertex vertices[BlockGeometry::nFaces][BlockGeometry::nVertsPerFace],
|
||||
const Block &block, float face, u8f orientation);
|
||||
const BlockState &blockState, float face, u8f orientation);
|
||||
|
||||
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;
|
||||
|
||||
@ -66,7 +66,7 @@ class BlockCursor : public gk::Drawable {
|
||||
|
||||
unsigned int m_animationStart = 0;
|
||||
glm::ivec4 m_selectedBlock{0, 0, 0, -1};
|
||||
const Block *m_currentBlock = nullptr;
|
||||
const BlockState *m_currentBlock = nullptr;
|
||||
const ItemStack *m_currentTool = nullptr;
|
||||
|
||||
gk::Texture *m_blockDestroyTexture = nullptr;
|
||||
|
@ -40,16 +40,16 @@ void BlockInfoWidget::update() {
|
||||
m_itemWidget.update();
|
||||
}
|
||||
|
||||
void BlockInfoWidget::setCurrentBlock(const Block *block) {
|
||||
m_currentBlock = block;
|
||||
void BlockInfoWidget::setCurrentBlock(const BlockState *blockState) {
|
||||
m_currentBlock = blockState;
|
||||
|
||||
if (!m_currentBlock)
|
||||
m_isVisible = false;
|
||||
else {
|
||||
m_isVisible = true;
|
||||
|
||||
m_text.setString(block->label());
|
||||
m_itemWidget.setStack(block->stringID(), 1);
|
||||
m_text.setString(blockState->label());
|
||||
m_itemWidget.setStack(blockState->block().stringID(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,8 @@ class BlockInfoWidget : public Widget {
|
||||
|
||||
void update() override;
|
||||
|
||||
const Block *currentBlock() const { return m_currentBlock; }
|
||||
void setCurrentBlock(const Block *block);
|
||||
const BlockState *currentBlock() const { return m_currentBlock; }
|
||||
void setCurrentBlock(const BlockState *blockState);
|
||||
|
||||
private:
|
||||
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;
|
||||
@ -51,7 +51,7 @@ class BlockInfoWidget : public Widget {
|
||||
|
||||
bool m_isVisible = false;
|
||||
|
||||
const Block *m_currentBlock = nullptr;
|
||||
const BlockState *m_currentBlock = nullptr;
|
||||
};
|
||||
|
||||
#endif // BLOCKINFOWIDGET_HPP_
|
||||
|
@ -117,12 +117,12 @@ void BlockCursorRaycast::rayCastToAxis(const Axis axis, const glm::dvec3 &positi
|
||||
ny = axis == AXIS_Y ? nodeRow : floor(isect.y);
|
||||
nz = axis == AXIS_Z ? nodeRow : floor(isect.z);
|
||||
|
||||
u32 blockID = world.getBlock(nx, ny, nz);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
const BlockState *blockState = world.getBlockState(nx, ny, nz);
|
||||
if (!blockState) continue;
|
||||
|
||||
u8f orientation = block.isRotatable() ? world.getData(nx, ny, nz) & 0x1F : 0;
|
||||
u8f orientation = blockState->block().isRotatable() ? world.getData(nx, ny, nz) & 0x1F : 0;
|
||||
|
||||
const gk::FloatBox &boundingBox = block.boundingBox();
|
||||
const gk::FloatBox &boundingBox = blockState->boundingBox();
|
||||
glm::vec3 localCorner1{boundingBox.x, boundingBox.y, boundingBox.z};
|
||||
glm::vec3 localCorner2{boundingBox.sizeX, boundingBox.sizeY, boundingBox.sizeZ};
|
||||
localCorner2 += localCorner1;
|
||||
@ -136,7 +136,7 @@ void BlockCursorRaycast::rayCastToAxis(const Axis axis, const glm::dvec3 &positi
|
||||
if (localCorner2.z < localCorner1.z) std::swap(localCorner1.z, localCorner2.z);
|
||||
}
|
||||
|
||||
if (blockID && block.drawType() != BlockDrawType::Liquid) {
|
||||
if (blockState->block().id() && blockState->drawType() != BlockDrawType::Liquid) {
|
||||
// Check bounding box; this should loop over all selection boxes
|
||||
// when they are implemented
|
||||
const glm::dvec3 cubePos{double(nx), double(ny), double(nz)};
|
||||
|
@ -43,22 +43,26 @@ std::array<std::size_t, ChunkBuilder::layers> ChunkBuilder::buildChunk(const Cli
|
||||
for (s8f z = 0 ; z < CHUNK_HEIGHT ; z++) {
|
||||
for (s8f y = 0 ; y < CHUNK_DEPTH ; y++) {
|
||||
for (s8f x = 0 ; x < CHUNK_WIDTH ; x++) {
|
||||
const Block &block = Registry::getInstance().getBlock(chunk.getBlock(x, y, z));
|
||||
if (!block.id()) continue;
|
||||
if (!chunk.getBlock(x, y, z)) continue;
|
||||
u16 blockID = chunk.getBlock(x, y, z);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
if (!blockID) continue;
|
||||
|
||||
const gk::FloatBox &boundingBox = block.boundingBox();
|
||||
u16 blockParam = chunk.getData(x, y, z);
|
||||
const BlockState &blockState = block.getState(block.param().hasParam(BlockParam::State)
|
||||
? block.param().getParam(BlockParam::State, blockParam) : 0);
|
||||
|
||||
const gk::FloatBox &boundingBox = blockState.boundingBox();
|
||||
|
||||
u8f orientation = block.isRotatable()
|
||||
? block.param().getParam(BlockParam::Rotation, chunk.getData(x, y, z)) : 0;
|
||||
? block.param().getParam(BlockParam::Rotation, blockParam) : 0;
|
||||
const glm::mat3 &orientMatrix = orientMatrices[orientation];
|
||||
|
||||
if (block.drawType() == BlockDrawType::Solid
|
||||
|| block.drawType() == BlockDrawType::Leaves
|
||||
|| block.drawType() == BlockDrawType::Liquid
|
||||
|| block.drawType() == BlockDrawType::Glass
|
||||
|| block.drawType() == BlockDrawType::Cactus
|
||||
|| block.drawType() == BlockDrawType::BoundingBox)
|
||||
if (blockState.drawType() == BlockDrawType::Solid
|
||||
|| blockState.drawType() == BlockDrawType::Leaves
|
||||
|| blockState.drawType() == BlockDrawType::Liquid
|
||||
|| blockState.drawType() == BlockDrawType::Glass
|
||||
|| blockState.drawType() == BlockDrawType::Cactus
|
||||
|| blockState.drawType() == BlockDrawType::BoundingBox)
|
||||
{
|
||||
glm::vec3 vertexPos[nVertsPerCube]{
|
||||
// Order is important. It matches the bit order defined in BlockGeometry::cubeVerts.
|
||||
@ -72,7 +76,7 @@ std::array<std::size_t, ChunkBuilder::layers> ChunkBuilder::buildChunk(const Cli
|
||||
{boundingBox.x + boundingBox.sizeX, boundingBox.y + boundingBox.sizeY, boundingBox.z + boundingBox.sizeZ},
|
||||
};
|
||||
|
||||
if (block.drawType() == BlockDrawType::Cactus) {
|
||||
if (blockState.drawType() == BlockDrawType::Cactus) {
|
||||
// Ignore bounding box, initialize it to full node coordinates
|
||||
for (u8f i = 0; i < nVertsPerCube; ++i) {
|
||||
vertexPos[i].x = (i >> 0) & 1;
|
||||
@ -115,10 +119,10 @@ std::array<std::size_t, ChunkBuilder::layers> ChunkBuilder::buildChunk(const Cli
|
||||
|
||||
const gk::Vector3i *vFaceNeighbours[nVertsPerFace]{&corner0, &corner1, &corner2, &corner3};
|
||||
|
||||
addFace(x, y, z, f, chunk, block, normal, faceVerts, vFaceNeighbours);
|
||||
addFace(x, y, z, f, chunk, blockState, normal, faceVerts, vFaceNeighbours);
|
||||
}
|
||||
}
|
||||
else if (block.drawType() == BlockDrawType::XShape) {
|
||||
else if (blockState.drawType() == BlockDrawType::XShape) {
|
||||
glm::vec3 vertexPos[nVertsPerCube]{
|
||||
{0, 0, 0},
|
||||
{1, 0, 0},
|
||||
@ -135,7 +139,7 @@ std::array<std::size_t, ChunkBuilder::layers> ChunkBuilder::buildChunk(const Cli
|
||||
{&vertexPos[crossVerts[1][0]], &vertexPos[crossVerts[1][1]],
|
||||
&vertexPos[crossVerts[1][2]], &vertexPos[crossVerts[1][3]]},
|
||||
};
|
||||
addCross(x, y, z, chunk, block, faceVertices);
|
||||
addCross(x, y, z, chunk, blockState, faceVertices);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,26 +161,25 @@ std::array<std::size_t, ChunkBuilder::layers> ChunkBuilder::buildChunk(const Cli
|
||||
return verticesCount;
|
||||
}
|
||||
|
||||
inline void ChunkBuilder::addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk &chunk, const Block &block,
|
||||
inline void ChunkBuilder::addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk &chunk, const BlockState &blockState,
|
||||
const gk::Vector3i &normal, const glm::vec3 *const vertexPos[nVertsPerFace],
|
||||
const gk::Vector3i *const neighbourOfs[nVertsPerFace])
|
||||
{
|
||||
// Get surrounding block for the face
|
||||
u16 surroundingBlockID = chunk.getBlock(x + normal.x, y + normal.y, z + normal.z);
|
||||
const Block *surroundingBlock = &Registry::getInstance().getBlock(surroundingBlockID);
|
||||
const BlockState *surroundingBlockState = chunk.getBlockState(x + normal.x, y + normal.y, z + normal.z);
|
||||
|
||||
// Skip hidden faces
|
||||
if (surroundingBlock && surroundingBlock->id()
|
||||
&& ((block.drawType() == BlockDrawType::Solid && surroundingBlock->drawType() == BlockDrawType::Solid && surroundingBlock->isOpaque())
|
||||
|| (block.id() == surroundingBlock->id() && (block.drawType() == BlockDrawType::Liquid || block.drawType() == BlockDrawType::Glass))
|
||||
|| (block.drawType() == BlockDrawType::Liquid && surroundingBlock->drawType() == BlockDrawType::Solid)
|
||||
|| (block.drawType() == BlockDrawType::Cactus && surroundingBlock->id() == block.id() && f > 3)))
|
||||
if (surroundingBlockState && surroundingBlockState->block().id()
|
||||
&& ((blockState.drawType() == BlockDrawType::Solid && surroundingBlockState->drawType() == BlockDrawType::Solid && surroundingBlockState->isOpaque())
|
||||
|| (blockState.block().id() == surroundingBlockState->block().id() && (blockState.drawType() == BlockDrawType::Liquid || blockState.drawType() == BlockDrawType::Glass))
|
||||
|| (blockState.drawType() == BlockDrawType::Liquid && surroundingBlockState->drawType() == BlockDrawType::Solid)
|
||||
|| (blockState.drawType() == BlockDrawType::Cactus && surroundingBlockState->block().id() == blockState.block().id() && f > 3)))
|
||||
return;
|
||||
|
||||
const gk::FloatBox &boundingBox = block.boundingBox();
|
||||
const gk::FloatBox &boundingBox = blockState.boundingBox();
|
||||
|
||||
const BlockData *blockData = chunk.getBlockData(x, y, z);
|
||||
const std::string &texture = block.tiles().getTextureForFace(f, blockData ? blockData->useAltTiles : false);
|
||||
const std::string &texture = blockState.tiles().getTextureForFace(f, blockData ? blockData->useAltTiles : false);
|
||||
const gk::FloatRect &blockTexCoords = m_textureAtlas.getTexCoords(texture);
|
||||
|
||||
// Calculate UV's
|
||||
@ -185,7 +188,7 @@ inline void ChunkBuilder::addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk
|
||||
// U0V0 -> 3 2 <- U1V0
|
||||
// U0V1 -> 0 1 <- U1V1
|
||||
float U0, V0, U1, V1;
|
||||
if (block.drawType() == BlockDrawType::Cactus) {
|
||||
if (blockState.drawType() == BlockDrawType::Cactus) {
|
||||
U0 = 0.f;
|
||||
V0 = 0.f;
|
||||
U1 = 1.f;
|
||||
@ -203,14 +206,14 @@ inline void ChunkBuilder::addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk
|
||||
// Prepare vertex information for VBO
|
||||
Vertex vertices[nVertsPerFace];
|
||||
for (s8f v = 0; v < nVertsPerFace; ++v) {
|
||||
if (block.drawType() == BlockDrawType::Cactus) {
|
||||
if (blockState.drawType() == BlockDrawType::Cactus) {
|
||||
vertices[v].coord3d[0] = x + vertexPos[v]->x - boundingBox.x * normal.x;
|
||||
vertices[v].coord3d[1] = y + vertexPos[v]->y - boundingBox.y * normal.y;
|
||||
vertices[v].coord3d[2] = z + vertexPos[v]->z - boundingBox.z * normal.z;
|
||||
}
|
||||
else {
|
||||
float blockHeight = vertexPos[v]->z;
|
||||
if (block.drawType() == BlockDrawType::Liquid && (f != BlockFace::Bottom || !surroundingBlock || !surroundingBlock->id())) {
|
||||
if (blockState.drawType() == BlockDrawType::Liquid && (f != BlockFace::Bottom || !surroundingBlockState || !surroundingBlockState->block().id())) {
|
||||
if (f == BlockFace::Bottom)
|
||||
blockHeight = vertexPos[v]->z - 2.f / 16.f;
|
||||
else
|
||||
@ -228,7 +231,7 @@ inline void ChunkBuilder::addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk
|
||||
vertices[v].normal[1] = normal.y;
|
||||
vertices[v].normal[2] = normal.z;
|
||||
|
||||
const gk::Color colorMultiplier = block.colorMultiplier();
|
||||
const gk::Color colorMultiplier = blockState.colorMultiplier();
|
||||
vertices[v].color[0] = colorMultiplier.r;
|
||||
vertices[v].color[1] = colorMultiplier.g;
|
||||
vertices[v].color[2] = colorMultiplier.b;
|
||||
@ -239,13 +242,13 @@ inline void ChunkBuilder::addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk
|
||||
vertices[v].texCoord[0] = gk::qlerp(blockTexCoords.x, blockTexCoords.x + blockTexCoords.sizeX, U);
|
||||
vertices[v].texCoord[1] = gk::qlerp(blockTexCoords.y, blockTexCoords.y + blockTexCoords.sizeY, V);
|
||||
|
||||
if (Config::isSmoothLightingEnabled && block.drawType() != BlockDrawType::Liquid)
|
||||
if (Config::isSmoothLightingEnabled && blockState.drawType() != BlockDrawType::Liquid)
|
||||
vertices[v].lightValue[0] = getLightForVertex(Light::Sun, x, y, z, *neighbourOfs[v], normal, chunk);
|
||||
else
|
||||
vertices[v].lightValue[0] = chunk.lightmap().getSunlight(x + normal.x, y + normal.y, z + normal.z);
|
||||
|
||||
int torchlight = chunk.lightmap().getTorchlight(x, y, z);
|
||||
if (Config::isSmoothLightingEnabled && torchlight == 0 && block.drawType() != BlockDrawType::Liquid)
|
||||
if (Config::isSmoothLightingEnabled && torchlight == 0 && blockState.drawType() != BlockDrawType::Liquid)
|
||||
vertices[v].lightValue[1] = getLightForVertex(Light::Torch, x, y, z, *neighbourOfs[v], normal, chunk);
|
||||
else
|
||||
vertices[v].lightValue[1] = chunk.lightmap().getTorchlight(x + normal.x, y + normal.y, z + normal.z);
|
||||
@ -257,11 +260,11 @@ inline void ChunkBuilder::addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk
|
||||
if (!Config::isAmbientOcclusionEnabled || Config::isSmoothLightingEnabled)
|
||||
vertices[v].ambientOcclusion = 5;
|
||||
|
||||
if (block.drawType() == BlockDrawType::Liquid)
|
||||
if (blockState.drawType() == BlockDrawType::Liquid)
|
||||
m_vertices[Layer::Liquid].emplace_back(vertices[v]);
|
||||
else if (block.drawType() == BlockDrawType::Glass)
|
||||
else if (blockState.drawType() == BlockDrawType::Glass)
|
||||
m_vertices[Layer::Glass].emplace_back(vertices[v]);
|
||||
else if (block.colorMultiplier() != gk::Color::White)
|
||||
else if (blockState.colorMultiplier() != gk::Color::White)
|
||||
m_vertices[Layer::NoMipMap].emplace_back(vertices[v]);
|
||||
else
|
||||
m_vertices[Layer::Solid].emplace_back(vertices[v]);
|
||||
@ -286,9 +289,9 @@ inline void ChunkBuilder::addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk
|
||||
}
|
||||
}
|
||||
|
||||
inline void ChunkBuilder::addCross(s8f x, s8f y, s8f z, const ClientChunk &chunk, const Block &block, const glm::vec3 *const vertexPos[nCrossFaces][nVertsPerFace]) {
|
||||
inline void ChunkBuilder::addCross(s8f x, s8f y, s8f z, const ClientChunk &chunk, const BlockState &blockState, const glm::vec3 *const vertexPos[nCrossFaces][nVertsPerFace]) {
|
||||
const BlockData *blockData = chunk.getBlockData(x, y, z);
|
||||
const std::string &texture = block.tiles().getTextureForFace(0, blockData ? blockData->useAltTiles : false);
|
||||
const std::string &texture = blockState.tiles().getTextureForFace(0, blockData ? blockData->useAltTiles : false);
|
||||
const gk::FloatRect &blockTexCoords = m_textureAtlas.getTexCoords(texture);
|
||||
|
||||
float faceTexCoords[nVertsPerFace][nCoordsPerUV] = {
|
||||
@ -310,7 +313,7 @@ inline void ChunkBuilder::addCross(s8f x, s8f y, s8f z, const ClientChunk &chunk
|
||||
vertices[v].normal[1] = 0;
|
||||
vertices[v].normal[2] = 0;
|
||||
|
||||
const gk::Color colorMultiplier = block.colorMultiplier();
|
||||
const gk::Color colorMultiplier = blockState.colorMultiplier();
|
||||
vertices[v].color[0] = colorMultiplier.r;
|
||||
vertices[v].color[1] = colorMultiplier.g;
|
||||
vertices[v].color[2] = colorMultiplier.b;
|
||||
@ -342,18 +345,18 @@ inline u8 ChunkBuilder::getAmbientOcclusion(s8f x, s8f y, s8f z, const gk::Vecto
|
||||
(normal.z != 0) ? offset.z : 0
|
||||
};
|
||||
|
||||
const Block *blocks[4] = {
|
||||
&Registry::getInstance().getBlock(chunk.getBlock(x + minOffset.x, y + minOffset.y, z + offset.z)),
|
||||
&Registry::getInstance().getBlock(chunk.getBlock(x + offset.x, y + minOffset.y, z + minOffset.z)),
|
||||
&Registry::getInstance().getBlock(chunk.getBlock(x + minOffset.x, y + offset.y, z + minOffset.z)),
|
||||
&Registry::getInstance().getBlock(chunk.getBlock(x + offset.x, y + offset.y, z + offset.z))
|
||||
const BlockState *blocks[4] = {
|
||||
chunk.getBlockState(x + minOffset.x, y + minOffset.y, z + offset.z),
|
||||
chunk.getBlockState(x + offset.x, y + minOffset.y, z + minOffset.z),
|
||||
chunk.getBlockState(x + minOffset.x, y + offset.y, z + minOffset.z),
|
||||
chunk.getBlockState(x + offset.x, y + offset.y, z + offset.z)
|
||||
};
|
||||
|
||||
bool blockPresence[4] = {
|
||||
blocks[0]->id() != 0 && blocks[0]->isOpaque(),
|
||||
blocks[1]->id() != 0 && blocks[1]->isOpaque(),
|
||||
blocks[2]->id() != 0 && blocks[2]->isOpaque(),
|
||||
blocks[3]->id() != 0 && blocks[3]->isOpaque()
|
||||
blocks[0] && blocks[0]->block().id() != 0 && blocks[0]->isOpaque(),
|
||||
blocks[1] && blocks[1]->block().id() != 0 && blocks[1]->isOpaque(),
|
||||
blocks[2] && blocks[2]->block().id() != 0 && blocks[2]->isOpaque(),
|
||||
blocks[3] && blocks[3]->block().id() != 0 && blocks[3]->isOpaque()
|
||||
};
|
||||
|
||||
bool side1 = blockPresence[(minOffset.x != 0) ? 2 : 1];
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
#include "Vertex.hpp"
|
||||
|
||||
class Block;
|
||||
class BlockState;
|
||||
class ClientChunk;
|
||||
class TextureAtlas;
|
||||
|
||||
@ -58,11 +58,11 @@ class ChunkBuilder {
|
||||
};
|
||||
|
||||
private:
|
||||
void addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk &chunk, const Block &block,
|
||||
void addFace(s8f x, s8f y, s8f z, s8f f, const ClientChunk &chunk, const BlockState &blockState,
|
||||
const gk::Vector3i &normal, const glm::vec3 *const vertexPos[4],
|
||||
const gk::Vector3i *const neighbourOfs[4]);
|
||||
|
||||
void addCross(s8f x, s8f y, s8f z, const ClientChunk &chunk, const Block &block,
|
||||
void addCross(s8f x, s8f y, s8f z, const ClientChunk &chunk, const BlockState &blockState,
|
||||
const glm::vec3 *const vertexPos[2][4]);
|
||||
|
||||
enum class Light {
|
||||
|
@ -144,12 +144,11 @@ void ClientPlayer::updatePosition(const ClientWorld &world) {
|
||||
m_velocity.z = 0.f;
|
||||
|
||||
// Checking to block at camera position to enable specific effects
|
||||
u16 blockID = world.getBlock(m_camera.getDPosition().x, m_camera.getDPosition().y, m_camera.getDPosition().z);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
if (block.fogDepth() != 0) {
|
||||
const BlockState *blockState = world.getBlockState(m_camera.getDPosition().x, m_camera.getDPosition().y, m_camera.getDPosition().z);
|
||||
if (blockState && blockState->fogDepth() != 0) {
|
||||
GameConfig::currentScreenEffect = 1;
|
||||
GameConfig::fogDepth = block.fogDepth();
|
||||
GameConfig::fogColor = block.fogColor();
|
||||
GameConfig::fogDepth = blockState->fogDepth();
|
||||
GameConfig::fogColor = blockState->fogColor();
|
||||
}
|
||||
else {
|
||||
GameConfig::currentScreenEffect = 0;
|
||||
@ -186,9 +185,8 @@ void ClientPlayer::checkCollisions(const ClientWorld &world) {
|
||||
}
|
||||
|
||||
bool passable(const ClientWorld &world, double x, double y, double z) {
|
||||
u32 blockID = world.getBlock(floor(x), floor(y), floor(z));
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
return !blockID || block.drawType() == BlockDrawType::Liquid || block.drawType() == BlockDrawType::XShape;
|
||||
const BlockState *blockState = world.getBlockState(floor(x), floor(y), floor(z));
|
||||
return !blockState || !blockState->block().id() || blockState->drawType() == BlockDrawType::Liquid || blockState->drawType() == BlockDrawType::XShape;
|
||||
}
|
||||
|
||||
void ClientPlayer::testPoint(const ClientWorld &world, double x, double y, double z, glm::vec3 &vel) {
|
||||
|
@ -47,10 +47,10 @@
|
||||
class Registry : public gk::ISerializable {
|
||||
public:
|
||||
template<typename T>
|
||||
auto registerBlock(const TilesDef &tiles, const std::string &stringID, const std::string &label) -> typename std::enable_if<std::is_base_of<Block, T>::value, T&>::type {
|
||||
auto registerBlock(const std::string &stringID) -> typename std::enable_if<std::is_base_of<Block, T>::value, T&>::type {
|
||||
u32 id = m_blocks.size();
|
||||
m_blocksID.emplace(stringID, id);
|
||||
m_blocks.emplace_back(std::make_unique<T>(id, tiles, stringID, label));
|
||||
m_blocks.emplace_back(std::make_unique<T>(id, stringID));
|
||||
return *static_cast<T*>(m_blocks.back().get());
|
||||
}
|
||||
|
||||
|
@ -67,13 +67,7 @@ void TilesDef::deserialize(sf::Packet &packet) {
|
||||
packet >> m_textureFilenames >> m_altTextureFilenames;
|
||||
}
|
||||
|
||||
void TilesDef::loadFromLuaTable(const sol::table &table) {
|
||||
if (table["tiles"].get_type() == sol::type::table) {
|
||||
m_textureFilenames = table["tiles"].get<std::vector<std::string>>();
|
||||
}
|
||||
else
|
||||
m_textureFilenames.emplace_back(table["tiles"].get<std::string>());
|
||||
|
||||
bool TilesDef::loadFromLuaTable(const sol::table &table) {
|
||||
if (table["alt_tiles"].get_type() != sol::type::none) {
|
||||
if (table["alt_tiles"].get_type() == sol::type::table) {
|
||||
m_altTextureFilenames = table["alt_tiles"].get<std::vector<std::string>>();
|
||||
@ -81,5 +75,17 @@ void TilesDef::loadFromLuaTable(const sol::table &table) {
|
||||
else
|
||||
m_altTextureFilenames.emplace_back(table["alt_tiles"].get<std::string>());
|
||||
}
|
||||
|
||||
if (table["tiles"].get_type() == sol::type::table) {
|
||||
m_textureFilenames = table["tiles"].get<std::vector<std::string>>();
|
||||
return true;
|
||||
}
|
||||
else if (table["tiles"].get_type() == sol::type::string) {
|
||||
m_textureFilenames.emplace_back(table["tiles"].get<std::string>());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ class TilesDef : public gk::ISerializable {
|
||||
void serialize(sf::Packet &packet) const override;
|
||||
void deserialize(sf::Packet &packet) override;
|
||||
|
||||
void loadFromLuaTable(const sol::table &table);
|
||||
bool loadFromLuaTable(const sol::table &table);
|
||||
|
||||
const std::vector<std::string> &textureFilenames() const { return m_textureFilenames; };
|
||||
const std::vector<std::string> &altTextureFilenames() const { return m_altTextureFilenames; }
|
||||
|
@ -29,50 +29,75 @@
|
||||
#include "Player.hpp"
|
||||
#include "World.hpp"
|
||||
|
||||
Block::Block(u32 id, const TilesDef &tiles, const std::string &stringID, const std::string &label) {
|
||||
Block::Block(u32 id, const std::string &stringID) {
|
||||
m_id = id;
|
||||
m_tiles = tiles;
|
||||
|
||||
m_stringID = stringID;
|
||||
m_label = label;
|
||||
|
||||
m_itemDrop = stringID;
|
||||
m_itemDropAmount = 1;
|
||||
BlockState &defaultState = addState();
|
||||
defaultState.itemDrop(stringID);
|
||||
defaultState.itemDropAmount(1);
|
||||
}
|
||||
|
||||
const TilesDef &Block::tiles(u16 stateID) const {
|
||||
if (stateID >= m_states.size()) {
|
||||
gkError() << ("Failed to get tiles for block '" + m_stringID + "': State").c_str() << stateID << "doesn't exist";
|
||||
return m_states[0].tiles();
|
||||
}
|
||||
|
||||
return m_states[stateID].tiles();
|
||||
}
|
||||
|
||||
void Block::serialize(sf::Packet &packet) const {
|
||||
packet << u32(m_id) << m_stringID << m_label << u8(m_drawType)
|
||||
<< m_hardness << m_harvestRequirements << m_itemDrop << m_itemDropAmount << m_tiles
|
||||
<< m_boundingBox << m_isOpaque << m_isLightSource << m_canUpdate << m_canBeActivated
|
||||
<< m_colorMultiplier << m_isRotatable << m_inventoryImage << m_groups
|
||||
<< m_fogDepth << m_fogColor << m_param;
|
||||
packet << u32(m_id) << m_stringID << m_canUpdate << m_canBeActivated
|
||||
<< m_isRotatable << m_groups << m_states << m_param;
|
||||
}
|
||||
|
||||
void Block::deserialize(sf::Packet &packet) {
|
||||
u32 id;
|
||||
u8 drawType;
|
||||
|
||||
packet >> id >> m_stringID >> m_label >> drawType
|
||||
>> m_hardness >> m_harvestRequirements >> m_itemDrop >> m_itemDropAmount >> m_tiles
|
||||
>> m_boundingBox >> m_isOpaque >> m_isLightSource >> m_canUpdate >> m_canBeActivated
|
||||
>> m_colorMultiplier >> m_isRotatable >> m_inventoryImage >> m_groups
|
||||
>> m_fogDepth >> m_fogColor >> m_param;
|
||||
|
||||
packet >> id >> m_stringID >> m_canUpdate >> m_canBeActivated
|
||||
>> m_isRotatable >> m_groups >> m_states >> m_param;
|
||||
m_id = id;
|
||||
m_drawType = BlockDrawType(drawType);
|
||||
|
||||
for (auto &it : m_states) {
|
||||
it.setBlock(this);
|
||||
it.setDefaultState(&m_states.at(0));
|
||||
}
|
||||
}
|
||||
|
||||
BlockState &Block::addState() {
|
||||
if (!m_states.empty())
|
||||
m_states.emplace_back(m_states.size(), this, &getState(0));
|
||||
else
|
||||
m_states.emplace_back(m_states.size(), this, nullptr);
|
||||
return m_states.back();
|
||||
}
|
||||
|
||||
BlockState &Block::getState(u16 id) {
|
||||
if (id >= m_states.size()) {
|
||||
gkError() << "Failed to get state" << id << "in block" << m_stringID;
|
||||
return m_states.at(0);
|
||||
}
|
||||
|
||||
return m_states.at(id);
|
||||
}
|
||||
|
||||
const BlockState &Block::getState(u16 id) const {
|
||||
if (id >= m_states.size()) {
|
||||
gkError() << "Failed to get state" << id << "in block" << m_stringID;
|
||||
return m_states.at(0);
|
||||
}
|
||||
|
||||
return m_states.at(id);
|
||||
}
|
||||
|
||||
// Please update 'docs/lua-api-cpp.md' if you change this
|
||||
void Block::initUsertype(sol::state &lua) {
|
||||
lua.new_usertype<Block>("Block",
|
||||
"id", &Block::id,
|
||||
"data", &Block::data,
|
||||
"string_id", &Block::stringID,
|
||||
"label", &Block::label,
|
||||
"mod_name", &Block::modName,
|
||||
"is_opaque", &Block::isOpaque,
|
||||
"get_item_drop", &Block::getItemDrop,
|
||||
"param", (const BlockParam &(Block::*)() const)&Block::param
|
||||
"param", (const BlockParam &(Block::*)() const)&Block::param,
|
||||
"get_state", (const BlockState &(Block::*)(u16) const)&Block::getState
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <gk/graphics/Color.hpp>
|
||||
|
||||
#include "BlockParam.hpp"
|
||||
#include "BlockState.hpp"
|
||||
#include "ItemStack.hpp"
|
||||
#include "TilesDef.hpp"
|
||||
|
||||
@ -44,72 +45,28 @@ class Chunk;
|
||||
class Player;
|
||||
class World;
|
||||
|
||||
enum class BlockDrawType : u8 {
|
||||
Solid = 0,
|
||||
XShape = 1,
|
||||
Leaves = 2,
|
||||
Liquid = 3,
|
||||
Glass = 4,
|
||||
Cactus = 5,
|
||||
BoundingBox = 6, // FIXME: Temporary
|
||||
};
|
||||
|
||||
class Block : public gk::ISerializable {
|
||||
public:
|
||||
Block() = default;
|
||||
Block(u32 id, const TilesDef &tiles, const std::string &stringID, const std::string &label);
|
||||
Block(u32 id, const std::string &stringID);
|
||||
virtual ~Block() = default;
|
||||
|
||||
void serialize(sf::Packet &packet) const override;
|
||||
void deserialize(sf::Packet &packet) override;
|
||||
|
||||
u16 id() const { return m_id & 0xffff; }
|
||||
u16 data() const { return (m_id >> 16) & 0xffff; }
|
||||
const TilesDef &tiles() const { return m_tiles; }
|
||||
u16 id() const { return m_id; }
|
||||
|
||||
const std::string &stringID() const { return m_stringID; }
|
||||
const std::string &label() const { return m_label; }
|
||||
void setLabel(const std::string &label) { m_label = label; }
|
||||
|
||||
std::string modName() const { return m_stringID.substr(0, m_stringID.find_first_of(":")); }
|
||||
|
||||
bool isOpaque() const { return m_id != 0 && m_isOpaque && m_drawType != BlockDrawType::XShape; }
|
||||
void setOpaque(bool isOpaque) { m_isOpaque = isOpaque; }
|
||||
|
||||
ItemStack getItemDrop() const { return ItemStack{m_itemDrop, m_itemDropAmount}; };
|
||||
void setItemDrop(const std::string &itemDrop, u16 itemDropAmount = 1) { m_itemDrop = itemDrop; m_itemDropAmount = itemDropAmount; }
|
||||
|
||||
u8 harvestRequirements() const { return m_harvestRequirements; }
|
||||
void setHarvestRequirements(u8 harvestRequirements) { m_harvestRequirements = harvestRequirements; }
|
||||
|
||||
float hardness() const { return m_hardness; }
|
||||
void setHardness(float hardness) { m_hardness = hardness; }
|
||||
|
||||
float timeToBreak(u8 harvestCapability, float miningSpeed) const {
|
||||
return ((m_harvestRequirements & harvestCapability) == m_harvestRequirements) ? 1.5 * m_hardness / miningSpeed : 5 * m_hardness;
|
||||
}
|
||||
|
||||
const gk::FloatBox &boundingBox() const { return m_boundingBox; }
|
||||
void setBoundingBox(const gk::FloatBox &boundingBox) { m_boundingBox = boundingBox; }
|
||||
|
||||
BlockDrawType drawType() const { return m_drawType; }
|
||||
void setDrawType(BlockDrawType drawType) { m_drawType = drawType; }
|
||||
const TilesDef &tiles(u16 state) const;
|
||||
|
||||
bool canUpdate() const { return m_canUpdate; }
|
||||
bool canBeActivated() const { return m_canBeActivated; }
|
||||
|
||||
bool isLightSource() const { return m_isLightSource; }
|
||||
void setLightSource(bool isLightSource) { m_isLightSource = isLightSource; }
|
||||
|
||||
const gk::Color &colorMultiplier() const { return m_colorMultiplier; }
|
||||
void setColorMultiplier(const gk::Color &colorMultiplier) { m_colorMultiplier = colorMultiplier; }
|
||||
|
||||
bool isRotatable() const { return m_isRotatable; }
|
||||
void setRotatable(bool isRotatable) { m_isRotatable = isRotatable; }
|
||||
|
||||
const std::string &inventoryImage() const { return m_inventoryImage; }
|
||||
void setInventoryImage(const std::string &inventoryImage) { m_inventoryImage = inventoryImage; }
|
||||
|
||||
void addGroup(const std::string &name, u16 value) { m_groups.emplace(name, value); }
|
||||
bool hasGroup(const std::string &name) const { return m_groups.find(name) != m_groups.end(); }
|
||||
|
||||
@ -121,15 +78,14 @@ class Block : public gk::ISerializable {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
float fogDepth() const { return m_fogDepth; }
|
||||
void setFogDepth(float fogDepth) { m_fogDepth = fogDepth; }
|
||||
|
||||
const gk::Color &fogColor() const { return m_fogColor; }
|
||||
void setFogColor(const gk::Color &fogColor) { m_fogColor = fogColor; }
|
||||
|
||||
const BlockParam ¶m() const { return m_param; }
|
||||
BlockParam ¶m() { return m_param; }
|
||||
|
||||
BlockState &addState();
|
||||
BlockState &getState(u16 id);
|
||||
const BlockState &getState(u16 id) const;
|
||||
const std::vector<BlockState> &states() const { return m_states; }
|
||||
|
||||
static void initUsertype(sol::state &lua);
|
||||
|
||||
protected:
|
||||
@ -139,36 +95,14 @@ class Block : public gk::ISerializable {
|
||||
bool m_canBeActivated = false;
|
||||
|
||||
private:
|
||||
u32 m_id = 0;
|
||||
TilesDef m_tiles;
|
||||
|
||||
u16 m_id = 0;
|
||||
std::string m_stringID;
|
||||
std::string m_label;
|
||||
|
||||
std::string m_itemDrop;
|
||||
u16 m_itemDropAmount;
|
||||
|
||||
u8 m_harvestRequirements = 0;
|
||||
float m_hardness = 1.0f;
|
||||
|
||||
gk::FloatBox m_boundingBox{0, 0, 0, 1, 1, 1};
|
||||
|
||||
BlockDrawType m_drawType = BlockDrawType::Solid;
|
||||
|
||||
bool m_isOpaque = true;
|
||||
|
||||
bool m_isLightSource = false;
|
||||
|
||||
gk::Color m_colorMultiplier = gk::Color::White;
|
||||
|
||||
bool m_isRotatable = false;
|
||||
|
||||
std::string m_inventoryImage;
|
||||
|
||||
std::unordered_map<std::string, u16> m_groups;
|
||||
|
||||
float m_fogDepth = 0;
|
||||
gk::Color m_fogColor = gk::Color::White;
|
||||
std::vector<BlockState> m_states;
|
||||
|
||||
BlockParam m_param{*this};
|
||||
};
|
||||
|
@ -42,7 +42,7 @@ void BlockParam::deserialize(sf::Packet &packet) {
|
||||
void BlockParam::allocateBits(u8 type, u8 size) {
|
||||
auto it = m_allocatedBits.find(type);
|
||||
if (it != m_allocatedBits.end()) {
|
||||
gkWarning() << "Can't allocate param type" << getTypeName(type) << "twice in block" << m_block.stringID();
|
||||
gkWarning() << "Can't allocate param type" << getTypeName(type) << "twice in block" << m_block->stringID();
|
||||
}
|
||||
else if (m_totalSize + size <= 16) {
|
||||
m_allocatedBits.emplace(type, Param{m_totalSize, size});
|
||||
@ -52,7 +52,7 @@ void BlockParam::allocateBits(u8 type, u8 size) {
|
||||
// gkDebug() << "Allocated" << (int)size << "bits for type" << getTypeName(type) << "in block" << m_block.stringID();
|
||||
}
|
||||
else {
|
||||
gkError() << "Failed to allocate bits for param" << getTypeName(type) << "in block" << m_block.stringID();
|
||||
gkError() << "Failed to allocate bits for param" << getTypeName(type) << "in block" << m_block->stringID();
|
||||
gkError() << "Reason: Can't allocate more than 16 bits. Allocated bits:";
|
||||
for (auto &it : m_allocatedBits) {
|
||||
gkError() << "\t-" << getTypeName(it.first) << "=" << (int)it.second.size;
|
||||
@ -63,7 +63,7 @@ void BlockParam::allocateBits(u8 type, u8 size) {
|
||||
u16 BlockParam::getParam(u8 type, u16 data) const {
|
||||
auto it = m_allocatedBits.find(type);
|
||||
if (it == m_allocatedBits.end()) {
|
||||
gkWarning() << "Failed to get param" << getTypeName(type) << "in block" << m_block.stringID();
|
||||
gkWarning() << "Failed to get param" << getTypeName(type) << "in block" << m_block->stringID();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -73,14 +73,14 @@ u16 BlockParam::getParam(u8 type, u16 data) const {
|
||||
u16 BlockParam::setParam(u8 type, u16 data, u16 param) {
|
||||
auto it = m_allocatedBits.find(type);
|
||||
if (it == m_allocatedBits.end()) {
|
||||
gkWarning() << "Failed to set param" << getTypeName(type) << "in block" << m_block.stringID();
|
||||
gkWarning() << "Failed to set param" << getTypeName(type) << "in block" << m_block->stringID();
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 mask = ~(~0u << it->second.size) << it->second.offset;
|
||||
param <<= it->second.offset;
|
||||
if ((param & ~mask) != 0)
|
||||
gkWarning() << "Block param overflow for type" << getTypeName(type) << "in block" << m_block.stringID();
|
||||
gkWarning() << "Block param overflow for type" << getTypeName(type) << "in block" << m_block->stringID();
|
||||
|
||||
return (data & ~mask) | (param & mask);
|
||||
}
|
||||
@ -88,6 +88,7 @@ u16 BlockParam::setParam(u8 type, u16 data, u16 param) {
|
||||
std::string BlockParam::getTypeName(u8 type) {
|
||||
std::array<std::string, Type::Count> names = {
|
||||
"Rotation",
|
||||
"State",
|
||||
};
|
||||
|
||||
return names[type];
|
||||
|
@ -41,13 +41,14 @@ class Block;
|
||||
|
||||
class BlockParam : public gk::ISerializable {
|
||||
public:
|
||||
BlockParam(Block &block) : m_block(block) {}
|
||||
BlockParam(Block &block) : m_block(&block) {}
|
||||
|
||||
void serialize(sf::Packet &packet) const override;
|
||||
void deserialize(sf::Packet &packet) override;
|
||||
|
||||
enum Type {
|
||||
Rotation,
|
||||
State,
|
||||
|
||||
Count
|
||||
};
|
||||
@ -56,13 +57,14 @@ class BlockParam : public gk::ISerializable {
|
||||
|
||||
u16 getParam(u8 type, u16 data) const;
|
||||
u16 setParam(u8 type, u16 data, u16 param);
|
||||
bool hasParam(u8 type) const { return m_allocatedBits.find(type) != m_allocatedBits.end(); }
|
||||
|
||||
static std::string getTypeName(u8 type);
|
||||
|
||||
static void initUsertype(sol::state &lua);
|
||||
|
||||
private:
|
||||
Block &m_block;
|
||||
Block *m_block = nullptr;
|
||||
u8 m_totalSize = 0;
|
||||
|
||||
struct Param : public gk::ISerializable {
|
||||
|
58
source/common/world/BlockState.cpp
Normal file
58
source/common/world/BlockState.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* OpenMiner
|
||||
*
|
||||
* Copyright (C) 2018-2020 Unarelith, Quentin Bazin <openminer@unarelith.net>
|
||||
* Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md)
|
||||
*
|
||||
* This file is part of OpenMiner.
|
||||
*
|
||||
* OpenMiner is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* OpenMiner is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with OpenMiner; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "BlockState.hpp"
|
||||
#include "Registry.hpp"
|
||||
|
||||
void BlockState::serialize(sf::Packet &packet) const {
|
||||
packet << m_id << m_label << m_tiles
|
||||
<< m_itemDrop << m_itemDropAmount
|
||||
<< m_hardness << m_harvestRequirements
|
||||
<< m_boundingBox << u8(m_drawType) << m_colorMultiplier
|
||||
<< m_isOpaque << m_isLightSource
|
||||
<< m_inventoryImage << m_fogDepth << m_fogColor << m_attrs;
|
||||
}
|
||||
|
||||
void BlockState::deserialize(sf::Packet &packet) {
|
||||
u8 drawType;
|
||||
|
||||
packet >> m_id >> m_label >> m_tiles
|
||||
>> m_itemDrop >> m_itemDropAmount
|
||||
>> m_hardness >> m_harvestRequirements
|
||||
>> m_boundingBox >> drawType >> m_colorMultiplier
|
||||
>> m_isOpaque >> m_isLightSource
|
||||
>> m_inventoryImage >> m_fogDepth >> m_fogColor >> m_attrs;
|
||||
|
||||
m_drawType = BlockDrawType(drawType);
|
||||
}
|
||||
|
||||
// Please update 'docs/lua-api-cpp.md' if you change this
|
||||
void BlockState::initUsertype(sol::state &lua) {
|
||||
lua.new_usertype<BlockState>("BlockState",
|
||||
"get_item_drop", &BlockState::getItemDrop
|
||||
);
|
||||
}
|
||||
|
157
source/common/world/BlockState.hpp
Normal file
157
source/common/world/BlockState.hpp
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* OpenMiner
|
||||
*
|
||||
* Copyright (C) 2018-2020 Unarelith, Quentin Bazin <openminer@unarelith.net>
|
||||
* Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md)
|
||||
*
|
||||
* This file is part of OpenMiner.
|
||||
*
|
||||
* OpenMiner is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* OpenMiner is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with OpenMiner; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef BLOCKSTATE_HPP_
|
||||
#define BLOCKSTATE_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <gk/core/Box.hpp>
|
||||
#include <gk/core/IntTypes.hpp>
|
||||
|
||||
#include "BlockParam.hpp"
|
||||
#include "ItemStack.hpp"
|
||||
#include "TilesDef.hpp"
|
||||
|
||||
enum class BlockDrawType : u8 {
|
||||
Solid = 0,
|
||||
XShape = 1,
|
||||
Leaves = 2,
|
||||
Liquid = 3,
|
||||
Glass = 4,
|
||||
Cactus = 5,
|
||||
BoundingBox = 6, // FIXME: Temporary
|
||||
};
|
||||
|
||||
#define BLOCK_ATTR_GETTER(attrName) \
|
||||
auto attrName() const -> const std::remove_reference<decltype(m_##attrName)>::type & { \
|
||||
if (!m_defaultState || m_attrs & BlockAttribute::attr_##attrName) \
|
||||
return m_##attrName; \
|
||||
else \
|
||||
return m_defaultState->m_##attrName; \
|
||||
}
|
||||
|
||||
#define BLOCK_ATTR_SETTER(attrName) \
|
||||
void attrName(const std::remove_reference<decltype(m_##attrName)>::type &value) { \
|
||||
m_##attrName = value; \
|
||||
m_attrs |= BlockAttribute::attr_##attrName; \
|
||||
}
|
||||
|
||||
#define BLOCK_ATTR(type, name) \
|
||||
private: \
|
||||
type m_##name; \
|
||||
public: \
|
||||
BLOCK_ATTR_GETTER(name) \
|
||||
BLOCK_ATTR_SETTER(name)
|
||||
|
||||
#define BLOCK_ATTR_V(type, name, defaultValue) \
|
||||
private: \
|
||||
type m_##name = defaultValue; \
|
||||
public: \
|
||||
BLOCK_ATTR_GETTER(name) \
|
||||
BLOCK_ATTR_SETTER(name)
|
||||
|
||||
|
||||
class BlockState : public gk::ISerializable {
|
||||
public:
|
||||
BlockState() = default;
|
||||
BlockState(u16 id, const Block *block, const BlockState *defaultState = nullptr)
|
||||
: m_block(block), m_defaultState(defaultState), m_id(id) {}
|
||||
|
||||
void serialize(sf::Packet &packet) const override;
|
||||
void deserialize(sf::Packet &packet) override;
|
||||
|
||||
const Block &block() const { return *m_block; }
|
||||
|
||||
u16 id() const { return m_id; }
|
||||
|
||||
float timeToBreak(u8 harvestCapability, float miningSpeed) const {
|
||||
return ((m_harvestRequirements & harvestCapability) == m_harvestRequirements) ? 1.5 * m_hardness / miningSpeed : 5 * m_hardness;
|
||||
}
|
||||
|
||||
ItemStack getItemDrop() const { return {m_itemDrop, m_itemDropAmount}; }
|
||||
|
||||
void setBlock(const Block *block) { m_block = block; }
|
||||
void setDefaultState(const BlockState *defaultState) { m_defaultState = defaultState; }
|
||||
|
||||
static void initUsertype(sol::state &lua);
|
||||
|
||||
private:
|
||||
const Block *m_block = nullptr;
|
||||
const BlockState *m_defaultState = nullptr;
|
||||
|
||||
u16 m_id = 0;
|
||||
|
||||
enum BlockAttribute : u32 {
|
||||
attr_tiles,
|
||||
attr_label,
|
||||
attr_itemDrop,
|
||||
attr_itemDropAmount,
|
||||
attr_harvestRequirements,
|
||||
attr_hardness,
|
||||
attr_boundingBox,
|
||||
attr_drawType,
|
||||
attr_colorMultiplier,
|
||||
attr_isOpaque,
|
||||
attr_isLightSource,
|
||||
attr_inventoryImage,
|
||||
attr_fogDepth,
|
||||
attr_fogColor,
|
||||
attr_param,
|
||||
};
|
||||
|
||||
BLOCK_ATTR(std::string, label);
|
||||
BLOCK_ATTR(TilesDef, tiles);
|
||||
|
||||
BLOCK_ATTR(std::string, itemDrop);
|
||||
BLOCK_ATTR_V(u16, itemDropAmount, 1);
|
||||
|
||||
BLOCK_ATTR_V(u8, harvestRequirements, 0);
|
||||
BLOCK_ATTR_V(float, hardness, 1.0f);
|
||||
|
||||
BLOCK_ATTR_V(gk::FloatBox, boundingBox, (gk::FloatBox{0, 0, 0, 1, 1, 1}));
|
||||
|
||||
BLOCK_ATTR_V(BlockDrawType, drawType, BlockDrawType::Solid);
|
||||
|
||||
BLOCK_ATTR_V(gk::Color, colorMultiplier, gk::Color::White);
|
||||
|
||||
BLOCK_ATTR_V(bool, isOpaque, true);
|
||||
BLOCK_ATTR_V(bool, isLightSource, false);
|
||||
|
||||
BLOCK_ATTR(std::string, inventoryImage);
|
||||
|
||||
BLOCK_ATTR_V(float, fogDepth, 0);
|
||||
BLOCK_ATTR_V(gk::Color, fogColor, gk::Color::White);
|
||||
|
||||
u32 m_attrs = 0;
|
||||
};
|
||||
|
||||
#undef BLOCK_ATTR
|
||||
#undef BLOCK_ATTR_GETTER
|
||||
#undef BLOCK_ATTR_SETTER
|
||||
|
||||
#endif // BLOCKSTATE_HPP_
|
@ -71,8 +71,12 @@ void Chunk::setBlock(int x, int y, int z, u16 type) {
|
||||
|
||||
if ((m_data[z][y][x] & 0xffff) == type) return;
|
||||
|
||||
u16 blockParam = getData(x, y, z);
|
||||
const Block &block = Registry::getInstance().getBlock(type);
|
||||
if (block.isLightSource())
|
||||
const BlockState &blockState = block.getState(block.param().hasParam(BlockParam::State)
|
||||
? block.param().getParam(BlockParam::State, blockParam) : 0);
|
||||
|
||||
if (blockState.isLightSource())
|
||||
m_lightmap.addTorchlight(x, y, z, 14);
|
||||
else {
|
||||
m_lightmap.removeTorchlight(x, y, z);
|
||||
@ -82,8 +86,8 @@ void Chunk::setBlock(int x, int y, int z, u16 type) {
|
||||
onBlockPlaced(x, y, z, block);
|
||||
m_world.onBlockPlaced(x + m_x * width, y + m_y * depth, z + m_z * height, block);
|
||||
|
||||
if (m_data[z][y][x] != 0) {
|
||||
const Block &oldBlock = Registry::getInstance().getBlock(m_data[z][y][x]);
|
||||
if ((m_data[z][y][x] & 0xffff) != 0) {
|
||||
const Block &oldBlock = Registry::getInstance().getBlock(m_data[z][y][x] & 0xffff);
|
||||
onBlockDestroyed(x, y, z, oldBlock);
|
||||
}
|
||||
|
||||
@ -133,6 +137,23 @@ void Chunk::setBlockRaw(int x, int y, int z, u16 type) {
|
||||
m_hasChanged = true;
|
||||
}
|
||||
|
||||
const BlockState *Chunk::getBlockState(int x, int y, int z) const {
|
||||
if(x < 0) return m_surroundingChunks[0] ? m_surroundingChunks[0]->getBlockState(x + Chunk::width, y, z) : nullptr;
|
||||
if(x >= Chunk::width) return m_surroundingChunks[1] ? m_surroundingChunks[1]->getBlockState(x - Chunk::width, y, z) : nullptr;
|
||||
if(y < 0) return m_surroundingChunks[2] ? m_surroundingChunks[2]->getBlockState(x, y + Chunk::depth, z) : nullptr;
|
||||
if(y >= Chunk::depth) return m_surroundingChunks[3] ? m_surroundingChunks[3]->getBlockState(x, y - Chunk::depth, z) : nullptr;
|
||||
if(z < 0) return m_surroundingChunks[4] ? m_surroundingChunks[4]->getBlockState(x, y, z + Chunk::height) : nullptr;
|
||||
if(z >= Chunk::height) return m_surroundingChunks[5] ? m_surroundingChunks[5]->getBlockState(x, y, z - Chunk::height) : nullptr;
|
||||
|
||||
u16 blockID = getBlock(x, y, z);
|
||||
u16 blockParam = getData(x, y, z);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
if (!block.param().hasParam(BlockParam::State))
|
||||
return &block.getState(0);
|
||||
|
||||
return &block.getState(block.param().getParam(BlockParam::State, blockParam));
|
||||
}
|
||||
|
||||
BlockData *Chunk::getBlockData(int x, int y, int z) const {
|
||||
if(x < 0) return m_surroundingChunks[0] ? m_surroundingChunks[0]->getBlockData(x + CHUNK_WIDTH, y, z) : 0;
|
||||
if(x >= CHUNK_WIDTH) return m_surroundingChunks[1] ? m_surroundingChunks[1]->getBlockData(x - CHUNK_WIDTH, y, z) : 0;
|
||||
|
@ -64,6 +64,8 @@ class Chunk : public gk::NonCopyable {
|
||||
|
||||
void setBlockRaw(int x, int y, int z, u16 block);
|
||||
|
||||
const BlockState *getBlockState(int x, int y, int z) const;
|
||||
|
||||
virtual void onBlockPlaced(int, int, int, const Block &) {}
|
||||
virtual void onBlockDestroyed(int, int, int, const Block &) {}
|
||||
|
||||
|
@ -129,9 +129,8 @@ bool ChunkLightmap::updateTorchlight() {
|
||||
m_torchlightBfsQueue.pop();
|
||||
|
||||
// If this block is opaque, don't propagate the light
|
||||
u16 blockID = m_chunk->getBlock(node.x, node.y, node.z);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
if (block.isOpaque() && !block.isLightSource()) {
|
||||
const BlockState *blockState = m_chunk->getBlockState(node.x, node.y, node.z);
|
||||
if (blockState && blockState->isOpaque() && !blockState->isLightSource()) {
|
||||
setTorchlight(node.x, node.y, node.z, 0);
|
||||
|
||||
// FIXME: This only reverts an addTorchlight that added light in a non-generated chunk
|
||||
@ -153,9 +152,8 @@ bool ChunkLightmap::updateTorchlight() {
|
||||
u8 lightLevel = getTorchlight(node.x, node.y, node.z);
|
||||
for (const gk::Vector3i &surroundingNode : surroundingNodes) {
|
||||
if (getTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z) + 2 <= lightLevel) {
|
||||
u16 blockID = m_chunk->getBlock(surroundingNode.x, surroundingNode.y, surroundingNode.z);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
if (!block.isOpaque()) {
|
||||
const BlockState *blockState = m_chunk->getBlockState(surroundingNode.x, surroundingNode.y, surroundingNode.z);
|
||||
if (blockState && blockState->isOpaque()) {
|
||||
addTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z, lightLevel - 1);
|
||||
|
||||
lightUpdated = true;
|
||||
@ -205,9 +203,8 @@ bool ChunkLightmap::updateSunlight() {
|
||||
m_sunlightBfsQueue.pop();
|
||||
|
||||
// If this block is opaque, don't propagate the light
|
||||
u16 blockID = m_chunk->getBlock(node.x, node.y, node.z);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
if (block.isOpaque()) {
|
||||
const BlockState *blockState = m_chunk->getBlockState(node.x, node.y, node.z);
|
||||
if (blockState && blockState->isOpaque()) {
|
||||
setSunlight(node.x, node.y, node.z, 0);
|
||||
|
||||
// FIXME: This only reverts an addSunlight that added light in a non-generated chunk
|
||||
@ -231,10 +228,9 @@ bool ChunkLightmap::updateSunlight() {
|
||||
u8 neighbourSunlightLevel = getSunlight(surroundingNode.x, surroundingNode.y, surroundingNode.z);
|
||||
if (neighbourSunlightLevel + 2 <= sunlightLevel
|
||||
|| (sunlightLevel == 15 && neighbourSunlightLevel != 15 && surroundingNode.z == node.z - 1)) {
|
||||
u16 blockID = m_chunk->getBlock(surroundingNode.x, surroundingNode.y, surroundingNode.z);
|
||||
const Block &block = Registry::getInstance().getBlock(blockID);
|
||||
if (!block.isOpaque()) {
|
||||
if (sunlightLevel == 15 && surroundingNode.z == node.z - 1 && (!blockID || block.drawType() == BlockDrawType::Glass || block.drawType() == BlockDrawType::XShape)) {
|
||||
const BlockState *blockState = m_chunk->getBlockState(surroundingNode.x, surroundingNode.y, surroundingNode.z);
|
||||
if (blockState && blockState->isOpaque()) {
|
||||
if (sunlightLevel == 15 && surroundingNode.z == node.z - 1 && (!blockState->block().id() || blockState->drawType() == BlockDrawType::Glass || blockState->drawType() == BlockDrawType::XShape)) {
|
||||
addSunlight(surroundingNode.x, surroundingNode.y, surroundingNode.z, sunlightLevel);
|
||||
|
||||
lightUpdated = true;
|
||||
|
@ -58,6 +58,14 @@ BlockData *World::addBlockData(int x, int y, int z, int inventoryWidth, int inve
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const BlockState *World::getBlockState(int x, int y, int z) const {
|
||||
Chunk *chunk = getChunkAtBlockPos(x, y, z);
|
||||
if (chunk)
|
||||
return chunk->getBlockState(x & (CHUNK_WIDTH - 1), y & (CHUNK_DEPTH - 1), z & (CHUNK_HEIGHT - 1));
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u16 World::getBlock(int x, int y, int z) const {
|
||||
Chunk *chunk = getChunkAtBlockPos(x, y, z);
|
||||
if (chunk)
|
||||
|
@ -41,6 +41,8 @@ class World {
|
||||
BlockData *getBlockData(int x, int y, int z) const;
|
||||
BlockData *addBlockData(int x, int y, int z, int inventoryWidth = 0, int inventoryHeight = 0) const;
|
||||
|
||||
const BlockState *getBlockState(int x, int y, int z) const;
|
||||
|
||||
u16 getBlock(int x, int y, int z) const;
|
||||
void setBlock(int x, int y, int z, u16 id) const;
|
||||
u16 getData(int x, int y, int z) const;
|
||||
|
@ -117,7 +117,7 @@ bool ServerApplication::init() {
|
||||
Registry::setInstance(m_registry);
|
||||
|
||||
// The id "_:air" is used in CraftingRecipe, update it there if it changes
|
||||
m_registry.registerBlock<ServerBlock>({}, "_:air", "Air");
|
||||
m_registry.registerBlock<ServerBlock>("_:air").getState(0).label("Air");
|
||||
m_registry.registerItem<Item>({}, "_:air", "Air").setIsBlock(true);
|
||||
|
||||
m_modLoader.loadMods();
|
||||
|
@ -32,54 +32,61 @@
|
||||
#include "ServerBlock.hpp"
|
||||
|
||||
void LuaBlockLoader::loadBlock(const sol::table &table) const {
|
||||
std::string stringID = m_mod.id() + ":" + table["id"].get<std::string>();
|
||||
|
||||
ServerBlock &block = Registry::getInstance().registerBlock<ServerBlock>(stringID);
|
||||
block.setRotatable(table["is_rotatable"].get_or(false));
|
||||
|
||||
BlockState &defaultState = block.getState(0);
|
||||
loadBlockState(defaultState, table, block);
|
||||
}
|
||||
|
||||
void LuaBlockLoader::loadBlockState(BlockState &state, const sol::table &table, ServerBlock &block) const {
|
||||
TilesDef tiles;
|
||||
tiles.loadFromLuaTable(table);
|
||||
state.tiles(tiles);
|
||||
|
||||
std::string stringID = m_mod.id() + ":" + table["id"].get<std::string>();
|
||||
std::string label = table["name"].get<std::string>();
|
||||
|
||||
ServerBlock &block = Registry::getInstance().registerBlock<ServerBlock>(tiles, stringID, label);
|
||||
|
||||
loadProperties(block, table);
|
||||
loadBoundingBox(block, table);
|
||||
loadDrawType(block, table);
|
||||
loadItemDrop(block, table);
|
||||
loadColorMultiplier(block, table);
|
||||
loadProperties(state, table);
|
||||
loadBoundingBox(state, table);
|
||||
loadDrawType(state, table, block);
|
||||
loadItemDrop(state, table);
|
||||
loadColorMultiplier(state, table);
|
||||
|
||||
Item *item = nullptr;
|
||||
if (!block.inventoryImage().empty()) {
|
||||
item = &Registry::getInstance().registerItem<Item>(TilesDef{block.inventoryImage()}, stringID, label);
|
||||
if (!state.inventoryImage().empty()) {
|
||||
item = &Registry::getInstance().registerItem<Item>(TilesDef{state.inventoryImage()}, block.stringID(), state.label());
|
||||
}
|
||||
else {
|
||||
item = &Registry::getInstance().registerItem<Item>(block.tiles(), stringID, label);
|
||||
item = &Registry::getInstance().registerItem<Item>(state.tiles(), block.stringID(), state.label());
|
||||
}
|
||||
|
||||
item->setIsBlock(true);
|
||||
|
||||
loadGroups(block, *item, table);
|
||||
loadGroups(block, table, item);
|
||||
|
||||
loadParams(block);
|
||||
}
|
||||
|
||||
inline void LuaBlockLoader::loadProperties(ServerBlock &block, const sol::table &table) const {
|
||||
block.setHarvestRequirements(table["harvest_requirements"].get_or(0));
|
||||
block.setHardness(table["hardness"].get_or(1.0f));
|
||||
block.setOpaque(table["is_opaque"].get_or(true));
|
||||
block.setLightSource(table["is_light_source"].get_or(false));
|
||||
block.setOnBlockActivated(table["on_block_activated"]);
|
||||
block.setOnTick(table["on_tick"]);
|
||||
block.setOnBlockPlaced(table["on_block_placed"]);
|
||||
block.setOnBlockDestroyed(table["on_block_destroyed"]);
|
||||
block.setRotatable(table["is_rotatable"].get_or(false));
|
||||
block.setInventoryImage(table["inventory_image"].get_or<std::string>(""));
|
||||
block.setFogDepth(table["fog_depth"].get_or<float>(0));
|
||||
block.setTickRandomly(table["tick_randomly"].get_or(false));
|
||||
block.setTickProbability(table["tick_probability"].get_or(0.f));
|
||||
inline void LuaBlockLoader::loadProperties(BlockState &state, const sol::table &table) const {
|
||||
state.label(table["name"].get<std::string>());
|
||||
state.harvestRequirements(table["harvest_requirements"].get_or(0));
|
||||
state.hardness(table["hardness"].get_or(1.0f));
|
||||
state.isOpaque(table["is_opaque"].get_or(true));
|
||||
state.isLightSource(table["is_light_source"].get_or(false));
|
||||
state.inventoryImage(table["inventory_image"].get_or<std::string>(""));
|
||||
state.fogDepth(table["fog_depth"].get_or<float>(0));
|
||||
|
||||
if (block.fogDepth()) {
|
||||
// state.onBlockActivated(table["on_block_activated"]);
|
||||
// state.onTick(table["on_tick"]);
|
||||
// state.onBlockPlaced(table["on_block_placed"]);
|
||||
// state.onBlockDestroyed(table["on_block_destroyed"]);
|
||||
// state.setTickRandomly(table["tick_randomly"].get_or(false));
|
||||
// state.setTickProbability(table["tick_probability"].get_or(0.f));
|
||||
|
||||
if (state.fogDepth()) {
|
||||
sol::optional<sol::table> fogColor = table["fog_color"];
|
||||
if (fogColor != sol::nullopt) {
|
||||
block.setFogColor(gk::Color{
|
||||
state.fogColor(gk::Color{
|
||||
fogColor.value().get<u8>(1),
|
||||
fogColor.value().get<u8>(2),
|
||||
fogColor.value().get<u8>(3),
|
||||
@ -88,10 +95,10 @@ inline void LuaBlockLoader::loadProperties(ServerBlock &block, const sol::table
|
||||
}
|
||||
}
|
||||
|
||||
inline void LuaBlockLoader::loadBoundingBox(ServerBlock &block, const sol::table &table) const {
|
||||
inline void LuaBlockLoader::loadBoundingBox(BlockState &state, const sol::table &table) const {
|
||||
sol::optional<sol::table> boundingBox = table["bounding_box"];
|
||||
if (boundingBox != sol::nullopt) {
|
||||
block.setBoundingBox(gk::FloatBox{
|
||||
state.boundingBox(gk::FloatBox{
|
||||
boundingBox.value().get<float>(1),
|
||||
boundingBox.value().get<float>(2),
|
||||
boundingBox.value().get<float>(3),
|
||||
@ -102,7 +109,7 @@ inline void LuaBlockLoader::loadBoundingBox(ServerBlock &block, const sol::table
|
||||
}
|
||||
}
|
||||
|
||||
inline void LuaBlockLoader::loadDrawType(ServerBlock &block, const sol::table &table) const {
|
||||
inline void LuaBlockLoader::loadDrawType(BlockState &state, const sol::table &table, const ServerBlock &block) const {
|
||||
sol::object drawTypeObject = table["draw_type"];
|
||||
if (drawTypeObject.valid()) {
|
||||
if (drawTypeObject.get_type() == sol::type::string) {
|
||||
@ -117,8 +124,9 @@ inline void LuaBlockLoader::loadDrawType(ServerBlock &block, const sol::table &t
|
||||
};
|
||||
|
||||
auto it = drawTypes.find(drawTypeObject.as<std::string>());
|
||||
if (it != drawTypes.end())
|
||||
block.setDrawType(it->second);
|
||||
if (it != drawTypes.end()) {
|
||||
state.drawType(it->second);
|
||||
}
|
||||
else
|
||||
gkError() << "In" << block.stringID() << " definition: Block draw type invalid";
|
||||
}
|
||||
@ -127,19 +135,18 @@ inline void LuaBlockLoader::loadDrawType(ServerBlock &block, const sol::table &t
|
||||
}
|
||||
}
|
||||
|
||||
inline void LuaBlockLoader::loadItemDrop(ServerBlock &block, const sol::table &table) const {
|
||||
inline void LuaBlockLoader::loadItemDrop(BlockState &state, const sol::table &table) const {
|
||||
sol::optional<sol::table> itemDrop = table["item_drop"];
|
||||
if (itemDrop != sol::nullopt) {
|
||||
std::string dropID = itemDrop.value()["id"];
|
||||
u16 dropAmount = itemDrop.value()["amount"];
|
||||
block.setItemDrop(dropID, dropAmount);
|
||||
state.itemDrop(itemDrop.value()["id"]);
|
||||
state.itemDropAmount(itemDrop.value()["amount"]);
|
||||
}
|
||||
}
|
||||
|
||||
inline void LuaBlockLoader::loadColorMultiplier(ServerBlock &block, const sol::table &table) const {
|
||||
inline void LuaBlockLoader::loadColorMultiplier(BlockState &state, const sol::table &table) const {
|
||||
sol::optional<sol::table> colorMultiplier = table["color_multiplier"];
|
||||
if (colorMultiplier != sol::nullopt) {
|
||||
block.setColorMultiplier(gk::Color{
|
||||
state.colorMultiplier(gk::Color{
|
||||
colorMultiplier.value().get<u8>(1),
|
||||
colorMultiplier.value().get<u8>(2),
|
||||
colorMultiplier.value().get<u8>(3),
|
||||
@ -148,7 +155,7 @@ inline void LuaBlockLoader::loadColorMultiplier(ServerBlock &block, const sol::t
|
||||
}
|
||||
}
|
||||
|
||||
inline void LuaBlockLoader::loadGroups(ServerBlock &block, Item &item, const sol::table &table) const {
|
||||
inline void LuaBlockLoader::loadGroups(ServerBlock &block, const sol::table &table, Item *item) const {
|
||||
sol::object groupsObject = table["groups"];
|
||||
if (groupsObject.valid()) {
|
||||
if (groupsObject.get_type() == sol::type::table) {
|
||||
@ -158,7 +165,8 @@ inline void LuaBlockLoader::loadGroups(ServerBlock &block, Item &item, const sol
|
||||
u16 groupValue = groupObject.second.as<u16>();
|
||||
|
||||
block.addGroup(groupName, groupValue);
|
||||
item.addGroup(groupName, groupValue);
|
||||
if (item)
|
||||
item->addGroup(groupName, groupValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
class Item;
|
||||
class LuaMod;
|
||||
class BlockState;
|
||||
class ServerBlock;
|
||||
|
||||
class LuaBlockLoader {
|
||||
@ -40,12 +41,13 @@ class LuaBlockLoader {
|
||||
void loadBlock(const sol::table &table) const;
|
||||
|
||||
private:
|
||||
void loadProperties(ServerBlock &block, const sol::table &table) const;
|
||||
void loadBoundingBox(ServerBlock &block, const sol::table &table) const;
|
||||
void loadDrawType(ServerBlock &block, const sol::table &table) const;
|
||||
void loadItemDrop(ServerBlock &block, const sol::table &table) const;
|
||||
void loadColorMultiplier(ServerBlock &block, const sol::table &table) const;
|
||||
void loadGroups(ServerBlock &block, Item &item, const sol::table &table) const;
|
||||
void loadBlockState(BlockState &state, const sol::table &table, ServerBlock &block) const;
|
||||
void loadProperties(BlockState &state, const sol::table &table) const;
|
||||
void loadBoundingBox(BlockState &state, const sol::table &table) const;
|
||||
void loadDrawType(BlockState &state, const sol::table &table, const ServerBlock &block) const;
|
||||
void loadItemDrop(BlockState &state, const sol::table &table) const;
|
||||
void loadColorMultiplier(BlockState &state, const sol::table &table) const;
|
||||
void loadGroups(ServerBlock &block, const sol::table &table, Item *item = nullptr) const;
|
||||
void loadParams(ServerBlock &block) const;
|
||||
|
||||
LuaMod &m_mod;
|
||||
|
@ -272,9 +272,11 @@ void ServerCommandHandler::setupCallbacks() {
|
||||
ServerWorld &world = getWorldForClient(client.id);
|
||||
world.setData(x, y, z, block >> 16);
|
||||
world.setBlock(x, y, z, block & 0xffff);
|
||||
const Block &blockDef = Registry::getInstance().getBlock(block & 0xffff);
|
||||
|
||||
m_scriptEngine.luaCore().onEvent(LuaEventType::BlockPlaced, glm::ivec3{x, y, z}, blockDef, *player, world, client, *this);
|
||||
const BlockState *blockState = world.getBlockState(x, y, z);
|
||||
if (!blockState) return;
|
||||
|
||||
m_scriptEngine.luaCore().onEvent(LuaEventType::BlockPlaced, glm::ivec3{x, y, z}, blockState, *player, world, client, *this);
|
||||
|
||||
Network::Packet answer;
|
||||
answer << Network::Command::BlockUpdate << x << y << z << block;
|
||||
@ -291,10 +293,11 @@ void ServerCommandHandler::setupCallbacks() {
|
||||
packet >> x >> y >> z;
|
||||
|
||||
ServerWorld &world = getWorldForClient(client.id);
|
||||
const Block &blockDef = Registry::getInstance().getBlock(world.getBlock(x, y, z));
|
||||
const BlockState *blockState = world.getBlockState(x, y, z);
|
||||
if (!blockState) return;
|
||||
world.setBlock(x, y, z, 0);
|
||||
|
||||
m_scriptEngine.luaCore().onEvent(LuaEventType::BlockDigged, glm::ivec3{x, y, z}, blockDef, *player, world, client, *this);
|
||||
m_scriptEngine.luaCore().onEvent(LuaEventType::BlockDigged, glm::ivec3{x, y, z}, blockState, *player, world, client, *this);
|
||||
|
||||
Network::Packet answer;
|
||||
answer << Network::Command::BlockUpdate << x << y << z << u32(0);
|
||||
|
@ -35,7 +35,7 @@
|
||||
void ServerBlock::onTick(const glm::ivec3 &pos, ServerChunk &chunk, ServerWorld &world, ServerCommandHandler &server) const {
|
||||
if (m_onTickEnabled && m_onTick) {
|
||||
try {
|
||||
m_onTick(pos, chunk, world);
|
||||
m_onTick(pos, *this, chunk, world);
|
||||
|
||||
BlockData *blockData = world.getBlockData(pos.x, pos.y, pos.z);
|
||||
if (blockData) {
|
||||
@ -59,7 +59,7 @@ void ServerBlock::onTick(const glm::ivec3 &pos, ServerChunk &chunk, ServerWorld
|
||||
bool ServerBlock::onBlockActivated(const glm::ivec3 &pos, ServerPlayer &player, ServerWorld &world, ClientInfo &client, ServerCommandHandler &server, u16 screenWidth, u16 screenHeight, u8 guiScale) const {
|
||||
try {
|
||||
if (m_onBlockActivated) {
|
||||
m_onBlockActivated(pos, player, world, client, server, screenWidth, screenHeight, guiScale);
|
||||
m_onBlockActivated(pos, *this, player, world, client, server, screenWidth, screenHeight, guiScale);
|
||||
|
||||
// FIXME: Check if data changed before sending
|
||||
BlockData *blockData = world.getBlockData(pos.x, pos.y, pos.z);
|
||||
|
@ -37,8 +37,8 @@ class ServerWorld;
|
||||
|
||||
class ServerBlock : public Block {
|
||||
public:
|
||||
ServerBlock(u32 id, const TilesDef &tiles, const std::string &name, const std::string &label)
|
||||
: Block(id, tiles, name, label) {}
|
||||
ServerBlock(u32 id, const std::string &name)
|
||||
: Block(id, name) {}
|
||||
|
||||
void onTick(const glm::ivec3 &pos, ServerChunk &chunk, ServerWorld &world, ServerCommandHandler &server) const;
|
||||
bool onBlockActivated(const glm::ivec3 &pos, ServerPlayer &player, ServerWorld &world, ClientInfo &client, ServerCommandHandler &server, u16 screenWidth, u16 screenHeight, u8 guiScale) const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user