Sign in to follow this  

Client giving orders problem (RTS)

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

Hello, Even if this is my first post, i enjoy reading this forum regularly. I'm actually writing a small RTS like game for myself, and i'm currently in a dead end. What my game currently do: - the game is a client/server application - i use client prediction and update with server datas when needed It works pretty well. The problem comes when a client gives an order which can't be predicted and *could* interract directly with another client. Example: both players [u]share[/u] the same primary ressource like money. Both players give the order 'build a big building ($500)' at the same time, but the shared ressource can only afford for 1. In this case, the client can't predict anything. Because if they build before the validation of the server, both players will build the building because they think they have enough money:
                             Client 1 | Client 2 | Server
t=0                              $500       $500     $500
t=1 (build with prediction)        $0         $0     $500 (error: both clients has built)
t=2 (order send to the server)     $0         $0    -$500
I've resolved this by waiting a validation from the server telling 'yes you can build'. That's why there's a slight delay (not noticeable) between the order given by the player, and the effective order taking effect on the screen:
                                Client 1 | Client 2 | Server
t=0                                 $500       $500     $500
t=1 (build without prediction)      $500       $500       $0 (clients wait validation)
t=2 (response from server)            $0         $0       $0 (ok: only one of the both client has built)
The real problem rises in the following case: The player can give a LOT of orders in 1 second! Example: He has 1000$, and buy 500 units costing 2$ each. For some internal rules i can't change, the only order available is 'Buy 1 unit (costing 2$)'. The order 'Buy 500 units (costing a total of 1000$)' can't be done (which could be a good solution). By giving 500 orders 'Buy 1 unit costing 2$' the game lags because at each order, the client waits the validation of the server. And i can't predict anything (like for the moves), because i can't rollback or correct the client if the server invalides the orders. I hope i'm enough clear :) Do you have any idea to solve this problem ? Thank you all, Pascal

Share this post


Link to post
Share on other sites
hi,

why do you want to share ressources?

if 2 players can play together you could implement something like:
if players belong to same group -> option to send a player in the group some of your ressources...

so the ressources CAN be shared but every group member owns its own...

you would not have the problem to send all the commands to the server and still can share ressources

i know that something like that could make the gameplay a bit slower but no other solution came to mind

Share this post


Link to post
Share on other sites
You have several possibilities:
  • Complete server authority. The client may do nothing without the server's approval. The client sends orders (build this here) to the server, and the server responds with the actual events (a building appears there). The client is mostly a glorified terminal with interpolation properties.

    This is slightly different from your current situation, is that you don't wait for confirmation. You send the orders and receive the effects (not confirmation) of your orders asynchronously.

  • Delayed server authority. The client keeps in memory the state of the world at time T, and, if the server doesn't send the diff to T+1 quickly, simulates times T+1, T+2, T+k according to the same rules as the server. Then, the server sends it the diff between times T and T+1, and the client drops everything except the state at time T+1, and resumes simulation.

    This eliminates lag (since the orders are reflected immediately, even if cancelled by the server), though it might be confusing if the network lags too much and too many things are rolled back.

  • Object taint. Like delayed server authority, except only "tainted" objects are send over network, rolled back and recomputed. "Taint" hits objects whose state was unpredictable because of client interaction, and spreads along interactions.

    More complex, but faster.

Share this post


Link to post
Share on other sites
You should try to explain further, since I too can't see the problem clearly.
In a regular RTS each player has their own resources and share these via a market or similar, but you already know this probably. =)

You could also do a different approach, i.e allow player to start a construction and then build it resource by resource. If a build costs 500 and two players begins building it - both players each end up with a half-finished building.
The constructing would, of course, continue when resources are available.

Another option would be that ALL communication goes through the server, i.e nothing gets built unless the server says its okay.

/Robert

Share this post


Link to post
Share on other sites
Quote:
Original post by Rasmadrak
In a regular RTS each player has their own resources and share these via a market or similar, but you already know this probably. =)


Starcraft has a mode where all players on a team control the same 'player' (one initial command center and builders, shared units, shared resource pools).

Share this post


