This commit is contained in:
A-lex-Ra 2024-02-03 09:16:10 +06:00
commit f599ed7fe7
58 changed files with 1217 additions and 492 deletions

View File

@ -9,7 +9,12 @@ on:
jobs:
build-appimage:
runs-on: ubuntu-20.04
strategy:
matrix:
include:
- os: ubuntu-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2

View File

@ -45,7 +45,7 @@ if(MSVC)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /source-charset:UTF-8")
else()
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -lstdc++fs
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra
# additional warnings
-Wformat-nonliteral -Wcast-align
-Wpointer-arith -Wundef
@ -114,7 +114,7 @@ if(UNIX)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie -lstdc++fs")
endif()
include_directories(${LUA_INCLUDE_DIR})

View File

@ -50,20 +50,20 @@ void AssetsLoader::createDefaults(AssetsLoader& loader) {
loader.addLoader(ASSET_ATLAS, assetload::atlas);
}
void AssetsLoader::addDefaults(AssetsLoader& loader, bool allAssets) {
if (allAssets) {
loader.add(ASSET_SHADER, SHADERS_FOLDER"/main", "main");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/lines", "lines");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui", "ui");
void AssetsLoader::addDefaults(AssetsLoader& loader, bool world) {
loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui", "ui");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/main", "main");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/lines", "lines");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/menubg.png", "gui/menubg");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/delete_icon.png", "gui/delete_icon");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/no_icon.png", "gui/no_icon");
if (world) {
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/menubg.png", "gui/menubg");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/delete_icon.png", "gui/delete_icon");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/no_icon.png", "gui/no_icon");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/sun.png", "misc/sun");
loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal");
}
loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/blocks", "blocks");
loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/items", "items");

View File

@ -36,7 +36,7 @@ public:
bool loadNext();
static void createDefaults(AssetsLoader& loader);
static void addDefaults(AssetsLoader& loader, bool allAssets);
static void addDefaults(AssetsLoader& loader, bool world);
const ResPaths* getPaths() const;
};

View File

@ -20,12 +20,14 @@ bool assetload::texture(Assets* assets,
const ResPaths* paths,
const std::string filename,
const std::string name) {
Texture* texture = png::load_texture(paths->find(filename).string());
std::unique_ptr<Texture> texture(
png::load_texture(paths->find(filename).string())
);
if (texture == nullptr) {
std::cerr << "failed to load texture '" << name << "'" << std::endl;
return false;
}
assets->store(texture, name);
assets->store(texture.release(), name);
return true;
}
@ -92,21 +94,21 @@ bool assetload::font(Assets* assets,
const ResPaths* paths,
const std::string filename,
const std::string name) {
std::vector<Texture*> pages;
std::vector<std::unique_ptr<Texture>> pages;
for (size_t i = 0; i <= 4; i++) {
std::string name = filename + "_" + std::to_string(i) + ".png";
name = paths->find(name).string();
Texture* texture = png::load_texture(name);
std::unique_ptr<Texture> texture (png::load_texture(name));
if (texture == nullptr) {
std::cerr << "failed to load bitmap font '" << name;
std::cerr << "' (missing page " << std::to_string(i) << ")";
std::cerr << std::endl;
return false;
}
pages.push_back(texture);
pages.push_back(std::move(texture));
}
Font* font = new Font(pages, pages[0]->height / 16);
assets->store(font, name);
int res = pages[0]->height / 16;
assets->store(new Font(std::move(pages), res, 4), name);
return true;
}
@ -135,7 +137,6 @@ bool assetload::animation(Assets* assets,
auto frameArr = root->list("frames");
Frame temp;
float frameDuration = DEFAULT_FRAME_DURATION;
std::string frameName;
@ -164,7 +165,7 @@ bool assetload::animation(Assets* assets,
if (!appendAtlas(builder, file)) continue;
}
Atlas* srcAtlas = builder.build(2);
std::unique_ptr<Atlas> srcAtlas (builder.build(2));
Texture* srcTex = srcAtlas->getTexture();
Texture* dstTex = dstAtlas->getTexture();
@ -196,7 +197,7 @@ bool assetload::animation(Assets* assets,
}
}
assets->store(srcAtlas, name + "_animation");
assets->store(srcAtlas.release(), name + "_animation");
assets->store(animation);
return true;

View File

@ -4,19 +4,6 @@
#include <stdexcept>
#include <math.h>
inline int char2int(int c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'f') {
return 10 + c - 'a';
}
if (c >= 'A' && c <= 'F') {
return 10 + c - 'A';
}
return -1;
}
inline double power(double base, int64_t power) {
double result = 1.0;
for (int64_t i = 0; i < power; i++) {
@ -98,6 +85,18 @@ void BasicParser::skipWhitespace() {
}
}
void BasicParser::skip(size_t n) {
n = std::min(n, source.length()-pos);
for (size_t i = 0; i < n; i++) {
char next = source[pos++];
if (next == '\n') {
line++;
linestart = pos;
}
}
}
void BasicParser::skipLine() {
while (hasNext()) {
if (source[pos] == '\n') {
@ -110,10 +109,28 @@ void BasicParser::skipLine() {
}
}
bool BasicParser::skipTo(const std::string& substring) {
size_t idx = source.find(substring, pos);
if (idx == std::string::npos) {
skip(source.length()-pos);
return false;
} else {
skip(idx-pos);
return true;
}
}
bool BasicParser::hasNext() {
return pos < source.length();
}
bool BasicParser::isNext(const std::string& substring) {
if (source.length() - pos < substring.length()) {
return false;
}
return source.substr(pos, substring.length()) == substring;
}
char BasicParser::nextChar() {
if (!hasNext()) {
throw error("unexpected end");
@ -129,6 +146,17 @@ void BasicParser::expect(char expected) {
pos++;
}
void BasicParser::expect(const std::string& substring) {
if (substring.empty())
return;
for (uint i = 0; i < substring.length(); i++) {
if (source.length() <= pos + i || source[pos+i] != substring[i]) {
throw error(escape_string(substring)+" expected");
}
}
pos += substring.length();
}
void BasicParser::expectNewLine() {
while (hasNext()) {
char next = source[pos];
@ -145,6 +173,10 @@ void BasicParser::expectNewLine() {
}
}
void BasicParser::goBack() {
if (pos) pos--;
}
char BasicParser::peek() {
skipWhitespace();
if (pos >= source.length()) {
@ -171,7 +203,7 @@ std::string BasicParser::parseName() {
int64_t BasicParser::parseSimpleInt(int base) {
char c = peek();
int index = char2int(c);
int index = hexchar2int(c);
if (index == -1 || index >= base) {
throw error("invalid number literal");
}
@ -182,7 +214,7 @@ int64_t BasicParser::parseSimpleInt(int base) {
while (c == '_') {
c = source[++pos];
}
index = char2int(c);
index = hexchar2int(c);
if (index == -1 || index >= base) {
return value;
}

View File

@ -41,6 +41,19 @@ inline bool is_identifier_part(int c) {
return is_identifier_start(c) || is_digit(c);
}
inline int hexchar2int(int c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'f') {
return 10 + c - 'a';
}
if (c >= 'A' && c <= 'F') {
return 10 + c - 'A';
}
return -1;
}
extern std::string escape_string(std::string s);
class parsing_error : public std::runtime_error {
@ -70,12 +83,17 @@ protected:
uint linestart = 0;
virtual void skipWhitespace();
void skip(size_t n);
void skipLine();
bool skipTo(const std::string& substring);
void expect(char expected);
void expect(const std::string& substring);
char peek();
char nextChar();
bool hasNext();
bool isNext(const std::string& substring);
void expectNewLine();
void goBack();
std::string parseName();
int64_t parseSimpleInt(int base);

View File

@ -34,7 +34,7 @@ std::vector<ubyte> gzip::compress(const ubyte* src, size_t size) {
std::vector<ubyte> gzip::decompress(const ubyte* src, size_t size) {
// getting uncompressed data length from gzip footer
size_t decompressed_size = *(uint32_t*)(src+size-4);
size_t decompressed_size = *reinterpret_cast<const uint32_t*>(src+size-4);
std::vector<ubyte> buffer;
buffer.resize(decompressed_size);

354
src/coders/xml.cpp Normal file
View File

@ -0,0 +1,354 @@
#include "xml.h"
#include <charconv>
#include <stdexcept>
#include <sstream>
#include "../util/stringutil.h"
using namespace xml;
Attribute::Attribute(std::string name, std::string text)
: name(name),
text(text) {
}
const std::string& Attribute::getName() const {
return name;
}
const std::string& Attribute::getText() const {
return text;
}
int64_t Attribute::asInt() const {
return std::stoll(text);
}
double Attribute::asFloat() const {
return util::parse_double(text);
}
bool Attribute::asBool() const {
return text == "true" || text == "1";
}
Node::Node(std::string tag) : tag(tag) {
}
void Node::add(xmlelement element) {
elements.push_back(element);
}
void Node::set(std::string name, std::string text) {
attrs[name] = Attribute(name, text);
}
const std::string& Node::getTag() const {
return tag;
}
const xmlattribute Node::attr(const std::string& name) const {
auto found = attrs.find(name);
if (found == attrs.end()) {
throw std::runtime_error("element <"+tag+" ...> missing attribute "+name);
}
return found->second;
}
const xmlattribute Node::attr(const std::string& name, const std::string& def) const {
auto found = attrs.find(name);
if (found == attrs.end()) {
return Attribute(name, def);
}
return found->second;
}
bool Node::has(const std::string& name) const {
auto found = attrs.find(name);
return found != attrs.end();
}
xmlelement Node::sub(size_t index) {
return elements.at(index);
}
size_t Node::size() const {
return elements.size();
}
const std::vector<xmlelement>& Node::getElements() const {
return elements;
}
const xmlelements_map& Node::getAttributes() const {
return attrs;
}
Document::Document(std::string version, std::string encoding)
: version(version),
encoding(encoding) {
}
void Document::setRoot(xmlelement element) {
this->root = element;
}
xmlelement Document::getRoot() const {
return root;
}
const std::string& Document::getVersion() const {
return version;
}
const std::string& Document::getEncoding() const {
return encoding;
}
Parser::Parser(std::string filename, std::string source)
: BasicParser(filename, source) {
}
xmlelement Parser::parseOpenTag() {
std::string tag = parseXMLName();
auto node = std::make_shared<Node>(tag);
char c;
while (true) {
skipWhitespace();
c = peek();
if (c == '/' || c == '>' || c == '?')
break;
std::string attrname = parseXMLName();
std::string attrtext = "";
skipWhitespace();
if (peek() == '=') {
nextChar();
skipWhitespace();
expect('"');
attrtext = parseString('"');
}
node->set(attrname, attrtext);
}
return node;
}
void Parser::parseDeclaration() {
std::string version = "1.0";
std::string encoding = "UTF-8";
expect('<');
if (peek() == '?') {
nextChar();
xmlelement node = parseOpenTag();
expect("?>");
if (node->getTag() != "xml") {
throw error("invalid declaration");
}
version = node->attr("version", version).getText();
encoding = node->attr("encoding", encoding).getText();
if (encoding != "utf-8" && encoding != "UTF-8") {
throw error("UTF-8 encoding is only supported");
}
} else {
goBack();
}
document = std::make_shared<Document>(version, encoding);
}
void Parser::parseComment() {
expect("!--");
if (skipTo("-->")) {
skip(3);
} else {
throw error("comment close missing");
}
}
std::string Parser::parseText() {
size_t start = pos;
while (hasNext()) {
char c = peek();
if (c == '<') {
break;
}
nextChar();
}
return source.substr(start, pos-start);
}
inline bool is_xml_identifier_start(char c) {
return is_identifier_start(c) || c == ':';
}
inline bool is_xml_identifier_part(char c) {
return is_identifier_part(c) || c == '-' || c == '.' || c == ':';
}
std::string Parser::parseXMLName() {
char c = peek();
if (!is_xml_identifier_start(c)) {
throw error("identifier expected");
}
int start = pos;
while (hasNext() && is_xml_identifier_part(source[pos])) {
pos++;
}
return source.substr(start, pos-start);
}
xmlelement Parser::parseElement() {
// text element
if (peek() != '<') {
auto element = std::make_shared<Node>("#");
auto text = parseText();
util::replaceAll(text, "&quot;", "\"");
util::replaceAll(text, "&apos;", "'");
util::replaceAll(text, "&lt;", "<");
util::replaceAll(text, "&gt;", ">");
util::replaceAll(text, "&amp;", "&");
element->set("#", text);
return element;
}
nextChar();
// <!--element-->
if (peek() == '!') {
if (isNext("!DOCTYPE ")) {
throw error("XML DTD is not supported yet");
}
parseComment();
return nullptr;
}
auto element = parseOpenTag();
char c = nextChar();
// <element/>
if (c == '/') {
expect('>');
}
// <element>...</element>
else if (c == '>') {
skipWhitespace();
while (!isNext("</")) {
auto sub = parseElement();
if (sub) {
element->add(sub);
}
skipWhitespace();
}
skip(2);
expect(element->getTag());
expect('>');
}
// <element?>
else {
throw error("invalid syntax");
}
return element;
}
xmldocument Parser::parse() {
parseDeclaration();
xmlelement root = nullptr;
while (root == nullptr) {
root = parseElement();
}
document->setRoot(root);
return document;
}
xmldocument xml::parse(std::string filename, std::string source) {
Parser parser(filename, source);
return parser.parse();
}
inline void newline(
std::stringstream& ss,
bool nice,
const std::string& indentStr,
int indent
) {
if (!nice)
return;
ss << '\n';
for (int i = 0; i < indent; i++) {
ss << indentStr;
}
}
static void stringifyElement(
std::stringstream& ss,
const xmlelement element,
bool nice,
const std::string& indentStr,
int indent
) {
if (element->isText()) {
std::string text = element->attr("#").getText();
util::replaceAll(text, "&", "&amp;");
util::replaceAll(text, "\"","&quot;");
util::replaceAll(text, "'", "&apos;");
util::replaceAll(text, "<", "&lt;");
util::replaceAll(text, ">", "&gt;");
ss << text;
return;
}
const std::string& tag = element->getTag();
ss << '<' << tag;
auto& attrs = element->getAttributes();
if (!attrs.empty()) {
ss << ' ';
int count = 0;
for (auto& entry : attrs) {
auto attr = entry.second;
ss << attr.getName();
if (!attr.getText().empty()) {
ss << "=" << escape_string(attr.getText());
}
if (count + 1 < int(attrs.size())) {
ss << " ";
}
count++;
}
}
auto& elements = element->getElements();
if (elements.size() == 1 && elements[0]->isText()) {
ss << ">";
stringifyElement(ss, elements[0], nice, indentStr, indent+1);
ss << "</" << tag << ">";
return;
}
if (!elements.empty()) {
ss << '>';
for (auto& sub : elements) {
newline(ss, nice, indentStr, indent+1);
stringifyElement(ss, sub, nice, indentStr, indent+1);
}
newline(ss, nice, indentStr, indent);
ss << "</" << tag << ">";
} else {
ss << "/>";
}
}
std::string xml::stringify(
const xmldocument document,
bool nice,
const std::string& indentStr
) {
std::stringstream ss;
// XML declaration
ss << "<?xml version=\"" << document->getVersion();
ss << "\" encoding=\"UTF-8\" ?>";
newline(ss, nice, indentStr, 0);
stringifyElement(ss, document->getRoot(), nice, indentStr, 0);
return ss.str();
}

134
src/coders/xml.h Normal file
View File

@ -0,0 +1,134 @@
#ifndef CODERS_XML_H_
#define CODERS_XML_H_
#include <string>
#include <memory>
#include <vector>
#include <unordered_map>
#include "commons.h"
namespace xml {
class Node;
class Attribute;
class Document;
typedef Attribute xmlattribute;
typedef std::shared_ptr<Node> xmlelement;
typedef std::shared_ptr<Document> xmldocument;
typedef std::unordered_map<std::string, xmlattribute> xmlelements_map;
class Attribute {
std::string name;
std::string text;
public:
Attribute() {};
Attribute(std::string name, std::string text);
const std::string& getName() const;
const std::string& getText() const;
int64_t asInt() const;
double asFloat() const;
bool asBool() const;
};
/* XML element class. Text element has tag 'text' and attribute 'text' */
class Node {
std::string tag;
std::unordered_map<std::string, xmlattribute> attrs;
std::vector<xmlelement> elements;
public:
Node(std::string tag);
/* Add sub-element */
void add(xmlelement element);
/* Set attribute value. Creates attribute if does not exists */
void set(std::string name, std::string text);
/* Get element tag */
const std::string& getTag() const;
inline bool isText() const {
return getTag() == "#";
}
inline const std::string& text() const {
return attr("#").getText();
}
/* Get attribute by name
@param name attribute name
@throws std::runtime_error if element has no attribute
@return xmlattribute - {name, value} */
const xmlattribute attr(const std::string& name) const;
/* Get attribute by name
@param name name
@param def default value will be returned wrapped in xmlattribute
if element has no attribute
@return xmlattribute - {name, value} or {name, def} if not found*/
const xmlattribute attr(const std::string& name, const std::string& def) const;
/* Check if element has attribute
@param name attribute name */
bool has(const std::string& name) const;
/* Get sub-element by index
@throws std::out_of_range if an invalid index given */
xmlelement sub(size_t index);
/* Get number of sub-elements */
size_t size() const;
const std::vector<xmlelement>& getElements() const;
const xmlelements_map& getAttributes() const;
};
class Document {
xmlelement root = nullptr;
std::string version;
std::string encoding;
public:
Document(std::string version, std::string encoding);
void setRoot(xmlelement element);
xmlelement getRoot() const;
const std::string& getVersion() const;
const std::string& getEncoding() const;
};
class Parser : public BasicParser {
xmldocument document;
xmlelement parseOpenTag();
xmlelement parseElement();
void parseDeclaration();
void parseComment();
std::string parseText();
std::string parseXMLName();
public:
Parser(std::string filename, std::string source);
xmldocument parse();
};
/* Serialize XML Document to string
@param document serializing document
@param nice use human readable format
(with indents and line-separators)
@param indentStr indentation characters sequence
(default - 4 spaces)*/
extern std::string stringify(
const xmldocument document,
bool nice=true,
const std::string& indentStr=" "
);
/* Read XML Document from string
@param filename file name will be shown in error messages
@param source xml source code string */
extern xmldocument parse(std::string filename, std::string source);
}
#endif // CODERS_XML_H_

View File

@ -71,7 +71,7 @@ Content* ContentBuilder::build() {
// Generating runtime info
def->rt.id = blockDefsIndices.size();
def->rt.emissive = *((uint32_t*)def->emission);
def->rt.emissive = *reinterpret_cast<uint32_t*>(def->emission);
def->rt.solid = def->model == BlockModel::block;
if (def->rotatable) {
@ -95,7 +95,7 @@ Content* ContentBuilder::build() {
// Generating runtime info
def->rt.id = itemDefsIndices.size();
def->rt.emissive = *((uint32_t*)def->emission);
def->rt.emissive = *reinterpret_cast<uint32_t*>(def->emission);
itemDefsIndices.push_back(def);
}

View File

@ -9,7 +9,7 @@
#include <set>
#include "../typedefs.h"
typedef std::set<unsigned char> DrawGroups;
using DrawGroups = std::set<unsigned char>;
class Block;
class ItemDef;

View File

@ -74,7 +74,7 @@ void ContentLoader::fixPackIndices() {
std::unique_ptr<dynamic::Map> root;
if (fs::is_regular_file(indexFile)) {
root = std::move(files::read_json(indexFile));
root = files::read_json(indexFile);
} else {
root.reset(new dynamic::Map());
}

View File

@ -8,7 +8,7 @@ namespace fs = std::filesystem;
class Block;
class ItemDef;
class ContentPack;
struct ContentPack;
class ContentBuilder;
namespace dynamic {

View File

@ -1,48 +1,43 @@
#include "definitions.h"
#include <glm/glm.hpp>
#include "items/ItemDef.h"
#include "content/Content.h"
#include "window/Window.h"
#include "window/Events.h"
#include "window/input.h"
#include "voxels/Block.h"
using glm::vec3;
// All in-game definitions (blocks, items, etc..)
void setup_definitions(ContentBuilder* builder) { // Strange function, need to REDO ?
Block* block = new Block("core:air", "air");
block->replaceable = true;
block->drawGroup = 1;
block->lightPassing = true;
block->skyLightPassing = true;
block->obstacle = false;
block->selectable = false;
block->model = BlockModel::none;
block->pickingItem = "core:empty";
builder->add(block);
ItemDef* item = builder->createItem("core:empty");
item->iconType = item_icon_type::none;
}
void setup_bindings() {
Events::bind(BIND_MOVE_FORWARD, inputtype::keyboard, keycode::W);
Events::bind(BIND_MOVE_BACK, inputtype::keyboard, keycode::S);
Events::bind(BIND_MOVE_RIGHT, inputtype::keyboard, keycode::D);
Events::bind(BIND_MOVE_LEFT, inputtype::keyboard, keycode::A);
Events::bind(BIND_MOVE_JUMP, inputtype::keyboard, keycode::SPACE);
Events::bind(BIND_MOVE_SPRINT, inputtype::keyboard, keycode::LEFT_CONTROL);
Events::bind(BIND_MOVE_CROUCH, inputtype::keyboard, keycode::LEFT_SHIFT);
Events::bind(BIND_MOVE_CHEAT, inputtype::keyboard, keycode::R);
Events::bind(BIND_CAM_ZOOM, inputtype::keyboard, keycode::C);
Events::bind(BIND_CAM_MODE, inputtype::keyboard, keycode::F4);
Events::bind(BIND_PLAYER_NOCLIP, inputtype::keyboard, keycode::N);
Events::bind(BIND_PLAYER_FLIGHT, inputtype::keyboard, keycode::F);
Events::bind(BIND_PLAYER_ATTACK, inputtype::mouse, mousecode::BUTTON_1);
Events::bind(BIND_PLAYER_BUILD, inputtype::mouse, mousecode::BUTTON_2);
Events::bind(BIND_PLAYER_PICK, inputtype::mouse, mousecode::BUTTON_3);
Events::bind(BIND_HUD_INVENTORY, inputtype::keyboard, keycode::TAB);
#include "core_defs.h"
#include "items/ItemDef.h"
#include "content/Content.h"
#include "window/Window.h"
#include "window/Events.h"
#include "window/input.h"
#include "voxels/Block.h"
// All in-game definitions (blocks, items, etc..)
void corecontent::setup(ContentBuilder* builder) {
Block* block = builder->createBlock("core:air");
block->replaceable = true;
block->drawGroup = 1;
block->lightPassing = true;
block->skyLightPassing = true;
block->obstacle = false;
block->selectable = false;
block->model = BlockModel::none;
block->pickingItem = "core:empty";
ItemDef* item = builder->createItem("core:empty");
item->iconType = item_icon_type::none;
}
void corecontent::setup_bindings() {
Events::bind(BIND_MOVE_FORWARD, inputtype::keyboard, keycode::W);
Events::bind(BIND_MOVE_BACK, inputtype::keyboard, keycode::S);
Events::bind(BIND_MOVE_RIGHT, inputtype::keyboard, keycode::D);
Events::bind(BIND_MOVE_LEFT, inputtype::keyboard, keycode::A);
Events::bind(BIND_MOVE_JUMP, inputtype::keyboard, keycode::SPACE);
Events::bind(BIND_MOVE_SPRINT, inputtype::keyboard, keycode::LEFT_CONTROL);
Events::bind(BIND_MOVE_CROUCH, inputtype::keyboard, keycode::LEFT_SHIFT);
Events::bind(BIND_MOVE_CHEAT, inputtype::keyboard, keycode::R);
Events::bind(BIND_CAM_ZOOM, inputtype::keyboard, keycode::C);
Events::bind(BIND_CAM_MODE, inputtype::keyboard, keycode::F4);
Events::bind(BIND_PLAYER_NOCLIP, inputtype::keyboard, keycode::N);
Events::bind(BIND_PLAYER_FLIGHT, inputtype::keyboard, keycode::F);
Events::bind(BIND_PLAYER_ATTACK, inputtype::mouse, mousecode::BUTTON_1);
Events::bind(BIND_PLAYER_BUILD, inputtype::mouse, mousecode::BUTTON_2);
Events::bind(BIND_PLAYER_PICK, inputtype::mouse, mousecode::BUTTON_3);
Events::bind(BIND_HUD_INVENTORY, inputtype::keyboard, keycode::TAB);
}

View File

@ -3,7 +3,6 @@
#include <string>
const std::string TEXTURE_NOTFOUND = "notfound";
/* bindings used in engine code */
@ -24,4 +23,11 @@ const std::string BIND_PLAYER_BUILD = "player.build";
const std::string BIND_PLAYER_PICK = "player.pick";
const std::string BIND_HUD_INVENTORY = "hud.inventory";
class ContentBuilder;
namespace corecontent {
extern void setup_bindings();
extern void setup(ContentBuilder* builder);
}
#endif // SRC_CORE_DEFS_H_

View File

@ -1,13 +0,0 @@
#ifndef DECLARATIONS_H
#define DECLARATIONS_H
#include <iostream>
#include "core_defs.h"
class ContentBuilder;
extern void setup_bindings();
extern void setup_definitions(ContentBuilder* builder);
#endif // DECLARATIONS_H

10
src/delegates.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef DELEGATES_H_
#define DELEGATES_H_
#include <functional>
#include <string>
typedef std::function<void()> runnable;
typedef std::function<void(const std::string&)> stringconsumer;
#endif // DELEGATES_H_

View File

@ -37,7 +37,7 @@
#include "frontend/locale/langs.h"
#include "logic/scripting/scripting.h"
#include "definitions.h"
#include "core_defs.h"
namespace fs = std::filesystem;
@ -56,7 +56,7 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths)
assets.reset(new Assets());
AssetsLoader loader(assets.get(), resPaths.get());
AssetsLoader::createDefaults(loader);
AssetsLoader::addDefaults(loader, true);
AssetsLoader::addDefaults(loader, false);
Shader::preprocessor->setPaths(resPaths.get());
while (loader.hasNext()) {
@ -148,7 +148,7 @@ inline const std::string checkPacks(const std::unordered_set<std::string>& packs
void Engine::loadContent() {
auto resdir = paths->getResources();
ContentBuilder contentBuilder;
setup_definitions(&contentBuilder);
corecontent::setup(&contentBuilder);
paths->setContentPacks(&contentPacks);
std::vector<fs::path> resRoots;
@ -183,7 +183,7 @@ void Engine::loadContent() {
std::cout << "-- loading assets" << std::endl;
AssetsLoader loader(new_assets.get(), resPaths.get());
AssetsLoader::createDefaults(loader);
AssetsLoader::addDefaults(loader, false);
AssetsLoader::addDefaults(loader, true);
while (loader.hasNext()) {
if (!loader.loadNext()) {
new_assets.reset();
@ -214,7 +214,7 @@ void Engine::setScreen(std::shared_ptr<Screen> screen) {
void Engine::setLanguage(std::string locale) {
settings.ui.language = locale;
langs::setup(paths->getResources(), locale, contentPacks);
menus::create_menus(this, gui->getMenu());
menus::create_menus(this);
}
gui::GUI* Engine::getGUI() {

View File

@ -30,10 +30,10 @@ fs::path EnginePaths::getScreenshotFile(std::string ext) {
ss << std::put_time(&tm, format);
std::string datetimestr = ss.str();
fs::path filename = folder/fs::path("screenshot-"+datetimestr+"."+ext);
fs::path filename = folder/fs::u8path("screenshot-"+datetimestr+"."+ext);
uint index = 0;
while (fs::exists(filename)) {
filename = folder/fs::path("screenshot-"+datetimestr+"-"+std::to_string(index)+"."+ext);
filename = folder/fs::u8path("screenshot-"+datetimestr+"-"+std::to_string(index)+"."+ext);
index++;
}
return filename;
@ -59,7 +59,7 @@ std::vector<fs::path> EnginePaths::scanForWorlds() {
continue;
}
fs::path worldFolder = entry.path();
fs::path worldFile = worldFolder/fs::path(WorldFiles::WORLD_FILE);
fs::path worldFile = worldFolder/fs::u8path(WorldFiles::WORLD_FILE);
if (!fs::is_regular_file(worldFile)) {
continue;
}
@ -91,31 +91,31 @@ void EnginePaths::setContentPacks(std::vector<ContentPack>* contentPacks) {
fs::path EnginePaths::resolve(std::string path) {
size_t separator = path.find(':');
if (separator == std::string::npos) {
return fs::path(path);
return fs::u8path(path);
}
std::string prefix = path.substr(0, separator);
std::string filename = path.substr(separator+1);
if (prefix == "res" || prefix == "core") {
return resources/fs::path(filename);
return resources/fs::u8path(filename);
}
if (prefix == "user") {
return userfiles/fs::path(filename);
return userfiles/fs::u8path(filename);
}
if (prefix == "world") {
return worldFolder/fs::path(filename);
return worldFolder/fs::u8path(filename);
}
if (contentPacks) {
for (auto& pack : *contentPacks) {
if (pack.id == prefix) {
return pack.folder/fs::path(filename);
return pack.folder/fs::u8path(filename);
}
}
}
return fs::path("./"+filename);
return fs::u8path("./"+filename);
}
ResPaths::ResPaths(fs::path mainRoot, std::vector<fs::path> roots)
@ -125,19 +125,19 @@ ResPaths::ResPaths(fs::path mainRoot, std::vector<fs::path> roots)
fs::path ResPaths::find(const std::string& filename) const {
for (int i = roots.size()-1; i >= 0; i--) {
auto& root = roots[i];
fs::path file = root / fs::path(filename);
fs::path file = root / fs::u8path(filename);
if (fs::exists(file)) {
return file;
}
}
return mainRoot / fs::path(filename);
return mainRoot / fs::u8path(filename);
}
std::vector<fs::path> ResPaths::listdir(const std::string& folderName) const {
std::vector<fs::path> entries;
for (int i = roots.size()-1; i >= 0; i--) {
auto& root = roots[i];
fs::path folder = root / fs::path(folderName);
fs::path folder = root / fs::u8path(folderName);
if (!fs::is_directory(folder))
continue;
for (const auto& entry : fs::directory_iterator(folder)) {
@ -145,7 +145,7 @@ std::vector<fs::path> ResPaths::listdir(const std::string& folderName) const {
}
}
{
fs::path folder = mainRoot / fs::path(folderName);
fs::path folder = mainRoot / fs::u8path(folderName);
if (!fs::is_directory(folder))
return entries;
for (const auto& entry : fs::directory_iterator(folder)) {

View File

@ -289,10 +289,11 @@ void SlotView::clicked(gui::GUI* gui, int button) {
if (stack.isEmpty()) {
stack.set(grabbed);
stack.setCount(1);
} else {
grabbed.setCount(grabbed.getCount()-1);
} else if (stack.accepts(grabbed)){
stack.setCount(stack.getCount()+1);
grabbed.setCount(grabbed.getCount()-1);
}
grabbed.setCount(grabbed.getCount()-1);
}
}
}

View File

@ -120,8 +120,6 @@ class InventoryView : public gui::Container {
InventoryInteraction* interaction;
std::vector<SlotView*> slots;
int scroll = 0;
public:
InventoryView(
const Content* content,

View File

@ -106,7 +106,7 @@ void WorldRenderer::drawChunks(Chunks* chunks,
}
float px = camera->position.x / (float)CHUNK_W;
float pz = camera->position.z / (float)CHUNK_D;
std::sort(indices.begin(), indices.end(), [this, chunks, px, pz](size_t i, size_t j) {
std::sort(indices.begin(), indices.end(), [chunks, px, pz](size_t i, size_t j) {
auto a = chunks->chunks[i];
auto b = chunks->chunks[j];
return ((a->x + 0.5f - px)*(a->x + 0.5f - px) +

View File

@ -39,7 +39,7 @@ Skybox::Skybox(uint size, Shader* shader)
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
};
vattr attrs[] {2, 0};
vattr attrs[] {{2}, {0}};
mesh = std::make_unique<Mesh>(vertices, 6, attrs);
sprites.push_back(skysprite {

View File

@ -13,30 +13,23 @@
#include "../../window/input.h"
#include "../../window/Camera.h"
using glm::vec2;
using glm::vec3;
using std::string;
using std::shared_ptr;
using namespace gui;
GUI::GUI() {
container = new Container(vec2(0, 0), vec2(1000));
uicamera = new Camera(vec3(), Window::height);
container = std::make_shared<Container>(glm::vec2(0, 0), glm::vec2(1000));
uicamera = std::make_unique<Camera>(glm::vec3(), Window::height);
uicamera->perspective = false;
uicamera->flipped = true;
menu = new PagesControl();
menu = std::make_shared<PagesControl>();
container->add(menu);
container->scrollable(false);
}
GUI::~GUI() {
delete uicamera;
delete container;
}
PagesControl* GUI::getMenu() {
std::shared_ptr<PagesControl> GUI::getMenu() {
return menu;
}
@ -85,7 +78,7 @@ void GUI::actMouse(float delta) {
}
void GUI::act(float delta) {
container->setSize(vec2(Window::width, Window::height));
container->setSize(glm::vec2(Window::width, Window::height));
container->act(delta);
auto prevfocus = focus;
@ -132,7 +125,7 @@ void GUI::draw(const GfxContext* pctx, Assets* assets) {
container->draw(pctx, assets);
}
shared_ptr<UINode> GUI::getFocused() const {
std::shared_ptr<UINode> GUI::getFocused() const {
return focus;
}
@ -144,19 +137,19 @@ void GUI::addBack(std::shared_ptr<UINode> panel) {
container->addBack(panel);
}
void GUI::add(shared_ptr<UINode> panel) {
void GUI::add(std::shared_ptr<UINode> panel) {
container->add(panel);
}
void GUI::remove(shared_ptr<UINode> panel) {
void GUI::remove(std::shared_ptr<UINode> panel) {
container->remove(panel);
}
void GUI::store(string name, shared_ptr<UINode> node) {
void GUI::store(std::string name, std::shared_ptr<UINode> node) {
storage[name] = node;
}
shared_ptr<UINode> GUI::get(string name) {
std::shared_ptr<UINode> GUI::get(std::string name) {
auto found = storage.find(name);
if (found == storage.end()) {
return nullptr;
@ -164,11 +157,11 @@ shared_ptr<UINode> GUI::get(string name) {
return found->second;
}
void GUI::remove(string name) {
void GUI::remove(std::string name) {
storage.erase(name);
}
void GUI::setFocus(shared_ptr<UINode> node) {
void GUI::setFocus(std::shared_ptr<UINode> node) {
if (focus) {
focus->defocus();
}

View File

@ -44,28 +44,25 @@ class Camera;
*/
namespace gui {
typedef std::function<void()> runnable;
typedef std::function<void(const std::string&)> stringconsumer;
class UINode;
class Container;
class PagesControl;
class GUI {
Container* container;
std::shared_ptr<Container> container;
std::shared_ptr<UINode> hover = nullptr;
std::shared_ptr<UINode> pressed = nullptr;
std::shared_ptr<UINode> focus = nullptr;
std::unordered_map<std::string, std::shared_ptr<UINode>> storage;
Camera* uicamera;
PagesControl* menu;
std::unique_ptr<Camera> uicamera;
std::shared_ptr<PagesControl> menu;
void actMouse(float delta);
public:
GUI();
~GUI();
PagesControl* getMenu();
std::shared_ptr<PagesControl> getMenu();
std::shared_ptr<UINode> getFocused() const;
bool isFocusCaught() const;

View File

@ -88,6 +88,14 @@ void UINode::setInteractive(bool flag) {
interactive = flag;
}
void UINode::setResizing(bool flag) {
resizing = flag;
}
bool UINode::isResizing() const {
return resizing;
}
vec2 UINode::calcCoord() const {
if (parent) {
return coord + parent->calcCoord() + parent->contentOffset();
@ -115,6 +123,15 @@ void UINode::setSize(vec2 size) {
void UINode::setColor(vec4 color) {
this->color = color;
this->hoverColor = color;
}
void UINode::setHoverColor(glm::vec4 newColor) {
this->hoverColor = newColor;
}
glm::vec4 UINode::getHoverColor() const {
return hoverColor;
}
vec4 UINode::getColor() const {

View File

@ -13,23 +13,26 @@ namespace gui {
class UINode;
class GUI;
typedef std::function<void(GUI*)> onaction;
typedef std::function<void(GUI*, double)> onnumberchange;
using onaction = std::function<void(GUI*)>;
using onnumberchange = std::function<void(GUI*, double)>;
enum class Align {
left, center, right
};
class UINode {
protected:
glm::vec2 coord;
glm::vec2 size;
glm::vec4 color {1.0f};
glm::vec4 hoverColor {1.0f};
glm::vec4 margin {1.0f};
bool visible = true;
bool hover = false;
bool pressed = false;
bool focused = false;
bool interactive = true;
bool resizing = true;
Align align = Align::left;
UINode* parent = nullptr;
UINode(glm::vec2 coord, glm::vec2 size);
@ -50,9 +53,16 @@ namespace gui {
virtual void setParent(UINode* node);
UINode* getParent() const;
/* Set element color (doesn't affect inner elements).
Also replaces hover color to avoid adding extra properties. */
virtual void setColor(glm::vec4 newColor);
/* Get element color */
glm::vec4 getColor() const;
virtual void setHoverColor(glm::vec4 newColor);
glm::vec4 getHoverColor() const;
virtual void setMargin(glm::vec4 margin);
glm::vec4 getMargin() const;
@ -66,18 +76,34 @@ namespace gui {
bool isPressed() const;
void defocus();
bool isFocused() const;
/* Check if elements catches all user input when focused */
virtual bool isFocuskeeper() const {return false;}
virtual void typed(unsigned int codepoint) {};
virtual void keyPressed(int key) {};
/* Check if screen position is inside of the element
@param pos screen position */
virtual bool isInside(glm::vec2 pos);
/* Get element under the cursor.
@param pos cursor screen position
@param self shared pointer to element
@return self, sub-element or nullptr if element is not interractive */
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self);
/* Check if element is opaque for cursor */
virtual bool isInteractive() const;
/* Make the element opaque (true) or transparent (false) for cursor */
virtual void setInteractive(bool flag);
virtual void setResizing(bool flag);
virtual bool isResizing() const;
/* Get inner content offset. Used for scroll */
virtual glm::vec2 contentOffset() {return glm::vec2(0.0f);};
/* Calculate screen position of the element */
virtual glm::vec2 calcCoord() const;
virtual void setCoord(glm::vec2 coord);
virtual glm::vec2 getSize() const;

View File

@ -20,6 +20,7 @@ Label::Label(std::string text, std::string fontName)
: UINode(vec2(), vec2(text.length() * 8, 15)),
text(util::str2wstr_utf8(text)),
fontName_(fontName) {
setInteractive(false);
}
@ -27,6 +28,7 @@ Label::Label(std::wstring text, std::string fontName)
: UINode(vec2(), vec2(text.length() * 8, 15)),
text(text),
fontName_(fontName) {
setInteractive(false);
}
void Label::setText(std::wstring text) {
@ -46,12 +48,23 @@ void Label::draw(const GfxContext* pctx, Assets* assets) {
batch->color = getColor();
Font* font = assets->getFont(fontName_);
vec2 size = getSize();
vec2 newsize = vec2(font->calcWidth(text), font->lineHeight());
if (newsize.x > size.x) {
setSize(newsize);
size = newsize;
}
vec2 newsize = vec2(
font->calcWidth(text),
font->getLineHeight()+font->getYOffset()
);
vec2 coord = calcCoord();
switch (align) {
case Align::left:
break;
case Align::center:
coord.x += (size.x-newsize.x)*0.5f;
break;
case Align::right:
coord.x += size.x-newsize.x;
break;
}
coord.y += (size.y-newsize.y)*0.5f;
font->draw(batch, text, coord.x, coord.y);
}
@ -60,10 +73,6 @@ Label* Label::textSupplier(wstringsupplier supplier) {
return this;
}
void Label::setSize(vec2 sizenew) {
UINode::setSize(vec2(UINode::getSize().x, sizenew.y));
}
// ================================= Image ====================================
Image::Image(std::string texture, vec2 size) : UINode(vec2(), size), texture(texture) {
setInteractive(false);
@ -87,17 +96,34 @@ Button::Button(std::shared_ptr<UINode> content, glm::vec4 padding)
padding[1]+padding[3]+margin[1]+margin[3]));
add(content);
scrollable(false);
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
}
Button::Button(std::wstring text, glm::vec4 padding, glm::vec4 margin)
: Panel(vec2(32,32), padding, 0)
Button::Button(
std::wstring text,
vec4 padding,
onaction action,
vec2 size
) : Panel(size, padding, 0)
{
setMargin(margin);
if (size.y < 0.0f) {
size = vec2(
glm::max(padding.x + padding.z + text.length()*8, size.x),
glm::max(padding.y + padding.w + 16, size.y)
);
}
setSize(size);
if (action) {
listenAction(action);
}
scrollable(false);
label = std::make_shared<Label>(text);
label->setAlign(Align::center);
label->setSize(size-vec2(padding.z+padding.x, padding.w+padding.y));
add(label);
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
}
void Button::setText(std::wstring text) {
@ -120,8 +146,11 @@ Button* Button::textSupplier(wstringsupplier supplier) {
return this;
}
void Button::setHoverColor(glm::vec4 color) {
hoverColor = color;
void Button::refresh() {
Panel::refresh();
if (label) {
label->setSize(size-vec2(padding.z+padding.x, padding.w+padding.y));
}
}
void Button::drawBackground(const GfxContext* pctx, Assets* assets) {
@ -159,6 +188,7 @@ void Button::textAlign(Align align) {
// ============================== RichButton ==================================
RichButton::RichButton(vec2 size) : Container(vec2(), size) {
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
}
void RichButton::mouseRelease(GUI* gui, int x, int y) {
@ -175,10 +205,6 @@ RichButton* RichButton::listenAction(onaction action) {
return this;
}
void RichButton::setHoverColor(glm::vec4 color) {
hoverColor = color;
}
void RichButton::drawBackground(const GfxContext* pctx, Assets* assets) {
vec2 coord = calcCoord();
auto batch = pctx->getBatch2D();
@ -189,11 +215,12 @@ void RichButton::drawBackground(const GfxContext* pctx, Assets* assets) {
// ================================ TextBox ===================================
TextBox::TextBox(std::wstring placeholder, vec4 padding)
: Panel(vec2(200,32), padding, 0, false),
: Panel(vec2(200,32), padding, 0),
input(L""),
placeholder(placeholder) {
label = std::make_shared<Label>(L"");
add(label);
setHoverColor(glm::vec4(0.05f, 0.1f, 0.2f, 0.75f));
}
void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) {
@ -251,7 +278,7 @@ bool TextBox::isValid() const {
return valid;
}
void TextBox::setOnEditStart(gui::runnable oneditstart) {
void TextBox::setOnEditStart(runnable oneditstart) {
onEditStart = oneditstart;
}
@ -312,9 +339,9 @@ void TextBox::text(std::wstring value) {
// ============================== InputBindBox ================================
InputBindBox::InputBindBox(Binding& binding, vec4 padding)
: Panel(vec2(100,32), padding, 0, false),
: Panel(vec2(100,32), padding, 0),
binding(binding) {
label = new Label(L"");
label = std::make_shared<Label>(L"");
add(label);
scrollable(false);
}
@ -437,7 +464,7 @@ FullCheckBox::FullCheckBox(std::wstring text, glm::vec2 size, bool checked)
: Panel(size),
checkbox(std::make_shared<CheckBox>(checked)){
setColor(vec4(0.0f));
orientation(Orientation::horizontal);
setOrientation(Orientation::horizontal);
add(checkbox);

View File

@ -6,25 +6,27 @@
#include <vector>
#include <functional>
#include <glm/glm.hpp>
#include "GUI.h"
#include "UINode.h"
#include "panels.h"
#include "../../window/input.h"
#include "../../delegates.h"
class Batch2D;
class Assets;
namespace gui {
typedef std::function<std::wstring()> wstringsupplier;
typedef std::function<void(std::wstring)> wstringconsumer;
using wstringsupplier = std::function<std::wstring()>;
using wstringconsumer = std::function<void(std::wstring)>;
typedef std::function<double()> doublesupplier;
typedef std::function<void(double)> doubleconsumer;
using doublesupplier = std::function<double()>;
using doubleconsumer = std::function<void(double)>;
typedef std::function<bool()> boolsupplier;
typedef std::function<void(bool)> boolconsumer;
using boolsupplier = std::function<bool()>;
using boolconsumer = std::function<void(bool)>;
typedef std::function<bool(const std::wstring&)> wstringchecker;
using wstringchecker = std::function<bool(const std::wstring&)>;
class Label : public UINode {
protected:
@ -41,7 +43,6 @@ namespace gui {
virtual void draw(const GfxContext* pctx, Assets* assets) override;
virtual Label* textSupplier(wstringsupplier supplier);
virtual void setSize(glm::vec2 size) override;
};
class Image : public UINode {
@ -55,15 +56,17 @@ namespace gui {
class Button : public Panel {
protected:
glm::vec4 hoverColor {0.05f, 0.1f, 0.15f, 0.75f};
glm::vec4 pressedColor {0.0f, 0.0f, 0.0f, 0.95f};
std::vector<onaction> actions;
std::shared_ptr<Label> label = nullptr;
public:
Button(std::shared_ptr<UINode> content, glm::vec4 padding=glm::vec4(2.0f));
Button(std::shared_ptr<UINode> content,
glm::vec4 padding=glm::vec4(2.0f));
Button(std::wstring text,
glm::vec4 padding=glm::vec4(2.0f),
glm::vec4 margin=glm::vec4(1.0f));
glm::vec4 padding,
onaction action,
glm::vec2 size=glm::vec2(-1));
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
@ -79,12 +82,11 @@ namespace gui {
virtual Button* textSupplier(wstringsupplier supplier);
virtual void setHoverColor(glm::vec4 color);
virtual void refresh() override;
};
class RichButton : public Container {
protected:
glm::vec4 hoverColor {0.05f, 0.1f, 0.15f, 0.75f};
glm::vec4 pressedColor {0.0f, 0.0f, 0.0f, 0.95f};
std::vector<onaction> actions;
public:
@ -94,13 +96,10 @@ namespace gui {
virtual void mouseRelease(GUI*, int x, int y) override;
virtual RichButton* listenAction(onaction action);
virtual void setHoverColor(glm::vec4 color);
};
class TextBox : public Panel {
protected:
glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f};
glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f};
glm::vec4 invalidColor {0.1f, 0.05f, 0.03f, 1.0f};
std::shared_ptr<Label> label;
@ -113,7 +112,7 @@ namespace gui {
bool valid = true;
public:
TextBox(std::wstring placeholder,
glm::vec4 padding=glm::vec4(2.0f));
glm::vec4 padding=glm::vec4(4.0f));
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
@ -137,7 +136,7 @@ namespace gui {
protected:
glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f};
glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f};
Label* label;
std::shared_ptr<Label> label;
Binding& binding;
public:
InputBindBox(Binding& binding, glm::vec4 padding=glm::vec4(6.0f));

View File

@ -5,30 +5,34 @@
#include <glm/glm.hpp>
#include "../locale/langs.h"
#include "../../delegates.h"
using namespace gui;
using glm::vec2;
using glm::vec4;
Button* guiutil::backButton(PagesControl* menu) {
return (new Button(langs::get(L"Back"), vec4(10.f)))->listenAction([=](GUI* gui) {
menu->back();
});
std::shared_ptr<Button> guiutil::backButton(std::shared_ptr<PagesControl> menu) {
return std::make_shared<Button>(
langs::get(L"Back"), vec4(10.f), [=](GUI*) {
menu->back();
}
);
}
Button* guiutil::gotoButton(
std::wstring text,
const std::string& page,
PagesControl* menu) {
std::shared_ptr<Button> guiutil::gotoButton(
std::wstring text,
const std::string& page,
std::shared_ptr<PagesControl> menu
) {
text = langs::get(text, L"menu");
return (new Button(text, vec4(10.f)))->listenAction([=](GUI* gui) {
menu->set(page);
return std::make_shared<Button>(text, vec4(10.f), [=](GUI* gui) {
menu->setPage(page);
});
}
void guiutil::alert(GUI* gui, const std::wstring& text, gui::runnable on_hidden) {
PagesControl* menu = gui->getMenu();
Panel* panel = new Panel(vec2(500, 200), vec4(8.0f), 8.0f);
void guiutil::alert(GUI* gui, const std::wstring& text, runnable on_hidden) {
auto menu = gui->getMenu();
auto panel = std::make_shared<Panel>(vec2(500, 200), vec4(8.0f), 8.0f);
panel->setColor(vec4(0.0f, 0.0f, 0.0f, 0.5f));
// TODO: implement built-in text wrapping
@ -43,48 +47,55 @@ void guiutil::alert(GUI* gui, const std::wstring& text, gui::runnable on_hidden)
}
extra = std::min(extra, wrap_length);
std::wstring part = text.substr(offset, extra);
panel->add(new Label(part));
panel->add(std::make_shared<Label>(part));
offset += extra;
}
} else {
panel->add(new Label(text));
panel->add(std::make_shared<Label>(text));
}
panel->add((new Button(langs::get(L"Ok"), vec4(10.f)))->listenAction([=](GUI* gui) {
if (on_hidden)
on_hidden();
menu->back();
}));
panel->add(std::make_shared<Button>(
langs::get(L"Ok"), vec4(10.f),
[=](GUI* gui) {
if (on_hidden) {
on_hidden();
}
menu->back();
}
));
panel->refresh();
menu->add("<alert>", panel);
menu->set("<alert>");
menu->addPage("<alert>", panel);
menu->setPage("<alert>");
}
void guiutil::confirm(
GUI* gui,
const std::wstring& text,
gui::runnable on_confirm,
runnable on_confirm,
std::wstring yestext,
std::wstring notext) {
if (yestext.empty()) yestext = langs::get(L"Yes");
if (notext.empty()) notext = langs::get(L"No");
PagesControl* menu = gui->getMenu();
Panel* panel = new Panel(vec2(600, 200), vec4(8.0f), 8.0f);
auto menu = gui->getMenu();
auto panel = std::make_shared<Panel>(vec2(600, 200), vec4(8.0f), 8.0f);
panel->setColor(vec4(0.0f, 0.0f, 0.0f, 0.5f));
panel->add(new Label(text));
Panel* subpanel = new Panel(vec2(600, 53));
panel->add(std::make_shared<Label>(text));
auto subpanel = std::make_shared<Panel>(vec2(600, 53));
subpanel->setColor(vec4(0));
subpanel->add((new Button(yestext, vec4(8.0f)))->listenAction([=](GUI*){
subpanel->add(std::make_shared<Button>(yestext, vec4(8.f), [=](GUI*){
if (on_confirm)
on_confirm();
menu->back();
}));
subpanel->add((new Button(notext, vec4(8.0f)))->listenAction([=](GUI*){
subpanel->add(std::make_shared<Button>(notext, vec4(8.f), [=](GUI*){
menu->back();
}));
panel->add(subpanel);
panel->refresh();
menu->add("<confirm>", panel);
menu->set("<confirm>");
menu->addPage("<confirm>", panel);
menu->setPage("<confirm>");
}

View File

@ -1,19 +1,38 @@
#ifndef FRONTEND_GUI_GUI_UTIL_H_
#define FRONTEND_GUI_GUI_UTIL_H_
#include <memory>
#include <string>
#include "GUI.h"
#include "../../delegates.h"
namespace gui {
class Button;
}
namespace guiutil {
gui::Button* backButton(gui::PagesControl* menu);
gui::Button* gotoButton(std::wstring text, const std::string& page, gui::PagesControl* menu);
void alert(gui::GUI* gui, const std::wstring& text, gui::runnable on_hidden=nullptr);
void confirm(gui::GUI* gui, const std::wstring& text, gui::runnable on_confirm=nullptr,
std::wstring yestext=L"", std::wstring notext=L"");
std::shared_ptr<gui::Button> backButton(
std::shared_ptr<gui::PagesControl> menu
);
std::shared_ptr<gui::Button> gotoButton(
std::wstring text,
const std::string& page,
std::shared_ptr<gui::PagesControl> menu
);
void alert(
gui::GUI* gui,
const std::wstring& text,
runnable on_hidden=nullptr
);
void confirm(
gui::GUI* gui,
const std::wstring& text,
runnable on_confirm=nullptr,
std::wstring yestext=L"",
std::wstring notext=L"");
}
#endif // FRONTEND_GUI_GUI_UTIL_H_

View File

@ -14,6 +14,7 @@ using glm::vec4;
Container::Container(vec2 coord, vec2 size) : UINode(coord, size) {
actualLength = size.y;
setColor(glm::vec4());
}
std::shared_ptr<UINode> Container::getAt(vec2 pos, std::shared_ptr<UINode> self) {
@ -96,6 +97,17 @@ void Container::draw(const GfxContext* pctx, Assets* assets) {
}
}
void Container::drawBackground(const GfxContext* pctx, Assets* assets) {
if (color.a <= 0.0f)
return;
vec2 coord = calcCoord();
auto batch = pctx->getBatch2D();
batch->texture(nullptr);
batch->color = color;
batch->rect(coord.x, coord.y, size.x, size.y);
}
void Container::addBack(std::shared_ptr<UINode> node) {
nodes.insert(nodes.begin(), node);
node->setParent(this);
@ -108,10 +120,6 @@ void Container::add(std::shared_ptr<UINode> node) {
refresh();
}
void Container::add(UINode* node) {
add(std::shared_ptr<UINode>(node));
}
void Container::add(std::shared_ptr<UINode> node, glm::vec2 coord) {
node->setCoord(coord);
add(node);
@ -131,71 +139,74 @@ void Container::listenInterval(float interval, ontimeout callback, int repeat) {
intervalEvents.push_back({callback, interval, 0.0f, repeat});
}
Panel::Panel(vec2 size, glm::vec4 padding, float interval, bool resizing)
void Container::setSize(glm::vec2 size) {
UINode::setSize(size);
refresh();
}
Panel::Panel(vec2 size, glm::vec4 padding, float interval)
: Container(vec2(), size),
padding(padding),
interval(interval),
resizing_(resizing) {
interval(interval) {
setColor(vec4(0.0f, 0.0f, 0.0f, 0.75f));
}
Panel::~Panel() {
}
void Panel::drawBackground(const GfxContext* pctx, Assets* assets) {
vec2 coord = calcCoord();
auto batch = pctx->getBatch2D();
batch->texture(nullptr);
batch->color = color;
batch->rect(coord.x, coord.y, size.x, size.y);
void Panel::setMaxLength(int value) {
maxLength = value;
}
void Panel::maxLength(int value) {
maxLength_ = value;
int Panel::getMaxLength() const {
return maxLength;
}
int Panel::maxLength() const {
return maxLength_;
void Panel::setPadding(glm::vec4 padding) {
this->padding = padding;
refresh();
}
glm::vec4 Panel::getPadding() const {
return padding;
}
void Panel::cropToContent() {
if (maxLength > 0.0f) {
setSize(vec2(getSize().x, glm::min(maxLength, actualLength)));
} else {
setSize(vec2(getSize().x, actualLength));
}
}
void Panel::add(std::shared_ptr<UINode> node) {
Container::add(node);
refresh();
cropToContent();
}
void Panel::refresh() {
float x = padding.x;
float y = padding.y;
vec2 size = getSize();
if (orientation_ == Orientation::vertical) {
if (orientation == Orientation::vertical) {
float maxw = size.x;
for (auto& node : nodes) {
vec2 nodesize = node->getSize();
const vec4 margin = node->getMargin();
y += margin.y;
float ex;
float spacex = size.x - margin.z - padding.z;
switch (node->getAlign()) {
case Align::center:
ex = x + fmax(0.0f, spacex - nodesize.x) / 2.0f;
break;
case Align::right:
ex = x + spacex - nodesize.x;
break;
default:
ex = x + margin.x;
}
float ex = x + margin.x;
node->setCoord(vec2(ex, y));
y += nodesize.y + margin.w + interval;
float width = size.x - padding.x - padding.z - margin.x - margin.z;
node->setSize(vec2(width, nodesize.y));;
if (node->isResizing()) {
node->setSize(vec2(width, nodesize.y));
}
node->refresh();
maxw = fmax(maxw, ex+node->getSize().x+margin.z+padding.z);
}
if (resizing_) {
if (maxLength_)
setSize(vec2(size.x, glm::min(maxLength_, (int)(y+padding.w))));
else
setSize(vec2(size.x, y+padding.w));
}
actualLength = y + padding.w;
} else {
float maxh = size.y;
@ -206,27 +217,19 @@ void Panel::refresh() {
node->setCoord(vec2(x, y+margin.y));
x += nodesize.x + margin.z + interval;
float height = size.y - padding.y - padding.w - margin.y - margin.w;
node->setSize(vec2(nodesize.x, height));
node->refresh();
maxh = fmax(maxh, y+margin.y+node->getSize().y+margin.w+padding.w);
}
if (resizing_) {
if (maxLength_)
setSize(vec2(glm::min(maxLength_, (int)(x+padding.z)), size.y));
else
setSize(vec2(x+padding.z, size.y));
}
actualLength = size.y;
}
}
void Panel::orientation(Orientation orientation) {
this->orientation_ = orientation;
void Panel::setOrientation(Orientation orientation) {
this->orientation = orientation;
}
Orientation Panel::orientation() const {
return orientation_;
Orientation Panel::getOrientation() const {
return orientation;
}
PagesControl::PagesControl() : Container(vec2(), vec2(1)){
@ -236,15 +239,11 @@ bool PagesControl::has(std::string name) {
return pages.find(name) != pages.end();
}
void PagesControl::add(std::string name, std::shared_ptr<UINode> panel) {
void PagesControl::addPage(std::string name, std::shared_ptr<UINode> panel) {
pages[name] = Page{panel};
}
void PagesControl::add(std::string name, UINode* panel) {
add(name, std::shared_ptr<UINode>(panel));
}
void PagesControl::set(std::string name, bool history) {
void PagesControl::setPage(std::string name, bool history) {
auto found = pages.find(name);
if (found == pages.end()) {
throw std::runtime_error("no page found");
@ -266,7 +265,7 @@ void PagesControl::back() {
return;
std::string name = pageStack.top();
pageStack.pop();
set(name, false);
setPage(name, false);
}
Page& PagesControl::current() {

View File

@ -12,7 +12,8 @@ class Batch2D;
class Assets;
namespace gui {
typedef std::function<void()> ontimeout;
using ontimeout = std::function<void()>;
struct IntervalEvent {
ontimeout callback;
float interval;
@ -34,40 +35,48 @@ namespace gui {
Container(glm::vec2 coord, glm::vec2 size);
virtual void act(float delta) override;
virtual void drawBackground(const GfxContext* pctx, Assets* assets) {};
virtual void drawBackground(const GfxContext* pctx, Assets* assets);
virtual void draw(const GfxContext* pctx, Assets* assets) override;
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
virtual void addBack(std::shared_ptr<UINode> node);
virtual void add(std::shared_ptr<UINode> node);
virtual void add(UINode* node);
virtual void add(std::shared_ptr<UINode> node, glm::vec2 coord);
virtual void remove(std::shared_ptr<UINode> node);
virtual void scrolled(int value) override;
virtual void scrollable(bool flag);
void listenInterval(float interval, ontimeout callback, int repeat=-1);
virtual glm::vec2 contentOffset() override {return glm::vec2(0.0f, scroll);};
virtual void setSize(glm::vec2 size);
};
class Panel : public Container {
protected:
Orientation orientation_ = Orientation::vertical;
Orientation orientation = Orientation::vertical;
glm::vec4 padding {2.0f};
float interval = 2.0f;
bool resizing_;
int maxLength_ = 0;
int maxLength = 0;
public:
Panel(glm::vec2 size, glm::vec4 padding=glm::vec4(2.0f), float interval=2.0f, bool resizing=true);
Panel(
glm::vec2 size,
glm::vec4 padding=glm::vec4(2.0f),
float interval=2.0f
);
virtual ~Panel();
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
virtual void cropToContent();
virtual void orientation(Orientation orientation);
Orientation orientation() const;
virtual void setOrientation(Orientation orientation);
Orientation getOrientation() const;
virtual void add(std::shared_ptr<UINode> node) override;
virtual void refresh() override;
virtual void maxLength(int value);
int maxLength() const;
virtual void setMaxLength(int value);
int getMaxLength() const;
virtual void setPadding(glm::vec4 padding);
glm::vec4 getPadding() const;
};
struct Page {
@ -88,9 +97,8 @@ namespace gui {
PagesControl();
bool has(std::string name);
void set(std::string name, bool history=true);
void add(std::string name, std::shared_ptr<UINode> panel);
void add(std::string name, UINode* panel);
void setPage(std::string name, bool history=true);
void addPage(std::string name, std::shared_ptr<UINode> panel);
void back();
void clearHistory();
void reset();

View File

@ -60,7 +60,7 @@ static std::shared_ptr<Label> create_label(gui::wstringsupplier supplier) {
std::shared_ptr<UINode> HudRenderer::createDebugPanel(Engine* engine) {
auto level = frontend->getLevel();
auto panel = std::make_shared<Panel>(vec2(250, 200), vec4(5.0f), 1.0f);
auto panel = std::make_shared<Panel>(vec2(250, 200), vec4(5.0f), 2.0f);
panel->listenInterval(0.5f, [this]() {
fpsString = std::to_wstring(fpsMax)+L" / "+std::to_wstring(fpsMin);
fpsMin = fps;
@ -68,7 +68,7 @@ std::shared_ptr<UINode> HudRenderer::createDebugPanel(Engine* engine) {
});
panel->setCoord(vec2(10, 10));
panel->add(create_label([this](){ return L"fps: "+this->fpsString;}));
panel->add(create_label([this](){
panel->add(create_label([](){
return L"meshes: " + std::to_wstring(Mesh::meshesCount);
}));
panel->add(create_label([=](){
@ -97,18 +97,18 @@ std::shared_ptr<UINode> HudRenderer::createDebugPanel(Engine* engine) {
}));
for (int ax = 0; ax < 3; ax++){
Panel* sub = new Panel(vec2(10, 27), vec4(0.0f));
sub->orientation(Orientation::horizontal);
auto sub = std::make_shared<Panel>(vec2(10, 27), vec4(0.0f));
sub->setOrientation(Orientation::horizontal);
std::wstring str = L"x: ";
str[0] += ax;
Label* label = new Label(str);
auto label = std::make_shared<Label>(str);
label->setMargin(vec4(2, 3, 2, 3));
sub->add(label);
sub->setColor(vec4(0.0f));
// Coord input
TextBox* box = new TextBox(L"");
auto box = std::make_shared<TextBox>(L"");
box->textSupplier([=]() {
Hitbox* hitbox = level->player->hitbox.get();
return util::to_wstring(hitbox->position[ax], 2);
@ -139,19 +139,21 @@ std::shared_ptr<UINode> HudRenderer::createDebugPanel(Engine* engine) {
return L"time: "+timeString;
}));
{
TrackBar* bar = new TrackBar(0.0f, 1.0f, 1.0f, 0.005f, 8);
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 1.0f, 0.005f, 8);
bar->supplier([=]() {return level->world->daytime;});
bar->consumer([=](double val) {level->world->daytime = val;});
panel->add(bar);
}
{
TrackBar* bar = new TrackBar(0.0f, 1.0f, 0.0f, 0.005f, 8);
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 0.0f, 0.005f, 8);
bar->supplier([=]() {return WorldRenderer::fog;});
bar->consumer([=](double val) {WorldRenderer::fog = val;});
panel->add(bar);
}
{
auto checkbox = new FullCheckBox(L"Show Chunk Borders", vec2(400, 32));
auto checkbox = std::make_shared<FullCheckBox>(
L"Show Chunk Borders", vec2(400, 24)
);
checkbox->supplier([=]() {
return engine->getSettings().debug.showChunkBorders;
});
@ -334,7 +336,7 @@ void HudRenderer::update(bool visible) {
closeInventory();
} else {
pause = true;
menu->set("pause");
menu->setPage("pause");
}
}
if (visible && Events::jactive(BIND_HUD_INVENTORY)) {

View File

@ -37,6 +37,8 @@ using glm::vec4;
namespace fs = std::filesystem;
using namespace gui;
const int PACKS_PANEL_WIDTH = 550;
inline uint64_t randU64() {
srand(time(NULL));
return rand() ^ (rand() << 8) ^
@ -46,74 +48,87 @@ inline uint64_t randU64() {
((uint64_t)rand() << 56);
}
std::shared_ptr<Panel> create_page(
Engine* engine,
std::string name,
int width,
float opacity,
int interval) {
PagesControl* menu = engine->getGUI()->getMenu();
static std::shared_ptr<Label> create_label(gui::wstringsupplier supplier) {
auto label = std::make_shared<Label>(L"-");
label->textSupplier(supplier);
return label;
}
static std::shared_ptr<Panel> create_page(
Engine* engine,
std::string name,
int width,
float opacity,
int interval
) {
auto menu = engine->getGUI()->getMenu();
auto panel = std::make_shared<Panel>(
vec2(width, 200), vec4(8.0f), interval
);
panel->setColor(vec4(0.0f, 0.0f, 0.0f, opacity));
menu->add(name, panel);
menu->addPage(name, panel);
return panel;
}
Button* create_button(std::wstring text,
glm::vec4 padding,
glm::vec4 margin,
gui::onaction action) {
auto btn = new Button(langs::get(text, L"menu"),
padding, margin);
btn->listenAction(action);
static std::shared_ptr<Button> create_button(
std::wstring text,
vec4 padding,
vec4 margin,
gui::onaction action
) {
auto btn = std::make_shared<Button>(
langs::get(text, L"menu"), padding, action
);
btn->setMargin(margin);
return btn;
}
void show_content_missing(Engine* engine, const Content* content,
std::shared_ptr<ContentLUT> lut) {
static void show_content_missing(
Engine* engine,
const Content* content,
std::shared_ptr<ContentLUT> lut
) {
auto* gui = engine->getGUI();
auto* menu = gui->getMenu();
auto menu = gui->getMenu();
auto panel = create_page(engine, "missing-content", 500, 0.5f, 8);
panel->add(new Label(langs::get(L"menu.missing-content")));
panel->add(std::make_shared<Label>(langs::get(L"menu.missing-content")));
Panel* subpanel = new Panel(vec2(500, 100));
auto subpanel = std::make_shared<Panel>(vec2(500, 100));
subpanel->setColor(vec4(0.0f, 0.0f, 0.0f, 0.5f));
for (auto& entry : lut->getMissingContent()) {
Panel* hpanel = new Panel(vec2(500, 30));
auto hpanel = std::make_shared<Panel>(vec2(500, 30));
hpanel->setColor(vec4(0.0f));
hpanel->orientation(Orientation::horizontal);
hpanel->setOrientation(Orientation::horizontal);
Label* namelabel = new Label(util::str2wstr_utf8(entry.name));
auto namelabel = std::make_shared<Label>(util::str2wstr_utf8(entry.name));
namelabel->setColor(vec4(1.0f, 0.2f, 0.2f, 0.5f));
auto contentname = util::str2wstr_utf8(contenttype_name(entry.type));
Label* typelabel = new Label(L"["+contentname+L"]");
auto typelabel = std::make_shared<Label>(L"["+contentname+L"]");
typelabel->setColor(vec4(0.5f));
hpanel->add(typelabel);
hpanel->add(namelabel);
subpanel->add(hpanel);
}
subpanel->maxLength(400);
subpanel->setMaxLength(400);
panel->add(subpanel);
panel->add((new Button(langs::get(L"Back to Main Menu", L"menu"),
vec4(8.0f)))
->listenAction([=](GUI*){
menu->back();
}));
menu->set("missing-content");
panel->add(std::make_shared<Button>(
langs::get(L"Back to Main Menu", L"menu"), vec4(8.0f), [=](GUI*){
menu->back();
}
));
menu->setPage("missing-content");
}
void show_convert_request(
Engine* engine,
const Content* content,
std::shared_ptr<ContentLUT> lut,
fs::path folder) {
fs::path folder
) {
guiutil::confirm(engine->getGUI(), langs::get(L"world.convert-request"),
[=]() {
// TODO: add multithreading here
@ -125,7 +140,8 @@ void show_convert_request(
}, L"", langs::get(L"Cancel"));
}
void create_languages_panel(Engine* engine, PagesControl* menu) {
void create_languages_panel(Engine* engine) {
auto menu = engine->getGUI()->getMenu();
auto panel = create_page(engine, "languages", 400, 0.5f, 1);
panel->scrollable(true);
@ -138,11 +154,14 @@ void create_languages_panel(Engine* engine, PagesControl* menu) {
auto& locale = langs::locales_info.at(name);
std::string& fullName = locale.name;
Button* button = new Button(util::str2wstr_utf8(fullName), vec4(10.f));
button->listenAction([=](GUI*) {
engine->setLanguage(name);
menu->back();
});
auto button = std::make_shared<Button>(
util::str2wstr_utf8(fullName),
vec4(10.f),
[=](GUI*) {
engine->setLanguage(name);
menu->back();
}
);
panel->add(button);
}
panel->add(guiutil::backButton(menu));
@ -191,10 +210,10 @@ void open_world(std::string name, Engine* engine) {
}
}
Panel* create_worlds_panel(Engine* engine) {
auto panel = new Panel(vec2(390, 200), vec4(5.0f));
std::shared_ptr<Panel> create_worlds_panel(Engine* engine) {
auto panel = std::make_shared<Panel>(vec2(390, 200), vec4(5.0f));
panel->setColor(vec4(1.0f, 1.0f, 1.0f, 0.07f));
panel->maxLength(400);
panel->setMaxLength(400);
auto paths = engine->getPaths();
@ -205,13 +224,10 @@ Panel* create_worlds_panel(Engine* engine) {
auto btn = std::make_shared<RichButton>(vec2(390, 46));
btn->setColor(vec4(1.0f, 1.0f, 1.0f, 0.1f));
btn->setHoverColor(vec4(1.0f, 1.0f, 1.0f, 0.17f));
auto label = std::make_shared<Label>(namews);
label->setInteractive(false);
btn->add(label, vec2(8, 8));
btn->listenAction([=](GUI*) {
open_world(name, engine);
});
btn->add(std::make_shared<Label>(namews), vec2(8, 8));
auto image = std::make_shared<Image>("gui/delete_icon", vec2(32, 32));
image->setColor(vec4(1, 1, 1, 0.5f));
@ -219,49 +235,49 @@ Panel* create_worlds_panel(Engine* engine) {
auto delbtn = std::make_shared<Button>(image, vec4(2));
delbtn->setColor(vec4(0.0f));
delbtn->setHoverColor(vec4(1.0f, 1.0f, 1.0f, 0.17f));
btn->add(delbtn, vec2(330, 3));
delbtn->listenAction([=](GUI* gui) {
guiutil::confirm(gui, langs::get(L"delete-confirm", L"world")+
L" ("+util::str2wstr_utf8(folder.u8string())+L")", [=]()
{
std::cout << "deleting " << folder.u8string() << std::endl;
fs::remove_all(folder);
menus::refresh_menus(engine, gui->getMenu());
menus::refresh_menus(engine);
});
});
btn->add(delbtn, vec2(330, 3));
panel->add(btn);
}
return panel;
}
void create_main_menu_panel(Engine* engine, PagesControl* menu) {
void create_main_menu_panel(Engine* engine) {
auto menu = engine->getGUI()->getMenu();
auto panel = create_page(engine, "main", 400, 0.0f, 1);
panel->add(guiutil::gotoButton(L"New World", "new-world", menu));
panel->add(create_worlds_panel(engine));
panel->add(guiutil::gotoButton(L"Settings", "settings", menu));
panel->add((new Button(langs::get(L"Quit", L"menu"), vec4(10.f)))
->listenAction([](GUI* gui) {
Window::setShouldClose(true);
}));
panel->add(std::make_shared<Button>(
langs::get(L"Quit", L"menu"), vec4(10.f), [](GUI*) {
Window::setShouldClose(true);
}
));
}
typedef std::function<void(const ContentPack& pack)> packconsumer;
const int PACKS_PANEL_WIDTH = 550;
std::shared_ptr<Panel> create_packs_panel(
const std::vector<ContentPack>& packs,
Engine* engine,
bool backbutton,
packconsumer callback)
{
packconsumer callback
){
auto assets = engine->getAssets();
auto panel = std::make_shared<Panel>(vec2(PACKS_PANEL_WIDTH, 200), vec4(5.0f));
panel->setColor(vec4(1.0f, 1.0f, 1.0f, 0.07f));
panel->maxLength(400);
panel->setMaxLength(400);
panel->scrollable(true);
for (auto& pack : packs) {
@ -298,7 +314,7 @@ std::shared_ptr<Panel> create_packs_panel(
descriptionlabel->setColor(vec4(1, 1, 1, 0.7f));
packpanel->add(descriptionlabel, vec2(80, 28));
packpanel->add(std::make_shared<Image>(icon, glm::vec2(64)), vec2(8));
packpanel->add(std::make_shared<Image>(icon, vec2(64)), vec2(8));
packpanel->setColor(vec4(0.06f, 0.12f, 0.18f, 0.7f));
panel->add(packpanel);
@ -310,7 +326,8 @@ std::shared_ptr<Panel> create_packs_panel(
}
// TODO: refactor
void create_content_panel(Engine* engine, PagesControl* menu) {
void create_content_panel(Engine* engine) {
auto menu = engine->getGUI()->getMenu();
auto paths = engine->getPaths();
auto mainPanel = create_page(engine, "content", PACKS_PANEL_WIDTH, 0.0f, 5);
@ -355,8 +372,8 @@ void create_content_panel(Engine* engine, PagesControl* menu) {
engine->setScreen(std::make_shared<MenuScreen>(engine));
open_world(wname, engine);
});
menu->add("content-packs", panel);
menu->set("content-packs");
menu->addPage("content-packs", panel);
menu->setPage("content-packs");
}));
mainPanel->add(guiutil::backButton(menu));
}
@ -375,7 +392,7 @@ inline uint64_t str2seed(std::wstring seedstr) {
}
}
void create_new_world_panel(Engine* engine, PagesControl* menu) {
void create_new_world_panel(Engine* engine) {
auto panel = create_page(engine, "new-world", 400, 0.0f, 1);
panel->add(std::make_shared<Label>(langs::get(L"Name", L"world")));
@ -398,54 +415,59 @@ void create_new_world_panel(Engine* engine, PagesControl* menu) {
if (!nameInput->validate())
return;
std::wstring name = nameInput->text();
std::string nameutf8 = util::wstr2str_utf8(name);
EnginePaths* paths = engine->getPaths();
std::wstring seedstr = seedInput->text();
uint64_t seed = str2seed(seedstr);
std::string name = util::wstr2str_utf8(nameInput->text());
uint64_t seed = str2seed(seedInput->text());
std::cout << "world seed: " << seed << std::endl;
auto folder = paths->getWorldsFolder()/fs::u8path(nameutf8);
EnginePaths* paths = engine->getPaths();
auto folder = paths->getWorldsFolder()/fs::u8path(name);
try {
engine->loadAllPacks();
engine->loadContent();
paths->setWorldFolder(folder);
} catch (const contentpack_error& error) {
guiutil::alert(engine->getGUI(),
langs::get(L"Content Error", L"menu")+
L":\n"+util::str2wstr_utf8(std::string(error.what())+
"\npack '"+error.getPackId()+"' from "+
error.getFolder().u8string()));
guiutil::alert(
engine->getGUI(),
langs::get(L"Content Error", L"menu")+L":\n"+
util::str2wstr_utf8(
std::string(error.what())+
"\npack '"+error.getPackId()+"' from "+
error.getFolder().u8string()
)
);
return;
} catch (const std::runtime_error& error) {
guiutil::alert(engine->getGUI(),
langs::get(L"Content Error", L"menu")+
L": "+util::str2wstr_utf8(error.what()));
guiutil::alert(
engine->getGUI(),
langs::get(L"Content Error", L"menu")+
L": "+util::str2wstr_utf8(error.what())
);
return;
}
Level* level = World::create(
nameutf8, folder, seed,
name, folder, seed,
engine->getSettings(),
engine->getContent(),
engine->getContentPacks());
engine->getContentPacks()
);
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
}));
panel->add(guiutil::backButton(menu));
panel->add(guiutil::backButton(engine->getGUI()->getMenu()));
}
void create_controls_panel(Engine* engine, PagesControl* menu) {
void create_controls_panel(Engine* engine) {
auto menu = engine->getGUI()->getMenu();
auto panel = create_page(engine, "controls", 400, 0.0f, 1);
/* Camera sensitivity setting track bar */{
panel->add((new Label(L""))->textSupplier([=]() {
panel->add(create_label([=]() {
float s = engine->getSettings().camera.sensitivity;
return langs::get(L"Mouse Sensitivity", L"settings")+L": "+
util::to_wstring(s, 1);
}));
TrackBar* trackbar = new TrackBar(0.1, 10.0, 2.0, 0.1, 4);
auto trackbar = std::make_shared<TrackBar>(0.1, 10.0, 2.0, 0.1, 4);
trackbar->supplier([=]() {
return engine->getSettings().camera.sensitivity;
});
@ -455,19 +477,18 @@ void create_controls_panel(Engine* engine, PagesControl* menu) {
panel->add(trackbar);
}
Panel* scrollPanel = new Panel(vec2(400, 200), vec4(2.0f), 1.0f);
auto scrollPanel = std::make_shared<Panel>(vec2(400, 200), vec4(2.0f), 1.0f);
scrollPanel->setColor(vec4(0.0f, 0.0f, 0.0f, 0.3f));
scrollPanel->maxLength(400);
scrollPanel->setMaxLength(400);
for (auto& entry : Events::bindings){
std::string bindname = entry.first;
Panel* subpanel = new Panel(vec2(400, 40), vec4(5.0f), 1.0f);
auto subpanel = std::make_shared<Panel>(vec2(400, 40), vec4(5.0f), 1.0f);
subpanel->setColor(vec4(0.0f));
subpanel->orientation(Orientation::horizontal);
subpanel->setOrientation(Orientation::horizontal);
subpanel->add(std::make_shared<InputBindBox>(entry.second));
InputBindBox* bindbox = new InputBindBox(entry.second);
subpanel->add(bindbox);
Label* label = new Label(langs::get(util::str2wstr_utf8(bindname)));
auto label = std::make_shared<Label>(langs::get(util::str2wstr_utf8(bindname)));
label->setMargin(vec4(6.0f));
subpanel->add(label);
scrollPanel->add(subpanel);
@ -476,16 +497,17 @@ void create_controls_panel(Engine* engine, PagesControl* menu) {
panel->add(guiutil::backButton(menu));
}
void create_settings_panel(Engine* engine, PagesControl* menu) {
void create_settings_panel(Engine* engine) {
auto menu = engine->getGUI()->getMenu();
auto panel = create_page(engine, "settings", 400, 0.0f, 1);
/* Load Distance setting track bar */{
panel->add((new Label(L""))->textSupplier([=]() {
panel->add(create_label([=]() {
return langs::get(L"Load Distance", L"settings")+L": " +
std::to_wstring(engine->getSettings().chunks.loadDistance);
}));
TrackBar* trackbar = new TrackBar(3, 66, 10, 1, 3);
auto trackbar = std::make_shared<TrackBar>(3, 66, 10, 1, 3);
trackbar->supplier([=]() {
return engine->getSettings().chunks.loadDistance;
});
@ -496,12 +518,12 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
}
/* Load Speed setting track bar */{
panel->add((new Label(L""))->textSupplier([=]() {
panel->add(create_label([=]() {
return langs::get(L"Load Speed", L"settings")+L": " +
std::to_wstring(engine->getSettings().chunks.loadSpeed);
}));
TrackBar* trackbar = new TrackBar(1, 32, 10, 1, 1);
auto trackbar = std::make_shared<TrackBar>(1, 32, 10, 1, 1);
trackbar->supplier([=]() {
return engine->getSettings().chunks.loadSpeed;
});
@ -512,13 +534,13 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
}
/* Fog Curve setting track bar */{
panel->add((new Label(L""))->textSupplier([=]() {
panel->add(create_label([=]() {
float value = engine->getSettings().graphics.fogCurve;
return langs::get(L"Fog Curve", L"settings")+L": " +
util::to_wstring(value, 1);
}));
TrackBar* trackbar = new TrackBar(1.0, 6.0, 1.0, 0.1, 2);
auto trackbar = std::make_shared<TrackBar>(1.0, 6.0, 1.0, 0.1, 2);
trackbar->supplier([=]() {
return engine->getSettings().graphics.fogCurve;
});
@ -529,12 +551,12 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
}
/* Fov setting track bar */{
panel->add((new Label(L""))->textSupplier([=]() {
panel->add(create_label([=]() {
int fov = (int)engine->getSettings().camera.fov;
return langs::get(L"FOV", L"settings")+L": "+std::to_wstring(fov)+L"°";
}));
TrackBar* trackbar = new TrackBar(30.0, 120.0, 90, 1, 4);
auto trackbar = std::make_shared<TrackBar>(30.0, 120.0, 90, 1, 4);
trackbar->supplier([=]() {
return engine->getSettings().camera.fov;
});
@ -545,7 +567,9 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
}
/* V-Sync checkbox */{
auto checkbox = new FullCheckBox(langs::get(L"V-Sync", L"settings"), vec2(400, 32));
auto checkbox = std::make_shared<FullCheckBox>(
langs::get(L"V-Sync", L"settings"), vec2(400, 32)
);
checkbox->supplier([=]() {
return engine->getSettings().display.swapInterval != 0;
});
@ -556,9 +580,11 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
}
/* Backlight checkbox */{
auto checkbox = new FullCheckBox(langs::get(L"Backlight", L"settings"), vec2(400, 32));
auto checkbox = std::make_shared<FullCheckBox>(
langs::get(L"Backlight", L"settings"), vec2(400, 32)
);
checkbox->supplier([=]() {
return engine->getSettings().graphics.backlight != 0;
return engine->getSettings().graphics.backlight;
});
checkbox->consumer([=](bool checked) {
engine->getSettings().graphics.backlight = checked;
@ -576,15 +602,16 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
panel->add(guiutil::backButton(menu));
}
void create_pause_panel(Engine* engine, PagesControl* menu) {
void create_pause_panel(Engine* engine) {
auto menu = engine->getGUI()->getMenu();
auto panel = create_page(engine, "pause", 400, 0.0f, 1);
panel->add(create_button(L"Continue", vec4(10.0f), vec4(1), [=](GUI*){
menu->reset();
}));
panel->add(create_button(L"Content", vec4(10.0f), vec4(1), [=](GUI*) {
create_content_panel(engine, menu);
menu->set("content");
create_content_panel(engine);
menu->setPage("content");
}));
panel->add(guiutil::gotoButton(L"Settings", "settings", menu));
@ -596,16 +623,16 @@ void create_pause_panel(Engine* engine, PagesControl* menu) {
}));
}
void menus::create_menus(Engine* engine, PagesControl* menu) {
create_new_world_panel(engine, menu);
create_settings_panel(engine, menu);
create_controls_panel(engine, menu);
create_pause_panel(engine, menu);
create_languages_panel(engine, menu);
create_main_menu_panel(engine, menu);
void menus::create_menus(Engine* engine) {
create_new_world_panel(engine);
create_settings_panel(engine);
create_controls_panel(engine);
create_pause_panel(engine);
create_languages_panel(engine);
create_main_menu_panel(engine);
}
void menus::refresh_menus(Engine* engine, PagesControl* menu) {
create_main_menu_panel(engine, menu);
create_new_world_panel(engine, menu);
void menus::refresh_menus(Engine* engine) {
create_main_menu_panel(engine);
create_new_world_panel(engine);
}

View File

@ -3,13 +3,9 @@
class Engine;
namespace gui {
class PagesControl;
}
namespace menus {
void create_menus(Engine* engine, gui::PagesControl* menu);
void refresh_menus(Engine* engine, gui::PagesControl* menu);
void create_menus(Engine* engine);
void refresh_menus(Engine* engine);
}
#endif // FRONTEND_MENU_H_

View File

@ -45,9 +45,9 @@ Screen::~Screen() {
MenuScreen::MenuScreen(Engine* engine_) : Screen(engine_) {
auto menu = engine->getGUI()->getMenu();
menus::refresh_menus(engine, menu);
menus::refresh_menus(engine);
menu->reset();
menu->set("main");
menu->setPage("main");
uicamera.reset(new Camera(glm::vec3(), Window::height));
uicamera->perspective = false;

View File

@ -11,17 +11,17 @@ using glm::vec2;
using glm::vec3;
using glm::vec4;
Batch2D::Batch2D(size_t capacity) : capacity(capacity), offset(0), color(1.0f, 1.0f, 1.0f, 1.0f){
Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
const vattr attrs[] = {
{2}, {2}, {4}, {0}
};
buffer = new float[capacity * B2D_VERTEX_SIZE];
mesh = new Mesh(buffer, 0, attrs);
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
index = 0;
unsigned char pixels[] = {
255, 255, 255, 255,
ubyte pixels[] = {
0xFF, 0xFF, 0xFF, 0xFF
};
blank = new Texture(pixels, 1, 1, GL_RGBA);
_texture = nullptr;
@ -30,7 +30,6 @@ Batch2D::Batch2D(size_t capacity) : capacity(capacity), offset(0), color(1.0f, 1
Batch2D::~Batch2D(){
delete blank;
delete[] buffer;
delete mesh;
}
void Batch2D::begin(){

View File

@ -1,6 +1,7 @@
#ifndef SRC_GRAPHICS_BATCH2D_H_
#define SRC_GRAPHICS_BATCH2D_H_
#include <memory>
#include <stdlib.h>
#include <glm/glm.hpp>
@ -13,8 +14,7 @@ class Sprite;
class Batch2D {
float* buffer;
size_t capacity;
size_t offset;
Mesh* mesh;
std::unique_ptr<Mesh> mesh;
size_t index;
Texture* blank;

View File

@ -13,8 +13,7 @@ using glm::vec3;
using glm::vec4;
Batch3D::Batch3D(size_t capacity)
: capacity(capacity),
offset(0) {
: capacity(capacity) {
const vattr attrs[] = {
{3}, {2}, {4}, {0}
};

View File

@ -12,7 +12,6 @@ class Texture;
class Batch3D {
float* buffer;
size_t capacity;
size_t offset;
Mesh* mesh;
size_t index;

View File

@ -4,16 +4,19 @@
using glm::vec4;
Font::Font(std::vector<Texture*> pages, int lineHeight) : lineHeight_(lineHeight), pages(pages) {
Font::Font(std::vector<std::unique_ptr<Texture>> pages, int lineHeight, int yoffset)
: lineHeight(lineHeight), yoffset(yoffset), pages(std::move(pages)) {
}
Font::~Font(){
for (Texture* texture : pages)
delete texture;
}
int Font::lineHeight() const {
return lineHeight_;
int Font::getYOffset() const {
return yoffset;
}
int Font::getLineHeight() const {
return lineHeight;
}
bool Font::isPrintableChar(int c) {
@ -48,11 +51,11 @@ void Font::draw(Batch2D* batch, std::wstring text, int x, int y, int style) {
if (isPrintableChar(c)){
int charpage = c >> 8;
if (charpage == page){
Texture* texture = pages[charpage];
Texture* texture = pages[charpage].get();
if (texture == nullptr){
texture = pages[0];
texture = pages[0].get();
}
batch->texture(pages[charpage]);
batch->texture(texture);
switch (style){
case STYLE_SHADOW:

View File

@ -1,6 +1,7 @@
#ifndef GRAPHICS_FONT_H_
#define GRAPHICS_FONT_H_
#include <memory>
#include <string>
#include <vector>
#include "../typedefs.h"
@ -13,13 +14,15 @@ const uint STYLE_SHADOW = 1;
const uint STYLE_OUTLINE = 2;
class Font {
int lineHeight_;
int lineHeight;
int yoffset;
public:
std::vector<Texture*> pages;
Font(std::vector<Texture*> pages, int lineHeight);
std::vector<std::unique_ptr<Texture>> pages;
Font(std::vector<std::unique_ptr<Texture>> pages, int lineHeight, int yoffset);
~Font();
int lineHeight() const;
int getLineHeight() const;
int getYOffset() const;
int calcWidth(std::wstring text);
// int getGlyphWidth(char c);
bool isPrintableChar(int c);

View File

@ -8,17 +8,23 @@ const uint LB_VERTEX_SIZE = (3+4);
LineBatch::LineBatch(size_t capacity) : capacity(capacity) {
const vattr attrs[] = { {3},{4}, {0} };
buffer = new float[capacity * LB_VERTEX_SIZE * 2];
mesh = new Mesh(buffer, 0, attrs);
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
index = 0;
}
LineBatch::~LineBatch(){
delete[] buffer;
delete mesh;
}
void LineBatch::line(float x1, float y1, float z1, float x2, float y2, float z2,
float r, float g, float b, float a) {
void LineBatch::line(
float x1, float y1,
float z1, float x2,
float y2, float z2,
float r, float g, float b, float a
) {
if (index + LB_VERTEX_SIZE * 2 >= capacity) {
render();
}
buffer[index] = x1;
buffer[index+1] = y1;
buffer[index+2] = z1;

View File

@ -1,13 +1,14 @@
#ifndef GRAPHICS_LINEBATCH_H_
#define GRAPHICS_LINEBATCH_H_
#include <memory>
#include <stdlib.h>
#include <glm/glm.hpp>
class Mesh;
class LineBatch {
Mesh* mesh;
std::unique_ptr<Mesh> mesh;
float* buffer;
size_t index;
size_t capacity;

View File

@ -19,7 +19,7 @@ Texture::Texture(ubyte* data, int width, int height, uint format)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glBindTexture(GL_TEXTURE_2D, 0);
}

View File

@ -19,9 +19,6 @@ private:
uint padding;
std::unique_ptr<WorldGenerator> generator;
/* Average measured microseconds duration of loadVisible call */
int64_t avgDurationMcs = 1000;
/* Process one chunk: load it or calculate lights for it */
bool loadVisible();
bool buildLights(std::shared_ptr<Chunk> chunk);

View File

@ -25,7 +25,7 @@ inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
return 3;
}
inline void luaL_openlib(lua_State* L, const char* name, const luaL_Reg* libfuncs, int nup) {
inline void openlib(lua_State* L, const char* name, const luaL_Reg* libfuncs, int nup) {
lua_newtable(L);
luaL_setfuncs(L, libfuncs, nup);
lua_setglobal(L, name);
@ -409,11 +409,11 @@ static int l_print(lua_State* L) {
lua_setglobal(L, NAME))
void apilua::create_funcs(lua_State* L) {
luaL_openlib(L, "pack", packlib, 0);
luaL_openlib(L, "world", worldlib, 0);
luaL_openlib(L, "player", playerlib, 0);
luaL_openlib(L, "time", timelib, 0);
luaL_openlib(L, "file", filelib, 0);
openlib(L, "pack", packlib, 0);
openlib(L, "world", worldlib, 0);
openlib(L, "player", playerlib, 0);
openlib(L, "time", timelib, 0);
openlib(L, "file", filelib, 0);
lua_addfunc(L, l_print, "print");
lua_addfunc(L, l_block_index, "block_index");

View File

@ -101,6 +101,20 @@ void scripting::initialize(Engine* engine) {
load_script(fs::path("stdlib.lua"));
}
// todo: luaL state check
runnable scripting::create_runnable(
const std::string& filename,
const std::string& src
) {
return [=](){
if (luaL_loadbuffer(L, src.c_str(), src.length(), filename.c_str())) {
handleError(L);
return;
}
call_func(L, 0, filename);
};
}
void scripting::on_world_load(Level* level, BlocksController* blocks) {
scripting::level = level;
scripting::content = level->content;

View File

@ -1,6 +1,8 @@
#include <string>
#include <filesystem>
#include "../../delegates.h"
namespace fs = std::filesystem;
class Engine;
@ -20,6 +22,12 @@ namespace scripting {
extern BlocksController* blocks;
void initialize(Engine* engine);
runnable create_runnable(
const std::string& filename,
const std::string& source
);
void on_world_load(Level* level, BlocksController* blocks);
void on_world_save();
void on_world_quit();

View File

@ -4,18 +4,17 @@
#include <stdlib.h>
#include <stdint.h>
typedef unsigned int uint;
using uint = unsigned int;
// use for bytes arrays
typedef uint8_t ubyte;
using ubyte = uint8_t;
// content indices
typedef uint32_t itemid_t;
typedef uint16_t blockid_t;
using itemid_t = uint32_t;
using blockid_t = uint16_t;
typedef uint32_t itemcount_t;
typedef uint16_t blockstate_t;
typedef uint16_t light_t;
using itemcount_t = uint32_t;
using blockstate_t = uint16_t;
using light_t = uint16_t;
#endif

View File

@ -252,3 +252,30 @@ std::vector<ubyte> util::base64_decode(const char* str, size_t size) {
std::vector<ubyte> util::base64_decode(const std::string& str) {
return base64_decode(str.c_str(), str.size());
}
int util::replaceAll(std::string& str, const std::string& from, const std::string& to) {
int count = 0;
size_t offset = 0;
while (true) {
size_t start_pos = str.find(from, offset);
if(start_pos == std::string::npos)
break;
str.replace(start_pos, from.length(), to);
offset = start_pos + to.length();
count++;
break;
}
return count;
}
// replace it with std::from_chars in the far far future
double util::parse_double(const std::string& str) {
std::istringstream ss(str);
ss.imbue(std::locale("C"));
double d;
ss >> d;
if (ss.fail()) {
throw std::runtime_error("invalid number format");
}
return d;
}

View File

@ -26,6 +26,10 @@ namespace util {
extern std::string base64_encode(const ubyte* data, size_t size);
extern std::vector<ubyte> base64_decode(const char* str, size_t size);
extern std::vector<ubyte> base64_decode(const std::string& str);
extern int replaceAll(std::string& str, const std::string& from, const std::string& to);
extern double parse_double(const std::string& str);
}
#endif // UTIL_STRINGUTIL_H_

View File

@ -5,7 +5,7 @@
#include <filesystem>
#include <stdexcept>
#include "definitions.h"
#include "core_defs.h"
#include "engine.h"
#include "util/platform.h"
#include "coders/toml.h"
@ -38,7 +38,7 @@ int main(int argc, char** argv) {
toml::Reader reader(wrapper.get(), settings_file.string(), text);
reader.read();
}
setup_bindings();
corecontent::setup_bindings();
Engine engine(settings, &paths);
if (fs::is_regular_file(controls_file)) {
std::cout << "-- loading controls" << std::endl;

View File

@ -13,7 +13,7 @@ struct AABB;
class Content;
class ContentIndices;
class Chunk;
class voxel;
struct voxel;
class WorldFiles;
class LevelEvents;

View File

@ -3,7 +3,7 @@
#include "../typedefs.h"
class voxel;
struct voxel;
class Content;
class WorldGenerator {

View File

@ -84,6 +84,10 @@ public:
uint getNextInventoryId() {
return nextInventoryId++;
}
const Content* getContent() const {
return content;
}
};
#endif /* WORLD_WORLD_H_ */