Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Farkon

Member Since 17 Sep 2011
Offline Last Active Jun 08 2014 10:49 AM

Topics I've Started

Timestamping & processing inputs

23 May 2014 - 03:24 AM

Hello,

 

I'm sorry to make yet another thread about this, but i've been confused reading the threads about processing inputs.

 

What i've been doing until now is : clients send inputs, server is calling process(input) as soon as it receives them, which means processing several netframes per server frame. It works well for my simple physics, it's deterministic.. but it's obviously vulnerable to speedhack.

 

So i was looking at another way, here is what i'm doing.

 

Client has its own frame ID and send its inputs with the frame ID to the server.

The server is caching each message by (client) frame ID.

(The server sets the first client frame ID via the first client message received (client ID))

From there the server increments each client ID according to its (the server) steps.

The server sets client inputs getting them from the buffer, if there is no frame, just skip it.

 

Using a dejitter buffer it works well but i'm not convinced that's how i should do it; here are my questions :

 

  • Here the latency is set by the first message received, how do i initialize my timestamps?
    • What happens if the client is suddenly lagging and the server ends up skipping all the received frames ? Do you adjust this in realtime?
    • In my game the server is sending the map & a player creation event all at once. I'm using a fixed timestep but what happens is that when the client is receiving the map and processing it, it takes around 1 second & in the same frame sends the first inputs. Next frame the fixed loop makes his job and tries to catch up from the lag introduced in the previous loop, so i end up sending X events to compensate for something the server isn't aware of which introduces a big amount of lag in the game.
  • Still related to time, what happens if the client or the server goes out of the fixed loop aka by being prevented to enter the spiral of death?

Processing inputs right away

04 February 2013 - 09:58 AM

Hello,

 

I was reading some Carmack updates about the QuakeWorld development here : http://fabiensanglard.net/quakeSource/johnc-log.aug.htm

 

And that part made me think about how to process inputs :

 

Instead of expecting everyone's messages to be dealt with at once, I now
deal with each packet as it comes in. That player alone is moved forward
in time, and a custom response is sent out in very short order. The rest
of the objects in the world are spread out between the incoming packets.
There are a lot of issues that that brings up. Time is no longer advancing
uniformly for all objects in the world, which can cause a lot of problems.

It works, though! The average time from a packet ariving at the system to
the time a response is sent back is down to under 4ms, as opposed to over
50 with the old dedicated servers. 

 

In my projects I usually have a big server loop, processing all the received messages and sending back "independently" the server updates to all the players.

 

It works but indeed, as he said, it adds some latency if you process the messages at 30 or 60fps but I always just dealed with it; now i'm wondering how you handle cheat with this kind of architecture.

 

The issue being cheaters trying to speedhack by just sending packets at a different expected rate. Do you average the number of packets received from the client and try to consume them at an arbitrary rate ?

 

Is it a good route to take ? Any drawback ?


T-Machine Entity Systems : Events, Parent/Child, Networking

16 November 2012 - 11:36 AM

After an extensive reading of the T-Machine articles about entity/components design i've decided to move part of my code to that.

It's *working* right now but i still have some questions :

Networking :

Not really a problem here but i'm still wondering if i'm doing it "right", I'm currently having a NetworkSystem which is filling components with network datas and then other systems will do their job. Basically my filling-datas pattern looks like that :

*New data is arriving with item ID*
allNetEntities = getAllEntitiesPossessingComponent(CNet);
for netEntity in allNetEntities {
	net = getComponent(netEntity, CNet)
	if net.id == itemID {
		pos = getComponent(netEntity, CPosition)
		pos.x = itemX
		pos.y = itemY
	}
}

I'm not into performances optimizations yet but it's a bit ugly, i guess the way to go would be add a NetworkSystem method like addNetEntity(entity, ID) populating a collection of some sort and then getting the item through that list. It seems totally logical but i'm mainly trying to see if i'm going to hit a wall of anti-e/s patterns at some point.

Events :

I'm not comfortable with using an event system here and i don't really know how to handle that myself.

Let's say i'm having a CHealthBar component which contains hp datas and i want to add a little animation when a player is losing health.
An idea that come to mind is just to update that hp data and let the system throws an animation when it detects that newHp < oldHp but it means that the system will always check for that condition. Again it looks like premature optimization but i'm more looking for nice habits.
Another idea would be to play with components which might be a bit more elegant : If the client is receiving new hp data he could update the CHealthBar component and adding a new CNewHp component, which will be handled by the HealthBarSystem and then removed. i'm still having that constant check to do in my loop though.

HealthBar parent/child:

Still with that HealthBar i'm wondering how you attach entities together. That's what i'm doing right now.

