2022-01-28 20:49:07 -08:00
using Cysharp.Threading.Tasks ;
2022-01-29 15:33:33 -08:00
using MonoMod.Utils ;
2022-01-28 20:49:07 -08:00
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
2022-02-24 22:04:54 -08:00
namespace QSB.WorldSync ;
public static class QSBWorldSync
2020-08-13 19:25:12 +02:00
{
2022-02-24 22:04:54 -08:00
public static WorldObjectManager [ ] Managers ;
/// <summary>
/// Set when all WorldObjectManagers have called Init() on all their objects (AKA all the objects are created)
/// </summary>
public static bool AllObjectsAdded { get ; private set ; }
/// <summary>
/// Set when all WorldObjects have finished running Init()
/// </summary>
public static bool AllObjectsReady { get ; private set ; }
private static CancellationTokenSource _cts ;
private static readonly Dictionary < WorldObjectManager , UniTask > _managersBuilding = new ( ) ;
private static readonly Dictionary < IWorldObject , UniTask > _objectsIniting = new ( ) ;
public static async UniTaskVoid BuildWorldObjects ( OWScene scene )
2020-12-02 21:29:53 +00:00
{
2022-02-24 22:04:54 -08:00
if ( _cts ! = null )
2022-01-18 00:27:32 -08:00
{
2022-02-24 22:04:54 -08:00
return ;
}
2022-01-28 21:17:59 -08:00
2022-02-24 22:04:54 -08:00
_cts = new CancellationTokenSource ( ) ;
2022-01-28 21:05:04 -08:00
2022-02-24 22:04:54 -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 ) ;
}
2022-01-28 21:05:04 -08:00
2022-02-24 22:04:54 -08:00
GameInit ( ) ;
2022-01-28 21:05:04 -08:00
2022-02-24 22:04:54 -08:00
foreach ( var manager in Managers )
{
2022-02-25 00:25:24 -08:00
switch ( manager . WorldObjectScene )
2022-01-18 00:27:32 -08:00
{
2022-02-25 00:25:24 -08:00
case WorldObjectScene . SolarSystem when QSBSceneManager . CurrentScene ! = OWScene . SolarSystem :
case WorldObjectScene . Eye when QSBSceneManager . CurrentScene ! = OWScene . EyeOfTheUniverse :
2022-02-24 22:04:54 -08:00
continue ;
}
2022-01-18 00:27:32 -08:00
2022-02-24 22:04:54 -08:00
var task = UniTask . Create ( async ( ) = >
{
await manager . Try ( "building world objects" , async ( ) = >
2022-01-28 20:49:07 -08:00
{
2022-02-24 22:04:54 -08:00
await manager . BuildWorldObjects ( scene , _cts . Token ) ;
DebugLog . DebugWrite ( $"Built {manager}" , MessageType . Info ) ;
2022-01-28 20:49:07 -08:00
} ) ;
2022-02-24 22:04:54 -08:00
_managersBuilding . Remove ( manager ) ;
} ) ;
if ( ! task . Status . IsCompleted ( ) )
2022-02-16 00:59:24 -08:00
{
2022-02-24 22:04:54 -08:00
_managersBuilding . Add ( manager , task ) ;
2022-02-16 00:59:24 -08:00
}
2022-02-24 22:04:54 -08:00
}
2022-02-16 00:59:24 -08:00
2022-02-24 22:04:54 -08:00
await _managersBuilding . Values ;
if ( _cts = = null )
{
return ;
}
2022-01-28 20:49:07 -08:00
2022-02-24 22:04:54 -08:00
AllObjectsAdded = true ;
DebugLog . DebugWrite ( "World Objects added." , MessageType . Success ) ;
2022-02-16 00:59:24 -08:00
2022-02-24 22:04:54 -08:00
await _objectsIniting . Values ;
if ( _cts = = null )
{
return ;
}
2022-01-28 20:49:07 -08:00
2022-02-24 22:04:54 -08:00
AllObjectsReady = true ;
DebugLog . DebugWrite ( "World Objects ready." , MessageType . Success ) ;
2022-01-28 20:49:07 -08:00
2022-02-24 22:04:54 -08:00
DeterministicManager . WorldObjectsReady ( ) ;
2022-01-18 00:27:32 -08:00
2022-02-24 22:04:54 -08:00
if ( ! QSBCore . IsHost )
2022-01-18 00:46:27 -08:00
{
2022-02-24 22:04:54 -08:00
new RequestInitialStatesMessage ( ) . Send ( ) ;
}
}
2022-01-28 21:09:14 -08:00
2022-02-24 22:04:54 -08:00
public static void RemoveWorldObjects ( )
{
if ( _cts = = null )
{
return ;
}
2022-01-28 23:05:42 -08:00
2022-02-24 22:04:54 -08:00
if ( _managersBuilding . Count > 0 )
{
DebugLog . DebugWrite ( $"{_managersBuilding.Count} managers still building" , MessageType . Warning ) ;
}
2022-01-28 21:56:39 -08:00
2022-02-24 22:04:54 -08:00
if ( _objectsIniting . Count > 0 )
{
DebugLog . DebugWrite ( $"{_objectsIniting.Count} objects still initing" , MessageType . Warning ) ;
}
2022-01-28 21:17:59 -08:00
2022-02-25 10:00:57 -08:00
_cts . Cancel ( ) ;
_cts . Dispose ( ) ;
_cts = null ;
2022-02-24 22:04:54 -08:00
_managersBuilding . Clear ( ) ;
_objectsIniting . Clear ( ) ;
AllObjectsAdded = false ;
AllObjectsReady = false ;
2022-01-18 00:46:27 -08:00
2022-02-24 22:04:54 -08:00
GameReset ( ) ;
2022-01-18 00:46:27 -08:00
2022-02-24 22:04:54 -08:00
foreach ( var item in WorldObjects )
{
item . Try ( "removing" , item . OnRemoval ) ;
2022-01-18 00:46:27 -08:00
}
2022-02-24 22:04:54 -08:00
WorldObjects . Clear ( ) ;
UnityObjectsToWorldObjects . Clear ( ) ;
2022-01-18 00:27:32 -08:00
2022-02-24 22:04:54 -08:00
foreach ( var manager in Managers )
{
manager . Try ( "unbuilding world objects" , manager . UnbuildWorldObjects ) ;
}
}
2020-09-22 21:11:29 +01:00
2022-02-24 22:04:54 -08:00
// =======================================================================================================
2020-12-14 21:41:56 +01:00
2022-02-24 22:04:54 -08:00
public static readonly List < CharacterDialogueTree > OldDialogueTrees = new ( ) ;
public static readonly Dictionary < string , bool > DialogueConditions = new ( ) ;
private static readonly Dictionary < string , bool > PersistentConditions = new ( ) ;
public static readonly List < FactReveal > ShipLogFacts = new ( ) ;
2022-01-08 11:41:55 +00:00
2022-02-24 22:04:54 -08:00
private static readonly List < IWorldObject > WorldObjects = new ( ) ;
private static readonly Dictionary < MonoBehaviour , IWorldObject > UnityObjectsToWorldObjects = new ( ) ;
2022-01-08 11:41:55 +00:00
2022-02-24 22:04:54 -08:00
private static void GameInit ( )
{
DebugLog . DebugWrite ( $"GameInit QSBWorldSync" , MessageType . Info ) ;
2022-01-08 11:41:55 +00:00
2022-02-24 22:04:54 -08:00
OldDialogueTrees . Clear ( ) ;
OldDialogueTrees . AddRange ( GetUnityObjects < CharacterDialogueTree > ( ) . SortDeterministic ( ) ) ;
2022-01-08 11:41:55 +00:00
2022-02-24 22:04:54 -08:00
if ( ! QSBCore . IsHost )
{
return ;
2022-01-08 11:41:55 +00:00
}
2022-02-24 22:04:54 -08:00
DebugLog . DebugWrite ( $"DIALOGUE CONDITIONS :" ) ;
DialogueConditions . Clear ( ) ;
DialogueConditions . AddRange ( DialogueConditionManager . SharedInstance . _dictConditions ) ;
foreach ( var item in DialogueConditions )
2022-01-08 11:41:55 +00:00
{
2022-02-24 22:04:54 -08:00
DebugLog . DebugWrite ( $"- {item.Key}, {item.Value}" ) ;
2022-01-08 11:41:55 +00:00
}
2022-02-24 22:04:54 -08:00
DebugLog . DebugWrite ( $"PERSISTENT CONDITIONS :" ) ;
var dictConditions = PlayerData . _currentGameSave . dictConditions ;
var syncedConditions = dictConditions . Where ( x = > ConversationPatches . PersistentConditionsToSync . Contains ( x . Key ) ) ;
PersistentConditions . Clear ( ) ;
PersistentConditions . AddRange ( syncedConditions . ToDictionary ( x = > x . Key , x = > x . Value ) ) ;
foreach ( var item in PersistentConditions )
2021-02-25 22:45:32 +00:00
{
2022-02-24 22:04:54 -08:00
DebugLog . DebugWrite ( $"- {item.Key}, {item.Value}" ) ;
}
}
2021-06-18 22:38:32 +01:00
2022-02-24 22:04:54 -08:00
private static void GameReset ( )
{
DebugLog . DebugWrite ( $"GameReset QSBWorldSync" , MessageType . Info ) ;
2021-12-11 22:04:48 -08:00
2022-02-24 22:04:54 -08:00
OldDialogueTrees . Clear ( ) ;
DialogueConditions . Clear ( ) ;
PersistentConditions . Clear ( ) ;
ShipLogFacts . Clear ( ) ;
}
2020-09-06 09:07:31 +01:00
2022-02-24 22:04:54 -08:00
public static IEnumerable < IWorldObject > GetWorldObjects ( ) = > WorldObjects ;
2021-06-18 22:38:32 +01:00
2022-02-24 22:04:54 -08:00
public static IEnumerable < TWorldObject > GetWorldObjects < TWorldObject > ( )
where TWorldObject : IWorldObject
= > WorldObjects . OfType < TWorldObject > ( ) ;
2021-06-18 22:38:32 +01:00
2022-02-24 22:04:54 -08:00
public static TWorldObject GetWorldObject < TWorldObject > ( 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 ;
2021-03-18 16:57:56 +00:00
}
2021-02-18 10:34:35 +00:00
2022-02-24 22:04:54 -08:00
if ( WorldObjects [ objectId ] is not TWorldObject worldObject )
2020-12-02 21:29:53 +00:00
{
2022-02-24 22:04:54 -08:00
DebugLog . ToConsole ( $"Error - {typeof(TWorldObject).Name} id {objectId} is actually {WorldObjects[objectId].GetType().Name}." , MessageType . Error ) ;
return default ;
2021-12-15 21:09:10 +00:00
}
2022-02-24 22:04:54 -08:00
return worldObject ;
}
public static TWorldObject GetWorldObject < TWorldObject > ( this MonoBehaviour unityObject )
where TWorldObject : IWorldObject
{
if ( ! unityObject )
2021-12-15 21:09:10 +00:00
{
2022-02-24 22:04:54 -08: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 ) ;
return default ;
2021-12-15 21:09:10 +00:00
}
2022-02-24 22:04:54 -08:00
if ( ! UnityObjectsToWorldObjects . TryGetValue ( unityObject , out var worldObject ) )
2021-12-15 21:09:10 +00:00
{
2022-02-24 22:04:54 -08: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 ) ;
return default ;
2022-01-12 19:12:37 -08:00
}
2022-02-24 22:04:54 -08:00
return ( TWorldObject ) worldObject ;
}
2022-01-25 02:13:48 -08:00
2022-02-24 22:04:54 -08:00
/// <summary>
/// not deterministic across platforms
/// </summary>
public static IEnumerable < TUnityObject > GetUnityObjects < TUnityObject > ( )
where TUnityObject : MonoBehaviour
= > Resources . FindObjectsOfTypeAll < TUnityObject > ( )
. Where ( x = > x . gameObject . scene . name ! = null ) ;
public static void Init < TWorldObject , TUnityObject > ( )
where TWorldObject : WorldObject < TUnityObject > , new ( )
where TUnityObject : MonoBehaviour
{
var list = GetUnityObjects < TUnityObject > ( ) . SortDeterministic ( ) ;
Init < TWorldObject , TUnityObject > ( list ) ;
}
2022-01-12 19:12:37 -08:00
2022-02-24 22:04:54 -08:00
public static void Init < TWorldObject , TUnityObject > ( params Type [ ] typesToExclude )
where TWorldObject : WorldObject < TUnityObject > , new ( )
where TUnityObject : MonoBehaviour
{
var list = GetUnityObjects < TUnityObject > ( )
. Where ( x = > ! typesToExclude . Contains ( x . GetType ( ) ) )
. SortDeterministic ( ) ;
Init < TWorldObject , TUnityObject > ( list ) ;
}
2022-01-28 23:22:13 -08:00
2022-02-24 22:04:54 -08:00
/// <summary>
/// make sure to sort the list!
/// </summary>
public static void Init < TWorldObject , TUnityObject > ( IEnumerable < TUnityObject > listToInitFrom )
where TWorldObject : WorldObject < TUnityObject > , new ( )
where TUnityObject : MonoBehaviour
{
foreach ( var item in listToInitFrom )
{
var obj = new TWorldObject
2022-01-28 23:05:42 -08:00
{
2022-02-24 22:04:54 -08:00
AttachedObject = item ,
ObjectId = WorldObjects . Count
} ;
AddAndInit ( obj , item ) ;
2020-12-02 21:29:53 +00:00
}
2022-02-24 22:04:54 -08:00
}
2020-09-06 09:07:31 +01:00
2022-02-24 22:04:54 -08:00
public static void Init < TWorldObject , TUnityObject > ( Func < TUnityObject , OWTriggerVolume > triggerSelector )
where TWorldObject : QSBTrigger < TUnityObject > , new ( )
where TUnityObject : MonoBehaviour
{
var list = GetUnityObjects < TUnityObject > ( ) . SortDeterministic ( ) ;
foreach ( var owner in list )
2020-12-11 13:14:58 +00:00
{
2022-02-24 22:04:54 -08:00
var item = triggerSelector ( owner ) ;
if ( ! item )
2020-12-11 13:14:58 +00:00
{
2022-02-24 22:04:54 -08:00
continue ;
2020-12-11 13:14:58 +00:00
}
2021-06-18 22:38:32 +01:00
2022-02-24 22:04:54 -08:00
var obj = new TWorldObject
{
AttachedObject = item ,
ObjectId = WorldObjects . Count ,
TriggerOwner = owner
} ;
AddAndInit ( obj , item ) ;
2020-12-11 13:14:58 +00:00
}
2022-02-24 22:04:54 -08:00
}
private static void AddAndInit < TWorldObject , TUnityObject > ( TWorldObject worldObject , TUnityObject unityObject )
where TWorldObject : WorldObject < TUnityObject >
where TUnityObject : MonoBehaviour
{
WorldObjects . Add ( worldObject ) ;
UnityObjectsToWorldObjects . Add ( unityObject , worldObject ) ;
2020-12-19 10:56:25 +00:00
2022-02-24 22:04:54 -08:00
var task = UniTask . Create ( async ( ) = >
2022-01-08 11:41:55 +00:00
{
2022-02-24 22:04:54 -08:00
await worldObject . Try ( "initing" , ( ) = > worldObject . Init ( _cts . Token ) ) ;
_objectsIniting . Remove ( worldObject ) ;
} ) ;
if ( ! task . Status . IsCompleted ( ) )
{
_objectsIniting . Add ( worldObject , task ) ;
}
}
2022-01-08 11:41:55 +00:00
2022-02-24 22:04:54 -08:00
public static void SetDialogueCondition ( string name , bool state )
{
if ( ! QSBCore . IsHost )
{
DebugLog . ToConsole ( "Warning - Cannot write to dialogue condition dict when not server!" , MessageType . Warning ) ;
return ;
2022-01-08 11:41:55 +00:00
}
2022-02-24 22:04:54 -08:00
DialogueConditions [ name ] = state ;
}
public static void SetPersistentCondition ( string name , bool state )
{
if ( ! QSBCore . IsHost )
2020-12-19 10:56:25 +00:00
{
2022-02-24 22:04:54 -08:00
DebugLog . ToConsole ( "Warning - Cannot write to persistent condition dict when not server!" , MessageType . Warning ) ;
return ;
}
2021-06-18 22:38:32 +01:00
2022-02-24 22:04:54 -08:00
PersistentConditions [ name ] = state ;
}
2021-06-18 22:38:32 +01:00
2022-02-24 22:04:54 -08:00
public static void AddFactReveal ( string id , bool saveGame )
{
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 ;
2020-12-19 10:56:25 +00:00
}
2022-02-24 22:04:54 -08:00
ShipLogFacts . Add ( new FactReveal
{
Id = id ,
SaveGame = saveGame
} ) ;
2020-12-02 21:29:53 +00:00
}
2022-02-24 22:04:54 -08:00
}