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,120 @@
|
||||
#include "BlocksController.h"
|
||||
|
||||
#include "../voxels/voxel.h"
|
||||
#include "../voxels/Block.h"
|
||||
#include "../voxels/Chunk.h"
|
||||
#include "../voxels/Chunks.h"
|
||||
#include "../world/Level.h"
|
||||
#include "../content/Content.h"
|
||||
#include "../lighting/Lighting.h"
|
||||
#include "../util/timeutil.h"
|
||||
|
||||
#include "scripting/scripting.h"
|
||||
|
||||
Clock::Clock(int tickRate, int tickParts)
|
||||
: tickRate(tickRate),
|
||||
tickParts(tickParts) {
|
||||
}
|
||||
|
||||
bool Clock::update(float delta) {
|
||||
tickTimer += delta;
|
||||
float delay = 1.0f / float(tickRate);
|
||||
if (tickTimer > delay || tickPartsUndone) {
|
||||
if (tickPartsUndone) {
|
||||
tickPartsUndone--;
|
||||
} else {
|
||||
tickTimer = fmod(tickTimer, delay);
|
||||
tickPartsUndone = tickParts-1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Clock::getParts() const {
|
||||
return tickParts;
|
||||
}
|
||||
|
||||
int Clock::getPart() const {
|
||||
return tickParts-tickPartsUndone-1;
|
||||
}
|
||||
|
||||
BlocksController::BlocksController(Level* level, uint padding)
|
||||
: level(level),
|
||||
chunks(level->chunks),
|
||||
lighting(level->lighting),
|
||||
randTickClock(20, 3),
|
||||
padding(padding) {
|
||||
}
|
||||
|
||||
void BlocksController::updateSides(int x, int y, int z) {
|
||||
updateBlock(x-1, y, z);
|
||||
updateBlock(x+1, y, z);
|
||||
updateBlock(x, y-1, z);
|
||||
updateBlock(x, y+1, z);
|
||||
updateBlock(x, y, z-1);
|
||||
updateBlock(x, y, z+1);
|
||||
}
|
||||
|
||||
void BlocksController::breakBlock(Player* player, const Block* def, int x, int y, int z) {
|
||||
chunks->set(x,y,z, 0, 0);
|
||||
lighting->onBlockSet(x,y,z, 0);
|
||||
if (def->rt.funcsset.onbroken) {
|
||||
scripting::on_block_broken(player, def, x, y, z);
|
||||
}
|
||||
updateSides(x, y, z);
|
||||
}
|
||||
|
||||
void BlocksController::updateBlock(int x, int y, int z) {
|
||||
voxel* vox = chunks->get(x, y, z);
|
||||
if (vox == nullptr)
|
||||
return;
|
||||
const Block* def = level->content->indices->getBlockDef(vox->id);
|
||||
if (def->grounded && !chunks->isSolid(x, y-1, z)) {
|
||||
breakBlock(nullptr, def, x, y, z);
|
||||
return;
|
||||
}
|
||||
if (def->rt.funcsset.update) {
|
||||
scripting::update_block(def, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
void BlocksController::update(float delta) {
|
||||
if (randTickClock.update(delta)) {
|
||||
randomTick(randTickClock.getPart(), randTickClock.getParts());
|
||||
}
|
||||
}
|
||||
|
||||
void BlocksController::randomTick(int tickid, int parts) {
|
||||
// timeutil::ScopeLogTimer timer(5000+tickid);
|
||||
const int w = chunks->w;
|
||||
const int d = chunks->d;
|
||||
auto indices = level->content->indices;
|
||||
for (uint z = padding; z < d-padding; z++){
|
||||
for (uint x = padding; x < w-padding; x++){
|
||||
int index = z * w + x;
|
||||
if ((index + tickid) % parts != 0)
|
||||
continue;
|
||||
std::shared_ptr<Chunk> chunk = chunks->chunks[index];
|
||||
if (chunk == nullptr || !chunk->isLighted())
|
||||
continue;
|
||||
int segments = 4;
|
||||
int segheight = CHUNK_H / segments;
|
||||
for (int s = 0; s < segments; s++) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int bx = rand() % CHUNK_W;
|
||||
int by = rand() % segheight + s * segheight;
|
||||
int bz = rand() % CHUNK_D;
|
||||
const voxel& vox = chunk->voxels[(by * CHUNK_D + bz) * CHUNK_W + bx];
|
||||
Block* block = indices->getBlockDef(vox.id);
|
||||
if (block->rt.funcsset.randupdate) {
|
||||
scripting::random_update_block(
|
||||
block,
|
||||
chunk->x * CHUNK_W + bx, by,
|
||||
chunk->z * CHUNK_D + bz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef LOGIC_BLOCKS_CONTROLLER_H_
|
||||
#define LOGIC_BLOCKS_CONTROLLER_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
class Player;
|
||||
class Block;
|
||||
class Level;
|
||||
class Chunks;
|
||||
class Lighting;
|
||||
|
||||
class Clock {
|
||||
int tickRate;
|
||||
int tickParts;
|
||||
|
||||
float tickTimer = 0.0f;
|
||||
int tickId = 0;
|
||||
int tickPartsUndone = 0;
|
||||
public:
|
||||
Clock(int tickRate, int tickParts);
|
||||
|
||||
bool update(float delta);
|
||||
|
||||
int getParts() const;
|
||||
int getPart() const;
|
||||
};
|
||||
|
||||
class BlocksController {
|
||||
Level* level;
|
||||
Chunks* chunks;
|
||||
Lighting* lighting;
|
||||
Clock randTickClock;
|
||||
uint padding;
|
||||
public:
|
||||
BlocksController(Level* level, uint padding);
|
||||
|
||||
void updateSides(int x, int y, int z);
|
||||
void updateBlock(int x, int y, int z);
|
||||
|
||||
void breakBlock(Player* player, const Block* def, int x, int y, int z);
|
||||
|
||||
void update(float delta);
|
||||
void randomTick(int tickid, int parts);
|
||||
};
|
||||
|
||||
#endif // LOGIC_BLOCKS_CONTROLLER_H_
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
#include <limits.h>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include "../voxels/Block.h"
|
||||
#include "../voxels/Chunk.h"
|
||||
#include "../voxels/Chunks.h"
|
||||
#include "../voxels/ChunksStorage.h"
|
||||
#include "../voxels/WorldGenerator.h"
|
||||
#include "../content/Content.h"
|
||||
#include "../graphics/Mesh.h"
|
||||
#include "../lighting/Lighting.h"
|
||||
#include "../files/WorldFiles.h"
|
||||
@@ -17,19 +17,14 @@
|
||||
#include "../maths/voxmaths.h"
|
||||
#include "../util/timeutil.h"
|
||||
|
||||
|
||||
const uint MAX_WORK_PER_FRAME = 64;
|
||||
const uint MIN_SURROUNDING = 9;
|
||||
|
||||
using std::unique_ptr;
|
||||
using std::shared_ptr;
|
||||
|
||||
ChunksController::ChunksController(Level* level,
|
||||
Chunks* chunks,
|
||||
Lighting* lighting,
|
||||
uint padding)
|
||||
ChunksController::ChunksController(Level* level, uint padding)
|
||||
: level(level),
|
||||
chunks(chunks),
|
||||
lighting(lighting),
|
||||
chunks(level->chunks),
|
||||
lighting(level->lighting),
|
||||
padding(padding),
|
||||
generator(new WorldGenerator(level->content)) {
|
||||
}
|
||||
@@ -66,7 +61,7 @@ bool ChunksController::loadVisible(){
|
||||
for (uint z = padding; z < d-padding; z++){
|
||||
for (uint x = padding; x < w-padding; x++){
|
||||
int index = z * w + x;
|
||||
shared_ptr<Chunk> chunk = chunks->chunks[index];
|
||||
std::shared_ptr<Chunk> chunk = chunks->chunks[index];
|
||||
if (chunk != nullptr){
|
||||
int surrounding = 0;
|
||||
for (int oz = -1; oz <= 1; oz++){
|
||||
@@ -98,7 +93,7 @@ bool ChunksController::loadVisible(){
|
||||
}
|
||||
|
||||
int index = nearZ * w + nearX;
|
||||
shared_ptr<Chunk> chunk = chunks->chunks[index];
|
||||
std::shared_ptr<Chunk> chunk = chunks->chunks[index];
|
||||
if (chunk != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
class Level;
|
||||
class Chunks;
|
||||
class Lighting;
|
||||
class WorldFiles;
|
||||
class VoxelRenderer;
|
||||
class ChunksLoader;
|
||||
class WorldGenerator;
|
||||
|
||||
/* ChunksController manages chunks dynamic loading/unloading */
|
||||
@@ -26,7 +23,7 @@ private:
|
||||
/* Process one chunk: load it or calculate lights for it */
|
||||
bool loadVisible();
|
||||
public:
|
||||
ChunksController(Level* level, Chunks* chunks, Lighting* lighting, uint padding);
|
||||
ChunksController(Level* level, uint padding);
|
||||
~ChunksController();
|
||||
|
||||
/* @param maxDuration milliseconds reserved for chunks loading */
|
||||
|
||||
@@ -2,28 +2,29 @@
|
||||
#include "../world/Level.h"
|
||||
|
||||
#include "PlayerController.h"
|
||||
#include "BlocksController.h"
|
||||
#include "ChunksController.h"
|
||||
|
||||
#include "scripting/scripting.h"
|
||||
|
||||
LevelController::LevelController(EngineSettings& settings, Level* level)
|
||||
: settings(settings), level(level) {
|
||||
chunks = new ChunksController(
|
||||
level,
|
||||
level->chunks,
|
||||
level->lighting,
|
||||
settings.chunks.padding);
|
||||
player = new PlayerController(level, settings);
|
||||
blocks = new BlocksController(level, settings.chunks.padding);
|
||||
chunks = new ChunksController(level, settings.chunks.padding);
|
||||
player = new PlayerController(level, settings, blocks);
|
||||
|
||||
scripting::on_world_load(level);
|
||||
}
|
||||
|
||||
LevelController::~LevelController() {
|
||||
scripting::on_world_quit();
|
||||
delete player;
|
||||
delete chunks;
|
||||
}
|
||||
|
||||
void LevelController::update(
|
||||
float delta,
|
||||
bool input,
|
||||
bool pause) {
|
||||
void LevelController::update(float delta, bool input, bool pause) {
|
||||
player->update(delta, input, pause);
|
||||
level->update();
|
||||
chunks->update(settings.chunks.loadSpeed);
|
||||
}
|
||||
blocks->update(delta);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../settings.h"
|
||||
|
||||
class Level;
|
||||
class BlocksController;
|
||||
class ChunksController;
|
||||
class PlayerController;
|
||||
|
||||
@@ -12,6 +13,7 @@ class LevelController {
|
||||
EngineSettings& settings;
|
||||
Level* level;
|
||||
// Sub-controllers
|
||||
BlocksController* blocks;
|
||||
ChunksController* chunks;
|
||||
PlayerController* player;
|
||||
public:
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "../window/Camera.h"
|
||||
#include "../window/Events.h"
|
||||
#include "../window/input.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "BlocksController.h"
|
||||
|
||||
#include "../core_defs.h"
|
||||
|
||||
@@ -25,9 +27,6 @@ const float RUN_ZOOM = 1.1f;
|
||||
const float C_ZOOM = 0.1f;
|
||||
const float CROUCH_SHIFT_Y = -0.2f;
|
||||
|
||||
using glm::vec2;
|
||||
using glm::vec3;
|
||||
using std::string;
|
||||
|
||||
CameraControl::CameraControl(Player* player, const CameraSettings& settings)
|
||||
: player(player),
|
||||
@@ -55,27 +54,27 @@ void CameraControl::updateMouse(PlayerInput& input) {
|
||||
float& camY = player->camY;
|
||||
camX += rotX;
|
||||
camY += rotY;
|
||||
if (camY < -radians(89.9f)){
|
||||
camY = -radians(89.9f);
|
||||
if (camY < -glm::radians(89.9f)){
|
||||
camY = -glm::radians(89.9f);
|
||||
}
|
||||
if (camY > radians(89.9f)){
|
||||
camY = radians(89.9f);
|
||||
if (camY > glm::radians(89.9f)){
|
||||
camY = glm::radians(89.9f);
|
||||
}
|
||||
|
||||
camera->rotation = mat4(1.0f);
|
||||
camera->rotation = glm::mat4(1.0f);
|
||||
camera->rotate(camY, camX, 0);
|
||||
}
|
||||
|
||||
void CameraControl::update(PlayerInput& input, float delta, Chunks* chunks) {
|
||||
Hitbox* hitbox = player->hitbox;
|
||||
|
||||
offset = vec3(0.0f, 0.7f, 0.0f);
|
||||
offset = glm::vec3(0.0f, 0.7f, 0.0f);
|
||||
|
||||
if (settings.shaking && !input.cheat) {
|
||||
const float k = CAM_SHAKE_DELTA_K;
|
||||
const float oh = CAM_SHAKE_OFFSET;
|
||||
const float ov = CAM_SHAKE_OFFSET_Y;
|
||||
const vec3& vel = hitbox->velocity;
|
||||
const glm::vec3& vel = hitbox->velocity;
|
||||
|
||||
interpVel = interpVel * (1.0f - delta * 5) + vel * delta * 0.1f;
|
||||
if (hitbox->grounded && interpVel.y < 0.0f){
|
||||
@@ -83,12 +82,12 @@ void CameraControl::update(PlayerInput& input, float delta, Chunks* chunks) {
|
||||
}
|
||||
shake = shake * (1.0f - delta * k);
|
||||
if (hitbox->grounded) {
|
||||
float f = length(vec2(vel.x, vel.z));
|
||||
float f = glm::length(glm::vec2(vel.x, vel.z));
|
||||
shakeTimer += delta * f * CAM_SHAKE_SPEED;
|
||||
shake += f * delta * k;
|
||||
}
|
||||
offset += camera->right * sin(shakeTimer) * oh * shake;
|
||||
offset += camera->up * abs(cos(shakeTimer)) * ov * shake;
|
||||
offset += camera->right * glm::sin(shakeTimer) * oh * shake;
|
||||
offset += camera->up * glm::abs(glm::cos(shakeTimer)) * ov * shake;
|
||||
offset -= glm::min(interpVel * 0.05f, 1.0f);
|
||||
}
|
||||
|
||||
@@ -98,7 +97,7 @@ void CameraControl::update(PlayerInput& input, float delta, Chunks* chunks) {
|
||||
float dt = fmin(1.0f, delta * ZOOM_SPEED);
|
||||
float zoomValue = 1.0f;
|
||||
if (crouch){
|
||||
offset += vec3(0.f, CROUCH_SHIFT_Y, 0.f);
|
||||
offset += glm::vec3(0.f, CROUCH_SHIFT_Y, 0.f);
|
||||
zoomValue = CROUCH_ZOOM;
|
||||
} else if (input.sprint){
|
||||
zoomValue = RUN_ZOOM;
|
||||
@@ -128,16 +127,20 @@ void CameraControl::update(PlayerInput& input, float delta, Chunks* chunks) {
|
||||
}
|
||||
}
|
||||
|
||||
vec3 PlayerController::selectedBlockPosition;
|
||||
vec3 PlayerController::selectedPointPosition;
|
||||
ivec3 PlayerController::selectedBlockNormal;
|
||||
glm::vec3 PlayerController::selectedBlockPosition;
|
||||
glm::vec3 PlayerController::selectedPointPosition;
|
||||
glm::ivec3 PlayerController::selectedBlockNormal;
|
||||
int PlayerController::selectedBlockId = -1;
|
||||
int PlayerController::selectedBlockStates = 0;
|
||||
|
||||
PlayerController::PlayerController(Level* level, const EngineSettings& settings)
|
||||
PlayerController::PlayerController(
|
||||
Level* level,
|
||||
const EngineSettings& settings,
|
||||
BlocksController* blocksController)
|
||||
: level(level),
|
||||
player(level->player),
|
||||
camControl(level->player, settings.camera) {
|
||||
camControl(level->player, settings.camera),
|
||||
blocksController(blocksController) {
|
||||
}
|
||||
|
||||
void PlayerController::update(float delta, bool input, bool pause) {
|
||||
@@ -177,7 +180,7 @@ void PlayerController::updateKeyboard() {
|
||||
// block choice
|
||||
for (int i = 1; i < 10; i++){
|
||||
if (Events::jpressed(keycode::NUM_0+i)){
|
||||
player->choosenBlock = i;
|
||||
player->chosenBlock = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,9 +214,9 @@ void PlayerController::updateInteraction(){
|
||||
Player* player = level->player;
|
||||
Lighting* lighting = level->lighting;
|
||||
Camera* camera = player->camera;
|
||||
vec3 end;
|
||||
ivec3 iend;
|
||||
ivec3 norm;
|
||||
glm::vec3 end;
|
||||
glm::ivec3 iend;
|
||||
glm::ivec3 norm;
|
||||
|
||||
bool xkey = Events::pressed(keycode::X);
|
||||
bool lclick = Events::jactive(BIND_PLAYER_ATTACK) ||
|
||||
@@ -241,9 +244,9 @@ void PlayerController::updateInteraction(){
|
||||
int z = iend.z;
|
||||
uint8_t states = 0;
|
||||
|
||||
Block* def = contentIds->getBlockDef(player->choosenBlock);
|
||||
Block* def = contentIds->getBlockDef(player->chosenBlock);
|
||||
if (def->rotatable){
|
||||
const string& name = def->rotations.name;
|
||||
const std::string& name = def->rotations.name;
|
||||
if (name == "pipe") {
|
||||
if (norm.x < 0.0f) states = BLOCK_DIR_WEST;
|
||||
else if (norm.x > 0.0f) states = BLOCK_DIR_EAST;
|
||||
@@ -252,7 +255,7 @@ void PlayerController::updateInteraction(){
|
||||
else if (norm.z > 0.0f) states = BLOCK_DIR_NORTH;
|
||||
else if (norm.z < 0.0f) states = BLOCK_DIR_SOUTH;
|
||||
} else if (name == "pane") {
|
||||
vec3 vec = camera->dir;
|
||||
glm::vec3 vec = camera->dir;
|
||||
if (abs(vec.x) > abs(vec.z)){
|
||||
if (vec.x > 0.0f) states = BLOCK_DIR_EAST;
|
||||
if (vec.x < 0.0f) states = BLOCK_DIR_WEST;
|
||||
@@ -266,8 +269,7 @@ void PlayerController::updateInteraction(){
|
||||
|
||||
Block* block = contentIds->getBlockDef(vox->id);
|
||||
if (lclick && block->breakable){
|
||||
chunks->set(x,y,z, 0, 0);
|
||||
lighting->onBlockSet(x,y,z, 0);
|
||||
blocksController->breakBlock(player, block, x, y, z);
|
||||
}
|
||||
if (rclick){
|
||||
if (block->model != BlockModel::xsprite){
|
||||
@@ -276,19 +278,30 @@ void PlayerController::updateInteraction(){
|
||||
z = (iend.z)+(norm.z);
|
||||
}
|
||||
vox = chunks->get(x, y, z);
|
||||
int chosenBlock = player->chosenBlock;
|
||||
if (vox && (block = contentIds->getBlockDef(vox->id))->replaceable) {
|
||||
if (!level->physics->isBlockInside(x,y,z, player->hitbox)
|
||||
|| !def->obstacle){
|
||||
chunks->set(x, y, z, player->choosenBlock, states);
|
||||
lighting->onBlockSet(x,y,z, player->choosenBlock);
|
||||
Block* def = contentIds->getBlockDef(chosenBlock);
|
||||
if (def->grounded && !chunks->isSolid(x, y-1, z)) {
|
||||
chosenBlock = 0;
|
||||
}
|
||||
if (chosenBlock != vox->id) {
|
||||
chunks->set(x, y, z, chosenBlock, states);
|
||||
lighting->onBlockSet(x,y,z, chosenBlock);
|
||||
if (def->rt.funcsset.onplaced) {
|
||||
scripting::on_block_placed(player, def, x, y, z);
|
||||
}
|
||||
blocksController->updateSides(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Events::jactive(BIND_PLAYER_PICK)){
|
||||
player->choosenBlock = chunks->get(x,y,z)->id;
|
||||
player->chosenBlock = chunks->get(x,y,z)->id;
|
||||
}
|
||||
} else {
|
||||
selectedBlockId = -1;
|
||||
selectedBlockStates = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
class Camera;
|
||||
class Level;
|
||||
class BlocksController;
|
||||
|
||||
class CameraControl {
|
||||
Player* player;
|
||||
@@ -29,6 +30,7 @@ class PlayerController {
|
||||
Player* player;
|
||||
PlayerInput input;
|
||||
CameraControl camControl;
|
||||
BlocksController* blocksController;
|
||||
|
||||
void updateKeyboard();
|
||||
void updateCamera(float delta, bool movement);
|
||||
@@ -42,7 +44,9 @@ public:
|
||||
static int selectedBlockId;
|
||||
static int selectedBlockStates;
|
||||
|
||||
PlayerController(Level* level, const EngineSettings& settings);
|
||||
PlayerController(Level* level,
|
||||
const EngineSettings& settings,
|
||||
BlocksController* blocksController);
|
||||
void update(float delta, bool input, bool pause);
|
||||
};
|
||||
|
||||
|
||||
@@ -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