Custom Properties ObjC client v3.0.4.0

edited January 2013 in Native

On Photon version custom player properties with string keys worked fine using KeyObjects. Now we've updated to version and migrated the keys to be NSString but our code is crashing. We've traced the issue back to the following code on the LoadBalancingClient library:

[code2=objc]+ (NSMutableDictionary*) stripToCustomProperties:(NSDictionary*)properties
EGArray* keys = properties&&properties.count?[EGArray arrayWithArray:properties.allKeys]:nil;
NSMutableDictionary* retVal = [NSMutableDictionary dictionary];
for(NSUInteger i=0; i<properties.count; i++)
id key = [keys objectAtIndex:i];
if([key isKindOfClass:[NSString class]])
id val = [properties objectForKey:key];
[retVal setObject:[[val respondsToSelector:@selector(;copyDeep)]?[val copyDeep]:[val copy] autorelease] forKey:key];
return retVal;

The first line produces the following error:
[code2=shell]INFO -[LoadBalancingClient onEvent:] line: 539 - EventData - code: 255
FATAL: EGArray.m -[EGArray initWithArray:copyItems:] line: 215 - An EGArray can't hold elements of different types at the same time.
Assertion failed: (0), function -[EGArray initWithArray:copyItems:], file /Applications/buildagent/work/2dddaab385799e22/Common-objc/src/EGArray.m, line 215.[/code2]

To test it you can replace the code for OpCreateRoom on the demo_loadBalancing_objc project with the following:

[code2=objc]- (void) opCreateRoom
// if last digits are always nearly the same, this is because of the timer calling this function being triggered every x ms with x being a factor of 10
NSString* tmp = [NSString stringWithFormat:@%d, GETTIMEMS()];
EGMutableDictionary *gameProperties = [[EGMutableDictionary alloc]initWithKeyType:EG_STR_NSSTRING :EG_STR_NSSTRING];
EGMutableDictionary *playerProperties = [[EGMutableDictionary alloc]initWithKeyType:EG_STR_NSSTRING :EG_STR_NSSTRING];
[playerProperties setObject:@OurCustomProperty forKey:@DDD];
EGMutableArray *lobbyProperties = [EGMutableArray arrayWithType:EG_STR_NSSTRING];
[lobbyProperties addObject:@WHYYY?];

