From dca9f8883ae094cd1600089ba3e3c59405621d21 Mon Sep 17 00:00:00 2001 From: Brajanowski Date: Tue, 1 Jul 2025 18:57:31 +0200 Subject: [PATCH] multiplayer stuff --- .../Engine/Code/EngineCoreServicesAsset.cs | 1 + Runtime/Engine/Code/Input/InputService.cs | 9 +- .../Engine/Code/Input/InputServiceAsset.cs | 1 + .../Code/Main/NetworkWorldController.cs | 6 + .../Code/Main/NetworkWorldController.cs.meta | 3 + Runtime/Engine/Code/Main/RR.cs | 56 ++-- .../Engine/Code/Simulation/Sensors/ISensor.cs | 2 +- .../Code/Simulation/Sensors/RaycastSensor.cs | 3 +- .../Engine/Code/Steam/FacepunchTransport.cs | 277 ++++++++++++++++++ .../Code/Steam/FacepunchTransport.cs.meta | 3 + Runtime/Engine/RebootKit.Engine.asmdef | 2 +- .../Engine/core_assets/boot/scn_boot.unity | 18 +- .../core_assets/services/service_input.asset | 1 + 13 files changed, 351 insertions(+), 31 deletions(-) create mode 100644 Runtime/Engine/Code/Main/NetworkWorldController.cs create mode 100644 Runtime/Engine/Code/Main/NetworkWorldController.cs.meta create mode 100644 Runtime/Engine/Code/Steam/FacepunchTransport.cs create mode 100644 Runtime/Engine/Code/Steam/FacepunchTransport.cs.meta diff --git a/Runtime/Engine/Code/EngineCoreServicesAsset.cs b/Runtime/Engine/Code/EngineCoreServicesAsset.cs index d162778..b0e02b6 100755 --- a/Runtime/Engine/Code/EngineCoreServicesAsset.cs +++ b/Runtime/Engine/Code/EngineCoreServicesAsset.cs @@ -1,4 +1,5 @@ using RebootKit.Engine.Foundation; +using RebootKit.Engine.Input; using RebootKit.Engine.Services.Console; using RebootKit.Engine.Services.Input; using RebootKit.Engine.Services.Simulation; diff --git a/Runtime/Engine/Code/Input/InputService.cs b/Runtime/Engine/Code/Input/InputService.cs index 37cd5a4..19ce286 100644 --- a/Runtime/Engine/Code/Input/InputService.cs +++ b/Runtime/Engine/Code/Input/InputService.cs @@ -5,7 +5,7 @@ using UnityEngine.AddressableAssets; using UnityEngine.InputSystem; using UnityEngine.ResourceManagement.AsyncOperations; -namespace RebootKit.Engine.Services.Input { +namespace RebootKit.Engine.Input { public class InputService : IService { readonly Config m_Config; @@ -15,14 +15,14 @@ namespace RebootKit.Engine.Services.Input { public InputService(Config config) { m_Config = config; - m_Handle = Addressables.LoadAssetAsync(m_Config.inputAssetReference); - m_InputActionAsset = m_Handle.WaitForCompletion(); + // m_Handle = Addressables.LoadAssetAsync(m_Config.inputAssetReference); + m_InputActionAsset = config.inputActionAsset; } public void Dispose() { m_InputActionAsset = null; - Addressables.Release(m_Handle); + // Addressables.Release(m_Handle); m_Handle = default; } @@ -55,6 +55,7 @@ namespace RebootKit.Engine.Services.Input { [Serializable] public class Config { public AssetReferenceT inputAssetReference; + public InputActionAsset inputActionAsset; } } } \ No newline at end of file diff --git a/Runtime/Engine/Code/Input/InputServiceAsset.cs b/Runtime/Engine/Code/Input/InputServiceAsset.cs index 2101123..8507188 100644 --- a/Runtime/Engine/Code/Input/InputServiceAsset.cs +++ b/Runtime/Engine/Code/Input/InputServiceAsset.cs @@ -1,4 +1,5 @@ using RebootKit.Engine.Foundation; +using RebootKit.Engine.Input; using UnityEngine; namespace RebootKit.Engine.Services.Input { diff --git a/Runtime/Engine/Code/Main/NetworkWorldController.cs b/Runtime/Engine/Code/Main/NetworkWorldController.cs new file mode 100644 index 0000000..a383c5b --- /dev/null +++ b/Runtime/Engine/Code/Main/NetworkWorldController.cs @@ -0,0 +1,6 @@ +using Unity.Netcode; + +namespace RebootKit.Engine.Main { + public abstract class NetworkWorldController : NetworkBehaviour { + } +} \ No newline at end of file diff --git a/Runtime/Engine/Code/Main/NetworkWorldController.cs.meta b/Runtime/Engine/Code/Main/NetworkWorldController.cs.meta new file mode 100644 index 0000000..6020e5b --- /dev/null +++ b/Runtime/Engine/Code/Main/NetworkWorldController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: edd521a69a6f4e43b97ec258adf499a6 +timeCreated: 1751377120 \ No newline at end of file diff --git a/Runtime/Engine/Code/Main/RR.cs b/Runtime/Engine/Code/Main/RR.cs index bb8ef42..1d764b7 100755 --- a/Runtime/Engine/Code/Main/RR.cs +++ b/Runtime/Engine/Code/Main/RR.cs @@ -4,10 +4,12 @@ using System.Threading; using Cysharp.Threading.Tasks; using R3; using RebootKit.Engine.Foundation; +using RebootKit.Engine.Input; using RebootKit.Engine.Services.Console; using RebootKit.Engine.Services.Input; using RebootKit.Engine.Services.Simulation; using RebootKit.Engine.Simulation; +using RebootKit.Engine.Steam; using Unity.Netcode; using UnityEngine; using UnityEngine.AddressableAssets; @@ -24,7 +26,7 @@ namespace RebootKit.Engine.Main { [ConfigVar("con.write_log", 1, "Enables writing game log to console output")] static ConfigVar s_writeLogToConsole; - + [ConfigVar("sv.tick_rate", 60, "Server tick rate in Hz")] public static ConfigVar TickRate; @@ -41,14 +43,14 @@ namespace RebootKit.Engine.Main { public static Camera MainCamera { get; internal set; } - internal static Game GameInstance; + public static Game GameInstance { get; internal set; } public static ulong TickCount { get; private set; } public static event Action ServerTick = delegate { }; public static event Action ClientTick = delegate { }; // Lifecycle API - + // @NOTE: This method is called at the very start of the game, when boot scene loaded. internal static async UniTask InitAsync(EngineConfigAsset configAsset, CancellationToken cancellationToken) { Assert.IsNotNull(configAsset, "Config asset is required"); @@ -66,11 +68,7 @@ namespace RebootKit.Engine.Main { await InitializeAssetsAsync(cancellationToken); - // await SteamManager.InitializeAsync(cancellationToken); - - // if (SteamManager.IsInitialized) { - // s_networkTransport = SteamManager.NetworkTransport; - // } + await SteamManager.InitializeAsync(cancellationToken); } // @NOTE: This method is called after the main scene is loaded. @@ -107,14 +105,13 @@ namespace RebootKit.Engine.Main { GameInstance = null; } - if (NetworkManager.Singleton is not null) { NetworkManager.Singleton.OnConnectionEvent -= OnConnectionEvent; NetworkManager.Singleton.OnServerStarted -= OnServerStarted; NetworkManager.Singleton.OnServerStopped -= OnServerStopped; } - // SteamManager.Shutdown(); + SteamManager.Shutdown(); s_servicesBag.Dispose(); s_disposableBag.Dispose(); @@ -167,7 +164,7 @@ namespace RebootKit.Engine.Main { if (!s_mainMenuSceneHandle.IsValid()) { return; } - + Addressables.UnloadSceneAsync(s_mainMenuSceneHandle); } @@ -176,7 +173,7 @@ namespace RebootKit.Engine.Main { s_Logger.Error("Cannot set server world. Not a server instance."); return; } - + if (GameInstance is null) { s_Logger.Error("Game is not initialized. Cannot set server world."); return; @@ -189,7 +186,7 @@ namespace RebootKit.Engine.Main { s_Logger.Error($"World '{worldID}' not found"); return; } - + GameInstance.SetCurrentWorldServerRpc(worldID); } @@ -272,7 +269,7 @@ namespace RebootKit.Engine.Main { public static bool IsClient() { return NetworkManager.Singleton.IsClient; } - + public static void StartHost() { if (NetworkManager.Singleton.IsHost) { s_Logger.Error("Already hosting a server"); @@ -282,9 +279,8 @@ namespace RebootKit.Engine.Main { s_Logger.Info("Starting host"); NetworkManager.Singleton.StartHost(); } - - public static void StopServer() { - } + + public static void StopServer() { } public static void Connect() { if (NetworkManager.Singleton.IsClient) { @@ -296,9 +292,23 @@ namespace RebootKit.Engine.Main { NetworkManager.Singleton.StartClient(); } - public static void Disconnect() { + public static void ConnectWithSteamID(ulong steamId) { + if (NetworkManager.Singleton.IsClient) { + s_Logger.Error("Already connected to a server"); + return; + } + + s_Logger.Info($"Connecting to server with Steam ID: {steamId}"); + if (NetworkManager.Singleton.NetworkConfig.NetworkTransport is FacepunchTransport facepunchTransport) { + facepunchTransport.targetSteamId = steamId; + NetworkManager.Singleton.StartClient(); + } else { + s_Logger.Error("Network transport is not FacepunchTransport. Cannot connect with Steam ID."); + } } + public static void Disconnect() { } + public static void SendChatMessage(string message) { if (!IsClient()) { s_Logger.Error("Cannot send chat message. Not connected to a server."); @@ -313,16 +323,16 @@ namespace RebootKit.Engine.Main { } static float s_tickTimer; - + static void Tick() { float deltaTime = Time.deltaTime; - + float minTickTime = 1.0f / TickRate.IndexValue; s_tickTimer += deltaTime; while (s_tickTimer >= minTickTime) { s_tickTimer -= minTickTime; - + if (IsServer()) { ServerTick?.Invoke(TickCount); } @@ -333,14 +343,14 @@ namespace RebootKit.Engine.Main { TickCount++; } - + World.Tick(deltaTime); } static void OnConnectionEvent(NetworkManager network, ConnectionEventData data) { s_Logger.Info("Connection event: " + data.EventType); } - + static void OnServerStarted() { s_Logger.Info("Server started"); diff --git a/Runtime/Engine/Code/Simulation/Sensors/ISensor.cs b/Runtime/Engine/Code/Simulation/Sensors/ISensor.cs index 23938fd..9e4bfc3 100644 --- a/Runtime/Engine/Code/Simulation/Sensors/ISensor.cs +++ b/Runtime/Engine/Code/Simulation/Sensors/ISensor.cs @@ -1,6 +1,6 @@ using UnityEngine; -namespace RebootKit.Engine.Services.Simulation.Sensors { +namespace RebootKit.Engine.Simulation.Sensors { public interface ISensor { GameObject Sense(); } diff --git a/Runtime/Engine/Code/Simulation/Sensors/RaycastSensor.cs b/Runtime/Engine/Code/Simulation/Sensors/RaycastSensor.cs index b269a60..0fbb942 100644 --- a/Runtime/Engine/Code/Simulation/Sensors/RaycastSensor.cs +++ b/Runtime/Engine/Code/Simulation/Sensors/RaycastSensor.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using RebootKit.Engine.Simulation.Sensors; +using UnityEngine; namespace RebootKit.Engine.Services.Simulation.Sensors { public class RaycastSensor : ISensor { diff --git a/Runtime/Engine/Code/Steam/FacepunchTransport.cs b/Runtime/Engine/Code/Steam/FacepunchTransport.cs new file mode 100644 index 0000000..2d9bc9f --- /dev/null +++ b/Runtime/Engine/Code/Steam/FacepunchTransport.cs @@ -0,0 +1,277 @@ +// Source: https://github.com/Unity-Technologies/multiplayer-community-contributions/blob/main/Transports/com.community.netcode.transport.facepunch/Runtime/FacepunchTransport.cs + +using System; +using System.Collections; +using System.Collections.Generic; +using Steamworks; +using Steamworks.Data; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Netcode; +using UnityEngine; + +namespace RebootKit.Engine.Steam { + using SocketConnection = Connection; + + public class FacepunchTransport : NetworkTransport, IConnectionManager, ISocketManager { + private ConnectionManager connectionManager; + private SocketManager socketManager; + private Dictionary connectedClients; + + [Space] + [Tooltip("The Steam App ID of your game. Technically you're not allowed to use 480, but Valve doesn't do anything about it so it's fine for testing purposes.")] + [SerializeField] private uint steamAppId = 480; + + [Tooltip("The Steam ID of the user targeted when joining as a client.")] + [SerializeField] public ulong targetSteamId; + + [Header("Info")] + [ReadOnly] + [Tooltip("When in play mode, this will display your Steam ID.")] + [SerializeField] private ulong userSteamId; + + private LogLevel LogLevel => NetworkManager.Singleton.LogLevel; + + private class Client { + public SteamId steamId; + public SocketConnection connection; + } + +// #region MonoBehaviour Messages +// +// private void Awake() { +// try { +// SteamClient.Init(steamAppId, false); +// } catch (Exception e) { +// if (LogLevel <= LogLevel.Error) +// Debug.LogError($"[{nameof(FacepunchTransport)}] - Caught an exeption during initialization of Steam client: {e}"); +// } finally { +// StartCoroutine(InitSteamworks()); +// } +// } +// +// private void Update() { +// SteamClient.RunCallbacks(); +// } +// +// private void OnDestroy() { +// SteamClient.Shutdown(); +// } +// +// #endregion + +#region NetworkTransport Overrides + + public override ulong ServerClientId => 0; + + public override void DisconnectLocalClient() { + connectionManager?.Connection.Close(); + + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Disconnecting local client."); + } + + public override void DisconnectRemoteClient(ulong clientId) { + if (connectedClients.TryGetValue(clientId, out Client user)) { + // Flush any pending messages before closing the connection + user.connection.Flush(); + user.connection.Close(); + connectedClients.Remove(clientId); + + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Disconnecting remote client with ID {clientId}."); + } else if (LogLevel <= LogLevel.Normal) + Debug.LogWarning($"[{nameof(FacepunchTransport)}] - Failed to disconnect remote client with ID {clientId}, client not connected."); + } + + public override unsafe ulong GetCurrentRtt(ulong clientId) { + return 0; + } + + public override void Initialize(NetworkManager networkManager = null) { + connectedClients = new Dictionary(); + } + + private SendType NetworkDeliveryToSendType(NetworkDelivery delivery) { + return delivery switch { + NetworkDelivery.Reliable => SendType.Reliable, + NetworkDelivery.ReliableFragmentedSequenced => SendType.Reliable, + NetworkDelivery.ReliableSequenced => SendType.Reliable, + NetworkDelivery.Unreliable => SendType.Unreliable, + NetworkDelivery.UnreliableSequenced => SendType.Unreliable, + _ => SendType.Reliable + }; + } + + public override void Shutdown() { + try { + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Shutting down."); + + connectionManager?.Close(); + socketManager?.Close(); + } catch (Exception e) { + if (LogLevel <= LogLevel.Error) + Debug.LogError($"[{nameof(FacepunchTransport)}] - Caught an exception while shutting down: {e}"); + } + } + + public override void Send(ulong clientId, ArraySegment data, NetworkDelivery delivery) { + var sendType = NetworkDeliveryToSendType(delivery); + + if (clientId == ServerClientId) + connectionManager.Connection.SendMessage(data.Array, data.Offset, data.Count, sendType); + else if (connectedClients.TryGetValue(clientId, out Client user)) + user.connection.SendMessage(data.Array, data.Offset, data.Count, sendType); + else if (LogLevel <= LogLevel.Normal) + Debug.LogWarning($"[{nameof(FacepunchTransport)}] - Failed to send packet to remote client with ID {clientId}, client not connected."); + } + + public override NetworkEvent PollEvent(out ulong clientId, + out ArraySegment payload, + out float receiveTime) { + connectionManager?.Receive(); + socketManager?.Receive(); + + clientId = 0; + receiveTime = Time.realtimeSinceStartup; + payload = default; + return NetworkEvent.Nothing; + } + + public override bool StartClient() { + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Starting as client."); + + connectionManager = SteamNetworkingSockets.ConnectRelay(targetSteamId); + connectionManager.Interface = this; + return true; + } + + public override bool StartServer() { + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Starting as server."); + + socketManager = SteamNetworkingSockets.CreateRelaySocket(); + socketManager.Interface = this; + return true; + } + +#endregion + +#region ConnectionManager Implementation + + private byte[] payloadCache = new byte[4096]; + + private void EnsurePayloadCapacity(int size) { + if (payloadCache.Length >= size) + return; + + payloadCache = new byte[Math.Max(payloadCache.Length * 2, size)]; + } + + void IConnectionManager.OnConnecting(ConnectionInfo info) { + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Connecting with Steam user {info.Identity.SteamId}."); + } + + void IConnectionManager.OnConnected(ConnectionInfo info) { + InvokeOnTransportEvent(NetworkEvent.Connect, ServerClientId, default, Time.realtimeSinceStartup); + + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Connected with Steam user {info.Identity.SteamId}."); + } + + void IConnectionManager.OnDisconnected(ConnectionInfo info) { + InvokeOnTransportEvent(NetworkEvent.Disconnect, ServerClientId, default, Time.realtimeSinceStartup); + + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Disconnected Steam user {info.Identity.SteamId}."); + } + + unsafe void IConnectionManager.OnMessage(IntPtr data, int size, long messageNum, long recvTime, int channel) { + EnsurePayloadCapacity(size); + + fixed (byte* payload = payloadCache) { + UnsafeUtility.MemCpy(payload, (byte*) data, size); + } + + InvokeOnTransportEvent(NetworkEvent.Data, ServerClientId, new ArraySegment(payloadCache, 0, size), + Time.realtimeSinceStartup); + } + +#endregion + +#region SocketManager Implementation + + void ISocketManager.OnConnecting(SocketConnection connection, ConnectionInfo info) { + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Accepting connection from Steam user {info.Identity.SteamId}."); + + connection.Accept(); + } + + void ISocketManager.OnConnected(SocketConnection connection, ConnectionInfo info) { + if (!connectedClients.ContainsKey(connection.Id)) { + connectedClients.Add(connection.Id, new Client() { + connection = connection, + steamId = info.Identity.SteamId + }); + + InvokeOnTransportEvent(NetworkEvent.Connect, connection.Id, default, Time.realtimeSinceStartup); + + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Connected with Steam user {info.Identity.SteamId}."); + } else if (LogLevel <= LogLevel.Normal) + Debug.LogWarning($"[{nameof(FacepunchTransport)}] - Failed to connect client with ID {connection.Id}, client already connected."); + } + + void ISocketManager.OnDisconnected(SocketConnection connection, ConnectionInfo info) { + if (connectedClients.Remove(connection.Id)) { + InvokeOnTransportEvent(NetworkEvent.Disconnect, connection.Id, default, Time.realtimeSinceStartup); + + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Disconnected Steam user {info.Identity.SteamId}"); + } else if (LogLevel <= LogLevel.Normal) + Debug.LogWarning($"[{nameof(FacepunchTransport)}] - Failed to diconnect client with ID {connection.Id}, client not connected."); + } + + unsafe void ISocketManager.OnMessage(SocketConnection connection, + NetIdentity identity, + IntPtr data, + int size, + long messageNum, + long recvTime, + int channel) { + EnsurePayloadCapacity(size); + + fixed (byte* payload = payloadCache) { + UnsafeUtility.MemCpy(payload, (byte*) data, size); + } + + InvokeOnTransportEvent(NetworkEvent.Data, connection.Id, new ArraySegment(payloadCache, 0, size), + Time.realtimeSinceStartup); + } + +#endregion + +#region Utility Methods + + private IEnumerator InitSteamworks() { + yield return new WaitUntil(() => SteamClient.IsValid); + + SteamNetworkingUtils.InitRelayNetworkAccess(); + + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Initialized access to Steam Relay Network."); + + userSteamId = SteamClient.SteamId; + + if (LogLevel <= LogLevel.Developer) + Debug.Log($"[{nameof(FacepunchTransport)}] - Fetched user Steam ID."); + } + +#endregion + + } +} \ No newline at end of file diff --git a/Runtime/Engine/Code/Steam/FacepunchTransport.cs.meta b/Runtime/Engine/Code/Steam/FacepunchTransport.cs.meta new file mode 100644 index 0000000..a7eb004 --- /dev/null +++ b/Runtime/Engine/Code/Steam/FacepunchTransport.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 516179f3a4a7476ea24875d52fae3042 +timeCreated: 1751378412 \ No newline at end of file diff --git a/Runtime/Engine/RebootKit.Engine.asmdef b/Runtime/Engine/RebootKit.Engine.asmdef index 9b62f61..6351e26 100755 --- a/Runtime/Engine/RebootKit.Engine.asmdef +++ b/Runtime/Engine/RebootKit.Engine.asmdef @@ -20,7 +20,7 @@ ], "includePlatforms": [], "excludePlatforms": [], - "allowUnsafeCode": false, + "allowUnsafeCode": true, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, diff --git a/Runtime/Engine/core_assets/boot/scn_boot.unity b/Runtime/Engine/core_assets/boot/scn_boot.unity index c809c7d..f4ac9e0 100755 --- a/Runtime/Engine/core_assets/boot/scn_boot.unity +++ b/Runtime/Engine/core_assets/boot/scn_boot.unity @@ -369,6 +369,7 @@ GameObject: - component: {fileID: 1456272200} - component: {fileID: 1456272199} - component: {fileID: 1456272198} + - component: {fileID: 1456272201} m_Layer: 0 m_Name: network m_TagString: Untagged @@ -420,7 +421,7 @@ MonoBehaviour: NetworkManagerExpanded: 0 NetworkConfig: ProtocolVersion: 0 - NetworkTransport: {fileID: 1456272198} + NetworkTransport: {fileID: 1456272201} PlayerPrefab: {fileID: 0} Prefabs: NetworkPrefabsLists: @@ -462,6 +463,21 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1456272201 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1456272197} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 516179f3a4a7476ea24875d52fae3042, type: 3} + m_Name: + m_EditorClassIdentifier: + steamAppId: 480 + targetSteamId: 0 + userSteamId: 0 --- !u!1 &1509941943 GameObject: m_ObjectHideFlags: 0 diff --git a/Runtime/Engine/core_assets/services/service_input.asset b/Runtime/Engine/core_assets/services/service_input.asset index 0f2ee14..49484a9 100755 --- a/Runtime/Engine/core_assets/services/service_input.asset +++ b/Runtime/Engine/core_assets/services/service_input.asset @@ -19,3 +19,4 @@ MonoBehaviour: m_SubObjectGUID: m_SubObjectType: m_EditorAssetChanged: 0 + inputActionAsset: {fileID: -944628639613478452, guid: f991e9abd9a53ee4b94b329a5ce96cb2, type: 3}