#ifndef __GAMESWFCALLBACK_H__
#define __GAMESWFCALLBACK_H__
#include <CasualCore.h>
namespace gameswf
{
void initCallbacks();
void deinitCallbacks();
class CallBackBase
{
protected:
friend void initCallbacks();
friend void deinitCallbacks();
static RKHashTable<void*> m_natives;
};
// \brief provides container for AS callbacks
// \details object that callback will be called on must exist at the time of the callback
template <class T>
class CallBackContainer final
{
class CallBack : CallBackBase
{
public:
typedef void (T::*MemberFunction)(const gameswf::FunctionCall&);
typedef void (T::*MemberFunctionWithUserData)(const gameswf::FunctionCall&, const gameswf::ASValue&);
public:
CallBack(T& host, MemberFunction p, const char* functionName)
: m_host(host)
, m_pMemberFunction(p)
, m_pMemberFunctionWithUserData(nullptr)
, m_handle()
, m_functionName(functionName)
, m_registeredNative(true) {
m_natives.Insert(this, functionName);
gameswf::registerNativeFunction(functionName, CallBackFunction);
}
CallBack(T& host, MemberFunction p, const char* functionName, const gameswf::CharacterHandle& handle)
: m_host(host)
, m_pMemberFunction(p)
, m_pMemberFunctionWithUserData(nullptr)
, m_handle(handle)
, m_functionName(functionName)
, m_registeredNative(false) {
RKASSERT(sizeof(gameswf::ASCppFunctionPtr) == sizeof(T*), "Types are different, consider wrapping 'this' pointer to another type (string?)");
m_handle.setMember(functionName, HandleCallbackFunction);
RKString sCppID = RKString::MakeFormatted("cpp_this_%s", functionName);
m_handle.setMember(sCppID.GetString(), reinterpret_cast<gameswf::ASCppFunctionPtr>(this));
}
CallBack(T& host, MemberFunctionWithUserData p, const char* functionName, const gameswf::CharacterHandle& handle, const gameswf::ASValue& userData)
: m_host(host)
, m_pMemberFunction(nullptr)
, m_pMemberFunctionWithUserData(p)
, m_handle(handle)
, m_functionName(functionName)
, m_registeredNative(false) {
RKASSERT(sizeof(gameswf::ASCppFunctionPtr) == sizeof(T*), "Types are different, consider wrapping 'this' pointer to another type (string?)");
m_handle.setMember(functionName, HandleCallbackFunctionWithUserData);
RKString sCppID = RKString::MakeFormatted("cpp_this_%s", functionName);
RKString sDataID = RKString::MakeFormatted("user_data_%s", functionName);
m_handle.setMember(sCppID.GetString(), reinterpret_cast<gameswf::ASCppFunctionPtr>(this));
m_handle.setMember(sDataID.GetString(), userData);
}
~CallBack() {
if (m_registeredNative)
{
if (m_natives.IsInited()){
RKHashTable<void*>::ConstIterator iter = m_natives.ConstFindKey(m_functionName.GetString());
RKASSERT(iter.IsValid(), "Removing native function more than once.");
if (iter.IsValid())
{
m_natives.Erase(iter);
}
}
gameswf::registerNativeFunction(m_functionName.GetString(), nullptr);
}
else
{
if (m_handle.isValid()) {
gameswf::ASValue dummy;
m_handle.setMember(m_functionName.GetString(), dummy);
RKString sCppID = RKString::MakeFormatted("cpp_this_%s", m_functionName.GetString());
RKString sDataID = RKString::MakeFormatted("user_data_%s", m_functionName.GetString());
m_handle.setMember(sCppID.GetString(), dummy);
m_handle.setMember(sDataID.GetString(), dummy);
}
}
}
void operator()(const gameswf::FunctionCall& fn) const {
RKASSERT(m_pMemberFunction, "CallBack Function is nullptr");
if (m_pMemberFunction) {
(m_host.*m_pMemberFunction)(fn);
}
}
void operator()(const gameswf::FunctionCall& fn, const gameswf::ASValue& userData) const {
RKASSERT(m_pMemberFunctionWithUserData, "CallBack Function is nullptr");
if (m_pMemberFunctionWithUserData) {
(m_host.*m_pMemberFunctionWithUserData)(fn, userData);
}
}
static void CallBackFunction(const gameswf::FunctionCall& fn) {
RKHashTable<void*>::Iterator iter = m_natives.FindKey(fn.name);
if (iter.IsValid()) {
CallBack* callback = reinterpret_cast<CallBack*>(iter.Value());
(*callback)(fn);
}
}
static void HandleCallbackFunction(const gameswf::FunctionCall& fn) {
RKString sCppID = RKString::MakeFormatted("cpp_this_%s", fn.name);
gameswf::ASValue thisVal; fn.this_ptr->getMember(sCppID.GetString(), &thisVal);
gameswf::ASCppFunctionPtr disguisedThisPtr = static_cast<gameswf::ASCppFunction*>(thisVal.toObject())->m_func;
CallBack* pOwner = reinterpret_cast<CallBack*>(disguisedThisPtr);
if (pOwner != nullptr) {
(*pOwner)(fn);
}
}
static void HandleCallbackFunctionWithUserData(const gameswf::FunctionCall& fn) {
RKString sCppID = RKString::MakeFormatted("cpp_this_%s", fn.name);
RKString sDataID = RKString::MakeFormatted("user_data_%s", fn.name);
gameswf::ASValue thisVal; fn.this_ptr->getMember(sCppID.GetString(), &thisVal);
gameswf::ASValue userdata; fn.this_ptr->getMember(sDataID.GetString(), &userdata);
gameswf::ASCppFunctionPtr disguisedThisPtr = static_cast<gameswf::ASCppFunction*>(thisVal.toObject())->m_func;
CallBack* pOwner = reinterpret_cast<CallBack*>(disguisedThisPtr);
if (pOwner) {
(*pOwner)(fn, userdata);
}
}
private:
T& m_host;
gameswf::CharacterHandle m_handle;
const RKString m_functionName;
bool m_registeredNative;
MemberFunction m_pMemberFunction;
MemberFunctionWithUserData m_pMemberFunctionWithUserData;
};
public:
inline CallBackContainer() {
m_callbacks.Reserve(4);
}
inline ~CallBackContainer(){
Clear();
}
inline void Clear() {
for (size_t i = 0; i < m_callbacks.Size(); ++i) {
RKDELETE(m_callbacks[i]);
}
m_callbacks.Clear();
}
// \brief adds a member function callback
// \param t (this) pointer to object, cannot be nullptr
// \param p address of a member function
// \param functionName exposed AS function name
// \return true on success, false otherwise
bool AddCallBack(T& t, void(T::*p)(const gameswf::FunctionCall&), const char* functionName) {
if (p != nullptr) {
m_callbacks.Append(RKNEW(CallBack)(t, p, functionName));
return true;
}
return false;
}
// \brief adds a member function callback
// \param t (this) pointer to object, cannot be nullptr
// \param p address of a member function
// \param functionName exposed AS function name
// \param userData eser defined data to pass to the callback
// \return true on success, false otherwise
bool AddCallBack(T& t, void(T::*p)(const gameswf::FunctionCall&, const gameswf::ASValue&), const char* functionName, const gameswf::ASValue& userData) {
if (p != nullptr) {
m_callbacks.Append(RKNEW(CallBack)(t, p, functionName, userData));
return true;
}
return false;
}
// \brief adds a member function callback
// \param t (this) pointer to object, cannot be nullptr
// \param p address of a member function
// \param functionName exposed AS function name
// \param handle AS object handle for the callback to be bound to, must be valid
// \return true on success, false otherwise
bool AddCallBack(T& t, void(T::*p)(const gameswf::FunctionCall&), const char* functionName, const gameswf::CharacterHandle& handle) {
if (p != nullptr && handle.isValid()) {
m_callbacks.Append(RKNEW(CallBack)(t, p, functionName, handle));
return true;
}
return false;
}
// \brief adds a member function callback
// \param t (this) pointer to object, cannot be nullptr
// \param p address of a member function
// \param functionName exposed AS function name
// \param handle AS object handle for the callback to be bound to, must be valid
// \param userData eser defined data to pass to the callback
// \return true on success, false otherwise
bool AddCallBack(T& t, void(T::*p)(const gameswf::FunctionCall&, const gameswf::ASValue&), const char* functionName, const gameswf::CharacterHandle& handle, const gameswf::ASValue& userData) {
if (p != nullptr && handle.isValid()) {
m_callbacks.Append(RKNEW(CallBack)(t, p, functionName, handle, userData));
return true;
}
return false;
}
private:
RKList<CallBack*> m_callbacks;
};
} // namespace gameswf
#endif