using System; using System.Runtime.InteropServices; using Newtonsoft.Json; using System.Collections.Generic; using MetaCity.Core.Messages; using UnityEngine; using UnityConsole; namespace MetaCity.Core { public class SyncController : MonoBehaviour { public static SyncController Instance { get; private set; } public PlayerInfo LocalPlayerInfo; [NonSerialized] public GameObject LocalPlayer; private readonly Dictionary _players = new Dictionary(); private float _elapsedTimeFromLastStamp = 0f; private float _stampInterval = 1f; private Dictionary messageCache = new Dictionary(); [DllImport("__Internal")] private static extern void SendMessageToJs(string jsonMessage); public Action ReceiveMessageEvent; private void Awake() { if (Instance != null && Instance != this) { Destroy(this); } else { Instance = this; } } void Start() { ConsoleCommandsDatabase.RegisterCommand("ReceiveMessage", (args => { if (args.Length != 2) { return ConsoleCommandResult.Failed("Must have 2 params. `ReceiveMessage type_int message_string`"); } var messageType = Int32.Parse(args[0]); var messageBody = args[1]; ReceiveMessageEvent.Invoke((MessageType)messageType, messageBody); return ConsoleCommandResult.Succeeded(); })); #if !UNITY_EDITOR && UNITY_WEBGL // disable WebGLInput.captureAllKeyboardInput so elements in web page can handle keyboard inputs // WebGLInput.captureAllKeyboardInput = false; #endif } void Update() { #if !UNITY_EDITOR && (UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX) string message = CloudStreaming.PeekMessage(); if (message != null) { ReceiveMessage(message); } #endif } public void ReportError(string message, bool isFatal) { SendMessage(MessageType.GameError, message); if (isFatal) { Application.Quit(-1); } } public void SendMessage(MessageType type, string body = "", bool ignoreIfNotChanged = false) { string message = JsonConvert.SerializeObject(new Message(type, body)); if (ignoreIfNotChanged) { string oldMessage; messageCache.TryGetValue(type, out oldMessage); if (message.Equals(oldMessage)) { return; } } messageCache[type] = message; #if !UNITY_EDITOR && UNITY_WEBGL SendMessageToJs(message); #elif !UNITY_EDITOR && (UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX) CloudStreaming.PostMessage(message); #else Debug.Log($"[SendMessage] MessageType: {type.ToString()} {type}\n {body}"); #endif } public void ReceiveMessage(string jsonMessage) { Message message = JsonConvert.DeserializeObject(jsonMessage); switch (message.type) { case MessageType.ApplicationQuit: #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #else Application.Quit(); #endif break; case MessageType.EnableConsole: ConsoleController.Instance.toggleKey = message.body == "1" ? KeyCode.BackQuote : KeyCode.None; break; default: break; } Debug.LogWarning("Processing message:" + jsonMessage); ReceiveMessageEvent.Invoke(message.type, message.body); } // Invoke when MessageType.PlayerJoins received public void RegisterPlayer(string userId, GameObject player) { _players.TryAdd(userId, player); } // Invoke when MessageType.PlayerExits received public void UnregisterPlayer(string userId) { _players.Remove(userId); } private void LateUpdate() { // join meeting _elapsedTimeFromLastStamp += Time.deltaTime; if (_elapsedTimeFromLastStamp >= _stampInterval) { _elapsedTimeFromLastStamp = 0; // Try to join meeting if (LocalPlayerInfo != null) { SortedList characters = new SortedList(); // GetCharactersWithinDistance(Self.Position, 2f, characters, true, false); GetPlayerWithinSphere(10f, characters, true); // Send available players to prepare join meeting SendMessage(MessageType.JoinMeeting, String.Join(",", characters.Values), true); } } } private void GetPlayerWithinSphere(float radius, SortedList charactersOut, bool excludeSelf = false, bool requireIdle = false) { float num = radius * radius; foreach (var kv in _players) { string userId = kv.Key; GameObject player = kv.Value; if (excludeSelf && userId == LocalPlayerInfo.userId) { continue; } var dist = (LocalPlayer.transform.position - player.transform.position).sqrMagnitude; if (dist < num) { charactersOut.Add(dist, userId); } } } private void OnDestroy() { ConsoleCommandsDatabase.UnRegisterCommand("ReceiveMessage"); } } }