[mLoadBalancingClient opCreateRoom:tmp
:YES // isVisible
:YES // isOpen
:4 // maxPlayers

//[mLoadBalancingClient opCreateRoom:tmp];
mStateAccessor.State = STATE_JOINING;
[mOutputListener writeLine:@creating room \%@\&quot;", tmp];

This is a major issue for us, since we were planning an early January launch, could you please provide us with an update for the ObjC client library?



  • Hi schmeuk.

    Most of our stuff is on Christmas vacation until the end of the year, so this could maybe take until next week, however we are on it and try to solve this issue asap.

    Could you please tell us, how EG_STR_NSSTRING is defined?
  • Hi schmeuk.
    Looks like library uses nByte as key type for player properties. For example for user name in function LoadBalancingClient::opCreateRoom, so you have to use the same key type for your properties, like this:

    [code2=objc]EGMutableDictionary *playerProperties = [[EGMutableDictionary alloc]initWithKeyType:[NSString stringWithUTF8String:@encode(;nByte)] :EG_STR_NSSTRING];
    nByte customKey = 0x10;

    [playerProperties setObject:@OurCustomProperty forKey:[NSValue value:&customKey withObjCType:@encode(;nByte)]];[/code2]
  • EG_STR_NSSTRING is defined as follows:

    [code2=objc]static NSString* const EG_STR_NSSTRING = @NSString;[/code2]

    For now we've recompiled the library changing the first line of stripToCustomProperties to:

    [code2=objc]NSArray* keys = properties&&properties.count?[NSArray arrayWithArray:properties.allKeys]:nil;[/code2]

    This is working fine.
  • That has indeed been the problem - we simply forgot to change that instance of EGArray to NSAray, when implementing the new 3.0.4 handling of keys.

    This bug has now been fixed with new version (no difference to except the change, that you have already made on your own): ... ... ... ...
  • Thanks for that, one more thing though: We've been experiencing problems with the roomList not being updated. This even happens with the Demo application for LoadBalancing that comes bundled with the SDK, using both the cpp and ObjC client with only 2 instances. Basically what we see is that not every room creation triggers a room list update event (is not delayed, it never happens), this also means that new players can't join the newly created room. Could you check this on your side to see if there is something wrong with the Cloud Server? I'm almost sure this was working much better before Dec 20th.

  • Hi schmeuk.
    I can't reproduce that issue. The roomlist updates work just fine for me. Can you give more information on how to reproduce it with the demo app from the sdk and on how often this happens, please?
  • We did some more digging and it looks like it was a connectivity issue. We are located in Uruguay, South America, and were connecting to the EU server, once we switched to the US server everything worked fine (we confirmed that we had long ping times and timeouts to EU but not to US). The problem is that our game (iOS) needs to have all players (worldwide) connected to the same server, which server provides the best worldwide connectivity?

  • Well, why do you need to have them all connected to the same server worldwide at all means?
    I can't come up with any reason therefor that results in accepting a connectivity at which it gets unplayable, just to have all players on the same server, as these aditional players on the server won't be able to reasonably play while the players with good connectivity also won't profit from more players, if those more players make the game even unplayable for everyone else by non-stop lagging and with their many disconnects.

    There really isn't a server location anywhere on the planet, which gives you good latencies to everywhere in the world.
    There is good reason, why major online games like World of Warcraft or World of Tanks split their userbases up to different servers at different locations in the world depending on the continent, from which the clients connect.

    If you really have to decide for one server region, than use the one, in which you are expecting the most users.
  • At least when we first lunch the game we want to minimise the waiting time for a match to start, and since we won't have too many players to begin with, we planned to connect all players to the same server. Then, another reason is to allow the top ranked players to compete against each other, this won't be possible if we use different servers for US and EU players.
    We currently have a similar game that uses Apple's Game Centre for Online Multiplayer and they seem to be able to connect players across the globe, but of course Apple's infrastructure is massive.
    Anyway, I think we end up having to split players across servers, so how would you recommend to divide the world, or do you suggest we try to reach each server before making a decision?
    Does the following sound reasonable to yo?

    Americas -> US server
    Europe -> EU server
    Asia? Oceania? We don't have too many players here, so I don't think it would be wise to connect them to JP or AS, which server would be better, US or EU?
    Africa? Which server would be better, US or EU?

    Thanks an dRegards
  • Apple game center does NOT provide any gameservers, but only matchmaking. With game center you can choose between peer to peer and hosted games. If you choose peer to peer,then there are no gameservers at all, but ifyou choose hosted, then you have to provide the gameservers yourself, for example use Photon for them.

    From iOS 6 / Mointain 10.8.2 on they provide the functionality, that you can specify multiple server regions and game center is then pinging your servers from all clients to determine which server region is being the best compromise between the different players and their ping to the different servers, so that you can use that server region to actually run the game.

    For matchmaking itself the latency by far isn't as important as it is for ingame realtime communcation, so Apple itself does not need to provide a world wide inrastructure for game center.

    However game Center still leaves you with bad latencies for at least some of the players, when it matches players from different continents into the same game.

    With Photon you have a few options on how to handle region choices as you can see here: ... ng_started.

    So you could for example let european users on default connect to the europe servers, but provide them with the possibility to set the server region to US.

    You can expect ping of below 50ms, if a european user connects to a european server or a us user to a US server and you can still expect around 100ms, ifa US user connects to a european server or vice versa, as the intercontinental connections between the US and europe are pretty good. However the ones between Asia and Europe and between Asia and US are both terrible. No matter if you let an Asian user connect to European or to US servers, you can at best expect a ping of 250-350 but it can often even be just 500-800ms. Indeed we even have just launched Japanese serverand are planning to additionally launched Korean servers, although we alread have had server ins Singapure, because even the inner Asian connections often have worse latencies than one is experiencing for connections between the US and Europe.
    I don't know anthiny about the pings between Africa and the rest of the world, but the African games market isn't very big anyway.
Sign In or Register to comment.