1
1
using System ;
2
+ using System . Diagnostics ;
2
3
using System . Linq ;
3
4
using System . Numerics ;
4
5
using System . Threading . Tasks ;
5
- using System . Timers ;
6
6
using InfectedRose . Luz ;
7
7
using RakDotNet . IO ;
8
8
using Uchu . Core ;
9
+ using Timer = System . Timers . Timer ;
9
10
10
11
namespace Uchu . World
11
12
{
@@ -16,6 +17,11 @@ public class MovingPlatformComponent : ReplicaComponent
16
17
/// </summary>
17
18
private Timer Timer { get ; set ; }
18
19
20
+ /// <summary>
21
+ /// Current stopwatch for delta times.
22
+ /// </summary>
23
+ private Stopwatch Stopwatch { get ; set ; } = new Stopwatch ( ) ;
24
+
19
25
public LuzMovingPlatformPath Path { get ; set ; }
20
26
21
27
public string PathName { get ; set ; }
@@ -34,7 +40,20 @@ public class MovingPlatformComponent : ReplicaComponent
34
40
35
41
public uint NextWaypointIndex { get ; set ; }
36
42
37
- public float IdleTimeElapsed { get ; set ; }
43
+ /// <summary>
44
+ /// Time spent idle
45
+ /// </summary>
46
+ public float IdleTimeElapsed =>
47
+ State == PlatformState . Idle
48
+ ? ( float ) ( Stopwatch . ElapsedMilliseconds / 1000.0 )
49
+ : 0 ;
50
+
51
+ /// <summary>
52
+ /// Percent of the platform's moving progress between the current waypoints
53
+ /// </summary>
54
+ public float PercentBetweenPoints => State != PlatformState . Idle
55
+ ? ( float ) ( ( Stopwatch . ElapsedMilliseconds / 1000.0 ) / _currentDuration )
56
+ : 0 ;
38
57
39
58
public override ComponentId Id => ComponentId . MovingPlatformComponent ;
40
59
@@ -53,6 +72,8 @@ public class MovingPlatformComponent : ReplicaComponent
53
72
/// </summary>
54
73
public LuzMovingPlatformWaypoint NextWayPoint => Path . Waypoints [ NextIndex ] as LuzMovingPlatformWaypoint ;
55
74
75
+ private double _currentDuration ;
76
+
56
77
protected MovingPlatformComponent ( )
57
78
{
58
79
Listen ( OnStart , ( ) =>
@@ -65,7 +86,7 @@ protected MovingPlatformComponent()
65
86
Path = Zone . ZoneInfo . LuzFile . PathData . FirstOrDefault ( p =>
66
87
p is LuzMovingPlatformPath && p . PathName == PathName ) as LuzMovingPlatformPath ;
67
88
68
- Type = GameObject . Settings . TryGetValue ( "platformIsMover" , out var isMover ) && ( bool ) isMover
89
+ Type = ! GameObject . Settings . TryGetValue ( "platformIsMover" , out var isMover ) || ( bool ) isMover
69
90
? PlatformType . Mover
70
91
: GameObject . Settings . TryGetValue ( "platformIsSimpleMover" , out var isSimpleMover ) &&
71
92
( bool ) isSimpleMover
@@ -76,20 +97,45 @@ protected MovingPlatformComponent()
76
97
77
98
State = PlatformState . Idle ;
78
99
79
- Task . Run ( WaitPoint ) ;
100
+ Task . Run ( ( ) => WaitPoint ( ) ) ;
101
+
102
+ if ( GameObject . TryGetComponent < SimplePhysicsComponent > ( out var simplePhysicsComponent ) )
103
+ {
104
+ simplePhysicsComponent . HasPosition = false ;
105
+ }
106
+
107
+ if ( ! GameObject . TryGetComponent < QuickBuildComponent > ( out var quickBuildComponent ) ) return ;
108
+ Listen ( quickBuildComponent . OnStateChange , ( state ) =>
109
+ {
110
+ if ( state != RebuildState . Completed ) return ;
111
+
112
+ // The waypoint must be set to the previous from the start since WaitPoint increments it.
113
+ this . Stop ( ) ;
114
+ CurrentWaypointIndex = PathStart == 0 ? ( uint ) ( Path . Waypoints . Length - 1 ) : PathStart - 1 ;
115
+ Task . Run ( ( ) =>
116
+ {
117
+ // TODO: A wait is required at the beginning, otherwise the platform moves right as the player is unfrozen from the building complete animation.
118
+ WaitPoint ( 1 ) ;
119
+ } ) ;
120
+ } ) ;
80
121
} ) ;
81
122
}
82
123
83
- public override void Construct ( BitWriter writer )
124
+ public override void Construct ( BitWriter writer )
84
125
{
85
- Serialize ( writer ) ;
126
+ Serialize ( writer , true ) ;
86
127
}
87
128
88
129
public override void Serialize ( BitWriter writer )
130
+ {
131
+ Serialize ( writer , false ) ;
132
+ }
133
+
134
+ public void Serialize ( BitWriter writer , bool includePath )
89
135
{
90
136
writer . WriteBit ( true ) ;
91
137
92
- var hasPath = PathName != null ;
138
+ var hasPath = includePath && PathName != null ;
93
139
94
140
writer . WriteBit ( hasPath ) ;
95
141
@@ -148,61 +194,101 @@ public override void Serialize(BitWriter writer)
148
194
}
149
195
}
150
196
197
+ public void Stop ( )
198
+ {
199
+ Timer . Stop ( ) ;
200
+ State = PlatformState . Idle ;
201
+ }
202
+
203
+ public void MoveTo ( uint position , Action moveCompleteCallback = default )
204
+ {
205
+ // Update Object in world.
206
+ CurrentWaypointIndex = position ;
207
+ NextWaypointIndex = NextIndex ;
208
+ _currentDuration = ( WayPoint . Position - NextWayPoint . Position ) . Length ( ) / WayPoint . Speed ;
209
+ Stopwatch . Restart ( ) ;
210
+ State = PlatformState . Move ;
211
+ TargetPosition = WayPoint . Position ;
212
+ TargetRotation = WayPoint . Rotation ;
213
+
214
+ GameObject . Serialize ( GameObject ) ;
215
+
216
+ // Start Waiting after completing path.
217
+ Timer = new Timer
218
+ {
219
+ AutoReset = false ,
220
+ Interval = _currentDuration * 1000
221
+ } ;
222
+ Timer . Elapsed += ( sender , args ) =>
223
+ {
224
+ Timer . Stop ( ) ;
225
+
226
+ // Update Object in world.
227
+ CurrentWaypointIndex = NextIndex ;
228
+ PathName = null ;
229
+ State = PlatformState . Idle ;
230
+ TargetPosition = WayPoint . Position ;
231
+ TargetRotation = WayPoint . Rotation ;
232
+ NextWaypointIndex = NextIndex ;
233
+
234
+ GameObject . Serialize ( GameObject ) ;
235
+ } ;
236
+ if ( moveCompleteCallback != default )
237
+ {
238
+ Timer . Elapsed += ( sender , args ) => moveCompleteCallback ( ) ;
239
+ }
240
+
241
+ Timer . Start ( ) ;
242
+ }
243
+
151
244
private void MovePlatform ( )
152
245
{
153
- /*
154
- * Update Object in world.
155
- */
156
- PathName = Path . PathName ;
246
+ // Update Object in world.
247
+ _currentDuration = ( WayPoint . Position - NextWayPoint . Position ) . Length ( ) / WayPoint . Speed ;
248
+ Stopwatch . Restart ( ) ;
157
249
State = PlatformState . Move ;
158
250
TargetPosition = WayPoint . Position ;
159
251
TargetRotation = WayPoint . Rotation ;
160
252
NextWaypointIndex = NextIndex ;
161
253
162
254
GameObject . Serialize ( GameObject ) ;
163
255
164
- /*
165
- * Start Waiting after completing path.
166
- */
256
+ // Start Waiting after completing path.
167
257
Timer = new Timer
168
258
{
169
259
AutoReset = false ,
170
- Interval = WayPoint . Speed * 1000
260
+ Interval = _currentDuration * 1000
171
261
} ;
172
-
173
262
Timer . Elapsed += ( sender , args ) => { WaitPoint ( ) ; } ;
174
263
175
- Task . Run ( ( ) => Timer . Start ( ) ) ;
264
+ Timer . Start ( ) ;
176
265
}
177
266
178
- private void WaitPoint ( )
267
+ private void WaitPoint ( int extraWaitTime = 0 )
179
268
{
180
269
// Move to next path index.
181
270
CurrentWaypointIndex = NextIndex ;
182
-
183
- /*
184
- * Update Object in world.
185
- */
186
- PathName = null ;
271
+ Stopwatch . Restart ( ) ;
272
+ _currentDuration = WayPoint . Wait ;
273
+
274
+ // Update Object in world.
187
275
State = PlatformState . Idle ;
188
276
TargetPosition = WayPoint . Position ;
189
277
TargetRotation = WayPoint . Rotation ;
190
278
NextWaypointIndex = NextIndex ;
191
279
192
280
GameObject . Serialize ( GameObject ) ;
193
281
194
- /*
195
- * Start Waiting after waiting.
196
- */
282
+ // Start Waiting after waiting.
197
283
Timer = new Timer
198
284
{
199
285
AutoReset = false ,
200
- Interval = WayPoint . Wait * 1000
286
+ Interval = ( WayPoint . Wait * 1000 ) + extraWaitTime
201
287
} ;
202
288
203
289
Timer . Elapsed += ( sender , args ) => { MovePlatform ( ) ; } ;
204
290
205
- Task . Run ( ( ) => Timer . Start ( ) ) ;
291
+ Timer . Start ( ) ;
206
292
}
207
293
}
208
294
}
0 commit comments