move lua libs to /logic/scripting/lua/libs

This commit is contained in:
MihailRis
2024-10-05 00:53:41 +03:00
parent d31a935009
commit 736fdbf964
31 changed files with 6 additions and 6 deletions
+76
View File
@@ -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}};
+387
View File
@@ -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}};
+605
View File
@@ -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}
};
+128
View File
@@ -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}};
+118
View File
@@ -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}};
+195
View File
@@ -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}};
+215
View File
@@ -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);
}
+277
View File
@@ -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}};
+629
View File
@@ -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}};
+153
View File
@@ -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}};
+106
View File
@@ -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}};
+56
View File
@@ -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}};
+21
View File
@@ -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}};
+285
View File
@@ -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}};
+176
View File
@@ -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}};
+231
View File
@@ -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}};
+51
View File
@@ -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}};
+16
View File
@@ -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}};
+26
View File
@@ -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}};
+225
View File
@@ -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}};
+99
View File
@@ -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}};