diff options
Diffstat (limited to 'platform/iphone/icloud.mm')
-rw-r--r-- | platform/iphone/icloud.mm | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/platform/iphone/icloud.mm b/platform/iphone/icloud.mm new file mode 100644 index 0000000000..518385992d --- /dev/null +++ b/platform/iphone/icloud.mm @@ -0,0 +1,385 @@ +/*************************************************************************/ +/* icloud.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifdef ICLOUD_ENABLED + +#include "icloud.h" + +#ifndef __IPHONE_9_0 +extern "C" { +#endif + +#import <Foundation/Foundation.h> +#import "app_delegate.h" + +#ifndef __IPHONE_9_0 +}; +#endif + +ICloud* ICloud::instance = NULL; + +void ICloud::_bind_methods() { + ObjectTypeDB::bind_method(_MD("remove_key"),&ICloud::remove_key); + ObjectTypeDB::bind_method(_MD("set_key_values"),&ICloud::set_key_values); + ObjectTypeDB::bind_method(_MD("get_key_value"),&ICloud::get_key_value); + ObjectTypeDB::bind_method(_MD("synchronize_key_values"),&ICloud::synchronize_key_values); + ObjectTypeDB::bind_method(_MD("get_all_key_values"),&ICloud::get_all_key_values); + + ObjectTypeDB::bind_method(_MD("get_pending_event_count"),&ICloud::get_pending_event_count); + ObjectTypeDB::bind_method(_MD("pop_pending_event"),&ICloud::pop_pending_event); +}; + +int ICloud::get_pending_event_count() { + + return pending_events.size(); +}; + +Variant ICloud::pop_pending_event() { + + Variant front = pending_events.front()->get(); + pending_events.pop_front(); + + return front; +}; + +ICloud* ICloud::get_singleton() { + return instance; +}; + +//convert from apple's abstract type to godot's abstract type.... +Variant nsobject_to_variant(NSObject* object) { + if ([object isKindOfClass:[NSString class]]) { + const char* str = [(NSString*)object UTF8String]; + return String::utf8(str != NULL ? str : ""); + } + else if ([object isKindOfClass:[NSData class]]) { + ByteArray ret; + NSData* data = (NSData*)object; + if ([data length] > 0) { + ret.resize([data length]); + { + ByteArray::Write w = ret.write(); + copymem(w.ptr(), [data bytes], [data length]); + } + } + return ret; + } + else if ([object isKindOfClass:[NSArray class]]) { + Array result; + NSArray* array = (NSArray*)object; + for (unsigned int i = 0; i < [array count]; ++i) { + NSObject* value = [array objectAtIndex:i]; + result.push_back(nsobject_to_variant(value)); + } + return result; + } + else if ([object isKindOfClass:[NSDictionary class]]) { + Dictionary result; + NSDictionary* dic = (NSDictionary*)object; + + + NSArray* keys = [dic allKeys]; + int count = [keys count]; + for (int i=0; i < count; ++i) { + NSObject* k = [ keys objectAtIndex:i]; + NSObject* v = [dic objectForKey:k]; + + result[nsobject_to_variant(k)] = nsobject_to_variant(v); + } + return result; + } + else if ([object isKindOfClass:[NSNumber class]]) { + //Every type except numbers can reliably identify its type. The following is comparing to the *internal* representation, which isn't guaranteed to match the type that was used to create it, and is not advised, particularly when dealing with potential platform differences (ie, 32/64 bit) + //To avoid errors, we'll cast as broadly as possible, and only return int or float. + //bool, char, int, uint, longlong -> int + //float, double -> float + NSNumber* num = (NSNumber*)object; + if(strcmp([num objCType], @encode(BOOL)) == 0) { + return Variant((int)[num boolValue]); + } + else if(strcmp([num objCType], @encode(char)) == 0) { + return Variant((int)[num charValue]); + } + else if(strcmp([num objCType], @encode(int)) == 0) { + return Variant([num intValue]); + } + else if(strcmp([num objCType], @encode(unsigned int)) == 0) { + return Variant((int)[num unsignedIntValue]); + } + else if(strcmp([num objCType], @encode(long long)) == 0) { + return Variant((int)[num longValue]); + } + else if(strcmp([num objCType], @encode(float)) == 0) { + return Variant([num floatValue]); + } + else if(strcmp([num objCType], @encode(double)) == 0) { + return Variant((float)[num doubleValue]); + } + } + else if ([object isKindOfClass:[NSDate class]]) { + //this is a type that icloud supports...but how did you submit it in the first place? + //I guess this is a type that *might* show up, if you were, say, trying to make your game + //compatible with existing cloud data written by another engine's version of your game + WARN_PRINT("NSDate unsupported, returning null Variant") + return Variant(); + } + else if ([object isKindOfClass:[NSNull class]] or object == nil) { + return Variant(); + } + else { + WARN_PRINT("Trying to convert unknown NSObject type to Variant"); + return Variant(); + } +} + +NSObject* variant_to_nsobject(Variant v) { + if (v.get_type() == Variant::STRING) { + return [[[NSString alloc] initWithUTF8String:((String)v).utf8().get_data()] autorelease]; + } + else if (v.get_type() == Variant::REAL) { + return [NSNumber numberWithDouble:(double)v]; + } + else if (v.get_type() == Variant::INT) { + return [NSNumber numberWithLongLong:(long)(int)v]; + } + else if (v.get_type() == Variant::BOOL) { + return [NSNumber numberWithBool:BOOL((bool)v)]; + } + else if (v.get_type() == Variant::DICTIONARY) { + NSMutableDictionary* result = [[[NSMutableDictionary alloc] init] autorelease]; + Dictionary dic = v; + Array keys = dic.keys(); + for (unsigned int i = 0; i < keys.size(); ++i) { + NSString* key = [[[NSString alloc] initWithUTF8String:((String)(keys[i])).utf8().get_data()] autorelease]; + NSObject* value = variant_to_nsobject(dic[keys[i]]); + + if (key == NULL || value == NULL) { + return NULL; + } + + [result setObject:value forKey:key]; + } + return result; + } + else if (v.get_type() == Variant::ARRAY) { + NSMutableArray* result = [[[NSMutableArray alloc] init] autorelease]; + Array arr = v; + for (unsigned int i = 0; i < arr.size(); ++i) { + NSObject* value = variant_to_nsobject(arr[i]); + if (value == NULL) { + //trying to add something unsupported to the array. cancel the whole array + return NULL; + } + [result addObject:value]; + } + return result; + } + else if (v.get_type() == Variant::RAW_ARRAY) { + ByteArray arr = v; + ByteArray::Read r = arr.read(); + NSData* result = [NSData dataWithBytes:r.ptr() length:arr.size()]; + return result; + } + WARN_PRINT(String("Could not add unsupported type to iCloud: '" + Variant::get_type_name(v.get_type())+"'").utf8().get_data()); + return NULL; +} + + +Error ICloud::remove_key(Variant p_param) { + String param = p_param; + NSString* key = [[[NSString alloc] initWithUTF8String:param.utf8().get_data()] autorelease]; + + NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; + + if (![[store dictionaryRepresentation] objectForKey:key]) { + return ERR_INVALID_PARAMETER; + } + + [store removeObjectForKey:key]; + return OK; +} + +//return an array of the keys that could not be set +Variant ICloud::set_key_values(Variant p_params) { + Dictionary params = p_params; + Array keys = params.keys(); + + Array error_keys; + + for (unsigned int i = 0; i < keys.size(); ++i) { + String variant_key = keys[i]; + Variant variant_value = params[variant_key]; + + NSString* key = [[[NSString alloc] initWithUTF8String:variant_key.utf8().get_data()] autorelease]; + if (key == NULL) { + error_keys.push_back(variant_key); + continue; + } + + NSObject* value = variant_to_nsobject(variant_value); + + if (value == NULL) { + error_keys.push_back(variant_key); + continue; + } + + NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; + [store setObject:value forKey:key]; + } + + return error_keys; +} + +Variant ICloud::get_key_value(Variant p_param) { + String param = p_param; + + NSString* key = [[[NSString alloc] initWithUTF8String:param.utf8().get_data()] autorelease]; + NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; + + if (![[store dictionaryRepresentation] objectForKey:key]) { + return Variant(); + } + + Variant result = nsobject_to_variant([[store dictionaryRepresentation] objectForKey:key]); + + return result; +} + +Variant ICloud::get_all_key_values() { + Dictionary result; + + NSUbiquitousKeyValueStore* store = [NSUbiquitousKeyValueStore defaultStore]; + NSDictionary* store_dictionary = [store dictionaryRepresentation]; + + NSArray* keys = [store_dictionary allKeys]; + int count = [keys count]; + for (int i=0; i < count; ++i) { + NSString* k = [ keys objectAtIndex:i]; + NSObject* v = [store_dictionary objectForKey:k]; + + const char* str = [k UTF8String]; + if (str != NULL) { + result[String::utf8(str)] = nsobject_to_variant(v); + } + } + + return result; +} + +Error ICloud::synchronize_key_values() { + NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; + BOOL result = [store synchronize]; + if (result == YES) { + return OK; + } + else { + return FAILED; + } +} +/* +Error ICloud::initial_sync() { + //you sometimes have to write something to the store to get it to download new data. go apple! + NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; + if ([store boolForKey:@"isb"]) + { + [store setBool:NO forKey:@"isb"]; + } + else + { + [store setBool:YES forKey:@"isb"]; + } + return synchronize(); +} +*/ +ICloud::ICloud() { + ERR_FAIL_COND(instance != NULL); + instance = this; + //connected = false; + + [ + //[NSNotificationCenter defaultCenter] addObserverForName: @"notify" + [NSNotificationCenter defaultCenter] addObserverForName: NSUbiquitousKeyValueStoreDidChangeExternallyNotification + object: [NSUbiquitousKeyValueStore defaultStore] + queue: nil + usingBlock: ^ (NSNotification * notification) { + NSDictionary* userInfo = [notification userInfo]; + NSInteger change = [[userInfo objectForKey:NSUbiquitousKeyValueStoreChangeReasonKey] integerValue]; + + Dictionary ret; + ret["type"] = "key_value_changed"; + + //StringArray result_keys; + //Array result_values; + Dictionary keyValues; + String reason = ""; + + if (change == NSUbiquitousKeyValueStoreServerChange) { + reason = "server"; + } + else if (change == NSUbiquitousKeyValueStoreInitialSyncChange) { + reason = "initial_sync"; + } + else if (change == NSUbiquitousKeyValueStoreQuotaViolationChange) { + reason = "quota_violation"; + } + else if (change == NSUbiquitousKeyValueStoreAccountChange) { + reason = "account"; + } + + ret["reason"] = reason; + + + NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; + + NSArray * keys = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangedKeysKey]; + for (NSString* key in keys) { + const char* str = [key UTF8String]; + if (str == NULL) { + continue; + } + + NSObject* object = [store objectForKey:key]; + + //figure out what kind of object it is + Variant value = nsobject_to_variant(object); + + keyValues[String::utf8(str)] = value; + } + + ret["changed_values"] = keyValues; + pending_events.push_back(ret); + } + ]; +} + + +ICloud::~ICloud() { + +}; + +#endif |