Link to post
Share on other sites
Quote:
  • Complete server authority: [...]

  • This was my first implementation. But i had too much lag (Nethertheless, i wanted to try it).
    Quote:
  • Object taint. Like delayed server authority, except only "tainted" objects are send over network, rolled back and recomputed. "Taint" hits objects whose state was unpredictable because of client interaction, and spreads along interactions.

  • Actually, this is what i've done. But because lots of orders are sent simultaneously by each client and they do prediction before receiving server validation, there are too much rollbacks and it gives strange results on the screen (you build a building and it disappears 2 seconds later). So this kind of order aren't rollbackable and so unpredictable like you said (i can't take the assumption the order is validated by the server).

    Quote:
    You could also do a different approach, i.e allow player to start a construction and then build it resource by resource. If a build costs 500 and two players begins building it - both players each end up with a half-finished building.

    If i don't find any solution to my problem, i'll have to change the rules to minimize the number of orders given at the same time (1 order 'build 500 units' instead of 500 orders 'build 1 unit'). But it *will* give another type of game :/

    Quote:
    Another option would be that ALL communication goes through the server, i.e nothing gets built unless the server says its okay.

    This was my first implementation like i said above. This removes the rollbacks but add big lags.

    The 'best' solution i've found was to simulate client-side with prediction (for others stuffs) and wait for validation from server for unpredictable orders. But building lots of units takes now several seconds (build 1 unit->wait validation->build 1 unit->wait validation, ...500 times).

    I think that commercial RTS games resolve this kind of problem by minimizing the number of validations needed from the server and so decreasing waits (or rollbacks). In my case, this changes the rules. But before doing that (the last solution for me), i wanted to know if i'm missing something :)

    Quote:
    Starcraft has a mode where all players on a team control the same 'player' (one initial command center and builders, shared units, shared resource pools).

    Yes, this is exactly this situation.

    Thank you for your help,
    Pascal

    Share this post


    Link to post
    Share on other sites
    Quote:
    Original post by Kroah
    Actually, this is what i've done. But because lots of orders are sent simultaneously by each client and they do prediction before receiving server validation, there are too much rollbacks and it gives strange results on the screen (you build a building and it disappears 2 seconds later).


    Are there so many collisions? Ouch...

    Besides, you have to keep in mind that:
    • You must prove that your server and client are in sync. Subtle race conditions can and do occur when systems are not thoroughly proven to work.
    • You don't have to start simulating right away. If you're in a laggy environment, you can get away with lagging for a short time before starting simulation and players will just have to accept it. Alternately, you may just slow down simulation speed.


    Quote:
    (build 1 unit->wait validation->build 1 unit->wait validation, ...500 times).


    Why are you waiting for validation before building the next unit?


    Share this post


    Link to post
    Share on other sites
    Quote:
    Original post by ToohrVyk
    Quote:
    (build 1 unit->wait validation->build 1 unit->wait validation, ...500 times).


    Why are you waiting for validation before building the next unit?


    I understand this may look strange, like wanting building 500 units one by one. But this is a rule limitation.
    The game i'm programming is an adaptation of an old game (multiplayer on the same computer), and i try to be the most faithful possible (and multiplayer across internet). I've reverse engineered the game, and i want to keep the same algorithm than the original.

    In this game, the AI builds 1 unit by one in a kind of loop (simplified):
    - while money > $2
    - build unit
    - end-while


    But this money may be shared among several players playing simultaneously.

    I don't want to change the AI (it will change too much the behavior).

    So this same loop may be executed by more than 1 player, and here comes the problem if i don't wait the validation: the two players think they have enough money, but the other one has already used this money. So i add validation and sync, but this lag (lots of validations):
    - while
    - send server 'build unit' order
    - wait response
    - if OK, build unit locally (server has already built it)
    - if KO, break
    - end-while


    This works perfectly for 10 loops, but not for 500 loops... which may be 3000 near the end of the game.

    Quote:
    Are there so many collisions? Ouch...

    Yes, like you see above, all the AIs play simultaneously (up to 4 sharing money) which gives 4 loops of 500 build units using the same variable 'money'.

    Pascal

    Share this post


    Link to post
    Share on other sites
    I would suggest the variation:
    - while money > $2
    - send server 'build unit' order
    - pay money for the unit
    - add unit to build list
    - end-while


    Then, when you receive an OK, you move the unit from the build list to the real world as if it had been built earlier. When you receive a KO, you remove it from the build list and refund. If no response, you also remove it and refund.

    By sending so many "build unit" requests to the server, any compression algorithm running on your packets will reduce the payload to almost nothing (compared to 3000 orders), and the same for a returning "OK, OK, ... OK, KO, ... KO" sequence.

    Share this post


    Link to post
    Share on other sites
    You don't need to wait for OK before issuing the next command. Implement a pipeline. You already have the UI to tell the user he "can't do that."

    So, issue commands when the player issues them. On the server, perform commands when you receive them. If the command fails, send a message back to the player, saying that command X failed. In the UI, you will need an "intermediate" state, after a command has been issued, but before it's actually in process. This could be empty, or a shadow/ghost image, or whatever.

    Share this post


    Link to post
    Share on other sites
    It sounds to me like the real problem is that your time steps are 1 second long. If you want less lag, make the server verify commands as soon as possible, and don't wait one second.
    I'm guessing the 1 second time probably comes from the original game you're cloning, but you're applying it in places where it doesn't really make sense - your server should be constantly giving out information, even if new things only happen once a second. As soon as it gets a command, it should send the response so that it gets back to the client as soon as possible.

    Share this post


    Link to post
    Share on other sites
    Quote:
    Then, when you receive an OK, you move the unit from the build list to the real world as if it had been built earlier. When you receive a KO, you remove it from the build list and refund. If no response, you also remove it and refund.

    I can't to this because the AI is iterative. The AI must know whether or not the build order has been done to iterate the next line of the AI script.

    Quote:
    It sounds to me like the real problem is that your time steps are 1 second long. If you want less lag, make the server verify commands as soon as possible, and don't wait one second.

    I've never sets the timestep to 1s. The server handles the commands as soon as it receives them. The lag comes from the high number of little "buy unit" orders.



    Here's how i've done to resolve my problem (no magic solution):

    To sum up, the problem comes from 2 points:
    - high number of simple 'build unit' orders given by an iterative AI script
    - each order has an impact on a shared variable (the money) and of course the shared money has an impact on the orders

    The AI script loops around 1000 times to buy units, each loop waits for the server response to sync the shared money with other players.
    According to your responses and my research, there isn't any possibility to *considerably* speed up the process without changing pre-requisites.

    I've made the choice to remove the shared money. This hasn't a big impact on the game and I don't think i'll implement it in the future. Thus, i can now predict the AI script, without waiting the server:
    - while money > $2
    - build unit locally
    - send server 'build unit' order to sync other players simulation (but no rush)
    - don't wait response from server
    - end-while


    I've updated my code and it works great.

    Thank you all for your support,
    Pascal

    Share this post


    Link to post
    Share on other sites
    Why dont you request from the server, a 'cash advance'? If you need 500$ to build something, say, "I want to block 500$ to do my constructions. Can I?". Server says yes / no and tranfers fund in your personal account and the construction starts.

    a basic banking system, bank holds the pot of gold, and each player has an account to transfer funds back and forth if they need / cancel a build.

    Share this post


    Link to post
    Share on other sites
    Quote:
    Original post by Kroah
    Quote:
    Then, when you receive an OK, you move the unit from the build list to the real world as if it had been built earlier. When you receive a KO, you remove it from the build list and refund. If no response, you also remove it and refund.

    I can't to this because the AI is iterative. The AI must know whether or not the build order has been done to iterate the next line of the AI script.


    I think this is the essence of your problem.

    (I know you said you've worked around it, but I'd like to talk about it anyway.)

    1) You have many orders to run quickly and in sequence.
    2) Each order must be fully acknowledged before the next one starts, due to consistency issues.
    3) Your system must use networking, which places inherent significant latency on how quickly an order can fully complete.

    There's absolutely no way around this without removing or relaxing one of the constraints. Reducing the number of orders (eg. by batching them) would help. Splitting the AI up so that some operations can run in parallel would help. And reducing the overhead of the networking would help.

    If it was my game - and I appreciate that I say this without understanding the underlying game you're modelling - I'd look at reworking the AI so that it can make assumptions about the current state and backtrack if that assumptions later proves to be false, resuming from the last known good point. (I suppose this would work much like branch prediction in CPUs, tech fans.)

    Share this post


    Link to post
    Share on other sites
    If you had "too much lag" in a server authoritative model, then what was the source of lag? StarCraft, Warcraft III, Age of Empires, and a lot of other RTS games all use that model. Note that, if you're using TCP, you must turn on the TCP_NODELAY socket option on client and server to get low latency communications, perhaps the lag came from there?

    One kind of resource that is implicitly shared is land. Thus, if I want to build on square X, and you also want to build on square X, then only one of us will win, and there is NO WAY of knowing who won without a round-trip on the network. Design for that round-trip. This typically means pipelining, and being able to back-track if you get a NAK for some previously issued command -- or just "adapt and deal" if the operation is later shown to have failed.

    After all, if you start building in spot X, and it succeeds, but then an enemy flies in and shoots down the project that's underway, that's not much different than the project not being started at all. Hopefully your AI already knows how to deal with a case like this?

    Share this post


    Link to post
    Share on other sites
    Something that seems possible is batching requests and validations.
    An AI loop would be:

    while my side has money
    ask to build N units (as many as we can afford)
    receive permission from the server to allow me to build X units (X<=N); the server commits the resources to make X units to me
    for X times
    actually build a unit paid from my own funds (with appropriate exchanges with the server)

    The server can make smarter assignments of resources than enough/not enough verifications; for example, human players can get more resources and units than their allied AI players, or fairness between allies can be enforced.
    The player AI knows something new, the value of X and that construction won't be slowed or delayed because of resource shortage after the server commits resources to a batch of X units: both information items can with the planning of unit formations and future attack and build orders.

    Share this post


    Link to post
    Share on other sites
    Quote:
    Original post by Kylotan
    I think this is the essence of your problem.

    (I know you said you've worked around it, but I'd like to talk about it anyway.)

    1) You have many orders to run quickly and in sequence.
    2) Each order must be fully acknowledged before the next one starts, due to consistency issues.
    3) Your system must use networking, which places inherent significant latency on how quickly an order can fully complete.

    You've really well summed up the problem.

    Quote:
    Original post by Kylotan
    There's absolutely no way around this without removing or relaxing one of the constraints. Reducing the number of orders (eg. by batching them) would help. Splitting the AI up so that some operations can run in parallel would help. And reducing the overhead of the networking would help.

    You're right. After many thoughts, i've finally chosen to remove constraint 2). The original game wasn't using this much anyway.

    If, for any reason, i want to put this rule back, i'll use something like oliii said: a bank system, or why not an automated donation system like supreme commander (when stocks are full, give %amount, and check this each second).

    Quote:
    Original post by Kylotan
    If it was my game - and I appreciate that I say this without understanding the underlying game you're modelling - I'd look at reworking the AI so that it can make assumptions about the current state and backtrack if that assumptions later proves to be false, resuming from the last known good point. (I suppose this would work much like branch prediction in CPUs, tech fans.)

    I first thought for this solution, but the AI being the core of the game, i had to do soo many changes i wasn't able to check the consistency of the AI beside the original one. So i rollbacked my work and choosed another way (another constraint) having less impacts.

    Quote:
    Original post by hplus0603
    If you had "too much lag" in a server authoritative model, then what was the source of lag? StarCraft, Warcraft III, Age of Empires, and a lot of other RTS games all use that model.

    The high number of server calls (one for each build unit order) with client waiting for response was the source of the lag.

    Quote:
    Original post by hplus0603
    Note that, if you're using TCP, you must turn on the TCP_NODELAY socket option on client and server to get low latency communications, perhaps the lag came from there?

    The game is programmed in C#. The .Net TCP code is not very well optimized (read here, it's slow as hell). I've tried to enable/disable some features but had no improvements. C# uses SOAP to communicate, so i thought it was full xml. I've used 'Packet Sniffer .NET' [url]http://www.packet-sniffer.net/[/url] to trace the communication and see if i was sending in plain SOAP text or not. But .Net serialization was already sending it in binary because the client is in C# too. The bandwidth wasn't highly used either.

    Quote:
    Original post by hplus0603
    One kind of resource that is implicitly shared is land. Thus, if I want to build on square X, and you also want to build on square X, then only one of us will win, and there is NO WAY of knowing who won without a round-trip on the network. Design for that round-trip. This typically means pipelining, and being able to back-track if you get a NAK for some previously issued command -- or just "adapt and deal" if the operation is later shown to have failed.

    For some order like this, i use a sort of basic pipeline. Because this kind of orders are sparse, i haven't problem with them.

    Thank you for your ideas and sharing your knowledge.
    Pascal

    [Edited by - Kroah on September 26, 2007 4:43:40 AM]

    Share this post


    Link to post
    Share on other sites
    Quote:
    The high number of server calls (one for each build unit order) with client waiting for response was the source of the lag.


    Unless the server was in France, and the player in Australia, you shouldn't see terrible lag with a server round-trip time. Thus, the source of lag might be something else. See below.

    C# doesn't "use" SOAP, unless you use some specific part of the .NET library that uses SOAP. You could write plain sockets on C#. And C# networking isn't "slow as hell," unless you use the high-level XML/SOAP/RPC interfaces. So don't use those! SOAP likely doesn't turn off Nagle (i e, keeps TCP_NODELAY off), thus the delay likely comes from that, much more than any SOAP processing.

    If you have lag, you have to analyze all parts of the pipeline to figure out where the lag is coming from.

    Share this post


    Link to post
    Share on other sites
    There is another way could solve this problem, which involves a double future solution, which you will understand in a moment.

    On Turn 0 two players REQUEST to build a tank for 500 bucks. Each does not 'start' to build a tank. This requst is sent out on turn 2 (or however far ahead turns are done in your game).

    When turn 2 rolls around, the total bank is 750, which isn't enough for 2 tanks. So a decision is made to see who builds the tank (random, or some other mechanism). Once a decision is made on who makes the tank, then a command is qued for turn 4, which says, Player X builds a tank.

    You could also begin executing the order on turn 2 and if the simulations are in synch then all clients will decide that player X is the one who gets the tank and remain consistent.

    Share this post


    Link to post
    Share on other sites

    This topic is 3731 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.

    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

    Sign in to follow this