Search Unity

The Lockstep Framework

Discussion in 'Connected Games' started by jpthek9, Apr 14, 2015.

  1. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Here's a demonstration of a multiplayer framework targeted at RTS games I've been working on:


    DPhysics will be released as a standalone asset but will also be included in the Lockstep Framework, which will be released later on. At the moment, I'm polishing up DPhysics for a release.

    Stick around for updates, overviews, and explanations. Happy developing :).
     
    Last edited: May 2, 2015
  2. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,320
    Wow jpthek9. That is cool. I don't know of a single other RTS networking/physics solution for Unity that is deterministic as well (well that is public anyways)!

    Great work man.
     
  3. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Thanks! I've worked really hard on it and I'm glad you think it turned out alright. At the moment, I don't want to take on too many tasks on but later, when I also further develop the Lockstep Framework, I'd like to polish up the code and release it to the public.
     
  4. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,320
    No problem, thanks for the reply. I understand not wanting to take on too much. It does look promising, so best of luck with it.
     
  5. Limyc

    Limyc

    Joined:
    Jan 27, 2013
    Posts:
    28
    You showed that the physic sim is deterministic on the same machine, but what about across multiple machines and operating systems? As far as I know, you cannot enforce floating-point precision flags in C# (a required component of P2P lockstep multiplayer).
     
    Last edited: Apr 19, 2015
  6. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    You're right - which is why I'm using fixed point math. My Windows computer isn't very powerful so can't run the simulation and screen record (actually, it just can't screen record) so I think I'll use a video camera to film it. Honestly, there's no reason why the physics engine wouldn't be deterministic - it's the implementation that's important and since all simulation in the Lockstep Framework is distributed from 1 event deterministcally, input will be the same on all computers in the same game. Plugging in the same input into a fixed-point math operation will return the same results.

    By the way, you can sign up for DPhysics Beta if you'd like to try it for yourself.
     
    Last edited: Apr 19, 2015
  7. Limyc

    Limyc

    Joined:
    Jan 27, 2013
    Posts:
    28
    Ooooohh, that explains it. That's an important thing to note since fixed-point math is way slower.
    It's not necessarily bad (AI Wars dev used fixed-point math for the physics sim), but something for potential buyers to be aware of, nonetheless.

    Does DPhysics have any dependencies on the Unity API? Could it be used outside of Unity?
     
  8. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Oh, I'll add that into the description right now. Thanks for catching that.

    DPhysics has some editor-integration and a GetComponent here or there to make it Unity developer-friendly. I think with a bit of tweaking, it can easily be used outside of Unity.

    I did some benchmarking tests and found that fixed point math is remarkably slower, but not for an intuitive reason. Because the fixed-point numbers are structs, they have to be copied while primitives can be passed on with a cavalry of optimizations. This alone makes my fixed-point implementation about 4x slower than floating-point ops. Doing all the behind-the-scenes operations without the struct makes it 4x faster.

    In a perfect world where there is a fixed-point primitive, I think that fixed-point math would be as fast, if not faster than floating-point numbers. Still, fixed-point math is good enough for a physics engine.
     
    Last edited: Apr 20, 2015
  9. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Okay, i might be unnecessarily micro optimizing a bit here since performance isn't an issue at all right now but i still want to squeeze as much speed juice as i can out of DPhysics.

    First off, im going to convert all operations to public methods. Secondly, im never going to pass on struct values - only struct refs. Thirdly, im going to use primitives instead of structs as much as possible. Fourthly, im going to cache structs whenrver possible - basically my ghetto attempt at inlining.

    Chk-chk. Let the bugs come. Im ready for them!
     
  10. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Finally finished making nearly all the arguments passed on by reference. Is DPhysics faster now? Yes, by a lot - a little less than twice as fast. Was it worth it? !@#$ TO THE NO! The worst part was in the middle after all the bugs woke up. I couldn't turn back so I had to sludge through the code with tears of agony in my eyes.
     
    Last edited: Apr 21, 2015
    Jamster likes this.
  11. bhseph

    bhseph

    Joined:
    Jan 7, 2013
    Posts:
    2
    good job bro! wrote some stuff myself ^^ a lot of nightmares
     
    jpthek9 likes this.
  12. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Thanks!
     
  13. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Made some more progress with LSF:
    .
    Hopefully I can knock out parenting/childing tomorrow for movable building platforms.
     
    Last edited: May 1, 2015
  14. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    I finished childing and go over it briefly. I mainly wanted to talk about Lockstep Framework commands in this video:

     
  15. Zerokx

    Zerokx

    Joined:
    Jul 24, 2015
    Posts:
    1
    Looks great, I wish networking wouldn't be such a trouble with RTS games.
    Any news about this?
     
  16. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
  17. Christian-Tucker

    Christian-Tucker

    Joined:
    Aug 18, 2013
    Posts:
    371
    Doesn't Path of Exile use lockstep now?
     
  18. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    CaoMengde777 likes this.
  19. Christian-Tucker

    Christian-Tucker

    Joined:
    Aug 18, 2013
    Posts:
    371
    I'm going to take a look at this when I have some time tomorrow. Are you the sole developer on this project? I took a quick look earlier and I was seeing some static variables which upset me quite a bit, considering it being a framework. Should definitely try to reduce the global state to none. Using more dependency injection would definitely help out and make it an over-all better experience for developers, especially in the event of wanting multiple implementations. (Perhaps for different game-modes, who the hell knows.)

    See: Why is global state the root of all evil

    Also, as for path of exile, I'd assume they used their own implementation of this considering the game is developed in C++. I haven't used yours or examined it much farther then a little bit of skimming so I can't say much more, but the path of exile lockstep has introduced quite a bit of frustration.
     
    Last edited: Jul 27, 2015
  20. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    LSF was designed for pooling so I figured that the pooling design might as well be integrated into the entire system. There are a lot of global variables but they have to be handled the same way as instance variables for agents and abilities.

    Think of Initialize () as the constructor method.
     
  21. ScriptGeek

    ScriptGeek

    Joined:
    Mar 4, 2011
    Posts:
    45
    This is very cool, but how to go about implementing LSF? Is there any documentation or an example to follow on how to get this setup for networking? Also, can this work with Photon Unity Networking?
     
  22. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    There's a test scene in the project along with some scripts to get you started. For networking, you need to implement your own system (I used DarkRift in those videos and Forge for my current project). Photon can definitely work.

    The key is to get the byte[] generated from Command.Serialize to everybody marked for the same frame. Then reconstruct Commands from the byte[] with Command.Reconstruct. Create a new Frame then add all reconstructed Commands to that frame. Finally, add that frame to FrameManager using the frame count it's designated for as the index. Once the Frame with all the Commands are tucked into FrameManager, the Commands will get injected into the simulation.
     
  23. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    1 question about the path finding (btw I was impressed with it handling large crowds).

    So I want to have rectangle buildings blocking grid nodes, I tested using the test scene and changing the Shape to AAbox, so each wall tile has 1 node. One issue I have is if you try to move a unit from one corner of the wall tile to the opposite side, it will turn to early and get a bit stuck moving into the wall, because the diagonal pathway isn't deactivated. This also causes the units attempting to try and move through two tiles place diagonally next to each other. My question is can you disable diagonal paths next to an unwalkable node? Otherwise, would it be simple to implement?

    Otherwise I was thinking to use more than one node for each tile, and reach a bit out of the building, but this may be performance expensive. Also question: Can you change the size of grid nodes?
     
  24. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    There are 2 easy fixes for the problem. The first is to reduce the size of the building by maybe 0.25.

    The other fix is to disable diagonal connections, as you've suggested, disable diagonal pathfinding. To do this, locate line 94 in GridNode and uncomment it out. When that line of code is run, GridNodes won't generate diagonal connections.
     
  25. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    I will probably dig a bit into it and see if I can only disable diagonal connections for the problem nodes and keep the remaining ones.

    Another issue, (but maybe it won't really happen in a real game where you are not trying to break it so hard), If you select a couple of hundred agents, and make them move against a solid rectangle wall (no path around it), they can push each other through. I know this is hard to deal with, since I wrote a physics game once where this issue came up a lot. But can you increase the walls' authority in pushing out movers so that the pressure from many other movers won't be enough to get through? When I dealt with this sort of thing, I went as far as checking what direction anyone entering a wall came from, and teleporting them back out.

    I may try to fix these issues myself if it turns out they are a problem, just mentioning it here in case you have some input.
     
  26. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Oh yeah, I noticed that too. One reason that happens is that agents actually teleport each other when hit. I think the best solution is to disable that if an agent is up against a wall.
     
  27. CaoMengde777

    CaoMengde777

    Joined:
    Nov 5, 2013
    Posts:
    813
    Amazing!! thanks for all the hard work!

    i might end up using this sometime
     
  28. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Thanks! I haven't been very active on the forums recently but a lot of things have been happening with the framework, mainly on the database and networking front.
     
  29. nsxdavid

    nsxdavid

    Joined:
    Apr 6, 2009
    Posts:
    348
    So I snagged a fork of your repository. Looks like your example scene doesn't work... maybe it's gone stale relative to other changes you are making?

    Your readme also seems out of date (such as the instructions in the quickstart).
     
  30. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Yeah, it's under heavy development at the moment. I'll update the readme with these instructions but to make the example scene work, you'll have to do this:
    Navigate to the Lockstep/Database window and open the Settings foldout. Select the Lockstep-Framework/Example/ExampleDatabase and click the load button. This'll link the database to the settings so the example will have a database to work off of.
     
  31. nsxdavid

    nsxdavid

    Joined:
    Apr 6, 2009
    Posts:
    348
    Yeah I did figure out doing that, but that didn't help. When you hit play, you still get:

    NullReferenceException: No LockstepFrameworkSettings detected. Make sure there is one in the root directory of a Resources folder

    There are other things, such as missing (like the Order marker in the Manager in the example scene).

    But I guess the biggest issue is that, I'm guessing, there is no implmeentaiton of the networking?

    There is an example ForgeNetworking implementation script, but it seems to be in a non-working state too. For example:

    void HandleData (MessageType messageType, NetworkingStream stream) {

    LSUtility.bufferBytes.FastClear ();

    for (int i = 0; i < stream.Bytes.Size - 1; i++) {
    LSUtility.bufferBytes.Add (stream.Bytes [stream.Bytes.StartIndex (i)]);
    }
    byte[] data = LSUtility.bufferBytes.ToArray ();
    switch (messageType) {

    }

    Note the incomplete switch() statement at the end there.
     
  32. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    I noticed too it's going through a lot of work currently, my plan was to wait with updating until it's settled. I was wondering jpthek9 will you announce "versions" or something? Or is there not yet "v1"?
     
    jpthek9 likes this.
  33. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Thanks for noticing that. I added a TODO for finishing up ForgeNetworkHelper so I won't forget to finish it later.

    WRT the bugs, did you open the Database Manager UI? Also, are you using the most recent version in the master branch?
     
  34. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    The version of LSF is kind of weird. It was stable for a while but then I decided to port the most updated version and make it work standalone for the project. Now it's back in Alpha and going through lots of changes.
     
  35. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    Question. I have multiplayer working, but I have a lot of lag between receiving the command from the server and unit begin moving (almost 1 second). I 've been thinking to tweak the amount of command frames or something, but not sure everything will work fine if I do this. I assume there is some standard delay in case of long pathfinding time. I've been looking into the jumpstart algorithm, which is faster than A* for regular grids. (some demo I saw it seemed to be at least 10x faster, at least in Javascript). I asked my slacker friend if he would implement it, but we don't have it yet :/ . Anyway I'm asking if the delay is intended or I can easily change some settings?

    2): I see you have a 2D array of collision pairs, with a max count of 30000 I get out of memory exception (or Unity crash) due to this. Now we would only need such an amount due to a mine, witch each rock tile having a square collider. So we could put these together, so that large collections of tiles uses the same collision square. But seeing as these tiles will never even collide, it's a waste to have every collision possibility in the array. So maybe there could be two arrays, one for those that can collide with every other hitbox, and those that can't collide with each other. For O(n*n + m*n) instead of O( (n+m)*(n+m) ), with m being the non-other-m colliding, so in my case reducing from 961 million pairs to 31 million if you have 1000 moving objects.

    Probably most games won't need nearly as many blocked tiles, but I can imagine if you are heavy on forest or something (we are as well), you could easily reach the limit with this n*n memory use, and with cavitys in the forest you can't group the hitboxes well.

    3) Found a bug in FastStack/FastList. In the ToString() method you call

    return output + innerArray [Count - 1];

    Which is out of bounds when count is 0. (Fix: )

    return output + ((Count > 0) ? innerArray [Count - 1].ToString() : string.Empty);

    I giggled a bit as I had just debugged this same error in my SortedArraySet class when this issue arouse...
     
    Last edited: Dec 8, 2015
  36. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    @KHR

    1) I think it's the influence frame rate, the rate at which frames are commanded on and validated. I set it to 1 influence frame every 4 simulation frames which is 8FPS, much too low for a real time game. Ram down LockstepManager.InfluenceResolution to maybe 2 for 16FPS or even 1 for 32 FPS if you're confident with the server.

    2) The source of the issue is that LSF was originally tailored to Order Of Ancients, a MOBA that needed upwards of 1000 moving units simulated. Optimization and spatial hashing was one of the best solutions and use of a 1D array of collision pairs significantly reduced the amount of time needed for broad phase checks.

    With the current spatial hashing though, I think the caching with CollisionPairs might be obsolete and a hindrance on memory. I'll look into removing it and calculating the values on the go instead of caching them.

    3) Thanks for the catch! I added a guard to those methods to prevent the exception.
     
  37. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    That's nice, it runs fine with InfluenceFrameRate lower.

    I have some general question on synchronization. I have multiplayer running, but not yet synced (while running on the same computer). Now I have removed everything that would cause this that I know of, so maybe there's something I don't know. So I have some lists of stuff that from what I heard will sync/desync on the same computer, I was wondering if you know any more that goes on the list? Or am I mistaken with what should remain synced on the same computer?

    Should be synced on same hardware:
    Floating point operations (float, Vector2/3, Rect )
    monobehaviour FixedUpdate/Awake/Start functions (I removed those and runs all from just 1, but maybe forgot one).

    Will desync on the same hardware: (should be none left)
    monobehaviour update functions
    Time.deltatime
    Random values not seeded and ran together always (Note: I am generating a huge random map which turns out identical for both players.)

    My theories for what the issue is:
    -Some objects are spawned in different orders for each player or just get opposite positions in some list somehow
    -Some 3rd party libary messed with something (I only have a few like RTS Camera Pro, Forge and DarkRift server which shouldn't do this)
    -Derp mistake (pls no)
     
  38. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    The indeterministic factors you listed are all correct. Keep in mind that you can use those as long as they don't affect simulation (i.e. changing a unit's position or health), except through commands.

    Which scene are you running? If it's not vanilla, can you link me a small repro project I can look through?
     
  39. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    I am talking about the game I'm working on so quite a bit of stuff in there... So I have the "TestManager" class running the FixedUpdate doing the LockstepManager.Simulate (), and then I put my update functions to run inside LockstepManager.Simulate by looping through my units (they have their own additional update stuff not done in the lockstep framework). There's really a lot of stuff so I think it would take you many hours to look at it. Now I plan to do more refactoring anyway, so I might as well do that before looking for the error (but I don't really want the mystery to just disappear). It wasn't my intention to have you look through so much stuff, just to get an idea on how to best identify the issue. So now I might do a bit of testing if the next changes doesn't somehow reveal the issue (I am thinking if I end up changing what's causing the issue, and it in the list of issues I know of, then it would be simple to spot.)

    Note: I didn't update your stuff in my game since the summer version, in case there was any bugs.
     
  40. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    The new version is pretty stable now but lots of changes are still coming in but they'll be extraneous to the core development of an RTS. I'd recommend updating. Make sure all the logic previously in Update functions don't use floats and don't rely on non-determinsitic factors if they influence simulation (as you've already identified).

    ND factors at the top of my head:
    - UnityEngine.Time
    - Floats
    - Framework problem: This is why I recommend updating - if it is a framework problem, it's fixed in the more recent versions
    - UnityEngine.Animation/Animator: don't depend on these for timings
    - GameObject.FindAllObjects____: the order changes with different objects in the scene
    - Not reseting an influential deterministic value in Initialize since objects are pooled
    - Using renderer.IsVisible or any ND camera-related logic in the simulation
    - UnityEngine.Physics.Raycast/Use of Unity colliders in simulation

    In the new version, you can use LockstepManager.GetStateHash to find the exact frame the desync happens. You can also implement something like that by taking a hodgepodge of volatile deterministic values and mixing them together. I.e. the desync could be happening the moment you give a move command or when you spawn in the teleporting squirrel.
     
  41. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    Yeah it will probably be good to update it before trying too much stuff (next year is when we hopefully get some funding so we can have some more workers making the game "for real"). It took some hours the first time to integrate the stuff in our game, but I think that's pretty impressive, I didn't think I would have it worked out until the Christmas vacation. It'll probably be a lot a faster this time also with the most incompatible stuff being sorted out. Just want to be sure you don't make a "change everything" commit right after I update it...
     
  42. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    A lot of small changes and new features will trickle in but most of the API will remain the same.
     
  43. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    OK I got the new version sorted out in not too long. How is that settings file creation supposed to happen though? It says to make the settings file if (Application.isPlaying == false), which I changed to true to have the settings file made. You can click somewhere to make the settings file in the editor?

    2) In the new acceleration system the movers will stop moving a bit before reaching their destination and just let the momentum carry them their last distance. I used to detect when the mover is finished and then check if they were in range of their destination so they could perform their task, but now it triggers before they got there. Is the somewhere official where you can run an on destination reached function? Or will I just have to detect when they reach it after the mover has stopped? (I have a move animation also, and now they just slide the last distance...)
     
    Last edited: Dec 16, 2015
  44. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    The settings file is generated per-use before runtime. Opening up the database editor will do that by navigating to the Lockstep/Database window.

    Regarding movement, there actually isn't any momentum - only velocity. The new Move behavior automatically adjusts velocity based on the distance so that the unit will arrive at the destination and not overshoot.

    Move.OnStopMove is called whenever the unit stops moving (i.e. to attack, or to arrive at destination). Move.OnArrive is called when the unit arrives at its destination. You can hook on to those events for the trigger you need.
     
  45. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    I recently optimized collision pairs and partitioning. You should be able to have many more LSBodies now.
     
  46. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    • Yeah I saw that, nice. I'm using the OnArrive event now, from the debug it should be arriving when it's pretty close to the point it's headed (2867 or 0.04), but in the game I can see the sliding distance after OnArrive has run is around a full length (40000-60000). It would seem the distance calculated there is wrong, but the graphic does stop at the correct spot. Also my units push each other before the graphic reach each other (about the same distance ahead as they arrive). So maybe the graphic is in a different spot than the body?
     
  47. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    That's exactly it. Heavy interpolation is used to get units to smoothly. You can mitigate this issue by reducing PhysicsManager.VisualSetSpread (currently, it sets a new visual position to interpolate to every 2 simulation frames which seemed to help with stuttering).
     
  48. KHRZ

    KHRZ

    Joined:
    Mar 2, 2013
    Posts:
    56
    But shouldn't the graphic be ahead of the body rather than behind? The difference is much bigger then the lag I have locally. I set it to 1 and not too much difference, at 0 no movement. Now I just base the animation change etc on the body position and not graphic position, but then workers will still slide a meter while beginning to chop wood. Just seem this setting doesn't allow you to live up to your true delay. (Btw I am using influence resolution 1 if this is a problem).

    Anyway I tried out the hashing, I made it so players sends each other their hash with a stack trace/message with a function call you can put anywhere, so it works like Unity debug, and it outputs the stack trace/message at the first desync. And it appears the game is already desynced right after I initialized my player teams, so will have to look into that. (I'm not using the framework for all this, some stuff I wrote myself is probably the issue).

    Edit: OK so the first desync detection was a fluke (I was supposedly comparing the getStateHash() from the same agent controller, but it's fine for the static method call comparison, so I guess I was mistaken. But now I was able to run the game, chop some trees without desync, and desync when starting a building (my building code). So the sync detection will work out well I think, I can just output whatever values I want and binary search the code with debug calls like normal.
     
    Last edited: Dec 17, 2015
  49. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    I looked into the interpolation issue and there was a value that was calculated to be incredibly low (PhysicsManager.LerpDamping). I tweaked the numbers a bit and I think it should be better now. Keep in mind that FixedUpdate does not run at a fixed framerate so there are stuttering problems with just interpolating between the last frame and the current frame (.03125s delay). Another layer of interpolation seemed to fix the problem but it looks like it makes the object lag behind even more.

    I'm still trying to think of a better solution. I tried looking at Unity's RigidBody code to see how it interpolates to prevent stuttering but I can't find it in AssemblyBrowser.

    Edit: Regarding determinism and desyncs, LOTS of changes are coming in over the course of this weekend. There'll be a system for not only checking gamestate, but also for determining exactly which lockstep variables are desynced.
     
    Last edited: Dec 18, 2015
  50. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,320
    Hey jpthek9. I still havn't tried implementing your system yet, but it's on my "To Do" list. So I'm gonna throw some noob questions at ya if you don't mind :)

    1. Is your system peer-to-peer only (where one client is the host server), or can you have multiple players with one dedicated server as well? Or can you do both if you wanted to with your system?

    2. How do animations and events work? Can I use a mecanim event in an animation......perhaps this doesn't matter because animations can simply be done client side and are not crucial to the simulation?

    3. If Physics.Raycast is not deterministic, how would you recommend players "select" units. Because my system heavily depended on units having colliders that could be raycasted against by a player click. Or can I simply still have Unity colliders on objects (perhaps only as triggers if necessary) that are only there for being raycasted against?

    Just kind of dipping my toe in the shallow end of the pool here lol.
     
    Last edited: Dec 19, 2015
    jpthek9 likes this.