Solved

RTS game state, how is it optimally encoded in a Java byte[] ?

Posted on 2014-12-06
12
309 Views
Last Modified: 2014-12-15
Hi,

My previous question's code became corrupt, and it was not clear that it was a Java project.
In Java, is my code below the correct way to store a game-state of an RTS on an x,y dimensioned map? for TCP authority updates? With a frame cycling below 100ms, this code updates the game-window well. I will add movement delta update messages, and use this big Game-State message as a periodic authority game-state confirmation.
In this code, I was only doing small test states of 20 visible units. How do I handle 100 to 1000 units? I'd need a huge byte[] listener?
each unit has a number, x,y, type,
which with 2 byte integers needs at least 4* 2=8 bytes per unit - at least byte[8000]
if no other value is needed?
are we talking an authority update send of a byte[10000] ?

Thanks

secondByte() is at the bottom

public void addGameStateToByteArray(byte[] bytesToAddStateTo) {
		
		// add game state to this byte array, all the unit x,y locations
		for (int i=0; i<unitMax;i++) {
			
			//unit x's . . 
			//put in the first byte to reconstruct the unit's X integer..(i*4) leaves room for the 
			//2 bytes of the x integer and 2 bytes of the y integer later, x first
			bytesToAddStateTo[2+(i*4)+0] = (byte) unitXs[i]; //first unitX byte
			
			//put in the second byte of the unit's X integer.. 
			bytesToAddStateTo[2+(i*4)+1] = (byte) this.SecondByte(unitXs[i]); //second unitX byte
			
			//unit y's . . 
			//put in the first byte to reconstruct the unit's Y integer..(i*4) leaves room for the 
			//2 bytes of the x,y integers
			bytesToAddStateTo[2+(i*4)+2] = (byte) unitYs[i]; //first y byte
			
			//put in the second byte of the unit's Y integer.. 
			bytesToAddStateTo[2+(i*4)+3] = (byte) this.SecondByte(unitYs[i]); //second byte
		}


	}

byte SecondByte(int x) {
		return (byte) ((x & 0x0000ff00) >> 8);
	}

Open in new window

0
Comment
Question by:beavoid
  • 7
  • 3
  • 2
12 Comments
 
LVL 26

Assisted Solution

by:dpearson
dpearson earned 250 total points
Comment Utility
If you're sending 10 bytes per unit then yes if there are 1000 units you're looking at 10,000 bytes.  But that's actually quite a small number.  Put another way that's 10K (or a very tiny image on a web page).

Now if you choose to send it every 100ms you'll need a data rate of 10K*10 = 100K/sec for the clients, which is about 1Mbps (the b there is 'bits per second'), which is a very slow broadband connection - but means no dial up modem players.

At the server end you'll need 100K/sec * the number of clients.  If you are allowing 8 clients, then you'd need 800K/sec at the server or about a 10Mbps server connection.  Nothing crazy.

If that seems like too much you could either drop the update rate (e.g. 500ms between updates means data rate is only 10K*2 = 20K/sec).

As for how to encode it into binary, you should check out ByteArrayOutputStream (and ByteArrayInputStream), which is designed to convert a set of values into binary:
http://www.tutorialspoint.com/java/java_bytearrayoutputstream.htm

Doug
0
 

Author Comment

by:beavoid
Comment Utility
Thanks Doug

Is that link mainly for a less complicated way to encode data into a byte array?

If I'm comfortable with my method, is it okay? for many thousands of bytes in the TCP state byte[] like > 10K
U'r right, a small pic on a website isn't too hectic.
When is it too much in the state byte[]?
So, I shouldn't be embarrassed by a 100ms or 200ms cycle time? 500 is pretty clunky.
Thanks
0
 
LVL 26

Expert Comment

by:dpearson
Comment Utility
Yeah that's just another way to encode data into a byte array.  You can certainly use bit shifting if you're happy with it.

So, I shouldn't be embarrassed by a 100ms or 200ms cycle time? 500 is pretty clunky.

These should all be fine since this is the TCP updates.  If the players have a good connection they'll be getting even more frequent UDP updates as well, so there's no lag.  It's only if they have a poor connection that's dropping some UDP packets that you need to fall back on the TCP updates to keep things going and then it'll get a bit choppier for them.  But that's natural when you have an iffy connection.
0
 

Author Comment

by:beavoid
Comment Utility
Thanks
So, I should have a server TCP socket and a server Datagram socket,
and send the same Game State byte[] every cycle?
TCP first?
Should I fire the UDP a couple of times, 1 ms apart to give better arrival chance?
Would that even matter if TCP is being sent? Isn't a big UDP byte[] a bad idea?

