I'm making a multiplayer 2d shooter platformer in unity. And after studying the different options to program an authoritarian server and with the great help that many of you have already provided me on this site. I have decided to create my server also with a unity in headless mode in order to reproduce or simulate the physics of the games on the server with the same engine (box2d) and that the server is the one that decides the movements of the clients.

As you have told me (Thanks @DMGregory), a good option for server development in unity is to use a single project to program both client and server and thus be able to reuse the scenes and prefabs without having to clone them in 2 different projects, but with This idea I find some main problems that I do not know how to solve.

  1. Debugging. How can I run the 2 editors of the same project in unity simultaneously to run server and client?

  2. Separate client and server. Is there a way to separate those elements necessary for the client from those necessary for the server in unity? If not, when compiling my project to use it as a server, it will have a lot of unnecessary material (scripts, sprites, prefabs, etc.) that will make the program more heavy without necessity.

Thank you very much and sorry for my level of English


1 Answer 1


Myself, I'd recommend keeping the server and client authored in a single Unity project. This minimizes the chance for mistakes where you change something in either the server or client and miss updating the other, resulting in divergent behaviour or major errors.

You could approach it in other ways, like bundling everything needed by both client and server into a shared library and asset pack referenced in each separate project, but that's extra hoops to jump through every time you change something.

Instead, we can keep everything in one project, and use preprocessor directives to control what gets built into the client versus server. Code wrapped in an #if SERVER_BUILD ... #endif pair will be compiled only if you've defined the SERVER_BUILD symbol in this compilation pass.

We can add our SERVER_BUILD symbol under Build > Player Settings... > Other Settings > Configuration> Scripting Define Symbols when we're exporting a server build, or leave it out when compiling for the client.

Defining a custom symbol

You can automate this with a custom build script or command line shortcut, so you can export either a client or server build on demand without manually twiddling the settings every time.

To avoid littering your code with #if directives all over the place, you can take advantage of a feature in C# called partial classes. This lets you split the definition of a single class between multiple files, and we'll use it to group together the common, client, and server-specific functionality we need.

First we'll define a partial class that has just the stuff that's always needed - no matter whether we're a server build or a client. Here's a very barebones example:

public partial class PlayerController : MonoBehaviour
    // Common variables needed on both server and client go here.
    public float movementSpeed;

    void Start() {
        // Common start-up code needed on both server and client
        // can be written here.

        // Call serve/client-specific start-up behaviour,
        // depending on which one we are.

    void Move(Vector2 input) {
        // TODO: implement move logic.
        // Note that here, we don't know whether the input
        // came from a locally-connected gamepad/keyboard,
        // or a network packet. We can handle it agnostically.

Note that this class has no notion of the source of input, or that the player has a model/sprite/animator at all, since only the client needs to worry about that stuff.

Then we can have a separate file, call it PlayerController_client.cs that expands on this with client-specific needs and implementations. We wrap the whole thing inside an #if !SERVER_BUILD || UNITY_EDITOR directive, so when we're compiling a server build, the compiler sees this as an empty file and it has no effect on the code that's generated or the data that's packed. But we still keep our public/serializable fields to be able to edit them in the Inspector, and persist our work as we toggle our build flags back and forth.

Any methods that might have conflicting definitions for the server vs the client should be in their own chunk that you restrict to just that version - rather than making an exception for the editor as we do for our serialized fields.

using UnityEngine;

public partial class PlayerController : MonoBehaviour
    // Client-only serialized fields, also accessible in editor.

    public Animator visualPrefab;
    public string horizontalAxis;
    public string verticalAxis;

    // Client-only methods and unserialized data.
    // We don't use the || UNITY_EDITOR
    // exception here, to ensure we don't conflict with the
    // server file's method definitions.
    #if !SERVER_BUILD    

    Animator _visual;
    Camera _camera;

    void OnStartup() {
        _visual = Instantiate(visualPrefab, transform);
        _camera = Camera.main;

    private void Update() {
        // Capture input from client's controller.
        Vector2 input = new Vector2(Input.GetAxis(horizontalAxis), 

        // TODO: SendInputToServer(input);        

        // Locally predict the movement based on this input.

        // Update our animation states accordingly.
        _visual.SetFloat("horizontal", input.x);
        _visual.SetFloat("vertical", input.y);

        // TODO: Handle applying corrections from server in case of bad predictions.

Here the visual representation of the player character isn't part of the character prefab. We spawn it from its own prefab in Start. (You could also do this in an editor callback if you need to position player avatars visually in the scene when setting up maps)

Because this reference to the visual prefab is only present in the client version, when we compile a server version the visual model is completely unreferenced, and Unity can optimize your build by excluding that model, animation data, materials, textures, etc. from the server version of the game.

Note that we still call into the same Move() function that's shared between the server and client functions. So any changes we make to that movement logic will take effect identically between server and client.

We can make another partial class for the server-specific functionality. In that version, our Update method will take its input from the network messages received from the client, instead of trying to read a local gamepad. But again we'll call into the same Move() function to get consistent simulation rules. And we'll skip the overhead of updating the character's animation state, since the server doesn't care about that detail (as long as you're not using animation events to affect gameplay beheviour - if you do that, then you'd want to move the animation logic into the shared file).

This basic strategy will let you very efficiently strip-out functionality or assets you don't need for one platform or another at compile time, and switch between implementations appropriate for each. Doing it in separate files through partial classes helps you keep the code organized, and clearly separate responsibilities - one member of your team could be updating the server logic while another one edits the client-side feedback, without versioning conflicts.

  • \$\begingroup\$ Thank you very much for your answer, I did not know the possibility of using different if SERVER_BUILD to make compilations of my project, I will certainly use it for my project. DMGregory I always thank you for your great interest in helping others \$\endgroup\$
    – coantia
    Commented Oct 12, 2020 at 19:55
  • \$\begingroup\$ I am currently using this approach on my project. However I am struggling with 2 issues: 1. When working in the unity editor, is there any fast way to switch between a server and client setup? (changing the player settings field takes really long and forces a recompile) 2. I am using Rider as my editor and it disables intellisense and refactoring on code that where the #if is not fulfilled. Do you know any way to avoid this? \$\endgroup\$
    – Aides
    Commented Jan 17, 2021 at 13:48
  • 1
    \$\begingroup\$ Those sound like good questions to post by clicking the "Ask Question" button. The one about intellisense and refactoring sounds like it would also impact non-game programmers, so asking it on StackOverflow might get you more answers, faster. \$\endgroup\$
    – DMGregory
    Commented Jan 17, 2021 at 13:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .