/// <summary> /// 处理玩家提交的快照数据 /// </summary> internal bool Commit(int frame, ulong gcNID, ByteString data) { if (!this._frameToSnapshots.TryGetValue(frame, out List <PlayerSnapshot> playerSnapshots)) { playerSnapshots = new List <PlayerSnapshot>(); this._frameToSnapshots[frame] = playerSnapshots; } //检查玩家是否重复提交 if (playerSnapshots.Any(snapshot => snapshot.gcNID == gcNID)) { Logger.Error($"user:{gcNID} duplicate commit snapshot!"); return(false); } PlayerSnapshot playerSnapshot = new PlayerSnapshot(); playerSnapshot.gcNID = gcNID; playerSnapshot.data = data; playerSnapshot.crc = CRC32.Compute(data.ToByteArray()); playerSnapshots.Add(playerSnapshot); return(this.CheckPlayerSnapshots(frame, playerSnapshots)); }
private bool CheckPlayerSnapshots(int frame, List <PlayerSnapshot> playerSnapshots) { //判断是否所有玩家都提交了快照 if (playerSnapshots.Count < this._battle.numChampions) { return(false); } //检查crc一致性 //先找出crc多数一致的组 bool success = true; var group = playerSnapshots.GroupBy(s => s.crc); //如果只有一个分组,则代表全部玩家的crc值一致 //否则每个玩家进行判断 if (group.Count() > 1) { IGrouping <uint, PlayerSnapshot> maxGroup = null; int max = 0; foreach (var e in group) { int c = e.Count(); if (c <= max) { continue; } maxGroup = e; max = c; } System.Diagnostics.Debug.Assert(maxGroup != null); //正确的crc值 uint crc = maxGroup.Key; int count = playerSnapshots.Count; for (int i = 0; i < count; i++) { PlayerSnapshot playerSnapshot = playerSnapshots[i]; if (playerSnapshot.crc == crc) { continue; } Logger.Log(PrintSnapshot(maxGroup.First().data)); Logger.Log(PrintSnapshot(playerSnapshot.data)); Logger.Warn($"{playerSnapshot.gcNID} different snapshot crc32 value, expect:{crc} but:{playerSnapshot.crc} at frame:{frame}"); success = false; //发生不同步,触发回调函数 this._battle.OnOutOfSync(playerSnapshot.gcNID, frame, maxGroup.First().data, playerSnapshot.data); } } //如果crc正确 if (success) { ByteString data = playerSnapshots[0].data; //把快照数据保存到历史记录里 FrameSnapshot frameSnapshot = new FrameSnapshot { data = data, frame = frame }; this.Set(frameSnapshot); //该帧的检查已经完成,可以不保留在内存了 this._frameToSnapshots.Remove(frame); Logger.Log($"success,f{frame},snap count:{this._frameToSnapshot.Count},wcount:{this._frameToSnapshots.Count}"); } return(success); }