Merge branch 'main' into blocks-metadata
This commit is contained in:
commit
c2ec0c3d18
@ -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.
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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) таблица вместо создания новой, если указан опциональный аргумент.
|
||||||
|
|||||||
@ -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). Возвращает таблицу с результатами если луч касается блока, либо сущности.
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)) {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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"};
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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),
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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}
|
||||||
|
};
|
||||||
|
|||||||
@ -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}
|
||||||
|
};
|
||||||
|
|||||||
@ -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)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
85
src/logic/scripting/lua/lua_wrapper.hpp
Normal file
85
src/logic/scripting/lua/lua_wrapper.hpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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
12
src/objects/EntityDef.cpp
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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>()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user