Lua parsing of Gui Elements!!!

master
Auri 2021-08-20 22:48:38 -07:00
parent 22bc36c9f2
commit 5bf82c4963
35 changed files with 663 additions and 498 deletions

View File

@ -5,31 +5,24 @@ setmetatable(env, {__index = _G})
-- create_element -- create_element
-- Build a GUI Element with the provided constructor data, apply the metatable. -- Build a GUI Element with the provided constructor data, apply the metatable.
local function create_element(elem_type, data) local function create_element(elem_type, data)
local elem = GuiElement.new(elem_type, data) return GuiElement.new(elem_type, data)
return elem
end end
-- register_element -- register_element
-- Add an element to the Gui namespace. -- Add an element to the Gui namespace.
local function register_element(key) local function register_element(key)
if type(key) == "table" then if type(key) == "table" then
for _,v in pairs(key) do register_element(v) end for _, v in pairs(key) do register_element(v) end
return return
end end
env.Gui[key] = function(data) return create_element(key, data) end env.Gui[key] = function(data) return create_element(key, data) end
end end
register_element({"Body", "Rect", "Text", "Model", "Button", "InventoryList"}) register_element({ "Box", "Text" })
-- pc
-- Formats a number to be a percent string.
env.pc = function(num)
return tostring(num) .. "%"
end
-- zepha.build_gui -- zepha.build_gui
-- Allows you to Build UI Elements with the GUI namespace outside of a callback. -- Allows you to Build UI Elements with the GUI namespace outside of a callback.
zepha.build_gui = function(fn) zepha.gui = function(fn)
setfenv(fn, env) setfenv(fn, env)
return fn() return fn()
end end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

View File

@ -331,6 +331,6 @@ add_library(Zepha_Core
client/gui/compound/GuiCellGraph.cpp client/gui/compound/GuiCellGraph.cpp
client/gui/compound/GuiCellGraph.h client/gui/compound/GuiCellGraph.h
client/gui/basic/GuiCells.cpp client/gui/basic/GuiCells.cpp
client/gui/basic/GuiCells.h client/gui/Gui.h client/gui/Root.cpp client/gui/Root.h client/gui/BoxElement.cpp client/gui/BoxElement.h client/gui/Gui.cpp client/gui/Style.h client/gui/TextElement.cpp client/gui/TextElement.h client/gui/Expression.cpp client/gui/Expression.h) client/gui/basic/GuiCells.h client/gui/Gui.h client/gui/Root.cpp client/gui/Root.h client/gui/BoxElement.cpp client/gui/BoxElement.h client/gui/Gui.cpp client/gui/Style.h client/gui/TextElement.cpp client/gui/TextElement.h client/gui/Expression.cpp client/gui/Expression.h client/gui/Style.cpp)
target_include_directories(Zepha_Core PUBLIC .) target_include_directories(Zepha_Core PUBLIC .)

View File

@ -16,9 +16,9 @@ Font::Font(TextureAtlas& atlas, std::shared_ptr<AtlasRef> tex) :
getCharWidths(atlas); getCharWidths(atlas);
} }
unsigned int Font::getCharWidth(char c) { u16 Font::getCharWidth(char c) {
unsigned int index = static_cast<unsigned int>(c) - 32; unsigned int index = static_cast<unsigned int>(c) - 32;
if (index >= amountOfChars) throw std::runtime_error("Invalid char index."); if (index >= C_COUNT) return charWidths[C_COUNT];
return charWidths[index]; return charWidths[index];
} }
@ -27,44 +27,44 @@ void Font::getCharWidths(TextureAtlas& atlas) {
charWidths[0] = 2; charWidths[0] = 2;
for (unsigned int i = 1; i < amountOfChars; i++) { for (u16 i = 1; i < C_COUNT + 1; i++) {
glm::vec2 charPos = { i % 18 * charWidth, std::floor(i / 18) * charHeight }; glm::vec2 charPos = { i % 18 * C_WIDTH, std::floor(i / 18) * C_HEIGHT };
unsigned int xBase = static_cast<unsigned int>(fontTex->pos.x) + static_cast<unsigned int>(charPos.x); u32 xBase = static_cast<u32>(fontTex->pos.x) + static_cast<u32>(charPos.x);
unsigned int yBase = static_cast<unsigned int>(fontTex->pos.y) + static_cast<unsigned int>(charPos.y); u32 yBase = static_cast<u32>(fontTex->pos.y) + static_cast<u32>(charPos.y);
unsigned short width = 0; u16 width = 0;
for (unsigned int j = 0; j < charWidth; j++) { for (u16 j = 0; j < C_WIDTH; j++) {
bool empty = true; bool empty = true;
for (unsigned int k = 0; k < charHeight; k++) { for (u16 k = 0; k < C_HEIGHT; k++) {
unsigned int xx = xBase + j; u32 xx = xBase + j;
unsigned int yy = yBase + k; u32 yy = yBase + k;
unsigned int offset = yy * static_cast<unsigned int>(atlasSize.x) * 4 + xx * 4 + 3; u32 offset = yy * static_cast<u32>(atlasSize.x) * 4 + xx * 4 + 3;
if (data[offset] != 0) { if (data[offset] != 0) {
empty = false; empty = false;
break; break;
} }
} }
if (!empty) width = static_cast<unsigned short>(j); if (!empty) width = static_cast<u16>(j);
} }
charWidths[i] = width; charWidths[i] = width;
} }
} }
glm::vec4 Font::getCharUVs(char c) { vec4 Font::getCharUVs(char c) {
unsigned int index = static_cast<unsigned int>(c) - 32; u16 index = static_cast<u16>(c) - 32;
if (index >= amountOfChars) throw std::runtime_error("Invalid char index."); if (index >= C_COUNT) index = C_COUNT;
glm::vec2 charPos = { (index % 18) * charWidth, std::floor(index / 18) * charHeight }; vec2 charPos = { (index % 18) * C_WIDTH, std::floor(index / 18) * C_HEIGHT };
glm::vec4 uv = { vec4 uv = {
fontTex->uv.x + (charPos.x) / atlasSize.x, fontTex->uv.x + (charPos.x) / atlasSize.x,
fontTex->uv.y + (charPos.y) / atlasSize.y, fontTex->uv.y + (charPos.y) / atlasSize.y,
fontTex->uv.x + (charPos.x + getCharWidth(c) + 1) / atlasSize.x, fontTex->uv.x + (charPos.x + getCharWidth(c) + 1) / atlasSize.x,
fontTex->uv.y + (charPos.y + charHeight) / atlasSize.y fontTex->uv.y + (charPos.y + C_HEIGHT) / atlasSize.y
}; };
return uv; return uv;

View File

@ -1,35 +1,29 @@
//
// Created by aurailus on 13/08/19.
//
#pragma once #pragma once
#include <memory> #include "util/Types.h"
#include <glm/vec2.hpp>
#include <glm/vec4.hpp>
class AtlasRef; class AtlasRef;
class TextureAtlas; class TextureAtlas;
class Font { class Font {
public: public:
Font() = default; Font() = default;
Font(TextureAtlas& atlas, std::shared_ptr<AtlasRef> tex); Font(TextureAtlas& atlas, std::shared_ptr<AtlasRef> tex);
unsigned int getCharWidth(char c); u16 getCharWidth(char c);
glm::vec4 getCharUVs(char c); vec4 getCharUVs(char c);
const static unsigned int amountOfChars = 95; constexpr static u16 C_COUNT = 95;
const static unsigned int charWidth = 7; constexpr static u16 C_WIDTH = 7;
const static unsigned int charHeight = 9; constexpr static u16 C_HEIGHT = 9;
private:
private:
void getCharWidths(TextureAtlas& atlas); void getCharWidths(TextureAtlas& atlas);
glm::vec2 atlasSize{}; vec2 atlasSize {};
std::shared_ptr<AtlasRef> fontTex = nullptr; sptr<AtlasRef> fontTex = nullptr;
std::array<unsigned short, 95> charWidths{}; array<u16, C_COUNT + 1> charWidths {};
}; };

View File

@ -24,6 +24,10 @@ ivec2 Gui::Element::getComputedSize() {
return size; return size;
} }
void Gui::Element::clear() {
children.clear();
}
ivec2 Gui::Element::getComputedOuterSize() { ivec2 Gui::Element::getComputedOuterSize() {
let size = getComputedSize(); let size = getComputedSize();
let margin = getStyle<ivec4, ValueType::LENGTH>(StyleRule::MARGIN, {}); let margin = getStyle<ivec4, ValueType::LENGTH>(StyleRule::MARGIN, {});
@ -195,4 +199,4 @@ void Gui::Element::layoutChildren() {
break; break;
} }
} }
} }

View File

@ -79,6 +79,8 @@ namespace Gui {
return elem; return elem;
} }
void clear();
/** Returns the element's computed size. */ /** Returns the element's computed size. */
virtual ivec2 getComputedSize(); virtual ivec2 getComputedSize();
@ -104,6 +106,7 @@ namespace Gui {
for (const let& ss : stylesheets) { for (const let& ss : stylesheets) {
for (const string& className : props.classes) { for (const string& className : props.classes) {
const let& styles = ss.find(className); const let& styles = ss.find(className);
if (styles == ss.end()) continue;
const optional<any> opt = styles->second.get(rule); const optional<any> opt = styles->second.get(rule);
if (opt) return *opt; if (opt) return *opt;
} }
@ -119,6 +122,7 @@ namespace Gui {
for (const let& ss : stylesheets) { for (const let& ss : stylesheets) {
for (const string& className : props.classes) { for (const string& className : props.classes) {
const let& styles = ss.find(className); const let& styles = ss.find(className);
if (styles == ss.end()) continue;
const optional<V> opt = styles->second.get<V, T>(rule); const optional<V> opt = styles->second.get<V, T>(rule);
if (opt) return *opt; if (opt) return *opt;
} }

View File

@ -1,3 +1,5 @@
#pragma once
#include <unordered_map> #include <unordered_map>
#include "client/gui/Gui.h" #include "client/gui/Gui.h"

20
src/client/gui/Style.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "Style.h"
const std::unordered_map<string, Gui::StyleRule> Gui::Style::RULE_STRINGS_TO_ENUMS = {
{ "pos", StyleRule::POS },
{ "size", StyleRule::SIZE },
{ "margin", StyleRule::MARGIN },
{ "padding", StyleRule::PADDING },
{ "GAP", StyleRule::GAP },
{ "layout", StyleRule::LAYOUT },
{ "direction", StyleRule::DIRECTION },
{ "h_align", StyleRule::H_ALIGN },
{ "v_align", StyleRule::V_ALIGN },
{ "cursor", StyleRule::CURSOR },
{ "overflow", StyleRule::OVERFLOW },
{ "background", StyleRule::BACKGROUND },
{ "background_hover", StyleRule::BACKGROUND_HOVER },
{ "content", StyleRule::CONTENT },
{ "text_size", StyleRule::TEXT_SIZE },
{ "text_color", StyleRule::TEXT_COLOR }
};

View File

@ -22,7 +22,9 @@ namespace Gui {
BACKGROUND, BACKGROUND,
BACKGROUND_HOVER, BACKGROUND_HOVER,
CONTENT CONTENT,
TEXT_SIZE,
TEXT_COLOR
}; };
enum class ValueType { enum class ValueType {
@ -180,6 +182,8 @@ namespace Gui {
} }
std::unordered_map<StyleRule, any> rules {}; std::unordered_map<StyleRule, any> rules {};
const static std::unordered_map<string, StyleRule> RULE_STRINGS_TO_ENUMS;
}; };
typedef std::unordered_map<string, Style> StyleSheet; typedef std::unordered_map<string, Style> StyleSheet;

View File

@ -36,7 +36,7 @@ void Gui::TextElement::updateElement() {
} }
vec3 offset = {}; vec3 offset = {};
u32 h = Font::charHeight; u32 h = Font::C_HEIGHT;
bool bold = false; bool bold = false;
bool italic = false; bool italic = false;
@ -192,9 +192,12 @@ void Gui::TextElement::updateElement() {
} }
entity.setScale(PX_SCALE * (2/3.f)); let scale = getStyle<f32, ValueType::LENGTH>(StyleRule::TEXT_SIZE, 3.f);
// entity.setScale(vec3(getComputedSize() * static_cast<i32>(PX_SCALE), 0)); let margin = getStyle<ivec4, ValueType::LENGTH>(StyleRule::MARGIN, {});
entity.setPos(vec3(getComputedScreenPos() * static_cast<i32>(PX_SCALE), 0));
entity.setScale(vec3(scale, scale, 0));
entity.setPos(vec3(getComputedScreenPos() + ivec2 { margin.x, margin.y }, 0));
Element::updateElement(); Element::updateElement();
} }

View File

