Tag Archive for 'opengta2'

OpenGBH better client prediction

I’ve added much better client prediction to OpenGBH, although I’m going to change it again because of some new ideas people gave me.

Now the client prediction correctly assigns predicted frame sequence number, which means when that sequence actually arrives from server, it is possible to check if the prediction was correct. And that is how it works, here’s the complete sourcecode of client prediction as it is right now:

//Prediction history
for (uint i = PredictHistory.AllocCount-1; i >= 1; i--) {
	memcpy(PredictHistory[i]->LocalPed,
		   PredictHistory[i-1]->LocalPed,
		   sizeof(Ped));
	PredictHistory[i]->Sequence = PredictHistory[i-1]->Sequence;
}

//Find reliable frame
frame_entry* reliableFrame = Frames.LastFrame;

//Find how far into future we should predict (in frames)
uint lagFrames = (uint)(0.5f+(Network.Statistics.Latency) / (1.0f/ServerTimer.FPSLimit));
lagFrames = clamp(lagFrames,0,History.AllocCount-2);

//Predict next frame
PredictHistory[0]->LocalPed->controlClient = BAD_ID;
PredictHistory[0]->LocalPed->handleMovement(Input.keyPressed);
PredictHistory[0]->LocalPed->Live();
PredictHistory[0]->Sequence = reliableFrame->Sequence+lagFrames;
//This prediction corresponds to sequence from future

//Find reliable pedestrian
Ped* reliablePed = reliableFrame->getLocalPed();
if (!reliablePed) return;

//Find corresponding predicted pedestrian
//He was predicted sometime in the past for this frame
Ped* predictedPed = 0;
uint predictedFrame = BAD_ID;
//Attempt to find predicted frame that matches this one
for (uint i = 0; i < PredictHistory.AllocCount; i++) {
	if (PredictHistory[i]->Sequence == reliableFrame->Sequence) {
		predictedPed = PredictHistory[i]->LocalPed;
		predictedFrame = i;
	}
}

//If this frame doesnt correspond to any predicted frame, then just ignore all error checks
if ((curtime() > PredictionErrorCheckStart) && (predictedPed)) {
	//Calculate prediction error
	Vector3f deltaPosition = predictedPed->Position-reliablePed->Position;
	Vector3f deltaVelocity = predictedPed->Velocity-reliablePed->Velocity;
	float deltaHeading = predictedPed->Heading-reliablePed->Heading;

	//How much the whole "snake" of future states should be moved to compensate
	//the prediction error
	Vector3f shiftPosition = Vector3f(0,0,0);
	Vector3f shiftVelocity = Vector3f(0,0,0);
	float shiftHeading = 0;

	Statistics.PredictionError = deltaPosition.Length();

	//Correct position error by moving snake a bit
	float positionErrorMargin = Convar.GetFloat("p_poserr",0.5f);
	float positionCorrection = Convar.GetFloat("p_poscorr",0.05f);
	if (deltaPosition.Length() > positionErrorMargin) {
		//Error too large, reset latest state
		predictedPed->Position = reliablePed->Position;
		predictedPed->Velocity = reliablePed->Velocity;
		predictedPed->Heading  = reliablePed->Heading;

		//Reset future states as well
		for (uint i = 0; i < predictedFrame; i++) {
			memcpy(PredictHistory[i]->LocalPed,
				PredictHistory[predictedFrame]->LocalPed,
				sizeof(Ped));
		}

		//Reset prediction so you don't get stuck in infinite error loop
		PredictionErrorCheckStart = curtime() + 1.0f;
	} else {
		//Small interpolation error, slightly move all future players into right position
		shiftPosition = (reliablePed->Position-predictedPed->Position)*positionCorrection;

		//Do not move over Z coordinate
		shiftPosition.z = 0;
	}

	//Velocity error is not corrected
	//

	//Correct heading error
	float headingCorrection = Convar.GetFloat("p_hdgcorr",0.1f);
	shiftHeading = (reliablePed->Heading - predictedPed->Heading)*headingCorrection;

	if (PredictHistory[0]->LocalPed->Velocity.Length() < 0.1f) {
		shiftPosition = Vector3f(0,0,0);
	}

	//Shift all future states
	for (uint i = 0; i <= predictedFrame; i++) {
		PredictHistory[i]->LocalPed->Position += shiftPosition;
		PredictHistory[i]->LocalPed->Velocity += shiftVelocity;
		PredictHistory[i]->LocalPed->Heading  += shiftHeading;
	}
} else {
	for (uint i = 1; i < PredictHistory.AllocCount; i++) {
		PredictHistory[i]->Sequence = PredictHistory[0]->Sequence-i;
	}
}

//Render predicted frame
PredictedRendered = PredictHistory[0];

This is not up-to-date anymore though, because I’m going to use client backlog timed to all server frames for much more precise input handling instead. This means that the client tells the server all keys he pressed, and at what time he presses them, and the server properly calculates time he pressed them on, and simulates that input.

From servers point of view, client input packets arrive marked with future time, so it takes some time until they actually happen.

OpenGBH project plans

