{"id":19458725,"url":"https://github.com/improbable-eng/ims-unity-demo","last_synced_at":"2026-06-11T02:31:48.060Z","repository":{"id":66220518,"uuid":"522885399","full_name":"improbable-eng/ims-unity-demo","owner":"improbable-eng","description":null,"archived":false,"fork":false,"pushed_at":"2022-08-10T10:48:59.000Z","size":2560,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-02-25T11:48:35.803Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/improbable-eng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-09T09:32:23.000Z","updated_at":"2022-08-16T09:46:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"1b8b47ae-c1c7-47ea-9b52-ef594d75d64b","html_url":"https://github.com/improbable-eng/ims-unity-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/improbable-eng/ims-unity-demo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fims-unity-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fims-unity-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fims-unity-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fims-unity-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/improbable-eng","download_url":"https://codeload.github.com/improbable-eng/ims-unity-demo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/improbable-eng%2Fims-unity-demo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34180147,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T17:28:15.230Z","updated_at":"2026-06-11T02:31:48.038Z","avatar_url":"https://github.com/improbable-eng.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IMS Unity Demo Game\n## Overview\nThis is a demo multiplayer project built in Unity. The goal is to demonstrate:\n1. How to support [IMS Zeuz](https://docs.ims.improbable.io/docs/ims-zeuz/getting-started) orchestration in your game.\n2. How to integrate [IMS Session Manager](https://docs.ims.improbable.io/docs/ims-session-manager/getting-started) functionality into your game.\n\n## Before Getting Started\nBefore getting started, please read through the IMS [documentation](https://docs.ims.improbable.io/). Follow the tutorial to [run your first game server](https://docs.ims.improbable.io/docs/ims-zeuz/guides/my-first-payload) to familiarize yourself with IMS. You should use this project as an example of what changes you need to make to your game to support IMS services.\n\nYour game should have a separate Unity projects for the client, and the dedicated server. In order to build your dedicated server you must first install the Linux Dedicated Server Build module (and optionally the Windows one for testing locally). This can be done by opening the Unity Hub \u003e Installs \u003e Click gear icon on chosen editor version \u003e Add modules \u003e Linux Dedicated Server Build Support.\n\nIn order to start, you must already have:\n- An IMS project\n- An account linked to IMS\n- The [IMS CLI](https://docs.ims.improbable.io/docs/ims-cli/installation) downloaded\n- IMS zeuz cluster\n- dotnet\n- npm\n\nIf you do not have any of these please reach out on your Improbable Slack channel.\n\n## Setting up OpenAPI Library\nNavigate to the Assets directory of your project. Open a PowerShell terminal.\n\n[Payload API](https://docs.ims.improbable.io/openapi/ims-zeuz/payload-local-api) setup\n```\n:: Download PayloadLocal API (do this in the server project)\nInvoke-WebRequest https://docs.ims.improbable.io/redocusaurus/ims-zeuz-payload-api.yaml -OutFile Scripts\\ims-zeuz-payload-api.yaml\n\n:: Run NSwag OpenAPI generator\nnpx nswag openapi2csclient /input:ims-zeuz-payload-api.yaml /classname:PayloadApi /namespace:IMS /output:ims-payload-api.cs\n\n:: Download dependency (this may fail if already installed)\ndotnet add package System.ComponentModel.Annotations --version 4.5.0\n\n:: Install dependency\ncopy ~\\.nuget\\packages\\system.componentmodel.annotations\\4.5.0\\lib\\netstandard2.0\\System.ComponentModel.Annotations.dll .\n\n:: Clearup\ndel Scripts\\ims-zeuz-payload-api.yaml\n\n:: Change env variable to point to Mock PayloadApi server\nsetx ORCHESTRATION_PAYLOAD_API localhost:8080\n```\n\n[Session Manager API](https://docs.ims.improbable.io/openapi/ims-session-manager/session-manager-api) setup:\n```\n:: Download SessionManagerV0 API (do this in the client project)\nInvoke-WebRequest https://docs.ims.improbable.io/redocusaurus/ims-session-manager-api.yaml -OutFile Scripts\\ims-session-manager-api.yaml\n\n:: Run NSwag OpenAPI generator\nnpx nswag openapi2csclient /input:ims-session-manager-api.yaml /classname:SessionManagerApi /namespace:IMS /output:ims-session-manager-api.cs\n\n:: Download dependency (this may fail if already installed)\ndotnet add package System.ComponentModel.Annotations --version 4.5.0\n\n:: Install dependency\ncopy ~\\.nuget\\packages\\system.componentmodel.annotations\\4.5.0\\lib\\netstandard2.0\\System.ComponentModel.Annotations.dll .\n\n:: Clearup\ndel Scripts\\ims-session-manager-api.yaml\n```\n\nThe OpenAPI library provides a wrapper to communicate with Zeuz and the Session Manager. It is also possible (although not recommended) to interact with the API directly via HTTP requests. Here is an example of sending a Payload ready request:\n```\nvar httpClient = new HttpClient();\nvar content = new FormUrlEncodedContent(new Dictionary\u003cstring, string\u003e());\nvar response = await httpClient.PostAsync(\"http://\" + ORCHESTRATION_PAYLOAD_API + \"/api/v0/ready\", content);\nvar responseString = await response.Content.ReadAsStringAsync();\n// Here you must parse the JSON in 'responseString' differently depending on the returned status code\n```\nThe rest of this guide will refer to the OpenAPI wrapper functions.\n\n## Testing / Uploading\n```\n:: Run a mock Payload Api server locally on port 8080 for testing\nims orchestration payload-local-api\n\n:: Create and upload a server image to IMS Zeuz\nims image publish --project-id \"...\" --name \"...\" --description \"...\" --version \"...\" --directory \"...\"\n```\nYou also need to create an [allocation](https://docs.ims.improbable.io/docs/ims-zeuz/allocation) for your game that uses your uploaded server image. Open the [IMS Allocations Console](https://console.ims.improbable.io/orchestration/allocations) and follow [this guide](https://docs.ims.improbable.io/docs/ims-zeuz/guides/my-first-payload#create-an-allocation).\n\n## Integrating IMS Zeuz on the server\nFollow the [integration guide](https://docs.ims.improbable.io/docs/ims-zeuz/guides/integration-patterns).\n\n### [Payload ready](https://docs.ims.improbable.io/openapi/ims-zeuz/payload-local-api#tag/PayloadLocal/operation/ReadyV0)\n\nThis code alerts Zeuz that the server is ready to start accepting connections from clients.\n```\n// Create an instance of the API library\nIMS.PayloadApi payloadApi = new IMS.PayloadApi(new HttpClient());\n\n// Set IMS Zeuz Url\nvar ORCHESTRATION_PAYLOAD_API = Environment.GetEnvironmentVariable(\"ORCHESTRATION_PAYLOAD_API\");\nif (String.IsNullOrEmpty(ORCHESTRATION_PAYLOAD_API)) {\n    Debug.LogError(\"Must set the ORCHESTRATION_PAYLOAD_API environment variable!\");\n}\nelse {\n    payloadApi.BaseUrl = \"http://\" + ORCHESTRATION_PAYLOAD_API;\n}\n\n// Tell Zeuz we are ready to start accepting connections\n// Retry this call in case the PayloadLocal API is initially unavailable\nvar attempts = 0;\nwhile (true)\n{\n    try\n    {\n        await payloadApi.ReadyV0Async();\n        break;\n    }\n    catch (Exception e)\n    {\n        Debug.LogError(e);\n        attempts++;\n        if (attempts \u003e= 3)\n        {\n            Application.Quit();\n        }\n    }\n}\n```\nThe server proccess should terminate once the game is finished and players are disconnected to make space for other payloads to start.\n\n## Integrating Session Manager on the server\nFollow the [integration guide](https://docs.ims.improbable.io/docs/ims-session-manager/guides/integration#game-server).\n![integration diagram](https://docs.ims.improbable.io/assets/images/reading-config-setting-status-9227d2038ccdebb3d816681461a42e93.svg)\n### [Check when payload has been reserved](https://docs.ims.improbable.io/openapi/ims-zeuz/payload-local-api#tag/PayloadLocal/operation/GetPayloadV0)\nThis code polls Zeuz to get details about the current payload and checks whether it is in the reserved state (meaning that a session has been allocated to this payload).\n```\n// Run this in a loop\n\nIMS.GetPayloadResponseV0 res;\ntry {\n    res = await payloadApi.GetPayloadV0Async();\n}\ncatch (IMS.ApiException e) {\n    Debug.LogError(e);\n    // Handle error\n}\n\nif (res.Result.Status.State == IMS.PayloadStatusStateV0.Reserved)\n{\n    // Payload has been reserved\n    \n    // You may want to get the session config here (see below)\n\n    // You may want to set the session status here (also see below)\n\n    // Wait for other players to connect then start the game\n}\n```\n\n### [Get session config](https://docs.ims.improbable.io/openapi/ims-zeuz/payload-local-api#tag/SessionManagerLocal/operation/GetSessionConfigV0)\nSee: [configuration](https://docs.ims.improbable.io/docs/ims-session-manager/guides/integration#key-definitions)\n```\nIMS.SessionConfigV0 config;\ntry\n{\n    config = await payloadApi.GetSessionConfigV0Async();\n}\ncatch (IMS.ApiException e)\n{\n    Debug.LogError(e);\n    // Handle error\n}\n\n// Do stuff with the config\n```\n\n### [Set session status](https://docs.ims.improbable.io/openapi/ims-zeuz/payload-local-api#tag/SessionManagerLocal/paths/~1api~1v0~1session-manager~1status/post)\nSee: [status](https://docs.ims.improbable.io/docs/ims-session-manager/guides/integration#key-definitions)\n```\ntry\n{\n    await payloadApi.SetSessionStatusV0Async(new Dictionary\u003cstring, string\u003e {\n        {\"game_mode\", \"king-of-the-hill\"},\n        {\"player_count\", \"3\"}\n    });\n}\ncatch (IMS.ApiException e) {\n    Debug.LogError(e);\n    // Handle error\n}\n```\n\n## Integrating Session Manager on the client\n### [Authentication with PlayFab and creating API instance](https://docs.ims.improbable.io/docs/ims-session-manager/guides/authentication#playfab)\nThe client must be authenticated in order to make session manager API calls.\nFirst install and set up the Playfab SDK, refer to the guide [here](https://docs.microsoft.com/en-us/gaming/playfab/sdks/unity3d/quickstart).\n```\n// Run when the project loads\n[RuntimeInitializeOnLoadMethod]\npublic static void Load()\n{\n    var httpClient = new HttpClient();\n    // Create an instance of the API library\n    var sessionManagerApi = new IMS.SessionManagerApi(httpClient);\n\n    if (string.IsNullOrEmpty(PlayFabSettings.staticSettings.TitleId)){\n        /*\n        Please change the titleId below to your own titleId from PlayFab Game Manager.\n        If you have already set the value in the Editor Extensions, this can be skipped.\n        */\n        PlayFabSettings.staticSettings.TitleId = \"42\";\n    }\n    var request = new LoginWithCustomIDRequest { CustomId = \"my_custom_id\", CreateAccount = true};\n    PlayFabClientAPI.LoginWithCustomID(request, OnLoginSuccess, OnLoginFailure);\n}\n\nprivate static void OnLoginSuccess(LoginResult result)\n{\n    // Successfully connected to PlayFab!\n    var sessionTicket = result.SessionTicket;\n\n    // Send ticket as a header on future requests\n    httpClient.DefaultRequestHeaders.Add(\"Authorization\", \"Bearer secret-token:playfab/\" + sessionTicket);\n}\n\nprivate static void OnLoginFailure(PlayFabError error)\n{\n    Debug.LogError(error.GenerateErrorReport());\n    // Handle authentication error\n}\n\n// We can now use sessionManagerApi to make API calls\n```\n\n### [Creating a new session](https://docs.ims.improbable.io/openapi/ims-session-manager/session-manager-api#tag/SessionManagerV0/operation/CreateSessionV0)\nHere we create a session (sending the configuration), and receive the IP address and port number of the server running the new session.\nSee: [session type](https://docs.ims.improbable.io/docs/ims-session-manager/guides/integration#key-definitions)\n```\nvar req = new IMS.V0CreateSessionRequestBody();\n\n// Set the session config\nreq.Session_config = \"{}\";\n\nIMS.V0CreateSessionResponse res;\ntry\n{\n    res = await sessionManagerApi.CreateSessionV0Async(\"my_project_id\", \"my_session_type\", req);\n}\ncatch (IMS.ApiException e)\n{\n    Debug.LogError(e);\n    // Handle error\n}\n\nvar ip = res.Address;\nvar port = res.Ports.FirstOrDefault().Port;\n// Connect to server using the ip address and port\n```\n\n### [Listing sessions](https://docs.ims.improbable.io/openapi/ims-session-manager/session-manager-api#tag/SessionManagerV0/operation/ListSessionsV0)\n```\nIMS.V0ListSessionsResponse res;\n\ntry\n{\n    res = await sessionManagerApi.ListSessionsV0Async(\"my_project_id\", \"my_session_type\");\n}\ncatch (IMS.ApiException e)\n{\n    Debug.LogError(e);\n    // Handle error\n}\n\n// Iterate through session list\nforeach (IMS.V0Session session in res.Sessions)\n{\n    var id = session.Id;\n    var ip = session.Address;\n    var port = session.Ports.FirstOrDefault().Port;\n    var status = session.Session_status;\n    \n    // Do stuff with this session\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimprobable-eng%2Fims-unity-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimprobable-eng%2Fims-unity-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimprobable-eng%2Fims-unity-demo/lists"}