[LuaGUIState] Now handles Shift+Left click to move items quickly.

This commit is contained in:
Quentin Bazin 2020-03-01 00:15:49 +01:00
parent 7ce30d3e5b
commit 4d9a2fbe7e
20 changed files with 221 additions and 50 deletions

View File

@ -0,0 +1,46 @@
/*
* =====================================================================================
*
* 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 ABSTRACTINVENTORYWIDGET_HPP_
#define ABSTRACTINVENTORYWIDGET_HPP_
#include "ItemWidget.hpp"
class AbstractInventoryWidget : public Widget {
public:
AbstractInventoryWidget(Widget *parent) : Widget(parent) {}
virtual void sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) = 0;
virtual bool receiveItemStack(const ItemWidget *itemStack) = 0;
const std::string &shiftDestination() const { return m_shiftDestination; }
void setShiftDestination(const std::string &shiftDestination) { m_shiftDestination = shiftDestination; }
private:
std::string m_shiftDestination;
};
#endif // ABSTRACTINVENTORYWIDGET_HPP_

View File

@ -28,22 +28,25 @@
#include "Registry.hpp"
CraftingWidget::CraftingWidget(ClientCommandHandler &client, Inventory &craftingInventory, Widget *parent)
: Widget(parent), m_client(client), m_craftingInventory(craftingInventory)
: AbstractInventoryWidget(parent), m_client(client), m_craftingInventory(craftingInventory)
{
}
void CraftingWidget::init(unsigned int offset, unsigned int size) {
m_craftingInventoryWidget.init(m_craftingInventory, offset, size * size);
// m_craftingInventoryWidget.setPosition(29, 16, 0);
m_craftingResultInventoryWidget.init(m_craftingResultInventory);
// m_craftingResultInventoryWidget.setPosition(123, 34, 0);
m_craftingInventoryWidget.setParent(this);
m_craftingResultInventoryWidget.setParent(this);
}
void CraftingWidget::onMouseEvent(const SDL_Event &event, MouseItemWidget &mouseItemWidget) {
m_craftingInventoryWidget.onMouseEvent(event, mouseItemWidget);
m_craftingResultInventoryWidget.onMouseEvent(event, mouseItemWidget, true);
m_currentInventoryWidget = m_craftingResultInventoryWidget.currentItemWidget()
? &m_craftingResultInventoryWidget : &m_craftingInventoryWidget;
if (m_recipe && !m_craftingResultInventory.getStack(0, 0).item().id()) {
for (u8 x = 0 ; x < m_craftingInventory.width() ; ++x) {
for (u8 y = 0 ; y < m_craftingInventory.height() ; ++y) {
@ -77,6 +80,25 @@ void CraftingWidget::update() {
}
}
void CraftingWidget::sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) {
if (m_currentInventoryWidget && dest->receiveItemStack(itemStack)) {
m_currentInventoryWidget->inventory()->clearStack(itemStack->x(), itemStack->y());
m_currentInventoryWidget->update();
m_currentInventoryWidget->sendUpdatePacket();
}
}
bool CraftingWidget::receiveItemStack(const ItemWidget *itemStack) {
bool stackAdded = m_craftingInventory.addStack(itemStack->stack().item().stringID(), itemStack->stack().amount());
if (stackAdded) {
m_craftingInventoryWidget.update();
m_craftingInventoryWidget.sendUpdatePacket();
}
return stackAdded;
}
void CraftingWidget::draw(gk::RenderTarget &target, gk::RenderStates states) const {
states.transform *= getTransform();

View File

@ -31,7 +31,7 @@
class Recipe;
class CraftingWidget : public Widget {
class CraftingWidget : public AbstractInventoryWidget {
public:
CraftingWidget(ClientCommandHandler &client, Inventory &craftingInventory, Widget *parent = nullptr);
@ -41,23 +41,27 @@ class CraftingWidget : public Widget {
void update() override;
void sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) override;
bool receiveItemStack(const ItemWidget *itemStack) override;
const ItemWidget *currentItemWidget() const { return m_craftingResultInventoryWidget.currentItemWidget() ? m_craftingResultInventoryWidget.currentItemWidget() : m_craftingInventoryWidget.currentItemWidget(); }
InventoryWidget &craftingInventoryWidget() { return m_craftingInventoryWidget; }
InventoryWidget &craftingResultInventoryWidget() { return m_craftingResultInventoryWidget; }
protected:
ClientCommandHandler &m_client;
Inventory &m_craftingInventory;
InventoryWidget m_craftingInventoryWidget{m_client, this};
Inventory m_craftingResultInventory{1, 1};
InventoryWidget m_craftingResultInventoryWidget{m_client, this};
private:
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;
ClientCommandHandler &m_client;
InventoryWidget *m_currentInventoryWidget = nullptr;
Inventory &m_craftingInventory;
InventoryWidget m_craftingInventoryWidget{m_client};
Inventory m_craftingResultInventory{1, 1};
InventoryWidget m_craftingResultInventoryWidget{m_client};
const Recipe *m_recipe = nullptr;
};

View File

@ -83,6 +83,23 @@ void InventoryWidget::update() {
it.update();
}
void InventoryWidget::sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) {
if (dest->receiveItemStack(itemStack)) {
m_inventory->clearStack(itemStack->x(), itemStack->y());
update();
sendUpdatePacket();
}
}
bool InventoryWidget::receiveItemStack(const ItemWidget *itemStack) {
bool stackAdded = m_inventory->addStack(itemStack->stack().item().stringID(), itemStack->stack().amount());
if (stackAdded)
sendUpdatePacket();
return stackAdded;
}
void InventoryWidget::sendUpdatePacket() {
if (m_inventory->inBlock()) {
m_client.sendBlockInvUpdate(*m_inventory);

View File

@ -29,14 +29,15 @@
#include <gk/graphics/RectangleShape.hpp>
#include "AbstractInventoryWidget.hpp"
#include "MouseItemWidget.hpp"
class ClientCommandHandler;
class InventoryWidget : public Widget {
class InventoryWidget : public AbstractInventoryWidget {
public:
InventoryWidget(ClientCommandHandler &client, Widget *parent = nullptr)
: Widget(parent), m_client(client) {}
: AbstractInventoryWidget(parent), m_client(client) {}
void init(Inventory &inventory, unsigned int offset = 0, unsigned int size = 0);
@ -44,13 +45,18 @@ class InventoryWidget : public Widget {
void update() override;
void sendItemStackToDest(const ItemWidget *itemStack, AbstractInventoryWidget *dest) override;
bool receiveItemStack(const ItemWidget *itemStack) override;
void sendUpdatePacket();
Inventory *inventory() { return m_inventory; }
const ItemWidget *currentItemWidget() const { return m_currentItemWidget; }
private:
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;
void sendUpdatePacket();
ClientCommandHandler &m_client;
Inventory *m_inventory = nullptr;

View File

@ -44,6 +44,9 @@ class ItemWidget : public Widget {
const ItemStack &stack() const { return m_inventory.getStack(m_x, m_y); }
void setStack(const std::string &name, unsigned int amount = 1);
unsigned int x() const { return m_x; }
unsigned int y() const { return m_y; }
protected:
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;

View File

@ -38,6 +38,7 @@ class MouseItemWidget : public ItemWidget {
void onEvent(const SDL_Event &event) override;
const ItemWidget *currentItemWidget() const { return m_currentItemWidget; }
void updateCurrentItem(const ItemWidget *currentItemWidget);
void swapItems(ItemWidget &widget, bool isReadOnly = false);

View File

@ -45,7 +45,7 @@ class Widget : public gk::Drawable, public gk::Transformable {
gk::FloatRect getGlobalBounds() const;
const Widget *parent() { return m_parent; }
const Widget *parent() const { return m_parent; }
void setParent(Widget *parent) { m_parent = parent; }
unsigned int width() const { return m_width; }

View File

@ -28,12 +28,14 @@
#include <gk/core/ApplicationStateStack.hpp>
#include <gk/core/Debug.hpp>
#include <gk/core/input/GamePad.hpp>
#include <gk/core/Mouse.hpp>
#include <gk/graphics/Color.hpp>
#include "ClientPlayer.hpp"
#include "ClientWorld.hpp"
#include "Config.hpp"
#include "GameKey.hpp"
#include "InventoryWidget.hpp"
#include "LuaGUIState.hpp"
#include "LuaWidget.hpp"
@ -69,13 +71,37 @@ void LuaGUIState::onEvent(const SDL_Event &event) {
for (auto &it : m_widgets)
it->onEvent(event);
for (auto &it : m_inventoryWidgets)
it.onMouseEvent(event, m_mouseItemWidget, false);
if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT
&& m_currentInventoryWidget && !m_currentInventoryWidget->shiftDestination().empty()
&& m_mouseItemWidget.currentItemWidget() && gk::GamePad::isKeyPressed(GameKey::Shift)) {
AbstractInventoryWidget *dest = nullptr;
for (auto &it : m_craftingWidgets)
it.onMouseEvent(event, m_mouseItemWidget);
auto it = m_craftingWidgets.find(m_currentInventoryWidget->shiftDestination());
if (it != m_craftingWidgets.end())
dest = &it->second;
m_mouseItemWidget.onEvent(event);
if (!dest) {
auto it = m_inventoryWidgets.find(m_currentInventoryWidget->shiftDestination());
if (it != m_inventoryWidgets.end())
dest = &it->second;
}
if (!dest) {
DEBUG("ERROR: Destination not found: '" + m_currentInventoryWidget->shiftDestination() + "'");
return;
}
m_currentInventoryWidget->sendItemStackToDest(m_mouseItemWidget.currentItemWidget(), dest);
}
else {
for (auto &it : m_inventoryWidgets)
it.second.onMouseEvent(event, m_mouseItemWidget, false);
for (auto &it : m_craftingWidgets)
it.second.onMouseEvent(event, m_mouseItemWidget);
m_mouseItemWidget.onEvent(event);
}
}
void LuaGUIState::update() {
@ -85,21 +111,24 @@ void LuaGUIState::update() {
it->update();
for (auto &it : m_craftingWidgets) {
it.update();
it.second.update();
}
for (auto &it : m_inventoryWidgets) {
it.update();
it.second.update();
}
const ItemWidget *currentItemWidget = nullptr;
m_currentInventoryWidget = nullptr;
for (auto &it : m_inventoryWidgets) {
if (!currentItemWidget)
currentItemWidget = it.currentItemWidget();
if (!currentItemWidget && ((currentItemWidget = it.second.currentItemWidget()))) {
m_currentInventoryWidget = &it.second;
}
}
for (auto &it : m_craftingWidgets) {
if (!currentItemWidget)
currentItemWidget = it.currentItemWidget();
if (!currentItemWidget && ((currentItemWidget = it.second.currentItemWidget()))) {
m_currentInventoryWidget = &it.second;
}
}
m_mouseItemWidget.updateCurrentItem(currentItemWidget);
@ -121,10 +150,10 @@ void LuaGUIState::draw(gk::RenderTarget &target, gk::RenderStates states) const
target.draw(*it, states);
for (auto &it : m_inventoryWidgets)
target.draw(it, states);
target.draw(it.second, states);
for (auto &it : m_craftingWidgets)
target.draw(it, states);
target.draw(it.second, states);
target.draw(m_mouseItemWidget, states);
}
@ -175,12 +204,12 @@ void LuaGUIState::loadTextButton(const std::string &, s32 x, s32 y, sf::Packet &
}
void LuaGUIState::loadInventoryWidget(const std::string &name, s32 x, s32 y, sf::Packet &packet) {
std::string inventory, playerName, inventory_name;
std::string inventory, playerName, inventory_name, shiftDestination;
gk::Vector3i block;
u16 width, height;
u16 offset, count;
packet >> inventory >> playerName >> inventory_name
>> block.x >> block.y >> block.z
>> block.x >> block.y >> block.z >> shiftDestination
>> width >> height >> offset >> count;
Inventory *widgetInventory = nullptr;
@ -211,23 +240,25 @@ void LuaGUIState::loadInventoryWidget(const std::string &name, s32 x, s32 y, sf:
}
if (widgetInventory) {
m_inventoryWidgets.emplace_back(m_client, &m_mainWidget);
m_inventoryWidgets.emplace(name, InventoryWidget{m_client, &m_mainWidget});
auto &inventoryWidget = m_inventoryWidgets.back();
auto &inventoryWidget = m_inventoryWidgets.at(name);
inventoryWidget.setPosition(x, y);
inventoryWidget.init(*widgetInventory, offset, count);
inventoryWidget.setShiftDestination(shiftDestination);
}
else {
DEBUG("ERROR: Inventory widget '" + name + "' is invalid");
}
}
void LuaGUIState::loadCraftingWidget(const std::string &, s32 x, s32 y, sf::Packet &packet) {
std::string inventory;
void LuaGUIState::loadCraftingWidget(const std::string &name, s32 x, s32 y, sf::Packet &packet) {
std::string inventory, shiftDestination;
gk::Vector3i block;
u16 offset, size;
s32 resultX, resultY;
packet >> inventory >> block.x >> block.y >> block.z >> offset >> size >> resultX >> resultY;
packet >> inventory >> block.x >> block.y >> block.z >> offset >> size
>> shiftDestination >> resultX >> resultY;
Inventory *craftingInventory = nullptr;
if (inventory == "block") {
@ -245,12 +276,13 @@ void LuaGUIState::loadCraftingWidget(const std::string &, s32 x, s32 y, sf::Pack
}
if (craftingInventory) {
m_craftingWidgets.emplace_back(m_client, *craftingInventory, &m_mainWidget);
m_craftingWidgets.emplace(name, CraftingWidget{m_client, *craftingInventory, &m_mainWidget});
auto &craftingWidget = m_craftingWidgets.back();
auto &craftingWidget = m_craftingWidgets.at(name);
craftingWidget.init(offset, size);
craftingWidget.craftingInventoryWidget().setPosition(x, y);
craftingWidget.craftingResultInventoryWidget().setPosition(resultX, resultY);
craftingWidget.setShiftDestination(shiftDestination);
}
else {
DEBUG("ERROR: Crafting inventory is invalid");

View File

@ -64,9 +64,10 @@ class LuaGUIState : public InterfaceState {
Widget m_mainWidget;
MouseItemWidget m_mouseItemWidget{&m_mainWidget};
AbstractInventoryWidget *m_currentInventoryWidget = nullptr;
std::deque<CraftingWidget> m_craftingWidgets;
std::deque<InventoryWidget> m_inventoryWidgets;
std::unordered_map<std::string, CraftingWidget> m_craftingWidgets;
std::unordered_map<std::string, InventoryWidget> m_inventoryWidgets;
std::vector<std::unique_ptr<Widget>> m_widgets;
std::vector<std::unique_ptr<gk::Drawable>> m_drawables;
std::unordered_map<std::string, Inventory> m_inventories;

View File

@ -70,7 +70,7 @@ class ClientWorld : public World, public gk::Drawable {
ClientCommandHandler *m_client = nullptr;
gk::Camera *m_camera = nullptr;
mutable float m_ud = 1000;
mutable float m_ud = 1000000.0;
mutable s32 m_ux;
mutable s32 m_uy;
mutable s32 m_uz;

View File

@ -49,6 +49,8 @@ namespace GameKey {
Chat,
Command,
Shift,
};
}

View File

@ -32,19 +32,25 @@ void Inventory::setStack(u16 x, u16 y, const std::string &stringID, u16 amount)
m_hasChanged = true;
}
void Inventory::addStack(const std::string &stringID, u16 amount) {
bool Inventory::addStack(const std::string &stringID, u16 amount) {
for (std::size_t i = 0 ; i < m_items.size() ; ++i) {
if (m_items[i].item().id() == 0) {
m_items[i] = ItemStack(stringID, amount);
m_hasChanged = true;
break;
return true;
}
else if (m_items[i].item().stringID() == stringID) {
m_items[i] = ItemStack(stringID, m_items[i].amount() + amount);
m_hasChanged = true;
break;
return true;
}
}
return false;
}
void Inventory::clearStack(u16 x, u16 y) {
setStack(x, y, "_:air", 0);
}
void Inventory::serialize(sf::Packet &packet) const {

View File

@ -43,7 +43,8 @@ class Inventory : public 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);
void addStack(const std::string &stringID, u16 amount = 1);
bool addStack(const std::string &stringID, u16 amount = 1);
void clearStack(u16 x, u16 y);
void serialize(sf::Packet &packet) const override;
void deserialize(sf::Packet &packet) override;

View File

@ -84,6 +84,8 @@ mod:block {
size = {x = 1, y = 1},
offset = 0,
count = 1,
shift_destination = "inv_main",
}
gui:inventory {
@ -96,6 +98,8 @@ mod:block {
size = {x = 1, y = 1},
offset = 1,
count = 1,
shift_destination = "inv_main",
}
gui:inventory {
@ -108,6 +112,8 @@ mod:block {
size = {x = 1, y = 1},
offset = 2,
count = 1,
shift_destination = "inv_main",
}
gui:inventory {
@ -121,6 +127,8 @@ mod:block {
size = {x = 9, y = 3},
offset = 9,
count = 9 * 3,
shift_destination = "inv_input",
}
gui:inventory {
@ -134,6 +142,8 @@ mod:block {
size = {x = 9, y = 1},
offset = 0,
count = 9,
shift_destination = "inv_input",
}
gui:image {

View File

@ -118,6 +118,8 @@ function show_inventory(client, screen_width, screen_height, gui_scale)
inventory = "temp",
size = 2,
shift_destination = "inv_main",
}
gui:show(client)

View File

@ -53,6 +53,8 @@ mod:block {
size = {x = 9, y = 3},
offset = 9,
count = 9 * 3,
shift_destination = "inv_crafting",
}
gui:inventory {
@ -65,6 +67,8 @@ mod:block {
size = {x = 9, y = 1},
offset = 0,
count = 9,
shift_destination = "inv_crafting",
}
gui:crafting {
@ -74,6 +78,8 @@ mod:block {
inventory = "block",
block = {x = pos.x, y = pos.y, z = pos.z},
shift_destination = "inv_main",
}
gui:image {

View File

@ -18,4 +18,6 @@
<key name="Chat" scancode="T" />
<key name="Command" scancode="Keypad /" />
<key name="Shift" scancode="Left Shift" />
</keys>

View File

@ -116,6 +116,8 @@ void LuaGUI::addInventoryWidget(const sol::table &table) {
DEBUG("ERROR: Inventory source '" + inventory + "' is not valid");
}
std::string shiftDestination = table["shift_destination"].get_or<std::string>("");
u16 offset = table["offset"].get<u16>();
u16 count = table["count"].get<u16>();
@ -136,6 +138,7 @@ void LuaGUI::addInventoryWidget(const sol::table &table) {
inv.player = player;
inv.inventory_name = inventory_name;
inv.block = block;
inv.shiftDestination = shiftDestination;
inv.width = width;
inv.height = height;
inv.offset = offset;
@ -174,6 +177,8 @@ void LuaGUI::addCraftingWidget(const sol::table &table) {
DEBUG("ERROR: Inventory source '" + inventory + "' is not valid");
}
std::string shiftDestination = table["shift_destination"].get_or<std::string>("");
s32 resultX = 0, resultY = 0;
sol::optional<sol::table> resultPosTable = table["result_pos"];
if (resultPosTable != sol::nullopt) {
@ -191,6 +196,7 @@ void LuaGUI::addCraftingWidget(const sol::table &table) {
craftingWidget.block = block;
craftingWidget.offset = offset;
craftingWidget.size = size;
craftingWidget.shiftDestination = shiftDestination;
craftingWidget.resultX = resultX;
craftingWidget.resultY = resultY;
}
@ -290,13 +296,13 @@ void LuaGUI::show(Client &client) {
for (auto &it : m_data.inventoryWidgetList)
packet << u8(LuaWidget::InventoryWidget) << it.name << it.x << it.y
<< it.inventory << it.player << it.inventory_name
<< it.block.x << it.block.y << it.block.z
<< it.block.x << it.block.y << it.block.z << it.shiftDestination
<< it.width << it.height << it.offset << it.count;
for (auto &it : m_data.craftingWidgetList)
packet << u8(LuaWidget::CraftingWidget) << it.name << it.x << it.y << it.inventory
<< it.block.x << it.block.y << it.block.z << it.offset << it.size
<< it.resultX << it.resultY;
<< it.shiftDestination << it.resultX << it.resultY;
for (auto &it : m_data.progressBarWidgetList)
packet << u8(LuaWidget::ProgressBarWidget) << it.name << it.x << it.y << it.type

View File

@ -60,6 +60,8 @@ struct InventoryWidget : public Widget {
gk::Vector3i block; // inventory == "block"
std::string shiftDestination;
u16 width = 0;
u16 height = 0;
@ -75,6 +77,8 @@ struct CraftingWidget : public Widget {
u16 offset = 0; // inventory == "block"
u16 size = 3; // inventory == "temp" or "block"
std::string shiftDestination;
s32 resultX = 0;
s32 resultY = 0;
};