Sorry for delayed posts. I just can’t seem to catch up, with all the stuff happening. Why is the stuff happening (but stuff, please keep happening, I like you).

Here’s rough outlay of the current plan:

  1. Finish up client input backlogging in the MP demo. And release it.
  2. Switch over to fixed-size numbers everywhere (improves portability, and also much more sane)
  3. Remove all current rendering code and make it work without that.
  4. Clean up all code which is still there to perfect state.
  5. Add proper rendering subsystem, which supports different renderers. Actually a lot here (sprite remapping, animation, etc).
  6. Add basic weapons system.
  7. Add scripting subsystem (placed after weapons so it would be easier to estimate proper architecture of scripting engine)
  8. Start adding cars and improving pedestrians
  9. Add basic AI and AI network syncing
  10. Everything else

(Oh right, time paradox, but some posts about new OpenGBH networking updates which actually precede this follow this)

OpenGBH server bug

Remember the server bug which seemingly halved the server FPS? I found the cause for it, and also I fixed another bug.

Anyway, the bug looked like this: if server was up for more than one day, after connecting to server you couldn’t really move around, all frames would be filled with the interpolated frames, or the extrapolated frames, and the whole thing was really unplayable:

There were two problems behind this. First problem is client-side, because if server frames arrived less often than client expects, the frame history wouldn’t be properly updated.

It would attempt to find the frame which is already somewhere in history, and then I realized it never actually wrote new frame (the new reliable server frame) into history. So I fixed this bug, and now after connecting it looks like this (and it’s playable):

Now, there is also serverside problem – after some time precision for “time since server startup” counter is lost (the value grows too big), because it is only a single-precision floating-point. I’m going to switch over to double-precision later, this should fix it.

I’ve tested this by simply adding 600000.0f to current timer, and the bug repeated itself even with fresh server startup. The packet send rate was decreased from 16 packets per second to only 10 packets per second.

OpenGBH networking test results

The alpha networking testing is complete. I found some problems I’ll fix before multiplayer demo, and generally the server performed well enough. My connection (4 mbit up and down) worked well for 10 players, and it wasn’t even exceeding the 1 mbps limit.

It’s a good sign, because right now the data sent over the network is still fairly unoptimized. There are the following problems uncovered and which I’ll fix in the MP demo:

  • The client prediction error correction is very “springy” at high latencies
  • It seems that there’s rare bug, if server was up for a long time, it starts running at seemingly half the FPS, resulting in a lot of interpolation on clientside. This occured after about 60 hours of uptime.
  • There are some misc bugs with the chat (it sends empty strings)

OpenGBH alpha multiplayer server update

Small server update, I have changed the way the tag messages are announced now. The server will now display who tagged who, and I also changed the rules (now there is no respawn between tags, rather there is immunity time of 0.5 seconds).

The server was up for about 12 hours so far without problems! We had about 10 players at most, and it worked fine (was really fun too). Here’s a screenshot:

OpenGBH alpha multiplayer demo

I’ve prepared an alpha multiplayer demo of OpenGTA2, you can download it and join the test server (it’s going to be up all weekend).

The current gamemode is a game of tag. One person is randomly picked as a tag, and then he is supposed to chase others. If you come close to other person, he respawns as a tag. I increased walking speed a lot, so everyone is running around like crazy.

You can download the client here: alpha test over

Connection instructions:

  • Unpack and run the game
  • Bring up console by pressing “~” or “Q”
  • Type in console: name yourname
  • Type in console: connect phoenix.wireos.com

That’s all, the server is hosted in Ukraine, which means you better be in Europe while testing this out. The networking engine works well for latencies under 200-300 msec, but as latency grows, everything becomes more bouncy.

The game might feel weird after you connect, just wait some time until ENet averages out your ping (the client prediction will work much more nicely). Oh and press “Y” to chat.

If you can’t see names in the chat, type in console net_reset. Many walls are still non-solid (especially diagonal ones), sorry for that. Falling through them respawns you as a tag.

Screenshot:

OpenGBH early alpha MP

I’ve been testing early alpha multiplayer out with some of my friends. It now actually works, and you can walk around! I added arrows which point to other players (purple ones – real players, green – AI bots):

I’ve improved client prediction. I’ll describe the new way a bit better in next post, but it generates really nice long prediction trails (history of 128 predicted frames):

The whole thing works quite nicely. It’s kind of fun standing in a tiny crowd, and spinning around like we’re some kind of gearbox.

New OpenGTA2 graphics

I always planned to redo original GTA2 art assets, and Fillipe said he could help. He started by redoing some of the GTA2 tilesets in a higher resolution. This means that instead of the 64×64 tiles we will have the 256×256 tiles complete with bump and specular maps.

This requires a rendering engine update, which I’m going to work on after releasing the multiplayer demo. Oh yeah, and besides bringing higher quality graphics, they will also make us independant of the Rockstar GTA2 licensing rights. And I will make sure that all new assets retain GTA2 feeling about them (same color pallete).

Here is the first iteration of road tiles:

But then Fillipe realized they were still 64×64 tiles, so here are the real 256×256 ones: