diff --git a/Assets/PlayroomKit/PlayroomKit.cs b/Assets/PlayroomKit/PlayroomKit.cs
index 20555ea9..fa47bbc2 100644
--- a/Assets/PlayroomKit/PlayroomKit.cs
+++ b/Assets/PlayroomKit/PlayroomKit.cs
@@ -10,11 +10,10 @@
namespace Playroom
{
- public class PlayroomKit
+ public partial class PlayroomKit
{
private static bool isPlayRoomInitialized;
-
///
/// Required Mock Mode:
///
@@ -30,8 +29,6 @@ public class PlayroomKit
private static readonly Dictionary Players = new();
-
-
[Serializable]
public class InitOptions
{
@@ -1056,213 +1053,6 @@ public class Dpad
}
- // RPC:
- public enum RpcMode
- {
- ALL,
- OTHERS,
- HOST
- }
-
- private static Dictionary> rpcRegisterCallbacks = new();
- private static List rpcCalledEvents = new();
-
- [DllImport("__Internal")]
- private extern static void RpcRegisterInternal(string name, Action rpcRegisterCallback, string onResponseReturn = null);
-
- public static void RpcRegister(string name, Action rpcRegisterCallback, string onResponseReturn = null)
- {
- if (IsRunningInBrowser())
- {
- rpcRegisterCallbacks.Add(name, rpcRegisterCallback);
- RpcRegisterInternal(name, InvokeRpcRegisterCallBack, onResponseReturn);
- }
- else
- {
- Debug.LogError("[Mock Mode] RPC is currently not supported in Mock Mode!\n Please build the project to test RPC.");
- }
- }
-
- [MonoPInvokeCallback(typeof(Action))]
- private static void InvokeRpcRegisterCallBack(string dataJson, string senderJson)
- {
- try
- {
- if (!Players.ContainsKey(senderJson))
- {
- var player = new Player(senderJson);
- Players.Add(senderJson, player);
- }
-
- }
- catch (Exception ex)
- {
- Debug.LogError(ex.Message);
- }
-
-
- List updatedRpcCalledEvents = new();
- // This state is required to update the called rpc events list, (Temp fix see RpcCall for more)
- string nameJson = GetState("rpcCalledEventName");
-
- JSONArray jsonArray = JSON.Parse(nameJson).AsArray;
- foreach (JSONNode node in jsonArray)
- {
- string item = node.Value;
- updatedRpcCalledEvents.Add(item);
- }
-
- foreach (string name in updatedRpcCalledEvents)
- {
- if (rpcRegisterCallbacks.TryGetValue(name, out Action callback))
- {
- callback?.Invoke(dataJson, senderJson);
- }
- }
-
- }
-
- [DllImport("__Internal")]
- private extern static void RpcCallInternal(string name, string data, RpcMode mode, Action callbackOnResponse);
-
- private static Dictionary> OnResponseCallbacks = new Dictionary>();
-
- public static void RpcCall(string name, object data, RpcMode mode, Action callbackOnResponse)
- {
-
- if (IsRunningInBrowser())
- {
- string jsonData = ConvertToJson(data);
- if (OnResponseCallbacks.ContainsKey(name))
- {
- OnResponseCallbacks[name].Add(callbackOnResponse);
- }
- else
- {
- OnResponseCallbacks.Add(name, new List { callbackOnResponse });
- if (!rpcCalledEvents.Contains(name))
- {
- rpcCalledEvents.Add(name);
- }
- }
- JSONArray jsonArray = new JSONArray();
- foreach (string item in rpcCalledEvents)
- {
- jsonArray.Add(item);
- }
- string jsonString = jsonArray.ToString();
- /*
- This is requrired to sync the rpc events between all players, without this players won't know which event has been called.
- this is a temporary fix, RPC's need to be handled within JS for better control.
- */
- SetState("rpcCalledEventName", jsonString, reliable: true);
-
- RpcCallInternal(name, jsonData, mode, InvokeOnResponseCallback);
- }
- else
- {
- Debug.LogError("[Mock Mode] RPC Calls are not supported in Mock Mode! yet.\nPlease make a build to test RPC.");
- }
-
- }
-
- // Default Mode
- public static void RpcCall(string name, object data, Action callbackOnResponse)
- {
- RpcCall(name, data, RpcMode.ALL, callbackOnResponse);
- }
-
- [MonoPInvokeCallback(typeof(Action))]
- private static void InvokeOnResponseCallback()
- {
- var namesToRemove = new List();
-
- foreach (string name in rpcCalledEvents)
- {
- try
- {
- if (OnResponseCallbacks.TryGetValue(name, out List callbacks))
- {
- foreach (var callback in callbacks)
- {
- callback?.Invoke();
- }
-
- namesToRemove.Add(name);
- }
- }
- catch (Exception ex)
- {
- Debug.LogError($"C#: Error in Invoking callback for RPC event name: '{name}': {ex.Message}");
- }
- }
-
- foreach (var name in namesToRemove)
- {
- rpcCalledEvents.Remove(name);
- OnResponseCallbacks.Remove(name);
- }
- }
-
-
- private static string ConvertToJson(object data)
- {
- if (data == null)
- {
- return null;
- }
- else if (data.GetType().IsPrimitive || data is string)
- {
- return data.ToString();
- }
- if (data is Vector2 vector2)
- {
- return JsonUtility.ToJson(vector2);
- }
- else if (data is Vector3 vector3)
- {
- return JsonUtility.ToJson(vector3);
- }
- else if (data is Vector4 vector4)
- {
- return JsonUtility.ToJson(vector4);
- }
- else if (data is Quaternion quaternion)
- {
- return JsonUtility.ToJson(quaternion);
- }
- else
- {
- return ConvertComplexToJson(data);
- }
- }
-
- private static string ConvertComplexToJson(object data)
- {
- if (data is IDictionary dictionary)
- {
- JSONObject dictNode = new JSONObject();
- foreach (DictionaryEntry entry in dictionary)
- {
- dictNode[entry.Key.ToString()] = ConvertToJson(entry.Value);
- }
- return dictNode.ToString();
- }
- else if (data is IEnumerable enumerable)
- {
- JSONArray arrayNode = new JSONArray();
- foreach (object element in enumerable)
- {
- arrayNode.Add(ConvertToJson(element));
- }
- return arrayNode.ToString();
- }
- else
- {
- Debug.Log($"{data} is '{data.GetType()}' which is currently not supported by RPC!");
- return JSON.Parse("{}").ToString();
- }
- }
[DllImport("__Internal")]
private static extern void StartMatchmakingInternal(Action callback);
@@ -1287,628 +1077,7 @@ private static void InvokeStartMatchmakingCallback()
startMatchmakingCallback?.Invoke();
}
- // Player class
-
- public interface IPlayerInteraction
- {
- void InvokeOnQuitWrapperCallback();
- }
-
- public class Player : IPlayerInteraction
- {
-
- [Serializable]
- public class Profile
- {
- [NonSerialized]
- public UnityEngine.Color color;
-
- public JsonColor jsonColor;
- public string name;
- public string photo;
-
- [Serializable]
- public class JsonColor
- {
- public int r;
- public int g;
- public int b;
- public string hexString;
- public int hex;
- }
-
-
-
- }
-
-
- public string id;
- private static int totalObjects = 0;
-
-
- public Player(string id)
- {
- this.id = id;
- totalObjects++;
-
- if (IsRunningInBrowser())
- {
- // OnQuitCallbacks.Add(OnQuitDefaultCallback);
- }
- else
- {
- if (!isPlayRoomInitialized)///
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- else
- Debug.Log("Mock Player Created");
- }
- }
-
- private List> OnQuitCallbacks = new();
-
-
- private void OnQuitDefaultCallback()
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("Playroom not initialized yet! Please call InsertCoin.");
- }
-
- Players.Remove(id);
- }
-
- [MonoPInvokeCallback(typeof(Action))]
- private void OnQuitWrapperCallback()
- {
- if (OnQuitCallbacks != null)
- foreach (var callback in OnQuitCallbacks)
- callback?.Invoke(id);
- }
-
- void IPlayerInteraction.InvokeOnQuitWrapperCallback()
- {
- OnQuitWrapperCallback();
- }
-
- public Action OnQuit(Action callback)
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("PlayroomKit is not loaded!. Please make sure to call InsertCoin first.");
- return null;
- }
- else
- {
- OnQuitCallbacks.Add(callback);
-
- void Unsubscribe()
- {
- OnQuitCallbacks.Remove(callback);
- }
-
- return Unsubscribe;
- }
- }
-
- public void SetState(string key, int value, bool reliable = false)
- {
- if (IsRunningInBrowser())
- {
- SetPlayerStateByPlayerId(id, key, value, reliable);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- }
- else
- {
- Debug.Log($"PlayerState Set! Key: {key}, Value: {value}");
- MockSetState(key, value);
- }
- }
- }
-
-
- public void SetState(string key, float value, bool reliable = false)
- {
- if (IsRunningInBrowser())
- {
- SetPlayerStateFloatByPlayerId(id, key, value.ToString(CultureInfo.InvariantCulture), reliable);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- }
- else
- {
- Debug.Log($"PlayerState Set! Key: {key}, Value: {value}");
- MockSetState(key, value);
- }
- }
- }
-
- public void SetState(string key, bool value, bool reliable = false)
- {
- if (IsRunningInBrowser())
- {
- SetPlayerStateByPlayerId(id, key, value, reliable);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- }
- else
- {
- Debug.Log($"PlayerState Set! Key: {key}, Value: {value}");
- MockSetState(key, value);
- }
- }
- }
-
- public void SetState(string key, string value, bool reliable = false)
- {
- if (IsRunningInBrowser())
- {
- SetPlayerStateStringById(id, key, value, reliable);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- }
- else
- {
- Debug.Log($"PlayerState Set! Key: {key}, Value: {value}");
- MockSetState(key, value);
- }
- }
- }
- public void SetState(string key, object value, bool reliable = false)
- {
- if (IsRunningInBrowser())
- {
- string jsonString = JsonUtility.ToJson(value);
- SetPlayerStateStringById(id, key, jsonString, reliable);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- }
- else
- {
- Debug.Log($"State Set! Key: {key}, Value: {value}");
- MockSetState(key, value);
- }
- }
- }
-
- public T GetState(string key)
- {
- if (IsRunningInBrowser())
- {
- Type type = typeof(T);
- if (type == typeof(int)) return (T)(object)GetPlayerStateIntById(id, key);
- else if (type == typeof(float)) return (T)(object)GetPlayerStateFloatById(id, key);
- else if (type == typeof(bool)) return (T)(object)GetPlayerStateBoolById(id, key);
- else if (type == typeof(string)) return (T)(object)GetPlayerStateStringById(id, key);
- else if (type == typeof(Vector3)) return (T)(object)JsonUtility.FromJson(GetPlayerStateStringById(id, key));
- else if (type == typeof(Vector2)) return (T)(object)JsonUtility.FromJson(GetPlayerStateStringById(id, key));
- else if (type == typeof(Quaternion)) return (T)(object)JsonUtility.FromJson(GetPlayerStateStringById(id, key));
- else throw new NotSupportedException($"Type {typeof(T)} is not supported by GetState");
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- return default;
- }
- else
- {
- return MockGetState(key);
- }
- }
- }
-
-
- public Dictionary GetState(string key, bool isReturnDictionary = false)
- {
-
- if (IsRunningInBrowser() && isReturnDictionary)
- {
- var jsonString = GetPlayerStateDictionary(id, key);
- return ParseJsonToDictionary(jsonString);
- }
- else
- {
- if (isPlayRoomInitialized)
- {
- if (isReturnDictionary)
- {
- return MockGetState>(key);
- }
- else
- {
- return default;
- }
- }
- else
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- return default;
- }
- }
- }
-
- private int GetPlayerStateInt(string key)
- {
- if (IsRunningInBrowser())
- {
- return GetPlayerStateIntById(id, key);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- return default;
- }
- else
- {
- return MockGetState(key);
- }
- }
- }
-
- private float GetPlayerStateFloat(string key)
- {
- if (IsRunningInBrowser())
- {
- return GetPlayerStateFloatById(id, key);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- return default;
- }
- else
- {
- return MockGetState(key);
- }
- }
- }
-
- private string GetPlayerStateString(string key)
- {
- if (IsRunningInBrowser())
- {
- return GetPlayerStateStringById(id, key);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- return default;
- }
- else
- {
- return MockGetState(key);
- }
- }
- }
-
- private bool GetPlayerStateBool(string key)
- {
- if (IsRunningInBrowser())
- {
- if (GetPlayerStateIntById(id, key) == 1)
- {
- return true;
- }
- else if (GetPlayerStateIntById(id, key) == 0)
- {
- return false;
- }
- else
- {
- Debug.LogError("GetPlayerStateByPlayerId: " + key + " is not a bool");
- return false;
- }
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- return default;
- }
- else
- {
- return MockGetState(key);
- }
- }
- }
-
- // Dictionaries:
- public void SetState(string key, Dictionary values, bool reliable = false)
- {
- if (IsRunningInBrowser())
- {
- SetStateHelper(id, key, values, reliable);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- }
- else
- {
- Debug.Log($"PlayerState Set! Key: {key}, Value: {values}");
- MockSetState(key, values);
- }
- }
- }
-
- public void SetState(string key, Dictionary values, bool reliable = false)
- {
- if (IsRunningInBrowser())
- {
- SetStateHelper(id, key, values, reliable);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- }
- else
- {
- Debug.Log($"PlayerState Set! Key: {key}, Value: {values}");
- MockSetState(key, values);
- }
- }
- }
-
- public void SetState(string key, Dictionary values, bool reliable = false)
- {
- if (IsRunningInBrowser())
- {
- SetStateHelper(id, key, values, reliable);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- }
- else
- {
- Debug.Log($"PlayerState Set! Key: {key}, Value: {values}");
- MockSetState(key, values);
- }
- }
- }
-
- public void SetState(string key, Dictionary values, bool reliable = false)
- {
- if (IsRunningInBrowser())
- {
- SetStateHelper(id, key, values, reliable);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- }
- else
- {
- Debug.Log($"PlayerState Set! Key: {key}, Value: {values}");
- MockSetState(key, values);
- }
- }
- }
-
- public void WaitForState(string StateKey, Action onStateSetCallback = null)
- {
- if (IsRunningInBrowser())
- {
- WaitForPlayerStateInternal(id, StateKey, onStateSetCallback);
- }
- }
-
- public void Kick(Action OnKickCallBack = null)
- {
- if (IsRunningInBrowser())
- {
- OnKickCallBack = onKickCallBack;
- KickInternal(id, InvokeKickCallBack);
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- return;
- }
- else
- {
- var player = GetPlayer(PlayerId);
- Players.Remove(player.id);
- onKickCallBack?.Invoke();
- }
- }
- }
-
- [DllImport("__Internal")]
- private static extern void SetPlayerStateByPlayerId(string playerID, string key, int value,
- bool reliable = false);
-
- [DllImport("__Internal")]
- private static extern void SetPlayerStateFloatByPlayerId(string playerID, string key, string value,
- bool reliable = false);
-
- [DllImport("__Internal")]
- private static extern void SetPlayerStateByPlayerId(string playerID, string key, bool value,
- bool reliable = false);
-
- [DllImport("__Internal")]
- private static extern void SetPlayerStateStringById(string playerID, string key, string value,
- bool reliable = false);
-
- [DllImport("__Internal")]
- private static extern string GetProfileByPlayerId(string playerID);
-
- private static Profile ParseProfile(string json)
- {
- var jsonNode = JSON.Parse(json);
- var profileData = new Profile();
- profileData.jsonColor = new Profile.JsonColor
- {
- r = jsonNode["color"]["r"].AsInt,
- g = jsonNode["color"]["g"].AsInt,
- b = jsonNode["color"]["b"].AsInt,
- hexString = jsonNode["color"]["hexString"].Value,
- hex = jsonNode["color"]["hex"].AsInt
- };
-
- ColorUtility.TryParseHtmlString(profileData.jsonColor.hexString, out UnityEngine.Color color1);
- profileData.color = color1;
- profileData.name = jsonNode["name"].Value;
- profileData.photo = jsonNode["photo"].Value;
-
- return profileData;
- }
-
- public Profile GetProfile()
- {
- if (IsRunningInBrowser())
- {
- var jsonString = GetProfileByPlayerId(id);
- var profileData = ParseProfile(jsonString);
- return profileData;
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- return default;
- }
- else
- {
- Profile.JsonColor mockJsonColor = new()
- {
- r = 166,
- g = 0,
- b = 142,
- hexString = "#a6008e"
- };
- ColorUtility.TryParseHtmlString(mockJsonColor.hexString, out UnityEngine.Color color1);
- var testProfile = new Profile()
- {
- color = color1,
- name = "CoolPlayTest",
- jsonColor = mockJsonColor,
- photo = "testPhoto"
-
- };
- return testProfile;
- }
- }
- }
-
-
- private static Action onKickCallBack = null;
-
- [MonoPInvokeCallback(typeof(Action))]
- private static void InvokeKickCallBack()
- {
- onKickCallBack?.Invoke();
- }
-
- [DllImport("__Internal")]
- private static extern void KickInternal(string playerID, Action onKickCallBack = null);
-
- [DllImport("__Internal")]
- private static extern void WaitForPlayerStateInternal(string playerID, string stateKey, Action onStateSetCallback = null);
-
-
- private static bool GetPlayerStateBoolById(string id, string key)
- {
- if (IsRunningInBrowser())
- {
- var stateValue = GetPlayerStateIntById(id, key);
- return stateValue == 1 ? true :
- stateValue == 0 ? false :
- throw new InvalidOperationException($"GetStateBool: {key} is not a bool");
- }
- else
- {
- if (!isPlayRoomInitialized)
- {
- Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
- return false;
- }
- else
- {
- return MockGetState(key);
- }
- }
- }
-
- [DllImport("__Internal")]
- private static extern int GetPlayerStateIntById(string playerID, string key);
-
- [DllImport("__Internal")]
- private static extern float GetPlayerStateFloatById(string playerID, string key);
-
- [DllImport("__Internal")]
- private static extern string GetPlayerStateStringById(string playerID, string key);
-
- // Helpers
- [DllImport("__Internal")]
- private static extern void SetPlayerStateDictionary(string playerID, string key, string jsonValues,
- bool reliable = false);
-
- [DllImport("__Internal")]
- private static extern string GetPlayerStateDictionary(string playerID, string key);
-
- private void SetStateHelper(string id, string key, Dictionary values, bool reliable = false)
- {
- var jsonObject = new JSONObject();
-
- // Add key-value pairs to the JSON object
- foreach (var kvp in values)
- {
- // Convert the value to double before adding to JSONNode
- var value = Convert.ToDouble(kvp.Value);
- jsonObject.Add(kvp.Key, value);
- }
-
- // Serialize the JSON object to a string
- var jsonString = jsonObject.ToString();
-
- // Output the JSON string
- SetPlayerStateDictionary(id, key, jsonString, reliable);
- }
-
-
- }
}
diff --git a/Assets/PlayroomKit/modules.meta b/Assets/PlayroomKit/modules.meta
new file mode 100644
index 00000000..c9d80163
--- /dev/null
+++ b/Assets/PlayroomKit/modules.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 79a6747e9bd7d634ab4eda87b3573984
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/PlayroomKit/modules/Player.cs b/Assets/PlayroomKit/modules/Player.cs
new file mode 100644
index 00000000..a0a815f0
--- /dev/null
+++ b/Assets/PlayroomKit/modules/Player.cs
@@ -0,0 +1,641 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using AOT;
+using SimpleJSON;
+using UnityEngine;
+
+namespace Playroom
+{
+ // Player class
+
+
+
+ public partial class PlayroomKit
+ {
+
+ public interface IPlayerInteraction
+ {
+ void InvokeOnQuitWrapperCallback();
+ }
+
+ public class Player : IPlayerInteraction
+ {
+ [Serializable]
+ public class Profile
+ {
+ [NonSerialized]
+ public UnityEngine.Color color;
+
+ public JsonColor jsonColor;
+ public string name;
+ public string photo;
+
+ [Serializable]
+ public class JsonColor
+ {
+ public int r;
+ public int g;
+ public int b;
+ public string hexString;
+ public int hex;
+ }
+
+
+
+ }
+
+
+ public string id;
+ private static int totalObjects = 0;
+
+
+ public Player(string id)
+ {
+ this.id = id;
+ totalObjects++;
+
+ if (IsRunningInBrowser())
+ {
+ // OnQuitCallbacks.Add(OnQuitDefaultCallback);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)///
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ else
+ Debug.Log("Mock Player Created");
+ }
+ }
+
+ private List> OnQuitCallbacks = new();
+
+
+ private void OnQuitDefaultCallback()
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("Playroom not initialized yet! Please call InsertCoin.");
+ }
+
+ Players.Remove(id);
+ }
+
+ [MonoPInvokeCallback(typeof(Action))]
+ private void OnQuitWrapperCallback()
+ {
+ if (OnQuitCallbacks != null)
+ foreach (var callback in OnQuitCallbacks)
+ callback?.Invoke(id);
+ }
+
+ void IPlayerInteraction.InvokeOnQuitWrapperCallback()
+ {
+ OnQuitWrapperCallback();
+ }
+
+ public Action OnQuit(Action callback)
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("PlayroomKit is not loaded!. Please make sure to call InsertCoin first.");
+ return null;
+ }
+ else
+ {
+ OnQuitCallbacks.Add(callback);
+
+ void Unsubscribe()
+ {
+ OnQuitCallbacks.Remove(callback);
+ }
+
+ return Unsubscribe;
+ }
+ }
+
+ public void SetState(string key, int value, bool reliable = false)
+ {
+ if (IsRunningInBrowser())
+ {
+ SetPlayerStateByPlayerId(id, key, value, reliable);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ }
+ else
+ {
+ Debug.Log($"PlayerState Set! Key: {key}, Value: {value}");
+ MockSetState(key, value);
+ }
+ }
+ }
+
+
+ public void SetState(string key, float value, bool reliable = false)
+ {
+ if (IsRunningInBrowser())
+ {
+ SetPlayerStateFloatByPlayerId(id, key, value.ToString(CultureInfo.InvariantCulture), reliable);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ }
+ else
+ {
+ Debug.Log($"PlayerState Set! Key: {key}, Value: {value}");
+ MockSetState(key, value);
+ }
+ }
+ }
+
+ public void SetState(string key, bool value, bool reliable = false)
+ {
+ if (IsRunningInBrowser())
+ {
+ SetPlayerStateByPlayerId(id, key, value, reliable);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ }
+ else
+ {
+ Debug.Log($"PlayerState Set! Key: {key}, Value: {value}");
+ MockSetState(key, value);
+ }
+ }
+ }
+
+ public void SetState(string key, string value, bool reliable = false)
+ {
+ if (IsRunningInBrowser())
+ {
+ SetPlayerStateStringById(id, key, value, reliable);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ }
+ else
+ {
+ Debug.Log($"PlayerState Set! Key: {key}, Value: {value}");
+ MockSetState(key, value);
+ }
+ }
+ }
+
+ public void SetState(string key, object value, bool reliable = false)
+ {
+ if (IsRunningInBrowser())
+ {
+ string jsonString = JsonUtility.ToJson(value);
+ SetPlayerStateStringById(id, key, jsonString, reliable);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ }
+ else
+ {
+ Debug.Log($"State Set! Key: {key}, Value: {value}");
+ MockSetState(key, value);
+ }
+ }
+ }
+
+ public T GetState(string key)
+ {
+ if (IsRunningInBrowser())
+ {
+ Type type = typeof(T);
+ if (type == typeof(int)) return (T)(object)GetPlayerStateIntById(id, key);
+ else if (type == typeof(float)) return (T)(object)GetPlayerStateFloatById(id, key);
+ else if (type == typeof(bool)) return (T)(object)GetPlayerStateBoolById(id, key);
+ else if (type == typeof(string)) return (T)(object)GetPlayerStateStringById(id, key);
+ else if (type == typeof(Vector3)) return (T)(object)JsonUtility.FromJson(GetPlayerStateStringById(id, key));
+ else if (type == typeof(Vector2)) return (T)(object)JsonUtility.FromJson(GetPlayerStateStringById(id, key));
+ else if (type == typeof(Quaternion)) return (T)(object)JsonUtility.FromJson(GetPlayerStateStringById(id, key));
+ else throw new NotSupportedException($"Type {typeof(T)} is not supported by GetState");
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ return default;
+ }
+ else
+ {
+ return MockGetState(key);
+ }
+ }
+ }
+
+
+ public Dictionary GetState(string key, bool isReturnDictionary = false)
+ {
+
+ if (IsRunningInBrowser() && isReturnDictionary)
+ {
+ var jsonString = GetPlayerStateDictionary(id, key);
+ return ParseJsonToDictionary(jsonString);
+ }
+ else
+ {
+ if (isPlayRoomInitialized)
+ {
+ if (isReturnDictionary)
+ {
+ return MockGetState>(key);
+ }
+ else
+ {
+ return default;
+ }
+ }
+ else
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ return default;
+ }
+ }
+ }
+
+ private int GetPlayerStateInt(string key)
+ {
+ if (IsRunningInBrowser())
+ {
+ return GetPlayerStateIntById(id, key);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ return default;
+ }
+ else
+ {
+ return MockGetState(key);
+ }
+ }
+ }
+
+ private float GetPlayerStateFloat(string key)
+ {
+ if (IsRunningInBrowser())
+ {
+ return GetPlayerStateFloatById(id, key);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ return default;
+ }
+ else
+ {
+ return MockGetState(key);
+ }
+ }
+ }
+
+ private string GetPlayerStateString(string key)
+ {
+ if (IsRunningInBrowser())
+ {
+ return GetPlayerStateStringById(id, key);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ return default;
+ }
+ else
+ {
+ return MockGetState(key);
+ }
+ }
+ }
+
+ private bool GetPlayerStateBool(string key)
+ {
+ if (IsRunningInBrowser())
+ {
+ if (GetPlayerStateIntById(id, key) == 1)
+ {
+ return true;
+ }
+ else if (GetPlayerStateIntById(id, key) == 0)
+ {
+ return false;
+ }
+ else
+ {
+ Debug.LogError("GetPlayerStateByPlayerId: " + key + " is not a bool");
+ return false;
+ }
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ return default;
+ }
+ else
+ {
+ return MockGetState(key);
+ }
+ }
+ }
+
+ // Dictionaries:
+ public void SetState(string key, Dictionary values, bool reliable = false)
+ {
+ if (IsRunningInBrowser())
+ {
+ SetStateHelper(id, key, values, reliable);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ }
+ else
+ {
+ Debug.Log($"PlayerState Set! Key: {key}, Value: {values}");
+ MockSetState(key, values);
+ }
+ }
+ }
+
+ public void SetState(string key, Dictionary values, bool reliable = false)
+ {
+ if (IsRunningInBrowser())
+ {
+ SetStateHelper(id, key, values, reliable);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ }
+ else
+ {
+ Debug.Log($"PlayerState Set! Key: {key}, Value: {values}");
+ MockSetState(key, values);
+ }
+ }
+ }
+
+ public void SetState(string key, Dictionary values, bool reliable = false)
+ {
+ if (IsRunningInBrowser())
+ {
+ SetStateHelper(id, key, values, reliable);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ }
+ else
+ {
+ Debug.Log($"PlayerState Set! Key: {key}, Value: {values}");
+ MockSetState(key, values);
+ }
+ }
+ }
+
+ public void SetState(string key, Dictionary values, bool reliable = false)
+ {
+ if (IsRunningInBrowser())
+ {
+ SetStateHelper(id, key, values, reliable);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ }
+ else
+ {
+ Debug.Log($"PlayerState Set! Key: {key}, Value: {values}");
+ MockSetState(key, values);
+ }
+ }
+ }
+
+ public void WaitForState(string StateKey, Action onStateSetCallback = null)
+ {
+ if (IsRunningInBrowser())
+ {
+ WaitForPlayerStateInternal(id, StateKey, onStateSetCallback);
+ }
+ }
+
+ public void Kick(Action OnKickCallBack = null)
+ {
+ if (IsRunningInBrowser())
+ {
+ OnKickCallBack = onKickCallBack;
+ KickInternal(id, InvokeKickCallBack);
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ return;
+ }
+ else
+ {
+ var player = GetPlayer(PlayerId);
+ Players.Remove(player.id);
+ onKickCallBack?.Invoke();
+ }
+ }
+ }
+
+
+
+ private static Profile ParseProfile(string json)
+ {
+ var jsonNode = JSON.Parse(json);
+ var profileData = new Profile();
+ profileData.jsonColor = new Profile.JsonColor
+ {
+ r = jsonNode["color"]["r"].AsInt,
+ g = jsonNode["color"]["g"].AsInt,
+ b = jsonNode["color"]["b"].AsInt,
+ hexString = jsonNode["color"]["hexString"].Value,
+ hex = jsonNode["color"]["hex"].AsInt
+ };
+
+ ColorUtility.TryParseHtmlString(profileData.jsonColor.hexString, out UnityEngine.Color color1);
+ profileData.color = color1;
+ profileData.name = jsonNode["name"].Value;
+ profileData.photo = jsonNode["photo"].Value;
+
+ return profileData;
+ }
+
+ public Profile GetProfile()
+ {
+ if (IsRunningInBrowser())
+ {
+ var jsonString = GetProfileByPlayerId(id);
+ var profileData = ParseProfile(jsonString);
+ return profileData;
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ return default;
+ }
+ else
+ {
+ Profile.JsonColor mockJsonColor = new()
+ {
+ r = 166,
+ g = 0,
+ b = 142,
+ hexString = "#a6008e"
+ };
+ ColorUtility.TryParseHtmlString(mockJsonColor.hexString, out UnityEngine.Color color1);
+ var testProfile = new Profile()
+ {
+ color = color1,
+ name = "CoolPlayTest",
+ jsonColor = mockJsonColor,
+ photo = "testPhoto"
+
+ };
+ return testProfile;
+ }
+ }
+ }
+
+
+ private static Action onKickCallBack = null;
+
+ [MonoPInvokeCallback(typeof(Action))]
+ private static void InvokeKickCallBack()
+ {
+ onKickCallBack?.Invoke();
+ }
+
+
+ private static bool GetPlayerStateBoolById(string id, string key)
+ {
+ if (IsRunningInBrowser())
+ {
+ var stateValue = GetPlayerStateIntById(id, key);
+ return stateValue == 1 ? true :
+ stateValue == 0 ? false :
+ throw new InvalidOperationException($"GetStateBool: {key} is not a bool");
+ }
+ else
+ {
+ if (!isPlayRoomInitialized)
+ {
+ Debug.LogError("[Mock Mode] Playroom not initialized yet! Please call InsertCoin.");
+ return false;
+ }
+ else
+ {
+ return MockGetState(key);
+ }
+ }
+ }
+
+
+
+ private void SetStateHelper(string id, string key, Dictionary values, bool reliable = false)
+ {
+ var jsonObject = new JSONObject();
+
+ // Add key-value pairs to the JSON object
+ foreach (var kvp in values)
+ {
+ // Convert the value to double before adding to JSONNode
+ var value = Convert.ToDouble(kvp.Value);
+ jsonObject.Add(kvp.Key, value);
+ }
+
+ // Serialize the JSON object to a string
+ var jsonString = jsonObject.ToString();
+
+ // Output the JSON string
+ SetPlayerStateDictionary(id, key, jsonString, reliable);
+ }
+
+ [DllImport("__Internal")]
+ private static extern void KickInternal(string playerID, Action onKickCallBack = null);
+
+ [DllImport("__Internal")]
+ private static extern void WaitForPlayerStateInternal(string playerID, string stateKey, Action onStateSetCallback = null);
+
+ [DllImport("__Internal")]
+ private static extern void SetPlayerStateByPlayerId(string playerID, string key, int value,
+ bool reliable = false);
+
+ [DllImport("__Internal")]
+ private static extern void SetPlayerStateFloatByPlayerId(string playerID, string key, string value,
+ bool reliable = false);
+
+ [DllImport("__Internal")]
+ private static extern void SetPlayerStateByPlayerId(string playerID, string key, bool value,
+ bool reliable = false);
+
+ [DllImport("__Internal")]
+ private static extern void SetPlayerStateDictionary(string playerID, string key, string jsonValues,
+ bool reliable = false);
+
+ [DllImport("__Internal")]
+ private static extern void SetPlayerStateStringById(string playerID, string key, string value,
+ bool reliable = false);
+
+ [DllImport("__Internal")]
+ private static extern int GetPlayerStateIntById(string playerID, string key);
+
+ [DllImport("__Internal")]
+ private static extern float GetPlayerStateFloatById(string playerID, string key);
+
+ [DllImport("__Internal")]
+ private static extern string GetPlayerStateStringById(string playerID, string key);
+
+
+ [DllImport("__Internal")]
+ private static extern string GetPlayerStateDictionary(string playerID, string key);
+
+ [DllImport("__Internal")]
+ private static extern string GetProfileByPlayerId(string playerID);
+ }
+ }
+}
diff --git a/Assets/PlayroomKit/modules/Player.cs.meta b/Assets/PlayroomKit/modules/Player.cs.meta
new file mode 100644
index 00000000..76a139f3
--- /dev/null
+++ b/Assets/PlayroomKit/modules/Player.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dee2bc384854b2843a7a68de0436f253
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/PlayroomKit/modules/RPC.cs b/Assets/PlayroomKit/modules/RPC.cs
new file mode 100644
index 00000000..75011d60
--- /dev/null
+++ b/Assets/PlayroomKit/modules/RPC.cs
@@ -0,0 +1,221 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using AOT;
+using SimpleJSON;
+using UnityEngine;
+
+namespace Playroom
+{
+ public partial class PlayroomKit
+ {
+ // RPC:
+ public enum RpcMode
+ {
+ ALL,
+ OTHERS,
+ HOST
+ }
+
+ private static Dictionary> rpcRegisterCallbacks = new();
+ private static List rpcCalledEvents = new();
+
+ [DllImport("__Internal")]
+ private extern static void RpcRegisterInternal(string name, Action rpcRegisterCallback, string onResponseReturn = null);
+
+ public static void RpcRegister(string name, Action rpcRegisterCallback, string onResponseReturn = null)
+ {
+ if (IsRunningInBrowser())
+ {
+ rpcRegisterCallbacks.Add(name, rpcRegisterCallback);
+ RpcRegisterInternal(name, InvokeRpcRegisterCallBack, onResponseReturn);
+ }
+ else
+ {
+ Debug.LogError("[Mock Mode] RPC is currently not supported in Mock Mode!\n Please build the project to test RPC.");
+ }
+ }
+
+ [MonoPInvokeCallback(typeof(Action))]
+ private static void InvokeRpcRegisterCallBack(string dataJson, string senderJson)
+ {
+ try
+ {
+ if (!Players.ContainsKey(senderJson))
+ {
+ var player = new Player(senderJson);
+ Players.Add(senderJson, player);
+ }
+
+ }
+ catch (Exception ex)
+ {
+ Debug.LogError(ex.Message);
+ }
+
+
+ List updatedRpcCalledEvents = new();
+ // This state is required to update the called rpc events list, (Temp fix see RpcCall for more)
+ string nameJson = GetState("rpcCalledEventName");
+
+ JSONArray jsonArray = JSON.Parse(nameJson).AsArray;
+ foreach (JSONNode node in jsonArray)
+ {
+ string item = node.Value;
+ updatedRpcCalledEvents.Add(item);
+ }
+
+ foreach (string name in updatedRpcCalledEvents)
+ {
+ if (rpcRegisterCallbacks.TryGetValue(name, out Action callback))
+ {
+ callback?.Invoke(dataJson, senderJson);
+ }
+ }
+
+ }
+
+ [DllImport("__Internal")]
+ private extern static void RpcCallInternal(string name, string data, RpcMode mode, Action callbackOnResponse);
+
+ private static Dictionary> OnResponseCallbacks = new Dictionary>();
+
+ public static void RpcCall(string name, object data, RpcMode mode, Action callbackOnResponse)
+ {
+
+ if (IsRunningInBrowser())
+ {
+ string jsonData = ConvertToJson(data);
+ if (OnResponseCallbacks.ContainsKey(name))
+ {
+ OnResponseCallbacks[name].Add(callbackOnResponse);
+ }
+ else
+ {
+ OnResponseCallbacks.Add(name, new List { callbackOnResponse });
+ if (!rpcCalledEvents.Contains(name))
+ {
+ rpcCalledEvents.Add(name);
+ }
+ }
+ JSONArray jsonArray = new JSONArray();
+ foreach (string item in rpcCalledEvents)
+ {
+ jsonArray.Add(item);
+ }
+ string jsonString = jsonArray.ToString();
+ /*
+ This is requrired to sync the rpc events between all players, without this players won't know which event has been called.
+ this is a temporary fix, RPC's need to be handled within JS for better control.
+ */
+ SetState("rpcCalledEventName", jsonString, reliable: true);
+
+ RpcCallInternal(name, jsonData, mode, InvokeOnResponseCallback);
+ }
+ else
+ {
+ Debug.LogError("[Mock Mode] RPC Calls are not supported in Mock Mode! yet.\nPlease make a build to test RPC.");
+ }
+
+ }
+
+ // Default Mode
+ public static void RpcCall(string name, object data, Action callbackOnResponse)
+ {
+ RpcCall(name, data, RpcMode.ALL, callbackOnResponse);
+ }
+
+ [MonoPInvokeCallback(typeof(Action))]
+ private static void InvokeOnResponseCallback()
+ {
+ var namesToRemove = new List();
+
+ foreach (string name in rpcCalledEvents)
+ {
+ try
+ {
+ if (OnResponseCallbacks.TryGetValue(name, out List callbacks))
+ {
+ foreach (var callback in callbacks)
+ {
+ callback?.Invoke();
+ }
+
+ namesToRemove.Add(name);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.LogError($"C#: Error in Invoking callback for RPC event name: '{name}': {ex.Message}");
+ }
+ }
+
+ foreach (var name in namesToRemove)
+ {
+ rpcCalledEvents.Remove(name);
+ OnResponseCallbacks.Remove(name);
+ }
+ }
+
+
+ private static string ConvertToJson(object data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ else if (data.GetType().IsPrimitive || data is string)
+ {
+ return data.ToString();
+ }
+ if (data is Vector2 vector2)
+ {
+ return JsonUtility.ToJson(vector2);
+ }
+ else if (data is Vector3 vector3)
+ {
+ return JsonUtility.ToJson(vector3);
+ }
+ else if (data is Vector4 vector4)
+ {
+ return JsonUtility.ToJson(vector4);
+ }
+ else if (data is Quaternion quaternion)
+ {
+ return JsonUtility.ToJson(quaternion);
+ }
+ else
+ {
+ return ConvertComplexToJson(data);
+ }
+ }
+
+ private static string ConvertComplexToJson(object data)
+ {
+ if (data is IDictionary dictionary)
+ {
+ JSONObject dictNode = new JSONObject();
+ foreach (DictionaryEntry entry in dictionary)
+ {
+ dictNode[entry.Key.ToString()] = ConvertToJson(entry.Value);
+ }
+ return dictNode.ToString();
+ }
+ else if (data is IEnumerable enumerable)
+ {
+ JSONArray arrayNode = new JSONArray();
+ foreach (object element in enumerable)
+ {
+ arrayNode.Add(ConvertToJson(element));
+ }
+ return arrayNode.ToString();
+ }
+ else
+ {
+ Debug.Log($"{data} is '{data.GetType()}' which is currently not supported by RPC!");
+ return JSON.Parse("{}").ToString();
+ }
+ }
+ }
+}
diff --git a/Assets/PlayroomKit/modules/RPC.cs.meta b/Assets/PlayroomKit/modules/RPC.cs.meta
new file mode 100644
index 00000000..0de8f1fc
--- /dev/null
+++ b/Assets/PlayroomKit/modules/RPC.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: daadfc50e11096c4598b324f48edf1e9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: