I have successfully wrote a routine that creates a new game session (or joins an existent one) and that reserves player sessions in it for my two clients. I successfully get an IP address and port and my status on the dashboard says “Reserved”. After that, I don’t really know what to do since I’m not rolling my own client, I’m using a JS realtime server script. Should I send a specific message? Or should I accept a session? As far as I understand, I need to somehow send the realtime server a RTMessage with an op code. I don’t really know what format the server expects though. As in, what should a proper C++ message struct look like? I’m currently sending a “Hello, World” message but nothing really happens… Also, all of the C++ samples roll their own servers.
Hi @CoolCoolCool, Thanks for reaching out. We may need more details to fully understand your question.
Are you trying to join your clients to the game session created by GameLift?
You mentioned that you’re not rolling your own client and all the C++ samples roll their own servers. That’s not quite clear to us. Is your server running on a GameLift fleet and you client running locally?
Once you have the game session, the flow is typically:
- Someone (client/server) Creates a player Sessions - player session is in Reserved state
- Client/player connects to the server using the ip address and port for the allocated player session.
- Server validates player and accepts the player session id passed in (or if you keep an internal map) - player session moves to ACTIVE
Are you using the GameLift Realtime client? You mention C++ which is confusing me a little here as Realtime provides a C# client for now; you can obviously roll your own client to wrap this but you also say “I’m not rolling my own client” so what client are you using?
For Realtime clients you typically connect via creating a Client() with the playerSessionId and then call Connect (with port, ip address) to join the game session as that player. Your server code can require the optional connectionToken (which can be whatever you want it to be), it can extend the player accept call to do extra checkin etc, but the Server code should automatically accept the player session for you if your script extensions return True (or by default if you don’t have extensions).
Can you talk a little about your setup and what you are trying todo?
You can get the source for the Realtime client here: https://aws.amazon.com/gamelift/getting-started/ theres nothing too complex about it. But the only official SDK is in C# for now (technically its all dotnetcore to make it very portable)
Woops, that is a typing mistake. I’m not rolling my own GameServer, I am using a Realtime Script and trying to connect to said Realtime Server session with C++ sockets. However, I have no clue how to get started on that. Sadly, the Realtime Client is only offered in C#, and I’m currently working on understanding what it does so I can replicate it in c++.
I’m having similar issues as CoolCoolCool.
I’m currently working in C++ with Cocos2d-x rolling my own client, and attempting to use the GameLift RealTime JS server. I’ve currently gotten it set up where it’s creating a player session and game session and then returning the details to my client through AWS Lambda.
Then I’m using that IP (or DNS if available) and Port to connect to the server via a C++ WebSocket. I’m then attempting to send the player session to the server to set the Player Session from Reserved to Accepted, however the server code is never actually calling onPlayerConnect and the server code isn’t receiving the player session I send it (or rather it’s ignoring it).
Here is the log from the game session:
13 Aug 2020 20:20:50,98 [INFO] (OurServer.js) 164: Tick… 0 activePlayers: 0
13 Aug 2020 20:20:50,98 [INFO] (gamelift.js) 39: GameLiftServerAPI completed StartGameSession
13 Aug 2020 20:20:51,98 [INFO] (OurServer.js) 164: Tick… 1 activePlayers: 0
13 Aug 2020 20:21:09,119 [INFO] (OurServer.js) 164: Tick… 19 activePlayers: 0
13 Aug 2020 20:21:09,300 [INFO] (index.js) 469: Player 1 connected from (device IP)
13 Aug 2020 20:21:09,300 [INFO] (ws.js) 139: Player 1 connecting from ::ffff:(device IP):(device port)
13 Aug 2020 20:21:10,120 [INFO] (OurServer.js) 164: Tick… 20 activePlayers: 0
13 Aug 2020 20:21:11,120 [INFO] (OurServer.js) 164: Tick… 21 activePlayers: 0
13 Aug 2020 20:21:11,562 [INFO] (index.js) 202: Message received from player 1
13 Aug 2020 20:21:12,120 [INFO] (OurServer.js) 164: Tick… 22 activePlayers: 0
The server script is almost verbatim the example server script found here. The main differences being that I added several more log statements to get a better understanding of the GameLift server logic flow.
I’m really getting distraught over these issues, as I’ve been working at them for a while now and have been unable to get passed this issue. I’m fairly sure it’s some format issue with the packet, or a some protocol issue with the WebSocket (though the WS appears to be connected just fine).
Any help on these issues would be greatly appreciated! I can provide more information or code snippets as well if need be.
Edit: Oddly enough onPlayerDisconnect is properly getting called when the WebSocket connection is closed on the client (which actually led to a bug with that server example where the player count would go negative, which caused the server instance to never terminate).
Firstly, sorry you are still having problems here and also for the late reply (have been away from the forums for a while)
Unfortunately, GameLift Realtime only has that one official C# client, so what you are trying todo is unsupported at this time.
However, as mentioned earlier its just pure dotnet code so its a) pretty portable b) pretty readable.
Before diving in, I have to say its been a while since I worked with the Realtime service so apologies if my memory is hazy about the specific details.
Nevertheless when a client connects its expected to perform a little login/handshake function.
So you have the right starting point with your C++ Websocket based client. Next I would download the C# Realtime client from: https://aws.amazon.com/gamelift/getting-started/ and walk the code from the Client.cs file.
In Client.cs look at the
OnConnectionOpen call to see that you will need to send a login command on connection. This is what the server is expecting and most likely the reason your players fail to connect and timeout.
You don’t need all the fancy bells and whistles in this code, but hopefully you can see what you need to do; all the commands are very simple payloads that are easy to mimic.
Obviously if you roll your own client like this, it comes with the same risks as other unsupported software. The best approach would be to provide a C++/.dotnet core bridge and use the DLL as is, but that maybe too cumbersome / hard to do on your platform of choice.
This could make a great open source project for others to contribute to
Hey thanks for your response! I’ve actually already been reading through Client.cs, ClientSession.cs, and the other Real-Time client classes attempting to replicate their functionality.
I’ll also add that I got in contact with, Al Murray, one of the Solutions Architects at Amazon on these questions and he gave me the following response:
"The customer is trying to use GameLift realtime servers, but since they are using Cocos2d-x they can’t use our client SDK, which is written in C#. They have to replicate its functionality in C++. This is not a trivial task, and not a supported pathway.
I would advise this customer to use a GameLift custom server, instead, and use a good networking library to implement communications between the client and server themselves that way. It might be a bit more long-winded, but it’s not going to be as tricky to create or debug, in my opinion.
If the customer does not want to do this, the C# source code for the client SDK is actually distributed with the GameLift SDK, so they will become fully acquainted with that code if they go that path, and the task is to make the C++ that they write work exactly the same as the client SDK that we provide.
In terms of where the customer is now, they need to know that there are two connections to the server. One is the reliable connection, used for sending connect and disconnect messages, and so forth using websockets, for when delivery has to be guaranteed. The C# code seems to go through the process of opening a client connection with the server side using code in Client.cs:
This creates a reliable connection factory with options from the ConnectionFactoryOptions() object, registers some handlers, and opens the connection, and so forth. This has been ‘done’ by the customer. The next stage is send messages using the reliable connection. These are formatted as protocol buffer packets. Get started by integrating the C++ version of protobuf into the client. The packets are formed using the rules in Packet.cs. For example, here are a list of the different types of packet (in Packet.cs):
I’m pretty sure, that the first message needs to be Login. The format of the message is defined in CoreCommands.cs:
So it has two parameters, PlayerSessionId and ClientVersion, which are added to the command. The customer should create .proto files that define an identical API.
This is just a start. The client should now wait for a response to the login message, and then the login response is handled in Client.cs:
The client attempts to create the UDP connection. I don’t think the messages in the UDP connection are defined, as this is supposed to be being used by the game to exchange input data (inward messages) and state data (outward messages) with the server.
I’m sorry I can’t be more helpful. There’s nothing easy or supported about this. I can’t help feeling that doing exactly this in the customers own client and getting the build machine to create a custom C++ server (i.e. not using realtime servers) would be just so much easier."
So this means that while the commands are very simple payloads that are easy to mimic, you do have to encode them using Google’s Protobuf format, specifically using an identical Protobuf defined API. Thankfully the .proto files are very easy to replicate (so long as you understand that the Real-Time servers are using Google Protobuf v3.3.x, which is about 4 years out of date now).
Newer and older versions of Protobuf aren’t compatible with the Real-Time Server API.
I received information on the protobuf definitions used by Al Murray however due to the licensing of that information I may never be able to share the exact info (which would unfortunately include an open source C++ client project). I am only restricted to redistribution at this point though, so I can share any knowledge I discover on my own still as well. I should be hearing back next week on an update to this license as well, which may or may not make it possible for my work to become an open source project at some point in the future.
At the point that I’m now at, I’ve defined an identical protobuf api for use, and have added and linked it and Protobuf to my project, I’m attempting to send the LoginCommand protobuf packet as a CodedOutputStream (as done in BaseConnection.cs), however the Real-Time server still isn’t properly handling this command. Occasionally in the logs it will say “failed to parse login command”, but other times it simply reports “(index.js) 202: Message received from player 1” as it did before implementing Protobuf.
Thanks again for your response @Pip!