Removes DeltaCompressedDataSet, ReplicaFunctions.inl and BitmaskInterestHandler from GridMate

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-12-13 14:12:02 -08:00
parent ce4ebc57c9
commit 10ecb525fe
5 changed files with 0 additions and 1017 deletions
@@ -1,257 +0,0 @@
/*
* 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
*
*/
#ifndef GM_DELTACOMPRESSED_DATASET_H
#define GM_DELTACOMPRESSED_DATASET_H
#pragma once
#include <AzCore/Math/Vector3.h>
#include <GridMate/Serialize/DataMarshal.h>
#include <GridMate/Replica/DataSet.h>
namespace GridMate
{
namespace Helper
{
template<AZ::u32 DeltaRange>
AZ::u8 GetQuantized(float value)
{
/*
* Quantizing into a single byte, thus 255 values.
* [-DeltaRange V +DeltaRange]
* [0 Q 255]
* Given V, solve for Q.
*/
const float quantized = (value + DeltaRange) * 255.f / (2.f * DeltaRange);
const int clamped = AZ::GetClamp(static_cast<int>(quantized), 0, 255);
return static_cast<AZ::u8>(clamped);
}
template<AZ::u32 DeltaRange>
float GetUnquantized(AZ::u8 quantized)
{
/*
* Unquantizing from a single byte, out of 255 values.
* [0 Q 255]
* [-DeltaRange V +DeltaRange]
* Given Q, solve for V.
*/
return 2 * DeltaRange * quantized / 255.f - DeltaRange;
}
template<typename FieldType>
struct DeltaHelper;
/**
* \brief Works for integer and floating points numbers
*/
template<typename FieldType>
struct DeltaHelper
{
static bool IsWithinDelta(const FieldType& base, const FieldType& another, AZ::u32 deltaRange)
{
return abs(base - another) < deltaRange;
}
};
/**
* \brief Specialization for AZ::Vector3
*/
template<>
struct DeltaHelper<AZ::Vector3>
{
static bool IsWithinDelta(const AZ::Vector3& base, const AZ::Vector3& another, AZ::u32 deltaRange)
{
const AZ::Vector3 absDiff = (base - another).GetAbs();
return absDiff.GetX() < deltaRange && absDiff.GetY() < deltaRange && absDiff.GetZ() < deltaRange;
}
};
}
/**
* \brief Packing a value into a single byte within +/- @DeltaRange
*/
template<AZ::u32 DeltaRange, typename FieldType>
class DeltaMarshaller;
// float specialization
template<AZ::u32 DeltaRange>
class DeltaMarshaller<DeltaRange, float>
{
public:
void Marshal(WriteBuffer& wb, const float &value)
{
wb.Write(Helper::GetQuantized<DeltaRange>(value));
}
void Unmarshal(float& value, ReadBuffer &rb)
{
AZ::u8 delta;
rb.Read(delta);
value = Helper::GetUnquantized<DeltaRange>(delta);
}
};
// AZ::Vector3 specialization
template<AZ::u32 DeltaRange>
class DeltaMarshaller<DeltaRange, AZ::Vector3>
{
public:
void Marshal(WriteBuffer& wb, const AZ::Vector3& value)
{
wb.Write(Helper::GetQuantized<DeltaRange>(value.GetX()));
wb.Write(Helper::GetQuantized<DeltaRange>(value.GetY()));
wb.Write(Helper::GetQuantized<DeltaRange>(value.GetZ()));
}
void Unmarshal(AZ::Vector3& value, ReadBuffer& rb)
{
AZ::u8 delta[3];
rb.Read(delta[0]);
rb.Read(delta[1]);
rb.Read(delta[2]);
value = AZ::Vector3(Helper::GetUnquantized<DeltaRange>(delta[0]), Helper::GetUnquantized<DeltaRange>(delta[1]), Helper::GetUnquantized<DeltaRange>(delta[2]));
}
};
/**
* \brief Delta compressed DataSet, stateless and cacheless. Stateless - because it does not keep per-player state of any kind.
* Cacheless - because it does not keep a history of its values.
* This approach requires only one extra copy of a field, because the field is split into two portions: absolute and relative portions.
* The value is always the sum of two portions. We leverage existing DataSets to omit sending the larger absolute value, thus achieving compression.
*
* \tparam FieldType
* \tparam DeltaRange
* \tparam MarshalerType
* \tparam DeltaMarshalerType
*/
template<typename FieldType, AZ::u32 DeltaRange, typename MarshalerType = Marshaler<FieldType>, typename DeltaMarshalerType = DeltaMarshaller<DeltaRange, FieldType>>
class DeltaCompressedDataSet
{
public:
virtual ~DeltaCompressedDataSet() = default;
template<class C, void (C::* FuncPtr)(const FieldType&, const TimeContext&)>
class BindInterface;
/**
Constructs a DataSet.
**/
explicit DeltaCompressedDataSet(const char* debugName, const FieldType& value = FieldType())
: m_absolutePortion(debugName, value)
, m_relativePortion(debugName)
{
static_assert(DeltaRange > 0, "Delta range cannot be zero!");
// We need to intercept changes to our two DataSets, in order to calculate the combined value and report back to Replica Chunk on our time.
m_absolutePortion.SetDispatchOverride([this](const TimeContext& tc) {OnAbsolutePortionChanged(tc); });
m_relativePortion.SetDispatchOverride([this](const TimeContext& tc) {OnRelativePortionChanged(tc); });
}
/**
Modify the DataSet. Call this on the Primary node to change the data,
which will be propagated to all proxies.
**/
void Set(const FieldType& v)
{
m_combinedValue = v;
if (Helper::DeltaHelper<FieldType>::IsWithinDelta(m_absolutePortion.Get(), v, DeltaRange))
{
// within bounds, so only the relative portion needs to be updated
m_relativePortion.Set(v - m_absolutePortion.Get());
}
else
{
// relative out of range, reset absolute
m_absolutePortion.Set(v);
m_relativePortion.Set(static_cast<FieldType>(0));
}
}
/**
Returns the current value of the DataSet.
**/
const FieldType& Get() const
{
return m_combinedValue;
}
protected:
virtual void OnAbsolutePortionChanged(const TimeContext& /*tc*/)
{
m_combinedValue = m_absolutePortion.Get() + m_relativePortion.Get();
}
virtual void OnRelativePortionChanged(const TimeContext& /*tc*/)
{
m_combinedValue = m_absolutePortion.Get() + m_relativePortion.Get();
}
private:
DataSet<FieldType, MarshalerType> m_absolutePortion;
DataSet<FieldType, DeltaMarshalerType> m_relativePortion;
FieldType m_combinedValue; // the latest value on either primary or proxy
};
//-----------------------------------------------------------------------------
/**
Declares a DeltaCompressedDataSet with an event handler that is called when the value is changed.
Use BindInterface<Class, FuncPtr> to dispatch to a method on the ReplicaChunk's
ReplicaChunkInterface event handler instance.
**/
template<typename FieldType, AZ::u32 DeltaRange, typename MarshalerType, typename DeltaMarshalerType>
template<class C, void (C::* FuncPtr)(const FieldType&, const TimeContext&)>
class DeltaCompressedDataSet<FieldType, DeltaRange, MarshalerType, DeltaMarshalerType>::BindInterface
: public DeltaCompressedDataSet<FieldType, DeltaRange, MarshalerType, DeltaMarshalerType>
{
public:
explicit BindInterface(const char* debugName) : DeltaCompressedDataSet(debugName) { }
protected:
void OnAbsolutePortionChanged(const GridMate::TimeContext& tc) override
{
DeltaCompressedDataSet::OnAbsolutePortionChanged(tc);
m_lastUpdateTime = m_absolutePortion.GetLastUpdateTime();
if (m_relativePortion.GetLastUpdateTime() < m_lastUpdateTime)
{
// relative portion wasn't updated, so its callback won't be invoked this tick, therefore we need to dispatch change event now
DispatchChangedEvent(tc);
}
}
void OnRelativePortionChanged(const GridMate::TimeContext& tc) override
{
DeltaCompressedDataSet::OnRelativePortionChanged(tc);
m_lastUpdateTime = m_relativePortion.GetLastUpdateTime();
// Assuming that relative portion DataSet is dispatched after absolute portion by construction in DeltaCompressedDataSet
DispatchChangedEvent(tc);
}
void DispatchChangedEvent(const TimeContext& tc)
{
AZ_Assert(m_relativePortion.GetReplicaChunkBase(), "DataSets should be attached to replica chunks!");
if (C* c = static_cast<C*>(m_relativePortion.GetReplicaChunkBase()->GetHandler()))
{
const TimeContext changeTime{ m_lastUpdateTime, m_lastUpdateTime - (tc.m_realTime - tc.m_localTime) };
(*c.*FuncPtr)(Get(), changeTime);
}
}
private:
AZ::u32 m_lastUpdateTime = 0; // the latest update time among m_absolutePortion and m_relativePortion
};
//-----------------------------------------------------------------------------
} // namespace GridMate
#endif // GM_DELTACOMPRESSED_DATASET_H
@@ -1,421 +0,0 @@
/*
* 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 <GridMate/Replica/Interest/BitmaskInterestHandler.h>
#include <GridMate/Replica/Interpolators.h>
#include <GridMate/Replica/Replica.h>
#include <GridMate/Replica/ReplicaFunctions.h>
#include <GridMate/Replica/ReplicaMgr.h>
#include <GridMate/Replica/Interest/InterestManager.h>
namespace GridMate
{
void BitmaskInterestChunk::OnReplicaActivate(const ReplicaContext& rc)
{
m_interestHandler = static_cast<BitmaskInterestHandler*>(rc.m_rm->GetUserContext(AZ_CRC("BitmaskInterestHandler", 0x5bf5d75b)));
AZ_Warning("GridMate", m_interestHandler != nullptr, "No bitmask interest handler in the user context");
if (m_interestHandler)
{
m_interestHandler->OnNewRulesChunk(this, rc.m_peer);
}
}
void BitmaskInterestChunk::OnReplicaDeactivate(const ReplicaContext& rc)
{
if (m_interestHandler)
{
// even if rc.m_peer is null, we still need to call OnDeleteRulesChunk so that the interest handler can clear m_rulesReplica
m_interestHandler->OnDeleteRulesChunk(this, rc.m_peer);
}
}
bool BitmaskInterestChunk::AddRuleFn(RuleNetworkId netId, InterestBitmask bits, const RpcContext& ctx)
{
if (IsProxy())
{
auto rulePtr = m_interestHandler->CreateRule(ctx.m_sourcePeer);
rulePtr->Set(bits);
m_rules.insert(AZStd::make_pair(netId, rulePtr));
}
return true;
}
bool BitmaskInterestChunk::RemoveRuleFn(RuleNetworkId netId, const RpcContext&)
{
if (IsProxy())
{
m_rules.erase(netId);
}
return true;
}
bool BitmaskInterestChunk::UpdateRuleFn(RuleNetworkId netId, InterestBitmask bits, const RpcContext&)
{
if (IsProxy())
{
auto it = m_rules.find(netId);
if (it != m_rules.end())
{
it->second->Set(bits);
}
}
return true;
}
bool BitmaskInterestChunk::AddRuleForPeerFn(RuleNetworkId netId, PeerId peerId, InterestBitmask bitmask, const RpcContext&)
{
BitmaskInterestChunk::Ptr peerChunk = m_interestHandler->FindRulesChunkByPeerId(peerId);
if (peerChunk)
{
auto it = peerChunk->m_rules.find(netId);
if (it == peerChunk->m_rules.end())
{
auto rulePtr = m_interestHandler->CreateRule(peerId);
peerChunk->m_rules.insert(AZStd::make_pair(netId, rulePtr));
rulePtr->Set(bitmask);
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////
/*
* BitmaskInterest
*/
BitmaskInterest::BitmaskInterest(BitmaskInterestHandler* handler)
: m_handler(handler)
, m_bits(0)
{
AZ_Assert(m_handler, "Invalid interest handler");
}
///////////////////////////////////////////////////////////////////////////
/*
* BitmaskInterestRule
*/
void BitmaskInterestRule::Set(InterestBitmask newBitmask)
{
m_bits = newBitmask;
m_handler->UpdateRule(this);
}
void BitmaskInterestRule::Destroy()
{
m_handler->DestroyRule(this);
}
///////////////////////////////////////////////////////////////////////////
/*
* BitmaskInterestAttribute
*/
void BitmaskInterestAttribute::Set(InterestBitmask newBitmask)
{
m_bits = newBitmask;
m_handler->UpdateAttribute(this);
}
void BitmaskInterestAttribute::Destroy()
{
m_handler->DestroyAttribute(this);
}
///////////////////////////////////////////////////////////////////////////
/*
* BitmaskInterestHandler
*/
BitmaskInterestHandler::BitmaskInterestHandler()
: m_im(nullptr)
, m_rm(nullptr)
, m_lastRuleNetId(0)
, m_rulesReplica(nullptr)
{
}
BitmaskInterestRule::Ptr BitmaskInterestHandler::CreateRule(PeerId peerId)
{
BitmaskInterestRule* rulePtr = aznew BitmaskInterestRule(this, peerId, GetNewRuleNetId());
m_rules.insert(rulePtr);
if (peerId == m_rm->GetLocalPeerId() && m_rulesReplica)
{
m_rulesReplica->AddRuleRpc(rulePtr->GetNetworkId(), rulePtr->Get());
m_localRules.insert(rulePtr);
}
return rulePtr;
}
void BitmaskInterestHandler::FreeRule(BitmaskInterestRule* rule)
{
//TODO: should be pool-allocated
m_rules.erase(rule);
delete rule;
}
void BitmaskInterestHandler::DestroyRule(BitmaskInterestRule* rule)
{
if (m_rm && rule->GetPeerId() == m_rm->GetLocalPeerId() && m_rulesReplica)
{
m_rulesReplica->RemoveRuleRpc(rule->GetNetworkId());
}
rule->m_bits = 0;
m_dirtyRules.insert(rule);
m_localRules.erase(rule);
}
void BitmaskInterestHandler::UpdateRule(BitmaskInterestRule* rule)
{
if (m_rm && m_rulesReplica && rule->GetPeerId() == m_rm->GetLocalPeerId())
{
m_rulesReplica->UpdateRuleRpc(rule->GetNetworkId(), rule->Get());
}
m_dirtyRules.insert(rule);
}
BitmaskInterestAttribute::Ptr BitmaskInterestHandler::CreateAttribute(ReplicaId replicaId)
{
auto ptr = aznew BitmaskInterestAttribute(this, replicaId);
m_attrs.insert(ptr);
return ptr;
}
void BitmaskInterestHandler::FreeAttribute(BitmaskInterestAttribute* attrib)
{
//TODO: should be pool-allocated
m_attrs.erase(attrib);
delete attrib;
}
void BitmaskInterestHandler::DestroyAttribute(BitmaskInterestAttribute* attrib)
{
attrib->m_bits = 0;
m_dirtyAttributes.insert(attrib);
}
void BitmaskInterestHandler::UpdateAttribute(BitmaskInterestAttribute* attrib)
{
m_dirtyAttributes.insert(attrib);
}
void BitmaskInterestHandler::OnNewRulesChunk(BitmaskInterestChunk::Ptr chunk, ReplicaPeer* peer)
{
if (chunk != m_rulesReplica) // non-local
{
m_peerChunks.insert(AZStd::make_pair(peer->GetId(), chunk));
for (auto& rule : m_localRules)
{
chunk->AddRuleForPeerRpc(rule->GetNetworkId(), rule->GetPeerId(), rule->Get());
}
}
}
void BitmaskInterestHandler::OnDeleteRulesChunk(BitmaskInterestChunk::Ptr chunk, ReplicaPeer* peer)
{
AZ_UNUSED(chunk);
m_rulesReplica = nullptr;
if (peer)
{
m_peerChunks.erase(peer->GetId());
}
}
RuleNetworkId BitmaskInterestHandler::GetNewRuleNetId()
{
++m_lastRuleNetId;
if (m_rulesReplica)
{
return m_rulesReplica->GetReplicaId() | (static_cast<AZ::u64>(m_lastRuleNetId) << 32);
}
return (static_cast<AZ::u64>(m_lastRuleNetId) << 32);
}
BitmaskInterestChunk::Ptr BitmaskInterestHandler::FindRulesChunkByPeerId(PeerId peerId)
{
auto it = m_peerChunks.find(peerId);
if (it == m_peerChunks.end())
{
return nullptr;
}
else
{
return it->second;
}
}
const InterestMatchResult& BitmaskInterestHandler::GetLastResult()
{
return m_resultCache;
}
void BitmaskInterestHandler::Update()
{
m_resultCache.clear();
for (BitmaskInterestRule* rule : m_dirtyRules)
{
InterestBitmask j = 1;
for (size_t i = 0; i < k_numGroups; ++i, j <<= 1)
{
auto ruleIt = m_ruleGroups[i].find(rule);
bool isMatch = !!(rule->m_bits & j);
if (isMatch && ruleIt == m_ruleGroups[i].end())
{
m_ruleGroups[i].insert(rule);
// recalculate all the attributes in this bucket
for (BitmaskInterestAttribute* attr : m_attrGroups[i])
{
m_dirtyAttributes.insert(attr);
}
}
else if (!isMatch && ruleIt != m_ruleGroups[i].end())
{
m_ruleGroups[i].erase(ruleIt);
// recalculate all the attributes in this bucket
for (BitmaskInterestAttribute* attr : m_attrGroups[i])
{
m_dirtyAttributes.insert(attr);
}
}
}
if (rule->IsDeleted())
{
FreeRule(rule);
}
}
m_dirtyRules.clear();
for (BitmaskInterestAttribute* attr : m_dirtyAttributes)
{
InterestBitmask j = 1;
for (size_t i = 0; i < k_numGroups; ++i, j <<= 1)
{
auto attrIt = m_attrGroups[i].find(attr);
bool isMatch = !!(attr->m_bits & j);
if (isMatch && attrIt == m_attrGroups[i].end())
{
m_attrGroups[i].insert(attr);
}
else if (!isMatch && attrIt != m_attrGroups[i].end())
{
m_attrGroups[i].erase(attrIt);
}
}
}
for (BitmaskInterestAttribute* attr : m_dirtyAttributes)
{
auto repIt = m_resultCache.insert(attr->GetReplicaId());
InterestBitmask j = 1;
for (size_t i = 0; i < k_numGroups; ++i, j <<= 1)
{
if (!!(attr->m_bits & j))
{
for (BitmaskInterestRule* rule : m_ruleGroups[i])
{
repIt.first->second.insert(rule->GetPeerId());
}
}
}
if (attr->IsDeleted())
{
FreeAttribute(attr);
}
}
m_dirtyAttributes.clear();
}
void BitmaskInterestHandler::OnRulesHandlerRegistered(InterestManager* manager)
{
AZ_Assert(m_im == nullptr, "Handler is already registered with manager %p (%p)\n", m_im, manager);
AZ_Assert(m_rulesReplica == nullptr, "Rules replica is already created\n");
AZ_TracePrintf("GridMate", "Bitmask interest handler is registered\n");
m_im = manager;
m_rm = m_im->GetReplicaManager();
m_rm->RegisterUserContext(AZ_CRC("BitmaskInterestHandler", 0x5bf5d75b), this);
auto replica = Replica::CreateReplica("BitmaskInterestHandlerRules");
m_rulesReplica = CreateAndAttachReplicaChunk<BitmaskInterestChunk>(replica);
m_rm->AddPrimary(replica);
}
void BitmaskInterestHandler::OnRulesHandlerUnregistered(InterestManager* manager)
{
(void)manager;
AZ_Assert(m_im == manager, "Handler was not registered with manager %p (%p)\n", manager, m_im);
AZ_TracePrintf("GridMate", "Bitmask interest handler is unregistered\n");
if (m_rulesReplica)
{
m_rulesReplica->m_rules.clear();
m_rulesReplica->m_interestHandler = nullptr;
}
for (auto& chunk : m_peerChunks)
{
chunk.second->m_rules.clear();
chunk.second->m_interestHandler = nullptr;
}
m_rulesReplica = nullptr;
m_im = nullptr;
m_rm->UnregisterUserContext(AZ_CRC("BitmaskInterestHandler", 0x5bf5d75b));
m_rm = nullptr;
m_peerChunks.clear();
m_localRules.clear();
for (auto& a : m_attrs)
{
delete a;
}
for (auto& r : m_rules)
{
delete r;
}
m_dirtyAttributes.clear();
m_dirtyRules.clear();
for (auto& group : m_attrGroups)
{
group.clear();
}
for (auto& group : m_ruleGroups)
{
group.clear();
}
m_resultCache.clear();
}
///////////////////////////////////////////////////////////////////////////
}
@@ -1,237 +0,0 @@
/*
* 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
*
*/
#ifndef GM_REPLICA_BITMASKINTERESTHANDLER_H
#define GM_REPLICA_BITMASKINTERESTHANDLER_H
#include <GridMate/Replica/RemoteProcedureCall.h>
#include <GridMate/Replica/ReplicaChunk.h>
#include <GridMate/Replica/Interest/RulesHandler.h>
#include <GridMate/Serialize/UtilityMarshal.h>
#include <GridMate/Containers/vector.h>
#include <GridMate/Containers/unordered_set.h>
#include <AzCore/std/containers/array.h>
namespace GridMate
{
class BitmaskInterestHandler;
using InterestBitmask = AZ::u32;
/*
* Base interest
*/
class BitmaskInterest
{
friend class BitmaskInterestHandler;
public:
InterestBitmask Get() const { return m_bits; }
protected:
explicit BitmaskInterest(BitmaskInterestHandler* handler);
BitmaskInterestHandler* m_handler;
InterestBitmask m_bits;
};
///////////////////////////////////////////////////////////////////////////
/*
* Bitmask rule
*/
class BitmaskInterestRule
: public InterestRule
, public BitmaskInterest
{
friend class BitmaskInterestHandler;
public:
using Ptr = AZStd::intrusive_ptr<BitmaskInterestRule>;
GM_CLASS_ALLOCATOR(BitmaskInterestRule);
void Set(InterestBitmask newBitmask);
private:
// Intrusive ptr
template<class T>
friend struct AZStd::IntrusivePtrCountPolicy;
unsigned int m_refCount = 0;
AZ_FORCE_INLINE void add_ref() { ++m_refCount; }
AZ_FORCE_INLINE void release() { --m_refCount; if (!m_refCount) Destroy(); }
AZ_FORCE_INLINE bool IsDeleted() const { return m_refCount == 0; }
///////////////////////////////////////////////////////////////////////////
BitmaskInterestRule(BitmaskInterestHandler* handler, PeerId peerId, RuleNetworkId netId)
: InterestRule(peerId, netId)
, BitmaskInterest(handler)
{}
void Destroy();
};
///////////////////////////////////////////////////////////////////////////
/*
* Bitmask attribute
*/
class BitmaskInterestAttribute
: public InterestAttribute
, public BitmaskInterest
{
friend class BitmaskInterestHandler;
template<class T> friend class InterestPtr;
public:
using Ptr = AZStd::intrusive_ptr<BitmaskInterestAttribute>;
GM_CLASS_ALLOCATOR(BitmaskInterestAttribute);
void Set(InterestBitmask newBitmask);
private:
// Intrusive ptr
template<class T>
friend struct AZStd::IntrusivePtrCountPolicy;
unsigned int m_refCount = 0;
AZ_FORCE_INLINE void add_ref() { ++m_refCount; }
AZ_FORCE_INLINE void release() { Destroy(); }
AZ_FORCE_INLINE bool IsDeleted() const { return m_refCount == 0; }
///////////////////////////////////////////////////////////////////////////
BitmaskInterestAttribute(BitmaskInterestHandler* handler, ReplicaId repId)
: InterestAttribute(repId)
, BitmaskInterest(handler)
{}
void Destroy();
};
///////////////////////////////////////////////////////////////////////////
class BitmaskInterestChunk
: public ReplicaChunk
{
public:
GM_CLASS_ALLOCATOR(BitmaskInterestChunk);
BitmaskInterestChunk()
: AddRuleRpc("AddRule")
, RemoveRuleRpc("RemoveRule")
, UpdateRuleRpc("UpdateRule")
, AddRuleForPeerRpc("AddRuleForPeerRpc")
, m_interestHandler(nullptr)
{}
typedef AZStd::intrusive_ptr<BitmaskInterestChunk> Ptr;
bool IsReplicaMigratable() override { return false; }
bool IsBroadcast() override { return true; }
static const char* GetChunkName() { return "BitmaskInterestChunk"; }
void OnReplicaActivate(const ReplicaContext& rc) override;
void OnReplicaDeactivate(const ReplicaContext& rc) override;
bool AddRuleFn(RuleNetworkId netId, InterestBitmask bits, const RpcContext& ctx);
bool RemoveRuleFn(RuleNetworkId netId, const RpcContext&);
bool UpdateRuleFn(RuleNetworkId netId, InterestBitmask bits, const RpcContext&);
bool AddRuleForPeerFn(RuleNetworkId netId, PeerId peerId, InterestBitmask bitmask, const RpcContext&);
Rpc<RpcArg<RuleNetworkId>, RpcArg<InterestBitmask>>::BindInterface<BitmaskInterestChunk, &BitmaskInterestChunk::AddRuleFn> AddRuleRpc;
Rpc<RpcArg<RuleNetworkId>>::BindInterface<BitmaskInterestChunk, &BitmaskInterestChunk::RemoveRuleFn> RemoveRuleRpc;
Rpc<RpcArg<RuleNetworkId>, RpcArg<InterestBitmask>>::BindInterface<BitmaskInterestChunk, &BitmaskInterestChunk::UpdateRuleFn> UpdateRuleRpc;
Rpc<RpcArg<RuleNetworkId>, RpcArg<PeerId>, RpcArg<InterestBitmask>>::BindInterface<BitmaskInterestChunk, &BitmaskInterestChunk::AddRuleForPeerFn> AddRuleForPeerRpc;
unordered_map<RuleNetworkId, BitmaskInterestRule::Ptr> m_rules;
BitmaskInterestHandler* m_interestHandler;
};
/*
* Rules handler
*/
class BitmaskInterestHandler
: public BaseRulesHandler
{
friend class BitmaskInterestRule;
friend class BitmaskInterestAttribute;
friend class BitmaskInterestChunk;
public:
GM_CLASS_ALLOCATOR(BitmaskInterestHandler);
BitmaskInterestHandler();
// Creates new bitmask rule and binds it to the peer
BitmaskInterestRule::Ptr CreateRule(PeerId peerId);
// Creates new bitmask attribute and binds it to the replica
BitmaskInterestAttribute::Ptr CreateAttribute(ReplicaId replicaId);
// Calculates rules and attributes matches
void Update() override;
// Returns last recalculated results
const InterestMatchResult& GetLastResult() override;
InterestManager* GetManager() override { return m_im; }
private:
// BaseRulesHandler
void OnRulesHandlerRegistered(InterestManager* manager) override;
void OnRulesHandlerUnregistered(InterestManager* manager) override;
void DestroyRule(BitmaskInterestRule* rule);
void FreeRule(BitmaskInterestRule* rule);
void UpdateRule(BitmaskInterestRule* rule);
void DestroyAttribute(BitmaskInterestAttribute* attrib);
void FreeAttribute(BitmaskInterestAttribute* attrib);
void UpdateAttribute(BitmaskInterestAttribute* attrib);
void OnNewRulesChunk(BitmaskInterestChunk::Ptr chunk, ReplicaPeer* peer);
void OnDeleteRulesChunk(BitmaskInterestChunk::Ptr chunk, ReplicaPeer* peer);
RuleNetworkId GetNewRuleNetId();
BitmaskInterestChunk::Ptr FindRulesChunkByPeerId(PeerId peerId);
typedef unordered_set<BitmaskInterestAttribute*> AttributeSet;
typedef unordered_set<BitmaskInterestRule*> RuleSet;
static const size_t k_numGroups = sizeof(InterestBitmask) * CHAR_BIT;
InterestManager* m_im;
ReplicaManager* m_rm;
AZ::u32 m_lastRuleNetId;
unordered_map<PeerId, BitmaskInterestChunk::Ptr> m_peerChunks;
RuleSet m_localRules;
AttributeSet m_dirtyAttributes;
RuleSet m_dirtyRules;
AZStd::array<AttributeSet, k_numGroups> m_attrGroups;
AZStd::array<RuleSet, k_numGroups> m_ruleGroups;
InterestMatchResult m_resultCache;
BitmaskInterestChunk* m_rulesReplica;
AttributeSet m_attrs;
RuleSet m_rules;
};
///////////////////////////////////////////////////////////////////////////
}
#endif
@@ -1,98 +0,0 @@
/*
* 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
*
*/
#if (GM_FUNCTION_NUM_ARGS == 0)
#define GM_FUNCTION_TEMPLATE_PARMS
#define GM_FUNCTION_ARGS
#define GM_FUNCTION_ARGS_CONCAT
#define GM_FUNCTION_FORWARD
#define GM_FUNCTION_FORWARD_CONCAT
#elif (GM_FUNCTION_NUM_ARGS == 1)
#define GM_FUNCTION_TEMPLATE_PARMS , typename T0
#define GM_FUNCTION_ARGS T0 && t0
#define GM_FUNCTION_ARGS_CONCAT , GM_FUNCTION_ARGS
#define GM_FUNCTION_FORWARD AZStd::forward<T0>(t0)
#define GM_FUNCTION_FORWARD_CONCAT , GM_FUNCTION_FORWARD
#elif (GM_FUNCTION_NUM_ARGS == 2)
#define GM_FUNCTION_TEMPLATE_PARMS , typename T0, typename T1
#define GM_FUNCTION_ARGS T0 && t0, T1 && t1
#define GM_FUNCTION_ARGS_CONCAT , GM_FUNCTION_ARGS
#define GM_FUNCTION_FORWARD AZStd::forward<T0>(t0), AZStd::forward<T1>(t1)
#define GM_FUNCTION_FORWARD_CONCAT , GM_FUNCTION_FORWARD
#elif (GM_FUNCTION_NUM_ARGS == 3)
#define GM_FUNCTION_TEMPLATE_PARMS , typename T0, typename T1, typename T2
#define GM_FUNCTION_ARGS T0 && t0, T1 && t1, T2 && t2
#define GM_FUNCTION_ARGS_CONCAT , GM_FUNCTION_ARGS
#define GM_FUNCTION_FORWARD AZStd::forward<T0>(t0), AZStd::forward<T1>(t1), AZStd::forward<T2>(t2)
#define GM_FUNCTION_FORWARD_CONCAT , GM_FUNCTION_FORWARD
#elif (GM_FUNCTION_NUM_ARGS == 4)
#define GM_FUNCTION_TEMPLATE_PARMS , typename T0, typename T1, typename T2, typename T3
#define GM_FUNCTION_ARGS T0 && t0, T1 && t1, T2 && t2, T3 && t3
#define GM_FUNCTION_ARGS_CONCAT , GM_FUNCTION_ARGS
#define GM_FUNCTION_FORWARD AZStd::forward<T0>(t0), AZStd::forward<T1>(t1), AZStd::forward<T2>(t2), AZStd::forward<T3>(t3)
#define GM_FUNCTION_FORWARD_CONCAT , GM_FUNCTION_FORWARD
#elif (GM_FUNCTION_NUM_ARGS == 5)
#define GM_FUNCTION_TEMPLATE_PARMS , typename T0, typename T1, typename T2, typename T3, typename T4
#define GM_FUNCTION_ARGS T0 && t0, T1 && t1, T2 && t2, T3 && t3, T4 && t4
#define GM_FUNCTION_ARGS_CONCAT , GM_FUNCTION_ARGS
#define GM_FUNCTION_FORWARD AZStd::forward<T0>(t0), AZStd::forward<T1>(t1), AZStd::forward<T2>(t2), AZStd::forward<T3>(t3), AZStd::forward<T4>(t4)
#define GM_FUNCTION_FORWARD_CONCAT , GM_FUNCTION_FORWARD
#else
#error Unsupported argument count
#endif
/**
Create a ReplicaChunk that isn't attached to a Replica. To attach it to a replica,
call replica->AttachReplicaChunk(chunk).
**/
template<class ChunkType GM_FUNCTION_TEMPLATE_PARMS>
ChunkType* CreateReplicaChunk(GM_FUNCTION_ARGS)
{
static_assert(AZStd::is_base_of<ReplicaChunkBase, ChunkType>::value, "Class must inherit from ReplicaChunk");
ReplicaChunkDescriptor* descriptor = ReplicaChunkDescriptorTable::Get().FindReplicaChunkDescriptor(ReplicaChunkClassId(ChunkType::GetChunkName()));
AZ_Assert(descriptor, "Cannot find replica chunk descriptor for %s. Did you remember to register the chunk type?", ChunkType::GetChunkName());
ReplicaChunkDescriptorTable::Get().BeginConstructReplicaChunk(descriptor);
ChunkType* chunk = aznew ChunkType(GM_FUNCTION_FORWARD);
ReplicaChunkDescriptorTable::Get().EndConstructReplicaChunk();
chunk->Init(descriptor);
return chunk;
}
/**
Create a ReplicaChunk that is automatically attached to the replica.
**/
template<class ChunkType GM_FUNCTION_TEMPLATE_PARMS>
ChunkType* CreateAndAttachReplicaChunk(const ReplicaPtr& replica GM_FUNCTION_ARGS_CONCAT)
{
return CreateAndAttachReplicaChunk<ChunkType>(replica.get() GM_FUNCTION_FORWARD_CONCAT);
}
/**
Create a ReplicaChunk that is automatically attached to the replica.
**/
template<class ChunkType GM_FUNCTION_TEMPLATE_PARMS>
ChunkType* CreateAndAttachReplicaChunk(Replica* replica GM_FUNCTION_ARGS_CONCAT)
{
// Chunks cannot be attached while active
if (replica->IsActive())
{
AZ_Warning("GridMate", false, "Cannot attach chunk %s while replica is active", ChunkType::GetChunkName());
return nullptr;
}
ChunkType* chunk = CreateReplicaChunk<ChunkType>(GM_FUNCTION_FORWARD);
replica->AttachReplicaChunk(chunk);
return chunk;
}
#undef GM_FUNCTION_TEMPLATE_PARMS
#undef GM_FUNCTION_ARGS
#undef GM_FUNCTION_ARGS_CONCAT
#undef GM_FUNCTION_FORWARD
#undef GM_FUNCTION_FORWARD_CONCAT
@@ -40,7 +40,6 @@ set(FILES
Containers/unordered_set.h
Containers/vector.h
Replica/BasicHostChunkDescriptor.h
Replica/DeltaCompressedDataSet.h
Replica/DataSet.cpp
Replica/DataSet.h
Replica/Interpolators.h
@@ -58,7 +57,6 @@ set(FILES
Replica/ReplicaCommon.h
Replica/ReplicaDefs.h
Replica/ReplicaFunctions.h
Replica/ReplicaFunctions.inl
Replica/ReplicaInline.inl
Replica/ReplicaMgr.cpp
Replica/ReplicaMgr.h
@@ -80,8 +78,6 @@ set(FILES
Replica/Tasks/ReplicaProcessPolicy.cpp
Replica/Tasks/ReplicaProcessPolicy.h
Replica/Tasks/ReplicaPriorityPolicy.h
Replica/Interest/BitmaskInterestHandler.cpp
Replica/Interest/BitmaskInterestHandler.h
Replica/Interest/InterestDefs.h
Replica/Interest/InterestManager.cpp
Replica/Interest/InterestManager.h