move lua libs to /logic/scripting/lua/libs
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
#include "../lua_util.hpp"
|
||||
|
||||
/// Definitions can be found in local .cpp files
|
||||
/// having same names as declarations
|
||||
|
||||
/// l_ prefix means that function is lua_CFunction:
|
||||
/// int l_function_name(lua_State* L);
|
||||
/// use following syntax:
|
||||
/// int l_function_name(lua::State* L);
|
||||
|
||||
// Libraries
|
||||
extern const luaL_Reg audiolib[];
|
||||
extern const luaL_Reg blocklib[];
|
||||
extern const luaL_Reg cameralib[];
|
||||
extern const luaL_Reg consolelib[];
|
||||
extern const luaL_Reg corelib[];
|
||||
extern const luaL_Reg entitylib[];
|
||||
extern const luaL_Reg filelib[];
|
||||
extern const luaL_Reg guilib[];
|
||||
extern const luaL_Reg hudlib[];
|
||||
extern const luaL_Reg inputlib[];
|
||||
extern const luaL_Reg inventorylib[];
|
||||
extern const luaL_Reg itemlib[];
|
||||
extern const luaL_Reg jsonlib[];
|
||||
extern const luaL_Reg mat4lib[];
|
||||
extern const luaL_Reg packlib[];
|
||||
extern const luaL_Reg playerlib[];
|
||||
extern const luaL_Reg generationlib[];
|
||||
extern const luaL_Reg quatlib[]; // quat.cpp
|
||||
extern const luaL_Reg timelib[];
|
||||
extern const luaL_Reg tomllib[];
|
||||
extern const luaL_Reg vec2lib[]; // vecn.cpp
|
||||
extern const luaL_Reg vec3lib[]; // vecn.cpp
|
||||
extern const luaL_Reg vec4lib[]; // vecn.cpp
|
||||
extern const luaL_Reg worldlib[];
|
||||
|
||||
// Components
|
||||
extern const luaL_Reg skeletonlib[];
|
||||
extern const luaL_Reg rigidbodylib[];
|
||||
extern const luaL_Reg transformlib[];
|
||||
|
||||
// Lua Overrides
|
||||
extern int l_print(lua::State* L);
|
||||
|
||||
namespace lua {
|
||||
inline uint check_argc(lua::State* L, int a) {
|
||||
int argc = lua::gettop(L);
|
||||
if (argc == a) {
|
||||
return static_cast<uint>(argc);
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"invalid number of arguments (" + std::to_string(a) +
|
||||
" expected)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uint check_argc(lua::State* L, int a, int b) {
|
||||
int argc = lua::gettop(L);
|
||||
if (argc == a || argc == b) {
|
||||
return static_cast<uint>(argc);
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"invalid number of arguments (" + std::to_string(a) + " or " +
|
||||
std::to_string(b) + " expected)"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initialize_libs_extends(lua::State* L);
|
||||
@@ -0,0 +1,151 @@
|
||||
#include "util/stringutil.hpp"
|
||||
#include "libentity.hpp"
|
||||
|
||||
static int l_get_vel(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushvec3(L, entity->getRigidbody().hitbox.velocity);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_vel(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getRigidbody().hitbox.velocity = lua::tovec3(L, 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_is_enabled(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
lua::pushboolean(L, entity->getRigidbody().enabled);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_enabled(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getRigidbody().enabled = lua::toboolean(L, 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_size(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushvec3(L, entity->getRigidbody().hitbox.halfsize * 2.0f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_size(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getRigidbody().hitbox.halfsize = lua::tovec3(L, 2) * 0.5f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_gravity_scale(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushnumber(L, entity->getRigidbody().hitbox.gravityScale);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_gravity_scale(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getRigidbody().hitbox.gravityScale = lua::tonumber(L, 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_is_vdamping(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushboolean(
|
||||
L, entity->getRigidbody().hitbox.verticalDamping
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_vdamping(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getRigidbody().hitbox.verticalDamping = lua::toboolean(L, 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_is_grounded(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushboolean(L, entity->getRigidbody().hitbox.grounded);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_is_crouching(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushboolean(L, entity->getRigidbody().hitbox.crouching);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_crouching(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getRigidbody().hitbox.crouching = lua::toboolean(L, 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_body_type(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushstring(
|
||||
L, to_string(entity->getRigidbody().hitbox.type)
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_body_type(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
if (auto type = BodyType_from(lua::tostring(L, 2))) {
|
||||
entity->getRigidbody().hitbox.type = *type;
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"unknown body type " + util::quote(lua::tostring(L, 2))
|
||||
);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_linear_damping(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushnumber(L, entity->getRigidbody().hitbox.linearDamping);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_linear_damping(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getRigidbody().hitbox.linearDamping = lua::tonumber(L, 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg rigidbodylib[] = {
|
||||
{"is_enabled", lua::wrap<l_is_enabled>},
|
||||
{"set_enabled", lua::wrap<l_set_enabled>},
|
||||
{"get_vel", lua::wrap<l_get_vel>},
|
||||
{"set_vel", lua::wrap<l_set_vel>},
|
||||
{"get_size", lua::wrap<l_get_size>},
|
||||
{"set_size", lua::wrap<l_set_size>},
|
||||
{"get_gravity_scale", lua::wrap<l_get_gravity_scale>},
|
||||
{"set_gravity_scale", lua::wrap<l_set_gravity_scale>},
|
||||
{"get_linear_damping", lua::wrap<l_get_linear_damping>},
|
||||
{"set_linear_damping", lua::wrap<l_set_linear_damping>},
|
||||
{"is_vdamping", lua::wrap<l_is_vdamping>},
|
||||
{"set_vdamping", lua::wrap<l_set_vdamping>},
|
||||
{"is_grounded", lua::wrap<l_is_grounded>},
|
||||
{"is_crouching", lua::wrap<l_is_crouching>},
|
||||
{"set_crouching", lua::wrap<l_set_crouching>},
|
||||
{"get_body_type", lua::wrap<l_get_body_type>},
|
||||
{"set_body_type", lua::wrap<l_set_body_type>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,145 @@
|
||||
#include "objects/rigging.hpp"
|
||||
#include "libentity.hpp"
|
||||
|
||||
static int index_range_check(
|
||||
const rigging::Skeleton& skeleton, lua::Integer index
|
||||
) {
|
||||
if (static_cast<size_t>(index) >= skeleton.pose.matrices.size()) {
|
||||
throw std::runtime_error(
|
||||
"index out of range [0, " +
|
||||
std::to_string(skeleton.pose.matrices.size()) + "]"
|
||||
);
|
||||
}
|
||||
return static_cast<int>(index);
|
||||
}
|
||||
|
||||
static int l_get_model(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
auto* rigConfig = skeleton.config;
|
||||
auto index = index_range_check(skeleton, lua::tointeger(L, 2));
|
||||
const auto& modelOverride = skeleton.modelOverrides[index];
|
||||
if (!modelOverride.model) {
|
||||
return lua::pushstring(L, modelOverride.name);
|
||||
}
|
||||
return lua::pushstring(L, rigConfig->getBones()[index]->model.name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_model(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
auto index = index_range_check(skeleton, lua::tointeger(L, 2));
|
||||
auto& modelOverride = skeleton.modelOverrides[index];
|
||||
if (lua::isnoneornil(L, 3)) {
|
||||
modelOverride = {"", nullptr, true};
|
||||
} else {
|
||||
modelOverride = {lua::require_string(L, 3), nullptr, true};
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_matrix(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
auto index = index_range_check(skeleton, lua::tointeger(L, 2));
|
||||
return lua::pushmat4(L, skeleton.pose.matrices[index]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_matrix(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
auto index = index_range_check(skeleton, lua::tointeger(L, 2));
|
||||
skeleton.pose.matrices[index] = lua::tomat4(L, 3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_texture(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
const auto& found = skeleton.textures.find(lua::require_string(L, 2));
|
||||
if (found != skeleton.textures.end()) {
|
||||
return lua::pushstring(L, found->second);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_texture(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
skeleton.textures[lua::require_string(L, 2)] =
|
||||
lua::require_string(L, 3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_index(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
if (auto bone = skeleton.config->find(lua::require_string(L, 2))) {
|
||||
return lua::pushinteger(L, bone->getIndex());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_is_visible(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
if (!lua::isnoneornil(L, 2)) {
|
||||
auto index = index_range_check(skeleton, lua::tointeger(L, 2));
|
||||
return lua::pushboolean(L, skeleton.flags.at(index).visible);
|
||||
}
|
||||
return lua::pushboolean(L, skeleton.visible);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_visible(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
if (!lua::isnoneornil(L, 3)) {
|
||||
auto index = index_range_check(skeleton, lua::tointeger(L, 2));
|
||||
skeleton.flags.at(index).visible = lua::toboolean(L, 3);
|
||||
} else {
|
||||
skeleton.visible = lua::toboolean(L, 2);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_color(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
return lua::pushvec(L, skeleton.tint);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_color(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto& skeleton = entity->getSkeleton();
|
||||
skeleton.tint = lua::tovec3(L, 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg skeletonlib[] = {
|
||||
{"get_model", lua::wrap<l_get_model>},
|
||||
{"set_model", lua::wrap<l_set_model>},
|
||||
{"get_matrix", lua::wrap<l_get_matrix>},
|
||||
{"set_matrix", lua::wrap<l_set_matrix>},
|
||||
{"get_texture", lua::wrap<l_get_texture>},
|
||||
{"set_texture", lua::wrap<l_set_texture>},
|
||||
{"index", lua::wrap<l_index>},
|
||||
{"is_visible", lua::wrap<l_is_visible>},
|
||||
{"set_visible", lua::wrap<l_set_visible>},
|
||||
{"get_color", lua::wrap<l_get_color>},
|
||||
{"set_color", lua::wrap<l_set_color>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "libentity.hpp"
|
||||
|
||||
static int l_get_pos(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushvec3(L, entity->getTransform().pos);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_pos(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
auto vec = lua::tovec3(L, 2);
|
||||
entity->getTransform().setPos(vec);
|
||||
entity->getRigidbody().hitbox.position = vec;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_size(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushvec3(L, entity->getTransform().size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_size(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getTransform().setSize(lua::tovec3(L, 2));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_rot(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushmat4(L, entity->getTransform().rot);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_rot(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getTransform().setRot(lua::tomat4(L, 2));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg transformlib[] = {
|
||||
{"get_pos", lua::wrap<l_get_pos>},
|
||||
{"set_pos", lua::wrap<l_set_pos>},
|
||||
{"get_size", lua::wrap<l_get_size>},
|
||||
{"set_size", lua::wrap<l_set_size>},
|
||||
{"get_rot", lua::wrap<l_get_rot>},
|
||||
{"set_rot", lua::wrap<l_set_rot>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,387 @@
|
||||
#include "audio/audio.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
inline const char* DEFAULT_CHANNEL = "regular";
|
||||
|
||||
inline int extract_channel_index(lua::State* L, int idx) {
|
||||
const char* channel = DEFAULT_CHANNEL;
|
||||
if (!lua::isnoneornil(L, idx)) {
|
||||
channel = lua::tostring(L, idx);
|
||||
}
|
||||
int index = audio::get_channel_index(channel);
|
||||
if (index == 0) {
|
||||
return -1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
inline audio::speakerid_t play_sound(
|
||||
const char* name,
|
||||
bool relative,
|
||||
lua::Number x,
|
||||
lua::Number y,
|
||||
lua::Number z,
|
||||
lua::Number volume,
|
||||
lua::Number pitch,
|
||||
bool loop,
|
||||
int channel
|
||||
) {
|
||||
if (channel == -1) {
|
||||
return 0;
|
||||
}
|
||||
auto assets = scripting::engine->getAssets();
|
||||
auto sound = assets->get<audio::Sound>(name);
|
||||
if (sound == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return audio::play(
|
||||
sound,
|
||||
glm::vec3(
|
||||
static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)
|
||||
),
|
||||
relative,
|
||||
volume,
|
||||
pitch,
|
||||
loop,
|
||||
audio::PRIORITY_NORMAL,
|
||||
channel
|
||||
);
|
||||
}
|
||||
|
||||
inline audio::speakerid_t play_stream(
|
||||
const char* filename,
|
||||
bool relative,
|
||||
lua::Number x,
|
||||
lua::Number y,
|
||||
lua::Number z,
|
||||
lua::Number volume,
|
||||
lua::Number pitch,
|
||||
bool loop,
|
||||
int channel
|
||||
) {
|
||||
if (channel == -1) {
|
||||
return 0;
|
||||
}
|
||||
auto paths = scripting::engine->getResPaths();
|
||||
return audio::play_stream(
|
||||
paths->find(filename),
|
||||
glm::vec3(
|
||||
static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)
|
||||
),
|
||||
relative,
|
||||
volume,
|
||||
pitch,
|
||||
loop,
|
||||
channel
|
||||
);
|
||||
}
|
||||
|
||||
/// @brief audio.play_stream(
|
||||
/// name: string,
|
||||
/// x: number,
|
||||
/// y: number,
|
||||
/// z: number,
|
||||
/// volume: number,
|
||||
/// pitch: number,
|
||||
/// channel: string = "regular",
|
||||
/// loop: bool = false)
|
||||
static int l_audio_play_stream(lua::State* L) {
|
||||
return lua::pushinteger(
|
||||
L,
|
||||
static_cast<lua::Integer>(play_stream(
|
||||
lua::tostring(L, 1),
|
||||
false,
|
||||
lua::tonumber(L, 2),
|
||||
lua::tonumber(L, 3),
|
||||
lua::tonumber(L, 4),
|
||||
lua::tonumber(L, 5),
|
||||
lua::tonumber(L, 6),
|
||||
lua::toboolean(L, 8),
|
||||
extract_channel_index(L, 7)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/// @brief audio.play_stream_2d(
|
||||
/// name: string,
|
||||
/// volume: number,
|
||||
/// pitch: number,
|
||||
/// channel: string = "regular",
|
||||
/// loop: bool = false)
|
||||
static int l_audio_play_stream_2d(lua::State* L) {
|
||||
return lua::pushinteger(
|
||||
L,
|
||||
static_cast<lua::Integer>(play_stream(
|
||||
lua::tostring(L, 1),
|
||||
true,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
lua::tonumber(L, 2),
|
||||
lua::tonumber(L, 3),
|
||||
lua::toboolean(L, 5),
|
||||
extract_channel_index(L, 4)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/// @brief audio.play_sound(
|
||||
/// name: string,
|
||||
/// x: number,
|
||||
/// y: number,
|
||||
/// z: number,
|
||||
/// volume: number,
|
||||
/// pitch: number,
|
||||
/// channel: string = "regular",
|
||||
/// loop: bool = false)
|
||||
static int l_audio_play_sound(lua::State* L) {
|
||||
return lua::pushinteger(
|
||||
L,
|
||||
static_cast<lua::Integer>(play_sound(
|
||||
lua::tostring(L, 1),
|
||||
false,
|
||||
lua::tonumber(L, 2),
|
||||
lua::tonumber(L, 3),
|
||||
lua::tonumber(L, 4),
|
||||
lua::tonumber(L, 5),
|
||||
lua::tonumber(L, 6),
|
||||
lua::toboolean(L, 8),
|
||||
extract_channel_index(L, 7)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/// @brief audio.play_sound_2d(
|
||||
/// name: string,
|
||||
/// volume: number,
|
||||
/// pitch: number,
|
||||
/// channel: string = "regular",
|
||||
/// loop: bool = false)
|
||||
static int l_audio_play_sound_2d(lua::State* L) {
|
||||
return lua::pushinteger(
|
||||
L,
|
||||
static_cast<lua::Integer>(play_sound(
|
||||
lua::tostring(L, 1),
|
||||
true,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
lua::tonumber(L, 2),
|
||||
lua::tonumber(L, 3),
|
||||
lua::toboolean(L, 5),
|
||||
extract_channel_index(L, 4)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/// @brief audio.stop(speakerid: integer) -> nil
|
||||
static int l_audio_stop(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
speaker->stop();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.pause(speakerid: integer) -> nil
|
||||
static int l_audio_pause(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
speaker->pause();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.resume(speakerid: integer) -> nil
|
||||
static int l_audio_resume(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr && speaker->isPaused()) {
|
||||
speaker->play();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.set_loop(speakerid: integer, value: bool) -> nil
|
||||
static int l_audio_set_loop(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
speaker->setLoop(lua::toboolean(L, 2));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.set_volume(speakerid: integer, value: number) -> nil
|
||||
static int l_audio_set_volume(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
speaker->setVolume(static_cast<float>(lua::tonumber(L, 2)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.set_pitch(speakerid: integer, value: number) -> nil
|
||||
static int l_audio_set_pitch(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
speaker->setPitch(static_cast<float>(lua::tonumber(L, 2)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.set_time(speakerid: integer, value: number) -> nil
|
||||
static int l_audio_set_time(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
speaker->setTime(static_cast<audio::duration_t>(lua::tonumber(L, 2)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.set_position(speakerid: integer, x: number, y: number, z:
|
||||
/// number) -> nil
|
||||
static int l_audio_set_position(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
auto x = lua::tonumber(L, 2);
|
||||
auto y = lua::tonumber(L, 3);
|
||||
auto z = lua::tonumber(L, 4);
|
||||
speaker->setPosition(glm::vec3(
|
||||
static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)
|
||||
));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.set_velocity(speakerid: integer, x: number, y: number, z:
|
||||
/// number) -> nil
|
||||
static int l_audio_set_velocity(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
auto x = lua::tonumber(L, 2);
|
||||
auto y = lua::tonumber(L, 3);
|
||||
auto z = lua::tonumber(L, 4);
|
||||
speaker->setVelocity(glm::vec3(
|
||||
static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)
|
||||
));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.is_playing(speakerid: integer) -> bool
|
||||
static int l_audio_is_playing(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
return lua::pushboolean(L, speaker->isPlaying());
|
||||
}
|
||||
return lua::pushboolean(L, false);
|
||||
}
|
||||
|
||||
/// @brief audio.is_paused(speakerid: integer) -> bool
|
||||
static int l_audio_is_paused(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
return lua::pushboolean(L, speaker->isPaused());
|
||||
}
|
||||
return lua::pushboolean(L, false);
|
||||
}
|
||||
|
||||
/// @brief audio.is_loop(speakerid: integer) -> bool
|
||||
static int l_audio_is_loop(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
return lua::pushboolean(L, speaker->isLoop());
|
||||
}
|
||||
return lua::pushboolean(L, false);
|
||||
}
|
||||
|
||||
/// @brief audio.get_volume(speakerid: integer) -> number
|
||||
static int l_audio_get_volume(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
return lua::pushnumber(L, speaker->getVolume());
|
||||
}
|
||||
return lua::pushnumber(L, 0.0);
|
||||
}
|
||||
|
||||
/// @brief audio.get_pitch(speakerid: integer) -> number
|
||||
static int l_audio_get_pitch(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
return lua::pushnumber(L, speaker->getPitch());
|
||||
}
|
||||
return lua::pushnumber(L, 1.0);
|
||||
}
|
||||
|
||||
/// @brief audio.get_time(speakerid: integer) -> number
|
||||
static int l_audio_get_time(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
return lua::pushnumber(L, speaker->getTime());
|
||||
}
|
||||
return lua::pushnumber(L, 0.0);
|
||||
}
|
||||
|
||||
/// @brief audio.get_duration(speakerid: integer) -> number
|
||||
static int l_audio_get_duration(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
return lua::pushnumber(L, speaker->getDuration());
|
||||
}
|
||||
return lua::pushnumber(L, 0.0);
|
||||
}
|
||||
|
||||
/// @brief audio.get_position(speakerid: integer) -> number, number, number
|
||||
static int l_audio_get_position(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
return lua::pushvec_stack(L, speaker->getPosition());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief audio.get_velocity(speakerid: integer) -> number, number, number
|
||||
static int l_audio_get_velocity(lua::State* L) {
|
||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||
if (speaker != nullptr) {
|
||||
return lua::pushvec_stack(L, speaker->getVelocity());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// @brief audio.count_speakers() -> integer
|
||||
static int l_audio_count_speakers(lua::State* L) {
|
||||
return lua::pushinteger(L, audio::count_speakers());
|
||||
}
|
||||
|
||||
// @brief audio.count_streams() -> integer
|
||||
static int l_audio_count_streams(lua::State* L) {
|
||||
return lua::pushinteger(L, audio::count_streams());
|
||||
}
|
||||
|
||||
const luaL_Reg audiolib[] = {
|
||||
{"play_sound", lua::wrap<l_audio_play_sound>},
|
||||
{"play_sound_2d", lua::wrap<l_audio_play_sound_2d>},
|
||||
{"play_stream", lua::wrap<l_audio_play_stream>},
|
||||
{"play_stream_2d", lua::wrap<l_audio_play_stream_2d>},
|
||||
{"stop", lua::wrap<l_audio_stop>},
|
||||
{"pause", lua::wrap<l_audio_pause>},
|
||||
{"resume", lua::wrap<l_audio_resume>},
|
||||
{"set_loop", lua::wrap<l_audio_set_loop>},
|
||||
{"set_volume", lua::wrap<l_audio_set_volume>},
|
||||
{"set_pitch", lua::wrap<l_audio_set_pitch>},
|
||||
{"set_time", lua::wrap<l_audio_set_time>},
|
||||
{"set_position", lua::wrap<l_audio_set_position>},
|
||||
{"set_velocity", lua::wrap<l_audio_set_velocity>},
|
||||
{"is_playing", lua::wrap<l_audio_is_playing>},
|
||||
{"is_paused", lua::wrap<l_audio_is_paused>},
|
||||
{"is_loop", lua::wrap<l_audio_is_loop>},
|
||||
{"get_volume", lua::wrap<l_audio_get_volume>},
|
||||
{"get_pitch", lua::wrap<l_audio_get_pitch>},
|
||||
{"get_time", lua::wrap<l_audio_get_time>},
|
||||
{"get_duration", lua::wrap<l_audio_get_duration>},
|
||||
{"get_position", lua::wrap<l_audio_get_position>},
|
||||
{"get_velocity", lua::wrap<l_audio_get_velocity>},
|
||||
{"count_speakers", lua::wrap<l_audio_count_speakers>},
|
||||
{"count_streams", lua::wrap<l_audio_count_streams>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,605 @@
|
||||
#include "content/Content.hpp"
|
||||
#include "lighting/Lighting.hpp"
|
||||
#include "logic/BlocksController.hpp"
|
||||
#include "logic/LevelController.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "voxels/Chunk.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "voxels/voxel.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "maths/voxmaths.hpp"
|
||||
#include "data/StructLayout.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static const Block* require_block(lua::State* L) {
|
||||
auto indices = content->getIndices();
|
||||
auto id = lua::tointeger(L, 1);
|
||||
return indices->blocks.get(id);
|
||||
}
|
||||
|
||||
static int l_get_def(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
return lua::pushstring(L, def->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_material(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
return lua::pushstring(L, def->material);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_is_solid_at(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
|
||||
return lua::pushboolean(L, level->chunks->isSolidBlock(x, y, z));
|
||||
}
|
||||
|
||||
static int l_count(lua::State* L) {
|
||||
return lua::pushinteger(L, indices->blocks.count());
|
||||
}
|
||||
|
||||
static int l_index(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
return lua::pushinteger(L, content->blocks.require(name).rt.id);
|
||||
}
|
||||
|
||||
static int l_is_extended(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
return lua::pushboolean(L, def->rt.extended);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_size(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
return lua::pushivec_stack(L, glm::ivec3(def->size));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_is_segment(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
return lua::pushboolean(L, vox->state.segment);
|
||||
}
|
||||
|
||||
static int l_seek_origin(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
auto& def = indices->blocks.require(vox->id);
|
||||
return lua::pushivec_stack(
|
||||
L, level->chunks->seekOrigin({x, y, z}, def, vox->state)
|
||||
);
|
||||
}
|
||||
|
||||
static int l_set(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto id = lua::tointeger(L, 4);
|
||||
auto state = lua::tointeger(L, 5);
|
||||
bool noupdate = lua::toboolean(L, 6);
|
||||
if (static_cast<size_t>(id) >= indices->blocks.count()) {
|
||||
return 0;
|
||||
}
|
||||
if (!level->chunks->get(x, y, z)) {
|
||||
return 0;
|
||||
}
|
||||
level->chunks->set(x, y, z, id, int2blockstate(state));
|
||||
level->lighting->onBlockSet(x, y, z, id);
|
||||
if (!noupdate) {
|
||||
blocks->updateSides(x, y, z);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
int id = vox == nullptr ? -1 : vox->id;
|
||||
return lua::pushinteger(L, id);
|
||||
}
|
||||
|
||||
static int l_get_x(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
if (vox == nullptr) {
|
||||
return lua::pushivec_stack(L, glm::ivec3(1, 0, 0));
|
||||
}
|
||||
const auto& def = level->content->getIndices()->blocks.require(vox->id);
|
||||
if (!def.rotatable) {
|
||||
return lua::pushivec_stack(L, glm::ivec3(1, 0, 0));
|
||||
} else {
|
||||
const CoordSystem& rot = def.rotations.variants[vox->state.rotation];
|
||||
return lua::pushivec_stack(L, rot.axisX);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_get_y(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
if (vox == nullptr) {
|
||||
return lua::pushivec_stack(L, glm::ivec3(0, 1, 0));
|
||||
}
|
||||
const auto& def = level->content->getIndices()->blocks.require(vox->id);
|
||||
if (!def.rotatable) {
|
||||
return lua::pushivec_stack(L, glm::ivec3(0, 1, 0));
|
||||
} else {
|
||||
const CoordSystem& rot = def.rotations.variants[vox->state.rotation];
|
||||
return lua::pushivec_stack(L, rot.axisY);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_get_z(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
if (vox == nullptr) {
|
||||
return lua::pushivec_stack(L, glm::ivec3(0, 0, 1));
|
||||
}
|
||||
const auto& def = level->content->getIndices()->blocks.require(vox->id);
|
||||
if (!def.rotatable) {
|
||||
return lua::pushivec_stack(L, glm::ivec3(0, 0, 1));
|
||||
} else {
|
||||
const CoordSystem& rot = def.rotations.variants[vox->state.rotation];
|
||||
return lua::pushivec_stack(L, rot.axisZ);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_get_rotation(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
voxel* vox = level->chunks->get(x, y, z);
|
||||
int rotation = vox == nullptr ? 0 : vox->state.rotation;
|
||||
return lua::pushinteger(L, rotation);
|
||||
}
|
||||
|
||||
static int l_set_rotation(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto value = lua::tointeger(L, 4);
|
||||
level->chunks->setRotation(x, y, z, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_states(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
int states = vox == nullptr ? 0 : blockstate2int(vox->state);
|
||||
return lua::pushinteger(L, states);
|
||||
}
|
||||
|
||||
static int l_set_states(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto states = lua::tointeger(L, 4);
|
||||
|
||||
auto chunk = level->chunks->getChunkByVoxel(x, y, z);
|
||||
if (chunk == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
vox->state = int2blockstate(states);
|
||||
chunk->setModifiedAndUnsaved();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_user_bits(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto offset = lua::tointeger(L, 4) + VOXEL_USER_BITS_OFFSET;
|
||||
auto bits = lua::tointeger(L, 5);
|
||||
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
if (vox == nullptr) {
|
||||
return lua::pushinteger(L, 0);
|
||||
}
|
||||
uint mask = ((1 << bits) - 1) << offset;
|
||||
uint data = (blockstate2int(vox->state) & mask) >> offset;
|
||||
return lua::pushinteger(L, data);
|
||||
}
|
||||
|
||||
static int l_set_user_bits(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto offset = lua::tointeger(L, 4);
|
||||
auto bits = lua::tointeger(L, 5);
|
||||
|
||||
size_t mask = ((1 << bits) - 1) << offset;
|
||||
auto value = (lua::tointeger(L, 6) << offset) & mask;
|
||||
|
||||
auto chunk = level->chunks->getChunkByVoxel(x, y, z);
|
||||
if (chunk == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
if (vox == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
vox->state.userbits = (vox->state.userbits & (~mask)) | value;
|
||||
chunk->setModifiedAndUnsaved();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_is_replaceable_at(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
return lua::pushboolean(L, level->chunks->isReplaceableBlock(x, y, z));
|
||||
}
|
||||
|
||||
static int l_caption(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
return lua::pushstring(L, def->caption);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_textures(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
lua::createtable(L, 6, 0);
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
lua::pushstring(L, def->textureFaces[i]);
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_model(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
return lua::pushstring(L, to_string(def->model));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_hitbox(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
auto& hitbox = def->rt.hitboxes[lua::tointeger(L, 2)].at(0);
|
||||
lua::createtable(L, 2, 0);
|
||||
|
||||
lua::pushvec3(L, hitbox.min());
|
||||
lua::rawseti(L, 1);
|
||||
|
||||
lua::pushvec3(L, hitbox.size());
|
||||
lua::rawseti(L, 2);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_rotation_profile(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
return lua::pushstring(L, def->rotations.name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_picking_item(lua::State* L) {
|
||||
if (auto def = require_block(L)) {
|
||||
return lua::pushinteger(L, def->rt.pickingItem);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_place(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto id = lua::tointeger(L, 4);
|
||||
auto state = lua::tointeger(L, 5);
|
||||
auto playerid = lua::gettop(L) >= 6 ? lua::tointeger(L, 6) : -1;
|
||||
if (static_cast<size_t>(id) >= indices->blocks.count()) {
|
||||
return 0;
|
||||
}
|
||||
if (!level->chunks->get(x, y, z)) {
|
||||
return 0;
|
||||
}
|
||||
const auto def = level->content->getIndices()->blocks.get(id);
|
||||
if (def == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"there is no block with index " + std::to_string(id)
|
||||
);
|
||||
}
|
||||
auto player = level->getObject<Player>(playerid);
|
||||
controller->getBlocksController()->placeBlock(
|
||||
player ? player.get() : nullptr, *def, int2blockstate(state), x, y, z
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_destruct(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto playerid = lua::gettop(L) >= 4 ? lua::tointeger(L, 4) : -1;
|
||||
auto voxel = level->chunks->get(x, y, z);
|
||||
if (voxel == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto& def = level->content->getIndices()->blocks.require(voxel->id);
|
||||
auto player = level->getObject<Player>(playerid);
|
||||
controller->getBlocksController()->breakBlock(
|
||||
player ? player.get() : nullptr, def, x, y, z
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
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::ivec3 normal;
|
||||
glm::ivec3 iend;
|
||||
if (auto voxel = level->chunks->rayCast(
|
||||
start, dir, maxDistance, end, normal, iend, filteredBlocks
|
||||
)) {
|
||||
if (lua::gettop(L) >= 4 && !lua::isnil(L, 4)) {
|
||||
lua::pushvalue(L, 4);
|
||||
} 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, voxel->id);
|
||||
lua::setfield(L, "block");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_compose_state(lua::State* L) {
|
||||
if (!lua::istable(L, 1) || lua::objlen(L, 1) < 3) {
|
||||
throw std::runtime_error("expected array of 3 integers");
|
||||
}
|
||||
blockstate state {};
|
||||
|
||||
lua::rawgeti(L, 1, 1);
|
||||
state.rotation = lua::tointeger(L, -1);
|
||||
lua::pop(L);
|
||||
lua::rawgeti(L, 2, 1);
|
||||
state.segment = lua::tointeger(L, -1);
|
||||
lua::pop(L);
|
||||
lua::rawgeti(L, 3, 1);
|
||||
state.userbits = lua::tointeger(L, -1);
|
||||
lua::pop(L);
|
||||
|
||||
return lua::pushinteger(L, blockstate2int(state));
|
||||
}
|
||||
|
||||
static int l_decompose_state(lua::State* L) {
|
||||
auto stateInt = static_cast<blockstate_t>(lua::tointeger(L, 1));
|
||||
auto state = int2blockstate(stateInt);
|
||||
|
||||
lua::createtable(L, 3, 0);
|
||||
lua::pushinteger(L, state.rotation);
|
||||
lua::rawseti(L, 1);
|
||||
|
||||
lua::pushinteger(L, state.segment);
|
||||
lua::rawseti(L, 2);
|
||||
|
||||
lua::pushinteger(L, state.userbits);
|
||||
lua::rawseti(L, 3);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_field(
|
||||
lua::State* L,
|
||||
const ubyte* src,
|
||||
const data::Field& field,
|
||||
size_t index,
|
||||
const data::StructLayout& dataStruct
|
||||
) {
|
||||
switch (field.type) {
|
||||
case data::FieldType::I8:
|
||||
case data::FieldType::I16:
|
||||
case data::FieldType::I32:
|
||||
case data::FieldType::I64:
|
||||
return lua::pushinteger(L, dataStruct.getInteger(src, field, index));
|
||||
case data::FieldType::F32:
|
||||
case data::FieldType::F64:
|
||||
return lua::pushnumber(L, dataStruct.getNumber(src, field, index));
|
||||
case data::FieldType::CHAR:
|
||||
return lua::pushstring(L,
|
||||
std::string(dataStruct.getChars(src, field)).c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_field(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto name = lua::require_string(L, 4);
|
||||
size_t index = 0;
|
||||
if (lua::gettop(L) >= 5) {
|
||||
index = lua::tointeger(L, 5);
|
||||
}
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
auto cx = floordiv(x, CHUNK_W);
|
||||
auto cz = floordiv(z, CHUNK_D);
|
||||
auto chunk = level->chunks->getChunk(cx, cz);
|
||||
auto lx = x - cx * CHUNK_W;
|
||||
auto lz = z - cz * CHUNK_W;
|
||||
size_t voxelIndex = vox_index(lx, y, lz);
|
||||
|
||||
const auto& def = content->getIndices()->blocks.require(vox->id);
|
||||
if (def.dataStruct == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
const auto& dataStruct = *def.dataStruct;
|
||||
const auto field = dataStruct.getField(name);
|
||||
if (field == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
if (index >= field->elements) {
|
||||
throw std::out_of_range(
|
||||
"index out of bounds [0, "+std::to_string(field->elements)+"]");
|
||||
}
|
||||
const ubyte* src = chunk->blocksMetadata.find(voxelIndex);
|
||||
if (src == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return get_field(L, src, *field, index, dataStruct);
|
||||
}
|
||||
|
||||
static int set_field(
|
||||
lua::State* L,
|
||||
ubyte* dst,
|
||||
const data::Field& field,
|
||||
size_t index,
|
||||
const data::StructLayout& dataStruct,
|
||||
const dv::value& value
|
||||
) {
|
||||
switch (field.type) {
|
||||
case data::FieldType::CHAR:
|
||||
if (value.isString()) {
|
||||
return lua::pushinteger(L,
|
||||
dataStruct.setUnicode(dst, value.asString(), field));
|
||||
}
|
||||
case data::FieldType::I8:
|
||||
case data::FieldType::I16:
|
||||
case data::FieldType::I32:
|
||||
case data::FieldType::I64:
|
||||
dataStruct.setInteger(dst, value.asInteger(), field, index);
|
||||
break;
|
||||
case data::FieldType::F32:
|
||||
case data::FieldType::F64:
|
||||
dataStruct.setNumber(dst, value.asNumber(), field, index);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_field(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto name = lua::require_string(L, 4);
|
||||
auto value = lua::tovalue(L, 5);
|
||||
size_t index = 0;
|
||||
if (lua::gettop(L) >= 6) {
|
||||
index = lua::tointeger(L, 6);
|
||||
}
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
auto cx = floordiv(x, CHUNK_W);
|
||||
auto cz = floordiv(z, CHUNK_D);
|
||||
auto chunk = level->chunks->getChunk(cx, cz);
|
||||
auto lx = x - cx * CHUNK_W;
|
||||
auto lz = z - cz * CHUNK_W;
|
||||
size_t voxelIndex = vox_index(lx, y, lz);
|
||||
|
||||
const auto& def = content->getIndices()->blocks.require(vox->id);
|
||||
if (def.dataStruct == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
const auto& dataStruct = *def.dataStruct;
|
||||
const auto field = dataStruct.getField(name);
|
||||
if (field == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
if (index >= field->elements) {
|
||||
throw std::out_of_range(
|
||||
"index out of bounds [0, "+std::to_string(field->elements)+"]");
|
||||
}
|
||||
ubyte* dst = chunk->blocksMetadata.find(voxelIndex);
|
||||
if (dst == nullptr) {
|
||||
dst = chunk->blocksMetadata.allocate(voxelIndex, dataStruct.size());
|
||||
}
|
||||
chunk->flags.unsaved = true;
|
||||
chunk->flags.blocksData = true;
|
||||
return set_field(L, dst, *field, index, dataStruct, value);
|
||||
}
|
||||
|
||||
const luaL_Reg blocklib[] = {
|
||||
{"index", lua::wrap<l_index>},
|
||||
{"name", lua::wrap<l_get_def>},
|
||||
{"material", lua::wrap<l_material>},
|
||||
{"caption", lua::wrap<l_caption>},
|
||||
{"defs_count", lua::wrap<l_count>},
|
||||
{"is_solid_at", lua::wrap<l_is_solid_at>},
|
||||
{"is_replaceable_at", lua::wrap<l_is_replaceable_at>},
|
||||
{"set", lua::wrap<l_set>},
|
||||
{"get", lua::wrap<l_get>},
|
||||
{"get_X", lua::wrap<l_get_x>},
|
||||
{"get_Y", lua::wrap<l_get_y>},
|
||||
{"get_Z", lua::wrap<l_get_z>},
|
||||
{"get_states", lua::wrap<l_get_states>},
|
||||
{"set_states", lua::wrap<l_set_states>},
|
||||
{"get_rotation", lua::wrap<l_get_rotation>},
|
||||
{"set_rotation", lua::wrap<l_set_rotation>},
|
||||
{"get_user_bits", lua::wrap<l_get_user_bits>},
|
||||
{"set_user_bits", lua::wrap<l_set_user_bits>},
|
||||
{"is_extended", lua::wrap<l_is_extended>},
|
||||
{"get_size", lua::wrap<l_get_size>},
|
||||
{"is_segment", lua::wrap<l_is_segment>},
|
||||
{"seek_origin", lua::wrap<l_seek_origin>},
|
||||
{"get_textures", lua::wrap<l_get_textures>},
|
||||
{"get_model", lua::wrap<l_get_model>},
|
||||
{"get_hitbox", lua::wrap<l_get_hitbox>},
|
||||
{"get_rotation_profile", lua::wrap<l_get_rotation_profile>},
|
||||
{"get_picking_item", lua::wrap<l_get_picking_item>},
|
||||
{"place", lua::wrap<l_place>},
|
||||
{"destruct", lua::wrap<l_destruct>},
|
||||
{"raycast", lua::wrap<l_raycast>},
|
||||
{"compose_state", lua::wrap<l_compose_state>},
|
||||
{"decompose_state", lua::wrap<l_decompose_state>},
|
||||
{"get_field", lua::wrap<l_get_field>},
|
||||
{"set_field", lua::wrap<l_set_field>},
|
||||
{NULL, NULL}
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
#include <glm/ext.hpp>
|
||||
|
||||
#include "content/Content.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
template <int (*getterfunc)(lua::State*, const Camera&)>
|
||||
static int l_camera_getter(lua::State* L) {
|
||||
size_t index = static_cast<size_t>(lua::tointeger(L, 1));
|
||||
return getterfunc(L, *level->cameras.at(index));
|
||||
}
|
||||
|
||||
template <void (*setterfunc)(lua::State*, Camera&, int)>
|
||||
static int l_camera_setter(lua::State* L) {
|
||||
size_t index = static_cast<size_t>(lua::tointeger(L, 1));
|
||||
setterfunc(L, *level->cameras.at(index), 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_index(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
auto& indices = content->getIndices(ResourceType::CAMERA);
|
||||
return lua::pushinteger(L, indices.indexOf(name));
|
||||
}
|
||||
|
||||
static int l_name(lua::State* L) {
|
||||
size_t index = static_cast<size_t>(lua::tointeger(L, 1));
|
||||
auto& indices = content->getIndices(ResourceType::CAMERA);
|
||||
return lua::pushstring(L, indices.getName(index));
|
||||
}
|
||||
|
||||
static int getter_pos(lua::State* L, const Camera& camera) {
|
||||
return lua::pushvec3(L, camera.position);
|
||||
}
|
||||
|
||||
static void setter_pos(lua::State* L, Camera& camera, int idx) {
|
||||
camera.position = lua::tovec<3>(L, idx);
|
||||
}
|
||||
|
||||
static int getter_rot(lua::State* L, const Camera& camera) {
|
||||
return lua::pushmat4(L, camera.rotation);
|
||||
}
|
||||
|
||||
static void setter_rot(lua::State* L, Camera& camera, int idx) {
|
||||
camera.rotation = lua::tomat4(L, idx);
|
||||
camera.updateVectors();
|
||||
}
|
||||
|
||||
static int getter_zoom(lua::State* L, const Camera& camera) {
|
||||
return lua::pushnumber(L, camera.zoom);
|
||||
}
|
||||
static void setter_zoom(lua::State* L, Camera& camera, int idx) {
|
||||
camera.zoom = lua::tonumber(L, idx);
|
||||
}
|
||||
|
||||
static int getter_fov(lua::State* L, const Camera& camera) {
|
||||
return lua::pushnumber(L, glm::degrees(camera.getFov()));
|
||||
}
|
||||
static void setter_fov(lua::State* L, Camera& camera, int idx) {
|
||||
camera.setFov(glm::radians(lua::tonumber(L, idx)));
|
||||
}
|
||||
|
||||
static int getter_perspective(lua::State* L, const Camera& camera) {
|
||||
return lua::pushboolean(L, camera.perspective);
|
||||
}
|
||||
static void setter_perspective(lua::State* L, Camera& camera, int idx) {
|
||||
camera.perspective = lua::toboolean(L, idx);
|
||||
}
|
||||
|
||||
static int getter_flipped(lua::State* L, const Camera& camera) {
|
||||
return lua::pushboolean(L, camera.flipped);
|
||||
}
|
||||
static void setter_flipped(lua::State* L, Camera& camera, int idx) {
|
||||
camera.flipped = lua::toboolean(L, idx);
|
||||
}
|
||||
|
||||
static int getter_front(lua::State* L, const Camera& camera) {
|
||||
return lua::pushvec3(L, camera.front);
|
||||
}
|
||||
static int getter_right(lua::State* L, const Camera& camera) {
|
||||
return lua::pushvec3(L, camera.right);
|
||||
}
|
||||
static int getter_up(lua::State* L, const Camera& camera) {
|
||||
return lua::pushvec3(L, camera.up);
|
||||
}
|
||||
|
||||
static int l_look_at(lua::State* L) {
|
||||
size_t index = static_cast<size_t>(lua::tointeger(L, 1));
|
||||
auto& camera = *level->cameras.at(index);
|
||||
auto center = lua::tovec<3>(L, 2);
|
||||
auto matrix = glm::inverse(
|
||||
glm::lookAt(glm::vec3(), center - camera.position, glm::vec3(0, 1, 0))
|
||||
);
|
||||
if (lua::isnumber(L, 3)) {
|
||||
matrix = glm::mat4_cast(glm::slerp(
|
||||
glm::quat(camera.rotation),
|
||||
glm::quat(matrix),
|
||||
static_cast<float>(lua::tonumber(L, 3))
|
||||
));
|
||||
}
|
||||
camera.rotation = matrix;
|
||||
camera.updateVectors();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg cameralib[] = {
|
||||
{"index", lua::wrap<l_index>},
|
||||
{"name", lua::wrap<l_name>},
|
||||
{"get_pos", lua::wrap<l_camera_getter<getter_pos>>},
|
||||
{"set_pos", lua::wrap<l_camera_setter<setter_pos>>},
|
||||
{"get_rot", lua::wrap<l_camera_getter<getter_rot>>},
|
||||
{"set_rot", lua::wrap<l_camera_setter<setter_rot>>},
|
||||
{"get_zoom", lua::wrap<l_camera_getter<getter_zoom>>},
|
||||
{"set_zoom", lua::wrap<l_camera_setter<setter_zoom>>},
|
||||
{"get_fov", lua::wrap<l_camera_getter<getter_fov>>},
|
||||
{"set_fov", lua::wrap<l_camera_setter<setter_fov>>},
|
||||
{"is_perspective", lua::wrap<l_camera_getter<getter_perspective>>},
|
||||
{"set_perspective", lua::wrap<l_camera_setter<setter_perspective>>},
|
||||
{"is_flipped", lua::wrap<l_camera_getter<getter_flipped>>},
|
||||
{"set_flipped", lua::wrap<l_camera_setter<setter_flipped>>},
|
||||
{"get_front", lua::wrap<l_camera_getter<getter_front>>},
|
||||
{"get_right", lua::wrap<l_camera_getter<getter_right>>},
|
||||
{"get_up", lua::wrap<l_camera_getter<getter_up>>},
|
||||
{"look_at", lua::wrap<l_look_at>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,118 @@
|
||||
#include "coders/commons.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "logic/CommandsInterpreter.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static int l_add_command(lua::State* L) {
|
||||
if (!lua::isfunction(L, 3)) {
|
||||
throw std::runtime_error("invalid callback");
|
||||
}
|
||||
auto scheme = lua::require_string(L, 1);
|
||||
auto description = lua::require_string(L, 2);
|
||||
lua::pushvalue(L, 3);
|
||||
auto func = lua::create_lambda(L);
|
||||
try {
|
||||
engine->getCommandsInterpreter()->getRepository()->add(
|
||||
scheme,
|
||||
description,
|
||||
[func](auto, auto args, auto kwargs) {
|
||||
return func({args, kwargs});
|
||||
}
|
||||
);
|
||||
} catch (const parsing_error& err) {
|
||||
throw std::runtime_error(
|
||||
("command scheme error:\n" + err.errorLog()).c_str()
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_execute(lua::State* L) {
|
||||
auto prompt = lua::require_string(L, 1);
|
||||
auto result = engine->getCommandsInterpreter()->execute(prompt);
|
||||
lua::pushvalue(L, result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_set(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
auto value = lua::tovalue(L, 2);
|
||||
(*engine->getCommandsInterpreter())[name] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_commands_list(lua::State* L) {
|
||||
auto interpreter = engine->getCommandsInterpreter();
|
||||
auto repo = interpreter->getRepository();
|
||||
const auto& commands = repo->getCommands();
|
||||
|
||||
lua::createtable(L, commands.size(), 0);
|
||||
size_t index = 1;
|
||||
for (const auto& entry : commands) {
|
||||
lua::pushstring(L, entry.first);
|
||||
lua::rawseti(L, index++);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_get_command_info(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
auto interpreter = engine->getCommandsInterpreter();
|
||||
auto repo = interpreter->getRepository();
|
||||
auto command = repo->get(name);
|
||||
if (command == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
const auto& args = command->getArgs();
|
||||
const auto& kwargs = command->getKwArgs();
|
||||
|
||||
lua::createtable(L, 0, 4);
|
||||
|
||||
lua::pushstring(L, name);
|
||||
lua::setfield(L, "name");
|
||||
|
||||
lua::pushstring(L, command->getDescription());
|
||||
lua::setfield(L, "description");
|
||||
|
||||
lua::createtable(L, args.size(), 0);
|
||||
for (size_t i = 0; i < args.size(); i++) {
|
||||
auto& arg = args[i];
|
||||
lua::createtable(L, 0, 2);
|
||||
|
||||
lua::pushstring(L, arg.name);
|
||||
lua::setfield(L, "name");
|
||||
|
||||
lua::pushstring(L, cmd::argtype_name(arg.type));
|
||||
lua::setfield(L, "type");
|
||||
|
||||
if (arg.optional) {
|
||||
lua::pushboolean(L, true);
|
||||
lua::setfield(L, "optional");
|
||||
}
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
lua::setfield(L, "args");
|
||||
|
||||
lua::createtable(L, 0, kwargs.size());
|
||||
for (auto& entry : kwargs) {
|
||||
auto& arg = entry.second;
|
||||
lua::createtable(L, 0, 1);
|
||||
|
||||
lua::pushstring(L, cmd::argtype_name(arg.type));
|
||||
lua::setfield(L, "type");
|
||||
|
||||
lua::setfield(L, arg.name);
|
||||
}
|
||||
lua::setfield(L, "kwargs");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg consolelib[] = {
|
||||
{"add_command", lua::wrap<l_add_command>},
|
||||
{"execute", lua::wrap<l_execute>},
|
||||
{"set", lua::wrap<l_set>},
|
||||
{"get_commands_list", lua::wrap<l_get_commands_list>},
|
||||
{"get_command_info", lua::wrap<l_get_command_info>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,195 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "constants.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "files/engine_paths.hpp"
|
||||
#include "files/settings_io.hpp"
|
||||
#include "frontend/menu.hpp"
|
||||
#include "frontend/screens/MenuScreen.hpp"
|
||||
#include "logic/EngineController.hpp"
|
||||
#include "logic/LevelController.hpp"
|
||||
#include "window/Events.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "world/generator/WorldGenerator.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "util/listutil.hpp"
|
||||
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
/// @brief Creating new world
|
||||
/// @param name Name world
|
||||
/// @param seed Seed world
|
||||
/// @param generator Type of generation
|
||||
static int l_new_world(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
auto seed = lua::require_string(L, 2);
|
||||
auto generator = lua::require_string(L, 3);
|
||||
auto controller = engine->getController();
|
||||
controller->createWorld(name, seed, generator);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Open world
|
||||
/// @param name Name world
|
||||
static int l_open_world(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
|
||||
auto controller = engine->getController();
|
||||
controller->openWorld(name, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Reopen world
|
||||
static int l_reopen_world(lua::State*) {
|
||||
auto controller = engine->getController();
|
||||
controller->reopenWorld(level->getWorld());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Close world
|
||||
/// @param flag Save world (bool)
|
||||
static int l_close_world(lua::State* L) {
|
||||
if (controller == nullptr) {
|
||||
throw std::runtime_error("no world open");
|
||||
}
|
||||
bool save_world = lua::toboolean(L, 1);
|
||||
if (save_world) {
|
||||
controller->saveWorld();
|
||||
}
|
||||
// destroy LevelScreen and run quit callbacks
|
||||
engine->setScreen(nullptr);
|
||||
// create and go to menu screen
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Delete world
|
||||
/// @param name Name world
|
||||
static int l_delete_world(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
auto controller = engine->getController();
|
||||
controller->deleteWorld(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Reconfigure packs
|
||||
/// @param addPacks An array of packs to add
|
||||
/// @param remPacks An array of packs to remove
|
||||
static int l_reconfig_packs(lua::State* L) {
|
||||
if (!lua::istable(L, 1)) {
|
||||
throw std::runtime_error("strings array expected as the first argument"
|
||||
);
|
||||
}
|
||||
if (!lua::istable(L, 2)) {
|
||||
throw std::runtime_error("strings array expected as the second argument"
|
||||
);
|
||||
}
|
||||
std::vector<std::string> addPacks;
|
||||
if (!lua::istable(L, 1)) {
|
||||
throw std::runtime_error("an array expected as argument 1");
|
||||
}
|
||||
int addLen = lua::objlen(L, 1);
|
||||
for (int i = 0; i < addLen; i++) {
|
||||
lua::rawgeti(L, i + 1, 1);
|
||||
addPacks.emplace_back(lua::tostring(L, -1));
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
std::vector<std::string> remPacks;
|
||||
if (!lua::istable(L, 2)) {
|
||||
throw std::runtime_error("an array expected as argument 2");
|
||||
}
|
||||
int remLen = lua::objlen(L, 2);
|
||||
for (int i = 0; i < remLen; i++) {
|
||||
lua::rawgeti(L, i + 1, 2);
|
||||
remPacks.emplace_back(lua::tostring(L, -1));
|
||||
lua::pop(L);
|
||||
}
|
||||
auto engine_controller = engine->getController();
|
||||
engine_controller->reconfigPacks(controller, addPacks, remPacks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Get a setting value
|
||||
/// @param name The name of the setting
|
||||
/// @return The value of the setting
|
||||
static int l_get_setting(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
const auto value = engine->getSettingsHandler().getValue(name);
|
||||
return lua::pushvalue(L, value);
|
||||
}
|
||||
|
||||
/// @brief Set a setting value
|
||||
/// @param name The name of the setting
|
||||
/// @param value The new value for the setting
|
||||
static int l_set_setting(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
const auto value = lua::tovalue(L, 2);
|
||||
engine->getSettingsHandler().setValue(name, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Convert a setting value to a string
|
||||
/// @param name The name of the setting
|
||||
/// @return The string representation of the setting value
|
||||
static int l_str_setting(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
const auto string = engine->getSettingsHandler().toString(name);
|
||||
return lua::pushstring(L, string);
|
||||
}
|
||||
|
||||
/// @brief Get information about a setting
|
||||
/// @param name The name of the setting
|
||||
/// @return A table with information about the setting
|
||||
static int l_get_setting_info(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
auto setting = engine->getSettingsHandler().getSetting(name);
|
||||
lua::createtable(L, 0, 1);
|
||||
if (auto number = dynamic_cast<NumberSetting*>(setting)) {
|
||||
lua::pushnumber(L, number->getMin());
|
||||
lua::setfield(L, "min");
|
||||
lua::pushnumber(L, number->getMax());
|
||||
lua::setfield(L, "max");
|
||||
return 1;
|
||||
}
|
||||
if (auto integer = dynamic_cast<IntegerSetting*>(setting)) {
|
||||
lua::pushinteger(L, integer->getMin());
|
||||
lua::setfield(L, "min");
|
||||
lua::pushinteger(L, integer->getMax());
|
||||
lua::setfield(L, "max");
|
||||
return 1;
|
||||
}
|
||||
lua::pop(L);
|
||||
throw std::runtime_error("unsupported setting type");
|
||||
}
|
||||
|
||||
/// @brief Quit the game
|
||||
static int l_quit(lua::State*) {
|
||||
Window::setShouldClose(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Get the default world generator
|
||||
/// @return The ID of the default world generator
|
||||
static int l_get_default_generator(lua::State* L) {
|
||||
return lua::pushstring(L, WorldGenerator::DEFAULT);
|
||||
}
|
||||
|
||||
const luaL_Reg corelib[] = {
|
||||
{"new_world", lua::wrap<l_new_world>},
|
||||
{"open_world", lua::wrap<l_open_world>},
|
||||
{"reopen_world", lua::wrap<l_reopen_world>},
|
||||
{"close_world", lua::wrap<l_close_world>},
|
||||
{"delete_world", lua::wrap<l_delete_world>},
|
||||
{"reconfig_packs", lua::wrap<l_reconfig_packs>},
|
||||
{"get_setting", lua::wrap<l_get_setting>},
|
||||
{"set_setting", lua::wrap<l_set_setting>},
|
||||
{"str_setting", lua::wrap<l_str_setting>},
|
||||
{"get_setting_info", lua::wrap<l_get_setting_info>},
|
||||
{"quit", lua::wrap<l_quit>},
|
||||
{"get_default_generator", lua::wrap<l_get_default_generator>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,215 @@
|
||||
#include "libentity.hpp"
|
||||
|
||||
#include "content/Content.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "objects/Entities.hpp"
|
||||
#include "objects/EntityDef.hpp"
|
||||
#include "objects/Player.hpp"
|
||||
#include "objects/rigging.hpp"
|
||||
#include "physics/Hitbox.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static const EntityDef* require_entity_def(lua::State* L) {
|
||||
auto indices = content->getIndices();
|
||||
auto id = lua::tointeger(L, 1);
|
||||
return indices->entities.get(id);
|
||||
}
|
||||
|
||||
static int l_exists(lua::State* L) {
|
||||
return lua::pushboolean(L, get_entity(L, 1).has_value());
|
||||
}
|
||||
|
||||
static int l_def_index(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
return lua::pushinteger(L, content->entities.require(name).rt.id);
|
||||
}
|
||||
|
||||
static int l_def_name(lua::State* L) {
|
||||
if (auto def = require_entity_def(L)) {
|
||||
return lua::pushstring(L, def->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int l_defs_count(lua::State* L) {
|
||||
return lua::pushinteger(L, indices->entities.count());
|
||||
}
|
||||
|
||||
static int l_get_def(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushinteger(L, entity->getDef().rt.id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_spawn(lua::State* L) {
|
||||
auto level = controller->getLevel();
|
||||
auto defname = lua::tostring(L, 1);
|
||||
auto& def = content->entities.require(defname);
|
||||
auto pos = lua::tovec3(L, 2);
|
||||
dv::value args = nullptr;
|
||||
if (lua::gettop(L) > 2) {
|
||||
args = lua::tovalue(L, 3);
|
||||
}
|
||||
level->entities->spawn(def, pos, std::move(args));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_despawn(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->destroy();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_skeleton(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
return lua::pushstring(L, entity->getSkeleton().config->getName());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_skeleton(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
std::string skeletonName = lua::require_string(L, 2);
|
||||
auto rigConfig = content->getSkeleton(skeletonName);
|
||||
if (rigConfig == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"skeleton not found '" + skeletonName + "'"
|
||||
);
|
||||
}
|
||||
entity->setRig(rigConfig);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_all_in_box(lua::State* L) {
|
||||
auto pos = lua::tovec<3>(L, 1);
|
||||
auto size = lua::tovec<3>(L, 2);
|
||||
auto found = level->entities->getAllInside(AABB(pos, pos + size));
|
||||
lua::createtable(L, found.size(), 0);
|
||||
for (size_t i = 0; i < found.size(); i++) {
|
||||
const auto& entity = found[i];
|
||||
lua::pushinteger(L, entity.getUID());
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_get_all_in_radius(lua::State* L) {
|
||||
auto pos = lua::tovec<3>(L, 1);
|
||||
auto radius = lua::tonumber(L, 2);
|
||||
auto found = level->entities->getAllInRadius(pos, radius);
|
||||
lua::createtable(L, found.size(), 0);
|
||||
for (size_t i = 0; i < found.size(); i++) {
|
||||
const auto& entity = found[i];
|
||||
lua::pushinteger(L, entity.getUID());
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
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);
|
||||
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::ivec3 normal;
|
||||
glm::ivec3 iend;
|
||||
|
||||
blockid_t block = BLOCK_VOID;
|
||||
|
||||
if (auto voxel = level->chunks->rayCast(
|
||||
start, dir, maxDistance, end, normal, iend, filteredBlocks
|
||||
)) {
|
||||
maxDistance = glm::distance(start, end);
|
||||
block = voxel->id;
|
||||
}
|
||||
if (auto ray =
|
||||
level->entities->rayCast(start, dir, maxDistance, ignoreEntityId)) {
|
||||
if (lua::gettop(L) >= 5 && !lua::isnil(L, 5)) {
|
||||
lua::pushvalue(L, 5);
|
||||
} else {
|
||||
lua::createtable(L, 0, 6);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg entitylib[] = {
|
||||
{"exists", lua::wrap<l_exists>},
|
||||
{"def_index", lua::wrap<l_def_index>},
|
||||
{"def_name", lua::wrap<l_def_name>},
|
||||
{"get_def", lua::wrap<l_get_def>},
|
||||
{"defs_count", lua::wrap<l_defs_count>},
|
||||
{"spawn", lua::wrap<l_spawn>},
|
||||
{"despawn", lua::wrap<l_despawn>},
|
||||
{"get_skeleton", lua::wrap<l_get_skeleton>},
|
||||
{"set_skeleton", lua::wrap<l_set_skeleton>},
|
||||
{"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>},
|
||||
{NULL, NULL}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "frontend/hud.hpp"
|
||||
#include "objects/Entities.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "logic/LevelController.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
namespace scripting {
|
||||
extern Hud* hud;
|
||||
}
|
||||
|
||||
inline std::optional<Entity> get_entity(lua::State* L, int idx) {
|
||||
auto id = lua::tointeger(L, idx);
|
||||
auto level = scripting::controller->getLevel();
|
||||
return level->entities->get(id);
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include "coders/gzip.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "files/engine_paths.hpp"
|
||||
#include "files/files.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace scripting;
|
||||
|
||||
static fs::path resolve_path(const std::string& path) {
|
||||
return engine->getPaths()->resolve(path);
|
||||
}
|
||||
|
||||
static fs::path resolve_path_soft(const std::string& path) {
|
||||
if (path.find(':') == std::string::npos) {
|
||||
return path;
|
||||
}
|
||||
return engine->getPaths()->resolve(path, false);
|
||||
}
|
||||
|
||||
static int l_file_find(lua::State* L) {
|
||||
auto path = lua::require_string(L, 1);
|
||||
try {
|
||||
return lua::pushstring(L, engine->getResPaths()->findRaw(path));
|
||||
} catch (const std::runtime_error& err) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_file_resolve(lua::State* L) {
|
||||
fs::path path = resolve_path(lua::require_string(L, 1));
|
||||
return lua::pushstring(L, path.u8string());
|
||||
}
|
||||
|
||||
static int l_file_read(lua::State* L) {
|
||||
fs::path path = resolve_path(lua::require_string(L, 1));
|
||||
if (fs::is_regular_file(path)) {
|
||||
return lua::pushstring(L, files::read_string(path));
|
||||
}
|
||||
throw std::runtime_error(
|
||||
"file does not exists " + util::quote(path.u8string())
|
||||
);
|
||||
}
|
||||
|
||||
static int l_file_write(lua::State* L) {
|
||||
fs::path path = resolve_path(lua::require_string(L, 1));
|
||||
std::string text = lua::require_string(L, 2);
|
||||
files::write_string(path, text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_file_remove(lua::State* L) {
|
||||
std::string rawpath = lua::require_string(L, 1);
|
||||
fs::path path = resolve_path(rawpath);
|
||||
auto entryPoint = rawpath.substr(0, rawpath.find(':'));
|
||||
if (entryPoint != "world") {
|
||||
throw std::runtime_error("access denied");
|
||||
}
|
||||
return lua::pushboolean(L, fs::remove(path));
|
||||
}
|
||||
|
||||
static int l_file_remove_tree(lua::State* L) {
|
||||
std::string rawpath = lua::require_string(L, 1);
|
||||
fs::path path = resolve_path(rawpath);
|
||||
auto entryPoint = rawpath.substr(0, rawpath.find(':'));
|
||||
if (entryPoint != "world") {
|
||||
throw std::runtime_error("access denied");
|
||||
}
|
||||
return lua::pushinteger(L, fs::remove_all(path));
|
||||
}
|
||||
|
||||
static int l_file_exists(lua::State* L) {
|
||||
fs::path path = resolve_path_soft(lua::require_string(L, 1));
|
||||
return lua::pushboolean(L, fs::exists(path));
|
||||
}
|
||||
|
||||
static int l_file_isfile(lua::State* L) {
|
||||
fs::path path = resolve_path_soft(lua::require_string(L, 1));
|
||||
return lua::pushboolean(L, fs::is_regular_file(path));
|
||||
}
|
||||
|
||||
static int l_file_isdir(lua::State* L) {
|
||||
fs::path path = resolve_path_soft(lua::require_string(L, 1));
|
||||
return lua::pushboolean(L, fs::is_directory(path));
|
||||
}
|
||||
|
||||
static int l_file_length(lua::State* L) {
|
||||
fs::path path = resolve_path(lua::require_string(L, 1));
|
||||
if (fs::exists(path)) {
|
||||
return lua::pushinteger(L, fs::file_size(path));
|
||||
} else {
|
||||
return lua::pushinteger(L, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_file_mkdir(lua::State* L) {
|
||||
fs::path path = resolve_path(lua::require_string(L, 1));
|
||||
return lua::pushboolean(L, fs::create_directory(path));
|
||||
}
|
||||
|
||||
static int l_file_mkdirs(lua::State* L) {
|
||||
fs::path path = resolve_path(lua::require_string(L, 1));
|
||||
return lua::pushboolean(L, fs::create_directories(path));
|
||||
}
|
||||
|
||||
static int l_file_read_bytes(lua::State* L) {
|
||||
fs::path path = resolve_path(lua::require_string(L, 1));
|
||||
if (fs::is_regular_file(path)) {
|
||||
size_t length = static_cast<size_t>(fs::file_size(path));
|
||||
|
||||
auto bytes = files::read_bytes(path, length);
|
||||
|
||||
lua::createtable(L, length, 0);
|
||||
int newTable = lua::gettop(L);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
lua::pushinteger(L, bytes[i]);
|
||||
lua::rawseti(L, i + 1, newTable);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
throw std::runtime_error(
|
||||
"file does not exists " + util::quote(path.u8string())
|
||||
);
|
||||
}
|
||||
|
||||
static int read_bytes_from_table(
|
||||
lua::State* L, int tableIndex, std::vector<ubyte>& bytes
|
||||
) {
|
||||
if (!lua::istable(L, tableIndex)) {
|
||||
throw std::runtime_error("table expected");
|
||||
} else {
|
||||
lua::pushnil(L);
|
||||
while (lua::next(L, tableIndex - 1) != 0) {
|
||||
const int byte = lua::tointeger(L, -1);
|
||||
if (byte < 0 || byte > 255) {
|
||||
throw std::runtime_error(
|
||||
"invalid byte '" + std::to_string(byte) + "'"
|
||||
);
|
||||
}
|
||||
bytes.push_back(byte);
|
||||
lua::pop(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_file_write_bytes(lua::State* L) {
|
||||
int pathIndex = 1;
|
||||
|
||||
if (!lua::isstring(L, pathIndex)) {
|
||||
throw std::runtime_error("string expected");
|
||||
}
|
||||
|
||||
fs::path path = resolve_path(lua::require_string(L, pathIndex));
|
||||
|
||||
if (auto bytearray = lua::touserdata<lua::LuaBytearray>(L, -1)) {
|
||||
auto& bytes = bytearray->data();
|
||||
return lua::pushboolean(
|
||||
L, files::write_bytes(path, bytes.data(), bytes.size())
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<ubyte> bytes;
|
||||
int result = read_bytes_from_table(L, -1, bytes);
|
||||
if (result != 1) {
|
||||
return result;
|
||||
} else {
|
||||
return lua::pushboolean(
|
||||
L, files::write_bytes(path, bytes.data(), bytes.size())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_file_list_all_res(lua::State* L, const std::string& path) {
|
||||
auto files = engine->getResPaths()->listdirRaw(path);
|
||||
lua::createtable(L, files.size(), 0);
|
||||
for (size_t i = 0; i < files.size(); i++) {
|
||||
lua::pushstring(L, files[i]);
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_file_list(lua::State* L) {
|
||||
std::string dirname = lua::require_string(L, 1);
|
||||
if (dirname.find(':') == std::string::npos) {
|
||||
return l_file_list_all_res(L, dirname);
|
||||
}
|
||||
fs::path path = resolve_path(dirname);
|
||||
if (!fs::is_directory(path)) {
|
||||
throw std::runtime_error(
|
||||
util::quote(path.u8string()) + " is not a directory"
|
||||
);
|
||||
}
|
||||
lua::createtable(L, 0, 0);
|
||||
size_t index = 1;
|
||||
for (auto& entry : fs::directory_iterator(path)) {
|
||||
auto name = entry.path().filename().u8string();
|
||||
auto file = dirname + "/" + name;
|
||||
lua::pushstring(L, file);
|
||||
lua::rawseti(L, index);
|
||||
index++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_file_gzip_compress(lua::State* L) {
|
||||
std::vector<ubyte> bytes;
|
||||
|
||||
int result = read_bytes_from_table(L, -1, bytes);
|
||||
|
||||
if (result != 1) {
|
||||
return result;
|
||||
} else {
|
||||
auto compressed_bytes = gzip::compress(bytes.data(), bytes.size());
|
||||
int newTable = lua::gettop(L);
|
||||
|
||||
for (size_t i = 0; i < compressed_bytes.size(); i++) {
|
||||
lua::pushinteger(L, compressed_bytes.data()[i]);
|
||||
lua::rawseti(L, i + 1, newTable);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_file_gzip_decompress(lua::State* L) {
|
||||
std::vector<ubyte> bytes;
|
||||
|
||||
int result = read_bytes_from_table(L, -1, bytes);
|
||||
|
||||
if (result != 1) {
|
||||
return result;
|
||||
} else {
|
||||
auto decompressed_bytes = gzip::decompress(bytes.data(), bytes.size());
|
||||
int newTable = lua::gettop(L);
|
||||
|
||||
for (size_t i = 0; i < decompressed_bytes.size(); i++) {
|
||||
lua::pushinteger(L, decompressed_bytes.data()[i]);
|
||||
lua::rawseti(L, i + 1, newTable);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_file_read_combined_list(lua::State* L) {
|
||||
std::string path = lua::require_string(L, 1);
|
||||
if (path.find(':') != std::string::npos) {
|
||||
throw std::runtime_error("entry point must not be specified");
|
||||
}
|
||||
return lua::pushvalue(L, engine->getResPaths()->readCombinedList(path));
|
||||
}
|
||||
|
||||
const luaL_Reg filelib[] = {
|
||||
{"exists", lua::wrap<l_file_exists>},
|
||||
{"find", lua::wrap<l_file_find>},
|
||||
{"isdir", lua::wrap<l_file_isdir>},
|
||||
{"isfile", lua::wrap<l_file_isfile>},
|
||||
{"length", lua::wrap<l_file_length>},
|
||||
{"list", lua::wrap<l_file_list>},
|
||||
{"mkdir", lua::wrap<l_file_mkdir>},
|
||||
{"mkdirs", lua::wrap<l_file_mkdirs>},
|
||||
{"read_bytes", lua::wrap<l_file_read_bytes>},
|
||||
{"read", lua::wrap<l_file_read>},
|
||||
{"remove", lua::wrap<l_file_remove>},
|
||||
{"remove_tree", lua::wrap<l_file_remove_tree>},
|
||||
{"resolve", lua::wrap<l_file_resolve>},
|
||||
{"write_bytes", lua::wrap<l_file_write_bytes>},
|
||||
{"write", lua::wrap<l_file_write>},
|
||||
{"gzip_compress", lua::wrap<l_file_gzip_compress>},
|
||||
{"gzip_decompress", lua::wrap<l_file_gzip_decompress>},
|
||||
{"read_combined_list", lua::wrap<l_file_read_combined_list>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,69 @@
|
||||
#include "api_lua.hpp"
|
||||
|
||||
#include "files/files.hpp"
|
||||
#include "files/util.hpp"
|
||||
#include "coders/binary_json.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "world/generator/VoxelFragment.hpp"
|
||||
#include "content/ContentLoader.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "../lua_custom_types.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static int l_save_structure(lua::State* L) {
|
||||
auto pointA = lua::tovec<3>(L, 1);
|
||||
auto pointB = lua::tovec<3>(L, 2);
|
||||
auto filename = lua::require_string(L, 3);
|
||||
if (!files::is_valid_name(filename)) {
|
||||
throw std::runtime_error("invalid file name");
|
||||
}
|
||||
bool saveEntities = lua::toboolean(L, 4);
|
||||
|
||||
auto structure = VoxelFragment::create(level, pointA, pointB, saveEntities);
|
||||
auto map = structure->serialize();
|
||||
|
||||
auto bytes = json::to_binary(map);
|
||||
files::write_bytes(fs::u8path(filename), bytes.data(), bytes.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_load_structure(lua::State* L) {
|
||||
auto paths = engine->getPaths();
|
||||
auto [prefix, filename] = EnginePaths::parsePath(lua::require_string(L, 1));
|
||||
|
||||
auto path = paths->resolve(prefix+":generators/"+filename+".vox");
|
||||
if (!std::filesystem::exists(path)) {
|
||||
throw std::runtime_error("file "+path.u8string()+" does not exist");
|
||||
}
|
||||
auto map = files::read_binary_json(path);
|
||||
|
||||
auto structure = std::make_shared<VoxelFragment>();
|
||||
structure->deserialize(map);
|
||||
return lua::newuserdata<lua::LuaVoxelStructure>(L, std::move(structure));
|
||||
}
|
||||
|
||||
/// @brief Get a list of all world generators
|
||||
/// @return A table with the IDs of all world generators
|
||||
static int l_get_generators(lua::State* L) {
|
||||
auto packs = engine->getAllContentPacks();
|
||||
|
||||
lua::createtable(L, 0, 0);
|
||||
|
||||
int i = 1;
|
||||
for (const auto& pack : packs) {
|
||||
auto names = ContentLoader::scanContent(pack, ContentType::GENERATOR);
|
||||
for (const auto& name : names) {
|
||||
lua::pushstring(L, name);
|
||||
lua::rawseti(L, i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg generationlib[] = {
|
||||
{"save_structure", lua::wrap<l_save_structure>},
|
||||
{"load_structure", lua::wrap<l_load_structure>},
|
||||
{"get_generators", lua::wrap<l_get_generators>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,629 @@
|
||||
#include "assets/Assets.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "frontend/UiDocument.hpp"
|
||||
#include "frontend/locale.hpp"
|
||||
#include "graphics/ui/elements/Button.hpp"
|
||||
#include "graphics/ui/elements/CheckBox.hpp"
|
||||
#include "graphics/ui/elements/Image.hpp"
|
||||
#include "graphics/ui/elements/InventoryView.hpp"
|
||||
#include "graphics/ui/elements/Menu.hpp"
|
||||
#include "graphics/ui/elements/Panel.hpp"
|
||||
#include "graphics/ui/elements/TextBox.hpp"
|
||||
#include "graphics/ui/elements/TrackBar.hpp"
|
||||
#include "graphics/ui/elements/UINode.hpp"
|
||||
#include "graphics/ui/gui_util.hpp"
|
||||
#include "items/Inventories.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace gui;
|
||||
using namespace scripting;
|
||||
|
||||
struct DocumentNode {
|
||||
UiDocument* document;
|
||||
std::shared_ptr<UINode> node;
|
||||
};
|
||||
|
||||
static DocumentNode getDocumentNode(
|
||||
lua::State*, const std::string& name, const std::string& nodeName
|
||||
) {
|
||||
auto doc = engine->getAssets()->get<UiDocument>(name);
|
||||
if (doc == nullptr) {
|
||||
throw std::runtime_error("document '" + name + "' not found");
|
||||
}
|
||||
auto node = doc->get(nodeName);
|
||||
if (node == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"document '" + name + "' has no element with id '" + nodeName + "'"
|
||||
);
|
||||
}
|
||||
return {doc, node};
|
||||
}
|
||||
|
||||
static DocumentNode getDocumentNode(lua::State* L, int idx = 1) {
|
||||
lua::getfield(L, "docname", idx);
|
||||
lua::getfield(L, "name", idx);
|
||||
auto docname = lua::require_string(L, -2);
|
||||
auto name = lua::require_string(L, -1);
|
||||
auto node = getDocumentNode(L, docname, name);
|
||||
lua::pop(L, 2);
|
||||
return node;
|
||||
}
|
||||
|
||||
static int l_menu_back(lua::State* L) {
|
||||
auto node = getDocumentNode(L);
|
||||
if (auto menu = dynamic_cast<Menu*>(node.node.get())) {
|
||||
menu->back();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_menu_reset(lua::State* L) {
|
||||
auto node = getDocumentNode(L);
|
||||
if (auto menu = dynamic_cast<Menu*>(node.node.get())) {
|
||||
menu->reset();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_textbox_paste(lua::State* L) {
|
||||
auto node = getDocumentNode(L);
|
||||
if (auto box = dynamic_cast<TextBox*>(node.node.get())) {
|
||||
auto text = lua::require_string(L, 2);
|
||||
box->paste(util::str2wstr_utf8(text));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_container_add(lua::State* L) {
|
||||
auto docnode = getDocumentNode(L);
|
||||
auto node = dynamic_cast<Container*>(docnode.node.get());
|
||||
if (node == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto xmlsrc = lua::require_string(L, 2);
|
||||
try {
|
||||
auto subnode =
|
||||
guiutil::create(xmlsrc, docnode.document->getEnvironment());
|
||||
node->add(subnode);
|
||||
UINode::getIndices(subnode, docnode.document->getMapWriteable());
|
||||
} catch (const std::exception& err) {
|
||||
throw std::runtime_error(err.what());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_node_destruct(lua::State* L) {
|
||||
auto docnode = getDocumentNode(L);
|
||||
auto node = docnode.node;
|
||||
engine->getGUI()->postRunnable([node]() {
|
||||
auto parent = node->getParent();
|
||||
if (auto container = dynamic_cast<Container*>(parent)) {
|
||||
container->remove(node);
|
||||
}
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_container_clear(lua::State* L) {
|
||||
auto node = getDocumentNode(L, 1);
|
||||
if (auto container = std::dynamic_pointer_cast<Container>(node.node)) {
|
||||
container->clear();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_container_set_interval(lua::State* L) {
|
||||
auto node = getDocumentNode(L, 1);
|
||||
auto interval = lua::tointeger(L, 2) / 1000.0f;
|
||||
if (auto container = std::dynamic_pointer_cast<Container>(node.node)) {
|
||||
lua::pushvalue(L, 3);
|
||||
auto runnable = lua::create_runnable(L);
|
||||
container->listenInterval(interval, runnable);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_move_into(lua::State* L) {
|
||||
auto node = getDocumentNode(L, 1);
|
||||
auto dest = getDocumentNode(L, 2);
|
||||
UINode::moveInto(
|
||||
node.node, std::dynamic_pointer_cast<Container>(dest.node)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_inventory(UINode* node, lua::State* L) {
|
||||
if (auto inventory = dynamic_cast<InventoryView*>(node)) {
|
||||
auto inv = inventory->getInventory();
|
||||
return lua::pushinteger(L, inv ? inv->getId() : 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_reset(UINode* node, lua::State* L) {
|
||||
if (dynamic_cast<Menu*>(node)) {
|
||||
return lua::pushcfunction(L, l_menu_reset);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_back(UINode* node, lua::State* L) {
|
||||
if (dynamic_cast<Menu*>(node)) {
|
||||
return lua::pushcfunction(L, l_menu_back);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_paste(UINode* node, lua::State* L) {
|
||||
if (dynamic_cast<TextBox*>(node)) {
|
||||
return lua::pushcfunction(L, l_textbox_paste);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_page(UINode* node, lua::State* L) {
|
||||
if (auto menu = dynamic_cast<Menu*>(node)) {
|
||||
return lua::pushstring(L, menu->getCurrent().name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_is_checked(UINode* node, lua::State* L) {
|
||||
if (auto box = dynamic_cast<CheckBox*>(node)) {
|
||||
return lua::pushboolean(L, box->isChecked());
|
||||
} else if (auto box = dynamic_cast<FullCheckBox*>(node)) {
|
||||
return lua::pushboolean(L, box->isChecked());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_value(UINode* node, lua::State* L) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
return lua::pushnumber(L, bar->getValue());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_min(UINode* node, lua::State* L) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
return lua::pushnumber(L, bar->getMin());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_max(UINode* node, lua::State* L) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
return lua::pushnumber(L, bar->getMax());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_step(UINode* node, lua::State* L) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
return lua::pushnumber(L, bar->getStep());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_track_width(UINode* node, lua::State* L) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
return lua::pushnumber(L, bar->getTrackWidth());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_track_color(UINode* node, lua::State* L) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
return lua::pushcolor(L, bar->getTrackColor());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_is_valid(UINode* node, lua::State* L) {
|
||||
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||
return lua::pushboolean(L, box->validate());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_caret(UINode* node, lua::State* L) {
|
||||
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||
return lua::pushinteger(L, static_cast<integer_t>(box->getCaret()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_placeholder(UINode* node, lua::State* L) {
|
||||
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||
return lua::pushwstring(L, box->getPlaceholder());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_text(UINode* node, lua::State* L) {
|
||||
if (auto button = dynamic_cast<Button*>(node)) {
|
||||
return lua::pushwstring(L, button->getText());
|
||||
} else if (auto label = dynamic_cast<Label*>(node)) {
|
||||
return lua::pushwstring(L, label->getText());
|
||||
} else if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||
return lua::pushwstring(L, box->getText());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_editable(UINode* node, lua::State* L) {
|
||||
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||
return lua::pushboolean(L, box->isEditable());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_src(UINode* node, lua::State* L) {
|
||||
if (auto image = dynamic_cast<Image*>(node)) {
|
||||
return lua::pushstring(L, image->getTexture());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_add(UINode* node, lua::State* L) {
|
||||
if (dynamic_cast<Container*>(node)) {
|
||||
return lua::pushcfunction(L, lua::wrap<l_container_add>);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_destruct(UINode*, lua::State* L) {
|
||||
return lua::pushcfunction(L, lua::wrap<l_node_destruct>);
|
||||
}
|
||||
|
||||
static int p_get_clear(UINode* node, lua::State* L) {
|
||||
if (dynamic_cast<Container*>(node)) {
|
||||
return lua::pushcfunction(L, lua::wrap<l_container_clear>);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_set_interval(UINode* node, lua::State* L) {
|
||||
if (dynamic_cast<Container*>(node)) {
|
||||
return lua::pushcfunction(L, lua::wrap<l_container_set_interval>);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p_get_color(UINode* node, lua::State* L) {
|
||||
return lua::pushcolor(L, node->getColor());
|
||||
}
|
||||
static int p_get_hover_color(UINode* node, lua::State* L) {
|
||||
return lua::pushcolor(L, node->getHoverColor());
|
||||
}
|
||||
static int p_get_pressed_color(UINode* node, lua::State* L) {
|
||||
return lua::pushcolor(L, node->getPressedColor());
|
||||
}
|
||||
static int p_get_tooltip(UINode* node, lua::State* L) {
|
||||
return lua::pushwstring(L, node->getTooltip());
|
||||
}
|
||||
static int p_get_tooltip_delay(UINode* node, lua::State* L) {
|
||||
return lua::pushnumber(L, node->getTooltipDelay());
|
||||
}
|
||||
static int p_get_pos(UINode* node, lua::State* L) {
|
||||
return lua::pushvec2(L, node->getPos());
|
||||
}
|
||||
static int p_get_wpos(UINode* node, lua::State* L) {
|
||||
return lua::pushvec2(L, node->calcPos());
|
||||
}
|
||||
static int p_get_size(UINode* node, lua::State* L) {
|
||||
return lua::pushvec2(L, node->getSize());
|
||||
}
|
||||
static int p_is_interactive(UINode* node, lua::State* L) {
|
||||
return lua::pushboolean(L, node->isInteractive());
|
||||
}
|
||||
static int p_is_visible(UINode* node, lua::State* L) {
|
||||
return lua::pushboolean(L, node->isVisible());
|
||||
}
|
||||
static int p_is_enabled(UINode* node, lua::State* L) {
|
||||
return lua::pushboolean(L, node->isEnabled());
|
||||
}
|
||||
static int p_move_into(UINode*, lua::State* L) {
|
||||
return lua::pushcfunction(L, l_move_into);
|
||||
}
|
||||
static int p_get_focused(UINode* node, lua::State* L) {
|
||||
return lua::pushboolean(L, node->isFocused());
|
||||
}
|
||||
|
||||
static int l_gui_getattr(lua::State* L) {
|
||||
auto docname = lua::require_string(L, 1);
|
||||
auto element = lua::require_string(L, 2);
|
||||
auto attr = lua::require_string(L, 3);
|
||||
|
||||
static const std::unordered_map<
|
||||
std::string_view,
|
||||
std::function<int(UINode*, lua::State*)>>
|
||||
getters {
|
||||
{"color", p_get_color},
|
||||
{"hoverColor", p_get_hover_color},
|
||||
{"pressedColor", p_get_pressed_color},
|
||||
{"tooltip", p_get_tooltip},
|
||||
{"tooltipDelay", p_get_tooltip_delay},
|
||||
{"pos", p_get_pos},
|
||||
{"wpos", p_get_wpos},
|
||||
{"size", p_get_size},
|
||||
{"interactive", p_is_interactive},
|
||||
{"visible", p_is_visible},
|
||||
{"enabled", p_is_enabled},
|
||||
{"move_into", p_move_into}, // deprecated
|
||||
{"moveInto", p_move_into},
|
||||
{"add", p_get_add},
|
||||
{"destruct", p_get_destruct},
|
||||
{"clear", p_get_clear},
|
||||
{"setInterval", p_set_interval},
|
||||
{"placeholder", p_get_placeholder},
|
||||
{"valid", p_is_valid},
|
||||
{"caret", p_get_caret},
|
||||
{"text", p_get_text},
|
||||
{"editable", p_get_editable},
|
||||
{"src", p_get_src},
|
||||
{"value", p_get_value},
|
||||
{"min", p_get_min},
|
||||
{"max", p_get_max},
|
||||
{"step", p_get_step},
|
||||
{"trackWidth", p_get_track_width},
|
||||
{"trackColor", p_get_track_color},
|
||||
{"checked", p_is_checked},
|
||||
{"page", p_get_page},
|
||||
{"back", p_get_back},
|
||||
{"reset", p_get_reset},
|
||||
{"paste", p_get_paste},
|
||||
{"inventory", p_get_inventory},
|
||||
{"focused", p_get_focused},
|
||||
};
|
||||
auto func = getters.find(attr);
|
||||
if (func != getters.end()) {
|
||||
auto docnode = getDocumentNode(L, docname, element);
|
||||
auto node = docnode.node;
|
||||
return func->second(node.get(), L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void p_set_color(UINode* node, lua::State* L, int idx) {
|
||||
node->setColor(lua::tocolor(L, idx));
|
||||
}
|
||||
static void p_set_hover_color(UINode* node, lua::State* L, int idx) {
|
||||
node->setHoverColor(lua::tocolor(L, idx));
|
||||
}
|
||||
static void p_set_pressed_color(UINode* node, lua::State* L, int idx) {
|
||||
node->setPressedColor(lua::tocolor(L, idx));
|
||||
}
|
||||
static void p_set_tooltip(UINode* node, lua::State* L, int idx) {
|
||||
node->setTooltip(lua::require_wstring(L, idx));
|
||||
}
|
||||
static void p_set_tooltip_delay(UINode* node, lua::State* L, int idx) {
|
||||
node->setTooltipDelay(lua::tonumber(L, idx));
|
||||
}
|
||||
static void p_set_pos(UINode* node, lua::State* L, int idx) {
|
||||
node->setPos(lua::tovec2(L, idx));
|
||||
}
|
||||
static void p_set_wpos(UINode* node, lua::State* L, int idx) {
|
||||
node->setPos(lua::tovec2(L, idx) - node->calcPos());
|
||||
}
|
||||
static void p_set_size(UINode* node, lua::State* L, int idx) {
|
||||
node->setSize(lua::tovec2(L, idx));
|
||||
}
|
||||
static void p_set_interactive(UINode* node, lua::State* L, int idx) {
|
||||
node->setInteractive(lua::toboolean(L, idx));
|
||||
}
|
||||
static void p_set_visible(UINode* node, lua::State* L, int idx) {
|
||||
node->setVisible(lua::toboolean(L, idx));
|
||||
}
|
||||
static void p_set_enabled(UINode* node, lua::State* L, int idx) {
|
||||
node->setEnabled(lua::toboolean(L, idx));
|
||||
}
|
||||
static void p_set_placeholder(UINode* node, lua::State* L, int idx) {
|
||||
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||
box->setPlaceholder(lua::require_wstring(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_text(UINode* node, lua::State* L, int idx) {
|
||||
if (auto label = dynamic_cast<Label*>(node)) {
|
||||
label->setText(lua::require_wstring(L, idx));
|
||||
} else if (auto button = dynamic_cast<Button*>(node)) {
|
||||
button->setText(lua::require_wstring(L, idx));
|
||||
} else if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||
box->setText(lua::require_wstring(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_caret(UINode* node, lua::State* L, int idx) {
|
||||
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||
box->setCaret(static_cast<ptrdiff_t>(lua::tointeger(L, idx)));
|
||||
}
|
||||
}
|
||||
static void p_set_editable(UINode* node, lua::State* L, int idx) {
|
||||
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||
box->setEditable(lua::toboolean(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_src(UINode* node, lua::State* L, int idx) {
|
||||
if (auto image = dynamic_cast<Image*>(node)) {
|
||||
image->setTexture(lua::require_string(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_value(UINode* node, lua::State* L, int idx) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
bar->setValue(lua::tonumber(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_min(UINode* node, lua::State* L, int idx) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
bar->setMin(lua::tonumber(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_max(UINode* node, lua::State* L, int idx) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
bar->setMax(lua::tonumber(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_step(UINode* node, lua::State* L, int idx) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
bar->setStep(lua::tonumber(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_track_width(UINode* node, lua::State* L, int idx) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
bar->setTrackWidth(lua::tointeger(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_track_color(UINode* node, lua::State* L, int idx) {
|
||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||
bar->setTrackColor(lua::tocolor(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_checked(UINode* node, lua::State* L, int idx) {
|
||||
if (auto box = dynamic_cast<CheckBox*>(node)) {
|
||||
box->setChecked(lua::toboolean(L, idx));
|
||||
} else if (auto box = dynamic_cast<FullCheckBox*>(node)) {
|
||||
box->setChecked(lua::toboolean(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_page(UINode* node, lua::State* L, int idx) {
|
||||
if (auto menu = dynamic_cast<Menu*>(node)) {
|
||||
menu->setPage(lua::require_string(L, idx));
|
||||
}
|
||||
}
|
||||
static void p_set_inventory(UINode* node, lua::State* L, int idx) {
|
||||
if (auto view = dynamic_cast<InventoryView*>(node)) {
|
||||
auto inventory = level->inventories->get(lua::tointeger(L, idx));
|
||||
if (inventory == nullptr) {
|
||||
view->unbind();
|
||||
} else {
|
||||
view->bind(inventory, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void p_set_focused(
|
||||
const std::shared_ptr<UINode>& node, lua::State* L, int idx
|
||||
) {
|
||||
if (lua::toboolean(L, idx) && !node->isFocused()) {
|
||||
engine->getGUI()->setFocus(node);
|
||||
} else if (node->isFocused()) {
|
||||
node->defocus();
|
||||
}
|
||||
}
|
||||
|
||||
static int l_gui_setattr(lua::State* L) {
|
||||
auto docname = lua::require_string(L, 1);
|
||||
auto element = lua::require_string(L, 2);
|
||||
auto attr = lua::require_string(L, 3);
|
||||
|
||||
auto docnode = getDocumentNode(L, docname, element);
|
||||
auto node = docnode.node;
|
||||
|
||||
static const std::unordered_map<
|
||||
std::string_view,
|
||||
std::function<void(UINode*, lua::State*, int)>>
|
||||
setters {
|
||||
{"color", p_set_color},
|
||||
{"hoverColor", p_set_hover_color},
|
||||
{"pressedColor", p_set_pressed_color},
|
||||
{"tooltip", p_set_tooltip},
|
||||
{"tooltipDelay", p_set_tooltip_delay},
|
||||
{"pos", p_set_pos},
|
||||
{"wpos", p_set_wpos},
|
||||
{"size", p_set_size},
|
||||
{"interactive", p_set_interactive},
|
||||
{"visible", p_set_visible},
|
||||
{"enabled", p_set_enabled},
|
||||
{"placeholder", p_set_placeholder},
|
||||
{"text", p_set_text},
|
||||
{"editable", p_set_editable},
|
||||
{"src", p_set_src},
|
||||
{"caret", p_set_caret},
|
||||
{"value", p_set_value},
|
||||
{"min", p_set_min},
|
||||
{"max", p_set_max},
|
||||
{"step", p_set_step},
|
||||
{"trackWidth", p_set_track_width},
|
||||
{"trackColor", p_set_track_color},
|
||||
{"checked", p_set_checked},
|
||||
{"page", p_set_page},
|
||||
{"inventory", p_set_inventory},
|
||||
};
|
||||
auto func = setters.find(attr);
|
||||
if (func != setters.end()) {
|
||||
func->second(node.get(), L, 4);
|
||||
}
|
||||
static const std::unordered_map<
|
||||
std::string_view,
|
||||
std::function<void(std::shared_ptr<UINode>, lua::State*, int)>>
|
||||
setters2 {
|
||||
{"focused", p_set_focused},
|
||||
};
|
||||
auto func2 = setters2.find(attr);
|
||||
if (func2 != setters2.end()) {
|
||||
func2->second(node, L, 4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_gui_get_env(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
auto doc = engine->getAssets()->get<UiDocument>(name);
|
||||
if (doc == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"document '" + std::string(name) + "' not found"
|
||||
);
|
||||
}
|
||||
lua::getglobal(L, lua::env_name(*doc->getEnvironment()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_gui_str(lua::State* L) {
|
||||
auto text = lua::require_wstring(L, 1);
|
||||
if (!lua::isnoneornil(L, 2)) {
|
||||
auto context = lua::require_wstring(L, 2);
|
||||
lua::pushwstring(L, langs::get(text, context));
|
||||
} else {
|
||||
lua::pushwstring(L, langs::get(text));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_gui_reindex(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
auto doc = engine->getAssets()->get<UiDocument>(name);
|
||||
if (doc == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"document '" + std::string(name) + "' not found"
|
||||
);
|
||||
}
|
||||
doc->rebuildIndices();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief gui.get_locales_info() -> table of tables
|
||||
static int l_gui_get_locales_info(lua::State* L) {
|
||||
auto& locales = langs::locales_info;
|
||||
lua::createtable(L, 0, locales.size());
|
||||
for (auto& entry : locales) {
|
||||
lua::createtable(L, 0, 1);
|
||||
lua::pushstring(L, entry.second.name);
|
||||
lua::setfield(L, "name");
|
||||
lua::setfield(L, entry.first);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_gui_getviewport(lua::State* L) {
|
||||
return lua::pushvec2(L, engine->getGUI()->getContainer()->getSize());
|
||||
}
|
||||
|
||||
const luaL_Reg guilib[] = {
|
||||
{"get_viewport", lua::wrap<l_gui_getviewport>},
|
||||
{"getattr", lua::wrap<l_gui_getattr>},
|
||||
{"setattr", lua::wrap<l_gui_setattr>},
|
||||
{"get_env", lua::wrap<l_gui_get_env>},
|
||||
{"str", lua::wrap<l_gui_str>},
|
||||
{"get_locales_info", lua::wrap<l_gui_get_locales_info>},
|
||||
{"__reindex", lua::wrap<l_gui_reindex>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,153 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include "assets/Assets.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "frontend/UiDocument.hpp"
|
||||
#include "frontend/hud.hpp"
|
||||
#include "graphics/ui/elements/InventoryView.hpp"
|
||||
#include "items/Inventories.hpp"
|
||||
#include "logic/BlocksController.hpp"
|
||||
#include "objects/Player.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "voxels/voxel.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
namespace scripting {
|
||||
extern Hud* hud;
|
||||
}
|
||||
using namespace scripting;
|
||||
|
||||
static int l_hud_open_inventory(lua::State*) {
|
||||
if (!hud->isInventoryOpen()) {
|
||||
hud->openInventory();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_hud_close_inventory(lua::State*) {
|
||||
if (hud->isInventoryOpen()) {
|
||||
hud->closeInventory();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_hud_open_block(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
bool playerInventory = !lua::toboolean(L, 4);
|
||||
|
||||
auto vox = level->chunks->get(x, y, z);
|
||||
if (vox == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"block does not exists at " + std::to_string(x) + " " +
|
||||
std::to_string(y) + " " + std::to_string(z)
|
||||
);
|
||||
}
|
||||
auto& def = content->getIndices()->blocks.require(vox->id);
|
||||
auto assets = engine->getAssets();
|
||||
auto layout = assets->get<UiDocument>(def.uiLayout);
|
||||
if (layout == nullptr) {
|
||||
throw std::runtime_error("block '" + def.name + "' has no ui layout");
|
||||
}
|
||||
|
||||
auto id = blocks->createBlockInventory(x, y, z);
|
||||
hud->openInventory(
|
||||
glm::ivec3(x, y, z),
|
||||
layout,
|
||||
level->inventories->get(id),
|
||||
playerInventory
|
||||
);
|
||||
|
||||
lua::pushinteger(L, id);
|
||||
lua::pushstring(L, def.uiLayout);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_hud_show_overlay(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
bool playerInventory = lua::toboolean(L, 2);
|
||||
|
||||
auto assets = engine->getAssets();
|
||||
auto layout = assets->get<UiDocument>(name);
|
||||
if (layout == nullptr) {
|
||||
throw std::runtime_error("there is no ui layout " + util::quote(name));
|
||||
}
|
||||
hud->showOverlay(layout, playerInventory);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UiDocument* require_layout(const char* name) {
|
||||
auto assets = engine->getAssets();
|
||||
auto layout = assets->get<UiDocument>(name);
|
||||
if (layout == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"layout '" + std::string(name) + "' is not found"
|
||||
);
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
|
||||
static int l_hud_open_permanent(lua::State* L) {
|
||||
auto layout = require_layout(lua::require_string(L, 1));
|
||||
hud->openPermanent(layout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_hud_close(lua::State* L) {
|
||||
auto layout = require_layout(lua::require_string(L, 1));
|
||||
hud->remove(layout->getRoot());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_hud_pause(lua::State*) {
|
||||
hud->setPause(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_hud_resume(lua::State*) {
|
||||
hud->setPause(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_hud_get_block_inventory(lua::State* L) {
|
||||
auto inventory = hud->getBlockInventory();
|
||||
if (inventory == nullptr) {
|
||||
return lua::pushinteger(L, 0);
|
||||
} else {
|
||||
return lua::pushinteger(L, inventory->getId());
|
||||
}
|
||||
}
|
||||
|
||||
static int l_hud_get_player(lua::State* L) {
|
||||
auto player = hud->getPlayer();
|
||||
return lua::pushinteger(L, player->getId());
|
||||
}
|
||||
|
||||
static int l_hud_is_paused(lua::State* L) {
|
||||
return lua::pushboolean(L, hud->isPause());
|
||||
}
|
||||
|
||||
static int l_hud_is_inventory_open(lua::State* L) {
|
||||
return lua::pushboolean(L, hud->isInventoryOpen());
|
||||
}
|
||||
|
||||
const luaL_Reg hudlib[] = {
|
||||
{"open_inventory", lua::wrap<l_hud_open_inventory>},
|
||||
{"close_inventory", lua::wrap<l_hud_close_inventory>},
|
||||
{"open_block", lua::wrap<l_hud_open_block>},
|
||||
{"open_permanent", lua::wrap<l_hud_open_permanent>},
|
||||
{"show_overlay", lua::wrap<l_hud_show_overlay>},
|
||||
{"get_block_inventory", lua::wrap<l_hud_get_block_inventory>},
|
||||
{"close", lua::wrap<l_hud_close>},
|
||||
{"pause", lua::wrap<l_hud_pause>},
|
||||
{"resume", lua::wrap<l_hud_resume>},
|
||||
{"is_paused", lua::wrap<l_hud_is_paused>},
|
||||
{"is_inventory_open", lua::wrap<l_hud_is_inventory_open>},
|
||||
{"get_player", lua::wrap<l_hud_get_player>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "engine.hpp"
|
||||
#include "frontend/hud.hpp"
|
||||
#include "frontend/screens/Screen.hpp"
|
||||
#include "graphics/ui/GUI.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "window/Events.hpp"
|
||||
#include "window/input.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
namespace scripting {
|
||||
extern Hud* hud;
|
||||
}
|
||||
using namespace scripting;
|
||||
|
||||
static int l_keycode(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
return lua::pushinteger(
|
||||
L, static_cast<int>(input_util::keycode_from(name))
|
||||
);
|
||||
}
|
||||
|
||||
static int l_mousecode(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
return lua::pushinteger(
|
||||
L, static_cast<int>(input_util::mousecode_from(name))
|
||||
);
|
||||
}
|
||||
|
||||
static int l_add_callback(lua::State* L) {
|
||||
auto bindname = lua::require_string(L, 1);
|
||||
const auto& bind = Events::bindings.find(bindname);
|
||||
if (bind == Events::bindings.end()) {
|
||||
throw std::runtime_error("unknown binding " + util::quote(bindname));
|
||||
}
|
||||
lua::pushvalue(L, 2);
|
||||
runnable actual_callback = lua::create_runnable(L);
|
||||
runnable callback = [=]() {
|
||||
if (!scripting::engine->getGUI()->isFocusCaught()) {
|
||||
actual_callback();
|
||||
}
|
||||
};
|
||||
if (hud) {
|
||||
hud->keepAlive(bind->second.onactived.add(callback));
|
||||
} else {
|
||||
throw std::runtime_error("on_hud_open is not called yet");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_mouse_pos(lua::State* L) {
|
||||
return lua::pushvec2(L, Events::cursor);
|
||||
}
|
||||
|
||||
static int l_get_bindings(lua::State* L) {
|
||||
auto& bindings = Events::bindings;
|
||||
lua::createtable(L, bindings.size(), 0);
|
||||
|
||||
int i = 0;
|
||||
for (auto& entry : bindings) {
|
||||
lua::pushstring(L, entry.first);
|
||||
lua::rawseti(L, i + 1);
|
||||
i++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_is_active(lua::State* L) {
|
||||
auto bindname = lua::require_string(L, 1);
|
||||
const auto& bind = Events::bindings.find(bindname);
|
||||
if (bind == Events::bindings.end()) {
|
||||
throw std::runtime_error("unknown binding " + util::quote(bindname));
|
||||
}
|
||||
return lua::pushboolean(L, bind->second.active());
|
||||
}
|
||||
|
||||
static int l_is_pressed(lua::State* L) {
|
||||
std::string code = lua::require_string(L, 1);
|
||||
size_t sep = code.find(':');
|
||||
if (sep == std::string::npos) {
|
||||
throw std::runtime_error("expected 'input_type:key' format");
|
||||
}
|
||||
auto prefix = code.substr(0, sep);
|
||||
auto name = code.substr(sep + 1);
|
||||
if (prefix == "key") {
|
||||
return lua::pushboolean(
|
||||
L, Events::pressed(static_cast<int>(input_util::keycode_from(name)))
|
||||
);
|
||||
} else if (prefix == "mouse") {
|
||||
return lua::pushboolean(
|
||||
L,
|
||||
Events::clicked(static_cast<int>(input_util::mousecode_from(name)))
|
||||
);
|
||||
} else {
|
||||
throw std::runtime_error("unknown input type " + util::quote(code));
|
||||
}
|
||||
}
|
||||
|
||||
const luaL_Reg inputlib[] = {
|
||||
{"keycode", lua::wrap<l_keycode>},
|
||||
{"mousecode", lua::wrap<l_mousecode>},
|
||||
{"add_callback", lua::wrap<l_add_callback>},
|
||||
{"get_mouse_pos", lua::wrap<l_get_mouse_pos>},
|
||||
{"get_bindings", lua::wrap<l_get_bindings>},
|
||||
{"is_active", lua::wrap<l_is_active>},
|
||||
{"is_pressed", lua::wrap<l_is_pressed>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,149 @@
|
||||
#include "content/Content.hpp"
|
||||
#include "items/Inventories.hpp"
|
||||
#include "items/ItemStack.hpp"
|
||||
#include "logic/BlocksController.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static void validate_itemid(itemid_t id) {
|
||||
if (id >= indices->items.count()) {
|
||||
throw std::runtime_error("invalid item id");
|
||||
}
|
||||
}
|
||||
|
||||
static std::shared_ptr<Inventory> get_inventory(int64_t id) {
|
||||
auto inv = level->inventories->get(id);
|
||||
if (inv == nullptr) {
|
||||
throw std::runtime_error("inventory not found: " + std::to_string(id));
|
||||
}
|
||||
return inv;
|
||||
}
|
||||
|
||||
static std::shared_ptr<Inventory> get_inventory(int64_t id, int arg) {
|
||||
auto inv = level->inventories->get(id);
|
||||
if (inv == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"inventory not found: " + std::to_string(id) + " argument " +
|
||||
std::to_string(arg)
|
||||
);
|
||||
}
|
||||
return inv;
|
||||
}
|
||||
|
||||
static void validate_slotid(int slotid, Inventory* inv) {
|
||||
if (static_cast<size_t>(slotid) >= inv->size()) {
|
||||
throw std::runtime_error(
|
||||
"slot index is out of range [0..inventory.size(invid)]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_inventory_get(lua::State* L) {
|
||||
auto invid = lua::tointeger(L, 1);
|
||||
auto slotid = lua::tointeger(L, 2);
|
||||
auto inv = get_inventory(invid);
|
||||
validate_slotid(slotid, inv.get());
|
||||
const ItemStack& item = inv->getSlot(slotid);
|
||||
lua::pushinteger(L, item.getItemId());
|
||||
lua::pushinteger(L, item.getCount());
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_inventory_set(lua::State* L) {
|
||||
auto invid = lua::tointeger(L, 1);
|
||||
auto slotid = lua::tointeger(L, 2);
|
||||
auto itemid = lua::tointeger(L, 3);
|
||||
auto count = lua::tointeger(L, 4);
|
||||
validate_itemid(itemid);
|
||||
|
||||
auto inv = get_inventory(invid);
|
||||
|
||||
validate_slotid(slotid, inv.get());
|
||||
ItemStack& item = inv->getSlot(slotid);
|
||||
item.set(ItemStack(itemid, count));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_inventory_size(lua::State* L) {
|
||||
auto invid = lua::tointeger(L, 1);
|
||||
auto inv = get_inventory(invid);
|
||||
return lua::pushinteger(L, inv->size());
|
||||
}
|
||||
|
||||
static int l_inventory_add(lua::State* L) {
|
||||
auto invid = lua::tointeger(L, 1);
|
||||
auto itemid = lua::tointeger(L, 2);
|
||||
auto count = lua::tointeger(L, 3);
|
||||
validate_itemid(itemid);
|
||||
|
||||
auto inv = get_inventory(invid);
|
||||
ItemStack item(itemid, count);
|
||||
inv->move(item, indices);
|
||||
return lua::pushinteger(L, item.getCount());
|
||||
}
|
||||
|
||||
static int l_inventory_get_block(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
int64_t id = blocks->createBlockInventory(x, y, z);
|
||||
return lua::pushinteger(L, id);
|
||||
}
|
||||
|
||||
static int l_inventory_bind_block(lua::State* L) {
|
||||
auto id = lua::tointeger(L, 1);
|
||||
auto x = lua::tointeger(L, 2);
|
||||
auto y = lua::tointeger(L, 3);
|
||||
auto z = lua::tointeger(L, 4);
|
||||
blocks->bindInventory(id, x, y, z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_inventory_unbind_block(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
blocks->unbindInventory(x, y, z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_inventory_clone(lua::State* L) {
|
||||
auto id = lua::tointeger(L, 1);
|
||||
auto clone = level->inventories->clone(id);
|
||||
if (clone == nullptr) {
|
||||
return lua::pushinteger(L, 0);
|
||||
}
|
||||
return lua::pushinteger(L, clone->getId());
|
||||
}
|
||||
|
||||
static int l_inventory_move(lua::State* L) {
|
||||
auto invAid = lua::tointeger(L, 1);
|
||||
auto slotAid = lua::tointeger(L, 2);
|
||||
auto invA = get_inventory(invAid, 1);
|
||||
validate_slotid(slotAid, invA.get());
|
||||
|
||||
auto invBid = lua::tointeger(L, 3);
|
||||
auto slotBid = lua::isnil(L, 4) ? -1 : lua::tointeger(L, 4);
|
||||
auto invB = get_inventory(invBid, 3);
|
||||
auto& slot = invA->getSlot(slotAid);
|
||||
if (slotBid == -1) {
|
||||
invB->move(slot, content->getIndices());
|
||||
} else {
|
||||
invB->move(slot, content->getIndices(), slotBid, slotBid + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg inventorylib[] = {
|
||||
{"get", lua::wrap<l_inventory_get>},
|
||||
{"set", lua::wrap<l_inventory_set>},
|
||||
{"size", lua::wrap<l_inventory_size>},
|
||||
{"add", lua::wrap<l_inventory_add>},
|
||||
{"move", lua::wrap<l_inventory_move>},
|
||||
{"get_block", lua::wrap<l_inventory_get_block>},
|
||||
{"bind_block", lua::wrap<l_inventory_bind_block>},
|
||||
{"unbind_block", lua::wrap<l_inventory_unbind_block>},
|
||||
{"clone", lua::wrap<l_inventory_clone>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "content/Content.hpp"
|
||||
#include "items/ItemDef.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static const ItemDef* get_item_def(lua::State* L, int idx) {
|
||||
auto indices = content->getIndices();
|
||||
auto id = lua::tointeger(L, idx);
|
||||
return indices->items.get(id);
|
||||
}
|
||||
|
||||
static int l_item_name(lua::State* L) {
|
||||
if (auto def = get_item_def(L, 1)) {
|
||||
return lua::pushstring(L, def->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_item_index(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
return lua::pushinteger(L, content->items.require(name).rt.id);
|
||||
}
|
||||
|
||||
static int l_item_stack_size(lua::State* L) {
|
||||
if (auto def = get_item_def(L, 1)) {
|
||||
return lua::pushinteger(L, def->stackSize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_item_defs_count(lua::State* L) {
|
||||
return lua::pushinteger(L, indices->items.count());
|
||||
}
|
||||
|
||||
static int l_item_get_icon(lua::State* L) {
|
||||
if (auto def = get_item_def(L, 1)) {
|
||||
switch (def->iconType) {
|
||||
case item_icon_type::none:
|
||||
return 0;
|
||||
case item_icon_type::sprite:
|
||||
return lua::pushstring(L, def->icon);
|
||||
case item_icon_type::block:
|
||||
return lua::pushstring(L, "block-previews:" + def->icon);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg itemlib[] = {
|
||||
{"index", lua::wrap<l_item_index>},
|
||||
{"name", lua::wrap<l_item_name>},
|
||||
{"stack_size", lua::wrap<l_item_stack_size>},
|
||||
{"defs_count", lua::wrap<l_item_defs_count>},
|
||||
{"icon", lua::wrap<l_item_get_icon>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "coders/json.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
static int l_json_stringify(lua::State* L) {
|
||||
auto value = lua::tovalue(L, 1);
|
||||
|
||||
bool nice = lua::toboolean(L, 2);
|
||||
auto string = json::stringify(value, nice, " ");
|
||||
return lua::pushstring(L, string);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
const luaL_Reg jsonlib[] = {
|
||||
{"tostring", lua::wrap<l_json_stringify>},
|
||||
{"parse", lua::wrap<l_json_parse>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,285 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "api_lua.hpp"
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/gtx/matrix_decompose.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
/// Overloads:
|
||||
/// mat4.idt() -> float[16] - creates identity matrix
|
||||
/// mat4.idt(dst: float[16]) -> float[16] - sets dst to identity matrix
|
||||
static int l_idt(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 0, 1);
|
||||
switch (argc) {
|
||||
case 0: {
|
||||
return lua::pushmat4(L, glm::mat4(1.0f));
|
||||
}
|
||||
case 1: {
|
||||
return lua::setmat4(L, 1, glm::mat4(1.0f));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// mat4.determinant(matrix: float[16]) - calculates matrix determinant
|
||||
static int l_determinant(lua::State* L) {
|
||||
if (lua::gettop(L) != 1) {
|
||||
throw std::runtime_error("invalid arguments number (1 expected)");
|
||||
}
|
||||
return lua::pushnumber(L, glm::determinant(lua::tomat4(L, 1)));
|
||||
}
|
||||
|
||||
/// Overloads:
|
||||
/// mat4.mul(m1: float[16], m2: float[16]) -> float[16] - creates matrix of m1
|
||||
/// and m2 multiplication result mat4.mul(m1: float[16], m2: float[16], dst:
|
||||
/// float[16]) -> float[16] - updates dst matrix with m1 and m2 multiplication
|
||||
/// result mat4.mul(m1: float[16], v: float[3 or 4]) -> float[3 or 4] - creates
|
||||
/// vector of m1 and v multiplication result mat4.mul(m1: float[16], v: float[3
|
||||
/// or 4], dst: float[3 or 4]) -> float[3 or 4] - updates dst vector with m1 and
|
||||
/// v multiplication result
|
||||
static int l_mul(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 2, 3);
|
||||
auto matrix1 = lua::tomat4(L, 1);
|
||||
uint len2 = lua::objlen(L, 2);
|
||||
if (len2 < 3) {
|
||||
throw std::runtime_error("argument #2: vec3 or vec4 expected");
|
||||
}
|
||||
switch (argc) {
|
||||
case 2: {
|
||||
if (len2 == 4) {
|
||||
return lua::pushvec(L, matrix1 * lua::tovec4(L, 2));
|
||||
} else if (len2 == 3) {
|
||||
return lua::pushvec(
|
||||
L, matrix1 * glm::vec4(lua::tovec3(L, 2), 1.0f)
|
||||
);
|
||||
}
|
||||
return lua::pushmat4(L, matrix1 * lua::tomat4(L, 2));
|
||||
}
|
||||
case 3: {
|
||||
if (len2 == 4) {
|
||||
return lua::setvec(L, 3, matrix1 * lua::tovec4(L, 2));
|
||||
} else if (len2 == 3) {
|
||||
return lua::setvec(
|
||||
L, 3, matrix1 * glm::vec4(lua::tovec3(L, 2), 1.0f)
|
||||
);
|
||||
}
|
||||
return lua::setmat4(L, 3, matrix1 * lua::tomat4(L, 2));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Overloads:
|
||||
/// mat4.<func>(vec: float[3]) -> float[16] - creates transform matrix
|
||||
/// mat4.<func>(matrix: float[16], vec: float[3]) -> float[16] - creates
|
||||
/// transformed copy of matrix mat4.<func>(matrix: float[16], vec: float[3],
|
||||
/// dst: float[16]) -> sets dst to transformed version of matrix
|
||||
template <glm::mat4 (*func)(const glm::mat4&, const glm::vec3&)>
|
||||
inline int l_binop_func(lua::State* L) {
|
||||
uint argc = lua::gettop(L);
|
||||
switch (argc) {
|
||||
case 1: {
|
||||
auto vec = lua::tovec3(L, 1);
|
||||
return lua::pushmat4(L, func(glm::mat4(1.0f), vec));
|
||||
}
|
||||
case 2: {
|
||||
auto matrix = lua::tomat4(L, 1);
|
||||
auto vec = lua::tovec3(L, 2);
|
||||
return lua::pushmat4(L, func(matrix, vec));
|
||||
}
|
||||
case 3: {
|
||||
auto matrix = lua::tomat4(L, 1);
|
||||
auto vec = lua::tovec3(L, 2);
|
||||
return lua::setmat4(L, 3, func(matrix, vec));
|
||||
}
|
||||
default: {
|
||||
throw std::runtime_error(
|
||||
"invalid arguments number (1, 2 or 3 expected)"
|
||||
);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Overloads:
|
||||
/// mat4.rotate(vec: float[3], angle: float) -> float[16] - creates rotation
|
||||
/// matrix mat4.rotate(matrix: float[16], vec: float[3], angle: float) ->
|
||||
/// float[16] - creates rotated copy of matrix mat4.rotate(matrix: float[16],
|
||||
/// vec: float[3], angle: float, dst: float[16]) -> sets dst to rotated version
|
||||
/// of matrix
|
||||
inline int l_rotate(lua::State* L) {
|
||||
uint argc = lua::gettop(L);
|
||||
switch (argc) {
|
||||
case 2: {
|
||||
auto vec = lua::tovec3(L, 1);
|
||||
auto angle = glm::radians(static_cast<float>(lua::tonumber(L, 2)));
|
||||
return lua::pushmat4(L, glm::rotate(glm::mat4(1.0f), angle, vec));
|
||||
}
|
||||
case 3: {
|
||||
auto matrix = lua::tomat4(L, 1);
|
||||
auto vec = lua::tovec3(L, 2);
|
||||
auto angle = glm::radians(static_cast<float>(lua::tonumber(L, 3)));
|
||||
return lua::pushmat4(L, glm::rotate(matrix, angle, vec));
|
||||
}
|
||||
case 4: {
|
||||
auto matrix = lua::tomat4(L, 1);
|
||||
auto vec = lua::tovec3(L, 2);
|
||||
auto angle = glm::radians(static_cast<float>(lua::tonumber(L, 3)));
|
||||
return lua::setmat4(L, 4, glm::rotate(matrix, angle, vec));
|
||||
}
|
||||
default: {
|
||||
throw std::runtime_error(
|
||||
"invalid arguments number (2, 3 or 4 expected)"
|
||||
);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Overloads:
|
||||
/// mat4.inverse(matrix: float[16]) -> float[16] - creates inversed version of
|
||||
/// the matrix mat4.inverse(matrix: float[16], dst: float[16]) -> float[16] -
|
||||
/// updates dst matrix with inversed version of the matrix
|
||||
static int l_inverse(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 1, 2);
|
||||
auto matrix = lua::tomat4(L, 1);
|
||||
switch (argc) {
|
||||
case 1: {
|
||||
return lua::pushmat4(L, glm::inverse(matrix));
|
||||
}
|
||||
case 2: {
|
||||
return lua::setmat4(L, 2, glm::inverse(matrix));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Overloads:
|
||||
/// mat4.transpose(matrix: float[16]) -> float[16] - creates transposed version
|
||||
/// of the matrix mat4.transpose(matrix: float[16], dst: float[16]) -> float[16]
|
||||
/// - updates dst matrix with transposed version of the matrix
|
||||
static int l_transpose(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 1, 2);
|
||||
auto matrix = lua::tomat4(L, 1);
|
||||
switch (argc) {
|
||||
case 1: {
|
||||
return lua::pushmat4(L, glm::transpose(matrix));
|
||||
}
|
||||
case 2: {
|
||||
return lua::setmat4(L, 2, glm::transpose(matrix));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// mat4.decompose(m: float[16]) -> {
|
||||
/// scale=float[3],
|
||||
/// rotation=float[16],
|
||||
/// quaternion=float[4],
|
||||
/// translation=float[3],
|
||||
/// skew=float[3],
|
||||
/// perspective=float[4]
|
||||
/// } or nil
|
||||
static int l_decompose(lua::State* L) {
|
||||
auto matrix = lua::tomat4(L, 1);
|
||||
glm::vec3 scale;
|
||||
glm::quat rotation;
|
||||
glm::vec3 translation;
|
||||
glm::vec3 skew;
|
||||
glm::vec4 perspective;
|
||||
if (glm::decompose(
|
||||
matrix, scale, rotation, translation, skew, perspective
|
||||
)) {
|
||||
lua::createtable(L, 0, 6);
|
||||
|
||||
lua::pushvec3(L, scale);
|
||||
lua::setfield(L, "scale");
|
||||
|
||||
lua::pushmat4(L, glm::toMat4(rotation));
|
||||
lua::setfield(L, "rotation");
|
||||
|
||||
lua::pushquat(L, rotation);
|
||||
lua::setfield(L, "quaternion");
|
||||
|
||||
lua::pushvec3(L, translation);
|
||||
lua::setfield(L, "translation");
|
||||
|
||||
lua::pushvec3(L, skew);
|
||||
lua::setfield(L, "skew");
|
||||
|
||||
lua::pushvec4(L, perspective);
|
||||
lua::setfield(L, "perspective");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_look_at(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 3, 4);
|
||||
auto eye = lua::tovec<3>(L, 1);
|
||||
auto center = lua::tovec<3>(L, 2);
|
||||
auto up = lua::tovec<3>(L, 3);
|
||||
|
||||
if (argc == 3) {
|
||||
return lua::pushmat4(L, glm::lookAt(eye, center, up));
|
||||
} else {
|
||||
return lua::setmat4(L, 4, glm::lookAt(eye, center, up));
|
||||
}
|
||||
}
|
||||
|
||||
static int l_from_quat(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 1, 2);
|
||||
auto quat = lua::toquat(L, 1);
|
||||
switch (argc) {
|
||||
case 1:
|
||||
return lua::pushmat4(L, glm::toMat4(quat));
|
||||
case 2:
|
||||
return lua::setmat4(L, 2, glm::toMat4(quat));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_tostring(lua::State* L) {
|
||||
auto matrix = lua::tomat4(L, 1);
|
||||
bool multiline = lua::toboolean(L, 2);
|
||||
std::stringstream ss;
|
||||
ss << "mat4 {";
|
||||
if (multiline) {
|
||||
ss << "\n";
|
||||
}
|
||||
for (uint y = 0; y < 4; y++) {
|
||||
for (uint x = 0; x < 4; x++) {
|
||||
if (multiline) {
|
||||
ss << "\t" << matrix[y][x];
|
||||
} else if (x > 0) {
|
||||
ss << " " << matrix[y][x];
|
||||
} else {
|
||||
ss << matrix[y][x];
|
||||
}
|
||||
}
|
||||
if (multiline) {
|
||||
ss << "\n";
|
||||
} else {
|
||||
ss << "; ";
|
||||
}
|
||||
}
|
||||
ss << "}";
|
||||
return lua::pushstring(L, ss.str());
|
||||
}
|
||||
|
||||
const luaL_Reg mat4lib[] = {
|
||||
{"idt", lua::wrap<l_idt>},
|
||||
{"mul", lua::wrap<l_mul>},
|
||||
{"scale", lua::wrap<l_binop_func<glm::scale>>},
|
||||
{"rotate", lua::wrap<l_rotate>},
|
||||
{"translate", lua::wrap<l_binop_func<glm::translate>>},
|
||||
{"inverse", lua::wrap<l_inverse>},
|
||||
{"transpose", lua::wrap<l_transpose>},
|
||||
{"determinant", lua::wrap<l_determinant>},
|
||||
{"decompose", lua::wrap<l_decompose>},
|
||||
{"look_at", lua::wrap<l_look_at>},
|
||||
{"from_quat", lua::wrap<l_from_quat>},
|
||||
{"tostring", lua::wrap<l_tostring>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,176 @@
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "assets/AssetsLoader.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "files/WorldFiles.hpp"
|
||||
#include "files/engine_paths.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "world/World.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static int l_pack_get_folder(lua::State* L) {
|
||||
std::string packName = lua::tostring(L, 1);
|
||||
auto packs = engine->getAllContentPacks();
|
||||
|
||||
for (auto& pack : packs) {
|
||||
if (pack.id == packName) {
|
||||
return lua::pushstring(L, pack.folder.u8string() + "/");
|
||||
}
|
||||
}
|
||||
return lua::pushstring(L, "");
|
||||
}
|
||||
|
||||
/// @brief pack.get_installed() -> array<string>
|
||||
static int l_pack_get_installed(lua::State* L) {
|
||||
auto& packs = engine->getContentPacks();
|
||||
lua::createtable(L, packs.size(), 0);
|
||||
for (size_t i = 0; i < packs.size(); i++) {
|
||||
lua::pushstring(L, packs[i].id);
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// @brief pack.get_available() -> array<string>
|
||||
static int l_pack_get_available(lua::State* L) {
|
||||
fs::path worldFolder("");
|
||||
if (level) {
|
||||
worldFolder = level->getWorld()->wfile->getFolder();
|
||||
}
|
||||
auto manager = engine->createPacksManager(worldFolder);
|
||||
manager.scan();
|
||||
|
||||
const auto& installed = engine->getContentPacks();
|
||||
for (auto& pack : installed) {
|
||||
manager.exclude(pack.id);
|
||||
}
|
||||
auto names = manager.getAllNames();
|
||||
|
||||
lua::createtable(L, names.size(), 0);
|
||||
for (size_t i = 0; i < names.size(); i++) {
|
||||
lua::pushstring(L, names[i]);
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_pack_get_info(
|
||||
lua::State* L, const ContentPack& pack, const Content* content
|
||||
) {
|
||||
lua::createtable(L, 0, 5);
|
||||
|
||||
lua::pushstring(L, pack.id);
|
||||
lua::setfield(L, "id");
|
||||
|
||||
lua::pushstring(L, pack.title);
|
||||
lua::setfield(L, "title");
|
||||
|
||||
lua::pushstring(L, pack.creator);
|
||||
lua::setfield(L, "creator");
|
||||
|
||||
lua::pushstring(L, pack.description);
|
||||
lua::setfield(L, "description");
|
||||
|
||||
lua::pushstring(L, pack.version);
|
||||
lua::setfield(L, "version");
|
||||
|
||||
auto assets = engine->getAssets();
|
||||
std::string icon = pack.id + ".icon";
|
||||
if (!AssetsLoader::loadExternalTexture(
|
||||
assets, icon, {pack.folder / fs::path("icon.png")}
|
||||
)) {
|
||||
icon = "gui/no_icon";
|
||||
}
|
||||
|
||||
lua::pushstring(L, icon);
|
||||
lua::setfield(L, "icon");
|
||||
|
||||
if (!pack.dependencies.empty()) {
|
||||
lua::createtable(L, pack.dependencies.size(), 0);
|
||||
for (size_t i = 0; i < pack.dependencies.size(); i++) {
|
||||
auto& dpack = pack.dependencies[i];
|
||||
std::string prefix;
|
||||
switch (dpack.level) {
|
||||
case DependencyLevel::required:
|
||||
prefix = "!";
|
||||
break;
|
||||
case DependencyLevel::optional:
|
||||
prefix = "?";
|
||||
break;
|
||||
case DependencyLevel::weak:
|
||||
prefix = "~";
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
lua::pushfstring(L, "%s%s", prefix.c_str(), dpack.id.c_str());
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
lua::setfield(L, "dependencies");
|
||||
}
|
||||
|
||||
auto runtime = content ? content->getPackRuntime(pack.id) : nullptr;
|
||||
if (runtime) {
|
||||
lua::pushboolean(L, runtime->getStats().hasSavingContent());
|
||||
lua::setfield(L, "has_indices");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// @brief pack.get_info(packid: str) -> {
|
||||
/// title: str,
|
||||
/// creator: str,
|
||||
/// description: str,
|
||||
/// version: str,
|
||||
/// [optional] has_indices: bool
|
||||
/// } or nil
|
||||
static int l_pack_get_info(lua::State* L) {
|
||||
auto packid = lua::tostring(L, 1);
|
||||
|
||||
auto content = engine->getContent();
|
||||
auto& packs = engine->getContentPacks();
|
||||
auto found =
|
||||
std::find_if(packs.begin(), packs.end(), [packid](const auto& pack) {
|
||||
return pack.id == packid;
|
||||
});
|
||||
if (found == packs.end()) {
|
||||
// TODO: optimize
|
||||
fs::path worldFolder("");
|
||||
if (level) {
|
||||
worldFolder = level->getWorld()->wfile->getFolder();
|
||||
}
|
||||
auto manager = engine->createPacksManager(worldFolder);
|
||||
manager.scan();
|
||||
auto vec = manager.getAll({packid});
|
||||
if (!vec.empty()) {
|
||||
return l_pack_get_info(L, vec[0], content);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const auto& pack = *found;
|
||||
return l_pack_get_info(L, pack, content);
|
||||
}
|
||||
|
||||
static int l_pack_get_base_packs(lua::State* L) {
|
||||
auto& packs = engine->getBasePacks();
|
||||
lua::createtable(L, packs.size(), 0);
|
||||
for (size_t i = 0; i < packs.size(); i++) {
|
||||
lua::pushstring(L, packs[i]);
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg packlib[] = {
|
||||
{"get_folder", lua::wrap<l_pack_get_folder>},
|
||||
{"get_installed", lua::wrap<l_pack_get_installed>},
|
||||
{"get_available", lua::wrap<l_pack_get_available>},
|
||||
{"get_info", lua::wrap<l_pack_get_info>},
|
||||
{"get_base_packs", lua::wrap<l_pack_get_base_packs>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,231 @@
|
||||
#include <algorithm>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "items/Inventory.hpp"
|
||||
#include "objects/Entities.hpp"
|
||||
#include "objects/Player.hpp"
|
||||
#include "physics/Hitbox.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "libentity.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
inline std::shared_ptr<Player> get_player(lua::State* L, int idx) {
|
||||
return level->getObject<Player>(lua::tointeger(L, idx));
|
||||
}
|
||||
|
||||
static int l_get_pos(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
return lua::pushvec_stack(L, player->getPosition());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_pos(lua::State* L) {
|
||||
auto player = get_player(L, 1);
|
||||
if (!player) {
|
||||
return 0;
|
||||
}
|
||||
auto x = lua::tonumber(L, 2);
|
||||
auto y = lua::tonumber(L, 3);
|
||||
auto z = lua::tonumber(L, 4);
|
||||
player->teleport(glm::vec3(x, y, z));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_vel(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
if (auto hitbox = player->getHitbox()) {
|
||||
return lua::pushvec_stack(L, hitbox->velocity);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_vel(lua::State* L) {
|
||||
auto player = get_player(L, 1);
|
||||
if (!player) {
|
||||
return 0;
|
||||
}
|
||||
auto x = lua::tonumber(L, 2);
|
||||
auto y = lua::tonumber(L, 3);
|
||||
auto z = lua::tonumber(L, 4);
|
||||
if (auto hitbox = player->getHitbox()) {
|
||||
hitbox->velocity = glm::vec3(x, y, z);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_rot(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
return lua::pushvec_stack(L, player->cam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_rot(lua::State* L) {
|
||||
auto player = get_player(L, 1);
|
||||
if (!player) {
|
||||
return 0;
|
||||
}
|
||||
glm::vec3& cam = player->cam;
|
||||
|
||||
auto x = lua::tonumber(L, 2);
|
||||
auto y = lua::tonumber(L, 3);
|
||||
auto z = cam.z;
|
||||
if (lua::isnumber(L, 4)) {
|
||||
z = lua::tonumber(L, 4);
|
||||
}
|
||||
cam.x = x;
|
||||
cam.y = y;
|
||||
cam.z = z;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_dir(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
return lua::pushvec3(L, player->camera->front);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_inv(lua::State* L) {
|
||||
auto player = get_player(L, 1);
|
||||
if (!player) {
|
||||
return 0;
|
||||
}
|
||||
lua::pushinteger(L, player->getInventory()->getId());
|
||||
lua::pushinteger(L, player->getChosenSlot());
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_is_flight(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
return lua::pushboolean(L, player->isFlight());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_flight(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
player->setFlight(lua::toboolean(L, 2));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_is_noclip(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
return lua::pushboolean(L, player->isNoclip());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_noclip(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
player->setNoclip(lua::toboolean(L, 2));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_selected_block(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
if (player->selection.vox.id == BLOCK_VOID) {
|
||||
return 0;
|
||||
}
|
||||
return lua::pushivec_stack(L, player->selection.position);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_selected_entity(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
if (auto eid = player->getSelectedEntity()) {
|
||||
return lua::pushinteger(L, eid);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_spawnpoint(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
return lua::pushvec_stack(L, player->getSpawnPoint());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_set_spawnpoint(lua::State* L) {
|
||||
if (auto player = get_player(L, 1)) {
|
||||
auto x = lua::tonumber(L, 2);
|
||||
auto y = lua::tonumber(L, 3);
|
||||
auto z = lua::tonumber(L, 4);
|
||||
player->setSpawnPoint(glm::vec3(x, y, z));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_entity(lua::State* L) {
|
||||
auto player = get_player(L, 1);
|
||||
if (player == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return lua::pushinteger(L, player->getEntity());
|
||||
}
|
||||
|
||||
static int l_set_entity(lua::State* L) {
|
||||
auto player = get_player(L, 1);
|
||||
if (player == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
if (auto entity = get_entity(L, 2)) {
|
||||
player->setEntity(entity->getUID());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_get_camera(lua::State* L) {
|
||||
auto player = get_player(L, 1);
|
||||
if (player == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto found = std::find(
|
||||
level->cameras.begin(), level->cameras.end(), player->currentCamera
|
||||
);
|
||||
if (found == level->cameras.end()) {
|
||||
return 0;
|
||||
}
|
||||
return lua::pushinteger(L, found - level->cameras.begin());
|
||||
}
|
||||
|
||||
static int l_set_camera(lua::State* L) {
|
||||
auto player = get_player(L, 1);
|
||||
if (player == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
size_t index = lua::tointeger(L, 2);
|
||||
player->currentCamera = level->cameras.at(index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg playerlib[] = {
|
||||
{"get_pos", lua::wrap<l_get_pos>},
|
||||
{"set_pos", lua::wrap<l_set_pos>},
|
||||
{"get_vel", lua::wrap<l_get_vel>},
|
||||
{"set_vel", lua::wrap<l_set_vel>},
|
||||
{"get_rot", lua::wrap<l_get_rot>},
|
||||
{"set_rot", lua::wrap<l_set_rot>},
|
||||
{"get_dir", lua::wrap<l_get_dir>},
|
||||
{"get_inventory", lua::wrap<l_get_inv>},
|
||||
{"is_flight", lua::wrap<l_is_flight>},
|
||||
{"set_flight", lua::wrap<l_set_flight>},
|
||||
{"is_noclip", lua::wrap<l_is_noclip>},
|
||||
{"set_noclip", lua::wrap<l_set_noclip>},
|
||||
{"get_selected_block", lua::wrap<l_get_selected_block>},
|
||||
{"get_selected_entity", lua::wrap<l_get_selected_entity>},
|
||||
{"set_spawnpoint", lua::wrap<l_set_spawnpoint>},
|
||||
{"get_spawnpoint", lua::wrap<l_get_spawnpoint>},
|
||||
{"get_entity", lua::wrap<l_get_entity>},
|
||||
{"set_entity", lua::wrap<l_set_entity>},
|
||||
{"get_camera", lua::wrap<l_get_camera>},
|
||||
{"set_camera", lua::wrap<l_set_camera>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "api_lua.hpp"
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <sstream>
|
||||
|
||||
static int l_from_mat4(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 1, 2);
|
||||
auto matrix = lua::tomat4(L, 1);
|
||||
if (argc == 1) {
|
||||
return lua::pushquat(L, glm::toQuat(matrix));
|
||||
} else {
|
||||
return lua::setquat(L, 2, glm::toQuat(matrix));
|
||||
}
|
||||
}
|
||||
|
||||
static int l_slerp(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 3, 4);
|
||||
auto quat1 = lua::toquat(L, 1);
|
||||
auto quat2 = lua::toquat(L, 2);
|
||||
float t = lua::tonumber(L, 3);
|
||||
if (argc == 3) {
|
||||
return lua::pushquat(L, glm::slerp(quat1, quat2, t));
|
||||
} else {
|
||||
return lua::setquat(L, 4, glm::slerp(quat1, quat2, t));
|
||||
}
|
||||
}
|
||||
|
||||
static int l_tostring(lua::State* L) {
|
||||
lua::check_argc(L, 1);
|
||||
auto quat = lua::toquat(L, 1);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "quat"
|
||||
<< "{";
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i > 0) {
|
||||
ss << ", ";
|
||||
}
|
||||
ss << quat[i];
|
||||
}
|
||||
ss << "}";
|
||||
return lua::pushstring(L, ss.str());
|
||||
}
|
||||
|
||||
const luaL_Reg quatlib[] = {
|
||||
{"from_mat4", lua::wrap<l_from_mat4>},
|
||||
{"slerp", lua::wrap<l_slerp>},
|
||||
{"tostring", lua::wrap<l_tostring>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "engine.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
static int l_time_uptime(lua::State* L) {
|
||||
return lua::pushnumber(L, Window::time());
|
||||
}
|
||||
|
||||
static int l_time_delta(lua::State* L) {
|
||||
return lua::pushnumber(L, scripting::engine->getDelta());
|
||||
}
|
||||
|
||||
const luaL_Reg timelib[] = {
|
||||
{"uptime", lua::wrap<l_time_uptime>},
|
||||
{"delta", lua::wrap<l_time_delta>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "coders/toml.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static int l_toml_stringify(lua::State* L) {
|
||||
auto value = lua::tovalue(L, 1);
|
||||
|
||||
if (value.isObject()) {
|
||||
auto string = toml::stringify(value);
|
||||
return lua::pushstring(L, string);
|
||||
} else {
|
||||
throw std::runtime_error("table expected");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
const luaL_Reg tomllib[] = {
|
||||
{"tostring", lua::wrap<l_toml_stringify>},
|
||||
{"parse", lua::wrap<l_toml_parse>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,225 @@
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/random.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <sstream>
|
||||
|
||||
#include "api_lua.hpp"
|
||||
|
||||
template <typename T>
|
||||
inline T angle(glm::vec<2, T> vec) {
|
||||
auto val = std::atan2(vec.y, vec.x);
|
||||
if (val < 0.0) {
|
||||
return val + glm::two_pi<double>();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <int n, template <class> class Op>
|
||||
static int l_binop(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 2, 3);
|
||||
auto a = lua::tovec<n>(L, 1);
|
||||
|
||||
if (lua::isnumber(L, 2)) { // scalar second operand overload
|
||||
auto b = lua::tonumber(L, 2);
|
||||
Op op;
|
||||
if (argc == 2) {
|
||||
lua::createtable(L, n, 0);
|
||||
for (uint i = 0; i < n; i++) {
|
||||
lua::pushnumber(L, op(a[i], b));
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return lua::setvec(L, 3, op(a, glm::vec<n, float>(b)));
|
||||
}
|
||||
} else {
|
||||
auto b = lua::tovec<n>(L, 2);
|
||||
Op op;
|
||||
if (argc == 2) {
|
||||
lua::createtable(L, n, 0);
|
||||
for (uint i = 0; i < n; i++) {
|
||||
lua::pushnumber(L, op(a[i], b[i]));
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return lua::setvec(L, 3, op(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int n, glm::vec<n, float> (*func)(const glm::vec<n, float>&)>
|
||||
static int l_unaryop(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 1, 2);
|
||||
auto vec = func(lua::tovec<n>(L, 1));
|
||||
switch (argc) {
|
||||
case 1:
|
||||
lua::createtable(L, n, 0);
|
||||
for (uint i = 0; i < n; i++) {
|
||||
lua::pushnumber(L, vec[i]);
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
case 2:
|
||||
return lua::setvec(L, 2, vec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <int n, float (*func)(const glm::vec<n, float>&)>
|
||||
static int l_scalar_op(lua::State* L) {
|
||||
lua::check_argc(L, 1);
|
||||
auto vec = lua::tovec<n>(L, 1);
|
||||
return lua::pushnumber(L, func(vec));
|
||||
}
|
||||
|
||||
template <int n>
|
||||
static int l_pow(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 2, 3);
|
||||
auto a = lua::tovec<n>(L, 1);
|
||||
|
||||
if (lua::isnumber(L, 2)) {
|
||||
auto b = lua::tonumber(L, 2);
|
||||
if (argc == 2) {
|
||||
lua::createtable(L, n, 0);
|
||||
for (uint i = 0; i < n; i++) {
|
||||
lua::pushnumber(L, pow(a[i], b));
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return lua::setvec(L, 3, pow(a, glm::vec<n, float>(b)));
|
||||
}
|
||||
} else {
|
||||
auto b = lua::tovec<n>(L, 2);
|
||||
if (argc == 2) {
|
||||
lua::createtable(L, n, 0);
|
||||
for (uint i = 0; i < n; i++) {
|
||||
lua::pushnumber(L, pow(a[i], b[i]));
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return lua::setvec(L, 3, pow(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int n>
|
||||
static int l_dot(lua::State* L) {
|
||||
lua::check_argc(L, 2);
|
||||
const auto& a = lua::tovec<n>(L, 1);
|
||||
const auto& b = lua::tovec<n>(L, 2);
|
||||
return lua::pushnumber(L, glm::dot(a, b));
|
||||
}
|
||||
|
||||
template <int n>
|
||||
static int l_inverse(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 1, 2);
|
||||
auto vec = lua::tovec<n>(L, 1);
|
||||
switch (argc) {
|
||||
case 1:
|
||||
lua::createtable(L, n, 0);
|
||||
for (uint i = 0; i < n; i++) {
|
||||
lua::pushnumber(L, (-1) * vec[i]);
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
case 2:
|
||||
return lua::setvec(L, 2, -vec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_spherical_rand(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 1, 2);
|
||||
switch (argc) {
|
||||
case 1:
|
||||
return lua::pushvec3(L, glm::sphericalRand(lua::tonumber(L, 1)));
|
||||
case 2:
|
||||
return lua::setvec(
|
||||
L,
|
||||
2,
|
||||
glm::sphericalRand(static_cast<float>(lua::tonumber(L, 1)))
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_vec2_angle(lua::State* L) {
|
||||
uint argc = lua::check_argc(L, 1, 2);
|
||||
if (argc == 1) {
|
||||
return lua::pushnumber(L, glm::degrees(angle(lua::tovec2(L, 1))));
|
||||
} else {
|
||||
return lua::pushnumber(
|
||||
L,
|
||||
glm::degrees(
|
||||
angle(glm::vec2(lua::tonumber(L, 1), lua::tonumber(L, 2)))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <int n>
|
||||
static int l_tostring(lua::State* L) {
|
||||
lua::check_argc(L, 1);
|
||||
auto vec = lua::tovec<n>(L, 1);
|
||||
std::stringstream ss;
|
||||
ss << "vec" << std::to_string(n) << "{";
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i > 0) {
|
||||
ss << ", ";
|
||||
}
|
||||
ss << vec[i];
|
||||
}
|
||||
ss << "}";
|
||||
return lua::pushstring(L, ss.str());
|
||||
}
|
||||
|
||||
const luaL_Reg vec2lib[] = {
|
||||
{"add", lua::wrap<l_binop<2, std::plus>>},
|
||||
{"sub", lua::wrap<l_binop<2, std::minus>>},
|
||||
{"mul", lua::wrap<l_binop<2, std::multiplies>>},
|
||||
{"div", lua::wrap<l_binop<2, std::divides>>},
|
||||
{"normalize", lua::wrap<l_unaryop<2, glm::normalize>>},
|
||||
{"length", lua::wrap<l_scalar_op<2, glm::length>>},
|
||||
{"tostring", lua::wrap<l_tostring<2>>},
|
||||
{"abs", lua::wrap<l_unaryop<2, glm::abs>>},
|
||||
{"round", lua::wrap<l_unaryop<2, glm::round>>},
|
||||
{"inverse", lua::wrap<l_inverse<2>>},
|
||||
{"pow", lua::wrap<l_pow<2>>},
|
||||
{"dot", lua::wrap<l_dot<2>>},
|
||||
{"angle", lua::wrap<l_vec2_angle>},
|
||||
{NULL, NULL}};
|
||||
|
||||
const luaL_Reg vec3lib[] = {
|
||||
{"add", lua::wrap<l_binop<3, std::plus>>},
|
||||
{"sub", lua::wrap<l_binop<3, std::minus>>},
|
||||
{"mul", lua::wrap<l_binop<3, std::multiplies>>},
|
||||
{"div", lua::wrap<l_binop<3, std::divides>>},
|
||||
{"normalize", lua::wrap<l_unaryop<3, glm::normalize>>},
|
||||
{"length", lua::wrap<l_scalar_op<3, glm::length>>},
|
||||
{"tostring", lua::wrap<l_tostring<3>>},
|
||||
{"abs", lua::wrap<l_unaryop<3, glm::abs>>},
|
||||
{"round", lua::wrap<l_unaryop<3, glm::round>>},
|
||||
{"inverse", lua::wrap<l_inverse<3>>},
|
||||
{"pow", lua::wrap<l_pow<3>>},
|
||||
{"dot", lua::wrap<l_dot<3>>},
|
||||
{"spherical_rand", lua::wrap<l_spherical_rand>},
|
||||
{NULL, NULL}};
|
||||
|
||||
const luaL_Reg vec4lib[] = {
|
||||
{"add", lua::wrap<l_binop<4, std::plus>>},
|
||||
{"sub", lua::wrap<l_binop<4, std::minus>>},
|
||||
{"mul", lua::wrap<l_binop<4, std::multiplies>>},
|
||||
{"div", lua::wrap<l_binop<4, std::divides>>},
|
||||
{"normalize", lua::wrap<l_unaryop<4, glm::normalize>>},
|
||||
{"length", lua::wrap<l_scalar_op<4, glm::length>>},
|
||||
{"tostring", lua::wrap<l_tostring<4>>},
|
||||
{"abs", lua::wrap<l_unaryop<4, glm::abs>>},
|
||||
{"round", lua::wrap<l_unaryop<4, glm::round>>},
|
||||
{"inverse", lua::wrap<l_inverse<4>>},
|
||||
{"pow", lua::wrap<l_pow<4>>},
|
||||
{"dot", lua::wrap<l_dot<4>>},
|
||||
{NULL, NULL}};
|
||||
@@ -0,0 +1,99 @@
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
|
||||
#include "assets/Assets.hpp"
|
||||
#include "assets/AssetsLoader.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "files/engine_paths.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "world/World.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static int l_world_get_list(lua::State* L) {
|
||||
auto paths = engine->getPaths();
|
||||
auto worlds = paths->scanForWorlds();
|
||||
|
||||
lua::createtable(L, worlds.size(), 0);
|
||||
for (size_t i = 0; i < worlds.size(); i++) {
|
||||
lua::createtable(L, 0, 1);
|
||||
|
||||
auto name = worlds[i].filename().u8string();
|
||||
lua::pushstring(L, name);
|
||||
lua::setfield(L, "name");
|
||||
|
||||
auto assets = engine->getAssets();
|
||||
std::string icon = "world#" + name + ".icon";
|
||||
if (!AssetsLoader::loadExternalTexture(
|
||||
assets,
|
||||
icon,
|
||||
{worlds[i] / fs::path("icon.png"),
|
||||
worlds[i] / fs::path("preview.png")}
|
||||
)) {
|
||||
icon = "gui/no_world_icon";
|
||||
}
|
||||
lua::pushstring(L, icon);
|
||||
lua::setfield(L, "icon");
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_world_get_total_time(lua::State* L) {
|
||||
return lua::pushnumber(L, level->getWorld()->getInfo().totalTime);
|
||||
}
|
||||
|
||||
static int l_world_get_day_time(lua::State* L) {
|
||||
return lua::pushnumber(L, level->getWorld()->getInfo().daytime);
|
||||
}
|
||||
|
||||
static int l_world_set_day_time(lua::State* L) {
|
||||
auto value = lua::tonumber(L, 1);
|
||||
level->getWorld()->getInfo().daytime = std::fmod(value, 1.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_world_set_day_time_speed(lua::State* L) {
|
||||
auto value = lua::tonumber(L, 1);
|
||||
level->getWorld()->getInfo().daytimeSpeed = std::abs(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_world_get_day_time_speed(lua::State* L) {
|
||||
return lua::pushnumber(L, level->getWorld()->getInfo().daytimeSpeed);
|
||||
}
|
||||
|
||||
static int l_world_get_seed(lua::State* L) {
|
||||
return lua::pushinteger(L, level->getWorld()->getSeed());
|
||||
}
|
||||
|
||||
static int l_world_exists(lua::State* L) {
|
||||
auto name = lua::require_string(L, 1);
|
||||
auto worldsDir = engine->getPaths()->getWorldFolderByName(name);
|
||||
return lua::pushboolean(L, fs::is_directory(worldsDir));
|
||||
}
|
||||
|
||||
static int l_world_is_day(lua::State* L) {
|
||||
auto daytime = level->getWorld()->getInfo().daytime;
|
||||
return lua::pushboolean(L, daytime >= 0.2 && daytime <= 0.8);
|
||||
}
|
||||
|
||||
static int l_world_is_night(lua::State* L) {
|
||||
auto daytime = level->getWorld()->getInfo().daytime;
|
||||
return lua::pushboolean(L, daytime < 0.2 || daytime > 0.8);
|
||||
}
|
||||
|
||||
const luaL_Reg worldlib[] = {
|
||||
{"get_list", lua::wrap<l_world_get_list>},
|
||||
{"get_total_time", lua::wrap<l_world_get_total_time>},
|
||||
{"get_day_time", lua::wrap<l_world_get_day_time>},
|
||||
{"set_day_time", lua::wrap<l_world_set_day_time>},
|
||||
{"set_day_time_speed", lua::wrap<l_world_set_day_time_speed>},
|
||||
{"get_day_time_speed", lua::wrap<l_world_get_day_time_speed>},
|
||||
{"get_seed", lua::wrap<l_world_get_seed>},
|
||||
{"is_day", lua::wrap<l_world_is_day>},
|
||||
{"is_night", lua::wrap<l_world_is_night>},
|
||||
{"exists", lua::wrap<l_world_exists>},
|
||||
{NULL, NULL}};
|
||||
Reference in New Issue
Block a user