mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-06 03:21:49 +00:00
Merge branch 'main' into environments
This commit is contained in:
commit
f9bc401236
134 changed files with 3186 additions and 883 deletions
|
|
@ -1,104 +0,0 @@
|
|||
#include "logic/scripting/descriptors_manager.hpp"
|
||||
|
||||
#include "debug/Logger.hpp"
|
||||
|
||||
static debug::Logger logger("descriptors-manager");
|
||||
|
||||
namespace scripting {
|
||||
|
||||
std::vector<std::optional<StreamDescriptor>> descriptors_manager::descriptors;
|
||||
|
||||
std::istream* descriptors_manager::get_input(int descriptor) {
|
||||
if (!is_readable(descriptor))
|
||||
return nullptr;
|
||||
|
||||
return descriptors[descriptor]->in.get();
|
||||
}
|
||||
|
||||
std::ostream* descriptors_manager::get_output(int descriptor) {
|
||||
if (!is_writeable(descriptor))
|
||||
return nullptr;
|
||||
|
||||
return descriptors[descriptor]->out.get();
|
||||
}
|
||||
|
||||
void descriptors_manager::flush(int descriptor) {
|
||||
if (is_writeable(descriptor)) {
|
||||
descriptors[descriptor]->out->flush();
|
||||
}
|
||||
}
|
||||
|
||||
bool descriptors_manager::has_descriptor(int descriptor) {
|
||||
return is_readable(descriptor) || is_writeable(descriptor);
|
||||
}
|
||||
|
||||
bool descriptors_manager::is_readable(int descriptor) {
|
||||
return descriptor >= 0 && descriptor < static_cast<int>(descriptors.size())
|
||||
&& descriptors[descriptor].has_value()
|
||||
&& descriptors[descriptor]->in != nullptr;
|
||||
}
|
||||
|
||||
bool descriptors_manager::is_writeable(int descriptor) {
|
||||
return descriptor >= 0 && descriptor < static_cast<int>(descriptors.size())
|
||||
&& descriptors[descriptor].has_value()
|
||||
&& descriptors[descriptor]->out != nullptr;
|
||||
}
|
||||
|
||||
void descriptors_manager::close(int descriptor) {
|
||||
if (descriptor >= 0 && descriptor < static_cast<int>(descriptors.size())) {
|
||||
if (descriptors[descriptor].has_value()) {
|
||||
auto& desc = descriptors[descriptor].value();
|
||||
|
||||
if (desc.out)
|
||||
desc.out->flush();
|
||||
|
||||
desc.in.reset();
|
||||
desc.out.reset();
|
||||
}
|
||||
|
||||
descriptors[descriptor].reset();
|
||||
|
||||
descriptors[descriptor] = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
int descriptors_manager::open_descriptor(const io::path& path, bool write, bool read) {
|
||||
std::unique_ptr<std::istream> in;
|
||||
std::unique_ptr<std::ostream> out;
|
||||
|
||||
try {
|
||||
if (read)
|
||||
in = io::read(path);
|
||||
|
||||
if (write)
|
||||
out = io::write(path);
|
||||
} catch (const std::exception& e) {
|
||||
logger.error() << "failed to open descriptor for " << path.string()
|
||||
<< ": " << e.what();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < static_cast<int>(descriptors.size()); ++i) {
|
||||
if (!descriptors[i].has_value()) {
|
||||
descriptors[i] = StreamDescriptor{ std::move(in), std::move(out) };
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
descriptors.emplace_back(StreamDescriptor{ std::move(in), std::move(out) });
|
||||
|
||||
return static_cast<int>(descriptors.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
void descriptors_manager::close_all_descriptors() {
|
||||
for (int i = 0; i < static_cast<int>(descriptors.size()); ++i) {
|
||||
if (descriptors[i].has_value()) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
descriptors.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
#include "io/io.hpp"
|
||||
|
||||
namespace scripting {
|
||||
|
||||
struct StreamDescriptor {
|
||||
std::unique_ptr<std::istream> in;
|
||||
std::unique_ptr<std::ostream> out;
|
||||
};
|
||||
|
||||
class descriptors_manager {
|
||||
private:
|
||||
static std::vector<std::optional<StreamDescriptor>> descriptors;
|
||||
|
||||
public:
|
||||
static std::istream* get_input(int descriptor);
|
||||
static std::ostream* get_output(int descriptor);
|
||||
|
||||
static void flush(int descriptor);
|
||||
|
||||
static bool has_descriptor(int descriptor);
|
||||
|
||||
static bool is_readable(int descriptor);
|
||||
static bool is_writeable(int descriptor);
|
||||
|
||||
static void close(int descriptor);
|
||||
static int open_descriptor(const io::path& path, bool write, bool read);
|
||||
|
||||
static void close_all_descriptors();
|
||||
};
|
||||
}
|
||||
160
src/logic/scripting/io_descriptors.cpp
Normal file
160
src/logic/scripting/io_descriptors.cpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#include "logic/scripting/io_descriptors.hpp"
|
||||
|
||||
#include "debug/Logger.hpp"
|
||||
#include "io/io.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
static debug::Logger logger("descriptors-manager");
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
namespace {
|
||||
struct StreamDescriptor {
|
||||
// TODO: std::iostream?
|
||||
std::unique_ptr<std::istream> in;
|
||||
std::unique_ptr<std::ostream> out;
|
||||
};
|
||||
std::vector<std::optional<StreamDescriptor>> descriptors;
|
||||
}
|
||||
|
||||
std::istream* io_descriptors::get_input(int id) {
|
||||
if (!is_readable(id)) {
|
||||
return nullptr;
|
||||
}
|
||||
return ::descriptors[id]->in.get();
|
||||
}
|
||||
|
||||
std::ostream* io_descriptors::get_output(int id) {
|
||||
if (!is_writeable(id)) {
|
||||
return nullptr;
|
||||
}
|
||||
return ::descriptors[id]->out.get();
|
||||
}
|
||||
|
||||
static StreamDescriptor& require_descriptor(int id) {
|
||||
if (!io_descriptors::has_descriptor(id)) {
|
||||
throw std::runtime_error(
|
||||
"io-descriptor with id " + std::to_string(id) + " does not exists"
|
||||
);
|
||||
}
|
||||
return *::descriptors[id];
|
||||
}
|
||||
|
||||
std::istream& io_descriptors::require_input(int id) {
|
||||
const auto& descriptor = require_descriptor(id);
|
||||
if (descriptor.in) {
|
||||
return *descriptor.in;
|
||||
}
|
||||
throw std::runtime_error("io-descriptor is not readable");
|
||||
}
|
||||
|
||||
std::ostream& io_descriptors::require_output(int id) {
|
||||
const auto& descriptor = require_descriptor(id);
|
||||
if (descriptor.out) {
|
||||
return *descriptor.out;
|
||||
}
|
||||
throw std::runtime_error("io-descriptor is not writeable");
|
||||
}
|
||||
|
||||
void io_descriptors::flush(int id) {
|
||||
if (is_writeable(id)) {
|
||||
::descriptors[id]->out->flush();
|
||||
}
|
||||
}
|
||||
|
||||
int io_descriptors::available(int id) {
|
||||
if (!is_readable(id))
|
||||
return 0;
|
||||
|
||||
auto* stream = descriptors[id]->in.get();
|
||||
|
||||
auto current_pos = stream->tellg();
|
||||
|
||||
if (current_pos == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->seekg(0, std::ios::end);
|
||||
|
||||
auto end_pos = stream->tellg();
|
||||
|
||||
stream->seekg(current_pos, std::ios::beg);
|
||||
|
||||
auto remaining = end_pos - current_pos;
|
||||
|
||||
if (remaining > std::numeric_limits<int>::max()) {
|
||||
return std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
return static_cast<int>(remaining);
|
||||
}
|
||||
|
||||
bool io_descriptors::has_descriptor(int id) {
|
||||
return id >= 0 && id < static_cast<int>(::descriptors.size()) &&
|
||||
::descriptors[id].has_value();
|
||||
}
|
||||
|
||||
bool io_descriptors::is_readable(int id) {
|
||||
return has_descriptor(id) && ::descriptors[id]->in != nullptr;
|
||||
}
|
||||
|
||||
bool io_descriptors::is_writeable(int id) {
|
||||
return id >= 0 && id < static_cast<int>(::descriptors.size())
|
||||
&& ::descriptors[id].has_value()
|
||||
&& ::descriptors[id]->out != nullptr;
|
||||
}
|
||||
|
||||
void io_descriptors::close(int id) {
|
||||
if (!has_descriptor(id)) {
|
||||
return;
|
||||
}
|
||||
auto& desc = ::descriptors[id].value();
|
||||
if (desc.out) {
|
||||
desc.out->flush();
|
||||
}
|
||||
desc.in.reset();
|
||||
desc.out.reset();
|
||||
::descriptors[id] = std::nullopt;
|
||||
}
|
||||
|
||||
int io_descriptors::open_descriptor(const io::path& path, bool write, bool read) {
|
||||
std::unique_ptr<std::istream> in;
|
||||
std::unique_ptr<std::ostream> out;
|
||||
|
||||
try {
|
||||
if (read) {
|
||||
in = io::read(path);
|
||||
}
|
||||
if (write) {
|
||||
out = io::write(path);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
logger.error() << "failed to open descriptor for " << path.string()
|
||||
<< ": " << e.what();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < static_cast<int>(descriptors.size()); ++i) {
|
||||
if (!descriptors[i].has_value()) {
|
||||
descriptors[i] = StreamDescriptor{ std::move(in), std::move(out) };
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
::descriptors.emplace_back(StreamDescriptor{ std::move(in), std::move(out) });
|
||||
return static_cast<int>(::descriptors.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
void io_descriptors::close_all_descriptors() {
|
||||
for (int i = 0; i < static_cast<int>(::descriptors.size()); ++i) {
|
||||
if (::descriptors[i].has_value()) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
::descriptors.clear();
|
||||
}
|
||||
27
src/logic/scripting/io_descriptors.hpp
Normal file
27
src/logic/scripting/io_descriptors.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
#include "io/fwd.hpp"
|
||||
|
||||
namespace scripting::io_descriptors {
|
||||
std::istream* get_input(int id);
|
||||
std::ostream* get_output(int id);
|
||||
|
||||
std::istream& require_input(int id);
|
||||
std::ostream& require_output(int id);
|
||||
|
||||
void flush(int id);
|
||||
int available(int id);
|
||||
|
||||
bool has_descriptor(int id);
|
||||
|
||||
bool is_readable(int id);
|
||||
bool is_writeable(int id);
|
||||
|
||||
void close(int id);
|
||||
int open_descriptor(const io::path& path, bool write, bool read);
|
||||
|
||||
void close_all_descriptors();
|
||||
}
|
||||
|
|
@ -44,6 +44,7 @@ extern const luaL_Reg posteffectslib[]; // gfx.posteffects
|
|||
extern const luaL_Reg quatlib[];
|
||||
extern const luaL_Reg randomlib[];
|
||||
extern const luaL_Reg compressionlib[];
|
||||
extern const luaL_Reg testlib[];
|
||||
extern const luaL_Reg text3dlib[]; // gfx.text3d
|
||||
extern const luaL_Reg timelib[];
|
||||
extern const luaL_Reg tomllib[];
|
||||
|
|
@ -53,6 +54,7 @@ extern const luaL_Reg vec3lib[]; // vecn.cpp
|
|||
extern const luaL_Reg vec4lib[]; // vecn.cpp
|
||||
extern const luaL_Reg weatherlib[]; // gfx.weather
|
||||
extern const luaL_Reg worldlib[];
|
||||
extern const luaL_Reg xmllib[];
|
||||
extern const luaL_Reg yamllib[];
|
||||
|
||||
// Components
|
||||
|
|
|
|||
|
|
@ -543,13 +543,16 @@ static int l_destruct(lua::State* L) {
|
|||
}
|
||||
|
||||
static int l_raycast(lua::State* L) {
|
||||
auto& level = require_level();
|
||||
const auto& level = require_level();
|
||||
|
||||
auto start = lua::tovec<3>(L, 1);
|
||||
auto dir = lua::tovec<3>(L, 2);
|
||||
auto maxDistance = lua::tonumber(L, 3);
|
||||
bool includeNonSelectable = false;
|
||||
|
||||
blocks_agent::RaycastSettings raycast {};
|
||||
std::set<blockid_t> filteredBlocks {};
|
||||
raycast.filter = &filteredBlocks;
|
||||
|
||||
const int luaStackSize = lua::gettop(L);
|
||||
if (luaStackSize >= 5) {
|
||||
if (lua::istable(L, 5)) {
|
||||
|
|
@ -568,21 +571,14 @@ static int l_raycast(lua::State* L) {
|
|||
}
|
||||
}
|
||||
if (luaStackSize >= 6) {
|
||||
includeNonSelectable = lua::toboolean(L, 6);
|
||||
raycast.includeNonSelectable = lua::toboolean(L, 6);
|
||||
}
|
||||
glm::vec3 end;
|
||||
glm::ivec3 normal;
|
||||
glm::ivec3 iend;
|
||||
|
||||
if (auto voxel = blocks_agent::raycast(
|
||||
*level.chunks,
|
||||
start,
|
||||
dir,
|
||||
maxDistance,
|
||||
end,
|
||||
normal,
|
||||
iend,
|
||||
filteredBlocks,
|
||||
includeNonSelectable
|
||||
*level.chunks, start, dir, maxDistance, end, normal, iend, raycast
|
||||
)) {
|
||||
if (luaStackSize >= 4 && !lua::isnil(L, 4)) {
|
||||
lua::pushvalue(L, 4);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
#include "voxels/blocks_agent.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static const EntityDef* require_entity_def(lua::State* L) {
|
||||
|
|
@ -48,6 +50,13 @@ static int l_def_hitbox(lua::State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int l_def_solid(lua::State* L) {
|
||||
if (auto def = require_entity_def(L)) {
|
||||
return lua::pushboolean(L, def->solid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_defs_count(lua::State* L) {
|
||||
return lua::pushinteger(L, indices->entities.count());
|
||||
}
|
||||
|
|
@ -145,34 +154,59 @@ static int l_get_all_in_radius(lua::State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_raycast(lua::State* L) {
|
||||
auto start = lua::tovec<3>(L, 1);
|
||||
auto dir = lua::tovec<3>(L, 2);
|
||||
auto maxDistance = lua::tonumber(L, 3);
|
||||
auto ignoreEntityId = lua::tointeger(L, 4);
|
||||
bool includeNonSelectable = false;
|
||||
std::set<blockid_t> filteredBlocks {};
|
||||
const int luaStackSize = lua::gettop(L);
|
||||
if (luaStackSize >= 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");
|
||||
}
|
||||
static int l_push_ray(
|
||||
lua::State* L,
|
||||
const std::optional<Entities::RaycastResult>& ray,
|
||||
blockid_t block,
|
||||
const glm::vec3& start,
|
||||
const glm::vec3& dir,
|
||||
const glm::vec3& end,
|
||||
const glm::ivec3& iend,
|
||||
const glm::ivec3& normal
|
||||
) {
|
||||
if (!ray.has_value() && block == BLOCK_VOID) {
|
||||
return 0;
|
||||
}
|
||||
if (luaStackSize >= 7) {
|
||||
includeNonSelectable = lua::toboolean(L, 6);
|
||||
if (lua::gettop(L) >= 5 && lua::istable(L, 5)) {
|
||||
lua::pushvalue(L, 5);
|
||||
} else {
|
||||
lua::createtable(L, 0, 6);
|
||||
}
|
||||
|
||||
lua::pushvec3(L, ray ? (start + dir * ray->distance) : end);
|
||||
lua::setfield(L, "endpoint");
|
||||
|
||||
lua::pushvec3(L, ray ? ray->normal : normal);
|
||||
lua::setfield(L, "normal");
|
||||
|
||||
lua::pushnumber(L, glm::distance(start, end));
|
||||
lua::setfield(L, "length");
|
||||
|
||||
lua::pushvec3(L, iend);
|
||||
lua::setfield(L, "iendpoint");
|
||||
|
||||
lua::pushinteger(L, block);
|
||||
lua::setfield(L, "block");
|
||||
|
||||
if (ray.has_value()) {
|
||||
lua::pushinteger(L, ray->entity);
|
||||
lua::setfield(L, "entity");
|
||||
} else if (block != BLOCK_VOID) {
|
||||
lua::pushinteger(L, block);
|
||||
lua::setfield(L, "block");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_raycast(
|
||||
lua::State* L,
|
||||
const glm::vec3& start,
|
||||
const glm::vec3& dir,
|
||||
float maxDistance,
|
||||
const blocks_agent::RaycastSettings& voxelRaycast,
|
||||
const Entities::RaycastSettings& entityRaycast,
|
||||
bool entities
|
||||
) {
|
||||
glm::vec3 end;
|
||||
glm::ivec3 normal;
|
||||
glm::ivec3 iend;
|
||||
|
|
@ -187,61 +221,139 @@ static int l_raycast(lua::State* L) {
|
|||
end,
|
||||
normal,
|
||||
iend,
|
||||
filteredBlocks,
|
||||
includeNonSelectable
|
||||
voxelRaycast
|
||||
)) {
|
||||
maxDistance = glm::distance(start, end);
|
||||
block = voxel->id;
|
||||
}
|
||||
if (auto ray =
|
||||
level->entities->rayCast(start, dir, maxDistance, ignoreEntityId)) {
|
||||
if (luaStackSize >= 5 && !lua::isnil(L, 5)) {
|
||||
lua::pushvalue(L, 5);
|
||||
auto ray =
|
||||
entities
|
||||
? level->entities->rayCast(start, dir, maxDistance, entityRaycast)
|
||||
: std::nullopt;
|
||||
return l_push_ray(L, ray, block, start, dir, end, iend, normal);
|
||||
}
|
||||
|
||||
static void load_blocks_filter(lua::State* L, int idx, std::set<blockid_t>& dst) {
|
||||
int count = lua::objlen(L, idx);
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua::rawgeti(L, i + 1, idx);
|
||||
if (lua::isnumber(L, -1)) {
|
||||
dst.insert(lua::touinteger(L, -1));
|
||||
} else {
|
||||
lua::createtable(L, 0, 6);
|
||||
auto blockName = std::string(lua::tostring(L, -1));
|
||||
const Block* block = content->blocks.find(blockName);
|
||||
if (block != nullptr) {
|
||||
dst.insert(block->rt.id);
|
||||
}
|
||||
}
|
||||
|
||||
lua::pushvec3(L, start + dir * ray->distance);
|
||||
lua::setfield(L, "endpoint");
|
||||
|
||||
lua::pushvec3(L, ray->normal);
|
||||
lua::setfield(L, "normal");
|
||||
|
||||
lua::pushnumber(L, glm::distance(start, end));
|
||||
lua::setfield(L, "length");
|
||||
|
||||
lua::pushvec3(L, iend);
|
||||
lua::setfield(L, "iendpoint");
|
||||
|
||||
lua::pushinteger(L, block);
|
||||
lua::setfield(L, "block");
|
||||
|
||||
lua::pushinteger(L, ray->entity);
|
||||
lua::setfield(L, "entity");
|
||||
return 1;
|
||||
} else if (block != BLOCK_VOID) {
|
||||
if (lua::gettop(L) >= 5 && !lua::isnil(L, 5)) {
|
||||
lua::pushvalue(L, 5);
|
||||
} else {
|
||||
lua::createtable(L, 0, 5);
|
||||
}
|
||||
lua::pushvec3(L, end);
|
||||
lua::setfield(L, "endpoint");
|
||||
|
||||
lua::pushvec3(L, normal);
|
||||
lua::setfield(L, "normal");
|
||||
|
||||
lua::pushnumber(L, glm::distance(start, end));
|
||||
lua::setfield(L, "length");
|
||||
|
||||
lua::pushvec3(L, iend);
|
||||
lua::setfield(L, "iendpoint");
|
||||
|
||||
lua::pushinteger(L, block);
|
||||
lua::setfield(L, "block");
|
||||
return 1;
|
||||
lua::pop(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void load_entities_filter(lua::State* L, int idx, std::set<entitydefid_t>& dst) {
|
||||
int count = lua::objlen(L, idx);
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua::rawgeti(L, i + 1, idx);
|
||||
if (lua::isnumber(L, -1)) {
|
||||
dst.insert(lua::touinteger(L, -1));
|
||||
} else {
|
||||
auto entityName = std::string(lua::tostring(L, -1));
|
||||
const EntityDef* entity = content->entities.find(entityName);
|
||||
if (entity != nullptr) {
|
||||
dst.insert(entity->rt.id);
|
||||
}
|
||||
}
|
||||
lua::pop(L);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_world_raycast(lua::State* L) {
|
||||
blocks_agent::RaycastSettings blocksRaycast {};
|
||||
Entities::RaycastSettings entityRaycast {};
|
||||
|
||||
std::set<blockid_t> filteredBlocks {};
|
||||
std::set<entitydefid_t> filteredEntities {};
|
||||
|
||||
glm::vec3 start, dir;
|
||||
float maxDistance;
|
||||
bool entities = true;
|
||||
|
||||
if (!lua::istable(L, 1)) {
|
||||
throw std::runtime_error("invalid function overload");
|
||||
}
|
||||
|
||||
lua::requirefield(L, "start", 1);
|
||||
start = lua::tovec3(L, -1);
|
||||
|
||||
lua::requirefield(L, "dir", 1);
|
||||
dir = lua::tovec3(L, -1);
|
||||
|
||||
lua::requirefield(L, "distance", 1);
|
||||
maxDistance = lua::tonumber(L, -1);
|
||||
|
||||
lua::pop(L, 3);
|
||||
|
||||
if (lua::getfield(L, "entities", 1)) {
|
||||
entities = lua::toboolean(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
if (lua::getfield(L, "ignore_uid", 1)) {
|
||||
entityRaycast.ignoredUid = lua::tointeger(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
if (lua::getfield(L, "filter_entities")) {
|
||||
load_entities_filter(L, -1, filteredEntities);
|
||||
blocksRaycast.filter = &filteredEntities;
|
||||
lua::pop(L);
|
||||
}
|
||||
if (lua::getfield(L, "entities_exclusion")) {
|
||||
entityRaycast.entityFilterExcludeMode = lua::toboolean(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
if (lua::getfield(L, "filter_blocks", 1)) {
|
||||
load_blocks_filter(L, -1, filteredBlocks);
|
||||
blocksRaycast.filter = &filteredBlocks;
|
||||
lua::pop(L);
|
||||
}
|
||||
if (lua::getfield(L, "blocks_exclusion")) {
|
||||
blocksRaycast.blocksFilterExcludeMode = lua::toboolean(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
if (lua::getfield(L, "nonselect_blocks", 1)) {
|
||||
blocksRaycast.includeNonSelectable = lua::toboolean(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
return l_raycast(
|
||||
L, start, dir, maxDistance, blocksRaycast, entityRaycast, entities
|
||||
);
|
||||
}
|
||||
|
||||
static int l_raycast(lua::State* L) {
|
||||
blocks_agent::RaycastSettings blocksRaycast {};
|
||||
Entities::RaycastSettings entityRaycast {};
|
||||
std::set<blockid_t> filteredBlocks {};
|
||||
|
||||
const int luaStackSize = lua::gettop(L);
|
||||
glm::vec3 start = lua::tovec<3>(L, 1);
|
||||
glm::vec3 dir = lua::tovec<3>(L, 2);
|
||||
float maxDistance = lua::tonumber(L, 3);
|
||||
|
||||
entityRaycast.ignoredUid = lua::tointeger(L, 4);
|
||||
if (luaStackSize >= 6) {
|
||||
if (lua::istable(L, 6)) {
|
||||
load_blocks_filter(L, 6, filteredBlocks);
|
||||
blocksRaycast.filter = &filteredBlocks;
|
||||
} else {
|
||||
throw std::runtime_error("table expected for filter");
|
||||
}
|
||||
}
|
||||
if (luaStackSize >= 7) {
|
||||
blocksRaycast.includeNonSelectable = lua::toboolean(L, 6);
|
||||
}
|
||||
return l_raycast(
|
||||
L, start, dir, maxDistance, blocksRaycast, entityRaycast, true
|
||||
);
|
||||
}
|
||||
|
||||
static int l_reload_component(lua::State* L) {
|
||||
|
|
@ -268,6 +380,7 @@ const luaL_Reg entitylib[] = {
|
|||
{"def_index", lua::wrap<l_def_index>},
|
||||
{"def_name", lua::wrap<l_def_name>},
|
||||
{"def_hitbox", lua::wrap<l_def_hitbox>},
|
||||
{"def_solid", lua::wrap<l_def_solid>},
|
||||
{"get_def", lua::wrap<l_get_def>},
|
||||
{"defs_count", lua::wrap<l_defs_count>},
|
||||
{"spawn", lua::wrap<l_spawn>},
|
||||
|
|
@ -278,6 +391,7 @@ const luaL_Reg entitylib[] = {
|
|||
{"get_all_in_box", lua::wrap<l_get_all_in_box>},
|
||||
{"get_all_in_radius", lua::wrap<l_get_all_in_radius>},
|
||||
{"raycast", lua::wrap<l_raycast>},
|
||||
{"__world_raycast", lua::wrap<l_world_raycast>},
|
||||
{"reload_component", lua::wrap<l_reload_component>},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include "util/stringutil.hpp"
|
||||
#include "api_lua.hpp"
|
||||
#include "../lua_engine.hpp"
|
||||
#include "logic/scripting/descriptors_manager.hpp"
|
||||
#include "logic/scripting/io_descriptors.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace scripting;
|
||||
|
|
@ -263,13 +263,13 @@ static int l_open_descriptor(lua::State* L) {
|
|||
std::vector<char> buffer;
|
||||
|
||||
if(wplusMode) {
|
||||
int temp_descriptor = scripting::descriptors_manager::open_descriptor(path, false, true);
|
||||
int temp_descriptor = io_descriptors::open_descriptor(path, false, true);
|
||||
|
||||
if (temp_descriptor == -1) {
|
||||
throw std::runtime_error("failed to open descriptor for initial reading");
|
||||
}
|
||||
|
||||
auto* in_stream = scripting::descriptors_manager::get_input(temp_descriptor);
|
||||
auto* in_stream = io_descriptors::get_input(temp_descriptor);
|
||||
|
||||
in_stream->seekg(0, std::ios::end);
|
||||
std::streamsize size = in_stream->tellg();
|
||||
|
|
@ -278,17 +278,17 @@ static int l_open_descriptor(lua::State* L) {
|
|||
buffer.resize(size);
|
||||
in_stream->read(buffer.data(), size);
|
||||
|
||||
scripting::descriptors_manager::close(temp_descriptor);
|
||||
io_descriptors::close(temp_descriptor);
|
||||
}
|
||||
|
||||
int descriptor = scripting::descriptors_manager::open_descriptor(path, write, read);
|
||||
int descriptor = io_descriptors::open_descriptor(path, write, read);
|
||||
|
||||
if(descriptor == -1) {
|
||||
throw std::runtime_error("failed to open descriptor");
|
||||
}
|
||||
|
||||
if(wplusMode) {
|
||||
auto* out_stream = scripting::descriptors_manager::get_output(descriptor);
|
||||
auto* out_stream = io_descriptors::get_output(descriptor);
|
||||
out_stream->write(buffer.data(), buffer.size());
|
||||
out_stream->flush();
|
||||
}
|
||||
|
|
@ -297,51 +297,31 @@ static int l_open_descriptor(lua::State* L) {
|
|||
}
|
||||
|
||||
static int l_has_descriptor(lua::State* L) {
|
||||
return lua::pushboolean(L, scripting::descriptors_manager::has_descriptor(lua::tointeger(L, 1)));
|
||||
return lua::pushboolean(L, io_descriptors::has_descriptor(lua::tointeger(L, 1)));
|
||||
}
|
||||
|
||||
static int l_read_descriptor(lua::State* L) {
|
||||
int descriptor = lua::tointeger(L, 1);
|
||||
|
||||
if (!scripting::descriptors_manager::has_descriptor(descriptor)) {
|
||||
throw std::runtime_error("unknown descriptor");
|
||||
}
|
||||
|
||||
if (!scripting::descriptors_manager::is_readable(descriptor)) {
|
||||
throw std::runtime_error("descriptor is not readable");
|
||||
}
|
||||
|
||||
int maxlen = lua::tointeger(L, 2);
|
||||
|
||||
auto* stream = scripting::descriptors_manager::get_input(descriptor);
|
||||
auto& stream = io_descriptors::require_input(descriptor);
|
||||
if (stream.eof()) {
|
||||
stream.clear();
|
||||
}
|
||||
|
||||
util::Buffer<char> buffer(maxlen);
|
||||
|
||||
stream->read(buffer.data(), maxlen);
|
||||
|
||||
std::streamsize read_len = stream->gcount();
|
||||
|
||||
stream.read(buffer.data(), maxlen);
|
||||
std::streamsize read_len = stream.gcount();
|
||||
return lua::create_bytearray(L, buffer.data(), read_len);
|
||||
}
|
||||
|
||||
static int l_write_descriptor(lua::State* L) {
|
||||
int descriptor = lua::tointeger(L, 1);
|
||||
|
||||
if (!scripting::descriptors_manager::has_descriptor(descriptor)) {
|
||||
throw std::runtime_error("unknown descriptor");
|
||||
}
|
||||
|
||||
if (!scripting::descriptors_manager::is_writeable(descriptor)) {
|
||||
throw std::runtime_error("descriptor is not writeable");
|
||||
}
|
||||
|
||||
auto data = lua::bytearray_as_string(L, 2);
|
||||
|
||||
auto* stream = scripting::descriptors_manager::get_output(descriptor);
|
||||
|
||||
stream->write(data.data(), static_cast<std::streamsize>(data.size()));
|
||||
|
||||
if (!stream->good()) {
|
||||
auto& stream = io_descriptors::require_output(descriptor);
|
||||
stream.write(data.data(), static_cast<std::streamsize>(data.size()));
|
||||
if (!stream.good()) {
|
||||
throw std::runtime_error("failed to write to stream");
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -350,12 +330,13 @@ static int l_write_descriptor(lua::State* L) {
|
|||
static int l_seek_descriptor(lua::State* L) {
|
||||
int descriptor = lua::tointeger(L, 1);
|
||||
|
||||
if (!scripting::descriptors_manager::has_descriptor(descriptor)) {
|
||||
if (!io_descriptors::has_descriptor(descriptor)) {
|
||||
throw std::runtime_error("unknown descriptor");
|
||||
}
|
||||
|
||||
std::string mode = lua::require_string(L, 2);
|
||||
auto mode = lua::require_string(L, 2);
|
||||
std::ios_base::seekdir dir;
|
||||
auto position = lua::tointeger(L, 3);
|
||||
|
||||
switch (mode[0]) {
|
||||
case 'b':
|
||||
|
|
@ -371,45 +352,81 @@ static int l_seek_descriptor(lua::State* L) {
|
|||
throw std::runtime_error("invalid seek mode");
|
||||
}
|
||||
|
||||
auto* stream = scripting::descriptors_manager::get_output(descriptor);
|
||||
if (io_descriptors::is_writeable(descriptor)) {
|
||||
auto& stream = io_descriptors::require_output(descriptor);
|
||||
stream.seekp(position, dir);
|
||||
if (!stream.good()) {
|
||||
throw std::runtime_error("failed to seek stream");
|
||||
}
|
||||
}
|
||||
if (io_descriptors::is_readable(descriptor)) {
|
||||
auto& stream = io_descriptors::require_input(descriptor);
|
||||
stream.seekg(position, dir);
|
||||
if (!stream.good()) {
|
||||
throw std::runtime_error("failed to seek stream");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->seekp(lua::tointeger(L, 3), dir);
|
||||
static int l_tell_descriptor(lua::State* L) {
|
||||
int descriptor = lua::tointeger(L, 1);
|
||||
|
||||
if (!stream->good()) {
|
||||
throw std::runtime_error("failed to seek stream");
|
||||
if (!io_descriptors::has_descriptor(descriptor)) {
|
||||
throw std::runtime_error("unknown descriptor");
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (io_descriptors::is_writeable(descriptor)) {
|
||||
auto& stream = io_descriptors::require_output(descriptor);
|
||||
return lua::pushinteger(L, stream.tellp());
|
||||
} else {
|
||||
auto& stream = io_descriptors::require_input(descriptor);
|
||||
return lua::pushinteger(L, stream.tellg());
|
||||
}
|
||||
}
|
||||
|
||||
static int l_flush_descriptor(lua::State* L) {
|
||||
int descriptor = lua::tointeger(L, 1);
|
||||
|
||||
if (!scripting::descriptors_manager::has_descriptor(descriptor)) {
|
||||
if (!io_descriptors::has_descriptor(descriptor)) {
|
||||
throw std::runtime_error("unknown descriptor");
|
||||
}
|
||||
|
||||
if (!scripting::descriptors_manager::is_writeable(descriptor)) {
|
||||
if (!io_descriptors::is_writeable(descriptor)) {
|
||||
throw std::runtime_error("descriptor is not writeable");
|
||||
}
|
||||
|
||||
scripting::descriptors_manager::flush(descriptor);
|
||||
io_descriptors::flush(descriptor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_available_descriptor(lua::State* L) {
|
||||
int descriptor = lua::tointeger(L, 1);
|
||||
|
||||
if (!io_descriptors::has_descriptor(descriptor)) {
|
||||
throw std::runtime_error("unknown descriptor");
|
||||
}
|
||||
|
||||
if (!io_descriptors::is_readable(descriptor)) {
|
||||
throw std::runtime_error("descriptor is not readable");
|
||||
}
|
||||
|
||||
return lua::pushinteger(L, io_descriptors::available(descriptor));
|
||||
}
|
||||
|
||||
static int l_close_descriptor(lua::State* L) {
|
||||
int descriptor = lua::tointeger(L, 1);
|
||||
|
||||
if (!scripting::descriptors_manager::has_descriptor(descriptor)) {
|
||||
if (!io_descriptors::has_descriptor(descriptor)) {
|
||||
throw std::runtime_error("unknown descriptor");
|
||||
}
|
||||
|
||||
scripting::descriptors_manager::close(descriptor);
|
||||
io_descriptors::close(descriptor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_close_all_descriptors(lua::State* L) {
|
||||
scripting::descriptors_manager::close_all_descriptors();
|
||||
io_descriptors::close_all_descriptors();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -442,7 +459,9 @@ const luaL_Reg filelib[] = {
|
|||
{"__read_descriptor", lua::wrap<l_read_descriptor>},
|
||||
{"__write_descriptor", lua::wrap<l_write_descriptor>},
|
||||
{"__seek_descriptor", lua::wrap<l_seek_descriptor>},
|
||||
{"__tell_descriptor", lua::wrap<l_tell_descriptor>},
|
||||
{"__flush_descriptor", lua::wrap<l_flush_descriptor>},
|
||||
{"__available_descriptor", lua::wrap<l_available_descriptor>},
|
||||
{"__close_descriptor", lua::wrap<l_close_descriptor>},
|
||||
{"__close_all_descriptors", lua::wrap<l_close_all_descriptors>},
|
||||
{nullptr, nullptr}
|
||||
|
|
|
|||
|
|
@ -420,15 +420,19 @@ static int p_get_data(UINode* node, lua::State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const std::string& request_node_id(const DocumentNode& docnode) {
|
||||
std::string id = docnode.node->getId();
|
||||
static const std::string& request_node_id(UiDocument& document, UINode& node) {
|
||||
const std::string& id = node.getId();
|
||||
if (id.empty()) {
|
||||
id = "#" + std::to_string(
|
||||
reinterpret_cast<std::ptrdiff_t>(docnode.node.get()));
|
||||
node.setId( "#" + std::to_string(
|
||||
reinterpret_cast<std::ptrdiff_t>(&node)));
|
||||
document.pushIndices(node.shared_from_this());
|
||||
return node.getId();
|
||||
}
|
||||
docnode.node->setId(std::move(id));
|
||||
docnode.document->pushIndices(docnode.node);
|
||||
return docnode.node->getId();
|
||||
return id;
|
||||
}
|
||||
|
||||
static const std::string& request_node_id(const DocumentNode& docnode) {
|
||||
return request_node_id(*docnode.document, *docnode.node);
|
||||
}
|
||||
|
||||
/// @brief Push UI-document node object to stack
|
||||
|
|
@ -443,15 +447,14 @@ static int push_document_node(lua::State* L, const std::string& id) {
|
|||
|
||||
static int p_get_parent(UINode* node, lua::State* L) {
|
||||
auto parent = node->getParent();
|
||||
if (!parent) {
|
||||
if (parent == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto docname = lua::require_string(L, 1);
|
||||
auto element = lua::require_string(L, 2);
|
||||
auto docnode = get_document_node_impl(L, docname, element);
|
||||
|
||||
const auto& id = request_node_id(docnode);
|
||||
|
||||
const auto& id = request_node_id(*docnode.document, *parent);
|
||||
return push_document_node(L, id);
|
||||
}
|
||||
|
||||
|
|
@ -1144,7 +1147,7 @@ static int l_gui_load_document(lua::State* L) {
|
|||
auto document = documentPtr.get();
|
||||
engine->requireAssets().store(std::move(documentPtr), alias);
|
||||
|
||||
scripting::on_ui_open(document, {args});
|
||||
scripting::on_ui_open(*document, {args});
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,6 +237,14 @@ static int l_get_all_data(lua::State* L, ItemStack& stack) {
|
|||
return lua::pushvalue(L, stack.getFields());
|
||||
}
|
||||
|
||||
static int l_set_all_data(lua::State* L, ItemStack& stack) {
|
||||
if (!lua::istable(L, 3)) {
|
||||
throw std::runtime_error("table expected as argument 1");
|
||||
}
|
||||
stack.setFields(lua::tovalue(L, 3), lua::toboolean(L, 4));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_has_data(lua::State* L, ItemStack& stack) {
|
||||
auto key = lua::tostring(L, 3);
|
||||
if (key == nullptr) {
|
||||
|
|
@ -267,6 +275,7 @@ const luaL_Reg inventorylib[] = {
|
|||
{"get_data", lua::wrap<wrap_slot<l_get_data>>},
|
||||
{"set_data", lua::wrap<wrap_slot<l_set_data>>},
|
||||
{"get_all_data", lua::wrap<wrap_slot<l_get_all_data>>},
|
||||
{"set_all_data", lua::wrap<wrap_slot<l_set_all_data>>},
|
||||
{"has_data", lua::wrap<wrap_slot<l_has_data>>},
|
||||
{"create", lua::wrap<l_create>},
|
||||
{"remove", lua::wrap<l_remove>},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "coders/json.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
static int l_json_stringify(lua::State* L) {
|
||||
|
|
@ -12,8 +13,12 @@ static int l_json_stringify(lua::State* L) {
|
|||
|
||||
static int l_json_parse(lua::State* L) {
|
||||
auto string = lua::require_string(L, 1);
|
||||
auto element = json::parse("[string]", string);
|
||||
return lua::pushvalue(L, element);
|
||||
try {
|
||||
auto element = json::parse("[string]", string);
|
||||
return lua::pushvalue(L, element);
|
||||
} catch (const parsing_error& err) {
|
||||
throw err.toRuntimeError();
|
||||
}
|
||||
}
|
||||
|
||||
const luaL_Reg jsonlib[] = {
|
||||
|
|
|
|||
45
src/logic/scripting/lua/libs/libtest.cpp
Normal file
45
src/logic/scripting/lua/libs/libtest.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "api_lua.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "window/input.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static int l_set_button_pressed(lua::State* L) {
|
||||
int button = lua::touinteger(L, 1);
|
||||
int x = lua::tointeger(L, 2);
|
||||
int y = lua::tointeger(L, 3);
|
||||
bool pressed = lua::toboolean(L, 4);
|
||||
|
||||
auto& input = engine->getInput();
|
||||
input.simulateCursorPos(x, y);
|
||||
input.simulateClick(button, pressed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_key_pressed(lua::State* L) {
|
||||
auto key = lua::require_string(L, 1);
|
||||
bool pressed = lua::toboolean(L, 2);
|
||||
|
||||
auto& input = engine->getInput();
|
||||
input.simulateKey(input_util::keycode_from(key), pressed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_enter_text(lua::State* L) {
|
||||
auto string = lua::require_wstring(L, 1);
|
||||
|
||||
auto& input = engine->getInput();
|
||||
for (auto chr : string) {
|
||||
input.simulateCodepoint(chr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg testlib[] = {
|
||||
{"set_button_pressed", lua::wrap<l_set_button_pressed>},
|
||||
{"set_key_pressed", lua::wrap<l_set_key_pressed>},
|
||||
{"enter_text", lua::wrap<l_enter_text>},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include "coders/toml.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
|
@ -16,8 +17,12 @@ static int l_toml_stringify(lua::State* L) {
|
|||
|
||||
static int l_toml_parse(lua::State* L) {
|
||||
auto string = lua::require_string(L, 1);
|
||||
auto element = toml::parse("[string]", string);
|
||||
return lua::pushvalue(L, element);
|
||||
try {
|
||||
auto element = toml::parse("[string]", string);
|
||||
return lua::pushvalue(L, element);
|
||||
} catch (const parsing_error& err) {
|
||||
throw err.toRuntimeError();
|
||||
}
|
||||
}
|
||||
|
||||
const luaL_Reg tomllib[] = {
|
||||
|
|
|
|||
|
|
@ -129,6 +129,9 @@ static int l_get_generator(lua::State* L) {
|
|||
}
|
||||
|
||||
static int l_get_chunk_data(lua::State* L) {
|
||||
if (level == nullptr) {
|
||||
throw std::runtime_error("world is not open");
|
||||
}
|
||||
int x = static_cast<int>(lua::tointeger(L, 1));
|
||||
int z = static_cast<int>(lua::tointeger(L, 2));
|
||||
const auto& chunk = level->chunks->getChunk(x, z);
|
||||
|
|
@ -175,7 +178,7 @@ static void integrate_chunk_client(Chunk& chunk) {
|
|||
|
||||
static int l_set_chunk_data(lua::State* L) {
|
||||
if (level == nullptr) {
|
||||
throw std::runtime_error("no open world");
|
||||
throw std::runtime_error("world is not open");
|
||||
}
|
||||
|
||||
int x = static_cast<int>(lua::tointeger(L, 1));
|
||||
|
|
@ -201,7 +204,7 @@ static int l_set_chunk_data(lua::State* L) {
|
|||
|
||||
static int l_save_chunk_data(lua::State* L) {
|
||||
if (level == nullptr) {
|
||||
throw std::runtime_error("no open world");
|
||||
throw std::runtime_error("world is not open");
|
||||
}
|
||||
|
||||
int x = static_cast<int>(lua::tointeger(L, 1));
|
||||
|
|
|
|||
114
src/logic/scripting/lua/libs/libxml.cpp
Normal file
114
src/logic/scripting/lua/libs/libxml.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#include "coders/xml.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
static const char* TAG_ATTR = "#";
|
||||
|
||||
static int push_xml(lua::State* L, const xml::xmlelement& elem) {
|
||||
if (elem.isText()) {
|
||||
return lua::pushlstring(L, elem.getInnerText());
|
||||
}
|
||||
|
||||
const auto& attrs = elem.getAttributes();
|
||||
const auto& elems = elem.getElements();
|
||||
const auto& tag = elem.getTag();
|
||||
|
||||
lua::createtable(L, elem.size(), attrs.size() + 1);
|
||||
lua::pushlstring(L, tag);
|
||||
lua::setfield(L, TAG_ATTR);
|
||||
|
||||
for (int i = 0; i < elems.size(); i++) {
|
||||
push_xml(L, *elems[i]);
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
|
||||
for (const auto& [key, value] : attrs) {
|
||||
lua::pushlstring(L, value.getText());
|
||||
lua::setfield(L, key);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static std::unique_ptr<xml::xmlelement> toxml(lua::State* L) {
|
||||
lua::getfield(L, TAG_ATTR);
|
||||
auto tag = lua::require_lstring(L, -1);
|
||||
lua::pop(L);
|
||||
|
||||
auto elem = std::make_unique<xml::xmlelement>(std::string(tag));
|
||||
int length = lua::objlen(L, -1);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua::rawgeti(L, i + 1);
|
||||
elem->add(toxml(L));
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
lua::pushnil(L);
|
||||
while (lua::next(L, -2)) {
|
||||
lua::pushvalue(L, -2);
|
||||
do {
|
||||
if (!lua::isstring(L, -1)) {
|
||||
break;
|
||||
}
|
||||
auto key = lua::require_lstring(L, -1);
|
||||
if (key == "@") {
|
||||
break;
|
||||
}
|
||||
auto value = lua::require_lstring(L, -2);
|
||||
elem->set(std::string(key), std::string(value));
|
||||
} while (false);
|
||||
|
||||
lua::pop(L, 2);
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
static int l_tostring(lua::State* L) {
|
||||
bool nice = lua::isboolean(L, 2) ? lua::toboolean(L, 2) : true;
|
||||
lua::pushvalue(L, 1);
|
||||
auto xml = toxml(L);
|
||||
lua::pop(L);
|
||||
return lua::pushstring(L, xml::stringify(*xml, nice));
|
||||
}
|
||||
|
||||
static int l_parse(lua::State* L) {
|
||||
auto string = lua::require_string(L, 1);
|
||||
try {
|
||||
auto document = xml::parse("[string]", string);
|
||||
return push_xml(L, *document->getRoot());
|
||||
} catch (const parsing_error& err) {
|
||||
throw err.toRuntimeError();
|
||||
}
|
||||
}
|
||||
|
||||
static int l_parse_vcd(lua::State* L) {
|
||||
auto string = lua::require_string(L, 1);
|
||||
auto rootTag = lua::tostring(L, 2);
|
||||
|
||||
std::unique_ptr<xml::Document> document;
|
||||
try {
|
||||
document = xml::parse_vcm(
|
||||
"[string]", string, rootTag ? rootTag : ""
|
||||
);
|
||||
} catch (const parsing_error& err) {
|
||||
throw err.toRuntimeError();
|
||||
}
|
||||
const auto& root = *document->getRoot();
|
||||
if (rootTag != nullptr) {
|
||||
return push_xml(L, root);
|
||||
}
|
||||
int rootElements = root.size();
|
||||
if (rootElements != 1) {
|
||||
throw std::runtime_error(
|
||||
"one root element expected, got " + std::to_string(rootElements)
|
||||
);
|
||||
}
|
||||
return push_xml(L, *root.getElements()[0]);
|
||||
}
|
||||
|
||||
const luaL_Reg xmllib[] = {
|
||||
{"tostring", lua::wrap<l_tostring>},
|
||||
{"parse", lua::wrap<l_parse>},
|
||||
{"parse_vcd", lua::wrap<l_parse_vcd>},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include "coders/yaml.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
static int l_stringify(lua::State* L) {
|
||||
|
|
@ -9,8 +10,12 @@ static int l_stringify(lua::State* L) {
|
|||
|
||||
static int l_parse(lua::State* L) {
|
||||
auto string = lua::require_string(L, 1);
|
||||
auto element = yaml::parse("[string]", string);
|
||||
return lua::pushvalue(L, element);
|
||||
try {
|
||||
auto element = yaml::parse("[string]", string);
|
||||
return lua::pushvalue(L, element);
|
||||
} catch (const parsing_error& err) {
|
||||
throw err.toRuntimeError();
|
||||
}
|
||||
}
|
||||
|
||||
const luaL_Reg yamllib[] = {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ namespace {
|
|||
debug::Logger logger("lua-state");
|
||||
lua::State* main_thread = nullptr;
|
||||
bool headless_mode = false;
|
||||
bool test_mode = false;
|
||||
const std::unordered_map<std::string, std::string>* project_args;
|
||||
}
|
||||
|
||||
|
|
@ -66,15 +67,16 @@ static void create_libs(State* L, StateType stateType) {
|
|||
openlib(L, "vec2", vec2lib);
|
||||
openlib(L, "vec3", vec3lib);
|
||||
openlib(L, "vec4", vec4lib);
|
||||
openlib(L, "xml", xmllib);
|
||||
openlib(L, "yaml", yamllib);
|
||||
|
||||
openlib(L, "__vc_app", applib);
|
||||
lua::getglobal(L, "__vc_app");
|
||||
lua::setregistry(L, "app");
|
||||
getglobal(L, "__vc_app");
|
||||
setregistry(L, "app");
|
||||
|
||||
if (stateType == StateType::SCRIPT) {
|
||||
lua::getregistry(L, "app");
|
||||
lua::setglobal(L, "app");
|
||||
getregistry(L, "app");
|
||||
setglobal(L, "app");
|
||||
}
|
||||
if (stateType == StateType::BASE || stateType == StateType::SCRIPT) {
|
||||
openlib(L, "assets", assetslib);
|
||||
|
|
@ -99,6 +101,10 @@ static void create_libs(State* L, StateType stateType) {
|
|||
openlib(L, "__transform", transformlib);
|
||||
}
|
||||
|
||||
if (::test_mode) {
|
||||
openlib(L, "test", testlib);
|
||||
}
|
||||
|
||||
addfunc(L, "print", lua::wrap<l_print>);
|
||||
addfunc(L, "crc32", lua::wrap<l_crc32>);
|
||||
}
|
||||
|
|
@ -191,6 +197,7 @@ void lua::initialize(const EnginePaths& paths, const CoreParameters& params) {
|
|||
logger.info() << LUAJIT_VERSION;
|
||||
|
||||
headless_mode = params.headless;
|
||||
test_mode = params.testMode;
|
||||
project_args = ¶ms.projectArgs;
|
||||
main_thread = create_state(
|
||||
paths, params.headless ? StateType::SCRIPT : StateType::BASE
|
||||
|
|
|
|||
|
|
@ -81,16 +81,17 @@ union RGBA {
|
|||
uint8_t arr[4];
|
||||
uint32_t rgba;
|
||||
};
|
||||
static_assert(sizeof(RGBA) == 4);
|
||||
|
||||
static RGBA* get_at(const ImageData& data, uint index) {
|
||||
if (index >= data.getWidth() * data.getHeight()) {
|
||||
return nullptr;
|
||||
}
|
||||
static RGBA* get_at(const ImageData& data, size_t index) {
|
||||
return reinterpret_cast<RGBA*>(data.getData() + index * sizeof(RGBA));
|
||||
}
|
||||
|
||||
static RGBA* get_at(const ImageData& data, uint x, uint y) {
|
||||
return get_at(data, y * data.getWidth() + x);
|
||||
if (x >= data.getWidth() || y >= data.getHeight()) {
|
||||
return nullptr;
|
||||
}
|
||||
return get_at(data, static_cast<size_t>(y) * data.getWidth() + x);
|
||||
}
|
||||
|
||||
static RGBA* get_at(State* L, uint x, uint y) {
|
||||
|
|
|
|||
|
|
@ -591,36 +591,46 @@ bool scripting::on_item_break_block(
|
|||
);
|
||||
}
|
||||
|
||||
void scripting::on_ui_open(
|
||||
UiDocument* layout, std::vector<dv::value> args
|
||||
) {
|
||||
auto argsptr =
|
||||
std::make_shared<std::vector<dv::value>>(std::move(args));
|
||||
std::string name = layout->getId() + ".open";
|
||||
lua::emit_event(lua::get_main_state(), name, [=](auto L) {
|
||||
for (const auto& value : *argsptr) {
|
||||
lua::pushvalue(L, value);
|
||||
static void call_layout_event(const UiDocument& layout, const std::vector<dv::value>& args, const std::string& eventName) {
|
||||
auto L = lua::get_main_state();
|
||||
lua::pushenv(L, *layout.getEnvironment());
|
||||
if (lua::getfield(L, eventName)) {
|
||||
for (const auto& arg : args) {
|
||||
lua::pushvalue(L, arg);
|
||||
}
|
||||
return argsptr->size();
|
||||
});
|
||||
lua::call_nothrow(L, args.size(), 0);
|
||||
}
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
void scripting::on_ui_open(
|
||||
const UiDocument& layout, std::vector<dv::value> args
|
||||
) {
|
||||
if (layout.getScript().onopen) {
|
||||
call_layout_event(layout, args, "on_open");
|
||||
}
|
||||
}
|
||||
|
||||
void scripting::on_ui_progress(
|
||||
UiDocument* layout, int workDone, int workTotal
|
||||
const UiDocument& layout, int workDone, int workTotal
|
||||
) {
|
||||
std::string name = layout->getId() + ".progress";
|
||||
lua::emit_event(lua::get_main_state(), name, [=](auto L) {
|
||||
lua::pushinteger(L, workDone);
|
||||
lua::pushinteger(L, workTotal);
|
||||
return 2;
|
||||
});
|
||||
if (layout.getScript().onprogress){
|
||||
call_layout_event(layout, {workDone, workTotal}, "on_progress");
|
||||
}
|
||||
}
|
||||
|
||||
void scripting::on_ui_close(UiDocument* layout, Inventory* inventory) {
|
||||
std::string name = layout->getId() + ".close";
|
||||
lua::emit_event(lua::get_main_state(), name, [inventory](auto L) {
|
||||
return lua::pushinteger(L, inventory ? inventory->getId() : 0);
|
||||
});
|
||||
void scripting::on_ui_close(const UiDocument& layout, Inventory* inventory) {
|
||||
if (layout.getScript().onclose) {
|
||||
call_layout_event(
|
||||
layout, {inventory ? inventory->getId() : 0}, "on_close"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void scripting::on_ui_destroy(const UiDocument& layout) {
|
||||
if (layout.getScript().ondestroy) {
|
||||
call_layout_event(layout, {}, "on_destroy");
|
||||
}
|
||||
}
|
||||
|
||||
void scripting::on_scripts_loading() {
|
||||
|
|
@ -734,9 +744,10 @@ void scripting::load_entity_component(
|
|||
const io::path& file,
|
||||
const std::string& fileName
|
||||
) {
|
||||
logger.info() << "script (component) " << file.string();
|
||||
|
||||
auto L = lua::get_main_state();
|
||||
std::string src = io::read_string(file);
|
||||
logger.info() << "script (component) " << file.string();
|
||||
lua::loadbuffer(L, *env, src, fileName);
|
||||
lua::store_in_registry(L, lua::CHUNKS_TABLE, name);
|
||||
}
|
||||
|
|
@ -805,11 +816,14 @@ void scripting::load_layout_script(
|
|||
) {
|
||||
int env = *senv;
|
||||
|
||||
lua::pop(lua::get_main_state(), load_script(env, "layout", file, fileName));
|
||||
script.onopen = register_event(env, "on_open", prefix + ".open");
|
||||
script.onprogress =
|
||||
register_event(env, "on_progress", prefix + ".progress");
|
||||
script.onclose = register_event(env, "on_close", prefix + ".close");
|
||||
auto L = lua::get_main_state();
|
||||
lua::pop(L, load_script(env, "layout", file, fileName));
|
||||
lua::pushenv(L, env);
|
||||
script.onopen = lua::hasfield(L, "on_open");
|
||||
script.onprogress = lua::hasfield(L, "on_progress");
|
||||
script.onclose = lua::hasfield(L, "on_close");
|
||||
script.ondestroy = lua::hasfield(L, "on_destroy");
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
void scripting::close() {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ namespace scripting {
|
|||
void on_entity_grounded(const Entity& entity, float force);
|
||||
void on_entity_fall(const Entity& entity);
|
||||
void on_entity_save(const Entity& entity);
|
||||
void on_entity_player_set(const Entity& entity, int64_t pid);
|
||||
void on_entities_update(int tps, int parts, int part);
|
||||
void on_entities_physics_update(float delta);
|
||||
void on_entities_render(float delta);
|
||||
|
|
@ -152,13 +153,16 @@ namespace scripting {
|
|||
void on_attacked(const Entity& entity, Player* player, entityid_t attacker);
|
||||
void on_entity_used(const Entity& entity, Player* player);
|
||||
|
||||
/// @brief Called on UI view show
|
||||
void on_ui_open(UiDocument* layout, std::vector<dv::value> args);
|
||||
/// @brief Called on UI document show
|
||||
void on_ui_open(const UiDocument& layout, std::vector<dv::value> args);
|
||||
|
||||
void on_ui_progress(UiDocument* layout, int workDone, int totalWork);
|
||||
void on_ui_progress(const UiDocument& layout, int workDone, int totalWork);
|
||||
|
||||
/// @brief Called on UI view close
|
||||
void on_ui_close(UiDocument* layout, Inventory* inventory);
|
||||
/// @brief Called on UI document close
|
||||
void on_ui_close(const UiDocument& layout, Inventory* inventory);
|
||||
|
||||
/// @brief Called on UI document destroy
|
||||
void on_ui_destroy(const UiDocument& layout);
|
||||
|
||||
/// @brief Called on Content loading
|
||||
void on_scripts_loading();
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ static void init_component_events(
|
|||
funcsset.on_aim_off = lua::hasfield(L, "on_aim_off");
|
||||
funcsset.on_attacked = lua::hasfield(L, "on_attacked");
|
||||
funcsset.on_used = lua::hasfield(L, "on_used");
|
||||
funcsset.on_player_set = lua::hasfield(L, "on_player_set");
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +148,12 @@ void scripting::on_entity_spawn(
|
|||
lua::call(L, 1);
|
||||
}
|
||||
for (auto& component : components) {
|
||||
create_component(L, -1, *component, args, saved);
|
||||
try {
|
||||
create_component(L, -1, *component, args, saved);
|
||||
} catch (const std::runtime_error& err) {
|
||||
logger.error() << "could not to initialize user component "
|
||||
<< component->name << ": " << err.what();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [packid, pack] : content->getPacks()) {
|
||||
|
|
@ -165,6 +171,9 @@ static void process_entity_callback(
|
|||
const std::string& name,
|
||||
std::function<int(lua::State*)> args
|
||||
) {
|
||||
if (env == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto L = lua::get_main_state();
|
||||
lua::pushenv(L, *env);
|
||||
if (lua::hasfield(L, "__disabled")) {
|
||||
|
|
@ -238,6 +247,15 @@ void scripting::on_entity_save(const Entity& entity) {
|
|||
);
|
||||
}
|
||||
|
||||
void scripting::on_entity_player_set(const Entity& entity, int64_t pid) {
|
||||
process_entity_callback(
|
||||
entity,
|
||||
"on_player_set",
|
||||
&EntityFuncsSet::on_player_set,
|
||||
[pid](auto L) { return lua::pushinteger(L, pid); }
|
||||
);
|
||||
}
|
||||
|
||||
void scripting::on_sensor_enter(
|
||||
const Entity& entity, size_t index, entityid_t oid
|
||||
) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue