Merge branch 'main' into blocks-metadata

This commit is contained in:
MihailRis 2024-08-28 11:59:57 +03:00
commit c2ec0c3d18
35 changed files with 668 additions and 240 deletions

View File

@ -115,17 +115,20 @@ Set specified bits.
## Raycast ## Raycast
```lua ```lua
block.raycast(start: vec3, dir: vec3, max_distance: number, [optional] dest: table) -> { block.raycast(start: vec3, dir: vec3, max_distance: number, [optional] dest: table, [optional] filter: table) -> {
block: int, -- block id block: int, -- block id
endpoint: vec3, -- point of the ray hit point endpoint: vec3, -- point of the ray hit point
iendpoint: vec3, -- position of the block hit by the ray iendpoint: vec3, -- position of the block hit by the ray
length: number, -- ray length length: number, -- ray length
normal: vec3 -- normal vector of the surface hit by the ray normal: vec3, -- normal vector of the surface hit by the ray
} or nil } or nil
``` ```
Casts a ray from the start point in the direction of *dir*. Max_distance specifies the maximum ray length. Casts a ray from the start point in the direction of *dir*. Max_distance specifies the maximum ray length.
Argument `filter` can be used to tell ray what blocks can be skipped(passed through) during ray-casting.
To use filter `dest` argument must be filled with some value(can be nil), it's done for backwards compatability
The function returns a table with the results or nil if the ray does not hit any block. The function returns a table with the results or nil if the ray does not hit any block.
The result will use the destination table instead of creating a new one if the optional argument specified. The result will use the destination table instead of creating a new one if the optional argument specified.

View File

