Generic Multiplayer Connector

Hi all.

I’ve recently finished developed something I’ve been thinking about creating for a while: a simple generic way to connect any single-player games to each other so they become multiplayer games. For example, connecting lots of single-player Tetris games to each other, so they if a player completes a row, it sends a message to the other players and speeds up their game.

Anyway, it’s finished now and I’ve called it the Generic Multiplayer Connector (GMC). I’ve designed it to be as simple as possible to incorporate into games. Once you’ve included the jar in your project, there are methods to connect to the server (server code also included), join a game, and send data to the other clients. It even comes with a very simple version of Tetris that has been retrofitted to be multi-player.

The jars, full source, and more detailed help can all be found here:- https://bitbucket.org/SteveSmith16384/genericmultiplayerconnector

All comments welcome, and I hope other people find it useful!

You might want to simplify the explanation on your bitbucket page by providing some very broad overview of what your library actually does and what benefits it provides. Right now, you basically start off with a mushy explanation of what it does and a big wall of text explanation for your lib instead of providing simplified sample code upfront, i also had to search through the source just to find the mentioned example code, you should provide a link!

Have a look at the KryoNet page for some inspiration:

[quote]KryoNet is a Java library that provides a clean and simple API for efficient TCP and UDP client/server network communication using NIO. KryoNet uses the Kryo serialization library to automatically and efficiently transfer object graphs across the network.
[/quote]
This contains all the information i need:
-It’s using Java, NIO and Kryo
-You have to use a Server/Client model
-Objects can be serialized automatically
This is all i need to know!

With your page on the other hand, it took me a while to get what your library actually does technically, it isn’t important what you think your library could be used for, people want to know what it actually does and how, so that they can judge whether it is worth using it or not.

[quote]Turn any single-player game into a multiplayer game
[/quote]
What does this mean for the developer, how does it do that, what does it do? sounds like marketing blabla…

[quote]easily connect clients to a shared server so they can pass simple data to each other
[/quote]
This is what any of the quadrillion networking libs out there already do, why should i use your stuff?

[quote]The GMC library includes both a server and client components […]
[/quote]
Yeah, but what is their specific function, what special stuff can Server/Client do for you?

[quote]simple MultiplayerTetris included
[/quote]
Provide a link, you’ll put off people who value their time, i don’t think anyone wants to waste minutes just to find some sample code, while they don’t even know yet what your lib does.

[quote]Quickstart Usage
HUGE WALL OF TEXT
[/quote]
What about some short spicy code samples?

[quote]ConnectorMain.sendKeyValue… or ConnectorMain.sendString
[/quote]
What about byte-arrays? No byte-arrays means no easy inter-operation with serialization libraries.

Many thanks for your detailed reply :). It’s always hard, when you know something from the inside, to know how others will see it from the outside. However, it was a big oversight by me to not include any reasons as to why anyone should use my library over any other. I’m in the middle of re-writing the readme based on your comments, but to answer that question here, its advantages are:-

  • Simple to use. Yes, I know every library in the world claims this, but running a server is simply a case of running a jar, and a single server can handle any number of players and different games with zero configuration. And running the client is just a case of calling connect() and then joinGame() and you’re away. When a client then sends any data, it is received by all the other clients, so there’s no need to worry about handling network connections, multithreading, keeping track of other players etc…

And I’ve almost finished adding the feature to send a byte array.

Forgive me for not reading the source, but as someone who would want a library like this I feel that if I am not under complete control of the way my data gets passed back in forth I rather just make it myself.

The concerns come from not being able to retrieve the objects and instantiate them first to pass them off to the library.

Create Socket
Adds proxy support
Gives to library

over

Gets socket from library
Messes around with it to set proxy

Just some work flow idea here.

Thanks for the feedback, apologies for the delay in replying, for some reason I’m not getting notifications.

Let me know if I’ve misunderstood where you’re coming from, but as the owner of the game code, you are in complete control of when and what data gets sent between clients, and to a certain extent how (TCP or UDP), but the idea behind the library is to save the game developer any of the other worries, e.g. socket handling, network threading etc…

For example, once the client has called connect() and joinGame(), they can just call “sendStringDataByTCP(myJsonData)” whenever they want to. All the other clients will then receive the data with the dataReceivedByTCP() method in the interface. Those 4 methods are literally the only ones that need to be used to send data between clients.

I’ve just finished retro-fitting a version of Tempest to make it multi-player using the GMC library. It’s a pretty accurate recreation of the original game that I found on the internet, and it shows every player’s scores on every players screen, and when a player completes a level, all the baddies on all the other player’s games shoot missiles.

Full source code is here: https://github.com/SteveSmith16384/wbt-multiplayer , or you can just download the jar.

