Various local prediction and input processing related fixes
This commit is contained in:
@@ -113,73 +113,57 @@ namespace Multiplayer
|
||||
[[maybe_unused]] const AzNetworking::PacketEncodingBuffer& clientState
|
||||
)
|
||||
{
|
||||
// After receiving the first input from the client, start the update event to check for slow hacking
|
||||
if (!m_updateBankedTimeEvent.IsScheduled())
|
||||
{
|
||||
m_updateBankedTimeEvent.Enqueue(sv_InputUpdateTimeMs, true);
|
||||
}
|
||||
|
||||
if (invokingConnection == nullptr)
|
||||
{
|
||||
// Discard any input messages that were locally dispatched or sent by disconnected clients
|
||||
return;
|
||||
}
|
||||
|
||||
const ClientInputId clientInputId = inputArray[0].GetClientInputId();
|
||||
if (clientInputId <= m_lastClientInputId)
|
||||
{
|
||||
AZLOG(NET_Prediction, "Discarding old or out of order move input (current: %u, received %u)",
|
||||
aznumeric_cast<uint32_t>(m_lastClientInputId), aznumeric_cast<uint32_t>(clientInputId));
|
||||
return;
|
||||
}
|
||||
|
||||
// After receiving the first input from the client, start the update event to check for slow hacking
|
||||
if (!m_updateBankedTimeEvent.IsScheduled())
|
||||
{
|
||||
m_updateBankedTimeEvent.Enqueue(sv_InputUpdateTimeMs, true);
|
||||
}
|
||||
|
||||
const AZ::TimeMs currentTimeMs = AZ::GetElapsedTimeMs();
|
||||
const double clientInputRateSec = static_cast<double>(static_cast<AZ::TimeMs>(cl_InputRateMs)) / 1000.0;
|
||||
m_lastInputReceivedTimeMs = currentTimeMs;
|
||||
|
||||
// Keep track of last inputs received, also allows us to update frame ids
|
||||
m_lastInputReceived = inputArray;
|
||||
|
||||
// Figure out which index from the input array we want
|
||||
// we start at the oldest input that has not been processed
|
||||
int32_t inputArrayIndex = -1;
|
||||
for (int32_t i = NetworkInputArray::MaxElements - 1; i >= 0; --i)
|
||||
{
|
||||
// Find an input that is newer than the last one we processed
|
||||
if (m_lastInputReceived[i].GetClientInputId() > GetLastInputId())
|
||||
{
|
||||
inputArrayIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputArrayIndex < 0)
|
||||
{
|
||||
AZLOG
|
||||
(
|
||||
NET_Prediction,
|
||||
"Discarding old or out of order move input (current: %u, received %u)",
|
||||
aznumeric_cast<uint32_t>(GetLastInputId()),
|
||||
aznumeric_cast<uint32_t>(m_lastInputReceived[0].GetClientInputId())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
bool lostInput = false;
|
||||
if (GetLastInputId() < inputArray.GetPreviousInputId())
|
||||
{
|
||||
// last move id processed is older than the previous input id, we missed some input packets
|
||||
lostInput = true;
|
||||
}
|
||||
|
||||
SetLastInputId(m_lastInputReceived[0].GetClientInputId()); // Set this variable in case of migration
|
||||
|
||||
while (inputArrayIndex >= 0)
|
||||
while (m_lastClientInputId < clientInputId)
|
||||
{
|
||||
NetworkInput& input = m_lastInputReceived[inputArrayIndex];
|
||||
++m_lastClientInputId;
|
||||
|
||||
// Figure out which index from the input array we want
|
||||
// If we have skipped an id, check if it was sent to us in the array. If we have lost too many, just use the oldest one in the array
|
||||
const uint32_t deltaFrameId = aznumeric_cast<uint32_t>(clientInputId - m_lastClientInputId); // always >= 0 because of while loop check
|
||||
const uint32_t inputArrayIdx = AZStd::min(deltaFrameId, NetworkInputArray::MaxElements - 1);
|
||||
const bool lostInput = deltaFrameId >= NetworkInputArray::MaxElements; // For logging only
|
||||
|
||||
NetworkInput &input = m_lastInputReceived[inputArrayIdx];
|
||||
input.SetClientInputId(m_lastClientInputId);
|
||||
|
||||
// Anticheat, if we're receiving too many inputs, and fall outside our variable latency input window
|
||||
// Discard move input events, client may be speed hacking
|
||||
if (m_clientBankedTime < sv_MaxBankTimeWindowSec)
|
||||
{
|
||||
m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary
|
||||
|
||||
{
|
||||
ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId());
|
||||
GetNetBindComponent()->ProcessInput(input, static_cast<float>(clientInputRateSec));
|
||||
}
|
||||
|
||||
if (lostInput)
|
||||
{
|
||||
AZLOG(NET_Prediction, "InputLost InputId=%u", aznumeric_cast<uint32_t>(input.GetClientInputId()));
|
||||
@@ -193,7 +177,6 @@ namespace Multiplayer
|
||||
{
|
||||
AZLOG(NET_Prediction, "Dropped InputId=%u", aznumeric_cast<uint32_t>(input.GetClientInputId()));
|
||||
}
|
||||
--inputArrayIndex;
|
||||
}
|
||||
|
||||
if (sv_EnableCorrections && (currentTimeMs - m_lastCorrectionSentTimeMs > sv_MinCorrectionTimeMs))
|
||||
@@ -205,6 +188,14 @@ namespace Multiplayer
|
||||
|
||||
const AZ::HashValue32 localAuthorityHash = hashSerializer.GetHash();
|
||||
|
||||
AZLOG
|
||||
(
|
||||
NET_Prediction,
|
||||
"Hash values for ProcessInput: client=%u, server=%u",
|
||||
aznumeric_cast<uint32_t>(stateHash),
|
||||
aznumeric_cast<uint32_t>(localAuthorityHash)
|
||||
);
|
||||
|
||||
if (stateHash != localAuthorityHash)
|
||||
{
|
||||
// Produce correction for client
|
||||
@@ -542,21 +533,15 @@ namespace Multiplayer
|
||||
m_inputHistory.PopFront();
|
||||
}
|
||||
|
||||
const size_t inputHistorySize = m_inputHistory.Size();
|
||||
const int64_t inputHistorySize = aznumeric_cast<int64_t>(m_inputHistory.Size());
|
||||
|
||||
// Form the rest of the input array using the n most recent elements in the history buffer
|
||||
// NOTE: inputArray[0] has already been initialized hence start at i = 1
|
||||
for (uint32_t i = 1; i < NetworkInputArray::MaxElements; ++i)
|
||||
for (int64_t i = 1; i < aznumeric_cast<int64_t>(NetworkInputArray::MaxElements); ++i)
|
||||
{
|
||||
if (i < inputHistorySize)
|
||||
{
|
||||
inputArray[i] = m_inputHistory[inputHistorySize - 1 - i];
|
||||
}
|
||||
else // History is too small?
|
||||
{
|
||||
// Plug in the most recent input
|
||||
inputArray[i] = input;
|
||||
}
|
||||
// Clamp to oldest element if history is too small
|
||||
const int64_t historyIndex = AZStd::max<int64_t>(inputHistorySize - 1 - i, 0);
|
||||
inputArray[i] = m_inputHistory[historyIndex];
|
||||
}
|
||||
|
||||
// Send the input to server (only when we are not migrating)
|
||||
|
||||
Reference in New Issue
Block a user