Communicating between CLIENT, UI and SERVER scripts#

All VMs (CLIENT, UI, SERVER) are seperate from each other and do not share any variables, even when running on the same machine.

However, there are different interfaces to communicate between all VMs.

SERVER to CLIENT vm#

Remote Functions#

Remote functions allow the SERVER vm to call a function from the CLIENT vm with parameters.

To use remote functions, you have to make a registration on both the CLIENT and the SERVER vm with Remote_RegisterFunction.

Northstar provides the AddCallback_OnRegisteringCustomNetworkVars( void functionref() ) callback in which you can use the Remote_RegisterFunction function. It’s not possible to register remote functions after Remote_EndRegisteringFunctions has been called. The callback exists to allow multiple mods to register remote vars.

Warning

You can only pass parameters of the types null, string, int, float or bool.

It is possible to communicate entities using eHandles. To get an eHandle, use the entity.GetEncodedEHandle() function. To get the corresponding entity of a handle, use entity ent = GetEntityFromEncodedEHandle( eHandle ). eHandles are of type int.

Example#

mod.json extract:

"Scripts": [
{
        "Path": "sh_spaceships.nut",
        "RunOn": "CLIENT || SERVER", // execute the same function on both CLIENT and SERVER
        "ClientCallback": {
                "Before": "Spaceship_Network"
        },
        "ServerCallback": {
                "Before": "Spaceship_Network"
        }
},
{
        // more script registrations ...

sh_spaceships.nut:

The networked CLIENT function has to be global

#if CLIENT
global function Server_GetNetworkedVariable // make the networked function only global on CLIENT
#endif

global function Spaceship_Network // this gets executed on both CLIENT & SERVER

void function Spaceship_Network()
{
        AddCallback_OnRegisteringCustomNetworkVars( RegisterNetworkVars ) // you can only register remote functions inside of this callback
}

void function RegisterNetworkVars()
{
        // this has to be executed on both CLIENT and SERVER, else they will be out of sync and the client disconnects
        Remote_RegisterFunction( "Server_GetNetworkedVariable" ) // register a remote function. Note that the parameters are not declared here
}

#if CLIENT
void function Server_GetNetworkedVariable( int number ) // you can declare as many or few parameters as you wish
{
        printt("got integer", number)
}
#endif

Calling the CLIENT function Server_GetNetworkedVariable on SERVER vm:

// player: CPlayer entity that should execute the function
// func: function identifier string
// ...: any parameters passed to the function
Remote_CallFunction_NonReplay( entity player, string func, ... ) // NOT reexecuted in a replay
Remote_CallFunction_Replay( entity player, string func, ... ) // reexecuted in a replay

// for the previous example, this would be a valid remote function call:

Remote_CallFunction_NonReplay( player, "Server_GetNetworkedVariable", RandomIntRange( 1, 100 ) )

Server to Client command callbacks#

Allows the SERVER vm to create a ServerToClientStringCommand on a player which is linked to a Callback locally

Register a server command#

Note

this has to be executed on the Before Client callback

the formatting for the server command is like a normal console command. Arguments are seperated by spaces

Register with the AddServerToClientStringCommandCallback( string func, void functionref( array<string> ) reference ) function clientside and execute with the ServerToClientStringCommand( entity player /*CPlayer*/, string command ) function server side

Example:#

void function MessageUtils_ClientInit()
{
        AddServerToClientStringCommandCallback( "ServerHUDMessageShow", ServerCallback_CreateServerHUDMessage )
}

void function ServerCallback_CreateServerHUDMessage ( array<string> args )
{
        // client side command handle logic ...
}

CLIENT to SERVER vm#

Client to Server command callbacks#

Register a client command callback serverside with AddClientCommandCallback( string command, bool functionref( entity player /*CPlayer*/, array<string> args ) callback )

player is the player that called the command client side. The callback function should return true if the command was accepted and false if it was invalid.

The CLIENT vm can execute commands with the player.ClientCommand( string command ) function. These will be handled by the SERVER if the command is registered.

CLIENT to UI vm#

Create a global function in the UI vm and call it in the CLIENT vm with the RunUIScript( string identifier, ... ) function. You can also pass parameters to the function. identifier is the name of the function you want to call.

#if UI
global function CallMe

void function CallMe( int a, int b )
{
        printt( a + b )
}
#elseif CLIENT
RunUIScript( "CallMe", 1, 2 ) // 3
#endif

UI to CLIENT vm#

Create a global function in the CLIENT vm and call it in the UI vm with the RunClientScript( string identifier, ... ) function. You can also pass parameters to the function. identifier is the name of the function you want to call.

#if CLIENT
global function CallMe

void function CallMe( int a, int b )
{
        printt( a + b )
}
#elseif UI
RunClientScript( "CallMe", 1, 2 ) // 3
#endif