@ -1,7 +1,7 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <cute_files/cute_files.h> #include <cute_files/cute_files.h>
#include <client/gui/TextElement.h>
#include "MenuSandbox.h" #include "MenuSandbox.h"
@ -9,29 +9,25 @@
#include "client/Client.h" #include "client/Client.h"
#include "lua/ErrorFormatter.h" #include "lua/ErrorFormatter.h"
#include "client/menu/SubgameDef.h" #include "client/menu/SubgameDef.h"
#include "client/gui/basic/GuiText.h"
#include "client/gui/basic/GuiContainer.h"
// Modules // Modules
#include "lua/modules/Time.h" #include "lua/modules/Time.h"
#include "lua/modules/mSetGui.h" #include "lua/modules/mSetGui.h"
#include "lua/modules/mStartGame.h" #include "lua/modules/mStartGame.h"
#include "lua/usertype/LuaGuiElement.h"
MenuSandbox::MenuSandbox(glm::ivec2& win, Client& client, std::shared_ptr<GuiContainer> container) : MenuSandbox::MenuSandbox(Client& client, Gui::Root& root, sptr<Gui::Element> sandboxRoot) :
LuaParser(*client.game), LuaParser(*client.game),
win(win), client(client),
client(client) root(root),
// container(container), sandboxRoot(sandboxRoot) {}
// luaContainer(std::dynamic_pointer_cast<GuiContainer>(container->add(std::make_shared<GuiContainer>("__lua"))))
// builder(client.game->textures, client.game->models, luaContainer) {}
{}
void MenuSandbox::reset() { void MenuSandbox::reset() {
// container->remove("error"); // container->remove("error");
// builder.clear(true); sandboxRoot->clear();
core = {}; core = {};
mod = {}; mod = {};
lua = sol::state{}; lua = sol::state {};
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::debug); lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::debug);
loadApi(); loadApi();
@ -46,9 +42,10 @@ void MenuSandbox::loadApi() {
modules.emplace_back(std::make_unique<Api::Module::Time>(Api::State::CLIENT, lua, core)); modules.emplace_back(std::make_unique<Api::Module::Time>(Api::State::CLIENT, lua, core));
Api::Usertype::GuiElement::bind(lua, core, root);
// ClientApi::gui_element(lua); // ClientApi::gui_element(lua);
// MenuApi::set_gui(builder, win, lua, core); MenuApi::set_gui(lua, core, sandboxRoot);
MenuApi::start_game(client, core); MenuApi::start_game(client, core);
bindModules(); bindModules();
@ -60,14 +57,15 @@ void MenuSandbox::loadApi() {
void MenuSandbox::load(const SubgameDef& subgame) { void MenuSandbox::load(const SubgameDef& subgame) {
reset(); reset();
subgameName = subgame.config.name;
try { // try {
loadAndRunMod(subgame.subgamePath + "/../../assets/base"); loadAndRunMod(subgame.subgamePath + "/../../assets/base");
loadAndRunMod(subgame.subgamePath + "/menu"); loadAndRunMod(subgame.subgamePath + "/menu");
} // }
catch (const std::runtime_error& e) { // catch (const std::runtime_error& e) {
showError(e.what(), subgame.config.name); // showError(e.what(), subgame.config.name);
} // }
} }
void MenuSandbox::windowResized() { void MenuSandbox::windowResized() {
@ -79,7 +77,7 @@ void MenuSandbox::update(double delta) {
core["__builtin"]["update_delayed_functions"](); core["__builtin"]["update_delayed_functions"]();
} }
sol::protected_function_result MenuSandbox::runFileSandboxed(const std::string& file) { sol::protected_function_result MenuSandbox::runFileSandboxed(const string& file) {
for (LuaMod::File& f : mod.files) { for (LuaMod::File& f : mod.files) {
if (f.path != file) continue; if (f.path != file) continue;
@ -94,18 +92,18 @@ sol::protected_function_result MenuSandbox::runFileSandboxed(const std::string&
throw std::runtime_error("Error opening '" + file + "', file not found."); throw std::runtime_error("Error opening '" + file + "', file not found.");
} }
void MenuSandbox::loadAndRunMod(const std::string& modPath) { void MenuSandbox::loadAndRunMod(const string& modPath) {
if (!cf_file_exists(modPath.data())) throw std::runtime_error("Directory not found."); if (!cf_file_exists(modPath.data())) throw std::runtime_error("Directory not found.");
LuaMod mod; LuaMod mod;
std::string root = modPath + "/script"; string root = modPath + "/script";
std::list<std::string> dirsToScan{ root }; std::list<string> dirsToScan{ root };
std::list<std::string> luaFiles{}; std::list<string> luaFiles{};
cf_dir_t dir; cf_dir_t dir;
while (!dirsToScan.empty()) { while (!dirsToScan.empty()) {
std::string dirStr = *dirsToScan.begin(); string dirStr = *dirsToScan.begin();
dirsToScan.erase(dirsToScan.begin()); dirsToScan.erase(dirsToScan.begin());
if (!cf_file_exists(dirStr.data())) throw std::runtime_error("Missing 'script' directory."); if (!cf_file_exists(dirStr.data())) throw std::runtime_error("Missing 'script' directory.");
@ -131,9 +129,9 @@ void MenuSandbox::loadAndRunMod(const std::string& modPath) {
mod.modPath = modPath; mod.modPath = modPath;
for (std::string& file : luaFiles) { for (string& file : luaFiles) {
size_t rootPos = file.find(root); size_t rootPos = file.find(root);
std::string modPath = file; string modPath = file;
if (rootPos == std::string::npos) if (rootPos == std::string::npos)
throw std::runtime_error("Attempted to access file \"" + file + "\", which is outside of the mod root."); throw std::runtime_error("Attempted to access file \"" + file + "\", which is outside of the mod root.");
@ -142,66 +140,67 @@ void MenuSandbox::loadAndRunMod(const std::string& modPath) {
modPath.resize(modPath.size() - 4); modPath.resize(modPath.size() - 4);
std::ifstream t(file); std::ifstream t(file);
std::string fileStr((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>()); string fileStr((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
LuaMod::File f{ modPath, fileStr }; LuaMod::File f { modPath, fileStr };
mod.files.push_back(f); mod.files.push_back(f);
} }
std::string texPath = modPath + "/textures"; string texPath = modPath + "/textures";
if (cf_file_exists(texPath.data())) { if (cf_file_exists(texPath.data()))
this->modAssets = client.game->textures.loadDirectory(texPath, false, true); menuAssets = client.game->textures.loadDirectory(texPath, false, true);
}
this->mod = mod; this->mod = mod;
runFileSandboxed("init"); runFileSandboxed("init");
} }
void MenuSandbox::showError(const std::string& what, const std::string& subgame) { void MenuSandbox::showError(const string& err) {
const std::string errPrefixText = "Encountered an error while loading the menu for " + subgame + " ;-;"; const string errPrefixText = "`cfEncountered an error while loading the menu for '" + subgameName + "' ;-;\n\n`r";
// Font f(client.game->textures, client.game->textures["font"]);
using Expr = Gui::Expression;
// auto errWrap = std::make_shared<GuiContainer>("error"); sandboxRoot->append<Gui::TextElement>({
// container->add(errWrap); .styles = {{
{ Gui::StyleRule::CONTENT, errPrefixText + err },
// auto errPrefix = std::make_shared<GuiText>("error_text"); { Gui::StyleRule::TEXT_SIZE, Expr("2px") },
// errPrefix->create({ 3, 3 }, {}, { 0.7, 0, 0.3, 1 }, { 1, 1, 1, 1 }, f); { Gui::StyleRule::SIZE, array<Expr, 2> { Expr("100dp"), Expr("-1") } },
// errPrefix->setText(errPrefixText); { Gui::StyleRule::MARGIN, array<Expr, 4> { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } }
// errPrefix->setPos({ 8, 16 }); }}
// errWrap->add(errPrefix); });
// auto errMsg = std::make_shared<GuiText>("error_text");
// errMsg->create({ 3, 3 }, {}, {}, { 1, 0.5, 0.6, 1 }, f);
// errMsg->setText(what);
// errMsg->setPos({ 8, 52 });
// errWrap->add(errMsg);
} }
sol::protected_function_result MenuSandbox::errorCallback(sol::protected_function_result r) const { sol::protected_function_result MenuSandbox::errorCallback(sol::protected_function_result r) {
sol::error err = r; string err = static_cast<sol::error>(r).what();
std::string errString = err.what();
try { std::cout << Log::err << err << Log::endl;
std::string::size_type lineNumStart = errString.find(':');
if (lineNumStart == std::string::npos) throw std::out_of_range("Improperly formatted error. [0]"); vec<string> lines;
std::string::size_type lineNumEnd = errString.find(':', lineNumStart + 1); {
if (lineNumEnd == std::string::npos) throw std::out_of_range("Improperly formatted error. [1]"); string line;
std::stringstream textStream(err);
std::string fileName = errString.substr(0, lineNumStart); while (std::getline(textStream, line, '\n')) lines.emplace_back(line);
int lineNum = std::stoi(errString.substr(lineNumStart + 1, lineNumEnd - lineNumStart - 1));
for (const LuaMod::File& file : mod.files)
if (file.path == fileName)
throw std::runtime_error(ErrorFormatter::formatError(fileName, lineNum, errString, file.file));
throw std::out_of_range("Error thrown outside of handled files. [2]");
} }
catch (const std::runtime_error& e) {
std::cout << Log::err << e.what() << std::endl; for (const let& line : lines) {
throw; usize lineNumStart = line.find(':');
} if (lineNumStart == string::npos) continue;
catch (const std::out_of_range& e) { usize lineNumEnd = line.find(':', lineNumStart + 1);
std::cout << Log::err << "Failed to format error, " << e.what() << Log::endl; if (lineNumEnd == string::npos) continue;
throw std::runtime_error(errString);
string fileName = line.substr(0, lineNumStart);
fileName.erase(std::remove_if(fileName.begin(), fileName.end(), isspace), fileName.end());
for (const let& file : mod.files) {
if (file.path == fileName) {
let msg = ErrorFormatter::formatError(fileName,
std::stoi(line.substr(lineNumStart + 1, lineNumEnd - lineNumStart - 1)),
err, file.file);
showError(msg);
return r;
}
}
} }
showError(err);
return r;
} }

View File

@ -7,6 +7,8 @@
#include "lua/LuaParser.h" #include "lua/LuaParser.h"
#include "lua/LuaMod.h" #include "lua/LuaMod.h"
#include "client/gui/Root.h"
#include "client/gui/Element.h"
#include "client/gui/GuiBuilder.h" #include "client/gui/GuiBuilder.h"
class Client; class Client;
@ -16,8 +18,8 @@ class SubgameDef;
class GuiContainer; class GuiContainer;
class MenuSandbox : LuaParser { class MenuSandbox : LuaParser {
public: public:
MenuSandbox(glm::ivec2& window, Client& client, std::shared_ptr<GuiContainer> container); MenuSandbox(Client& client, Gui::Root& root, sptr<Gui::Element> sandboxRoot);
void load(const SubgameDef& subgame); void load(const SubgameDef& subgame);
@ -26,28 +28,27 @@ class MenuSandbox : LuaParser {
void windowResized(); void windowResized();
using LuaParser::update; using LuaParser::update;
private:
private:
void reset(); void reset();
void loadApi(); void loadApi();
void loadAndRunMod(const std::string& modPath); void loadAndRunMod(const string& modPath);
void showError(const std::string& what, const std::string& subgame); void showError(const string& err);
sol::protected_function_result runFileSandboxed(const std::string& file); sol::protected_function_result runFileSandboxed(const string& file);
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override; virtual sol::protected_function_result errorCallback(sol::protected_function_result r) override;
LuaMod mod {}; LuaMod mod {};
std::vector<std::shared_ptr<AtlasRef>> modAssets{}; string subgameName;
// GuiRoot gui;
// std::shared_ptr<GuiContainer> container = nullptr;
// std::shared_ptr<GuiContainer> luaContainer = nullptr;
// GuiBuilder builder;
Client& client; Client& client;
glm::ivec2& win;
Gui::Root& root;
sptr<Gui::Element> sandboxRoot;
vec<sptr<AtlasRef>> menuAssets {};
}; };

View File

@ -17,36 +17,34 @@
#include "client/gui/compound/GuiImageButton.h" #include "client/gui/compound/GuiImageButton.h"
MainMenuScene::MainMenuScene(Client& client) : Scene(client), MainMenuScene::MainMenuScene(Client& client) : Scene(client),
root(client.renderer.window, client.game->textures) { root(client.renderer.window, client.game->textures),
sandboxElem(root.create<Gui::BoxElement>({ .classes = { "sandbox" }})),
sandbox(client, root, sandboxElem) {
client.renderer.setClearColor(0, 0, 0); client.renderer.setClearColor(0, 0, 0);
client.renderer.window.input.setMouseLocked(false); client.renderer.window.input.setMouseLocked(false);
root.body->setStyle(Gui::StyleRule::BACKGROUND, string("#123")); using Expr = Gui::Expression;
root.addStylesheet({ root.addStylesheet({
{ "sandbox", {{
{ Gui::StyleRule::H_ALIGN, string("center") },
{ Gui::StyleRule::V_ALIGN, string("center") }
}}},
{ "navigation", {{ { "navigation", {{
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("-1"), Gui::Expression("18dp") } } { Gui::StyleRule::SIZE, array<Expr, 2> { Expr("-1"), Expr("18dp") } }
}}}, }}},
{ "navigationWrap", {{ { "navigationWrap", {{
{ Gui::StyleRule::DIRECTION, string("row") }, { Gui::StyleRule::DIRECTION, string("row") },
{ Gui::StyleRule::POS, array<Gui::Expression, 2> { Gui::Expression("0"), Gui::Expression("0") } } { Gui::StyleRule::POS, array<Expr, 2> { Expr("0"), Expr("0") } }
}}}, }}},
{ "navigationBackground", {{ { "navigationBackground", {{
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("64dp"), Gui::Expression("18dp") } }, { Gui::StyleRule::SIZE, array<Expr, 2> { Expr("64dp"), Expr("18dp") } },
{ Gui::StyleRule::BACKGROUND, string("menu_bar_bg") } { Gui::StyleRule::BACKGROUND, string("menu_bar_bg") }
}}}, }}},
{ "navigationButton", {{ { "navigationButton", {{
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("16dp"), Gui::Expression("16dp") } }, { Gui::StyleRule::SIZE, array<Expr, 2> { Expr("16dp"), Expr("16dp") } },
{ Gui::StyleRule::CURSOR, string("pointer") } { Gui::StyleRule::CURSOR, string("pointer") }
}}} }}}
}); });
let sandbox = root.body->append<Gui::BoxElement>({ .classes = { "sandbox" } }); root.body->append(sandboxElem);
let navigation = root.body->append<Gui::BoxElement>({ .classes = { "navigation" } }); let navigation = root.body->append<Gui::BoxElement>({ .classes = { "navigation" } });
let navigationBG = navigation->append<Gui::BoxElement>({ .classes = { "navigationWrap" } }); let navigationBG = navigation->append<Gui::BoxElement>({ .classes = { "navigationWrap" } });
@ -56,9 +54,8 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client),
let navigationList = navigation->append<Gui::BoxElement>({ let navigationList = navigation->append<Gui::BoxElement>({
.classes = { "navigationWrap" }, .classes = { "navigationWrap" },
.styles = {{ .styles = {{
{ Gui::StyleRule::PADDING, array<Gui::Expression, 4> { Gui::StyleRule::PADDING, array<Expr, 4> { Expr("1dp"), Expr("1dp"), Expr("1dp"), Expr("1dp") } },
{ Gui::Expression("1dp"), Gui::Expression("1dp"), Gui::Expression("1dp"), Gui::Expression("1dp") } }, { Gui::StyleRule::GAP, array<Expr, 2> { Expr("1dp"), Expr("1dp") } }
{ Gui::StyleRule::GAP, array<Gui::Expression, 2> { Gui::Expression("1dp"), Gui::Expression("1dp") } }
}} }}
}); });
@ -81,9 +78,8 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client),
navigationList->append<Gui::BoxElement>({ navigationList->append<Gui::BoxElement>({
.styles = {{ .styles = {{
{ Gui::StyleRule::BACKGROUND, string("#fff5") }, { Gui::StyleRule::BACKGROUND, string("#fff5") },
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("1dp"), Gui::Expression("10dp") } }, { Gui::StyleRule::SIZE, array<Expr, 2> { Expr("1dp"), Expr("10dp") } },
{ Gui::StyleRule::MARGIN, array<Gui::Expression, 4> { Gui::StyleRule::MARGIN, array<Expr, 4> { Expr("2dp"), Expr("3dp"), Expr("2dp"), Expr("3dp") } }
{ Gui::Expression("2dp"), Gui::Expression("3dp"), Gui::Expression("2dp"), Gui::Expression("3dp") } }
}} }}
}); });
@ -108,7 +104,7 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client),
if (subgames.size() > 0) { if (subgames.size() > 0) {
selectedSubgame = &subgames[0]; selectedSubgame = &subgames[0];
// sandbox.load(*selectedSubgame); sandbox.load(*selectedSubgame);
} }
navigationList->append<Gui::BoxElement>(); navigationList->append<Gui::BoxElement>();

View File

@ -28,11 +28,16 @@ private:
/** Find valid subgames in the subgames folder. */ /** Find valid subgames in the subgames folder. */
void findSubgames(); void findSubgames();
/** The GUI root. */
Gui::Root root;
/** The GUI sandbox element root. */
sptr<Gui::Element> sandboxElem;
/** Provides the API for menu mods. */ /** Provides the API for menu mods. */
// MenuSandbox sandbox; MenuSandbox sandbox;
Gui::Root root;
/** A list of found subgames. */ /** A list of found subgames. */
vec<SubgameDef> subgames; vec<SubgameDef> subgames;

View File

@ -4,23 +4,25 @@
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <iostream>
#include <algorithm> #include <algorithm>
#include "ErrorFormatter.h" #include "ErrorFormatter.h"
#include "../util/Log.h" std::string ErrorFormatter::formatError(const string& fileName, usize line,
const string& stack, string file, bool ansiColors) noexcept {
std::string const string RED = "`cf";
ErrorFormatter::formatError(const string& fileName, usize line, const string& stack, string file, const string LTGRAY = "`c1";
bool ansiColors) noexcept { const string GRAY = "`c2";
const string red = (ansiColors ? Log::red : ""); const string BOLD = "`b";
const string unbl = (ansiColors ? Log::unbl : ""); const string UNDL = "`u";
const string endl = (ansiColors ? Log::endl : "\n"); const string ENDL = "`r\n";
std::stringstream out{}; std::stringstream out {};
// Split the file into lines, and add them to a vector out << BOLD << UNDL << fileName << ".lua" << ENDL << "\n";
vec<string> fileLines{};
vec<string> fileLines {};
usize pos = 0; usize pos = 0;
string token; string token;
@ -33,14 +35,28 @@ ErrorFormatter::formatError(const string& fileName, usize line, const string& st
while (fileLines.back() == "") fileLines.pop_back(); while (fileLines.back() == "") fileLines.pop_back();
// Format and add lines to the stringstream usize printStart = (std::max)(0, static_cast<i32>(line - LOOK_AROUND - 1));
for (usize i = (std::max)(static_cast<usize>(0), line - 6); i < (std::min)(fileLines.size(), line + 5); i++) { usize printEnd = (std::min)(fileLines.size(), line + LOOK_AROUND);
for (usize j = 0; j < 3 - std::to_string(i + 1).length(); j++) out << " ";
out << red << (i + 1 == line ? unbl : "") << (i + 1) << (i + 1 == line ? " # " : " | ") << fileLines[i] << endl; if (printStart != 0) {
for (usize j = 0; j < 3 - std::to_string(printStart).length(); j++) out << " ` ` ";
out << GRAY << printStart << " | -- snip --" << ENDL;
} }
// Add the stack trace at the bottom for (i32 i = printStart; i < printEnd; i++) {
out << endl << red << stack << endl; for (usize j = 0; j < 3 - std::to_string(i + 1).length(); j++) out << " ` ` ";
out << (i + 1 == line ? RED : LTGRAY) << (i + 1)
<< (i + 1 == line ? "" : "`cr")
<< " | " << (i + 1 == line ? BOLD : "")
<< fileLines[i] << ENDL;
}
if (printEnd != fileLines.size()) {
for (usize j = 0; j < 3 - std::to_string(printEnd + 1).length(); j++) out << " ` ` ";
out << GRAY << (printEnd + 1) << " | -- snip --" << ENDL;
}
out << "\n" << BOLD << UNDL << "Traceback" << ENDL << "\n" << RED << stack << ENDL;
return out.str(); return out.str();
} }

View File

@ -10,4 +10,6 @@ class ErrorFormatter {
public: public:
static string formatError(const string& fileName, usize line, static string formatError(const string& fileName, usize line,
const string& stack, string file, bool ansiColors = true) noexcept; const string& stack, string file, bool ansiColors = true) noexcept;
constexpr static i32 LOOK_AROUND = 4;
}; };

View File

@ -62,7 +62,7 @@ void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) {
core["__builtin"] = lua.create_table(); core["__builtin"] = lua.create_table();
// Types // Types
ClientApi::gui_element(lua); // ClientApi::gui_element(lua);
Api::Usertype::Target::bind(Api::State::CLIENT, lua, core); Api::Usertype::Target::bind(Api::State::CLIENT, lua, core);
Api::Usertype::Entity::bind(Api::State::CLIENT, lua, core); Api::Usertype::Entity::bind(Api::State::CLIENT, lua, core);
@ -116,7 +116,7 @@ void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) {
lua.set_function("runfile", &LocalLuaParser::runFileSandboxed, this); lua.set_function("runfile", &LocalLuaParser::runFileSandboxed, this);
} }
sol::protected_function_result LocalLuaParser::errorCallback(sol::protected_function_result r) const { sol::protected_function_result LocalLuaParser::errorCallback(sol::protected_function_result r) {
sol::error err = r; sol::error err = r;
std::string errString = err.what(); std::string errString = err.what();

View File

@ -28,7 +28,7 @@ class LocalLuaParser : public LuaParser {
private: private:
void loadApi(WorldPtr world, PlayerPtr player); void loadApi(WorldPtr world, PlayerPtr player);
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override; virtual sol::protected_function_result errorCallback(sol::protected_function_result r) override;
sol::protected_function_result runFileSandboxed(const std::string& file); sol::protected_function_result runFileSandboxed(const std::string& file);

View File

@ -26,5 +26,5 @@ class LuaKeybindHandler {
std::array<std::vector<sol::protected_function>, 1024> callbacksDown{}; std::array<std::vector<sol::protected_function>, 1024> callbacksDown{};
std::array<std::vector<sol::protected_function>, 1024> callbacksUp{}; std::array<std::vector<sol::protected_function>, 1024> callbacksUp{};
const LocalLuaParser* parser; LocalLuaParser* parser;
}; };

View File

@ -26,13 +26,13 @@ class LuaParser {
void bindModules(); void bindModules();
template<typename... Args> template<typename... Args>
sol::protected_function_result safe_function(sol::protected_function f, Args... args) const { sol::protected_function_result safe_function(sol::protected_function f, Args... args) {
auto res = f(args...); auto res = f(args...);
if (!res.valid()) errorCallback(res); if (!res.valid()) errorCallback(res);
return res; return res;
} }
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const = 0; virtual sol::protected_function_result errorCallback(sol::protected_function_result r) = 0;
Subgame& game; Subgame& game;

View File

@ -145,7 +145,7 @@ void ServerLuaParser::loadApi(WorldPtr world) {
lua.set_function("runfile", &ServerLuaParser::runFileSandboxed, this); lua.set_function("runfile", &ServerLuaParser::runFileSandboxed, this);
} }
sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_function_result r) const { sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_function_result r) {
sol::error err = r; sol::error err = r;
std::string errString = err.what(); std::string errString = err.what();

View File

@ -33,7 +33,7 @@ public:
private: private:
void loadApi(WorldPtr world); void loadApi(WorldPtr world);
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override; virtual sol::protected_function_result errorCallback(sol::protected_function_result r) override;
sol::protected_function_result runFileSandboxed(const std::string& file); sol::protected_function_result runFileSandboxed(const std::string& file);

View File

@ -1,7 +1,3 @@
//
// Created by aurailus on 2019-12-12.
//
#pragma once #pragma once
#include "lua/Lua.h" #include "lua/Lua.h"
@ -10,10 +6,10 @@
class LuaGuiElement; class LuaGuiElement;
namespace MenuApi { namespace MenuApi {
// void set_gui(GuiBuilder& builder, glm::ivec2& win, sol::state& lua, sol::table& core) { void set_gui(sol::state& lua, sol::table& core, sptr<Gui::Element>& root) {
// core.set_function("set_gui", [&](std::shared_ptr<LuaGuiElement> gui) { core.set_function("set_gui", [&](sptr<Gui::Element> elem) {
// builder.setGuiRoot(gui); root->clear();
// builder.build(win); root->append(elem);
// }); });
// } }
} }

View File

@ -12,12 +12,11 @@
#include "../../util/CovariantPtr.h" #include "../../util/CovariantPtr.h"
class Subgame; class Subgame;
class ItemStack; class ItemStack;
namespace Api::Usertype { namespace Api::Usertype {
class ItemStack : SubgameUsertype { class ItemStack : SubgameUsertype {
public: public:
ItemStack() = default; ItemStack() = default;
explicit ItemStack(sol::table tbl); explicit ItemStack(sol::table tbl);
@ -38,7 +37,7 @@ namespace Api::Usertype {
static void bind(State state, sol::state& lua, sol::table& core); static void bind(State state, sol::state& lua, sol::table& core);
private: private:
std::string name; std::string name;
unsigned short count; unsigned short count;
}; };

View File

@ -1,180 +1,297 @@
//
// Created by aurailus on 2020-04-12.
//
#include <iostream>
#include <glm/vec2.hpp>
#include "LuaGuiElement.h" #include "LuaGuiElement.h"
#include "client/gui/SerialGui.h" #include "client/gui/Gui.h"
#include "client/gui/Root.h"
#include "client/gui/Element.h"
#include "client/gui/BoxElement.h"
#include "client/gui/TextElement.h"
std::shared_ptr<LuaGuiElement> LuaGuiElement::create(const std::string& type, sol::table data) { static const Gui::Expression parseObjectToExpr(sol::object value) {
auto elem = std::make_shared<LuaGuiElement>(); if (value.is<f32>()) return Gui::Expression(std::to_string(value.as<f32>()) + "dp");
elem->type = type; if (value.is<string>()) return Gui::Expression(value.as<string>());
throw std::invalid_argument("Object cannot be converted to an expression.");
}
template <usize D>
static const array<Gui::Expression, D> parseLengthTableVal(sol::object value) {
array<Gui::Expression, D> arr {};
for (const auto& pair : data) { if (value.is<sol::table>()) {
if (pair.first.is<float>()) { const let& t = value.as<sol::table>();
if (!pair.second.is<std::shared_ptr<LuaGuiElement>>()) continue;
elem->children.push_back(pair.second.as<std::shared_ptr<LuaGuiElement>>()); vec<Gui::Expression> exprs {};
elem->children.back()->parent = elem.get(); exprs.reserve(t.size());
} for (let& v : t) exprs.emplace_back(parseObjectToExpr(v.second));
else if (pair.first.is<std::string>()) elem->set_trait(pair.first.as<std::string>(), pair.second);
for (usize i = 0; i < arr.size() / exprs.size(); i++)
for (usize j = 0; j < exprs.size(); j++)
arr[j + i * exprs.size()] = exprs[j];
return arr;
}
let v = parseObjectToExpr(value);
for (usize i = 0; i < arr.size(); i++) arr[i] = v;
return arr;
throw std::invalid_argument("Invalid length table configuration.");
}
void Api::Usertype::GuiElement::parseRule(const string& ruleStr, const sol::object& value, Gui::Style& styles) {
using namespace Gui;
const let ruleIt = Style::RULE_STRINGS_TO_ENUMS.find(ruleStr);
if (ruleIt == Style::RULE_STRINGS_TO_ENUMS.end())
throw std::invalid_argument("Style rule '" + ruleStr + "' doesn't exist.");
const StyleRule rule = ruleIt->second;
switch (rule) {
default:
throw std::invalid_argument("Unhandled rule '" + ruleStr + "'! This is an engine error!");
case StyleRule::LAYOUT:
case StyleRule::DIRECTION:
case StyleRule::H_ALIGN:
case StyleRule::V_ALIGN:
case StyleRule::CURSOR:
case StyleRule::OVERFLOW:
case StyleRule::TEXT_COLOR:
case StyleRule::BACKGROUND:
case StyleRule::BACKGROUND_HOVER:
case StyleRule::CONTENT:
styles.rules[rule] = value.as<string>();
break;
case StyleRule::POS:
case StyleRule::SIZE:
case StyleRule::GAP:
styles.rules[rule] = parseLengthTableVal<2>(value);
break;
case StyleRule::MARGIN:
case StyleRule::PADDING:
styles.rules[rule] = parseLengthTableVal<4>(value);
break;
case StyleRule::TEXT_SIZE:
styles.rules[rule] = parseObjectToExpr(value);
break;
}
}
std::shared_ptr<Gui::Element> Api::Usertype::GuiElement::create(const string& type, sol::table data, Gui::Root& root) {
Gui::Element::Props props {};
for (let& style : data) {
if (!style.first.is<string>()) continue;
GuiElement::parseRule(style.first.as<string>(), style.second, props.styles);
}
sptr<Gui::Element> elem = nullptr;
switch (Util::hash(type.data())) {
default: throw std::invalid_argument("Invalid element type '" + type + "'.");
case Util::hash("Box"): elem = root.create<Gui::BoxElement>(props); break;
case Util::hash("Text"): elem = root.create<Gui::TextElement>(props); break;
}
for (usize i = 1; i <= data.size(); i++) {
const sol::object& child = data.get<sol::object>(i);
if (!child.is<sptr<Gui::Element>>()) continue;
elem->append(child.as<sptr<Gui::Element>>());
} }
return elem; return elem;
}
sol::object LuaGuiElement::get_trait(sol::this_state s, const std::string& key) {
if (key == "key") return sol::make_object<std::string>(s, this->key);
if (key == "type") return sol::make_object<std::string>(s, this->type);
if (traits.count(key)) return traits.at(key); // let elem = root.create<Gui::BoxElement>(props);
return sol::nil; // return elem;
} // auto elem = std::make_shared<LuaGuiElement>();
sol::object LuaGuiElement::set_trait(const std::string& key, sol::object val) {
if (key == "callbacks") {
callbacks.clear();
for (auto pair : val.as<sol::table>()) callbacks[pair.first.as<std::string>()] = pair.second.as<sol::function>();
}
else if (key == "key") {
this->key = val.as<std::string>();
}
else {
traits.erase(key);
traits.emplace(key, val);
}
if (updateFunction) updateFunction();
return val;
}
sol::object LuaGuiElement::call(sol::this_state s, sol::protected_function fun) {
sol::table tbl = sol::state_view(s)["zepha"]["__builtin"]["gui_env"];
sol::environment env(s, sol::create, tbl);
sol::set_environment(env, fun);
return fun(this);
}
sol::object LuaGuiElement::get_child(sol::this_state s, sol::object key) {
if (key.is<float>() && key.as<float>() <= children.size()) {
auto begin = children.begin();
std::advance(begin, key.as<float>() - 1);
return sol::make_object<std::shared_ptr<LuaGuiElement>>(s, *begin);
}
else if (key.is<std::string>()) {
for (auto& child : children) {
if (child->key == key.as<std::string>()) return sol::make_object<std::shared_ptr<LuaGuiElement>>(s, child);
}
for (auto& child : children) {
auto recurse = child->get_child(s, key);
if (recurse) return recurse;
}
}
return sol::nil;
}
void LuaGuiElement::append(sol::this_state s, sol::object elem) {
if (elem.is<std::shared_ptr<LuaGuiElement>>()) children.push_back(elem.as<std::shared_ptr<LuaGuiElement>>());
else if (elem.is<sol::protected_function>())
children.push_back(call(s, elem.as<sol::protected_function>()).as<std::shared_ptr<LuaGuiElement>>());
else throw std::runtime_error("Append arg is not an element or a function to generate one.");
children.back()->parent = this;
if (updateFunction) updateFunction();
}
void LuaGuiElement::prepend(sol::this_state s, sol::object elem) {
if (elem.is<std::shared_ptr<LuaGuiElement>>())
children.insert(children.begin(), elem.as<std::shared_ptr<LuaGuiElement>>());
else if (elem.is<sol::function>())
children.insert(children.begin(), call(s, elem.as<sol::function>()).as<std::shared_ptr<LuaGuiElement>>());
else throw std::runtime_error("Append arg is not an element or a function to generate one.");
children.front()->parent = this;
if (updateFunction) updateFunction();
}
void LuaGuiElement::remove(sol::this_state s, sol::object elem) {
if (!elem) {
if (parent != nullptr) parent->remove(s, sol::make_object<std::string>(s, key));
else throw std::runtime_error("Tried to remove self from nil parent.");
}
else if (elem.is<std::string>()) {
auto child = this->get_child(s, sol::make_object<std::string>(s, elem.as<std::string>()));
if (child) remove(s, child);
}
else if (elem.is<std::shared_ptr<LuaGuiElement>>()) {
auto parent = elem.as<std::shared_ptr<LuaGuiElement>>()->parent;
for (auto it = parent->children.cbegin(); it != parent->children.cend(); it++) {
if ((*it)->key == elem.as<std::shared_ptr<LuaGuiElement>>()->key) {
(*it)->parent = nullptr;
(*it)->updateFunction = nullptr;
parent->children.erase(it);
if (parent->updateFunction) parent->updateFunction();
return;
}
}
}
}
void LuaGuiElement::clear(sol::this_state s) {
for (auto it = children.cbegin(); it != children.cend();) {
(*it)->parent = nullptr;
(*it)->updateFunction = nullptr;
it = children.erase(it);
}
if (updateFunction) updateFunction();
}
Any LuaGuiElement::getAsAny(const std::string& key) const {
if (!traits.count(key)) return Any();
// auto object = traits.at(key);
// //
// if (object.is<float>()) return Any::from<float>(object.as<float>()); // elem->type = type;
// else if (object.is<bool>()) return Any::from<bool>(object.as<bool>());
// else if (object.is<std::string>()) return Any::from<std::string>(object.as<std::string>());
// else if (object.is<sol::table>()) {
// auto table = object.as<sol::table>();
// //
// if (table.size() == 2) { // for (const auto& pair : data) {
// auto x = table.get<sol::object>(1); // if (pair.first.is<float>()) {
// auto y = table.get<sol::object>(2); // if (!pair.second.is<std::shared_ptr<LuaGuiElement>>()) continue;
// // elem->children.push_back(pair.second.as<std::shared_ptr<LuaGuiElement>>());
// glm::vec2 values = {}; // elem->children.back()->parent = elem.get();
// if (x.is<float>()) values.x = x.as<float>();
// else if (x.is<std::string>()) values.x = SerialGui::toDouble(x.as<std::string>());
// if (y.is<float>()) values.y = y.as<float>();
// else if (y.is<std::string>()) values.y = SerialGui::toDouble(y.as<std::string>());
//
// return Any::from<glm::vec2>(values);
// } // }
// else if (table.size() == 4) { // else if (pair.first.is<std::string>()) elem->set_trait(pair.first.as<std::string>(), pair.second);
// auto x = table.get<sol::object>(1); // }
// auto y = table.get<sol::object>(2);
// auto z = table.get<sol::object>(3);
// auto w = table.get<sol::object>(4);
// //
// glm::vec4 values = {}; // return elem;
// if (x.is<float>()) values.x = x.as<float>(); }
// else if (x.is<std::string>()) values.x = SerialGui::toDouble(x.as<std::string>());
// if (y.is<float>()) values.y = y.as<float>(); void Api::Usertype::GuiElement::bind(sol::state& lua, sol::table& core, Gui::Root& root) {
// else if (y.is<std::string>()) values.y = SerialGui::toDouble(y.as<std::string>()); lua.new_usertype<Gui::Element>("GuiElement",
// if (z.is<float>()) values.z = z.as<float>(); sol::meta_function::construct, sol::factories([&](const string& type, sol::table data) {
// else if (z.is<std::string>()) values.z = SerialGui::toDouble(z.as<std::string>()); return GuiElement::create(type, data, root);
// if (w.is<float>()) values.w = w.as<float>(); })
// else if (w.is<std::string>()) values.w = SerialGui::toDouble(w.as<std::string>()); );
}
// //
// return Any::from<glm::vec4>(values); //// sol::meta_function::index, &LuaGuiElement::get_trait,
//// sol::meta_function::new_index, &LuaGuiElement::set_trait,
//
//// sol::meta_function::call, &LuaGuiElement::call,
//
//// "get", &LuaGuiElement::get_child,
//// "append", &LuaGuiElement::append,
//// "prepend", &LuaGuiElement::prepend,
//// "remove", &LuaGuiElement::remove,
//// "clear", &LuaGuiElement::clear
//
//sol::object LuaGuiElement::get_trait(sol::this_state s, const std::string& key) {
// if (key == "key") return sol::make_object<std::string>(s, this->key);
// if (key == "type") return sol::make_object<std::string>(s, this->type);
//
// if (traits.count(key)) return traits.at(key);
// return sol::nil;
//}
//
//sol::object LuaGuiElement::set_trait(const std::string& key, sol::object val) {
// if (key == "callbacks") {
// callbacks.clear();
// for (auto pair : val.as<sol::table>()) callbacks[pair.first.as<std::string>()] = pair.second.as<sol::function>();
// }
// else if (key == "key") {
// this->key = val.as<std::string>();
// }
// else {
// traits.erase(key);
// traits.emplace(key, val);
// }
//
// if (updateFunction) updateFunction();
// return val;
//}
//
//sol::object LuaGuiElement::call(sol::this_state s, sol::protected_function fun) {
// sol::table tbl = sol::state_view(s)["zepha"]["__builtin"]["gui_env"];
// sol::environment env(s, sol::create, tbl);
//
// sol::set_environment(env, fun);
// return fun(this);
//}
//
//sol::object LuaGuiElement::get_child(sol::this_state s, sol::object key) {
// if (key.is<float>() && key.as<float>() <= children.size()) {
// auto begin = children.begin();
// std::advance(begin, key.as<float>() - 1);
// return sol::make_object<std::shared_ptr<LuaGuiElement>>(s, *begin);
// }
// else if (key.is<std::string>()) {
// for (auto& child : children) {
// if (child->key == key.as<std::string>()) return sol::make_object<std::shared_ptr<LuaGuiElement>>(s, child);
// }
//
// for (auto& child : children) {
// auto recurse = child->get_child(s, key);
// if (recurse) return recurse;
// } // }
// } // }
//
throw std::runtime_error("Invalid type requested in getAsAny"); // return sol::nil;
} //}
//
//void LuaGuiElement::append(sol::this_state s, sol::object elem) {
// if (elem.is<std::shared_ptr<LuaGuiElement>>()) children.push_back(elem.as<std::shared_ptr<LuaGuiElement>>());
// else if (elem.is<sol::protected_function>())
// children.push_back(call(s, elem.as<sol::protected_function>()).as<std::shared_ptr<LuaGuiElement>>());
// else throw std::runtime_error("Append arg is not an element or a function to generate one.");
//
// children.back()->parent = this;
// if (updateFunction) updateFunction();
//}
//
//void LuaGuiElement::prepend(sol::this_state s, sol::object elem) {
// if (elem.is<std::shared_ptr<LuaGuiElement>>())
// children.insert(children.begin(), elem.as<std::shared_ptr<LuaGuiElement>>());
// else if (elem.is<sol::function>())
// children.insert(children.begin(), call(s, elem.as<sol::function>()).as<std::shared_ptr<LuaGuiElement>>());
// else throw std::runtime_error("Append arg is not an element or a function to generate one.");
//
// children.front()->parent = this;
// if (updateFunction) updateFunction();
//}
//
//void LuaGuiElement::remove(sol::this_state s, sol::object elem) {
// if (!elem) {
// if (parent != nullptr) parent->remove(s, sol::make_object<std::string>(s, key));
// else throw std::runtime_error("Tried to remove self from nil parent.");
// }
// else if (elem.is<std::string>()) {
// auto child = this->get_child(s, sol::make_object<std::string>(s, elem.as<std::string>()));
// if (child) remove(s, child);
// }
// else if (elem.is<std::shared_ptr<LuaGuiElement>>()) {
// auto parent = elem.as<std::shared_ptr<LuaGuiElement>>()->parent;
//
// for (auto it = parent->children.cbegin(); it != parent->children.cend(); it++) {
// if ((*it)->key == elem.as<std::shared_ptr<LuaGuiElement>>()->key) {
// (*it)->parent = nullptr;
// (*it)->updateFunction = nullptr;
//
// parent->children.erase(it);
// if (parent->updateFunction) parent->updateFunction();
// return;
// }
// }
// }
//}
//
//void LuaGuiElement::clear(sol::this_state s) {
// for (auto it = children.cbegin(); it != children.cend();) {
// (*it)->parent = nullptr;
// (*it)->updateFunction = nullptr;
// it = children.erase(it);
// }
//
// if (updateFunction) updateFunction();
//}
//
//Any LuaGuiElement::getAsAny(const std::string& key) const {
// if (!traits.count(key)) return Any();
//// auto object = traits.at(key);
////
//// if (object.is<float>()) return Any::from<float>(object.as<float>());
//// else if (object.is<bool>()) return Any::from<bool>(object.as<bool>());
//// else if (object.is<std::string>()) return Any::from<std::string>(object.as<std::string>());
//// else if (object.is<sol::table>()) {
//// auto table = object.as<sol::table>();
////
//// if (table.size() == 2) {
//// auto x = table.get<sol::object>(1);
//// auto y = table.get<sol::object>(2);
////
//// glm::vec2 values = {};
//// if (x.is<float>()) values.x = x.as<float>();
//// else if (x.is<std::string>()) values.x = SerialGui::toDouble(x.as<std::string>());
//// if (y.is<float>()) values.y = y.as<float>();
//// else if (y.is<std::string>()) values.y = SerialGui::toDouble(y.as<std::string>());
////
//// return Any::from<glm::vec2>(values);
//// }
//// else if (table.size() == 4) {
//// auto x = table.get<sol::object>(1);
//// auto y = table.get<sol::object>(2);
//// auto z = table.get<sol::object>(3);
//// auto w = table.get<sol::object>(4);
////
//// glm::vec4 values = {};
//// if (x.is<float>()) values.x = x.as<float>();
//// else if (x.is<std::string>()) values.x = SerialGui::toDouble(x.as<std::string>());
//// if (y.is<float>()) values.y = y.as<float>();
//// else if (y.is<std::string>()) values.y = SerialGui::toDouble(y.as<std::string>());
//// if (z.is<float>()) values.z = z.as<float>();
//// else if (z.is<std::string>()) values.z = SerialGui::toDouble(z.as<std::string>());
//// if (w.is<float>()) values.w = w.as<float>();
//// else if (w.is<std::string>()) values.w = SerialGui::toDouble(w.as<std::string>());
////
//// return Any::from<glm::vec4>(values);
//// }
//// }
//
// throw std::runtime_error("Invalid type requested in getAsAny");
//}

View File

@ -1,84 +1,97 @@
//
// Created by aurailus on 2020-04-12.
//
#pragma once #pragma once
#include <list> #include "lua/Lua.h"
#include "../Lua.h" #include "util/Types.h"
#include "../../util/Any.h" //#include "BaseUsertype.h"
//#include "../../util/CovariantPtr.h"
class LuaGuiElement { //class Subgame;
public: //class ItemStack;
LuaGuiElement() = default;
namespace Gui {
class Style;
class Root;
class Element;
}
namespace Api::Usertype::GuiElement {
void parseRule(const string& ruleStr, const sol::object& value, Gui::Style& styles);
// Lua Functions and Properties std::shared_ptr<Gui::Element> create(const string& type, sol::table data, Gui::Root& root);
static std::shared_ptr<LuaGuiElement> create(const std::string& type, sol::table data);
sol::object get_trait(sol::this_state s, const std::string& key);
sol::object set_trait(const std::string& key, sol::object val);
sol::object call(sol::this_state s, sol::protected_function fun); sol::object call(sol::this_state s, sol::protected_function fun);
sol::object get_child(sol::this_state s, sol::object key); void bind(sol::state& lua, sol::table& core, Gui::Root& root);
void append(sol::this_state s, sol::object elem);
void prepend(sol::this_state s, sol::object elem);
void remove(sol::this_state s, sol::object elem);
void clear(sol::this_state s);
std::string type{}, key{};
LuaGuiElement* parent = nullptr;
std::list<std::shared_ptr<LuaGuiElement>> children{};
std::unordered_map<std::string, sol::function> callbacks{};
std::unordered_map<std::string, sol::object> traits{};
// C++ Functions and Properties
Any getAsAny(const std::string& key) const;
template<typename T>
const T& get(const std::string& key) const {
return getAsAny(key).get<T>();
}
template<typename T>
const T& get_or(const std::string& key, const T& other) const noexcept {
Any a = getAsAny(key);
if (a.empty() || !a.is<T>()) return other;
return a.get<T>();
}
template<typename T>
const bool has(const std::string& key) const noexcept {
Any a = getAsAny(key);
return !a.empty() && a.is<T>();
}
std::function<void()> updateFunction = nullptr;
};
namespace ClientApi {
static void gui_element(sol::state& lua) {
lua.new_usertype<LuaGuiElement>("GuiElement",
sol::meta_function::construct, sol::factories(&LuaGuiElement::create),
sol::meta_function::index, &LuaGuiElement::get_trait,
sol::meta_function::new_index, &LuaGuiElement::set_trait,
sol::meta_function::call, &LuaGuiElement::call,
"get", &LuaGuiElement::get_child,
"append", &LuaGuiElement::append,
"prepend", &LuaGuiElement::prepend,
"remove", &LuaGuiElement::remove,
"clear", &LuaGuiElement::clear
);
}
} }
//class LuaGuiElement {
// public:
// LuaGuiElement() = default;
//
// // Lua Functions and Properties
//
// sol::object get_trait(sol::this_state s, const std::string& key);
//
// sol::object set_trait(const std::string& key, sol::object val);
//
//
// sol::object get_child(sol::this_state s, sol::object key);
//
// void append(sol::this_state s, sol::object elem);
//
// void prepend(sol::this_state s, sol::object elem);
//
// void remove(sol::this_state s, sol::object elem);
//
// void clear(sol::this_state s);
//
// std::string type{}, key{};
//
// LuaGuiElement* parent = nullptr;
// std::list<std::shared_ptr<LuaGuiElement>> children{};
//
// std::unordered_map<std::string, sol::function> callbacks{};
// std::unordered_map<std::string, sol::object> traits{};
//
// // C++ Functions and Properties
// Any getAsAny(const std::string& key) const;
//
// template<typename T>
// const T& get(const std::string& key) const {
// return getAsAny(key).get<T>();
// }
//
// template<typename T>
// const T& get_or(const std::string& key, const T& other) const noexcept {
// Any a = getAsAny(key);
// if (a.empty() || !a.is<T>()) return other;
// return a.get<T>();
// }
//
// template<typename T>
// const bool has(const std::string& key) const noexcept {
// Any a = getAsAny(key);
// return !a.empty() && a.is<T>();
// }
//
// std::function<void()> updateFunction = nullptr;
//};
//
//namespace ClientApi {
// static void gui_element(sol::state& lua) {
// lua.new_usertype<Gui::Element>("GuiElement",
// sol::meta_function::construct, sol::factories(&LuaGuiElement::create),
//
// sol::meta_function::index, &LuaGuiElement::get_trait,
// sol::meta_function::new_index, &LuaGuiElement::set_trait,
//
// sol::meta_function::call, &LuaGuiElement::call,
//
// "get", &LuaGuiElement::get_child,
// "append", &LuaGuiElement::append,
// "prepend", &LuaGuiElement::prepend,
// "remove", &LuaGuiElement::remove,
// "clear", &LuaGuiElement::clear
// );
// }
//}

View File

@ -8,7 +8,6 @@
#include "ItemStack.h" #include "ItemStack.h"
#include "InventoryList.h" #include "InventoryList.h"
#include "LuaGuiElement.h"
#include "world/LocalWorld.h" #include "world/LocalWorld.h"
#include "world/ServerWorld.h" #include "world/ServerWorld.h"
#include "world/inv/Inventory.h" #include "world/inv/Inventory.h"
@ -168,21 +167,25 @@ bool Api::Usertype::LocalPlayer::is_in_menu() {
return player.l()->isInMenu(); return player.l()->isInMenu();
} }
void Api::Usertype::LocalPlayer::show_menu(std::shared_ptr<LuaGuiElement> root) { //void Api::Usertype::LocalPlayer::show_menu(std::shared_ptr<LuaGuiElement> root) {
return player.l()->showMenu(root); //// return player.l()->showMenu(root);
} // return;
//}
void Api::Usertype::LocalPlayer::close_menu() { void Api::Usertype::LocalPlayer::close_menu() {
return player.l()->closeMenu(); // return player.l()->closeMenu();
return;
} }
std::shared_ptr<LuaGuiElement> Api::Usertype::LocalPlayer::get_hud() { //std::shared_ptr<LuaGuiElement> Api::Usertype::LocalPlayer::get_hud() {
return player.l()->getHud(); //// return player.l()->getHud();
} // return nullptr;
//}
void Api::Usertype::LocalPlayer::set_hud(std::shared_ptr<LuaGuiElement> hud) { //void Api::Usertype::LocalPlayer::set_hud(std::shared_ptr<LuaGuiElement> hud) {
player.l()->setHud(hud); //// player.l()->setHud(hud);
} // return;
//}
void Api::Usertype::LocalPlayer::bind(State, sol::state& lua, sol::table& core) { void Api::Usertype::LocalPlayer::bind(State, sol::state& lua, sol::table& core) {
lua.new_usertype<LocalPlayer>("Player", lua.new_usertype<LocalPlayer>("Player",
@ -209,10 +212,10 @@ void Api::Usertype::LocalPlayer::bind(State, sol::state& lua, sol::table& core)
"get_dimension", &LocalPlayer::get_dimension, "get_dimension", &LocalPlayer::get_dimension,
"show_menu", &LocalPlayer::show_menu, // "show_menu", &LocalPlayer::show_menu,
"close_menu", &LocalPlayer::close_menu, "close_menu", &LocalPlayer::close_menu,
"set_hud", &LocalPlayer::set_hud, // "set_hud", &LocalPlayer::set_hud,
"get_hud", &LocalPlayer::get_hud, // "get_hud", &LocalPlayer::get_hud,
"pos", sol::property(&LocalPlayer::get_pos, &LocalPlayer::set_pos), "pos", sol::property(&LocalPlayer::get_pos, &LocalPlayer::set_pos),
"block_pos", sol::property(&LocalPlayer::get_block_pos, &LocalPlayer::set_pos), "block_pos", sol::property(&LocalPlayer::get_block_pos, &LocalPlayer::set_pos),

View File

@ -12,7 +12,7 @@
#include "Dimension.h" #include "Dimension.h"
#include "world/player/LocalPlayer.h" #include "world/player/LocalPlayer.h"
class LuaGuiElement; //class LuaGuiElement;
namespace Api::Usertype { namespace Api::Usertype {
class ServerPlayer; class ServerPlayer;
@ -82,13 +82,13 @@ public:
bool is_in_menu(); bool is_in_menu();
void show_menu(std::shared_ptr<LuaGuiElement> root); // void show_menu(std::shared_ptr<LuaGuiElement> root);
void close_menu(); void close_menu();
std::shared_ptr<LuaGuiElement> get_hud(); // std::shared_ptr<LuaGuiElement> get_hud();
void set_hud(std::shared_ptr<LuaGuiElement> hud); // void set_hud(std::shared_ptr<LuaGuiElement> hud);
static void bind(State state, sol::state& lua, sol::table& core); static void bind(State state, sol::state& lua, sol::table& core);
}; };

View File

@ -100,23 +100,23 @@ bool LocalPlayer::isInMenu() {
// return gameGui.isInMenu(); // return gameGui.isInMenu();
} }
void LocalPlayer::showMenu(sptr<LuaGuiElement> root) { //void LocalPlayer::showMenu(sptr<LuaGuiElement> root) {
// gameGui.showMenu(root); //// gameGui.showMenu(root);
renderer.window.input.setMouseLocked(false); // renderer.window.input.setMouseLocked(false);
} //}
void LocalPlayer::closeMenu() { void LocalPlayer::closeMenu() {
// gameGui.closeMenu(); // gameGui.closeMenu();
renderer.window.input.setMouseLocked(true); renderer.window.input.setMouseLocked(true);
} }
sptr<LuaGuiElement> LocalPlayer::getHud() { //sptr<LuaGuiElement> LocalPlayer::getHud() {
// return gameGui.getHud(); //// return gameGui.getHud();
} //}
void LocalPlayer::setHud(sptr<LuaGuiElement> hud) { //void LocalPlayer::setHud(sptr<LuaGuiElement> hud) {
// gameGui.setHud(hud); //// gameGui.setHud(hud);
} //}
void LocalPlayer::setHudVisible(bool hudVisible) { void LocalPlayer::setHudVisible(bool hudVisible) {
// gameGui.setVisible(hudVisible); // gameGui.setVisible(hudVisible);

View File

@ -11,7 +11,6 @@
class Input; class Input;
class Deserializer; class Deserializer;
class LuaGuiElement;
class LocalInventory; class LocalInventory;
class LocalInventoryRefs; class LocalInventoryRefs;
enum class NetPlayerField; enum class NetPlayerField;
@ -89,7 +88,7 @@ public:
* @param root - The root GUI element to display. * @param root - The root GUI element to display.
*/ */
void showMenu(sptr<LuaGuiElement> root); // void showMenu(sptr<LuaGuiElement> root);
/** /**
* Closes the currently open menu. * Closes the currently open menu.
@ -102,7 +101,7 @@ public:
* @returns the root GUI element of the hud. * @returns the root GUI element of the hud.
*/ */
sptr<LuaGuiElement> getHud(); // sptr<LuaGuiElement> getHud();
/** /**
* Sets the HUD to the specified GUI tree. The hud does not constitute * Sets the HUD to the specified GUI tree. The hud does not constitute
@ -111,7 +110,7 @@ public:
* @param hud - The root GUI element to display. * @param hud - The root GUI element to display.
*/ */
void setHud(sptr<LuaGuiElement> hud); // void setHud(sptr<LuaGuiElement> hud);
/** /**
* Sets the visibility state of the HUD. * Sets the visibility state of the HUD.

View File

@ -1,7 +0,0 @@
{
"name": "minimal",
"display_name": "Minimal Subgame",
"author": "@aurailus",
"description": "Minimal subgame for development.",
"version": "0.0.1"
}

View File

@ -1,31 +1,31 @@
local gui = zepha.build_gui(function() zepha.set_gui(zepha.gui(function()
return Gui.Body { return Gui.Box {
-- background = "#214a21",
background = "#334", background = "#334",
Gui.Text { Gui.Text {
position = { 4, 4 }, pos = { 4, 4 },
text_size = "2px",
content = "Minimalminimalmmnal" content = "Minimalminimalmmnal"
}, },
Gui.Rect { Gui.Box {
position = { 64, 64 }, pos = { 64, 64 },
size = { 128 * (16/9), 128 }, size = { 128 * (16/9), 128 },
background = "zeus_background" background = "zeus_background"
}, },
Gui.Rect { Gui.Box {
position = { 64 + 128, 64 + 64 }, pos = { 64 + 128, 64 + 64 },
size = { 128 * (16/9), 128 }, size = { 128 * (16/9), 128 },
background = "zeus_background", background = "zeus_background",
Gui.Text { Gui.Text {
pos = 4,
text_size = "4px",
content = "What's the fuck it'd going on?" content = "What's the fuck it'd going on?"
} }
} }
} }
end) end))
zepha.set_gui(gui)

View File

@ -1,9 +1,11 @@
zepha.set_gui(zepha.build_gui(function() zepha.set_gui(zepha.gui(function()
return Gui.Body { return Gui.Box {
background = "#124778", background = "#124778",
h_align = "center",
v_align = "center",
Gui.Text { Gui.Text {
position = { 4, 4 }, size = { 64, 4 },
content = "Parentheses" content = "Parentheses"
} }
} }