Thanks
0
 

Author Comment

by:beavoid
Comment Utility
Hi

After my previous comment,
I probably mustn't send the full state every cycle, but unit deltas in-between.
Should I send the full state every nth cycle 10th 20th?
And, the unit deltas must be UDP and full state in TCP?
But, if UDP packets can get dropped, must I tag these UDP deltas with a game-clock? Some might get lost and a cycle won't have any deltas? How long should we wait for a UDP to be collected for a cycle? couple milliseconds? And, if nothing comes after, say 5 ms, the cycle is ignored . . So, the TCP covers that..
?
Thanks
0
 
LVL 35

Assisted Solution

by:mccarl
mccarl earned 250 total points
Comment Utility
Some might get lost and a cycle won't have any deltas? How long should we wait for a UDP to be collected for a cycle?
It sounds like you are using the reception of your messages to "drive" your game cycle. Personally, I probably wouldn't want to do that. I would have your game cycle running independently of the message reception, and on each game cycle you just apply what ever update messages were received since the last game cycle. But yes, it could be a good idea to include a game-clock in each message, not because the packets might get dropped but more so if they get delayed more the usual. You could then use the game-clock in the update to logically apply that update at the correct point in the game state history. I guess that means that you might keep a short game state history on the client side so you can perform that last point that I mentioned. You would probably only need to keep the history of each incremental game state since the previous full state message.

As for using sending full state vs some form of delta, I think that that would be a very good idea. Theoretically, you only need to send an update for an action that the client has no way of knowing about. Considering the following scenario...

Say Player A has a unit moving north at 1 step per cycle, and Player B needs to know about this unit because it is in their field of view. Then after 5 cycles Player A commands there unit to be moving east at 2 steps per cycle. The following lists the messages to be sent using a bad way and a good way...

Bad way
Cycle 1 message: Unit A, x = 0, y = 0
Cycle 2 message: Unit A, x = 0, y = 1
Cycle 3 message: Unit A, x = 0, y = 2
Cycle 4 message: Unit A, x = 0, y = 3
Cycle 5 message: Unit A, x = 0, y = 4
Cycle 6 message: Unit A, x = 2, y = 4
Cycle 7 message: Unit A, x = 4, y = 4
Cycle 8 message: Unit A, x = 6, y = 4
Cycle 9 message: Unit A, x = 8, y = 4
Cycle 10 message: Unit A, x = 10, y = 4

Good way
Cycle 1 message: Unit A, dir = N, spd = 1
Cycle 2 message: not sent
Cycle 3 message: not sent
Cycle 4 message: not sent
Cycle 5 message: not sent
Cycle 6 message: Unit A, dir = E, spd = 2
Cycle 7 message: not sent
Cycle 8 message: not sent
Cycle 9 message: not sent
Cycle 10 message: not sent

The client at Player B can work out all the details in between. It just (obviously) doesn't know the Player A provided an input that changed the game, so it needs to know about that but the other stuff is all just calculated.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Author Comment

by:beavoid
Comment Utility
Hi
Thanks

This is what my server's game loop looks like ( with satellite Thread assistance)
Right now, it sends only the game state in the cycle
and the delegates listen for client activity, register actions in the server, and the server updates the game-state every cycle, based on movement waypoints, for example.

boolean inGameProcess = true;

	byte[] inGameBytes = new byte[256];
	
	while (inGameProcess) {
		//send authority to each client
		inGameBytes[0]=IN_GAME_MSG;
		moveUnits();
		addGameStateToByteArray(inGameBytes);

		//sleep to let delegates handle client activity for exactly one frame, 100 ms
		Thread.sleep(100);
		System.out.println("");
		for ( int i=0; i<numClientsJoined; i++) {
			System.out.print(" in.g"+i); // in game 
			outputStreams[i].write(inGameBytes);
		
		
		        //authority state sent, now send movement updates?
                 }
		
		
	}

Open in new window


So, that relies on complete state in every message.

Okay, I thought of your tactic before, that I don't really need UDP update messages.

I think this is what you are hinting at ?

So,  when you don't send a message for a cycle, the unit updates just happen on their own?
Will these messages be fast enough to live up to the frames per second needs of a real time game? That's the reason for UDP, I was told.

But, this means the full game state will be in memory on the clients, if there are units in the edge of the fog of war? - not good
?
Thanks
0
 

Author Comment

by:beavoid
Comment Utility
So,
Doug,

