Merge branch 'main' into content-loader-refactor
This commit is contained in:
commit
3bfe24c63c
27
dev/tests/bytearray.lua
Normal file
27
dev/tests/bytearray.lua
Normal 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())
|
||||
@ -1,8 +1,8 @@
|
||||
local util = require "core:tests_util"
|
||||
util.create_demo_world()
|
||||
|
||||
app.set_setting("chunks.load-distance", 3)
|
||||
app.set_setting("chunks.load-speed", 1)
|
||||
app.set_setting("chunks.load-distance", 15)
|
||||
app.set_setting("chunks.load-speed", 15)
|
||||
|
||||
local pid1 = player.create("Xerxes")
|
||||
assert(player.get_name(pid1) == "Xerxes")
|
||||
|
||||
4
dev/tests/data_buffer.lua
Normal file
4
dev/tests/data_buffer.lua
Normal 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)
|
||||
@ -29,6 +29,9 @@ entity:has_component(name: str) -> bool
|
||||
|
||||
-- Enables/disables the component
|
||||
entity:set_enabled(name: str, enable: bool)
|
||||
|
||||
-- Returns id of player the entity is bound
|
||||
entity:get_player() -> int or nil
|
||||
```
|
||||
|
||||
## Built-in components
|
||||
|
||||
@ -29,6 +29,9 @@ entity:has_component(name: str) -> bool
|
||||
|
||||
-- Включает/выключает компонент по имени
|
||||
entity:set_enabled(name: str, enable: bool)
|
||||
|
||||
-- Возвращает id игрока, к которому привязана сущность
|
||||
entity:get_player() -> int или nil
|
||||
```
|
||||
|
||||
## Встроенные компоненты
|
||||
|
||||
28
res/devtools/syntax/glsl.toml
Normal file
28
res/devtools/syntax/glsl.toml
Normal 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
res/devtools/syntax/lua.toml
Normal file
12
res/devtools/syntax/lua.toml
Normal 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"
|
||||
]
|
||||
@ -74,7 +74,6 @@
|
||||
multiline='true'
|
||||
line-numbers='true'
|
||||
oncontrolkey='on_control_combination'
|
||||
syntax='lua'
|
||||
size-func="-1,40"
|
||||
text-wrap='false'
|
||||
scroll-step='50'
|
||||
|
||||
@ -197,6 +197,7 @@ function open_file_in_editor(filename, line, mutable)
|
||||
editor.scroll = 0
|
||||
editor.text = source
|
||||
editor.focused = true
|
||||
editor.syntax = file.ext(filename)
|
||||
if line then
|
||||
time.post_runnable(function()
|
||||
editor.caret = editor:linePos(line)
|
||||
|
||||
215
res/modules/internal/bytearray.lua
Normal file
215
res/modules/internal/bytearray.lua
Normal 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
|
||||
}
|
||||
@ -263,6 +263,11 @@ entities.get_all = function(uids)
|
||||
return stdcomp.get_all(uids)
|
||||
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)
|
||||
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
local _ffi = ffi
|
||||
ffi = nil
|
||||
|
||||
-- Lua has no parallelizm, also _set_data does not call any lua functions so
|
||||
-- may be reused one global ffi buffer per lua_State
|
||||
local canvas_ffi_buffer
|
||||
@ -8,14 +5,14 @@ local canvas_ffi_buffer_size = 0
|
||||
|
||||
function __vc_Canvas_set_data(self, data)
|
||||
if type(data) == "cdata" then
|
||||
self:_set_data(tostring(_ffi.cast("uintptr_t", data)))
|
||||
self:_set_data(tostring(ffi.cast("uintptr_t", data)))
|
||||
end
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
|
||||
local size = width * height * 4
|
||||
if size > canvas_ffi_buffer_size then
|
||||
canvas_ffi_buffer = _ffi.new(
|
||||
canvas_ffi_buffer = ffi.new(
|
||||
string.format("unsigned char[%s]", size)
|
||||
)
|
||||
canvas_ffi_buffer_size = size
|
||||
@ -23,7 +20,7 @@ function __vc_Canvas_set_data(self, data)
|
||||
for i=0, size - 1 do
|
||||
canvas_ffi_buffer[i] = data[i + 1]
|
||||
end
|
||||
self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer)))
|
||||
self:_set_data(tostring(ffi.cast("uintptr_t", canvas_ffi_buffer)))
|
||||
end
|
||||
|
||||
function crc32(bytes, chksum)
|
||||
@ -31,14 +28,14 @@ function crc32(bytes, chksum)
|
||||
|
||||
local length = #bytes
|
||||
if type(bytes) == "table" then
|
||||
local buffer_len = _ffi.new('int[1]', length)
|
||||
local buffer = _ffi.new(
|
||||
local buffer_len = ffi.new('int[1]', length)
|
||||
local buffer = ffi.new(
|
||||
string.format("char[%s]", length)
|
||||
)
|
||||
for i=1, length do
|
||||
buffer[i - 1] = bytes[i]
|
||||
end
|
||||
bytes = _ffi.string(buffer, buffer_len[0])
|
||||
bytes = ffi.string(buffer, buffer_len[0])
|
||||
end
|
||||
return _crc32(bytes, chksum)
|
||||
end
|
||||
|
||||
@ -166,6 +166,9 @@ size_t BasicParser<CharT>::remain() const {
|
||||
|
||||
template<typename CharT>
|
||||
bool BasicParser<CharT>::isNext(const std::basic_string<CharT>& substring) {
|
||||
if (substring.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (source.length() - pos < substring.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "GLSLExtension.hpp"
|
||||
|
||||
#include <sstream>
|
||||
@ -95,22 +96,6 @@ inline void source_line(std::stringstream& ss, uint linenum) {
|
||||
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) {
|
||||
switch (type) {
|
||||
case Type::FLOAT:
|
||||
@ -212,11 +197,13 @@ public:
|
||||
}
|
||||
|
||||
bool processParamDirective() {
|
||||
using Param = PostEffect::Param;
|
||||
|
||||
skipWhitespace(false);
|
||||
// Parse type name
|
||||
auto typeName = parseName();
|
||||
auto type = param_type_from(typeName);
|
||||
if (!type.has_value()) {
|
||||
Param::Type type;
|
||||
if (!Param::TypeMeta.getItem(typeName, type)) {
|
||||
throw error("unsupported param type " + util::quote(typeName));
|
||||
}
|
||||
skipWhitespace(false);
|
||||
@ -228,17 +215,17 @@ public:
|
||||
skipWhitespace(false);
|
||||
ss << "uniform " << typeName << " " << paramName << ";\n";
|
||||
|
||||
auto defValue = default_value_for(type.value());
|
||||
auto defValue = default_value_for(type);
|
||||
// Parse default value
|
||||
if (peekNoJump() == '=') {
|
||||
skip(1);
|
||||
skipWhitespace(false);
|
||||
defValue = parseDefaultValue(type.value(), typeName);
|
||||
defValue = parseDefaultValue(type, typeName);
|
||||
}
|
||||
|
||||
skipLine();
|
||||
|
||||
params[paramName] = PostEffect::Param(type.value(), std::move(defValue));
|
||||
params[paramName] = PostEffect::Param(type, std::move(defValue));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -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 "data/dv.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "BasicParser.hpp"
|
||||
|
||||
using namespace lua;
|
||||
using namespace devtools;
|
||||
|
||||
static std::set<std::wstring_view> keywords {
|
||||
L"and", L"break", L"do", L"else", L"elseif", L"end", L"false", L"for", L"function",
|
||||
L"if", L"in", L"local", L"nil", L"not", L"or", L"repeat", L"return", L"then", L"true",
|
||||
L"until", L"while"
|
||||
};
|
||||
dv::value Syntax::serialize() const {
|
||||
auto map = dv::object();
|
||||
map["language"] = language;
|
||||
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) {
|
||||
return keywords.find(view) != keywords.end();
|
||||
auto& extsList = map.list("extensions");
|
||||
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 == '_';
|
||||
}
|
||||
|
||||
inline bool is_lua_identifier_part(int c) {
|
||||
return is_lua_identifier_start(c) || is_digit(c);
|
||||
inline bool is_common_identifier_part(int c) {
|
||||
return is_common_identifier_start(c) || is_digit(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> {
|
||||
const Syntax& syntax;
|
||||
std::vector<Token> tokens;
|
||||
public:
|
||||
Tokenizer(std::string_view file, std::wstring_view source)
|
||||
: BasicParser(file, source) {
|
||||
Tokenizer(
|
||||
const Syntax& syntax, std::string_view file, std::wstring_view source
|
||||
)
|
||||
: BasicParser(file, source), syntax(syntax) {
|
||||
}
|
||||
|
||||
std::wstring parseLuaName() {
|
||||
@ -111,9 +160,12 @@ public:
|
||||
}
|
||||
wchar_t c = peek();
|
||||
auto start = currentLocation();
|
||||
if (is_lua_identifier_start(c)) {
|
||||
if (is_common_identifier_start(c)) {
|
||||
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(
|
||||
tag,
|
||||
std::move(name),
|
||||
@ -133,24 +185,29 @@ public:
|
||||
emitToken(tag, std::wstring(literal), start);
|
||||
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) {
|
||||
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);
|
||||
continue;
|
||||
case ')': case ']': case '}':
|
||||
@ -188,6 +245,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<Token> lua::tokenize(std::string_view file, std::wstring_view source) {
|
||||
return Tokenizer(file, source).tokenize();
|
||||
std::vector<Token> devtools::tokenize(
|
||||
const Syntax& syntax, std::string_view file, std::wstring_view source
|
||||
) {
|
||||
return Tokenizer(syntax, file, source).tokenize();
|
||||
}
|
||||
28
src/coders/syntax_parser.hpp
Normal file
28
src/coders/syntax_parser.hpp
Normal 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
|
||||
);
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@ -25,23 +24,6 @@ namespace rigging {
|
||||
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 {
|
||||
ContentType type;
|
||||
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];
|
||||
|
||||
/// @brief Content is a definitions repository
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "ContentLoader.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@ -259,28 +260,25 @@ void ContentLoader::loadBlock(
|
||||
}
|
||||
|
||||
// block model
|
||||
std::string modelTypeName = to_string(def.model);
|
||||
std::string modelTypeName = BlockModelMeta.getNameString(def.model);
|
||||
root.at("model").get(modelTypeName);
|
||||
root.at("model-name").get(def.modelName);
|
||||
if (auto model = BlockModel_from(modelTypeName)) {
|
||||
if (*model == BlockModel::custom && def.customModelRaw == nullptr) {
|
||||
if (BlockModelMeta.getItem(modelTypeName, def.model)) {
|
||||
if (def.model == BlockModel::custom && def.customModelRaw == nullptr) {
|
||||
if (root.has("model-primitives")) {
|
||||
def.customModelRaw = root["model-primitives"];
|
||||
} else if (def.modelName.empty()) {
|
||||
throw std::runtime_error(name + ": no 'model-primitives' or 'model-name' found");
|
||||
}
|
||||
}
|
||||
def.model = *model;
|
||||
} else if (!modelTypeName.empty()) {
|
||||
logger.error() << "unknown model: " << modelTypeName;
|
||||
def.model = BlockModel::none;
|
||||
}
|
||||
|
||||
std::string cullingModeName = to_string(def.culling);
|
||||
std::string cullingModeName = CullingModeMeta.getNameString(def.culling);
|
||||
root.at("culling").get(cullingModeName);
|
||||
if (auto mode = CullingMode_from(cullingModeName)) {
|
||||
def.culling = *mode;
|
||||
} else {
|
||||
if (!CullingModeMeta.getItem(cullingModeName, def.culling)) {
|
||||
logger.error() << "unknown culling mode: " << cullingModeName;
|
||||
}
|
||||
|
||||
@ -518,9 +516,7 @@ void ContentLoader::loadEntity(
|
||||
|
||||
std::string bodyTypeName;
|
||||
root.at("body-type").get(bodyTypeName);
|
||||
if (auto bodyType = BodyType_from(bodyTypeName)) {
|
||||
def.bodyType = *bodyType;
|
||||
}
|
||||
BodyTypeMeta.getItem(bodyTypeName, def.bodyType);
|
||||
|
||||
root.at("skeleton-name").get(def.skeletonName);
|
||||
root.at("blocking").get(def.blocking);
|
||||
@ -749,8 +745,9 @@ void ContentLoader::load() {
|
||||
if (io::exists(resourcesFile)) {
|
||||
auto resRoot = io::read_json(resourcesFile);
|
||||
for (const auto& [key, arr] : resRoot.asObject()) {
|
||||
if (auto resType = ResourceType_from(key)) {
|
||||
loadResources(*resType, arr);
|
||||
ResourceType type;
|
||||
if (ResourceTypeMeta.getItem(key, type)) {
|
||||
loadResources(type, arr);
|
||||
} else {
|
||||
// Ignore unknown resources
|
||||
logger.warning() << "unknown resource type: " << key;
|
||||
@ -763,8 +760,9 @@ void ContentLoader::load() {
|
||||
if (io::exists(aliasesFile)) {
|
||||
auto resRoot = io::read_json(aliasesFile);
|
||||
for (const auto& [key, arr] : resRoot.asObject()) {
|
||||
if (auto resType = ResourceType_from(key)) {
|
||||
loadResourceAliases(*resType, arr);
|
||||
ResourceType type;
|
||||
if (ResourceTypeMeta.getItem(key, type)) {
|
||||
loadResourceAliases(type, arr);
|
||||
} else {
|
||||
// Ignore unknown resources
|
||||
logger.warning() << "unknown resource type: " << key;
|
||||
|
||||
@ -1,12 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
class Content;
|
||||
class ContentPackRuntime;
|
||||
|
||||
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 {
|
||||
CAMERA,
|
||||
POST_EFFECT_SLOT,
|
||||
@ -15,3 +24,8 @@ enum class ResourceType : size_t {
|
||||
|
||||
inline constexpr auto RESOURCE_TYPES_COUNT =
|
||||
static_cast<size_t>(ResourceType::LAST) + 1;
|
||||
|
||||
VC_ENUM_METADATA(ResourceType)
|
||||
{"camera", ResourceType::CAMERA},
|
||||
{"post-effect-slot", ResourceType::POST_EFFECT_SLOT},
|
||||
VC_ENUM_END
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "../ContentLoader.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@ -210,13 +211,9 @@ void ContentLoader::loadGenerator(
|
||||
map.at("heights-bpd").get(def.heightsBPD);
|
||||
std::string interpName;
|
||||
map.at("heights-interpolation").get(interpName);
|
||||
if (auto interp = InterpolationType_from(interpName)) {
|
||||
def.heightsInterpolation = *interp;
|
||||
}
|
||||
InterpolationTypeMeta.getItem(interpName, def.heightsInterpolation);
|
||||
map.at("biomes-interpolation").get(interpName);
|
||||
if (auto interp = InterpolationType_from(interpName)) {
|
||||
def.biomesInterpolation = *interp;
|
||||
}
|
||||
InterpolationTypeMeta.getItem(interpName, def.biomesInterpolation);
|
||||
|
||||
map.at("sea-level").get(def.seaLevel);
|
||||
map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius);
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "interfaces/Serializable.hpp"
|
||||
|
||||
29
src/devtools/Editor.cpp
Normal file
29
src/devtools/Editor.cpp
Normal 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
src/devtools/Editor.hpp
Normal file
23
src/devtools/Editor.hpp
Normal 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/lua_parsing.hpp"
|
||||
#include "coders/syntax_parser.hpp"
|
||||
#include "graphics/core/Font.hpp"
|
||||
|
||||
using namespace devtools;
|
||||
@ -55,16 +55,28 @@ static std::unique_ptr<FontStylesScheme> build_styles(
|
||||
return std::make_unique<FontStylesScheme>(std::move(styles));
|
||||
}
|
||||
|
||||
std::unique_ptr<FontStylesScheme> devtools::syntax_highlight(
|
||||
const std::string& lang, std::wstring_view source
|
||||
void SyntaxProcessor::addSyntax(
|
||||
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 {
|
||||
if (lang == "lua") {
|
||||
auto tokens = lua::tokenize("<string>", source);
|
||||
return build_styles(tokens);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
auto tokens = tokenize(syntax, "<string>", source);
|
||||
return build_styles(tokens);
|
||||
} catch (const parsing_error& err) {
|
||||
return nullptr;
|
||||
}
|
||||
29
src/devtools/SyntaxProcessor.hpp
Normal file
29
src/devtools/SyntaxProcessor.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
@ -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
|
||||
);
|
||||
}
|
||||
@ -12,6 +12,7 @@
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/toml.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "devtools/Editor.hpp"
|
||||
#include "content/ContentControl.hpp"
|
||||
#include "core_defs.hpp"
|
||||
#include "io/io.hpp"
|
||||
@ -73,6 +74,7 @@ Engine& Engine::getInstance() {
|
||||
void Engine::initialize(CoreParameters coreParameters) {
|
||||
params = std::move(coreParameters);
|
||||
settingsHandler = std::make_unique<SettingsHandler>(settings);
|
||||
editor = std::make_unique<devtools::Editor>(*this);
|
||||
cmd = std::make_unique<cmd::CommandsInterpreter>();
|
||||
network = network::Network::create(settings.network);
|
||||
|
||||
@ -134,6 +136,7 @@ void Engine::initialize(CoreParameters coreParameters) {
|
||||
);
|
||||
}
|
||||
content = std::make_unique<ContentControl>(paths, *input, [this]() {
|
||||
editor->loadTools();
|
||||
langs::setup(langs::get_current(), paths.resPaths.collectRoots());
|
||||
if (!isHeadless()) {
|
||||
for (auto& pack : content->getAllContentPacks()) {
|
||||
|
||||
@ -33,6 +33,10 @@ namespace network {
|
||||
class Network;
|
||||
}
|
||||
|
||||
namespace devtools {
|
||||
class Editor;
|
||||
}
|
||||
|
||||
class initialize_error : public std::runtime_error {
|
||||
public:
|
||||
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<Input> input;
|
||||
std::unique_ptr<gui::GUI> gui;
|
||||
std::unique_ptr<devtools::Editor> editor;
|
||||
PostRunnables postRunnables;
|
||||
Time time;
|
||||
OnWorldOpen levelConsumer;
|
||||
@ -161,4 +166,8 @@ public:
|
||||
cmd::CommandsInterpreter& getCmd() {
|
||||
return *cmd;
|
||||
}
|
||||
|
||||
devtools::Editor& getEditor() {
|
||||
return *editor;
|
||||
}
|
||||
};
|
||||
|
||||
@ -314,6 +314,7 @@ void Hud::updateWorldGenDebug() {
|
||||
|
||||
void Hud::update(bool visible) {
|
||||
const auto& chunks = *player.chunks;
|
||||
bool is_menu_open = menu.hasOpenPage();
|
||||
|
||||
debugPanel->setVisible(
|
||||
debug && visible && !(inventoryOpen && inventoryView == nullptr)
|
||||
@ -322,13 +323,13 @@ void Hud::update(bool visible) {
|
||||
if (!visible && inventoryOpen) {
|
||||
closeInventory();
|
||||
}
|
||||
if (pause && !menu.hasOpenPage()) {
|
||||
if (pause && !is_menu_open) {
|
||||
setPause(false);
|
||||
}
|
||||
if (!gui.isFocusCaught()) {
|
||||
processInput(visible);
|
||||
}
|
||||
if ((menu.hasOpenPage() || inventoryOpen) == input.getCursor().locked) {
|
||||
if ((is_menu_open || inventoryOpen) == input.getCursor().locked) {
|
||||
input.toggleCursor();
|
||||
}
|
||||
|
||||
@ -349,6 +350,8 @@ void Hud::update(bool visible) {
|
||||
contentAccessPanel->setSize(glm::vec2(caSize.x, windowSize.y));
|
||||
contentAccess->setMinSize(glm::vec2(1, windowSize.y));
|
||||
hotbarView->setVisible(visible && !(secondUI && !inventoryView));
|
||||
darkOverlay->setVisible(is_menu_open);
|
||||
menu.setVisible(is_menu_open);
|
||||
|
||||
if (visible) {
|
||||
for (auto& element : elements) {
|
||||
@ -360,7 +363,7 @@ void Hud::update(bool visible) {
|
||||
}
|
||||
cleanup();
|
||||
|
||||
debugMinimap->setVisible(debug && showGeneratorMinimap);
|
||||
debugMinimap->setVisible(debug && showGeneratorMinimap && visible);
|
||||
if (debug && showGeneratorMinimap) {
|
||||
updateWorldGenDebug();
|
||||
}
|
||||
@ -593,10 +596,6 @@ void Hud::setDebug(bool flag) {
|
||||
void Hud::draw(const DrawContext& ctx){
|
||||
const auto& viewport = ctx.getViewport();
|
||||
|
||||
bool is_menu_open = menu.hasOpenPage();
|
||||
darkOverlay->setVisible(is_menu_open);
|
||||
menu.setVisible(is_menu_open);
|
||||
|
||||
updateElementsPosition(viewport);
|
||||
|
||||
uicamera->setFov(viewport.y);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "data/dv_fwd.hpp"
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
class Shader;
|
||||
|
||||
@ -14,6 +15,14 @@ class PostEffect {
|
||||
public:
|
||||
struct Param {
|
||||
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>;
|
||||
|
||||
Type type;
|
||||
|
||||
@ -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)];
|
||||
}
|
||||
@ -3,6 +3,8 @@
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
enum class DrawPrimitive {
|
||||
point = 0,
|
||||
line,
|
||||
@ -48,8 +50,18 @@ enum class CursorShape {
|
||||
LAST=NOT_ALLOWED
|
||||
};
|
||||
|
||||
std::optional<CursorShape> CursorShape_from(std::string_view name);
|
||||
std::string to_string(CursorShape shape);
|
||||
VC_ENUM_METADATA(CursorShape)
|
||||
{"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 {
|
||||
public:
|
||||
|
||||
@ -364,3 +364,7 @@ Input& GUI::getInput() {
|
||||
Window& GUI::getWindow() {
|
||||
return engine.getWindow();
|
||||
}
|
||||
|
||||
devtools::Editor& GUI::getEditor() {
|
||||
return engine.getEditor();
|
||||
}
|
||||
|
||||
@ -18,6 +18,10 @@ class Engine;
|
||||
class Input;
|
||||
class Window;
|
||||
|
||||
namespace devtools {
|
||||
class Editor;
|
||||
}
|
||||
|
||||
/*
|
||||
Some info about padding and margin.
|
||||
Padding is element inner space, margin is outer
|
||||
@ -159,5 +163,6 @@ namespace gui {
|
||||
const Input& getInput() const;
|
||||
Input& getInput();
|
||||
Window& getWindow();
|
||||
devtools::Editor& getEditor();
|
||||
};
|
||||
}
|
||||
|
||||
@ -8,7 +8,8 @@
|
||||
#include "../markdown.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "devtools/syntax_highlighting.hpp"
|
||||
#include "devtools/Editor.hpp"
|
||||
#include "devtools/SyntaxProcessor.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
@ -811,7 +812,8 @@ void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) {
|
||||
|
||||
void TextBox::refreshSyntax() {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "gui_xml.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
@ -168,8 +169,9 @@ static void read_uinode(
|
||||
node.setTooltipDelay(element.attr("tooltip-delay").asFloat());
|
||||
}
|
||||
if (element.has("cursor")) {
|
||||
if (auto cursor = CursorShape_from(element.attr("cursor").getText())) {
|
||||
node.setCursor(*cursor);
|
||||
CursorShape cursor;
|
||||
if (CursorShapeMeta.getItem(element.attr("cursor").getText(), cursor)) {
|
||||
node.setCursor(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -35,12 +35,14 @@ void ChunksController::update(
|
||||
int64_t maxDuration, int loadDistance, uint padding, Player& player
|
||||
) const {
|
||||
const auto& position = player.getPosition();
|
||||
int centerX = floordiv<CHUNK_W>(position.x);
|
||||
int centerY = floordiv<CHUNK_D>(position.z);
|
||||
int centerX = floordiv<CHUNK_W>(glm::floor(position.x));
|
||||
int centerY = floordiv<CHUNK_D>(glm::floor(position.z));
|
||||
|
||||
if (player.isLoadingChunks()) {
|
||||
/// FIXME: one generator for multiple players
|
||||
generator->update(centerX, centerY, loadDistance);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t mcstotal = 0;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "EngineController.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@ -164,7 +165,7 @@ static dv::value create_missing_content_report(
|
||||
auto root = dv::object();
|
||||
auto& contentEntries = root.list("content");
|
||||
for (auto& entry : report->getMissingContent()) {
|
||||
std::string contentName = ContentType_name(entry.type);
|
||||
std::string contentName = ContentTypeMeta.getNameString(entry.type);
|
||||
auto& contentEntry = contentEntries.object();
|
||||
contentEntry["type"] = contentName;
|
||||
contentEntry["name"] = entry.name;
|
||||
|
||||
@ -77,8 +77,8 @@ void LevelController::update(float delta, bool pause) {
|
||||
player->updateEntity();
|
||||
glm::vec3 position = player->getPosition();
|
||||
player->chunks->configure(
|
||||
position.x,
|
||||
position.z,
|
||||
glm::floor(position.x),
|
||||
glm::floor(position.z),
|
||||
settings.chunks.loadDistance.get() + settings.chunks.padding.get()
|
||||
);
|
||||
chunks->update(
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
|
||||
#include "util/stringutil.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) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushstring(
|
||||
L, to_string(entity->getRigidbody().hitbox.type)
|
||||
return lua::pushlstring(
|
||||
L, BodyTypeMeta.getName(entity->getRigidbody().hitbox.type)
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
@ -105,9 +107,9 @@ static int l_get_body_type(lua::State* L) {
|
||||
|
||||
static int l_set_body_type(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
if (auto type = BodyType_from(lua::tostring(L, 2))) {
|
||||
entity->getRigidbody().hitbox.type = *type;
|
||||
} else {
|
||||
if (!BodyTypeMeta.getItem(
|
||||
lua::tostring(L, 2), entity->getRigidbody().hitbox.type
|
||||
)) {
|
||||
throw std::runtime_error(
|
||||
"unknown body type " + util::quote(lua::tostring(L, 2))
|
||||
);
|
||||
|
||||
@ -16,14 +16,14 @@ static int l_encode(lua::State* L) {
|
||||
return lua::pushstring(L, util::base64_encode(
|
||||
reinterpret_cast<const ubyte*>(buffer.data()), buffer.size()
|
||||
));
|
||||
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 1)) {
|
||||
return lua::pushstring(
|
||||
L,
|
||||
util::base64_encode(
|
||||
bytes->data().data(),
|
||||
bytes->data().size()
|
||||
)
|
||||
} else {
|
||||
auto string = lua::bytearray_as_string(L, 1);
|
||||
auto out = util::base64_encode(
|
||||
reinterpret_cast<const ubyte*>(string.data()),
|
||||
string.size()
|
||||
);
|
||||
lua::pop(L);
|
||||
return lua::pushstring(L, std::move(out));
|
||||
}
|
||||
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::rawseti(L, i+1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
lua::newuserdata<lua::LuaBytearray>(L, 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 lua::create_bytearray(L, buffer.data(), buffer.size());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg base64lib[] = {
|
||||
|
||||
@ -9,9 +9,7 @@ static int l_tobytes(lua::State* L) {
|
||||
if (lua::gettop(L) >= 2) {
|
||||
compress = lua::toboolean(L, 2);
|
||||
}
|
||||
return lua::newuserdata<lua::LuaBytearray>(
|
||||
L, json::to_binary(value, compress)
|
||||
);
|
||||
return lua::create_bytearray(L, json::to_binary(value, compress));
|
||||
}
|
||||
|
||||
static int l_frombytes(lua::State* L) {
|
||||
@ -24,17 +22,18 @@ static int l_frombytes(lua::State* L) {
|
||||
lua::pop(L);
|
||||
}
|
||||
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 {
|
||||
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[] = {
|
||||
{"tobytes", lua::wrap<l_tobytes>},
|
||||
{"frombytes", lua::wrap<l_frombytes>},
|
||||
{NULL, NULL}};
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "content/Content.hpp"
|
||||
#include "content/ContentLoader.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) {
|
||||
if (auto def = require_block(L)) {
|
||||
return lua::pushstring(L, to_string(def->model));
|
||||
return lua::pushlstring(L, BlockModelMeta.getName(def->model));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ static int pack(lua::State* L, const char* format, bool usetable) {
|
||||
}
|
||||
return 1;
|
||||
} 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) {
|
||||
const char* format = lua::require_string(L, 1);
|
||||
int count = count_elements(format);
|
||||
auto bytes = lua::require_bytearray(L, 2);
|
||||
ByteReader reader(bytes);
|
||||
auto bytes = lua::bytearray_as_string(L, 2);
|
||||
ByteReader reader(reinterpret_cast<const ubyte*>(bytes.data()), bytes.size());
|
||||
bool bigEndian = false;
|
||||
|
||||
for (size_t i = 0; format[i]; i++) {
|
||||
|
||||
@ -248,12 +248,14 @@ static int l_load_texture(lua::State* L) {
|
||||
}
|
||||
lua::pop(L);
|
||||
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(
|
||||
bytes->data().data(),
|
||||
bytes->data().size(),
|
||||
reinterpret_cast<const ubyte*>(string.data()),
|
||||
string.size(),
|
||||
lua::require_string(L, 2)
|
||||
);
|
||||
lua::pop(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ static int l_read_bytes(lua::State* L) {
|
||||
auto bytes = io::read_bytes(path);
|
||||
|
||||
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 {
|
||||
lua::createtable(L, length, 0);
|
||||
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) {
|
||||
io::path path = get_writeable_path(L);
|
||||
|
||||
if (auto bytearray = lua::touserdata<lua::LuaBytearray>(L, 2)) {
|
||||
auto& bytes = bytearray->data();
|
||||
return lua::pushboolean(
|
||||
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())
|
||||
auto string = lua::bytearray_as_string(L, 2);
|
||||
bool res = io::write_bytes(
|
||||
path, reinterpret_cast<const ubyte*>(string.data()), string.size()
|
||||
);
|
||||
lua::pop(L);
|
||||
return lua::pushboolean(L, res);
|
||||
}
|
||||
|
||||
static int l_list_all_res(lua::State* L, const std::string& path) {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "libgui.hpp"
|
||||
#include "assets/Assets.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) {
|
||||
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) {
|
||||
@ -660,9 +661,9 @@ static void p_set_focused(
|
||||
}
|
||||
|
||||
static void p_set_cursor(UINode* node, lua::State* L, int idx) {
|
||||
if (auto cursor = CursorShape_from(lua::require_string(L, idx))) {
|
||||
node->setCursor(*cursor);
|
||||
}
|
||||
auto cursor = CursorShape::ARROW; // reset to default
|
||||
CursorShapeMeta.getItem(lua::require_string(L, idx), cursor);
|
||||
node->setCursor(cursor);
|
||||
}
|
||||
|
||||
static int p_set_scroll(UINode* node, lua::State* L, int idx) {
|
||||
|
||||
@ -109,13 +109,13 @@ static int l_send(lua::State* L, network::Network& network) {
|
||||
}
|
||||
lua::pop(L);
|
||||
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)) {
|
||||
auto string = lua::tolstring(L, 2);
|
||||
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;
|
||||
}
|
||||
@ -140,13 +140,10 @@ static int l_recv(lua::State* L, network::Network& network) {
|
||||
lua::pushinteger(L, buffer[i] & 0xFF);
|
||||
lua::rawseti(L, i+1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
lua::newuserdata<lua::LuaBytearray>(L, size);
|
||||
auto bytearray = lua::touserdata<lua::LuaBytearray>(L, -1);
|
||||
bytearray->data().reserve(size);
|
||||
std::memcpy(bytearray->data().data(), buffer.data(), size);
|
||||
return lua::create_bytearray(L, buffer.data(), size);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_available(lua::State* L, network::Network& network) {
|
||||
|
||||
@ -14,13 +14,10 @@ static int l_tobytes(lua::State* L) {
|
||||
lua::pushinteger(L, string[i] & 0xFF);
|
||||
lua::rawseti(L, i+1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
lua::newuserdata<lua::LuaBytearray>(L, 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 lua::create_bytearray(L, string.data(), string.length());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_tostring(lua::State* L) {
|
||||
@ -35,16 +32,10 @@ static int l_tostring(lua::State* L) {
|
||||
}
|
||||
lua::pop(L);
|
||||
return lua::pushlstring(L, buffer.data(), size);
|
||||
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 1)) {
|
||||
return lua::pushstring(
|
||||
L,
|
||||
std::string(
|
||||
reinterpret_cast<char*>(bytes->data().data()),
|
||||
bytes->data().size()
|
||||
)
|
||||
);
|
||||
} else {
|
||||
lua::bytearray_as_string(L, 1);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_length(lua::State* L) {
|
||||
|
||||
@ -144,7 +144,7 @@ static int l_get_chunk_data(lua::State* L) {
|
||||
} else {
|
||||
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) {
|
||||
@ -175,14 +175,17 @@ static int l_set_chunk_data(lua::State* L) {
|
||||
|
||||
int x = static_cast<int>(lua::tointeger(L, 1));
|
||||
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);
|
||||
if (chunk == nullptr) {
|
||||
return lua::pushboolean(L, false);
|
||||
}
|
||||
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) {
|
||||
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 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(
|
||||
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;
|
||||
}
|
||||
|
||||
@ -18,26 +18,6 @@ namespace lua {
|
||||
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 {
|
||||
std::shared_ptr<Heightmap> map;
|
||||
std::unique_ptr<fnl_state> noise;
|
||||
|
||||
@ -117,7 +117,6 @@ void lua::init_state(State* L, StateType stateType) {
|
||||
|
||||
initialize_libs_extends(L);
|
||||
|
||||
newusertype<LuaBytearray>(L);
|
||||
newusertype<LuaHeightmap>(L);
|
||||
newusertype<LuaVoxelFragment>(L);
|
||||
newusertype<LuaCanvas>(L);
|
||||
|
||||
@ -39,14 +39,16 @@ int l_crc32(lua::State* L) {
|
||||
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)) {
|
||||
std::vector<ubyte> bytes;
|
||||
lua::read_bytes_from_table(L, 1, bytes);
|
||||
return lua::pushinteger(L, crc32(value, bytes.data(), bytes.size()));
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ int lua::pushvalue(State* L, const dv::value& value) {
|
||||
break;
|
||||
case value_type::bytes: {
|
||||
const auto& bytes = value.asBytes();
|
||||
newuserdata<LuaBytearray>(L, bytes.data(), bytes.size());
|
||||
create_bytearray(L, bytes.data(), bytes.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -128,18 +128,14 @@ dv::value lua::tovalue(State* L, int idx) {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
case LUA_TUSERDATA: {
|
||||
if (auto bytes = touserdata<LuaBytearray>(L, idx)) {
|
||||
const auto& data = bytes->data();
|
||||
return std::make_shared<dv::objects::Bytes>(data.data(), data.size());
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
"lua type " + std::string(lua_typename(L, type)) +
|
||||
" is not supported"
|
||||
default: {
|
||||
auto data = bytearray_as_string(L, idx);
|
||||
auto bytes = std::make_shared<dv::objects::Bytes>(
|
||||
reinterpret_cast<const ubyte*>(data.data()), data.size()
|
||||
);
|
||||
pop(L);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -746,14 +746,22 @@ namespace lua {
|
||||
}
|
||||
}
|
||||
|
||||
inline std::vector<ubyte> require_bytearray(lua::State* L, int idx) {
|
||||
if (auto* bytearray = lua::touserdata<LuaBytearray>(L, idx)) {
|
||||
return bytearray->data();
|
||||
} else if (lua::istable(L, idx)) {
|
||||
std::vector<ubyte> bytes;
|
||||
read_bytes_from_table(L, idx, bytes);
|
||||
return bytes;
|
||||
}
|
||||
throw std::runtime_error("bytearray expected");
|
||||
inline int create_bytearray(lua::State* L, const void* bytes, size_t size) {
|
||||
lua::requireglobal(L, "Bytearray_construct");
|
||||
lua::pushlstring(
|
||||
L, std::string_view(reinterpret_cast<const char*>(bytes), size)
|
||||
);
|
||||
return lua::call(L, 1, 1);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -5,17 +5,6 @@
|
||||
#include <stdexcept>
|
||||
#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(
|
||||
const float* buffer,
|
||||
uint width,
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "maths/Heightmap.hpp"
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
enum class InterpolationType {
|
||||
NEAREST,
|
||||
@ -13,7 +14,11 @@ enum class InterpolationType {
|
||||
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 {
|
||||
uint width, height;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "Entities.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);
|
||||
std::string bodyTypeName;
|
||||
map.at("type").get(bodyTypeName);
|
||||
if (auto bodyType = BodyType_from(bodyTypeName)) {
|
||||
body.hitbox.type = *bodyType;
|
||||
}
|
||||
BodyTypeMeta.getItem(bodyTypeName, body.hitbox.type);
|
||||
bodymap["crouch"].asBoolean(body.hitbox.crouching);
|
||||
bodymap["damping"].asNumber(body.hitbox.linearDamping);
|
||||
}
|
||||
@ -329,7 +328,7 @@ dv::value Entities::serialize(const Entity& entity) {
|
||||
if (def.save.body.settings) {
|
||||
bodymap["damping"] = rigidbody.hitbox.linearDamping;
|
||||
if (hitbox.type != def.bodyType) {
|
||||
bodymap["type"] = to_string(hitbox.type);
|
||||
bodymap["type"] = BodyTypeMeta.getNameString(hitbox.type);
|
||||
}
|
||||
if (hitbox.crouching) {
|
||||
bodymap["crouch"] = hitbox.crouching;
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "interfaces/Serializable.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
@ -2,26 +2,6 @@
|
||||
|
||||
#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)
|
||||
: type(type),
|
||||
position(position),
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
|
||||
#include "maths/aabb.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
@ -41,8 +41,11 @@ enum class BodyType {
|
||||
STATIC, KINEMATIC, DYNAMIC
|
||||
};
|
||||
|
||||
std::optional<BodyType> BodyType_from(std::string_view str);
|
||||
std::string to_string(BodyType type);
|
||||
VC_ENUM_METADATA(BodyType)
|
||||
{"static", BodyType::STATIC},
|
||||
{"kinematic", BodyType::KINEMATIC},
|
||||
{"dynamic", BodyType::DYNAMIC},
|
||||
VC_ENUM_END
|
||||
|
||||
struct Hitbox {
|
||||
BodyType type;
|
||||
|
||||
@ -1,37 +1,13 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
|
||||
#include "NotePreset.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "data/dv_util.hpp"
|
||||
|
||||
std::string to_string(NoteDisplayMode mode) {
|
||||
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;
|
||||
}
|
||||
#include <vector>
|
||||
|
||||
dv::value NotePreset::serialize() const {
|
||||
return dv::object({
|
||||
{"display", to_string(displayMode)},
|
||||
{"display", NoteDisplayModeMeta.getNameString(displayMode)},
|
||||
{"color", dv::to_value(color)},
|
||||
{"scale", scale},
|
||||
{"render_distance", renderDistance},
|
||||
@ -42,7 +18,7 @@ dv::value NotePreset::serialize() const {
|
||||
|
||||
void NotePreset::deserialize(const dv::value& src) {
|
||||
if (src.has("display")) {
|
||||
displayMode = NoteDisplayMode_from(src["display"].asString()).value();
|
||||
NoteDisplayModeMeta.getItem(src["display"].asString(), displayMode);
|
||||
}
|
||||
if (src.has("color")) {
|
||||
dv::get_vec(src["color"], color);
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "interfaces/Serializable.hpp"
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
enum class NoteDisplayMode {
|
||||
STATIC_BILLBOARD,
|
||||
@ -14,8 +14,12 @@ enum class NoteDisplayMode {
|
||||
PROJECTED
|
||||
};
|
||||
|
||||
std::string to_string(NoteDisplayMode mode);
|
||||
std::optional<NoteDisplayMode> NoteDisplayMode_from(std::string_view s);
|
||||
VC_ENUM_METADATA(NoteDisplayMode)
|
||||
{"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 {
|
||||
NoteDisplayMode displayMode = NoteDisplayMode::STATIC_BILLBOARD;
|
||||
|
||||
@ -1,26 +1,8 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
|
||||
#include "ParticlesPreset.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 {
|
||||
auto root = dv::object();
|
||||
if (frames.empty()) {
|
||||
@ -47,7 +29,7 @@ dv::value ParticlesPreset::serialize() const {
|
||||
root["min_angular_vel"] = minAngularVelocity;
|
||||
root["max_angular_vel"] = maxAngularVelocity;
|
||||
root["spawn_spread"] = dv::to_value(size);
|
||||
root["spawn_shape"] = to_string(spawnShape);
|
||||
root["spawn_shape"] = ParticleSpawnShapeMeta.getName(spawnShape);
|
||||
root["random_sub_uv"] = randomSubUV;
|
||||
return root;
|
||||
}
|
||||
@ -82,7 +64,7 @@ void ParticlesPreset::deserialize(const dv::value& src) {
|
||||
dv::get_vec(src["explosion"], explosion);
|
||||
}
|
||||
if (src.has("spawn_shape")) {
|
||||
spawnShape = ParticleSpawnShape_from(src["spawn_shape"].asString());
|
||||
ParticleSpawnShapeMeta.getItem(src["spawn_shape"].asString(), spawnShape);
|
||||
}
|
||||
if (src.has("frames")) {
|
||||
for (const auto& frame : src["frames"]) {
|
||||
|
||||
@ -5,8 +5,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "interfaces/Serializable.hpp"
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
enum ParticleSpawnShape {
|
||||
enum class ParticleSpawnShape {
|
||||
/// @brief Coordinates are regulary distributed within
|
||||
/// the volume of a ball.
|
||||
BALL = 0,
|
||||
@ -18,8 +19,11 @@ enum ParticleSpawnShape {
|
||||
BOX
|
||||
};
|
||||
|
||||
std::string to_string(ParticleSpawnShape shape);
|
||||
ParticleSpawnShape ParticleSpawnShape_from(std::string_view s);
|
||||
VC_ENUM_METADATA(ParticleSpawnShape)
|
||||
{"ball", ParticleSpawnShape::BALL},
|
||||
{"sphere", ParticleSpawnShape::SPHERE},
|
||||
{"box", ParticleSpawnShape::BOX},
|
||||
VC_ENUM_END
|
||||
|
||||
struct ParticlesPreset : public Serializable {
|
||||
/// @brief Collision detection
|
||||
@ -53,7 +57,7 @@ struct ParticlesPreset : public Serializable {
|
||||
/// @brief Maximum angular velocity
|
||||
float maxAngularVelocity = 0.0f;
|
||||
/// @brief Spawn spread shape
|
||||
ParticleSpawnShape spawnShape = BALL;
|
||||
ParticleSpawnShape spawnShape = ParticleSpawnShape::BALL;
|
||||
/// @brief Spawn spread
|
||||
glm::vec3 spawnSpread {};
|
||||
/// @brief Texture name
|
||||
|
||||
61
src/util/EnumMetadata.hpp
Normal file
61
src/util/EnumMetadata.hpp
Normal 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
|
||||
@ -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)
|
||||
: axes({axisX, axisY, axisZ}) {
|
||||
fix = glm::ivec3(0);
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
@ -10,6 +9,7 @@
|
||||
#include "maths/UVRegion.hpp"
|
||||
#include "maths/aabb.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
struct ParticlesPreset;
|
||||
|
||||
@ -93,8 +93,13 @@ enum class BlockModel {
|
||||
custom
|
||||
};
|
||||
|
||||
std::string to_string(BlockModel model);
|
||||
std::optional<BlockModel> BlockModel_from(std::string_view str);
|
||||
VC_ENUM_METADATA(BlockModel)
|
||||
{"none", BlockModel::none},
|
||||
{"block", BlockModel::block},
|
||||
{"X", BlockModel::xsprite},
|
||||
{"aabb", BlockModel::aabb},
|
||||
{"custom", BlockModel::custom},
|
||||
VC_ENUM_END
|
||||
|
||||
enum class CullingMode {
|
||||
DEFAULT,
|
||||
@ -102,8 +107,11 @@ enum class CullingMode {
|
||||
DISABLED,
|
||||
};
|
||||
|
||||
std::string to_string(CullingMode mode);
|
||||
std::optional<CullingMode> CullingMode_from(std::string_view str);
|
||||
VC_ENUM_METADATA(CullingMode)
|
||||
{"default", CullingMode::DEFAULT},
|
||||
{"optional", CullingMode::OPTIONAL},
|
||||
{"disabled", CullingMode::DISABLED},
|
||||
VC_ENUM_END
|
||||
|
||||
using BoxModel = AABB;
|
||||
|
||||
|
||||
@ -32,18 +32,18 @@ Chunks::Chunks(
|
||||
: events(events),
|
||||
indices(indices),
|
||||
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) {
|
||||
this->events->trigger(LevelEventType::CHUNK_HIDDEN, chunk.get());
|
||||
});
|
||||
}
|
||||
|
||||
void Chunks::configure(int32_t x, int32_t z, uint32_t radius) {
|
||||
setCenter(x, z);
|
||||
uint32_t diameter = radius * 2LL;
|
||||
if (getWidth() != diameter) {
|
||||
resize(diameter, diameter);
|
||||
}
|
||||
setCenter(x, z);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "World.hpp"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
@ -49,7 +50,7 @@ void World::updateTimers(float delta) {
|
||||
void World::writeResources(const Content& content) {
|
||||
auto root = dv::object();
|
||||
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& indices = content.resourceIndices[typeIndex];
|
||||
for (size_t i = 0; i < indices.size(); i++) {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "WorldFiles.hpp"
|
||||
|
||||
#include <cassert>
|
||||
@ -182,8 +183,9 @@ bool WorldFiles::readResourcesData(const Content& content) {
|
||||
}
|
||||
auto root = io::read_json(file);
|
||||
for (const auto& [key, arr] : root.asObject()) {
|
||||
if (auto resType = ResourceType_from(key)) {
|
||||
read_resources_data(content, arr, *resType);
|
||||
ResourceType type;
|
||||
if (ResourceTypeMeta.getItem(key, type)) {
|
||||
read_resources_data(content, arr, type);
|
||||
} else {
|
||||
logger.warning() << "unknown resource type: " << key;
|
||||
}
|
||||
|
||||
@ -355,8 +355,7 @@ void WorldGenerator::generateHeightmap(
|
||||
|
||||
void WorldGenerator::update(int centerX, int centerY, int loadDistance) {
|
||||
surroundMap.setCenter(centerX, centerY);
|
||||
// 2 is safety padding preventing ChunksController rounding problem
|
||||
surroundMap.resize(loadDistance + 2);
|
||||
surroundMap.resize(loadDistance);
|
||||
surroundMap.setCenter(centerX, centerY);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user