Server-only/Client-only code

How to strip code from the server or client, making code server or client only.

When developing a game in Airship, it may be prudent to not have server logic on the client. For example, if you have an anti-cheat system or other code that the client should not know about.

Method 1: Server-only/Client-only methods

Inside AirshipBehaviour classes, you can use the @Server() and @Client() method decorators to tell the compiler you want the given methods to be server or client only.

export default class ServerAndClientOnlyMethods extends AirshipBehaviour {
    @Server()
    public ServerOnlyMethod() {
        print("This will only be on, and callable by the server!")
    }
    
    @Client()
    public ClientOnlyMethod() {
        print("This will only be on, and callable by the client!");
    }
}

Server/Client only lifecycle methods

Normal methods by default will error if called in the wrong place. However, will lifecycle methods this is not the case as they may be intended to be server or client only, but not error!

export default class ServerComponent extends AirshipBehaviour {
    @Server()
    protected Start() {
         print("I am a server component, printing hello from the server!");   
    }
}

Method 2: Conditional directives

There may be cases you want to mark blocks of code server/client only rather than entire functions. This will work even if it's not inside an AirshipBehaviour. To do this, we use directives. There are two directives:

  • $SERVER - when in a condition, will check if it's the server

  • $CLIENT - when in a condition, will check if it's the client

export default class DirectivesExample extends AirshipBehaviour {
    protected Start() {
       // You can use directives within ternaries!
       const contextGreeting = $SERVER ? "Hi I'm the server" : "Hi I'm the client!";
    
       // this will print different depending on server or client! :D
       print(contextGreeting);
    
       // Server only code block
       if ($SERVER) {
          print("This will only show up in server code, and print on the server!");
       }
       
       // Client only code block
       if ($CLIENT) {
          print("This will only show up in client code, and print on the client!");
       } else {
          // Of course you can also use else for the opposite!
          print("This will show up in server code and print on the server!");
       }
       
       // Dedicated server block (no shared mode)
       if ($SERVER && !$CLIENT) {
          print("This will only be on a dedicated server (no shared mode)");
       }
       
       // Dedicated client block (no shared mode)
       if ($CLIENT && !$SERVER) {
          print("This will only be on a dedicated client (no shared mode)")
       }
    }
}

You can mix these with the decorators as well, to do cool things like create server/client lifecycle event methods:

export default class MyComponent extends AirshipBehaviour {
    protected Start() {
        // It will call 'StartServer' on the server!
        if ($SERVER) this.StartServer();
        // It will call 'StartClient' on the client!
        if ($CLIENT) this.StartClient();
    }
    
    @Server() // server start method :D
    protected StartServer() {
        print("Hello, server!");
    }
    
    @Client() // client start method :D
    protected StartClient() {
        print("Hello, client!");
    }
}

Last updated