mirror of
https://github.com/defold/extension-iap
synced 2025-09-28 17:42:18 +02:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f1d53948e9 | ||
|
607b4a117e | ||
|
38656e973c | ||
|
4efe0c2a25 | ||
|
3fb09c3b95 | ||
|
2843080690 | ||
|
1c017cf4ed | ||
|
eda78dda4f | ||
|
8d9ea79d7d | ||
|
c8d2d4e0d8 | ||
|
d2e2a640df | ||
|
aa9448b5e9 | ||
|
ce26b8fdd9 | ||
|
1a778d0e98 | ||
|
6056ff8eeb | ||
|
0e76cd4f24 | ||
|
4221a3ba27 | ||
|
8eebb889e3 |
@@ -11,7 +11,7 @@ To use this library in your Defold project, add the following URL to your <code
|
|||||||
|
|
||||||
https://github.com/defold/extension-iap/archive/master.zip
|
https://github.com/defold/extension-iap/archive/master.zip
|
||||||
|
|
||||||
We recommend using a link to a zip file of a [https://github.com/defold/extension-iap/releases](specific release).
|
We recommend using a link to a zip file of a [specific release](https://github.com/defold/extension-iap/releases).
|
||||||
|
|
||||||
## Source code
|
## Source code
|
||||||
|
|
||||||
|
@@ -31,7 +31,7 @@ var LibraryFacebookIAP = {
|
|||||||
FB_PAYMENT_RESPONSE_APPINVALIDITEMPARAM : 1383051
|
FB_PAYMENT_RESPONSE_APPINVALIDITEMPARAM : 1383051
|
||||||
},
|
},
|
||||||
|
|
||||||
http_callback: function(xmlhttp, callback, lua_state, products, product_ids, product_count, url_index, url_count) {
|
http_callback: function(xmlhttp, callback, lua_callback, products, product_ids, product_count, url_index, url_count) {
|
||||||
if (xmlhttp.readyState == 4) {
|
if (xmlhttp.readyState == 4) {
|
||||||
if(xmlhttp.status == 200) {
|
if(xmlhttp.status == 200) {
|
||||||
var xmlDoc = document.createElement( 'html' );
|
var xmlDoc = document.createElement( 'html' );
|
||||||
@@ -72,11 +72,11 @@ var LibraryFacebookIAP = {
|
|||||||
if(url_index == product_count-1) {
|
if(url_index == product_count-1) {
|
||||||
var productsJSON = JSON.stringify(products);
|
var productsJSON = JSON.stringify(products);
|
||||||
var res_buf = allocate(intArrayFromString(productsJSON), 'i8', ALLOC_STACK);
|
var res_buf = allocate(intArrayFromString(productsJSON), 'i8', ALLOC_STACK);
|
||||||
Runtime.dynCall('vii', callback, [lua_state, res_buf]);
|
Runtime.dynCall('vii', callback, [lua_callback, res_buf]);
|
||||||
} else {
|
} else {
|
||||||
var xmlhttp = new XMLHttpRequest();
|
var xmlhttp = new XMLHttpRequest();
|
||||||
xmlhttp.onreadystatechange = function() {
|
xmlhttp.onreadystatechange = function() {
|
||||||
FBinner.http_callback(xmlhttp, callback, lua_state, products, product_ids, product_count, url_index+1);
|
FBinner.http_callback(xmlhttp, callback, lua_callback, products, product_ids, product_count, url_index+1);
|
||||||
};
|
};
|
||||||
xmlhttp.open("GET", product_ids[url_index+1], true);
|
xmlhttp.open("GET", product_ids[url_index+1], true);
|
||||||
xmlhttp.send();
|
xmlhttp.send();
|
||||||
@@ -86,7 +86,7 @@ var LibraryFacebookIAP = {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
dmIAPFBList: function(params, callback, lua_state) {
|
dmIAPFBList: function(params, callback, lua_callback) {
|
||||||
var product_ids = Pointer_stringify(params).trim().split(',');
|
var product_ids = Pointer_stringify(params).trim().split(',');
|
||||||
var product_count = product_ids.length;
|
var product_count = product_ids.length;
|
||||||
if(product_count == 0) {
|
if(product_count == 0) {
|
||||||
@@ -96,7 +96,7 @@ var LibraryFacebookIAP = {
|
|||||||
products = {};
|
products = {};
|
||||||
var xmlhttp = new XMLHttpRequest();
|
var xmlhttp = new XMLHttpRequest();
|
||||||
xmlhttp.onreadystatechange = function() {
|
xmlhttp.onreadystatechange = function() {
|
||||||
FBinner.http_callback(xmlhttp, callback, lua_state, products, product_ids, product_count, 0);
|
FBinner.http_callback(xmlhttp, callback, lua_callback, products, product_ids, product_count, 0);
|
||||||
};
|
};
|
||||||
// chain of async http read of product files
|
// chain of async http read of product files
|
||||||
xmlhttp.open("GET", product_ids[0], true);
|
xmlhttp.open("GET", product_ids[0], true);
|
||||||
@@ -104,7 +104,7 @@ var LibraryFacebookIAP = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// https://developers.facebook.com/docs/javascript/reference/FB.ui
|
// https://developers.facebook.com/docs/javascript/reference/FB.ui
|
||||||
dmIAPFBBuy: function(param_product_id, param_request_id, callback, lua_state) {
|
dmIAPFBBuy: function(param_product_id, param_request_id, callback, lua_callback) {
|
||||||
var product_id = Pointer_stringify(param_product_id);
|
var product_id = Pointer_stringify(param_product_id);
|
||||||
|
|
||||||
var buy_params = {
|
var buy_params = {
|
||||||
@@ -144,7 +144,7 @@ var LibraryFacebookIAP = {
|
|||||||
|
|
||||||
var productsJSON = JSON.stringify(result)
|
var productsJSON = JSON.stringify(result)
|
||||||
var res_buf = allocate(intArrayFromString(productsJSON), 'i8', ALLOC_STACK);
|
var res_buf = allocate(intArrayFromString(productsJSON), 'i8', ALLOC_STACK);
|
||||||
Runtime.dynCall('viii', callback, [lua_state, res_buf, 0]);
|
Runtime.dynCall('viii', callback, [lua_callback, res_buf, 0]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ var LibraryFacebookIAP = {
|
|||||||
reason = FBinner.BillingResponse.BILLING_RESPONSE_RESULT_ERROR;
|
reason = FBinner.BillingResponse.BILLING_RESPONSE_RESULT_ERROR;
|
||||||
console.log("Unknown response: ", response);
|
console.log("Unknown response: ", response);
|
||||||
}
|
}
|
||||||
Runtime.dynCall('viii', callback, [lua_state, 0, reason]);
|
Runtime.dynCall('viii', callback, [lua_callback, 0, reason]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -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,17 @@ 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;
|
if (cmd->m_Callback == 0)
|
||||||
int top = lua_gettop(L);
|
{
|
||||||
|
dmLogWarning("Received product list but no listener was set!");
|
||||||
if (g_IAP.m_Callback == LUA_NOREF) {
|
|
||||||
dmLogError("No callback set");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, g_IAP.m_Callback);
|
lua_State* L = dmScript::GetCallbackLuaContext(cmd->m_Callback);
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
|
||||||
// Setup self
|
if (!dmScript::SetupCallback(cmd->m_Callback))
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -320,42 +283,29 @@ static void HandleProductResult(const IAPCommand* cmd)
|
|||||||
IAP_PushError(L, "failed to fetch product", REASON_UNSPECIFIED);
|
IAP_PushError(L, "failed to fetch product", REASON_UNSPECIFIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = lua_pcall(L, 3, 0, 0);
|
dmScript::PCall(L, 3, 0);
|
||||||
if (ret != 0) {
|
|
||||||
dmLogError("Error running callback: %s", lua_tostring(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;
|
if (cmd->m_Callback == 0)
|
||||||
int top = lua_gettop(L);
|
{
|
||||||
|
dmLogWarning("Received purchase result but no listener was set!");
|
||||||
if (g_IAP.m_Listener.m_Callback == LUA_NOREF) {
|
|
||||||
dmLogError("No callback set");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lua_State* L = dmScript::GetCallbackLuaContext(cmd->m_Callback);
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, g_IAP.m_Listener.m_Callback);
|
if (!dmScript::SetupCallback(cmd->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,11 +343,9 @@ 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);
|
dmScript::PCall(L, 3, 0);
|
||||||
if (ret != 0) {
|
|
||||||
dmLogError("Error running callback: %s", lua_tostring(L, -1));
|
dmScript::TeardownCallback(cmd->m_Callback);
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(top == lua_gettop(L));
|
assert(top == lua_gettop(L));
|
||||||
}
|
}
|
||||||
@@ -500,12 +448,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) {
|
||||||
|
@@ -15,63 +15,35 @@ 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;
|
||||||
}
|
}
|
||||||
int m_InitCount;
|
|
||||||
int m_Callback;
|
|
||||||
int m_Self;
|
|
||||||
bool m_autoFinishTransactions;
|
|
||||||
lua_State* m_L;
|
|
||||||
IAPListener m_Listener;
|
|
||||||
|
|
||||||
|
dmScript::LuaCallbackInfo* m_Listener;
|
||||||
|
int m_InitCount;
|
||||||
|
bool m_autoFinishTransactions;
|
||||||
} g_IAP;
|
} g_IAP;
|
||||||
|
|
||||||
typedef void (*OnIAPFBList)(void *L, const char* json);
|
typedef void (*OnIAPFBList)(void* luacallback, const char* json);
|
||||||
typedef void (*OnIAPFBListenerCallback)(void *L, const char* json, int error_code);
|
typedef void (*OnIAPFBListenerCallback)(void* luacallback, const char* json, int error_code);
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// Implementation in library_facebook_iap.js
|
// Implementation in library_facebook_iap.js
|
||||||
void dmIAPFBList(const char* item_ids, OnIAPFBList callback, lua_State* L);
|
void dmIAPFBList(const char* item_ids, OnIAPFBList callback, dmScript::LuaCallbackInfo* luacallback);
|
||||||
void dmIAPFBBuy(const char* item_id, const char* request_id, OnIAPFBListenerCallback callback, lua_State* L);
|
void dmIAPFBBuy(const char* item_id, const char* request_id, OnIAPFBListenerCallback callback, dmScript::LuaCallbackInfo* luacallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void IAPList_Callback(void* luacallback, const char* result_json)
|
||||||
static void VerifyCallback(lua_State* L)
|
|
||||||
{
|
{
|
||||||
if (g_IAP.m_Callback != LUA_NOREF) {
|
dmScript::LuaCallbackInfo* callback = (dmScript::LuaCallbackInfo*)luacallback;
|
||||||
dmLogError("Unexpected callback set");
|
lua_State* L = dmScript::GetCallbackLuaContext(callback);
|
||||||
dmScript::Unref(L, LUA_REGISTRYINDEX, g_IAP.m_Callback);
|
DM_LUA_STACK_CHECK(L, 0);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IAPList_Callback(void* Lv, const char* result_json)
|
if (!dmScript::SetupCallback(callback))
|
||||||
{
|
|
||||||
lua_State* L = (lua_State*) Lv;
|
|
||||||
if (g_IAP.m_Callback != LUA_NOREF) {
|
|
||||||
int top = lua_gettop(L);
|
|
||||||
int callback = g_IAP.m_Callback;
|
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, 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 facebook callback because the instance has been deleted.");
|
dmScript::DestroyCallback(callback);
|
||||||
lua_pop(L, 2);
|
|
||||||
assert(top == lua_gettop(L));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result_json != 0)
|
if(result_json != 0)
|
||||||
{
|
{
|
||||||
dmJson::Document doc;
|
dmJson::Document doc;
|
||||||
@@ -99,68 +71,41 @@ void IAPList_Callback(void* Lv, const char* result_json)
|
|||||||
IAP_PushError(L, "Got empty list result.", REASON_UNSPECIFIED);
|
IAP_PushError(L, "Got empty list result.", REASON_UNSPECIFIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = lua_pcall(L, 3, 0, 0);
|
dmScript::PCall(L, 3, 0);
|
||||||
if (ret != 0) {
|
|
||||||
dmLogError("Error running callback: %s", lua_tostring(L, -1));
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
assert(top == lua_gettop(L));
|
|
||||||
dmScript::Unref(L, LUA_REGISTRYINDEX, callback);
|
|
||||||
|
|
||||||
g_IAP.m_Callback = LUA_NOREF;
|
|
||||||
} else {
|
|
||||||
dmLogError("No callback set");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
dmScript::DestroyCallback(callback);
|
||||||
|
dmScript::TeardownCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
int IAP_List(lua_State* L)
|
static int IAP_List(lua_State* L)
|
||||||
{
|
{
|
||||||
int top = lua_gettop(L);
|
DM_LUA_STACK_CHECK(L, 0);
|
||||||
VerifyCallback(L);
|
|
||||||
|
|
||||||
char* buf = IAP_List_CreateBuffer(L);
|
char* buf = IAP_List_CreateBuffer(L);
|
||||||
if( buf == 0 )
|
if( buf == 0 )
|
||||||
{
|
{
|
||||||
assert(top == lua_gettop(L));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
dmScript::LuaCallbackInfo* callback = dmScript::CreateCallback(L, 2);
|
||||||
lua_pushvalue(L, 2);
|
|
||||||
g_IAP.m_Callback = dmScript::Ref(L, LUA_REGISTRYINDEX);
|
dmIAPFBList(buf, (OnIAPFBList)IAPList_Callback, callback);
|
||||||
dmScript::GetInstance(L);
|
|
||||||
g_IAP.m_Self = dmScript::Ref(L, LUA_REGISTRYINDEX);
|
|
||||||
g_IAP.m_L = dmScript::GetMainThread(L);
|
|
||||||
dmIAPFBList(buf, (OnIAPFBList)IAPList_Callback, g_IAP.m_L);
|
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
assert(top == lua_gettop(L));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAPListener_Callback(void* Lv, const char* result_json, int error_code)
|
static void IAPListener_Callback(void* luacallback, const char* result_json, int error_code)
|
||||||
{
|
{
|
||||||
lua_State* L = g_IAP.m_Listener.m_L;
|
dmScript::LuaCallbackInfo* callback = (dmScript::LuaCallbackInfo*)luacallback;
|
||||||
int top = lua_gettop(L);
|
lua_State* L = dmScript::GetCallbackLuaContext(callback);
|
||||||
if (g_IAP.m_Listener.m_Callback == LUA_NOREF) {
|
DM_LUA_STACK_CHECK(L, 0);
|
||||||
dmLogError("No callback set");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, g_IAP.m_Listener.m_Callback);
|
|
||||||
|
|
||||||
// Setup self
|
if (!dmScript::SetupCallback(callback))
|
||||||
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));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result_json) {
|
if (result_json) {
|
||||||
dmJson::Document doc;
|
dmJson::Document doc;
|
||||||
dmJson::Result r = dmJson::Parse(result_json, &doc);
|
dmJson::Result r = dmJson::Parse(result_json, &doc);
|
||||||
@@ -197,21 +142,22 @@ void IAPListener_Callback(void* Lv, const char* result_json, int error_code)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int ret = lua_pcall(L, 3, 0, 0);
|
|
||||||
if (ret != 0) {
|
dmScript::PCall(L, 3, 0);
|
||||||
dmLogError("Error running callback: %s", lua_tostring(L, -1));
|
|
||||||
lua_pop(L, 1);
|
dmScript::TeardownCallback(callback);
|
||||||
}
|
|
||||||
assert(top == lua_gettop(L));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int IAP_Buy(lua_State* L)
|
static int IAP_Buy(lua_State* L)
|
||||||
{
|
{
|
||||||
if (g_IAP.m_Listener.m_Callback == LUA_NOREF) {
|
DM_LUA_STACK_CHECK(L, 0);
|
||||||
|
|
||||||
|
if (!g_IAP.m_Listener) {
|
||||||
dmLogError("No callback set");
|
dmLogError("No callback set");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
const char* id = luaL_checkstring(L, 1);
|
const char* id = luaL_checkstring(L, 1);
|
||||||
const char* request_id = 0x0;
|
const char* request_id = 0x0;
|
||||||
@@ -224,43 +170,34 @@ int IAP_Buy(lua_State* L)
|
|||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
dmIAPFBBuy(id, request_id, (OnIAPFBListenerCallback)IAPListener_Callback, L);
|
dmIAPFBBuy(id, request_id, (OnIAPFBListenerCallback)IAPListener_Callback, g_IAP.m_Listener);
|
||||||
assert(top == lua_gettop(L));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int IAP_SetListener(lua_State* L)
|
static int IAP_SetListener(lua_State* L)
|
||||||
{
|
{
|
||||||
IAP* iap = &g_IAP;
|
DM_LUA_STACK_CHECK(L, 0);
|
||||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
if (g_IAP.m_Listener)
|
||||||
lua_pushvalue(L, 1);
|
dmScript::DestroyCallback(g_IAP.m_Listener);
|
||||||
int cb = dmScript::Ref(L, LUA_REGISTRYINDEX);
|
g_IAP.m_Listener = dmScript::CreateCallback(L, 1);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
iap->m_Listener.m_L = dmScript::GetMainThread(L);
|
|
||||||
iap->m_Listener.m_Callback = cb;
|
|
||||||
dmScript::GetInstance(L);
|
|
||||||
iap->m_Listener.m_Self = dmScript::Ref(L, LUA_REGISTRYINDEX);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int IAP_Finish(lua_State* L)
|
static int IAP_Finish(lua_State* L)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int IAP_Restore(lua_State* L)
|
static int IAP_Restore(lua_State* L)
|
||||||
{
|
{
|
||||||
|
DM_LUA_STACK_CHECK(L, 1);
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int IAP_GetProviderId(lua_State* L)
|
static int IAP_GetProviderId(lua_State* L)
|
||||||
{
|
{
|
||||||
|
DM_LUA_STACK_CHECK(L, 1);
|
||||||
lua_pushinteger(L, PROVIDER_ID_FACEBOOK);
|
lua_pushinteger(L, PROVIDER_ID_FACEBOOK);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -276,13 +213,13 @@ static const luaL_reg IAP_methods[] =
|
|||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
dmExtension::Result InitializeIAP(dmExtension::Params* params)
|
static dmExtension::Result InitializeIAP(dmExtension::Params* params)
|
||||||
{
|
{
|
||||||
if (g_IAP.m_InitCount == 0) {
|
if (g_IAP.m_InitCount == 0) {
|
||||||
g_IAP.m_autoFinishTransactions = dmConfigFile::GetInt(params->m_ConfigFile, "iap.auto_finish_transactions", 1) == 1;
|
g_IAP.m_autoFinishTransactions = dmConfigFile::GetInt(params->m_ConfigFile, "iap.auto_finish_transactions", 1) == 1;
|
||||||
}
|
}
|
||||||
g_IAP.m_InitCount++;
|
g_IAP.m_InitCount++;
|
||||||
lua_State*L = params->m_L;
|
lua_State* L = params->m_L;
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
luaL_register(L, LIB_NAME, IAP_methods);
|
luaL_register(L, LIB_NAME, IAP_methods);
|
||||||
|
|
||||||
@@ -293,15 +230,13 @@ dmExtension::Result InitializeIAP(dmExtension::Params* params)
|
|||||||
return dmExtension::RESULT_OK;
|
return dmExtension::RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
dmExtension::Result FinalizeIAP(dmExtension::Params* params)
|
static dmExtension::Result FinalizeIAP(dmExtension::Params* params)
|
||||||
{
|
{
|
||||||
--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 (g_IAP.m_Listener && g_IAP.m_InitCount == 0)
|
||||||
dmScript::Unref(g_IAP.m_Listener.m_L, LUA_REGISTRYINDEX, g_IAP.m_Listener.m_Callback);
|
{
|
||||||
dmScript::Unref(g_IAP.m_Listener.m_L, LUA_REGISTRYINDEX, g_IAP.m_Listener.m_Self);
|
dmScript::DestroyCallback(g_IAP.m_Listener);
|
||||||
g_IAP.m_Listener.m_L = 0;
|
g_IAP.m_Listener = 0;
|
||||||
g_IAP.m_Listener.m_Callback = LUA_NOREF;
|
|
||||||
g_IAP.m_Listener.m_Self = LUA_NOREF;
|
|
||||||
}
|
}
|
||||||
return dmExtension::RESULT_OK;
|
return dmExtension::RESULT_OK;
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -121,8 +119,20 @@ static void IAP_FreeTransaction(IAPTransaction* transaction)
|
|||||||
|
|
||||||
IAPProduct product = {0};
|
IAPProduct product = {0};
|
||||||
product.ident = strdup([p.productIdentifier UTF8String]);
|
product.ident = strdup([p.productIdentifier UTF8String]);
|
||||||
|
if (p.localizedTitle) {
|
||||||
product.title = strdup([p.localizedTitle UTF8String]);
|
product.title = strdup([p.localizedTitle UTF8String]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dmLogWarning("Product %s has no localizedTitle", [p.productIdentifier UTF8String]);
|
||||||
|
product.title = "";
|
||||||
|
}
|
||||||
|
if (p.localizedDescription) {
|
||||||
product.description = strdup([p.localizedDescription UTF8String]);
|
product.description = strdup([p.localizedDescription UTF8String]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dmLogWarning("Product %s has no localizedDescription", [p.productIdentifier UTF8String]);
|
||||||
|
product.description = "";
|
||||||
|
}
|
||||||
product.currency_code = strdup([[p.priceLocale objectForKey:NSLocaleCurrencyCode] UTF8String]);
|
product.currency_code = strdup([[p.priceLocale objectForKey:NSLocaleCurrencyCode] UTF8String]);
|
||||||
product.price = p.price.floatValue;
|
product.price = p.price.floatValue;
|
||||||
|
|
||||||
@@ -141,7 +151,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 +161,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 +198,10 @@ static void HandleProductResult(IAPCommand* cmd)
|
|||||||
}
|
}
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
|
|
||||||
int ret = lua_pcall(L, 3, 0, 0);
|
dmScript::PCall(L, 3, 0);
|
||||||
if (ret != 0) {
|
|
||||||
dmLogError("%d: Error running callback: %s", __LINE__, lua_tostring(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 +210,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 +221,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);
|
||||||
@@ -239,6 +245,7 @@ static void CopyTransaction(SKPaymentTransaction* transaction, IAPTransaction* o
|
|||||||
}
|
}
|
||||||
|
|
||||||
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
|
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
|
||||||
|
[dateFormatter setLocale: [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
|
||||||
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZ"];
|
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZ"];
|
||||||
|
|
||||||
out->ident = strdup([transaction.payment.productIdentifier UTF8String]);
|
out->ident = strdup([transaction.payment.productIdentifier UTF8String]);
|
||||||
@@ -300,13 +307,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,11 +327,9 @@ static void HandlePurchaseResult(IAPCommand* cmd)
|
|||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = lua_pcall(L, 3, 0, 0);
|
dmScript::PCall(L, 3, 0);
|
||||||
if (ret != 0) {
|
|
||||||
dmLogError("%d: Error running callback: %s", __LINE__, lua_tostring(L, -1));
|
dmScript::TeardownCallback(cmd->m_Callback);
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
IAP_FreeTransaction(transaction);
|
IAP_FreeTransaction(transaction);
|
||||||
|
|
||||||
@@ -344,8 +348,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 +397,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 +486,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 +579,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) {
|
||||||
|
@@ -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)
|
||||||
|
@@ -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);
|
||||||
|
@@ -17,6 +17,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@@ -155,10 +156,24 @@ public class IapGooglePlay implements Handler.Callback {
|
|||||||
this.autoFinishTransactions = autoFinishTransactions;
|
this.autoFinishTransactions = autoFinishTransactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isPlayStoreInstalled(Context context){
|
||||||
|
try {
|
||||||
|
context.getPackageManager().getPackageInfo("com.android.vending", 0);
|
||||||
|
return true;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
// NOTE: We must create Handler lazily as construction of
|
// NOTE: We must create Handler lazily as construction of
|
||||||
// handlers must be in the context of a "looper" on Android
|
// handlers must be in the context of a "looper" on Android
|
||||||
|
|
||||||
|
if (!isPlayStoreInstalled(activity)) {
|
||||||
|
Log.e(TAG, "Unable to find Google Play Store (com.android.vending)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.initialized)
|
if (this.initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
13
game.project
13
game.project
@@ -5,13 +5,13 @@ main_collection = /main/main.collectionc
|
|||||||
shared_state = 1
|
shared_state = 1
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
width = 960
|
width = 640
|
||||||
height = 640
|
height = 1136
|
||||||
|
|
||||||
[android]
|
[android]
|
||||||
input_method = HiddenInputField
|
input_method = HiddenInputField
|
||||||
package = com.defold.iaprtestapp
|
package = com.defold.extension.iap
|
||||||
version_code = 3
|
version_code = 5
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
title = extension-iap
|
title = extension-iap
|
||||||
@@ -21,8 +21,11 @@ dependencies = https://github.com/andsve/dirtylarry/archive/master.zip
|
|||||||
include_dirs = extension-iap
|
include_dirs = extension-iap
|
||||||
|
|
||||||
[ios]
|
[ios]
|
||||||
bundle_identifier = com.defoldextension.push
|
bundle_identifier = com.defold.extension.iap
|
||||||
|
|
||||||
[iap]
|
[iap]
|
||||||
auto_finish_transactions = 0
|
auto_finish_transactions = 0
|
||||||
|
|
||||||
|
[osx]
|
||||||
|
bundle_identifier = com.defold.extension.iap
|
||||||
|
|
||||||
|
883
main/main.gui
883
main/main.gui
@@ -41,7 +41,7 @@ nodes {
|
|||||||
w: 1.0
|
w: 1.0
|
||||||
}
|
}
|
||||||
type: TYPE_TEMPLATE
|
type: TYPE_TEMPLATE
|
||||||
id: "consumable"
|
id: "goldbars_small"
|
||||||
layer: ""
|
layer: ""
|
||||||
inherit_alpha: true
|
inherit_alpha: true
|
||||||
alpha: 1.0
|
alpha: 1.0
|
||||||
@@ -82,12 +82,12 @@ nodes {
|
|||||||
type: TYPE_BOX
|
type: TYPE_BOX
|
||||||
blend_mode: BLEND_MODE_ALPHA
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
texture: "button/button_normal"
|
texture: "button/button_normal"
|
||||||
id: "consumable/larrybutton"
|
id: "goldbars_small/larrybutton"
|
||||||
xanchor: XANCHOR_NONE
|
xanchor: XANCHOR_NONE
|
||||||
yanchor: YANCHOR_NONE
|
yanchor: YANCHOR_NONE
|
||||||
pivot: PIVOT_CENTER
|
pivot: PIVOT_CENTER
|
||||||
adjust_mode: ADJUST_MODE_FIT
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
parent: "consumable"
|
parent: "goldbars_small"
|
||||||
layer: ""
|
layer: ""
|
||||||
inherit_alpha: true
|
inherit_alpha: true
|
||||||
slice9 {
|
slice9 {
|
||||||
@@ -129,16 +129,16 @@ nodes {
|
|||||||
w: 1.0
|
w: 1.0
|
||||||
}
|
}
|
||||||
color {
|
color {
|
||||||
x: 0.6
|
x: 1.0
|
||||||
y: 0.0
|
y: 1.0
|
||||||
z: 0.0
|
z: 1.0
|
||||||
w: 1.0
|
w: 1.0
|
||||||
}
|
}
|
||||||
type: TYPE_TEXT
|
type: TYPE_TEXT
|
||||||
blend_mode: BLEND_MODE_ALPHA
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
text: "consumable"
|
text: "Goldbars - S"
|
||||||
font: "larryfont"
|
font: "larryfont"
|
||||||
id: "consumable/larrylabel"
|
id: "goldbars_small/larrylabel"
|
||||||
xanchor: XANCHOR_NONE
|
xanchor: XANCHOR_NONE
|
||||||
yanchor: YANCHOR_NONE
|
yanchor: YANCHOR_NONE
|
||||||
pivot: PIVOT_CENTER
|
pivot: PIVOT_CENTER
|
||||||
@@ -156,172 +156,12 @@ nodes {
|
|||||||
}
|
}
|
||||||
adjust_mode: ADJUST_MODE_FIT
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
line_break: false
|
line_break: false
|
||||||
parent: "consumable/larrybutton"
|
parent: "goldbars_small/larrybutton"
|
||||||
layer: ""
|
layer: ""
|
||||||
inherit_alpha: true
|
inherit_alpha: true
|
||||||
alpha: 1.0
|
alpha: 1.0
|
||||||
outline_alpha: 1.0
|
outline_alpha: 1.0
|
||||||
shadow_alpha: 1.0
|
shadow_alpha: 1.0
|
||||||
overridden_fields: 5
|
|
||||||
overridden_fields: 8
|
|
||||||
template_node_child: true
|
|
||||||
text_leading: 1.0
|
|
||||||
text_tracking: 0.0
|
|
||||||
}
|
|
||||||
nodes {
|
|
||||||
position {
|
|
||||||
x: 171.0
|
|
||||||
y: 449.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
rotation {
|
|
||||||
x: 0.0
|
|
||||||
y: 0.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
scale {
|
|
||||||
x: 1.0
|
|
||||||
y: 1.0
|
|
||||||
z: 1.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
size {
|
|
||||||
x: 200.0
|
|
||||||
y: 100.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
color {
|
|
||||||
x: 1.0
|
|
||||||
y: 1.0
|
|
||||||
z: 1.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
type: TYPE_TEMPLATE
|
|
||||||
id: "nonconsumable"
|
|
||||||
layer: ""
|
|
||||||
inherit_alpha: true
|
|
||||||
alpha: 1.0
|
|
||||||
template: "/dirtylarry/button.gui"
|
|
||||||
template_node_child: false
|
|
||||||
}
|
|
||||||
nodes {
|
|
||||||
position {
|
|
||||||
x: 0.0
|
|
||||||
y: 0.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
rotation {
|
|
||||||
x: 0.0
|
|
||||||
y: 0.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
scale {
|
|
||||||
x: 1.0
|
|
||||||
y: 1.0
|
|
||||||
z: 1.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
size {
|
|
||||||
x: 300.0
|
|
||||||
y: 88.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
color {
|
|
||||||
x: 1.0
|
|
||||||
y: 1.0
|
|
||||||
z: 1.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
type: TYPE_BOX
|
|
||||||
blend_mode: BLEND_MODE_ALPHA
|
|
||||||
texture: "button/button_normal"
|
|
||||||
id: "nonconsumable/larrybutton"
|
|
||||||
xanchor: XANCHOR_NONE
|
|
||||||
yanchor: YANCHOR_NONE
|
|
||||||
pivot: PIVOT_CENTER
|
|
||||||
adjust_mode: ADJUST_MODE_FIT
|
|
||||||
parent: "nonconsumable"
|
|
||||||
layer: ""
|
|
||||||
inherit_alpha: true
|
|
||||||
slice9 {
|
|
||||||
x: 32.0
|
|
||||||
y: 32.0
|
|
||||||
z: 32.0
|
|
||||||
w: 32.0
|
|
||||||
}
|
|
||||||
clipping_mode: CLIPPING_MODE_NONE
|
|
||||||
clipping_visible: true
|
|
||||||
clipping_inverted: false
|
|
||||||
alpha: 1.0
|
|
||||||
template_node_child: true
|
|
||||||
size_mode: SIZE_MODE_MANUAL
|
|
||||||
}
|
|
||||||
nodes {
|
|
||||||
position {
|
|
||||||
x: 0.0
|
|
||||||
y: 0.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
rotation {
|
|
||||||
x: 0.0
|
|
||||||
y: 0.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
scale {
|
|
||||||
x: 1.0
|
|
||||||
y: 1.0
|
|
||||||
z: 1.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
size {
|
|
||||||
x: 200.0
|
|
||||||
y: 100.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
color {
|
|
||||||
x: 0.6
|
|
||||||
y: 0.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
type: TYPE_TEXT
|
|
||||||
blend_mode: BLEND_MODE_ALPHA
|
|
||||||
text: "non-consumable"
|
|
||||||
font: "larryfont"
|
|
||||||
id: "nonconsumable/larrylabel"
|
|
||||||
xanchor: XANCHOR_NONE
|
|
||||||
yanchor: YANCHOR_NONE
|
|
||||||
pivot: PIVOT_CENTER
|
|
||||||
outline {
|
|
||||||
x: 0.0
|
|
||||||
y: 0.0
|
|
||||||
z: 0.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
shadow {
|
|
||||||
x: 1.0
|
|
||||||
y: 1.0
|
|
||||||
z: 1.0
|
|
||||||
w: 1.0
|
|
||||||
}
|
|
||||||
adjust_mode: ADJUST_MODE_FIT
|
|
||||||
line_break: false
|
|
||||||
parent: "nonconsumable/larrybutton"
|
|
||||||
layer: ""
|
|
||||||
inherit_alpha: true
|
|
||||||
alpha: 1.0
|
|
||||||
outline_alpha: 1.0
|
|
||||||
shadow_alpha: 1.0
|
|
||||||
overridden_fields: 5
|
|
||||||
overridden_fields: 8
|
overridden_fields: 8
|
||||||
template_node_child: true
|
template_node_child: true
|
||||||
text_leading: 1.0
|
text_leading: 1.0
|
||||||
@@ -330,7 +170,7 @@ nodes {
|
|||||||
nodes {
|
nodes {
|
||||||
position {
|
position {
|
||||||
x: 485.0
|
x: 485.0
|
||||||
y: 449.0
|
y: 56.0
|
||||||
z: 0.0
|
z: 0.0
|
||||||
w: 1.0
|
w: 1.0
|
||||||
}
|
}
|
||||||
@@ -447,14 +287,14 @@ nodes {
|
|||||||
w: 1.0
|
w: 1.0
|
||||||
}
|
}
|
||||||
color {
|
color {
|
||||||
x: 0.6
|
x: 1.0
|
||||||
y: 0.0
|
y: 1.0
|
||||||
z: 0.0
|
z: 1.0
|
||||||
w: 1.0
|
w: 1.0
|
||||||
}
|
}
|
||||||
type: TYPE_TEXT
|
type: TYPE_TEXT
|
||||||
blend_mode: BLEND_MODE_ALPHA
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
text: "<- reset"
|
text: "Reset"
|
||||||
font: "larryfont"
|
font: "larryfont"
|
||||||
id: "reset/larrylabel"
|
id: "reset/larrylabel"
|
||||||
xanchor: XANCHOR_NONE
|
xanchor: XANCHOR_NONE
|
||||||
@@ -480,7 +320,700 @@ nodes {
|
|||||||
alpha: 1.0
|
alpha: 1.0
|
||||||
outline_alpha: 1.0
|
outline_alpha: 1.0
|
||||||
shadow_alpha: 1.0
|
shadow_alpha: 1.0
|
||||||
overridden_fields: 5
|
overridden_fields: 8
|
||||||
|
template_node_child: true
|
||||||
|
text_leading: 1.0
|
||||||
|
text_tracking: 0.0
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 20.0
|
||||||
|
y: 1124.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 600.0
|
||||||
|
y: 450.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEXT
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
text: "<text>"
|
||||||
|
font: "system_font"
|
||||||
|
id: "log"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_NW
|
||||||
|
outline {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
shadow {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
line_break: true
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
outline_alpha: 1.0
|
||||||
|
shadow_alpha: 1.0
|
||||||
|
template_node_child: false
|
||||||
|
text_leading: 1.0
|
||||||
|
text_tracking: 0.0
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 171.0
|
||||||
|
y: 465.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEMPLATE
|
||||||
|
id: "goldbars_medium"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
template: "/dirtylarry/button.gui"
|
||||||
|
template_node_child: false
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 300.0
|
||||||
|
y: 88.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_BOX
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
texture: "button/button_normal"
|
||||||
|
id: "goldbars_medium/larrybutton"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
parent: "goldbars_medium"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
slice9 {
|
||||||
|
x: 32.0
|
||||||
|
y: 32.0
|
||||||
|
z: 32.0
|
||||||
|
w: 32.0
|
||||||
|
}
|
||||||
|
clipping_mode: CLIPPING_MODE_NONE
|
||||||
|
clipping_visible: true
|
||||||
|
clipping_inverted: false
|
||||||
|
alpha: 1.0
|
||||||
|
template_node_child: true
|
||||||
|
size_mode: SIZE_MODE_MANUAL
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEXT
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
text: "Goldbars - M"
|
||||||
|
font: "larryfont"
|
||||||
|
id: "goldbars_medium/larrylabel"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
outline {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
shadow {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
line_break: false
|
||||||
|
parent: "goldbars_medium/larrybutton"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
outline_alpha: 1.0
|
||||||
|
shadow_alpha: 1.0
|
||||||
|
overridden_fields: 8
|
||||||
|
template_node_child: true
|
||||||
|
text_leading: 1.0
|
||||||
|
text_tracking: 0.0
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 171.0
|
||||||
|
y: 357.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEMPLATE
|
||||||
|
id: "goldbars_large"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
template: "/dirtylarry/button.gui"
|
||||||
|
template_node_child: false
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 300.0
|
||||||
|
y: 88.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_BOX
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
texture: "button/button_normal"
|
||||||
|
id: "goldbars_large/larrybutton"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
parent: "goldbars_large"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
slice9 {
|
||||||
|
x: 32.0
|
||||||
|
y: 32.0
|
||||||
|
z: 32.0
|
||||||
|
w: 32.0
|
||||||
|
}
|
||||||
|
clipping_mode: CLIPPING_MODE_NONE
|
||||||
|
clipping_visible: true
|
||||||
|
clipping_inverted: false
|
||||||
|
alpha: 1.0
|
||||||
|
template_node_child: true
|
||||||
|
size_mode: SIZE_MODE_MANUAL
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEXT
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
text: "Goldbars - L"
|
||||||
|
font: "larryfont"
|
||||||
|
id: "goldbars_large/larrylabel"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
outline {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
shadow {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
line_break: false
|
||||||
|
parent: "goldbars_large/larrybutton"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
outline_alpha: 1.0
|
||||||
|
shadow_alpha: 1.0
|
||||||
|
overridden_fields: 8
|
||||||
|
template_node_child: true
|
||||||
|
text_leading: 1.0
|
||||||
|
text_tracking: 0.0
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 159.0
|
||||||
|
y: 56.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEMPLATE
|
||||||
|
id: "list"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
template: "/dirtylarry/button.gui"
|
||||||
|
template_node_child: false
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 300.0
|
||||||
|
y: 88.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_BOX
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
texture: "button/button_normal"
|
||||||
|
id: "list/larrybutton"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
parent: "list"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
slice9 {
|
||||||
|
x: 32.0
|
||||||
|
y: 32.0
|
||||||
|
z: 32.0
|
||||||
|
w: 32.0
|
||||||
|
}
|
||||||
|
clipping_mode: CLIPPING_MODE_NONE
|
||||||
|
clipping_visible: true
|
||||||
|
clipping_inverted: false
|
||||||
|
alpha: 1.0
|
||||||
|
template_node_child: true
|
||||||
|
size_mode: SIZE_MODE_MANUAL
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEXT
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
text: "List"
|
||||||
|
font: "larryfont"
|
||||||
|
id: "list/larrylabel"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
outline {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
shadow {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
line_break: false
|
||||||
|
parent: "list/larrybutton"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
outline_alpha: 1.0
|
||||||
|
shadow_alpha: 1.0
|
||||||
|
overridden_fields: 8
|
||||||
|
template_node_child: true
|
||||||
|
text_leading: 1.0
|
||||||
|
text_tracking: 0.0
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 171.0
|
||||||
|
y: 251.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEMPLATE
|
||||||
|
id: "subscription"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
template: "/dirtylarry/button.gui"
|
||||||
|
template_node_child: false
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 300.0
|
||||||
|
y: 88.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_BOX
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
texture: "button/button_normal"
|
||||||
|
id: "subscription/larrybutton"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
parent: "subscription"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
slice9 {
|
||||||
|
x: 32.0
|
||||||
|
y: 32.0
|
||||||
|
z: 32.0
|
||||||
|
w: 32.0
|
||||||
|
}
|
||||||
|
clipping_mode: CLIPPING_MODE_NONE
|
||||||
|
clipping_visible: true
|
||||||
|
clipping_inverted: false
|
||||||
|
alpha: 1.0
|
||||||
|
template_node_child: true
|
||||||
|
size_mode: SIZE_MODE_MANUAL
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEXT
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
text: "Subscription"
|
||||||
|
font: "larryfont"
|
||||||
|
id: "subscription/larrylabel"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
outline {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
shadow {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
line_break: false
|
||||||
|
parent: "subscription/larrybutton"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
outline_alpha: 1.0
|
||||||
|
shadow_alpha: 1.0
|
||||||
overridden_fields: 8
|
overridden_fields: 8
|
||||||
template_node_child: true
|
template_node_child: true
|
||||||
text_leading: 1.0
|
text_leading: 1.0
|
||||||
|
@@ -1,59 +1,113 @@
|
|||||||
local dirtylarry = require "dirtylarry/dirtylarry"
|
local dirtylarry = require "dirtylarry/dirtylarry"
|
||||||
|
|
||||||
|
local GOLDBARS_SMALL = "com.defold.iap.goldbar.small"
|
||||||
|
local GOLDBARS_MEDIUM = "com.defold.iap.goldbar.medium"
|
||||||
|
local GOLDBARS_LARGE = "com.defold.iap.goldbar.large"
|
||||||
|
local SUBSCRIPTION = "com.defold.iap.subscription"
|
||||||
|
|
||||||
local items = {
|
local items = {
|
||||||
"consumable",
|
GOLDBARS_SMALL,
|
||||||
"nonconsumable"
|
GOLDBARS_MEDIUM,
|
||||||
|
GOLDBARS_LARGE,
|
||||||
|
SUBSCRIPTION,
|
||||||
}
|
}
|
||||||
|
|
||||||
local product_items = {}
|
-- mapping between product id and button name
|
||||||
|
local item_buttons = {
|
||||||
|
[GOLDBARS_SMALL] = "goldbars_small",
|
||||||
|
[GOLDBARS_MEDIUM] = "goldbars_medium",
|
||||||
|
[GOLDBARS_LARGE] = "goldbars_large",
|
||||||
|
[SUBSCRIPTION] = "subscription",
|
||||||
|
}
|
||||||
|
|
||||||
local function list_callback(self, products, error)
|
local available_items = {}
|
||||||
if error == nil then
|
|
||||||
for k,p in pairs(products) do
|
local LOG = {}
|
||||||
product_items[p.ident] = p
|
|
||||||
local name = p.ident.."/larrylabel"
|
local function log(fmt, ...)
|
||||||
gui.set_color(gui.get_node(name), vmath.vector4(1,1,1,1))
|
if not fmt then return end
|
||||||
end
|
local line = fmt:format(...)
|
||||||
else
|
print(line)
|
||||||
print(error.error)
|
table.insert(LOG, line)
|
||||||
|
if #LOG > 10 then
|
||||||
|
table.remove(LOG, 1)
|
||||||
end
|
end
|
||||||
|
local s = table.concat(LOG, "\n")
|
||||||
|
gui.set_text(gui.get_node("log"), s)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function buy(id)
|
||||||
|
log("iap.buy() " .. id)
|
||||||
|
iap.buy(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function list()
|
||||||
|
log("iap.list()")
|
||||||
|
for item, button in pairs(item_buttons) do
|
||||||
|
gui.set_color(gui.get_node(button.."/larrylabel"), vmath.vector4(1,1,1,0.5))
|
||||||
|
end
|
||||||
|
iap.list(items, function(self, products, error)
|
||||||
|
if error then
|
||||||
|
log(error.error)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,p in pairs(products) do
|
||||||
|
available_items[p.ident] = p
|
||||||
|
log("Item %s", p.ident)
|
||||||
|
local button = item_buttons[p.ident]
|
||||||
|
if button then
|
||||||
|
gui.set_color(gui.get_node(button.."/larrylabel"), vmath.vector4(1,1,1,1))
|
||||||
|
else
|
||||||
|
log("Unable to find button for %s", tostring(p.ident))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local function buy_listener(self, transaction, error)
|
local function buy_listener(self, transaction, error)
|
||||||
pprint(transaction, error)
|
pprint(transaction, error)
|
||||||
if not error and iap.get_provider_id() == iap.PROVIDER_ID_GOOGLE and transaction.ident == "nonconsumable" then
|
if error then
|
||||||
local name = "reset/larrylabel"
|
log("iap.buy() error %s - %s", tostring(error.error), tostring(error.reason))
|
||||||
gui.set_color(gui.get_node(name), vmath.vector4(1,1,1,1))
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if iap.get_provider_id() == iap.PROVIDER_ID_GOOGLE and transaction.ident == NON_CONSUMABLE then
|
||||||
|
log("iap.buy() ok - google")
|
||||||
|
gui.set_color(gui.get_node("reset/larrylabel"), vmath.vector4(1,1,1,1))
|
||||||
product_items["reset"] = transaction
|
product_items["reset"] = transaction
|
||||||
elseif not error then
|
else
|
||||||
|
log("iap.buy() ok")
|
||||||
|
log("iap.finish()")
|
||||||
iap.finish(transaction)
|
iap.finish(transaction)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function init(self)
|
function init(self)
|
||||||
|
self.log = {}
|
||||||
|
log("init()")
|
||||||
msg.post(".", "acquire_input_focus")
|
msg.post(".", "acquire_input_focus")
|
||||||
iap.list(items, list_callback)
|
if not iap then
|
||||||
|
log("In-App Purchases not supported")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
list()
|
||||||
iap.set_listener(buy_listener)
|
iap.set_listener(buy_listener)
|
||||||
end
|
end
|
||||||
|
|
||||||
function on_input(self, action_id, action)
|
function on_input(self, action_id, action)
|
||||||
if product_items["consumable"] then
|
if action_id then
|
||||||
dirtylarry:button("consumable", action_id, action, function()
|
for item, button in pairs(item_buttons) do
|
||||||
iap.buy("consumable")
|
if available_items[item] then
|
||||||
|
dirtylarry:button(button, action_id, action, function()
|
||||||
|
buy(item)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
if product_items["nonconsumable"] then
|
|
||||||
dirtylarry:button("nonconsumable", action_id, action, function()
|
|
||||||
iap.buy("nonconsumable")
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
dirtylarry:button("list", action_id, action, function()
|
||||||
if product_items["reset"] then
|
list()
|
||||||
dirtylarry:button("reset", action_id, action, function()
|
|
||||||
iap.finish(product_items["reset"])
|
|
||||||
product_items["reset"] = nil
|
|
||||||
gui.set_color(gui.get_node("reset/larrylabel"), vmath.vector4(1,0,0,1))
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
Reference in New Issue
Block a user