[source lang="jscript"]// Playervar playerSprite = DrawableSystem.getBitmapFromFile("player_healer_walking1");var player = this.game.em.createEntity();this.game.em.addComponent(player, new CPosition(netx, nety));this.game.em.addComponent(player, new CNet(id, netx, nety));var pdrawable = this.game.em.addComponent(player, new CDrawable(playerSprite, this.game));// Healthbarvar barSprite = new Bar(0x6CF048, 50, 8);var healthbar = this.game.em.createEntity();this.game.em.addComponent(healthbar, new CHealthBar(player)); // Reference to parent player entitythis.game.em.addComponent(healthbar, new CDrawable(barSprite, pdrawable.sprite));this.game.em.addComponent(healthbar, new CPosition(-25, -40));[/source]

Graphically : Right now my CDrawable takes two arguments, the sprite object and the parent sprite object. Here i don't really respect the rule of data-only components since the constructor is actually doing parent.addChild(child), that's an exception I made and i'm not really proud of it since i will eventually need a method to remove that component from the screen; I used to do that differently by just calling drawableSystem.addOnScreen(component), is that better ?

Events/Graphic datas : Since i don't really know how to handle events i'm a bit stuck on where to put initialization code. In the snippet above i'm writing new Bar() and passing it to my CDrawable component but Adam (from T-Machine) doesn't seem to talk about sad and lonely classes going around your code. I want to put that in the component constructor since it doesn't contain any logic code and is actually *datas* even if i'm initializing stuff in it but i'm not sure about that. Or it could be a method in the system but would need to be abstracted IMO.

Relationship : When the client is receiving new hp datas i need to update that component. I'm having an ID for each player so i need to reach that hp entity starting from the player entity. In my example above the player component doesn't know about the hp component whereas the hp component does know who's its owner, it works, but it's a bit weird to update that hp component.

Pseudo-code :
allHpComponents = getComponents(CHealthBar)

for hpComponent in allHpComponents {
	id = getComponentFromEntity(hpComponent.parent, CNet)
	if id == netId {
		hpComponent.hp = newHp
	}
}

I'm having the same kind of code than my network one, the only workaround i can see is to have another component called CHealthBarEntity added to the player entity and redirecting to the healthBar entity, how dirty does that look ?

Data size & circular sequences

17 February 2012 - 08:22 AM

Hello,

Below is how my datas are packed :



[UDP HEADER][SEQ][ACKED_SEQ][TYPE][LENGTH][BITMASK][X][Y]
  28bytes    int    int     1byte  1byte    1byte   b  b

I'm trying to find how much players can fit in a 50kb/s upload connection.

header_size = 28 + 8
msg_size = 5
players = 15
netfps = 30

packet_size = header_size + players * msg_size
outgoing_size = packet_size * players
bandwidth_needed = outgoing_size * netfps
>> 49 950 for 15 players

First question, is my math ok ?

Also, i'm using 4bytes for my sequences, I could use 1 byte if i say that after 255 it goes back to 0. Of course it's problematic since i'm discarding too old packets based on that sequence but i could build something really ugly on top of it and maybe totally unsafe. Is that something which has already been done in those situations ? Are there some algorithms for it ? How stupid is that idea ?
I can almost answer the last question in my situation since reducing the header_size from 36 to 30 let me accept half a player more. I guess it could matter at larger players scale but not here.

Can i be more compact than what i'm doing ? I'm voluntary ignoring variable netfps, hidden players...
I could remove the length field since i know how much size my properties have, but that's all. With this and my weird new 2bytes msg header i'm now at 17 players. Knowing that it's not even true in real game experience since i'm having projectiles which counts as much as a player in a stress situation.

And by curiosity, how much bandwidth i could get for a dedicated server at ~40$/m ? (not VPS)

Client frames digestion

02 February 2012 - 11:27 AM

Hello !

I just coded a bot to simulate players on my game; while setting some wild fps for him i noticed that my netcode might not be built like it should.

At 120fps the bot moved twice faster and that for a simple reason, my physics server-side is set for a client with 60fps, now the real issue is that the server is actually eating everything it receives : The server have a physics tick of 60fps and a net tick of 30fps (but only for output). What arrives from clients to the server is directly dispatched hence the problem when too much data arrives. So i'm having two thought :

* Either i calculate dt for the player server-side depending on how fast i receive the frames and digest every frame with an appropriate dt
* Either i actually limit the rate at what i'm reading the frames from the client using the existing net tick. It sounds more appropriate but then i'll have a queue and i'm not sure how to handle that. What if the server is slowing down ? The queue will grow and add some latency.
* Or something else :3

Thanks.

PARTNERS