using MonomiPark.SlimeRancher.Persist; using MonomiPark.SlimeRancher.Regions; using SRMultiplayer.Networking; using SRMultiplayer.Packets; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using UnityEngine; using UnityEngine.SceneManagement; namespace SRMultiplayer { public class SRMP : SRSingleton { public static string ModDataPath { get { return Path.Combine(Application.dataPath, "..", "SRMP"); } } private float m_LastTimeSync; /// /// Acts as the initializer for the Mod /// public override void Awake() { base.Awake(); //attach scene manager to trigger event when in a menu or loading up a game SceneManager.activeSceneChanged += SceneManager_activeSceneChanged; //attach log messager to log all game errors and exceptions into the SRMP Logs Application.logMessageReceived += Application_logMessageReceived; //load up mod specific resources var myLoadedAssetBundle = AssetBundle.LoadFromMemory(Utils.ExtractResource("SRMultiplayer.srmultiplayer.dat")); if (myLoadedAssetBundle == null) { SRMP.Log("Failed to load AssetBundle!"); return; } //load up the Player moment animator for the Beatrix model Globals.BeatrixController = myLoadedAssetBundle.LoadAsset("Controller"); //unused prefab menus, these menus functions are handled in the floating gui //Globals.IngameMultiplayerMenuPrefab = myLoadedAssetBundle.LoadAsset("IngameMultiplayerMenu"); //Globals.MainMultiplayerMenuPrefab = myLoadedAssetBundle.LoadAsset("MainMultiplayerMenu"); } /// /// Subscriber to the Applicaiton log and process it on to the Mods console /// /// Log condition /// Stack trace of log strigger (if applicable) /// Log Type private void Application_logMessageReceived(string condition, string stackTrace, LogType type) { //if Error or Exception hand the error of to the Mods log/console to display if(type == LogType.Error || type == LogType.Exception) { SRMP.Log(condition); if (!string.IsNullOrEmpty(stackTrace)) SRMP.Log(stackTrace); } } private void Start() { //var menuObj = Instantiate(Globals.MainMultiplayerMenuPrefab, null, false); //menuObj.AddComponent(); } /// /// After triggering base destroy /// trigger disconnect and shut down the server /// public override void OnDestroy() { base.OnDestroy(); NetworkClient.Instance.Disconnect(); NetworkServer.Instance.Disconnect(); } /// /// On Game quit trigger disconnect and shut down the server /// private void OnApplicationQuit() { NetworkClient.Instance.Disconnect(); NetworkServer.Instance.Disconnect(); } /// /// On Update triggered sync up game time /// private void Update() { if(Globals.GameLoaded) { if(Globals.IsServer) { //every 30 seconds send a time updater out to all clients if(Time.time - m_LastTimeSync > 30) { m_LastTimeSync = Time.time; new PacketWorldTime() { Time = SRSingleton.Instance.TimeDirector.WorldTime() }.Send(); } } //if(Time.time - m_LastActorTime > 0.5f) //{ // foreach(var actor in Globals.Actors.Values.ToList()) // { // if(actor.IsLocal && !actor.gameObject.activeInHierarchy) // { // actor.DropOwnership(); // //SRMP.Log($"Dropping actor {actor.name} ({actor.ID}) as it's unloaded"); // } // } //} } } /// /// Handle scene changed events triggered by the game /// /// Scene previously /// New Scene private void SceneManager_activeSceneChanged(Scene from, Scene to) { //trigger handlers for returning or going to the main menu if (to.buildIndex == 2) OnMainMenuLoaded(); //trigger handlers for loading the game else if (to.buildIndex == 3) OnGameLoaded(); } /// /// Handle user changing to the main menu, whether it is start up or from saving/ being kicked out of the game /// private void OnMainMenuLoaded() { //var menuObj = Instantiate(Globals.MainMultiplayerMenuPrefab, null, false); //menuObj.AddComponent(); //innitialize all necessary global variables Globals.LocalID = 0; Globals.DisableAchievements = false; Globals.GameLoaded = false; Globals.ClientLoaded = false; Globals.LocalPlayer = null; Globals.Audios.Clear(); Globals.Actors.Clear(); Globals.Regions.Clear(); Globals.LandPlots.Clear(); Globals.SpawnResources.Clear(); Globals.FXPrefabs.Clear(); Globals.AccessDoors.Clear(); Globals.Gordos.Clear(); Globals.PuzzleSlots.Clear(); Globals.Switches.Clear(); Globals.GadgetSites.Clear(); Globals.PacketSize.Clear(); Globals.Spawners.Clear(); Globals.TreasurePods.Clear(); Globals.ExchangeAcceptors.Clear(); Globals.FireColumns.Clear(); Globals.Kookadobas.Clear(); Globals.LemonTrees.Clear(); Globals.Nutcrackers.Clear(); Globals.RaceTriggers.Clear(); NetworkAmmo.All.Clear(); //clean up any lingering players in the global list foreach (var player in Globals.Players.Values.ToList()) { if(player != null && player.gameObject != null) { Destroy(player.gameObject); } } Globals.Players.Clear(); //reset the chat ChatUI.Instance.Clear(); } /// /// Handle the user loading into the multiplayer game /// private void OnGameLoaded() { System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); var ranchui = Resources.FindObjectsOfTypeAll().FirstOrDefault(); if (ranchui != null) { Globals.BeatrixModel = Instantiate(ranchui.beatrixPrefab.transform.GetChild(1).GetChild(0).gameObject); Globals.BeatrixModel.transform.localScale *= 0.75f; Globals.BeatrixModel.SetActive(false); Utils.SetLayer(Globals.BeatrixModel, 0); } foreach (var audio in Resources.FindObjectsOfTypeAll()) { Globals.Audios.Add(audio.name, audio); } var splashOnTrigger = GameObject.FindObjectOfType(); Globals.FXPrefabs.Add(splashOnTrigger.playerSplashFX.name, splashOnTrigger.playerSplashFX); Globals.FXPrefabs.Add(splashOnTrigger.splashFX.name, splashOnTrigger.splashFX); if (Globals.IsClient) { Globals.DisableAchievements = true; Globals.LocalPlayer.transform.SetParent(SRSingleton.Instance.Player.transform, false); Globals.LocalPlayer.HasLoaded = true; foreach (var player in Globals.Players.Values.ToList()) { if (player.HasLoaded) { player.Spawn(); } } new PacketPlayerLoaded().Send(); } else { //var hostMenuObj = Instantiate(Globals.IngameMultiplayerMenuPrefab, SRSingleton.Instance.transform, true); //hostMenuObj.AddComponent(); //hostMenuObj.SetActive(false); } Globals.PauseState = PauseState.Playing; Globals.GameLoaded = true; stopwatch.Stop(); SRMP.Log($"Loaded the game in {stopwatch.ElapsedMilliseconds}ms"); } private static FileStream m_LogFileStream; private static StreamWriter m_LogWriter; /// /// Custom message logging of a given message /// /// Main message to be logged /// Prefix to be displayed before the message. Prefix will be after time marker and before the message /// It will also be incapsulated in [] public static void Log(string msg, string prefix = null) { if(m_LogFileStream == null) { string n = string.Format("log-{0:yyyy-MM-dd_hh-mm-ss-tt}.txt", DateTime.Now); Directory.CreateDirectory(Path.Combine(ModDataPath, "Logs")); m_LogFileStream = File.Create(Path.Combine(ModDataPath, "Logs", n)); m_LogWriter = new StreamWriter(m_LogFileStream); } string txt = $"[{DateTime.Now.ToString("HH:mm:ss")}]{(prefix != null ? "[" + prefix + "]" : "")} {msg}"; Debug.Log("[SRMP]" + txt); m_LogWriter.WriteLine(txt); m_LogWriter.Flush(); } } }