Better META_LUA. Shorter code, moved more stuff intro script.c

This commit is contained in:
nobody_ 2004-01-19 23:24:40 +00:00
parent a89c58a658
commit 57f422d32d
5 changed files with 162 additions and 149 deletions

View file

@ -90,30 +90,39 @@ extern void CleanCclCredits(); /// Free Ccl Credits Memory
-- Functions and data structures.
----------------------------------------------------------------------------*/
/// Script get/set function prototype. The values is on the lua stack.
typedef int ScriptGetSetFunction(void* object, const char* key, lua_State* l);
/// Script get/set function prototype with string key. The value is on the lua stack.
typedef int ScriptGetSetStrFunction(void* object, const char* key, lua_State* l);
/// Script get/set function prototype with int index. The value is on the lua stack.
typedef int ScriptGetSetIntFunction(void* object, int index, lua_State* l);
/// Script garbage collector function prototype.
typedef int ScriptCollectFunction(void* object);
/// Structure for a script proxy type. Make one of those for every scriptable struct.
typedef struct {
ScriptGetSetStrFunction* GetStr; /// Get function with strings.
ScriptGetSetStrFunction* SetStr; /// Set function with strings.
ScriptGetSetIntFunction* GetInt; /// Get function with int index.
ScriptGetSetIntFunction* SetInt; /// Set function with int index.
ScriptCollectFunction* Collect; /// Garbage collection function.
} ScriptProxyType;
/// Structure for a script proxy. Don't mess with this outside of scripting
typedef struct {
void* Object; /// The actual Object
ScriptGetSetFunction* GetFunction; /// Get function
ScriptGetSetFunction* SetFunction; /// Set function
void* Object; /// The actual Object
ScriptProxyType* Type; /// Type information
} ScriptProxy;
/// Userdata Constructor.
extern void ScriptDoCreateUserdata(lua_State* l, void* Object,
ScriptGetSetFunction* GetFunction, ScriptGetSetFunction* SetFunction);
/// Really dumb set function that always goes into an error.
extern int ScriptSetValueBlock(lua_State* l);
/// Userdata Constructor. Push userdata on the stack.
extern void ScriptCreateUserdata(lua_State* l, void* object, ScriptProxyType* type);
/// Really dumb set function that always goes into an error, with string key
extern int ScriptGetSetStrBlock(void* object, const char* key, lua_State* l);
/// Really dumb set function that always goes into an error, with int index
extern int ScriptGetSetIntBlock(void* object, int index, lua_State* l);
/*----------------------------------------------------------------------------
-- Quick macros for meta lua. Use them in well-formed get/set functions.
----------------------------------------------------------------------------*/
/// Macro to call ScriptDoCreateUserdata w/o casts.
#define ScriptCreateUserdata(l, o, g, s) (ScriptDoCreateUserdata(l, o, \
(ScriptGetSetFunction*)(g), (ScriptGetSetFunction*)(s)))
/// Quick way to fail in a function. You can use _C_ like in DebugLevelx
#ifdef DEBUG
#define LuaError(l, args) \
@ -182,6 +191,24 @@ extern int ScriptSetValueBlock(lua_State* l);
} \
}
#define META_GET_FUNC(keyval, v) \
{ \
if (!strcmp(key, keyval)) { \
lua_pushcfunction(l, v); \
return 1; \
} \
}
/*
#define META_SET_FUNC(keyval, v) \
{ \
if (!strcmp(key, keyval)) { \
luaL_checktype(l, -1, LUA_TBOOLEAN); \
v = lua_toboolean(l, -1); \
return 0; \
} \
}*/
#endif // META_LUA
//@}

View file

@ -44,7 +44,7 @@
#define NEW_UNIT_CACHE
// New Lua scripting.
//#define META_LUA
// #define META_LUA
// Dynamic loading.
//#define DYNAMIC_LOAD
@ -52,12 +52,7 @@
//
// Default speed for many things, set it higher for faster actions.
//
#define SPEED_MINE 1 /// Speed factor for mine gold
#define SPEED_GOLD 1 /// Speed factor for getting gold
#define SPEED_CHOP 1 /// Speed factor for chop
#define SPEED_WOOD 1 /// Speed factor for getting wood
#define SPEED_HAUL 1 /// Speed factor for haul oil
#define SPEED_OIL 1 /// Speed factor for getting oil
#define SPEED_RESOURCE 1 /// Speed factor for resources
#define SPEED_BUILD 1 /// Speed factor for building
#define SPEED_TRAIN 1 /// Speed factor for training
#define SPEED_UPGRADE 1 /// Speed factor for upgrading

