Jump to content
  • Advertisement
Sign in to follow this  
Telanor

Network input handling

This topic is 2065 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

I'm trying to wrap my head around how to map input into network commands to be sent to the server in an extensible way. Right now, the way input is handled locally is the input is polled every frame and systems interested in handling input can then check the state of a particular action. At startup, an XML file is loaded that maps keys to actions. Currently actions are referred to using strings since I couldn't really see a more mod-friendly way of creating new actions.

The problem is, how should I send the networked-related actions out to the server? The simple solution is to just let each input-handling system say "if IsHeld(action) then NetMessage.send(action)" but that's going to send a bunch of separate packets. I'm not a networking expert but that's probably a bad idea, right? I'm looking for a better idea that allows me to send the changed state of relevant actions across the network in 1 go.

I'm also wondering how to handle the commands on the other end. I'm trying to keep as much overlap as possible between client and server code. It's obviously not possible for everything but I think the input handling could be set up in a way that it doesn't matter if the command came in locally or is being handled on the server. This is also why I want to find a higher-level way of sending out actions to the server. If it's done in the input-handling of the system, I can't reuse that same code on the server.

Share this post


Link to post
Share on other sites
Advertisement
I would say that the input handling code is different -- read from keyboard, vs read from network -- but the simulation code is the same. The simulation code just needs to know what actions/triggers are active each time step, not where they came from.

I would assign a small integer ID to each action, so that talking about actions over the network would be cheaper than sending a string. If you have less than 30 actions and they are all binary (on/off) you can even get good efficiency by just sending all actions as a bitmask, assigning them each an id from 0 through (N-1) and using the smallest integer that will fit all the actions. The client and the server then have to agree on the XML file that maps action names to integers, or that mapping has to be dynamically established during session open. (Much easier to make sure they just use the same XML file :-)

Share this post


Link to post
Share on other sites
So you're suggesting I separate the client and server HandleInput methods? I dunno, somehow, having to separate them doesn't sit well with me. I feel like it shouldn't be too hard to abstract the input state enough so that it the handling code can be the same for both client and server.

As for assigning an ID to the actions, I suppose that will work, but I won't know how many actions there will be, since mods can add new ones. I'll have to make it load all the network related ones from the server, since any changes to the mods can change the ID mapping.

Share this post


Link to post
Share on other sites
I would suggest that there is no problem here.
Firstly, let's unify the term "event". Each client may handle input with different keys mapped to each event. Therefore, it is best to have an event defined independently of the keys that triggered it. The client and server can use this definition of Event for all simulation systems. We therefore need to manage where the event comes from. This is simple. Both client and server user classes call a "get_input" event. For the client, this polls the keyboard and parses it into an Event class instance, whereas the server does the same but parsing from the network packet.

This seems akin to your suggestion. In the case of Hplus's suggestion, that would make sense for I believe he means the same as you and I have suggested.

Share this post


Link to post
Share on other sites
Right now I have an InputState class which is constructed each frame with the current/previous mouse/keyboard state by the input manager and then sent out to the various systems. The systems can call IsHeld or IsTriggered to find out about the current state of an action (or event as you call it). I'm starting to think I should make an interface and then have 2 different InputState classes, one that is constructed from the mouse/keyboard state and another that is constructed from the net state. The only issue is that this InputState class also provides access to the raw input state for things that can't really be described in terms of the actions I have set up. Like rotating the screen based on the relative mouse movement. Any ideas for this?

Share this post


Link to post
Share on other sites
I don't think I say so explicitly in the article, but one of the motivations for this piece was actually to solve this exact problem.

If you follow the general architecture I described there, rigging up different "sources" of input becomes trivial. You can source from keyboards, mice, joysticks, network messages, telepathy... you name it.

Share this post


Link to post
Share on other sites

So you're suggesting I separate the client and server HandleInput methods?


That depends on what they do! If they handle input type tasks, such as "read keyboard for input," then yes, that's the right seam.
If they actually processes simulation based on inputs that are read somewhere else, then no, that's the part that should be the same!
So I think we're saying the same thing. Reading keyboard vs receiving data from network is different. Updating simulation based on "cooked" input data (events) should be the same.

Share this post


Link to post
Share on other sites
The HandleInput methods in my classes do indeed process simulation based on inputs read elsewhere. I've made some progress with this. I took the idea of ranges from Apoch's code so I could abstract the mouse X/Y/WheelDelta. I was able to remove public access to the input once I did that.

Now it's just a matter of finding a way to send the relevant actions to the server so it can construct an InputState based off that. Right now my current thought on this is to create a kind of RegisterAction method in the input manager where various systems can inform the input manager about the actions they'll be looking for and, the important part, whether or not its a network related action or not. Then I can just have the input manager check the state of the actions and send out a packet containing any that have changed state. Hopefully that'll work out

Share this post


Link to post
Share on other sites
Ok, that seems to be working pretty well. The input is being automatically packed up and sent to the server. Next step is to actually feed it to the various systems, but that should be easy. The one thing I was wondering about though is if I should limit the rate input is sent to the server. Its not much of an issue with keyboard input but moving the mouse around (to rotate your character) will pretty much result in a constant stream of input messages being sent as fast as the input can be read. Is that something I should bother with or is it ok to leave it as is?

Share this post


Link to post
Share on other sites
Rate limiting network traffic is always a good idea. For instance, you could have the client accumulate transmitted input a fixed 30 times a second and send that instead of spamming the server at whatever framerate the game happens to hit.

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.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!