1
1
using System ;
2
- using System . Collections ;
3
2
using System . Collections . Generic ;
4
3
using System . Linq ;
5
4
using NitroxClient . GameLogic . InitialSync . Abstract ;
5
+ using NitroxClient . MonoBehaviours ;
6
6
using NitroxModel . DataStructures . GameLogic ;
7
7
using NitroxModel . Packets ;
8
8
using Story ;
@@ -22,10 +22,9 @@ public StoryGoalInitialSyncProcessor(TimeManager timeManager)
22
22
AddStep ( SetupTrackers ) ;
23
23
AddStep ( SetupAuroraAndSunbeam ) ;
24
24
AddStep ( SetScheduledGoals ) ;
25
- AddStep ( RefreshStoryWithLatestData ) ;
26
25
}
27
26
28
- private static IEnumerator SetupStoryGoalManager ( InitialPlayerSync packet )
27
+ private static void SetupStoryGoalManager ( InitialPlayerSync packet )
29
28
{
30
29
List < string > completedGoals = packet . StoryGoalData . CompletedGoals ;
31
30
List < string > radioQueue = packet . StoryGoalData . RadioQueue ;
@@ -61,20 +60,23 @@ private static IEnumerator SetupStoryGoalManager(InitialPlayerSync packet)
61
60
- Personal goals : { personalGoals . Count }
62
61
- Radio queue : { radioQueue . Count }
63
62
""" ) ;
64
- yield break ;
65
63
}
66
64
67
- private static IEnumerator SetupTrackers ( InitialPlayerSync packet )
65
+ private static void SetupTrackers ( InitialPlayerSync packet )
68
66
{
69
67
List < string > completedGoals = packet . StoryGoalData . CompletedGoals ;
70
68
StoryGoalManager storyGoalManager = StoryGoalManager . main ;
71
-
72
- // Initialize CompoundGoalTracker and OnGoalUnlockTracker and clear their already completed goals
69
+ OnGoalUnlockTracker onGoalUnlockTracker = storyGoalManager . onGoalUnlockTracker ;
70
+ CompoundGoalTracker compoundGoalTracker = storyGoalManager . compoundGoalTracker ;
71
+
72
+ // Initializing CompoundGoalTracker and OnGoalUnlockTracker again (with OnSceneObjectsLoaded) requires us to
73
+ // we first clear what was done in the first iteration of OnSceneObjectsLoaded
74
+ onGoalUnlockTracker . goalUnlocks . Clear ( ) ;
75
+ compoundGoalTracker . goals . Clear ( ) ;
76
+ // we force initialized to false so OnSceneObjectsLoaded actually does something
77
+ storyGoalManager . initialized = false ;
73
78
storyGoalManager . OnSceneObjectsLoaded ( ) ;
74
-
75
- storyGoalManager . compoundGoalTracker . goals . RemoveAll ( goal => completedGoals . Contains ( goal . key ) ) ;
76
- completedGoals . ForEach ( goal => storyGoalManager . onGoalUnlockTracker . goalUnlocks . Remove ( goal ) ) ;
77
-
79
+
78
80
// Clean LocationGoalTracker, BiomeGoalTracker and ItemGoalTracker already completed goals
79
81
storyGoalManager . locationGoalTracker . goals . RemoveAll ( goal => completedGoals . Contains ( goal . key ) ) ;
80
82
storyGoalManager . biomeGoalTracker . goals . RemoveAll ( goal => completedGoals . Contains ( goal . key ) ) ;
@@ -90,15 +92,39 @@ private static IEnumerator SetupTrackers(InitialPlayerSync packet)
90
92
}
91
93
}
92
94
techTypesToRemove . ForEach ( techType => storyGoalManager . itemGoalTracker . goals . Remove ( techType ) ) ;
93
- yield break ;
95
+
96
+ // OnGoalUnlock might trigger the creation of a signal which is later on set to invisible when getting close to it
97
+ // the invisibility is managed by PingInstance_Set_Patches and is restored during PlayerPreferencesInitialSyncProcessor
98
+ // So we still need to recreate the signals at every game launch
99
+
100
+ // To avoid having the SignalPing play its sound we just make its notification null while triggering it
101
+ // (the sound is something like "coordinates added to the gps" or something)
102
+ SignalPing prefabSignalPing = onGoalUnlockTracker . signalPrefab . GetComponent < SignalPing > ( ) ;
103
+ PDANotification pdaNotification = prefabSignalPing . vo ;
104
+ prefabSignalPing . vo = null ;
105
+
106
+ foreach ( OnGoalUnlock onGoalUnlock in onGoalUnlockTracker . unlockData . onGoalUnlocks )
107
+ {
108
+ if ( completedGoals . Contains ( onGoalUnlock . goal ) )
109
+ {
110
+ // Code adapted from OnGoalUnlock.Trigger
111
+ foreach ( UnlockSignalData unlockSignalData in onGoalUnlock . signals )
112
+ {
113
+ unlockSignalData . Trigger ( onGoalUnlockTracker ) ;
114
+ }
115
+ }
116
+ }
117
+
118
+ // recover the notification sound
119
+ prefabSignalPing . vo = pdaNotification ;
94
120
}
95
121
96
122
// Must happen after CompletedGoals
97
- private static IEnumerator SetupAuroraAndSunbeam ( InitialPlayerSync packet )
123
+ private static void SetupAuroraAndSunbeam ( InitialPlayerSync packet )
98
124
{
99
125
TimeData timeData = packet . TimeData ;
100
126
101
- AuroraWarnings auroraWarnings = UnityEngine . Object . FindObjectOfType < AuroraWarnings > ( ) ;
127
+ AuroraWarnings auroraWarnings = Player . mainObject . GetComponentInChildren < AuroraWarnings > ( true ) ;
102
128
auroraWarnings . timeSerialized = DayNightCycle . main . timePassedAsFloat ;
103
129
auroraWarnings . OnProtoDeserialize ( null ) ;
104
130
@@ -115,15 +141,17 @@ private static IEnumerator SetupAuroraAndSunbeam(InitialPlayerSync packet)
115
141
StoryGoalCustomEventHandler . main . countdownStartingTime = sunbeamCountdownGoal . TimeExecute - 2370 ;
116
142
// See StoryGoalCustomEventHandler.endTime for calculation (endTime - 30 seconds)
117
143
}
118
-
119
- yield break ;
120
144
}
121
145
122
146
// Must happen after CompletedGoals
123
- private static IEnumerator SetScheduledGoals ( InitialPlayerSync packet )
147
+ private static void SetScheduledGoals ( InitialPlayerSync packet )
124
148
{
125
149
List < NitroxScheduledGoal > scheduledGoals = packet . StoryGoalData . ScheduledGoals ;
126
150
151
+ // We don't want any scheduled goal we add now to be executed before initial sync has finished, else they might not get broadcasted
152
+ StoryGoalScheduler . main . paused = true ;
153
+ Multiplayer . OnLoadingComplete += ( ) => StoryGoalScheduler . main . paused = false ;
154
+
127
155
foreach ( NitroxScheduledGoal scheduledGoal in scheduledGoals )
128
156
{
129
157
// Clear duplicated goals that might have appeared during loading and before sync
@@ -135,17 +163,17 @@ private static IEnumerator SetScheduledGoals(InitialPlayerSync packet)
135
163
goalType = ( Story . GoalType ) scheduledGoal . GoalType ,
136
164
timeExecute = scheduledGoal . TimeExecute ,
137
165
} ;
138
- if ( goal . timeExecute >= DayNightCycle . main . timePassedAsDouble && ! StoryGoalManager . main . completedGoals . Contains ( goal . goalKey ) )
166
+ if ( ! StoryGoalManager . main . completedGoals . Contains ( goal . goalKey ) )
139
167
{
140
168
StoryGoalScheduler . main . schedule . Add ( goal ) ;
141
169
}
142
170
}
143
171
144
- yield break ;
172
+ RefreshStoryWithLatestData ( ) ;
145
173
}
146
174
147
175
// Must happen after CompletedGoals
148
- private static IEnumerator RefreshStoryWithLatestData ( )
176
+ private static void RefreshStoryWithLatestData ( )
149
177
{
150
178
// If those aren't set up yet, they'll initialize correctly in time
151
179
// Else, we need to force them to acquire the right data
@@ -157,7 +185,6 @@ private static IEnumerator RefreshStoryWithLatestData()
157
185
{
158
186
PrecursorGunStoryEvents . main . Start ( ) ;
159
187
}
160
- yield break ;
161
188
}
162
189
163
190
private void SetTimeData ( InitialPlayerSync packet )
0 commit comments