Scripting WIP (#70)
* Scripting introduced * AppImage workflow fixes * AppImage workflow simplified * README.md update * README.md update * small fix
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
#include "api_lua.h"
|
||||
#include "scripting.h"
|
||||
|
||||
#include "../../world/Level.h"
|
||||
#include "../../content/Content.h"
|
||||
#include "../../voxels/Block.h"
|
||||
#include "../../voxels/Chunks.h"
|
||||
#include "../../voxels/voxel.h"
|
||||
|
||||
int l_block_name(lua_State* L) {
|
||||
int id = lua_tointeger(L, 1);
|
||||
lua_pushstring(L, scripting::content->indices->getBlockDef(id)->name.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
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->isSolid(x, y, z));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_blocks_count(lua_State* L) {
|
||||
lua_pushinteger(L, scripting::content->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) {
|
||||
int x = lua_tointeger(L, 1);
|
||||
int y = lua_tointeger(L, 2);
|
||||
int z = lua_tointeger(L, 3);
|
||||
int id = lua_tointeger(L, 4);
|
||||
scripting::level->chunks->set(x, y, z, id, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#define lua_addfunc(L, FUNC, NAME) (lua_pushcfunction(L, FUNC),\
|
||||
lua_setglobal(L, NAME))
|
||||
|
||||
void apilua::create_funcs(lua_State* L) {
|
||||
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_set_block, "set_block");
|
||||
lua_addfunc(L, l_get_block, "get_block");
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#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_
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "scripting.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <lua.hpp>
|
||||
|
||||
#include "../../files/engine_paths.h"
|
||||
#include "../../files/files.h"
|
||||
#include "../../util/timeutil.h"
|
||||
#include "../../world/Level.h"
|
||||
#include "../../voxels/Block.h"
|
||||
#include "api_lua.h"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
namespace scripting {
|
||||
extern lua_State* L;
|
||||
extern EnginePaths* paths;
|
||||
}
|
||||
|
||||
lua_State* scripting::L = nullptr;
|
||||
Level* scripting::level = nullptr;
|
||||
const Content* scripting::content = nullptr;
|
||||
EnginePaths* scripting::paths = nullptr;
|
||||
|
||||
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;
|
||||
}
|
||||
lua_setglobal(L, dst);
|
||||
delete_global(L, src);
|
||||
return true;
|
||||
}
|
||||
|
||||
void call_func(lua_State* L, int argc, const std::string& name) {
|
||||
if (lua_pcall(L, argc, LUA_MULTRET, 0)) {
|
||||
std::cerr << "Lua error in " << name << ": ";
|
||||
std::cerr << lua_tostring(L,-1) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void scripting::initialize(EnginePaths* paths) {
|
||||
scripting::paths = paths;
|
||||
|
||||
L = luaL_newstate();
|
||||
if (L == nullptr) {
|
||||
throw std::runtime_error("could not to initialize Lua");
|
||||
}
|
||||
luaopen_base(L);
|
||||
luaopen_math(L);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void scripting::on_world_load(Level* level) {
|
||||
scripting::level = level;
|
||||
scripting::content = level->content;
|
||||
|
||||
fs::path file = paths->getResources()/fs::path("scripts/world.lua");
|
||||
std::string src = files::read_string(file);
|
||||
luaL_loadbuffer(L, src.c_str(), src.length(), file.string().c_str());
|
||||
call_func(L, 0, "<script>");
|
||||
}
|
||||
|
||||
void scripting::on_world_quit() {
|
||||
scripting::level = nullptr;
|
||||
scripting::content = nullptr;
|
||||
}
|
||||
|
||||
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_pushinteger(L, x);
|
||||
lua_pushinteger(L, y);
|
||||
lua_pushinteger(L, z);
|
||||
call_func(L, 3, name);
|
||||
}
|
||||
|
||||
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_pushinteger(L, x);
|
||||
lua_pushinteger(L, y);
|
||||
lua_pushinteger(L, z);
|
||||
call_func(L, 3, name);
|
||||
}
|
||||
|
||||
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_pushinteger(L, x);
|
||||
lua_pushinteger(L, y);
|
||||
lua_pushinteger(L, z);
|
||||
call_func(L, 3, name);
|
||||
}
|
||||
|
||||
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_pushinteger(L, x);
|
||||
lua_pushinteger(L, y);
|
||||
lua_pushinteger(L, z);
|
||||
call_func(L, 3, name);
|
||||
}
|
||||
|
||||
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())) {
|
||||
std::cerr << "Lua error:" << lua_tostring(L,-1) << std::endl;
|
||||
return;
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
void scripting::close() {
|
||||
lua_close(L);
|
||||
|
||||
L = nullptr;
|
||||
content = nullptr;
|
||||
level = nullptr;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class EnginePaths;
|
||||
class Content;
|
||||
class Level;
|
||||
class Block;
|
||||
class Player;
|
||||
struct block_funcs_set;
|
||||
|
||||
namespace scripting {
|
||||
extern const Content* content;
|
||||
extern Level* level;
|
||||
|
||||
void initialize(EnginePaths* paths);
|
||||
void on_world_load(Level* level);
|
||||
void on_world_quit();
|
||||
void update_block(const Block* block, int x, int y, int z);
|
||||
void random_update_block(const Block* block, int x, int y, int z);
|
||||
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);
|
||||
void load_block_script(std::string prefix, fs::path file, block_funcs_set* funcsset);
|
||||
void close();
|
||||
}
|
||||
Reference in New Issue
Block a user