GameSparks in cocos2d-x

GameSparks in cocos2d-x
0

#1

Hi,
has anyone using GameSparks? I’d say their documentation sucks. They’re not covering anything c++ related on the official page. I’ve only found a SDK on bitbucket with documentation, but this one is much shorter.

After struggling with the basic configuration / compilation, I’m stuck on the first thing I call. GameSparksAvailable or GameSparksAuthenticated events are never called. Because of this I cannot really continue.

I thought it’s a decent library. Previously I’ve tried AppWarp, which has a very easy to use API, but I’m encountering random crashes (in socket classes from AppWarp) on Android and it forced (with few other reasons) me to find something else.


#2

@dimon4eg someone is talking to you. Defend your idea of using GameSparks hahaha.
@piotrros in my case, i would like to try with AppWarp. It’s very easy to use the API and the cpp-tests worked for me (thanks to @dimon4eg).

But your “crash” problem worries me. Did you try to talk with the official support?
I sent an email to support [@] shephertz [.] com and they answered me.


#3

I’m thinking of coming back to AppWarp or to find something else.

Maybe they can help me with the crash, but there are other issues I had as well:

  • you can only send 512 long message to the other players. I had about 1500 bytes long string and this caused a lot of trouble (I wanted to send it only once, next messages were very small). In the end I had to change the data structure to shorten the string, but still I had about 700 bytes. Finally, I’ve found I could send data instead of chat message, which has limit of 1024 bytes, so not much more. But this is rather strange to me (I get the limits, but 512 bytes in 2019 is a joke) and it can be a real hassle in the future.
  • second thing, it just refuses to connect with error 4 (if I remember correctly). I have to restart the app in order to fix it.
  • third thing is the crash.

And by the way the ninja-thing example project is written very poorly and uses a lot of deprecated apis. All these things made me to believe I’d like to find something more professional. I’ve found GameSparks. First impression was good, but then well… it may be great for Unity, but c++ support is bad.


#4

I can’t give you my opinion because i only compiled the Ninja test. It worked for me and my idea was to use this API in the future. But your words worries me :frowning:
Plz share your final decision as soon as possible…

I also evaluated another APIs but i didn’t find a better api for use…


#5

Last time when I tried GameSparks C++ SDK worked fine for me.
What problem do you have?

P.S. I switched to open source solution: nakama
It’s works nice with cocos2d-js.
C++ version works with nakama 1.4.
C++ version for nakama 2.x will be in month (I’m doing this).


#6

I’ve also found PlayFab. Looks promising: https://api.playfab.com/docs/getting-started/cocos2d-x-getting-started-guide

They even have a damn documentation! :slight_smile: Though it’s strange they use windows in the example, but whatever, cocos2d-x itself is not a problem. I’m hesitating to give it a try. And that’s because pricing is pretty ridiculous.

$0.008 per MAU seems nice, especially compared to the other SDKs. But other SDKs often have a free limit and you only pay after that limit. What’s more there’s dirty catch: $299 monthly minimum. 299$ divided by 0.008$ gives 37375 users. But we estimate to have much less users, when the game starts (about 5k), so we’d have to pay much more and I’m not sure if we can still be indie, but that’s still 99$ :slight_smile: Ofc It won’t be bad as you have a lot of users and revenue from the app. But we make only single player games for now.

edit:
my bad, it seems you can use free account as well. But I have to check the limits :slight_smile:


#7

https://api.gamesparks.net/?cppsdk#introduction

I’m not getting any lifecycle callbacks, though logs are saying:

**easywsclient: connecting: host=preview-A374812cRdGw.ws.gamesparks.net port=443 path=/ws/device/A374812cRdGw**

**[GameSparks]: Initialized**

**Connected to: wss://preview-A374812cRdGw.ws.gamesparks.net/ws/device/A374812cRdGw**

code looks like this:

void AuthenticationRequest_Response(GameSparks::Core::GS&, const GameSparks::Api::Responses::AuthenticationResponse& response)
{
    CCLOG("AuthenticationRequest_Response");
}

void GameSparksAvailable(GS& gsInstance, bool available)
{
    if(available) {
        CCLOG("GameSparksAvailable: true");
    } else {
        CCLOG("GameSparksAvailable: false");
    }
}

in applicationDidFinishLaunching (AppDelegate.cpp):

Cocos2dxPlatform* gsPlatform = new Cocos2dxPlatform(GAME_SPARKS_API_KEY, GAME_SPARKS_SECRET, true, true);
gs.Initialise(gsPlatform);
gs.GameSparksAvailable = GameSparksAvailable;
gs.GameSparksAuthenticated = GameSparksAuthenticated;

#8

You have to call gs.Update(dt); periodically to allow GS handle responses in cocos2d thread and call callbacks.

I don’t know why this is missing in documentation but check their example.


#9

Thank you, that was it! Guess I’m sticking with GameSparks for now and I’ll see what it can do.

edit:

I wonder about it, maybe you can help me:

GameSparks::Api::Requests::DeviceAuthenticationRequest authRequest(gsInstance);
        authRequest.SetDeviceId(username);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
        authRequest.SetDeviceOS("iOS");
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
        authRequest.SetDeviceOS("Android");