I send the exact-same Game State byte[] in UDP as in the TCP fallback messages,  and whichever arrives first is taken?
But, won't the UDP state byte[] be chopped up and useless?
How is UDP practically useful from server to client?
It is all working without UDP right now. Would UDP be sent instantly before TCP, or after?

McCarl suggests I have things automatically calculated on the client. But that means units in the fog unit locations might need to be present on the client, and that might lead to hacking.
?
Thanks
0
 
LVL 35

Accepted Solution

by:
mccarl earned 250 total points
Comment Utility
Okay, I thought of your tactic before, that I don't really need UDP update messages.

I think this is what you are hinting at ?
No, not necessarily. This would be a detail that I would (if I were doing this) want to trial and error, but I would probably send all those unit state changes (such as a change in dir, speed, ......, etc) in UDP messages. Because they would be small and only sent when a change occurs, you might look to batch X number of unit change messages into a UDP packet (X being what ever fills your maximum desired UDP packet, because you are correct, you don't want the network to fragment a UDP packet for you, best do it yourself in a controlled way). And then send the full state in a TCP packet at some regular interval (I'd really have no good idea what that interval would be, again a trial and error thing) and this just syncs/corrects the game state. In the ideal world, and if all your code that controls this is 100% correct, the TCP shouldn't be necessary, but in the real world it would correct any issues that arise from missed UDP packets.

Will these messages be fast enough to live up to the frames per second needs of a real time game? That's the reason for UDP, I was told.
Again, this comment gives me the impression that you are still tying your game cycle with your video update cycle with your network packet reception. They should all be independent.... in each game cycle, you apply any changes received from UDP messages since the last game cycle, and the same for loose-coupling between your game cycle and your video refresh cycle. (although this may be less of a problem since you CAN generally control both the game cycle and the video refresh cycle)

But, this means the full game state will be in memory on the clients, if there are units in the edge of the fog of war?
No, the server should know about each clients "view" and it will only send the required updates that apply to units in each particular clients view.


McCarl suggests I have things automatically calculated on the client. But that means units in the fog unit locations might need to be present on the client, and that might lead to hacking.
No, as mentioned above, the server wouldn't send any more updates for a unit when that unit leaves the clients view. Yes, the client knows the last direction and speed, say, of that unit but that doesn't really give you much. A hacked client could extrapolate the same from the last few position updates in "your" solution of sending full position state on every cycle. The other player in control of that unit may subsequently command that unit to do something else, and the first client wouldn't know about it.


These below questions were directed at Doug, but I will add my 2c.

But, won't the UDP state byte[] be chopped up and useless?
Potentially yes, and that is why you wouldn't send one large UDP packet. The underlying network doesn't guarantee that it would be able to fully, correctly reconstruct the packet if it was required to be fragmented at any point between server and client.

How is UDP practically useful from server to client?
Hopefully from what I've written above, you can see that it can be useful.
0
 
LVL 26

Assisted Solution

by:dpearson
dpearson earned 250 total points
Comment Utility
We've discussed this before beavoid and I always suggest you get the whole thing working with TCP first and only then add the UDP layer for extra smoothness on the client.  Since the UDP packets can't be assumed to arrive, it must all work with just the TCP implementation.

And yes like mccarl says, you can't send the entire game state to each client.  That's fine as a first version while you get the bugs out, but eventually each client will need to be sent a custom portion of the game state - just the parts they can see.

As for whether you send a full game state (customized to the client's view) or just deltas - if you're using TCP you can just send deltas.  TCP will ensure delivery and if it can't complete the delivery even after multiple retries, that client is hosed anyway and will need to be dropped from the game (the network connection is way too poor to support an RTS game).

Sending just deltas will hugely reduce the amount of data being sent if you're efficient about the design.  Like mccarl showed you a few comments up, you can just send deltas when new commands are issued to units, not on each individual move.  So e.g. you could ask a unit to walk right across the map, turning to pass obstacles as it goes all with just 1 packet that indicated where it needed to move to.

But that level of sophistication may be a bit much.  Just sending the list of units that have new positions that each client can currently see is a reasonable first step.

Doug
0
 

Author Comment

by:beavoid
Comment Utility
Thanks
Okay, deal

I'll do the game in TCP. Period, on my two adjacent machines on my desk.
an then worry about optimal UDP updating, improved connectivity. - Not sending the actual entire game state every cycle.

?
Thanks
0
 

Author Closing Comment

by:beavoid
Comment Utility
Thanks All
Is going v. well
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

This article will show, step by step, how to integrate R code into a R Sweave document
Although it can be difficult to imagine, someday your child will have a career of his or her own. He or she will likely start a family, buy a home and start having their own children. So, while being a kid is still extremely important, it’s also …
Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now