Files
2025-12-18 16:59:29 -05:00

682 lines
28 KiB
C++

#pragma once
#include "ClusterUpdateBuffer.h"
#include "ConcurrentRakPeer.h"
#include "Item.h"
#include "NetworkSettings.h"
#include "PacketIds.h"
#include "ReplicatorStats.h"
#include "Streaming.h"
#include "Network/api.h"
#include "RakNet/Source/PluginInterface2.h"
#include "RakNetStatistics.h"
#include "V8Tree/Instance.h"
#include "Util/ClusterCellIterator.h"
#include "util/StreamRegion.h"
#include "Util/RunStateOwner.h"
#include "Util/Region2.h"
#include "Util/SystemAddress.h"
#include "Util/Memory.h"
#include "Util/IMetric.h"
#include "Util/ProtectedString.h"
#include "V8DataModel/DataModelJob.h"
#include "Voxel/CellChangeListener.h"
#include "voxel2/GridListener.h"
#include "queue"
#include <boost/unordered_set.hpp>
#include <boost/pool/object_pool.hpp>
#include <boost/unordered_map.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/optional.hpp>
#define NETWORK_PROTOCOL_VERSION_MIN 24 // Release 0.157
#define NETWORK_PROTOCOL_VERSION 34
#define REPLICATED_FIRST_FINISHED_TAG 12
#define TOP_REPLICATION_CONTAINER_FINISHED_TAG 13
namespace RakNet {
class RakPeerInterface;
class PacketLogger;
class RakPeer;
}
struct ReplicatorTestWrapper;
namespace RBX {
class PartInstance;
class SimJob;
class Assembly;
class MegaClusterInstance;
namespace Stats {
class StatsService;
}
namespace Network {
class ConcurrentRakPeer;
class Players;
class Player;
class PhysicsSender;
class PhysicsReceiver;
class Marker;
class InstancePacketCache;
class ClusterPacketCache;
class OneQuarterClusterPacketCache;
class StrictNetworkFilter;
struct PropValuePair;
class DeserializedChangePropertyItem;
class DeserializedDeleteInstanceItem;
class DeserializedEventInvocationItem;
class DeserializedNewInstanceItem;
class DeserializedJoinDataItem;
class DeserializedPingItem;
class DeserializedMarkerItem;
struct DeserializedPacket
{
RakNet::Packet* rawPacket;
std::vector<shared_ptr<DeserializedItem> > deserializedItems;
DeserializedPacket() {}
DeserializedPacket(RakNet::Packet* pkt) : rawPacket(pkt) {}
};
extern const char* const sReplicator;
class Replicator
: public RBX::DescribedNonCreatable<Replicator, IdSerializer, sReplicator, Reflection::ClassDescriptor::INTERNAL_LOCAL>
, public RakNet::PluginInterface2
, public RBX::IMetric
, public Voxel::CellChangeListener
, public Voxel2::GridListener
{
class ItemSender;
friend class DeserializedChangePropertyItem;
friend class DeserializedDeleteInstanceItem;
friend class DeserializedEventInvocationItem;
friend class DeserializedNewInstanceItem;
friend class DeserializedJoinDataItem;
friend class DeserializedPingItem;
friend class DeserializedMarkerItem;
friend class DeserializedTouchItem;
public:
friend struct ::ReplicatorTestWrapper; //testing
enum PropertyCacheType
{
PropertyCacheType_All,
PropertyCacheType_NonCacheable,
PropertyCacheType_Cacheable
};
enum DisconnectReason
{
DisconnectReason_BadHash,
DisconnectReason_SecurityKeyMismatch,
DisconnectReason_ProtocolMismatch,
DisconnectReason_ReceivePacketError,
DisconnectReason_ReceivePacketStreamError,
DisconnectReason_SendPacketError,
DisconnectReason_IllegalTeleport,
DisconnectReason_DuplicatePlayer,
DisconnectReason_DuplicateTicket,
DisconnectReason_TimeOut,
DisconnectReason_LuaKick,
DisconnectReason_OnRemoteSysStats,
DisconnectReason_HashTimeOut,
DisconnectReason_CloudEditKick
};
// --- ReplicationData and ClusterReplicationData are visible for testing ---
// The dictionary of objects that are involved in replication
// The Replicator listens to property changed and child added events
struct ReplicationData
{
shared_ptr<Instance> instance;
rbx::signals::connection connection;
bool deleteOnDisconnect;
bool replicateChildren : 1;
bool listenToChanges : 1;
};
struct ClusterReplicationData
{
static const int kUpdateChunkSizeLog2 = 2;
static const int kUpdateChunkVolume = 1 << (kUpdateChunkSizeLog2 * 3);
ClusterReplicationData()
{
readyToSendChunks = false;
}
rbx::signals::connection parentConnection;
ClusterUpdateBuffer updateBuffer;
boost::unordered_set<Vector3int32> updateBufferSmooth;
ClusterChunksIterator initialSendIterator;
std::vector<SpatialRegion::Id> initialChunkIterator;
std::vector<StreamRegion::Id> initialSendSmooth;
bool readyToSendChunks;
bool hasDataToSend()
{
return updateBuffer.size() > 0 || initialSendIterator.size() > 0 || initialChunkIterator.size() > 0 || initialSendSmooth.size() > 0 || updateBufferSmooth.size() > 0;
}
};
boost::shared_ptr<ConcurrentRakPeer> rakPeer;
RakNet::SystemAddress const remotePlayerId;
Instance* removingInstance; // The currently deleting Instance
ReplicatorStats replicatorStats;
// ServerReplicator and Client implement these
virtual bool checkDistributedReceive(PartInstance* part) = 0;
virtual bool checkDistributedSend(const PartInstance* part) = 0;
virtual bool checkDistributedSendFast(const PartInstance* part) = 0;
virtual void readPlayerSimulationRegion(const PartInstance* playerHead, Region2::WeightedPoint& weightedPoint){RBXASSERT(false);}
size_t incomingPacketsCount() const;
double incomingPacketsCountHeadWaitTimeSec(const RBX::Time& timeNow);
// Call this function to request that the Replicator disconnect.
// This function will submit a task to set Parent to null.
// The reason for the delay is that some context are unsafe
// to set Parent to NULL, such as RakPeerInterface::OnUpdate
void requestDisconnect(DisconnectReason reason);
void requestDisconnectWithSignal(DisconnectReason reason);
unsigned int getApproximateSizeOfPendingClusterDeltas() const { return approximateSizeOfPendingClusterDeltas; }
size_t getAdjustedMtuSize() const;
size_t getPhysicsMtuSize() const;
// Used for debugging
void disableProcessPackets();
void enableProcessPackets();
virtual void setPropSyncExpiration(double value) = 0;
Replicator(
RakNet::SystemAddress remotePlayerId,
boost::shared_ptr<ConcurrentRakPeer> rakPeer,
NetworkSettings* networkSettings,
bool clusterDebounceEnabled);
~Replicator();
double getRakOffsetTime() { return rakTimeOffset; }
// Utility routines
virtual Player* findTargetPlayer() const = 0;
virtual Player* getRemotePlayer() const = 0;
shared_ptr<Instance> getPlayer();
bool isInstanceAChildOfClientsCharacterModel(const Instance* testInstance) const;
static Reflection::BoundProp<int> prop_maxDataModelSendBuffer;
rbx::signal<void(std::string, bool)> disconnectionSignal;
virtual RakNet::PluginReceiveResult OnReceive(RakNet::Packet *packet);
virtual bool UsesReliabilityLayer(void) const {return true;} // this need to be set to true for OnInternalPacket to be called
virtual void OnInternalPacket(RakNet::InternalPacket *internalPacket, unsigned frameNumber, RakNet::SystemAddress remoteSystemAddress, RakNet::TimeMS time, int isSend);
virtual const RBX::Name& getClassName() const {
return Name::getNullName();
}
int getPort() const;
std::string getIpAddress() const;
//shared_ptr<Instance> sendMarker();
bool isSerializePending(const Instance* instance) const;
bool isPropertyChangedPending(const RBX::Reflection::ConstProperty& property) const;
virtual void requestCharacter() { throw std::runtime_error(""); }
virtual void requestInstances() { throw std::runtime_error(""); } // overwrite in client replicator
void closeConnection();
bool processNextIncomingPacket();
virtual void postProcessPacket(){} // overwrite in client replicator
std::string getRakStatsString(int verbosityLevel);
const ReplicatorStats& stats() const { return replicatorStats; }
ReplicatorStats::PhysicsSenderStats& physicsSenderStats();
int getBufferCountAvailable(int bufferLimit, PacketPriority priority);
bool isInitialDataSent();
std::string getMetric(const std::string& metric) const;
double getMetricValue(const std::string& metric) const;
virtual void addTopReplicationContainers(ServiceProvider* newProvider);
static bool isTopContainer(const Instance* instance);
inline const NetworkSettings& settings() const { return *networkSettings; }
virtual bool canUseProtocolVersion(int replicationProtocolVersion) const = 0;
// Part streaming
bool isInStreamedRegions(const Extents& ext) const;
bool isAreaInStreamedRadius(const Vector3& center, float radius) const;
bool isStreamingEnabled() const { return streamingEnabled; }
bool isReplicationContainer(const Instance* instance) const;
virtual bool isProtocolCompatible() const {return true;}
static void teachDictionaries(const Replicator* rep, RakNet::BitStream& bitStream, bool teachSchema, bool toBeCompressed);
virtual void sendDictionaries();
virtual bool isServerReplicator() {return false;}
void sendDisconnectionSignal(std::string peer, bool lostConnection);
Time getSendQueueHeadTime() const { return pendingItems.head_time(); }
RBX::Time remoteRaknetTimeToLocalRbxTime(const RemoteTime& time);
RBX::Time raknetTimeToRbxTime(const RakNet::Time& time);
RakNet::Time rbxTimeToRakNetTime(const RBX::Time& time);
protected:
class ChangePropertyItem;
class DeleteInstanceItem;
class EventInvocationItem;
class JoinDataItem;
class MarkerItem;
class TagItem;
class NewInstanceItem;
class ReferencePropertyChangedItem;
class StatsItem;
class ProcessPacketsJob;
class PingBackItem;
class PingItem;
class HashItem;
class PingJob;
class RockyItem;
class SendDataJob;
class StreamJob;
class Stats;
class SendStatsJob;
#ifndef RBX_STUDIO_BUILD
class NetPmcResponseItem;
class RockyDbgItem;
#endif
#ifdef RBX_RCC_SECURITY
class NetPmcChallengeItem;
#endif
// Item pools
boost::scoped_ptr<RBX::AutoMemPool> newInstancePool;
boost::scoped_ptr<RBX::AutoMemPool> deleteInstancePool;
boost::scoped_ptr<RBX::AutoMemPool> changePropertyPool;
boost::scoped_ptr<RBX::AutoMemPool> eventInvocationPool;
boost::scoped_ptr<RBX::AutoMemPool> pingPool;
boost::scoped_ptr<RBX::AutoMemPool> pingBackPool;
boost::scoped_ptr<RBX::AutoMemPool> referencePropertyChangedPool;
DescriptorDictionary<Reflection::ClassDescriptor> classDictionary;
DescriptorDictionary<Reflection::PropertyDescriptor> propDictionary;
DescriptorDictionary<Reflection::EventDescriptor> eventDictionary;
DescriptorDictionary<Reflection::Type> typeDictionary;
boost::scoped_ptr<StrictNetworkFilter> strictFilter;
// Replication
typedef boost::unordered_map<const Instance*, ReplicationData> RepConts;
RepConts replicationContainers;
MegaClusterInstance* megaClusterInstance;
ClusterReplicationData clusterReplicationData;
const bool clusterDebounceEnabled;
bool clusterDebounce;
// HACK FOR SINGLE CLUSTER
bool isClusterSpotted;
bool isOkToSendClusters;
unsigned int approximateSizeOfPendingClusterDeltas;
shared_ptr<InstancePacketCache> instancePacketCache;
shared_ptr<OneQuarterClusterPacketCache> oneQuarterClusterPacketCache; // used by streaming
shared_ptr<ClusterPacketCache> clusterPacketCache;
// An ordered list of the top-most replication containers
typedef std::list<Instance*> TopReplConts;
TopReplConts topReplicationContainers; // Instances whose children should be replicated
typedef boost::unordered_map<const Reflection::ClassDescriptor*, TopReplConts::iterator> TopReplContsMap;
TopReplContsMap topReplicationContainersMap; // fast lookup into top replication containers list
Players* players;
boost::shared_ptr<PhysicsReceiver> physicsReceiver;
// Jobs
shared_ptr<SendDataJob> sendDataJob;
shared_ptr<PingJob> pingJob;
shared_ptr<ProcessPacketsJob> processPacketsJob;
shared_ptr<Replicator::StreamJob> streamJob;
class SendClusterJob;
shared_ptr<SendClusterJob> sendClusterJob;
// Data-out
ItemQueue pendingItems;
ItemQueue highPriorityPendingItems;
int numItemsLeftFromPrevStep;
typedef boost::unordered_set<RBX::Reflection::ConstProperty, boost::hash<RBX::Reflection::ConstProperty>,
std::equal_to<RBX::Reflection::ConstProperty>, boost::fast_pool_allocator<RBX::Reflection::ConstProperty> > PendingPropertyChanges;
PendingPropertyChanges pendingChangedPropertyItems;
typedef boost::unordered_set<const Instance*> PendingInstances; // note - now watching for concurrency issues here
mutable RBX::mutex pendingInstancesMutex;
PendingInstances pendingNewInstances;
const Instance* serializingInstance;
// Data-in
const Reflection::Property* deserializingProperty; // The currently deserializing Event (if any)
const Reflection::EventInvocation* deserializingEventInvocation; // The currently deserializing EventInvocation (if any)
// Data-in/out
typedef std::map< const RBX::Name*, shared_ptr<Instance> > DefaultObjects;
DefaultObjects defaultObjects; // Used for stripping out default properties (compression)
// Note: This queue doesn't need a concurrency guard, but we need the timestamping feature
rbx::timestamped_safe_queue<RakNet::Packet*> incomingPackets;
bool processAllPacketsPerStep; // determine if ProcessPacketsJob should budget each step
void pushIncomingPacket(RakNet::Packet* packet);
void clearIncomingPackets();
std::queue<shared_ptr<Marker> > incomingMarkers;
NetworkSettings* networkSettings;
SharedDictionary<RBX::SystemAddress> systemAddressDictionary;
SharedDictionary<RBX::ContentId> contentIdDictionary;
// Part Streaming
bool streamingEnabled;
// protocol sync
bool protocolSyncEnabled;
bool apiDictionaryCompression;
bool connected;
bool enableHashCheckBypass;
bool enableMccCheckBypass;
bool canTimeout;
bool canReplicateInstance(Instance* instance, int replicationProtocolVersion);
void learnDictionaries(RakNet::BitStream& rawBitStream, bool compressed, bool learnSchema);
virtual bool isProtectedStringEnabled() = 0;
virtual std::string encodeProtectedString(const ProtectedString& value, const Instance* instance, const Reflection::PropertyDescriptor& desc) = 0;
virtual boost::optional<ProtectedString> decodeProtectedString(const std::string& value, const Instance* instance, const Reflection::PropertyDescriptor& desc) = 0;
virtual bool isLegalReceiveInstance(Instance* instance, Instance* parent) { return true; }
virtual bool isLegalDeleteInstance(Instance* instance) { return true; }
virtual bool isLegalReceiveEvent(Instance* instance, const Reflection::EventDescriptor& desc) { return true; }
virtual bool isLegalReceiveProperty(Instance* instance, const Reflection::PropertyDescriptor& desc) { return true; }
virtual bool isLegalSendProperty(Instance* instance, const Reflection::PropertyDescriptor& desc) = 0;
virtual bool isLegalSendInstance(const Instance* instance) { return true; }
virtual bool isLegalSendEvent(Instance* instance, const Reflection::EventDescriptor& desc) { return true;}
virtual bool isCloudEdit() const = 0;
static bool isCloudEditReplicateProperty(const Reflection::PropertyDescriptor& descriptor);
virtual bool prepareRemotePlayer(shared_ptr<Instance> instance) { return false; }
virtual bool checkRemotePlayer() { return true; }
virtual void rebroadcastEvent(Reflection::EventInvocation& eventInvocation) {}
virtual void readChangedProperty(RakNet::BitStream& bitStream, Reflection::Property prop);
virtual void readChangedPropertyItem(DeserializedChangePropertyItem* item, Reflection::Property prop);
virtual void processChangedParentProperty(Guid::Data parentId, Reflection::Property prop);
virtual void writeChangedProperty(const Instance* instance, const Reflection::PropertyDescriptor& desc, RakNet::BitStream& outBitStream);
virtual void writeChangedRefProperty(const Instance* instance,
const Reflection::RefPropertyDescriptor& desc, const Guid::Data& newRefGuid,
RakNet::BitStream& outBitStream);
// Called when a property is received from the remote peer:
virtual FilterResult filterReceivedChangedProperty(Instance* instance, const Reflection::PropertyDescriptor& desc) { return Accept; }
virtual FilterResult filterReceivedParent(Instance* instance, Instance* parent) { return Accept; }
virtual FilterResult filterPhysics(PartInstance* instance);
// Called when a property changes locally:
virtual FilterResult filterChangedProperty(Instance* instance, const Reflection::PropertyDescriptor& desc);
virtual void onPropertyChanged(Instance* instance, const Reflection::PropertyDescriptor* descriptor);
virtual shared_ptr<Stats> createStatsItem() = 0;
// These stats are updated asynchronously. Individual stats will be valid
// but combinations of stats may not be in sync.
const RakNet::RakNetStatistics* getRakNetStats() const;
virtual void processPacket(RakNet::Packet *packet);
virtual void processDeserializedPacket(const DeserializedPacket& deserializedPacket);
static void closeReplicationItem(ReplicationData& item);
bool disconnectReplicationData(shared_ptr<Instance> instance);
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
void onCombinedSignal(ReplicationData* replicationData, Instance::CombinedSignalType type, const ICombinedSignalData* genericData);
void onChildAdded(shared_ptr<Instance> child, boost::function<void (shared_ptr<Instance>)> replicationMethodFunc);
void onParentChanged(shared_ptr<Instance> instance);
void onEventInvocation(Instance* instance, const Reflection::EventDescriptor* descriptor, const Reflection::EventArguments* args, const SystemAddress* target);
void onTerrainParentChanged(shared_ptr<Instance> instance, shared_ptr<Instance> parent);
virtual void terrainCellChanged(const Voxel::CellChangeInfo& info);
virtual void onTerrainRegionChanged(const Voxel2::Region& region);
void onStatisticsChanged(const ConnectionStats&);
// Creates a "Default" object which has all default properties. Used to optimize streaming
const Instance* getDefault(const RBX::Name& className);
virtual bool wantReplicate(const Instance* source) const;
virtual void setRefValue(WaitItem& wi, Instance* instance);
virtual void onSentMarker(long id) {}
virtual void onSentTag(int tag) {}
void createPhysicsSender(NetworkSettings::PhysicsSendMethod method);
void createPhysicsReceiver(NetworkSettings::PhysicsReceiveMethod method, bool isServer);
void readPropertiesFromValueArray(const std::vector<PropValuePair>& propValueArray, Instance* instance);
void readProperties(RakNet::BitStream& inBitstream, Instance* instance, PropertyCacheType cacheType, bool useDictionary, bool preventBounceBack = true, std::vector<PropValuePair>* valueArray = NULL);
void readPropertiesInternal(Reflection::Property& property, RakNet::BitStream& inBitstream, bool useDictionary, bool preventBounceBack, Reflection::Variant* value);
virtual void writeProperties(const Instance* instance, RakNet::BitStream& outBitstream, PropertyCacheType cacheType, bool useDictionary);
void writePropertiesInternal(const Instance* instance, const Reflection::ConstProperty& property, RakNet::BitStream& outBitstream, PropertyCacheType cacheType, bool useDictionary);
virtual bool sendItemsPacket();
int sendItems(ItemSender& sender, ItemQueue& itemQueue);
virtual bool sendClusterPacket();
void sendClusterChunk(const StreamRegion::Id &regionId);
virtual void readItem(RakNet::BitStream& inBitstream, Item::ItemType itemType);
virtual shared_ptr<DeserializedItem> deserializeItem(RakNet::BitStream& inBitstream, Item::ItemType itemType);
virtual void addTopReplicationContainer(Instance* instance, bool replicateProperties, bool replicateChildren,
boost::function<void (shared_ptr<Instance>)> replicationMethodFunc);
virtual void dataOutStep();
virtual void processSendStats(unsigned int sendStats, unsigned int extraStats) {}
virtual void processHashStats(unsigned int hashStats) {}
virtual void checkPingItemTime() {}
// visible for testing
ReplicationData& addReplicationData(shared_ptr<Instance> instance, bool listenToChanges, bool replicateChildren);
void sendClusterContent(shared_ptr<RakNet::BitStream>& bitStream, ClusterUpdateBuffer& container, unsigned maxBytesSend);
void sendClusterContent(shared_ptr<RakNet::BitStream>& bitStream, ClusterChunksIterator& container, unsigned maxBytesSend);
void sendClusterContent(shared_ptr<RakNet::BitStream>& bitStream, OneQuarterClusterChunkCellIterator &container);
static void RemoteCheatHelper2(weak_ptr<RBX::DataModel> weakDataModel);
void serializePropertyValue(const Reflection::ConstProperty& property, RakNet::BitStream& outBitStream, bool useDictionary);
void deserializePropertyValue(RakNet::BitStream& inBitStream, Reflection::Property property, bool useDictionary, bool preventBounceBack, Reflection::Variant* value);
bool deserializeValue(RakNet::BitStream& inBitStream, const Reflection::Type& type, Reflection::Variant& value);
// visible for testing
virtual void receiveCluster(RakNet::BitStream& inBitstream, Instance* instance, bool usingOneQuarterIterator);
SharedStringProtectedDictionary& getSharedPropertyProtectedDictionary(const Reflection::PropertyDescriptor& descriptor);
SharedStringDictionary& getSharedPropertyDictionary(const Reflection::PropertyDescriptor& descriptor);
SharedStringDictionary& getSharedEventDictionary(const Reflection::EventDescriptor& descriptor);
SharedBinaryStringDictionary& getSharedPropertyBinaryDictionary(const Reflection::PropertyDescriptor& descriptor);
virtual bool canSendItems() = 0;
virtual void serializeSFFlags(RakNet::BitStream& outBitStream) const{}
virtual void deserializeSFFlags(RakNet::BitStream& inBitStream){}
unsigned int readJoinData(RakNet::BitStream& bitStream);
unsigned int readJoinDataItem(DeserializedJoinDataItem* item);
virtual bool isClassRemoved(const Instance* instance) {return false;}
virtual bool isPropertyRemoved(const Instance* instance, const Name& propertyName) {return false;}
virtual bool isEventRemoved(const Instance* instance, const Name& eventName) {return false;}
bool isPropertyCacheable(const Reflection::Type& type);
bool isPropertyCacheable(const Reflection::Type* type, bool isEnum);
virtual bool ProcessOutdatedChangedProperty(RakNet::BitStream& inBitstream, const RBX::Guid::Data& id, const Instance* instance, const Reflection::PropertyDescriptor* propertyDescriptor, unsigned int propId) {return false;}
virtual bool ProcessOutdatedProperties(RakNet::BitStream& inBitstream, Instance* instance, PropertyCacheType cacheType, bool useDictionary, bool preventBounceBack, std::vector<PropValuePair>* valueArray) {return false;}
virtual bool ProcessOutdatedInstance(RakNet::BitStream& inBitstream, bool isJoinData, const RBX::Guid::Data& id, const Reflection::ClassDescriptor* classDescriptor, unsigned int classId) {return false;}
virtual bool ProcessOutdatedEventInvocation(RakNet::BitStream& inBitstream, const RBX::Guid::Data& id, const Instance* instance, const Reflection::EventDescriptor* eventDescriptor, unsigned int eventId) {return false;}
virtual bool ProcessOutdatedEnumSerialization(const Reflection::Type& type, const Reflection::Variant& value, RakNet::BitStream& outBitStream) {return false;}
virtual bool ProcessOutdatedEnumDeserialization(RakNet::BitStream& inBitStream, const Reflection::Type& type, Reflection::Variant& value) {return false;}
virtual bool ProcessOutdatedPropertyEnumSerialization(const Reflection::ConstProperty& property, RakNet::BitStream& outBitStream) {return false;}
virtual bool ProcessOutdatedPropertyEnumDeserialization(Reflection::Property& property, RakNet::BitStream& inBitStream) {return false;}
static void compressBitStream(const RakNet::BitStream& inUncompressedBitStream, RakNet::BitStream& outCompressedBitStream, uint8_t compressRatio);
static void decompressBitStream(RakNet::BitStream& inCompressedBitStream, RakNet::BitStream& outUncompressedBitStream);
void enableDeserializePacketThread();
// Physics-out
boost::shared_ptr<PhysicsSender> physicsSender;
friend class PhysicsReceiver;
private:
typedef RBX::DescribedNonCreatable<Replicator, IdSerializer, sReplicator, Reflection::ClassDescriptor::INTERNAL_LOCAL> Super;
// Physics-in
shared_ptr<Stats> statsItem;
// Maintain a string dictionary for each Property type
typedef std::map<const Reflection::PropertyDescriptor*, shared_ptr<SharedStringDictionary> > PropertyStrings;
PropertyStrings strings;
typedef std::map<const Reflection::PropertyDescriptor*, shared_ptr<SharedStringProtectedDictionary> > PropertyProtectedStrings;
PropertyProtectedStrings protectedStrings;
typedef std::map<const Reflection::EventDescriptor*, shared_ptr<SharedStringDictionary> > EventStrings;
EventStrings eventStrings;
typedef std::map<const Reflection::PropertyDescriptor*, shared_ptr<SharedBinaryStringDictionary> > PropertyBinaryStrings;
PropertyBinaryStrings binaryStrings;
float rakTimeOffset;
bool remoteDeleteOnDisconnect(const Instance* instance) const;
bool removeFromPendingNewInstances(const Instance* instance);
void createStatsItems(RBX::Stats::StatsService* stats);
void updateStatsItem(RBX::Stats::StatsService* stats);
void clusterOutStep();
bool serializeValue(const Reflection::Type& type, const Reflection::Variant& value, RakNet::BitStream& outBitStream);
void serializeVariant(const Reflection::Variant& value, RakNet::BitStream& outBitStream);
void deserializeVariant(RakNet::BitStream& inBitStream, Reflection::Variant& value);
void serializeEventInvocation(const Reflection::EventInvocation& eventInvocation, RakNet::BitStream& outBitStream);
void deserializeEventInvocation(RakNet::BitStream& inBitStream, Reflection::EventInvocation& eventInvocation, bool resolveRefTypes = true);
void addToPendingItemsList(shared_ptr<Instance> instance);
rbx::signals::scoped_connection sendFilteredChatMessageConnection;
void sendFilteredChatMessage(const RakNet::SystemAddress &systemAddress, const shared_ptr<RakNet::BitStream> &data, const shared_ptr<Instance> sourceInstance, const std::string &blacklist, const std::string &whitelist);
void writeInstance(shared_ptr<Instance> instance, RakNet::BitStream* outBitstream);
void receiveData(RakNet::BitStream& bitStream);
void receiveData(RakNet::Packet *packet);
void readInstanceNew(RakNet::BitStream& bitStream, bool isJoinData);
void readInstanceNewItem(DeserializedNewInstanceItem* item, bool isJoinData);
void readInstanceDelete(RakNet::BitStream& bitStream);
void readInstanceDeleteItem(DeserializedDeleteInstanceItem* item);
void deleteInstanceById(Guid::Data id);
void readChangedProperty(RakNet::BitStream& bitStream);
void readChangedPropertyItem(DeserializedChangePropertyItem* item);
void readMarker(RakNet::BitStream& bitStream);
void readMarkerItem(DeserializedMarkerItem* item);
void processMarker(int id);
void readDataPing(RakNet::BitStream& bitStream);
void readDataPingItem(DeserializedPingItem* item);
void processDataPing(bool isPingBack, RakNet::Time timeStamp);
void readEventInvocation(RakNet::BitStream& bitStream);
void readEventInvocationItem(DeserializedEventInvocationItem* item);
void sendDataPing();
void sendStats(int version);
virtual void sendNetPmcChallenge() {}
void assignRef(Reflection::Property& property, RBX::Guid::Data id);
bool shouldStreamingHandleOnAddedForChild(shared_ptr<const Instance> child);
bool isHighPriorityInstance(const Instance* instance);
void assignParent(Instance* instance, Instance* parent);
void assignDefaultPropertyValue(Reflection::Property& property, bool preventBounceBack, Reflection::Variant* var);
void disconnectClusterReplicationData();
CEvent packetReceivedEvent;
boost::mutex receivedPacketsMutex;
bool deserializePacketsThreadEnabled;
std::list<RakNet::Packet*> receivedPackets;
std::list<RakNet::Packet*> packetsToDeserailze;
rbx::timestamped_safe_queue<DeserializedPacket> deserializedPackets;
boost::scoped_ptr<boost::thread> deserializePacketsThread;
void deserializePacketsThreadImpl();
void deserializeData(RakNet::BitStream& inBitstream, std::vector<shared_ptr<DeserializedItem> >& items);
void logPacketError(RakNet::Packet* packet, const std::string& type, const std::string& message);
};
class ReplicatorJob : public DataModelJob
{
protected:
boost::shared_ptr<Replicator> replicator;
ReplicatorJob(const char* name, Replicator& replicator, TaskType taskType);
static bool canSendPacket(shared_ptr<Replicator>& replicator, PacketPriority packetPriority);
};
} }