Jump to content

  • Log In with Google      Sign In   
  • Create Account

Angus Hollands

Member Since 06 Apr 2012
Offline Last Active Sep 05 2016 06:53 AM

#5309510 How to structure my pure client/server model properly?

Posted by on 05 September 2016 - 06:51 AM

Simple answer: 
Don't allow different simulation rates. Update the simulation at the same frequency on all players. Render at a different framerate to suit the player.
Complex answer:
Use timestamps instead of ticks, and introduce time into all input values.
The simple answer is both simpler, more predictable and a whole lot more reliable. It's also quicker as you're not introducing lerps and other tolerance based comparisons where timestamps don't match exactly.
The important point is that you need to decouple the rendering framerate, and the simulation tick rate. You can render the game at a different framerate to the update.
If you set a baseline minimum for the update frequency, clients who can render at a higher framerate than the simulation rate can interpolate between the most recent states. This does mean you're rendering in the past by one-two simulation ticks, but that is usually acceptable, as you would otherwise be rendering the old frame anyway, and the effect is to reduce jagged movement, which will improve the UX.
I tried doing things using timestamps and variable simulation rates. It doesn't make any sense. You gain nothing by doing it, but a whole host of problems. Something about your game needs to be predictable and constant. That is the simulation. The rendering can happen at any rate, and the client will still move predictably and have a predictable experience across hardware.

#5306952 Friends living abroad have really laggy connection to me, why?(using raknet,...

Posted by on 20 August 2016 - 08:49 PM

There are several issues at play here.


Firstly, you shouldn't really be running at 500FPS simulation framerate. That's absurd! Most games with any physics will ask for at most 60FPS. You should lock your simulation frequency to something like 60Hz, and render separately to that timestep.


Secondly, you can't hope to send data every tick. You'll flood the connection. Running at a reduced transmission rate, and keeping packets small reduces the liklihood of this happening.


Thirdly, the speed at which information can travel between two end points is finite and non-zero. At best, it's the speed of light distance, realistically though the path between two nodes is not a geometric minimum, and isn't entirely vacuum (instead copper + fibre). In short, there will be latency, and it's calculable for a ballpark figure.


The clients do not need "new" state for each sim tick. You can interpolate between recent states, or extrapolate the latest state to smooth the timestep between two simulation states from the server.

#5284143 "Weapon Fired" Event -- Reliable, Unreliable, or In-Between?

Posted by on 29 March 2016 - 05:55 PM

Whatever solution you use will depend on a few things, including whether your client simulation runs in the past or not. If you're already interpolating entities, that will give you some additional time to receive information about projectiles.


When it comes to entity replication, I will send a reliable un-ordered packet that contains the information required to instantiate the entity client-side. From there, I would send state updates as unreliable, discarding out-of-date packets. You could even reduce bandwidth for predictable projectiles and just send the initial state, with the network tick and velocity, and allow the client to simulate it.


I'm generally uncomfortable with the notion of reliable ordered. The reason most use UDP for fast-paced games is to avoid the latency that is fundamental to the operation of a reliable stream over unreliable network conditions. At least with reliable unordered you can proceed other state whilst the packet is redelivered when dropped.

#5236469 Glitches in Navigating my NavMesh

Posted by on 23 June 2015 - 06:17 PM

The way that Recast & Detour handles this is to include the agent's radius in the navmesh (to avoid having to post-process paths). In my game, I just apply velocity in the bearing of the waypoint until within a specific margin (0.01 m or so (> than 1 frame velocity error)) and then switch to the next waypoint. You could also check if the dot of the vector from the current waypoint to the npc position is greater than the distance between the current and next waypoint.

I avoid recalculating paths by only doing so if the target moves. You could extend this further by keeping track of entites within the same node and checking if they're in the path or not. To handle the case where the player leaves the navmesh, I keep track of the last node the player was within, then find the nearest neighbour according to the edge distance (assuming that I'm not currently in a node).

#5213092 Component-based architecture - entity and component storage

Posted by on 26 February 2015 - 09:08 AM

As you may be aware, there are a large number of different implementations of component based systems.

Especially in languages such as C++, the benefits of ECS designs can be the ability to employ contiguous memory. If you have each system allocate a pool of components, then you can reduce the frequency of cache misses, and hence improve performance of system updates.