#else
        authRequest.SetDeviceOS("Other");
#endif
        
        authRequest.Send(AuthenticationRequest_Response);

this works, however:

void AuthenticationRequest_Response(GameSparks::Core::GS&, const GameSparks::Api::Responses::AuthenticationResponse& response)
{
    CCLOG("AuthenticationRequest_Response");
}

I want to make this function a class function like this:

void GameScene::AuthenticationRequest_Response(GameSparks::Core::GS&, const GameSparks::Api::Responses::AuthenticationResponse& response)
{
    CCLOG("AuthenticationRequest_Response");
}

However, I don’t know how to bind it using std::bind like for (example) GameSparksAvailable:

gs.GameSparksAvailable = std::bind(&GameScene::GameSparksAvailable, this, std::placeholders::_1, std::placeholders::_2);

I’ve only succeded with lambda:

authRequest.Send([&](GameSparks::Core::GS&, const GameSparks::Api::Responses::AuthenticationResponse& response) {
            
});

#10

define GS_USE_STD_FUNCTION before include GS.h to use bind

class GS_API GS // this naming should be discussed, it was chosen because we need the static object with the name "GS"
{
    public:
        #if defined(GS_USE_STD_FUNCTION)
            typedef gsstl::function<void(GS&, bool)> t_AvailableCallback;
        #else
            typedef void(*t_AvailableCallback)(GS&, bool);
        #endif /* GS_USE_STD_FUNCTION */

        /// Callback which is triggered whenever the service becomes available or the connection to the service is lost. 
        t_AvailableCallback GameSparksAvailable;

#11

But I can use std::bind for GameSparksAvailable, the problem is with authRequest.Send method.


#12

ok then bind should also work for Send.
Show your code and error.


#13
void GameScene::AuthenticationRequest_Response(GameSparks::Core::GS&, const GameSparks::Api::Responses::AuthenticationResponse& response)
{
    CCLOG("AuthenticationRequest_Response");
}

Now I don’t even really now how to use std::bind in this situation as Send is the method, not a std::function property, which I could bind to.

authRequest.Send(&GameScene::AuthenticationRequest_Response);

this obviously cannot possibly work :slight_smile:


#14

try this:

authRequest.Send(std::bind(&GameScene::AuthenticationRequest_Response, this, std::placeholders::_1, std::placeholders::_2));

#15

Very nice, thank you! I didn’t know I can do this like that.


#16

:slight_smile:
Is it working now?


#17

It is. I was confused that there are no rooms in GameSparks. But I’ve found that I could use challenges to do the same. We’ll see how it goes.


#18

I’ve got some trouble using Challenges as room.

I can create room (challenge):

void GameScene::createRoom() {
    long timestamp = getCurrentDateAndTimeAsLong();
    string room = "room" + to_str(timestamp);
    
    CCLOG("creating room: %s", room.c_str());
    
    CreateChallengeRequest request(gs);
    request.SetAccessType("PUBLIC");
    request.SetAutoStartJoinedChallengeOnMaxPlayers(false);
    request.SetChallengeMessage(room);
    request.SetChallengeShortCode("room");
    request.SetEndTime(GSDateTime::Now().AddHours(2));
    request.SetMaxPlayers(4);
    request.SetMinPlayers(1);
    request.Send(std::bind(&GameScene::CreateChallengeRequest_Response, this, std::placeholders::_1, std::placeholders::_2));
}

And I think I’m automatically joined. But now the thing is, when I close the game and go back, I cannot join this room, because I’m probably automatically joined, but now the game doesn’t know to which one. And I should be kicked out of the room after closing the same. Also I shouldn’t be able to join multiple rooms at the same time, because it doesn’t make much sense.

I also can get list of rooms, which I do just after successful authentication:

void GameScene::AuthenticationRequest_Response(GameSparks::Core::GS&, const GameSparks::Api::Responses::AuthenticationResponse& response)
{
    CCLOG("AuthenticationRequest_Response");
    
    if (response.GetHasErrors()) {
        string error = response.GetErrors().GetValue().GetJSON();
        CCLOG("something went wrong during the authentication: %s", error.c_str());
        txtGameMaster->setString("Auth error: " + error);
    } else {
        string displayName = response.GetBaseData().GetString("displayName").GetValue();
        CCLOG("you successfully authenticated to GameSparks with your credentials");
        CCLOG("your displayname is %s", displayName.c_str());
        txtGameMaster->setString("Authenticated");
        
        ListChallengeRequest request(gs);
        request.SetEntryCount(50);
        request.SetOffset(0);
        request.SetShortCode("room");
        request.SetState("ISSUED");
        request.Send(std::bind(&GameScene::ListChallengeRequest_Response, this, std::placeholders::_1, std::placeholders::_2));
    }
}

I’m getting the list, but with the ones that current player created. Second player just gets an empty list (no errors, just empty list).


#19

I don’t know.
Better to ask GameSparks support.


#20

Ok, I will. So you didn’t try making rooms? It’s strange to me something that basic isn’t made out of the box.