@ -51,7 +51,7 @@ entities.get_all_in_radius(center: vec3, radius: number) -> array<int>
```lua ```lua
entities.raycast(start: vec3, dir: vec3, max_distance: number, entities.raycast(start: vec3, dir: vec3, max_distance: number,
ignore: int, [optional] destination: table) -> table or nil ignore: int, [optional] destination: table, [optional] filter: table) -> table or nil
``` ```
The function is an extended version of [block.raycast](libblock.md#raycast). Returns a table with the results if the ray touches a block or entity. The function is an extended version of [block.raycast](libblock.md#raycast). Returns a table with the results if the ray touches a block or entity.

View File

@ -60,17 +60,20 @@ block.get_picking_item(id: int) -> int
### Raycast ### Raycast
```lua ```lua
block.raycast(start: vec3, dir: vec3, max_distance: number, [опционально] dest: table) -> { block.raycast(start: vec3, dir: vec3, max_distance: number, [опционально] dest: table, [опционально] filter: table) -> {
block: int, -- id блока block: int, -- id блока
endpoint: vec3, -- точка касания луча endpoint: vec3, -- точка касания луча
iendpoint: vec3, -- позиция блока, которого касается луч iendpoint: vec3, -- позиция блока, которого касается луч
length: number, -- длина луча length: number, -- длина луча
normal: vec3 -- вектор нормали поверхности, которой касается луч normal: vec3, -- вектор нормали поверхности, которой касается луч
} или nil } или nil
``` ```
Бросает луч из точки start в направлении dir. Max_distance указывает максимальную длину луча. Бросает луч из точки start в направлении dir. Max_distance указывает максимальную длину луча.
Аргумент `filter` позволяет указать какие блоки являются "прозрачными" для луча, прим.: {"base:glass","base:water"}.
Для использования агрумент `dest` нужно чем-то заполнить(можно nil), это сделано для обратной совместимости
Функция возвращает таблицу с результатами или nil, если луч не касается блока. Функция возвращает таблицу с результатами или nil, если луч не касается блока.
Для результата будет использоваться целевая (dest) таблица вместо создания новой, если указан опциональный аргумент. Для результата будет использоваться целевая (dest) таблица вместо создания новой, если указан опциональный аргумент.

View File

@ -51,7 +51,7 @@ entities.get_all_in_radius(center: vec3, radius: number) -> array<int>
```lua ```lua
entities.raycast(start: vec3, dir: vec3, max_distance: number, entities.raycast(start: vec3, dir: vec3, max_distance: number,
ignore: int, [optional] destination: table) -> table или nil ignore: int, [optional] destination: table, [optional] filter: table) -> table или nil
``` ```
Функция является расширенным вариантом [block.raycast](libblock.md#raycast). Возвращает таблицу с результатами если луч касается блока, либо сущности. Функция является расширенным вариантом [block.raycast](libblock.md#raycast). Возвращает таблицу с результатами если луч касается блока, либо сущности.

View File

@ -22,6 +22,9 @@ local Camera = {__index={
local wrappers = {} local wrappers = {}
cameras.get = function(name) cameras.get = function(name)
if type(name) == 'number' then
return cameras.get(cameras.name(name))
end
local wrapper = wrappers[name] local wrapper = wrappers[name]
if wrapper ~= nil then if wrapper ~= nil then
return wrapper return wrapper

View File

@ -194,6 +194,9 @@ void AssetsLoader::processPreloadConfigs(const Content* content) {
return; return;
} }
for (auto& entry : content->getPacks()) { for (auto& entry : content->getPacks()) {
if (entry.first == "core") {
continue;
}
const auto& pack = entry.second; const auto& pack = entry.second;
auto preloadFile = pack->getInfo().folder / fs::path("preload.json"); auto preloadFile = pack->getInfo().folder / fs::path("preload.json");
if (fs::exists(preloadFile)) { if (fs::exists(preloadFile)) {

View File

@ -12,6 +12,7 @@
#include "coders/obj.hpp" #include "coders/obj.hpp"
#include "constants.hpp" #include "constants.hpp"
#include "data/dynamic.hpp" #include "data/dynamic.hpp"
#include "debug/Logger.hpp"
#include "files/engine_paths.hpp" #include "files/engine_paths.hpp"
#include "files/files.hpp" #include "files/files.hpp"
#include "frontend/UiDocument.hpp" #include "frontend/UiDocument.hpp"
@ -26,6 +27,8 @@
#include "Assets.hpp" #include "Assets.hpp"
#include "AssetsLoader.hpp" #include "AssetsLoader.hpp"
static debug::Logger logger("assetload-funcs");
namespace fs = std::filesystem; namespace fs = std::filesystem;
static bool animation( static bool animation(
@ -263,7 +266,7 @@ static TextureAnimation create_animation(
for (const auto& elem : frameList) { for (const auto& elem : frameList) {
if (!srcAtlas->has(elem.first)) { if (!srcAtlas->has(elem.first)) {
std::cerr << "Unknown frame name: " << elem.first << std::endl; logger.error() << "unknown frame name: " << elem.first;
continue; continue;
} }
region = srcAtlas->get(elem.first); region = srcAtlas->get(elem.first);

View File

@ -65,14 +65,6 @@ public:
return defs[id]; return defs[id];
} }
[[deprecated]]
inline T* getWriteable(blockid_t id) const { // TODO: remove
if (id >= defs.size()) {
return nullptr;
}
return defs[id];
}
inline const T& require(blockid_t id) const { inline const T& require(blockid_t id) const {
return *defs.at(id); return *defs.at(id);
} }
@ -111,14 +103,14 @@ public:
ContentUnitDefs(UptrsMap<std::string, T> defs) : defs(std::move(defs)) { ContentUnitDefs(UptrsMap<std::string, T> defs) : defs(std::move(defs)) {
} }
T* find(const std::string& id) const { const T* find(const std::string& id) const {
const auto& found = defs.find(id); const auto& found = defs.find(id);
if (found == defs.end()) { if (found == defs.end()) {
return nullptr; return nullptr;
} }
return found->second.get(); return found->second.get();
} }
T& require(const std::string& id) const { const T& require(const std::string& id) const {
const auto& found = defs.find(id); const auto& found = defs.find(id);
if (found == defs.end()) { if (found == defs.end()) {
throw std::runtime_error("missing content unit " + id); throw std::runtime_error("missing content unit " + id);

View File

@ -44,6 +44,14 @@ public:
defs[id] = std::make_unique<T>(id); defs[id] = std::make_unique<T>(id);
return *defs[id]; return *defs[id];
} }
// Only fetch existing definition, return null otherwise.
T* get(const std::string& id) {
auto found = defs.find(id);
if (found != defs.end()) {
return &*found->second;
}
return nullptr;
}
auto build() { auto build() {
return std::move(defs); return std::move(defs);

View File

@ -6,6 +6,9 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "Content.hpp"
#include "ContentBuilder.hpp"
#include "ContentPack.hpp"
#include "coders/json.hpp" #include "coders/json.hpp"
#include "core_defs.hpp" #include "core_defs.hpp"
#include "data/dynamic.hpp" #include "data/dynamic.hpp"
@ -18,9 +21,6 @@
#include "util/listutil.hpp" #include "util/listutil.hpp"
#include "util/stringutil.hpp" #include "util/stringutil.hpp"
#include "voxels/Block.hpp" #include "voxels/Block.hpp"
#include "Content.hpp"
#include "ContentBuilder.hpp"
#include "ContentPack.hpp"
namespace fs = std::filesystem; namespace fs = std::filesystem;
@ -123,6 +123,18 @@ void ContentLoader::loadBlock(
) { ) {
auto root = files::read_json(file); auto root = files::read_json(file);
if (root->has("parent")) {
std::string parentName;
root->str("parent", parentName);
auto parentDef = this->builder.blocks.get(parentName);
if (parentDef == nullptr) {
throw std::runtime_error(
"Failed to find parent(" + parentName + ") for " + name
);
}
parentDef->cloneTo(def);
}
root->str("caption", def.caption); root->str("caption", def.caption);
// block texturing // block texturing
@ -289,6 +301,19 @@ void ContentLoader::loadItem(
ItemDef& def, const std::string& name, const fs::path& file ItemDef& def, const std::string& name, const fs::path& file
) { ) {
auto root = files::read_json(file); auto root = files::read_json(file);
if (root->has("parent")) {
std::string parentName;
root->str("parent", parentName);
auto parentDef = this->builder.items.get(parentName);
if (parentDef == nullptr) {
throw std::runtime_error(
"Failed to find parent(" + parentName + ") for " + name
);
}
parentDef->cloneTo(def);
}
root->str("caption", def.caption); root->str("caption", def.caption);
std::string iconTypeStr = ""; std::string iconTypeStr = "";
@ -319,6 +344,19 @@ void ContentLoader::loadEntity(
EntityDef& def, const std::string& name, const fs::path& file EntityDef& def, const std::string& name, const fs::path& file
) { ) {
auto root = files::read_json(file); auto root = files::read_json(file);
if (root->has("parent")) {
std::string parentName;
root->str("parent", parentName);
auto parentDef = this->builder.entities.get(parentName);
if (parentDef == nullptr) {
throw std::runtime_error(
"Failed to find parent(" + parentName + ") for " + name
);
}
parentDef->cloneTo(def);
}
if (auto componentsarr = root->list("components")) { if (auto componentsarr = root->list("components")) {
for (size_t i = 0; i < componentsarr->size(); i++) { for (size_t i = 0; i < componentsarr->size(); i++) {
def.components.emplace_back(componentsarr->str(i)); def.components.emplace_back(componentsarr->str(i));
@ -340,7 +378,8 @@ void ContentLoader::loadEntity(
sensorarr->num(3)}, sensorarr->num(3)},
{sensorarr->num(4), {sensorarr->num(4),
sensorarr->num(5), sensorarr->num(5),
sensorarr->num(6)}} sensorarr->num(6)}
}
); );
} else if (sensorType == "radius") { } else if (sensorType == "radius") {
def.radialSensors.emplace_back(i, sensorarr->num(1)); def.radialSensors.emplace_back(i, sensorarr->num(1));
@ -441,46 +480,157 @@ void ContentLoader::load() {
if (!fs::is_regular_file(pack->getContentFile())) return; if (!fs::is_regular_file(pack->getContentFile())) return;
auto root = files::read_json(pack->getContentFile()); auto root = files::read_json(pack->getContentFile());
std::vector<std::pair<std::string, std::string>> pendingDefs;
auto getJsonParent = [this](const std::string& prefix, const std::string& name) {
auto configFile = pack->folder / fs::path(prefix + "/" + name + ".json");
std::string parent;
if (fs::exists(configFile)) {
auto root = files::read_json(configFile);
if (root->has("parent")) root->str("parent", parent);
}
return parent;
};
auto processName = [this](const std::string& name) {
auto colon = name.find(':');
auto new_name = name;
std::string full =
colon == std::string::npos ? pack->id + ":" + name : name;
if (colon != std::string::npos) new_name[colon] = '/';
return std::make_pair(full, new_name);
};
if (auto blocksarr = root->list("blocks")) { if (auto blocksarr = root->list("blocks")) {
for (size_t i = 0; i < blocksarr->size(); i++) { for (size_t i = 0; i < blocksarr->size(); i++) {
std::string name = blocksarr->str(i); auto [full, name] = processName(blocksarr->str(i));
auto colon = name.find(':'); auto parent = getJsonParent("blocks", name);
std::string full = if (parent.empty() || builder.blocks.get(parent)) {
colon == std::string::npos ? pack->id + ":" + name : name; // No dependency or dependency already loaded/exists in another
if (colon != std::string::npos) name[colon] = '/'; // content pack
auto& def = builder.blocks.create(full); auto& def = builder.blocks.create(full);
if (colon != std::string::npos)
def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
loadBlock(def, full, name); loadBlock(def, full, name);
stats->totalBlocks++; stats->totalBlocks++;
} else {
// Dependency not loaded yet, add to pending items
pendingDefs.emplace_back(full, name);
} }
} }
// Resolve dependencies for pending items
bool progressMade = true;
while (!pendingDefs.empty() && progressMade) {
progressMade = false;
for (auto it = pendingDefs.begin(); it != pendingDefs.end();) {
auto parent = getJsonParent("blocks", it->second);
if (builder.blocks.get(parent)) {
// Dependency resolved or parent exists in another pack,
// load the item
auto& def = builder.blocks.create(it->first);
loadBlock(def, it->first, it->second);
stats->totalBlocks++;
it = pendingDefs.erase(it); // Remove resolved item
progressMade = true;
} else {
++it;
}
}
}
if (!pendingDefs.empty()) {
// Handle circular dependencies or missing dependencies
// You can log an error or throw an exception here if necessary
throw std::runtime_error("Unresolved block dependencies detected.");
}
}
if (auto itemsarr = root->list("items")) { if (auto itemsarr = root->list("items")) {
for (size_t i = 0; i < itemsarr->size(); i++) { for (size_t i = 0; i < itemsarr->size(); i++) {
std::string name = itemsarr->str(i); auto [full, name] = processName(itemsarr->str(i));
auto colon = name.find(':'); auto parent = getJsonParent("items", name);
std::string full = if (parent.empty() || builder.items.get(parent)) {
colon == std::string::npos ? pack->id + ":" + name : name; // No dependency or dependency already loaded/exists in another
if (colon != std::string::npos) name[colon] = '/'; // content pack
auto& def = builder.items.create(full); auto& def = builder.items.create(full);
if (colon != std::string::npos)
def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
loadItem(def, full, name); loadItem(def, full, name);
stats->totalItems++; stats->totalItems++;
} else {
// Dependency not loaded yet, add to pending items
pendingDefs.emplace_back(full, name);
}
}
// Resolve dependencies for pending items
bool progressMade = true;
while (!pendingDefs.empty() && progressMade) {
progressMade = false;
for (auto it = pendingDefs.begin(); it != pendingDefs.end();) {
auto parent = getJsonParent("items", it->second);
if (builder.items.get(parent)) {
// Dependency resolved or parent exists in another pack,
// load the item
auto& def = builder.items.create(it->first);
loadItem(def, it->first, it->second);
stats->totalItems++;
it = pendingDefs.erase(it); // Remove resolved item
progressMade = true;
} else {
++it;
}
}
}
if (!pendingDefs.empty()) {
// Handle circular dependencies or missing dependencies
// You can log an error or throw an exception here if necessary
throw std::runtime_error("Unresolved item dependencies detected.");
} }
} }
if (auto entitiesarr = root->list("entities")) { if (auto entitiesarr = root->list("entities")) {
for (size_t i = 0; i < entitiesarr->size(); i++) { for (size_t i = 0; i < entitiesarr->size(); i++) {
std::string name = entitiesarr->str(i); auto [full, name] = processName(entitiesarr->str(i));
auto colon = name.find(':'); auto parent = getJsonParent("entities", name);
std::string full = if (parent.empty() || builder.entities.get(parent)) {
colon == std::string::npos ? pack->id + ":" + name : name; // No dependency or dependency already loaded/exists in another
if (colon != std::string::npos) name[colon] = '/'; // content pack
auto& def = builder.entities.create(full); auto& def = builder.entities.create(full);
loadEntity(def, full, name); loadEntity(def, full, name);
stats->totalEntities++; stats->totalEntities++;
} else {
// Dependency not loaded yet, add to pending items
pendingDefs.emplace_back(full, name);
}
}
// Resolve dependencies for pending items
bool progressMade = true;
while (!pendingDefs.empty() && progressMade) {
progressMade = false;
for (auto it = pendingDefs.begin(); it != pendingDefs.end();) {
auto parent = getJsonParent("entities", it->second);
if (builder.entities.get(parent)) {
// Dependency resolved or parent exists in another pack,
// load the item
auto& def = builder.entities.create(it->first);
loadEntity(def, it->first, it->second);
stats->totalEntities++;
it = pendingDefs.erase(it); // Remove resolved item
progressMade = true;
} else {
++it;
}
}
}
if (!pendingDefs.empty()) {
// Handle circular dependencies or missing dependencies
// You can log an error or throw an exception here if necessary
throw std::runtime_error(
"Unresolved entities dependencies detected."
);
} }
} }

View File

@ -42,13 +42,13 @@ class ContentLoader {
static void loadCustomBlockModel(Block& def, dynamic::Map* primitives); static void loadCustomBlockModel(Block& def, dynamic::Map* primitives);
static void loadBlockMaterial(BlockMaterial& def, const fs::path& file); static void loadBlockMaterial(BlockMaterial& def, const fs::path& file);
static void loadBlock( void loadBlock(
Block& def, const std::string& name, const fs::path& file Block& def, const std::string& name, const fs::path& file
); );
static void loadItem( void loadItem(
ItemDef& def, const std::string& name, const fs::path& file ItemDef& def, const std::string& name, const fs::path& file
); );
static void loadEntity( void loadEntity(
EntityDef& def, const std::string& name, const fs::path& file EntityDef& def, const std::string& name, const fs::path& file
); );
void loadResources(ResourceType type, dynamic::List* list); void loadResources(ResourceType type, dynamic::List* list);

View File

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
#include <utility> #include <utility>
#include "constants.hpp"
#include "coders/json.hpp" #include "coders/json.hpp"
#include "data/dynamic.hpp" #include "data/dynamic.hpp"
#include "files/engine_paths.hpp" #include "files/engine_paths.hpp"
@ -11,6 +12,12 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
ContentPack ContentPack::createCore(const EnginePaths* paths) {
return ContentPack {
"core", "Core", ENGINE_VERSION_STRING, "", "", paths->getResourcesFolder(), {}
};
}
const std::vector<std::string> ContentPack::RESERVED_NAMES = { const std::vector<std::string> ContentPack::RESERVED_NAMES = {
"res", "abs", "local", "core", "user", "world", "none", "null"}; "res", "abs", "local", "core", "user", "world", "none", "null"};

View File

@ -67,6 +67,8 @@ struct ContentPack {
const fs::path& worldDir, const fs::path& worldDir,
const std::string& name const std::string& name
); );
static ContentPack createCore(const EnginePaths*);
}; };
struct ContentPackStats { struct ContentPackStats {

View File

@ -313,12 +313,17 @@ void Engine::loadContent() {
contentPacks = manager.getAll(names); contentPacks = manager.getAll(names);
std::vector<PathsRoot> resRoots; std::vector<PathsRoot> resRoots;
{
auto pack = ContentPack::createCore(paths);
resRoots.push_back({"core", pack.folder});
ContentLoader(&pack, contentBuilder).load();
load_configs(pack.folder);
}
for (auto& pack : contentPacks) { for (auto& pack : contentPacks) {
resRoots.push_back({pack.id, pack.folder}); resRoots.push_back({pack.id, pack.folder});
ContentLoader(&pack, contentBuilder).load(); ContentLoader(&pack, contentBuilder).load();
load_configs(pack.folder); load_configs(pack.folder);
} }
load_configs(paths->getResourcesFolder());
content = contentBuilder.build(); content = contentBuilder.build();
resPaths = std::make_unique<ResPaths>(resdir, resRoots); resPaths = std::make_unique<ResPaths>(resdir, resRoots);
@ -330,7 +335,13 @@ void Engine::loadContent() {
void Engine::resetContent() { void Engine::resetContent() {
auto resdir = paths->getResourcesFolder(); auto resdir = paths->getResourcesFolder();
resPaths = std::make_unique<ResPaths>(resdir, std::vector<PathsRoot>()); std::vector<PathsRoot> resRoots;
{
auto pack = ContentPack::createCore(paths);
resRoots.push_back({"core", pack.folder});
load_configs(pack.folder);
}
resPaths = std::make_unique<ResPaths>(resdir, resRoots);
contentPacks.clear(); contentPacks.clear();
content.reset(); content.reset();

View File

@ -218,10 +218,6 @@ std::string ResPaths::findRaw(const std::string& filename) const {
return root.name + ":" + filename; return root.name + ":" + filename;
} }
} }
auto resDir = mainRoot;
if (fs::exists(resDir / std::filesystem::path(filename))) {
return "core:" + filename;
}
throw std::runtime_error("could not to find file " + util::quote(filename)); throw std::runtime_error("could not to find file " + util::quote(filename));
} }
@ -236,14 +232,6 @@ std::vector<std::string> ResPaths::listdirRaw(const std::string& folderName) con
entries.emplace_back(root.name + ":" + folderName + "/" + name); entries.emplace_back(root.name + ":" + folderName + "/" + name);
} }
} }
{
auto folder = mainRoot / fs::u8path(folderName);
if (!fs::is_directory(folder)) return entries;
for (const auto& entry : fs::directory_iterator(folder)) {
auto name = entry.path().filename().u8string();
entries.emplace_back("core:" + folderName + "/" + name);
}
}
return entries; return entries;
} }
@ -259,13 +247,6 @@ std::vector<std::filesystem::path> ResPaths::listdir(
entries.push_back(entry.path()); entries.push_back(entry.path());
} }
} }
{
auto folder = mainRoot / fs::u8path(folderName);
if (!fs::is_directory(folder)) return entries;
for (const auto& entry : fs::directory_iterator(folder)) {
entries.push_back(entry.path());
}
}
return entries; return entries;
} }

View File

@ -102,6 +102,7 @@ std::unique_ptr<ImageData> BlocksPreview::draw(
} }
break; break;
case BlockModel::xsprite: { case BlockModel::xsprite: {
shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset));
glm::vec3 right = glm::normalize(glm::vec3(1.f, 0.f, -1.f)); glm::vec3 right = glm::normalize(glm::vec3(1.f, 0.f, -1.f));
batch->sprite( batch->sprite(
right*float(size)*0.43f+glm::vec3(0, size*0.4f, 0), right*float(size)*0.43f+glm::vec3(0, size*0.4f, 0),

View File

@ -5,3 +5,13 @@
ItemDef::ItemDef(const std::string& name) : name(name) { ItemDef::ItemDef(const std::string& name) : name(name) {
caption = util::id_to_caption(name); caption = util::id_to_caption(name);
} }
void ItemDef::cloneTo(ItemDef& dst) {
dst.caption = caption;
dst.stackSize = stackSize;
dst.generated = generated;
std::copy(&emission[0], &emission[3], dst.emission);
dst.iconType = iconType;
dst.icon = icon;
dst.placingBlock = placingBlock;
dst.scriptName = scriptName;
}

View File

@ -44,4 +44,5 @@ struct ItemDef {
ItemDef(const std::string& name); ItemDef(const std::string& name);
ItemDef(const ItemDef&) = delete; ItemDef(const ItemDef&) = delete;
void cloneTo(ItemDef& dst);
}; };

View File

@ -335,7 +335,7 @@ static int l_audio_get_duration(lua::State* L) {
static int l_audio_get_position(lua::State* L) { static int l_audio_get_position(lua::State* L) {
auto speaker = audio::get_speaker(lua::tointeger(L, 1)); auto speaker = audio::get_speaker(lua::tointeger(L, 1));
if (speaker != nullptr) { if (speaker != nullptr) {
return lua::pushvec3_stack(L, speaker->getPosition()); return lua::pushvec_stack(L, speaker->getPosition());
} }
return 0; return 0;
} }
@ -344,7 +344,7 @@ static int l_audio_get_position(lua::State* L) {
static int l_audio_get_velocity(lua::State* L) { static int l_audio_get_velocity(lua::State* L) {
auto speaker = audio::get_speaker(lua::tointeger(L, 1)); auto speaker = audio::get_speaker(lua::tointeger(L, 1));
if (speaker != nullptr) { if (speaker != nullptr) {
return lua::pushvec3_stack(L, speaker->getVelocity()); return lua::pushvec_stack(L, speaker->getVelocity());
} }
return 0; return 0;
} }

View File

@ -57,7 +57,7 @@ static int l_is_extended(lua::State* L) {
static int l_get_size(lua::State* L) { static int l_get_size(lua::State* L) {
if (auto def = require_block(L)) { if (auto def = require_block(L)) {
return lua::pushivec3_stack(L, def->size.x, def->size.y, def->size.z); return lua::pushivec_stack(L, glm::ivec3(def->size));
} }
return 0; return 0;
} }
@ -76,7 +76,7 @@ static int l_seek_origin(lua::State* L) {
auto z = lua::tointeger(L, 3); auto z = lua::tointeger(L, 3);
auto vox = level->chunks->get(x, y, z); auto vox = level->chunks->get(x, y, z);
auto& def = indices->blocks.require(vox->id); auto& def = indices->blocks.require(vox->id);
return lua::pushivec3_stack( return lua::pushivec_stack(
L, level->chunks->seekOrigin({x, y, z}, def, vox->state) L, level->chunks->seekOrigin({x, y, z}, def, vox->state)
); );
} }
@ -117,14 +117,14 @@ static int l_get_x(lua::State* L) {
auto z = lua::tointeger(L, 3); auto z = lua::tointeger(L, 3);
auto vox = level->chunks->get(x, y, z); auto vox = level->chunks->get(x, y, z);
if (vox == nullptr) { if (vox == nullptr) {
return lua::pushivec3_stack(L, 1, 0, 0); return lua::pushivec_stack(L, glm::ivec3(1, 0, 0));
} }
auto& def = level->content->getIndices()->blocks.require(vox->id); const auto& def = level->content->getIndices()->blocks.require(vox->id);
if (!def.rotatable) { if (!def.rotatable) {
return lua::pushivec3_stack(L, 1, 0, 0); return lua::pushivec_stack(L, glm::ivec3(1, 0, 0));
} else { } else {
const CoordSystem& rot = def.rotations.variants[vox->state.rotation]; const CoordSystem& rot = def.rotations.variants[vox->state.rotation];
return lua::pushivec3_stack(L, rot.axisX.x, rot.axisX.y, rot.axisX.z); return lua::pushivec_stack(L, rot.axisX);
} }
} }
@ -134,14 +134,14 @@ static int l_get_y(lua::State* L) {
auto z = lua::tointeger(L, 3); auto z = lua::tointeger(L, 3);
auto vox = level->chunks->get(x, y, z); auto vox = level->chunks->get(x, y, z);
if (vox == nullptr) { if (vox == nullptr) {
return lua::pushivec3_stack(L, 0, 1, 0); return lua::pushivec_stack(L, glm::ivec3(0, 1, 0));
} }
auto& def = level->content->getIndices()->blocks.require(vox->id); const auto& def = level->content->getIndices()->blocks.require(vox->id);
if (!def.rotatable) { if (!def.rotatable) {
return lua::pushivec3_stack(L, 0, 1, 0); return lua::pushivec_stack(L, glm::ivec3(0, 1, 0));
} else { } else {
const CoordSystem& rot = def.rotations.variants[vox->state.rotation]; const CoordSystem& rot = def.rotations.variants[vox->state.rotation];
return lua::pushivec3_stack(L, rot.axisY.x, rot.axisY.y, rot.axisY.z); return lua::pushivec_stack(L, rot.axisY);
} }
} }
@ -151,14 +151,14 @@ static int l_get_z(lua::State* L) {
auto z = lua::tointeger(L, 3); auto z = lua::tointeger(L, 3);
auto vox = level->chunks->get(x, y, z); auto vox = level->chunks->get(x, y, z);
if (vox == nullptr) { if (vox == nullptr) {
return lua::pushivec3_stack(L, 0, 0, 1); return lua::pushivec_stack(L, glm::ivec3(0, 0, 1));
} }
auto& def = level->content->getIndices()->blocks.require(vox->id); const auto& def = level->content->getIndices()->blocks.require(vox->id);
if (!def.rotatable) { if (!def.rotatable) {
return lua::pushivec3_stack(L, 0, 0, 1); return lua::pushivec_stack(L, glm::ivec3(0, 0, 1));
} else { } else {
const CoordSystem& rot = def.rotations.variants[vox->state.rotation]; const CoordSystem& rot = def.rotations.variants[vox->state.rotation];
return lua::pushivec3_stack(L, rot.axisZ.x, rot.axisZ.y, rot.axisZ.z); return lua::pushivec_stack(L, rot.axisZ);
} }
} }
@ -353,13 +353,30 @@ static int l_raycast(lua::State* L) {
auto start = lua::tovec<3>(L, 1); auto start = lua::tovec<3>(L, 1);
auto dir = lua::tovec<3>(L, 2); auto dir = lua::tovec<3>(L, 2);
auto maxDistance = lua::tonumber(L, 3); auto maxDistance = lua::tonumber(L, 3);
std::set<blockid_t> filteredBlocks {};
if (lua::gettop(L) >= 5) {
if (lua::istable(L, 5)) {
int addLen = lua::objlen(L, 5);
for (int i = 0; i < addLen; i++) {
lua::rawgeti(L, i + 1, 5);
auto blockName = std::string(lua::tostring(L, -1));
const Block* block = content->blocks.find(blockName);
if (block != nullptr) {
filteredBlocks.insert(block->rt.id);
}
lua::pop(L);
}
} else {
throw std::runtime_error("table expected for filter");
}
}
glm::vec3 end; glm::vec3 end;
glm::ivec3 normal; glm::ivec3 normal;
glm::ivec3 iend; glm::ivec3 iend;
if (auto voxel = level->chunks->rayCast( if (auto voxel = level->chunks->rayCast(
start, dir, maxDistance, end, normal, iend start, dir, maxDistance, end, normal, iend, filteredBlocks
)) { )) {
if (lua::gettop(L) >= 4) { if (lua::gettop(L) >= 4 && !lua::isnil(L, 4)) {
lua::pushvalue(L, 4); lua::pushvalue(L, 4);
} else { } else {
lua::createtable(L, 0, 5); lua::createtable(L, 0, 5);
@ -452,4 +469,5 @@ const luaL_Reg blocklib[] = {
{"raycast", lua::wrap<l_raycast>}, {"raycast", lua::wrap<l_raycast>},
{"compose_state", lua::wrap<l_compose_state>}, {"compose_state", lua::wrap<l_compose_state>},
{"decompose_state", lua::wrap<l_decompose_state>}, {"decompose_state", lua::wrap<l_decompose_state>},
{NULL, NULL}}; {NULL, NULL}
};

View File

@ -8,6 +8,7 @@
#include "objects/rigging.hpp" #include "objects/rigging.hpp"
#include "physics/Hitbox.hpp" #include "physics/Hitbox.hpp"
#include "voxels/Chunks.hpp" #include "voxels/Chunks.hpp"
#include "voxels/Block.hpp"
#include "window/Camera.hpp" #include "window/Camera.hpp"
using namespace scripting; using namespace scripting;
@ -118,7 +119,25 @@ static int l_raycast(lua::State* L) {
auto start = lua::tovec<3>(L, 1); auto start = lua::tovec<3>(L, 1);
auto dir = lua::tovec<3>(L, 2); auto dir = lua::tovec<3>(L, 2);
auto maxDistance = lua::tonumber(L, 3); auto maxDistance = lua::tonumber(L, 3);
auto ignore = lua::tointeger(L, 4); auto ignoreEntityId = lua::tointeger(L, 4);
std::set<blockid_t> filteredBlocks {};
if (lua::gettop(L) >= 6) {
if (lua::istable(L, 6)) {
int addLen = lua::objlen(L, 6);
for (int i = 0; i < addLen; i++) {
lua::rawgeti(L, i + 1, 6);
auto blockName = std::string(lua::tostring(L, -1));
const Block* block = content->blocks.find(blockName);
if (block != nullptr) {
filteredBlocks.insert(block->rt.id);
}
lua::pop(L);
}
} else {
throw std::runtime_error("table expected for filter");
}
}
glm::vec3 end; glm::vec3 end;
glm::ivec3 normal; glm::ivec3 normal;
glm::ivec3 iend; glm::ivec3 iend;
@ -126,13 +145,14 @@ static int l_raycast(lua::State* L) {
blockid_t block = BLOCK_VOID; blockid_t block = BLOCK_VOID;
if (auto voxel = level->chunks->rayCast( if (auto voxel = level->chunks->rayCast(
start, dir, maxDistance, end, normal, iend start, dir, maxDistance, end, normal, iend, filteredBlocks
)) { )) {
maxDistance = glm::distance(start, end); maxDistance = glm::distance(start, end);
block = voxel->id; block = voxel->id;
} }
if (auto ray = level->entities->rayCast(start, dir, maxDistance, ignore)) { if (auto ray =
if (lua::gettop(L) >= 5) { level->entities->rayCast(start, dir, maxDistance, ignoreEntityId)) {
if (lua::gettop(L) >= 5 && !lua::isnil(L, 5)) {
lua::pushvalue(L, 5); lua::pushvalue(L, 5);
} else { } else {
lua::createtable(L, 0, 6); lua::createtable(L, 0, 6);
@ -157,7 +177,7 @@ static int l_raycast(lua::State* L) {
lua::setfield(L, "entity"); lua::setfield(L, "entity");
return 1; return 1;
} else if (block != BLOCK_VOID) { } else if (block != BLOCK_VOID) {
if (lua::gettop(L) >= 5) { if (lua::gettop(L) >= 5 && !lua::isnil(L, 5)) {
lua::pushvalue(L, 5); lua::pushvalue(L, 5);
} else { } else {
lua::createtable(L, 0, 5); lua::createtable(L, 0, 5);
@ -194,4 +214,5 @@ const luaL_Reg entitylib[] = {
{"get_all_in_box", lua::wrap<l_get_all_in_box>}, {"get_all_in_box", lua::wrap<l_get_all_in_box>},
{"get_all_in_radius", lua::wrap<l_get_all_in_radius>}, {"get_all_in_radius", lua::wrap<l_get_all_in_radius>},
{"raycast", lua::wrap<l_raycast>}, {"raycast", lua::wrap<l_raycast>},
{NULL, NULL}}; {NULL, NULL}
};

View File

@ -49,9 +49,9 @@ static int l_mul(lua::State* L) {
switch (argc) { switch (argc) {
case 2: { case 2: {
if (len2 == 4) { if (len2 == 4) {
return lua::pushvec4_stack(L, matrix1 * lua::tovec4(L, 2)); return lua::pushvec(L, matrix1 * lua::tovec4(L, 2));
} else if (len2 == 3) { } else if (len2 == 3) {
return lua::pushvec3_stack( return lua::pushvec(
L, matrix1 * glm::vec4(lua::tovec3(L, 2), 1.0f) L, matrix1 * glm::vec4(lua::tovec3(L, 2), 1.0f)
); );
} }

View File

@ -17,7 +17,7 @@ inline std::shared_ptr<Player> get_player(lua::State* L, int idx) {
static int l_get_pos(lua::State* L) { static int l_get_pos(lua::State* L) {
if (auto player = get_player(L, 1)) { if (auto player = get_player(L, 1)) {
return lua::pushvec3_stack(L, player->getPosition()); return lua::pushvec_stack(L, player->getPosition());
} }
return 0; return 0;
} }
@ -37,7 +37,7 @@ static int l_set_pos(lua::State* L) {
static int l_get_vel(lua::State* L) { static int l_get_vel(lua::State* L) {
if (auto player = get_player(L, 1)) { if (auto player = get_player(L, 1)) {
if (auto hitbox = player->getHitbox()) { if (auto hitbox = player->getHitbox()) {
return lua::pushvec3_stack(L, hitbox->velocity); return lua::pushvec_stack(L, hitbox->velocity);
} }
} }
return 0; return 0;
@ -59,7 +59,7 @@ static int l_set_vel(lua::State* L) {
static int l_get_rot(lua::State* L) { static int l_get_rot(lua::State* L) {
if (auto player = get_player(L, 1)) { if (auto player = get_player(L, 1)) {
return lua::pushvec3_stack(L, player->cam); return lua::pushvec_stack(L, player->cam);
} }
return 0; return 0;
} }
@ -133,7 +133,7 @@ static int l_get_selected_block(lua::State* L) {
if (player->selection.vox.id == BLOCK_VOID) { if (player->selection.vox.id == BLOCK_VOID) {
return 0; return 0;
} }
return lua::pushivec3_stack(L, player->selection.position); return lua::pushivec_stack(L, player->selection.position);
} }
return 0; return 0;
} }
@ -149,15 +149,13 @@ static int l_get_selected_entity(lua::State* L) {
static int l_get_spawnpoint(lua::State* L) { static int l_get_spawnpoint(lua::State* L) {
if (auto player = get_player(L, 1)) { if (auto player = get_player(L, 1)) {
return lua::pushvec3_stack(L, player->getSpawnPoint()); return lua::pushvec_stack(L, player->getSpawnPoint());
} }
return 0; return 0;
} }
static int l_set_spawnpoint(lua::State* L) { static int l_set_spawnpoint(lua::State* L) {
auto player = get_player(L, 1); if (auto player = get_player(L, 1)) {
if (player) {
auto x = lua::tonumber(L, 2); auto x = lua::tonumber(L, 2);
auto y = lua::tonumber(L, 3); auto y = lua::tonumber(L, 3);
auto z = lua::tonumber(L, 4); auto z = lua::tonumber(L, 4);

View File

@ -1,5 +1,7 @@
#include "debug/Logger.hpp" #include <iostream>
#include "api_lua.hpp" #include "api_lua.hpp"
#include "debug/Logger.hpp"
static debug::Logger logger("lua-debug"); static debug::Logger logger("lua-debug");
@ -21,6 +23,128 @@ static int l_debug_log(lua::State* L) {
return 0; return 0;
} }
const int MAX_DEPTH = 10;
int l_debug_print(lua::State* L) {
auto addIndentation = [](int depth) {
for (int i = 0; i < depth; ++i) std::cout << " ";
};
auto printHexData = [](const void* ptr, size_t size) {
const auto* bytePtr = reinterpret_cast<const uint8_t*>(ptr);
for (size_t i = 0; i < size; ++i) {
std::cout << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(bytePtr[i])
<< ((i + 1) % 8 == 0 && i + 1 < size ? "\n" : " ");
}
};
auto printEscapedString = [](const char* str) {
while (*str) {
switch (*str) {
case '\\': std::cout << "\\\\"; break;
case '\"': std::cout << "\\\""; break;
case '\n': std::cout << "\\n"; break;
case '\t': std::cout << "\\t"; break;
case '\r': std::cout << "\\r"; break;
case '\b': std::cout << "\\b"; break;
case '\f': std::cout << "\\f"; break;
default:
if (iscntrl(static_cast<unsigned char>(*str))) {
// Print other control characters in \xHH format
std::cout << "\\x" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(static_cast<unsigned char>(*str)) << std::dec;
} else {
std::cout << *str;
}
break;
}
++str;
}
};
std::function<void(int, int, bool)> debugPrint = [&](int index,
int depth,
bool is_key) {
if (depth > MAX_DEPTH) {
std::cout << "{...}";
return;
}
switch (lua::type(L, index)) {
case LUA_TSTRING:
if (is_key){
std::cout << lua::tostring(L, index);
}else{
std::cout << "\"";
printEscapedString(lua::tostring(L, index));
std::cout << "\"";
}
break;
case LUA_TBOOLEAN:
std::cout << (lua::toboolean(L, index) ? "true" : "false");
break;
case LUA_TNUMBER:
std::cout << lua::tonumber(L, index);
break;
case LUA_TTABLE: {
bool is_list = lua::objlen(L, index) > 0, hadItems = false;
int absTableIndex =
index > 0 ? index : lua::gettop(L) + index + 1;
std::cout << "{";
lua::pushnil(L);
while (lua::next(L, absTableIndex) != 0) {
if (hadItems)
std::cout << "," << '\n';
else
std::cout << '\n';
addIndentation(depth + 1);
if (!is_list) {
debugPrint(-2, depth, true);
std::cout << " = ";
}
debugPrint(-1, depth + 1, false);
lua::pop(L, 1);
hadItems = true;
}
if (hadItems) std::cout << '\n';
addIndentation(depth);
std::cout << "}";
break;
}
case LUA_TFUNCTION:
std::cout << "function(0x" << std::hex
<< lua::topointer(L, index) << std::dec << ")";
break;
case LUA_TUSERDATA:
std::cout << "userdata:\n";
printHexData(lua::topointer(L, index), lua::objlen(L, index));
break;
case LUA_TLIGHTUSERDATA:
std::cout << "lightuserdata:\n";
printHexData(lua::topointer(L, index), sizeof(void*));
break;
case LUA_TNIL:
std::cout << "nil";
break;
default:
std::cout << lua::type_name(L, lua::type(L, index));
break;
}
};
int n = lua::gettop(L);
std::cout << "debug.print(" << '\n';
for (int i = 1; i <= n; ++i) {
addIndentation(1);
debugPrint(i, 1, false);
if (i < n) std::cout << "," << '\n';
}
std::cout << '\n' << ")" << std::endl;
lua::pop(L, n);
return 0;
}
void initialize_libs_extends(lua::State* L) { void initialize_libs_extends(lua::State* L) {
if (lua::getglobal(L, "debug")) { if (lua::getglobal(L, "debug")) {
lua::pushcfunction(L, lua::wrap<l_debug_error>); lua::pushcfunction(L, lua::wrap<l_debug_error>);
@ -32,6 +156,9 @@ void initialize_libs_extends(lua::State* L) {
lua::pushcfunction(L, lua::wrap<l_debug_log>); lua::pushcfunction(L, lua::wrap<l_debug_log>);
lua::setfield(L, "log"); lua::setfield(L, "log");
lua::pushcfunction(L, lua::wrap<l_debug_print>);
lua::setfield(L, "print");
lua::pop(L); lua::pop(L);
} }
} }

View File

@ -4,7 +4,7 @@
#include <typeinfo> #include <typeinfo>
#include <unordered_map> #include <unordered_map>
#include "lua_commons.hpp" #include "lua_wrapper.hpp"
#include "lua_custom_types.hpp" #include "lua_custom_types.hpp"
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
@ -18,68 +18,6 @@ namespace lua {
std::string env_name(int env); std::string env_name(int env);
template <lua_CFunction func>
int wrap(lua_State* L) {
int result = 0;
try {
result = func(L);
}
// transform exception with description into lua_error
catch (std::exception& e) {
luaL_error(L, e.what());
}
// Rethrow any other exception (lua error for example)
catch (...) {
throw;
}
return result;
}
inline void pop(lua::State* L, int n = 1) {
lua_pop(L, n);
}
inline void insert(lua::State* L, int idx) {
lua_insert(L, idx);
}
inline void remove(lua::State* L, int idx) {
lua_remove(L, idx);
}
inline int gettop(lua::State* L) {
return lua_gettop(L);
}
inline size_t objlen(lua::State* L, int idx) {
return lua_objlen(L, idx);
}
inline int next(lua::State* L, int idx) {
return lua_next(L, idx);
}
inline int type(lua::State* L, int idx) {
return lua_type(L, idx);
}
inline const char* type_name(lua::State* L, int idx) {
return lua_typename(L, idx);
}
inline int rawget(lua::State* L, int idx = -2) {
lua_rawget(L, idx);
return 1;
}
inline int rawgeti(lua::State* L, int n, int idx = -1) {
lua_rawgeti(L, idx, n);
return 1;
}
inline void rawseti(lua::State* L, int n, int idx = -2) {
lua_rawseti(L, idx, n);
}
inline int createtable(lua::State* L, int narr, int nrec) {
lua_createtable(L, narr, nrec);
return 1;
}
inline bool isnil(lua::State* L, int idx) {
return lua_isnil(L, idx);
}
inline bool getglobal(lua::State* L, const std::string& name) { inline bool getglobal(lua::State* L, const std::string& name) {
lua_getglobal(L, name.c_str()); lua_getglobal(L, name.c_str());
if (isnil(L, -1)) { if (isnil(L, -1)) {
@ -107,25 +45,8 @@ namespace lua {
return true; return true;
} }
// function wrappers with number of pushed values as return value
inline int pushnil(lua::State* L) {
lua_pushnil(L);
return 1;
}
inline int pushinteger(lua::State* L, lua::Integer x) {
lua_pushinteger(L, x);
return 1;
}
inline int pushnumber(lua::State* L, lua::Number x) {
lua_pushnumber(L, x);
return 1;
}
template <int n> template <int n>
inline int pushvec(lua::State* L, glm::vec<n, float> vec) { inline int pushvec(lua::State* L, const glm::vec<n, float>& vec) {
createtable(L, n, 0); createtable(L, n, 0);
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
pushnumber(L, vec[i]); pushnumber(L, vec[i]);
@ -135,7 +56,7 @@ namespace lua {
} }
template <int n> template <int n>
inline int pushivec(lua::State* L, glm::vec<n, int> vec) { inline int pushivec(lua::State* L, const glm::vec<n, int>& vec) {
createtable(L, n, 0); createtable(L, n, 0);
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
pushinteger(L, vec[i]); pushinteger(L, vec[i]);
@ -144,34 +65,20 @@ namespace lua {
return 1; return 1;
} }
inline int pushivec3_stack( template<int n>
lua::State* L, lua::Integer x, lua::Integer y, lua::Integer z inline int pushvec_stack(lua::State* L, const glm::vec<n, float>& vec) {
) { for (int i = 0; i < n; i++) {
pushinteger(L, x); pushnumber(L, vec[i]);
pushinteger(L, y); }
pushinteger(L, z); return n;
return 3;
} }
inline int pushivec3_stack(lua::State* L, glm::ivec3 vec) { template<int n>
pushinteger(L, vec.x); inline int pushivec_stack(lua::State* L, const glm::vec<n, int>& vec) {
pushinteger(L, vec.y); for (int i = 0; i < n; i++) {
pushinteger(L, vec.z); pushinteger(L, vec[i]);
return 3;
} }
return n;
inline int pushvec3_stack(lua::State* L, glm::vec3 vec) {
pushnumber(L, vec.x);
pushnumber(L, vec.y);
pushnumber(L, vec.z);
return 3;
}
inline int pushvec4_stack(lua::State* L, glm::vec4 vec) {
pushnumber(L, vec.x);
pushnumber(L, vec.y);
pushnumber(L, vec.z);
pushnumber(L, vec.w);
return 4;
} }
inline void setmetatable(lua::State* L, int idx = -2) { inline void setmetatable(lua::State* L, int idx = -2) {
@ -637,4 +544,40 @@ namespace lua {
luaL_setfuncs(L, libfuncs, 0); luaL_setfuncs(L, libfuncs, 0);
setglobal(L, name); setglobal(L, name);
} }
inline int requirefield(lua::State* L, const std::string& name, int idx = -1) {
if (getfield(L, name, idx)) {
return 1;
}
throw std::runtime_error("object has no member '"+name+"'");
}
inline const char* require_string_field(
lua::State* L, const std::string& name, int idx=-1
) {
requirefield(L, name, idx);
auto value = require_string(L, -1);
lua::pop(L);
return value;
}
inline Integer require_integer_field(
lua::State* L, const std::string& name, int idx=-1
) {
requirefield(L, name, idx);
auto value = tointeger(L, -1);
lua::pop(L);
return value;
}
inline bool get_boolean_field(
lua::State* L, const std::string& name, bool def, int idx=-1
) {
if (getfield(L, name, idx)) {
bool value = toboolean(L, -1);
pop(L);
return value;
}
return def;
}
} }

View File

@ -0,0 +1,85 @@
#pragma once
#include "lua_commons.hpp"
namespace lua {
template <lua_CFunction func>
int wrap(lua_State* L) {
int result = 0;
try {
result = func(L);
}
// transform exception with description into lua_error
catch (std::exception& e) {
luaL_error(L, e.what());
}
// Rethrow any other exception (lua error for example)
catch (...) {
throw;
}
return result;
}
inline void pop(lua::State* L, int n = 1) {
lua_pop(L, n);
}
inline void insert(lua::State* L, int idx) {
lua_insert(L, idx);
}
inline void remove(lua::State* L, int idx) {
lua_remove(L, idx);
}
inline int gettop(lua::State* L) {
return lua_gettop(L);
}
inline size_t objlen(lua::State* L, int idx) {
return lua_objlen(L, idx);
}
inline int next(lua::State* L, int idx) {
return lua_next(L, idx);
}
inline int type(lua::State* L, int idx) {
return lua_type(L, idx);
}
inline const char* type_name(lua::State* L, int idx) {
return lua_typename(L, idx);
}
inline int rawget(lua::State* L, int idx = -2) {
lua_rawget(L, idx);
return 1;
}
inline int rawgeti(lua::State* L, int n, int idx = -1) {
lua_rawgeti(L, idx, n);
return 1;
}
inline void rawseti(lua::State* L, int n, int idx = -2) {
lua_rawseti(L, idx, n);
}
inline int createtable(lua::State* L, int narr, int nrec) {
lua_createtable(L, narr, nrec);
return 1;
}
inline bool isnil(lua::State* L, int idx) {
return lua_isnil(L, idx);
}
// function wrappers with number of pushed values as return value
inline int pushnil(lua::State* L) {
lua_pushnil(L);
return 1;
}
inline int pushinteger(lua::State* L, lua::Integer x) {
lua_pushinteger(L, x);
return 1;
}
inline int pushnumber(lua::State* L, lua::Number x) {
lua_pushnumber(L, x);
return 1;
}
}

View File

@ -39,7 +39,6 @@ LevelController* scripting::controller = nullptr;
static void load_script(const fs::path& name, bool throwable) { static void load_script(const fs::path& name, bool throwable) {
auto paths = scripting::engine->getPaths(); auto paths = scripting::engine->getPaths();
fs::path file = paths->getResourcesFolder() / fs::path("scripts") / name; fs::path file = paths->getResourcesFolder() / fs::path("scripts") / name;
std::string src = files::read_string(file); std::string src = files::read_string(file);
auto L = lua::get_main_thread(); auto L = lua::get_main_thread();
lua::loadbuffer(L, 0, src, file.u8string()); lua::loadbuffer(L, 0, src, file.u8string());
@ -206,14 +205,14 @@ void scripting::on_blocks_tick(const Block& block, int tps) {
void scripting::update_block(const Block& block, int x, int y, int z) { void scripting::update_block(const Block& block, int x, int y, int z) {
std::string name = block.name + ".update"; std::string name = block.name + ".update";
lua::emit_event(lua::get_main_thread(), name, [x, y, z](auto L) { lua::emit_event(lua::get_main_thread(), name, [x, y, z](auto L) {
return lua::pushivec3_stack(L, x, y, z); return lua::pushivec_stack(L, glm::ivec3(x, y, z));
}); });
} }
void scripting::random_update_block(const Block& block, int x, int y, int z) { void scripting::random_update_block(const Block& block, int x, int y, int z) {
std::string name = block.name + ".randupdate"; std::string name = block.name + ".randupdate";
lua::emit_event(lua::get_main_thread(), name, [x, y, z](auto L) { lua::emit_event(lua::get_main_thread(), name, [x, y, z](auto L) {
return lua::pushivec3_stack(L, x, y, z); return lua::pushivec_stack(L, glm::ivec3(x, y, z));
}); });
} }
@ -222,13 +221,13 @@ void scripting::on_block_placed(
) { ) {
std::string name = block.name + ".placed"; std::string name = block.name + ".placed";
lua::emit_event(lua::get_main_thread(), name, [x, y, z, player](auto L) { lua::emit_event(lua::get_main_thread(), name, [x, y, z, player](auto L) {
lua::pushivec3_stack(L, x, y, z); lua::pushivec_stack(L, glm::ivec3(x, y, z));
lua::pushinteger(L, player ? player->getId() : -1); lua::pushinteger(L, player ? player->getId() : -1);
return 4; return 4;
}); });
auto world_event_args = [&](lua::State* L) { auto world_event_args = [&](lua::State* L) {
lua::pushinteger(L, block.rt.id); lua::pushinteger(L, block.rt.id);
lua::pushivec3_stack(L, x, y, z); lua::pushivec_stack(L, glm::ivec3(x, y, z));
lua::pushinteger(L, player ? player->getId() : -1); lua::pushinteger(L, player ? player->getId() : -1);
return 5; return 5;
}; };
@ -252,7 +251,7 @@ void scripting::on_block_broken(
lua::get_main_thread(), lua::get_main_thread(),
name, name,
[x, y, z, player](auto L) { [x, y, z, player](auto L) {
lua::pushivec3_stack(L, x, y, z); lua::pushivec_stack(L, glm::ivec3(x, y, z));
lua::pushinteger(L, player ? player->getId() : -1); lua::pushinteger(L, player ? player->getId() : -1);
return 4; return 4;
} }
@ -260,7 +259,7 @@ void scripting::on_block_broken(
} }
auto world_event_args = [&](lua::State* L) { auto world_event_args = [&](lua::State* L) {
lua::pushinteger(L, block.rt.id); lua::pushinteger(L, block.rt.id);
lua::pushivec3_stack(L, x, y, z); lua::pushivec_stack(L, glm::ivec3(x, y, z));
lua::pushinteger(L, player ? player->getId() : -1); lua::pushinteger(L, player ? player->getId() : -1);
return 5; return 5;
}; };
@ -280,7 +279,7 @@ bool scripting::on_block_interact(
) { ) {
std::string name = block.name + ".interact"; std::string name = block.name + ".interact";
return lua::emit_event(lua::get_main_thread(), name, [pos, player](auto L) { return lua::emit_event(lua::get_main_thread(), name, [pos, player](auto L) {
lua::pushivec3_stack(L, pos.x, pos.y, pos.z); lua::pushivec_stack(L, pos);
lua::pushinteger(L, player->getId()); lua::pushinteger(L, player->getId());
return 4; return 4;
}); });
@ -303,7 +302,7 @@ bool scripting::on_item_use_on_block(
lua::get_main_thread(), lua::get_main_thread(),
name, name,
[ipos, normal, player](auto L) { [ipos, normal, player](auto L) {
lua::pushivec3_stack(L, ipos.x, ipos.y, ipos.z); lua::pushivec_stack(L, ipos);
lua::pushinteger(L, player->getId()); lua::pushinteger(L, player->getId());
lua::pushivec(L, normal); lua::pushivec(L, normal);
return 5; return 5;
@ -319,7 +318,7 @@ bool scripting::on_item_break_block(
lua::get_main_thread(), lua::get_main_thread(),
name, name,
[x, y, z, player](auto L) { [x, y, z, player](auto L) {
lua::pushivec3_stack(L, x, y, z); lua::pushivec_stack(L, glm::ivec3(x, y, z));
lua::pushinteger(L, player->getId()); lua::pushinteger(L, player->getId());
return 4; return 4;
} }

View File

@ -75,7 +75,7 @@ static sensorcallback create_sensor_callback(Entities* entities) {
} }
static void initialize_body( static void initialize_body(
EntityDef& def, Rigidbody& body, entityid_t id, Entities* entities const EntityDef& def, Rigidbody& body, entityid_t id, Entities* entities
) { ) {
body.sensors.resize(def.radialSensors.size() + def.boxSensors.size()); body.sensors.resize(def.radialSensors.size() + def.boxSensors.size());
for (auto& [i, box] : def.boxSensors) { for (auto& [i, box] : def.boxSensors) {
@ -111,7 +111,7 @@ static void initialize_body(
} }
entityid_t Entities::spawn( entityid_t Entities::spawn(
EntityDef& def, const EntityDef& def,
glm::vec3 position, glm::vec3 position,
dynamic::Map_sptr args, dynamic::Map_sptr args,
dynamic::Map_sptr saved, dynamic::Map_sptr saved,

View File

@ -202,7 +202,7 @@ public:
); );
entityid_t spawn( entityid_t spawn(
EntityDef& def, const EntityDef& def,
glm::vec3 position, glm::vec3 position,
dynamic::Map_sptr args = nullptr, dynamic::Map_sptr args = nullptr,
dynamic::Map_sptr saved = nullptr, dynamic::Map_sptr saved = nullptr,

12
src/objects/EntityDef.cpp Normal file
View File

@ -0,0 +1,12 @@
#include "EntityDef.hpp"
void EntityDef::cloneTo(EntityDef& dst) {
dst.components = components;
dst.bodyType = bodyType;
dst.hitbox = hitbox;
dst.boxSensors = boxSensors;
dst.radialSensors = radialSensors;
dst.skeletonName = skeletonName;
dst.blocking = blocking;
dst.save = save;
}

View File

@ -56,4 +56,6 @@ struct EntityDef {
EntityDef(const std::string& name) : name(name) {} EntityDef(const std::string& name) : name(name) {}
EntityDef(const EntityDef&) = delete; EntityDef(const EntityDef&) = delete;
void cloneTo(EntityDef& dst);
}; };

View File

@ -64,7 +64,8 @@ const BlockRotProfile BlockRotProfile::NONE {
{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, // West {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, // West
{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, // Up {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, // Up
{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, // Down {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, // Down
}}; }
};
const BlockRotProfile BlockRotProfile::PIPE { const BlockRotProfile BlockRotProfile::PIPE {
"pipe", "pipe",
@ -75,7 +76,8 @@ const BlockRotProfile BlockRotProfile::PIPE {
{{0, 0, -1}, {1, 0, 0}, {0, -1, 0}}, // West {{0, 0, -1}, {1, 0, 0}, {0, -1, 0}}, // West
{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, // Up {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, // Up
{{1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, // Down {{1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, // Down
}}; }
};
const BlockRotProfile BlockRotProfile::PANE { const BlockRotProfile BlockRotProfile::PANE {
"pane", "pane",
@ -84,7 +86,8 @@ const BlockRotProfile BlockRotProfile::PANE {
{{0, 0, -1}, {0, 1, 0}, {1, 0, 0}}, // East {{0, 0, -1}, {0, 1, 0}, {1, 0, 0}}, // East
{{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}}, // South {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}}, // South
{{0, 0, 1}, {0, 1, 0}, {-1, 0, 0}}, // West {{0, 0, 1}, {0, 1, 0}, {-1, 0, 0}}, // West
}}; }
};
Block::Block(const std::string& name) Block::Block(const std::string& name)
: name(name), : name(name),
@ -95,10 +98,43 @@ Block::Block(const std::string& name)
TEXTURE_NOTFOUND, TEXTURE_NOTFOUND,
TEXTURE_NOTFOUND, TEXTURE_NOTFOUND,
TEXTURE_NOTFOUND, TEXTURE_NOTFOUND,
TEXTURE_NOTFOUND} { TEXTURE_NOTFOUND
} {
} }
Block::Block(std::string name, const std::string& texture) Block::Block(std::string name, const std::string& texture)
: name(std::move(name)), : name(std::move(name)),
textureFaces {texture, texture, texture, texture, texture, texture} { textureFaces {texture, texture, texture, texture, texture, texture} {
} }
void Block::cloneTo(Block& dst) {
dst.caption = caption;
for (int i = 0; i < 6; i++) {
dst.textureFaces[i] = textureFaces[i];
}
dst.modelTextures = modelTextures;
dst.modelBoxes = modelBoxes;
dst.modelExtraPoints = modelExtraPoints;
dst.modelUVs = modelUVs;
dst.material = material;
std::copy(&emission[0], &emission[3], dst.emission);
dst.size = size;
dst.model = model;
dst.lightPassing = lightPassing;
dst.skyLightPassing = skyLightPassing;
dst.shadeless = shadeless;
dst.ambientOcclusion = ambientOcclusion;
dst.obstacle = obstacle;
dst.selectable = selectable;
dst.replaceable = replaceable;
dst.breakable = breakable;
dst.rotatable = rotatable;
dst.grounded = grounded;
dst.hidden = hidden;
dst.hitboxes = hitboxes;
dst.rotations = rotations;
dst.pickingItem = pickingItem;
dst.scriptName = scriptName;
dst.uiLayout = uiLayout;
dst.inventorySize = inventorySize;
dst.tickInterval = tickInterval;
}

View File

@ -211,6 +211,8 @@ public:
Block(const std::string& name); Block(const std::string& name);
Block(std::string name, const std::string& texture); Block(std::string name, const std::string& texture);
Block(const Block&) = delete; Block(const Block&) = delete;
void cloneTo(Block& dst);
}; };
inline glm::ivec3 get_ground_direction(const Block& def, int rotation) { inline glm::ivec3 get_ground_direction(const Block& def, int rotation) {

View File

@ -414,7 +414,8 @@ voxel* Chunks::rayCast(
float maxDist, float maxDist,
glm::vec3& end, glm::vec3& end,
glm::ivec3& norm, glm::ivec3& norm,
glm::ivec3& iend glm::ivec3& iend,
std::set<blockid_t> filter
) { ) {
float px = start.x; float px = start.x;
float py = start.y; float py = start.y;
@ -454,8 +455,10 @@ voxel* Chunks::rayCast(
if (voxel == nullptr) { if (voxel == nullptr) {
return nullptr; return nullptr;
} }
const auto& def = indices->blocks.require(voxel->id); const auto& def = indices->blocks.require(voxel->id);
if (def.selectable) { if ((filter.empty() && def.selectable) ||
(!filter.empty() && filter.find(def.rt.id) == filter.end())) {
end.x = px + t * dx; end.x = px + t * dx;
end.y = py + t * dy; end.y = py + t * dy;
end.z = pz + t * dz; end.z = pz + t * dz;
@ -750,7 +753,9 @@ void Chunks::save(Chunk* chunk) {
chunk->flags.entities = true; chunk->flags.entities = true;
} }
worldFiles->getRegions().put( worldFiles->getRegions().put(
chunk, json::to_binary(root, true) chunk,
chunk->flags.entities ? json::to_binary(root, true)
: std::vector<ubyte>()
); );
} }
} }

View File

@ -4,6 +4,7 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <memory> #include <memory>
#include <set>
#include <vector> #include <vector>
#include "typedefs.hpp" #include "typedefs.hpp"
@ -93,7 +94,8 @@ public:
float maxLength, float maxLength,
glm::vec3& end, glm::vec3& end,
glm::ivec3& norm, glm::ivec3& norm,
glm::ivec3& iend glm::ivec3& iend,
std::set<blockid_t> filter = {}
); );
glm::vec3 rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDist); glm::vec3 rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDist);