Eluna add int64 datatype, rename functions for osx, enhance object checking code

This commit is contained in:
Rochet2
2014-12-15 23:29:19 +02:00
parent 7671054425
commit cb7f9d5145
4 changed files with 270 additions and 77 deletions

View File

@@ -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<ElunaObject>(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<ElunaObject>(L, narg, error);
ElunaObject* elunaObj = Eluna::CHECKTYPE(L, narg, tname, error);
if (!elunaObj)
return NULL;
@@ -308,27 +370,22 @@ public:
return static_cast<T*>(elunaObj->GetObj());
}
static int typeT(lua_State* L)
static int GetType(lua_State* L)
{
lua_pushstring(L, tname);
return 1;
}
// Remember special case ElunaTemplate<Vehicle>::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<ElunaObject**>(luaL_testudata(L, -1, tname));
if (ptrHold)
{
if (manageMemory)
delete static_cast<T*>((*ptrHold)->GetObj());
delete *ptrHold;
}
ElunaObject* elunaObj = Eluna::CHECKOBJ<ElunaObject>(L, 1);
bool invalidate = Eluna::CHECKVAL<bool>(L, 2);
elunaObj->SetValidation(invalidate);
return 0;
}
static int thunk(lua_State* L)
static int CallMethod(lua_State* L)
{
T* obj = Eluna::CHECKOBJ<T>(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<Vehicle>::CollectGarbage
static int CollectGarbage(lua_State* L)
{
T* obj = Eluna::CHECKOBJ<T>(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<ElunaObject>(L, 1, false);
if (obj && manageMemory)
delete static_cast<T*>(obj->GetObj());
delete obj;
return 0;
}
static int ToString(lua_State* L)
{
T* obj = Eluna::CHECKOBJ<T>(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<typename T> const char* ElunaTemplate<T>::tname;
//template<typename T> bool ElunaTemplate<T>::manageMemory;
#if (!defined(TBC) && !defined(CLASSIC))
template<> int ElunaTemplate<Vehicle>::CollectGarbage(lua_State* L);
#endif
template<> int ElunaTemplate<uint32>::Add(lua_State* L);
template<> int ElunaTemplate<uint32>::Substract(lua_State* L);
template<> int ElunaTemplate<uint32>::Multiply(lua_State* L);
template<> int ElunaTemplate<uint32>::Divide(lua_State* L);
template<> int ElunaTemplate<uint32>::Mod(lua_State* L);
template<> int ElunaTemplate<uint32>::Pow(lua_State* L);
// template<> int ElunaTemplate<uint32>::UnaryMinus(lua_State* L);
template<> int ElunaTemplate<uint32>::Concat(lua_State* L);
template<> int ElunaTemplate<uint32>::Length(lua_State* L);
template<> int ElunaTemplate<uint32>::Equal(lua_State* L);
template<> int ElunaTemplate<uint32>::Less(lua_State* L);
template<> int ElunaTemplate<uint32>::LessOrEqual(lua_State* L);
template<> int ElunaTemplate<uint32>::Call(lua_State* L);
template<> int ElunaTemplate<int32>::Add(lua_State* L);
template<> int ElunaTemplate<int32>::Substract(lua_State* L);
template<> int ElunaTemplate<int32>::Multiply(lua_State* L);
template<> int ElunaTemplate<int32>::Divide(lua_State* L);
template<> int ElunaTemplate<int32>::Mod(lua_State* L);
template<> int ElunaTemplate<int32>::Pow(lua_State* L);
template<> int ElunaTemplate<int32>::UnaryMinus(lua_State* L);
template<> int ElunaTemplate<int32>::Concat(lua_State* L);
template<> int ElunaTemplate<int32>::Length(lua_State* L);
template<> int ElunaTemplate<int32>::Equal(lua_State* L);
template<> int ElunaTemplate<int32>::Less(lua_State* L);
template<> int ElunaTemplate<int32>::LessOrEqual(lua_State* L);
template<> int ElunaTemplate<int32>::Call(lua_State* L);
#endif

View File

@@ -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<HookMgr::ItemEvents>("ItemEvents", *this)),
ItemGossipBindings(new EntryBind<HookMgr::GossipEvents>("GossipEvents (item)", *this)),
playerGossipBindings(new EntryBind<HookMgr::GossipEvents>("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<uint64>::Push(L, new uint64(l));
}
void Eluna::Push(lua_State* L, const int64 l)
{
std::ostringstream ss;
ss << l;
Push(L, ss.str());
ElunaTemplate<int64>::Push(L, new int64(l));
}
//void Eluna::Push(lua_State* L, const time_t l)
//{
// ElunaTemplate<uint64>::Push(L, new uint64(l));
//}
//void Eluna::Push(lua_State* L, const size_t l)
//{
// ElunaTemplate<int64>::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<Unit>::push(L, unit);
ElunaTemplate<Unit>::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<WorldObject>::push(L, obj);
ElunaTemplate<WorldObject>::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<Object>::push(L, obj);
ElunaTemplate<Object>::Push(L, obj);
}
}
@@ -642,30 +653,28 @@ template<> std::string Eluna::CHECKVAL<std::string>(lua_State* L, int narg)
}
template<> int64 Eluna::CHECKVAL<int64>(lua_State* L, int narg)
{
const char* c_str = CHECKVAL<const char*>(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<int64>(CHECKVAL<double>(L, narg));
return *(Eluna::CHECKOBJ<int64>(L, narg, true));
}
template<> uint64 Eluna::CHECKVAL<uint64>(lua_State* L, int narg)
{
const char* c_str = CHECKVAL<const char*>(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<uint64>(CHECKVAL<uint32>(L, narg));
return *(Eluna::CHECKOBJ<uint64>(L, narg, true));
}
//template<> time_t Eluna::CHECKVAL<time_t>(lua_State* L, int narg)
//{
// if (lua_isnumber(L, narg))
// return static_cast<time_t>(CHECKVAL<double>(L, narg));
// return static_cast<time_t>(*(Eluna::CHECKOBJ<int64>(L, narg, true)));
//}
//template<> size_t Eluna::CHECKVAL<size_t>(lua_State* L, int narg)
//{
// if (lua_isnumber(L, narg))
// return static_cast<size_t>(CHECKVAL<uint32>(L, narg));
// return static_cast<size_t>(*(Eluna::CHECKOBJ<uint64>(L, narg, true)));
//}
#define TEST_OBJ(T, O, R, F)\
{\
@@ -711,13 +720,39 @@ template<> Corpse* Eluna::CHECKOBJ<Corpse>(lua_State* L, int narg, bool error)
template<> ElunaObject* Eluna::CHECKOBJ<ElunaObject>(lua_State* L, int narg, bool error)
{
ElunaObject** ptrHold = static_cast<ElunaObject**>(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<ElunaObject**>(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<ElunaObject**>(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;

View File

@@ -171,7 +171,7 @@ public:
static void Push(lua_State* L, const std::string);
template<typename T> static void Push(lua_State* L, T const* ptr)
{
ElunaTemplate<T>::push(L, ptr);
ElunaTemplate<T>::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<typename T> static T* CHECKOBJ(lua_State* L, int narg, bool error = true)
{
return ElunaTemplate<T>::check(L, narg, error);
return ElunaTemplate<T>::Check(L, narg, error);
}
static ElunaObject* CHECKTYPE(lua_State* L, int narg, const char *tname, bool error = true);
CreatureAI* GetAI(Creature* creature);

View File

@@ -1251,22 +1251,59 @@ ElunaRegister<BattleGround> BattleGroundMethods[] =
template<typename T> const char* ElunaTemplate<T>::tname = NULL;
template<typename T> bool ElunaTemplate<T>::manageMemory = false;
#if (!defined(TBC) && !defined(CLASSIC))
// fix compile error about accessing vehicle destructor
template<> int ElunaTemplate<Vehicle>::gcT(lua_State* L)
template<> int ElunaTemplate<Vehicle>::CollectGarbage(lua_State* L)
{
ASSERT(!manageMemory);
// Get object pointer (and check type, no error)
ElunaObject** ptrHold = static_cast<ElunaObject**>(luaL_testudata(L, -1, tname));
if (ptrHold)
{
delete *ptrHold;
}
ElunaObject* obj = Eluna::CHECKOBJ<ElunaObject>(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<uint64>::Add(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<uint64>(L, 1) + Eluna::CHECKVAL<uint64>(L, 2)); return 1; }
template<> int ElunaTemplate<uint64>::Substract(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<uint64>(L, 1) - Eluna::CHECKVAL<uint64>(L, 2)); return 1; }
template<> int ElunaTemplate<uint64>::Multiply(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<uint64>(L, 1) * Eluna::CHECKVAL<uint64>(L, 2)); return 1; }
template<> int ElunaTemplate<uint64>::Divide(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<uint64>(L, 1) / Eluna::CHECKVAL<uint64>(L, 2)); return 1; }
template<> int ElunaTemplate<uint64>::Mod(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<uint64>(L, 1) % Eluna::CHECKVAL<uint64>(L, 2)); return 1; }
template<> int ElunaTemplate<uint64>::Pow(lua_State* L) { Eluna::Push(L, pow(Eluna::CHECKVAL<uint64>(L, 1), Eluna::CHECKVAL<uint64>(L, 2))); return 1; }
// template<> int ElunaTemplate<uint64>::UnaryMinus(lua_State* L) { Eluna::Push(L, -Eluna::CHECKVAL<uint64>(L, 1)); return 1; }
template<> int ElunaTemplate<uint64>::Equal(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<uint64>(L, 1) == Eluna::CHECKVAL<uint64>(L, 2)); return 1; }
template<> int ElunaTemplate<uint64>::Less(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<uint64>(L, 1) < Eluna::CHECKVAL<uint64>(L, 2)); return 1; }
template<> int ElunaTemplate<uint64>::LessOrEqual(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<uint64>(L, 1) <= Eluna::CHECKVAL<uint64>(L, 2)); return 1; }
template<> int ElunaTemplate<uint64>::ToString(lua_State* L)
{
uint64 l = Eluna::CHECKVAL<uint64>(L, 1);
std::ostringstream ss;
ss << l;
Eluna::Push(L, ss.str());
return 1;
}
template<> int ElunaTemplate<int64>::Add(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<int64>(L, 1) + Eluna::CHECKVAL<int64>(L, 2)); return 1; }
template<> int ElunaTemplate<int64>::Substract(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<int64>(L, 1) - Eluna::CHECKVAL<int64>(L, 2)); return 1; }
template<> int ElunaTemplate<int64>::Multiply(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<int64>(L, 1) * Eluna::CHECKVAL<int64>(L, 2)); return 1; }
template<> int ElunaTemplate<int64>::Divide(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<int64>(L, 1) / Eluna::CHECKVAL<int64>(L, 2)); return 1; }
template<> int ElunaTemplate<int64>::Mod(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<int64>(L, 1) % Eluna::CHECKVAL<int64>(L, 2)); return 1; }
template<> int ElunaTemplate<int64>::Pow(lua_State* L) { Eluna::Push(L, pow(Eluna::CHECKVAL<int64>(L, 1), Eluna::CHECKVAL<int64>(L, 2))); return 1; }
template<> int ElunaTemplate<int64>::UnaryMinus(lua_State* L) { Eluna::Push(L, -Eluna::CHECKVAL<int64>(L, 1)); return 1; }
template<> int ElunaTemplate<int64>::Equal(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<int64>(L, 1) == Eluna::CHECKVAL<int64>(L, 2)); return 1; }
template<> int ElunaTemplate<int64>::Less(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<int64>(L, 1) < Eluna::CHECKVAL<int64>(L, 2)); return 1; }
template<> int ElunaTemplate<int64>::LessOrEqual(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL<int64>(L, 1) <= Eluna::CHECKVAL<int64>(L, 2)); return 1; }
template<> int ElunaTemplate<int64>::ToString(lua_State* L)
{
int64 l = Eluna::CHECKVAL<int64>(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<ElunaQuery>::Register(E, "ElunaQuery", true);
ElunaTemplate<ElunaQuery>::SetMethods(E, QueryMethods);
ElunaTemplate<uint64>::Register(E, "uint64", true);
ElunaTemplate<int64>::Register(E, "int64", true);
}