Item stack limit added (server global + per block/item definition).
This commit is contained in:
parent
103127ee96
commit
a4dfd7a7aa
@ -162,6 +162,17 @@ item_drop = {
|
||||
} -- this is the default drop of a 'default:cobblestone' block
|
||||
```
|
||||
|
||||
### `max_stack_size`
|
||||
|
||||
Max amount of blocks in a stack.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
max_stack_size = 64
|
||||
```
|
||||
|
||||
If not defined, it defaults to the server config.
|
||||
|
||||
### `name`
|
||||
|
||||
Label of the block. **Mandatory field.**
|
||||
|
@ -73,7 +73,7 @@
|
||||
|
||||
## Inventory
|
||||
|
||||
- `void add_stack(string name, u16 amount)`
|
||||
- `ItemStack add_stack(string name, u16 amount)`
|
||||
- `ItemStack get_stack(u16 x, u16 y)`
|
||||
- `void set_stack(u16 x, u16 y, string name, u16 amount)`
|
||||
|
||||
|
@ -70,6 +70,17 @@ Example:
|
||||
mining_speed = 1 -- this is the default value
|
||||
```
|
||||
|
||||
### `max_stack_size`
|
||||
|
||||
Max amount of items in a stack.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
max_stack_size = 64
|
||||
```
|
||||
|
||||
If not defined, it defaults to the server config.
|
||||
|
||||
### `name`
|
||||
|
||||
Label of the item. **Mandatory field.**
|
||||
|
@ -30,6 +30,7 @@ function register_tool(name, material, mining_speed, harvest_capability)
|
||||
id = material .. "_" .. name,
|
||||
name = material:gsub("^%l", string.upper) .. " " .. name:gsub("^%l", string.upper),
|
||||
tiles = material .. "_" .. name .. ".png",
|
||||
max_stack_size = 1,
|
||||
}
|
||||
|
||||
if mining_speed then
|
||||
|
@ -35,7 +35,7 @@ class AbstractInventoryWidget : public Widget {
|
||||
: Widget(parent), m_isReadOnly(isReadOnly) {}
|
||||
|
||||
virtual bool sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) = 0;
|
||||
virtual bool receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *src) = 0;
|
||||
virtual ItemStack receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *src) = 0;
|
||||
|
||||
const std::vector<std::string> &shiftDestination() const { return m_shiftDestination; }
|
||||
void setShiftDestination(const std::string &shiftDestination);
|
||||
|
@ -91,15 +91,15 @@ bool CraftingWidget::sendItemStackToDest(const ItemWidget *itemStack, AbstractIn
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CraftingWidget::receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *) {
|
||||
bool stackAdded = m_craftingInventory.addStack(itemStack->stack().item().stringID(), itemStack->stack().amount());
|
||||
ItemStack CraftingWidget::receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *) {
|
||||
ItemStack stackRet = m_craftingInventory.addStack(itemStack->stack().item().stringID(), itemStack->stack().amount());
|
||||
|
||||
if (stackAdded) {
|
||||
if (stackRet.amount() != itemStack->stack().amount()) {
|
||||
m_craftingInventoryWidget.update();
|
||||
m_craftingInventoryWidget.sendUpdatePacket();
|
||||
}
|
||||
|
||||
return stackAdded;
|
||||
return stackRet;
|
||||
}
|
||||
|
||||
void CraftingWidget::draw(gk::RenderTarget &target, gk::RenderStates states) const {
|
||||
|
@ -42,7 +42,7 @@ class CraftingWidget : public AbstractInventoryWidget {
|
||||
void update() override;
|
||||
|
||||
bool sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) override;
|
||||
bool receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *src) override;
|
||||
ItemStack receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *src) override;
|
||||
|
||||
ItemWidget *currentItemWidget() const { return m_craftingResultInventoryWidget.currentItemWidget() ? m_craftingResultInventoryWidget.currentItemWidget() : m_craftingInventoryWidget.currentItemWidget(); }
|
||||
InventoryWidget *currentInventoryWidget() const { return m_currentInventoryWidget; }
|
||||
|
@ -80,31 +80,32 @@ void InventoryWidget::update() {
|
||||
}
|
||||
|
||||
bool InventoryWidget::sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) {
|
||||
if (dest->doItemMatchFilter(itemStack->stack().item()) && dest->receiveItemStack(itemStack, this)) {
|
||||
if (dest != this)
|
||||
m_inventory->clearStack(itemStack->x(), itemStack->y());
|
||||
if (dest->doItemMatchFilter(itemStack->stack().item())) {
|
||||
ItemStack stackRet = dest->receiveItemStack(itemStack, this);
|
||||
if (stackRet.amount() != itemStack->stack().amount()) {
|
||||
if (dest != this && stackRet.amount() == 0)
|
||||
m_inventory->clearStack(itemStack->x(), itemStack->y());
|
||||
|
||||
update();
|
||||
sendUpdatePacket();
|
||||
return true;
|
||||
update();
|
||||
sendUpdatePacket();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InventoryWidget::receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *src) {
|
||||
ItemStack stack = itemStack->stack();
|
||||
ItemStack InventoryWidget::receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *src) {
|
||||
const ItemStack &stack = itemStack->stack();
|
||||
if (src == this)
|
||||
m_inventory->clearStack(itemStack->x(), itemStack->y());
|
||||
|
||||
bool stackAdded = m_inventory->addStack(stack.item().stringID(), stack.amount(), m_offset, m_size);
|
||||
ItemStack stackRet = m_inventory->addStack(stack.item().stringID(), stack.amount(), m_offset, m_size);
|
||||
|
||||
if (stackAdded)
|
||||
if (stackRet.amount() != stack.amount())
|
||||
sendUpdatePacket();
|
||||
else if (src == this)
|
||||
m_inventory->setStack(itemStack->x(), itemStack->y(), stack.item().stringID(), stack.amount());
|
||||
|
||||
return stackAdded;
|
||||
return stackRet;
|
||||
}
|
||||
|
||||
void InventoryWidget::sendUpdatePacket() {
|
||||
|
@ -48,7 +48,7 @@ class InventoryWidget : public AbstractInventoryWidget {
|
||||
void update() override;
|
||||
|
||||
bool sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) override;
|
||||
bool receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *src) override;
|
||||
ItemStack receiveItemStack(const ItemWidget *itemStack, AbstractInventoryWidget *src) override;
|
||||
|
||||
void sendUpdatePacket();
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "EngineConfig.hpp"
|
||||
#include "InventoryWidget.hpp"
|
||||
#include "MouseItemWidget.hpp"
|
||||
|
||||
@ -81,7 +82,7 @@ void MouseItemWidget::leftClickBehaviour() {
|
||||
if (!m_currentInventoryWidget->inventory()->isUnlimited())
|
||||
swapItems(*currentItemWidget, m_currentInventoryWidget->isReadOnly());
|
||||
else if (getStack().amount() == 0 && currentItemWidget->stack().amount() != 0)
|
||||
setStack(currentItemWidget->stack().item().stringID(), 64);
|
||||
setStack(currentItemWidget->stack().item().stringID(), currentItemWidget->stack().item().maxStackSize());
|
||||
|
||||
m_currentInventoryWidget->sendUpdatePacket();
|
||||
}
|
||||
@ -198,12 +199,19 @@ void MouseItemWidget::swapItems(ItemWidget &widget, bool isReadOnly) {
|
||||
setStack(widgetItemName, widgetItemAmount);
|
||||
}
|
||||
else if (!isReadOnly) {
|
||||
widget.setStack(widgetItemName, widgetItemAmount + stack().amount());
|
||||
setStack("", 0);
|
||||
u16 sum = widgetItemAmount + stack().amount();
|
||||
if (sum > stack().item().maxStackSize()) {
|
||||
widget.setStack(widgetItemName, stack().item().maxStackSize());
|
||||
setStack(widgetItemName, sum - stack().item().maxStackSize());
|
||||
}
|
||||
else {
|
||||
widget.setStack(widgetItemName, sum);
|
||||
setStack(BLOCK_AIR, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setStack(stack().item().stringID(), stack().amount() + widgetItemAmount);
|
||||
widget.setStack("", 0);
|
||||
widget.setStack(BLOCK_AIR, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,8 @@ namespace {
|
||||
static_assert(CHUNK_DEPTH >= -128 && CHUNK_DEPTH < 128, "CHUNK_DEPTH out of range");
|
||||
|
||||
constexpr int SEALEVEL = 4;
|
||||
|
||||
constexpr const char *BLOCK_AIR = "_:air";
|
||||
}
|
||||
|
||||
#endif // ENGINECONFIG_HPP_
|
||||
|
@ -32,25 +32,44 @@ void Inventory::setStack(u16 x, u16 y, const std::string &stringID, u16 amount)
|
||||
m_hasChanged = true;
|
||||
}
|
||||
|
||||
bool Inventory::addStack(const std::string &stringID, u16 amount, u16 offset, u16 size, bool mergeOnly) {
|
||||
for (std::size_t i = offset ; i < (size ? offset + size : m_items.size()) ; ++i) {
|
||||
if (m_items[i].item().id() == 0 && !mergeOnly) {
|
||||
m_items[i] = ItemStack(stringID, amount);
|
||||
ItemStack Inventory::addStack(const std::string &stringID, u16 amount, u16 offset, u16 size, bool mergeOnly) {
|
||||
ItemStack ret{stringID, amount};
|
||||
for (std::size_t i = offset ; ret.amount() && i < (size ? offset + size : m_items.size()) ; ++i) {
|
||||
const Item &item = m_items[i].item();
|
||||
if (item.id() == 0 && !mergeOnly) {
|
||||
if (ret.amount() > item.maxStackSize()) {
|
||||
m_items[i] = ItemStack(stringID, item.maxStackSize());
|
||||
ret.setAmount(ret.amount() - item.maxStackSize());
|
||||
}
|
||||
else {
|
||||
m_items[i] = ItemStack(stringID, ret.amount());
|
||||
ret.setAmount(0);
|
||||
}
|
||||
m_hasChanged = true;
|
||||
return true;
|
||||
}
|
||||
else if (m_items[i].item().stringID() == stringID) {
|
||||
m_items[i] = ItemStack(stringID, m_items[i].amount() + amount);
|
||||
else if (item.stringID() == stringID) {
|
||||
u16 sum = m_items[i].amount() + ret.amount();
|
||||
if (sum > item.maxStackSize()) {
|
||||
m_items[i] = ItemStack(stringID, item.maxStackSize());
|
||||
ret.setAmount(sum - item.maxStackSize());
|
||||
}
|
||||
else {
|
||||
m_items[i] = ItemStack(stringID, sum);
|
||||
ret.setAmount(0);
|
||||
}
|
||||
|
||||
m_hasChanged = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!m_hasChanged && mergeOnly && ret.amount())
|
||||
return addStack(ret.item().stringID(), ret.amount(), offset, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// NOTE: This fonction is only used by Lua since default parameters don't work properly
|
||||
bool Inventory::addStack2(const std::string &stringID, u16 amount) {
|
||||
ItemStack Inventory::addStack2(const std::string &stringID, u16 amount) {
|
||||
return addStack(stringID, amount, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,8 @@ class Inventory : public gk::ISerializable {
|
||||
const ItemStack &getStack(u16 x, u16 y) const { return m_items.at(x + y * m_width); }
|
||||
ItemStack &getStackRef(u16 x, u16 y) { return m_items.at(x + y * m_width); }
|
||||
void setStack(u16 x, u16 y, const std::string &stringID, u16 amount = 1);
|
||||
bool addStack(const std::string &stringID, u16 amount = 1, u16 offset = 0, u16 size = 0, bool mergeOnly = false);
|
||||
bool addStack2(const std::string &stringID, u16 amount = 1); // Needed for Lua
|
||||
ItemStack addStack(const std::string &stringID, u16 amount = 1, u16 offset = 0, u16 size = 0, bool mergeOnly = false);
|
||||
ItemStack addStack2(const std::string &stringID, u16 amount = 1); // Needed for Lua
|
||||
void clearStack(u16 x, u16 y);
|
||||
|
||||
void serialize(sf::Packet &packet) const override;
|
||||
|
@ -38,13 +38,13 @@ Item::Item(u32 id, const TilesDef &tiles, const std::string &stringID, const std
|
||||
void Item::serialize(sf::Packet &packet) const {
|
||||
packet << m_id << m_tiles << m_stringID << m_label << m_isBlock
|
||||
<< m_miningSpeed << m_harvestCapability << m_groups << m_canBeActivated
|
||||
<< m_effectiveOn;
|
||||
<< m_effectiveOn << m_maxStackSize;
|
||||
}
|
||||
|
||||
void Item::deserialize(sf::Packet &packet) {
|
||||
packet >> m_id >> m_tiles >> m_stringID >> m_label >> m_isBlock
|
||||
>> m_miningSpeed >> m_harvestCapability >> m_groups >> m_canBeActivated
|
||||
>> m_effectiveOn;
|
||||
>> m_effectiveOn >> m_maxStackSize;
|
||||
}
|
||||
|
||||
// Please update 'docs/lua-api-cpp.md' if you change this
|
||||
|
@ -76,6 +76,9 @@ class Item : public gk::ISerializable {
|
||||
const std::vector<std::string> &effectiveOn() const { return m_effectiveOn; }
|
||||
void addEffectiveBlock(const std::string &blockID) { m_effectiveOn.emplace_back(blockID); }
|
||||
|
||||
u16 maxStackSize() const { return m_maxStackSize; }
|
||||
void setMaxStackSize(u16 maxStackSize) { m_maxStackSize = maxStackSize; }
|
||||
|
||||
static void initUsertype(sol::state &lua);
|
||||
|
||||
protected:
|
||||
@ -96,6 +99,8 @@ class Item : public gk::ISerializable {
|
||||
std::unordered_map<std::string, u16> m_groups;
|
||||
|
||||
std::vector<std::string> m_effectiveOn;
|
||||
|
||||
u16 m_maxStackSize = 64;
|
||||
};
|
||||
|
||||
#endif // ITEM_HPP_
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
// Server
|
||||
u8 ServerConfig::maxPlayers = 5;
|
||||
u16 ServerConfig::maxItemStackSize = 64;
|
||||
|
||||
// Mod-defined options
|
||||
std::unordered_map<std::string, sol::object> ServerConfig::options;
|
||||
@ -45,6 +46,7 @@ void ServerConfig::loadConfigFromFile(const char *file) {
|
||||
lua.safe_script_file(file);
|
||||
|
||||
maxPlayers = lua["max_players"].get_or(maxPlayers);
|
||||
maxItemStackSize = lua["max_item_stack_size"].get_or(maxItemStackSize);
|
||||
|
||||
if (lua["mod_options"].valid() && lua["mod_options"].get_type() == sol::type::table) {
|
||||
for (auto &it : lua["mod_options"].get<sol::table>()) {
|
||||
@ -63,6 +65,7 @@ void ServerConfig::loadConfigFromFile(const char *file) {
|
||||
void ServerConfig::saveConfigToFile(const char *filename) {
|
||||
std::ofstream file{filename, std::ofstream::out | std::ofstream::trunc};
|
||||
file << "max_players = " << (u16)maxPlayers << std::endl;
|
||||
file << "max_item_stack_size = " << maxItemStackSize << std::endl;
|
||||
file << "mod_options = {" << std::endl;
|
||||
|
||||
for (auto &it : options) {
|
||||
|
@ -37,6 +37,7 @@
|
||||
namespace ServerConfig {
|
||||
// Server
|
||||
extern u8 maxPlayers;
|
||||
extern u16 maxItemStackSize;
|
||||
|
||||
// Mod-defined options
|
||||
extern std::unordered_map<std::string, sol::object> options;
|
||||
|
@ -109,8 +109,9 @@ void LuaMod::despawnEntity(EntityWrapper &entity) {
|
||||
void LuaMod::giveItemStack(ServerPlayer &player, ItemStack *itemStack) {
|
||||
if (itemStack) {
|
||||
// FIXME: This should probably be moved to a mod
|
||||
if (!player.inventory().addStack(itemStack->item().stringID(), itemStack->amount(), 9, 24, true))
|
||||
player.inventory().addStack(itemStack->item().stringID(), itemStack->amount(), 0, 9);
|
||||
ItemStack stackRet = player.inventory().addStack(itemStack->item().stringID(), itemStack->amount(), 9, 24, true);
|
||||
if (stackRet.amount() != 0)
|
||||
player.inventory().addStack(stackRet.item().stringID(), stackRet.amount(), 0, 9);
|
||||
|
||||
m_worldController.server()->sendPlayerInvUpdate(player.clientID(), player.client());
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "LuaMod.hpp"
|
||||
#include "Registry.hpp"
|
||||
#include "ServerBlock.hpp"
|
||||
#include "ServerConfig.hpp"
|
||||
|
||||
void LuaBlockLoader::loadBlock(const sol::table &table) const {
|
||||
std::string stringID = m_mod.id() + ":" + table["id"].get<std::string>();
|
||||
@ -57,6 +58,7 @@ void LuaBlockLoader::loadBlock(const sol::table &table) const {
|
||||
}
|
||||
|
||||
item->setIsBlock(true);
|
||||
item->setMaxStackSize(table["max_stack_size"].get_or(ServerConfig::maxItemStackSize));
|
||||
|
||||
loadGroups(block, table, item);
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "LuaItemLoader.hpp"
|
||||
#include "LuaMod.hpp"
|
||||
#include "Registry.hpp"
|
||||
#include "ServerConfig.hpp"
|
||||
#include "ServerItem.hpp"
|
||||
|
||||
void LuaItemLoader::loadItem(const sol::table &table) const {
|
||||
@ -42,6 +43,7 @@ void LuaItemLoader::loadItem(const sol::table &table) const {
|
||||
item.setHarvestCapability(table["harvest_capability"].get_or(0));
|
||||
item.setMiningSpeed(table["mining_speed"].get_or(1));
|
||||
item.setOnItemActivated(table["on_item_activated"]);
|
||||
item.setMaxStackSize(table["max_stack_size"].get_or(ServerConfig::maxItemStackSize));
|
||||
|
||||
sol::object groupsObject = table["groups"];
|
||||
if (groupsObject.valid()) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user