Merge pull request #11 from defold/sdk-lua-callback

Use Lua callback handling functions from DefoldSDK
This commit is contained in:
Mathias Westerdahl 2019-11-19 08:59:10 +01:00 committed by GitHub
commit 4221a3ba27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 188 deletions

View File

@ -27,20 +27,15 @@ struct IAP
IAP() IAP()
{ {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
m_Callback = LUA_NOREF;
m_Self = LUA_NOREF;
m_Listener.m_Callback = LUA_NOREF;
m_Listener.m_Self = LUA_NOREF;
m_autoFinishTransactions = true; m_autoFinishTransactions = true;
m_ProviderId = PROVIDER_ID_GOOGLE; m_ProviderId = PROVIDER_ID_GOOGLE;
} }
int m_InitCount; int m_InitCount;
int m_Callback;
int m_Self;
bool m_autoFinishTransactions; bool m_autoFinishTransactions;
int m_ProviderId; int m_ProviderId;
lua_State* m_L;
IAPListener m_Listener; dmScript::LuaCallbackInfo* m_ProductCallback;
dmScript::LuaCallbackInfo* m_Listener;
jobject m_IAP; jobject m_IAP;
jobject m_IAPJNI; jobject m_IAPJNI;
@ -56,22 +51,9 @@ struct IAP
static IAP g_IAP; static IAP g_IAP;
static void ResetCallback(lua_State* L)
{
if (g_IAP.m_Callback != LUA_NOREF) {
dmScript::Unref(L, LUA_REGISTRYINDEX, g_IAP.m_Callback);
dmScript::Unref(L, LUA_REGISTRYINDEX, g_IAP.m_Self);
g_IAP.m_Callback = LUA_NOREF;
g_IAP.m_Self = LUA_NOREF;
g_IAP.m_L = 0;
}
}
static int IAP_List(lua_State* L) static int IAP_List(lua_State* L)
{ {
int top = lua_gettop(L); int top = lua_gettop(L);
ResetCallback(L);
char* buf = IAP_List_CreateBuffer(L); char* buf = IAP_List_CreateBuffer(L);
if( buf == 0 ) if( buf == 0 )
{ {
@ -79,14 +61,10 @@ static int IAP_List(lua_State* L)
return 0; return 0;
} }
luaL_checktype(L, 2, LUA_TFUNCTION); if (g_IAP.m_ProductCallback)
lua_pushvalue(L, 2); dmScript::DestroyCallback(g_IAP.m_ProductCallback);
g_IAP.m_Callback = dmScript::Ref(L, LUA_REGISTRYINDEX);
dmScript::GetInstance(L); g_IAP.m_ProductCallback = dmScript::CreateCallback(L, 2);
g_IAP.m_Self = dmScript::Ref(L, LUA_REGISTRYINDEX);
g_IAP.m_L = dmScript::GetMainThread(L);
JNIEnv* env = Attach(); JNIEnv* env = Attach();
jstring products = env->NewStringUTF(buf); jstring products = env->NewStringUTF(buf);
@ -180,22 +158,13 @@ static int IAP_Restore(lua_State* L)
static int IAP_SetListener(lua_State* L) static int IAP_SetListener(lua_State* L)
{ {
IAP* iap = &g_IAP; IAP* iap = &g_IAP;
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_pushvalue(L, 1);
int cb = dmScript::Ref(L, LUA_REGISTRYINDEX);
bool had_previous = false; bool had_previous = iap->m_Listener != 0;
if (iap->m_Listener.m_Callback != LUA_NOREF) {
dmScript::Unref(iap->m_Listener.m_L, LUA_REGISTRYINDEX, iap->m_Listener.m_Callback);
dmScript::Unref(iap->m_Listener.m_L, LUA_REGISTRYINDEX, iap->m_Listener.m_Self);
had_previous = true;
}
iap->m_Listener.m_L = dmScript::GetMainThread(L); if (iap->m_Listener)
iap->m_Listener.m_Callback = cb; dmScript::DestroyCallback(iap->m_Listener);
dmScript::GetInstance(L); iap->m_Listener = dmScript::CreateCallback(L, 1);
iap->m_Listener.m_Self = dmScript::Ref(L, LUA_REGISTRYINDEX);
// On first set listener, trigger process old ones. // On first set listener, trigger process old ones.
if (!had_previous) { if (!had_previous) {
@ -238,6 +207,7 @@ JNIEXPORT void JNICALL Java_com_defold_iap_IapJNI_onProductsResult__ILjava_lang_
} }
IAPCommand cmd; IAPCommand cmd;
cmd.m_Callback = g_IAP.m_ProductCallback;
cmd.m_Command = IAP_PRODUCT_RESULT; cmd.m_Command = IAP_PRODUCT_RESULT;
cmd.m_ResponseCode = responseCode; cmd.m_ResponseCode = responseCode;
if (pl) if (pl)
@ -257,6 +227,7 @@ JNIEXPORT void JNICALL Java_com_defold_iap_IapJNI_onPurchaseResult__ILjava_lang_
} }
IAPCommand cmd; IAPCommand cmd;
cmd.m_Callback = g_IAP.m_Listener;
cmd.m_Command = IAP_PURCHASE_RESULT; cmd.m_Command = IAP_PURCHASE_RESULT;
cmd.m_ResponseCode = responseCode; cmd.m_ResponseCode = responseCode;
if (pd) if (pd)
@ -273,25 +244,11 @@ JNIEXPORT void JNICALL Java_com_defold_iap_IapJNI_onPurchaseResult__ILjava_lang_
static void HandleProductResult(const IAPCommand* cmd) static void HandleProductResult(const IAPCommand* cmd)
{ {
lua_State* L = g_IAP.m_L; lua_State* L = dmScript::GetCallbackLuaContext(cmd->m_Callback);
int top = lua_gettop(L); int top = lua_gettop(L);
if (g_IAP.m_Callback == LUA_NOREF) { if (!dmScript::SetupCallback(cmd->m_Callback))
dmLogError("No callback set");
return;
}
lua_rawgeti(L, LUA_REGISTRYINDEX, g_IAP.m_Callback);
// Setup self
lua_rawgeti(L, LUA_REGISTRYINDEX, g_IAP.m_Self);
lua_pushvalue(L, -1);
dmScript::SetInstance(L);
if (!dmScript::IsInstanceValid(L))
{ {
dmLogError("Could not run IAP callback because the instance has been deleted.");
lua_pop(L, 2);
assert(top == lua_gettop(L)); assert(top == lua_gettop(L));
return; return;
} }
@ -326,36 +283,21 @@ static void HandleProductResult(const IAPCommand* cmd)
lua_pop(L, 1); lua_pop(L, 1);
} }
dmScript::Unref(L, LUA_REGISTRYINDEX, g_IAP.m_Callback); dmScript::TeardownCallback(cmd->m_Callback);
dmScript::Unref(L, LUA_REGISTRYINDEX, g_IAP.m_Self); dmScript::DestroyCallback(cmd->m_Callback);
g_IAP.m_Callback = LUA_NOREF; assert(g_IAP.m_ProductCallback == cmd->m_Callback);
g_IAP.m_Self = LUA_NOREF; g_IAP.m_ProductCallback = 0;
assert(top == lua_gettop(L)); assert(top == lua_gettop(L));
} }
static void HandlePurchaseResult(const IAPCommand* cmd) static void HandlePurchaseResult(const IAPCommand* cmd)
{ {
lua_State* L = g_IAP.m_Listener.m_L; lua_State* L = dmScript::GetCallbackLuaContext(cmd->m_Callback);
int top = lua_gettop(L); int top = lua_gettop(L);
if (g_IAP.m_Listener.m_Callback == LUA_NOREF) { if (!dmScript::SetupCallback(cmd->m_Callback))
dmLogError("No callback set");
return;
}
lua_rawgeti(L, LUA_REGISTRYINDEX, g_IAP.m_Listener.m_Callback);
// Setup self
lua_rawgeti(L, LUA_REGISTRYINDEX, g_IAP.m_Listener.m_Self);
lua_pushvalue(L, -1);
dmScript::SetInstance(L);
if (!dmScript::IsInstanceValid(L))
{ {
dmLogError("Could not run IAP callback because the instance has been deleted.");
lua_pop(L, 2);
assert(top == lua_gettop(L)); assert(top == lua_gettop(L));
return; return;
} }
@ -393,12 +335,14 @@ static void HandlePurchaseResult(const IAPCommand* cmd)
IAP_PushError(L, "failed to buy product", REASON_UNSPECIFIED); IAP_PushError(L, "failed to buy product", REASON_UNSPECIFIED);
} }
int ret = lua_pcall(L, 3, 0, 0); int ret = dmScript::PCall(L, 3, 0);
if (ret != 0) { if (ret != 0) {
dmLogError("Error running callback: %s", lua_tostring(L, -1)); dmLogError("Error running callback: %s", lua_tostring(L, -1));
lua_pop(L, 1); lua_pop(L, 1);
} }
dmScript::TeardownCallback(cmd->m_Callback);
assert(top == lua_gettop(L)); assert(top == lua_gettop(L));
} }
@ -500,12 +444,9 @@ static dmExtension::Result FinalizeIAP(dmExtension::Params* params)
IAP_Queue_Destroy(&g_IAP.m_CommandQueue); IAP_Queue_Destroy(&g_IAP.m_CommandQueue);
--g_IAP.m_InitCount; --g_IAP.m_InitCount;
if (params->m_L == g_IAP.m_Listener.m_L && g_IAP.m_Listener.m_Callback != LUA_NOREF) { if (params->m_L == dmScript::GetCallbackLuaContext(g_IAP.m_Listener)) {
dmScript::Unref(g_IAP.m_Listener.m_L, LUA_REGISTRYINDEX, g_IAP.m_Listener.m_Callback); dmScript::DestroyCallback(g_IAP.m_Listener);
dmScript::Unref(g_IAP.m_Listener.m_L, LUA_REGISTRYINDEX, g_IAP.m_Listener.m_Self); g_IAP.m_Listener = 0;
g_IAP.m_Listener.m_L = 0;
g_IAP.m_Listener.m_Callback = LUA_NOREF;
g_IAP.m_Listener.m_Self = LUA_NOREF;
} }
if (g_IAP.m_InitCount == 0) { if (g_IAP.m_InitCount == 0) {

View File

@ -23,12 +23,11 @@ struct IAP
{ {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
m_AutoFinishTransactions = true; m_AutoFinishTransactions = true;
IAP_ClearCallback(&m_Listener);
} }
int m_InitCount; int m_InitCount;
bool m_AutoFinishTransactions; bool m_AutoFinishTransactions;
NSMutableDictionary* m_PendingTransactions; NSMutableDictionary* m_PendingTransactions;
IAPListener m_Listener; dmScript::LuaCallbackInfo* m_Listener;
IAPCommandQueue m_CommandQueue; IAPCommandQueue m_CommandQueue;
SKPaymentTransactionObserver* m_Observer; SKPaymentTransactionObserver* m_Observer;
}; };
@ -101,15 +100,14 @@ static void IAP_FreeTransaction(IAPTransaction* transaction)
@interface SKProductsRequestDelegate : NSObject<SKProductsRequestDelegate> @interface SKProductsRequestDelegate : NSObject<SKProductsRequestDelegate>
@property IAPListener m_Callback; @property dmScript::LuaCallbackInfo* m_Callback;
@property (assign) SKProductsRequest* m_Request; @property (assign) SKProductsRequest* m_Request;
@end @end
@implementation SKProductsRequestDelegate @implementation SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{ - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
IAPListener callback = self.m_Callback; if (!dmScript::IsCallbackValid(self.m_Callback)) {
if (!IAP_CallbackIsValid(&callback)) {
dmLogError("No callback set"); dmLogError("No callback set");
return; return;
} }
@ -141,7 +139,7 @@ static void IAP_FreeTransaction(IAPTransaction* transaction)
IAPCommand cmd; IAPCommand cmd;
cmd.m_Command = IAP_PRODUCT_RESULT; cmd.m_Command = IAP_PRODUCT_RESULT;
cmd.m_Callback = callback; cmd.m_Callback = self.m_Callback;
cmd.m_Data = iap_response; cmd.m_Data = iap_response;
IAP_Queue_Push(&g_IAP.m_CommandQueue, &cmd); IAP_Queue_Push(&g_IAP.m_CommandQueue, &cmd);
} }
@ -151,10 +149,10 @@ static void HandleProductResult(IAPCommand* cmd)
IAPResponse* response = (IAPResponse*)cmd->m_Data; IAPResponse* response = (IAPResponse*)cmd->m_Data;
lua_State* L = cmd->m_Callback.m_L; lua_State* L = dmScript::GetCallbackLuaContext(g_IAP.m_Listener);
int top = lua_gettop(L); int top = lua_gettop(L);
if (!IAP_SetupCallback(&cmd->m_Callback)) if (!dmScript::SetupCallback(cmd->m_Callback))
{ {
assert(top == lua_gettop(L)); assert(top == lua_gettop(L));
delete response; delete response;
@ -188,13 +186,14 @@ static void HandleProductResult(IAPCommand* cmd)
} }
lua_pushnil(L); lua_pushnil(L);
int ret = lua_pcall(L, 3, 0, 0); int ret = dmScript::PCall(L, 3, 0);
if (ret != 0) { if (ret != 0) {
dmLogError("%d: Error running callback: %s", __LINE__, lua_tostring(L, -1)); dmLogError("%d: Error running callback: %s", __LINE__, lua_tostring(L, -1));
lua_pop(L, 1); lua_pop(L, 1);
} }
IAP_UnregisterCallback(&cmd->m_Callback); dmScript::TeardownCallback(cmd->m_Callback);
dmScript::DestroyCallback(cmd->m_Callback);
delete response; delete response;
assert(top == lua_gettop(L)); assert(top == lua_gettop(L));
@ -203,8 +202,7 @@ static void HandleProductResult(IAPCommand* cmd)
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{ - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
dmLogWarning("SKProductsRequest failed: %s", [error.localizedDescription UTF8String]); dmLogWarning("SKProductsRequest failed: %s", [error.localizedDescription UTF8String]);
IAPListener callback = self.m_Callback; if (!dmScript::IsCallbackValid(self.m_Callback)) {
if (!IAP_CallbackIsValid(&callback)) {
dmLogError("No callback set"); dmLogError("No callback set");
return; return;
} }
@ -215,7 +213,7 @@ static void HandleProductResult(IAPCommand* cmd)
IAPCommand cmd; IAPCommand cmd;
cmd.m_Command = IAP_PRODUCT_RESULT; cmd.m_Command = IAP_PRODUCT_RESULT;
cmd.m_Callback = callback; cmd.m_Callback = self.m_Callback;
cmd.m_Data = response; cmd.m_Data = response;
IAP_Queue_Push(&g_IAP.m_CommandQueue, &cmd); IAP_Queue_Push(&g_IAP.m_CommandQueue, &cmd);
@ -300,13 +298,12 @@ static void PushTransaction(lua_State* L, IAPTransaction* transaction)
static void HandlePurchaseResult(IAPCommand* cmd) static void HandlePurchaseResult(IAPCommand* cmd)
{ {
IAPTransaction* transaction = (IAPTransaction*)cmd->m_Data; IAPTransaction* transaction = (IAPTransaction*)cmd->m_Data;
lua_State* L = cmd->m_Callback.m_L; lua_State* L = dmScript::GetCallbackLuaContext(cmd->m_Callback);
int top = lua_gettop(L); int top = lua_gettop(L);
if (!IAP_SetupCallback(&cmd->m_Callback)) if (!dmScript::SetupCallback(cmd->m_Callback))
{ {
assert(top == lua_gettop(L)); assert(top == lua_gettop(L));
return; return;
@ -321,12 +318,14 @@ static void HandlePurchaseResult(IAPCommand* cmd)
lua_pushnil(L); lua_pushnil(L);
} }
int ret = lua_pcall(L, 3, 0, 0); int ret = dmScript::PCall(L, 3, 0);
if (ret != 0) { if (ret != 0) {
dmLogError("%d: Error running callback: %s", __LINE__, lua_tostring(L, -1)); dmLogError("%d: Error running callback: %s", __LINE__, lua_tostring(L, -1));
lua_pop(L, 1); lua_pop(L, 1);
} }
dmScript::TeardownCallback(cmd->m_Callback);
IAP_FreeTransaction(transaction); IAP_FreeTransaction(transaction);
delete transaction; delete transaction;
@ -344,8 +343,7 @@ static void HandlePurchaseResult(IAPCommand* cmd)
[self.m_IAP->m_PendingTransactions setObject:transaction forKey:[NSNumber numberWithInteger:trans_id_hash] ]; [self.m_IAP->m_PendingTransactions setObject:transaction forKey:[NSNumber numberWithInteger:trans_id_hash] ];
} }
bool has_listener = self.m_IAP->m_Listener.m_Callback != LUA_NOREF; if (!self.m_IAP->m_Listener)
if (!has_listener)
continue; continue;
IAPTransaction* iap_transaction = new IAPTransaction; IAPTransaction* iap_transaction = new IAPTransaction;
@ -394,10 +392,7 @@ static int IAP_List(lua_State* L)
SKProductsRequest* products_request = [[SKProductsRequest alloc] initWithProductIdentifiers: product_identifiers]; SKProductsRequest* products_request = [[SKProductsRequest alloc] initWithProductIdentifiers: product_identifiers];
SKProductsRequestDelegate* delegate = [SKProductsRequestDelegate alloc]; SKProductsRequestDelegate* delegate = [SKProductsRequestDelegate alloc];
IAPListener callback; delegate.m_Callback = dmScript::CreateCallback(L, 2);
IAP_RegisterCallback(L, 2, &callback);
delegate.m_Callback = callback;
delegate.m_Request = products_request; delegate.m_Request = products_request;
products_request.delegate = delegate; products_request.delegate = delegate;
[products_request start]; [products_request start];
@ -486,8 +481,10 @@ static int IAP_SetListener(lua_State* L)
{ {
IAP* iap = &g_IAP; IAP* iap = &g_IAP;
IAP_UnregisterCallback(&iap->m_Listener); if (iap->m_Listener)
IAP_RegisterCallback(L, 1, &iap->m_Listener); dmScript::DestroyCallback(iap->m_Listener);
iap->m_Listener = dmScript::CreateCallback(L, 1);
if (g_IAP.m_Observer == 0) { if (g_IAP.m_Observer == 0) {
SKPaymentTransactionObserver* observer = [[SKPaymentTransactionObserver alloc] init]; SKPaymentTransactionObserver* observer = [[SKPaymentTransactionObserver alloc] init];
@ -577,8 +574,9 @@ static dmExtension::Result FinalizeIAP(dmExtension::Params* params)
// TODO: Should we support one listener per lua-state? // TODO: Should we support one listener per lua-state?
// Or just use a single lua-state...? // Or just use a single lua-state...?
if (params->m_L == g_IAP.m_Listener.m_L) { if (params->m_L == dmScript::GetCallbackLuaContext(g_IAP.m_Listener)) {
IAP_UnregisterCallback(&g_IAP.m_Listener); dmScript::DestroyCallback(g_IAP.m_Listener);
g_IAP.m_Listener = 0;
} }
if (g_IAP.m_InitCount == 0) { if (g_IAP.m_InitCount == 0) {

View File

@ -7,65 +7,6 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
IAPListener::IAPListener() {
IAP_ClearCallback(this);
}
void IAP_ClearCallback(IAPListener* callback)
{
callback->m_L = 0;
callback->m_Callback = LUA_NOREF;
callback->m_Self = LUA_NOREF;
}
void IAP_RegisterCallback(lua_State* L, int index, IAPListener* callback)
{
luaL_checktype(L, index, LUA_TFUNCTION);
lua_pushvalue(L, index);
callback->m_Callback = dmScript::Ref(L, LUA_REGISTRYINDEX);
dmScript::GetInstance(L);
callback->m_Self = dmScript::Ref(L, LUA_REGISTRYINDEX);
callback->m_L = L;
}
void IAP_UnregisterCallback(IAPListener* callback)
{
if (LUA_NOREF != callback->m_Callback)
dmScript::Unref(callback->m_L, LUA_REGISTRYINDEX, callback->m_Callback);
if (LUA_NOREF != callback->m_Self)
dmScript::Unref(callback->m_L, LUA_REGISTRYINDEX, callback->m_Self);
callback->m_Callback = LUA_NOREF;
callback->m_Self = LUA_NOREF;
callback->m_L = 0;
}
bool IAP_SetupCallback(IAPListener* callback)
{
lua_State* L = callback->m_L;
lua_rawgeti(L, LUA_REGISTRYINDEX, callback->m_Callback);
// Setup self
lua_rawgeti(L, LUA_REGISTRYINDEX, callback->m_Self);
lua_pushvalue(L, -1);
dmScript::SetInstance(L);
if (!dmScript::IsInstanceValid(L))
{
dmLogError("Could not run callback because the instance has been deleted.");
lua_pop(L, 2);
return false;
}
return true;
}
bool IAP_CallbackIsValid(IAPListener* callback)
{
return callback != 0 && callback->m_L != 0 && callback->m_Callback != LUA_NOREF && callback->m_Self != LUA_NOREF;
}
// Creates a comma separated string, given a table where all values are strings (or numbers) // Creates a comma separated string, given a table where all values are strings (or numbers)
// Returns a malloc'ed string, which the caller must free // Returns a malloc'ed string, which the caller must free
char* IAP_List_CreateBuffer(lua_State* L) char* IAP_List_CreateBuffer(lua_State* L)

View File

@ -5,16 +5,6 @@
#include <dmsdk/sdk.h> #include <dmsdk/sdk.h>
// TODO: Rename Callback
struct IAPListener
{
IAPListener();
lua_State* m_L;
int m_Callback;
int m_Self;
};
enum EIAPCommand enum EIAPCommand
{ {
IAP_PRODUCT_RESULT, IAP_PRODUCT_RESULT,
@ -29,7 +19,7 @@ struct DM_ALIGNED(16) IAPCommand
} }
// Used for storing eventual callback info (if needed) // Used for storing eventual callback info (if needed)
IAPListener m_Callback; dmScript::LuaCallbackInfo* m_Callback;
// THe actual command payload // THe actual command payload
int32_t m_Command; int32_t m_Command;
@ -43,12 +33,6 @@ struct IAPCommandQueue
dmMutex::HMutex m_Mutex; dmMutex::HMutex m_Mutex;
}; };
void IAP_ClearCallback(IAPListener* callback);
void IAP_RegisterCallback(lua_State* L, int index, IAPListener* callback);
void IAP_UnregisterCallback(IAPListener* callback);
bool IAP_SetupCallback(IAPListener* callback);
bool IAP_CallbackIsValid(IAPListener* callback);
char* IAP_List_CreateBuffer(lua_State* L); char* IAP_List_CreateBuffer(lua_State* L);
void IAP_PushError(lua_State* L, const char* error, int reason); void IAP_PushError(lua_State* L, const char* error, int reason);
void IAP_PushConstants(lua_State* L); void IAP_PushConstants(lua_State* L);