Added seeds and wheat. You can grow wheat but it's quite clunky atm.

This commit is contained in:
Quentin Bazin 2020-07-05 23:32:24 +02:00
parent 084a002a6d
commit 14e23dc83d
36 changed files with 173 additions and 47 deletions

View File

@ -162,6 +162,26 @@ name = "Cobblestone"
This label is the name that will appear everywhere in the game.
### `tick_probability`
Probability to call the `on_tick` function when `tick_randomly` is enabled.
Example:
```lua
tick_probability = 0.5 -- 50%
```
### `tick_randomly`
Whether or not the block `on_tick` function is executed randomly.
See also `tick_probability`.
Example:
```lua
tick_randomly = true
```
### `tiles`
This field can be either a single string, or a table of strings.
@ -243,8 +263,8 @@ Useful for flora, tallgrass, mushrooms, etc...
Parameters:
- `pos` (`ivec3`): position of the block
- `player` (`Player`): player that activated the block
- `world` (`World`): instance of the `ServerWorld`
- `player` (`ServerPlayer`): player that activated the block
- `world` (`ServerWorld`): instance of the world
- `client` (`Client`): client that activated the block
- `server` (`Server`): current server
- `screen_width` (`u16`): width of the screen
@ -256,20 +276,20 @@ Parameters:
Parameters:
- `pos` (`ivec3`): position of the block
- `world` (`World`): instance of `ServerWorld`
- `world` (`ServerWorld`): instance of the world
### `on_block_placed`
Parameters:
- `pos` (`ivec3`): position of the block
- `world` (`World`): instance of `ServerWorld`
- `world` (`ServerWorld`): instance of the world
### `on_tick`
Parameters:
- `pos` (`ivec3`): position of the block
- `chunk` (`Chunk`): current chunk
- `world` (`World`): instance of the `ServerWorld`
- `chunk` (`ServerChunk`): current chunk
- `world` (`ServerWorld`): instance of the world

View File

@ -149,7 +149,7 @@ mod:block {
id = "dandelion",
name = "Dandelion",
tiles = "dandelion.png",
hardness = 0.05,
hardness = 0,
draw_type = "xshape",
bounding_box = {0.25, 0.25, 0.0, 0.5, 0.5, 0.5},
}
@ -159,7 +159,7 @@ mod:block {
name = "Grass",
tiles = "grass.png",
color_multiplier = {129, 191, 91, 255},
hardness = 0.05,
hardness = 0,
draw_type = "xshape",
}
@ -352,6 +352,49 @@ mod:block {
bounding_box = {0, 0, 0, 1, 1, 15 / 16},
}
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,
tick_randomly = true,
tick_probability = 0.01,
on_block_placed = function(pos, world)
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)
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)
-- FIXME: It should drop the item if 'default:use_item_drops' is enabled
local item_stack = ItemStack.new("default:wheat", 1)
mods["default"]:give_item_stack(player, item_stack)
end
end
}
dofile("blocks/workbench.lua")
dofile("blocks/furnace.lua")
dofile("blocks/door.lua")

View File

@ -320,3 +320,16 @@ mod:item {
end
end
}
mod:item {
id = "wheat",
name = "Wheat",
tiles = "wheat.png",
}
mod:item {
id = "bread",
name = "Bread",
tiles = "bread.png",
}

View File

