forked from CleverRaven/Cataclysm-DDA
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request CleverRaven#4337 from GlyphGryph/cibs_lua_for_debu…
…gging Cib's lua for debugging
- Loading branch information
Showing
16 changed files
with
1,337 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,322 @@ | ||
#include "catalua.h" | ||
|
||
#ifdef LUA | ||
extern "C" { | ||
#include "lua.h" | ||
#include "lualib.h" | ||
#include "lauxlib.h" | ||
} | ||
|
||
lua_State *lua_state; | ||
|
||
// Helper functions for making working with the lua API more straightforward. | ||
// -------------------------------------------------------------------------- | ||
|
||
// Stores item at the given stack position into the registry. | ||
int luah_store_in_registry(lua_State* L, int stackpos) { | ||
lua_pushvalue(L, stackpos); | ||
return luaL_ref(L, LUA_REGISTRYINDEX); | ||
} | ||
|
||
// Removes item from registry and pushes on the top of stack. | ||
void luah_remove_from_registry(lua_State* L, int item_index) { | ||
lua_rawgeti(L, LUA_REGISTRYINDEX, item_index); | ||
luaL_unref(L, LUA_REGISTRYINDEX, item_index); | ||
} | ||
|
||
// Sets the metatable for the element on top of the stack. | ||
void luah_setmetatable(lua_State* L, const char* metatable_name) { | ||
// Push the metatable on top of the stack. | ||
lua_getglobal(L, metatable_name); | ||
|
||
// The element we want to set the metatable for is now below the top. | ||
lua_setmetatable(L, -2); | ||
} | ||
|
||
void luah_setglobal(lua_State*L, const char* name, int index) { | ||
lua_pushvalue(L, index); | ||
lua_setglobal(L, name); | ||
} | ||
|
||
void update_globals(lua_State *L) { | ||
// Make sure the player reference is up to date. | ||
{ | ||
player** player_userdata = (player**) lua_newuserdata(L, sizeof(player*)); | ||
*player_userdata = &g->u; | ||
|
||
// Set the metatable for the player. | ||
luah_setmetatable(L, "player_metatable"); | ||
|
||
luah_setglobal(L, "player", -1); | ||
} | ||
|
||
// Make sure the map reference is up to date. | ||
{ | ||
map** map_userdata = (map**) lua_newuserdata(L, sizeof(map*)); | ||
*map_userdata = &g->m; | ||
|
||
// Set the metatable for the player. | ||
luah_setmetatable(L, "map_metatable"); | ||
|
||
luah_setglobal(L, "map", -1); | ||
} | ||
} | ||
|
||
// iuse abstraction to make iuse's both in lua and C++ possible | ||
// ------------------------------------------------------------ | ||
void Item_factory::register_iuse_lua(const char* name, int lua_function) { | ||
iuse_function_list[name] = use_function(lua_function); | ||
} | ||
|
||
// Call the given string directly, used in the lua debug command. | ||
int call_lua(std::string tocall) { | ||
lua_State* L = lua_state; | ||
|
||
update_globals(L); | ||
|
||
int err = luaL_dostring(L, tocall.c_str()); | ||
if(err) { | ||
// Error handling. | ||
const char* error = lua_tostring(L, -1); | ||
debugmsg("Error in lua command: %s", error); | ||
} | ||
return err; | ||
} | ||
|
||
// Lua monster movement override | ||
int lua_monster_move(monster* m) { | ||
lua_State *L = lua_state; | ||
|
||
update_globals(L); | ||
|
||
lua_getglobal(L, "monster_move"); | ||
lua_getfield(L, -1, m->type->name.c_str()); | ||
|
||
// OK our function should now be at the top. | ||
if(lua_isnil(L, -1)) { | ||
lua_settop(L, 0); | ||
return 0; | ||
} | ||
|
||
// Push the monster on top of the stack. | ||
monster** monster_userdata = (monster**) lua_newuserdata(L, sizeof(monster*)); | ||
*monster_userdata = m; | ||
|
||
// Set the metatable for the monster. | ||
luah_setmetatable(L, "monster_metatable"); | ||
|
||
// Call the function | ||
int err = lua_pcall(lua_state, 1, 0, 0); | ||
if(err) { | ||
// Error handling. | ||
const char* error = lua_tostring(L, -1); | ||
debugmsg("Error in lua monster move function: %s", error); | ||
} | ||
lua_settop(L, 0); | ||
|
||
return 1; | ||
} | ||
|
||
// Custom functions that are to be wrapped from lua. | ||
// ------------------------------------------------- | ||
static uimenu uimenu_instance; | ||
uimenu* create_uimenu() { | ||
uimenu_instance = uimenu(); | ||
return &uimenu_instance; | ||
} | ||
|
||
ter_t* get_terrain_type(int id) { | ||
return (ter_t*) &terlist[id]; | ||
} | ||
|
||
// Manually implemented lua functions | ||
// | ||
// Most lua functions are generated by catalua/generate_bindings.lua, | ||
// these generated functions can be found in catalua/catabindings.cpp | ||
|
||
/* | ||
This function is commented out until I find a way to get a list of all | ||
currently loaded monsters >_> | ||
// monster_list = game.get_monsters() | ||
static int game_get_monsters(lua_State *L) { | ||
lua_createtable(L, g->_z.size(), 0); // Preallocate enough space for all our monsters. | ||
// Iterate over the monster list and insert each monster into our returned table. | ||
for(int i=0; i < g->_z.size(); i++) { | ||
// The stack will look like this: | ||
// 1 - t, table containing monsters | ||
// 2 - k, index at which the next monster will be inserted | ||
// 3 - v, next monster to insert | ||
// | ||
// lua_rawset then does t[k] = v and pops v and k from the stack | ||
lua_pushnumber(L, i + 1); | ||
monster** monster_userdata = (monster**) lua_newuserdata(L, sizeof(monster*)); | ||
*monster_userdata = &(g->_z[i]); | ||
luah_setmetatable(L, "monster_metatable"); | ||
lua_rawset(L, -3); | ||
} | ||
return 1; // 1 return values | ||
} | ||
*/ | ||
|
||
// items = game.items_at(x, y) | ||
static int game_items_at(lua_State *L) { | ||
int x = lua_tointeger(L, 1); | ||
int y = lua_tointeger(L, 2); | ||
|
||
std::vector<item>& items = g->m.i_at(x, y); | ||
|
||
lua_createtable(L, items.size(), 0); // Preallocate enough space for all our items. | ||
|
||
// Iterate over the monster list and insert each monster into our returned table. | ||
for(int i=0; i < items.size(); i++) { | ||
// The stack will look like this: | ||
// 1 - t, table containing item | ||
// 2 - k, index at which the next item will be inserted | ||
// 3 - v, next item to insert | ||
// | ||
// lua_rawset then does t[k] = v and pops v and k from the stack | ||
|
||
lua_pushnumber(L, i + 1); | ||
item** item_userdata = (item**) lua_newuserdata(L, sizeof(item*)); | ||
*item_userdata = &(items[i]); | ||
luah_setmetatable(L, "item_metatable"); | ||
lua_rawset(L, -3); | ||
} | ||
|
||
return 1; // 1 return values | ||
} | ||
|
||
// game.remove_item(x, y, item) | ||
void game_remove_item(int x, int y, item *it) { | ||
std::vector<item>& items = g->m.i_at(x, y); | ||
|
||
for(int i=0; i<items.size(); i++) { | ||
if(&(items[i]) == it) { | ||
items.erase(items.begin() + i); | ||
} | ||
} | ||
} | ||
|
||
// game.register_iuse(string, function_object) | ||
static int game_register_iuse(lua_State *L) { | ||
// Make sure the first argument is a string. | ||
const char* name = luaL_checkstring(L, 1); | ||
if(!name) { | ||
return luaL_error(L, "First argument to game.register_iuse is not a string."); | ||
} | ||
|
||
// Make sure the second argument is a function | ||
luaL_checktype(L, 2, LUA_TFUNCTION); | ||
|
||
// function_object is at the top of the stack, so we can just pop | ||
// it with luaL_ref | ||
int function_index = luaL_ref(L, LUA_REGISTRYINDEX); | ||
|
||
// Now register function_object with our iuse's | ||
item_controller->register_iuse_lua(name, function_index); | ||
|
||
return 0; // 0 return values | ||
} | ||
|
||
#include "catalua/catabindings.cpp" | ||
|
||
// Registry containing all the game functions exported to lua. | ||
// ----------------------------------------------------------- | ||
static const struct luaL_Reg global_funcs [] = { | ||
{"register_iuse", game_register_iuse}, | ||
//{"get_monsters", game_get_monsters}, | ||
{"items_at", game_items_at}, | ||
{NULL, NULL} | ||
}; | ||
|
||
// Lua initialization. | ||
void game::init_lua() { | ||
lua_state = luaL_newstate(); | ||
|
||
luaL_openlibs(lua_state); // Load standard lua libs | ||
|
||
// Load our custom "game" module | ||
luaL_register(lua_state, "game", gamelib); | ||
luaL_register(lua_state, "game", global_funcs); | ||
|
||
// Load lua-side metatables etc. | ||
luaL_dofile(lua_state,"catalua/catalua.lua"); | ||
|
||
// Load main lua mod | ||
int err = luaL_dofile(lua_state,"data/main.lua"); | ||
if(err) { | ||
// Error handling. | ||
const char* error = lua_tostring(lua_state, -1); | ||
debugmsg("Error in lua module: %s", error); | ||
} | ||
} | ||
#endif // #ifdef LUA | ||
|
||
// If we're not using lua, need to define Use_function in a way to always call the C++ function | ||
int use_function::call(game* game, player* player_instance, item* item_instance, bool active) { | ||
if(function_type == USE_FUNCTION_CPP) { | ||
// If it's a C++ function, simply call it with the given arguments. | ||
iuse tmp; | ||
return (tmp.*cpp_function)(game, player_instance, item_instance, active); | ||
} else { | ||
#ifdef LUA | ||
|
||
// We'll be using lua_state a lot! | ||
lua_State* L = lua_state; | ||
|
||
// If it's a lua function, the arguments have to be wrapped in | ||
// lua userdata's and passed on the lua stack. | ||
// We will now call the function f(player, item, active) | ||
|
||
update_globals(L); | ||
|
||
// Push the lua function on top of the stack | ||
lua_rawgeti(L, LUA_REGISTRYINDEX, lua_function); | ||
|
||
// Push the item on top of the stack. | ||
int item_in_registry; | ||
{ | ||
item** item_userdata = (item**) lua_newuserdata(L, sizeof(item*)); | ||
*item_userdata = item_instance; | ||
|
||
// Save a reference to the item in the registry so that we can deallocate it | ||
// when we're done. | ||
item_in_registry = luah_store_in_registry(L, -1); | ||
|
||
// Set the metatable for the item. | ||
luah_setmetatable(L, "item_metatable"); | ||
} | ||
|
||
// Push the "active" parameter on top of the stack. | ||
lua_pushboolean(L, active); | ||
|
||
// Call the iuse function | ||
int err = lua_pcall(L, 3, 1, 0); | ||
if(err) { | ||
// Error handling. | ||
const char* error = lua_tostring(L, -1); | ||
debugmsg("Error in lua iuse function: %s", error); | ||
} | ||
|
||
// Make sure the now outdated parameters we passed to lua aren't | ||
// being used anymore by setting a metatable that will error on | ||
// access. | ||
luah_remove_from_registry(L, item_in_registry); | ||
luah_setmetatable(L, "outdated_metatable"); | ||
|
||
return lua_tointeger(L, -1); | ||
|
||
#else | ||
|
||
// If LUA isn't defined and for some reason we registered a lua function, | ||
// simply do nothing. | ||
return 0; | ||
|
||
#endif | ||
|
||
} | ||
} |
Oops, something went wrong.