Merge branch 'main' into content-loader-refactor

This commit is contained in:
MihailRis
2025-04-13 18:04:15 +03:00
75 changed files with 862 additions and 746 deletions
+27
View File
@@ -0,0 +1,27 @@
local arr = Bytearray()
assert(#arr == 0)
for i=1,10 do
arr[i] = 10 - i
assert(#arr == i)
assert(arr[i] == 10 - i)
end
for i, v in ipairs(arr) do
assert(v == 10 - i)
end
Bytearray.remove(arr, 2)
assert(#arr == 9)
Bytearray.insert(arr, {5, 3, 6})
assert(#arr == 12)
Bytearray.insert(arr, 2, 8)
assert(#arr == 13)
for i=1,10 do
assert(arr[i] == 10 - i)
end
print(#arr, arr:get_capacity())
arr:trim()
assert(#arr == arr:get_capacity())
+2 -2
View File
@@ -1,8 +1,8 @@
local util = require "core:tests_util" local util = require "core:tests_util"
util.create_demo_world() util.create_demo_world()
app.set_setting("chunks.load-distance", 3) app.set_setting("chunks.load-distance", 15)
app.set_setting("chunks.load-speed", 1) app.set_setting("chunks.load-speed", 15)
local pid1 = player.create("Xerxes") local pid1 = player.create("Xerxes")
assert(player.get_name(pid1) == "Xerxes") assert(player.get_name(pid1) == "Xerxes")
+4
View File
@@ -0,0 +1,4 @@
local data_buffer = require "core:data_buffer"
local buffer = data_buffer({}, 'LE', true)
buffer:put_int16(2025)
debug.print(buffer)
+3
View File
@@ -29,6 +29,9 @@ entity:has_component(name: str) -> bool
-- Enables/disables the component -- Enables/disables the component
entity:set_enabled(name: str, enable: bool) entity:set_enabled(name: str, enable: bool)
-- Returns id of player the entity is bound
entity:get_player() -> int or nil
``` ```
## Built-in components ## Built-in components
+3
View File
@@ -29,6 +29,9 @@ entity:has_component(name: str) -> bool
-- Включает/выключает компонент по имени -- Включает/выключает компонент по имени
entity:set_enabled(name: str, enable: bool) entity:set_enabled(name: str, enable: bool)
-- Возвращает id игрока, к которому привязана сущность
entity:get_player() -> int или nil
``` ```
## Встроенные компоненты ## Встроенные компоненты
+28
View File
@@ -0,0 +1,28 @@
language = "GLSL"
extensions = ["glsl", "glslv", "glslf"]
line-comment = "//"
multiline-comment-start = "/*"
multiline-comment-end = "*/"
keywords = [
"attribute", "break", "bvec2", "bvec3", "bvec4", "centroid", "continue",
"discard", "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2",
"dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4", "dvec2",
"dvec3", "dvec4", "else", "flat", "float", "highp", "if", "in", "inout",
"int", "invariant", "isampler1D", "isampler1DArray", "isampler2D",
"isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect",
"isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray",
"ivec2", "ivec3", "ivec4", "layout", "lowp", "mat2", "mat2x2", "mat2x3",
"mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3",
"mat4x4", "mediump", "noperspective", "out", "patch", "precision", "return",
"sample", "sampler1D", "sampler1DArray", "sampler1DArrayShadow",
"sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow",
"sampler2DMS", "sampler2DMSArray", "sampler2DRect", "sampler2DRectShadow",
"sampler2DShadow", "sampler3D", "samplerBuffer", "samplerCube",
"samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "smooth",
"subroutine", "uniform", "usampler1D", "usampler1DArray", "usampler2D",
"usampler2DArray", "usampler2DMS", "usampler2DMSArray", "usampler2DRect",
"usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray",
"uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void",
"while",
]
+12
View File
@@ -0,0 +1,12 @@
language = "Lua"
extensions = ["lua"]
line-comment = "--"
multiline-comment-start = "[==["
multiline-comment-end = "]==]"
multiline-string-start = "[["
multiline-string-end = "]]"
keywords = [
"and", "break", "do", "else", "elseif", "end", "false", "for", "function",
"if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true",
"until", "while"
]
-1
View File
@@ -74,7 +74,6 @@
multiline='true' multiline='true'
line-numbers='true' line-numbers='true'
oncontrolkey='on_control_combination' oncontrolkey='on_control_combination'
syntax='lua'
size-func="-1,40" size-func="-1,40"
text-wrap='false' text-wrap='false'
scroll-step='50' scroll-step='50'
+1
View File
@@ -197,6 +197,7 @@ function open_file_in_editor(filename, line, mutable)
editor.scroll = 0 editor.scroll = 0
editor.text = source editor.text = source
editor.focused = true editor.focused = true
editor.syntax = file.ext(filename)
if line then if line then
time.post_runnable(function() time.post_runnable(function()
editor.caret = editor:linePos(line) editor.caret = editor:linePos(line)
+215
View File
@@ -0,0 +1,215 @@
local MIN_CAPACITY = 8
local _type = type
local FFI = ffi
FFI.cdef[[
void* malloc(size_t);
void free(void*);
typedef struct {
unsigned char* bytes;
int size;
int capacity;
} bytearray_t;
]]
local malloc = FFI.C.malloc
local free = FFI.C.free
local function grow_buffer(self, elems)
local new_capacity = math.ceil(self.capacity / 0.75 + elems)
local prev = self.bytes
self.bytes = malloc(new_capacity)
FFI.copy(self.bytes, prev, self.size)
self.capacity = new_capacity
free(prev)
end
local function trim_buffer(self)
if self.size == self.capacity then
return
end
local size = self.size
local prev = self.bytes
self.bytes = malloc(size)
FFI.copy(self.bytes, prev, self.size)
self.capacity = size
free(prev)
end
local function count_elements(b)
local elems = 1
if _type(b) ~= "number" then
elems = #b
end
return elems
end
local function append(self, b)
local elems = count_elements(b)
if self.size + elems > self.capacity then
grow_buffer(self, elems)
end
if _type(b) == "number" then
self.bytes[self.size] = b
else
for i=1, #b do
self.bytes[self.size + i - 1] = b[i]
end
end
self.size = self.size + elems
end
local function insert(self, index, b)
if b == nil then
b = index
index = self.size + 1
end
if index <= 0 or index > self.size + 1 then
return
end
local elems = count_elements(b)
if self.size + elems > self.capacity then
grow_buffer(self, elems)
end
for i=self.size, index - 1, -1 do
self.bytes[i + elems] = self.bytes[i]
end
if _type(b) == "number" then
self.bytes[index - 1] = b
else
for i=1, #b do
self.bytes[index + i - 2] = b[i]
end
end
self.size = self.size + elems
end
local function remove(self, index, elems)
if index <= 0 or index > self.size then
return
end
if elems == nil then
elems = 1
end
if index + elems > self.size then
elems = self.size - index + 1
end
for i=index - 1, self.size - elems - 1 do
self.bytes[i] = self.bytes[i + elems]
end
self.size = self.size - elems
end
local function clear(self)
self.size = 0
end
local function reserve(self, new_capacity)
if new_capacity <= self.capacity then
return
end
local prev = self.bytes
self.bytes = malloc(new_capacity)
FFI.copy(self.bytes, prev, self.size)
self.capacity = new_capacity
free(prev)
end
local function get_capacity(self)
return self.capacity
end
local bytearray_methods = {
append=append,
insert=insert,
remove=remove,
trim=trim_buffer,
clear=clear,
reserve=reserve,
get_capacity=get_capacity,
}
local bytearray_mt = {
__index = function(self, key)
if _type(key) == "string" then
return bytearray_methods[key]
end
if key <= 0 or key > self.size then
return
end
return self.bytes[key - 1]
end,
__newindex = function(self, key, value)
if key == self.size + 1 then
return append(self, value)
elseif key <= 0 or key > self.size then
return
end
self.bytes[key - 1] = value
end,
__tostring = function(self)
return string.format("FFIBytearray[%s]{...}", tonumber(self.size))
end,
__len = function(self)
return tonumber(self.size)
end,
__gc = function(self)
free(self.bytes)
end,
__ipairs = function(self)
local i = 0
return function()
i = i + 1
if i <= self.size then
return i, self.bytes[i - 1]
end
end
end
}
local bytearray_type = FFI.metatype("bytearray_t", bytearray_mt)
local FFIBytearray = {
__call = function (n)
local t = type(n)
if t == "string" then
local buffer = malloc(#n)
FFI.copy(buffer, n, #n)
return bytearray_type(buffer, #n, #n)
elseif t == "table" then
local capacity = math.max(#n, MIN_CAPACITY)
local buffer = malloc(capacity)
for i=1,#n do
buffer[i - 1] = n[i]
end
return bytearray_type(buffer, #n, capacity)
end
n = n or 0
if n < MIN_CAPACITY then
return bytearray_type(malloc(MIN_CAPACITY), n, MIN_CAPACITY)
else
return bytearray_type(malloc(n), n, n)
end
end,
}
table.merge(FFIBytearray, bytearray_methods)
local function FFIBytearray_as_string(bytes)
local t = type(bytes)
if t == "cdata" then
return FFI.string(bytes.bytes, bytes.size)
elseif t == "table" then
local buffer = FFI.new("unsigned char[?]", #bytes)
for i=1, #bytes do
buffer[i - 1] = bytes[i]
end
return FFI.string(buffer, #bytes)
else
error("Bytearray expected, got "..type(bytes))
end
end
return {
FFIBytearray = setmetatable(FFIBytearray, FFIBytearray),
FFIBytearray_as_string = FFIBytearray_as_string
}
+5
View File
@@ -263,6 +263,11 @@ entities.get_all = function(uids)
return stdcomp.get_all(uids) return stdcomp.get_all(uids)
end end
end end
local bytearray = require "core:internal/bytearray"
Bytearray = bytearray.FFIBytearray
Bytearray_as_string = bytearray.FFIBytearray_as_string
Bytearray_construct = Bytearray.__call
ffi = nil
math.randomseed(time.uptime() * 1536227939) math.randomseed(time.uptime() * 1536227939)
+6 -9
View File
@@ -1,6 +1,3 @@
local _ffi = ffi
ffi = nil
-- Lua has no parallelizm, also _set_data does not call any lua functions so -- Lua has no parallelizm, also _set_data does not call any lua functions so
-- may be reused one global ffi buffer per lua_State -- may be reused one global ffi buffer per lua_State
local canvas_ffi_buffer local canvas_ffi_buffer
@@ -8,14 +5,14 @@ local canvas_ffi_buffer_size = 0
function __vc_Canvas_set_data(self, data) function __vc_Canvas_set_data(self, data)
if type(data) == "cdata" then if type(data) == "cdata" then
self:_set_data(tostring(_ffi.cast("uintptr_t", data))) self:_set_data(tostring(ffi.cast("uintptr_t", data)))
end end
local width = self.width local width = self.width
local height = self.height local height = self.height
local size = width * height * 4 local size = width * height * 4
if size > canvas_ffi_buffer_size then if size > canvas_ffi_buffer_size then
canvas_ffi_buffer = _ffi.new( canvas_ffi_buffer = ffi.new(
string.format("unsigned char[%s]", size) string.format("unsigned char[%s]", size)
) )
canvas_ffi_buffer_size = size canvas_ffi_buffer_size = size
@@ -23,7 +20,7 @@ function __vc_Canvas_set_data(self, data)
for i=0, size - 1 do for i=0, size - 1 do
canvas_ffi_buffer[i] = data[i + 1] canvas_ffi_buffer[i] = data[i + 1]
end end
self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer))) self:_set_data(tostring(ffi.cast("uintptr_t", canvas_ffi_buffer)))
end end
function crc32(bytes, chksum) function crc32(bytes, chksum)
@@ -31,14 +28,14 @@ function crc32(bytes, chksum)
local length = #bytes local length = #bytes
if type(bytes) == "table" then if type(bytes) == "table" then
local buffer_len = _ffi.new('int[1]', length) local buffer_len = ffi.new('int[1]', length)
local buffer = _ffi.new( local buffer = ffi.new(
string.format("char[%s]", length) string.format("char[%s]", length)
) )
for i=1, length do for i=1, length do
buffer[i - 1] = bytes[i] buffer[i - 1] = bytes[i]
end end
bytes = _ffi.string(buffer, buffer_len[0]) bytes = ffi.string(buffer, buffer_len[0])
end end
return _crc32(bytes, chksum) return _crc32(bytes, chksum)
end end
+3
View File
@@ -166,6 +166,9 @@ size_t BasicParser<CharT>::remain() const {
template<typename CharT> template<typename CharT>
bool BasicParser<CharT>::isNext(const std::basic_string<CharT>& substring) { bool BasicParser<CharT>::isNext(const std::basic_string<CharT>& substring) {
if (substring.empty()) {
return false;
}
if (source.length() - pos < substring.length()) { if (source.length() - pos < substring.length()) {
return false; return false;
} }
+8 -21
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "GLSLExtension.hpp" #include "GLSLExtension.hpp"
#include <sstream> #include <sstream>
@@ -95,22 +96,6 @@ inline void source_line(std::stringstream& ss, uint linenum) {
ss << "#line " << linenum << "\n"; ss << "#line " << linenum << "\n";
} }
static std::optional<Type> param_type_from(
const std::string& name
) {
static const std::unordered_map<std::string, Type> typeNames {
{"float", Type::FLOAT},
{"vec2", Type::VEC2},
{"vec3", Type::VEC3},
{"vec4", Type::VEC4},
};
const auto& found = typeNames.find(name);
if (found == typeNames.end()) {
return std::nullopt;
}
return found->second;
}
static Value default_value_for(Type type) { static Value default_value_for(Type type) {
switch (type) { switch (type) {
case Type::FLOAT: case Type::FLOAT:
@@ -212,11 +197,13 @@ public:
} }
bool processParamDirective() { bool processParamDirective() {
using Param = PostEffect::Param;
skipWhitespace(false); skipWhitespace(false);
// Parse type name // Parse type name
auto typeName = parseName(); auto typeName = parseName();
auto type = param_type_from(typeName); Param::Type type;
if (!type.has_value()) { if (!Param::TypeMeta.getItem(typeName, type)) {
throw error("unsupported param type " + util::quote(typeName)); throw error("unsupported param type " + util::quote(typeName));
} }
skipWhitespace(false); skipWhitespace(false);
@@ -228,17 +215,17 @@ public:
skipWhitespace(false); skipWhitespace(false);
ss << "uniform " << typeName << " " << paramName << ";\n"; ss << "uniform " << typeName << " " << paramName << ";\n";
auto defValue = default_value_for(type.value()); auto defValue = default_value_for(type);
// Parse default value // Parse default value
if (peekNoJump() == '=') { if (peekNoJump() == '=') {
skip(1); skip(1);
skipWhitespace(false); skipWhitespace(false);
defValue = parseDefaultValue(type.value(), typeName); defValue = parseDefaultValue(type, typeName);
} }
skipLine(); skipLine();
params[paramName] = PostEffect::Param(type.value(), std::move(defValue)); params[paramName] = PostEffect::Param(type, std::move(defValue));
return false; return false;
} }
-12
View File
@@ -1,12 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include "devtools/syntax.hpp"
namespace lua {
std::vector<devtools::Token> tokenize(
std::string_view file, std::wstring_view source
);
}
@@ -1,28 +1,74 @@
#include "lua_parsing.hpp" #include "syntax_parser.hpp"
#include <set> #include <set>
#include "data/dv.hpp"
#include "util/stringutil.hpp"
#include "BasicParser.hpp" #include "BasicParser.hpp"
using namespace lua;
using namespace devtools; using namespace devtools;
static std::set<std::wstring_view> keywords { dv::value Syntax::serialize() const {
L"and", L"break", L"do", L"else", L"elseif", L"end", L"false", L"for", L"function", auto map = dv::object();
L"if", L"in", L"local", L"nil", L"not", L"or", L"repeat", L"return", L"then", L"true", map["language"] = language;
L"until", L"while" map["line-comment"] = util::wstr2str_utf8(lineComment);
}; map["multiline-comment-start"] = util::wstr2str_utf8(multilineCommentStart);
map["multiline-comment-end"] = util::wstr2str_utf8(multilineCommentEnd);
map["multiline-string-start"] = util::wstr2str_utf8(multilineStringStart);
map["multiline-string-end"] = util::wstr2str_utf8(multilineStringEnd);
static bool is_lua_keyword(std::wstring_view view) { auto& extsList = map.list("extensions");
return keywords.find(view) != keywords.end(); for (const auto& ext : extensions) {
extsList.add(ext);
}
auto& keywordsList = map.list("keywords");
for (const auto& keyword : keywords) {
keywordsList.add(util::wstr2str_utf8(keyword));
}
return map;
} }
inline bool is_lua_identifier_start(int c) { void Syntax::deserialize(const dv::value& src) {
src.at("language").get(language);
std::string lineComment;
std::string multilineCommentStart;
std::string multilineCommentEnd;
std::string multilineStringStart;
std::string multilineStringEnd;
src.at("line-comment").get(lineComment);
src.at("multiline-comment-start").get(multilineCommentStart);
src.at("multiline-comment-end").get(multilineCommentEnd);
src.at("multiline-string-start").get(multilineStringStart);
src.at("multiline-string-end").get(multilineStringEnd);
this->lineComment = util::str2wstr_utf8(lineComment);
this->multilineCommentStart = util::str2wstr_utf8(multilineCommentStart);
this->multilineCommentEnd = util::str2wstr_utf8(multilineCommentEnd);
this->multilineStringStart = util::str2wstr_utf8(multilineStringStart);
this->multilineStringEnd = util::str2wstr_utf8(multilineStringEnd);
if (src.has("extensions")) {
const auto& extsList = src["extensions"];
for (const auto& ext : extsList) {
extensions.insert(ext.asString());
}
}
if (src.has("keywords")) {
const auto& keywordsList = src["keywords"];
for (const auto& keyword : keywordsList) {
keywords.insert(util::str2wstr_utf8(keyword.asString()));
}
}
}
inline bool is_common_identifier_start(int c) {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'; return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_';
} }
inline bool is_lua_identifier_part(int c) { inline bool is_common_identifier_part(int c) {
return is_lua_identifier_start(c) || is_digit(c); return is_common_identifier_start(c) || is_digit(c);
} }
inline bool is_lua_operator_start(int c) { inline bool is_lua_operator_start(int c) {
@@ -32,10 +78,13 @@ inline bool is_lua_operator_start(int c) {
} }
class Tokenizer : BasicParser<wchar_t> { class Tokenizer : BasicParser<wchar_t> {
const Syntax& syntax;
std::vector<Token> tokens; std::vector<Token> tokens;
public: public:
Tokenizer(std::string_view file, std::wstring_view source) Tokenizer(
: BasicParser(file, source) { const Syntax& syntax, std::string_view file, std::wstring_view source
)
: BasicParser(file, source), syntax(syntax) {
} }
std::wstring parseLuaName() { std::wstring parseLuaName() {
@@ -111,9 +160,12 @@ public:
} }
wchar_t c = peek(); wchar_t c = peek();
auto start = currentLocation(); auto start = currentLocation();
if (is_lua_identifier_start(c)) { if (is_common_identifier_start(c)) {
auto name = parseLuaName(); auto name = parseLuaName();
TokenTag tag = (is_lua_keyword(name) ? TokenTag::KEYWORD : TokenTag::NAME); TokenTag tag =
(syntax.keywords.find(name) == syntax.keywords.end()
? TokenTag::NAME
: TokenTag::KEYWORD);
emitToken( emitToken(
tag, tag,
std::move(name), std::move(name),
@@ -133,24 +185,29 @@ public:
emitToken(tag, std::wstring(literal), start); emitToken(tag, std::wstring(literal), start);
continue; continue;
} }
const auto& mcommentStart = syntax.multilineCommentStart;
if (!mcommentStart.empty() && c == mcommentStart[0] &&
isNext(syntax.multilineCommentStart)) {
auto string = readUntil(syntax.multilineCommentEnd, true);
skip(syntax.multilineCommentEnd.length());
emitToken(
TokenTag::COMMENT,
std::wstring(string) + syntax.multilineCommentEnd,
start
);
continue;
}
const auto& mstringStart = syntax.multilineStringStart;
if (!mstringStart.empty() && c == mstringStart[0] &&
isNext(syntax.multilineStringStart)) {
skip(mstringStart.length());
auto string = readUntil(syntax.multilineStringEnd, true);
skip(syntax.multilineStringEnd.length());
emitToken(TokenTag::STRING, std::wstring(string), start);
continue;
}
switch (c) { switch (c) {
case '(': case '[': case '{': case '(': case '[': case '{':
if (isNext(L"[==[")) {
auto string = readUntil(L"]==]", true);
skip(4);
emitToken(
TokenTag::COMMENT,
std::wstring(string) + L"]==]",
start
);
continue;
} else if (isNext(L"[[")) {
skip(2);
auto string = readUntil(L"]]", true);
skip(2);
emitToken(TokenTag::STRING, std::wstring(string), start);
continue;
}
emitToken(TokenTag::OPEN_BRACKET, std::wstring({c}), start, true); emitToken(TokenTag::OPEN_BRACKET, std::wstring({c}), start, true);
continue; continue;
case ')': case ']': case '}': case ')': case ']': case '}':
@@ -188,6 +245,8 @@ public:
} }
}; };
std::vector<Token> lua::tokenize(std::string_view file, std::wstring_view source) { std::vector<Token> devtools::tokenize(
return Tokenizer(file, source).tokenize(); const Syntax& syntax, std::string_view file, std::wstring_view source
) {
return Tokenizer(syntax, file, source).tokenize();
} }
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <set>
#include <string>
#include <vector>
#include "devtools/syntax.hpp"
#include "interfaces/Serializable.hpp"
namespace devtools {
struct Syntax : Serializable {
std::string language;
std::set<std::string> extensions;
std::set<std::wstring> keywords;
std::wstring lineComment;
std::wstring multilineCommentStart;
std::wstring multilineCommentEnd;
std::wstring multilineStringStart;
std::wstring multilineStringEnd;
dv::value serialize() const override;
void deserialize(const dv::value& src) override;
};
std::vector<Token> tokenize(
const Syntax& syntax, std::string_view file, std::wstring_view source
);
}
-38
View File
@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <optional>
#include <set> #include <set>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
@@ -25,23 +24,6 @@ namespace rigging {
class SkeletonConfig; class SkeletonConfig;
} }
constexpr const char* ContentType_name(ContentType type) {
switch (type) {
case ContentType::NONE:
return "none";
case ContentType::BLOCK:
return "block";
case ContentType::ITEM:
return "item";
case ContentType::ENTITY:
return "entity";
case ContentType::GENERATOR:
return "generator";
default:
return "unknown";
}
}
class namereuse_error : public std::runtime_error { class namereuse_error : public std::runtime_error {
ContentType type; ContentType type;
public: public:
@@ -185,26 +167,6 @@ public:
} }
}; };
constexpr const char* to_string(ResourceType type) {
switch (type) {
case ResourceType::CAMERA:
return "camera";
case ResourceType::POST_EFFECT_SLOT:
return "post-effect-slot";
default:
return "unknown";
}
}
inline std::optional<ResourceType> ResourceType_from(std::string_view str) {
if (str == "camera") {
return ResourceType::CAMERA;
} else if (str == "post-effect-slot") {
return ResourceType::POST_EFFECT_SLOT;
}
return std::nullopt;
}
using ResourceIndicesSet = ResourceIndices[RESOURCE_TYPES_COUNT]; using ResourceIndicesSet = ResourceIndices[RESOURCE_TYPES_COUNT];
/// @brief Content is a definitions repository /// @brief Content is a definitions repository
+13 -15
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "ContentLoader.hpp" #include "ContentLoader.hpp"
#include <algorithm> #include <algorithm>
@@ -259,28 +260,25 @@ void ContentLoader::loadBlock(
} }
// block model // block model
std::string modelTypeName = to_string(def.model); std::string modelTypeName = BlockModelMeta.getNameString(def.model);
root.at("model").get(modelTypeName); root.at("model").get(modelTypeName);
root.at("model-name").get(def.modelName); root.at("model-name").get(def.modelName);
if (auto model = BlockModel_from(modelTypeName)) { if (BlockModelMeta.getItem(modelTypeName, def.model)) {
if (*model == BlockModel::custom && def.customModelRaw == nullptr) { if (def.model == BlockModel::custom && def.customModelRaw == nullptr) {
if (root.has("model-primitives")) { if (root.has("model-primitives")) {
def.customModelRaw = root["model-primitives"]; def.customModelRaw = root["model-primitives"];
} else if (def.modelName.empty()) { } else if (def.modelName.empty()) {
throw std::runtime_error(name + ": no 'model-primitives' or 'model-name' found"); throw std::runtime_error(name + ": no 'model-primitives' or 'model-name' found");
} }
} }
def.model = *model;
} else if (!modelTypeName.empty()) { } else if (!modelTypeName.empty()) {
logger.error() << "unknown model: " << modelTypeName; logger.error() << "unknown model: " << modelTypeName;
def.model = BlockModel::none; def.model = BlockModel::none;
} }
std::string cullingModeName = to_string(def.culling); std::string cullingModeName = CullingModeMeta.getNameString(def.culling);
root.at("culling").get(cullingModeName); root.at("culling").get(cullingModeName);
if (auto mode = CullingMode_from(cullingModeName)) { if (!CullingModeMeta.getItem(cullingModeName, def.culling)) {
def.culling = *mode;
} else {
logger.error() << "unknown culling mode: " << cullingModeName; logger.error() << "unknown culling mode: " << cullingModeName;
} }
@@ -518,9 +516,7 @@ void ContentLoader::loadEntity(
std::string bodyTypeName; std::string bodyTypeName;
root.at("body-type").get(bodyTypeName); root.at("body-type").get(bodyTypeName);
if (auto bodyType = BodyType_from(bodyTypeName)) { BodyTypeMeta.getItem(bodyTypeName, def.bodyType);
def.bodyType = *bodyType;
}
root.at("skeleton-name").get(def.skeletonName); root.at("skeleton-name").get(def.skeletonName);
root.at("blocking").get(def.blocking); root.at("blocking").get(def.blocking);
@@ -749,8 +745,9 @@ void ContentLoader::load() {
if (io::exists(resourcesFile)) { if (io::exists(resourcesFile)) {
auto resRoot = io::read_json(resourcesFile); auto resRoot = io::read_json(resourcesFile);
for (const auto& [key, arr] : resRoot.asObject()) { for (const auto& [key, arr] : resRoot.asObject()) {
if (auto resType = ResourceType_from(key)) { ResourceType type;
loadResources(*resType, arr); if (ResourceTypeMeta.getItem(key, type)) {
loadResources(type, arr);
} else { } else {
// Ignore unknown resources // Ignore unknown resources
logger.warning() << "unknown resource type: " << key; logger.warning() << "unknown resource type: " << key;
@@ -763,8 +760,9 @@ void ContentLoader::load() {
if (io::exists(aliasesFile)) { if (io::exists(aliasesFile)) {
auto resRoot = io::read_json(aliasesFile); auto resRoot = io::read_json(aliasesFile);
for (const auto& [key, arr] : resRoot.asObject()) { for (const auto& [key, arr] : resRoot.asObject()) {
if (auto resType = ResourceType_from(key)) { ResourceType type;
loadResourceAliases(*resType, arr); if (ResourceTypeMeta.getItem(key, type)) {
loadResourceAliases(type, arr);
} else { } else {
// Ignore unknown resources // Ignore unknown resources
logger.warning() << "unknown resource type: " << key; logger.warning() << "unknown resource type: " << key;
+14
View File
@@ -1,12 +1,21 @@
#pragma once #pragma once
#include "typedefs.hpp" #include "typedefs.hpp"
#include "util/EnumMetadata.hpp"
class Content; class Content;
class ContentPackRuntime; class ContentPackRuntime;
enum class ContentType { NONE, BLOCK, ITEM, ENTITY, GENERATOR }; enum class ContentType { NONE, BLOCK, ITEM, ENTITY, GENERATOR };
VC_ENUM_METADATA(ContentType)
{"none", ContentType::NONE},
{"block", ContentType::BLOCK},
{"item", ContentType::ITEM},
{"entity", ContentType::ENTITY},
{"generator", ContentType::GENERATOR},
VC_ENUM_END
enum class ResourceType : size_t { enum class ResourceType : size_t {
CAMERA, CAMERA,
POST_EFFECT_SLOT, POST_EFFECT_SLOT,
@@ -15,3 +24,8 @@ enum class ResourceType : size_t {
inline constexpr auto RESOURCE_TYPES_COUNT = inline constexpr auto RESOURCE_TYPES_COUNT =
static_cast<size_t>(ResourceType::LAST) + 1; static_cast<size_t>(ResourceType::LAST) + 1;
VC_ENUM_METADATA(ResourceType)
{"camera", ResourceType::CAMERA},
{"post-effect-slot", ResourceType::POST_EFFECT_SLOT},
VC_ENUM_END
+3 -6
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "../ContentLoader.hpp" #include "../ContentLoader.hpp"
#include <algorithm> #include <algorithm>
@@ -210,13 +211,9 @@ void ContentLoader::loadGenerator(
map.at("heights-bpd").get(def.heightsBPD); map.at("heights-bpd").get(def.heightsBPD);
std::string interpName; std::string interpName;
map.at("heights-interpolation").get(interpName); map.at("heights-interpolation").get(interpName);
if (auto interp = InterpolationType_from(interpName)) { InterpolationTypeMeta.getItem(interpName, def.heightsInterpolation);
def.heightsInterpolation = *interp;
}
map.at("biomes-interpolation").get(interpName); map.at("biomes-interpolation").get(interpName);
if (auto interp = InterpolationType_from(interpName)) { InterpolationTypeMeta.getItem(interpName, def.biomesInterpolation);
def.biomesInterpolation = *interp;
}
map.at("sea-level").get(def.seaLevel); map.at("sea-level").get(def.seaLevel);
map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius); map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius);
-1
View File
@@ -4,7 +4,6 @@
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#include <unordered_map> #include <unordered_map>
#include <optional>
#include "typedefs.hpp" #include "typedefs.hpp"
#include "interfaces/Serializable.hpp" #include "interfaces/Serializable.hpp"
+29
View File
@@ -0,0 +1,29 @@
#include "Editor.hpp"
#include "engine/Engine.hpp"
#include "io/engine_paths.hpp"
#include "coders/syntax_parser.hpp"
#include "SyntaxProcessor.hpp"
using namespace devtools;
Editor::Editor(Engine& engine)
: engine(engine), syntaxProcessor(std::make_unique<SyntaxProcessor>()) {
}
Editor::~Editor() = default;
void Editor::loadTools() {
const auto& paths = engine.getResPaths();
auto files = paths.listdir("devtools/syntax");
for (const auto& file : files) {
auto config = io::read_object(file);
auto syntax = std::make_unique<Syntax>();
syntax->deserialize(config);
syntaxProcessor->addSyntax(std::move(syntax));
}
}
SyntaxProcessor& Editor::getSyntaxProcessor() {
return *syntaxProcessor;
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <string>
#include <memory>
class Engine;
namespace devtools {
class SyntaxProcessor;
class Editor {
public:
Editor(Engine& engine);
~Editor();
void loadTools();
SyntaxProcessor& getSyntaxProcessor();
private:
Engine& engine;
std::unique_ptr<SyntaxProcessor> syntaxProcessor;
};
}
@@ -1,7 +1,7 @@
#include "syntax_highlighting.hpp" #include "SyntaxProcessor.hpp"
#include "coders/commons.hpp" #include "coders/commons.hpp"
#include "coders/lua_parsing.hpp" #include "coders/syntax_parser.hpp"
#include "graphics/core/Font.hpp" #include "graphics/core/Font.hpp"
using namespace devtools; using namespace devtools;
@@ -55,16 +55,28 @@ static std::unique_ptr<FontStylesScheme> build_styles(
return std::make_unique<FontStylesScheme>(std::move(styles)); return std::make_unique<FontStylesScheme>(std::move(styles));
} }
std::unique_ptr<FontStylesScheme> devtools::syntax_highlight( void SyntaxProcessor::addSyntax(
const std::string& lang, std::wstring_view source std::unique_ptr<Syntax> syntax
) { ) {
const auto ptr = syntax.get();
langs.emplace_back(std::move(syntax));
for (auto& ext : ptr->extensions) {
langsExtensions[ext] = ptr;
}
}
std::unique_ptr<FontStylesScheme> SyntaxProcessor::highlight(
const std::string& ext, std::wstring_view source
) const {
const auto& found = langsExtensions.find(ext);
if (found == langsExtensions.end()) {
return nullptr;
}
const auto& syntax = *found->second;
try { try {
if (lang == "lua") { auto tokens = tokenize(syntax, "<string>", source);
auto tokens = lua::tokenize("<string>", source); return build_styles(tokens);
return build_styles(tokens);
} else {
return nullptr;
}
} catch (const parsing_error& err) { } catch (const parsing_error& err) {
return nullptr; return nullptr;
} }
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include <set>
#include <string>
#include <memory>
#include <vector>
#include <unordered_map>
struct FontStylesScheme;
namespace devtools {
struct Syntax;
enum SyntaxStyles {
DEFAULT, KEYWORD, LITERAL, COMMENT, ERROR
};
class SyntaxProcessor {
public:
std::unique_ptr<FontStylesScheme> highlight(
const std::string& ext, std::wstring_view source
) const;
void addSyntax(std::unique_ptr<Syntax> syntax);
private:
std::vector<std::unique_ptr<Syntax>> langs;
std::unordered_map<std::string, const Syntax*> langsExtensions;
};
}
-16
View File
@@ -1,16 +0,0 @@
#pragma once
#include <string>
#include <memory>
struct FontStylesScheme;
namespace devtools {
enum SyntaxStyles {
DEFAULT, KEYWORD, LITERAL, COMMENT, ERROR
};
std::unique_ptr<FontStylesScheme> syntax_highlight(
const std::string& lang, std::wstring_view source
);
}
+3
View File
@@ -12,6 +12,7 @@
#include "coders/json.hpp" #include "coders/json.hpp"
#include "coders/toml.hpp" #include "coders/toml.hpp"
#include "coders/commons.hpp" #include "coders/commons.hpp"
#include "devtools/Editor.hpp"
#include "content/ContentControl.hpp" #include "content/ContentControl.hpp"
#include "core_defs.hpp" #include "core_defs.hpp"
#include "io/io.hpp" #include "io/io.hpp"
@@ -73,6 +74,7 @@ Engine& Engine::getInstance() {
void Engine::initialize(CoreParameters coreParameters) { void Engine::initialize(CoreParameters coreParameters) {
params = std::move(coreParameters); params = std::move(coreParameters);
settingsHandler = std::make_unique<SettingsHandler>(settings); settingsHandler = std::make_unique<SettingsHandler>(settings);
editor = std::make_unique<devtools::Editor>(*this);
cmd = std::make_unique<cmd::CommandsInterpreter>(); cmd = std::make_unique<cmd::CommandsInterpreter>();
network = network::Network::create(settings.network); network = network::Network::create(settings.network);
@@ -134,6 +136,7 @@ void Engine::initialize(CoreParameters coreParameters) {
); );
} }
content = std::make_unique<ContentControl>(paths, *input, [this]() { content = std::make_unique<ContentControl>(paths, *input, [this]() {
editor->loadTools();
langs::setup(langs::get_current(), paths.resPaths.collectRoots()); langs::setup(langs::get_current(), paths.resPaths.collectRoots());
if (!isHeadless()) { if (!isHeadless()) {
for (auto& pack : content->getAllContentPacks()) { for (auto& pack : content->getAllContentPacks()) {
+9
View File
@@ -33,6 +33,10 @@ namespace network {
class Network; class Network;
} }
namespace devtools {
class Editor;
}
class initialize_error : public std::runtime_error { class initialize_error : public std::runtime_error {
public: public:
initialize_error(const std::string& message) : std::runtime_error(message) {} initialize_error(const std::string& message) : std::runtime_error(message) {}
@@ -63,6 +67,7 @@ class Engine : public util::ObjectsKeeper {
std::unique_ptr<Window> window; std::unique_ptr<Window> window;
std::unique_ptr<Input> input; std::unique_ptr<Input> input;
std::unique_ptr<gui::GUI> gui; std::unique_ptr<gui::GUI> gui;
std::unique_ptr<devtools::Editor> editor;
PostRunnables postRunnables; PostRunnables postRunnables;
Time time; Time time;
OnWorldOpen levelConsumer; OnWorldOpen levelConsumer;
@@ -161,4 +166,8 @@ public:
cmd::CommandsInterpreter& getCmd() { cmd::CommandsInterpreter& getCmd() {
return *cmd; return *cmd;
} }
devtools::Editor& getEditor() {
return *editor;
}
}; };
+6 -7
View File
@@ -314,6 +314,7 @@ void Hud::updateWorldGenDebug() {
void Hud::update(bool visible) { void Hud::update(bool visible) {
const auto& chunks = *player.chunks; const auto& chunks = *player.chunks;
bool is_menu_open = menu.hasOpenPage();
debugPanel->setVisible( debugPanel->setVisible(
debug && visible && !(inventoryOpen && inventoryView == nullptr) debug && visible && !(inventoryOpen && inventoryView == nullptr)
@@ -322,13 +323,13 @@ void Hud::update(bool visible) {
if (!visible && inventoryOpen) { if (!visible && inventoryOpen) {
closeInventory(); closeInventory();
} }
if (pause && !menu.hasOpenPage()) { if (pause && !is_menu_open) {
setPause(false); setPause(false);
} }
if (!gui.isFocusCaught()) { if (!gui.isFocusCaught()) {
processInput(visible); processInput(visible);
} }
if ((menu.hasOpenPage() || inventoryOpen) == input.getCursor().locked) { if ((is_menu_open || inventoryOpen) == input.getCursor().locked) {
input.toggleCursor(); input.toggleCursor();
} }
@@ -349,6 +350,8 @@ void Hud::update(bool visible) {
contentAccessPanel->setSize(glm::vec2(caSize.x, windowSize.y)); contentAccessPanel->setSize(glm::vec2(caSize.x, windowSize.y));
contentAccess->setMinSize(glm::vec2(1, windowSize.y)); contentAccess->setMinSize(glm::vec2(1, windowSize.y));
hotbarView->setVisible(visible && !(secondUI && !inventoryView)); hotbarView->setVisible(visible && !(secondUI && !inventoryView));
darkOverlay->setVisible(is_menu_open);
menu.setVisible(is_menu_open);
if (visible) { if (visible) {
for (auto& element : elements) { for (auto& element : elements) {
@@ -360,7 +363,7 @@ void Hud::update(bool visible) {
} }
cleanup(); cleanup();
debugMinimap->setVisible(debug && showGeneratorMinimap); debugMinimap->setVisible(debug && showGeneratorMinimap && visible);
if (debug && showGeneratorMinimap) { if (debug && showGeneratorMinimap) {
updateWorldGenDebug(); updateWorldGenDebug();
} }
@@ -593,10 +596,6 @@ void Hud::setDebug(bool flag) {
void Hud::draw(const DrawContext& ctx){ void Hud::draw(const DrawContext& ctx){
const auto& viewport = ctx.getViewport(); const auto& viewport = ctx.getViewport();
bool is_menu_open = menu.hasOpenPage();
darkOverlay->setVisible(is_menu_open);
menu.setVisible(is_menu_open);
updateElementsPosition(viewport); updateElementsPosition(viewport);
uicamera->setFov(viewport.y); uicamera->setFov(viewport.y);
+9
View File
@@ -7,6 +7,7 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "data/dv_fwd.hpp" #include "data/dv_fwd.hpp"
#include "util/EnumMetadata.hpp"
class Shader; class Shader;
@@ -14,6 +15,14 @@ class PostEffect {
public: public:
struct Param { struct Param {
enum class Type { FLOAT, VEC2, VEC3, VEC4 }; enum class Type { FLOAT, VEC2, VEC3, VEC4 };
VC_ENUM_METADATA(Type)
{"float", Type::FLOAT},
{"vec2", Type::VEC2},
{"vec3", Type::VEC3},
{"vec4", Type::VEC4},
VC_ENUM_END
using Value = std::variant<float, glm::vec2, glm::vec3, glm::vec4>; using Value = std::variant<float, glm::vec2, glm::vec3, glm::vec4>;
Type type; Type type;
-39
View File
@@ -1,39 +0,0 @@
#include "commons.hpp"
#include <map>
std::optional<CursorShape> CursorShape_from(std::string_view name) {
static std::map<std::string_view, CursorShape> shapes = {
{"arrow", CursorShape::ARROW},
{"text", CursorShape::TEXT},
{"crosshair", CursorShape::CROSSHAIR},
{"pointer", CursorShape::POINTER},
{"ew-resize", CursorShape::EW_RESIZE},
{"ns-resize", CursorShape::NS_RESIZE},
{"nwse-resize", CursorShape::NWSE_RESIZE},
{"nesw-resize", CursorShape::NESW_RESIZE},
{"all-resize", CursorShape::ALL_RESIZE},
{"not-allowed", CursorShape::NOT_ALLOWED}
};
const auto& found = shapes.find(name);
if (found == shapes.end()) {
return std::nullopt;
}
return found->second;
}
std::string to_string(CursorShape shape) {
static std::string names[] = {
"arrow",
"text",
"crosshair",
"pointer",
"ew-resize",
"ns-resize",
"nwse-resize",
"nesw-resize",
"all-resize",
"not-allowed"
};
return names[static_cast<int>(shape)];
}
+14 -2
View File
@@ -3,6 +3,8 @@
#include <string> #include <string>
#include <optional> #include <optional>
#include "util/EnumMetadata.hpp"
enum class DrawPrimitive { enum class DrawPrimitive {
point = 0, point = 0,
line, line,
@@ -48,8 +50,18 @@ enum class CursorShape {
LAST=NOT_ALLOWED LAST=NOT_ALLOWED
}; };
std::optional<CursorShape> CursorShape_from(std::string_view name); VC_ENUM_METADATA(CursorShape)
std::string to_string(CursorShape shape); {"arrow", CursorShape::ARROW},
{"text", CursorShape::TEXT},
{"crosshair", CursorShape::CROSSHAIR},
{"pointer", CursorShape::POINTER},
{"ew-resize", CursorShape::EW_RESIZE},
{"ns-resize", CursorShape::NS_RESIZE},
{"nwse-resize", CursorShape::NWSE_RESIZE},
{"nesw-resize", CursorShape::NESW_RESIZE},
{"all-resize", CursorShape::ALL_RESIZE},
{"not-allowed", CursorShape::NOT_ALLOWED},
VC_ENUM_END
class Flushable { class Flushable {
public: public:
+4
View File
@@ -364,3 +364,7 @@ Input& GUI::getInput() {
Window& GUI::getWindow() { Window& GUI::getWindow() {
return engine.getWindow(); return engine.getWindow();
} }
devtools::Editor& GUI::getEditor() {
return engine.getEditor();
}
+5
View File
@@ -18,6 +18,10 @@ class Engine;
class Input; class Input;
class Window; class Window;
namespace devtools {
class Editor;
}
/* /*
Some info about padding and margin. Some info about padding and margin.
Padding is element inner space, margin is outer Padding is element inner space, margin is outer
@@ -159,5 +163,6 @@ namespace gui {
const Input& getInput() const; const Input& getInput() const;
Input& getInput(); Input& getInput();
Window& getWindow(); Window& getWindow();
devtools::Editor& getEditor();
}; };
} }
+4 -2
View File
@@ -8,7 +8,8 @@
#include "../markdown.hpp" #include "../markdown.hpp"
#include "Label.hpp" #include "Label.hpp"
#include "assets/Assets.hpp" #include "assets/Assets.hpp"
#include "devtools/syntax_highlighting.hpp" #include "devtools/Editor.hpp"
#include "devtools/SyntaxProcessor.hpp"
#include "engine/Engine.hpp" #include "engine/Engine.hpp"
#include "graphics/core/Batch2D.hpp" #include "graphics/core/Batch2D.hpp"
#include "graphics/core/DrawContext.hpp" #include "graphics/core/DrawContext.hpp"
@@ -811,7 +812,8 @@ void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) {
void TextBox::refreshSyntax() { void TextBox::refreshSyntax() {
if (!syntax.empty()) { if (!syntax.empty()) {
if (auto styles = devtools::syntax_highlight(syntax, input)) { const auto& processor = gui.getEditor().getSyntaxProcessor();
if (auto styles = processor.highlight(syntax, input)) {
label->setStyles(std::move(styles)); label->setStyles(std::move(styles));
} }
} }
+4 -2
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "gui_xml.hpp" #include "gui_xml.hpp"
#include <stdexcept> #include <stdexcept>
@@ -168,8 +169,9 @@ static void read_uinode(
node.setTooltipDelay(element.attr("tooltip-delay").asFloat()); node.setTooltipDelay(element.attr("tooltip-delay").asFloat());
} }
if (element.has("cursor")) { if (element.has("cursor")) {
if (auto cursor = CursorShape_from(element.attr("cursor").getText())) { CursorShape cursor;
node.setCursor(*cursor); if (CursorShapeMeta.getItem(element.attr("cursor").getText(), cursor)) {
node.setCursor(cursor);
} }
} }
+4 -2
View File
@@ -35,12 +35,14 @@ void ChunksController::update(
int64_t maxDuration, int loadDistance, uint padding, Player& player int64_t maxDuration, int loadDistance, uint padding, Player& player
) const { ) const {
const auto& position = player.getPosition(); const auto& position = player.getPosition();
int centerX = floordiv<CHUNK_W>(position.x); int centerX = floordiv<CHUNK_W>(glm::floor(position.x));
int centerY = floordiv<CHUNK_D>(position.z); int centerY = floordiv<CHUNK_D>(glm::floor(position.z));
if (player.isLoadingChunks()) { if (player.isLoadingChunks()) {
/// FIXME: one generator for multiple players /// FIXME: one generator for multiple players
generator->update(centerX, centerY, loadDistance); generator->update(centerX, centerY, loadDistance);
} else {
return;
} }
int64_t mcstotal = 0; int64_t mcstotal = 0;
+2 -1
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "EngineController.hpp" #include "EngineController.hpp"
#include <algorithm> #include <algorithm>
@@ -164,7 +165,7 @@ static dv::value create_missing_content_report(
auto root = dv::object(); auto root = dv::object();
auto& contentEntries = root.list("content"); auto& contentEntries = root.list("content");
for (auto& entry : report->getMissingContent()) { for (auto& entry : report->getMissingContent()) {
std::string contentName = ContentType_name(entry.type); std::string contentName = ContentTypeMeta.getNameString(entry.type);
auto& contentEntry = contentEntries.object(); auto& contentEntry = contentEntries.object();
contentEntry["type"] = contentName; contentEntry["type"] = contentName;
contentEntry["name"] = entry.name; contentEntry["name"] = entry.name;
+2 -2
View File
@@ -77,8 +77,8 @@ void LevelController::update(float delta, bool pause) {
player->updateEntity(); player->updateEntity();
glm::vec3 position = player->getPosition(); glm::vec3 position = player->getPosition();
player->chunks->configure( player->chunks->configure(
position.x, glm::floor(position.x),
position.z, glm::floor(position.z),
settings.chunks.loadDistance.get() + settings.chunks.padding.get() settings.chunks.loadDistance.get() + settings.chunks.padding.get()
); );
chunks->update( chunks->update(
@@ -1,3 +1,5 @@
#define VC_ENABLE_REFLECTION
#include "util/stringutil.hpp" #include "util/stringutil.hpp"
#include "libentity.hpp" #include "libentity.hpp"
@@ -96,8 +98,8 @@ static int l_set_crouching(lua::State* L) {
static int l_get_body_type(lua::State* L) { static int l_get_body_type(lua::State* L) {
if (auto entity = get_entity(L, 1)) { if (auto entity = get_entity(L, 1)) {
return lua::pushstring( return lua::pushlstring(
L, to_string(entity->getRigidbody().hitbox.type) L, BodyTypeMeta.getName(entity->getRigidbody().hitbox.type)
); );
} }
return 0; return 0;
@@ -105,9 +107,9 @@ static int l_get_body_type(lua::State* L) {
static int l_set_body_type(lua::State* L) { static int l_set_body_type(lua::State* L) {
if (auto entity = get_entity(L, 1)) { if (auto entity = get_entity(L, 1)) {
if (auto type = BodyType_from(lua::tostring(L, 2))) { if (!BodyTypeMeta.getItem(
entity->getRigidbody().hitbox.type = *type; lua::tostring(L, 2), entity->getRigidbody().hitbox.type
} else { )) {
throw std::runtime_error( throw std::runtime_error(
"unknown body type " + util::quote(lua::tostring(L, 2)) "unknown body type " + util::quote(lua::tostring(L, 2))
); );
+9 -12
View File
@@ -16,14 +16,14 @@ static int l_encode(lua::State* L) {
return lua::pushstring(L, util::base64_encode( return lua::pushstring(L, util::base64_encode(
reinterpret_cast<const ubyte*>(buffer.data()), buffer.size() reinterpret_cast<const ubyte*>(buffer.data()), buffer.size()
)); ));
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 1)) { } else {
return lua::pushstring( auto string = lua::bytearray_as_string(L, 1);
L, auto out = util::base64_encode(
util::base64_encode( reinterpret_cast<const ubyte*>(string.data()),
bytes->data().data(), string.size()
bytes->data().size()
)
); );
lua::pop(L);
return lua::pushstring(L, std::move(out));
} }
throw std::runtime_error("array or ByteArray expected"); throw std::runtime_error("array or ByteArray expected");
} }
@@ -36,13 +36,10 @@ static int l_decode(lua::State* L) {
lua::pushinteger(L, buffer[i] & 0xFF); lua::pushinteger(L, buffer[i] & 0xFF);
lua::rawseti(L, i+1); lua::rawseti(L, i+1);
} }
return 1;
} else { } else {
lua::newuserdata<lua::LuaBytearray>(L, buffer.size()); return lua::create_bytearray(L, buffer.data(), buffer.size());
auto bytearray = lua::touserdata<lua::LuaBytearray>(L, -1);
bytearray->data().reserve(buffer.size());
std::memcpy(bytearray->data().data(), buffer.data(), buffer.size());
} }
return 1;
} }
const luaL_Reg base64lib[] = { const luaL_Reg base64lib[] = {
+9 -10
View File
@@ -9,9 +9,7 @@ static int l_tobytes(lua::State* L) {
if (lua::gettop(L) >= 2) { if (lua::gettop(L) >= 2) {
compress = lua::toboolean(L, 2); compress = lua::toboolean(L, 2);
} }
return lua::newuserdata<lua::LuaBytearray>( return lua::create_bytearray(L, json::to_binary(value, compress));
L, json::to_binary(value, compress)
);
} }
static int l_frombytes(lua::State* L) { static int l_frombytes(lua::State* L) {
@@ -24,17 +22,18 @@ static int l_frombytes(lua::State* L) {
lua::pop(L); lua::pop(L);
} }
return lua::pushvalue(L, json::from_binary(buffer.data(), len)); return lua::pushvalue(L, json::from_binary(buffer.data(), len));
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, -1)) {
const auto& buffer = bytes->data();
return lua::pushvalue(
L, json::from_binary(buffer.data(), buffer.size())
);
} else { } else {
throw std::runtime_error("table or Bytearray expected"); auto string = lua::bytearray_as_string(L, 1);
auto out = json::from_binary(
reinterpret_cast<const ubyte*>(string.data()), string.size()
);
lua::pop(L);
return lua::pushvalue(L, std::move(out));
} }
} }
const luaL_Reg bjsonlib[] = { const luaL_Reg bjsonlib[] = {
{"tobytes", lua::wrap<l_tobytes>}, {"tobytes", lua::wrap<l_tobytes>},
{"frombytes", lua::wrap<l_frombytes>}, {"frombytes", lua::wrap<l_frombytes>},
{NULL, NULL}}; {NULL, NULL}
};
+2 -1
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "content/Content.hpp" #include "content/Content.hpp"
#include "content/ContentLoader.hpp" #include "content/ContentLoader.hpp"
#include "content/ContentControl.hpp" #include "content/ContentControl.hpp"
@@ -311,7 +312,7 @@ static int l_get_textures(lua::State* L) {
static int l_get_model(lua::State* L) { static int l_get_model(lua::State* L) {
if (auto def = require_block(L)) { if (auto def = require_block(L)) {
return lua::pushstring(L, to_string(def->model)); return lua::pushlstring(L, BlockModelMeta.getName(def->model));
} }
return 0; return 0;
} }
+3 -3
View File
@@ -99,7 +99,7 @@ static int pack(lua::State* L, const char* format, bool usetable) {
} }
return 1; return 1;
} else { } else {
return lua::newuserdata<lua::LuaBytearray>(L, builder.build()); return lua::create_bytearray(L, builder.build());
} }
} }
@@ -130,8 +130,8 @@ static int count_elements(const char* format) {
static int l_unpack(lua::State* L) { static int l_unpack(lua::State* L) {
const char* format = lua::require_string(L, 1); const char* format = lua::require_string(L, 1);
int count = count_elements(format); int count = count_elements(format);
auto bytes = lua::require_bytearray(L, 2); auto bytes = lua::bytearray_as_string(L, 2);
ByteReader reader(bytes); ByteReader reader(reinterpret_cast<const ubyte*>(bytes.data()), bytes.size());
bool bigEndian = false; bool bigEndian = false;
for (size_t i = 0; format[i]; i++) { for (size_t i = 0; format[i]; i++) {
+5 -3
View File
@@ -248,12 +248,14 @@ static int l_load_texture(lua::State* L) {
} }
lua::pop(L); lua::pop(L);
load_texture(buffer.data(), buffer.size(), lua::require_string(L, 2)); load_texture(buffer.data(), buffer.size(), lua::require_string(L, 2));
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 1)) { } else {
auto string = lua::bytearray_as_string(L, 1);
load_texture( load_texture(
bytes->data().data(), reinterpret_cast<const ubyte*>(string.data()),
bytes->data().size(), string.size(),
lua::require_string(L, 2) lua::require_string(L, 2)
); );
lua::pop(L);
} }
return 0; return 0;
} }
+6 -12
View File
@@ -128,7 +128,7 @@ static int l_read_bytes(lua::State* L) {
auto bytes = io::read_bytes(path); auto bytes = io::read_bytes(path);
if (lua::gettop(L) < 2 || !lua::toboolean(L, 2)) { if (lua::gettop(L) < 2 || !lua::toboolean(L, 2)) {
lua::newuserdata<lua::LuaBytearray>(L, std::move(bytes)); lua::create_bytearray(L, std::move(bytes));
} else { } else {
lua::createtable(L, length, 0); lua::createtable(L, length, 0);
int newTable = lua::gettop(L); int newTable = lua::gettop(L);
@@ -148,18 +148,12 @@ static int l_read_bytes(lua::State* L) {
static int l_write_bytes(lua::State* L) { static int l_write_bytes(lua::State* L) {
io::path path = get_writeable_path(L); io::path path = get_writeable_path(L);
if (auto bytearray = lua::touserdata<lua::LuaBytearray>(L, 2)) { auto string = lua::bytearray_as_string(L, 2);
auto& bytes = bytearray->data(); bool res = io::write_bytes(
return lua::pushboolean( path, reinterpret_cast<const ubyte*>(string.data()), string.size()
L, io::write_bytes(path, bytes.data(), bytes.size())
);
}
std::vector<ubyte> bytes;
lua::read_bytes_from_table(L, 2, bytes);
return lua::pushboolean(
L, io::write_bytes(path, bytes.data(), bytes.size())
); );
lua::pop(L);
return lua::pushboolean(L, res);
} }
static int l_list_all_res(lua::State* L, const std::string& path) { static int l_list_all_res(lua::State* L, const std::string& path) {
+5 -4
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "libgui.hpp" #include "libgui.hpp"
#include "assets/Assets.hpp" #include "assets/Assets.hpp"
#include "engine/Engine.hpp" #include "engine/Engine.hpp"
@@ -422,7 +423,7 @@ static int p_get_line_pos(UINode*, lua::State* L) {
} }
static int p_get_cursor(UINode* node, lua::State* L) { static int p_get_cursor(UINode* node, lua::State* L) {
return lua::pushstring(L, to_string(node->getCursor())); return lua::pushlstring(L, CursorShapeMeta.getName(node->getCursor()));
} }
static int p_get_scroll(UINode* node, lua::State* L) { static int p_get_scroll(UINode* node, lua::State* L) {
@@ -660,9 +661,9 @@ static void p_set_focused(
} }
static void p_set_cursor(UINode* node, lua::State* L, int idx) { static void p_set_cursor(UINode* node, lua::State* L, int idx) {
if (auto cursor = CursorShape_from(lua::require_string(L, idx))) { auto cursor = CursorShape::ARROW; // reset to default
node->setCursor(*cursor); CursorShapeMeta.getItem(lua::require_string(L, idx), cursor);
} node->setCursor(cursor);
} }
static int p_set_scroll(UINode* node, lua::State* L, int idx) { static int p_set_scroll(UINode* node, lua::State* L, int idx) {
+6 -9
View File
@@ -109,13 +109,13 @@ static int l_send(lua::State* L, network::Network& network) {
} }
lua::pop(L); lua::pop(L);
connection->send(buffer.data(), size); connection->send(buffer.data(), size);
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 2)) {
connection->send(
reinterpret_cast<char*>(bytes->data().data()), bytes->data().size()
);
} else if (lua::isstring(L, 2)) { } else if (lua::isstring(L, 2)) {
auto string = lua::tolstring(L, 2); auto string = lua::tolstring(L, 2);
connection->send(string.data(), string.length()); connection->send(string.data(), string.length());
} else {
auto string = lua::bytearray_as_string(L, 2);
connection->send(string.data(), string.length());
lua::pop(L);
} }
return 0; return 0;
} }
@@ -140,13 +140,10 @@ static int l_recv(lua::State* L, network::Network& network) {
lua::pushinteger(L, buffer[i] & 0xFF); lua::pushinteger(L, buffer[i] & 0xFF);
lua::rawseti(L, i+1); lua::rawseti(L, i+1);
} }
return 1;
} else { } else {
lua::newuserdata<lua::LuaBytearray>(L, size); return lua::create_bytearray(L, buffer.data(), size);
auto bytearray = lua::touserdata<lua::LuaBytearray>(L, -1);
bytearray->data().reserve(size);
std::memcpy(bytearray->data().data(), buffer.data(), size);
} }
return 1;
} }
static int l_available(lua::State* L, network::Network& network) { static int l_available(lua::State* L, network::Network& network) {
+5 -14
View File
@@ -14,13 +14,10 @@ static int l_tobytes(lua::State* L) {
lua::pushinteger(L, string[i] & 0xFF); lua::pushinteger(L, string[i] & 0xFF);
lua::rawseti(L, i+1); lua::rawseti(L, i+1);
} }
return 1;
} else { } else {
lua::newuserdata<lua::LuaBytearray>(L, string.length()); return lua::create_bytearray(L, string.data(), string.length());
auto bytearray = lua::touserdata<lua::LuaBytearray>(L, -1);
bytearray->data().reserve(string.length());
std::memcpy(bytearray->data().data(), string.data(), string.length());
} }
return 1;
} }
static int l_tostring(lua::State* L) { static int l_tostring(lua::State* L) {
@@ -35,16 +32,10 @@ static int l_tostring(lua::State* L) {
} }
lua::pop(L); lua::pop(L);
return lua::pushlstring(L, buffer.data(), size); return lua::pushlstring(L, buffer.data(), size);
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 1)) { } else {
return lua::pushstring( lua::bytearray_as_string(L, 1);
L, return 1;
std::string(
reinterpret_cast<char*>(bytes->data().data()),
bytes->data().size()
)
);
} }
return 1;
} }
static int l_length(lua::State* L) { static int l_length(lua::State* L) {
+14 -5
View File
@@ -144,7 +144,7 @@ static int l_get_chunk_data(lua::State* L) {
} else { } else {
chunkData = compressed_chunks::encode(*chunk); chunkData = compressed_chunks::encode(*chunk);
} }
return lua::newuserdata<lua::LuaBytearray>(L, std::move(chunkData)); return lua::create_bytearray(L, std::move(chunkData));
} }
static void integrate_chunk_client(Chunk& chunk) { static void integrate_chunk_client(Chunk& chunk) {
@@ -175,14 +175,17 @@ static int l_set_chunk_data(lua::State* L) {
int x = static_cast<int>(lua::tointeger(L, 1)); int x = static_cast<int>(lua::tointeger(L, 1));
int z = static_cast<int>(lua::tointeger(L, 2)); int z = static_cast<int>(lua::tointeger(L, 2));
auto buffer = lua::require_bytearray(L, 3); auto buffer = lua::bytearray_as_string(L, 3);
auto chunk = level->chunks->getChunk(x, z); auto chunk = level->chunks->getChunk(x, z);
if (chunk == nullptr) { if (chunk == nullptr) {
return lua::pushboolean(L, false); return lua::pushboolean(L, false);
} }
compressed_chunks::decode( compressed_chunks::decode(
*chunk, buffer.data(), buffer.size(), *content->getIndices() *chunk,
reinterpret_cast<const ubyte*>(buffer.data()),
buffer.size(),
*content->getIndices()
); );
if (controller->getChunksController()->lighting == nullptr) { if (controller->getChunksController()->lighting == nullptr) {
return lua::pushboolean(L, true); return lua::pushboolean(L, true);
@@ -198,10 +201,16 @@ static int l_save_chunk_data(lua::State* L) {
int x = static_cast<int>(lua::tointeger(L, 1)); int x = static_cast<int>(lua::tointeger(L, 1));
int z = static_cast<int>(lua::tointeger(L, 2)); int z = static_cast<int>(lua::tointeger(L, 2));
auto buffer = lua::require_bytearray(L, 3); auto buffer = lua::bytearray_as_string(L, 3);
compressed_chunks::save( compressed_chunks::save(
x, z, std::move(buffer), level->getWorld()->wfile->getRegions() x,
z,
std::vector(
reinterpret_cast<const ubyte*>(buffer.data()),
reinterpret_cast<const ubyte*>(buffer.data()) + buffer.size()
),
level->getWorld()->wfile->getRegions()
); );
return 0; return 0;
} }
@@ -18,26 +18,6 @@ namespace lua {
virtual const std::string& getTypeName() const = 0; virtual const std::string& getTypeName() const = 0;
}; };
class LuaBytearray : public Userdata {
std::vector<ubyte> buffer;
public:
LuaBytearray(size_t capacity);
LuaBytearray(std::vector<ubyte> buffer);
LuaBytearray(const ubyte* data, size_t size);
virtual ~LuaBytearray();
const std::string& getTypeName() const override {
return TYPENAME;
}
inline std::vector<ubyte>& data() {
return buffer;
}
static int createMetatable(lua::State*);
inline static std::string TYPENAME = "Bytearray";
};
static_assert(!std::is_abstract<LuaBytearray>());
class LuaHeightmap : public Userdata { class LuaHeightmap : public Userdata {
std::shared_ptr<Heightmap> map; std::shared_ptr<Heightmap> map;
std::unique_ptr<fnl_state> noise; std::unique_ptr<fnl_state> noise;
-1
View File
@@ -117,7 +117,6 @@ void lua::init_state(State* L, StateType stateType) {
initialize_libs_extends(L); initialize_libs_extends(L);
newusertype<LuaBytearray>(L);
newusertype<LuaHeightmap>(L); newusertype<LuaHeightmap>(L);
newusertype<LuaVoxelFragment>(L); newusertype<LuaVoxelFragment>(L);
newusertype<LuaCanvas>(L); newusertype<LuaCanvas>(L);
+6 -4
View File
@@ -39,14 +39,16 @@ int l_crc32(lua::State* L) {
string.length() string.length()
) )
); );
} else if (auto bytearray = lua::touserdata<lua::LuaBytearray>(L, 1)) {
auto& bytes = bytearray->data();
return lua::pushinteger(L, crc32(value, bytes.data(), bytes.size()));
} else if (lua::istable(L, 1)) { } else if (lua::istable(L, 1)) {
std::vector<ubyte> bytes; std::vector<ubyte> bytes;
lua::read_bytes_from_table(L, 1, bytes); lua::read_bytes_from_table(L, 1, bytes);
return lua::pushinteger(L, crc32(value, bytes.data(), bytes.size())); return lua::pushinteger(L, crc32(value, bytes.data(), bytes.size()));
} else { } else {
throw std::runtime_error("invalid argument 1"); auto string = lua::bytearray_as_string(L, 1);
auto res = crc32(
value, reinterpret_cast<const ubyte*>(string.data()), string.size()
);
lua::pop(L);
return lua::pushinteger(L, res);
} }
} }
+8 -12
View File
@@ -61,7 +61,7 @@ int lua::pushvalue(State* L, const dv::value& value) {
break; break;
case value_type::bytes: { case value_type::bytes: {
const auto& bytes = value.asBytes(); const auto& bytes = value.asBytes();
newuserdata<LuaBytearray>(L, bytes.data(), bytes.size()); create_bytearray(L, bytes.data(), bytes.size());
break; break;
} }
} }
@@ -128,18 +128,14 @@ dv::value lua::tovalue(State* L, int idx) {
return map; return map;
} }
} }
case LUA_TUSERDATA: { default: {
if (auto bytes = touserdata<LuaBytearray>(L, idx)) { auto data = bytearray_as_string(L, idx);
const auto& data = bytes->data(); auto bytes = std::make_shared<dv::objects::Bytes>(
return std::make_shared<dv::objects::Bytes>(data.data(), data.size()); reinterpret_cast<const ubyte*>(data.data()), data.size()
}
[[fallthrough]];
}
default:
throw std::runtime_error(
"lua type " + std::string(lua_typename(L, type)) +
" is not supported"
); );
pop(L);
return bytes;
}
} }
} }
+17 -9
View File
@@ -746,14 +746,22 @@ namespace lua {
} }
} }
inline std::vector<ubyte> require_bytearray(lua::State* L, int idx) { inline int create_bytearray(lua::State* L, const void* bytes, size_t size) {
if (auto* bytearray = lua::touserdata<LuaBytearray>(L, idx)) { lua::requireglobal(L, "Bytearray_construct");
return bytearray->data(); lua::pushlstring(
} else if (lua::istable(L, idx)) { L, std::string_view(reinterpret_cast<const char*>(bytes), size)
std::vector<ubyte> bytes; );
read_bytes_from_table(L, idx, bytes); return lua::call(L, 1, 1);
return bytes; }
}
throw std::runtime_error("bytearray expected"); inline int create_bytearray(lua::State* L, const std::vector<ubyte>& bytes) {
return create_bytearray(L, bytes.data(), bytes.size());
}
inline std::string_view bytearray_as_string(lua::State* L, int idx) {
lua::requireglobal(L, "Bytearray_as_string");
lua::pushvalue(L, idx);
lua::call(L, 1, 1);
return lua::tolstring(L, -1);
} }
} }
@@ -1,206 +0,0 @@
#include "../lua_custom_types.hpp"
#include <sstream>
#include "util/listutil.hpp"
#include "../lua_util.hpp"
using namespace lua;
LuaBytearray::LuaBytearray(size_t capacity) : buffer(capacity) {
buffer.resize(capacity);
}
LuaBytearray::LuaBytearray(std::vector<ubyte> buffer) : buffer(std::move(buffer)) {
}
LuaBytearray::LuaBytearray(const ubyte* data, size_t size) : buffer(data, data + size) {
}
LuaBytearray::~LuaBytearray() {
}
static int l_append(lua::State* L) {
if (auto buffer = touserdata<LuaBytearray>(L, 1)) {
if (lua::isnumber(L, 2)) {
auto value = tointeger(L, 2);
buffer->data().push_back(static_cast<ubyte>(value));
} else if (lua::istable(L, 2)) {
lua::read_bytes_from_table(L, 2, buffer->data());
} else if (auto extension = lua::touserdata<LuaBytearray>(L, 2)) {
util::concat(buffer->data(), extension->data());
} else {
throw std::runtime_error("integer/table/Bytearray expected");
}
}
return 0;
}
static int l_insert(lua::State* L) {
auto buffer = touserdata<LuaBytearray>(L, 1);
if (buffer == nullptr) {
return 0;
}
auto& data = buffer->data();
auto index = tointeger(L, 2) - 1;
if (static_cast<size_t>(index) > data.size()) {
return 0;
}
if (lua::isnumber(L, 3)) {
auto value = tointeger(L, 3);
data.insert(data.begin() + index, static_cast<ubyte>(value));
} else if (lua::istable(L, 3)) {
std::vector<ubyte> temp;
lua::read_bytes_from_table(L, 3, temp);
data.insert(data.begin() + index, temp.begin(), temp.end());
} else if (auto extension = lua::touserdata<LuaBytearray>(L, 3)) {
const std::vector<ubyte>& src = extension->data();
data.insert(data.begin() + index, src.begin(), src.end());
} else {
throw std::runtime_error("integer/table/Bytearray expected");
}
return 0;
}
static int l_remove(lua::State* L) {
auto buffer = touserdata<LuaBytearray>(L, 1);
if (buffer == nullptr) {
return 0;
}
auto& data = buffer->data();
auto index = tointeger(L, 2) - 1;
if (static_cast<size_t>(index) > data.size()) {
return 0;
}
data.erase(data.begin() + index);
return 0;
}
static std::unordered_map<std::string, lua_CFunction> methods {
{"append", lua::wrap<l_append>},
{"insert", lua::wrap<l_insert>},
{"remove", lua::wrap<l_remove>},
};
static int l_meta_meta_call(lua::State* L) {
if (lua_istable(L, 2)) {
size_t len = objlen(L, 2);
std::vector<ubyte> buffer(len);
buffer.resize(len);
for (size_t i = 0; i < len; i++) {
rawgeti(L, i + 1);
buffer[i] = static_cast<ubyte>(tointeger(L, -1));
pop(L);
}
return newuserdata<LuaBytearray>(L, std::move(buffer));
}
auto size = tointeger(L, 2);
if (size < 0) {
throw std::runtime_error("size can not be less than 0");
}
return newuserdata<LuaBytearray>(L, static_cast<size_t>(size));
}
static int l_meta_index(lua::State* L) {
auto buffer = touserdata<LuaBytearray>(L, 1);
if (buffer == nullptr) {
return 0;
}
auto& data = buffer->data();
if (isstring(L, 2)) {
auto found = methods.find(tostring(L, 2));
if (found != methods.end()) {
return pushcfunction(L, found->second);
}
}
auto index = tointeger(L, 2) - 1;
if (static_cast<size_t>(index) > data.size()) {
return 0;
}
return pushinteger(L, data.at(index));
}
static int l_meta_newindex(lua::State* L) {
auto buffer = touserdata<LuaBytearray>(L, 1);
if (buffer == nullptr) {
return 0;
}
auto& data = buffer->data();
auto index = static_cast<size_t>(tointeger(L, 2) - 1);
auto value = tointeger(L, 3);
if (index >= data.size()) {
if (index == data.size()) {
data.push_back(static_cast<ubyte>(value));
}
return 0;
}
data[index] = static_cast<ubyte>(value);
return 0;
}
static int l_meta_len(lua::State* L) {
if (auto buffer = touserdata<LuaBytearray>(L, 1)) {
return pushinteger(L, buffer->data().size());
}
return 0;
}
static int l_meta_tostring(lua::State* L) {
auto buffer = touserdata<LuaBytearray>(L, 1);
if (buffer == nullptr) {
return 0;
}
auto& data = buffer->data();
if (data.size() > 512) {
return pushstring(
L, "bytearray[" + std::to_string(data.size()) + "]{...}"
);
} else {
std::stringstream ss;
ss << "bytearray[" << std::to_string(data.size()) << "]{";
for (size_t i = 0; i < data.size(); i++) {
if (i > 0) {
ss << " ";
}
ss << static_cast<uint>(data[i]);
}
ss << "}";
return pushstring(L, ss.str());
}
}
static int l_meta_add(lua::State* L) {
auto bufferA = touserdata<LuaBytearray>(L, 1);
auto bufferB = touserdata<LuaBytearray>(L, 2);
if (bufferA == nullptr || bufferB == nullptr) {
return 0;
}
auto& dataA = bufferA->data();
auto& dataB = bufferB->data();
std::vector<ubyte> ab;
ab.reserve(dataA.size() + dataB.size());
ab.insert(ab.end(), dataA.begin(), dataA.end());
ab.insert(ab.end(), dataB.begin(), dataB.end());
return newuserdata<LuaBytearray>(L, std::move(ab));
}
int LuaBytearray::createMetatable(lua::State* L) {
createtable(L, 0, 6);
pushcfunction(L, lua::wrap<l_meta_index>);
setfield(L, "__index");
pushcfunction(L, lua::wrap<l_meta_newindex>);
setfield(L, "__newindex");
pushcfunction(L, lua::wrap<l_meta_len>);
setfield(L, "__len");
pushcfunction(L, lua::wrap<l_meta_tostring>);
setfield(L, "__tostring");
pushcfunction(L, lua::wrap<l_meta_add>);
setfield(L, "__add");
createtable(L, 0, 1);
pushcfunction(L, lua::wrap<l_meta_meta_call>);
setfield(L, "__call");
setmetatable(L);
return 1;
}
-11
View File
@@ -5,17 +5,6 @@
#include <stdexcept> #include <stdexcept>
#include <glm/glm.hpp> #include <glm/glm.hpp>
std::optional<InterpolationType> InterpolationType_from(std::string_view str) {
if (str == "nearest") {
return InterpolationType::NEAREST;
} else if (str == "linear") {
return InterpolationType::LINEAR;
} else if (str == "cubic") {
return InterpolationType::CUBIC;
}
return std::nullopt;
}
static inline float sample_at( static inline float sample_at(
const float* buffer, const float* buffer,
uint width, uint width,
+6 -1
View File
@@ -6,6 +6,7 @@
#include "typedefs.hpp" #include "typedefs.hpp"
#include "maths/Heightmap.hpp" #include "maths/Heightmap.hpp"
#include "util/EnumMetadata.hpp"
enum class InterpolationType { enum class InterpolationType {
NEAREST, NEAREST,
@@ -13,7 +14,11 @@ enum class InterpolationType {
CUBIC, CUBIC,
}; };
std::optional<InterpolationType> InterpolationType_from(std::string_view str); VC_ENUM_METADATA(InterpolationType)
{"nearest", InterpolationType::NEAREST},
{"linear", InterpolationType::LINEAR},
{"cubic", InterpolationType::CUBIC},
VC_ENUM_END
class Heightmap { class Heightmap {
uint width, height; uint width, height;
+3 -4
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "Entities.hpp" #include "Entities.hpp"
#include <glm/ext/matrix_transform.hpp> #include <glm/ext/matrix_transform.hpp>
@@ -216,9 +217,7 @@ void Entities::loadEntity(const dv::value& map, Entity entity) {
dv::get_vec(bodymap, "vel", body.hitbox.velocity); dv::get_vec(bodymap, "vel", body.hitbox.velocity);
std::string bodyTypeName; std::string bodyTypeName;
map.at("type").get(bodyTypeName); map.at("type").get(bodyTypeName);
if (auto bodyType = BodyType_from(bodyTypeName)) { BodyTypeMeta.getItem(bodyTypeName, body.hitbox.type);
body.hitbox.type = *bodyType;
}
bodymap["crouch"].asBoolean(body.hitbox.crouching); bodymap["crouch"].asBoolean(body.hitbox.crouching);
bodymap["damping"].asNumber(body.hitbox.linearDamping); bodymap["damping"].asNumber(body.hitbox.linearDamping);
} }
@@ -329,7 +328,7 @@ dv::value Entities::serialize(const Entity& entity) {
if (def.save.body.settings) { if (def.save.body.settings) {
bodymap["damping"] = rigidbody.hitbox.linearDamping; bodymap["damping"] = rigidbody.hitbox.linearDamping;
if (hitbox.type != def.bodyType) { if (hitbox.type != def.bodyType) {
bodymap["type"] = to_string(hitbox.type); bodymap["type"] = BodyTypeMeta.getNameString(hitbox.type);
} }
if (hitbox.crouching) { if (hitbox.crouching) {
bodymap["crouch"] = hitbox.crouching; bodymap["crouch"] = hitbox.crouching;
-1
View File
@@ -2,7 +2,6 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <memory> #include <memory>
#include <optional>
#include "interfaces/Serializable.hpp" #include "interfaces/Serializable.hpp"
#include "settings.hpp" #include "settings.hpp"
-20
View File
@@ -2,26 +2,6 @@
#include <stdexcept> #include <stdexcept>
std::optional<BodyType> BodyType_from(std::string_view str) {
if (str == "kinematic") {
return BodyType::KINEMATIC;
} else if (str == "dynamic") {
return BodyType::DYNAMIC;
} else if (str == "static") {
return BodyType::STATIC;
}
return std::nullopt;
}
std::string to_string(BodyType type) {
switch (type) {
case BodyType::KINEMATIC: return "kinematic";
case BodyType::DYNAMIC: return "dynamic";
case BodyType::STATIC: return "static";
default: return "unknown";
}
}
Hitbox::Hitbox(BodyType type, glm::vec3 position, glm::vec3 halfsize) Hitbox::Hitbox(BodyType type, glm::vec3 position, glm::vec3 halfsize)
: type(type), : type(type),
position(position), position(position),
+6 -3
View File
@@ -2,10 +2,10 @@
#include "maths/aabb.hpp" #include "maths/aabb.hpp"
#include "typedefs.hpp" #include "typedefs.hpp"
#include "util/EnumMetadata.hpp"
#include <set> #include <set>
#include <string> #include <string>
#include <optional>
#include <functional> #include <functional>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@@ -41,8 +41,11 @@ enum class BodyType {
STATIC, KINEMATIC, DYNAMIC STATIC, KINEMATIC, DYNAMIC
}; };
std::optional<BodyType> BodyType_from(std::string_view str); VC_ENUM_METADATA(BodyType)
std::string to_string(BodyType type); {"static", BodyType::STATIC},
{"kinematic", BodyType::KINEMATIC},
{"dynamic", BodyType::DYNAMIC},
VC_ENUM_END
struct Hitbox { struct Hitbox {
BodyType type; BodyType type;
+5 -29
View File
@@ -1,37 +1,13 @@
#define VC_ENABLE_REFLECTION
#include "NotePreset.hpp" #include "NotePreset.hpp"
#include <map>
#include <vector>
#include "data/dv_util.hpp" #include "data/dv_util.hpp"
std::string to_string(NoteDisplayMode mode) { #include <vector>
static std::vector<std::string> names = {
"static_billboard",
"y_free_billboard",
"xy_free_billboard",
"projected"
};
return names.at(static_cast<int>(mode));
}
std::optional<NoteDisplayMode> NoteDisplayMode_from(std::string_view s) {
static std::map<std::string_view, NoteDisplayMode, std::less<>> map {
{"static_billboard", NoteDisplayMode::STATIC_BILLBOARD},
{"y_free_billboard", NoteDisplayMode::Y_FREE_BILLBOARD},
{"xy_free_billboard", NoteDisplayMode::XY_FREE_BILLBOARD},
{"projected", NoteDisplayMode::PROJECTED}
};
const auto& found = map.find(s);
if (found == map.end()) {
return std::nullopt;
}
return found->second;
}
dv::value NotePreset::serialize() const { dv::value NotePreset::serialize() const {
return dv::object({ return dv::object({
{"display", to_string(displayMode)}, {"display", NoteDisplayModeMeta.getNameString(displayMode)},
{"color", dv::to_value(color)}, {"color", dv::to_value(color)},
{"scale", scale}, {"scale", scale},
{"render_distance", renderDistance}, {"render_distance", renderDistance},
@@ -42,7 +18,7 @@ dv::value NotePreset::serialize() const {
void NotePreset::deserialize(const dv::value& src) { void NotePreset::deserialize(const dv::value& src) {
if (src.has("display")) { if (src.has("display")) {
displayMode = NoteDisplayMode_from(src["display"].asString()).value(); NoteDisplayModeMeta.getItem(src["display"].asString(), displayMode);
} }
if (src.has("color")) { if (src.has("color")) {
dv::get_vec(src["color"], color); dv::get_vec(src["color"], color);
+7 -3
View File
@@ -2,10 +2,10 @@
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
#include <glm/vec4.hpp> #include <glm/vec4.hpp>
#include <optional>
#include <string> #include <string>
#include "interfaces/Serializable.hpp" #include "interfaces/Serializable.hpp"
#include "util/EnumMetadata.hpp"
enum class NoteDisplayMode { enum class NoteDisplayMode {
STATIC_BILLBOARD, STATIC_BILLBOARD,
@@ -14,8 +14,12 @@ enum class NoteDisplayMode {
PROJECTED PROJECTED
}; };
std::string to_string(NoteDisplayMode mode); VC_ENUM_METADATA(NoteDisplayMode)
std::optional<NoteDisplayMode> NoteDisplayMode_from(std::string_view s); {"static_billboard", NoteDisplayMode::STATIC_BILLBOARD},
{"y_free_billboard", NoteDisplayMode::Y_FREE_BILLBOARD},
{"xy_free_billboard", NoteDisplayMode::XY_FREE_BILLBOARD},
{"projected", NoteDisplayMode::PROJECTED},
VC_ENUM_END
struct NotePreset : public Serializable { struct NotePreset : public Serializable {
NoteDisplayMode displayMode = NoteDisplayMode::STATIC_BILLBOARD; NoteDisplayMode displayMode = NoteDisplayMode::STATIC_BILLBOARD;
+4 -22
View File
@@ -1,26 +1,8 @@
#define VC_ENABLE_REFLECTION
#include "ParticlesPreset.hpp" #include "ParticlesPreset.hpp"
#include "data/dv_util.hpp" #include "data/dv_util.hpp"
std::string to_string(ParticleSpawnShape shape) {
static std::string names[] = {
"ball",
"sphere",
"box"
};
return names[static_cast<int>(shape)];
}
ParticleSpawnShape ParticleSpawnShape_from(std::string_view s) {
if (s == "ball") {
return ParticleSpawnShape::BALL;
} else if (s == "sphere") {
return ParticleSpawnShape::SPHERE;
} else {
return ParticleSpawnShape::BOX;
}
}
dv::value ParticlesPreset::serialize() const { dv::value ParticlesPreset::serialize() const {
auto root = dv::object(); auto root = dv::object();
if (frames.empty()) { if (frames.empty()) {
@@ -47,7 +29,7 @@ dv::value ParticlesPreset::serialize() const {
root["min_angular_vel"] = minAngularVelocity; root["min_angular_vel"] = minAngularVelocity;
root["max_angular_vel"] = maxAngularVelocity; root["max_angular_vel"] = maxAngularVelocity;
root["spawn_spread"] = dv::to_value(size); root["spawn_spread"] = dv::to_value(size);
root["spawn_shape"] = to_string(spawnShape); root["spawn_shape"] = ParticleSpawnShapeMeta.getName(spawnShape);
root["random_sub_uv"] = randomSubUV; root["random_sub_uv"] = randomSubUV;
return root; return root;
} }
@@ -82,7 +64,7 @@ void ParticlesPreset::deserialize(const dv::value& src) {
dv::get_vec(src["explosion"], explosion); dv::get_vec(src["explosion"], explosion);
} }
if (src.has("spawn_shape")) { if (src.has("spawn_shape")) {
spawnShape = ParticleSpawnShape_from(src["spawn_shape"].asString()); ParticleSpawnShapeMeta.getItem(src["spawn_shape"].asString(), spawnShape);
} }
if (src.has("frames")) { if (src.has("frames")) {
for (const auto& frame : src["frames"]) { for (const auto& frame : src["frames"]) {
+8 -4
View File
@@ -5,8 +5,9 @@
#include <vector> #include <vector>
#include "interfaces/Serializable.hpp" #include "interfaces/Serializable.hpp"
#include "util/EnumMetadata.hpp"
enum ParticleSpawnShape { enum class ParticleSpawnShape {
/// @brief Coordinates are regulary distributed within /// @brief Coordinates are regulary distributed within
/// the volume of a ball. /// the volume of a ball.
BALL = 0, BALL = 0,
@@ -18,8 +19,11 @@ enum ParticleSpawnShape {
BOX BOX
}; };
std::string to_string(ParticleSpawnShape shape); VC_ENUM_METADATA(ParticleSpawnShape)
ParticleSpawnShape ParticleSpawnShape_from(std::string_view s); {"ball", ParticleSpawnShape::BALL},
{"sphere", ParticleSpawnShape::SPHERE},
{"box", ParticleSpawnShape::BOX},
VC_ENUM_END
struct ParticlesPreset : public Serializable { struct ParticlesPreset : public Serializable {
/// @brief Collision detection /// @brief Collision detection
@@ -53,7 +57,7 @@ struct ParticlesPreset : public Serializable {
/// @brief Maximum angular velocity /// @brief Maximum angular velocity
float maxAngularVelocity = 0.0f; float maxAngularVelocity = 0.0f;
/// @brief Spawn spread shape /// @brief Spawn spread shape
ParticleSpawnShape spawnShape = BALL; ParticleSpawnShape spawnShape = ParticleSpawnShape::BALL;
/// @brief Spawn spread /// @brief Spawn spread
glm::vec3 spawnSpread {}; glm::vec3 spawnSpread {};
/// @brief Texture name /// @brief Texture name
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#ifdef VC_ENABLE_REFLECTION
#define VC_ENUM_METADATA(NAME) static inline util::EnumMetadata<NAME> NAME##Meta {
#define VC_ENUM_END };
#include <map>
#include <string>
#include <utility>
namespace util {
template<typename EnumT>
class EnumMetadata {
public:
EnumMetadata(
std::initializer_list<std::pair<const std::string_view, EnumT>> items
)
: items(items) {
for (const auto& [name, item] : items) {
names[item] = name;
}
}
std::string_view getName(EnumT item) const {
const auto& found = names.find(item);
if (found == names.end()) {
return "";
}
return found->second;
}
std::string getNameString(EnumT item) const {
return std::string(getName(item));
}
bool getItem(std::string_view name, EnumT& dst) const {
const auto& found = items.find(name);
if (found == items.end()) {
return false;
}
dst = found->second;
return true;
}
size_t size() const {
return items.size();
}
private:
std::map<std::string_view, EnumT> items;
std::map<EnumT, std::string_view> names;
};
}
#else
#include <initializer_list>
#define VC_ENUM_METADATA(NAME) \
struct NAME##__PAIR {const char* n; NAME i;}; \
[[maybe_unused]] static inline std::initializer_list<NAME##__PAIR> NAME##_PAIRS {
#define VC_ENUM_END };
#endif // VC_ENABLE_REFLECTION
-56
View File
@@ -18,62 +18,6 @@ dv::value BlockMaterial::serialize() const {
}); });
} }
std::string to_string(BlockModel model) {
switch (model) {
case BlockModel::none:
return "none";
case BlockModel::block:
return "block";
case BlockModel::xsprite:
return "X";
case BlockModel::aabb:
return "aabb";
case BlockModel::custom:
return "custom";
default:
return "unknown";
}
}
std::optional<BlockModel> BlockModel_from(std::string_view str) {
if (str == "none") {
return BlockModel::none;
} else if (str == "block") {
return BlockModel::block;
} else if (str == "X") {
return BlockModel::xsprite;
} else if (str == "aabb") {
return BlockModel::aabb;
} else if (str == "custom") {
return BlockModel::custom;
}
return std::nullopt;
}
std::string to_string(CullingMode mode) {
switch (mode) {
case CullingMode::DEFAULT:
return "default";
case CullingMode::OPTIONAL:
return "optional";
case CullingMode::DISABLED:
return "disabled";
default:
return "unknown";
}
}
std::optional<CullingMode> CullingMode_from(std::string_view str) {
if (str == "default") {
return CullingMode::DEFAULT;
} else if (str == "optional") {
return CullingMode::OPTIONAL;
} else if (str == "disabled") {
return CullingMode::DISABLED;
}
return std::nullopt;
}
CoordSystem::CoordSystem(glm::ivec3 axisX, glm::ivec3 axisY, glm::ivec3 axisZ) CoordSystem::CoordSystem(glm::ivec3 axisX, glm::ivec3 axisY, glm::ivec3 axisZ)
: axes({axisX, axisY, axisZ}) { : axes({axisX, axisY, axisZ}) {
fix = glm::ivec3(0); fix = glm::ivec3(0);
+13 -5
View File
@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <array> #include <array>
@@ -10,6 +9,7 @@
#include "maths/UVRegion.hpp" #include "maths/UVRegion.hpp"
#include "maths/aabb.hpp" #include "maths/aabb.hpp"
#include "typedefs.hpp" #include "typedefs.hpp"
#include "util/EnumMetadata.hpp"
struct ParticlesPreset; struct ParticlesPreset;
@@ -93,8 +93,13 @@ enum class BlockModel {
custom custom
}; };
std::string to_string(BlockModel model); VC_ENUM_METADATA(BlockModel)
std::optional<BlockModel> BlockModel_from(std::string_view str); {"none", BlockModel::none},
{"block", BlockModel::block},
{"X", BlockModel::xsprite},
{"aabb", BlockModel::aabb},
{"custom", BlockModel::custom},
VC_ENUM_END
enum class CullingMode { enum class CullingMode {
DEFAULT, DEFAULT,
@@ -102,8 +107,11 @@ enum class CullingMode {
DISABLED, DISABLED,
}; };
std::string to_string(CullingMode mode); VC_ENUM_METADATA(CullingMode)
std::optional<CullingMode> CullingMode_from(std::string_view str); {"default", CullingMode::DEFAULT},
{"optional", CullingMode::OPTIONAL},
{"disabled", CullingMode::DISABLED},
VC_ENUM_END
using BoxModel = AABB; using BoxModel = AABB;
+3 -3
View File
@@ -32,18 +32,18 @@ Chunks::Chunks(
: events(events), : events(events),
indices(indices), indices(indices),
areaMap(w, d) { areaMap(w, d) {
areaMap.setCenter(ox-w/2, oz-d/2); areaMap.setCenter(ox - w / 2, oz - d / 2);
areaMap.setOutCallback([this](int, int, const auto& chunk) { areaMap.setOutCallback([this](int, int, const auto& chunk) {
this->events->trigger(LevelEventType::CHUNK_HIDDEN, chunk.get()); this->events->trigger(LevelEventType::CHUNK_HIDDEN, chunk.get());
}); });
} }
void Chunks::configure(int32_t x, int32_t z, uint32_t radius) { void Chunks::configure(int32_t x, int32_t z, uint32_t radius) {
setCenter(x, z);
uint32_t diameter = radius * 2LL; uint32_t diameter = radius * 2LL;
if (getWidth() != diameter) { if (getWidth() != diameter) {
resize(diameter, diameter); resize(diameter, diameter);
} }
setCenter(x, z);
} }
voxel* Chunks::get(int32_t x, int32_t y, int32_t z) const { voxel* Chunks::get(int32_t x, int32_t y, int32_t z) const {
@@ -313,7 +313,7 @@ glm::vec3 Chunks::rayCastToObstacle(
} }
void Chunks::setCenter(int32_t x, int32_t z) { void Chunks::setCenter(int32_t x, int32_t z) {
areaMap.setCenter(floordiv(x, CHUNK_W), floordiv(z, CHUNK_D)); areaMap.setCenter(floordiv<CHUNK_W>(x), floordiv<CHUNK_D>(z));
} }
void Chunks::resize(uint32_t newW, uint32_t newD) { void Chunks::resize(uint32_t newW, uint32_t newD) {
+2 -1
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "World.hpp" #include "World.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
@@ -49,7 +50,7 @@ void World::updateTimers(float delta) {
void World::writeResources(const Content& content) { void World::writeResources(const Content& content) {
auto root = dv::object(); auto root = dv::object();
for (size_t typeIndex = 0; typeIndex < RESOURCE_TYPES_COUNT; typeIndex++) { for (size_t typeIndex = 0; typeIndex < RESOURCE_TYPES_COUNT; typeIndex++) {
auto typeName = to_string(static_cast<ResourceType>(typeIndex)); auto typeName = ResourceTypeMeta.getNameString(static_cast<ResourceType>(typeIndex));
auto& list = root.list(typeName); auto& list = root.list(typeName);
auto& indices = content.resourceIndices[typeIndex]; auto& indices = content.resourceIndices[typeIndex];
for (size_t i = 0; i < indices.size(); i++) { for (size_t i = 0; i < indices.size(); i++) {
+4 -2
View File
@@ -1,3 +1,4 @@
#define VC_ENABLE_REFLECTION
#include "WorldFiles.hpp" #include "WorldFiles.hpp"
#include <cassert> #include <cassert>
@@ -182,8 +183,9 @@ bool WorldFiles::readResourcesData(const Content& content) {
} }
auto root = io::read_json(file); auto root = io::read_json(file);
for (const auto& [key, arr] : root.asObject()) { for (const auto& [key, arr] : root.asObject()) {
if (auto resType = ResourceType_from(key)) { ResourceType type;
read_resources_data(content, arr, *resType); if (ResourceTypeMeta.getItem(key, type)) {
read_resources_data(content, arr, type);
} else { } else {
logger.warning() << "unknown resource type: " << key; logger.warning() << "unknown resource type: " << key;
} }
+1 -2
View File
@@ -355,8 +355,7 @@ void WorldGenerator::generateHeightmap(
void WorldGenerator::update(int centerX, int centerY, int loadDistance) { void WorldGenerator::update(int centerX, int centerY, int loadDistance) {
surroundMap.setCenter(centerX, centerY); surroundMap.setCenter(centerX, centerY);
// 2 is safety padding preventing ChunksController rounding problem surroundMap.resize(loadDistance);
surroundMap.resize(loadDistance + 2);
surroundMap.setCenter(centerX, centerY); surroundMap.setCenter(centerX, centerY);
} }
-27
View File
@@ -1,27 +0,0 @@
#include "coders/lua_parsing.hpp"
#include <gtest/gtest.h>
#include "coders/commons.hpp"
#include "io/io.hpp"
#include "io/devices/StdfsDevice.hpp"
#include "util/stringutil.hpp"
namespace fs = std::filesystem;
TEST(lua_parsing, Tokenizer) {
io::set_device("res", std::make_shared<io::StdfsDevice>(fs::u8path("../../res")));
auto filename = "res:scripts/stdlib.lua";
auto source = io::read_string(filename);
try {
auto tokens = lua::tokenize(filename, util::str2wstr_utf8(source));
for (const auto& token : tokens) {
std::cout << (int)token.tag << " "
<< util::quote(util::wstr2str_utf8(token.text))
<< std::endl;
}
} catch (const parsing_error& err) {
std::cerr << err.errorLog() << std::endl;
throw err;
}
}