diff --git a/ElunaTemplate.h b/ElunaTemplate.h index 215c448..98fa444 100644 --- a/ElunaTemplate.h +++ b/ElunaTemplate.h @@ -15,6 +15,7 @@ extern "C" }; #include "LuaEngine.h" #include "ElunaUtility.h" +#include "SharedDefines.h" class ElunaGlobal { @@ -73,22 +74,32 @@ public: { } + // Get wrapped object pointer void* GetObj() const { return object; } + // Returns whether the object is valid or not bool IsValid() const { return _isvalid; } + // Returns whether the object can be invalidated or not bool CanInvalidate() const { return _invalidate; } + // Sets the object pointer that is wrapped void SetObj(void* obj) { + ASSERT(obj); object = obj; + SetValid(true); } + // Sets the object pointer to valid or invalid void SetValid(bool valid) { - _isvalid = object && valid; + ASSERT(!valid || (valid && object)); + _isvalid = valid; } + // Sets whether the pointer will be invalidated at end of calls void SetValidation(bool invalidate) { _invalidate = invalidate; } + // Invalidates the pointer if it should be invalidated void Invalidate() { if (CanInvalidate()) @@ -138,15 +149,12 @@ public: int metatable = lua_gettop(E->L); // tostring - lua_pushcfunction(E->L, tostringT); + lua_pushcfunction(E->L, ToString); lua_setfield(E->L, metatable, "__tostring"); // garbage collecting - if (manageMemory) - { - lua_pushcfunction(E->L, gcT); - lua_setfield(E->L, metatable, "__gc"); - } + lua_pushcfunction(E->L, CollectGarbage); + lua_setfield(E->L, metatable, "__gc"); // make methods accessible through metatable lua_pushvalue(E->L, methods); @@ -156,10 +164,66 @@ public: lua_pushvalue(E->L, methods); lua_setfield(E->L, metatable, "__newindex"); + // make new indexes saved to methods + lua_pushcfunction(E->L, Add); + lua_setfield(E->L, metatable, "__add"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Substract); + lua_setfield(E->L, metatable, "__sub"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Multiply); + lua_setfield(E->L, metatable, "__mul"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Divide); + lua_setfield(E->L, metatable, "__div"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Mod); + lua_setfield(E->L, metatable, "__mod"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Pow); + lua_setfield(E->L, metatable, "__pow"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, UnaryMinus); + lua_setfield(E->L, metatable, "__unm"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Concat); + lua_setfield(E->L, metatable, "__concat"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Length); + lua_setfield(E->L, metatable, "__len"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Equal); + lua_setfield(E->L, metatable, "__eq"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Less); + lua_setfield(E->L, metatable, "__lt"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, LessOrEqual); + lua_setfield(E->L, metatable, "__le"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Call); + lua_setfield(E->L, metatable, "__call"); + // special method to get the object type - lua_pushcfunction(E->L, typeT); + lua_pushcfunction(E->L, GetType); lua_setfield(E->L, methods, "GetObjectType"); + // special method to decide object invalidation at end of call + lua_pushcfunction(E->L, SetInvalidation); + lua_setfield(E->L, methods, "SetInvalidation"); + // pop methods and metatable lua_pop(E->L, 2); } @@ -192,14 +256,14 @@ public: lua_pushstring(E->L, methodTable->name); lua_pushlightuserdata(E->L, (void*)methodTable); lua_pushlightuserdata(E->L, (void*)E); - lua_pushcclosure(E->L, thunk, 2); + lua_pushcclosure(E->L, CallMethod, 2); lua_settable(E->L, -3); } lua_remove(E->L, -1); } - static int push(lua_State* L, T const* obj) + static int Push(lua_State* L, T const* obj) { if (!obj) { @@ -213,14 +277,13 @@ public: ASSERT(lua_istable(L, -1)); lua_pushfstring(L, "%p", obj); lua_gettable(L, -2); - if (!lua_isnoneornil(L, -1) && luaL_checkudata(L, -1, tname)) + if (ElunaObject* elunaObj = Eluna::CHECKTYPE(L, -1, tname, false)) { + // set userdata valid + elunaObj->SetValid(true); + // remove userdata_table, leave userdata lua_remove(L, -2); - - // set userdata valid - if (ElunaObject* elunaObj = Eluna::CHECKOBJ(L, -1, false)) - elunaObj->SetValid(true); return 1; } lua_remove(L, -1); @@ -259,10 +322,9 @@ public: return 1; } - static T* check(lua_State* L, int narg, bool error = true) + static T* Check(lua_State* L, int narg, bool error = true) { - ElunaObject* elunaObj = Eluna::CHECKOBJ(L, narg, error); - + ElunaObject* elunaObj = Eluna::CHECKTYPE(L, narg, tname, error); if (!elunaObj) return NULL; @@ -308,27 +370,22 @@ public: return static_cast(elunaObj->GetObj()); } - static int typeT(lua_State* L) + static int GetType(lua_State* L) { lua_pushstring(L, tname); return 1; } - // Remember special case ElunaTemplate::gcT - static int gcT(lua_State* L) + static int SetInvalidation(lua_State* L) { - // Get object pointer (and check type, no error) - ElunaObject** ptrHold = static_cast(luaL_testudata(L, -1, tname)); - if (ptrHold) - { - if (manageMemory) - delete static_cast((*ptrHold)->GetObj()); - delete *ptrHold; - } + ElunaObject* elunaObj = Eluna::CHECKOBJ(L, 1); + bool invalidate = Eluna::CHECKVAL(L, 2); + + elunaObj->SetValidation(invalidate); return 0; } - static int thunk(lua_State* L) + static int CallMethod(lua_State* L) { T* obj = Eluna::CHECKOBJ(L, 1); // get self if (!obj) @@ -348,15 +405,74 @@ public: return 0; } - static int tostringT(lua_State* L) + // Metamethods ("virtual") + + // Remember special cases like ElunaTemplate::CollectGarbage + static int CollectGarbage(lua_State* L) { - T* obj = Eluna::CHECKOBJ(L, 1); // get self - if (obj) - lua_pushfstring(L, "%s: (%p)", tname, obj); - else - lua_pushstring(L, "nil"); + // Get object pointer (and check type, no error) + ElunaObject* obj = Eluna::CHECKOBJ(L, 1, false); + if (obj && manageMemory) + delete static_cast(obj->GetObj()); + delete obj; + return 0; + } + + static int ToString(lua_State* L) + { + T* obj = Eluna::CHECKOBJ(L, 1, true); // get self + lua_pushfstring(L, "%s: (%p)", tname, obj); return 1; } + + static int Add(lua_State* L) { return 0; } + static int Substract(lua_State* L) { return 0; } + static int Multiply(lua_State* L) { return 0; } + static int Divide(lua_State* L) { return 0; } + static int Mod(lua_State* L) { return 0; } + static int Pow(lua_State* L) { return 0; } + static int UnaryMinus(lua_State* L) { return 0; } + static int Concat(lua_State* L) { return 0; } + static int Length(lua_State* L) { return 0; } + static int Equal(lua_State* L) { return 0; } + static int Less(lua_State* L) { return 0; } + static int LessOrEqual(lua_State* L) { return 0; } + static int Call(lua_State* L) { return 0; } }; +// +//template const char* ElunaTemplate::tname; +//template bool ElunaTemplate::manageMemory; + +#if (!defined(TBC) && !defined(CLASSIC)) +template<> int ElunaTemplate::CollectGarbage(lua_State* L); +#endif + +template<> int ElunaTemplate::Add(lua_State* L); +template<> int ElunaTemplate::Substract(lua_State* L); +template<> int ElunaTemplate::Multiply(lua_State* L); +template<> int ElunaTemplate::Divide(lua_State* L); +template<> int ElunaTemplate::Mod(lua_State* L); +template<> int ElunaTemplate::Pow(lua_State* L); +// template<> int ElunaTemplate::UnaryMinus(lua_State* L); +template<> int ElunaTemplate::Concat(lua_State* L); +template<> int ElunaTemplate::Length(lua_State* L); +template<> int ElunaTemplate::Equal(lua_State* L); +template<> int ElunaTemplate::Less(lua_State* L); +template<> int ElunaTemplate::LessOrEqual(lua_State* L); +template<> int ElunaTemplate::Call(lua_State* L); + +template<> int ElunaTemplate::Add(lua_State* L); +template<> int ElunaTemplate::Substract(lua_State* L); +template<> int ElunaTemplate::Multiply(lua_State* L); +template<> int ElunaTemplate::Divide(lua_State* L); +template<> int ElunaTemplate::Mod(lua_State* L); +template<> int ElunaTemplate::Pow(lua_State* L); +template<> int ElunaTemplate::UnaryMinus(lua_State* L); +template<> int ElunaTemplate::Concat(lua_State* L); +template<> int ElunaTemplate::Length(lua_State* L); +template<> int ElunaTemplate::Equal(lua_State* L); +template<> int ElunaTemplate::Less(lua_State* L); +template<> int ElunaTemplate::LessOrEqual(lua_State* L); +template<> int ElunaTemplate::Call(lua_State* L); #endif diff --git a/LuaEngine.cpp b/LuaEngine.cpp index f97ff78..ddd5eac 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -22,8 +22,11 @@ extern "C" { +// Base lua libraries #include "lualib.h" #include "lauxlib.h" + +// Additional lua libraries }; Eluna::ScriptList Eluna::lua_scripts; @@ -132,8 +135,12 @@ ItemEventBindings(new EntryBind("ItemEvents", *this)), ItemGossipBindings(new EntryBind("GossipEvents (item)", *this)), playerGossipBindings(new EntryBind("GossipEvents (player)", *this)) { - // open base lua + // open base lua libraries luaL_openlibs(L); + + // open additional lua libraries + + // Register methods and functions RegisterFunctions(this); // Create hidden table with weak values @@ -443,16 +450,20 @@ void Eluna::Push(lua_State* L) } void Eluna::Push(lua_State* L, const uint64 l) { - std::ostringstream ss; - ss << l; - Push(L, ss.str()); + ElunaTemplate::Push(L, new uint64(l)); } void Eluna::Push(lua_State* L, const int64 l) { - std::ostringstream ss; - ss << l; - Push(L, ss.str()); + ElunaTemplate::Push(L, new int64(l)); } +//void Eluna::Push(lua_State* L, const time_t l) +//{ +// ElunaTemplate::Push(L, new uint64(l)); +//} +//void Eluna::Push(lua_State* L, const size_t l) +//{ +// ElunaTemplate::Push(L, new int64(l)); +//} void Eluna::Push(lua_State* L, const uint32 u) { lua_pushunsigned(L, u); @@ -505,7 +516,7 @@ void Eluna::Push(lua_State* L, Unit const* unit) Push(L, unit->ToPlayer()); break; default: - ElunaTemplate::push(L, unit); + ElunaTemplate::Push(L, unit); } } void Eluna::Push(lua_State* L, WorldObject const* obj) @@ -530,7 +541,7 @@ void Eluna::Push(lua_State* L, WorldObject const* obj) Push(L, obj->ToCorpse()); break; default: - ElunaTemplate::push(L, obj); + ElunaTemplate::Push(L, obj); } } void Eluna::Push(lua_State* L, Object const* obj) @@ -555,7 +566,7 @@ void Eluna::Push(lua_State* L, Object const* obj) Push(L, obj->ToCorpse()); break; default: - ElunaTemplate::push(L, obj); + ElunaTemplate::Push(L, obj); } } @@ -642,30 +653,28 @@ template<> std::string Eluna::CHECKVAL(lua_State* L, int narg) } template<> int64 Eluna::CHECKVAL(lua_State* L, int narg) { - const char* c_str = CHECKVAL(L, narg, NULL); - if (!c_str) - return luaL_argerror(L, narg, "int64 (as string) expected"); - - int64 l = 0; - int parsed_count = sscanf(c_str, SI64FMTD, &l); - if (parsed_count != 1) - return luaL_argerror(L, narg, "int64 (as string) could not be converted"); - - return l; + if (lua_isnumber(L, narg)) + return static_cast(CHECKVAL(L, narg)); + return *(Eluna::CHECKOBJ(L, narg, true)); } template<> uint64 Eluna::CHECKVAL(lua_State* L, int narg) { - const char* c_str = CHECKVAL(L, narg, NULL); - if (!c_str) - return luaL_argerror(L, narg, "uint64 (as string) expected"); - - uint64 l = 0; - int parsed_count = sscanf(c_str, UI64FMTD, &l); - if (parsed_count != 1) - return luaL_argerror(L, narg, "uint64 (as string) could not be converted"); - - return l; + if (lua_isnumber(L, narg)) + return static_cast(CHECKVAL(L, narg)); + return *(Eluna::CHECKOBJ(L, narg, true)); } +//template<> time_t Eluna::CHECKVAL(lua_State* L, int narg) +//{ +// if (lua_isnumber(L, narg)) +// return static_cast(CHECKVAL(L, narg)); +// return static_cast(*(Eluna::CHECKOBJ(L, narg, true))); +//} +//template<> size_t Eluna::CHECKVAL(lua_State* L, int narg) +//{ +// if (lua_isnumber(L, narg)) +// return static_cast(CHECKVAL(L, narg)); +// return static_cast(*(Eluna::CHECKOBJ(L, narg, true))); +//} #define TEST_OBJ(T, O, R, F)\ {\ @@ -711,13 +720,39 @@ template<> Corpse* Eluna::CHECKOBJ(lua_State* L, int narg, bool error) template<> ElunaObject* Eluna::CHECKOBJ(lua_State* L, int narg, bool error) { - ElunaObject** ptrHold = static_cast(lua_touserdata(L, narg)); - if (!ptrHold) + return CHECKTYPE(L, narg, NULL, error); +} + +ElunaObject* Eluna::CHECKTYPE(lua_State* L, int narg, const char* tname, bool error) +{ + bool valid = false; + ElunaObject** ptrHold = NULL; + + if (!tname) + { + valid = true; + ptrHold = static_cast(lua_touserdata(L, narg)); + } + else + { + if (lua_getmetatable(L, narg)) + { + luaL_getmetatable(L, tname); + if (lua_rawequal(L, -1, -2) == 1) + { + valid = true; + ptrHold = static_cast(lua_touserdata(L, narg)); + } + lua_pop(L, 2); + } + } + + if (!valid || !ptrHold) { if (error) { char buff[256]; - snprintf(buff, 256, "Error fetching object index %i", narg); + snprintf(buff, 256, "bad argument : %s expected, got %s", tname ? tname : "userdata", luaL_typename(L, narg)); luaL_argerror(L, narg, buff); } return NULL; diff --git a/LuaEngine.h b/LuaEngine.h index 95f7413..6930276 100644 --- a/LuaEngine.h +++ b/LuaEngine.h @@ -171,7 +171,7 @@ public: static void Push(lua_State* L, const std::string); template static void Push(lua_State* L, T const* ptr) { - ElunaTemplate::push(L, ptr); + ElunaTemplate::Push(L, ptr); } static void Push(lua_State* L, Object const* obj); static void Push(lua_State* L, WorldObject const* obj); @@ -187,8 +187,9 @@ public: } template static T* CHECKOBJ(lua_State* L, int narg, bool error = true) { - return ElunaTemplate::check(L, narg, error); + return ElunaTemplate::Check(L, narg, error); } + static ElunaObject* CHECKTYPE(lua_State* L, int narg, const char *tname, bool error = true); CreatureAI* GetAI(Creature* creature); diff --git a/LuaFunctions.cpp b/LuaFunctions.cpp index 29cc80a..7943596 100644 --- a/LuaFunctions.cpp +++ b/LuaFunctions.cpp @@ -1251,22 +1251,59 @@ ElunaRegister BattleGroundMethods[] = template const char* ElunaTemplate::tname = NULL; template bool ElunaTemplate::manageMemory = false; + #if (!defined(TBC) && !defined(CLASSIC)) // fix compile error about accessing vehicle destructor -template<> int ElunaTemplate::gcT(lua_State* L) +template<> int ElunaTemplate::CollectGarbage(lua_State* L) { ASSERT(!manageMemory); // Get object pointer (and check type, no error) - ElunaObject** ptrHold = static_cast(luaL_testudata(L, -1, tname)); - if (ptrHold) - { - delete *ptrHold; - } + ElunaObject* obj = Eluna::CHECKOBJ(L, 1, false); + delete obj; return 0; } #endif +// Template by Mud from http://stackoverflow.com/questions/4484437/lua-integer-type/4485511#4485511 +template<> int ElunaTemplate::Add(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) + Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Substract(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) - Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Multiply(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) * Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Divide(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) / Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Mod(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) % Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Pow(lua_State* L) { Eluna::Push(L, pow(Eluna::CHECKVAL(L, 1), Eluna::CHECKVAL(L, 2))); return 1; } +// template<> int ElunaTemplate::UnaryMinus(lua_State* L) { Eluna::Push(L, -Eluna::CHECKVAL(L, 1)); return 1; } +template<> int ElunaTemplate::Equal(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) == Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Less(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) < Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::LessOrEqual(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) <= Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::ToString(lua_State* L) +{ + uint64 l = Eluna::CHECKVAL(L, 1); + std::ostringstream ss; + ss << l; + Eluna::Push(L, ss.str()); + return 1; +} + +template<> int ElunaTemplate::Add(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) + Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Substract(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) - Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Multiply(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) * Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Divide(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) / Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Mod(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) % Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Pow(lua_State* L) { Eluna::Push(L, pow(Eluna::CHECKVAL(L, 1), Eluna::CHECKVAL(L, 2))); return 1; } +template<> int ElunaTemplate::UnaryMinus(lua_State* L) { Eluna::Push(L, -Eluna::CHECKVAL(L, 1)); return 1; } +template<> int ElunaTemplate::Equal(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) == Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Less(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) < Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::LessOrEqual(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) <= Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::ToString(lua_State* L) +{ + int64 l = Eluna::CHECKVAL(L, 1); + std::ostringstream ss; + ss << l; + Eluna::Push(L, ss.str()); + return 1; +} + void RegisterFunctions(Eluna* E) { ElunaGlobal::SetMethods(E, GlobalMethods); @@ -1348,4 +1385,8 @@ void RegisterFunctions(Eluna* E) ElunaTemplate::Register(E, "ElunaQuery", true); ElunaTemplate::SetMethods(E, QueryMethods); + + ElunaTemplate::Register(E, "uint64", true); + + ElunaTemplate::Register(E, "int64", true); }