Xcode: How do I end a 2 player turn based multiplayer match with a winner and loser using GameCenter? - objective-c

I've had a bit of trouble finding any information on this and all the code samples I come across are based on the match ending in a tie for all players. In my 2 player turn based game I want to be able to end the match with a winner and loser. With the below code I've written the match always ends with the same result for both players, if its a win then both player 1 and 2 win, if its a loss both player 1 and 2 loose... any help? Thank you.
if (gameOver == true) {
if (GameWinner == 0) {
GKTurnBasedParticipant *player0 = [currentMatch.participants objectAtIndex:0];
player0.matchOutcome = GKTurnBasedMatchOutcomeWon;
GKTurnBasedParticipant *player1 = [currentMatch.participants objectAtIndex:1];
player1.matchOutcome = GKTurnBasedMatchOutcomeLost;
[currentMatch endMatchInTurnWithMatchData:data completionHandler:^(NSError *error) {
if (error) {
NSLog(#"%#", error);
}
}];
testlabel.text = #"Player 1 Wins!";
} else if (GameWinner == 1) {
GKTurnBasedParticipant *player0 = [currentMatch.participants objectAtIndex:0];
player0.matchOutcome = GKTurnBasedMatchOutcomeLost;
GKTurnBasedParticipant *player1 = [currentMatch.participants objectAtIndex:1];
player1.matchOutcome = GKTurnBasedMatchOutcomeWon;
[currentMatch endMatchInTurnWithMatchData:data completionHandler:^(NSError *error) {
if (error) {
NSLog(#"%#", error);
}
}];
testlabel.text = #"Player 2 Wins!";
} else if (GameWinner == 2) {
for (GKTurnBasedParticipant *part in currentMatch.participants) {
part.matchOutcome = GKTurnBasedMatchOutcomeTied;
}
[currentMatch endMatchInTurnWithMatchData:data completionHandler:^(NSError *error) {
if (error) {
NSLog(#"%#", error);
}
}];
testlabel.text = #"Tie Game!";
} else {
testlabel.text = #"Your turn is over.";
}

This sounds similar to this SO Question, try:
GKTurnBasedParticipant *curr = currentMatch.currentParticipant;
NSUInteger currentIndex = [currentMatch.participants indexOfObject:currentMatch.currentParticipant];
NSUInteger nextIndex = (currentIndex + 1) % [currentMatch.participants count];
GKTurnBasedParticipant *next = [currentMatch.participants objectAtIndex:nextIndex];
if (currScore < otherScore)
{
// Curr player lost
curr.matchOutcome = GKTurnBasedMatchOutcomeLost;
next.matchOutcome = GKTurnBasedMatchOutcomeWon;
}
else if (currScore == otherScore)
{
// Tied
curr.matchOutcome = GKTurnBasedMatchOutcomeTied;
next.matchOutcome = GKTurnBasedMatchOutcomeTied;
}
else
{
// Won
curr.matchOutcome = GKTurnBasedMatchOutcomeWon;
next.matchOutcome = GKTurnBasedMatchOutcomeLost;
}

Related

iOS 13 get application statusBar crash

only crash on beta2 and beta 3 when call code like this,:
[application valueForKeyPath:#"statusBar"]
some can help me? i call this method to get phone's network status.
the whole code like this:
if (![self isIPhoneX]) {
if ([[application valueForKeyPath:#"_statusBar"] isKindOfClass:NSClassFromString(#"UIStatusBar_Modern")]) {
children = [[[[application valueForKeyPath:#"_statusBar"] valueForKeyPath:#"_statusBar"] valueForKeyPath:#"foregroundView"] subviews];
} else {
children = [[[application valueForKeyPath:#"_statusBar"] valueForKeyPath:#"foregroundView"] subviews];
}
Class expectClass = NSClassFromString(#"UIStatusBarDataNetworkItemView");
for (id child in children) {
if ([child isKindOfClass:expectClass]) {
int netType = [[child valueForKeyPath:#"dataNetworkType"] intValue];
switch (netType) {
case 0: state = #"";break;
case 1: state = #"2g";break;
case 2: state = #"3g";break;
case 3: state = #"4g";break;
case 5: state = #"wifi";break;
default: state = #"";break;
} /* switch */
}
}
} else {
id statusBar = [application valueForKeyPath:#"statusBar"];
id statusBarView = [statusBar valueForKeyPath:#"statusBar"];
UIView *foregroundView = [statusBarView valueForKeyPath:#"foregroundView"];
children = [[foregroundView subviews][2] subviews];
for (id child in children) {
if ([child isKindOfClass:NSClassFromString(#"_UIStatusBarWifiSignalView")]) {
state = #"wifi";
}else if ([child isKindOfClass:NSClassFromString(#"_UIStatusBarStringView")]) {
NSString *str = [child valueForKeyPath:#"_originalText"];
if ([str isEqualToString:#"4G"]) {
state = #"4g";
}else if([str isEqualToString:#"3G"]){
state = #"3g";
} else{
state = #"2g";
}
}
}
}
I install iOS 13 open beta version and every thing runs good except some label showing ...,but i receive crash when online beta2 and beta3 version.
+ (NSString *)deviceNetworkingType
{
NSString *strNetworkInfo = #"No Network";
struct sockaddr_storage zeroAddress;
bzero(&zeroAddress,sizeof(zeroAddress)); zeroAddress.ss_len = sizeof(zeroAddress);
zeroAddress.ss_family = AF_INET;
// Recover reachability flags
SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL,(struct sockaddr *)&zeroAddress);
SCNetworkReachabilityFlags flags;
BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability,&flags);
CFRelease(defaultRouteReachability);
if(!didRetrieveFlags){ return strNetworkInfo;}
BOOL isReachable = ((flags & kSCNetworkFlagsReachable)!=0);
BOOL needsConnection = ((flags & kSCNetworkFlagsConnectionRequired)!=0);
if(!isReachable || needsConnection) {return strNetworkInfo;}
if((flags & kSCNetworkReachabilityFlagsConnectionRequired)== 0){
strNetworkInfo = #"WIFI";
}
if(((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0) {
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0){
strNetworkInfo = #"WIFI";
}
}
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) ==kSCNetworkReachabilityFlagsIsWWAN) {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
CTTelephonyNetworkInfo * info = [[CTTelephonyNetworkInfo alloc] init];
NSString *currentRadioAccessTechnology = info.currentRadioAccessTechnology;
if (currentRadioAccessTechnology) {
if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {
strNetworkInfo =#"4G";
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS]) {
strNetworkInfo =#"2G";
} else {
strNetworkInfo =#"3G";
}
}
} else {
if((flags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable) {
if ((flags & kSCNetworkReachabilityFlagsTransientConnection) == kSCNetworkReachabilityFlagsTransientConnection) {
if((flags & kSCNetworkReachabilityFlagsConnectionRequired) == kSCNetworkReachabilityFlagsConnectionRequired) {
strNetworkInfo =#"2G";
} else {
strNetworkInfo =#"3G";
}
}
}
}
}
return strNetworkInfo;
}

FFmpeg jump to most recent frame

I am looking for some help with dropping/skipping FFmpeg frames. The project I am working on streams live video which when the app goes into the background, upon returning to an active state the video stream spends a long time catching up by fast forwarding itself to the current frame. This isn't ideal and what I am aiming to achieve is have the app immediately jump to the most recent frame.
What I need to do is drop the amount of frames that are being fast-forwarded in order to catch up to the most recent frame. Is this possible? Here is my current code which decodes the frames:
- (NSArray *) decodeFrames: (CGFloat) minDuration
{
NSMutableArray *result = [NSMutableArray array];
#synchronized (lock) {
if([_reading integerValue] != 1){
_reading = [NSNumber numberWithInt:1];
#synchronized (_seekPosition) {
if([_seekPosition integerValue] != -1 && _seekPosition){
[self seekDecoder:[_seekPosition longLongValue]];
_seekPosition = [NSNumber numberWithInt:-1];
}
}
if (_videoStream == -1 &&
_audioStream == -1)
return nil;
AVPacket packet;
CGFloat decodedDuration = 0;
CGFloat totalDuration = [TimeHelper calculateTimeDifference];
do {
BOOL finished = NO;
int count = 0;
while (!finished) {
if (av_read_frame(_formatCtx, &packet) < 0) {
_isEOF = YES;
[self endOfFileReached];
break;
}
[self frameRead];
if (packet.stream_index ==_videoStream) {
int pktSize = packet.size;
while (pktSize > 0) {
int gotframe = 0;
int len = avcodec_decode_video2(_videoCodecCtx,
_videoFrame,
&gotframe,
&packet);
if (len < 0) {
LoggerVideo(0, #"decode video error, skip packet");
break;
}
if (gotframe) {
if (!_disableDeinterlacing &&
_videoFrame->interlaced_frame) {
avpicture_deinterlace((AVPicture*)_videoFrame,
(AVPicture*)_videoFrame,
_videoCodecCtx->pix_fmt,
_videoCodecCtx->width,
_videoCodecCtx->height);
}
KxVideoFrame *frame = [self handleVideoFrame];
if (frame) {
[result addObject:frame];
_position = frame.position;
decodedDuration += frame.duration;
if (decodedDuration > minDuration)
finished = YES;
}
} else {
count++;
}
if (0 == len)
break;
pktSize -= len;
}
}
av_free_packet(&packet);
}
} while (totalDuration > 0);
_reading = [NSNumber numberWithInt:0];
return result;
}
}
return result;

(Objective-c/Mac OSX) How to distinguish managed AD users (AD user create mobile card) from local users on Mac OSX

<\RESOLVED>, Please see the first reply
My mac(10.9) has joined into a AD domain. In my program, I tried to recognize whether the current login user is local account or AD user. I can successfully distinguish them by using the following code.
+ (bool)isLocalUser:(NSString*)user
{
NSError *dirSearchError = nil;
ODRecord *foundUser = findUser(user, &dirSearchError);
if(foundUser !=nil)
{
return YES;
}else
{
return NO;
}
}
ODRecord *findUser(NSString *user, NSError **error)
{
NSLog(#"[MacLogonUI] findUser");
ODNode *searchNode = [ODNode nodeWithSession: [ODSession defaultSession]
type: kODNodeTypeLocalNodes
error: error];
if (searchNode == nil) {
return nil;
}
NSDictionary *nodeInfo = [searchNode nodeDetailsForKeys:nil error:error];
/* query this node for the user record we're interested in.
* We only need one result, which is why maximumResults is set to 1.
*/
ODQuery *userSearch = [ODQuery queryWithNode: searchNode
forRecordTypes: kODRecordTypeUsers
attribute: kODAttributeTypeRecordName
matchType: kODMatchEqualTo
queryValues: user
returnAttributes: kODAttributeTypeStandardOnly
maximumResults: 1
error: error];
if (userSearch == nil) {
return nil;
}
/* For this example we'll use a synchronous search. This could take a while
* so asynchronous searching is preferable.
*/
NSArray *foundRecords = [userSearch resultsAllowingPartial: NO error: error];
if (foundRecords == nil || [foundRecords count] == 0) {
return nil;
}
ODRecord *userRecord = [foundRecords objectAtIndex: 0];
return [[userRecord retain] autorelease];
}
While when the AD user create a mobile card, it is viewed as a managed user(from the System preference -> Users & Groups). The code also recognize this kind of AD user as local. How to deal with this kind of situation?
Do you guys have any idea of this problem?
I have solved this problem by myself. Hope the following code helps:
#import "DasUser.h"
#import <OpenDirectory/OpenDirectory.h>
#import <Collaboration/Collaboration.h>
#implementation DasUser
+ (bool)isLocalUser:(NSString*)user
{
NSError *dirSearchError = nil;
ODRecord *foundUser = findUser(user, &dirSearchError);
if(foundUser !=nil)
{
return YES;
}else
{
return NO;
}
}
ODRecord *findUser(NSString *user, NSError **error)
{
NSLog(#"[MacLogonUI] findUser");
CSIdentityAuthorityRef defaultAuthority = CSGetManagedIdentityAuthority();
CSIdentityClass identityClass = kCSIdentityClassUser;
CSIdentityQueryRef query = CSIdentityQueryCreate(NULL, identityClass, defaultAuthority);
CFErrorRef err = NULL;
CSIdentityQueryExecute(query, 0, &err);
CFArrayRef results = CSIdentityQueryCopyResults(query);
int numResults = CFArrayGetCount(results);
NSMutableArray * managedUsers = [NSMutableArray array];
for (int i = 0; i < numResults; ++i) {
CSIdentityRef identity = (CSIdentityRef)CFArrayGetValueAtIndex(results, i);
CBIdentity * identityObject = [CBIdentity identityWithCSIdentity:identity];
NSString* posixName = [identityObject posixName];
[managedUsers addObject:posixName];
}
CFRelease(results);
CFRelease(query);
ODNode *searchNode = [ODNode nodeWithSession: [ODSession defaultSession]
type: kODNodeTypeLocalNodes
error: error];
if (searchNode == nil) {
return nil;
}
/* query this node for the user record we're interested in.
* We only need one result, which is why maximumResults is set to 1.
*/
ODQuery *userSearch = [ODQuery queryWithNode: searchNode
forRecordTypes: kODRecordTypeUsers
attribute: kODAttributeTypeRecordName
matchType: kODMatchEqualTo
queryValues: user
returnAttributes: kODAttributeTypeStandardOnly
maximumResults: 1
error: error];
if (userSearch == nil) {
return nil;
}
/* For this example we'll use a synchronous search. This could take a while
* so asynchronous searching is preferable.
*/
NSArray *foundRecords = [userSearch resultsAllowingPartial: NO error: error];
if([foundRecords count]>0)
{
NSString *nameStr = [foundRecords[0] recordName];
NSLog(#"[MacLogonUI] findUser nameStr %#", nameStr);
int j;
for( j = 0; j<[managedUsers count]; j++)
{
if([nameStr isEqualToString:managedUsers[j]])
{
break;
}
}
if(j<[managedUsers count])
{
foundRecords = nil;
}
}
if (foundRecords == nil || [foundRecords count] == 0) {
return nil;
}
ODRecord *userRecord = [foundRecords objectAtIndex: 0];
return [[userRecord retain] autorelease];
}
#end
While when network of the mac is disconnected. The managed user can not be listed. Is there anybody has any idea of this?

STTwitter - How can i take just 5 record on Stream API

I used STTwitter in my project and I want 5 tweet on some coordinates. There is question like this but i dont understand.
How can I stop a stream when using STTWitter
I tried like this, but its not stop at 5 records and always return tweet.
-(void)getTwitterActivityWithLocation:(CLLocation *)location withSuccessBlock:(void(^)(NSMutableArray *activities))successBlock
{
STTwitterAPI *twitter = [STTwitterAPI twitterAPIOSWithFirstAccount];
[twitter verifyCredentialsWithSuccessBlock:^(NSString *username) {
NSString *latRectLeft = [[NSString alloc] initWithFormat:#"%f",location.coordinate.latitude];
NSMutableArray *data = [[NSMutableArray alloc] init];
id twitterRequest = [twitter postStatusesFilterUserIDs:nil keywordsToTrack:nil locationBoundingBoxes:#[#"28.9986108",#"41.0377369",#"28.9996108",#"41.0387369"] delimited:#20 stallWarnings:nil progressBlock:^(NSDictionary *tweet) {
if ([data count] > 4) {
[twitterRequest cancel];
successBlock(data);
}
else if (([[tweet valueForKey:#"geo"] valueForKey:#"coordinates"] != nil)) {
if (![tweet isEqual:nil] && [tweet count] > 0)
{
NSLog(#"%#",[tweet valueForKey:#"text"]);
[data addObject:tweet];
}
}
} stallWarningBlock:nil
errorBlock:^(NSError *error) {
NSLog(#"Error");
}];
} errorBlock:^(NSError *error) {
NSLog(#"%#",[error description]);
}];
}
If take [twitterRequest cancel]; line to outside of block, its work. But this time i don't have any tweet record.
How can i solve this ?
Use __block id twitterRequest instead of id twitterRequest.
Example:
STTwitterAPI *twitter = [STTwitterAPI twitterAPIOSWithFirstAccount];
[twitter verifyCredentialsWithSuccessBlock:^(NSString *username) {
NSMutableArray *data = [NSMutableArray array];
__block id twitterRequest = [twitter postStatusesFilterUserIDs:nil
keywordsToTrack:nil
locationBoundingBoxes:#[#"28.9986108",#"41.0377369",#"28.9996108",#"41.0387369"]
delimited:#20
stallWarnings:nil
progressBlock:^(NSDictionary *tweet) {
NSLog(#"-- data count: %lu", (unsigned long)[data count]);
if ([data count] > 4) {
NSLog(#"-- cancel");
[twitterRequest cancel];
} else if (([[tweet valueForKey:#"geo"] valueForKey:#"coordinates"] != nil)) {
if ([tweet count] > 0) {
NSLog(#"%#",[tweet valueForKey:#"text"]);
[data addObject:tweet];
}
}
} stallWarningBlock:nil
errorBlock:^(NSError *error) {
NSLog(#"-- error 2: %#", error);
}];
} errorBlock:^(NSError *error) {
NSLog(#"-- error 1: %#", error);
}];
Logs:
-- data count: 0
Rabbim sana cok sukur (...)
-- data count: 1
+Sevgilin varmı evladım (...)
-- data count: 2
#RussoftMe gt or unf *-*
-- data count: 3
Essege altin semer vursan essek yine essektir...
-- data count: 4
:-) (# Pizza Hut) http://t.co/SZim78OnsU
-- data count: 5
-- cancel

iOS: Best Way to do This w/o Calling Method 32 Times?

I'm currently retrieving the Top 100 Scores for one of my leaderboards the following way:
- (void) retrieveTop100Scores {
__block int totalScore = 0;
GKLeaderboard *myLB = [[GKLeaderboard alloc] init];
myLB.identifier = [Team currentTeam];
myLB.timeScope = GKLeaderboardTimeScopeAllTime;
myLB.playerScope = GKLeaderboardPlayerScopeGlobal;
myLB.range = NSMakeRange(1, 100);
[myLB loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
if (scores != nil) {
for (GKScore *score in scores) {
NSLog(#"%lld", score.value);
totalScore += score.value;
}
NSLog(#"Total Score: %d", totalScore);
[self loadingDidEnd];
}
}];
}
The problem is I want to do this for 32 leaderboards. I have an array with all 32 leaderboard identifiers:
NSArray *leaderboardIDs;
So my question is, how can I combine those 2 segments of code to pull in the 100 values for each leaderboard, resulting in a dictionary with all of the leaderboard names as keys, and the Total (of each 100 scores) of the leaderboards for values.
UPDATED:
So I have updated my answer using CrimsonChris' help. The only question I have is, how can I know when it is done totaling the score for all 32 teams? The reason I ask, is because I would then like to organize them from highest to lowest, and display them in that order in a tableView.
This is what I've updated my answer to:
In my viewDidLoad:
- (void)loadLeaderboardData {
// Array of leaderboard ID's to get high scores for
NSArray *leaderboardIDs = #[#"algeria", #"argentina", #"australia", #"belgium", #"bosniaandherzegovina", #"brazil", #"cameroon", #"chile", #"colombia", #"costarica", #"croatia", #"ecuador", #"england", #"france", #"germany", #"ghana", #"greece", #"honduras", #"iran", #"italy", #"ivorycoast", #"japan", #"mexico", #"netherlands", #"nigeria", #"portugal", #"russia", #"southkorea", #"spain", #"switzerland", #"unitedstates", #"uruguay"];
scoresByLeaderboardID = [NSMutableDictionary dictionary];
__block int requestCount = (int)leaderboardIDs.count;
for (NSString *leaderboardID in leaderboardIDs) {
[self loadScoresForLeaderboardID:leaderboardID range:NSMakeRange(1, 100) callback:^(NSArray *scores) {
scoresByLeaderboardID[leaderboardID] = scores;
if (--requestCount <= 0) {
if (callback)callback(scoresByLeaderboardID);
}
}];
}
}
- (void)loadScoresForLeaderboardID:(NSString*)leaderboardID range:(NSRange)range callback:(CallbackBlock)callback {
__block int totalScore = 0;
GKLeaderboard *myLB = [[GKLeaderboard alloc] init];
myLB.identifier = leaderboardID;
myLB.timeScope = GKLeaderboardTimeScopeAllTime;
myLB.playerScope = GKLeaderboardPlayerScopeGlobal;
myLB.range = range;
[myLB loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if (error != nil) {
//NSLog(#"%#", [error localizedDescription]);
}
if (scores != nil) {
for (GKScore *score in scores) {
//NSLog(#"Individual Scores: %lld (For %#)", score.value, leaderboardID);
}
}
}];
}
Your method can be cleaned up by using callback blocks.
typedef void(^CallbackBlock)(id object);
//callback accepts an NSArray* of GKScore*
- (void)loadScoresForLeaderboardID:(NSString *)leaderboardID range:(NSRange)range callback:(CallbackBlock)callback {
GKLeaderboard *myLB = [[GKLeaderboard alloc] init];
myLB.identifier = leaderboardID;
myLB.timeScope = GKLeaderboardTimeScopeAllTime;
myLB.playerScope = GKLeaderboardPlayerScopeGlobal;
myLB.range = range;
[myLB loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if (error != nil) NSLog(#"%#", [error localizedDescription]);
if (callback) callback(scores);
}];
}
You can then loop over your leaderboards.
//callback accepts an NSDictionary* of NSArray*(of GKScore*) by NSNumber*
- (void)loadScoresForLeaderboardIDs:(NSArray *)leaderboardIDs withCallback:(CallbackBlock)callback {
NSMutableDictionary *scoresByLeaderboardID = [NSMutableDictionary dictionary];
__block int requestCount = leaderboardIDs.count;
for (NSString *leaderboardID in leaderboardIDs) {
[LeaderboardLoader loadScoresForLeaderboardID:leaderboardID range:NSMakeRange(1, 100) callback:^(NSArray *scores) {
scoresByLeaderboardID[leaderboardID] = scores;
if (--requestCount <= 0) { //not thread safe
if (callback) callback(scoresByLeaderboardID);
}
}];
}
}
Once this method fires its callback you should have all your scores.
[LeaderboardLoader loadScoresForLeaderboardIDs:#[#"FirstID", #"SecondID", #"ThirdID"] withCallback:^(NSDictionary *scoresByLeaderboardID) {
NSLog(#"%#", scoresByLeaderboardID);
//do whatever you need to with all your scores here.
}];