using OWML.Common; using QSB.Utility; using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace QSB.WorldSync { public static class QSBWorldSync { public static readonly List OldDialogueTrees = new(); public static readonly Dictionary DialogueConditions = new(); public static readonly List ShipLogFacts = new(); private static readonly List WorldObjects = new(); private static readonly Dictionary WorldObjectsToUnityObjects = new(); public static IEnumerable GetWorldObjects() where TWorldObject : IWorldObject => WorldObjects.OfType(); public static TWorldObject GetWorldObject(this int objectId) where TWorldObject : IWorldObject { if (!WorldObjects.IsInRange(objectId)) { DebugLog.ToConsole($"Warning - Tried to find {typeof(TWorldObject).Name} id {objectId}. Count is {WorldObjects.Count}.", MessageType.Warning); return default; } if (WorldObjects[objectId] is not TWorldObject worldObject) { DebugLog.ToConsole($"Error - {typeof(TWorldObject).Name} id {objectId} is actually {WorldObjects[objectId].GetType().Name}.", MessageType.Error); return default; } return worldObject; } public static TWorldObject GetWorldObject(this MonoBehaviour unityObject) where TWorldObject : IWorldObject { if (unityObject == null) { DebugLog.ToConsole($"Error - Trying to run GetWorldFromUnity with a null unity object! TWorldObject:{typeof(TWorldObject).Name}, TUnityObject:NULL, Stacktrace:\r\n{Environment.StackTrace}", MessageType.Error); return default; } if (!QSBCore.IsInMultiplayer) { DebugLog.ToConsole($"Warning - Trying to run GetWorldFromUnity while not in multiplayer! TWorldObject:{typeof(TWorldObject).Name}, TUnityObject:{unityObject.GetType().Name}, Stacktrace:\r\n{Environment.StackTrace}", MessageType.Warning); return default; } if (!WorldObjectsToUnityObjects.TryGetValue(unityObject, out var worldObject)) { DebugLog.ToConsole($"Error - WorldObjectsToUnityObjects does not contain \"{unityObject.name}\"! TWorldObject:{typeof(TWorldObject).Name}, TUnityObject:{unityObject.GetType().Name}, Stacktrace:\r\n{Environment.StackTrace}", MessageType.Error); return default; } if (worldObject == null) { DebugLog.ToConsole($"Error - World object for unity object {unityObject.name} is null! TWorldObject:{typeof(TWorldObject).Name}, TUnityObject:{unityObject.GetType().Name}, Stacktrace:\r\n{Environment.StackTrace}", MessageType.Error); return default; } return (TWorldObject)worldObject; } public static void RemoveWorldObjects() { if (WorldObjects.Count == 0) { DebugLog.ToConsole($"Warning - Trying to remove WorldObjects, but there are no WorldObjects!", MessageType.Warning); return; } foreach (var item in WorldObjects) { try { item.OnRemoval(); } catch (Exception e) { DebugLog.ToConsole($"Error - Exception in OnRemoval() for {item.GetType()}. Message : {e.Message}, Stack trace : {e.StackTrace}", MessageType.Error); } } WorldObjects.Clear(); WorldObjectsToUnityObjects.Clear(); } public static IEnumerable GetUnityObjects() where TUnityObject : MonoBehaviour => Resources.FindObjectsOfTypeAll() .Where(x => x.gameObject.scene.name != null); public static void Init() where TWorldObject : WorldObject, new() where TUnityObject : MonoBehaviour { var list = GetUnityObjects(); Init(list); } public static void Init(params Type[] typesToExclude) where TWorldObject : WorldObject, new() where TUnityObject : MonoBehaviour { var list = GetUnityObjects().Where(x => !typesToExclude.Contains(x.GetType())); Init(list); } public static void Init(IEnumerable listToInitFrom) where TWorldObject : WorldObject, new() where TUnityObject : MonoBehaviour { //DebugLog.DebugWrite($"{typeof(TWorldObject).Name} init : {listToInitFrom.Count()} instances.", MessageType.Info); foreach (var item in listToInitFrom) { var obj = new TWorldObject { AttachedObject = item, ObjectId = WorldObjects.Count }; obj.Init(); WorldObjects.Add(obj); WorldObjectsToUnityObjects.Add(item, obj); } } public static void SetDialogueCondition(string name, bool state) { if (!QSBCore.IsHost) { DebugLog.ToConsole("Warning - Cannot write to condition dict when not server!", MessageType.Warning); return; } DialogueConditions[name] = state; } public static void AddFactReveal(string id, bool saveGame, bool showNotification) { if (!QSBCore.IsHost) { DebugLog.ToConsole("Warning - Cannot write to fact list when not server!", MessageType.Warning); return; } if (ShipLogFacts.Any(x => x.Id == id)) { return; } ShipLogFacts.Add(new FactReveal { Id = id, SaveGame = saveGame, ShowNotification = showNotification }); } } }