Jump to content
  • Advertisement
Sign in to follow this  
kangaroocow

Timers on buffs - server or client timer?

This topic is 3844 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Could anyone tell me how developers implement a buff system (typically MMOs) inside a game? Does the timer get started on the client from a command on the server? I'm assuming it's actually a lot of timers on the server as the games I've played, the timers still exist when you logout. I can't begin to think how complex this threadpool of timers must be?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by kangaroocow

I'm assuming it's actually a lot of timers on the server as the games I've played, the timers still exist when you logout. I can't begin to think how complex this threadpool of timers must be?


Thread pool likely isn't optimal choice for this type of timing. Aside from being innacurate, doing timing in separate threads makes it hard to synchronize events reliably.

In your game loop, you have something like this:
while (true) {
currentTime += step;
for (Timer t : timers) {
if (t.expired()) {
// trigger the timer, remove it, ....
}
}

// do the rest
};


The step will likely be some fixed value, not real time. When you store timer to database, rather than storing when it expires, you write how much is left (548 seconds).

When you load this into your server, you set timer's expiry time to currentTime + 548.

The client-side representation of timers for most of the MMOs are usually somewhat inaccurate (not timing in general). So when a timer is created, depending on how you simulate, you just notify that it exists, and when it expires. When it does expire, you just send that to client, confirming it really happened.

Structure that holds timers is also subject to whatever adaptation you need, perhaps a priority queue or some simpler or more complex structure. Depends on your needs.

The timer triggers may also be implemented in different ways. Perhaps as messages, if you have message oriented system.

In the end it all depends on your accuracy requirements.

Share this post


Link to post
Share on other sites
I was thinking more along the lines of sending 1000 (or more) messages to different clients when a buff has expired from the server. Multiply the maximum buffs by whatever you want your maximum to be, say 16, and you have to surely send these off to worker threads to dispatch each update?

So at busy times such as 6pm-10pm you might be sending off 10,000 timer expired messages to 500 different clients at once (per second). Combine that with "debuffs" too, and then network balance it too as one server might not handle that very well. It makes my mind boggle a bit, but I suppose it's just the same as an email server in many ways, but being UDP a lot less fussy about knowing the packet got to its destination.

I'm guessing the client keeps displaying the buff timer (stuck on 1 second) until it receives its kill command for that buff.

Share this post


Link to post
Share on other sites
I don't relly understand your question.
But implementation should be trivial. The client tells the server that it has buffed some player. The server sends a add buff event to all effected clients, those who can see the buffed player. The server then adds a buff object with an end time to some buff list, per player or per world, doesn't matter. Then for every tick it just loops trough it and checks if the timer has expired. If yes, remove it from the list and send a kill buff event to all clients affected, ie those who can see the player.
Clients not being present when the buff was added get the buff list with some new player event.

Share this post


Link to post
Share on other sites
Quote:
Original post by kangaroocow
I was thinking more along the lines of sending 1000 (or more) messages to different clients when a buff has expired from the server. Multiply the maximum buffs by whatever you want your maximum to be, say 16, and you have to surely send these off to worker threads to dispatch each update?


Sure, but those are just a small fraction of events you need to dispatch. This is where Massive comes from.

Worker threads have nothing to do with this. Especially for sending.

16000 events is somewhat rare. Let's say that typical encounter involves 16 entities (4 players, 12 NPCs). After you process your state for that particular time slice, you send all that has changed in single packet. For WoW-like MMOs, this is typically less than 1kB/sec. It really isn't that much data.

But all MMOs use aggressive area of interest management, so that each player knows only about what's going on some 50m around them. So even if 10,000 buff changes occur globally, each client only receives one message, stating that 5 buffs have changed on objects they know about.

Quote:
So at busy times such as 6pm-10pm you might be sending off 10,000 timer expired messages to 500 different clients at once (per second).


Yes, you could be. And something will have to give. Decrease timer tick on buffs, require higher bandwidth, use more servers....

No matter which system you use, there's a limit.

Realistically, it will likely be 10 buffs per second per client in some pvp or something, not 10,000.

For conventional MMOs, the maximum number of players that seems to work is 200 (visible to each other). Not saying it's hard limit, it just seems that gameplay modes are well beyond that.

Quote:
Combine that with "debuffs" too
This doesn't really change anything. Due to exponential complexity, doubling the number of messages has little effect on scalability.

Share this post


Link to post
Share on other sites
Quote:
Original post by kangaroocow
I was thinking more along the lines of sending 1000 (or more) messages to different clients when a buff has expired from the server. Multiply the maximum buffs by whatever you want your maximum to be, say 16, and you have to surely send these off to worker threads to dispatch each update?

So at busy times such as 6pm-10pm you might be sending off 10,000 timer expired messages to 500 different clients at once (per second). Combine that with "debuffs" too, and then network balance it too as one server might not handle that very well. It makes my mind boggle a bit, but I suppose it's just the same as an email server in many ways, but being UDP a lot less fussy about knowing the packet got to its destination.

I'm guessing the client keeps displaying the buff timer (stuck on 1 second) until it receives its kill command for that buff.


Compared to the network traffic that movement, combat, spellcasting etc etc consumes, buffs are a reasonably minor part :). And you'll likely have a dedicated network thread that handles all outgoing traffic, not a threadpool system.

Say an average buff lasts five minutes (averaging short-time debuffs and long-duration buffs). And the average number of observers of a given player is 10 (likely lower, but for arguments sake). That's 20 packets (one activate, one deactivate) every five minutes. Or just 10 if you just do the activate packets (assuming your buffs have server-side effects only, just let the client ditch them on its own once their timer has expired). Which, in the grand scheme of things, is very little.

Oh, and a good alternative to polling all the buffs serverside for expiration time is to register a callback with a dedicated timer class, which can then do sorting and other clever things to cut down on the per-frame time dealing with this.

Share this post


Link to post
Share on other sites
All clients, and the server, share a sense of "game time." This time proceeds mostly in sync, modulo whatever delays/jitter there may be.

When character A gets cast buff B on it at time C, and the buff lasts for D time, the easiest way to store this on the character is in a list of buffs per character, where you just store the tuple (A : C+D). Each client can then, when drawing or testing the character buff, test whether the current world time is > C+D, and if so, remove the buff from the list.

When you see a new character, the list of buffs is sent along with the character name, position, weapons etc. When a buff is cast on a character you're already seeing, a message is sent to add the buff to the list. The networking needed seems minimal to me.

Alternative implementations may store "time remaining" in the buff table, and decrement the time remaining value each cycle of the game. That requires a little more memory writes for changing the buff, but it makes it easier to save the buff duration when logging out. (Else logging out and back in needs to convert between "expires at time" and "time remaining" if you want the buff to persist). The implementation on the network is more or less the same, though.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!