Make a build that enables both UNITY_CLIENT and UNITY_SERVER

Hello,

I’m managed to make a build of my project that works if I make a dedicated server and client build.

The client connect to the server on the DefaultConnectAddress.

What I’d like to make is an option for the client to host and then connect to itself.
Then other client can use a join option to join the first hosting client.

I made it work in the editor. But when a Imake the client build, I can use the ClientServerBootstrap.CreateServerWorld() because of the :

#if UNITY_CLIENT && !UNITY_SERVER && !UNITY_EDITOR
            throw new NotImplementedException();
#else

The question is how can I make a client build that also enables the UNITY_SERVER define constraint ?

I tried adding it to the player settings but then the client build ends up switching platform and making a dedicated server build…

To have a build that work as client/server you just need to remove both UNITY_CLIENT and UNITY_SERVER define.
They are and must be used only for making either a client-only or server-only build respectively.

Enabling both is considered an error, because of some #ifdef logic that would break apart (they are not designed for that in first place).

Usually you don’t need to add any in your build workflow. They are automatically added for you as necessary (depending on the Entities/Build settings)

ok now I see I got confused by the distinction between

Multiplayer > PlayMode Tools and set the PlayMode Type to Client & Server

and

Project Settings --> Entities --> Build --> NetCode Client Target is set to *ClientAndServer*

:roll_eyes:

UNITY_CLIENT define is not automatically added for client build that u will get the following warning and failed to connect to server even u set to Client at Project Settings - Entities. I think currently only dedicated server build will automatically add UNITY_SERVER define.

Trying to connect to a server at address xxx.xxx.xx.x:xxxx using an IPCNetworkInterface. IPC interfaces only support loopback address. Forcing using the NetworkEndPoint.Loopback address; family (IPV4/IPV6) and port will be preserved

Unity.NetCode.NetworkStreamDriver:SanitizeConnectAddress(NetworkEndpoint&, Int32)

Unity.NetCode.NetworkStreamDriver:Connect(EntityManager, NetworkEndpoint, Entity)

This is an editor-specific bootstrapping flow designator. I.e. You set this to define editor bootstrap behaviour. It has zero impact on builds, as it only defines how the editor should behave. You can even ignore it when writing your own bootstrapping.

This is a build setting, only applicable to non-dedicated server build targets (e.g. Windows Standalone, Xbox etc). This dropdown determines what kind of client build to make:

  • ClientAndServer - Will make a build containing both the Client and Server code assemblies (you must pass these .asmdef’s in, for them to be stripped). This is useful for games that let players (clients) host their own lobbies, and invite friends to said lobbies. This client executable can create client, thin client, and server worlds.
  • Client - Will remove (strip) the Server assemblies (again, only the ones you pass in), and add the UNITY_CLIENT define to your build, and you’ll be unable to call ClientServerBootstrap.CreateServerWorld.

If you make a dedicated server build, UNITY_SERVER define will be set, and you’ll be unable to call ClientServerBootstrap.CreateClientWorld (nor CreateThinClientWorld).

I’ll make a PR improving the tooltips, to make this distinction more clear. It’s a common question.

2 Likes

I need to clarify about this client build part. Until latest 2022.3.14f1 editor, UNITY_CLIENT define still won’t auto add into build and only dedicated server build will auto add UNITY_SERVER define into build. It’s always behave like that since the first 1.0 release until now that I think it’s bug. Not sure this needs to fix at dots netcode package or need engine fix.

You need to change the Entities/Build settings in the project setting to make a client-only build. Otherwise, the build is made client/server and by default does not have any define set.

And, of course, if you are using your custom build or invoking manually the build pipeline, then it is another story.

Entities register a BuildPlayerOptionsHandler on the IntializeOnLoad in the Editor via BuildPlayerWindow.RegisterGetBuildPlayerOptionsHandler, and this is used when the build is invoked by clicking the Build button.
The handler invoke the GetExtraScriptingDefines method defined by the IEntitiesPlayerSettingProvider (we have three for Netcode).
The UNITY_CLIENT is added by the ClientSetting class that is used if the Cliient mode is selected

