Serialization Issues with client and server

Hello jMonkeys,

Im in a situation where i have 3 programs, namely a matchmaking server, a gameserver and a client.

  • the matchmaking server runs 2 servers, one for the clients to connect to and one for the gameservers.
  • the client runs 2 clients, one connecting to the matchmaking server and the other one connecting to the gameserver once it was told to do so by the matchmaking server.
  • the gameserver should run one client and one server, the client connecting to the matchmaking server, and the server for clients connections

Im now facing some Serialization / Registration issues, especially on the gameserver.
when i start the gameserver server before i start its client to the matchmaking server, there is a message in the log saying “Skipping registration as registry is locked, presumably by a local server process.”. The comment above the logging line in the source code assumes that this is intended in case the client and server are meant to connect to each other, or in case thats not wanted (in my case also) one would have to disable ServerSerializerRegistrationsService.
How exactly would i go about doing that? I mean i can probably disable it but wouldnt i somehow have to replace its functionality?
When i do it the other way round and connect the gamservers client to the matchmaking server before i start the gameservers server for clients, i get “java.lang.IllegalArgumentException: Channel is undefined:0” when trying to do rmi calls to the matchmaking server (the matchmaking server has properly setup that extra channel). i guess that is because the server i started later has overriden some serialization settings?

And since i guess its related to this, in the sim-es-eth example, a DelayService is added to do some delay once a new client has connected. the comment above it tells that is to assure some serialization has been probably properly finished. I guess its not something that should appear in a final release, so out of interest, how would i go about solving the problem this solution temporarily solves? maybe @pspeed already had a cleaner solution in mind when saying its for debugging only?

Yes i know, my code must look fine from over there, but im not about getting it to work, im about understanding whats actually behind the serialization process.
I understand that serialization should be done on the server, so once the serialization is done the server can send some precompiled serialization instructions that are used on the clients then so there is no need to ensure exact same serialization code on client and server. Just this seems to be singleton style and i would like to understand how i would go about doing this in my situation

EDIT: i see 2 solutions:

  1. have all code that either of the 3 server-client-connections use (2 servers on matchmakingserver and 1 server on gameserver) and register them all together so even the gameserver would have the serialization information that would actually only be needed for matchmaking - client connections.
  2. basically copy and paste all Serializer related code and make it not static / singleton, but that would enclude a whole lot of code that i would have to dublicate

is this the only solutions?

Many thanks and greetings from the shire,
Samwise

The built-in serializer registration service was not meant to be used in this way. (Usually it’s strange to use a game networking API to do what a web service would normally do… but it’s not impossible.)

If you want to run two completely separate serialization domains then you will probably need to remove the service that is doing the automatic registration and then go back to making sure your clients and servers all register all of their classes in exactly the same order, etc…

Edit: and yeah, register all the classes for everything.

You technically could do it with multiple ClassLoaders also.

thanks for the quick response!

Ill go for registering all classes manually in each programm by putting that method in a common class thats called from all 3 programs. I would have to disable that automatic serialization but im sure i can get that done.

as to the DelayService thing, could i remove it then, because there is no need to wait for any serialization when i ensure in all 3 programs that serialization is done before any connections are established?

and out of curiousity, am i going a right direction here? or would the usual setup be completly different? considering i need matchmaking and want to be able to easily add more processing power to run more games simultaneously?

Personally, I wouldn’t necessarily use a low-level game networking API for a matchmaking service. It seems like something that a web-based REST API would be better suited.

Note: if you register everything in advance then I guess you may not need to remove the service… but yes, if you remove the service then you can also remove the delay service.

the matchmaking server also handles the users registration and login with a database and keeps track of connected clients and their authtokens, so in case a client disconnects it can connect to the matchmaking server again, login and get its old token back to connect to the gameserver again.
it also does matchmaking based on different gamemodes that have different team sizes while players can join together in lobbies before entering matchmaking so different lobbies might have to be put together in order to reach the team size.
it also keeps track of all the stats like games played, games won, and so on

is it inefficient to do it the way i do it to an extend where its like not sustainable anymore? or is it basically just uncommon?

I think the first time you want to allow the user to change their password without logging into the game… or get a password reset e-mail… etc… you will wish you’d used a more mainstream account management setup.

And yeah, SpiderMonkey was never really designed to handle many 10s of thousands of users… so you are automatically limiting your rollout.

