2022-01-28 20:49:07 -08:00
using Cysharp.Threading.Tasks ;
using OWML.Common ;
2022-01-08 11:41:55 +00:00
using QSB.ConversationSync.Patches ;
2021-12-26 00:53:43 -08:00
using QSB.LogSync ;
2022-01-25 23:46:41 -08:00
using QSB.Messaging ;
2022-01-18 00:27:32 -08:00
using QSB.Player.TransformSync ;
2022-01-12 19:18:59 -08:00
using QSB.TriggerSync.WorldObjects ;
2020-09-29 21:34:46 +01:00
using QSB.Utility ;
2021-12-07 15:56:08 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
2022-01-28 20:49:07 -08:00
using System.Threading ;
2020-12-23 22:43:05 +00:00
using UnityEngine ;
2020-08-13 19:25:12 +02:00
namespace QSB.WorldSync
{
2020-12-11 13:14:58 +00:00
public static class QSBWorldSync
2020-12-02 21:29:53 +00:00
{
2022-01-18 01:50:24 -08:00
public static WorldObjectManager [ ] Managers ;
2022-01-18 00:27:32 -08:00
/// <summary>
/// Set when all WorldObjectManagers have called Init() on all their objects (AKA all the objects are created)
/// </summary>
2022-01-28 21:56:39 -08:00
public static bool AllObjectsAdded { get ; private set ; }
2022-01-18 00:27:32 -08:00
/// <summary>
/// Set when all WorldObjects have finished running Init()
/// </summary>
2022-01-28 21:56:39 -08:00
public static bool AllObjectsReady { get ; private set ; }
2022-01-18 00:27:32 -08:00
2022-01-28 20:49:07 -08:00
private static CancellationTokenSource _cts ;
private static readonly List < UniTask > _managerTasks = new ( ) ;
private static readonly List < UniTask > _objectTasks = new ( ) ;
2022-01-28 21:05:04 -08:00
public static async UniTaskVoid BuildWorldObjects ( OWScene scene )
2022-01-18 00:27:32 -08:00
{
2022-01-28 21:17:59 -08:00
if ( _cts ! = null )
{
return ;
}
2022-01-28 20:49:07 -08:00
_cts = new CancellationTokenSource ( ) ;
2022-01-28 21:05:04 -08:00
if ( ! PlayerTransformSync . LocalInstance )
{
DebugLog . ToConsole ( "Warning - Tried to build WorldObjects when LocalPlayer is not ready! Building when ready..." , MessageType . Warning ) ;
await UniTask . WaitUntil ( ( ) = > PlayerTransformSync . LocalInstance , cancellationToken : _cts . Token ) ;
}
GameInit ( ) ;
2022-01-18 01:50:24 -08:00
foreach ( var manager in Managers )
2022-01-18 00:27:32 -08:00
{
switch ( manager . WorldObjectType )
{
case WorldObjectType . SolarSystem when QSBSceneManager . CurrentScene ! = OWScene . SolarSystem :
case WorldObjectType . Eye when QSBSceneManager . CurrentScene ! = OWScene . EyeOfTheUniverse :
2022-01-25 19:42:22 -08:00
DebugLog . DebugWrite ( $"skipping {manager} as it is type {manager.WorldObjectType} and scene is {QSBSceneManager.CurrentScene}" ) ;
2022-01-18 00:27:32 -08:00
continue ;
}
2022-01-28 21:40:26 -08:00
var task = manager . Try ( "building world objects" , async ( ) = >
2022-01-28 20:49:07 -08:00
{
await manager . BuildWorldObjects ( scene , _cts . Token ) ;
DebugLog . DebugWrite ( $"Built {manager}" , MessageType . Info ) ;
} ) ;
_managerTasks . Add ( task ) ;
2022-01-18 00:27:32 -08:00
}
2022-01-28 20:49:07 -08:00
await _managerTasks ;
2022-01-28 21:09:14 -08:00
_managerTasks . Clear ( ) ;
2022-01-28 21:56:39 -08:00
AllObjectsAdded = true ;
2022-01-28 20:49:07 -08:00
DebugLog . DebugWrite ( "World Objects added." , MessageType . Success ) ;
await _objectTasks ;
2022-01-28 21:09:14 -08:00
_objectTasks . Clear ( ) ;
2022-01-28 21:56:39 -08:00
AllObjectsReady = true ;
2022-01-28 20:49:07 -08:00
DebugLog . DebugWrite ( "World Objects ready." , MessageType . Success ) ;
DeterministicManager . WorldObjectsReady ( ) ;
if ( ! QSBCore . IsHost )
2022-01-18 00:27:32 -08:00
{
2022-01-28 20:49:07 -08:00
new RequestInitialStatesMessage ( ) . Send ( ) ;
}
2022-01-18 00:27:32 -08:00
}
2022-01-18 00:46:27 -08:00
public static void RemoveWorldObjects ( )
{
2022-01-28 21:17:59 -08:00
if ( _cts = = null )
{
return ;
}
_cts . Cancel ( ) ;
_cts . Dispose ( ) ;
_cts = null ;
2022-01-28 21:09:14 -08:00
2022-01-28 21:17:59 -08:00
_managerTasks . Clear ( ) ;
_objectTasks . Clear ( ) ;
2022-01-28 21:56:39 -08:00
AllObjectsAdded = false ;
AllObjectsReady = false ;
GameReset ( ) ;
2022-01-28 21:17:59 -08:00
2022-01-18 00:46:27 -08:00
foreach ( var item in WorldObjects )
{
2022-01-25 19:42:22 -08:00
item . Try ( "removing" , item . OnRemoval ) ;
2022-01-18 00:46:27 -08:00
}
WorldObjects . Clear ( ) ;
2022-01-25 18:13:34 -08:00
UnityObjectsToWorldObjects . Clear ( ) ;
2022-01-18 00:46:27 -08:00
2022-01-18 01:50:24 -08:00
foreach ( var manager in Managers )
2022-01-18 00:46:27 -08:00
{
2022-01-25 19:42:22 -08:00
manager . Try ( "unbuilding world objects" , manager . UnbuildWorldObjects ) ;
2022-01-18 00:46:27 -08:00
}
}
2022-01-18 00:27:32 -08:00
// =======================================================================================================
public static List < CharacterDialogueTree > OldDialogueTrees { get ; } = new ( ) ;
2022-01-08 11:41:55 +00:00
public static Dictionary < string , bool > DialogueConditions { get ; private set ; } = new ( ) ;
2022-01-25 02:14:37 -08:00
private static Dictionary < string , bool > PersistentConditions { get ; set ; } = new ( ) ;
2022-01-18 00:27:32 -08:00
public static List < FactReveal > ShipLogFacts { get ; } = new ( ) ;
2020-09-22 21:11:29 +01:00
2021-11-20 19:49:50 +00:00
private static readonly List < IWorldObject > WorldObjects = new ( ) ;
2022-01-25 18:13:34 -08:00
private static readonly Dictionary < MonoBehaviour , IWorldObject > UnityObjectsToWorldObjects = new ( ) ;
2020-12-14 21:41:56 +01:00
2022-01-18 00:46:27 -08:00
private static void GameInit ( )
2022-01-08 11:41:55 +00:00
{
2022-01-18 00:46:27 -08:00
DebugLog . DebugWrite ( $"GameInit QSBWorldSync" , MessageType . Info ) ;
2022-01-08 11:41:55 +00:00
OldDialogueTrees . Clear ( ) ;
2022-01-25 02:13:48 -08:00
OldDialogueTrees . AddRange ( GetUnityObjects < CharacterDialogueTree > ( ) . SortDeterministic ( ) ) ;
2022-01-08 11:41:55 +00:00
if ( ! QSBCore . IsHost )
{
return ;
}
DebugLog . DebugWrite ( $"DIALOGUE CONDITIONS :" ) ;
DialogueConditions = ( Dictionary < string , bool > ) DialogueConditionManager . SharedInstance . _dictConditions ;
foreach ( var item in DialogueConditions )
{
DebugLog . DebugWrite ( $"- {item.Key}, {item.Value}" ) ;
}
DebugLog . DebugWrite ( $"PERSISTENT CONDITIONS :" ) ;
var dictConditions = PlayerData . _currentGameSave . dictConditions ;
var syncedConditions = dictConditions . Where ( x = > ConversationPatches . PersistentConditionsToSync . Contains ( x . Key ) ) ;
PersistentConditions = syncedConditions . ToDictionary ( x = > x . Key , x = > x . Value ) ;
foreach ( var item in PersistentConditions )
{
DebugLog . DebugWrite ( $"- {item.Key}, {item.Value}" ) ;
}
}
2022-01-18 00:46:27 -08:00
private static void GameReset ( )
2022-01-08 11:41:55 +00:00
{
2022-01-18 00:46:27 -08:00
DebugLog . DebugWrite ( $"GameReset QSBWorldSync" , MessageType . Info ) ;
2022-01-08 11:41:55 +00:00
OldDialogueTrees . Clear ( ) ;
DialogueConditions . Clear ( ) ;
PersistentConditions . Clear ( ) ;
ShipLogFacts . Clear ( ) ;
}
2021-12-28 16:10:58 -08:00
public static IEnumerable < IWorldObject > GetWorldObjects ( ) = > WorldObjects ;
2020-12-24 10:06:17 +00:00
public static IEnumerable < TWorldObject > GetWorldObjects < TWorldObject > ( )
2021-12-11 15:08:56 -08:00
where TWorldObject : IWorldObject
2020-12-24 10:06:17 +00:00
= > WorldObjects . OfType < TWorldObject > ( ) ;
2020-08-13 19:25:12 +02:00
2021-12-25 22:37:20 -08:00
public static TWorldObject GetWorldObject < TWorldObject > ( this int objectId )
2021-12-11 15:08:56 -08:00
where TWorldObject : IWorldObject
2021-02-25 22:45:32 +00:00
{
2021-12-25 22:37:20 -08:00
if ( ! WorldObjects . IsInRange ( objectId ) )
2021-02-25 22:45:32 +00:00
{
2021-12-25 22:37:20 -08:00
DebugLog . ToConsole ( $"Warning - Tried to find {typeof(TWorldObject).Name} id {objectId}. Count is {WorldObjects.Count}." , MessageType . Warning ) ;
2021-02-25 22:45:32 +00:00
return default ;
}
2021-06-18 22:38:32 +01:00
2021-12-25 22:37:20 -08:00
if ( WorldObjects [ objectId ] is not TWorldObject worldObject )
2021-12-11 22:04:48 -08:00
{
2021-12-25 22:37:20 -08:00
DebugLog . ToConsole ( $"Error - {typeof(TWorldObject).Name} id {objectId} is actually {WorldObjects[objectId].GetType().Name}." , MessageType . Error ) ;
2021-12-11 22:04:48 -08:00
return default ;
}
return worldObject ;
2021-02-25 22:45:32 +00:00
}
2020-09-06 09:07:31 +01:00
2021-12-25 22:37:20 -08:00
public static TWorldObject GetWorldObject < TWorldObject > ( this MonoBehaviour unityObject )
2021-11-01 15:49:00 +00:00
where TWorldObject : IWorldObject
2021-03-18 16:57:56 +00:00
{
2022-01-28 21:05:04 -08:00
if ( ! unityObject )
2021-03-25 20:56:26 +00:00
{
2021-12-04 09:14:48 +00:00
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 ) ;
2021-03-25 20:56:26 +00:00
return default ;
}
2021-06-18 22:38:32 +01:00
2022-01-25 18:13:34 -08:00
if ( ! UnityObjectsToWorldObjects . TryGetValue ( unityObject , out var worldObject ) )
2021-03-18 16:57:56 +00:00
{
2021-12-04 09:14:48 +00:00
DebugLog . ToConsole ( $"Error - WorldObjectsToUnityObjects does not contain \" { unityObject . name } \ "! TWorldObject:{typeof(TWorldObject).Name}, TUnityObject:{unityObject.GetType().Name}, Stacktrace:\r\n{Environment.StackTrace}" , MessageType . Error ) ;
2021-03-18 16:57:56 +00:00
return default ;
}
2021-06-18 22:38:32 +01:00
2021-12-20 18:35:38 -08:00
return ( TWorldObject ) worldObject ;
2021-03-18 16:57:56 +00:00
}
2021-02-18 10:34:35 +00:00
2022-01-25 02:13:48 -08:00
/// <summary>
/// not deterministic across platforms
/// </summary>
2021-11-14 03:51:22 -08:00
public static IEnumerable < TUnityObject > GetUnityObjects < TUnityObject > ( )
where TUnityObject : MonoBehaviour
= > Resources . FindObjectsOfTypeAll < TUnityObject > ( )
. Where ( x = > x . gameObject . scene . name ! = null ) ;
2021-12-28 16:10:58 -08:00
public static void Init < TWorldObject , TUnityObject > ( )
2021-12-11 15:08:56 -08:00
where TWorldObject : WorldObject < TUnityObject > , new ( )
2021-01-29 15:29:50 +00:00
where TUnityObject : MonoBehaviour
2020-12-02 21:29:53 +00:00
{
2022-01-25 02:13:48 -08:00
var list = GetUnityObjects < TUnityObject > ( ) . SortDeterministic ( ) ;
2021-12-28 16:10:58 -08:00
Init < TWorldObject , TUnityObject > ( list ) ;
2021-12-15 21:09:10 +00:00
}
2021-12-28 16:10:58 -08:00
public static void Init < TWorldObject , TUnityObject > ( params Type [ ] typesToExclude )
2021-12-15 21:09:10 +00:00
where TWorldObject : WorldObject < TUnityObject > , new ( )
where TUnityObject : MonoBehaviour
{
2022-01-25 02:13:48 -08:00
var list = GetUnityObjects < TUnityObject > ( )
. Where ( x = > ! typesToExclude . Contains ( x . GetType ( ) ) )
. SortDeterministic ( ) ;
2021-12-28 16:10:58 -08:00
Init < TWorldObject , TUnityObject > ( list ) ;
2021-12-15 21:09:10 +00:00
}
2022-01-25 02:13:48 -08:00
/// <summary>
/// make sure to sort the list!
/// </summary>
2021-12-28 16:10:58 -08:00
public static void Init < TWorldObject , TUnityObject > ( IEnumerable < TUnityObject > listToInitFrom )
2021-12-15 21:09:10 +00:00
where TWorldObject : WorldObject < TUnityObject > , new ( )
where TUnityObject : MonoBehaviour
{
//DebugLog.DebugWrite($"{typeof(TWorldObject).Name} init : {listToInitFrom.Count()} instances.", MessageType.Info);
foreach ( var item in listToInitFrom )
2020-12-02 21:29:53 +00:00
{
2021-12-11 20:13:49 -08:00
var obj = new TWorldObject
{
2021-12-15 21:09:10 +00:00
AttachedObject = item ,
2022-01-12 20:10:04 -08:00
ObjectId = WorldObjects . Count
2021-12-11 20:13:49 -08:00
} ;
2021-12-15 21:09:10 +00:00
2022-01-28 20:49:07 -08:00
var task = obj . Try ( "initing" , async ( ) = > await obj . Init ( _cts . Token ) ) ;
_objectTasks . Add ( task ) ;
2022-01-12 19:12:37 -08:00
WorldObjects . Add ( obj ) ;
2022-01-25 18:13:34 -08:00
UnityObjectsToWorldObjects . Add ( item , obj ) ;
2022-01-12 19:12:37 -08:00
}
}
public static void Init < TWorldObject , TUnityObject > ( Func < TUnityObject , OWTriggerVolume > triggerSelector )
where TWorldObject : QSBTrigger < TUnityObject > , new ( )
where TUnityObject : MonoBehaviour
{
2022-01-25 02:13:48 -08:00
var list = GetUnityObjects < TUnityObject > ( ) . SortDeterministic ( ) ;
foreach ( var owner in list )
2022-01-12 19:12:37 -08:00
{
2022-01-25 02:13:48 -08:00
var item = triggerSelector ( owner ) ;
if ( ! item )
{
continue ;
}
2022-01-12 19:12:37 -08:00
var obj = new TWorldObject
{
AttachedObject = item ,
ObjectId = WorldObjects . Count ,
TriggerOwner = owner
} ;
2022-01-28 20:49:07 -08:00
var task = obj . Try ( "initing" , async ( ) = > await obj . Init ( _cts . Token ) ) ;
_objectTasks . Add ( task ) ;
2021-12-11 20:13:49 -08:00
WorldObjects . Add ( obj ) ;
2022-01-25 18:13:34 -08:00
UnityObjectsToWorldObjects . Add ( item , obj ) ;
2020-12-02 21:29:53 +00:00
}
}
2020-09-06 09:07:31 +01:00
2020-12-11 22:42:21 +00:00
public static void SetDialogueCondition ( string name , bool state )
2020-12-11 13:14:58 +00:00
{
2021-08-08 19:53:55 +01:00
if ( ! QSBCore . IsHost )
2020-12-11 13:14:58 +00:00
{
2022-01-08 11:41:55 +00:00
DebugLog . ToConsole ( "Warning - Cannot write to dialogue condition dict when not server!" , MessageType . Warning ) ;
2020-12-11 13:14:58 +00:00
return ;
}
2021-06-18 22:38:32 +01:00
2020-12-11 13:14:58 +00:00
DialogueConditions [ name ] = state ;
}
2020-12-19 10:56:25 +00:00
2022-01-08 11:41:55 +00:00
public static void SetPersistentCondition ( string name , bool state )
{
if ( ! QSBCore . IsHost )
{
DebugLog . ToConsole ( "Warning - Cannot write to persistent condition dict when not server!" , MessageType . Warning ) ;
return ;
}
PersistentConditions [ name ] = state ;
}
2021-12-26 00:58:03 -08:00
public static void AddFactReveal ( string id , bool saveGame )
2020-12-19 10:56:25 +00:00
{
2021-08-08 19:53:55 +01:00
if ( ! QSBCore . IsHost )
2020-12-19 10:56:25 +00:00
{
2020-12-19 18:44:27 +00:00
DebugLog . ToConsole ( "Warning - Cannot write to fact list when not server!" , MessageType . Warning ) ;
2020-12-19 10:56:25 +00:00
return ;
}
2021-06-18 22:38:32 +01:00
2020-12-19 10:56:25 +00:00
if ( ShipLogFacts . Any ( x = > x . Id = = id ) )
{
return ;
}
2021-06-18 22:38:32 +01:00
2020-12-19 10:56:25 +00:00
ShipLogFacts . Add ( new FactReveal
{
Id = id ,
2021-12-26 00:58:03 -08:00
SaveGame = saveGame
2020-12-19 10:56:25 +00:00
} ) ;
}
2020-12-02 21:29:53 +00:00
}
2021-11-14 03:51:22 -08:00
}