However, if you run the build pipeline manually these extra defines are not added. In that case you need to add the options by yourself (sorry, about that).

Yes. I changed to Client at Entities/Build settings in the project settings and it’s still not working. You will just get the following warning.

Trying to connect to a server at address xxx.xxx.xx.x:xxxx using an IPCNetworkInterface. IPC interfaces only support loopback address. Forcing using the NetworkEndPoint.Loopback address; family (IPV4/IPV6) and port will be preserved

Unity.NetCode.NetworkStreamDriver:SanitizeConnectAddress(NetworkEndpoint&, Int32)

Unity.NetCode.NetworkStreamDriver:Connect(EntityManager, NetworkEndpoint, Entity)

mmm… I think something build side got broken somewhere. The build does two compilation steps:

  • One before asset processing (still recompile scripts, because the EDITOR define is removed).
  • One that build the player scripts.

I presume, and this is just one assumptions, that one of the two does not pass the correct defines and that is affecting the whole compilation somehow.

Tried myself and there is something a little odd in the build indeed.

The options are passed correctly:

But then:

And indeed in the final build the define is set:

So, indeed there is an odd behaviour in this first compilation (when the target is switched) but then it looks like to me the defines are properly set (because only the JOIN options is there).

And also no error trying to connect to the local server

So, given all this, @ , I’m really curious to understand what are the difference in the way we are building the player.

I just found the issue. When writing your own build menu to build client player runtime instead of using regular File - Build Settings… to build player runtime, it will break client build. Not sure about whether it will also break build server player runtime or not. Need to test.

@CMarastoni Have u tried this?

If you write your own custom build system, it is up to you to call something like this:

var dotsSettings = var instance = DotsGlobalSettings.Instance;
if (dotsSettings.GetPlayerType() == DotsGlobalSettings.PlayerType.Server)
{
    //If a server provider is not present use at least the default setting for the client build.
    var provider = instance.ServerProvider;
    if (provider == null)
        provider = instance.ClientProvider;
    opts.extraScriptingDefines = provider.GetExtraScriptingDefines();
    opts.options |= provider.GetExtraBuildOptions();
}
else
{
    opts.extraScriptingDefines = instance.ClientProvider.GetExtraScriptingDefines();
    opts.options |= instance.ClientProvider.GetExtraBuildOptions();
}

The way entities hooks up with build system is to react to the press of the build button. If that does not occur, all these settings are never applied correctly, nor will do baking or any other particular step potentially.

1 Like

What if I want to connect the client to the dedicated server, Do I have to do anything differently? I am trying this workflow using the MegaCity sample project.

I have followed the below steps for the Dedicated server build

  1. Converted the target platform to a Dedicated server
  2. Created the Linux build and uploaded the server build on Game Server Hosting by following the steps defined in the docs (GitHub - Unity-Technologies/Megacity-2019: Megacity is a sample showcasing streaming a large scale environment. It also contains an action-packed, multiplayer shooter mode. It leverages the power of Netcode for Entities for an immersive, multiplayer experience that can support 64+ players simultaneously.)

For the client-only build, I have followed the below steps

  1. Project Settings → Entities → Build → NetCode Client Target is set to Client
  2. Created the build on the Windows platform

But when I test it on the editor by setting the play mode type to the client, matchmaking is working as expected and also getting the log that connected to the server But in the Playmode tools it’s showing that “Connecting” after sometime game comes back to the main menu. The same thing is happening with window build as well. I think the server is not accepting the client’s request. I am not sure what am I missing here. I have also checked the logs on the server side on Game Server Hosting but didn’t find anything there as well.

Can anyone please help?

What logs did you get indicating a successful client connection to the DGS? Be careful not to conflate “Called connect on addresss xx.xx.xx.xx” with “Connected to …” as verbiage can be misleading. Look for concrete signs the player connected, like netcode’s debug logs, or some server ship spawning logic that logs the NetworkId of the player.

I sat this because clear a lack of error logs (on client and server) implies no connection was established by the client.