Hence, when you register a component with an entity, it makes sense to request it from a system, which will maintain an internal pool (and therefore update internally) of components.

IComponent* physics_component = physics_system->create_component();

// Some time later
double delta_time = 1.0/60;

This has its difficulties when you have systems which share components with other systems. Generally speaking, avoiding this dependency helps a great deal.

#5208642 Why is scaling an mmo so difficult?

Posted by on 04 February 2015 - 10:09 AM

I think the best option is to run the safe code on the server, use databases to store players game state and balance out the load between servers. Any tips here?

That's exactly it! Now, good luck developing!

The tricky part is in the how - how do we "share load" between servers, in a seamless fashion to the end user? How to we divide the calculations required across multiple servers? Do we split them geographically in the real world (for faster latency response) or in world (for faster lookup of local entity data)? How should we handle interactions across servers?


I'm not an MMO specialist, but there are a number of topics recently posted in this forum which should be of use :)

#5201776 Average user packets per second

Posted by on 04 January 2015 - 12:21 PM

If you're trying to ensure that you don't flood clients with data, then it would be sensible to perform some dynamic throttling. Start with an estimate of what you might consider appropriate. When you start dropping packets, halve the estimated bandwidth, otherwise increase slowly by some constant value.

(Thanks to hplus0603 for this recommendation in a previous discussion)


I would also recommend only modifying this value (reduction or growth) after it can be confirmed that data has been received from the client since the last change was made (as there might be n packets dropped before the client receives data at a reduced rate from the server due to the packet loss, so you would actually reduce the bandwidth by 2^n if you did not take this into account).

#5159483 game's protocol between client/server

Posted by on 10 June 2014 - 06:22 AM

Typically, it won't matter what the contents of the message are when you need to handle where it goes. Usually, you might prefix the message with an identifier (type) that can be used to select the appropriate recipient. The contents are then managed by the requesting handler.


If you're using JSON, everything is serialised/deserialised in one go, so this is less explicit in practice, but you can still simply define the message to include a type field, and the rest is up to the sender.


That way, you check the type field and dispatch to the recipient as needed. Creating a generic message that does everything every message might need is both a waste of bandwidth and development time.

#5155768 Variance Shadow Mapping Shadow Brightness Issue

Posted by on 24 May 2014 - 07:49 PM

Whilst I have little immediate experience on the subject, we had VSM shadows implemented recently, and a similar effect was observed.
The developer who implemented speculated (in passing) that the intensity of the light source was influencing the shadow


#5155757 Timestamping & processing inputs

Posted by on 24 May 2014 - 06:15 PM

As long as the buffer has reasonable bounds, dropping any extra inputs which exceed the maximum buffer length will prevent the client from feeling lagged, instead they will notice server correction. This case will only occur if you send an excessive number of inputs, so you have to tune your upper bound for your buffer to consider the tradeoff between command latency and connection quality. 


Best ensure that you start sending inputs at a consistent rate though, don't try and account for the time spend loading for the map - that time is "dead time", meaning that user-input wasn't useful or valid during this time.

#5155707 Packet combining

Posted by on 24 May 2014 - 01:08 PM

There are many different ways of handling your packets. I tend to define a header as the size of the packet contents, then its protocol. That is it. This helps avoid errors within a single packet from causing off-by-n errors elsewhere. So an entity update packet might involve sending the number of repeated entities, then packing their data, and appending the header to that packet. 

#5153321 Perfectionism and Programmer's Block

Posted by on 13 May 2014 - 09:12 AM

I think that there is merit in thinking very carefully about what you do before you do it, just to stress this point. However, it is true that you cannot foresee what you will eventually ask of your code, so the most important thing is to keep to good design principles. It becomes structurally much easier to later modify the flow of execution if everything is nicely encapsulated, and even change implementation details.


But best choose one or the other. Either spend an inordinate amount of time planning and thinking before writing anything, or do the basic ground work, and get started - and quickly identify what might need to be changed. That way you make the best use of your time :)

#5148946 Your most valuable debugging techniques for Networked games?

Posted by on 23 April 2014 - 06:58 AM

Unit tests are a god send!


I've never been exposed to their necessity in a production environment, but now I don't think that I will need that experience to encourage me to use them. If you can't write a unit test for it, it probably needs refactoring!


