@@ -18,13 +18,19 @@ public enum PlaybackState
1818 public partial class PlaybackViewModel : ViewModelBase
1919 {
2020 private const double FrameIntervalMs = 100 ;
21- private const int MaximumReasonableLiveGameMilliseconds = 2 * 60 * 60 * 1000 ;
22- private const int MaximumSingleLiveTimeJumpMilliseconds = 10 * 60 * 1000 ;
21+ private const int OfficialMatchDurationMilliseconds = 10 * 60 * 1000 ;
22+ private const int TimelineGameTimeGuardSlackMilliseconds = 5 * 60 * 1000 ;
23+ private const int MaximumReasonableTimelineGameMilliseconds =
24+ OfficialMatchDurationMilliseconds + TimelineGameTimeGuardSlackMilliseconds ;
25+ private const int MaximumSingleTimelineTimeJumpMilliseconds =
26+ OfficialMatchDurationMilliseconds + TimelineGameTimeGuardSlackMilliseconds ;
2327 private static readonly double [ ] PlaybackSpeeds = { 0.5 , 1 , 2 , 4 } ;
2428 private readonly PlaybackReader _reader = new ( ) ;
2529 private DispatcherTimer ? _playbackTimer ;
2630 private int _currentFrame ;
2731 private int _totalFrames ;
32+ private int _stablePlaybackGameTimeMs ;
33+ private bool _hasStablePlaybackGameTime ;
2834 private int _stableLiveGameTimeMs ;
2935 private bool _hasStableLiveGameTime ;
3036 private Action < MessageToClient > ? _onMessageReceived ;
@@ -71,6 +77,7 @@ public void LoadPlayback(string filePath)
7177 IsFileLoaded = true ;
7278 _totalFrames = CountTotalFrames ( ) ;
7379 _currentFrame = 0 ;
80+ ResetStablePlaybackGameTime ( ) ;
7481 State = PlaybackState . Stopped ;
7582 UpdatePlaybackProgress ( null ) ;
7683 }
@@ -80,6 +87,7 @@ public void LoadPlayback(string filePath)
8087 FilePath = string . Empty ;
8188 _currentFrame = 0 ;
8289 _totalFrames = 0 ;
90+ ResetStablePlaybackGameTime ( ) ;
8391 UpdatePlaybackProgress ( null ) ;
8492 System . Diagnostics . Debug . WriteLine ( $ "加载回放失败:{ ex . Message } ") ;
8593 throw ;
@@ -127,6 +135,7 @@ public void Stop()
127135 StopPlaybackTimer ( ) ;
128136 _reader . Reset ( ) ;
129137 _currentFrame = 0 ;
138+ ResetStablePlaybackGameTime ( ) ;
130139 State = PlaybackState . Stopped ;
131140 UpdatePlaybackProgress ( null ) ;
132141 }
@@ -173,11 +182,32 @@ private TimeSpan GetPlaybackInterval()
173182
174183 private void UpdatePlaybackProgress ( MessageToClient ? message )
175184 {
176- int gameTimeMs = message ? . AllMessage ? . GameTime ?? ( int ) Math . Round ( _currentFrame * FrameIntervalMs ) ;
185+ int gameTimeMs = ResolveStablePlaybackGameTime ( message , _currentFrame ) ;
177186 PlaybackTimeText = FormatGameTime ( gameTimeMs ) ;
178187 FrameProgressText = IsFileLoaded ? $ "帧 { _currentFrame } /{ _totalFrames } " : "帧 0/0" ;
179188 }
180189
190+ private int ResolveStablePlaybackGameTime ( MessageToClient ? message , int frameIndex )
191+ {
192+ int estimatedGameTimeMs = EstimateTimelineGameTime ( frameIndex ) ;
193+
194+ if ( message ? . AllMessage == null )
195+ {
196+ return _hasStablePlaybackGameTime ? _stablePlaybackGameTimeMs : estimatedGameTimeMs ;
197+ }
198+
199+ int rawGameTimeMs = message . AllMessage . GameTime ;
200+ if ( AcceptTimelineGameTime ( rawGameTimeMs , message . GameState , _hasStablePlaybackGameTime , _stablePlaybackGameTimeMs ) )
201+ {
202+ _stablePlaybackGameTimeMs = _hasStablePlaybackGameTime
203+ ? Math . Max ( _stablePlaybackGameTimeMs , rawGameTimeMs )
204+ : rawGameTimeMs ;
205+ _hasStablePlaybackGameTime = true ;
206+ }
207+
208+ return _hasStablePlaybackGameTime ? _stablePlaybackGameTimeMs : estimatedGameTimeMs ;
209+ }
210+
181211 public void UpdateLiveProgress ( MessageToClient ? message , int liveFrameCount )
182212 {
183213 int safeFrameCount = Math . Max ( liveFrameCount , 0 ) ;
@@ -188,7 +218,7 @@ public void UpdateLiveProgress(MessageToClient? message, int liveFrameCount)
188218
189219 private int ResolveStableLiveGameTime ( MessageToClient ? message , int liveFrameCount )
190220 {
191- int estimatedGameTimeMs = EstimateLiveGameTime ( liveFrameCount ) ;
221+ int estimatedGameTimeMs = EstimateTimelineGameTime ( liveFrameCount ) ;
192222
193223 if ( message ? . AllMessage == null )
194224 {
@@ -201,7 +231,7 @@ private int ResolveStableLiveGameTime(MessageToClient? message, int liveFrameCou
201231 }
202232
203233 int rawGameTimeMs = message . AllMessage . GameTime ;
204- if ( AcceptLiveGameTime ( rawGameTimeMs , message . GameState ) )
234+ if ( AcceptTimelineGameTime ( rawGameTimeMs , message . GameState , _hasStableLiveGameTime , _stableLiveGameTimeMs ) )
205235 {
206236 _stableLiveGameTimeMs = _hasStableLiveGameTime
207237 ? Math . Max ( _stableLiveGameTimeMs , rawGameTimeMs )
@@ -212,29 +242,41 @@ private int ResolveStableLiveGameTime(MessageToClient? message, int liveFrameCou
212242 return _hasStableLiveGameTime ? _stableLiveGameTimeMs : estimatedGameTimeMs ;
213243 }
214244
215- private bool AcceptLiveGameTime ( int rawGameTimeMs , GameState gameState )
245+ private static bool AcceptTimelineGameTime (
246+ int rawGameTimeMs ,
247+ GameState gameState ,
248+ bool hasStableGameTime ,
249+ int stableGameTimeMs )
216250 {
217- if ( rawGameTimeMs < 0 || rawGameTimeMs > MaximumReasonableLiveGameMilliseconds )
251+ if ( rawGameTimeMs < 0 || rawGameTimeMs > MaximumReasonableTimelineGameMilliseconds )
218252 {
219253 return false ;
220254 }
221255
222- if ( ! _hasStableLiveGameTime )
256+ if ( ! hasStableGameTime )
223257 {
224258 return true ;
225259 }
226260
227- if ( gameState == GameState . GameEnd && rawGameTimeMs > _stableLiveGameTimeMs + MaximumSingleLiveTimeJumpMilliseconds )
261+ if ( gameState == GameState . GameEnd &&
262+ rawGameTimeMs > stableGameTimeMs + MaximumSingleTimelineTimeJumpMilliseconds )
228263 {
229264 return false ;
230265 }
231266
232- return rawGameTimeMs <= _stableLiveGameTimeMs + MaximumSingleLiveTimeJumpMilliseconds ;
267+ return rawGameTimeMs <= stableGameTimeMs + MaximumSingleTimelineTimeJumpMilliseconds ;
268+ }
269+
270+ private static int EstimateTimelineGameTime ( int frameCount )
271+ {
272+ int estimatedGameTimeMs = ( int ) Math . Round ( Math . Max ( frameCount , 0 ) * FrameIntervalMs ) ;
273+ return Math . Min ( estimatedGameTimeMs , MaximumReasonableTimelineGameMilliseconds ) ;
233274 }
234275
235- private static int EstimateLiveGameTime ( int liveFrameCount )
276+ private void ResetStablePlaybackGameTime ( )
236277 {
237- return ( int ) Math . Round ( Math . Max ( liveFrameCount , 0 ) * FrameIntervalMs ) ;
278+ _stablePlaybackGameTimeMs = 0 ;
279+ _hasStablePlaybackGameTime = false ;
238280 }
239281
240282 private void ResetStableLiveGameTime ( )
@@ -250,6 +292,7 @@ private static string FormatGameTime(int gameTimeMs)
250292 gameTimeMs = 0 ;
251293 }
252294
295+ gameTimeMs = Math . Min ( gameTimeMs , MaximumReasonableTimelineGameMilliseconds ) ;
253296 var time = TimeSpan . FromMilliseconds ( gameTimeMs ) ;
254297 return time . TotalHours >= 1
255298 ? $ "{ ( int ) time . TotalHours : 00} :{ time . Minutes : 00} :{ time . Seconds : 00} "
0 commit comments