2012-03-24 03:25:10 -06:00
|
|
|
/*
|
|
|
|
https://github.com/peterix/dfhack
|
2012-09-29 20:03:37 -06:00
|
|
|
Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com)
|
2012-03-24 03:25:10 -06:00
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any
|
|
|
|
damages arising from the use of this software.
|
|
|
|
|
|
|
|
Permission is granted to anyone to use this software for any
|
|
|
|
purpose, including commercial applications, and to alter it and
|
|
|
|
redistribute it freely, subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must
|
|
|
|
not claim that you wrote the original software. If you use this
|
|
|
|
software in a product, an acknowledgment in the product documentation
|
|
|
|
would be appreciated but is not required.
|
|
|
|
|
|
|
|
2. Altered source versions must be plainly marked as such, and
|
|
|
|
must not be misrepresented as being the original software.
|
|
|
|
|
|
|
|
3. This notice may not be removed or altered from any source
|
|
|
|
distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <sstream>
|
|
|
|
#include <vector>
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
#include "DataDefs.h"
|
|
|
|
|
|
|
|
#include <lua.h>
|
|
|
|
#include <lauxlib.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal header file of the lua wrapper.
|
|
|
|
*/
|
|
|
|
|
2015-08-11 20:59:19 -06:00
|
|
|
|
|
|
|
namespace DFHack {
|
|
|
|
struct FunctionReg;
|
|
|
|
namespace LuaWrapper {
|
2012-04-01 08:34:04 -06:00
|
|
|
struct LuaToken;
|
2012-03-24 03:25:10 -06:00
|
|
|
|
2012-04-01 08:34:04 -06:00
|
|
|
/**
|
|
|
|
* Metatable pkey: type identity of the object
|
|
|
|
*/
|
|
|
|
extern LuaToken DFHACK_IDENTITY_FIELD_TOKEN;
|
2012-03-24 03:25:10 -06:00
|
|
|
|
2012-04-01 08:34:04 -06:00
|
|
|
/**
|
|
|
|
* Registry pkey: hash of type metatables <-> type identities.
|
|
|
|
*/
|
|
|
|
extern LuaToken DFHACK_TYPETABLE_TOKEN;
|
2012-03-24 03:25:10 -06:00
|
|
|
|
2012-04-01 08:34:04 -06:00
|
|
|
/**
|
|
|
|
* Registry pkey: hash of type identity -> node in df.etc...
|
|
|
|
*/
|
|
|
|
extern LuaToken DFHACK_TYPEID_TABLE_TOKEN;
|
2012-03-24 03:25:10 -06:00
|
|
|
|
2012-04-01 08:34:04 -06:00
|
|
|
/**
|
|
|
|
* Registry pkey: hash of enum/bitfield identity -> index lookup table
|
|
|
|
*/
|
|
|
|
extern LuaToken DFHACK_ENUM_TABLE_TOKEN;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registry pkey: hash of pointer target identity <-> adhoc pointer identity userdata.
|
|
|
|
*/
|
|
|
|
extern LuaToken DFHACK_PTR_IDTABLE_TOKEN;
|
2012-03-24 03:25:10 -06:00
|
|
|
|
|
|
|
// Function registry names
|
|
|
|
#define DFHACK_CHANGEERROR_NAME "DFHack::ChangeError"
|
|
|
|
#define DFHACK_COMPARE_NAME "DFHack::ComparePtrs"
|
|
|
|
#define DFHACK_TYPE_TOSTRING_NAME "DFHack::TypeToString"
|
|
|
|
#define DFHACK_SIZEOF_NAME "DFHack::Sizeof"
|
|
|
|
#define DFHACK_DISPLACE_NAME "DFHack::Displace"
|
|
|
|
#define DFHACK_NEW_NAME "DFHack::New"
|
|
|
|
#define DFHACK_ASSIGN_NAME "DFHack::Assign"
|
2012-04-01 07:32:57 -06:00
|
|
|
#define DFHACK_IS_INSTANCE_NAME "DFHack::IsInstance"
|
2012-03-25 05:48:18 -06:00
|
|
|
#define DFHACK_DELETE_NAME "DFHack::Delete"
|
2012-06-13 12:26:54 -06:00
|
|
|
#define DFHACK_CAST_NAME "DFHack::Cast"
|
2012-04-01 08:34:04 -06:00
|
|
|
|
|
|
|
extern LuaToken DFHACK_EMPTY_TABLE_TOKEN;
|
2012-03-24 03:25:10 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Upvalue: contents of DFHACK_TYPETABLE_NAME
|
|
|
|
*/
|
|
|
|
#define UPVAL_TYPETABLE lua_upvalueindex(1)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Expected metatable of the current object.
|
|
|
|
*/
|
|
|
|
#define UPVAL_METATABLE lua_upvalueindex(2)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Table mapping field names to indices or data structure pointers.
|
|
|
|
* Enum index table is linked into here via getmetatable($).__index.
|
|
|
|
* Fields that are actually in UPVAL_METATABLE are marked with NULL light udata.
|
|
|
|
*/
|
|
|
|
#define UPVAL_FIELDTABLE lua_upvalueindex(3)
|
2012-03-24 06:28:53 -06:00
|
|
|
#define UPVAL_METHOD_NAME lua_upvalueindex(3)
|
2012-03-24 03:25:10 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Only for containers: light udata with container identity.
|
|
|
|
*/
|
|
|
|
#define UPVAL_CONTAINER_ID lua_upvalueindex(4)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only for containers: light udata with item identity.
|
|
|
|
*/
|
|
|
|
#define UPVAL_ITEM_ID lua_upvalueindex(5)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only for containers: if not nil, overrides the item count.
|
|
|
|
*/
|
|
|
|
#define UPVAL_ITEM_COUNT lua_upvalueindex(6)
|
|
|
|
|
|
|
|
inline void lua_dup(lua_State *state) { lua_pushvalue(state, -1); }
|
|
|
|
inline void lua_swap(lua_State *state) { lua_insert(state, -2); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Object references are represented as userdata instances
|
|
|
|
* with an appropriate metatable; the payload of userdata is
|
|
|
|
* this structure:
|
|
|
|
*/
|
|
|
|
struct DFRefHeader {
|
|
|
|
void *ptr;
|
2020-04-08 22:02:07 -06:00
|
|
|
const struct_field_info *field_info;
|
2021-03-30 14:55:06 -06:00
|
|
|
const void *tag_ptr;
|
|
|
|
const type_identity *tag_identity;
|
|
|
|
const char *tag_attr;
|
2012-03-24 03:25:10 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Push the pointer as DF object ref using metatable on the stack.
|
|
|
|
*/
|
|
|
|
void push_object_ref(lua_State *state, void *ptr);
|
2020-02-14 18:47:26 -07:00
|
|
|
DFHACK_EXPORT void *get_object_ref(lua_State *state, int val_index);
|
2020-04-08 22:02:07 -06:00
|
|
|
DFHACK_EXPORT DFRefHeader *get_object_ref_header(lua_State *state, int val_index);
|
2012-03-24 03:25:10 -06:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Report an error while accessing a field (index = field name).
|
|
|
|
*/
|
|
|
|
void field_error(lua_State *state, int index, const char *err, const char *mode);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If is_method is true, these use UPVAL_TYPETABLE to save a hash lookup.
|
|
|
|
*/
|
|
|
|
void push_object_internal(lua_State *state, type_identity *type, void *ptr, bool in_method = true);
|
|
|
|
void *get_object_internal(lua_State *state, type_identity *type, int val_index, bool exact_type, bool in_method = true);
|
|
|
|
|
|
|
|
void push_adhoc_pointer(lua_State *state, void *ptr, type_identity *target);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Verify that the object is a DF ref with UPVAL_METATABLE.
|
|
|
|
* If everything ok, extract the address.
|
|
|
|
*/
|
Allow plugins to export functions to lua with safe reload support.
- To ensure reload safety functions have to be wrapped. Every call
checks the loaded state and locks a mutex in Plugin. If the plugin
is unloaded, calling its functions throws a lua error. Therefore,
plugins may not create closures or export yieldable functions.
- The set of function argument and return types supported by
LuaWrapper is severely limited when compared to being compiled
inside the main library.
Currently supported types: numbers, bool, std::string, df::foo,
df::foo*, std::vector<bool>, std::vector<df::foo*>.
- To facilitate postponing initialization until after all plugins
have been loaded, the core sends a SC_CORE_INITIALIZED event.
- As an example, the burrows plugin now exports its functions.
2012-04-14 09:44:07 -06:00
|
|
|
DFHACK_EXPORT uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode);
|
2012-03-24 03:25:10 -06:00
|
|
|
|
Implement recursive transfer of values from lua to c++ structures.
E.g. df.global.cursor = { x = 1, y = 2, z = 3 }. The lua data
must be represented by raw lua tables.
For structs, the entries in the table are assigned to matching fields.
For containers, if a 'resize' field is missing or nil, the table is
treated like 1-based lua array, and the container is resized to match
its # length. Otherwise, the field must be either an explicit number,
true or false. If it is true, the size is selected by the highest index
in the table. After that, entries are copied using 0-based indices.
For pointers, the table must match the target object. If the pointer
is null, the object is auto-allocated; this can be controlled using
the 'new' field, the value of which will be passed to df.new().
2012-03-27 11:47:52 -06:00
|
|
|
bool is_type_compatible(lua_State *state, type_identity *type1, int meta1,
|
|
|
|
type_identity *type2, int meta2, bool exact_equal);
|
|
|
|
|
2020-02-14 18:47:26 -07:00
|
|
|
DFHACK_EXPORT
|
Implement recursive transfer of values from lua to c++ structures.
E.g. df.global.cursor = { x = 1, y = 2, z = 3 }. The lua data
must be represented by raw lua tables.
For structs, the entries in the table are assigned to matching fields.
For containers, if a 'resize' field is missing or nil, the table is
treated like 1-based lua array, and the container is resized to match
its # length. Otherwise, the field must be either an explicit number,
true or false. If it is true, the size is selected by the highest index
in the table. After that, entries are copied using 0-based indices.
For pointers, the table must match the target object. If the pointer
is null, the object is auto-allocated; this can be controlled using
the 'new' field, the value of which will be passed to df.new().
2012-03-27 11:47:52 -06:00
|
|
|
type_identity *get_object_identity(lua_State *state, int objidx,
|
|
|
|
const char *ctx, bool allow_type = false,
|
|
|
|
bool keep_metatable = false);
|
|
|
|
|
2012-04-01 08:34:04 -06:00
|
|
|
void LookupInTable(lua_State *state, void *id, LuaToken *tname);
|
|
|
|
void SaveInTable(lua_State *state, void *node, LuaToken *tname);
|
2012-03-24 03:25:10 -06:00
|
|
|
void SaveTypeInfo(lua_State *state, void *node);
|
|
|
|
|
2012-03-29 04:39:13 -06:00
|
|
|
void AssociateId(lua_State *state, int table, int val, const char *name);
|
|
|
|
|
2012-03-24 03:25:10 -06:00
|
|
|
/**
|
|
|
|
* Look up the key on the stack in DFHACK_TYPETABLE;
|
|
|
|
* if found, put result on the stack and return true.
|
|
|
|
*/
|
|
|
|
bool LookupTypeInfo(lua_State *state, bool in_method);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make a metatable with most common fields, and an empty table for UPVAL_FIELDTABLE.
|
|
|
|
*/
|
|
|
|
void MakeMetatable(lua_State *state, type_identity *type, const char *kind);
|
|
|
|
/**
|
|
|
|
* Enable a metafield by injecting an entry into a UPVAL_FIELDTABLE.
|
|
|
|
*/
|
|
|
|
void EnableMetaField(lua_State *state, int ftable_idx, const char *name, void *id = NULL);
|
|
|
|
/**
|
|
|
|
* Set metatable properties common to all actual DF object references.
|
|
|
|
*/
|
|
|
|
void SetPtrMethods(lua_State *state, int meta_idx, int read_idx);
|
2012-03-29 04:39:13 -06:00
|
|
|
/**
|
|
|
|
* Add a __pairs/__ipairs metamethod using iterator on the top of stack.
|
|
|
|
*/
|
|
|
|
void SetPairsMethod(lua_State *state, int meta_idx, const char *name);
|
|
|
|
/**
|
|
|
|
* Add a struct-style (3 upvalues) metamethod to the stack.
|
|
|
|
*/
|
|
|
|
void PushStructMethod(lua_State *state, int meta_idx, int ftable_idx,
|
|
|
|
lua_CFunction function);
|
2012-03-24 03:25:10 -06:00
|
|
|
/**
|
|
|
|
* Add a struct-style (3 upvalues) metamethod to the metatable.
|
|
|
|
*/
|
|
|
|
void SetStructMethod(lua_State *state, int meta_idx, int ftable_idx,
|
|
|
|
lua_CFunction function, const char *name);
|
2012-03-29 04:39:13 -06:00
|
|
|
/**
|
|
|
|
* Add a 6 upvalue metamethod to the stack.
|
|
|
|
*/
|
|
|
|
void PushContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
|
|
|
|
lua_CFunction function,
|
|
|
|
type_identity *container, type_identity *item, int count);
|
2012-03-24 03:25:10 -06:00
|
|
|
/**
|
|
|
|
* Add a 6 upvalue metamethod to the metatable.
|
|
|
|
*/
|
|
|
|
void SetContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
|
|
|
|
lua_CFunction function, const char *name,
|
|
|
|
type_identity *container, type_identity *item, int count);
|
|
|
|
/**
|
|
|
|
* If ienum refers to a valid enum, attach its keys to UPVAL_FIELDTABLE,
|
2012-03-29 04:39:13 -06:00
|
|
|
* and the enum itself to the _enum metafield. Pushes the key table on the stack.
|
2012-03-24 03:25:10 -06:00
|
|
|
*/
|
|
|
|
void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum);
|
2012-04-05 09:55:59 -06:00
|
|
|
|
2012-04-15 09:09:25 -06:00
|
|
|
/**
|
|
|
|
* Push a closure invoking the given function.
|
|
|
|
*/
|
|
|
|
void PushFunctionWrapper(lua_State *state, int meta_idx,
|
|
|
|
const char *name, function_identity_base *fun);
|
|
|
|
|
2012-04-05 01:59:39 -06:00
|
|
|
/**
|
2012-04-05 09:55:59 -06:00
|
|
|
* Wrap functions and add them to the table on the top of the stack.
|
2012-04-05 01:59:39 -06:00
|
|
|
*/
|
2015-08-11 20:59:19 -06:00
|
|
|
typedef DFHack::FunctionReg FunctionReg;
|
2012-04-05 09:55:59 -06:00
|
|
|
void SetFunctionWrappers(lua_State *state, const FunctionReg *reg);
|
2012-03-25 05:20:58 -06:00
|
|
|
|
Allow plugins to export functions to lua with safe reload support.
- To ensure reload safety functions have to be wrapped. Every call
checks the loaded state and locks a mutex in Plugin. If the plugin
is unloaded, calling its functions throws a lua error. Therefore,
plugins may not create closures or export yieldable functions.
- The set of function argument and return types supported by
LuaWrapper is severely limited when compared to being compiled
inside the main library.
Currently supported types: numbers, bool, std::string, df::foo,
df::foo*, std::vector<bool>, std::vector<df::foo*>.
- To facilitate postponing initialization until after all plugins
have been loaded, the core sends a SC_CORE_INITIALIZED event.
- As an example, the burrows plugin now exports its functions.
2012-04-14 09:44:07 -06:00
|
|
|
int method_wrapper_core(lua_State *state, function_identity_base *id);
|
|
|
|
|
2012-03-25 05:20:58 -06:00
|
|
|
void IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct);
|
2012-03-31 05:40:54 -06:00
|
|
|
|
|
|
|
void AttachDFGlobals(lua_State *state);
|
2012-03-24 03:25:10 -06:00
|
|
|
}}
|
|
|
|
|