LSClientHelper.cs 4.3 KB

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