Merge remote-tracking branch 'upstream/main'

This commit is contained in:
DanielProl1xy
2024-02-19 10:23:29 +03:00
154 changed files with 6818 additions and 2760 deletions
+51
View File
@@ -5,10 +5,13 @@
#include "../voxels/Chunk.h"
#include "../voxels/Chunks.h"
#include "../world/Level.h"
#include "../world/World.h"
#include "../content/Content.h"
#include "../lighting/Lighting.h"
#include "../util/timeutil.h"
#include "../maths/fastmaths.h"
#include "../items/Inventory.h"
#include "../items/Inventories.h"
#include "scripting/scripting.h"
@@ -44,6 +47,10 @@ int Clock::getTickRate() const {
return tickRate;
}
int Clock::getTickId() const {
return tickId;
}
BlocksController::BlocksController(Level* level, uint padding)
: level(level),
chunks(level->chunks),
@@ -141,3 +148,47 @@ void BlocksController::randomTick(int tickid, int parts) {
}
}
}
int64_t BlocksController::createBlockInventory(int x, int y, int z) {
auto chunk = chunks->getChunkByVoxel(x, y, z);
if (chunk == nullptr) {
return 0;
}
int lx = x - chunk->x * CHUNK_W;
int lz = z - chunk->z * CHUNK_D;
auto inv = chunk->getBlockInventory(lx, y, lz);
if (inv == nullptr) {
auto indices = level->content->getIndices();
auto def = indices->getBlockDef(chunk->voxels[vox_index(lx, y, lz)].id);
int invsize = def->inventorySize;
if (invsize == 0) {
return 0;
}
inv = level->inventories->create(invsize);
chunk->addBlockInventory(inv, lx, y, lz);
}
return inv->getId();
}
void BlocksController::bindInventory(int64_t invid, int x, int y, int z) {
auto chunk = chunks->getChunkByVoxel(x, y, z);
if (chunk == nullptr) {
throw std::runtime_error("block does not exists");
}
if (invid <= 0) {
throw std::runtime_error("unable to bind virtual inventory");
}
int lx = x - chunk->x * CHUNK_W;
int lz = z - chunk->z * CHUNK_D;
chunk->addBlockInventory(level->inventories->get(invid), lx, y, lz);
}
void BlocksController::unbindInventory(int x, int y, int z) {
auto chunk = chunks->getChunkByVoxel(x, y, z);
if (chunk == nullptr) {
throw std::runtime_error("block does not exists");
}
int lx = x - chunk->x * CHUNK_W;
int lz = z - chunk->z * CHUNK_D;
chunk->removeBlockInventory(lx, y, lz);
}
+4
View File
@@ -25,6 +25,7 @@ public:
int getParts() const;
int getPart() const;
int getTickRate() const;
int getTickId() const;
};
class BlocksController {
@@ -46,6 +47,9 @@ public:
void update(float delta);
void randomTick(int tickid, int parts);
void onBlocksTick(int tickid, int parts);
int64_t createBlockInventory(int x, int y, int z);
void bindInventory(int64_t invid, int x, int y, int z);
void unbindInventory(int x, int y, int z);
};
#endif // LOGIC_BLOCKS_CONTROLLER_H_
-3
View File
@@ -19,9 +19,6 @@ private:
uint padding;
std::unique_ptr<WorldGenerator> generator;
/* Average measured microseconds duration of loadVisible call */
int64_t avgDurationMcs = 1000;
/* Process one chunk: load it or calculate lights for it */
bool loadVisible();
bool buildLights(std::shared_ptr<Chunk> chunk);
+11 -9
View File
@@ -24,20 +24,22 @@ void LevelController::update(float delta, bool input, bool pause) {
player->update(delta, input, pause);
level->update();
chunks->update(settings.chunks.loadSpeed);
blocks->update(delta);
// erease null pointers
level->objects.remove_if([](Object* obj) { return obj == nullptr; });
// update all objects that needed
for(Object *obj : level->objects)
{
if(obj) {
if(obj->shouldUpdate) {
obj->update(delta);
if (!pause) {
// update all objects that needed
for(Object *obj : level->objects)
{
if(obj) {
if(obj->shouldUpdate) {
obj->update(delta);
}
}
}
}
}
blocks->update(delta);
}
}
void LevelController::onWorldSave() {
+1 -1
View File
@@ -306,7 +306,7 @@ void PlayerController::updateInteraction(){
if (def->grounded && !chunks->isSolidBlock(x, y-1, z)) {
chosenBlock = 0;
}
if (chosenBlock != vox->id) {
if (chosenBlock != vox->id && chosenBlock) {
chunks->set(x, y, z, chosenBlock, states);
lighting->onBlockSet(x,y,z, chosenBlock);
if (def->rt.funcsset.onplaced) {
-432
View File
@@ -1,432 +0,0 @@
#include "api_lua.h"
#include "scripting.h"
#include <glm/glm.hpp>
#include <iostream>
#include "../../files/files.h"
#include "../../physics/Hitbox.h"
#include "../../objects/Player.h"
#include "../../world/Level.h"
#include "../../world/World.h"
#include "../../content/Content.h"
#include "../../voxels/Block.h"
#include "../../voxels/Chunks.h"
#include "../../voxels/voxel.h"
#include "../../lighting/Lighting.h"
#include "../../logic/BlocksController.h"
#include "../../window/Window.h"
#include "../../engine.h"
inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
lua_pushinteger(L, x);
lua_pushinteger(L, y);
lua_pushinteger(L, z);
return 3;
}
inline void luaL_openlib(lua_State* L, const char* name, const luaL_Reg* libfuncs, int nup) {
lua_newtable(L);
luaL_setfuncs(L, libfuncs, nup);
lua_setglobal(L, name);
}
/* == file library == */
static int l_file_resolve(lua_State* L) {
std::string path = lua_tostring(L, 1);
fs::path resolved = scripting::engine->getPaths()->resolve(path);
lua_pushstring(L, resolved.u8string().c_str());
return 1;
}
static int l_file_read(lua_State* L) {
auto paths = scripting::engine->getPaths();
fs::path path = paths->resolve(lua_tostring(L, 1));
if (fs::is_regular_file(path)) {
lua_pushstring(L, files::read_string(path).c_str());
return 1;
}
return luaL_error(L, "file does not exists '%s'", path.u8string().c_str());
}
static int l_file_write(lua_State* L) {
auto paths = scripting::engine->getPaths();
fs::path path = paths->resolve(lua_tostring(L, 1));
const char* text = lua_tostring(L, 2);
files::write_string(path, text);
return 1;
}
static int l_file_exists(lua_State* L) {
auto paths = scripting::engine->getPaths();
fs::path path = paths->resolve(lua_tostring(L, 1));
lua_pushboolean(L, fs::exists(path));
return 1;
}
static int l_file_isfile(lua_State* L) {
auto paths = scripting::engine->getPaths();
fs::path path = paths->resolve(lua_tostring(L, 1));
lua_pushboolean(L, fs::is_regular_file(path));
return 1;
}
static int l_file_isdir(lua_State* L) {
auto paths = scripting::engine->getPaths();
fs::path path = paths->resolve(lua_tostring(L, 1));
lua_pushboolean(L, fs::is_directory(path));
return 1;
}
static int l_file_length(lua_State* L) {
auto paths = scripting::engine->getPaths();
fs::path path = paths->resolve(lua_tostring(L, 1));
if (fs::exists(path)){
lua_pushinteger(L, fs::file_size(path));
} else {
lua_pushinteger(L, -1);
}
return 1;
}
static int l_file_mkdir(lua_State* L) {
auto paths = scripting::engine->getPaths();
fs::path path = paths->resolve(lua_tostring(L, 1));
lua_pushboolean(L, fs::create_directory(path));
return 1;
}
static const luaL_Reg filelib [] = {
{"resolve", l_file_resolve},
{"read", l_file_read},
{"write", l_file_write},
{"exists", l_file_exists},
{"isfile", l_file_isfile},
{"isdir", l_file_isdir},
{"length", l_file_length},
{"mkdir", l_file_mkdir},
{NULL, NULL}
};
/* == time library == */
static int l_time_uptime(lua_State* L) {
lua_pushnumber(L, Window::time());
return 1;
}
static const luaL_Reg timelib [] = {
{"uptime", l_time_uptime},
{NULL, NULL}
};
/* == pack library == */
static int l_pack_get_folder(lua_State* L) {
std::string packName = lua_tostring(L, 1);
if (packName == "core") {
auto folder = scripting::engine->getPaths()
->getResources().u8string()+"/";
lua_pushstring(L, folder.c_str());
return 1;
}
for (auto& pack : scripting::engine->getContentPacks()) {
if (pack.id == packName) {
lua_pushstring(L, (pack.folder.u8string()+"/").c_str());
return 1;
}
}
lua_pushstring(L, "");
return 1;
}
static const luaL_Reg packlib [] = {
{"get_folder", l_pack_get_folder},
{NULL, NULL}
};
/* == world library == */
static int l_world_get_total_time(lua_State* L) {
lua_pushnumber(L, scripting::level->world->totalTime);
return 1;
}
static int l_world_get_day_time(lua_State* L) {
lua_pushnumber(L, scripting::level->world->daytime);
return 1;
}
static int l_world_set_day_time(lua_State* L) {
double value = lua_tonumber(L, 1);
scripting::level->world->daytime = fmod(value, 1.0);
return 0;
}
static int l_world_get_seed(lua_State* L) {
lua_pushinteger(L, scripting::level->world->getSeed());
return 1;
}
static const luaL_Reg worldlib [] = {
{"get_total_time", l_world_get_total_time},
{"get_day_time", l_world_get_day_time},
{"set_day_time", l_world_set_day_time},
{"get_seed", l_world_get_seed},
{NULL, NULL}
};
/* == player library ==*/
static int l_player_get_pos(lua_State* L) {
int playerid = lua_tointeger(L, 1);
if (playerid != 1)
return 0;
glm::vec3 pos = scripting::level->player->hitbox->position;
lua_pushnumber(L, pos.x);
lua_pushnumber(L, pos.y);
lua_pushnumber(L, pos.z);
return 3;
}
static int l_player_get_rot(lua_State* L) {
int playerid = lua_tointeger(L, 1);
if (playerid != 1)
return 0;
glm::vec2 rot = scripting::level->player->cam;
lua_pushnumber(L, rot.x);
lua_pushnumber(L, rot.y);
return 2;
}
static int l_player_set_rot(lua_State* L) {
int playerid = lua_tointeger(L, 1);
if (playerid != 1)
return 0;
double x = lua_tonumber(L, 2);
double y = lua_tonumber(L, 3);
glm::vec2& cam = scripting::level->player->cam;
cam.x = x;
cam.y = y;
return 0;
}
static int l_player_set_pos(lua_State* L) {
int playerid = lua_tointeger(L, 1);
if (playerid != 1)
return 0;
double x = lua_tonumber(L, 2);
double y = lua_tonumber(L, 3);
double z = lua_tonumber(L, 4);
scripting::level->player->hitbox->position = glm::vec3(x, y, z);
return 0;
}
static const luaL_Reg playerlib [] = {
{"get_pos", l_player_get_pos},
{"set_pos", l_player_set_pos},
{"get_rot", l_player_get_rot},
{"set_rot", l_player_set_rot},
{NULL, NULL}
};
/* == blocks-related functions == */
static int l_block_name(lua_State* L) {
int id = lua_tointeger(L, 1);
auto def = scripting::content->getIndices()->getBlockDef(id);
lua_pushstring(L, def->name.c_str());
return 1;
}
static int l_is_solid_at(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
lua_pushboolean(L, scripting::level->chunks->isSolidBlock(x, y, z));
return 1;
}
static int l_blocks_count(lua_State* L) {
lua_pushinteger(L, scripting::content->getIndices()->countBlockDefs());
return 1;
}
static int l_block_index(lua_State* L) {
auto name = lua_tostring(L, 1);
lua_pushinteger(L, scripting::content->requireBlock(name)->rt.id);
return 1;
}
static int l_set_block(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
int id = lua_tointeger(L, 4);
int states = lua_tointeger(L, 5);
bool noupdate = lua_toboolean(L, 6);
scripting::level->chunks->set(x, y, z, id, states);
scripting::level->lighting->onBlockSet(x,y,z, id);
if (!noupdate)
scripting::blocks->updateSides(x, y, z);
return 0;
}
static int l_get_block(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
int id = vox == nullptr ? -1 : vox->id;
lua_pushinteger(L, id);
return 1;
}
static int l_get_block_x(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua_pushivec3(L, 1, 0, 0);
}
auto def = scripting::level->content->getIndices()->getBlockDef(vox->id);
if (!def->rotatable) {
return lua_pushivec3(L, 1, 0, 0);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua_pushivec3(L, rot.axisX.x, rot.axisX.y, rot.axisX.z);
}
}
static int l_get_block_y(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua_pushivec3(L, 0, 1, 0);
}
auto def = scripting::level->content->getIndices()->getBlockDef(vox->id);
if (!def->rotatable) {
return lua_pushivec3(L, 0, 1, 0);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua_pushivec3(L, rot.axisY.x, rot.axisY.y, rot.axisY.z);
}
}
static int l_get_block_z(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua_pushivec3(L, 0, 0, 1);
}
auto def = scripting::level->content->getIndices()->getBlockDef(vox->id);
if (!def->rotatable) {
return lua_pushivec3(L, 0, 0, 1);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua_pushivec3(L, rot.axisZ.x, rot.axisZ.y, rot.axisZ.z);
}
}
static int l_get_block_states(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
int states = vox == nullptr ? 0 : vox->states;
lua_pushinteger(L, states);
return 1;
}
static int l_get_block_user_bits(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
int offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET;
int bits = lua_tointeger(L, 5);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
lua_pushinteger(L, 0);
return 1;
}
uint mask = ((1 << bits) - 1) << offset;
uint data = (vox->states & mask) >> offset;
lua_pushinteger(L, data);
return 1;
}
static int l_set_block_user_bits(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
int offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET;
int bits = lua_tointeger(L, 5);
uint mask = ((1 << bits) - 1) << offset;
int value = (lua_tointeger(L, 6) << offset) & mask;
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return 0;
}
vox->states = (vox->states & (~mask)) | value;
return 0;
}
static int l_is_replaceable_at(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
lua_pushboolean(L, scripting::level->chunks->isReplaceableBlock(x, y, z));
return 1;
}
// Modified version of luaB_print from lbaselib.c
static int l_print(lua_State* L) {
int n = lua_gettop(L); /* number of arguments */
lua_getglobal(L, "tostring");
for (int i=1; i<=n; i++) {
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
const char* s = lua_tostring(L, -1); /* get result */
if (s == NULL)
return luaL_error(L, LUA_QL("tostring") " must return a string to "
LUA_QL("print"));
if (i > 1)
std::cout << "\t";
std::cout << s;
lua_pop(L, 1); /* pop result */
}
std::cout << std::endl;
return 0;
}
#define lua_addfunc(L, FUNC, NAME) (lua_pushcfunction(L, FUNC),\
lua_setglobal(L, NAME))
void apilua::create_funcs(lua_State* L) {
luaL_openlib(L, "pack", packlib, 0);
luaL_openlib(L, "world", worldlib, 0);
luaL_openlib(L, "player", playerlib, 0);
luaL_openlib(L, "time", timelib, 0);
luaL_openlib(L, "file", filelib, 0);
lua_addfunc(L, l_print, "print");
lua_addfunc(L, l_block_index, "block_index");
lua_addfunc(L, l_block_name, "block_name");
lua_addfunc(L, l_blocks_count, "blocks_count");
lua_addfunc(L, l_is_solid_at, "is_solid_at");
lua_addfunc(L, l_is_replaceable_at, "is_replaceable_at");
lua_addfunc(L, l_set_block, "set_block");
lua_addfunc(L, l_get_block, "get_block");
lua_addfunc(L, l_get_block_x, "get_block_X");
lua_addfunc(L, l_get_block_y, "get_block_Y");
lua_addfunc(L, l_get_block_z, "get_block_Z");
lua_addfunc(L, l_get_block_states, "get_block_states");
lua_addfunc(L, l_get_block_user_bits, "get_block_user_bits");
lua_addfunc(L, l_set_block_user_bits, "set_block_user_bits");
}
-14
View File
@@ -1,14 +0,0 @@
#ifndef LOGIC_SCRIPTING_API_LUA_H_
#define LOGIC_SCRIPTING_API_LUA_H_
#include <lua.hpp>
#ifndef LUAJIT_VERSION
#pragma message("better use LuaJIT instead of plain Lua")
#endif // LUAJIT_VERSION
namespace apilua {
extern void create_funcs(lua_State* L);
}
#endif // LOGIC_SCRIPTING_API_LUA_H_
+276
View File
@@ -0,0 +1,276 @@
#include "LuaState.h"
#include <iostream>
#include "lua_util.h"
#include "api_lua.h"
#include "libgui.h"
#include "libinventory.h"
#include "../../../util/stringutil.h"
lua::luaerror::luaerror(const std::string& message) : std::runtime_error(message) {
}
lua::LuaState::LuaState() {
L = luaL_newstate();
if (L == nullptr) {
throw lua::luaerror("could not to initialize Lua");
}
// Allowed standard libraries
luaopen_base(L);
luaopen_math(L);
luaopen_string(L);
luaopen_table(L);
luaopen_debug(L);
luaopen_jit(L);
luaopen_bit(L);
std::cout << LUA_VERSION << std::endl;
std::cout << LUAJIT_VERSION << std::endl;
createFuncs();
lua_pushvalue(L, LUA_GLOBALSINDEX);
setglobal(envName(0));
}
const std::string lua::LuaState::envName(int env) const {
return "_ENV"+util::mangleid(env);
}
lua::LuaState::~LuaState() {
lua_close(L);
}
void lua::LuaState::logError(const std::string& text) {
std::cerr << text << std::endl;
}
void lua::LuaState::addfunc(const std::string& name, lua_CFunction func) {
lua_pushcfunction(L, func);
lua_setglobal(L, name.c_str());
}
bool lua::LuaState::getglobal(const std::string& name) {
lua_getglobal(L, name.c_str());
if (lua_isnil(L, lua_gettop(L))) {
lua_pop(L, lua_gettop(L));
return false;
}
return true;
}
bool lua::LuaState::hasglobal(const std::string& name) {
lua_getglobal(L, name.c_str());
if (lua_isnil(L, lua_gettop(L))) {
lua_pop(L, lua_gettop(L));
return false;
}
lua_pop(L, lua_gettop(L));
return true;
}
void lua::LuaState::setglobal(const std::string& name) {
lua_setglobal(L, name.c_str());
}
bool lua::LuaState::rename(const std::string& from, const std::string& to) {
const char* src = from.c_str();
lua_getglobal(L, src);
if (lua_isnil(L, lua_gettop(L))) {
lua_pop(L, lua_gettop(L));
return false;
}
lua_setglobal(L, to.c_str());
// remove previous
lua_pushnil(L);
lua_setglobal(L, src);
return true;
}
void lua::LuaState::remove(const std::string& name) {
lua_pushnil(L);
lua_setglobal(L, name.c_str());
}
void lua::LuaState::createFuncs() {
openlib("pack", packlib, 0);
openlib("world", worldlib, 0);
openlib("player", playerlib, 0);
openlib("inventory", inventorylib, 0);
openlib("item", itemlib, 0);
openlib("time", timelib, 0);
openlib("file", filelib, 0);
openlib("gui", guilib, 0);
addfunc("print", lua_wrap_errors<l_print>);
addfunc("block_index", lua_wrap_errors<l_block_index>);
addfunc("block_name", lua_wrap_errors<l_block_name>);
addfunc("blocks_count", lua_wrap_errors<l_blocks_count>);
addfunc("is_solid_at", lua_wrap_errors<l_is_solid_at>);
addfunc("is_replaceable_at", lua_wrap_errors<l_is_replaceable_at>);
addfunc("set_block", lua_wrap_errors<l_set_block>);
addfunc("get_block", lua_wrap_errors<l_get_block>);
addfunc("get_block_X", lua_wrap_errors<l_get_block_x>);
addfunc("get_block_Y", lua_wrap_errors<l_get_block_y>);
addfunc("get_block_Z", lua_wrap_errors<l_get_block_z>);
addfunc("get_block_states", lua_wrap_errors<l_get_block_states>);
addfunc("set_block_states", lua_wrap_errors<l_set_block_states>);
addfunc("get_block_rotation", lua_wrap_errors<l_get_block_rotation>);
addfunc("set_block_rotation", lua_wrap_errors<l_set_block_rotation>);
addfunc("get_block_user_bits", lua_wrap_errors<l_get_block_user_bits>);
addfunc("set_block_user_bits", lua_wrap_errors<l_set_block_user_bits>);
}
void lua::LuaState::loadbuffer(int env, const std::string& src, const std::string& file) {
if (luaL_loadbuffer(L, src.c_str(), src.length(), file.c_str())) {
throw lua::luaerror(lua_tostring(L, -1));
}
if (env && getglobal(envName(env))) {
lua_setfenv(L, -2);
}
}
int lua::LuaState::call(int argc) {
if (lua_pcall(L, argc, LUA_MULTRET, 0)) {
throw lua::luaerror(lua_tostring(L, -1));
}
return 1;
}
int lua::LuaState::callNoThrow(int argc) {
if (lua_pcall(L, argc, LUA_MULTRET, 0)) {
logError(lua_tostring(L, -1));
return 0;
}
return 1;
}
int lua::LuaState::eval(int env, const std::string& src, const std::string& file) {
auto srcText = "return ("+src+")";
loadbuffer(env, srcText, file);
return call(0);
}
int lua::LuaState::execute(int env, const std::string& src, const std::string& file) {
loadbuffer(env, src, file);
return callNoThrow(0);
}
int lua::LuaState::gettop() const {
return lua_gettop(L);
}
int lua::LuaState::pushinteger(luaint x) {
lua_pushinteger(L, x);
return 1;
}
int lua::LuaState::pushnumber(luanumber x) {
lua_pushnumber(L, x);
return 1;
}
int lua::LuaState::pushivec3(luaint x, luaint y, luaint z) {
lua::pushivec3(L, x, y, z);
return 3;
}
int lua::LuaState::pushstring(const std::string& str) {
lua_pushstring(L, str.c_str());
return 1;
}
int lua::LuaState::pushenv(int env) {
if (getglobal(envName(env))) {
return 1;
}
return 0;
}
int lua::LuaState::pushvalue(int idx) {
lua_pushvalue(L, idx);
return 1;
}
int lua::LuaState::pushglobals() {
lua_pushvalue(L, LUA_GLOBALSINDEX);
return 1;
}
void lua::LuaState::pop(int n) {
lua_pop(L, n);
}
int lua::LuaState::pushnil() {
lua_pushnil(L);
return 1;
}
bool lua::LuaState::getfield(const std::string& name) {
lua_getfield(L, -1, name.c_str());
if (lua_isnil(L, -1)) {
lua_pop(L, -1);
return false;
}
return true;
}
void lua::LuaState::setfield(const std::string& name, int idx) {
lua_setfield(L, idx, name.c_str());
}
bool lua::LuaState::toboolean(int idx) {
return lua_toboolean(L, idx);
}
lua::luaint lua::LuaState::tointeger(int idx) {
return lua_tointeger(L, idx);
}
lua::luanumber lua::LuaState::tonumber(int idx) {
return lua_tonumber(L, idx);
}
void lua::LuaState::openlib(const std::string& name, const luaL_Reg* libfuncs, int nup) {
lua_newtable(L);
luaL_setfuncs(L, libfuncs, nup);
lua_setglobal(L, name.c_str());
}
const std::string lua::LuaState::storeAnonymous() {
auto funcId = uintptr_t(lua_topointer(L, lua_gettop(L)));
auto funcName = "F$"+util::mangleid(funcId);
lua_setglobal(L, funcName.c_str());
return funcName;
}
int lua::LuaState::createEnvironment(int parent) {
int id = nextEnvironment++;
// local env = {}
lua_createtable(L, 0, 1);
// setmetatable(env, {__index=_G})
lua_createtable(L, 0, 1);
if (parent == 0 || true) {
lua_pushvalue(L, LUA_GLOBALSINDEX);
} else {
if (pushenv(parent) == 0) {
lua_pushvalue(L, LUA_GLOBALSINDEX);
}
}
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
// envname = env
setglobal(envName(id));
return id;
}
void lua::LuaState::removeEnvironment(int id) {
lua_pushnil(L);
setglobal(envName(id));
}
+63
View File
@@ -0,0 +1,63 @@
#ifndef LOGIC_SCRIPTING_LUA_STATE_H_
#define LOGIC_SCRIPTING_LUA_STATE_H_
#include "lua_commons.h"
#include <string>
#include <stdexcept>
#ifndef LUAJIT_VERSION
#error LuaJIT required
#endif
namespace lua {
class luaerror : public std::runtime_error {
public:
luaerror(const std::string& message);
};
class LuaState {
lua_State* L;
int nextEnvironment = 1;
void logError(const std::string& text);
void initEnvironment();
public:
LuaState();
~LuaState();
const std::string envName(int env) const;
void loadbuffer(int env, const std::string& src, const std::string& file);
int gettop() const;
int pushivec3(luaint x, luaint y, luaint z);
int pushinteger(luaint x);
int pushnumber(luanumber x);
int pushstring(const std::string& str);
int pushenv(int env);
int pushvalue(int idx);
int pushnil();
int pushglobals();
void pop(int n=1);
bool getfield(const std::string& name);
void setfield(const std::string& name, int idx=-2);
bool toboolean(int idx);
luaint tointeger(int idx);
luanumber tonumber(int idx);
int call(int argc);
int callNoThrow(int argc);
int execute(int env, const std::string& src, const std::string& file="<string>");
int eval(int env, const std::string& src, const std::string& file="<eval>");
void openlib(const std::string& name, const luaL_Reg* libfuncs, int nup);
void addfunc(const std::string& name, lua_CFunction func);
bool getglobal(const std::string& name);
void setglobal(const std::string& name);
bool hasglobal(const std::string& name);
bool rename(const std::string& from, const std::string& to);
void remove(const std::string& name);;
void createFuncs();
int createEnvironment(int parent);
void removeEnvironment(int id);
const std::string storeAnonymous();
};
}
#endif // LOGIC_SCRIPTING_LUA_STATE_H_
+457
View File
@@ -0,0 +1,457 @@
#include "api_lua.h"
#include "../scripting.h"
#include "lua_util.h"
#include <glm/glm.hpp>
#include <iostream>
#include "../../../files/files.h"
#include "../../../physics/Hitbox.h"
#include "../../../objects/Player.h"
#include "../../../world/Level.h"
#include "../../../world/World.h"
#include "../../../content/Content.h"
#include "../../../voxels/Block.h"
#include "../../../voxels/Chunks.h"
#include "../../../voxels/voxel.h"
#include "../../../voxels/Chunk.h"
#include "../../../items/ItemDef.h"
#include "../../../items/Inventory.h"
#include "../../../items/Inventories.h"
#include "../../../lighting/Lighting.h"
#include "../../../logic/BlocksController.h"
#include "../../../window/Window.h"
#include "../../../engine.h"
fs::path resolve_path(lua_State* L, const std::string& path) {
try {
return scripting::engine->getPaths()->resolve(path);
} catch (const files_access_error& err) {
luaL_error(L, err.what());
abort(); // unreachable
}
}
/* == file library == */
int l_file_resolve(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1));
lua_pushstring(L, path.u8string().c_str());
return 1;
}
int l_file_read(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1));
if (fs::is_regular_file(path)) {
lua_pushstring(L, files::read_string(path).c_str());
return 1;
}
return luaL_error(L, "file does not exists '%s'", path.u8string().c_str());
}
int l_file_write(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1));
const char* text = lua_tostring(L, 2);
files::write_string(path, text);
return 1;
}
int l_file_exists(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1));
lua_pushboolean(L, fs::exists(path));
return 1;
}
int l_file_isfile(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1));
lua_pushboolean(L, fs::is_regular_file(path));
return 1;
}
int l_file_isdir(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1));
lua_pushboolean(L, fs::is_directory(path));
return 1;
}
int l_file_length(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1));
if (fs::exists(path)){
lua_pushinteger(L, fs::file_size(path));
} else {
lua_pushinteger(L, -1);
}
return 1;
}
int l_file_mkdir(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1));
lua_pushboolean(L, fs::create_directory(path));
return 1;
}
/* == time library == */
int l_time_uptime(lua_State* L) {
lua_pushnumber(L, Window::time());
return 1;
}
int l_time_delta(lua_State* L) {
lua_pushnumber(L, scripting::engine->getDelta());
return 1;
}
/* == pack library == */
int l_pack_get_folder(lua_State* L) {
std::string packName = lua_tostring(L, 1);
if (packName == "core") {
auto folder = scripting::engine->getPaths()
->getResources().u8string()+"/";
lua_pushstring(L, folder.c_str());
return 1;
}
for (auto& pack : scripting::engine->getContentPacks()) {
if (pack.id == packName) {
lua_pushstring(L, (pack.folder.u8string()+"/").c_str());
return 1;
}
}
lua_pushstring(L, "");
return 1;
}
/* == world library == */
int l_world_get_total_time(lua_State* L) {
lua_pushnumber(L, scripting::level->world->totalTime);
return 1;
}
int l_world_get_day_time(lua_State* L) {
lua_pushnumber(L, scripting::level->world->daytime);
return 1;
}
int l_world_set_day_time(lua_State* L) {
double value = lua_tonumber(L, 1);
scripting::level->world->daytime = fmod(value, 1.0);
return 0;
}
int l_world_get_seed(lua_State* L) {
lua_pushinteger(L, scripting::level->world->getSeed());
return 1;
}
/* == player library ==*/
int l_player_get_pos(lua_State* L) {
int playerid = lua_tointeger(L, 1);
if (playerid != 1)
return 0;
glm::vec3 pos = scripting::level->player->hitbox->position;
lua_pushnumber(L, pos.x);
lua_pushnumber(L, pos.y);
lua_pushnumber(L, pos.z);
return 3;
}
int l_player_get_rot(lua_State* L) {
int playerid = lua_tointeger(L, 1);
if (playerid != 1)
return 0;
glm::vec2 rot = scripting::level->player->cam;
lua_pushnumber(L, rot.x);
lua_pushnumber(L, rot.y);
return 2;
}
int l_player_set_rot(lua_State* L) {
int playerid = lua_tointeger(L, 1);
if (playerid != 1)
return 0;
lua::luanumber x = lua_tonumber(L, 2);
lua::luanumber y = lua_tonumber(L, 3);
glm::vec2& cam = scripting::level->player->cam;
cam.x = x;
cam.y = y;
return 0;
}
int l_player_set_pos(lua_State* L) {
int playerid = lua_tointeger(L, 1);
if (playerid != 1)
return 0;
lua::luanumber x = lua_tonumber(L, 2);
lua::luanumber y = lua_tonumber(L, 3);
lua::luanumber z = lua_tonumber(L, 4);
scripting::level->player->hitbox->position = glm::vec3(x, y, z);
return 0;
}
int l_player_get_inv(lua_State* L) {
int playerid = lua_tointeger(L, 1);
if (playerid != 1)
return 0;
Player* player = scripting::level->player;
lua_pushinteger(L, player->getInventory()->getId());
lua_pushinteger(L, player->getChosenSlot());
return 2;
}
/* == item library == */
int l_item_name(lua_State* L) {
auto indices = scripting::content->getIndices();
lua::luaint id = lua_tointeger(L, 1);
if (id < 0 || size_t(id) >= indices->countItemDefs()) {
return 0;
}
auto def = indices->getItemDef(id);
lua_pushstring(L, def->name.c_str());
return 1;
}
int l_item_index(lua_State* L) {
auto name = lua_tostring(L, 1);
lua_pushinteger(L, scripting::content->requireItem(name).rt.id);
return 1;
}
int l_item_stack_size(lua_State* L) {
auto indices = scripting::content->getIndices();
lua::luaint id = lua_tointeger(L, 1);
if (id < 0 || size_t(id) >= indices->countItemDefs()) {
return 0;
}
auto def = indices->getItemDef(id);
lua_pushinteger(L, def->stackSize);
return 1;
}
int l_item_defs_count(lua_State* L) {
lua_pushinteger(L, scripting::indices->countItemDefs());
return 1;
}
/* == blocks-related functions == */
int l_block_name(lua_State* L) {
auto indices = scripting::content->getIndices();
lua::luaint id = lua_tointeger(L, 1);
if (id < 0 || size_t(id) >= indices->countBlockDefs()) {
return 0;
}
auto def = indices->getBlockDef(id);
lua_pushstring(L, def->name.c_str());
return 1;
}
int l_is_solid_at(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
lua_pushboolean(L, scripting::level->chunks->isSolidBlock(x, y, z));
return 1;
}
int l_blocks_count(lua_State* L) {
lua_pushinteger(L, scripting::indices->countBlockDefs());
return 1;
}
int l_block_index(lua_State* L) {
auto name = lua_tostring(L, 1);
lua_pushinteger(L, scripting::content->requireBlock(name).rt.id);
return 1;
}
int l_set_block(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
lua::luaint id = lua_tointeger(L, 4);
lua::luaint states = lua_tointeger(L, 5);
bool noupdate = lua_toboolean(L, 6);
if (id < 0 || size_t(id) >= scripting::indices->countBlockDefs()) {
return 0;
}
scripting::level->chunks->set(x, y, z, id, states);
scripting::level->lighting->onBlockSet(x,y,z, id);
if (!noupdate)
scripting::blocks->updateSides(x, y, z);
return 0;
}
int l_get_block(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
int id = vox == nullptr ? -1 : vox->id;
lua_pushinteger(L, id);
return 1;
}
int l_get_block_x(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua::pushivec3(L, 1, 0, 0);
}
auto def = scripting::level->content->getIndices()->getBlockDef(vox->id);
if (!def->rotatable) {
return lua::pushivec3(L, 1, 0, 0);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua::pushivec3(L, rot.axisX.x, rot.axisX.y, rot.axisX.z);
}
}
int l_get_block_y(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua::pushivec3(L, 0, 1, 0);
}
auto def = scripting::level->content->getIndices()->getBlockDef(vox->id);
if (!def->rotatable) {
return lua::pushivec3(L, 0, 1, 0);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua::pushivec3(L, rot.axisY.x, rot.axisY.y, rot.axisY.z);
}
}
int l_get_block_z(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua::pushivec3(L, 0, 0, 1);
}
auto def = scripting::level->content->getIndices()->getBlockDef(vox->id);
if (!def->rotatable) {
return lua::pushivec3(L, 0, 0, 1);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua::pushivec3(L, rot.axisZ.x, rot.axisZ.y, rot.axisZ.z);
}
}
int l_get_block_rotation(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
int rotation = vox == nullptr ? 0 : vox->rotation();
lua_pushinteger(L, rotation);
return 1;
}
int l_set_block_rotation(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
lua::luaint value = lua_tointeger(L, 4);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return 0;
}
vox->setRotation(value);
scripting::level->chunks->getChunkByVoxel(x, y, z)->setModified(true);
return 0;
}
int l_get_block_states(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
int states = vox == nullptr ? 0 : vox->states;
lua_pushinteger(L, states);
return 1;
}
int l_set_block_states(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
lua::luaint states = lua_tointeger(L, 4);
Chunk* chunk = scripting::level->chunks->getChunkByVoxel(x, y, z);
if (chunk == nullptr) {
return 0;
}
voxel* vox = scripting::level->chunks->get(x, y, z);
vox->states = states;
chunk->setModified(true);
return 0;
}
int l_get_block_user_bits(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
lua::luaint offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET;
lua::luaint bits = lua_tointeger(L, 5);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
lua_pushinteger(L, 0);
return 1;
}
uint mask = ((1 << bits) - 1) << offset;
uint data = (vox->states & mask) >> offset;
lua_pushinteger(L, data);
return 1;
}
int l_set_block_user_bits(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
lua::luaint offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET;
lua::luaint bits = lua_tointeger(L, 5);
uint mask = ((1 << bits) - 1) << offset;
lua::luaint value = (lua_tointeger(L, 6) << offset) & mask;
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return 0;
}
vox->states = (vox->states & (~mask)) | value;
return 0;
}
int l_is_replaceable_at(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
lua_pushboolean(L, scripting::level->chunks->isReplaceableBlock(x, y, z));
return 1;
}
int l_print(lua_State* L) {
int n = lua_gettop(L); /* number of arguments */
lua_getglobal(L, "tostring");
for (int i=1; i<=n; i++) {
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
const char* s = lua_tostring(L, -1); /* get result */
if (s == NULL)
return luaL_error(L, LUA_QL("tostring") " must return a string to "
LUA_QL("print"));
if (i > 1)
std::cout << "\t";
std::cout << s;
lua_pop(L, 1); /* pop result */
}
std::cout << std::endl;
return 0;
}
+112
View File
@@ -0,0 +1,112 @@
#ifndef LOGIC_SCRIPTING_API_LUA_H_
#define LOGIC_SCRIPTING_API_LUA_H_
#include <exception>
#include "lua_commons.h"
/* == file library == */
extern int l_file_resolve(lua_State* L);
extern int l_file_read(lua_State* L);
extern int l_file_write(lua_State* L);
extern int l_file_exists(lua_State* L);
extern int l_file_isfile(lua_State* L);
extern int l_file_isdir(lua_State* L);
extern int l_file_length(lua_State* L);
extern int l_file_mkdir(lua_State* L);
static const luaL_Reg filelib [] = {
{"resolve", lua_wrap_errors<l_file_resolve>},
{"read", lua_wrap_errors<l_file_read>},
{"write", lua_wrap_errors<l_file_write>},
{"exists", lua_wrap_errors<l_file_exists>},
{"isfile", lua_wrap_errors<l_file_isfile>},
{"isdir", lua_wrap_errors<l_file_isdir>},
{"length", lua_wrap_errors<l_file_length>},
{"mkdir", lua_wrap_errors<l_file_mkdir>},
{NULL, NULL}
};
/* == time library == */
extern int l_time_uptime(lua_State* L);
extern int l_time_delta(lua_State* L);
static const luaL_Reg timelib [] = {
{"uptime", lua_wrap_errors<l_time_uptime>},
{"delta", lua_wrap_errors<l_time_delta>},
{NULL, NULL}
};
/* == pack library == */
extern int l_pack_get_folder(lua_State* L);
static const luaL_Reg packlib [] = {
{"get_folder", lua_wrap_errors<l_pack_get_folder>},
{NULL, NULL}
};
/* == world library == */
extern int l_world_get_total_time(lua_State* L);
extern int l_world_get_day_time(lua_State* L);
extern int l_world_set_day_time(lua_State* L);
extern int l_world_get_seed(lua_State* L);
static const luaL_Reg worldlib [] = {
{"get_total_time", lua_wrap_errors<l_world_get_total_time>},
{"get_day_time", lua_wrap_errors<l_world_get_day_time>},
{"set_day_time", lua_wrap_errors<l_world_set_day_time>},
{"get_seed", lua_wrap_errors<l_world_get_seed>},
{NULL, NULL}
};
/* == player library ==*/
extern int l_player_get_pos(lua_State* L);
extern int l_player_get_rot(lua_State* L);
extern int l_player_set_rot(lua_State* L);
extern int l_player_set_pos(lua_State* L);
extern int l_player_get_inv(lua_State* L);
static const luaL_Reg playerlib [] = {
{"get_pos", lua_wrap_errors<l_player_get_pos>},
{"set_pos", lua_wrap_errors<l_player_set_pos>},
{"get_rot", lua_wrap_errors<l_player_get_rot>},
{"set_rot", lua_wrap_errors<l_player_set_rot>},
{"get_inventory", lua_wrap_errors<l_player_get_inv>},
{NULL, NULL}
};
/* == item library == */
extern int l_item_name(lua_State* L);
extern int l_item_index(lua_State* L);
extern int l_item_stack_size(lua_State* L);
extern int l_item_defs_count(lua_State* L);
static const luaL_Reg itemlib [] = {
{"index", lua_wrap_errors<l_item_index>},
{"name", lua_wrap_errors<l_item_name>},
{"stack_size", lua_wrap_errors<l_item_stack_size>},
{"defs_count", lua_wrap_errors<l_item_defs_count>},
{NULL, NULL}
};
/* == blocks-related functions == */
extern int l_block_name(lua_State* L);
extern int l_is_solid_at(lua_State* L);
extern int l_blocks_count(lua_State* L);
extern int l_block_index(lua_State* L);
extern int l_set_block(lua_State* L);
extern int l_get_block(lua_State* L);
extern int l_get_block_x(lua_State* L);
extern int l_get_block_y(lua_State* L);
extern int l_get_block_z(lua_State* L);
extern int l_get_block_states(lua_State* L);
extern int l_set_block_states(lua_State* L);
extern int l_get_block_rotation(lua_State* L);
extern int l_set_block_rotation(lua_State* L);
extern int l_get_block_user_bits(lua_State* L);
extern int l_set_block_user_bits(lua_State* L);
extern int l_is_replaceable_at(lua_State* L);
// Modified version of luaB_print from lbaselib.c
extern int l_print(lua_State* L);
#endif // LOGIC_SCRIPTING_API_LUA_H_
+110
View File
@@ -0,0 +1,110 @@
#include "libgui.h"
#include <iostream>
#include "../scripting.h"
#include "lua_util.h"
#include "../../../engine.h"
#include "../../../assets/Assets.h"
#include "../../../frontend/gui/UINode.h"
#include "../../../frontend/gui/controls.h"
#include "../../../frontend/UiDocument.h"
#include "../../../util/stringutil.h"
static gui::UINode* getDocumentNode(lua_State* L, const std::string& name, const std::string& nodeName) {
auto doc = scripting::engine->getAssets()->getLayout(name);
if (doc == nullptr) {
luaL_error(L, "document '%s' not found", name.c_str());
}
auto node = doc->get(nodeName);
if (node == nullptr) {
luaL_error(L, "document '%s' has no element with id '%s'", name.c_str(), nodeName.c_str());
}
return node.get();
}
static bool getattr(lua_State* L, gui::Button* button, const std::string& attr) {
if (button == nullptr)
return false;
if (attr == "text") {
lua_pushstring(L, util::wstr2str_utf8(button->getText()).c_str());
return true;
}
return false;
}
static bool getattr(lua_State* L, gui::Label* label, const std::string& attr) {
if (label == nullptr)
return false;
if (attr == "text") {
lua_pushstring(L, util::wstr2str_utf8(label->getText()).c_str());
return true;
}
return false;
}
static bool setattr(lua_State* L, gui::Button* button, const std::string& attr) {
if (button == nullptr)
return false;
if (attr == "text") {
button->setText(util::str2wstr_utf8(lua_tostring(L, 4)));
return true;
}
return false;
}
static bool setattr(lua_State* L, gui::Label* label, const std::string& attr) {
if (label == nullptr)
return false;
if (attr == "text") {
label->setText(util::str2wstr_utf8(lua_tostring(L, 4)));
return true;
}
return false;
}
int l_gui_getattr(lua_State* L) {
auto docname = lua_tostring(L, 1);
auto element = lua_tostring(L, 2);
const std::string attr = lua_tostring(L, 3);
auto node = getDocumentNode(L, docname, element);
if (attr == "color") {
return lua::pushcolor_arr(L, node->getColor());
} else if (attr == "pos") {
return lua::pushvec2_arr(L, node->getCoord());
} else if (attr == "size") {
return lua::pushvec2_arr(L, node->getSize());
}
if (getattr(L, dynamic_cast<gui::Button*>(node), attr))
return 1;
if (getattr(L, dynamic_cast<gui::Label*>(node), attr))
return 1;
return 0;
}
int l_gui_getviewport(lua_State* L) {
lua::pushvec2_arr(L, scripting::engine->getGUI()->getContainer()->getSize());
return 1;
}
int l_gui_setattr(lua_State* L) {
auto docname = lua_tostring(L, 1);
auto element = lua_tostring(L, 2);
const std::string attr = lua_tostring(L, 3);
auto node = getDocumentNode(L, docname, element);
if (attr == "pos") {
node->setCoord(lua::tovec2(L, 1));
} else if (attr == "size") {
node->setSize(lua::tovec2(L, 1));
} else {
if (setattr(L, dynamic_cast<gui::Button*>(node), attr))
return 0;
if (setattr(L, dynamic_cast<gui::Label*>(node), attr))
return 0;
}
return 0;
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef LOGIC_SCRIPTING_API_LIBGUI_H_
#define LOGIC_SCRIPTING_API_LIBGUI_H_
#include <lua.hpp>
extern int l_gui_getviewport(lua_State* L);
extern int l_gui_getattr(lua_State* L);
extern int l_gui_setattr(lua_State* L);
static const luaL_Reg guilib [] = {
{"get_viewport", l_gui_getviewport},
{"getattr", l_gui_getattr},
{"setattr", l_gui_setattr},
{NULL, NULL}
};
#endif // LOGIC_SCRIPTING_API_LIBGUI_H_
+92
View File
@@ -0,0 +1,92 @@
#include "libhud.h"
#include "LuaState.h"
#include <iostream>
#include <glm/glm.hpp>
#include "../scripting.h"
#include "../../../assets/Assets.h"
#include "../../../frontend/hud.h"
#include "../../../world/Level.h"
#include "../../../voxels/Chunks.h"
#include "../../../voxels/voxel.h"
#include "../../../voxels/Block.h"
#include "../../../content/Content.h"
#include "../../../logic/BlocksController.h"
#include "../../../items/Inventories.h"
#include "../../../engine.h"
#include "../../../frontend/UiDocument.h"
#include "../../../frontend/InventoryView.h"
namespace scripting {
extern Hud* hud;
}
int l_hud_open_inventory(lua_State* L) {
if (!scripting::hud->isInventoryOpen()) {
scripting::hud->openInventory();
}
return 0;
}
int l_hud_close_inventory(lua_State* L) {
if (scripting::hud->isInventoryOpen()) {
scripting::hud->closeInventory();
}
return 0;
}
int l_hud_open_block(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
luaL_error(L, "block does not exists at %d %d %d", x, y, z);
}
auto def = scripting::content->getIndices()->getBlockDef(vox->id);
auto assets = scripting::engine->getAssets();
auto layout = assets->getLayout(def->uiLayout);
if (layout == nullptr) {
luaL_error(L, "block '%s' has no ui layout", def->name.c_str());
}
auto id = scripting::blocks->createBlockInventory(x, y, z);
if (id == 0) {
luaL_error(L,
"block '%s' at %d %d %d has no inventory",
def->name.c_str(),
x, y, z
);
}
scripting::hud->openInventory(
glm::ivec3(x, y, z), layout, scripting::level->inventories->get(id)
);
lua_pushinteger(L, id);
lua_pushstring(L, def->uiLayout.c_str());
return 2;
}
UiDocument* require_layout(lua_State* L, const char* name) {
auto assets = scripting::engine->getAssets();
auto layout = assets->getLayout(name);
if (layout == nullptr) {
luaL_error(L, "layout '%s' is not found", name);
}
return layout;
}
int l_hud_open_permanent(lua_State* L) {
auto layout = require_layout(L, lua_tostring(L, 1));
scripting::hud->openPermanent(layout);
return 0;
}
int l_hud_close(lua_State* L) {
auto layout = require_layout(L, lua_tostring(L, 1));
scripting::hud->remove(layout->getRoot());
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef LOGIC_SCRIPTING_API_LIBHUD_H_
#define LOGIC_SCRIPTING_API_LIBHUD_H_
#include "lua_commons.h"
extern int l_hud_open_inventory(lua_State* L);
extern int l_hud_close_inventory(lua_State* L);
extern int l_hud_open_block(lua_State* L);
extern int l_hud_open_permanent(lua_State* L);
extern int l_hud_close(lua_State* L);
static const luaL_Reg hudlib [] = {
{"open_inventory", lua_wrap_errors<l_hud_open_inventory>},
{"close_inventory", lua_wrap_errors<l_hud_close_inventory>},
{"open_block", lua_wrap_errors<l_hud_open_block>},
{"open_permanent", lua_wrap_errors<l_hud_open_permanent>},
{"close", lua_wrap_errors<l_hud_close>},
{NULL, NULL}
};
#endif // LOGIC_SCRIPTING_API_LIBHUD_H_
+114
View File
@@ -0,0 +1,114 @@
#include "libinventory.h"
#include "lua_util.h"
#include "../scripting.h"
#include "../../../content/Content.h"
#include "../../../world/Level.h"
#include "../../../items/ItemStack.h"
#include "../../../items/Inventories.h"
#include "../../../logic/BlocksController.h"
static void validate_itemid(lua_State* L, itemid_t id) {
if (id >= scripting::indices->countItemDefs()) {
luaL_error(L, "invalid item id");
}
}
/* == inventory library == */
int l_inventory_get(lua_State* L) {
lua::luaint invid = lua_tointeger(L, 1);
lua::luaint slotid = lua_tointeger(L, 2);
auto inv = scripting::level->inventories->get(invid);
if (inv == nullptr) {
luaL_error(L, "inventory does not exists in runtime: %d", invid);
}
if (slotid < 0 || uint64_t(slotid) >= inv->size()) {
luaL_error(L, "slot index is out of range [0, inventory.size(invid)]");
}
ItemStack& item = inv->getSlot(slotid);
lua_pushinteger(L, item.getItemId());
lua_pushinteger(L, item.getCount());
return 2;
}
int l_inventory_set(lua_State* L) {
lua::luaint invid = lua_tointeger(L, 1);
lua::luaint slotid = lua_tointeger(L, 2);
lua::luaint itemid = lua_tointeger(L, 3);
lua::luaint count = lua_tointeger(L, 4);
validate_itemid(L, itemid);
auto inv = scripting::level->inventories->get(invid);
if (inv == nullptr) {
luaL_error(L, "inventory does not exists in runtime: %d", invid);
}
if (slotid < 0 || uint64_t(slotid) >= inv->size()) {
luaL_error(L, "slot index is out of range [0, inventory.size(invid)]");
}
ItemStack& item = inv->getSlot(slotid);
item.set(ItemStack(itemid, count));
return 0;
}
int l_inventory_size(lua_State* L) {
lua::luaint invid = lua_tointeger(L, 1);
auto inv = scripting::level->inventories->get(invid);
if (inv == nullptr) {
luaL_error(L, "inventory does not exists in runtime: %d", invid);
}
lua_pushinteger(L, inv->size());
return 1;
}
int l_inventory_add(lua_State* L) {
lua::luaint invid = lua_tointeger(L, 1);
lua::luaint itemid = lua_tointeger(L, 2);
lua::luaint count = lua_tointeger(L, 3);
validate_itemid(L, itemid);
auto inv = scripting::level->inventories->get(invid);
if (inv == nullptr) {
luaL_error(L, "inventory does not exists in runtime: %d", invid);
}
ItemStack item(itemid, count);
inv->move(item, scripting::indices);
lua_pushinteger(L, item.getCount());
return 1;
}
int l_inventory_get_block(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
int64_t id = scripting::blocks->createBlockInventory(x, y, z);
lua_pushinteger(L, id);
return 1;
}
int l_inventory_bind_block(lua_State* L) {
lua::luaint id = lua_tointeger(L, 1);
lua::luaint x = lua_tointeger(L, 2);
lua::luaint y = lua_tointeger(L, 3);
lua::luaint z = lua_tointeger(L, 4);
scripting::blocks->bindInventory(id, x, y, z);
return 0;
}
int l_inventory_unbind_block(lua_State* L) {
lua::luaint x = lua_tointeger(L, 1);
lua::luaint y = lua_tointeger(L, 2);
lua::luaint z = lua_tointeger(L, 3);
scripting::blocks->unbindInventory(x, y, z);
return 0;
}
int l_inventory_clone(lua_State* L) {
lua::luaint id = lua_tointeger(L, 1);
auto clone = scripting::level->inventories->clone(id);
if (clone == nullptr) {
lua_pushinteger(L, 0);
return 1;
}
lua_pushinteger(L, clone->getId());
return 1;
}
+27
View File
@@ -0,0 +1,27 @@
#ifndef LOGIC_SCRIPTING_API_LIBINVENTORY_H_
#define LOGIC_SCRIPTING_API_LIBINVENTORY_H_
#include "lua_commons.h"
extern int l_inventory_get(lua_State* L);
extern int l_inventory_set(lua_State* L);
extern int l_inventory_size(lua_State* L);
extern int l_inventory_add(lua_State* L);
extern int l_inventory_get_block(lua_State* L);
extern int l_inventory_bind_block(lua_State* L);
extern int l_inventory_unbind_block(lua_State* L);
extern int l_inventory_clone(lua_State* L);
static const luaL_Reg inventorylib [] = {
{"get", lua_wrap_errors<l_inventory_get>},
{"set", lua_wrap_errors<l_inventory_set>},
{"size", lua_wrap_errors<l_inventory_size>},
{"add", lua_wrap_errors<l_inventory_add>},
{"get_block", lua_wrap_errors<l_inventory_get_block>},
{"bind_block", lua_wrap_errors<l_inventory_bind_block>},
{"unbind_block", lua_wrap_errors<l_inventory_unbind_block>},
{"clone", lua_wrap_errors<l_inventory_clone>},
{NULL, NULL}
};
#endif // LOGIC_SCRIPTING_API_LIBINVENTORY_H_
+28
View File
@@ -0,0 +1,28 @@
#ifndef LOGIC_SCRIPTING_LUA_H_
#define LOGIC_SCRIPTING_LUA_H_
#include <lua.hpp>
#include <exception>
namespace lua {
using luaint = lua_Integer;
using luanumber = lua_Number;
}
template <lua_CFunction func> int lua_wrap_errors(lua_State *L) {
int result = 0;
try {
result = func(L);
}
// transform exception with description into lua_error
catch (std::exception &e) {
luaL_error(L, e.what());
}
// Rethrow any other exception (lua error for example)
catch (...) {
throw;
}
return result;
}
#endif // LOGIC_SCRIPTING_LUA_H_
+98
View File
@@ -0,0 +1,98 @@
#ifndef LOGIC_SCRIPTING_LUA_UTIL_H_
#define LOGIC_SCRIPTING_LUA_UTIL_H_
#include <lua.hpp>
#include <glm/glm.hpp>
#include "LuaState.h"
namespace lua {
inline int pushivec3(lua_State* L, luaint x, luaint y, luaint z) {
lua_pushinteger(L, x);
lua_pushinteger(L, y);
lua_pushinteger(L, z);
return 3;
}
inline int pushvec3(lua_State* L, glm::vec3 vec) {
lua_pushnumber(L, vec.x);
lua_pushnumber(L, vec.y);
lua_pushnumber(L, vec.z);
return 3;
}
inline int pushvec4(lua_State* L, glm::vec4 vec) {
lua_pushnumber(L, vec.x);
lua_pushnumber(L, vec.y);
lua_pushnumber(L, vec.z);
lua_pushnumber(L, vec.w);
return 4;
}
inline int pushvec2_arr(lua_State* L, glm::vec2 vec) {
lua_createtable(L, 2, 0);
lua_getglobal(L, "vec2_mt");
lua_setmetatable(L, -2);
lua_pushnumber(L, vec.x);
lua_rawseti(L, -2, 1);
lua_pushnumber(L, vec.y);
lua_rawseti(L, -2, 2);
return 1;
}
inline int pushvec3_arr(lua_State* L, glm::vec3 vec) {
lua_createtable(L, 3, 0);
lua_getglobal(L, "vec3_mt");
lua_setmetatable(L, -2);
lua_pushnumber(L, vec.x);
lua_rawseti(L, -2, 1);
lua_pushnumber(L, vec.y);
lua_rawseti(L, -2, 2);
lua_pushnumber(L, vec.z);
lua_rawseti(L, -2, 3);
return 1;
}
inline int pushvec4_arr(lua_State* L, glm::vec4 vec) {
lua_createtable(L, 4, 0);
lua_getglobal(L, "vec4_mt");
lua_setmetatable(L, -2);
lua_pushnumber(L, vec.x);
lua_rawseti(L, -2, 1);
lua_pushnumber(L, vec.y);
lua_rawseti(L, -2, 2);
lua_pushnumber(L, vec.z);
lua_rawseti(L, -2, 3);
lua_pushnumber(L, vec.w);
lua_rawseti(L, -2, 4);
return 1;
}
inline int pushcolor_arr(lua_State* L, glm::vec4 vec) {
lua_createtable(L, 4, 0);
lua_getglobal(L, "color_mt");
lua_setmetatable(L, -2);
lua_pushinteger(L, vec.x*255);
lua_rawseti(L, -2, 1);
lua_pushinteger(L, vec.y*255);
lua_rawseti(L, -2, 2);
lua_pushinteger(L, vec.z*255);
lua_rawseti(L, -2, 3);
lua_pushinteger(L, vec.w*255);
lua_rawseti(L, -2, 4);
return 1;
}
inline glm::vec2 tovec2(lua_State* L, int idx) {
lua_rawgeti(L, idx, 1);
lua::luanumber x = lua_tonumber(L, -1); lua_pop(L, -1);
lua_rawgeti(L, idx, 1);
lua::luanumber y = lua_tonumber(L, -1); lua_pop(L, -1);
return glm::vec2(x, y);
}
}
#endif // LOGIC_SCRIPTING_LUA_UTIL_H_
+174 -146
View File
@@ -2,7 +2,6 @@
#include <iostream>
#include <stdexcept>
#include <lua.hpp>
#include "../../content/ContentPack.h"
#include "../../files/engine_paths.h"
@@ -11,55 +10,38 @@
#include "../../world/Level.h"
#include "../../voxels/Block.h"
#include "../../items/ItemDef.h"
#include "../../items/Inventory.h"
#include "../../logic/BlocksController.h"
#include "../../frontend/UiDocument.h"
#include "../../engine.h"
#include "api_lua.h"
#include "lua/LuaState.h"
#include "../../util/stringutil.h"
#include "../../util/timeutil.h"
using namespace scripting;
namespace scripting {
extern lua_State* L;
extern lua::LuaState* state;
}
Engine* scripting::engine = nullptr;
lua_State* scripting::L = nullptr;
lua::LuaState* scripting::state = nullptr;
Level* scripting::level = nullptr;
const Content* scripting::content = nullptr;
const ContentIndices* scripting::indices = nullptr;
BlocksController* scripting::blocks = nullptr;
static void handleError(lua_State* L) {
std::cerr << "lua error: " << lua_tostring(L,-1) << std::endl;
Environment::Environment(int env) : env(env) {
}
inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
lua_pushinteger(L, x);
lua_pushinteger(L, y);
lua_pushinteger(L, z);
return 3;
}
void delete_global(lua_State* L, const char* name) {
lua_pushnil(L);
lua_setglobal(L, name);
}
bool rename_global(lua_State* L, const char* src, const char* dst) {
lua_getglobal(L, src);
if (lua_isnil(L, lua_gettop(L))) {
lua_pop(L, lua_gettop(L));
return false;
Environment::~Environment() {
if (env) {
state->removeEnvironment(env);
}
lua_setglobal(L, dst);
delete_global(L, src);
return true;
}
int call_func(lua_State* L, int argc, const std::string& name) {
if (lua_pcall(L, argc, LUA_MULTRET, 0)) {
handleError(L);
return 0;
}
return 1;
int Environment::getId() const {
return env;
}
void load_script(fs::path name) {
@@ -67,203 +49,249 @@ void load_script(fs::path name) {
fs::path file = paths->getResources()/fs::path("scripts")/name;
std::string src = files::read_string(file);
if (luaL_loadbuffer(L, src.c_str(), src.length(), file.u8string().c_str())) {
handleError(L);
return;
}
call_func(L, 0, file.u8string());
state->execute(0, src, file.u8string());
}
void scripting::initialize(Engine* engine) {
scripting::engine = engine;
L = luaL_newstate();
if (L == nullptr) {
throw std::runtime_error("could not to initialize Lua");
}
// Allowed standard libraries
luaopen_base(L);
luaopen_math(L);
luaopen_string(L);
luaopen_table(L);
// io-manipulations will be implemented via api functions
std::cout << LUA_VERSION << std::endl;
# ifdef LUAJIT_VERSION
luaopen_jit(L);
std::cout << LUAJIT_VERSION << std::endl;
# endif // LUAJIT_VERSION
apilua::create_funcs(L);
state = new lua::LuaState();
load_script(fs::path("stdlib.lua"));
}
std::unique_ptr<Environment> scripting::create_environment(int parent) {
return std::make_unique<Environment>(state->createEnvironment(parent));
}
std::unique_ptr<Environment> scripting::create_pack_environment(const ContentPack& pack) {
int id = state->createEnvironment(0);
state->pushenv(id);
state->pushvalue(-1);
state->setfield("PACK_ENV");
state->pushstring(pack.id);
state->setfield("PACK_ID");
state->pop();
return std::make_unique<Environment>(id);
}
std::unique_ptr<Environment> scripting::create_doc_environment(int parent, const std::string& name) {
int id = state->createEnvironment(parent);
state->pushenv(id);
state->pushvalue(-1);
state->setfield("DOC_ENV");
state->pushstring(name.c_str());
state->setfield("DOC_NAME");
if (state->getglobal("Document")) {
if (state->getfield("new")) {
state->pushstring(name.c_str());
if (state->callNoThrow(1)) {
state->setfield("document", -3);
}
}
state->pop();
}
state->pop();
return std::make_unique<Environment>(id);
}
void scripting::on_world_load(Level* level, BlocksController* blocks) {
scripting::level = level;
scripting::content = level->content;
scripting::indices = level->content->getIndices();
scripting::blocks = blocks;
load_script("world.lua");
for (auto& pack : scripting::engine->getContentPacks()) {
std::string name = pack.id+".worldopen";
lua_getglobal(L, name.c_str());
if (lua_isnil(L, lua_gettop(L))) {
lua_pop(L, lua_gettop(L));
continue;
if (state->getglobal(pack.id+".worldopen")) {
state->callNoThrow(0);
}
call_func(L, 0, name);
}
}
void scripting::on_world_save() {
for (auto& pack : scripting::engine->getContentPacks()) {
std::string name = pack.id+".worldsave";
lua_getglobal(L, name.c_str());
if (lua_isnil(L, lua_gettop(L))) {
lua_pop(L, lua_gettop(L));
continue;
if (state->getglobal(pack.id+".worldsave")) {
state->callNoThrow(0);
}
call_func(L, 0, name);
}
}
void scripting::on_world_quit() {
for (auto& pack : scripting::engine->getContentPacks()) {
std::string name = pack.id+".worldquit";
lua_getglobal(L, name.c_str());
if (lua_isnil(L, lua_gettop(L))) {
lua_pop(L, lua_gettop(L));
continue;
if (state->getglobal(pack.id+".worldquit")) {
state->callNoThrow(0);
}
call_func(L, 0, name);
}
scripting::level = nullptr;
scripting::content = nullptr;
scripting::indices = nullptr;
}
void scripting::on_blocks_tick(const Block* block, int tps) {
std::string name = block->name+".blockstick";
lua_getglobal(L, name.c_str());
lua_pushinteger(L, tps);
call_func(L, 1, name);
if (state->getglobal(name)) {
state->pushinteger(tps);
state->callNoThrow(1);
}
}
void scripting::update_block(const Block* block, int x, int y, int z) {
std::string name = block->name+".update";
lua_getglobal(L, name.c_str());
lua_pushivec3(L, x, y, z);
call_func(L, 3, name);
if (state->getglobal(name)) {
state->pushivec3(x, y, z);
state->callNoThrow(3);
}
}
void scripting::random_update_block(const Block* block, int x, int y, int z) {
std::string name = block->name+".randupdate";
lua_getglobal(L, name.c_str());
lua_pushivec3(L, x, y, z);
call_func(L, 3, name);
if (state->getglobal(name)) {
state->pushivec3(x, y, z);
state->callNoThrow(3);
}
}
void scripting::on_block_placed(Player* player, const Block* block, int x, int y, int z) {
std::string name = block->name+".placed";
lua_getglobal(L, name.c_str());
lua_pushivec3(L, x, y, z);
lua_pushinteger(L, 1); // player id placeholder
call_func(L, 4, name);
if (state->getglobal(name)) {
state->pushivec3(x, y, z);
state->pushinteger(1); // playerid placeholder
state->callNoThrow(4);
}
}
void scripting::on_block_broken(Player* player, const Block* block, int x, int y, int z) {
std::string name = block->name+".broken";
lua_getglobal(L, name.c_str());
lua_pushivec3(L, x, y, z);
lua_pushinteger(L, 1); // player id placeholder
call_func(L, 4, name);
if (state->getglobal(name)) {
state->pushivec3(x, y, z);
state->pushinteger(1); // playerid placeholder
state->callNoThrow(4);
}
}
bool scripting::on_block_interact(Player* player, const Block* block, int x, int y, int z) {
std::string name = block->name+".oninteract";
lua_getglobal(L, name.c_str());
lua_pushivec3(L, x, y, z);
lua_pushinteger(L, 1);
if (call_func(L, 4, name)) {
return lua_toboolean(L, -1);
std::string name = block->name+".interact";
if (state->getglobal(name)) {
state->pushivec3(x, y, z);
state->pushinteger(1); // playerid placeholder
if (state->callNoThrow(4)) {
return state->toboolean(-1);
}
}
return false;
}
bool scripting::on_item_use_on_block(Player* player, const ItemDef* item, int x, int y, int z) {
std::string name = item->name+".useon";
lua_getglobal(L, name.c_str());
lua_pushivec3(L, x, y, z);
lua_pushinteger(L, 1); // player id placeholder
if (call_func(L, 4, name)) {
return lua_toboolean(L, -1);
if (state->getglobal(name)) {
state->pushivec3(x, y, z);
state->pushinteger(1); // playerid placeholder
if (state->callNoThrow(4)) {
return state->toboolean(-1);
}
}
return false;
}
bool scripting::on_item_break_block(Player* player, const ItemDef* item, int x, int y, int z) {
std::string name = item->name+".blockbreakby";
lua_getglobal(L, name.c_str());
lua_pushivec3(L, x, y, z);
lua_pushinteger(L, 1); // player id placeholder
if (call_func(L, 4, name)) {
return lua_toboolean(L, -1);
if (state->getglobal(name)) {
state->pushivec3(x, y, z);
state->pushinteger(1); // playerid placeholder
if (state->callNoThrow(4)) {
return state->toboolean(-1);
}
}
return false;
}
// todo: refactor
void scripting::load_block_script(std::string prefix, fs::path file, block_funcs_set* funcsset) {
std::string src = files::read_string(file);
std::cout << "loading script " << file.u8string() << std::endl;
if (luaL_loadbuffer(L, src.c_str(), src.size(), file.string().c_str())) {
handleError(L);
return;
void scripting::on_ui_open(UiDocument* layout, Inventory* inventory, glm::ivec3 blockcoord) {
std::string name = layout->getId()+".open";
if (state->getglobal(name)) {
state->pushinteger(inventory == nullptr ? 0 : inventory->getId());
state->pushivec3(blockcoord.x, blockcoord.y, blockcoord.z);
state->callNoThrow(4);
}
call_func(L, 0, "<script>");
funcsset->init=rename_global(L, "init", (prefix+".init").c_str());
funcsset->update=rename_global(L, "on_update", (prefix+".update").c_str());
funcsset->randupdate=rename_global(L, "on_random_update", (prefix+".randupdate").c_str());
funcsset->onbroken=rename_global(L, "on_broken", (prefix+".broken").c_str());
funcsset->onplaced=rename_global(L, "on_placed", (prefix+".placed").c_str());
funcsset->oninteract=rename_global(L, "on_interact", (prefix+".oninteract").c_str());
funcsset->onblockstick=rename_global(L, "on_blocks_tick", (prefix+".blockstick").c_str());
}
void scripting::load_item_script(std::string prefix, fs::path file, item_funcs_set* funcsset) {
std::string src = files::read_string(file);
std::cout << "loading script " << file.u8string() << std::endl;
if (luaL_loadbuffer(L, src.c_str(), src.size(), file.string().c_str())) {
handleError(L);
return;
void scripting::on_ui_close(UiDocument* layout, Inventory* inventory) {
std::string name = layout->getId()+".close";
if (state->getglobal(name)) {
state->pushinteger(inventory->getId());
state->callNoThrow(1);
}
call_func(L, 0, "<script>");
funcsset->init=rename_global(L, "init", (prefix+".init").c_str());
funcsset->on_use_on_block=rename_global(L, "on_use_on_block", (prefix+".useon").c_str());
funcsset->on_block_break_by=rename_global(L, "on_block_break_by", (prefix+".blockbreakby").c_str());
}
void scripting::load_world_script(std::string prefix, fs::path file) {
bool scripting::register_event(int env, const std::string& name, const std::string& id) {
if (state->pushenv(env) == 0) {
state->pushglobals();
}
if (state->getfield(name)) {
// remove previous name
state->pushnil();
state->setfield(name, -3);
// add new global name
state->setglobal(id);
state->pop();
return true;
}
return false;
}
void scripting::load_block_script(int env, std::string prefix, fs::path file, block_funcs_set& funcsset) {
std::string src = files::read_string(file);
std::cout << "loading script " << file.u8string() << std::endl;
if (luaL_loadbuffer(L, src.c_str(), src.size(), file.string().c_str())) {
handleError(L);
return;
}
call_func(L, 0, "<script>");
rename_global(L, "init", (prefix+".init").c_str());
rename_global(L, "on_world_open", (prefix+".worldopen").c_str());
rename_global(L, "on_world_save", (prefix+".worldsave").c_str());
rename_global(L, "on_world_quit", (prefix+".worldquit").c_str());
state->execute(env, src, file.u8string());
funcsset.init = register_event(env, "init", prefix+".init");
funcsset.update = register_event(env, "on_update", prefix+".update");
funcsset.randupdate = register_event(env, "on_random_update", prefix+".randupdate");
funcsset.onbroken = register_event(env, "on_broken", prefix+".broken");
funcsset.onplaced = register_event(env, "on_placed", prefix+".placed");
funcsset.oninteract = register_event(env, "on_interact", prefix+".interact");
funcsset.onblockstick = register_event(env, "on_blocks_tick", prefix+".blockstick");
}
void scripting::load_item_script(int env, std::string prefix, fs::path file, item_funcs_set& funcsset) {
std::string src = files::read_string(file);
std::cout << "loading script " << file.u8string() << std::endl;
state->execute(env, src, file.u8string());
funcsset.init = register_event(env, "init", prefix+".init");
funcsset.on_use_on_block = register_event(env, "on_use_on_block", prefix+".useon");
funcsset.on_block_break_by = register_event(env, "on_block_break_by", prefix+".blockbreakby");
}
void scripting::load_world_script(int env, std::string prefix, fs::path file) {
std::string src = files::read_string(file);
std::cout << "loading script " << file.u8string() << std::endl;
state->loadbuffer(env, src, file.u8string());
state->callNoThrow(0);
register_event(env, "init", prefix+".init");
register_event(env, "on_world_open", prefix+".worldopen");
register_event(env, "on_world_save", prefix+".worldsave");
register_event(env, "on_world_quit", prefix+".worldquit");
}
void scripting::load_layout_script(int env, std::string prefix, fs::path file, uidocscript& script) {
std::string src = files::read_string(file);
std::cout << "loading script " << file.u8string() << std::endl;
script.environment = env;
state->loadbuffer(env, src, file.u8string());
state->callNoThrow(0);
script.onopen = register_event(env, "on_open", prefix+".open");
script.onclose = register_event(env, "on_close", prefix+".close");
}
void scripting::close() {
lua_close(L);
delete state;
L = nullptr;
state = nullptr;
content = nullptr;
indices = nullptr;
level = nullptr;
}
+56 -3
View File
@@ -1,25 +1,53 @@
#include <string>
#include <filesystem>
#include <glm/glm.hpp>
#include "../../delegates.h"
#include "scripting_functional.h"
namespace fs = std::filesystem;
class Engine;
class Content;
struct ContentPack;
class ContentIndices;
class Level;
class Block;
class Player;
class ItemDef;
class Inventory;
class UiDocument;
struct block_funcs_set;
struct item_funcs_set;
struct uidocscript;
class BlocksController;
namespace scripting {
extern Engine* engine;
extern const Content* content;
extern const ContentIndices* indices;
extern Level* level;
extern BlocksController* blocks;
/* Lua environment wrapper for automatic deletion */
class Environment {
int env;
public:
Environment(int env);
~Environment();
int getId() const;
};
void initialize(Engine* engine);
extern bool register_event(int env, const std::string& name, const std::string& id);
std::unique_ptr<Environment> create_environment(int parent=0);
std::unique_ptr<Environment> create_pack_environment(const ContentPack& pack);
std::unique_ptr<Environment> create_doc_environment(int parent, const std::string& name);
void on_world_load(Level* level, BlocksController* blocks);
void on_world_save();
void on_world_quit();
@@ -29,10 +57,35 @@ namespace scripting {
void on_block_placed(Player* player, const Block* block, int x, int y, int z);
void on_block_broken(Player* player, const Block* block, int x, int y, int z);
bool on_block_interact(Player* player, const Block* block, int x, int y, int z);
/** Called on RMB click on block with the item selected
@return true if prevents default action */
bool on_item_use_on_block(Player* player, const ItemDef* item, int x, int y, int z);
/** Called on LMB click on block with the item selected
@return true if prevents default action */
bool on_item_break_block(Player* player, const ItemDef* item, int x, int y, int z);
void load_block_script(std::string prefix, fs::path file, block_funcs_set* funcsset);
void load_item_script(std::string prefix, fs::path file, item_funcs_set* funcsset);
void load_world_script(std::string prefix, fs::path file);
/** Called on UI view show */
void on_ui_open(UiDocument* layout, Inventory* inventory, glm::ivec3 blockcoord);
/** Called on UI view close*/
void on_ui_close(UiDocument* layout, Inventory* inventory);
/** Load script associated with a Block */
void load_block_script(int env, std::string prefix, fs::path file, block_funcs_set& funcsset);
/** Load script associated with an Item */
void load_item_script(int env, std::string prefix, fs::path file, item_funcs_set& funcsset);
/**
* Load package-specific world script
* @param env environment id
* @param packid content-pack id
* @param file script file path
*/
void load_world_script(int env, std::string packid, fs::path file);
/** Load script associated with an UiDocument */
void load_layout_script(int env, std::string prefix, fs::path file, uidocscript& script);
/** Finalize lua state. Using scripting after will lead to Lua panic */
void close();
}
@@ -0,0 +1,52 @@
#include "scripting_frontend.h"
#include "scripting.h"
#include "lua/libhud.h"
#include "lua/LuaState.h"
#include "../../frontend/hud.h"
#include "../../objects/Player.h"
#include "../../files/files.h"
#include "../../engine.h"
#include <iostream>
namespace scripting {
extern lua::LuaState* state;
}
Hud* scripting::hud = nullptr;
void scripting::on_frontend_init(Hud* hud) {
scripting::hud = hud;
scripting::state->openlib("hud", hudlib, 0);
for (auto& pack : scripting::engine->getContentPacks()) {
if (state->getglobal(pack.id+".hudopen")) {
state->pushinteger(hud->getPlayer()->getId());
state->callNoThrow(1);
}
}
}
void scripting::on_frontend_close() {
scripting::hud = nullptr;
for (auto& pack : scripting::engine->getContentPacks()) {
if (state->getglobal(pack.id+".hudclose")) {
state->pushinteger(hud->getPlayer()->getId());
state->callNoThrow(1);
}
}
}
void scripting::load_hud_script(int env, std::string packid, fs::path file) {
std::string src = files::read_string(file);
std::cout << "loading script " << file.u8string() << std::endl;
state->loadbuffer(env, src, file.u8string());
state->callNoThrow(0);
register_event(env, "init", packid+".init");
register_event(env, "on_hud_open", packid+".hudopen");
register_event(env, "on_hud_close", packid+".hudclose");
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef LOGIC_SCRIPTING_SCRIPTING_FRONTEND_H_
#define LOGIC_SCRIPTING_SCRIPTING_FRONTEND_H_
#include <string>
#include <filesystem>
namespace fs = std::filesystem;
class Hud;
namespace scripting {
extern Hud* hud;
void on_frontend_init(Hud* hud);
void on_frontend_close();
/**
* Load package-specific hud script
* @param env environment id
* @param packid content-pack id
* @param file script file path
*/
void load_hud_script(int env, std::string packid, fs::path file);
}
#endif // LOGIC_SCRIPTING_SCRIPTING_FRONTEND_H_
@@ -0,0 +1,107 @@
#include "scripting_functional.h"
#include <iostream>
#include "lua/LuaState.h"
#include "../../util/stringutil.h"
namespace scripting {
extern lua::LuaState* state;
}
using namespace scripting;
runnable scripting::create_runnable(
int env,
const std::string& src,
const std::string& file
) {
return [=](){
state->execute(env, src, file);
};
}
static bool processCallback(
int env,
const std::string& src,
const std::string& file
) {
try {
return state->eval(env, src, file) != 0;
} catch (lua::luaerror& err) {
std::cerr << err.what() << std::endl;
return false;
}
}
wstringconsumer scripting::create_wstring_consumer(
int env,
const std::string& src,
const std::string& file
) {
return [=](const std::wstring& x){
if (processCallback(env, src, file)) {
state->pushstring(util::wstr2str_utf8(x));
state->callNoThrow(1);
}
};
}
doubleconsumer scripting::create_number_consumer(
int env,
const std::string& src,
const std::string& file
) {
return [=](double x){
if (processCallback(env, src, file)) {
state->pushnumber(x);
state->callNoThrow(1);
}
};
}
doublesupplier scripting::create_number_supplier(
int env,
const std::string& src,
const std::string& file
) {
return [=](){
if (processCallback(env, src, file)) {
state->callNoThrow(0);
lua::luanumber x = state->tonumber(-1); state->pop();
return x;
}
return 0.0;
};
}
int_array_consumer scripting::create_int_array_consumer(
int env,
const std::string& src,
const std::string& file
) {
return [=](const int arr[], size_t len){
if (processCallback(env, src, file)) {
for (uint i = 0; i < len; i++) {
state->pushinteger(arr[i]);
}
state->callNoThrow(len);
}
};
}
vec2supplier scripting::create_vec2_supplier(
int env,
const std::string& src,
const std::string& file
) {
return [=](){
if (processCallback(env, src, file)) {
state->callNoThrow(0);
lua::luanumber y = state->tonumber(-1); state->pop();
lua::luanumber x = state->tonumber(-1); state->pop();
return glm::vec2(x, y);
}
return glm::vec2(0, 0);
};
}
@@ -0,0 +1,46 @@
#ifndef LOGIC_SCRIPTING_SCRIPTING_FUNCTIONAL_H_
#define LOGIC_SCRIPTING_SCRIPTING_FUNCTIONAL_H_
#include <glm/glm.hpp>
#include <string>
#include "../../delegates.h"
namespace scripting {
runnable create_runnable(
int env,
const std::string& src,
const std::string& file="<string>"
);
wstringconsumer create_wstring_consumer(
int env,
const std::string& src,
const std::string& file="<string>"
);
doubleconsumer create_number_consumer(
int env,
const std::string& src,
const std::string& file="<string>"
);
doublesupplier create_number_supplier(
int env,
const std::string& src,
const std::string& file="<string>"
);
int_array_consumer create_int_array_consumer(
int env,
const std::string& src,
const std::string& file="<string>"
);
vec2supplier create_vec2_supplier(
int env,
const std::string& src,
const std::string& file="<string>"
);
}
#endif // LOGIC_SCRIPTING_SCRIPTING_FUNCTIONAL_H_