Web services are more elastic (can increase capacity as needed), have built in features that you will want (HTTPS) for password management, have existing protocols you could tap into (OAUTH2, etc.)… I mean, really the only down side here is whether you personally are familiar with web development or not.

If you only ever plan to have a hundred players or so and will manually handle all user/password issues then you are probably fine going as you are.

None of that precludes a separate web service. Your game server would just be another client of that service.

And following pauls advice, I would recommend jetty and oauth2. They are my go-to for anything like this. I like jackson for json, but either that or gson and you’re all set. I hate php with a passion. Your mileage may vary.

One of the best features of Jetty is that it’s embeddable and therefore it is very easy to make use of in-memory data and skip out on using a DB to transmit transient data between matchmaking servers (you’ll likely have to resort to this if you don’t go the embedded route). That’s hardly a showstopper, but it’s inelegant and adds a whole extra layer of complexity that you may be able to avoid.

ok sounds like a bunch of new stuff to wrap my head around, thanks everyone for pointing me into the right direction.
Im still having a hard time to really get what i should go for.
So here is how i take it, below are the questions i have about it:

  • have some webserver going like jetty
  • hook webservices onto it like an AccountWebService and MatchmakingService that would handle appropriate requests probably in json format, the AccountWebService would use OAuth2 so the client can get a token when logging in which is needed because werservices should be stateless and every clients request needs to contain that token so the server knows that it actually is the right client since the connection from the last request is not kept
  • use the gameserver i have now, but replace its spidermonkey-client that connects to the spidermonkey matchmaking server with some requests to the matchmaking webservice to see if that gameserver now should host a new game and get information about the players that are going to connect to it

would it be better to have a seperate DatabaseWebService that only handles database requests so i can in theory even have multiple matchmaking webservices that would behind the scenes send requests to that single DatabaseWebService when needed?

that already feels wrong, but i especially wonder about how webservices should be stateless.
i read something like “every request should include all infos needed for the server” does it also mean the service cannot inform the client for example once a match was found since the connection is not kept alive? would the client continuously have to request the server to get an answer if the player is in a match now and accordingly would the gameservers continously have to request the matchmaking server if they should host a game now?
and how does the lobby joining thing work? would this all be requests to a database on the matchmaking service and how would i inform the lobby owner once another player joined that lobby owners lobby, i thought the connections would not be kept?
@danielp: is this what you meant by embeddable? i wouldnt have to make all the matchmaking requests database requests since i could keep the matchmaking infos and infos like which player is in which lobby in memory?

im sorry that this topic goes like off-jmonkey, but i wasnt actually expecting to be told to turn away from using spidermonkey, so there were some questions popping up
btw, i know i could just go with what i currently do if that is all going too crazy for me. but this project is about learning and not about getting it done as soon as possible so i would like to do it the way its usually done and not the way that is the most intuitive to me since whats intuitive for me is what i already know
thanks in advance for every more pointing me into directions

When the user starts the game it will login. On success you will now have a token or what’s called a session. If a session is already there remove it and thus invalidate it and replace it with the new one to enforce one session per user.

When the user requests a match making game you would either send a single request with the token and then timed queries (and if the user hasn’t queried after x seconds, take them off the list - they must have give up or connection died) about the state of the match making, or use sockets for two way communication if you prefer. In which case the client asks for a match and you only respond when one has been made or you want to update the client with information (such as how many people are still required, time left until the match fails, etc).

I’ve basically successfully changed my matchmaking-spidermonkey-server to be servlets running on embedded jetty without any jme class (thanks to danielp for pointing me towards embedded jetty)
I have also looked into OAuth2 and although i didnt precisely follow the exact pattern and implement all grant_types and such i got the account management working and i can both, access it in html in browser as well as get json responses for my client (thanks to pspeed for pointing me into more mainstream account management and thanks to jayfella for explaining the basic setup)

