LSClientHelper.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. using System.IO;
  2. using ET.Client;
  3. namespace ET
  4. {
  5. public static class LSClientHelper
  6. {
  7. public static void RunRollbackSystem(Entity entity)
  8. {
  9. if (entity is LSEntity)
  10. {
  11. return;
  12. }
  13. LSEntitySystemSington.Instance.Rollback(entity);
  14. if (entity.ComponentsCount() > 0)
  15. {
  16. foreach (var kv in entity.Components)
  17. {
  18. RunRollbackSystem(kv.Value);
  19. }
  20. }
  21. if (entity.ChildrenCount() > 0)
  22. {
  23. foreach (var kv in entity.Children)
  24. {
  25. RunRollbackSystem(kv.Value);
  26. }
  27. }
  28. }
  29. // 回滚
  30. public static void Rollback(Room room, int frame)
  31. {
  32. Log.Debug($"roll back start {frame}");
  33. room.LSWorld.Dispose();
  34. FrameBuffer frameBuffer = room.FrameBuffer;
  35. // 回滚
  36. room.LSWorld = room.GetLSWorld(SceneType.LockStepClient, frame);
  37. OneFrameInputs authorityFrameInput = frameBuffer.FrameInputs(frame);
  38. // 执行AuthorityFrame
  39. room.Update(authorityFrameInput);
  40. room.SendHash(frame);
  41. // 重新执行预测的帧
  42. for (int i = room.AuthorityFrame + 1; i <= room.PredictionFrame; ++i)
  43. {
  44. OneFrameInputs oneFrameInputs = frameBuffer.FrameInputs(i);
  45. LSClientHelper.CopyOtherInputsTo(room, authorityFrameInput, oneFrameInputs); // 重新预测消息
  46. room.Update(oneFrameInputs);
  47. }
  48. RunRollbackSystem(room);
  49. Log.Debug($"roll back finish {frame}");
  50. }
  51. public static void SendHash(this Room self, int frame)
  52. {
  53. if (frame > self.AuthorityFrame)
  54. {
  55. return;
  56. }
  57. long hash = self.FrameBuffer.GetHash(frame);
  58. C2Room_CheckHash c2RoomCheckHash = NetServices.Instance.FetchMessage<C2Room_CheckHash>();
  59. c2RoomCheckHash.Frame = frame;
  60. c2RoomCheckHash.Hash = hash;
  61. self.GetParent<Scene>().GetComponent<SessionComponent>().Session.Send(c2RoomCheckHash);
  62. }
  63. // 重新调整预测消息,只需要调整其他玩家的输入
  64. public static void CopyOtherInputsTo(Room room, OneFrameInputs from, OneFrameInputs to)
  65. {
  66. long myId = room.GetComponent<LSClientUpdater>().MyId;
  67. foreach (var kv in from.Inputs)
  68. {
  69. if (kv.Key == myId)
  70. {
  71. continue;
  72. }
  73. to.Inputs[kv.Key] = kv.Value;
  74. }
  75. }
  76. public static void SaveReplay(Room room, string path)
  77. {
  78. if (room.IsReplay)
  79. {
  80. return;
  81. }
  82. Log.Debug($"save replay: {path} frame: {room.Replay.FrameInputs.Count}");
  83. byte[] bytes = MemoryPackHelper.Serialize(room.Replay);
  84. File.WriteAllBytes(path, bytes);
  85. }
  86. public static void JumpReplay(Room room, int frame)
  87. {
  88. if (!room.IsReplay)
  89. {
  90. return;
  91. }
  92. if (frame >= room.Replay.FrameInputs.Count)
  93. {
  94. frame = room.Replay.FrameInputs.Count - 1;
  95. }
  96. int snapshotIndex = frame / LSConstValue.SaveLSWorldFrameCount;
  97. Log.Debug($"jump replay start {room.AuthorityFrame} {frame} {snapshotIndex}");
  98. if (snapshotIndex != room.AuthorityFrame / LSConstValue.SaveLSWorldFrameCount || frame < room.AuthorityFrame)
  99. {
  100. room.LSWorld.Dispose();
  101. // 回滚
  102. byte[] memoryBuffer = room.Replay.Snapshots[snapshotIndex];
  103. LSWorld lsWorld = MongoHelper.Deserialize(typeof (LSWorld), memoryBuffer, 0, memoryBuffer.Length) as LSWorld;
  104. room.LSWorld = lsWorld;
  105. room.AuthorityFrame = snapshotIndex * LSConstValue.SaveLSWorldFrameCount;
  106. RunRollbackSystem(room);
  107. }
  108. room.FixedTimeCounter.Reset(TimeHelper.ServerFrameTime() - frame * LSConstValue.UpdateInterval, 0);
  109. Log.Debug($"jump replay finish {frame}");
  110. }
  111. }
  112. }