You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp

179 lines
6.4 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Multiplayer/NetworkInput/NetworkInput.h>
#include <Multiplayer/Components/MultiplayerComponentRegistry.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/IMultiplayer.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Console/ILogger.h>
namespace Multiplayer
{
NetworkInput::NetworkInput(const NetworkInput& rhs)
: m_inputId(rhs.m_inputId)
, m_owner(rhs.m_owner)
{
CopyInternal(rhs);
}
NetworkInput& NetworkInput::operator= (const NetworkInput& rhs)
{
if (&rhs != this)
{
CopyInternal(rhs);
}
return *this;
}
void NetworkInput::SetClientInputId(ClientInputId inputId)
{
m_inputId = inputId;
}
ClientInputId NetworkInput::GetClientInputId() const
{
return m_inputId;
}
ClientInputId& NetworkInput::ModifyClientInputId()
{
return m_inputId;
}
void NetworkInput::SetHostFrameId(HostFrameId hostFrameId)
{
m_hostFrameId = hostFrameId;
}
HostFrameId NetworkInput::GetHostFrameId() const
{
return m_hostFrameId;
}
HostFrameId& NetworkInput::ModifyHostFrameId()
{
return m_hostFrameId;
}
void NetworkInput::SetHostTimeMs(AZ::TimeMs hostTimeMs)
{
m_hostTimeMs = hostTimeMs;
}
AZ::TimeMs NetworkInput::GetHostTimeMs() const
{
return m_hostTimeMs;
}
AZ::TimeMs& NetworkInput::ModifyHostTimeMs()
{
return m_hostTimeMs;
}
void NetworkInput::AttachNetBindComponent(NetBindComponent* netBindComponent)
{
m_wasAttached = true;
m_componentInputs.clear();
if (netBindComponent)
{
m_owner = netBindComponent->GetEntityHandle();
m_componentInputs = netBindComponent->AllocateComponentInputs();
}
}
bool NetworkInput::Serialize(AzNetworking::ISerializer& serializer)
{
if (!serializer.Serialize(m_inputId, "InputId")
|| !serializer.Serialize(m_hostTimeMs, "HostTimeMs")
|| !serializer.Serialize(m_hostFrameId, "HostFrameId"))
{
return false;
}
uint16_t componentInputCount = static_cast<uint16_t>(m_componentInputs.size());
serializer.Serialize(componentInputCount, "ComponentInputCount");
m_componentInputs.resize(componentInputCount);
if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject)
{
for (uint16_t i = 0; i < componentInputCount; ++i)
{
// We need to do a little extra work here, the delta serializer won't actually write out values if they were the same as the parent.
// We need to make sure we don't lose state that is intrinsic to the underlying type
// The default InvalidNetComponentId is a placeholder, we expect it to be overwritten by the serializer
// This happens when deserializing a non-delta'd input command
// However in the delta serializer case, we use the previous input as our initial value
// which will have the NetworkInputs setup and therefore won't write out the componentId
NetComponentId componentId = m_componentInputs[i] ? m_componentInputs[i]->GetNetComponentId() : InvalidNetComponentId;
serializer.Serialize(componentId, "ComponentType");
// Create a new input if we don't have one or the types do not match
if ((m_componentInputs[i] == nullptr) || (componentId != m_componentInputs[i]->GetNetComponentId()))
{
m_componentInputs[i] = AZStd::move(GetMultiplayerComponentRegistry()->AllocateComponentInput(componentId));
}
if (!m_componentInputs[i])
{
// If the client tells us a component type that does not have a NetworkInput, they are likely hacking
AZLOG_ERROR("Unexpected MultiplayerComponent type, unable to deserialize, dropping message");
return false;
}
serializer.Serialize(*m_componentInputs[i], "ComponentInput");
}
m_wasAttached = true;
}
else
{
AZ_Assert(m_wasAttached, "AttachNetSystemComponent was never called for NetworkInput");
// We assume that the order of the network inputs is fixed between the server and client
for (auto& componentInput : m_componentInputs)
{
NetComponentId componentId = componentInput->GetNetComponentId();
serializer.Serialize(componentId, "ComponentId");
serializer.Serialize(*componentInput, "ComponentInput");
}
}
return true;
}
const IMultiplayerComponentInput* NetworkInput::FindComponentInput(NetComponentId componentId) const
{
// linear search since we expect to have very few components
for (auto& componentInput : m_componentInputs)
{
if (componentInput->GetNetComponentId() == componentId)
{
return componentInput.get();
}
}
return nullptr;
}
IMultiplayerComponentInput* NetworkInput::FindComponentInput(NetComponentId componentId)
{
const NetworkInput* tmp = this;
return const_cast<IMultiplayerComponentInput*>(tmp->FindComponentInput(componentId));
}
void NetworkInput::CopyInternal(const NetworkInput& rhs)
{
m_inputId = rhs.m_inputId;
m_hostFrameId = rhs.m_hostFrameId;
m_hostTimeMs = rhs.m_hostTimeMs;
m_componentInputs.resize(rhs.m_componentInputs.size());
for (int32_t i = 0; i < rhs.m_componentInputs.size(); ++i)
{
const NetComponentId rhsComponentId = rhs.m_componentInputs[i]->GetNetComponentId();
if (m_componentInputs[i] == nullptr || m_componentInputs[i]->GetNetComponentId() != rhsComponentId)
{
m_componentInputs[i] = AZStd::move(GetMultiplayerComponentRegistry()->AllocateComponentInput(rhsComponentId));
}
*(m_componentInputs[i]) = *(rhs.m_componentInputs[i]);
}
m_wasAttached = rhs.m_wasAttached;
}
}