private void InterpolatePlayerState(bool grabAngles) { float f; int i; var gamestate = CDataModel.GameState; PlayerState outP = predictedPlayerState; SnapShot prev = gamestate.snap; SnapShot next = gamestate.nextSnap; gamestate.snap.playerState.CopyTo(outP); var cl = CDataModel.GameState.ClActive; if (grabAngles) { UserCmd cmd; int cmdNum = cl.cmdNum; CDataModel.GameState.GetUserCmd(cmdNum, out cmd); PMove.UpdateViewAngles(outP, cmd); } if (gamestate.nextFrameTeleport) { return; } if (next == null || next.serverTime <= prev.serverTime) { return; } f = (float)(gamestate.time - prev.serverTime) / (next.serverTime - prev.serverTime); i = next.playerState.bobCycle; if (i < prev.playerState.bobCycle) { i += 256; } outP.bobCycle = prev.playerState.bobCycle + (int)(f * (i - prev.playerState.bobCycle)); for (i = 0; i < 3; i++) { outP.origin[i] = prev.playerState.origin[i] * (int)(f * (next.playerState.origin[i] - prev.playerState.origin[i])); if (!grabAngles) { outP.viewangles[i] = CUtils.LerpAngles(prev.playerState.viewangles[i], next.playerState.viewangles[i], f); } outP.velocity[i] = prev.playerState.velocity[i] + f * (next.playerState.velocity[i] - prev.playerState.velocity[i]); } }
private void PredictPlayerState() { int cmdNum, current; PlayerState oldPlayerState; bool moved; UserCmd oldestCmd; UserCmd latestCmd; int stateIndex = 0, predictCmd = 0; int numPredicted = 0, numPlayedBack = 0; var gamestate = CDataModel.GameState; gamestate.hyperspace = false; if (!validPPS) { validPPS = true; predictedPlayerState = gamestate.snap.playerState; } //如果是播回放,那么就复制移动,不做预测 if (gamestate.demoPlayback || (gamestate.snap.playerState.pmFlags & PMoveFlags.FOLLOW) != PMoveFlags.NONE) { InterpolatePlayerState(false); return; } //非预测的本地移动会抓取最近的视角 if (CConstVar.NoPredict || CConstVar.SynchronousClients) { InterpolatePlayerState(true); return; } pmove.playerState = predictedPlayerState; if (pmove.playerState.pmType == PMoveType.DEAD) { // pmove.tracemask = } else { // pmove.tracemask } // if(gamestate.snap.playerState.persistant[3] == ) // pmove.noFootsteps = gamestate.dm oldPlayerState = predictedPlayerState; current = CDataModel.GameState.ClActive.cmdNum; //如果没有紧接着snapshot之后的comands,就不能精确预测当前的位置,所以就停在最后的正确位置上 cmdNum = current - CConstVar.CMD_BACKUP + 1; CDataModel.GameState.GetUserCmd(cmdNum, out oldestCmd); if (oldestCmd.serverTime > gamestate.snap.playerState.commandTime && oldestCmd.serverTime < gamestate.time) { if (CConstVar.ShowMiss > 0) { CLog.Info("exceeded Packet_Backup on commands"); } return; } CDataModel.GameState.GetUserCmd(current, out latestCmd); if (gamestate.nextSnap != null && !gamestate.nextFrameTeleport && !gamestate.thisFrameTeleport) { predictedPlayerState = gamestate.nextSnap.playerState; gamestate.physicsTime = gamestate.nextSnap.serverTime; } else { predictedPlayerState = gamestate.snap.playerState; gamestate.physicsTime = gamestate.snap.serverTime; } if (CConstVar.PMoveMsec < 8) { CConstVar.PMoveMsec = 8; } else if (CConstVar.PMoveMsec > 33) { CConstVar.PMoveMsec = 33; } pmove.pmoveFixed = CConstVar.PMoveFixed; pmove.pmoveMsec = CConstVar.PMoveMsec; pmove.pmoveFloat = CConstVar.PMoveFloat; // pmove.pmv if (CConstVar.OptimizePrediction) { if (gamestate.nextFrameTeleport || gamestate.thisFrameTeleport) { gamestate.lastPredictedCommand = 0; gamestate.stateTail = gamestate.stateHead; predictCmd = current - CConstVar.CMD_BACKUP + 1; } else if (gamestate.time == gamestate.lastServerTime) { predictCmd = gamestate.lastPredictedCommand + 1; } else { bool error = true; for (int i = gamestate.stateHead; i != gamestate.stateTail; i = (i + 1) % CConstVar.NUM_SAVED_STATES) { if (gamestate.savedPmoveState[i].commandTime == predictedPlayerState.commandTime) { int errorcode = IsUnacceptableError(predictedPlayerState, gamestate.savedPmoveState[i]); if (errorcode > 0) { if (CConstVar.ShowMiss > 0) { CLog.Info("errorcode %d at %d", errorcode, gamestate.time); } break; } pmove.playerState = gamestate.savedPmoveState[i]; gamestate.stateHead = (i + 1) % CConstVar.NUM_SAVED_STATES; predictCmd = gamestate.lastPredictedCommand + 1; error = false; break; } } if (error) { gamestate.lastPredictedCommand = 0; gamestate.stateTail = gamestate.stateHead; predictCmd = current - CConstVar.CMD_BACKUP + 1; } } gamestate.lastServerTime = gamestate.physicsTime; stateIndex = gamestate.stateHead; } moved = false; for (cmdNum = current - CConstVar.CMD_BACKUP + 1; cmdNum <= current; cmdNum++) { CDataModel.GameState.GetUserCmd(current, out pmove.cmd); if (pmove.pmoveFixed > 0) { PMove.UpdateViewAngles(pmove.playerState, pmove.cmd); } if (pmove.cmd.serverTime <= predictedPlayerState.commandTime) { continue; } if (pmove.cmd.serverTime > latestCmd.serverTime) { continue; } if (predictedPlayerState.commandTime == oldPlayerState.commandTime) { Vector3 delta; float len; if (gamestate.thisFrameTeleport) { gamestate.predictedError = Vector3.zero; if (CConstVar.ShowMiss > 0) { CLog.Info("PredictionTeleport"); } gamestate.thisFrameTeleport = false; } else { Vector3 adjusted, new_angles; AdjustPositionForMover(predictedPlayerState.origin, predictedPlayerState.groundEntityNum, gamestate.physicsTime, gamestate.oldTime, out adjusted, predictedPlayerState.viewangles, out new_angles); if (CConstVar.ShowMiss > 0) { if (oldPlayerState.origin != adjusted) { CLog.Info("prediction error"); } } delta = oldPlayerState.origin - adjusted; len = delta.magnitude; if (len > 0.1) { if (CConstVar.ShowMiss > 0) { CLog.Info("Prediction miss: %d", len); } if (CConstVar.ErrorDecay > 0) { int t = gamestate.time - gamestate.predictedErrorTime; float f = (CConstVar.ErrorDecay - t) / CConstVar.ErrorDecay; if (f < 0f) { f = 0f; } if (f > 0f && CConstVar.ShowMiss > 0) { CLog.Info("Double prediction decay: %d", f); } gamestate.predictedError = gamestate.predictedError * f; } else { gamestate.predictedError = Vector3.zero; } gamestate.predictedError = delta + gamestate.predictedError; gamestate.predictedErrorTime = gamestate.oldTime; } } } pmove.gauntletHit = false; if (pmove.pmoveFixed > 0) { pmove.cmd.serverTime = ((pmove.cmd.serverTime + CConstVar.PMoveMsec - 1) / CConstVar.PMoveMsec) * CConstVar.PMoveMsec; } if (CConstVar.OptimizePrediction) { if (cmdNum >= predictCmd || (stateIndex + 1) % CConstVar.NUM_SAVED_STATES == gamestate.stateHead) { pmove.Move(); numPredicted++; gamestate.lastPredictedCommand = cmdNum; if ((stateIndex + 1) % CConstVar.NUM_SAVED_STATES != gamestate.stateHead) { gamestate.savedPmoveState[stateIndex] = pmove.playerState; stateIndex = (stateIndex + 1) % CConstVar.NUM_SAVED_STATES; gamestate.stateTail = stateIndex; } } else { numPlayedBack++; if (CConstVar.ShowMiss > 0 && gamestate.savedPmoveState[stateIndex].commandTime != pmove.cmd.serverTime) { CLog.Info("saved state miss"); } pmove.playerState = gamestate.savedPmoveState[stateIndex]; stateIndex = (stateIndex + 1) % CConstVar.NUM_SAVED_STATES; } } else { pmove.Move(); numPredicted++; } moved = true; } if (CConstVar.ShowMiss > 1) { CLog.Info("[%d : %d] ", pmove.cmd.serverTime, gamestate.time); } if (!moved) { if (CConstVar.ShowMiss > 0) { CLog.Info("not moved"); } return; } AdjustPositionForMover(predictedPlayerState.origin, predictedPlayerState.groundEntityNum, gamestate.physicsTime, gamestate.time, out predictedPlayerState.origin, predictedPlayerState.viewangles, out predictedPlayerState.viewangles); if (CConstVar.ShowMiss > 0) { if (predictedPlayerState.eventSequence > oldPlayerState.eventSequence + CConstVar.MAX_PS_EVENTS) { CLog.Info("dropped event"); } } }