• Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By akshayMore
      Hello,
      I am trying to make a GeometryUtil class that has methods to draw point,line ,polygon etc. I am trying to make a method to draw circle.  
      There are many ways to draw a circle.  I have found two ways, 
      The one way:
      public static void drawBresenhamCircle(PolygonSpriteBatch batch, int centerX, int centerY, int radius, ColorRGBA color) { int x = 0, y = radius; int d = 3 - 2 * radius; while (y >= x) { drawCirclePoints(batch, centerX, centerY, x, y, color); if (d <= 0) { d = d + 4 * x + 6; } else { y--; d = d + 4 * (x - y) + 10; } x++; //drawCirclePoints(batch,centerX,centerY,x,y,color); } } private static void drawCirclePoints(PolygonSpriteBatch batch, int centerX, int centerY, int x, int y, ColorRGBA color) { drawPoint(batch, centerX + x, centerY + y, color); drawPoint(batch, centerX - x, centerY + y, color); drawPoint(batch, centerX + x, centerY - y, color); drawPoint(batch, centerX - x, centerY - y, color); drawPoint(batch, centerX + y, centerY + x, color); drawPoint(batch, centerX - y, centerY + x, color); drawPoint(batch, centerX + y, centerY - x, color); drawPoint(batch, centerX - y, centerY - x, color); } The other way:
      public static void drawCircle(PolygonSpriteBatch target, Vector2 center, float radius, int lineWidth, int segments, int tintColorR, int tintColorG, int tintColorB, int tintColorA) { Vector2[] vertices = new Vector2[segments]; double increment = Math.PI * 2.0 / segments; double theta = 0.0; for (int i = 0; i < segments; i++) { vertices[i] = new Vector2((float) Math.cos(theta) * radius + center.x, (float) Math.sin(theta) * radius + center.y); theta += increment; } drawPolygon(target, vertices, lineWidth, segments, tintColorR, tintColorG, tintColorB, tintColorA); } In the render loop:
      polygonSpriteBatch.begin(); Bitmap.drawBresenhamCircle(polygonSpriteBatch,500,300,200,ColorRGBA.Blue); Bitmap.drawCircle(polygonSpriteBatch,new Vector2(500,300),200,5,50,255,0,0,255); polygonSpriteBatch.end(); I am trying to choose one of them. So I thought that I should go with the one that does not involve heavy calculations and is efficient and faster.  It is said that the use of floating point numbers , trigonometric operations etc. slows down things a bit.  What do you think would be the best method to use?  When I compared the code by observing the time taken by the flow from start of the method to the end, it shows that the second one is faster. (I think I am doing something wrong here ).
      Please help!  
      Thank you.  
    • By ethancodes
      I'm working on an endless wave-based arkanoid/space invaders style hybrid. Bricks spawn above the screen and move down line by line. You must destroy all bricks before they hit the bottom of the screen. There will be multiple types of bricks and random power-up spawns. Currently I am just using a simple Log function that takes in the current wave as a parameter. This works to increase the number of bricks spawned each wave, but I want to find a way to make this much more complicated. Here is a list of everything that should be effected by the increase in difficulty:
      1. Number of bricks
      2. Types of bricks (1 hit bricks, 2 hit bricks, 3 hit bricks, etc.) 
      3. Speed that the bricks move down the screen
      4. How often power-ups spawn
      The biggest problem here is that I can't just increase all of these with each new wave. If I did that, it would quickly become far to difficult. What I would like is an algorithm that gives some amount of variance in the increase between all 4 of these. Say one wave we put 60% of the increase to number of bricks, 20% increase to power-up spawns, 10% to types of bricks and 10% to speed of bricks. But on the next wave those percentages are all moved around and we now have say 105% to work with so the overall difficulty has increased as well. The different types of bricks need to also change to the point where if someone has made it to a certain wave, such as wave 50 for example, there are no longer any 1 hit bricks. We now would have just 2-4 hit bricks, and if they are crazy good and make it all the way to round 100, Now it's just 3-5 hit bricks, etc. 
      If anybody has any good ideas or suggestions on this, I'd appreciate anything you've got! Thanks!
    • By fazook
      Hi, guys!
      I have a rather abstract question, because I don't know which side to approach to its solution. So, I would appreciate any information.
      I have a task to create a simple game that generates floor plans and I following by this perfect algorithm (https://www.hindawi.com/journals/ijcgt/2010/624817/). At the moment I use squarified treemaps (http://www.win.tue.nl/~vanwijk/stm.pdf) and here no problems. I create nested array in which elements are rooms with size. Problems starts when I trying to represent generated "rooms" as edges and vertexes (a, b, c, d steps in attached picture) That representation can give me access to this elements as special "entities" in future game versions.
      I don't have skills in graphs (and do I need graphs?) and at the moment totally stucked at this step. How can I represent room walls as trees (or graphs?) at this step? Calculate size of squares (rooms) and convert sides to a vectors? Then in loop find shared vectors (same position by "x" or "y") and determine them as shared walls? The instinct tells me that there exist more elegant and efficient ways.
      Anyway, thanks for any information about this.

    • By Januario
      Hey guys!,
      So, I'm basically working on an explorer right now.
      It should, as the name suggests, explore the entire thing, the most efficient way possible.
      Your character has vision around you, of, 10x10. The map is much bigger, 100x100. However, it can't just go straight from a corner to another, because: The tiles can be an occupied, or un-occupied one. You can add weights to the tiles, so feel free to use this in your advantage (let's say, adding an extra weight to a visited tile so you can compare visited against non-visited ones). You can use the Pathfinder I'm using, based on the A* algorithm. So, I could be wrong, but by basic logic, I assumed that the "fastest way" to explore the entire thing, is answering the question "What is the nearest tile that I can walk in, that is not occupied and that can reveal as much fog-of-war (unvisited tile) as possible?"...
      My questions are:
      1) Is my question correct? is that really the best way to explore the entire map? 2) If so, what's the best way to know "which is the tile that could reveal the most fog of war"? Once I get the tile that reveals the most fog of war possible, then I just throw the pathfinder to it.
      But I'm having problems doing a good way to achieve that :'( 
      I hope you guys can help me on this one! 
      Thank you
  • Advertisement
  • Advertisement

Server state synchronization and input handling

Recommended Posts

Hello Game Dev! Sorry if I'm beating a dead horse with this thread, but I'm making a fast paced action networked game, and I'm having trouble wrapping my head around some things. Namely, how should the server handle ticking player input packets that arrive at the server at an incorrect simulation steps, as a result of network lag, lag jitter, and inevitably imperfect time synchronization algorithms. I'll start by outlining my understandings, and I would be eternally grateful to anyone who can shed some light on what I'm missing.

For the sake of simplicity, I'm assuming the client has synchronized to the server's clock in some respect, and bundles a "suggested simulation step" that the input ought to be executed on by the server.

I've read a few threads here, and a lot of the documentation that exists out there. As far as I can tell, there are 2 main methods to rectify inputs arriving at the server at incorrect times:

method 1. allow the server to rewind time and re simulate the game for late arriving input packets. This would allow late inputs to still have a chance of being simulated. The server would only allow rewinding to some maximum amount of time, to help curb cheating, and undesirably large jumps in the simulation for other players.

method 2. synchronize the client's clock forward of the server's clock by half of round trip time (RTT/2), plus some constant (c) to account for jitter in lag. So in total, (RTT/2) + c. Then, when the input arrives at the server, it arrives on time most of the time. If the input arrives earlier than it needs to, it can be buffered at the server until the appropriate simulation step to execute the input.

As far as I can tell, method 1 has the benefit of minimizing any sort of input buffering for players with good pings, but is a very heavy handed solution, and might cause frequent jumps in a given client's simulation. Method 2 seems to be a nice simple solution, would provide nice smooth simulation, but introduces a sizable lag for a given player's input to be seen by other players.

I suppose I have 3 main questions on this topic, and I would be a very happy boy if I could get some help on them:

1. Is method 1 a widely used approach? It seems like it introduces a massive amount of work, as a result of the server and clients having to correct their simulation state, all the while introducing potentially jittery movement.

2. I get that method 2 can buffer early input packets, but how does it account for late arriving input packets? I get that the server should acknowledge the late input packet in some way to let the client know it should adjust its simulation time, but would it drop that late arrived input? would it execute it, but at the CURRENT frame? What if there are 2 or more late inputs?

3. Am I missing any other solution? Are these 2 methods the widely used methods for handling state and input on the server? I can imagine a combination solution of method 1 and method 2, is this advisable?

 

Thanks in advance for all of your time! I feel very stuck on this, and will send all the karma your way for any help. In the mean time, I'll keep reading forum posts, to see if this has come up before.

 

*edit* wording.

 

Edited by Nantuk

Share this post


Link to post
Share on other sites
Advertisement

The methods are not mutually exclusive.

In fact, the "source networking model" is a little bit of both.

For an approach that uses entirely method 1, look at "GGPO" which is a networking library for fighting games. Because fighting simulation is typically cheap, rewinding and replaying simulation is not a big deal in that context.

In method 2, you would add slightly more than just RTT/2 to the buffer time, so that packets generally don't arrive late. When packets arrive late, you simply discard them. If you assume that the player will do whatever they did last tick (if moving forward, keep moving forward, and so forth,) then you will guess right-ish enough.

When packets are lost you will of course have to correct the player whose packets were lost. This may cause snapping on their screen, the magnitude of which depends on the time duration between loss and correction. If your simulation is not 100% deterministic, you will likely want to correct all clients on some regular schedule anyway, because otherwise they will drift out of sync over time.

 

 

Share this post


Link to post
Share on other sites

Thanks for the reply, this helps a lot. I think the simulation is pretty close to 100% deterministic, but I will for sure regularly correct player movement. I think to do otherwise would be asking for de-syncing trouble.

Discarding old packets in method 2 makes sense, and assuming the last input is sustained for the future also makes sense.

I was not aware that Valve's Source Engine did rewinding for late arriving input on the server (method 1). I have read that it does a sort of rewind in order to see if a player's ray-cast bullet hit anything (outlined in link1, and link 2), but nothing on the topic of the server rewinding the entire simulation for something like a player's movement input. I know the client basically does this, for locally predicting the input, but should the server? I really want to clarify this, because before I go implementing a globally rewindable server, I want to ensure it is a good strategy to do so. I see that GGPO does this, but it would typically be between 2 players. I plan on supporting upwards of 16-32 player. In your opinion, is allowing the server to rewind to account for late movement input packets generally recommendable?

Share this post


Link to post
Share on other sites

You are correct, Source does not rewind the entire simulation. It only rewinds for hit tests. The point of my answer was that you can mix and match the different approaches, until you get a solution that matches your particular game. And, because each game has different gameplay requirements, there can't be a one-size-fits-all solution to this problem.

For 32 players, I would not use rewinding on the server. In general, I prefer to never rewind on the server, and instead discard late inputs, but it does depend on what kind of feel (and what kind of simulation cost) your game has.

Share this post


Link to post
Share on other sites

Thats fair, I guess it really depends on the game. Its probably time for me to jump feet first in and see what is best for me. I'll start with the simulating the client ahead of the server method, and build off of that. Thanks for all your help!

Share this post


Link to post
Share on other sites

Let me elaborate on how Quake 3 and Source networking do this which I think will clear up a few things for you:

 

The server sends snapshots of the world state to clients at 20 Hz. These snapshots are timestamped with the server time.

 

Once the client receives two of these snapshots, they initialize their time clock to the timestamp of the first snapshot and then run this clock forward each frame. The client then renders the world each frame as an interpolation between the first snapshot and the second snapshot. In an ideal scenario, the client will receive a third snapshot at the exact moment they've reached the timestamp of snapshot 2 and so on. Because snapshots are sent at 20 Hz, it means that the client time is typically 50ms + RTT/2 behind the server at any given time.

 

To keep the clock synchronized, the client clock is adjusted each time a new snapshot is received from the server. If the client hadn't yet finished interpolating to the next snapshot, the clock is bumped forward because the client is probably behind. If the client had already finished interpolating to the next snapshot and had begun extrapolating, the clock is nudged back because the client is probably ahead. If you're looking at the Quake 3 source code, this is the CL_AdjustTimeDelta function.

 

When clients send input to the server, they timestamp them with their clock so that the server can tell where they were in their snapshot interpolation and therefore what the state of the world was, as they saw it, when their input was entered. If the server stores a history of the snapshots they send out, then this timestamp can be used to rewind the state of the server for checking things like bullet traces. However, for general movement and gameplay the server usually does not rewind time. In these cases, the timestamp of the input is subtracted from the last input that was received on the server and this delta time is used to advance the player.

 

highly suggest you download the Quake 3 source code and get it running. It's an invaluable learning tool and is really quite an elegant implementation of the networking model.

Share this post


Link to post
Share on other sites

Thanks for all the info on Quake 3. That sounds like good advice, I should take a look at Quake 3 to see how they did what they did.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Advertisement