public void Simulate() { if (authoritativeTimeline.Last == null) // Not initialized yet { return; } logger.Debug("Simulate: time: {0}, commands: {1}" , time , nextCommandFrame != null ? nextCommandFrame.Commands.Count : 0); int lastAcknowledgedCommandTime = -1; // Dequeue acknowledge commands and get last time that command is predicted if (lastAcknowledgedCommandSeq != null) { lastAcknowledgedCommandTime = DequeueAcknowledgedCommands(); } if (lastAcknowledgedCommandTime >= 0) { var authoritativeSnapshot = authoritativeTimeline.Last.Snapshot; var predictiveTimepoint = predictiveTimeline.InterpolatePoint(lastAcknowledgedCommandTime); if (predictiveTimepoint == null) { throw new InvalidOperationException(); // TODO: Message } var currentSnapshot = predictiveTimeline.Last.Snapshot; if (!authoritativeSnapshot.IsApproximate(predictiveTimepoint.Snapshot)) // Rollback and replay { predictiveTimeline = new Timeline(); predictiveTimeline.AddPoint(lastAcknowledgedCommandTime, authoritativeSnapshot); RecoverSnapshot((SimulatorSnapshot)authoritativeSnapshot); // TODO: Use SceneDesc.ReconciliationDeltaTime to optimize replay performance var deltaTime = Scene.Desc.SimulationDeltaTime; for (var replayTime = lastAcknowledgedCommandTime; replayTime < time; replayTime += deltaTime) { if (replayTime + deltaTime > time) { deltaTime = time - replayTime; } Simulate(from command in unacknowledgedCommands where command.Time >= replayTime && command.Time < replayTime + deltaTime select command); predictiveTimeline.AddPoint(replayTime + deltaTime, CreateSnapshot()); } } // TODO: Get jitter detail for analysis if (!currentSnapshot.IsApproximate(predictiveTimeline.Last.Snapshot)) { logger.Debug("Correction done with possible jitter"); } } if (nextCommandFrame != null || predictiveTimeline != null) { SimulatorSnapshot snapshot; if (predictiveTimeline != null) { snapshot = (SimulatorSnapshot)predictiveTimeline.InterpolatePoint(time).Snapshot; logger.Debug("RecoverSnapshot from predictive timeline"); } else { snapshot = (SimulatorSnapshot)authoritativeTimeline.InterpolatePoint(time).Snapshot; predictiveTimeline = new Timeline(); predictiveTimeline.AddPoint(time, snapshot); logger.Debug("RecoverSnapshot from authoritative timeline"); } RecoverSnapshot(snapshot); Simulate(nextCommandFrame != null ? nextCommandFrame.Commands : null); snapshot = CreateSnapshot(); if (unacknowledgedCommands.Count > 0) { predictiveTimeline.AddPoint(time + Scene.Desc.SimulationDeltaTime, snapshot); nextConvergenceTime = time + Scene.Desc.ConvergenceTime; logger.Debug("Simulate and CreateSnapshot for predictive timeline"); } else if (time < nextConvergenceTime) { /* * var authoritativeSnapshot = authoritativeTimeline.Last.Snapshot; * * // TODO: Need a better convergence algorithm * //snapshot = (SimulatorSnapshot)((ISnapshotArgs)snapshot).Interpolate(authoritativeSnapshot, Scene.Desc.ConvergenceRate); * * if (authoritativeSnapshot.IsApproximate(snapshot)) * { * logger.Debug("All commands are acknowledged and convergence is done in advance: {0} < {1}", time, nextConvergenceTime); * * snapshot = (SimulatorSnapshot)authoritativeSnapshot; * * predictiveTimeline = null; * nextConvergenceTime = null; * } * else * { * predictiveTimeline.AddPoint(time + Scene.Desc.SimulationDeltaTime, snapshot); * * logger.Info("All commands are acknowledged and convergence predictive timeline"); * } */ } else { predictiveTimeline = null; nextConvergenceTime = null; snapshot = (SimulatorSnapshot)authoritativeTimeline.InterpolatePoint(time + Scene.Desc.SimulationDeltaTime).Snapshot; logger.Debug("RecoverSnapshot from authoritative timeline and remove predictive timeline"); } RecoverSnapshot(snapshot); } else { var snapshot = (SimulatorSnapshot)authoritativeTimeline.InterpolatePoint(time + Scene.Desc.SimulationDeltaTime).Snapshot; logger.Debug("RecoverSnapshot from authoritative timeline"); RecoverSnapshot(snapshot); } CurrentStats.Time = time; CurrentStats.DeltaTime = Scene.Desc.SimulationDeltaTime; CurrentStats.SimulateTime = DateTime.UtcNow; CurrentStats.AdvanceStats(StatsFrames.Current); Scene.OnLateUpdate(); StatsFrames.CreateNextFrame(); StatsFrames.Current.AddStats <ClientSimulatorStats>(); CurrentStats.CreateTime = DateTime.UtcNow; time += Scene.Desc.SimulationDeltaTime; commandFrame = nextCommandFrame; nextCommandFrame = null; lastAcknowledgedCommandSeq = null; }
public void SaveStatsFrame(string filename) { File.WriteAllText(filename, StatsFrames.ToCsv()); }