Bunch of thanks and changes later im facing the following problem:
I want to easily scale the amount of GameServers that are running at a time to make sure Games that are created by the MatchmakingService will be hosted soon after they were created.
I already got it working that a GameServer can ask for a new Game to host and in case there was one Game created by MatchmakingService that is not yet hosted, the GameServer is sent information about the Game and Players that are going to join and if the GameServer sends an accept after it, the Game on MatchmakingService side is marked as hosted and Player-clients can get the ip of the game hosting GameServer to then connect to it.
I’ve got 2 questions related to that:
question 1: how would i go about making sure i can trust the GameServers that send GameHostRequests to the MatchmakingService?
Currently i have hardcoded ServerName - Password map in the MatchmakingService project and when i start a GameServer i do so by something like:
java -jar GameServer.jar name=Official_101 pass=2UIBb7Gs8CVHv9sh8v8
that causes the GameServer to register with the MatchmakingService similar to when a Player logs in (just Players can also request new account creation while GameServers have their “accounts” hardcoded in the map i mentioned)
but it is not what i actually want since it means i can only start as many GameServers as were hardcoded in the MatchmakingService
question 2: whats the best way to get the IP of the GameServer that sends requests to the MatchmakingService on the MatchmakingService-side?
i found some lines:

remoteAddr = request.getHeader("X-FORWARDED-FOR");
if (remoteAddr == null || "".equals(remoteAddr)) {
    remoteAddr = request.getRemoteAddr();
}

with request beeing an HttpServletRequest
is that a recommended way or should i rather send some custom header or parameter containing the IP when the GameServer tries to register with the MatchmakingService since its about making sure i can trust the GameServer and if i trust it i can rely on some custom way to get the IP

Thanks in advance already and many greetings from the shire,
Samwise

For 2) I would think you’d want the IP of the server “as seen from the internet” and not necessarily the IP as seen from the server. Quite likely it’s behind a NAT or firewall. I think you can still get this as the origin of the request, though… unless you are also being proxied locally (why?).

As for 1) logistically, what’s your chain of trust for game hosts? Do you want to give out accounts? Only accept connections from your own code? ???

The former is probably what you want since “only accept connections from your own code” is impossible.

How else would you authorize a game host? I mean conceptually.

Well optimally I’d of course want to only accept connections from my own code. I see that it’s not possible, that’s why I try to find a way to trust the GameServers as much as I would trust them if they were definitely my code.
Users can of course create new accounts (actually send requests to do so) but they cannot change their stats directly like set their number of games won, while GameServers should be able to tell the MatchmakingService about the winner of a game eg which would cause the Users stats to change on the MatchmakingService-side so i want to actually trust them

So is it basically a good way to have these hardcoded servername - password pairs (just hardcode as many pairs as i would maximally expect GameServers to run at a time)?
Or is it more recommended to like give the MatchmakingService itsself the ability to start new GameServer instances (dont know how i would go about that) and then dynamically create new servername - password pairs and start a GameServer with these credentials once a new GameServer is needed?
Instead of servername - password pairs i could also have a single “GameServer-MasterPassword” and each GameServer just sends a name and that masterpassword and is then fully trusted?

I just wonder how this is usually done (in case there is a usual way) for example in games like PUBG, Fortnite, League of Legends…

And thanks again for helping me out again, especially since its quite jmonkey-off-topic now

I imagine usually you would login as your user before you host a game. Is that not true for games like PUBG, Fortnite, etc.?

Else they must have arranged to have their servers listed in some common list somehow…

And no, hardcoded passwords is not really the right answer. You wouldn’t do that for user logins, eh?

Oh I’m sorry i guess i misunderstand or i used the wrong words to explain.
When i say ‘host a game’ i mean ‘run the simulation like physics and all of that’, i dont think that happens on the computer on one of the players that are currently ingame.
Users have to log in in order to join a lobby, yes (like when you log into the game you are automatically put into your own lobby, then you can send requests to join other players lobbies in order to enter matchmaking together and be guaranteed to be members of the same team)

Of course i dont hardcode the users credentials but again, i dont actually need to trust the users, since they only ever send requests that either the matchmaking service or the gameserver can verify while the GameServers (running on seperate machines) sends some requests to the MatchmakingService to update users stats that the matchmaking service cannot verify since it didnt simulate the game, so it has to trust the GameServer about these stats and update the related Users stats accordingly so next time the users enter matchmaking this matchmaking is based on the new stats (like players that have a lot of wins should be matched with others that have a lot of wins)

And what do you mean by “arranged to have their servers listed in some common list somehow”? I imagined the MatchmakingService first tells the Users about which GameServer IP to connect to once a Match was actually made and the GameServer is informed about the game already (i guess the GameServer needs to be informed about the Game to host, since it needs to know the teams and players in teams and gamemode)

So all of the game servers are run by you?

Or are they ever run by users… that should be logging in?

If they are run by you then I don’t see what the issue is.