TL; DR: Design your game mechanics around limiting your multiplayer to the absolute minimum numbers and stick with Mirror + Unity. In my opinion, it gives you the most likely path to shipping your game and you will learn tons on how to scale your next game’s match size up to much larger numbers by going this route first.
Latency is a really hard one to pin down without having your game already setup so that we can talk about what is slowing things down. It could be network, disk io, CPU bottlenecks, too much data going over the network, your serialization / deserialization, and probably others I forgot.
If you are wanting to spend the extra time up front here to get the absolute best performance from your server, I don’t recommend building your server in Unity at all. Instead, go with a c++, C, or RUST for your server backend, and then write your own network stack on the C# client side which transmits just the bytes you know need to go over the wire between the client and server. That is the absolute best way to get the highest performance and to push your server to its physical limits with the fastest possible response to every user input.
Now, with that said, if you aren’t already a seasoned multiplayer developer, I’d say to stick with one platform like Unity and C#, and then just pick Mirror, Photon PUN, or MLAPI and design your game around the logical limits of what that platform is known to have.
The benefits that you get in that trade off are:
- you have just one code base to maintain
- you get a huge increase of developer efficiency because you aren’t having to jump back and forth compiling each project with different toolchains, just to test each new feature you add
- you can ask in forums for the particular framework for help (since others will be having the same challenges you do)
- because of all of the above, you are much more likely to finish your game
Photon PUN’s 20 CCU limit is a pricing tier of ALL USERS across ALL MATCHES, not a technical limit per match. As for how many you can put into a match, the same problem we have talking about latency applies here.
I don’t have a lot of experience with PUN yet, but I doubt PUN would stop you from joining 100 users to a run if you have that CCU level. But if you did, your server is going to have a hard time keeping up with 60FPS because that means that it has about 16.67ms to get network input, process the whole game sim with input from 100 users, and send the updated data back to all those users. The amount of work the server is having to do, and the packets it is having to read and send back for every frame will be the biggest limit to how many people you have in each match.
Also, as I understand Photon PUN, you don’t have too much control on the server architecture nor on exactly what is being sent and read back across the wire, which is why I have chosen Mirror for my project.
There are ways to mitigate complex server loads per match such as:
- calculate areas of interest within a match and only accept and transmit data that is important to those users on this thread
- run a multithreaded server with a shared in-memory simple data store such as Redis or MongoDB for data that needs to be shared between threads
- split responsibilities of different domains such as position/rotation to one thread or server with other things such as inventory, bullet fire, damage calculation, voxel deforming done on another thread or server.
But again, doing all of that could slow down your game by years so I highly recommend designing your game to not need any of that super-high-performance stuff for now.
Sorry for the wall of text, but hopefully the TL; DR helps