Most network errors are caused by misreading data from the byte stream (off by-n errors).I always check the data coming in. However, recently I had an error in some reading code which caused an off by one error. The best thing to do in those circumstances (my error only arose after data was already sent) is to break the simulation into three different states and compare the transition between them (whenever my variable was set to None, it remained considered as a None value (Which isn't included in the byte stream) hence we forgot to read an extra byte from later packets! I had to break it down to fix it.


Having an inspector in game is really useful, (assuming you're a runtime interpreted language) even a GUI with a command input dialogue is all you'd need (as long as you can prevent the game state from progressing)

#5148423 Can a non-programmer make games?

Posted by on 20 April 2014 - 05:18 PM

Simple answer, no. More complex answer, yes:


A game is really an abstract concept, many things can be considered "a game". A game involves creating an experience, and that is a broad field. Anyone can create a game by this logic. What you're really asking is, can someone without programming knowledge create a playable game with existing tools, and the answer to that is yes. Programming itself is often a case of learning about logical thinking - maintaining an understanding of how your code translates into the user's experience, and how your systems work with one another, and any potential APIs. As a programmer, one doesn't possess any ability a "non" programmer does not, they have merely developed the line of logical analysis further, to enable them to express their thoughts in another language, on another architecture.


For example, I specialise in Python, but I have a good grasp of many other languages. After learning how programming necessitates a certain mindset and adopting it, it was far easier to learn new languages, and even the difference between typing, interpreting and additional language capabilities did not prove to be too challenging to grasp, given the initial toolset that I had learned.


You will need to program in order to develop a game. A game requires some form of interactive experience, and interactive experiences need to be designed. However, programming is a diverse and loosely defined concept, and there are many restricted and abstracted programming environments which enable you to write "code" through a more visual approach.


Such examples include Blender Game Engine's logic bricks and Hive nodes (which are currently quite young in implementation), Unity PlayMaker and UScript, UDK's Blueprints / Kismet, the list goes on.


Ultimately these translate, like programming languages, into machine code,the difference is the semantics. With all of these systems, there comes a price. Typically, more complicated programs either do not translate into visual languages, or they do so poorly. It may be  that on occasion, you require someone else to implement logic into a visual logic editor for you (e.g writing a new node), which limits you as the developer. 


My advice would be to understand to adopt the programmer's mindset, even if you don't intend to write complex programs any time soon.


I wish you the best!


#5148211 Entity Interpolation

Posted by on 19 April 2014 - 01:31 PM

You might want to split it into more functions, so it can be easier maintained and checked for errors:

function interpolateClientState(stateA, stateB, interpolationFactor)
	// Interpolate between the two states
	var interpolatedPosition = previousSnapshot.position.lerp(nextSnapshot.position, interpolationFactor);

	// Create interpolated state
	State interpolatedState;

	// Set the position from the state
	interpolatedState.position = interpolatedPosition;
	return interpolatedState;

function applyState(state, actor)
	// ...

function updateRemoteClients() {
	var currentTime = new Date().getTime();
	var renderLatency = 400;
	var delayedTime = currentTime - renderLatency;

	// loop over all our remote clients and find the interpolated position to draw them at
	for (var c in remoteClients) {
		var actor = remoteClients[c];
		for (var i = 0; i < actor.snapshots.length; i++) {
			// make sure we don't go out of bounds with our checks
			if (!(i + 1 < actor.snapshots.length))
			// Get snapshots
			previousSnapshot = actor.snapshots[i];
			nextSnapshot = actor.snapshots[i + 1];
			// Get timestamps
			var previousTimestamp = previousSnapshot.timestamp;
			var nextTimestamp = nextSnapshot.timestamp;

			//  Determine if we straddle the delayed timestamp
			if (!(previousTimestamp < delayedTime) or !(nextTimestamp > delayedTime))
			// Calculate the factor (0.0 <= factor <= 1.0) to interpolate by
			var interpolationFactor = (delayedTime - previousTimestamp) / (nextTimestamp - previousTimestamp);
			// Get new state
			var interpolatedState = interpolateClientState(previousSnapshot, nextSnapshot, interpolationFactor);
			// Apply new state
			applyState(interpolatedState, actor);

Be aware this is psuedocode (I can't remember all the Javascript object creation information).