View file

@ -959,14 +959,17 @@ global int CclCommand(const char* command)
local int ScriptGet(lua_State* l)
{
ScriptProxy* sp;
const char* key;
sp = (ScriptProxy*)lua_touserdata(l, -2);
key = LuaToString(l, -1);
DebugCheck((!sp) || (!key) || (!sp->Object) || (!sp->GetFunction));
DebugLevel3Fn("%p->(%s)\n" _C_ sp _C_ key);
DebugCheck((!sp) || (!sp->Type));
if (sp->Type->GetInt && lua_isnumber(l, -1)) {
return sp->Type->GetInt(sp->Object, lua_tonumber(l, -1), l);
}
if (sp->Type->GetStr && lua_isstring(l, -1)) {
return sp->Type->GetStr(sp->Object, lua_tostring(l, -1), l);
}
return sp->GetFunction(sp->Object, key, l);
LuaError(l, "Only int or string indexing available for userdata, sorry.\n");
}
/**
@ -978,53 +981,56 @@ local int ScriptGet(lua_State* l)
local int ScriptSet(lua_State* l)
{
ScriptProxy* sp;
const char* key;
sp = (ScriptProxy*)lua_touserdata(l, -3);
key = LuaToString(l, -2);
DebugCheck((!sp) || (!key) || (!sp->Object) || (!sp->SetFunction));
DebugLevel3Fn("%p->(%s)\n" _C_ sp _C_ key);
return sp->SetFunction(sp->Object, key, l);
if (sp->Type->SetInt && lua_isnumber(l, -2)) {
return sp->Type->SetInt(sp->Object, lua_tonumber(l, -2), l);
}
if (sp->Type->SetStr && lua_isstring(l, -2)) {
return sp->Type->SetStr(sp->Object, lua_tostring(l, -2), l);
}
LuaError(l, "Only int or string indexing available for userdata, sorry.\n");
}
/**
** Garbage collector function for normal userdata. This is only used inside
** scripting, getting called when lua decides to collect the proxy for a C
** structure.
** Generic Collect Function for a script proxy. Delegate the call to the object's
** Collection function.
**
** @param l The lua state.
**
** @see ScriptCreateUserdata for garbage details.
** @param l The lua state.
*/
local int ScriptCollectUserdata(lua_State* l)
local int ScriptCollect(lua_State* l)
{
ScriptProxy* sp;
char key[20];
sp = (ScriptProxy*)lua_touserdata(l, -1);
DebugLevel3Fn("Collecting ScriptProxy at %p for obj at %p.\n" _C_ sp _C_ sp->Object);
// Remove the key from the table.
lua_pushstring(l, "StratagusReferences");
lua_gettable(l, LUA_REGISTRYINDEX);
sprintf(key, "%p%p%p", sp->Object, sp->GetFunction, sp->SetFunction);
sprintf(key, "%p%p", sp->Object, sp->Type);
lua_pushstring(l, key);
lua_pushnil(l);
lua_settable(l, -3);
lua_remove(l, -1);
/// Call custom garbage collector, if any.
if (sp->Type->Collect) {
return sp->Type->Collect(sp);
}
return 0;
}
/**
** Create a lua proxy for a C structure. This will not always create new
** Push a lua proxy on the stack for a C structure. This will not always create new
** userdata, but use an old one for the same structure. The userdata is pushed on
** the lua stack anyway.
**
** @param l The lua state
** @param Object The Object to create userdata for.
** @param GetFunction The function called to "Get" a value from the structure.
** @param SetFunction The function called to "Set" a value from the structure.
** @param object The Object to create userdata for.
** @param Type Type info for the object
**
** @notes The Object is sent to the get/set functions, otherwise it is not touched.
** @notes Internals. All lua proxies are kept inside a weak table inside the registry.
@ -1033,15 +1039,13 @@ local int ScriptCollectUserdata(lua_State* l)
** Otherwise it create a new userdata, and sets it's metatable. A garbage collection
** proc is called to remove it from the table.
*/
global void ScriptDoCreateUserdata(lua_State* l, void* Object,
ScriptGetSetFunction* GetFunction, ScriptGetSetFunction* SetFunction)
global void ScriptCreateUserdata(lua_State* l, void* object, ScriptProxyType* type)
{
char key[40];
ScriptProxy* sp;
// FIXME: FASTER?
sprintf(key, "%p%p%p", Object, GetFunction, SetFunction);
sprintf(key, "%p%p", object, type);
lua_pushstring(l, "StratagusReferences");
lua_gettable(l, LUA_REGISTRYINDEX);
lua_pushstring(l, key);
@ -1051,9 +1055,8 @@ global void ScriptDoCreateUserdata(lua_State* l, void* Object,
lua_remove(l, -1);
// Create userdata.
sp = (ScriptProxy*)lua_newuserdata(l, sizeof(ScriptProxy));
sp->Object = Object;
sp->GetFunction = GetFunction;
sp->SetFunction = SetFunction;
sp->Object = object;
sp->Type = type;
// Get the standard metatable
lua_pushstring(l, "StratagusStandardMetatable");
lua_gettable(l, LUA_REGISTRYINDEX);
@ -1064,18 +1067,27 @@ global void ScriptDoCreateUserdata(lua_State* l, void* Object,
lua_settable(l, -4);
// Remove StratagusReferences reference
lua_remove(l, -2);
DebugLevel3Fn("Creating ScriptProxy at %p for obj at %p.\n" _C_ lua_touserdata(l, -1) _C_ Object);
DebugLevel3Fn("Creating ScriptProxy at %p for obj at %p.\n" _C_ lua_touserdata(l, -1) _C_ object);
} else {
lua_remove(l, -2);
DebugLevel3Fn("Reusing ScriptProxy at %p for obj at %p.\n" _C_ lua_touserdata(l, -1) _C_ Object);
DebugLevel3Fn("Reusing ScriptProxy at %p for obj at %p.\n" _C_ lua_touserdata(l, -1) _C_ object);
}
}
global int ScriptSetValueBlock(lua_State* l)
/**
** Really dumb set function that always goes into an error, with string key
*/
extern int ScriptGetSetStrBlock(void* object, const char* key, lua_State* l)
{
lua_pushstring(l, "Structure is read-only, sorry.\n");
lua_error(l);
return 0;
LuaError(l, "Access denied");
}
/**
** Really dumb set function that always goes into an error, with int index
*/
extern int ScriptGetSetIntBlock(void* object, int index, lua_State* l)
{
LuaError(l, "Access denied");
}
/**
@ -1149,7 +1161,7 @@ local void InitScript(void)
lua_pushcfunction(Lua, ScriptSet);
lua_settable(Lua, -3);
lua_pushstring(Lua, "__gc");
lua_pushcfunction(Lua, ScriptCollectUserdata);
lua_pushcfunction(Lua, ScriptCollect);
lua_settable(Lua, -3);
lua_settable(Lua, LUA_REGISTRYINDEX);

View file

@ -427,17 +427,17 @@ global void MissileCclRegister(void)
#ifdef META_LUA
/// Get func for SpellType
local int ScriptMissileTypeGet(MissileType* missiletype, const char* key, lua_State* l);
/// Set func for SpellType
local int ScriptMissileTypeSet(MissileType* missiletype, const char* key, lua_State* l);
/// Proxy type for MissileType
local ScriptProxyType ScriptProxyMissileType;
/// Proxy type for the SpellType array
local ScriptProxyType ScriptProxyMissileTypes;
/**
** Create a new missile Type
**
** @param l Lua state
*/
local int ScriptMissileTypesCreate(lua_State* l)
local int ScriptMissileTypeCreate(lua_State* l)
{
const char* name;
MissileType* mtype;
@ -458,8 +458,7 @@ local int ScriptMissileTypesCreate(lua_State* l)
mtype->Flip = 1;
mtype->SplashFactor = 100;
ScriptCreateUserdata(l, mtype,
ScriptMissileTypeGet, ScriptMissileTypeSet);
ScriptCreateUserdata(l, mtype, &ScriptProxyMissileType);
return 1;
}
}
@ -549,32 +548,28 @@ local int ScriptMissileTypeSet(MissileType* mtype, const char* key, lua_State* l
}
/**
** Get function for the big spell namespace.
** Get function for the big missile types namespace, with int index
*/
local int ScriptMissileTypesNamespaceGet(lua_State* l)
local int ScriptMissileTypesGetInt(void* object, int index, lua_State* l)
{
if (index < 0 || index >= NumMissileTypes) {
LuaError(l, "Missile type index out of range");
}
ScriptCreateUserdata(l, MissileTypes[index], &ScriptProxyMissileType);
return 1;
}
/**
** Get function for the big missile types namespace, with string key
*/
local int ScriptMissileTypesGetStr(void* object, const char* key, lua_State* l)
{
int i;
const char* key;
MissileType* mtype;
// Index with number
if (lua_isnumber(l, 2)) {
i = LuaToNumber(l, 2);
DebugLevel3Fn("(%d)\n" _C_ i);
if (i < 0 || i >= NumMissileTypes) {
LuaError(l, "Missile type index out of range");
}
ScriptCreateUserdata(l, MissileTypes[i], ScriptMissileTypeGet, ScriptMissileTypeSet);
return 1;
}
// Index with string.
key = LuaToString(l, 2);
META_GET_INT("n", NumMissileTypes);
META_GET_FUNC("Create", ScriptMissileTypeCreate);
if ((mtype = MissileTypeByIdent(key))) {
ScriptCreateUserdata(l, mtype, ScriptMissileTypeGet, ScriptMissileTypeSet);
ScriptCreateUserdata(l, mtype, &ScriptProxyMissileType);
return 1;
}
@ -588,26 +583,21 @@ local int ScriptMissileTypesNamespaceGet(lua_State* l)
*/
global void ScriptMissileTypesInit(void)
{
// Create Stratagus.Missiles namespace.
// No userdata, there's no data. And no finalizer
ScriptProxyMissileType.GetStr = (ScriptGetSetStrFunction *)ScriptMissileTypeGet;
ScriptProxyMissileType.SetStr = (ScriptGetSetStrFunction *)ScriptMissileTypeSet;
ScriptProxyMissileType.GetInt = ScriptGetSetIntBlock;
ScriptProxyMissileType.SetInt = ScriptGetSetIntBlock;
ScriptProxyMissileType.Collect = 0;
ScriptProxyMissileTypes.GetStr = (ScriptGetSetStrFunction *)ScriptMissileTypesGetStr;
ScriptProxyMissileTypes.SetStr = ScriptGetSetStrBlock;
ScriptProxyMissileTypes.GetInt = (ScriptGetSetIntFunction *)ScriptMissileTypesGetInt;
ScriptProxyMissileTypes.SetInt = ScriptGetSetIntBlock;
ScriptProxyMissileTypes.Collect = 0;
// Create Stratagus.MissileTypes namespace.
lua_pushstring(Lua, "MissileTypes");
lua_newtable(Lua);
// Generate the metatable
lua_newtable(Lua);
lua_pushstring(Lua, "__index");
lua_pushcfunction(Lua, ScriptMissileTypesNamespaceGet);
lua_settable(Lua, -3);
lua_pushstring(Lua, "__newindex");
lua_pushcfunction(Lua, ScriptSetValueBlock); // Read-Only
lua_settable(Lua, -3);
lua_setmetatable(Lua, -2);
// Add functions.
lua_pushstring(Lua, "Create");
lua_pushcfunction(Lua, ScriptMissileTypesCreate);
lua_rawset(Lua, -3);
ScriptCreateUserdata(Lua, 0, &ScriptProxyMissileTypes);
lua_rawset(Lua, -3);
}

View file

@ -1013,10 +1013,10 @@ global void SaveSpells(CLFile* file)
#ifdef META_LUA
/// Get func for SpellType
local int ScriptSpellGet(SpellType* spell, const char* key, lua_State* l);
/// Set func for SpellType
local int ScriptSpellSet(SpellType* spell, const char* key, lua_State* l);
/// Proxy type for SpellType
local ScriptProxyType ScriptProxySpell;
/// Proxy type for the SpellType array
local ScriptProxyType ScriptProxySpellTypes;
//
// Functions directly acessible from lua. Placed in the stratagus namespace.
@ -1045,7 +1045,7 @@ local int ScriptSpellCreate(lua_State* l)
spell->Slot = SpellTypeCount - 1;
spell->Ident = strdup(name);
spell->DependencyId = -1;
ScriptCreateUserdata(l, spell, ScriptSpellGet, ScriptSpellSet);
ScriptCreateUserdata(l, spell, &ScriptProxySpell);
return 1;
}
}
@ -1120,34 +1120,28 @@ local int ScriptSpellSet(SpellType* spell, const char* key, lua_State* l)
}
/**
** Get function for the big spell namespace.
** Get function for the big spell namespace, with int index
*/
local int ScriptSpellNamespaceGet(lua_State* l)
local int ScriptSpellTypesGetInt(void* object, int index, lua_State* l)
{
if (index < 0 || index >= SpellTypeCount) {
LuaError(l, "Spell index out of range");
}
ScriptCreateUserdata(l, SpellTypeTable[index], &ScriptProxySpell);
return 1;
}
/**
** Get function for the big spell namespace, with string key
*/
local int ScriptSpellTypesGetStr(void* object, const char* key, lua_State* l)
{
int i;
const char* key;
SpellType* spell;
// Index with number
if (lua_isnumber(l, 2)) {
i = LuaToNumber(l, 2);
DebugLevel3Fn("(%d)\n" _C_ i);
if (i < 0 || i >= SpellTypeCount) {
LuaError(l, "Spell index out of range");
}
ScriptCreateUserdata(l, SpellTypeTable[i], ScriptSpellGet, ScriptSpellSet);
return 1;
}
// Index with string. FIXME: hashtable? :)
key = LuaToString(l, 2);
DebugCheck(!key);
DebugLevel3Fn("(%s)\n" _C_ key);
META_GET_INT("n", SpellTypeCount);
META_GET_FUNC("Create", ScriptSpellCreate);
if ((spell = SpellTypeByIdent(key))) {
ScriptCreateUserdata(l, spell, ScriptSpellGet, ScriptSpellSet);
ScriptCreateUserdata(l, spell, &ScriptProxySpell);
return 1;
}
@ -1159,26 +1153,21 @@ local int ScriptSpellNamespaceGet(lua_State* l)
*/
global void ScriptSpellInit(void)
{
ScriptProxySpell.GetStr = (ScriptGetSetStrFunction *)ScriptSpellGet;
ScriptProxySpell.SetStr = (ScriptGetSetStrFunction *)ScriptSpellSet;
ScriptProxySpell.GetInt = ScriptGetSetIntBlock;
ScriptProxySpell.SetInt = ScriptGetSetIntBlock;
ScriptProxySpell.Collect = 0;
ScriptProxySpellTypes.GetStr = (ScriptGetSetStrFunction *)ScriptSpellTypesGetStr;
ScriptProxySpellTypes.SetStr = ScriptGetSetStrBlock;
ScriptProxySpellTypes.GetInt = (ScriptGetSetIntFunction *)ScriptSpellTypesGetInt;
ScriptProxySpellTypes.SetInt = ScriptGetSetIntBlock;
ScriptProxySpellTypes.Collect = 0;
// Create Stratagus.Spells namespace.
// No userdata, there's no data. And no finalizer
lua_pushstring(Lua, "Spells");
lua_newtable(Lua);
// Generate the metatable
lua_newtable(Lua);
lua_pushstring(Lua, "__index");
lua_pushcfunction(Lua, ScriptSpellNamespaceGet);
lua_settable(Lua, -3);
lua_pushstring(Lua, "__newindex");
lua_pushcfunction(Lua, ScriptSetValueBlock); // Read-Only
lua_settable(Lua, -3);
lua_setmetatable(Lua, -2);
// Add functions.
lua_pushstring(Lua, "Create");
lua_pushcfunction(Lua, ScriptSpellCreate);
lua_rawset(Lua, -3);
ScriptCreateUserdata(Lua, 0, &ScriptProxySpellTypes);
lua_rawset(Lua, -3);
}