From 57f422d32d82a1e4c78e91717462158b106f6f30 Mon Sep 17 00:00:00 2001 From: nobody_ <> Date: Mon, 19 Jan 2004 23:24:40 +0000 Subject: [PATCH] Better META_LUA. Shorter code, moved more stuff intro script.c --- src/include/script.h | 55 ++++++++++++++------ src/include/stratagus.h | 9 +--- src/stratagus/script.cpp | 86 ++++++++++++++++++-------------- src/stratagus/script_missile.cpp | 82 +++++++++++++----------------- src/stratagus/script_spell.cpp | 79 +++++++++++++---------------- 5 files changed, 162 insertions(+), 149 deletions(-) diff --git a/src/include/script.h b/src/include/script.h index 72814cfbc..a5fff4b3b 100644 --- a/src/include/script.h +++ b/src/include/script.h @@ -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 //@} diff --git a/src/include/stratagus.h b/src/include/stratagus.h index f570e840b..2ac90a19c 100644 --- a/src/include/stratagus.h +++ b/src/include/stratagus.h @@ -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 diff --git a/src/stratagus/script.cpp b/src/stratagus/script.cpp index 5c047a65b..360ce4520 100644 --- a/src/stratagus/script.cpp +++ b/src/stratagus/script.cpp @@ -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); diff --git a/src/stratagus/script_missile.cpp b/src/stratagus/script_missile.cpp index 4b98b15be..18aa21452 100644 --- a/src/stratagus/script_missile.cpp +++ b/src/stratagus/script_missile.cpp @@ -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); } diff --git a/src/stratagus/script_spell.cpp b/src/stratagus/script_spell.cpp index 73e490aea..f98af35b3 100644 --- a/src/stratagus/script_spell.cpp +++ b/src/stratagus/script_spell.cpp @@ -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); }