@ -635,3 +635,14 @@ mod:crafting_recipe {
keys = {["#"] = "default:oak_planks"}
}
-- Bread
mod:crafting_recipe {
result = {
id = "default:bread",
amount = 1
},
pattern = {
"###",
},
keys = {["#"] = "default:wheat"}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

View File

@ -286,7 +286,10 @@ 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]) {
const gk::FloatRect &blockTexCoords = m_textureAtlas.getTexCoords(block.tiles().getTextureForFace(0));
const BlockData *blockData = chunk.getBlockData(x, y, z);
const std::string &texture = block.tiles().getTextureForFace(0, blockData ? blockData->useAltTiles : false);
const gk::FloatRect &blockTexCoords = m_textureAtlas.getTexCoords(texture);
float faceTexCoords[nVertsPerFace][nCoordsPerUV] = {
{blockTexCoords.x, blockTexCoords.y + blockTexCoords.sizeY},
{blockTexCoords.x + blockTexCoords.sizeX, blockTexCoords.y + blockTexCoords.sizeY},

View File

@ -34,6 +34,7 @@ const Item &ItemStack::item() const {
// Please update 'docs/lua-api-cpp.md' if you change this
void ItemStack::initUsertype(sol::state &lua) {
lua.new_usertype<ItemStack>("ItemStack",
sol::constructors<ItemStack(const std::string &, u16)>(),
"amount", &ItemStack::amount,
"item", &ItemStack::item
);

View File

@ -72,15 +72,6 @@ void Chunk::setBlock(int x, int y, int z, u16 type) {
if ((m_data[z][y][x] & 0xffff) == type) return;
const Block &block = Registry::getInstance().getBlock(type);
if (block.canUpdate()) {
addTickingBlock(x, y, z, block);
}
else {
auto it = m_tickingBlocks.find(gk::Vector3i{x, y, z});
if (it != m_tickingBlocks.end())
m_tickingBlocks.erase(it);
}
if (block.isLightSource())
m_lightmap.addTorchlight(x, y, z, 14);
else {

View File

@ -83,8 +83,6 @@ class Chunk : public gk::NonCopyable {
bool areAllNeighboursLoaded() const;
bool areAllNeighboursInitialized() const;
void addTickingBlock(int x, int y, int z, const Block &block) { m_tickingBlocks.emplace(gk::Vector3i{x, y, z}, block); }
bool hasChanged() const { return m_hasChanged; }
void setChanged(bool hasChanged) { m_hasChanged = hasChanged; }
@ -126,7 +124,6 @@ class Chunk : public gk::NonCopyable {
std::atomic_bool m_hasLightChanged{false};
std::atomic_bool m_isInitialized{false};
std::unordered_map<gk::Vector3i, const Block&> m_tickingBlocks;
std::unordered_map<gk::Vector3i, std::unique_ptr<BlockData>> m_blockData;
};

View File

@ -71,6 +71,8 @@ inline void LuaBlockLoader::loadProperties(ServerBlock &block, const sol::table
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));
if (block.fogDepth()) {
sol::optional<sol::table> fogColor = table["fog_color"];

View File

@ -29,11 +29,12 @@
#include "ServerBlock.hpp"
#include "ServerCommandHandler.hpp"
#include "ServerPlayer.hpp"
#include "ServerWorld.hpp"
#include "World.hpp"
void ServerBlock::onTick(const glm::ivec3 &pos, Chunk &chunk, World &world, ServerCommandHandler &server) const {
try {
if (m_onTick && m_onTickEnabled) {
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);
BlockData *blockData = world.getBlockData(pos.x, pos.y, pos.z);
@ -47,18 +48,24 @@ void ServerBlock::onTick(const glm::ivec3 &pos, Chunk &chunk, World &world, Serv
}
}
}
}
catch (const sol::error &e) {
m_onTickEnabled = false;
gkError() << e.what();
gkError() << "Block stopped ticking at (" << pos.x << ", " << pos.y << ", " << pos.z << ")";
catch (const sol::error &e) {
m_onTickEnabled = false;
gkError() << e.what();
gkError() << "Block stopped ticking at (" << pos.x << ", " << pos.y << ", " << pos.z << ")";
}
}
}
bool ServerBlock::onBlockActivated(const glm::ivec3 &pos, Player &player, World &world, ClientInfo &client, ServerCommandHandler &server, u16 screenWidth, u16 screenHeight, u8 guiScale) const {
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);
// FIXME: Check if data changed before sending
BlockData *blockData = world.getBlockData(pos.x, pos.y, pos.z);
if (blockData)
server.sendBlockDataUpdate(pos.x, pos.y, pos.z, blockData);
return true;
}
}
@ -69,7 +76,7 @@ bool ServerBlock::onBlockActivated(const glm::ivec3 &pos, Player &player, World
return false;
}
void ServerBlock::onBlockPlaced(const glm::ivec3 &pos, World &world) const {
void ServerBlock::onBlockPlaced(const glm::ivec3 &pos, ServerWorld &world) const {
try {
if (m_onBlockPlaced) {
m_onBlockPlaced(pos, world);
@ -80,7 +87,7 @@ void ServerBlock::onBlockPlaced(const glm::ivec3 &pos, World &world) const {
}
}
void ServerBlock::onBlockDestroyed(const glm::ivec3 &pos, World &world) const {
void ServerBlock::onBlockDestroyed(const glm::ivec3 &pos, ServerWorld &world) const {
try {
if (m_onBlockDestroyed) {
m_onBlockDestroyed(pos, world);

View File

@ -30,18 +30,20 @@
#include "Block.hpp"
class ClientInfo;
class ServerChunk;
class ServerCommandHandler;
class ServerPlayer;
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) {}
void onTick(const glm::ivec3 &, Chunk &, World &, ServerCommandHandler &) const;
bool onBlockActivated(const glm::ivec3 &pos, Player &player, World &world, ClientInfo &client, ServerCommandHandler &server, u16 screenWidth, u16 screenHeight, u8 guiScale) const;
void onBlockPlaced(const glm::ivec3 &pos, World &world) const;
void onBlockDestroyed(const glm::ivec3 &pos, World &world) const;
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;
void onBlockPlaced(const glm::ivec3 &pos, ServerWorld &world) const;
void onBlockDestroyed(const glm::ivec3 &pos, ServerWorld &world) const;
bool canUpdate() const { return m_onTick.valid(); }
@ -50,6 +52,12 @@ class ServerBlock : public Block {
void setOnBlockPlaced(const sol::protected_function &function) { m_onBlockPlaced = function; }
void setOnBlockDestroyed(const sol::protected_function &function) { m_onBlockDestroyed = function; }
bool isTickingRandomly() const { return m_isTickingRandomly; }
void setTickRandomly(bool isTickingRandomly) { m_isTickingRandomly = isTickingRandomly; }
float tickProbability() const { return m_tickProbability; }
void setTickProbability(float tickProbability) { m_tickProbability = tickProbability; }
static void initUsertype(sol::state &lua);
private:
@ -59,6 +67,9 @@ class ServerBlock : public Block {
sol::unsafe_function m_onBlockDestroyed;
mutable bool m_onTickEnabled = true;
bool m_isTickingRandomly = false;
float m_tickProbability = 0.f;
};
#endif // SERVERBLOCK_HPP_

View File

@ -30,6 +30,10 @@
#include "ServerCommandHandler.hpp"
#include "World.hpp"
ServerChunk::ServerChunk(s32 x, s32 y, s32 z, World &world) : Chunk(x, y, z, world) {
m_random.seed(std::time(nullptr));
}
void ServerChunk::updateLights() {
if (m_lightmap.updateLights() || m_hasChanged) {
m_isSent = false;
@ -39,14 +43,23 @@ void ServerChunk::updateLights() {
void ServerChunk::onBlockPlaced(int x, int y, int z, const Block &block) {
const ServerBlock &serverBlock = (ServerBlock &)block;
serverBlock.onBlockPlaced(glm::ivec3{x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH, z + m_z * CHUNK_HEIGHT}, m_world);
if (block.canUpdate()) {
addTickingBlock(x, y, z, serverBlock);
}
else {
auto it = m_tickingBlocks.find(gk::Vector3i{x, y, z});
if (it != m_tickingBlocks.end())
m_tickingBlocks.erase(it);
}
serverBlock.onBlockPlaced(glm::ivec3{x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH, z + m_z * CHUNK_HEIGHT}, (ServerWorld &)m_world);
m_hasBeenModified = true;
}
void ServerChunk::onBlockDestroyed(int x, int y, int z, const Block &block) {
const ServerBlock &serverBlock = (ServerBlock &)block;
serverBlock.onBlockDestroyed(glm::ivec3{x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH, z + m_z * CHUNK_HEIGHT}, m_world);
serverBlock.onBlockDestroyed(glm::ivec3{x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH, z + m_z * CHUNK_HEIGHT}, (ServerWorld &)m_world);
m_hasBeenModified = true;
}
@ -54,13 +67,15 @@ void ServerChunk::onBlockDestroyed(int x, int y, int z, const Block &block) {
void ServerChunk::tick(World &world, ServerCommandHandler &server) {
if (!m_tickingBlocks.empty()) {
for (auto &it : m_tickingBlocks) {
((ServerBlock &)it.second).onTick(
glm::ivec3{
it.first.x + m_x * width,
it.first.y + m_y * depth,
it.first.z + m_z * height
},
*this, world, server);
if (!it.second.isTickingRandomly() || m_random.get<bool>(it.second.tickProbability())) {
it.second.onTick(
glm::ivec3{
it.first.x + m_x * width,
it.first.y + m_y * depth,
it.first.z + m_z * height
},
*this, (ServerWorld &)world, server);
}
}
}
}

View File

@ -31,14 +31,19 @@
#include <gk/core/IntTypes.hpp>
#include <random.hpp>
#include "Chunk.hpp"
using Random_t = effolkronium::random_local;
class ServerBlock;
class ServerCommandHandler;
class ServerPlayer;
class ServerChunk : public Chunk {
public:
ServerChunk(s32 x, s32 y, s32 z, World &world) : Chunk(x, y, z, world) {}
ServerChunk(s32 x, s32 y, s32 z, World &world);
void updateLights();
@ -53,9 +58,15 @@ class ServerChunk : public Chunk {
bool hasBeenModified() const { return m_hasBeenModified; }
void setModified(bool hasBeenModified) { m_hasBeenModified = hasBeenModified; }
void addTickingBlock(int x, int y, int z, const ServerBlock &block) { m_tickingBlocks.emplace(gk::Vector3i{x, y, z}, block); }
private:
std::atomic_bool m_isSent{false};
std::atomic_bool m_hasBeenModified{false};
Random_t m_random;
std::unordered_map<gk::Vector3i, const ServerBlock &> m_tickingBlocks;
};
#endif // SERVERCHUNK_HPP_

View File

@ -34,6 +34,7 @@
#include "Network.hpp"
#include "NetworkComponent.hpp"
#include "Registry.hpp"
#include "ServerBlock.hpp"
#include "ServerWorld.hpp"
#include "WorldSaveBasicBackend.hpp"
@ -87,7 +88,7 @@ void WorldSaveBasicBackend::load(const std::string &name) {
chunk.setData(x, y, z, data >> 16);
chunk.lightmap().setLightData(x, y, z, light);
const Block &block = Registry::getInstance().getBlock(data & 0xffff);
const ServerBlock &block = (ServerBlock &)Registry::getInstance().getBlock(data & 0xffff);
if (block.canUpdate())
chunk.addTickingBlock(x, y, z, block);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B