### ServerWelcomeComponent Example Source: https://github.com/easy-games/airship-docs/blob/main/networking/airshipnetworkbehaviour/README.md Demonstrates how to use AirshipNetworkBehaviour to implement client-only and server-only start events, observe players, and send targeted RPCs. ```typescript import { AirshipNetworkBehaviour, TargetRpc } from "@Easy/Core/Shared/Network"; export default class ServerWelcomeComponent extends AirshipNetworkBehaviour { // This is a client-only "Start" event public OnClientStart() { print("Hello, Client!"); } // This is a server-only "Start" event public OnServerStart() { print("Hello, Server!"); Airship.Players.ObservePlayers((player) => { // Personalized server introduction :-) this.SendServerIntroduction(player, `Hello, World! - to you - ${player.username}!`); }); } // TargetRpc will only send to the specified player // this method will also only invoke on the client it's sent to @TargetRpc() public SendServerIntroduction(player: Player, message: string) { Game.BroadcastMessage(`[SERVER] ${message}`); } } ``` -------------------------------- ### Start Component Startup Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/lifecycles.md Called once after Awake and OnEnable. Recommended for most general startup code. ```typescript class Example extends AirshipBehaviour { Start() { // Code } } ``` -------------------------------- ### Awake Initialization Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/lifecycles.md Called once when the component first starts up, after the GameObject is active and the component is enabled. Use for initial setup. ```typescript class Example extends AirshipBehaviour { Awake() { // Code } } ``` -------------------------------- ### Weighted Random Item Selection Example Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/random.md This example demonstrates how to select an item from an array with weighted probabilities using `PickItemWeighted`. For optimal performance, freeze the weights array using `table.freeze`. ```typescript //Create the data enum Rarity { Common, Rare, Legendary, } interface Item { name: string; rarity: Rarity; } const items: Item[] = [ { name: "Leather Hat", rarity: Rarity.Common, }, { name: "Golden Glove", rarity: Rarity.Rare, }, { name: "Diamond Bat", rarity: Rarity.Legendary, }, ]; // Freeze a set of values to act as the weights for randomization const weights = table.freeze( items.map((item) => { switch (item.rarity) { case Rarity.Common: return 15; case Rarity.Rare: return 4; case Rarity.Legendary: return 1; } }), ); //Create a new random instance const rng = new Random(); //Get a single item out of the array using weighted randomization const randomItem = rng.PickItemWeighted(items, weights); ``` -------------------------------- ### Basic AirshipBehaviour Example Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/README.md Extends AirshipBehaviour to define custom game logic. The Start method is called once when the behaviour is initialized. Attach this component to a Game Object in the Unity editor. ```typescript export default class ExampleAirshipBehaviour extends AirshipBehaviour { public greeting = "Hello, World!"; public Start(): void { print(this.greeting); } } ``` -------------------------------- ### Vector3 Addition Example Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/datatype-math.md Demonstrates adding two Vector3 instances using the .add() method. Ensure Vector3 is imported or available in the scope. ```typescript const v1 = new Vector3(1,0,1); const v2 = Vector3.up; //(0,1,0) const v3 = v1.add(v2); //Equals (1,1,1) ``` -------------------------------- ### Add and Get Unity and Airship Components Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/accessing-other-components.md Demonstrates adding and retrieving both standard Unity components (like BoxCollider) and custom Airship components (like Test) using their respective methods. This is typically done within the Start method to set up initial component interactions. ```typescript export default class Test extends AirshipBehaviour {} export default class MyComponent extends AirshipBehaviour { public Start() { // Adding a Unity and Airship component: this.gameObject.AddComponent(); this.gameObject.AddAirshipComponent(); // Get Unity and Airship components: const boxCollider = this.gameObject.GetComponent(); const test = this.gameObject.GetAirshipComponent(); } } ``` -------------------------------- ### Making GET and POST Requests Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/external-services.md Demonstrates how to perform asynchronous GET and POST requests to external APIs using HttpManager. Ensure requests are made on the server-side; client-side requests will fail. The response includes the status code and data. ```typescript if (!Game.IsServer()) return; let getResult = HttpManager.GetAsync("https://jsonplaceholder.typicode.com/todos/1"); print(getResult.statusCode, getResult.data); let postResult = HttpManager.PostAsync("https://jsonplaceholder.typicode.com/posts", json.encode({ title: 'foo', body: 'bar', })); print(postResult.statusCode, postResult.data); ``` -------------------------------- ### Server-Only Lifecycle Method Source: https://github.com/easy-games/airship-docs/blob/main/typescript/server-only-client-only-code.md Designate lifecycle methods like Start as server-only using the @Server() decorator. This example shows a Start method that will automatically run on the server but not the client. ```typescript export default class ServerComponent extends AirshipBehaviour { @Server() protected Start() { print("I am a server component, printing hello from the server!"); } } ``` -------------------------------- ### Create Example Data Object Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airship-scriptable-objects.md Define a custom ScriptableObject by extending AirshipScriptableObject. Use the @CreateAssetMenu decorator to make it available in the Unity editor's Create menu. Implement Awake and OnDestroy for initialization and cleanup. ```typescript // This will show in Create -> ScriptableObjects -> Example Data Object by default @CreateAssetMenu() export default class ExampleDataObject extends AirshipScriptableObject { public message = "Hello, world!"; protected Awake() { // This will be fired when the scriptable object is first referenced/created. // The properties of this object will be set up on Awake print(this.message, "from the example scriptable object awake!"); } protected OnDestroy() { // This will be called if: // - A CreateInstance() ScriptableObject is destroyed print("This object was destroyed!"); } } ``` -------------------------------- ### Get Match Configuration (Server) Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/matchmaking.md Server-side code to retrieve the match configuration, including teams, groups, players, and attributes. This is available on servers started by the matchmaking service. ```typescript // On a server that was started by the matchmaking service, you can get // the match configuration, which includes the teams, groups, players, and // attributes for the match. const matchConfig = await Platform.Server.Matchmaking.GetMatchConfig(); ``` -------------------------------- ### Basic Custom Inspector Script Source: https://github.com/easy-games/airship-docs/blob/main/editor-extensions/custom-inspectors-c/README.md Creates a custom inspector for 'ExampleComponent' by deriving from 'AirshipEditor' and adding the 'CustomAirshipEditor' attribute. This example simply displays a label in the inspector. ```csharp [CustomAirshipEditor("ExampleComponent")] public class ExampleComponentEditor : AirshipEditor { public override void OnInspectorGUI() { EditorGUILayout.LabelField("This is a custom inspector"); } } ``` -------------------------------- ### Example Component Definition Source: https://github.com/easy-games/airship-docs/blob/main/editor-extensions/custom-inspectors-c/README.md Defines a basic AirshipBehaviour component with properties like name, age, and favorite color. ```typescript export default class ExampleComponent extends AirshipBehaviour { public name = "Bob"; public age = 20; public favouriteColor = Color.blue; } ``` -------------------------------- ### Join Queue with String Equality Attributes Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/matchmaking.md Example of joining a queue with specific attributes for string equality rules, such as clan-based matchmaking. Ensure the 'clan' attribute is present on the matchmaking group. ```typescript await Platform.Server.Matchmaking.JoinQueue({ groupId: groupId, queueId: "clan-4v4", attributes: { "clan": "fightingFrogs" } }); ``` -------------------------------- ### Broadcasting a Message Source: https://github.com/easy-games/airship-docs/blob/main/networking/airshipnetworkbehaviour/observersrpc.md This example demonstrates how to use the ObserversRpc decorator to broadcast a message from the server to all clients. The `BroadcastMessage` method is decorated with `@ObserversRpc()`, making it callable from the server to send messages to all connected clients. ```APIDOC ## ObserversRpc ### Description This is for broadcasting a call to all clients from the server. ### Method Signature `BroadcastMessage(string message)` ### Usage Decorate a method with `@ObserversRpc()` to make it a broadcastable RPC. ```typescript import { AirshipNetworkBehaviour, ObserversRpc } from "@Easy/Core/Shared/Network"; export default class ExampleGlobalButton extends AirshipNetworkBehaviour { @ObserversRpc() private BroadcastMessage(string message) { print("Server has sent everyone", message, "!") } } ``` ### Parameters * **message** (string) - The message to broadcast to all clients. ``` -------------------------------- ### Initialize VoxelWorld Generation Source: https://github.com/easy-games/airship-docs/blob/main/guides/tutorial-top-down-battle/voxelworld-level-generation.md On component enable, get the VoxelWorld reference and initiate level generation after the world has finished loading. Level generation is typically server-side only. ```typescript public override OnEnable(): void { //Only the server needs to generate the level if (Game.IsClient()) { return; } //Store half size for conveniance this.levelHalfSize = math.floor(this.levelSize / 2); //Load the world let foundWorld = WorldAPI.GetMainWorld(); if (!foundWorld) { error("No voxel world found in game"); } this.world = foundWorld; //Don't place blocks until the world is loaded this.world.OnFinishedWorldLoading(() => { this.GenerateBase(); this.GenerateWalls(); this.GenerateObstacles(); }); } ``` -------------------------------- ### Working with Physics Layers in TypeScript Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/physics-layers.md Demonstrates how to create a layer mask from layer names and check if a GameObject belongs to a specific game layer. Includes an example of performing a Raycast using a game layer mask. ```typescript const layerMask = LayerMask.GetMask("GameLayer0", "GameLayer1"); if (this.gameObject.layer === GameLayer.GAMELAYER_0) { //Raycast with a game layer mask if (Physics.Raycast(this.transform.position, this.transform.forward, 10, layerMask)) { print("Hit a game layer object"); } } ``` -------------------------------- ### GetMatchConfig Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/matchmaking.md Retrieves the match configuration, including teams, groups, players, and attributes, for a server started by the matchmaking service. This is a server-side operation. ```APIDOC ## Server.Matchmaking.GetMatchConfig ### Description Retrieves the configuration details for the current match, including teams, groups, players, and attributes. ### Method Server.Matchmaking.GetMatchConfig ### Parameters None ### Request Example ```typescript const matchConfig = await Platform.Server.Matchmaking.GetMatchConfig(); ``` ### Response #### Success Response (200) * **matchConfig** (object) - Contains the match configuration details. #### Response Example ```json { "matchConfig": { "teams": [...], "groups": [...], "players": [...], "attributes": {} } } ``` ``` -------------------------------- ### Store and Get User Unlocks Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/data-store/README.md Demonstrates how to store complex data like user unlocks using a unique key and retrieve it. Ensure the key format is consistent and data types match. ```typescript const unlocks: UnlockData = { level1: true, level2: true, level3: false, } await Platform.Server.DataStore.SetKey(`Unlocks:${player.userId}`, unlocks); const result = await Platform.Server.DataStore.GetKey( `Unlocks:${player.userId}`, ); if (!result) return; // Key did not exist if (result.level2) { // Unlocked! } ``` -------------------------------- ### Define NPC Template ScriptableObject Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airship-scriptable-objects.md Create a ScriptableObject to serve as a template for NPCs. This example demonstrates using @Header and @Min decorators for organizing and validating properties like name and maxHealth, and optionally assigning a custom prefab. ```typescript @CreateAssetMenu() export default class NPCTemplate extends AirshipScriptableObject { @Header("Metadata") public name = "Example NPC"; @Min(1) public maxHealth = 100; @Header("Appearance") public customPrefab?: GameObject; } ``` -------------------------------- ### Join Queue with Team Fixed Roles Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/matchmaking.md Example of joining a queue where players have specific roles assigned. This is useful for role-based game modes. The 'role' attribute is used here to specify the player's role. ```typescript await Platform.Server.Matchmaking.JoinQueue({ groupId: groupId, queueId: "clan-4v4", members: [ { "uid": user1, "attributes": { "role": "dps" }, } ] }); ``` -------------------------------- ### Set and Get Cache Entry with Cooldown Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/cache-store.md Demonstrates how to set a temporary cache entry with a cooldown and then check if that entry exists. Use this for implementing temporary restrictions or tracking time-sensitive states. ```typescript await Platform.Server.CacheStore.SetKey( `BossQueue:${player.userId}`, // The key for this cache entry os.time(), // The time the cooldown was created is stored as the value 60, // 60 second cooldown ); // Check a queue cooldown const result = await Platform.server.cacheStore.GetKey(`BossQueue:${player.userId}`); if (result) { // On cooldown } else { // Not on cooldown } ``` -------------------------------- ### Reference and Use NPCTemplate in Spawner Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airship-scriptable-objects.md Reference an NPCTemplate ScriptableObject in another AirshipBehaviour to spawn NPCs with specific properties. The Start method uses the template's data to configure the spawned character's health, name, and appearance. ```typescript import { Airship } from "@Easy/Core/Shared/Airship"; import NPCTemplate from "Code/ScriptableObjects/NPCTemplate"; export default class NPCCharacterSpawner extends AirshipBehaviour { // Just like referencing other AirshipBehaviours // We can also reference AirshipScriptableObject classes public template: NPCTemplate; @Server() protected Start(): void { if (this.template === undefined) return; const character = Airship.Characters.SpawnNonPlayerCharacter(this.transform.position, { customCharacterTemplate: this.template.customPrefab, }); character.SetMaxHealth(this.template.maxHealth); character.SeatHealth(this.template.maxHealth); character.SetDisplayName(this.template.name); } } ``` -------------------------------- ### Create an Open Match Server Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/server-transfers.md Creates a new server that is open for anyone to join at any time. Players are then transferred to this server. ```typescript // Create an open match server. Anyone can join these servers at any time. let server = await Platform.Server.ServerManager.CreateServer({ accessMode: AirshipServerAccessMode.Open, // The default mode is Closed sceneId: "MatchScene", }); await Platform.Server.Transfer.TransferGroupToServer(players, server.serverId); ``` -------------------------------- ### Generate Server Profile Source: https://github.com/easy-games/airship-docs/blob/main/optimization/live-game-profiler.md Run this command in the Developer Console to generate a server CPU profile. The first argument specifies the duration in seconds, and the second disables deep callstacks. ```console profile server 5 false ``` -------------------------------- ### Listening for Key Presses Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/user-input/keyboard.md Use `OnKeyDown` and `OnKeyUp` to register callbacks for key press and release events. You can optionally specify a signal priority. ```APIDOC ## Listening for Key Presses Use the `OnKeyDown` and `OnKeyUp` methods to listen for key events. ```typescript Keyboard.OnKeyDown(Key.E, (event) => { print("E key down"); }); Keyboard.OnKeyUp(Key.E, (event) => { print("E key up"); }); // Optional signal priority: Keyboard.OnKeyDown(Key.E, (event) => { print("E key down, before the other one!"); }, SignalPriority.HIGH); ``` ``` -------------------------------- ### Spawn NetworkIdentity on Server Source: https://github.com/easy-games/airship-docs/blob/main/networking/network-identity.md Instantiates a prefab and spawns it on the network. The prefab must be registered in a NetworkPrefabCollection. ```typescript const cube = Object.Instantiate(cubePrefab); NetworkServer.Spawn(cube); ``` -------------------------------- ### OnTriggerEnter Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/lifecycles.md Called when a collider or rigidbody attached to the same GameObject as this component starts touching another collider or rigidbody. ```APIDOC ## OnTriggerEnter ### Description Called when a collider or rigidbody attached to the same GameObject as this component starts touching another collider or rigidbody. ### Method Signature ```typescript OnTriggerEnter(collision: Collision) ``` ### Parameters - **collision** (Collision) - The collision data. ``` -------------------------------- ### Define and Listen to Basic Actions Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/user-input/actions.md Use `CreateAction` to define a new input action with a specific binding. Listen for input events on this action using `OnDown` and connect a callback function. ```typescript // Define an action Airship.Input.CreateAction("Dash", Binding.Key(Key.LeftShift)); // Listen to using the action Airship.Input.OnDown("Dash").Connect(() => { print("Dash!"); }); ``` -------------------------------- ### OnCollisionEnter Method Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/lifecycles.md Called when a collider or rigidbody attached to the same GameObject starts touching another collider or rigidbody. ```typescript class Example extends AirshipBehaviour { OnCollisionEnter(collision: Collision) { // Code } } ``` -------------------------------- ### Get Current Matchmaking Group (Client) Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/matchmaking.md Client-side code to check if the player is part of a matchmaking group. ```typescript // Client // On the player, check to see if the player is a part of a matchmaking group const group = await Platform.Client.Matchmaking.GetCurrentGroup(); ``` -------------------------------- ### Subscribe and Publish Messages Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/server-messaging.md Demonstrates how to subscribe to a topic to receive messages, publish messages to a topic, and unsubscribe from a topic. Server Messaging is only available on game servers. ```typescript if (!Game.IsServer()) return; const subscription = Platform.Server.Messaging.Subscribe("player-events", (data) => { print("Received message:", data); }); Platform.Server.Messaging.Publish("player-events", { event: "player-joined", userId: "12345", serverName: "Battle Arena 1" }).then((result) => { if (result.success) { print("Message published successfully"); } }); subscription.unsubscribe(); // Alternatively, if you are using a Bin to manage resources, // the subscription can be added directly to it. // this.bin.Add(subscription); ``` -------------------------------- ### OnEnable Component Activation Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/lifecycles.md Called when the component is enabled. Runs after Awake and before Start on initial startup, and anytime the component is re-enabled. ```typescript class Example extends AirshipBehaviour { OnEnable() { // Code } } ``` -------------------------------- ### Listen for Network Signal on Server Source: https://github.com/easy-games/airship-docs/blob/main/networking/network-signals.md On the server, this code sets up a listener for the 'usePotion' Network Signal. It receives the player who sent the signal and the event data, then processes the potion usage. ```typescript usePotion.server.OnClientEvent((player, event) => { print(`${player.username} is using potion: ${event.potion}`); }); ``` -------------------------------- ### Get Airship Type by Name Source: https://github.com/easy-games/airship-docs/blob/main/editor-extensions/editor-api-c.md Query the types available in Airship by their string name. This is useful for runtime type inspection. ```csharp var exampleComponentType = AirshipType.GetType("ExampleComponent"); ``` -------------------------------- ### Find or Create a Server for a Group Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/server-transfers.md Attempts to find an existing open server for a group; if none is found, it creates a new open server and transfers the group. ```typescript // Find a server for the group. Make sure we check that the access mode is set to // "Open" so we don't accidently join a private match. const result = await Platform.Server.Transfer.TransferGroupToMatchingServer(players, { sceneId: "MatchScene", accessMode: AirshipServerAccessMode.Open, }) // "transfersRequested" being true means the group found a server, so we are done. if (result.transfersRequested) return; // Create a new server for the group and transfer them to it. const server = await Platform.Server.ServerManager.CreateServer({ sceneId: "MatchScene", // Access mode is Closed by default, so we set it to open explicitly accessMode: AirshipServerAccessMode.Open, }); await Platform.Server.Transfer.TransferGroupToServer(players, server.serverId); ``` -------------------------------- ### JoinQueue Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/matchmaking.md Joins a preconfigured matchmaking queue for a given group. This initiates the matchmaking process. ```APIDOC ## Server.Matchmaking.JoinQueue ### Description Joins a specified matchmaking queue for a given group, starting the matchmaking process. ### Method Server.Matchmaking.JoinQueue ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **groupId** (string) - Required - The ID of the group to join the queue. * **queueId** (string) - Required - The ID of the matchmaking queue to join. ### Request Example ```typescript await Platform.Server.Matchmaking.JoinQueue({ groupId: groupId, queueId: "team-deathmatch" }); ``` ### Response #### Success Response (200) No specific response body documented. ``` -------------------------------- ### BeginGroup Source: https://github.com/easy-games/airship-docs/blob/main/editor-extensions/editor-api-c.md Begins a group, which will be visually grouped in a padded frame. ```APIDOC ## BeginGroup ### Description Begin a group (will be "grouped" in a padded frame). ### Method static void ### Parameters - **label** (GUIContent) - Required - The label for the group. ``` -------------------------------- ### OnCreateCommand Event Source: https://github.com/easy-games/airship-docs/blob/main/characters/character-movement-system/character-movement-events.md Fired before a new command is created. Allows for setting custom input data for the command. ```csharp /// /// Called when a new command is being created. This can be used to set custom data for new /// command by calling the SetCustomInputData function during this event. /// public event Action OnCreateCommand; ``` -------------------------------- ### Get Individual Player Rank Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/leaderboards.md Retrieves the rank and score for a specific player ID on a leaderboard. Results may be delayed up to 1 minute. ```typescript // Get the rank of a given id (note: results may be delayed up to 1 minute) const result = await Platform.Server.Leaderboard.GetRank("TopScores", player.userId); if (!result) return; // No entry for this userId // Result is an object with the fields id, rank, and value const rank = result.rank; ``` -------------------------------- ### Set Default Character Prefab and Observe Spawns Source: https://github.com/easy-games/airship-docs/blob/main/characters/character-system/README.md Configure the default character prefab and set up a listener for new character spawns. The listener waits for initialization and prints the display name. ```typescript Airship.Characters.SetDefaultCharacterPrefab(myCharacter); Airship.Characters.ObserveCharacters((newCharacter) => { newCharacter.WaitForInit(); print("Character Spawned: " + newCharacter.GetDisplayName()); }) ``` -------------------------------- ### OnTriggerEnter - 3D Collision Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/lifecycles.md Called when a collider or rigidbody attached to the same GameObject starts touching another collider or rigidbody. Use this for initial contact detection. ```typescript class Example extends AirshipBehaviour { OnTriggerEnter(collision: Collision) { // Code } } ``` -------------------------------- ### Create and Use Network Signal in PotionManager Source: https://github.com/easy-games/airship-docs/blob/main/networking/network-signals.md Demonstrates creating a NetworkSignal for potion usage and handling it on both client and server within a PotionManager class. The client fires the event, and the server listens for it to apply effects. ```typescript export default class PotionManager extends AirshipSingleton { // Creating a NetworkSignal private usePotion = new NetworkSignal<{ potion: string }>("UsePotion"); public override Start(): void { if (Game.IsClient()) { // Tell the server that the local player is trying to use a potion this.usePotion.client.FireServer({ potion: "health" }); } if (Game.IsServer()) { // Listen for a player use potion request this.usePotion.server.OnClientEvent((player, event) => { const hasPotion = DoesPlayerHavePotion(player, event.potion); if (!hasPotion) return; // Apply the potion's effect player.character?.SetHealth(100); }); } } } ``` -------------------------------- ### Get Matchmaking Group Information (Server) Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/matchmaking.md Server-side code to retrieve information about matchmaking groups and their status, either by group ID or user ID. ```typescript // Server // Get matchmaking group + status const group = await Platform.Server.Matchmaking.GetGroupById( this.matchmakerSingleton.groupId, ); // Get the matchmaking group + status for a specific user // This is useful if you don't have the group id, check if they are in a group const group = await Platform.Server.Matchmaking.GetGroupByUserId( player.userId, ); ``` -------------------------------- ### Setting a Custom CameraMode Source: https://github.com/easy-games/airship-docs/blob/main/characters/character-camera/custom-camera-mode.md Demonstrates how to set an instance of a custom CameraMode on the CameraSystem. This is used to activate a new camera behavior. ```typescript cameraSystem.SetMode(new MyCameraMode()); ``` ```typescript cameraController.cameraSystem.SetMode(new MyCameraMode()); ``` -------------------------------- ### Get Character Rotation and Look Vector Source: https://github.com/easy-games/airship-docs/blob/main/characters/character-movement-system/README.md Access the character's rotation via its graphic transform or use the GetLookVector method for directional information. ```typescript //To get the characters rotation character.movement.graphicTransform.rotation; //To get the look vector of the character character.movement.GetLookVector(); ``` -------------------------------- ### List a Server Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/server-list.md Use this function to make a server accessible in the server list. The name and description are optional parameters that can be updated by calling the function again. ```typescript await Platform.Server.ServerManager.ListServer({ // Name and description are optional name: "My Server", description: "A running server you can join", }) ``` -------------------------------- ### OnProcessCommand Event Source: https://github.com/easy-games/airship-docs/blob/main/characters/character-movement-system/character-movement-events.md Called on the start of processing for a tick. The state passed in is the last state of the movement system. Use this for logic that needs to execute before command processing. ```APIDOC ## OnProcessCommand Event ### Description Called on the start of processing for a tick. The state passed in is the last state of the movement system. ### Event Signature `Action OnProcessCommand` ### Parameters - `input` (object) - The character movement input. - `state` (object) - The last state of the movement system. - `isReplay` (boolean) - Indicates if this is a replay. ``` -------------------------------- ### BeginTabs Source: https://github.com/easy-games/airship-docs/blob/main/editor-extensions/editor-api-c.md Begins a tab view. Must be paired with an EndTabs call. Returns the index of the currently selected tab. ```APIDOC ## BeginTabs ### Description Will draw a tab view, must contain an `EndTabs` call at the end of the content. Returns the index of the currently selected tab. ### Method static int ### Parameters - **selectedIndex** (int) - Required - The index of the initially selected tab. - **tabs** (GUIContent[]) - Required - An array of GUIContent representing the tabs. ### Request Example ```csharp selectedTabIndex = AirshipEditorGUI.BeginTabs(selectedTabIndex, new [] { new GUIContent("Tab 1"), new GUIContent("Tab 2"), }); if (selectedTabIndex == 0) { // render content of tab #1 } else if (selectedTabIndex == 1) { // render content of tab #2 } ``` ``` -------------------------------- ### Create a Private Match Server Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/server-transfers.md Creates a private match server for a specific group of players. Only players on the allowed list can join. ```typescript // Create a private match server for a group const server = await Platform.Server.ServerManager.CreateServer({ sceneId: "MatchScene", // We can use any access mode in combination with allowedPlayers. Players must // pass the checks for both access mode and be on the allowed players list // to join the server. accessMode: AirshipServerAccessMode.Closed, allowedPlayers: players, }); await Platform.Server.Transfer.TransferGroupToServer(players, server.serverId); ``` -------------------------------- ### Mouse Movement Events Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/user-input/mouse.md Subscribe to the `Moved` event to get notified when the mouse cursor changes position on the screen. The `onScrolled` event fires when the mouse wheel is used. ```typescript Mouse.onMoved.Connect((screenPosition) => { print("Mouse position", screenPosition); }); Mouse.onScrolled.Connect((delta) => { print("Scrolled", delta); }); ``` -------------------------------- ### Get User's Party and Members Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/parties.md Retrieve a user's party information and access its members. Handles cases where a user might not have a party (e.g., offline). ```typescript // Get a user's party const party = await Platform.party.GetPartyForUserId(player.userId); if (!party) return; // No party. The user may have no party if they are offline. // Party data such as members and leader const members = party.members; ``` -------------------------------- ### Define Level Generation Variables Source: https://github.com/easy-games/airship-docs/blob/main/guides/tutorial-top-down-battle/voxelworld-level-generation.md Declare variables for block types, level dimensions, and obstacle parameters. Ensure the Survival package is installed for default block assets. ```typescript export default class TopDownBattleLevelGenerator extends AirshipBehaviour { @Header("Variables") public baseBlockType: SurvivalBlockType = SurvivalBlockType.EMERALD_BLOCK; public floorBlockType: SurvivalBlockType = SurvivalBlockType.GRASS; public wallBlockType: SurvivalBlockType = SurvivalBlockType.STONE_BRICK; public obstacleBlockType: SurvivalBlockType = SurvivalBlockType.OAK_WOOD_PLANK; public levelSize = 75; public wallHeight = 5; public minBlockCount = 10; public maxBlockCount = 30; public minBlockSize = 2; public maxBlockSize = 6; //Stored reference to the current world private world!: World; private levelHalfSize = 0; ``` -------------------------------- ### Register Chat Command on Server Source: https://github.com/easy-games/airship-docs/blob/main/core-package/chat-commands.md Register your custom chat command with Airship's chat system. This should be done on the server-side, typically within an AirshipBehaviour's Start method. ```typescript import { Airship } from "@Easy/Core/Shared/Airship"; import { Game } from "@Easy/Core/Shared/Game"; import MyCommand from "./MyCommand"; export default class CommandManager extends AirshipBehaviour { override Start() { if (Game.IsServer()) { Airship.Chat.RegisterCommand(new MyCommand()); } } } ``` -------------------------------- ### Define and Listen to Actions Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/user-input/README.md Use CreateAction to define a new input action and OnDown to listen for when that action is triggered. ```typescript // Define an action Airship.Input.CreateAction("Jump", Binding.Key(Key.Space)); // Listen to using the action Airship.Input.OnDown("Jump").Connect(() => { print("Jump pressed") }); ``` -------------------------------- ### Access AirshipSingleton Instance Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/airshipsingleton.md Use the static `Get` method to retrieve the singleton instance from anywhere in your codebase. This method finds an existing instance or creates one if it doesn't exist. ```typescript const myMoney = WalletManager.Get().money; ``` -------------------------------- ### Getting Player Username from Spawned Character Source: https://github.com/easy-games/airship-docs/blob/main/characters/player-system.md Observe character spawns and retrieve the username of the player associated with the character. Ensure character data is initialized before accessing player properties. ```typescript //Get a players username from their spawned character Airship.Characters.ObserveCharacters((character) => { //Let the server and client sync their data character.WaitForInit(); print("New character username: " + character.player?.username); }); ``` -------------------------------- ### Load Asset from Unity Resources Folder Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/resources-folder.md Use the Asset.LoadAsset method to load a GameObject prefab from a specified local path within the Unity Resources folder. Ensure the path is correct relative to the Resources folder. ```typescript const myPrefab: GameObject = Asset.LoadAsset("Local/Path/From/Resources.prefab"); ``` -------------------------------- ### Lag Compensation Check Example Source: https://github.com/easy-games/airship-docs/blob/main/characters/character-movement-system/character-movement-networking/lag-compensation.md Implement lag compensation checks by calling LagCompensationCheck on a Player object on the server. The check function should only read world state, while the processing function can modify it. ```typescript this.character.player?.LagCompensationCheck( // The first parameter is the check function. The check function will run after the position of each player has been // updated to reflect the position the client saw. // This check function should NOT modify the world, it should only read the positions of player and perform raycast checks. // If you make changes to the position or velocity of players, it will be overwritten. () => { // Do a raycast hit check. const [hit, position, normal, collider] = Physics.Raycast( this.character.movement .GetPosition() .add(new Vector3(0, 1.5, 0)), this.character.movement.GetLookVector(), WEAPON_RAYCAST_DISTANCE, this.hitLayers, ); // Pass the results to the processing function return { hit, position, normal, collider }; }, // The second parameter is the processing function. You can process the result of the check here. This function runs // with the latest state of the world, so it is safe to modify positions, apply forces, etc. ({ hit, position, normal, collider }) => { // If there was no hit, return if (!hit) return; // Get the character we hit. const hitChar = collider.gameObject.GetAirshipComponentInParent(); // If there was no character, return. if (!hitChar) return; // Inflict damage on the character we hit. hitChar.InflictDamage(10, this.character.gameObject); hitChar.movement.AddImpulse(new Vector3(0, 20, 0)); } ); ``` -------------------------------- ### Mouse Movement Polling Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/user-input/mouse.md Retrieve the current mouse position directly using the `position` field. Use the `GetDelta` method to get the change in mouse position since the last frame. ```typescript // Get current position of mouse: const screenPosition = Mouse.position; // Get movement of mouse since last frame: const delta = Mouse.GetDelta(); ``` -------------------------------- ### Spawn and Despawn Cube with NetworkIdentity Source: https://github.com/easy-games/airship-docs/blob/main/networking/network-identity.md This TypeScript code demonstrates spawning a cube prefab with a NetworkIdentity on the server and then despawning it after a delay. Ensure the 'Cube' prefab is assigned and has a NetworkIdentity component. ```typescript export default class CubeManager extends AirshipSingleton { // This is a reference to a prefab with a NetworkIdentity component public Cube: GameObject; public override Start(): void { if (Game.IsServer()) { // Spawn a cube on the server and replicate it to each player const cube = Object.Instantiate( this.Cube, new Vector3(0, 1, 0), Quaternion.identity ); NetworkServer.Spawn(cube); // Despawn cube after 4 seconds task.delay(4, () => NetworkServer.Destroy(cube)); } } } ``` -------------------------------- ### Global ServerRpc Call Source: https://github.com/easy-games/airship-docs/blob/main/networking/airshipnetworkbehaviour/serverrpc.md Demonstrates how to call a ServerRpc from a client that can be run by any player. The 'player' argument is necessary when ownership is not required. ```typescript import { AirshipNetworkBehaviour, ServerRpc } from "@Easy/Core/Shared/Network"; export default class ExampleGlobalButton extends AirshipNetworkBehaviour { // This will send a button press message to the server _only_ @ServerRpc() public PressButton(player: Player, message: string) { // Player argument necessary if not requiring ownership print("The player", player, "pressed the button with their message", message); } } ``` -------------------------------- ### Simple Interval Loop with task.spawn Source: https://github.com/easy-games/airship-docs/blob/main/other/javascript-greater-than-luau.md Implement interval behavior by spawning a new Luau coroutine with `task.spawn` that repeatedly waits and executes code. ```typescript // Simple interval loop: const interval = 3; task.spawn(() => { while (true) { task.wait(interval); // Foo } }); ``` -------------------------------- ### Get Top Scores and User Data Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/leaderboards.md Retrieves the top scores from a leaderboard and maps them to user data. Note that individual entry ranks may take up to 1 minute to reflect changes. ```typescript // Get top scores for a leaderboard in realtime // Contains an array of objects with the id, rank, and value const entries = await Platform.Server.Leaderboard.GetRankRange("TopScores"); // Get the usernames to display const idMap = await Platform.Server.User.GetUsersById(entries.map(e => e.id)); // Array of objects containing userData, rank, and scoreValue. const entriesWithUserdata = entries.map((entry) => { return { username: idMap[entry.id]?.username ?? "Unknown User", rank: entry.rank, scoreValue: entry.value, } }); ``` -------------------------------- ### Console Logging Equivalents Source: https://github.com/easy-games/airship-docs/blob/main/other/javascript-greater-than-luau.md Use `print`, `warn`, and `error` for console logging in Luau. `error` halts execution. ```typescript print("Hello world"); print("anything", "can be", "listed", 10, true, false); warn("This is a warning"); error("This is an error"); print("This won't print because the above error halted execution"); ``` -------------------------------- ### Listen for Key Presses Source: https://github.com/easy-games/airship-docs/blob/main/unity-for-airship/user-input/keyboard.md Use OnKeyDown and OnKeyUp to register callbacks for key press and release events. You can optionally specify a signal priority to control the order of execution. ```typescript Keyboard.OnKeyDown(Key.E, (event) => { print("E key down"); }); Keyboard.OnKeyUp(Key.E, (event) => { print("E key up"); }); // Optional signal priority: Keyboard.OnKeyDown(Key.E, (event) => { print("E key down, before the other one!"); }, SignalPriority.HIGH); ``` -------------------------------- ### Create a Friends Only Match Server Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/server-transfers.md Creates a server where only friends of the owner can join. The owner is then transferred to this server. ```typescript // Create a server that only friends can join const server = await Platform.Server.ServerManager.CreateServer({ sceneId: "MatchScane", accessMode: AirshipServerAccessMode.FriendsOnly }); // Transfer the owner of the match using TranferToMatchingServer await Platform.Server.Transfer.TransferToMatchingServer(player, { serverId: server.serverId, }); ``` -------------------------------- ### Create Matchmaking Group Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/matchmaking.md Server-side code to create a matchmaking group with a list of user IDs. This is the first step before joining a queue. ```typescript // Server // Create a matchmaking group with various users const createGroupResult = await Platform.Server.Matchmaking.CreateGroup( userIds, ); const groupId = createGroupResult.groupId; ``` -------------------------------- ### CubeManager Script for Spawning and Rotating Cubes Source: https://github.com/easy-games/airship-docs/blob/main/networking/network-transform.md This TypeScript script demonstrates how to spawn a networked cube prefab on the server and continuously rotate it. It utilizes Airship's Game and NetworkServer APIs. Ensure the prefab has NetworkIdentity and NetworkTransform components. ```typescript export default class CubeManager extends AirshipSingleton { // This is a reference to a prefab with NetworkIdentity and NetworkTransform // components public Cube: GameObject; // This is a reference to an instantiated cube private cubeInstance?: GameObject; public override Start(): void { if (!Game.IsServer()) return; // Spawn a cube on the server this.cubeInstance = Object.Instantiate( this.Cube, new Vector3(0, 1, 0), Quaternion.identity ); NetworkServer.Spawn(this.cubeInstance); } public override Update(dt: number): void { if (!Game.IsServer() || !this.cubeInstance) return; // Rotate the cube on the server this.cubeInstance.transform.Rotate(Vector3.up, 10 * dt); } } ``` -------------------------------- ### Cache Component References for Performance Source: https://github.com/easy-games/airship-docs/blob/main/typescript/airshipbehaviour/accessing-other-components.md Shows how to cache component references obtained via GetComponent to avoid performance overhead in per-frame methods like Update. Fetch the component once in Start and reuse the cached reference in Update. ```typescript export default class MyComponent extends AirshipBehaviour { private boxCollider: BoxCollider; public Start() { // Fetch box collider once: this.boxCollider = this.gameObject.GetComponent(); } public Update(dt: number) { // Use box collider per-frame: const closestToOrigin = this.boxCollider.ClosestPoint(Vector3.zero); } } ``` -------------------------------- ### Create and Use Network Function for Loot Crate Source: https://github.com/easy-games/airship-docs/blob/main/networking/network-functions.md Demonstrates creating a NetworkFunction for loot crates, firing it from the client to the server, and setting up a server-side callback to handle the request and return a response. This is useful for actions like opening a loot crate where the client requests an item and the server provides it. ```typescript interface CrateResponse { item: string; rarity: string; } export default class CrateManager extends AirshipSingleton { // Creating a NetworkFunction private open = new NetworkFunction<{ crateType: string }, CrateResponse>("LootCrate"); public override Start(): void { if (Game.IsClient()) { // Tell the server that you'd like to open a loot crate const loot = this.open.client.FireServer({ crateType: "weapon" }); print(`You received a ${loot.rarity} ${loot.item}`); } if (Game.IsServer()) { // Listen for player crate open requests this.openCrate.server.SetCallback((player, event) => { return { item: "sword", rarity: "legendary", } }); } } } ``` -------------------------------- ### Get Friends List Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/users.md Retrieves a list of friends for the current user. The list contains objects with user data like username and status text. Use this when you need to display a user's friends or their online status. ```typescript // Get a users friends // List of objects containing user data such as username and status text. const friends = await Platform.client.user.GetFriends(); ``` -------------------------------- ### Listen for Proximity Prompt Activation Source: https://github.com/easy-games/airship-docs/blob/main/core-package/proximity-prompts.md Connect to the `onActivated` event to execute code when a local player interacts with a prompt. This event is client-only. ```typescript import ProximityPrompt from "@Easy/Core/Shared/Input/ProximityPrompts/ProximityPrompt"; export default class PromptExample extends AirshipBehaviour { public prompt: ProximityPrompt; override Start(): void { this.prompt.onActivated.Connect(() => { print("Activated prompt"); }); } } ``` -------------------------------- ### List Server in Lobby Scene Source: https://github.com/easy-games/airship-docs/blob/main/platform-services/server-list.md Lists the server for friends to find once the first player joins the lobby. It cleans up the connection listener to prevent overwriting the owner. ```typescript // In our lobby scene on the new server, we can list the server when a player joins const cleanUpConnection = Airship.Players.onPlayerJoined.Connect(async (player) => { // The first player to connect is the owner of the lobby owner = player; // Clean up the connection so we don't overwrite the owner when another // player joins cleanUpConnection(); // List the server for the owner's friends to find await Platform.Server.ServerManager.ListServer({ name: `${owner.username}'s Server` }) }) // We can also unlist the server when the owner starts the match YourGameManager.onStartMatch.Connect(async () => { await Platform.Server.ServerManager.UnlistServer(); }) ```