Here’s next project to retro-fit a game into multiplayer using GMC, this time MazEvolution written by KevinWorkman. It’s a maze game where each player gets the same maze, and the first to get to the exit wins. And then everyone gets a new maze.

Full source is at https://bitbucket.org/SteveSmith16384/mazeevolution

So this is basically a simplified text based broadcast protocol? I wouldn’t consider a single pub/sub-channel a proper base to implement multiplayer.

This is really cool to see. Wouldn’t it make more sense to have the winner get a more complicated maze though?

I like the idea. Anyhow since I think you might want to get somebody looking into the source itself, here’s a list of some glitches I found at a rough first sight:

  • inconsistent source code format (not only in terms of upper-, lowercase in method names but also sometimes enum, sometimes public static final)
  • no way to automatically build it (gradle, maven, sbt, …)
  • methods with 200+ lines (just don’t do that :-))
  • hardcoded single thread design (ServerMain) which will not scale
  • why is winner a special message and not just another data item?
  • synchronized in a single threaded environment (did I miss anything and why no concurrent data structures?)
  • tons of object creations (by using iterators and stuff)
  • I SEE SYSTEM.EXIT! Just finish threads gracefully
  • ServerMain::decodeError - you should exchange the todo with something useful :wink:
  • what is the license? I see plenty of GPL which means it’s unusable for closed source commercial games
  • don’t extend Thread but implement Runable (composition over inheritance)

Guess that’s ok for now :slight_smile: Feel free to take suggestions or ask for points that are not clear.

That was just an example; it can broadcast byte arrays or a key/value as well.

Thanks. You’re right; I wanted to get the multiplayer up-and-running quickly, so I didn’t actually think about the actual game mechanics much. The latest version now gives all players the same maze though, to make it fair and competitive. Maybe it should handicap the winner or something?

Yeah that’s what I was thinking. Although I like the idea of putting them in the same maze. Would it be possible to drop them into the same maze so they see each other? I don’t know if that would work with the kind of mazes it generates though, since there’s only really one main path.

I’d also be curious to hear about how you had it generate more or less complicated mazes. The generator is a little blind to that, using how long it takes you to solve previous mazes to make more complicated mazes. In other words it doesn’t come from the programmer, it comes from the player. I’d be curious to hear how you programmed around that.

It shouldn’t be too hard to show each other, although (as I think you allude to) I can imagine players just following each other.

Regarding the maze complication, I think I just increased the seed that your function used, which I assumed made it harder. However, there is also the function to check the maze is valid by counting the distance between the start and exit. Making a harder maze would just be a case of recreating a maze if this number was too low.

[quote=“SteveSmith,post:14,topic:57760”]
Sorry, but this is not at all how it works. The maze generator is defined by a few likelihoods: likelihood that the path goes forward, likelihood that the path goes left or right, etc. There is no concept of harder or easier or more or less complicated in the generator itself. Instead, the generator uses how long the human players take to solve a maze to find the “hardest” maze and then uses that maze as the parent for the next generation.

Think of it this way: each “round” of the game is actually 3 mazes: one was generated with more likelihood for straight paths, one was generated with more likelihood for left paths, and one was generated with more likelihood for right paths. At the end of the round, the generator takes the maze that took you the longest to solve and uses that as the parent of the next generation, so subsequent mazes will be generated with similar (but still mutated) likelihoods.

After a few rounds of that, the mazes naturally evolve to be more complicated, but it’s not based on any idea of complication in the code itself. It’s based entirely on player performance, and in fact two players might get completely different types of mazes based on how they perform.

You could use the generator to evolve mazes based on both player performances (evolve mazes that would be easier for the loser? or more complicated for the winner?), but it’s not as simple as modifying a seed value. That doesn’t actually change anything other than the initial seed value used by the random generator.

[quote=“KevinWorkman,post:15,topic:57760”]
The game sends the maze data to the other players, so they have the same mazes.

I understand that part. I wasn’t talking about your multiplayer version, I was talking about the generator itself. I’m trying to say that the seed has nothing to do with the difficulty of the maze, and it’s all based on player performance. Your current multiplayer version will just end up with random (and probably pretty easy) mazes without any notion of difficulty.

Now that it’s multiplayer, that’s all I need.

To be honest, I probably spent less than 10 seconds thinking about the maze generation. Your game generates random mazes which is all I needed to create a nice simple game I can play against my kids.

Fair enough. Enjoy!

But you might want to play a few rounds against yourself and then use those likelihoods instead of the default, that way the mazes are actually interesting. Up to you!

I’ve create a multiplayer Bejeweled game as my next project.

I’ve got it all written, the only problem is I can’t think of what can happen to a player’s opponent if one player completes a line. Any suggestions anyone?