InventoryView inventory property

This commit is contained in:
MihailRis
2024-04-29 15:18:45 +03:00
parent 1401eca712
commit beaeba43af
10 changed files with 382 additions and 369 deletions
-2
View File
@@ -4,8 +4,6 @@
#include "../typedefs.h"
#include <memory>
#include <string>
#include <unordered_map>
class Content;
class Assets;
-472
View File
@@ -1,472 +0,0 @@
#include "InventoryView.h"
#include <iostream>
#include <glm/glm.hpp>
#include "../assets/Assets.h"
#include "../content/Content.h"
#include "../graphics/core/Atlas.hpp"
#include "../graphics/core/Batch2D.hpp"
#include "../graphics/core/Font.hpp"
#include "../graphics/core/GfxContext.hpp"
#include "../graphics/core/Shader.hpp"
#include "../graphics/ui/GUI.hpp"
#include "../graphics/render/BlocksPreview.hpp"
#include "../items/Inventories.h"
#include "../items/Inventory.h"
#include "../items/ItemDef.h"
#include "../items/ItemStack.h"
#include "../logic/scripting/scripting.h"
#include "../maths/voxmaths.h"
#include "../objects/Player.h"
#include "../util/stringutil.h"
#include "../voxels/Block.h"
#include "../window/Events.h"
#include "../window/input.h"
#include "../world/Level.h"
#include "LevelFrontend.h"
SlotLayout::SlotLayout(
int index,
glm::vec2 position,
bool background,
bool itemSource,
slotcallback updateFunc,
slotcallback shareFunc,
slotcallback rightClick
) : index(index),
position(position),
background(background),
itemSource(itemSource),
updateFunc(updateFunc),
shareFunc(shareFunc),
rightClick(rightClick) {}
InventoryBuilder::InventoryBuilder() {
view = std::make_shared<InventoryView>();
}
void InventoryBuilder::addGrid(
int cols, int count,
glm::vec2 pos,
int padding,
bool addpanel,
SlotLayout slotLayout
) {
const int slotSize = InventoryView::SLOT_SIZE;
const int interval = InventoryView::SLOT_INTERVAL;
int rows = ceildiv(count, cols);
uint width = cols * (slotSize + interval) - interval + padding*2;
uint height = rows * (slotSize + interval) - interval + padding*2;
glm::vec2 vsize = view->getSize();
if (pos.x + width > vsize.x) {
vsize.x = pos.x + width;
}
if (pos.y + height > vsize.y) {
vsize.y = pos.y + height;
}
view->setSize(vsize);
if (addpanel) {
auto panel = std::make_shared<gui::Container>(glm::vec2(width, height));
view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f));
view->add(panel, pos);
}
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (row * cols + col >= count) {
break;
}
glm::vec2 position (
col * (slotSize + interval) + padding,
row * (slotSize + interval) + padding
);
auto builtSlot = slotLayout;
builtSlot.index = row * cols + col;
builtSlot.position = position;
add(builtSlot);
}
}
}
void InventoryBuilder::add(SlotLayout layout) {
view->add(view->addSlot(layout), layout.position);
}
std::shared_ptr<InventoryView> InventoryBuilder::build() {
return view;
}
SlotView::SlotView(
SlotLayout layout
) : UINode(glm::vec2(InventoryView::SLOT_SIZE)),
layout(layout)
{
setColor(glm::vec4(0, 0, 0, 0.2f));
}
void SlotView::draw(const GfxContext* pctx, Assets* assets) {
if (bound == nullptr)
return;
const int slotSize = InventoryView::SLOT_SIZE;
ItemStack& stack = *bound;
glm::vec4 tint(1.0f);
glm::vec2 pos = calcPos();
glm::vec4 color = getColor();
if (hover || highlighted) {
tint *= 1.333f;
color = glm::vec4(1, 1, 1, 0.2f);
}
auto batch = pctx->getBatch2D();
batch->setColor(color);
if (color.a > 0.0) {
batch->texture(nullptr);
if (highlighted) {
batch->rect(pos.x-4, pos.y-4, slotSize+8, slotSize+8);
} else {
batch->rect(pos.x, pos.y, slotSize, slotSize);
}
}
batch->setColor(glm::vec4(1.0f));
auto previews = assets->getAtlas("block-previews");
auto indices = content->getIndices();
ItemDef* item = indices->getItemDef(stack.getItemId());
switch (item->iconType) {
case item_icon_type::none:
break;
case item_icon_type::block: {
const Block& cblock = content->requireBlock(item->icon);
batch->texture(previews->getTexture());
UVRegion region = previews->get(cblock.name);
batch->rect(
pos.x, pos.y, slotSize, slotSize,
0, 0, 0, region, false, true, tint);
break;
}
case item_icon_type::sprite: {
size_t index = item->icon.find(':');
std::string name = item->icon.substr(index+1);
UVRegion region(0.0f, 0.0, 1.0f, 1.0f);
if (index == std::string::npos) {
batch->texture(assets->getTexture(name));
} else {
std::string atlasname = item->icon.substr(0, index);
Atlas* atlas = assets->getAtlas(atlasname);
if (atlas && atlas->has(name)) {
region = atlas->get(name);
batch->texture(atlas->getTexture());
}
}
batch->rect(
pos.x, pos.y, slotSize, slotSize,
0, 0, 0, region, false, true, tint);
break;
}
}
if (stack.getCount() > 1) {
auto font = assets->getFont("normal");
std::wstring text = std::to_wstring(stack.getCount());
int x = pos.x+slotSize-text.length()*8;
int y = pos.y+slotSize-16;
batch->setColor({0, 0, 0, 1.0f});
font->draw(batch, text, x+1, y+1);
batch->setColor(glm::vec4(1.0f));
font->draw(batch, text, x, y);
}
}
void SlotView::setHighlighted(bool flag) {
highlighted = flag;
}
bool SlotView::isHighlighted() const {
return highlighted;
}
void SlotView::clicked(gui::GUI* gui, mousecode button) {
if (bound == nullptr)
return;
auto exchangeSlot = std::dynamic_pointer_cast<SlotView>(gui->get(EXCHANGE_SLOT_NAME));
if (exchangeSlot == nullptr) {
return;
}
ItemStack& grabbed = exchangeSlot->getStack();
ItemStack& stack = *bound;
if (button == mousecode::BUTTON_1) {
if (Events::pressed(keycode::LEFT_SHIFT)) {
if (layout.shareFunc) {
layout.shareFunc(layout.index, stack);
}
if (layout.updateFunc) {
layout.updateFunc(layout.index, stack);
}
return;
}
if (!layout.itemSource && stack.accepts(grabbed)) {
stack.move(grabbed, content->getIndices());
} else {
if (layout.itemSource) {
if (grabbed.isEmpty()) {
grabbed.set(stack);
} else {
grabbed.clear();
}
} else {
std::swap(grabbed, stack);
}
}
} else if (button == mousecode::BUTTON_2) {
if (layout.rightClick) {
layout.rightClick(inventoryid, stack);
if (layout.updateFunc) {
layout.updateFunc(layout.index, stack);
}
return;
}
if (layout.itemSource)
return;
if (grabbed.isEmpty()) {
if (!stack.isEmpty()) {
grabbed.set(stack);
int halfremain = stack.getCount() / 2;
grabbed.setCount(stack.getCount() - halfremain);
stack.setCount(halfremain);
}
} else {
if (stack.isEmpty()) {
stack.set(grabbed);
stack.setCount(1);
grabbed.setCount(grabbed.getCount()-1);
} else if (stack.accepts(grabbed)){
stack.setCount(stack.getCount()+1);
grabbed.setCount(grabbed.getCount()-1);
}
}
}
if (layout.updateFunc) {
layout.updateFunc(layout.index, stack);
}
}
void SlotView::onFocus(gui::GUI* gui) {
clicked(gui, mousecode::BUTTON_1);
}
void SlotView::bind(
int64_t inventoryid,
ItemStack& stack,
const Content* content
) {
this->inventoryid = inventoryid;
bound = &stack;
this->content = content;
}
const SlotLayout& SlotView::getLayout() const {
return layout;
}
ItemStack& SlotView::getStack() {
return *bound;
}
InventoryView::InventoryView() : Container(glm::vec2()) {
setColor(glm::vec4(0, 0, 0, 0.0f));
}
InventoryView::~InventoryView() {}
std::shared_ptr<SlotView> InventoryView::addSlot(SlotLayout layout) {
uint width = InventoryView::SLOT_SIZE + layout.padding;
uint height = InventoryView::SLOT_SIZE + layout.padding;
auto pos = layout.position;
auto vsize = getSize();
if (pos.x + width > vsize.x) {
vsize.x = pos.x + width;
}
if (pos.y + height > vsize.y) {
vsize.y = pos.y + height;
}
setSize(vsize);
auto slot = std::make_shared<SlotView>(layout);
if (!layout.background) {
slot->setColor(glm::vec4());
}
slots.push_back(slot.get());
return slot;
}
std::shared_ptr<Inventory> InventoryView::getInventory() const {
return inventory;
}
size_t InventoryView::getSlotsCount() const {
return slots.size();
}
void InventoryView::bind(
std::shared_ptr<Inventory> inventory,
const Content* content
) {
this->inventory = inventory;
this->content = content;
for (auto slot : slots) {
slot->bind(
inventory->getId(),
inventory->getSlot(slot->getLayout().index),
content
);
}
}
void InventoryView::unbind() {
inventory = nullptr;
}
void InventoryView::setSelected(int index) {
for (size_t i = 0; i < slots.size(); i++) {
slots[i]->setHighlighted(static_cast<int>(i) == index);
}
}
void InventoryView::setPos(glm::vec2 pos) {
Container::setPos(pos - origin);
}
void InventoryView::setOrigin(glm::vec2 origin) {
this->origin = origin;
}
glm::vec2 InventoryView::getOrigin() const {
return origin;
}
#include "../coders/xml.h"
#include "../graphics/ui/gui_xml.hpp"
static slotcallback readSlotFunc(InventoryView* view, gui::UiXmlReader& reader, xml::xmlelement& element, const std::string& attr) {
auto consumer = scripting::create_int_array_consumer(
reader.getEnvironment(),
element->attr(attr).getText()
);
return [=](uint slot, ItemStack& stack) {
int args[] {int(view->getInventory()->getId()), int(slot)};
consumer(args, 2);
};
}
static void readSlot(InventoryView* view, gui::UiXmlReader& reader, xml::xmlelement element) {
int index = element->attr("index", "0").asInt();
bool itemSource = element->attr("item-source", "false").asBool();
SlotLayout layout(index, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr);
if (element->has("pos")) {
layout.position = element->attr("pos").asVec2();
}
if (element->has("updatefunc")) {
layout.updateFunc = readSlotFunc(view, reader, element, "updatefunc");
}
if (element->has("sharefunc")) {
layout.shareFunc = readSlotFunc(view, reader, element, "sharefunc");
}
if (element->has("onrightclick")) {
layout.rightClick = readSlotFunc(view, reader, element, "onrightclick");
}
auto slot = view->addSlot(layout);
reader.readUINode(reader, element, *slot);
view->add(slot);
}
static void readSlotsGrid(InventoryView* view, gui::UiXmlReader& reader, xml::xmlelement element) {
int startIndex = element->attr("start-index", "0").asInt();
int rows = element->attr("rows", "0").asInt();
int cols = element->attr("cols", "0").asInt();
int count = element->attr("count", "0").asInt();
const int slotSize = InventoryView::SLOT_SIZE;
int interval = element->attr("interval", "-1").asInt();
if (interval < 0) {
interval = InventoryView::SLOT_INTERVAL;
}
int padding = element->attr("padding", "-1").asInt();
if (padding < 0) {
padding = interval;
}
if (rows == 0) {
rows = ceildiv(count, cols);
} else if (cols == 0) {
cols = ceildiv(count, rows);
} else if (count == 0) {
count = rows * cols;
}
bool itemSource = element->attr("item-source", "false").asBool();
SlotLayout layout(-1, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr);
if (element->has("pos")) {
layout.position = element->attr("pos").asVec2();
}
if (element->has("updatefunc")) {
layout.updateFunc = readSlotFunc(view, reader, element, "updatefunc");
}
if (element->has("sharefunc")) {
layout.shareFunc = readSlotFunc(view, reader, element, "sharefunc");
}
if (element->has("onrightclick")) {
layout.rightClick = readSlotFunc(view, reader, element, "onrightclick");
}
layout.padding = padding;
int idx = 0;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++, idx++) {
if (idx >= count) {
return;
}
SlotLayout slotLayout = layout;
slotLayout.index = startIndex + idx;
slotLayout.position += glm::vec2(
padding + col * (slotSize + interval),
padding + (rows-row-1) * (slotSize + interval)
);
auto slot = view->addSlot(slotLayout);
view->add(slot, slotLayout.position);
}
}
}
void InventoryView::createReaders(gui::UiXmlReader& reader) {
reader.add("inventory", [=](gui::UiXmlReader& reader, xml::xmlelement element) {
auto view = std::make_shared<InventoryView>();
view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f)); // todo: fixme
reader.addIgnore("slot");
reader.addIgnore("slots-grid");
reader.readUINode(reader, element, *view);
for (auto& sub : element->getElements()) {
if (sub->getTag() == "slot") {
readSlot(view.get(), reader, sub);
} else if (sub->getTag() == "slots-grid") {
readSlotsGrid(view.get(), reader, sub);
}
}
return view;
});
}
-140
View File
@@ -1,140 +0,0 @@
#ifndef FRONTEND_INVENTORY_VIEW_H_
#define FRONTEND_INVENTORY_VIEW_H_
#include "../graphics/ui/elements/UINode.hpp"
#include "../graphics/ui/elements/Container.hpp"
#include "../typedefs.h"
#include "../constants.h"
#include <vector>
#include <functional>
#include <glm/glm.hpp>
class Assets;
class GfxContext;
class Content;
class ItemStack;
class ContentIndices;
class LevelFrontend;
class Inventory;
namespace gui {
class UiXmlReader;
}
using slotcallback = std::function<void(uint, ItemStack&)>;
struct SlotLayout {
int index;
glm::vec2 position;
bool background;
bool itemSource;
slotcallback updateFunc;
slotcallback shareFunc;
slotcallback rightClick;
int padding = 0;
SlotLayout(
int index,
glm::vec2 position,
bool background,
bool itemSource,
slotcallback updateFunc,
slotcallback shareFunc,
slotcallback rightClick
);
};
class SlotView : public gui::UINode {
const Content* content;
SlotLayout layout;
bool highlighted = false;
int64_t inventoryid = 0;
ItemStack* bound = nullptr;
public:
SlotView(SlotLayout layout);
virtual void draw(const GfxContext* pctx, Assets* assets) override;
void setHighlighted(bool flag);
bool isHighlighted() const;
virtual void clicked(gui::GUI*, mousecode) override;
virtual void onFocus(gui::GUI*) override;
void bind(
int64_t inventoryid,
ItemStack& stack,
const Content* content
);
ItemStack& getStack();
const SlotLayout& getLayout() const;
static inline std::string EXCHANGE_SLOT_NAME = "exchange-slot";
};
class InventoryView : public gui::Container {
const Content* content;
std::shared_ptr<Inventory> inventory;
std::vector<SlotView*> slots;
glm::vec2 origin {};
public:
InventoryView();
virtual ~InventoryView();
virtual void setPos(glm::vec2 pos) override;
void setOrigin(glm::vec2 origin);
glm::vec2 getOrigin() const;
void setSelected(int index);
void bind(
std::shared_ptr<Inventory> inventory,
const Content* content
);
void unbind();
std::shared_ptr<SlotView> addSlot(SlotLayout layout);
std::shared_ptr<Inventory> getInventory() const;
size_t getSlotsCount() const;
static void createReaders(gui::UiXmlReader& reader);
static const int SLOT_INTERVAL = 4;
static const int SLOT_SIZE = ITEM_ICON_SIZE;
};
class InventoryBuilder {
std::shared_ptr<InventoryView> view;
public:
InventoryBuilder();
/// @brief Add slots grid to inventory view
/// @param cols grid columns
/// @param count total number of grid slots
/// @param pos position of the first slot of the grid
/// @param padding additional space around the grid
/// @param addpanel automatically create panel behind the grid
/// with size including padding
/// @param slotLayout slot settings (index and position are ignored)
void addGrid(
int cols, int count,
glm::vec2 pos,
int padding,
bool addpanel,
SlotLayout slotLayout
);
void add(SlotLayout slotLayout);
std::shared_ptr<InventoryView> build();
};
#endif // FRONTEND_INVENTORY_VIEW_H_
+1 -2
View File
@@ -2,9 +2,9 @@
#include "../files/files.h"
#include "../graphics/ui/elements/UINode.hpp"
#include "../graphics/ui/elements/InventoryView.hpp"
#include "../graphics/ui/gui_xml.hpp"
#include "../logic/scripting/scripting.h"
#include "InventoryView.h"
UiDocument::UiDocument(
std::string id,
@@ -60,7 +60,6 @@ std::unique_ptr<UiDocument> UiDocument::read(scriptenv penv, std::string name, f
: scripting::create_doc_environment(penv, name);
gui::UiXmlReader reader(env);
InventoryView::createReaders(reader);
auto view = reader.readXML(
file.u8string(), xmldoc->getRoot()
);
+9 -8
View File
@@ -14,6 +14,7 @@
#include "../graphics/core/Shader.hpp"
#include "../graphics/core/Texture.hpp"
#include "../graphics/render/WorldRenderer.hpp"
#include "../graphics/ui/elements/InventoryView.hpp"
#include "../graphics/ui/elements/Menu.hpp"
#include "../graphics/ui/elements/Panel.hpp"
#include "../graphics/ui/elements/Plotter.hpp"
@@ -39,7 +40,6 @@
#include "../world/Level.h"
#include "../world/World.h"
#include "ContentGfxCache.h"
#include "InventoryView.h"
#include "LevelFrontend.h"
#include "UiDocument.h"
@@ -48,9 +48,10 @@
#include <stdexcept>
#include <string>
using namespace gui;
// implemented in debug_panel.cpp
extern std::shared_ptr<gui::UINode> create_debug_panel(
extern std::shared_ptr<UINode> create_debug_panel(
Engine* engine,
Level* level,
Player* player
@@ -59,7 +60,7 @@ extern std::shared_ptr<gui::UINode> create_debug_panel(
HudElement::HudElement(
hud_element_mode mode,
UiDocument* document,
std::shared_ptr<gui::UINode> node,
std::shared_ptr<UINode> node,
bool debug
) : mode(mode), document(document), node(node), debug(debug) {
}
@@ -89,7 +90,7 @@ UiDocument* HudElement::getDocument() const {
return document;
}
std::shared_ptr<gui::UINode> HudElement::getNode() const {
std::shared_ptr<UINode> HudElement::getNode() const {
return node;
}
@@ -144,7 +145,7 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player)
player(player)
{
contentAccess = createContentAccess();
contentAccessPanel = std::make_shared<gui::Panel>(
contentAccessPanel = std::make_shared<Panel>(
contentAccess->getSize(), glm::vec4(0.0f), 0.0f
);
contentAccessPanel->setColor(glm::vec4());
@@ -168,8 +169,8 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player)
gui->add(debugPanel);
gui->add(contentAccessPanel);
auto dplotter = std::make_shared<gui::Plotter>(350, 250, 2000, 16);
dplotter->setGravity(gui::Gravity::bottom_right);
auto dplotter = std::make_shared<Plotter>(350, 250, 2000, 16);
dplotter->setGravity(Gravity::bottom_right);
add(HudElement(hud_element_mode::permanent, nullptr, dplotter, true));
}
@@ -411,7 +412,7 @@ void Hud::onRemove(HudElement& element) {
gui->remove(element.getNode());
}
void Hud::remove(std::shared_ptr<gui::UINode> node) {
void Hud::remove(std::shared_ptr<UINode> node) {
for (auto& element : elements) {
if (element.getNode() == node) {
element.setRemoved();
+9 -9
View File
@@ -13,9 +13,7 @@ class Block;
class Assets;
class Player;
class Engine;
class SlotView;
class Inventory;
class InventoryView;
class LevelFrontend;
class UiDocument;
class GfxContext;
@@ -26,6 +24,8 @@ namespace gui {
class UINode;
class Panel;
class Container;
class InventoryView;
class SlotView;
}
enum class hud_element_mode {
@@ -78,24 +78,24 @@ class Hud {
/// @brief Content access panel scroll container
std::shared_ptr<gui::Container> contentAccessPanel;
/// @brief Content access panel itself
std::shared_ptr<InventoryView> contentAccess;
std::shared_ptr<gui::InventoryView> contentAccess;
/// @brief Player inventory hotbar
std::shared_ptr<InventoryView> hotbarView;
std::shared_ptr<gui::InventoryView> hotbarView;
/// @brief Debug info and control panel (F3 key)
std::shared_ptr<gui::UINode> debugPanel;
/// @brief Overlay used in pause mode
std::shared_ptr<gui::UINode> darkOverlay;
/// @brief Inventories interaction agent (grabbed item)
std::shared_ptr<SlotView> exchangeSlot;
std::shared_ptr<gui::SlotView> exchangeSlot;
/// @brief Exchange slot inventory (1 slot only)
std::shared_ptr<Inventory> exchangeSlotInv = nullptr;
/// @brief List of all controlled hud elements
std::vector<HudElement> elements;
/// @brief Player inventory view
std::shared_ptr<InventoryView> inventoryView = nullptr;
std::shared_ptr<gui::InventoryView> inventoryView = nullptr;
/// @brief Block inventory view
std::shared_ptr<InventoryView> blockUI = nullptr;
std::shared_ptr<gui::InventoryView> blockUI = nullptr;
/// @brief Position of the block open
glm::ivec3 blockPos {};
/// @brief Id of the block open (used to detect block destruction or replacement)
@@ -104,8 +104,8 @@ class Hud {
/// @brief UI element will be dynamicly positioned near to inventory or in screen center
std::shared_ptr<gui::UINode> secondUI = nullptr;
std::shared_ptr<InventoryView> createContentAccess();
std::shared_ptr<InventoryView> createHotbar();
std::shared_ptr<gui::InventoryView> createContentAccess();
std::shared_ptr<gui::InventoryView> createHotbar();
void processInput(bool visible);
void updateElementsPosition(const Viewport& viewport);