Skip to content

Commit

Permalink
Add initial Craft API example
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielOaks committed Sep 24, 2014
1 parent d71652d commit 1c209e9
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 0 deletions.
18 changes: 18 additions & 0 deletions modules/water.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-- water.lua
-- adding a water block via lua module

water_block_id = 0;

function startup()
io.write("adding a 'water' block\n");

water_block_id = api.add_block_type('water');
end

function shutdown()
io.write("water module shutting down\n");
end

function after_terrain_generated()
io.write("fires after a block of terrain is generated");
end
169 changes: 169 additions & 0 deletions src/api.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#include "api.h"
#include <string.h>
#include <stdlib.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <dirent.h>
#endif

#define MAX_FILENAME_LENGTH 1024
#define MAX_ERROR_SIZE 255

#define MODULE_DIR "modules/"

// API functions
int api_add_block_type(lua_State *l)
{
// add the given 'block type' to our engine and return the generated block ID
const char *block_name = lua_tostring(l, 1);
int block_id = 37; // random id. we should have a real dynamic way to add block types in the engine
lua_pushnumber(l, block_id);
return 1;
}

luaL_Reg clua_regs[] =
{
{ "add_block_type", api_add_block_type },
{ NULL, NULL }
};


// structs
struct module_name_list {
char *filename;
struct module_name_list *next_ptr;
};

struct loaded_module_list {
char *filename;
lua_State *L;
struct loaded_module_list *next_ptr;
};

struct loaded_module_list *loaded_mods;


// lua init/shutdown
int clua_init()
{
struct module_name_list *mod, *mod_names;
mod_names = NULL;
loaded_mods = NULL;

// get list of modules
#ifdef _WIN32
WIN32_FIND_DATA fdFile;
HANDLE hFind = NULL;

char sPath[2048];

sprintf(sPath, "%s\\*.lua", MODULE_DIR);

if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE) {
dprintf(stderr, "Module folder not found: [%s]\n", sDir);
return 1;
}

do {
if(strcmp(fdFile.cFileName, ".") != 0
&& strcmp(fdFile.cFileName, "..") != 0)
{
sprintf(sPath, "%s\\%s", sDir, fdFile.cFileName);

mod = malloc(sizeof(struct module_name_list));
mod->filename = sPath;

SGLIB_LIST_ADD(struct module_name_list, mod_names, mod, next_ptr);
}
} while (FindNextFile(hFind, &fdFile));

FindClose(hFind);
#else
DIR *d;
struct dirent *dir;
d = opendir(MODULE_DIR);

if (d) {
char *ext = ".lua";
int ext_len = strlen(ext);

while ((dir = readdir(d)) != NULL) {
int name_len = strlen(dir->d_name);

if ((name_len > ext_len) && (0 == strncmp(dir->d_name + (name_len - ext_len), ext, ext_len))) {
char module_filename[MAX_FILENAME_LENGTH] = {0};

if (MAX_FILENAME_LENGTH <= (strlen(MODULE_DIR) + strlen(dir->d_name))) {
fprintf(stderr, "Module name is too large: %s\n", dir->d_name);
continue;
}

strncpy(module_filename, MODULE_DIR, strlen(MODULE_DIR));
strncat(module_filename, dir->d_name, MAX_FILENAME_LENGTH - strlen(MODULE_DIR) - 1);

mod = malloc(sizeof(struct module_name_list));
mod->filename = module_filename;

SGLIB_LIST_ADD(struct module_name_list, mod_names, mod, next_ptr);
}
}

closedir(d);
}
#endif

// load lua modules
SGLIB_LIST_MAP_ON_ELEMENTS(struct module_name_list, mod_names, mod_name, next_ptr, {
printf("Loading module %s\n", mod_name->filename);

struct loaded_module_list *mod;
mod = malloc(sizeof(struct loaded_module_list));

// we have a separate lua state for every single module we load
mod->L = luaL_newstate();
luaL_openlibs(mod->L);

// init our API
lua_newtable(mod->L);
luaL_setfuncs(mod->L, clua_regs, 0);
lua_setglobal(mod->L, "api");

if (luaL_loadfile(mod->L, mod_name->filename)) {
fprintf(stderr, "Lua module %s failed to load\n", mod_name->filename);
free(mod);
}
else {
if (lua_pcall(mod->L, 0, 0, 0)) {
fprintf(stderr, "Lua module %s failed to run\n", mod_name->filename);
free(mod);
}
else {
lua_getglobal(mod->L, "startup");

if (lua_pcall(mod->L, 0, 0, 0)) {
fprintf(stderr, "Startup in %s failed\n", mod_name->filename);
free(mod);
}
else {
SGLIB_LIST_ADD(struct loaded_module_list, loaded_mods, mod, next_ptr)
}
}
}
});

return 0;
}


int clua_close()
{
// close lua on every loaded module
SGLIB_LIST_MAP_ON_ELEMENTS(struct loaded_module_list, loaded_mods, mod, next_ptr, {
lua_close(mod->L);
free(mod);
});

return 0;
}
13 changes: 13 additions & 0 deletions src/api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef _api_h_
#define _api_h_

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include <sglib.h>

int clua_init();
int clua_load_modules();
int clua_close();

#endif
5 changes: 5 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "api.h"
#include "auth.h"
#include "client.h"
#include "config.h"
Expand Down Expand Up @@ -2771,6 +2772,9 @@ int main(int argc, char **argv) {
s->y = highest_block(s->x, s->z) + 2;
}

// INITIALIZE LUA //
clua_init();

// BEGIN MAIN LOOP //
double previous = glfwGetTime();
while (1) {
Expand Down Expand Up @@ -2947,6 +2951,7 @@ int main(int argc, char **argv) {
}

// SHUTDOWN //
clua_close();
db_save_state(s->x, s->y, s->z, s->rx, s->ry);
db_close();
db_disable();
Expand Down

0 comments on commit 1c209e9

Please sign in to comment.