Search Unity

"GameMaps" Concept in a Server-Client Networked Game

Discussion in 'Multiplayer' started by ModLunar, Mar 3, 2020.

  1. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    I'm trying to create this concept of a "GameMap" in my project. In this networked multiplayer 2D platformer RPG, a GameMap represents a map, that may contain some of the following:
    - The 2D level itself, using the TileMap system
    - MapPortals that lead players to connected maps
    - Enemies and non-harmful NPCs
    - Other connected players
    - Projectiles, combat skill effects, etc.

    However, I'm running into a problem. Say there are 3 players in my game, and they all started in the "First Level" map. This is all cool, cause the Server handles NPCs' and enemies' logic, for things like movement and damage. Then, the server will send updates to every client about what they're doing. This keeps the server authoritative over their actions (make sure they NPCs/enemies don't do anything unfair/cheat-like), and also performs their actions once, and then just relays the effects of that action to each client.

    However, say that 2 of the players decide to go through the portal into the "Second Level" map.
    All of a sudden, the server needs to keep track of NPCs, enemies, etc. from multiple maps at the same time.


    My GameMap class is a MonoBehaviour, and I use prefabs with them, so I could just instantiate the 2nd map and call it a day. My main concern with this is that objects from 1 map may "do stuff" to objects from the 2nd map. For example,
    1. An enemy in the 2nd map may incorrectly decide to attack a player from the 1st map
    2. A cleric-like character might accidentally be able to heal a player from a different map
    3.If I decided to render this on the server's side of things, the maps would be overlapping each other since I just instantiate them at the same world-space (0, 0, 0) position.

    There are a couple ways I might start to address these map "mixing" issues, but I not sure what way would be the most sustainable for the longterm. Does anyone have any suggestions for how I can fix this map system, taking into account the Server-Client architecture?
     
  2. Cranom

    Cranom

    Joined:
    Jan 31, 2018
    Posts:
    26
    Assuming everyone stays in the same scene and you load the map inside it:
    - Everyone load all the maps, and place each one at z = LevelNumber.
    - Clients activate the map they are on.

    As for the server, depends... is it by any chance in glorious turn-based mode:
    - Server looks where players are, if multiple maps, activate the 1st one and play its logic then deactivate it, activate the next one and play its logic, rinse&repeat..
    If it is in millennial real-time, first get the Server to activate each map where a player is at the moment and do either one of those:
    (If you already have code, use 2D physics and its automated functions like "OnTriggerEnter2D", two ugly ways)
    - Put all the elements of a map on a specified layer, so that the physics triggers only happen on the same level (you're limited in map by the amount of layers).
    - Let all the triggers happen and add a check at the beginning of triggered functions that look up the level's current entities, in order to skip unwanted interactions.
    (If not many 2D functions used in code)
    - Make it visually 2D but have 3D physics so that collisions are handled correctly since maps are ordered in z axis (weird but works ?).
    (Proper and clean way to do it, time-consuming)
    - Make the physics happen manually for each map instead of relying on automated functions, that way you won't have unwanted superposed interactions.

    Those are my 2 cents, I am actually curious of what people will advice you and how you're gonna do it :)
     
    ModLunar likes this.
  3. olejuer

    olejuer

    Joined:
    Dec 1, 2014
    Posts:
    211
    When it comes to networking, there are no real go-to solutions. It is always kinda custom. I think you can either force all players to be on the same map at all times. You probably don't want to, but with networked games you also want to keep it as simple as possible. Think of all the games that solve it this way and have been developed with serious budget and know-how. Just saying. Have your players wait for each other and make them change levels simultaneously. Or you displace the maps somehow.

    I would not stack them in the z-direction, because that seems quite hacky and would not go well with parallaxing and collisions etc. You would have to use layers and that will interfere with everything else you might want to use layers for.

    But you could stack them next to each other (x or y displacement). Could pass a map-id with every network message so that clients can decide to discard it. I would work with additive scenes here so you can use individual scene properties for each map. It also makes the loading and unloading of maps easier. I think that's what I would do if I ABSOLUTELY had to support multiple levels at the same time.
     
    ModLunar likes this.
  4. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    @Cranom Haha I was thinking of something like that at first, but then was like ew to the Layers limitation. But it does get the thoughts rolling, so thank you for your help! :)

    @olejuer That was super insightful, thanks for explaining that. I'll continue tinkering with these possibilities over the next few days.. :)
     
  5. Cranom

    Cranom

    Joined:
    Jan 31, 2018
    Posts:
    26
    I probably discarded a displacement on x/y axis too quickly because of map size variations, but like suggested by @olejuer, could be better this way. And if your maps are of fixed length you can offset them by that amount, or if this value changes you could stock its max size and use it as offset when loading the map.
    As for additive scenes loading you might want to check that it is supported by whatever network solution you're using.
     
    ModLunar likes this.
  6. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Unity unfortunately has no feature for entirely separate world spaces which cannot interact. Even if you did a good job separating objects from one map from objects in another, I suspect the solution would be fragile and error prone.

    You could consider separate server instances for each level. That would be pretty much a clean break.
     
    ModLunar likes this.
  7. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    Interesting..

    I might be on to something with "Separate Physics Scenes", so thank the Unity lords for that perhaps.
    https://forum.unity.com/threads/separating-physics-scenes.597697/

    I still need to see if this is a viable solution, or if perhaps like you said, I actually need separate server instances to run in isolation. (I guess they'd need to coordinate with each other behind the scenes, maybe to a central headless C#/Unity-based server program that actually connects to the players' clients?)

    I'll be back with updates once I find some results from trying this out :)


    ---

    Unrelated:
    (also shoutout to @Joe-Censored !! I remember your HighlightDesuckifier script (along with the help of others on the forums here) that helped me a lot hahah!)
     
    Joe-Censored likes this.
  8. olejuer

    olejuer

    Joined:
    Dec 1, 2014
    Posts:
    211
    Separate Physics scenes?! Never heard that one before, huh. Interesting.

    Managing separate server instances is certainly the cleanest separation between your scenes. I guess, a central instance to connect all those would make sense. Sounds like fun to implement. Orchestrating this is quite a task, though. You don't want to startup server instances for each set of players and each map. Rather you would want to start them up on demand. To avoid waiting times, you would have to anticipate which maps to preload. State would now be split three-wise between map servers, central server, and clients. Also it is pretty resource intense. For n players you can easily end up running n server instances. Or even more.

    What's your networking tech stack, anyway?
     
    Joe-Censored likes this.
  9. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    Haha yeah right, it's new to me! So far, I've needed to make the following changes:

    1. Create a scene at runtime with SceneManager.CreateScene(...). Make sure to use the overload with CreateSceneParameters, so you can use LocalPhysicsMode.Physics2D or LocalPhysicsMode.Physics3D. This makes the scene use its own scene/local physics simulation.

    1. Use the PhysicsScene2D instead of the static Physics2D (or PhysicsScene instead of Physics) methods. For example, from:
    Code (CSharp):
    1. Physics2D.CheckBox(...)
    to

    Code (CSharp):
    1. PhysicsScene2D physicsScene2D = gameObject.scene.GetPhysicsScene2D();
    2. physicsScene2D.CheckBox(...);
    2. Move any objects that need to "exist" in that game map into that scene (so it reacts with the physics of that scene). So any time my player moves to a new map, I move them into the new scene now, so they can stand on the ground of the Tilemap2D in that scene without falling through the floor, or staying stuck in mid-air.


    3. Manually simulate each PhysicsScene2D during a MonoBehaviour's Update(). See the link from the earlier posts for a code snippet example (https://forum.unity.com/threads/separating-physics-scenes.597697/)
     
  10. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    Yeah right? .. It would be a beautiful separation, but possibly ouch for scalability!
    What I'm wondering though is that because they would be separate Unity builds running, that means they could take advantage of multiple processors, since each program could be running completely separately. I'd like to test how good that is sometime.

    @olejuer If you don't mind explaining, what do you mean by networking tech stack?
     
    Last edited: Mar 4, 2020
  11. olejuer

    olejuer

    Joined:
    Dec 1, 2014
    Posts:
    211
    Concerning the physics scenes, keep in mind that not only physics matters. All your custom scripts will have to be compatible with multiple scenes stacked on top of each other, as well as lighting and sound. Might be less tricky than I think, but I'd be wary.

    With networking tech stack I mean a few things.
    What technique do you use to establish a network connection between server and clients? Do you use the deprecated UNet, the new transport package preview, or some asset like Photon, Mirror, Smartfox Server, ...
    If you use something that manages game objects (spawning, unspawning, state sync) for you, you have limited capabilities to add custom stuff like this advanced scene management you are planning.
    If you use something low level, how do you synchronize stuff? Do you write your own protocol? That would give you all the power, but is quite a task.
    And then what do you use for hosting, i.e., where are your server binaries going to run? Will you roll out the server so that people host their own games or will you use a hosting provider like Multiplay, AWS, Google, Photon, ...?

    As for scalability, separate processes of course make maximum use of multiple cores with no multithreading overhead. If you manage to run as many processes as you have cores, you never even have to think about multithreading which is nice. Of course that requires your processes to be fast enough to run with one core. But still, you don't wanna start more processes than you need to.

    If you are aiming for maximum performance, you might want to take a look at the transport package and ECS. ECS also comes with a world concept that might work well for your use case, but I really have no clue.
     
    ModLunar likes this.
  12. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I'm currently implementing this for an MMO without using DOTS/ECS. My experience is Unity had made strides in running what they can in separate threads, but you end up with 1 main thread which dominates usage still. Running multiple server instances on a multicore processor works great.

    I'm sure the question was asking about your game's network API, as there are many to choose from or you could roll your own, and using a premade API it may have functionality which can help with what you're trying to do (or be designed in such a way to make it more difficult).
     
  13. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    True, it may also need to be accounted for in other parts of my code, like I'll need to be careful with static lists of things. That no longer holds if I want to separate execution by GameMap. I admit I haven't had as much time as I'd like to test this theory out enough yet.

    @Joe-Censored ah true. So I'm using my own API built on top of the built-in C# TcpListener, TcpClient, and NetworkStream classes from System.Net.Sockets.

    In the future, I'd like this to be a game with a centralized server (or servers), so I suppose I'd use something like AWS, GCP, or etc. (though I am very new to actually working with the cloud myself). That way, I can have "any number" of players join the game, just like logging on to play MapleStory, RuneScape, etc.
     
    Joe-Censored likes this.