From 9cd57b731ab1c666d4a1cb725538fdc137763d12 Mon Sep 17 00:00:00 2001 From: Starla Insigna Date: Sat, 30 Jul 2011 11:19:14 -0400 Subject: Initial commit (version 0.2.1) --- libs/cocoslive/CLScoreServerPost.h | 142 ++++++++++++++ libs/cocoslive/CLScoreServerPost.m | 335 ++++++++++++++++++++++++++++++++++ libs/cocoslive/CLScoreServerRequest.h | 122 +++++++++++++ libs/cocoslive/CLScoreServerRequest.m | 257 ++++++++++++++++++++++++++ libs/cocoslive/cocoslive.h | 43 +++++ libs/cocoslive/cocoslive.m | 37 ++++ 6 files changed, 936 insertions(+) create mode 100755 libs/cocoslive/CLScoreServerPost.h create mode 100755 libs/cocoslive/CLScoreServerPost.m create mode 100755 libs/cocoslive/CLScoreServerRequest.h create mode 100755 libs/cocoslive/CLScoreServerRequest.m create mode 100755 libs/cocoslive/cocoslive.h create mode 100755 libs/cocoslive/cocoslive.m (limited to 'libs/cocoslive') diff --git a/libs/cocoslive/CLScoreServerPost.h b/libs/cocoslive/CLScoreServerPost.h new file mode 100755 index 0000000..e782b90 --- /dev/null +++ b/libs/cocoslive/CLScoreServerPost.h @@ -0,0 +1,142 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011 Zynga Inc. + * + * 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. + * + */ + + + +#import + +// for MD5 signing +#import + +// cocoslive definitions +#import "cocoslive.h" + +// Score Server protocol version +#define SCORE_SERVER_PROTOCOL_VERSION @"1.1" + +// Server URL +#ifdef USE_LOCAL_SERVER +#define SCORE_SERVER_SEND_URL @"http://localhost:8080/api/post-score" +#define SCORE_SERVER_UPDATE_URL @"http://localhost:8080/api/update-score" +#else +#define SCORE_SERVER_SEND_URL @"http://fourislandscores.appspot.com/api/post-score" +#define SCORE_SERVER_UPDATE_URL @"http://fourislandscores.appspot.com/api/update-score" +#endif + +/// Type of errors from the Post Score request +typedef enum { + /// post request successful + kPostStatusOK = 0, + /// post request failed to establish a connection. wi-fi isn't enabled. + /// Don't retry when this option is preset + kPostStatusConnectionFailed = 1, + /// post request failed to post the score. Server might be busy. + /// Retry is suggested + kPostStatusPostFailed = 2, +} tPostStatus; + +enum { + //! Invalid Ranking. Valid rankins are from 1 to ... + kServerPostInvalidRanking = 0, +}; + +/** + * Handles the Score Post to the cocos live server + */ +@interface CLScoreServerPost : NSObject { + /// game key. secret shared with the server. + /// used to sign the values to prevent spoofing. + NSString *gameKey; + + /// game name, used as a login name. + NSString *gameName; + + /// delegate instance of fetch score + id delegate; + + /// ranking + NSUInteger ranking_; + + /// score was updated + BOOL scoreDidUpdate_; + + /// data received + NSMutableData *receivedData; + + /// values to send in the POST + NSMutableArray *bodyValues; + + /// status of the request + tPostStatus postStatus_; + + /// mdt context + CC_MD5_CTX md5Ctx; + + /// the connection + NSURLConnection *connection_; +} + +/** status from the score post */ +@property (nonatomic,readonly) tPostStatus postStatus; + +/** connection to the server */ +@property (nonatomic, retain) NSURLConnection *connection; + +/** ranking of your score + @since v0.7.3 + */ +@property (nonatomic,readonly) NSUInteger ranking; + +/** whether or not the score was updated + @since v0.7.3 + */ +@property (nonatomic,readonly) BOOL scoreDidUpdate; + +/** creates a cocos server with a game name and a game key */ ++(id) serverWithGameName:(NSString*) name gameKey:(NSString*) key delegate:(id)delegate; + +/** initializes a cocos server with a game name and a game key */ +-(id) initWithGameName:(NSString*) name gameKey:(NSString*) key delegate:(id)delegate; + +/** send the scores to the server. A new entre will be created on the server */ +-(BOOL) sendScore: (NSDictionary*) dict; + +/** + * Sends a score dictionary to the server for updating an existing entry by playername and device id, or creating a new one. + * The passed dictionary must contain a cc_playername key, otherwise it will raise and exception. + * @since v0.7.1 + */ +-(BOOL) updateScore: (NSDictionary*) dict; + +@end + +/** CocosLivePost protocol */ +@protocol CLPostDelegate +/** callback method that will be called if the post is successful */ +-(void) scorePostOk:(id) sender; +/** callback method that will be called if the post fails */ +-(void) scorePostFail:(id) sender; +@end diff --git a/libs/cocoslive/CLScoreServerPost.m b/libs/cocoslive/CLScoreServerPost.m new file mode 100755 index 0000000..43ee7b2 --- /dev/null +++ b/libs/cocoslive/CLScoreServerPost.m @@ -0,0 +1,335 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011 Zynga Inc. + * + * 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. + * + */ + + +#import "CLScoreServerPost.h" +#import "ccMacros.h" + +// free function used to sort +NSInteger alphabeticSort(id string1, id string2, void *reverse); + +NSInteger alphabeticSort(id string1, id string2, void *reverse) +{ + if ((NSInteger *)reverse == NO) + return [string2 localizedCaseInsensitiveCompare:string1]; + return [string1 localizedCaseInsensitiveCompare:string2]; +} + + +@interface CLScoreServerPost (Private) +-(void) addValue:(NSString*)value key:(NSString*)key; +-(void) calculateHashAndAddValue:(id)value key:(NSString*)key; +-(NSString*) getHashForData; +-(NSData*) getBodyValues; +-(NSString*) encodeData:(NSString*)data; +-(NSMutableURLRequest *) scoreServerRequestWithURLString:(NSString *)url; +-(BOOL) submitScore:(NSDictionary*)dict forUpdate:(BOOL)isUpdate; +@end + + +@implementation CLScoreServerPost + +@synthesize postStatus = postStatus_; +@synthesize ranking = ranking_; +@synthesize scoreDidUpdate = scoreDidUpdate_; +@synthesize connection = connection_; + ++(id) serverWithGameName:(NSString*) name gameKey:(NSString*) key delegate:(id) delegate +{ + return [[[self alloc] initWithGameName:name gameKey:key delegate:delegate] autorelease]; +} + +-(id) initWithGameName:(NSString*) name gameKey:(NSString*) key delegate:(id)aDelegate +{ + self = [super init]; + if( self ) { + gameKey = [key retain]; + gameName = [name retain]; + bodyValues = [[NSMutableArray arrayWithCapacity:5] retain]; + delegate = [aDelegate retain]; + receivedData = [[NSMutableData data] retain]; + + ranking_ = kServerPostInvalidRanking; + } + + return self; +} + +-(void) dealloc +{ + CCLOGINFO(@"deallocing %@", self); + [delegate release]; + [gameKey release]; + [gameName release]; + [bodyValues release]; + [receivedData release]; + [connection_ release]; + [super dealloc]; +} + + +#pragma mark ScoreServer send scores +-(BOOL) sendScore: (NSDictionary*) dict +{ + return [self submitScore:dict forUpdate:NO]; +} + +-(BOOL) updateScore: (NSDictionary*) dict +{ + if (![dict objectForKey:@"cc_playername"]) { + // fail. cc_playername + cc_device_id are needed to update an score + [NSException raise:@"cocosLive:updateScore" format:@"cc_playername not found"]; + } + return [self submitScore:dict forUpdate:YES]; +} + +-(BOOL) submitScore: (NSDictionary*)dict forUpdate:(BOOL)isUpdate +{ + [receivedData setLength:0]; + [bodyValues removeAllObjects]; + + // reset status + postStatus_ = kPostStatusOK; + + // create the request + NSMutableURLRequest *post = [self scoreServerRequestWithURLString:(isUpdate ? SCORE_SERVER_UPDATE_URL : SCORE_SERVER_SEND_URL)]; + + CC_MD5_Init( &md5Ctx); + + // hash SHALL be calculated in certain order + NSArray *keys = [dict allKeys]; + int reverseSort = NO; + NSArray *sortedKeys = [keys sortedArrayUsingFunction:alphabeticSort context:&reverseSort]; + for( id key in sortedKeys ) + [self calculateHashAndAddValue:[dict objectForKey:key] key:key]; + + // device id is hashed to prevent spoofing this same score from different devices + // one way to prevent a replay attack is to send cc_id & cc_time and use it as primary keys + + [self addValue:[[UIDevice currentDevice] uniqueIdentifier] key:@"cc_device_id"]; + [self addValue:gameName key:@"cc_gamename"]; + [self addValue:[self getHashForData] key:@"cc_hash"]; + [self addValue:SCORE_SERVER_PROTOCOL_VERSION key:@"cc_prot_ver"]; + + [post setHTTPBody: [self getBodyValues] ]; + + // create the connection with the request + // and start loading the data + self.connection=[NSURLConnection connectionWithRequest:post delegate:self]; + + if ( ! connection_) + return NO; + + return YES; +} + +-(NSMutableURLRequest *) scoreServerRequestWithURLString:(NSString *)url { + NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString: url] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:10.0]; + + [request setHTTPMethod: @"POST"]; + [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + return request; +} + +-(void) calculateHashAndAddValue:(id) value key:(NSString*) key +{ + NSString *val; + // value shall be a string or nsnumber + if( [value respondsToSelector:@selector(stringValue)] ) + val = [value stringValue]; + else if( [value isKindOfClass:[NSString class]] ) + val = value; + else + [NSException raise:@"Invalid format for value" format:@"Invalid format for value. addValue"]; + + [self addValue:val key:key]; + + const char * data = [val UTF8String]; + CC_MD5_Update( &md5Ctx, data, strlen(data) ); +} + +-(void) addValue:(NSString*)value key:(NSString*) key +{ + + NSString *encodedValue = [self encodeData:value]; + NSString *encodedKey = [self encodeData:key]; + + [bodyValues addObject: [NSString stringWithFormat:@"%@=%@", encodedKey, encodedValue] ]; +} + +-(NSData*) getBodyValues { + NSMutableData *data = [[NSMutableData alloc] init]; + + BOOL first=YES; + for( NSString *s in bodyValues ) { + if( !first) + [data appendBytes:"&" length:1]; + + [data appendBytes:[s UTF8String] length:[s length]]; + first = NO; + } + + return [data autorelease]; +} + +-(NSString*) getHashForData +{ + NSString *ret; + unsigned char pTempKey[16]; + + // update the hash with the secret key + const char *data = [gameKey UTF8String]; + CC_MD5_Update(&md5Ctx, data, strlen(data)); + + // then get the hash + CC_MD5_Final( pTempKey, &md5Ctx); + +// NSData *nsdata = [NSData dataWithBytes:pTempKey length:16]; + ret = [NSString stringWithString:@""]; + for( int i=0;i<16;i++) { + ret = [NSString stringWithFormat:@"%@%02x", ret, pTempKey[i] ]; + } + + return ret; +} + +-(NSString*) encodeData:(NSString*) data +{ + NSString *newData; + + newData = [data stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + + // '&' and '=' should be encoded manually + newData = [newData stringByReplacingOccurrencesOfString:@"&" withString:@"%26"]; + newData = [newData stringByReplacingOccurrencesOfString:@"=" withString:@"%3D"]; + + return newData; +} + +#pragma mark NSURLConnection Delegate + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response +{ + // this method is called when the server has determined that it + // has enough information to create the NSURLResponse + + // it can be called multiple times, for example in the case of a + // redirect, so each time we reset the data. + // receivedData is declared as a method instance elsewhere + [receivedData setLength:0]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data +{ + // append the new data to the receivedData + // receivedData is declared as a method instance elsewhere + [receivedData appendData:data]; + +// NSString *dataString = [NSString stringWithCString:[data bytes] length: [data length]]; +// CCLOG( @"data: %@", dataString); +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + CCLOG(@"Connection failed"); + + // wifi problems ? + postStatus_ = kPostStatusConnectionFailed; + + // release the connection + self.connection = nil; + + if( [delegate respondsToSelector:@selector(scorePostFail:) ] ) + [delegate scorePostFail:self]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection +{ + // release the connection + self.connection = nil; + +// NSString *dataString = [NSString stringWithCString:[receivedData bytes] length: [receivedData length]]; + NSString *dataString = [NSString stringWithCString:[receivedData bytes] encoding: NSASCIIStringEncoding]; + + if( [dataString hasPrefix:@"OK:"] ) { + // parse ranking and other possible answers + NSArray *values = [dataString componentsSeparatedByString:@":"]; + NSArray *answer = [ [values objectAtIndex:1] componentsSeparatedByString:@","]; + NSEnumerator *nse = [answer objectEnumerator]; + + // Create a holder for each line we are going to work with + NSString *line; + + // Loop through all the lines in the lines array processing each one + while( (line = [nse nextObject]) ) { + NSArray *keyvalue = [line componentsSeparatedByString:@"="]; +// NSLog(@"%@",keyvalue); + if( [[keyvalue objectAtIndex:0] isEqual:@"ranking"] ) { + ranking_ = [[keyvalue objectAtIndex:1] intValue]; + } else if( [[keyvalue objectAtIndex:0] isEqual:@"score_updated"] ) { + scoreDidUpdate_ = [[keyvalue objectAtIndex:1] boolValue]; + } + + } + if( [delegate respondsToSelector:@selector(scorePostOk:) ] ) + [delegate scorePostOk:self]; + + } else if( [dataString hasPrefix: @"OK"] ) { + + // Ok + postStatus_ = kPostStatusOK; + + if( [delegate respondsToSelector:@selector(scorePostOk:) ] ) + [delegate scorePostOk:self]; + + + } else { + + NSLog(@"cocoslive: Post Score failed. Reason: %@", dataString); + + // Error parsing answer + postStatus_ = kPostStatusPostFailed; + + if( [delegate respondsToSelector:@selector(scorePostFail:) ] ) + [delegate scorePostFail:self]; + } +} + +-(NSURLRequest *)connection:(NSURLConnection *)connection + willSendRequest:(NSURLRequest *)request + redirectResponse:(NSURLResponse *)redirectResponse +{ + NSURLRequest *newRequest=request; + if (redirectResponse) { + newRequest=nil; + } + + return newRequest; +} + +@end diff --git a/libs/cocoslive/CLScoreServerRequest.h b/libs/cocoslive/CLScoreServerRequest.h new file mode 100755 index 0000000..2002d4c --- /dev/null +++ b/libs/cocoslive/CLScoreServerRequest.h @@ -0,0 +1,122 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011 Zynga Inc. + * + * 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. + * + */ + + + +#import + +// cocoslive definitions +#import "cocoslive.h" + +// Server URL +#if USE_LOCAL_SERVER +#define SCORE_SERVER_REQUEST_URL @"http://localhost:8080/api/get-scores" +#define SCORE_SERVER_GETRANK_URL @"http://localhost:8080/api/get-rank-for-score" +#else +#define SCORE_SERVER_REQUEST_URL @"http://fourislandscores.appspot.com/api/get-scores" +#define SCORE_SERVER_GETRANK_URL @"http://fourislandscores.appspot.com/api/get-rank-for-score" +#endif + +/** Type of predefined Query */ +typedef enum { + kQueryIgnore = 0, + kQueryDay = 1, + kQueryWeek = 2, + kQueryMonth = 3, + kQueryAllTime = 4, +} tQueryType; + +/** Flags that can be added to the query */ +typedef enum { + kQueryFlagIgnore = 0, + kQueryFlagByCountry = 1 << 0, + kQueryFlagByDevice = 1 << 1, +} tQueryFlags; + +/** + * Handles the Request Scores to the cocos live server + */ +@interface CLScoreServerRequest : NSObject { + + /// game name, used as a login name. + NSString *gameName; + + /// delegate instance of fetch score + id delegate; + + // data received + NSMutableData *receivedData; + + // To determine which delegate method will be called in connectionDidFinishLoading: of NSURLConnection Delegate + BOOL reqRankOnly; + + /// the connection + NSURLConnection *connection_; +} + +/** connection to the server */ +@property (nonatomic, retain) NSURLConnection *connection; + + +/** creates a ScoreServerRequest server with a game name*/ ++(id) serverWithGameName:(NSString*) name delegate:(id)delegate; + +/** initializes a ScoreServerRequest with a game name*/ +-(id) initWithGameName:(NSString*) name delegate:(id)delegate; + +/** request scores from server using a predefined query. This is an asyncronous request. + * limit: how many scores are being requested. Maximun is 100 + * flags: can be kQueryFlagByCountry (fetches only scores from country) + * category: an NSString. For example: 'easy', 'medium', 'type1'... When requesting scores, they can be filtered by this field. + */ +-(BOOL) requestScores: (tQueryType) type limit:(int)limit offset:(int)offset flags:(tQueryFlags)flags category:(NSString*)category; + +/** request scores from server using a predefined query. This is an asyncronous request. + * limit: how many scores are being requested. Maximun is 100 + * flags: can be kQueryFlagByCountry (fetches only scores from country) + */ +-(BOOL) requestScores: (tQueryType) type limit:(int)limit offset:(int)offset flags:(tQueryFlags)flags; + +/** parse the received JSON scores and convert it to objective-c objects */ +-(NSArray*) parseScores; + +/** request rank for a given score using a predefined query. This is an asyncronous request. + * score: int for a score + * category: an NSString. For example: 'easy', 'medium', 'type1'... When requesting ranks, they can be filtered by this field. + */ +-(BOOL) requestRankForScore:(int)score andCategory:(NSString*)category; + +/** It's actually not parsing anything, just returning int for a rank. Kept name PARSE for convinience with parseScores */ +-(int) parseRank; + +@end + +/** CocosLive Request protocol */ +@protocol CLRequestDelegate +-(void) scoreRequestOk:(id) sender; +-(void) scoreRequestRankOk:(id) sender; +-(void) scoreRequestFail:(id) sender; +@end diff --git a/libs/cocoslive/CLScoreServerRequest.m b/libs/cocoslive/CLScoreServerRequest.m new file mode 100755 index 0000000..e16b895 --- /dev/null +++ b/libs/cocoslive/CLScoreServerRequest.m @@ -0,0 +1,257 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011 Zynga Inc. + * + * 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. + * + */ + + +// 3rd party imports +#import "CJSONDeserializer.h" + +// local imports +#import "CLScoreServerPost.h" +#import "CLScoreServerRequest.h" +#import "ccMacros.h" + +@implementation CLScoreServerRequest + +@synthesize connection=connection_; + ++(id) serverWithGameName:(NSString*) name delegate:(id)delegate +{ + return [[[self alloc] initWithGameName:name delegate:delegate] autorelease]; +} + +-(id) initWithGameName:(NSString*) name delegate:(id)aDelegate +{ + self = [super init]; + if( self ) { + gameName = [[name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] retain]; + delegate = [aDelegate retain]; + receivedData = [[NSMutableData data] retain]; + } + return self; +} + +-(void) dealloc +{ + CCLOGINFO(@"deallocing %@", self); + + [delegate release]; + [gameName release]; + [receivedData release]; + [connection_ release]; + [super dealloc]; +} + +-(BOOL) requestScores:(tQueryType)type + limit:(int)limit + offset:(int)offset + flags:(tQueryFlags)flags + category:(NSString*)category +{ + // create the request + [receivedData setLength:0]; + + // it's not a call for rank + reqRankOnly = NO; + + NSString *device = @""; + if( flags & kQueryFlagByDevice ) + device = [[UIDevice currentDevice] uniqueIdentifier]; + + // arguments: + // query: type of query + // limit: how many scores are being requested. Default is 25. Maximun is 100 + // offset: offset of the scores + // flags: bring only country scores, world scores, etc. + // category: string user defined string used to filter + NSString *url= [NSString stringWithFormat:@"%@?gamename=%@&querytype=%d&offset=%d&limit=%d&flags=%d&category=%@&device=%@", + SCORE_SERVER_REQUEST_URL, + gameName, + type, + offset, + limit, + flags, + [category stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding], + device + ]; + + // NSLog(@"%@", url); + + NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:url] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:10.0]; + + // create the connection with the request + // and start loading the data + self.connection=[NSURLConnection connectionWithRequest:request delegate:self]; + if (! connection_) + return NO; + + return YES; +} + +-(BOOL) requestScores:(tQueryType)type + limit:(int)limit + offset:(int)offset + flags:(tQueryFlags)flags +{ + // create the request + [receivedData setLength:0]; + + // arguments: + // query: type of query + // limit: how many scores are being requested. Maximun is 100 + // offset: offset of the scores + // flags: bring only country scores, world scores, etc. + return [self requestScores:type limit:limit offset:offset flags:flags category:@""]; +} + +-(NSArray*) parseScores +{ + NSArray *array = nil; + NSError *error = nil; + NSDictionary *dictionary = [[CJSONDeserializer deserializer] deserializeAsDictionary:receivedData error:&error]; + +// NSLog(@"r: %@", dictionary); + if( ! error ) { + array = [dictionary objectForKey:@"scores"]; + } else { + CCLOG(@"Error parsing scores: %@", error); + } + return array; +} + +#pragma mark Request rank for score + +-(BOOL) requestRankForScore:(int)score andCategory:(NSString*)category { + // create the request + [receivedData setLength:0]; + + reqRankOnly = YES; + + // arguments: + // score: score for which you need rank + // category: user defined string used to filter + NSString *url= [NSString stringWithFormat:@"%@?gamename=%@&category=%@&score=%d", + SCORE_SERVER_GETRANK_URL, + gameName, + [category stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding], + score + ]; + + NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:url] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:10.0]; + + // create the connection with the request + // and start loading the data + self.connection=[NSURLConnection connectionWithRequest:request delegate:self]; + if (! connection_) + return NO; + + return YES; +} + +-(int) parseRank { +// NSString *rankStr = [NSString stringWithCString:[receivedData bytes] length: [receivedData length]]; + NSString *rankStr = [NSString stringWithCString:[receivedData bytes] encoding: NSASCIIStringEncoding]; + +// NSLog(@"XXXX: Ranking: %@", rankStr); + + // creating trimmed string by trimming everything that's not numbers from the receivedData + NSString *trimmedStr = [rankStr stringByTrimmingCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; + + int scoreInt = [trimmedStr intValue]; + + return scoreInt; +} + + +#pragma mark NSURLConnection Delegate + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response +{ + // this method is called when the server has determined that it + // has enough information to create the NSURLResponse + + // it can be called multiple times, for example in the case of a + // redirect, so each time we reset the data. + // receivedData is declared as a method instance elsewhere + + [receivedData setLength:0]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data +{ + // append the new data to the receivedData + // receivedData is declared as a method instance elsewhere + [receivedData appendData:data]; +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + // release the connection, and the data object + self.connection = nil; + + + CCLOG(@"Error getting scores: %@", error); + + if( [delegate respondsToSelector:@selector(scoreRequestFail:) ] ) + [delegate scoreRequestFail:self]; + +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection +{ + // release the connection, and the data object + self.connection = nil; + + + if(reqRankOnly) { + // because it's request for rank, different delegate method is called scoreRequestRankOk: + // if connection failed the same delegate method is used as for standard scores - scoreRequestFail: + if( [delegate respondsToSelector:@selector(scoreRequestRankOk:) ] ) { + [delegate scoreRequestRankOk:self]; + } + } else { + if( [delegate respondsToSelector:@selector(scoreRequestOk:) ] ) { + [delegate scoreRequestOk:self]; + } + + } +} + +-(NSURLRequest *)connection:(NSURLConnection *)connection + willSendRequest:(NSURLRequest *)request + redirectResponse:(NSURLResponse *)redirectResponse +{ + NSURLRequest *newRequest=request; + if (redirectResponse) { + newRequest=nil; + } + return newRequest; +} + +@end diff --git a/libs/cocoslive/cocoslive.h b/libs/cocoslive/cocoslive.h new file mode 100755 index 0000000..15dbe1a --- /dev/null +++ b/libs/cocoslive/cocoslive.h @@ -0,0 +1,43 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011 Zynga Inc. + * + * 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. + * + */ + + + +// 0x00 HI ME LO +// 00 00 03 02 +#define COCOSLIVE_VERSION 0x00000302 + +// to use localserver. DEBUG ONLY +//#define USE_LOCAL_SERVER 1 + +// all cocos live include files +// +#import "CLScoreServerPost.h" +#import "CLScoreServerRequest.h" + + +// free functions +NSString * cocosLiveVersion(void); diff --git a/libs/cocoslive/cocoslive.m b/libs/cocoslive/cocoslive.m new file mode 100755 index 0000000..613a9d7 --- /dev/null +++ b/libs/cocoslive/cocoslive.m @@ -0,0 +1,37 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011 Zynga Inc. + * + * 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. + * + */ + + +#import + +#import "cocoslive.h" + +static NSString *version = @"cocoslive v0.3.2"; + +NSString *cocosLiveVersion() +{ + return version; +} -- cgit 1.4.1