@@ -44,6 +44,7 @@ class EPF_PersistenceManager
44
44
45
45
// Setup buffers, discarded after world init
46
46
protected ref map < string , EPF_PersistenceComponent > m_mBakedRoots ;
47
+ protected int m_iPendingLoadTypes ;
47
48
48
49
//------------------------------------------------------------------------------------------------
49
50
//! Check if current game instance is intended to run the persistence system. Only the mission host should do so.
@@ -247,10 +248,17 @@ class EPF_PersistenceManager
247
248
//! \return entity instance or null if not found
248
249
EPF_PersistenceComponent FindPersistenceComponentById (string persistentId )
249
250
{
251
+ if (!CheckLoaded ())
252
+ return null ;
253
+
250
254
FlushRegistrations ();
251
255
EPF_PersistenceComponent result ;
252
- if (m_mRootAutoSave .Find (persistentId , result )) return result ;
253
- if (m_mRootShutdown .Find (persistentId , result )) return result ;
256
+ if (m_mRootAutoSave .Find (persistentId , result ))
257
+ return result ;
258
+
259
+ if (m_mRootShutdown .Find (persistentId , result ))
260
+ return result ;
261
+
254
262
return m_mUncategorizedEntities .Get (persistentId );
255
263
}
256
264
@@ -259,18 +267,25 @@ class EPF_PersistenceManager
259
267
//! \return scripted state instance or null if not found
260
268
EPF_PersistentScriptedState FindScriptedStateByPersistentId (string persistentId )
261
269
{
270
+ if (!CheckLoaded ())
271
+ return null ;
272
+
262
273
FlushRegistrations ();
263
274
EPF_PersistentScriptedState result ;
264
- if (m_mScriptedStateAutoSave .Find (persistentId , result )) return result ;
265
- if (m_mScriptedStateShutdown .Find (persistentId , result )) return result ;
275
+ if (m_mScriptedStateAutoSave .Find (persistentId , result ))
276
+ return result ;
277
+
278
+ if (m_mScriptedStateShutdown .Find (persistentId , result ))
279
+ return result ;
280
+
266
281
return m_mScriptedStateUncategorized .Get (persistentId );
267
282
}
268
283
269
284
//------------------------------------------------------------------------------------------------
270
285
//! Manually trigger the global auto-save. Resets the timer until the next auto-save cycle. If an auto-save is already in progress it will do nothing.
271
286
void AutoSave ()
272
287
{
273
- if (m_bAutoSaveActive )
288
+ if (m_bAutoSaveActive || ! CheckLoaded () )
274
289
return ;
275
290
276
291
m_bAutoSaveActive = true;
@@ -499,7 +514,7 @@ class EPF_PersistenceManager
499
514
//------------------------------------------------------------------------------------------------
500
515
void UpdateRootEntityCollection (notnull EPF_PersistenceComponent persistenceComponent , string id , bool isRootEntity )
501
516
{
502
- if (m_eState < EPF_EPersistenceManagerState .ACTIVE )
517
+ if (m_eState < EPF_EPersistenceManagerState .SETUP )
503
518
{
504
519
if (m_mBakedRoots && EPF_BitFlags .CheckFlags (persistenceComponent .GetFlags (), EPF_EPersistenceFlags .BAKED ))
505
520
{
@@ -529,6 +544,9 @@ class EPF_PersistenceManager
529
544
//------------------------------------------------------------------------------------------------
530
545
void ForceSelfSpawn (notnull EPF_PersistenceComponent persistenceComponent )
531
546
{
547
+ if (!CheckLoaded ())
548
+ return ;
549
+
532
550
EPF_PersistenceComponentClass settings = EPF_ComponentData < EPF_PersistenceComponentClass > .Get (persistenceComponent );
533
551
m_pRootEntityCollection .ForceSelfSpawn (persistenceComponent , persistenceComponent .GetPersistentId (), settings );
534
552
}
@@ -638,6 +656,18 @@ class EPF_PersistenceManager
638
656
m_aPendingScriptedStateRegistrations .Clear ();
639
657
}
640
658
659
+ //------------------------------------------------------------------------------------------------
660
+ protected bool CheckLoaded ()
661
+ {
662
+ if (m_eState < EPF_EPersistenceManagerState .SETUP )
663
+ {
664
+ Debug .Error ("Attempted to call persistence operation before setup phase. Await setup/completion using GetOnStateChangeEvent/GetOnActiveEvent." );
665
+ return false;
666
+ }
667
+
668
+ return true;
669
+ }
670
+
641
671
//------------------------------------------------------------------------------------------------
642
672
event void OnPostInit (IEntity gameMode , EPF_PersistenceManagerComponentClass settings )
643
673
{
@@ -655,14 +685,6 @@ class EPF_PersistenceManager
655
685
if (!m_pDbContext )
656
686
return ;
657
687
658
- string rootEntityCollectionId = string .Format ("00EC%1-0000-0000-0000-000000000000" , EPF_PersistenceIdGenerator .GetHiveId ().ToString (4 ));
659
- m_pRootEntityCollection = EDF_DbEntityHelper < EPF_PersistentRootEntityCollection > .GetRepository (m_pDbContext ).Find (rootEntityCollectionId ).GetEntity ();
660
- if (!m_pRootEntityCollection )
661
- {
662
- m_pRootEntityCollection = new EPF_PersistentRootEntityCollection ();
663
- m_pRootEntityCollection .SetId (rootEntityCollectionId );
664
- }
665
-
666
688
SetState (EPF_EPersistenceManagerState .POST_INIT );
667
689
}
668
690
@@ -685,7 +707,31 @@ class EPF_PersistenceManager
685
707
{
686
708
Print ("Persistence initial world load started..." , LogLevel .DEBUG );
687
709
710
+ // Flush all pending objects so they register as baked
688
711
FlushRegistrations ();
712
+
713
+ EDF_DbFindCallbackSingle < EPF_PersistentRootEntityCollection > callback (this , "OnRootEntityCollectionLoaded" );
714
+ EDF_DbEntityHelper < EPF_PersistentRootEntityCollection > .GetRepository (m_pDbContext )
715
+ .FindAsync (GetRootEntityCollectionId (), callback );
716
+ }
717
+
718
+ //------------------------------------------------------------------------------------------------
719
+ protected string GetRootEntityCollectionId ()
720
+ {
721
+ return string .Format ("00EC%1-0000-0000-0000-000000000000" , EPF_PersistenceIdGenerator .GetHiveId ().ToString (4 ));
722
+ }
723
+
724
+ //------------------------------------------------------------------------------------------------
725
+ protected void OnRootEntityCollectionLoaded (EDF_EDbOperationStatusCode statusCode , EPF_PersistentRootEntityCollection rootEntityCollection )
726
+ {
727
+ m_pRootEntityCollection = rootEntityCollection ;
728
+ if (!m_pRootEntityCollection )
729
+ {
730
+ m_pRootEntityCollection = new EPF_PersistentRootEntityCollection ();
731
+ m_pRootEntityCollection .SetId (GetRootEntityCollectionId ());
732
+ }
733
+
734
+ // Anything spawned after this is considered dynamic
689
735
SetState (EPF_EPersistenceManagerState .SETUP );
690
736
691
737
// Remove baked entities that shall no longer be root entities in the world
@@ -737,53 +783,69 @@ class EPF_PersistenceManager
737
783
loadIds .Insert (id );
738
784
}
739
785
786
+ // Save any mapping or root entity changes detected during world init
787
+ m_pRootEntityCollection .Save (m_pDbContext );
788
+
740
789
// Load all known initial entity types from db, both baked and dynamic in one bulk operation
790
+ m_iPendingLoadTypes = bulkLoad .Count ();
741
791
foreach (typename saveDataType , array < string > persistentIds : bulkLoad )
742
792
{
743
- array < ref EDF_DbEntity > findResults = m_pDbContext .FindAll (saveDataType , EDF_DbFind .Id ().EqualsAnyOf (persistentIds )).GetEntities ();
744
- if (!findResults ) continue ;
793
+ EDF_DbFindCallbackMultipleUntyped callback (this , "OnTypeCollectionLoaded ");
794
+ m_pDbContext .FindAllAsync (saveDataType , EDF_DbFind .Id ().EqualsAnyOf (persistentIds ), callback : callback );
795
+ }
796
+ }
745
797
746
- foreach (EDF_DbEntity findResult : findResults )
798
+ //------------------------------------------------------------------------------------------------
799
+ protected void OnTypeCollectionLoaded (EDF_EDbOperationStatusCode code , array < ref EDF_DbEntity > findResults )
800
+ {
801
+ foreach (EDF_DbEntity findResult : findResults )
802
+ {
803
+ EPF_EntitySaveData saveData = EPF_EntitySaveData .Cast (findResult );
804
+ if (!saveData )
747
805
{
748
- EPF_EntitySaveData saveData = EPF_EntitySaveData .Cast (findResult );
749
- if (!saveData )
750
- {
751
- Debug .Error (string .Format ("Unexpected database find result type '%1' encountered during entity load. Ignored." , findResult .Type ().ToString ()));
752
- continue ;
753
- }
754
-
755
- // Load data for baked roots
756
- EPF_PersistenceComponent persistenceComponent = m_mBakedRoots .Get (saveData .GetId ());
757
- if (persistenceComponent )
758
- {
759
- persistenceComponent .Load (saveData );
760
- continue ;
761
- }
806
+ Debug .Error (string .Format ("Unexpected database find result type '%1' encountered during entity load. Ignored." , findResult .Type ().ToString ()));
807
+ continue ;
808
+ }
762
809
763
- // Spawn additional dynamic entites
764
- SpawnWorldEntity (saveData );
810
+ // Load data for baked roots
811
+ EPF_PersistenceComponent persistenceComponent = m_mBakedRoots .Get (saveData .GetId ());
812
+ if (persistenceComponent )
813
+ {
814
+ persistenceComponent .Load (saveData );
815
+ continue ;
765
816
}
817
+
818
+ // Spawn additional dynamic entites
819
+ SpawnWorldEntity (saveData );
766
820
}
767
821
768
- // Save any mapping or root entity changes detected during world init
769
- m_pRootEntityCollection .Save (m_pDbContext );
822
+ if (-- m_iPendingLoadTypes == 0 )
823
+ OnPostSetup ();
824
+ }
770
825
826
+ //------------------------------------------------------------------------------------------------
827
+ protected void OnPostSetup ()
828
+ {
771
829
// Free memory as it not needed after setup
772
830
m_mBakedRoots = null ;
773
-
774
831
Print ("Persistence initial world load complete." , LogLevel .DEBUG );
775
-
776
832
SetState (EPF_EPersistenceManagerState .ACTIVE );
777
833
}
778
834
779
835
//------------------------------------------------------------------------------------------------
780
836
event void OnGameEnd ()
781
837
{
782
838
Print ("Persistence shutting down..." , LogLevel .DEBUG );
839
+
840
+ bool wasActive = m_eState == EPF_EPersistenceManagerState .ACTIVE ;
783
841
SetState (EPF_EPersistenceManagerState .SHUTDOWN );
784
- AutoSave (); // Trigger auto-save
785
- AutoSaveTick (); // Execute auto-save instantly till end
786
- ShutDownSave (); // Save those who only save on shutdown
842
+ if (wasActive )
843
+ {
844
+ AutoSave (); // Trigger auto-save
845
+ AutoSaveTick (); // Execute auto-save instantly till end
846
+ ShutDownSave (); // Save those who only save on shutdown
847
+ }
848
+
787
849
Reset ();
788
850
Print ("Persistence shut down successfully." , LogLevel .DEBUG );
789
851
}
0 commit comments