This commit is contained in:
2025-11-24 14:19:51 +05:30
commit f5c1412b28
6734 changed files with 1527575 additions and 0 deletions

View File

@ -0,0 +1,24 @@
#
# This file was taken from RakNet 4.082.
# Please see licenses/RakNet license.txt for the underlying license and related copyright.
#
#
# Modified work: Copyright (c) 2019, SLikeSoft UG (haftungsbeschr<68>nkt)
#
# This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
# license found in the license.txt file in the root directory of this source tree.
#
cmake_minimum_required(VERSION 2.6)
project(LibRPC3)
IF (NOT WIN32 AND UNIX)
FILE(GLOB ALL_HEADER_SRCS *.h)
FILE(GLOB ALL_CPP_SRCS *.cpp)
FINDBOOST()
include_directories("${Boost_INCLUDE_DIRS}" ${SLIKENET_HEADER_FILES})
add_library(LibRPC3 STATIC ${ALL_CPP_SRCS} ${ALL_HEADER_SRCS} "${Boost_INCLUDE_DIRS}" "${Boost_INCLUDE_DIRS}/boost")
target_link_libraries(LibRPC3 ${SLIKENET_COMMON_LIBS} ${Boost_LIBRARIES})
ENDIF(NOT WIN32 AND UNIX)

View File

@ -0,0 +1,651 @@
/*
* Original work: Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
*
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
* license found in the license.txt file in the root directory of this source tree.
*/
#include "RPC3.h"
#include "slikenet/memoryoverride.h"
#include "slikenet/assert.h"
#include "slikenet/StringCompressor.h"
#include "slikenet/BitStream.h"
#include "slikenet/peerinterface.h"
#include "slikenet/MessageIdentifiers.h"
#include "slikenet/NetworkIDManager.h"
#include <stdlib.h>
using namespace SLNet;
// int RPC3::RemoteRPCFunctionComp( const RPC3::RPCIdentifier &key, const RemoteRPCFunction &data )
// {
// return strcmp(key.C_String(), data.identifier.C_String());
// }
int SLNet::RPC3::LocalSlotObjectComp( const LocalSlotObject &key, const LocalSlotObject &data )
{
if (key.callPriority>data.callPriority)
return -1;
if (key.callPriority==data.callPriority)
{
if (key.registrationCount<data.registrationCount)
return -1;
if (key.registrationCount==data.registrationCount)
return 0;
return 1;
}
return 1;
}
RPC3::RPC3()
{
currentExecution[0]=0;
networkIdManager=0;
outgoingTimestamp=0;
outgoingPriority=HIGH_PRIORITY;
outgoingReliability=RELIABLE_ORDERED;
outgoingOrderingChannel=0;
outgoingBroadcast=true;
incomingTimeStamp=0;
nextSlotRegistrationCount=0;
}
RPC3::~RPC3()
{
Clear();
}
void RPC3::SetNetworkIDManager(NetworkIDManager *idMan)
{
networkIdManager=idMan;
}
bool RPC3::UnregisterFunction(const char *uniqueIdentifier)
{
// unused parameters
(void)uniqueIdentifier;
return false;
}
bool RPC3::IsFunctionRegistered(const char *uniqueIdentifier)
{
DataStructures::HashIndex i = GetLocalFunctionIndex(uniqueIdentifier);
return i.IsInvalid()==false;
}
void RPC3::SetTimestamp(SLNet::Time timeStamp)
{
outgoingTimestamp=timeStamp;
}
void RPC3::SetSendParams(PacketPriority priority, PacketReliability reliability, char orderingChannel)
{
outgoingPriority=priority;
outgoingReliability=reliability;
outgoingOrderingChannel=orderingChannel;
}
void RPC3::SetRecipientAddress(const SystemAddress &systemAddress, bool broadcast)
{
outgoingSystemAddress=systemAddress;
outgoingBroadcast=broadcast;
}
void RPC3::SetRecipientObject(NetworkID networkID)
{
outgoingNetworkID=networkID;
}
SLNet::Time RPC3::GetLastSenderTimestamp(void) const
{
return incomingTimeStamp;
}
SystemAddress RPC3::GetLastSenderAddress(void) const
{
return incomingSystemAddress;
}
RakPeerInterface *RPC3::GetRakPeer(void) const
{
return rakPeerInterface;
}
const char *RPC3::GetCurrentExecution(void) const
{
return (const char *) currentExecution;
}
bool RPC3::SendCallOrSignal(RakString uniqueIdentifier, char parameterCount, SLNet::BitStream *serializedParameters, bool isCall)
{
SystemAddress systemAddr;
// unsigned int outerIndex;
// unsigned int innerIndex;
if (uniqueIdentifier.IsEmpty())
return false;
SLNet::BitStream bs;
if (outgoingTimestamp!=0)
{
bs.Write((MessageID)ID_TIMESTAMP);
bs.Write(outgoingTimestamp);
}
bs.Write((MessageID)ID_RPC_PLUGIN);
bs.Write(parameterCount);
if (outgoingNetworkID!=UNASSIGNED_NETWORK_ID && isCall)
{
bs.Write(true);
bs.Write(outgoingNetworkID);
}
else
{
bs.Write(false);
}
bs.Write(isCall);
// This is so the call SetWriteOffset works
bs.AlignWriteToByteBoundary();
BitSize_t writeOffset = bs.GetWriteOffset();
if (outgoingBroadcast)
{
unsigned systemIndex;
for (systemIndex=0; systemIndex < rakPeerInterface->GetMaximumNumberOfPeers(); systemIndex++)
{
systemAddr=rakPeerInterface->GetSystemAddressFromIndex(systemIndex);
if (systemAddr!= SLNet::UNASSIGNED_SYSTEM_ADDRESS && systemAddr!=outgoingSystemAddress)
{
// if (GetRemoteFunctionIndex(systemAddr, uniqueIdentifier, &outerIndex, &innerIndex, isCall))
// {
// // Write a number to identify the function if possible, for faster lookup and less bandwidth
// bs.Write(true);
// if (isCall)
// bs.WriteCompressed(remoteFunctions[outerIndex]->operator [](innerIndex).functionIndex);
// else
// bs.WriteCompressed(remoteSlots[outerIndex]->operator [](innerIndex).functionIndex);
// }
// else
// {
// bs.Write(false);
StringCompressor::Instance()->EncodeString(uniqueIdentifier, 512, &bs, 0);
// }
bs.WriteCompressed(serializedParameters->GetNumberOfBitsUsed());
// serializedParameters->PrintBits();
bs.WriteAlignedBytes((const unsigned char*) serializedParameters->GetData(), serializedParameters->GetNumberOfBytesUsed());
SendUnified(&bs, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddr, false);
// Start writing again after ID_AUTO_RPC_CALL
bs.SetWriteOffset(writeOffset);
}
}
}
else
{
systemAddr = outgoingSystemAddress;
if (systemAddr!= SLNet::UNASSIGNED_SYSTEM_ADDRESS)
{
// if (GetRemoteFunctionIndex(systemAddr, uniqueIdentifier, &outerIndex, &innerIndex, isCall))
// {
// // Write a number to identify the function if possible, for faster lookup and less bandwidth
// bs.Write(true);
// if (isCall)
// bs.WriteCompressed(remoteFunctions[outerIndex]->operator [](innerIndex).functionIndex);
// else
// bs.WriteCompressed(remoteSlots[outerIndex]->operator [](innerIndex).functionIndex);
// }
// else
// {
// bs.Write(false);
StringCompressor::Instance()->EncodeString(uniqueIdentifier, 512, &bs, 0);
// }
bs.WriteCompressed(serializedParameters->GetNumberOfBitsUsed());
bs.WriteAlignedBytes((const unsigned char*) serializedParameters->GetData(), serializedParameters->GetNumberOfBytesUsed());
SendUnified(&bs, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddr, false);
}
else
return false;
}
return true;
}
void RPC3::OnAttach(void)
{
outgoingSystemAddress= SLNet::UNASSIGNED_SYSTEM_ADDRESS;
outgoingNetworkID=UNASSIGNED_NETWORK_ID;
incomingSystemAddress= SLNet::UNASSIGNED_SYSTEM_ADDRESS;
}
PluginReceiveResult RPC3::OnReceive(Packet *packet)
{
SLNet::Time timestamp=0;
unsigned char packetIdentifier, packetDataOffset;
if ( ( unsigned char ) packet->data[ 0 ] == ID_TIMESTAMP )
{
if ( packet->length > sizeof( unsigned char ) + sizeof(SLNet::Time ) )
{
packetIdentifier = ( unsigned char ) packet->data[ sizeof( unsigned char ) + sizeof(SLNet::Time ) ];
// Required for proper endian swapping
SLNet::BitStream tsBs(packet->data+sizeof(MessageID),packet->length-1,false);
tsBs.Read(timestamp);
packetDataOffset=sizeof( unsigned char )*2 + sizeof(SLNet::Time );
}
else
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
else
{
packetIdentifier = ( unsigned char ) packet->data[ 0 ];
packetDataOffset=sizeof( unsigned char );
}
switch (packetIdentifier)
{
case ID_RPC_PLUGIN:
incomingTimeStamp=timestamp;
incomingSystemAddress=packet->systemAddress;
OnRPC3Call(packet->systemAddress, packet->data+packetDataOffset, packet->length-packetDataOffset);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
// case ID_AUTO_RPC_REMOTE_INDEX:
// OnRPCRemoteIndex(packet->systemAddress, packet->data+packetDataOffset, packet->length-packetDataOffset);
// return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
return RR_CONTINUE_PROCESSING;
}
void RPC3::OnRPC3Call(const SystemAddress &systemAddress, unsigned char *data, unsigned int lengthInBytes)
{
SLNet::BitStream bs(data,lengthInBytes,false);
DataStructures::HashIndex functionIndex;
LocalRPCFunction *lrpcf;
char parameterCount;
NetworkIDObject *networkIdObject;
NetworkID networkId;
bool hasNetworkId=false;
// bool hasFunctionIndex=false;
// unsigned int functionIndex;
BitSize_t bitsOnStack;
char strIdentifier[512];
incomingExtraData.Reset();
bs.Read(parameterCount);
bs.Read(hasNetworkId);
if (hasNetworkId)
{
SLNET_VERIFY(bs.Read(networkId));
RakAssert(networkId!=UNASSIGNED_NETWORK_ID);
if (networkIdManager==0)
{
// Failed - Tried to call object member, however, networkIDManager system was never registered
SendError(systemAddress, RPC_ERROR_NETWORK_ID_MANAGER_UNAVAILABLE, "");
return;
}
networkIdObject = networkIdManager->GET_OBJECT_FROM_ID<NetworkIDObject*>(networkId);
if (networkIdObject==0)
{
// Failed - Tried to call object member, object does not exist (deleted?)
SendError(systemAddress, RPC_ERROR_OBJECT_DOES_NOT_EXIST, "");
return;
}
}
else
{
networkIdObject=0;
}
bool isCall;
bs.Read(isCall);
bs.AlignReadToByteBoundary();
// bs.Read(hasFunctionIndex);
// if (hasFunctionIndex)
// bs.ReadCompressed(functionIndex);
// else
StringCompressor::Instance()->DecodeString(strIdentifier,512,&bs,0);
bs.ReadCompressed(bitsOnStack);
SLNet::BitStream serializedParameters;
if (bitsOnStack>0)
{
serializedParameters.AddBitsAndReallocate(bitsOnStack);
// BITS_TO_BYTES is correct, why did I change this?
bs.ReadAlignedBytes(serializedParameters.GetData(), BITS_TO_BYTES(bitsOnStack));
serializedParameters.SetWriteOffset(bitsOnStack);
}
// if (hasFunctionIndex)
// {
// if (
// (isCall==true && functionIndex>localFunctions.Size()) ||
// (isCall==false && functionIndex>localSlots.Size())
// )
// {
// // Failed - other system specified a totally invalid index
// // Possible causes: Bugs, attempts to crash the system, requested function not registered
// SendError(systemAddress, RPC_ERROR_FUNCTION_INDEX_OUT_OF_RANGE, "");
// return;
// }
// }
// else
{
// Find the registered function with this str
if (isCall)
{
// for (functionIndex=0; functionIndex < localFunctions.Size(); functionIndex++)
// {
// bool isObjectMember = boost::fusion::get<0>(localFunctions[functionIndex].functionPointer);
// // boost::function<_RPC3::InvokeResultCodes (_RPC3::InvokeArgs)> functionPtr = boost::fusion::get<0>(localFunctions[functionIndex].functionPointer);
//
// if (isObjectMember == (networkIdObject!=0) &&
// strcmp(localFunctions[functionIndex].identifier.C_String(), strIdentifier)==0)
// {
// // SEND RPC MAPPING
// SLNet::BitStream outgoingBitstream;
// outgoingBitstream.Write((MessageID)ID_AUTO_RPC_REMOTE_INDEX);
// outgoingBitstream.Write(hasNetworkId);
// outgoingBitstream.WriteCompressed(functionIndex);
// StringCompressor::Instance()->EncodeString(strIdentifier,512,&outgoingBitstream,0);
// outgoingBitstream.Write(isCall);
// SendUnified(&outgoingBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemAddress, false);
// break;
// }
// }
functionIndex = localFunctions.GetIndexOf(strIdentifier);
if (functionIndex.IsInvalid())
{
SendError(systemAddress, RPC_ERROR_FUNCTION_NOT_REGISTERED, strIdentifier);
return;
}
lrpcf = localFunctions.ItemAtIndex(functionIndex);
bool isObjectMember = boost::fusion::get<0>(lrpcf->functionPointer);
if (isObjectMember==true && networkIdObject==0)
{
// Failed - Calling C++ function as C function
SendError(systemAddress, RPC_ERROR_CALLING_CPP_AS_C, strIdentifier);
return;
}
if (isObjectMember==false && networkIdObject!=0)
{
// Failed - Calling C function as C++ function
SendError(systemAddress, RPC_ERROR_CALLING_C_AS_CPP, strIdentifier);
return;
}
}
else
{
functionIndex = localSlots.GetIndexOf(strIdentifier);
if (functionIndex.IsInvalid())
{
SendError(systemAddress, RPC_ERROR_FUNCTION_NOT_REGISTERED, strIdentifier);
return;
}
}
}
if (isCall)
{
/*bool isObjectMember = */ boost::fusion::get<0>(lrpcf->functionPointer);
boost::function<_RPC3::InvokeResultCodes (_RPC3::InvokeArgs)> functionPtr = boost::fusion::get<1>(lrpcf->functionPointer);
// int arity = boost::fusion::get<2>(localFunctions[functionIndex].functionPointer);
// if (isObjectMember)
// arity--; // this pointer
if (functionPtr==0)
{
// Failed - Function was previously registered, but isn't registered any longer
SendError(systemAddress, RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED, strIdentifier);
return;
}
// Boost doesn't support this for class members
// if (arity!=parameterCount)
// {
// // Failed - The number of parameters that this function has was explicitly specified, and does not match up.
// SendError(systemAddress, RPC_ERROR_INCORRECT_NUMBER_OF_PARAMETERS, localFunctions[functionIndex].identifier);
// return;
// }
_RPC3::InvokeArgs functionArgs;
functionArgs.bitStream=&serializedParameters;
functionArgs.networkIDManager=networkIdManager;
functionArgs.caller=this;
functionArgs.thisPtr=networkIdObject;
// serializedParameters.PrintBits();
functionPtr(functionArgs);
}
else
{
InvokeSignal(functionIndex, &serializedParameters, false);
}
}
void RPC3::InterruptSignal(void)
{
interruptSignal=true;
}
void RPC3::InvokeSignal(DataStructures::HashIndex functionIndex, SLNet::BitStream *serializedParameters, bool temporarilySetUSA)
{
if (functionIndex.IsInvalid())
return;
SystemAddress lastIncomingAddress=incomingSystemAddress;
if (temporarilySetUSA)
incomingSystemAddress= SLNet::UNASSIGNED_SYSTEM_ADDRESS;
interruptSignal=false;
LocalSlot *localSlot = localSlots.ItemAtIndex(functionIndex);
unsigned int i;
_RPC3::InvokeArgs functionArgs;
functionArgs.bitStream=serializedParameters;
functionArgs.networkIDManager=networkIdManager;
functionArgs.caller=this;
i=0;
while (i < localSlot->slotObjects.Size())
{
if (localSlot->slotObjects[i].associatedObject!=UNASSIGNED_NETWORK_ID)
{
functionArgs.thisPtr = networkIdManager->GET_OBJECT_FROM_ID<NetworkIDObject*>(localSlot->slotObjects[i].associatedObject);
if (functionArgs.thisPtr==0)
{
localSlot->slotObjects.RemoveAtIndex(i);
continue;
}
}
else
functionArgs.thisPtr=0;
functionArgs.bitStream->ResetReadPointer();
// #med - review whether the call is actually required at all
boost::fusion::get<0>(localSlot->slotObjects[i].functionPointer);
boost::function<_RPC3::InvokeResultCodes (_RPC3::InvokeArgs)> functionPtr = boost::fusion::get<1>(localSlot->slotObjects[i].functionPointer);
if (functionPtr==0)
{
if (temporarilySetUSA==false)
{
// Failed - Function was previously registered, but isn't registered any longer
SendError(lastIncomingAddress, RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED, localSlots.KeyAtIndex(functionIndex).C_String());
}
return;
}
functionPtr(functionArgs);
// Not threadsafe
if (interruptSignal==true)
break;
i++;
}
if (temporarilySetUSA)
incomingSystemAddress=lastIncomingAddress;
}
// void RPC3::OnRPCRemoteIndex(const SystemAddress &systemAddress, unsigned char *data, unsigned int lengthInBytes)
// {
// // A remote system has given us their internal index for a particular function.
// // Store it and use it from now on, to save bandwidth and search time
// bool objectExists;
// RakString strIdentifier;
// unsigned int insertionIndex;
// unsigned int remoteIndex;
// RemoteRPCFunction newRemoteFunction;
// SLNet::BitStream bs(data,lengthInBytes,false);
// RPCIdentifier identifier;
// bool isObjectMember;
// bool isCall;
// bs.Read(isObjectMember);
// bs.ReadCompressed(remoteIndex);
// bs.Read(strIdentifier);
// bs.Read(isCall);
//
// if (strIdentifier.IsEmpty())
// return;
//
// DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, RPC3::RemoteRPCFunctionComp> *theList;
// if (
// (isCall==true && remoteFunctions.Has(systemAddress)) ||
// (isCall==false && remoteSlots.Has(systemAddress))
// )
// {
// if (isCall==true)
// theList = remoteFunctions.Get(systemAddress);
// else
// theList = remoteSlots.Get(systemAddress);
// insertionIndex=theList->GetIndexFromKey(identifier, &objectExists);
// if (objectExists==false)
// {
// newRemoteFunction.functionIndex=remoteIndex;
// newRemoteFunction.identifier = strIdentifier;
// theList->InsertAtIndex(newRemoteFunction, insertionIndex, _FILE_AND_LINE_ );
// }
// }
// else
// {
// theList = SLNet::OP_NEW<DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, RPC3::RemoteRPCFunctionComp> >(_FILE_AND_LINE_);
//
// newRemoteFunction.functionIndex=remoteIndex;
// newRemoteFunction.identifier = strIdentifier;
// theList->InsertAtEnd(newRemoteFunction, _FILE_AND_LINE_ );
//
// if (isCall==true)
// remoteFunctions.SetNew(systemAddress,theList);
// else
// remoteSlots.SetNew(systemAddress,theList);
// }
// }
void RPC3::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
{
// unused parameters
(void)systemAddress;
(void)rakNetGUID;
(void)lostConnectionReason;
// if (remoteFunctions.Has(systemAddress))
// {
// DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, RPC3::RemoteRPCFunctionComp> *theList = remoteFunctions.Get(systemAddress);
// delete theList;
// remoteFunctions.Delete(systemAddress);
// }
//
// if (remoteSlots.Has(systemAddress))
// {
// DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, RPC3::RemoteRPCFunctionComp> *theList = remoteSlots.Get(systemAddress);
// delete theList;
// remoteSlots.Delete(systemAddress);
// }
}
void RPC3::OnShutdown(void)
{
// Not needed, and if the user calls Shutdown inadvertantly, it unregisters his functions
// Clear();
}
void RPC3::Clear(void)
{
unsigned j;
// for (j=0; j < remoteFunctions.Size(); j++)
// {
// DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, RPC3::RemoteRPCFunctionComp> *theList = remoteFunctions[j];
// SLNet::OP_DELETE(theList,_FILE_AND_LINE_);
// }
// for (j=0; j < remoteSlots.Size(); j++)
// {
// DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, RPC3::RemoteRPCFunctionComp> *theList = remoteSlots[j];
// SLNet::OP_DELETE(theList,_FILE_AND_LINE_);
// }
DataStructures::List<SLNet::RakString> keyList;
DataStructures::List<LocalSlot*> outputList;
localSlots.GetAsList(outputList,keyList,_FILE_AND_LINE_);
for (j=0; j < outputList.Size(); j++)
{
SLNet::OP_DELETE(outputList[j],_FILE_AND_LINE_);
}
localSlots.Clear(_FILE_AND_LINE_);
DataStructures::List<LocalRPCFunction*> outputList2;
localFunctions.GetAsList(outputList2,keyList,_FILE_AND_LINE_);
for (j=0; j < outputList2.Size(); j++)
{
SLNet::OP_DELETE(outputList2[j],_FILE_AND_LINE_);
}
localFunctions.Clear(_FILE_AND_LINE_);
// remoteFunctions.Clear();
// remoteSlots.Clear();
outgoingExtraData.Reset();
incomingExtraData.Reset();
}
void RPC3::SendError(SystemAddress target, unsigned char errorCode, const char *functionName)
{
SLNet::BitStream bs;
bs.Write((MessageID)ID_RPC_REMOTE_ERROR);
bs.Write(errorCode);
bs.WriteAlignedBytes((const unsigned char*) functionName,(const unsigned int) strlen(functionName)+1);
SendUnified(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, target, false);
}
// bool RPC3::GetRemoteFunctionIndex(const SystemAddress &systemAddress, RPC3::RPCIdentifier identifier, unsigned int *outerIndex, unsigned int *innerIndex, bool isCall)
// {
// bool objectExists=false;
// if (isCall)
// {
// if (remoteFunctions.Has(systemAddress))
// {
// *outerIndex = remoteFunctions.GetIndexAtKey(systemAddress);
// DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, RPC3::RemoteRPCFunctionComp> *theList = remoteFunctions[*outerIndex];
// *innerIndex = theList->GetIndexFromKey(identifier, &objectExists);
// }
// }
// else
// {
// if (remoteSlots.Has(systemAddress))
// {
// *outerIndex = remoteFunctions.GetIndexAtKey(systemAddress);
// DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, RPC3::RemoteRPCFunctionComp> *theList = remoteSlots[*outerIndex];
// *innerIndex = theList->GetIndexFromKey(identifier, &objectExists);
// }
// }
// return objectExists;
// }
DataStructures::HashIndex RPC3::GetLocalSlotIndex(const char *sharedIdentifier)
{
return localSlots.GetIndexOf(sharedIdentifier);
}
DataStructures::HashIndex RPC3::GetLocalFunctionIndex(RPC3::RPCIdentifier identifier)
{
return localFunctions.GetIndexOf(identifier.C_String());
}

View File

@ -0,0 +1,880 @@
/*
* Original work: Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
*
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
* license found in the license.txt file in the root directory of this source tree.
*/
/// \file
/// \brief Automatically serializing and deserializing RPC system. Third generation of RPC.
#ifndef __RPC_3_H
#define __RPC_3_H
// Most of the internals of the boost code to make this work
#include "RPC3_Boost.h"
#include "slikenet/PluginInterface2.h"
#include "slikenet/PacketPriority.h"
#include "slikenet/types.h"
#include "slikenet/BitStream.h"
#include "slikenet/string.h"
#include "slikenet/NetworkIDObject.h"
#include "slikenet/DS_Hash.h"
#include "slikenet/DS_OrderedList.h"
/// \defgroup RPC_3_GROUP RPC3
/// \brief Remote procedure calls, powered by the 3rd party library Boost
/// \details
/// \ingroup PLUGINS_GROUP
namespace SLNet
{
class RakPeerInterface;
class NetworkIDManager;
/// \ingroup RPC_3_GROUP
#define RPC3_REGISTER_FUNCTION(RPC3Instance, _FUNCTION_PTR_ ) (RPC3Instance)->RegisterFunction((#_FUNCTION_PTR_), (_FUNCTION_PTR_))
/// \brief Error codes returned by a remote system as to why an RPC function call cannot execute
/// \details Error code follows packet ID ID_RPC_REMOTE_ERROR, that is packet->data[1]<BR>
/// Name of the function will be appended starting at packet->data[2]
/// \ingroup RPC_3_GROUP
enum RPCErrorCodes
{
/// RPC3::SetNetworkIDManager() was not called, and it must be called to call a C++ object member
RPC_ERROR_NETWORK_ID_MANAGER_UNAVAILABLE,
/// Cannot execute C++ object member call because the object specified by SetRecipientObject() does not exist on this system
RPC_ERROR_OBJECT_DOES_NOT_EXIST,
/// Internal error, index optimization for function lookup does not exist
RPC_ERROR_FUNCTION_INDEX_OUT_OF_RANGE,
/// Named function was not registered with RegisterFunction(). Check your spelling.
RPC_ERROR_FUNCTION_NOT_REGISTERED,
/// Named function was registered, but later unregistered with UnregisterFunction() and can no longer be called.
RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED,
/// SetRecipientObject() was not called before Call(), but the registered pointer is a class member
/// If you intended to call a class member function, call SetRecipientObject() with a valid object first.
RPC_ERROR_CALLING_CPP_AS_C,
/// SetRecipientObject() was called before Call(), but RegisterFunction() was called with isObjectMember=false
/// If you intended to call a C function, call SetRecipientObject(UNASSIGNED_NETWORK_ID) first.
RPC_ERROR_CALLING_C_AS_CPP,
};
/// \brief The RPC3 plugin allows you to call remote functions as if they were local functions, using the standard function call syntax
/// \details No serialization or deserialization is needed.<BR>
/// As of this writing, the system is not threadsafe.<BR>
/// Features:<BR>
/// <LI>Pointers to classes that derive from NetworkID are automatically looked up using NetworkIDManager
/// <LI>Types are written to BitStream, meaning built-in serialization operations are performed, including endian swapping
/// <LI>Types can customize autoserialization by providing an implementation of operator << and operator >> to and from BitStream
/// \note You cannot use RPC4 at the same time as RPC3
/// \ingroup RPC_3_GROUP
class RPC3 : public PluginInterface2
{
public:
// Constructor
RPC3();
// Destructor
virtual ~RPC3();
/// Sets the network ID manager to use for object lookup
/// Required to call C++ object member functions via SetRecipientObject()
/// \param[in] idMan Pointer to the network ID manager to use
void SetNetworkIDManager(NetworkIDManager *idMan);
/// Register a function pointer as callable using RPC()
/// \param[in] uniqueIdentifier String identifying the function. Recommended that this is the name of the function
/// \param[in] functionPtr Pointer to the function. For C, just pass the name of the function. For C++, use ARPC_REGISTER_CPP_FUNCTION
/// \return True on success, false on uniqueIdentifier already used
template<typename Function>
bool RegisterFunction(const char *uniqueIdentifier, Function functionPtr)
{
if (IsFunctionRegistered(uniqueIdentifier)) return false;
_RPC3::FunctionPointer fp;
fp= _RPC3::GetBoundPointer(functionPtr);
localFunctions.Push(uniqueIdentifier, SLNet::OP_NEW_1<LocalRPCFunction>( _FILE_AND_LINE_, fp ),_FILE_AND_LINE_);
return true;
}
/// \internal
// Callable object, along with priority to call relative to other objects
struct LocalSlotObject
{
LocalSlotObject() {}
LocalSlotObject(NetworkID _associatedObject,unsigned int _registrationCount,int _callPriority,_RPC3::FunctionPointer _functionPointer)
{associatedObject=_associatedObject;registrationCount=_registrationCount;callPriority=_callPriority;functionPointer=_functionPointer;}
~LocalSlotObject() {}
// Used so slots are called in the order they are registered
NetworkID associatedObject;
unsigned int registrationCount;
int callPriority;
_RPC3::FunctionPointer functionPointer;
};
/// \internal
/// Identifies an RPC function, by string identifier and if it is a C or C++ function
typedef RakString RPCIdentifier;
static int LocalSlotObjectComp( const LocalSlotObject &key, const LocalSlotObject &data );
/// \internal
struct LocalSlot
{
// RPCIdentifier identifier;
DataStructures::OrderedList<LocalSlotObject,LocalSlotObject,LocalSlotObjectComp> slotObjects;
};
/// Register a slot, which is a function pointer to one or more instances of a class that supports this function signature
/// When a signal occurs, all slots with the same identifier are called.
/// \param[in] sharedIdentifier A string to identify the slot. Recommended to be the same as the name of the function.
/// \param[in] functionPtr Pointer to the function. For C, just pass the name of the function. For C++, use ARPC_REGISTER_CPP_FUNCTION
/// \param[in] objectInstance If 0, then this slot is just a regular C function. Otherwise, this is a member of the given class instance.
/// \param[in] callPriority Slots are called by order of the highest callPriority first. For slots with the same priority, they are called in the order they are registered
template<typename Function>
void RegisterSlot(const char *sharedIdentifier, Function functionPtr, NetworkID objectInstanceId, int callPriority)
{
_RPC3::FunctionPointer fp;
fp= _RPC3::GetBoundPointer(functionPtr);
LocalSlotObject lso(objectInstanceId, nextSlotRegistrationCount++, callPriority, _RPC3::GetBoundPointer(functionPtr));
DataStructures::HashIndex idx = GetLocalSlotIndex(sharedIdentifier);
LocalSlot *localSlot;
if (idx.IsInvalid())
{
localSlot = SLNet::OP_NEW<LocalSlot>(_FILE_AND_LINE_);
localSlots.Push(sharedIdentifier, localSlot,_FILE_AND_LINE_);
}
else
{
localSlot=localSlots.ItemAtIndex(idx);
}
localSlot->slotObjects.Insert(lso,lso,true,_FILE_AND_LINE_);
}
/// Unregisters a function pointer to be callable given an identifier for the pointer
/// \param[in] uniqueIdentifier String identifying the function.
/// \return True on success, false on function was not previously or is not currently registered.
bool UnregisterFunction(const char *uniqueIdentifier);
/// Returns if a function identifier was previously registered on this system with RegisterFunction(), and not unregistered with UnregisterFunction()
/// \param[in] uniqueIdentifier String identifying the function.
/// \return True if the function was registered, false otherwise
bool IsFunctionRegistered(const char *uniqueIdentifier);
/// Send or stop sending a timestamp with all following calls to Call()
/// Use GetLastSenderTimestamp() to read the timestamp.
/// \param[in] timeStamp Non-zero to pass this timestamp using the ID_TIMESTAMP system. 0 to clear passing a timestamp.
void SetTimestamp(SLNet::Time timeStamp);
/// Set parameters to pass to RakPeer::Send() for all following calls to Call()
/// Deafults to HIGH_PRIORITY, RELIABLE_ORDERED, ordering channel 0
/// \param[in] priority See RakPeer::Send()
/// \param[in] reliability See RakPeer::Send()
/// \param[in] orderingChannel See RakPeer::Send()
void SetSendParams(PacketPriority priority, PacketReliability reliability, char orderingChannel);
/// Set system to send to for all following calls to Call()
/// Defaults to SLNet::UNASSIGNED_SYSTEM_ADDRESS, broadcast=true
/// \param[in] systemAddress See RakPeer::Send()
/// \param[in] broadcast See RakPeer::Send()
void SetRecipientAddress(const SystemAddress &systemAddress, bool broadcast);
/// Set the NetworkID to pass for all following calls to Call()
/// Defaults to UNASSIGNED_NETWORK_ID (none)
/// If set, the remote function will be considered a C++ function, e.g. an object member function
/// If set to UNASSIGNED_NETWORK_ID (none), the remote function will be considered a C function
/// If this is set incorrectly, you will get back either RPC_ERROR_CALLING_C_AS_CPP or RPC_ERROR_CALLING_CPP_AS_C
/// \sa NetworkIDManager
/// \param[in] networkID Returned from NetworkIDObject::GetNetworkID()
void SetRecipientObject(NetworkID networkID);
/// If the last received function call has a timestamp included, it is stored and can be retrieved with this function.
/// \return 0 if the last call did not have a timestamp, else non-zero
SLNet::Time GetLastSenderTimestamp(void) const;
/// Returns the system address of the last system to send us a received function call
/// Equivalent to the old system RPCParameters::sender
/// \return Last system to send an RPC call using this system
SystemAddress GetLastSenderAddress(void) const;
/// If called while processing a slot, no further slots for the currently executing signal will be executed
void InterruptSignal(void);
/// Returns the instance of RakPeer this plugin was attached to
RakPeerInterface *GetRakPeer(void) const;
/// Returns the currently running RPC call identifier, set from RegisterFunction::uniqueIdentifier
/// Returns an empty string "" if none
/// \return which RPC call is currently running
const char *GetCurrentExecution(void) const;
/// Calls a remote function, using as send parameters whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// If you call a C++ class member function, don't forget to first call SetRecipientObject(). You can use CallExplicit() instead of Call() to force yourself not to forget.
///
/// Parameters passed to Call are processed as follows:
/// 1. If the parameter is not a pointer
/// 2. - And you overloaded SLNet::BitStream& operator<<(SLNet::BitStream& out, MyClass& in) then that will be used to do the serialization
/// 3. - Otherwise, it will use bitStream.Write(myClass); BitStream already defines specializations for NetworkIDObject, SystemAddress, other BitStreams
/// 4. If the parameter is a pointer
/// 5. - And the pointer can be converted to NetworkIDObject, then it will write bitStream.Write(myClass->GetNetworkID()); To make it also dereference the pointer, use SLNet::_RPC3::Deref(myClass)
/// 6. - And the pointer can not be converted to NetworkID, but it is a pointer to SLNet::RPC3, then it is skipped
/// 7. Otherwise, the pointer is dereferenced and written as in step 2 and 3.
///
/// \note If you need endian swapping (Mac talking to PC for example), you pretty much need to define operator << and operator >> for all classes you want to serialize. Otherwise the member variables will not be endian swapped.
/// \note If the call fails on the remote system, you will get back ID_RPC_REMOTE_ERROR. packet->data[1] will contain one of the values of RPCErrorCodes. packet->data[2] and on will contain the name of the function.
///
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
bool Call(const char *uniqueIdentifier){
SLNet::BitStream bitStream;
return SendCallOrSignal(uniqueIdentifier, 0, &bitStream, true);
}
template <class P1>
bool Call(const char *uniqueIdentifier, P1 &p1) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
return SendCallOrSignal(uniqueIdentifier, 1, &bitStream, true);
}
template <class P1, class P2>
bool Call(const char *uniqueIdentifier, P1 &p1, P2 &p2) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
return SendCallOrSignal(uniqueIdentifier, 2, &bitStream, true);
}
template <class P1, class P2, class P3>
bool Call(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
return SendCallOrSignal(uniqueIdentifier, 3, &bitStream, true);
}
template <class P1, class P2, class P3, class P4>
bool Call(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
return SendCallOrSignal(uniqueIdentifier, 4, &bitStream, true);
}
template <class P1, class P2, class P3, class P4, class P5>
bool Call(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
return SendCallOrSignal(uniqueIdentifier, 5, &bitStream, true);
}
template <class P1, class P2, class P3, class P4, class P5, class P6>
bool Call(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
return SendCallOrSignal(uniqueIdentifier, 6, &bitStream, true);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
bool Call(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
_RPC3::SerializeCallParameterBranch<P7>::type::apply(bitStream, p7);
return SendCallOrSignal(uniqueIdentifier, 7, &bitStream, true);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
bool Call(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
_RPC3::SerializeCallParameterBranch<P7>::type::apply(bitStream, p7);
_RPC3::SerializeCallParameterBranch<P8>::type::apply(bitStream, p8);
return SendCallOrSignal(uniqueIdentifier, 8, &bitStream, true);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
bool Call(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
_RPC3::SerializeCallParameterBranch<P7>::type::apply(bitStream, p7);
_RPC3::SerializeCallParameterBranch<P8>::type::apply(bitStream, p8);
_RPC3::SerializeCallParameterBranch<P9>::type::apply(bitStream, p9);
// bitStream.PrintBits();
return SendCallOrSignal(uniqueIdentifier, 9, &bitStream, true);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>
bool Call(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9, P10 &p10) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
_RPC3::SerializeCallParameterBranch<P7>::type::apply(bitStream, p7);
_RPC3::SerializeCallParameterBranch<P8>::type::apply(bitStream, p8);
_RPC3::SerializeCallParameterBranch<P9>::type::apply(bitStream, p9);
_RPC3::SerializeCallParameterBranch<P10>::type::apply(bitStream, p10);
// bitStream.PrintBits();
return SendCallOrSignal(uniqueIdentifier, 10, &bitStream, true);
}
struct CallExplicitParameters
{
CallExplicitParameters(
NetworkID _networkID=UNASSIGNED_NETWORK_ID, SystemAddress _systemAddress= SLNet::UNASSIGNED_SYSTEM_ADDRESS,
bool _broadcast=true, SLNet::Time _timeStamp=0, PacketPriority _priority=HIGH_PRIORITY,
PacketReliability _reliability=RELIABLE_ORDERED, char _orderingChannel=0
) : networkID(_networkID), systemAddress(_systemAddress), broadcast(_broadcast), timeStamp(_timeStamp), priority(_priority), reliability(_reliability), orderingChannel(_orderingChannel)
{}
NetworkID networkID;
SystemAddress systemAddress;
bool broadcast;
SLNet::Time timeStamp;
PacketPriority priority;
PacketReliability reliability;
char orderingChannel;
};
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are serialized using operator << with SLNet::BitStream. If you provide an overload it will be used, otherwise the seriailzation is equivalent to memcpy except for native RakNet types (NetworkIDObject, SystemAddress, etc.)
/// If the type is a pointer to a type deriving from NetworkIDObject, then only the NetworkID is sent, and the object looked up on the remote system. Otherwise, the pointer is dereferenced and the contents serialized as usual.
/// \note The this pointer, for this instance of RPC3, is pushed as the last parameter on the stack. See RPC3Sample.cpp for an example of this
/// \note If the call fails on the remote system, you will get back ID_RPC_REMOTE_ERROR. packet->data[1] will contain one of the values of RPCErrorCodes. packet->data[2] and on will contain the name of the function.
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters){
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier);
}
template <class P1 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1);
}
template <class P1, class P2 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1, P2 &p2
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1, p2);
}
template <class P1, class P2, class P3 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1, P2 &p2, P3 &p3
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1, p2, p3);
}
template <class P1, class P2, class P3, class P4 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1, p2, p3, p4);
}
template <class P1, class P2, class P3, class P4, class P5 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1, p2, p3, p4, p5);
}
template <class P1, class P2, class P3, class P4, class P5, class P6 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1, p2, p3, p4, p5, p6);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1, p2, p3, p4, p5, p6, p7);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1, p2, p3, p4, p5, p6, p7, p8);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1, p2, p3, p4, p5, p6, p7, p8, p9);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10 >
bool CallExplicit(const char *uniqueIdentifier, const CallExplicitParameters * const callExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9, P10 &p10
) {
SetTimestamp(callExplicitParameters->timeStamp);
SetSendParams(callExplicitParameters->priority, callExplicitParameters->reliability, callExplicitParameters->orderingChannel);
SetRecipientAddress(callExplicitParameters->systemAddress, callExplicitParameters->broadcast);
SetRecipientObject(callExplicitParameters->networkID);
return Call(uniqueIdentifier, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
}
bool CallC(const char *uniqueIdentifier) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier);}
template <class P1>
bool CallC(const char *uniqueIdentifier, P1 &p1) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1);}
template <class P1, class P2>
bool CallC(const char *uniqueIdentifier, P1 &p1, P2 &p2) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1,p2);}
template <class P1, class P2, class P3>
bool CallC(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1,p2,p3);}
template <class P1, class P2, class P3, class P4>
bool CallC(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1,p2,p3,p4);}
template <class P1, class P2, class P3, class P4, class P5>
bool CallC(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1,p2,p3,p4,p5);}
template <class P1, class P2, class P3, class P4, class P5, class P6>
bool CallC(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6);}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
bool CallC(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6,p7);}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
bool CallC(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6,p7,p8);}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
bool CallC(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6,p7,p8,p9);}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>
bool CallC(const char *uniqueIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9, P10 &p10) {SetRecipientObject(UNASSIGNED_NETWORK_ID); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10);}
bool CallCPP(const char *uniqueIdentifier, NetworkID nid) { SetRecipientObject(nid); return Call(uniqueIdentifier); }
template <class P1>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1); }
template <class P1, class P2>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1, P2 &p2) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1,p2); }
template <class P1, class P2, class P3>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1, P2 &p2, P3 &p3) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1,p2,p3); }
template <class P1, class P2, class P3, class P4>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1, P2 &p2, P3 &p3, P4 &p4) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1,p2,p3,p4); }
template <class P1, class P2, class P3, class P4, class P5>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1,p2,p3,p4,p5); }
template <class P1, class P2, class P3, class P4, class P5, class P6>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6); }
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6,p7); }
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6,p7,p8); }
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6,p7,p8,p9); }
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>
bool CallCPP(const char *uniqueIdentifier, NetworkID nid, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9, P10 &p10) { SetRecipientObject(nid); return Call(uniqueIdentifier,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10); }
// ---------------------------- Signals and slots ----------------------------------
/// Calls zero or more functions identified by sharedIdentifier.
/// Uses as send parameters whatever was last passed to SetTimestamp(), SetSendParams(), and SetRecipientAddress()
/// You can use CallExplicit() instead of Call() to force yourself not to forget to set parameters
///
/// See the Call() function for a description of parameters
///
/// \param[in] sharedIdentifier parameter of the same name passed to RegisterSlot() on the remote system
bool Signal(const char *sharedIdentifier){
SLNet::BitStream bitStream;
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 0, &bitStream, false);
}
template <class P1>
bool Signal(const char *sharedIdentifier, P1 &p1) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 1, &bitStream, false);
}
template <class P1, class P2>
bool Signal(const char *sharedIdentifier, P1 &p1, P2 &p2) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 2, &bitStream, false);
}
template <class P1, class P2, class P3>
bool Signal(const char *sharedIdentifier, P1 &p1, P2 &p2, P3 &p3) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 3, &bitStream, false);
}
template <class P1, class P2, class P3, class P4>
bool Signal(const char *sharedIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 4, &bitStream, false);
}
template <class P1, class P2, class P3, class P4, class P5>
bool Signal(const char *sharedIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 5, &bitStream, false);
}
template <class P1, class P2, class P3, class P4, class P5, class P6>
bool Signal(const char *sharedIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 6, &bitStream, false);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
bool Signal(const char *sharedIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
_RPC3::SerializeCallParameterBranch<P7>::type::apply(bitStream, p7);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 7, &bitStream, false);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
bool Signal(const char *sharedIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
_RPC3::SerializeCallParameterBranch<P7>::type::apply(bitStream, p7);
_RPC3::SerializeCallParameterBranch<P8>::type::apply(bitStream, p8);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 8, &bitStream, false);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
bool Signal(const char *sharedIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
_RPC3::SerializeCallParameterBranch<P7>::type::apply(bitStream, p7);
_RPC3::SerializeCallParameterBranch<P8>::type::apply(bitStream, p8);
_RPC3::SerializeCallParameterBranch<P9>::type::apply(bitStream, p9);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 9, &bitStream, false);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>
bool Signal(const char *sharedIdentifier, P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9, P10 &p10) {
SLNet::BitStream bitStream;
_RPC3::SerializeCallParameterBranch<P1>::type::apply(bitStream, p1);
_RPC3::SerializeCallParameterBranch<P2>::type::apply(bitStream, p2);
_RPC3::SerializeCallParameterBranch<P3>::type::apply(bitStream, p3);
_RPC3::SerializeCallParameterBranch<P4>::type::apply(bitStream, p4);
_RPC3::SerializeCallParameterBranch<P5>::type::apply(bitStream, p5);
_RPC3::SerializeCallParameterBranch<P6>::type::apply(bitStream, p6);
_RPC3::SerializeCallParameterBranch<P7>::type::apply(bitStream, p7);
_RPC3::SerializeCallParameterBranch<P8>::type::apply(bitStream, p8);
_RPC3::SerializeCallParameterBranch<P9>::type::apply(bitStream, p9);
_RPC3::SerializeCallParameterBranch<P10>::type::apply(bitStream, p10);
InvokeSignal(GetLocalSlotIndex(sharedIdentifier), &bitStream, true);
return SendCallOrSignal(sharedIdentifier, 10, &bitStream, false);
}
struct SignalExplicitParameters
{
SignalExplicitParameters(
SystemAddress _systemAddress= SLNet::UNASSIGNED_SYSTEM_ADDRESS,
bool _broadcast=true, SLNet::Time _timeStamp=0, PacketPriority _priority=HIGH_PRIORITY,
PacketReliability _reliability=RELIABLE_ORDERED, char _orderingChannel=0
) : systemAddress(_systemAddress), broadcast(_broadcast), timeStamp(_timeStamp), priority(_priority), reliability(_reliability), orderingChannel(_orderingChannel)
{}
SystemAddress systemAddress;
bool broadcast;
SLNet::Time timeStamp;
PacketPriority priority;
PacketReliability reliability;
char orderingChannel;
};
/// Same as Signal(), but you are forced to specify the remote system parameters
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters){
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier);
}
template <class P1 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1);
}
template <class P1, class P2 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1, P2 &p2
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1, p2);
}
template <class P1, class P2, class P3 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1, P2 &p2, P3 &p3
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1, p2, p3);
}
template <class P1, class P2, class P3, class P4 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1, p2, p3, p4);
}
template <class P1, class P2, class P3, class P4, class P5 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1, p2, p3, p4, p5);
}
template <class P1, class P2, class P3, class P4, class P5, class P6 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1, p2, p3, p4, p5, p6);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1, p2, p3, p4, p5, p6, p7);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1, p2, p3, p4, p5, p6, p7, p8);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1, p2, p3, p4, p5, p6, p7, p8, p9);
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10 >
bool SignalExplicit(const char *sharedIdentifier, const SignalExplicitParameters * const signalExplicitParameters,
P1 &p1, P2 &p2, P3 &p3, P4 &p4, P5 &p5, P6 &p6, P7 &p7, P8 &p8, P9 &p9, P10 &p10
) {
SetTimestamp(signalExplicitParameters->timeStamp);
SetSendParams(signalExplicitParameters->priority, signalExplicitParameters->reliability, signalExplicitParameters->orderingChannel);
SetRecipientAddress(signalExplicitParameters->systemAddress, signalExplicitParameters->broadcast);
return Signal(sharedIdentifier, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
}
// ---------------------------- ALL INTERNAL AFTER HERE ----------------------------
/// \internal
/// The RPC identifier, and a pointer to the function
struct LocalRPCFunction
{
LocalRPCFunction() {}
LocalRPCFunction(_RPC3::FunctionPointer _functionPointer) {functionPointer=_functionPointer;};
// LocalRPCFunction(RPCIdentifier _identifier, _RPC3::FunctionPointer _functionPointer) {identifier=_identifier; functionPointer=_functionPointer;};
// RPCIdentifier identifier;
_RPC3::FunctionPointer functionPointer;
};
/// \internal
/// The RPC identifier, and the index of the function on a remote system
// struct RemoteRPCFunction
// {
// RPCIdentifier identifier;
// unsigned int functionIndex;
// };
//
// /// \internal
// static int RemoteRPCFunctionComp( const RPCIdentifier &key, const RemoteRPCFunction &data );
/// \internal
/// Sends the RPC call, with a given serialized function
bool SendCallOrSignal(RakString uniqueIdentifier, char parameterCount, SLNet::BitStream *serializedParameters, bool isCall);
/// Call a given signal with a bitstream representing the parameter list
void InvokeSignal(DataStructures::HashIndex functionIndex, SLNet::BitStream *serializedParameters, bool temporarilySetUSA);
protected:
// --------------------------------------------------------------------------------------------
// Packet handling functions
// --------------------------------------------------------------------------------------------
void OnAttach(void);
virtual PluginReceiveResult OnReceive(Packet *packet);
virtual void OnRPC3Call(const SystemAddress &systemAddress, unsigned char *data, unsigned int lengthInBytes);
// virtual void OnRPCRemoteIndex(const SystemAddress &systemAddress, unsigned char *data, unsigned int lengthInBytes);
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
virtual void OnShutdown(void);
void Clear(void);
void SendError(SystemAddress target, unsigned char errorCode, const char *functionName);
DataStructures::HashIndex GetLocalFunctionIndex(RPCIdentifier identifier);
DataStructures::HashIndex GetLocalSlotIndex(const char *sharedIdentifier);
// bool GetRemoteFunctionIndex(const SystemAddress &systemAddress, RPCIdentifier identifier, unsigned int *outerIndex, unsigned int *innerIndex, bool isCall);
DataStructures::Hash<SLNet::RakString, LocalSlot*,256, SLNet::RakString::ToInteger> localSlots;
DataStructures::Hash<SLNet::RakString, LocalRPCFunction*,256, SLNet::RakString::ToInteger> localFunctions;
// DataStructures::List<LocalSlot*> localSlots;
// DataStructures::List<LocalRPCFunction> localFunctions;
// DataStructures::Map<SystemAddress, DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, RPC3::RemoteRPCFunctionComp> *> remoteFunctions, remoteSlots;
SLNet::Time outgoingTimestamp;
PacketPriority outgoingPriority;
PacketReliability outgoingReliability;
char outgoingOrderingChannel;
SystemAddress outgoingSystemAddress;
bool outgoingBroadcast;
NetworkID outgoingNetworkID;
SLNet::BitStream outgoingExtraData;
SLNet::Time incomingTimeStamp;
SystemAddress incomingSystemAddress;
SLNet::BitStream incomingExtraData;
NetworkIDManager *networkIdManager;
char currentExecution[512];
/// Used so slots are called in the order they are registered
unsigned int nextSlotRegistrationCount;
bool interruptSignal;
};
} // End namespace
#endif

View File

@ -0,0 +1,712 @@
/*
* Original work: Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*
* Modified work: Copyright (c) 2017-2020, SLikeSoft UG (haftungsbeschränkt)
*
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
* license found in the license.txt file in the root directory of this source tree.
*/
#ifndef __RPC3_BOOST_H
#define __RPC3_BOOST_H
// Fixes
// error C2504: 'boost::fusion::detail::invoke_impl<Function,Sequence,N,CBI,RandomAccess>' : base class undefined
// This defines the maximum number of parameters you can have
#ifndef BOOST_FUSION_INVOKE_MAX_ARITY
#define BOOST_FUSION_INVOKE_MAX_ARITY 10
#endif
// Boost dependencies
// Boost is assumed to be at C:\boost_1_43_0 based on the project settings
// If this is not where you downloaded boost, change the project settings Configuration Properties / C/C++ / General / Additional Include Directories
// If you don't have boost, get it from http://www.boost.org/users/download/
// If you don't want to use boost, use RPC4 instead which relies on assembly but has fewer features
#include "boost/type_traits.hpp"
#include "boost/function.hpp"
#include "boost/bind.hpp"
#include "boost/mpl/if.hpp"
#include "boost/mpl/apply.hpp"
#include "boost/function_types/parameter_types.hpp"
#include "boost/fusion/container/list/cons.hpp" // boost::fusion::nil
#include "boost/fusion/include/push_back.hpp"
#include "boost/fusion/include/invoke.hpp"
#include "boost/fusion/tuple/tuple.hpp"
#include "boost/fusion/tuple/make_tuple.hpp"
#include "boost/fusion/functional/invocation/invoke.hpp"
#include "boost/type_traits/is_array.hpp"
// Not needed?
//#include <boost/fusion/container/generation/make_vector.hpp>
#include "slikenet/NetworkIDManager.h"
#include "slikenet/NetworkIDObject.h"
#include "slikenet/BitStream.h"
namespace SLNet
{
class RPC3;
class BitStream;
namespace _RPC3
{
enum InvokeResultCodes
{
IRC_SUCCESS,
IRC_NEED_BITSTREAM,
IRC_NEED_NETWORK_ID_MANAGER,
IRC_NEED_NETWORK_ID,
IRC_NEED_CLASS_OBJECT,
};
struct InvokeArgs
{
// Bitstream to use to deserialize
SLNet::BitStream *bitStream;
// NetworkIDManager to use to lookup objects
NetworkIDManager *networkIDManager;
// C++ class member object
NetworkID classMemberObjectId;
// The calling plugin
RPC3 *caller;
// The this pointer for C++
NetworkIDObject *thisPtr;
};
typedef boost::fusion::tuple<bool, boost::function<InvokeResultCodes (InvokeArgs)> > FunctionPointer;
struct StrWithDestructor
{
char *c;
~StrWithDestructor() {if (c) delete c;}
};
enum RPC3TagFlag
{
RPC3_TAG_FLAG_DEREF=1,
RPC3_TAG_FLAG_ARRAY=2,
};
struct RPC3Tag
{
RPC3Tag() {}
RPC3Tag(void *_v, unsigned int _count, RPC3TagFlag _flag) : v(_v), count(_count), flag((unsigned char)_flag) {}
void* v;
unsigned int count;
unsigned char flag;
};
// Track the pointers tagged with SLNet::_RPC3::Deref
static RPC3Tag __RPC3TagPtrs[BOOST_FUSION_INVOKE_MAX_ARITY+1];
static int __RPC3TagHead=0;
static int __RPC3TagTail=0;
// If this assert hits, then SLNet::_RPC3::Deref was called more times than the argument was passed to the function
static void __RPC3_Tag_AddHead(const RPC3Tag &p)
{
// Update tag if already in array
int i;
for (i=__RPC3TagTail; i!=__RPC3TagHead; i=(i+1)%BOOST_FUSION_INVOKE_MAX_ARITY)
{
if (__RPC3TagPtrs[i].v==p.v)
{
if (p.flag==RPC3_TAG_FLAG_ARRAY)
{
__RPC3TagPtrs[i].count=p.count;
}
__RPC3TagPtrs[i].flag|=p.flag;
return;
}
}
__RPC3TagPtrs[__RPC3TagHead]=p;
__RPC3TagHead = (__RPC3TagHead + 1) % BOOST_FUSION_INVOKE_MAX_ARITY;
assert(__RPC3TagHead!=__RPC3TagTail);
}
static void __RPC3ClearTail(void) {
while (__RPC3TagTail!=__RPC3TagHead)
{
if (__RPC3TagPtrs[__RPC3TagTail].v==0)
__RPC3TagTail = (__RPC3TagTail+1) % BOOST_FUSION_INVOKE_MAX_ARITY;
else
return;
}
}
static bool __RPC3ClearPtr(void* p, RPC3Tag *tag) {
int i;
for (i=__RPC3TagTail; i!=__RPC3TagHead; i=(i+1)%BOOST_FUSION_INVOKE_MAX_ARITY)
{
if (__RPC3TagPtrs[i].v==p)
{
*tag=__RPC3TagPtrs[i];
__RPC3TagPtrs[i].v=0;
__RPC3ClearTail();
return true;
}
}
tag->flag=0;
tag->count=1;
return false;
}
template <class templateType>
inline const templateType& Deref(const templateType & t) {
__RPC3_Tag_AddHead(RPC3Tag((void*)t,1,RPC3_TAG_FLAG_DEREF));
return t;
}
template <class templateType>
inline const templateType& PtrToArray(unsigned int count, const templateType & t) {
__RPC3_Tag_AddHead(RPC3Tag((void*)t,count,RPC3_TAG_FLAG_ARRAY));
return t;
}
struct ReadBitstream
{
static void applyArray(SLNet::BitStream &bitStream, SLNet::BitStream* t){apply(bitStream,t);}
static void apply(SLNet::BitStream &bitStream, SLNet::BitStream* t)
{
BitSize_t numBitsUsed;
bitStream.ReadCompressed(numBitsUsed);
bitStream.Read(t,numBitsUsed);
}
};
//template <typename T>
struct ReadPtr
{
template <typename T2>
static inline void applyArray(SLNet::BitStream &bitStream, T2 *t) {bitStream >> (*t);}
template <typename T2>
static inline void apply(SLNet::BitStream &bitStream, T2 *t) {bitStream >> (*t);}
static inline void apply(SLNet::BitStream &bitStream, char *&t) {applyStr(bitStream, (char *&) t);}
static inline void apply(SLNet::BitStream &bitStream, unsigned char *&t) {applyStr(bitStream, (char *&) t);}
static inline void apply(SLNet::BitStream &bitStream, const char *&t) {applyStr(bitStream, (char *&) t);}
static inline void apply(SLNet::BitStream &bitStream, const unsigned char *&t) {applyStr(bitStream, (char *&) t);}
static inline void applyStr(SLNet::BitStream &bitStream, char *&t)
{
SLNet::RakString rs;
bitStream >> rs;
size_t len = rs.GetLength()+1;
// The caller should have already allocated memory, so we need to free
// it and allocate a new buffer.
RakAssert("Expected allocated array, got a null pointer" && (nullptr != t));
delete [] t;
t = new char [len];
memcpy(t,rs.C_String(),len);
}
};
template< typename T >
struct DoRead
{
typedef typename boost::mpl::if_<
boost::is_convertible<T*, SLNet::BitStream*>,
ReadBitstream,
ReadPtr >::type type;
};
template< typename T >
struct ReadWithoutNetworkIDNoPtr
{
static InvokeResultCodes apply(InvokeArgs &args, T &t)
{
// printf("ReadWithoutNetworkIDNoPtr\n");
DoRead< typename boost::remove_pointer<T>::type >::type::apply(* (args.bitStream),&t);
return IRC_SUCCESS;
}
// typedef boost::mpl::false_ Cleanup;
template< typename T2 >
static void Cleanup(T2 &t)
{
// unused parameters
(void)t;
}
};
template< typename T >
struct ReadWithNetworkIDPtr
{
static InvokeResultCodes apply(InvokeArgs &args, T &t)
{
// printf("ReadWithNetworkIDPtr\n");
// Read the network ID
bool isNull;
args.bitStream->Read(isNull);
if (isNull)
{
t=0;
return IRC_SUCCESS;
}
bool deref, isArray;
args.bitStream->Read(deref);
args.bitStream->Read(isArray);
unsigned int count;
if (isArray)
args.bitStream->ReadCompressed(count);
else
count=1;
NetworkID networkId;
for (unsigned int i=0; i < count; i++)
{
args.bitStream->Read(networkId);
t = args.networkIDManager->GET_OBJECT_FROM_ID< T >(networkId);
if (deref)
{
BitSize_t bitsUsed;
args.bitStream->AlignReadToByteBoundary();
args.bitStream->Read(bitsUsed);
if (t)
{
DoRead< typename boost::remove_pointer<T>::type >::type::apply(* (args.bitStream),t);
}
else
{
// Skip data!
args.bitStream->IgnoreBits(bitsUsed);
}
}
}
return IRC_SUCCESS;
}
template< typename T2 >
static void Cleanup(T2 &t)
{
// unused parameters
(void)t;
}
};
template< typename T >
struct ReadWithoutNetworkIDPtr
{
template <typename T2>
static InvokeResultCodes apply(InvokeArgs &args, T2 &t)
{
// printf("ReadWithoutNetworkIDPtr\n");
bool isNull=false;
args.bitStream->Read(isNull);
if (isNull)
{
t=0;
return IRC_SUCCESS;
}
typedef typename boost::remove_pointer< T >::type ActualObjectType;
bool isArray=false;
unsigned int count;
args.bitStream->Read(isArray);
if (isArray)
args.bitStream->ReadCompressed(count);
else
count=1;
t = new ActualObjectType[count]();
if (isArray)
{
for (unsigned int i=0; i < count; i++)
{
DoRead< typename boost::remove_pointer<T>::type >::type::applyArray(* (args.bitStream),t+i);
}
}
else
{
DoRead< typename boost::remove_pointer<T>::type >::type::apply(* (args.bitStream),t);
}
return IRC_SUCCESS;
}
template< typename T2 >
static void Cleanup(T2 &t)
{
if (t)
delete [] t;
}
};
template< typename T >
struct SetRPC3Ptr
{
static InvokeResultCodes apply(InvokeArgs &args, T &obj)
{
obj=args.caller;
return IRC_SUCCESS;
}
//typedef boost::mpl::false_ Cleanup;
template< typename T2 >
static void Cleanup(T2 &t)
{
// unused parameters
(void)t;
}
};
/*
template< typename T >
struct ReadWithNetworkID
{
typedef typename boost::mpl::if_<
boost::is_pointer<T>
, typename ReadWithNetworkIDPtr<T> // true
, typename ReadWithNetworkIDNoPtr<T>
>::type type;
};
*/
template< typename T >
struct ReadWithoutNetworkID
{
typedef typename boost::mpl::if_<
boost::is_pointer<T>
, ReadWithoutNetworkIDPtr<T> // true
, ReadWithoutNetworkIDNoPtr<T>
>::type type;
};
template< typename T >
struct identity
{
typedef T type;
};
template< typename T >
struct IsRPC3Ptr
{
typedef typename boost::mpl::if_<
boost::is_convertible<T,RPC3*>,
boost::mpl::true_,
boost::mpl::false_>::type type;
};
template< typename T >
struct ShouldReadNetworkID
{
/*
typedef typename boost::mpl::if_<
boost::is_pointer<T>,
typename identity<T>::type,
boost::add_pointer<T>>::type typeWithPtr;
typedef typename boost::mpl::if_<
boost::is_convertible<typeWithPtr,NetworkIDObject*>,
boost::mpl::true_,
boost::mpl::false_>::type type;
*/
typedef typename boost::mpl::if_<
boost::is_convertible<T,NetworkIDObject*>,
boost::mpl::true_,
boost::mpl::false_>::type type;
};
template< typename T >
struct GetReadFunction
{
/*
typedef typename boost::mpl::if_<
typename ShouldReadNetworkID<T>::type
, typename ReadWithNetworkID<T>::type
, typename ReadWithoutNetworkID<T>::type
>::type type;
*/
typedef typename boost::mpl::if_<
typename ShouldReadNetworkID<T>::type
, ReadWithNetworkIDPtr<T>
, typename ReadWithoutNetworkID<T>::type
>::type type;
};
template< typename T >
struct ProcessArgType
{
typedef typename boost::mpl::if_<
typename IsRPC3Ptr<T>::type
, SetRPC3Ptr<T>
, typename GetReadFunction<T>::type
>::type type;
};
template< typename Function
, class From = typename boost::mpl::begin< boost::function_types::parameter_types<Function> >::type
, class To = typename boost::mpl::end< boost::function_types::parameter_types<Function> >::type
>
struct BoostRPCInvoker
{
// add an argument to a Fusion cons-list for each parameter type
template<typename Args>
static inline
InvokeResultCodes apply(Function func, InvokeArgs &functionArgs, Args const &args)
{
typedef typename boost::mpl::deref<From>::type arg_type;
typedef typename boost::mpl::next<From>::type next_iter_type;
typedef typename boost::remove_reference<arg_type>::type arg_type_no_ref;
arg_type_no_ref argType;
ProcessArgType< arg_type_no_ref >::type::apply(functionArgs, argType);
InvokeResultCodes irc = BoostRPCInvoker<Function, next_iter_type, To>::apply
( func, functionArgs, boost::fusion::push_back(args, boost::ref(argType) ) );
ProcessArgType< arg_type_no_ref >::type::Cleanup(argType);
return irc;
}
};
template< typename Function
, class From = typename boost::mpl::begin< boost::function_types::parameter_types<Function> >::type
, class To = typename boost::mpl::end< boost::function_types::parameter_types<Function> >::type
>
struct BoostRPCInvoker_ThisPtr
{
// add an argument to a Fusion cons-list for each parameter type
template<typename Args>
static inline
InvokeResultCodes apply(Function func, InvokeArgs &functionArgs, Args const &args)
{
typedef typename boost::mpl::deref<From>::type arg_type;
typedef typename boost::mpl::next<From>::type next_iter_type;
arg_type argType = (arg_type) *(functionArgs.thisPtr);
return BoostRPCInvoker<Function, next_iter_type, To>::apply
( func, functionArgs, boost::fusion::push_back(args, boost::ref(argType) ) );
}
};
template<typename Function, class To>
struct BoostRPCInvoker<Function,To,To>
{
// the argument list is complete, now call the function
template<typename Args>
static inline
InvokeResultCodes apply(Function func, InvokeArgs&, Args const &args)
{
boost::fusion::invoke(func,args);
return IRC_SUCCESS;
}
};
template <typename T>
struct DoNothing
{
static void apply(SLNet::BitStream &bitStream, T& t)
{
(void) bitStream;
(void) t;
// printf("DoNothing\n");
}
};
struct WriteBitstream
{
static void applyArray(SLNet::BitStream &bitStream, SLNet::BitStream* t) {apply(bitStream,t);}
static void apply(SLNet::BitStream &bitStream, SLNet::BitStream* t)
{
BitSize_t oldReadOffset = t->GetReadOffset();
t->ResetReadPointer();
bitStream.WriteCompressed(t->GetNumberOfBitsUsed());
bitStream.Write(t);
t->SetReadOffset(oldReadOffset);
}
};
//template <typename T>
struct WritePtr
{
template <typename T2>
static inline void applyArray(SLNet::BitStream &bitStream, T2 *t) {bitStream << (*t);}
template <typename T2>
static inline void apply(SLNet::BitStream &bitStream, T2 *t) {bitStream << (*t);}
// template <>
static inline void apply(SLNet::BitStream &bitStream, char *t) {bitStream << t;}
// template <>
static inline void apply(SLNet::BitStream &bitStream, unsigned char *t) {bitStream << t;}
// template <>
static inline void apply(SLNet::BitStream &bitStream, const char *t) {bitStream << t;}
// template <>
static inline void apply(SLNet::BitStream &bitStream, const unsigned char *t) {bitStream << t;}
};
template< typename T >
struct DoWrite
{
typedef typename boost::mpl::if_<
boost::is_convertible<T*, SLNet::BitStream*>,
WriteBitstream,
WritePtr >::type type;
};
template <typename T>
struct WriteWithNetworkIDPtr
{
static void apply(SLNet::BitStream &bitStream, T& t)
{
bool isNull;
isNull=(t==0);
bitStream.Write(isNull);
if (isNull)
return;
RPC3Tag tag;
__RPC3ClearPtr(t, &tag);
bool deref = (tag.flag & RPC3_TAG_FLAG_DEREF) !=0;
bool isArray = (tag.flag & RPC3_TAG_FLAG_ARRAY) !=0;
bitStream.Write(deref);
bitStream.Write(isArray);
if (isArray)
{
bitStream.WriteCompressed(tag.count);
}
for (unsigned int i=0; i < tag.count; i++)
{
NetworkID inNetworkID=t->GetNetworkID();
bitStream << inNetworkID;
if (deref)
{
// skip bytes, write data, go back, write number of bits written, reset cursor
bitStream.AlignWriteToByteBoundary();
BitSize_t writeOffset1 = bitStream.GetWriteOffset();
BitSize_t bitsUsed1=bitStream.GetNumberOfBitsUsed();
bitStream.Write(bitsUsed1);
bitsUsed1=bitStream.GetNumberOfBitsUsed();
DoWrite< typename boost::remove_pointer<T>::type >::type::apply(bitStream,t);
BitSize_t writeOffset2 = bitStream.GetWriteOffset();
BitSize_t bitsUsed2=bitStream.GetNumberOfBitsUsed();
bitStream.SetWriteOffset(writeOffset1);
bitStream.Write(bitsUsed2-bitsUsed1);
bitStream.SetWriteOffset(writeOffset2);
}
}
}
};
template <typename T>
struct WriteWithoutNetworkIDNoPtr
{
static void apply(SLNet::BitStream &bitStream, T& t)
{
DoWrite< typename boost::remove_pointer<T>::type >::type::apply(bitStream,&t);
}
};
template <typename T>
struct WriteWithoutNetworkIDPtr
{
static void apply(SLNet::BitStream &bitStream, T& t)
{
bool isNull;
isNull=(t==0);
bitStream.Write(isNull);
if (isNull)
return;
RPC3Tag tag;
__RPC3ClearPtr((void*) t, &tag);
bool isArray = (tag.flag & RPC3_TAG_FLAG_ARRAY) !=0;
bitStream.Write(isArray);
if (isArray)
{
bitStream.WriteCompressed(tag.count);
}
if (isArray)
{
for (unsigned int i=0; i < tag.count; i++)
DoWrite< typename boost::remove_pointer<T>::type >::type::applyArray(bitStream,t+i);
}
else
{
DoWrite< typename boost::remove_pointer<T>::type >::type::apply(bitStream,t);
}
}
};
template <typename T>
struct SerializeCallParameterBranch
{
typedef typename boost::mpl::if_<
typename IsRPC3Ptr<T>::type
, DoNothing<T>
, WriteWithoutNetworkIDPtr<T>
>::type typeCheck1;
typedef typename boost::mpl::if_<
boost::is_pointer<T>
, typeCheck1
, WriteWithoutNetworkIDNoPtr<T>
>::type typeCheck2;
typedef typename boost::mpl::if_<
typename ShouldReadNetworkID<T>::type
, WriteWithNetworkIDPtr<T>
, typeCheck2
>::type type;
};
template<typename Function>
struct GetBoundPointer_C
{
// typedef typename GetBoundPointer_C type;
static FunctionPointer GetBoundPointer(Function f)
{
return FunctionPointer(false, boost::bind( & BoostRPCInvoker<Function>::template apply<boost::fusion::nil>, f, _1, boost::fusion::nil() ));
}
};
template<typename Function>
struct GetBoundPointer_CPP
{
// typedef typename GetBoundPointer_CPP type;
static FunctionPointer GetBoundPointer(Function f)
{
return FunctionPointer(true, boost::bind( & BoostRPCInvoker_ThisPtr<Function>::template apply<boost::fusion::nil>, f, _1, boost::fusion::nil() ));
}
};
template<typename Function>
FunctionPointer GetBoundPointer(Function f)
{
return boost::mpl::if_<
boost::is_member_function_pointer<Function>
, GetBoundPointer_CPP<Function>
, GetBoundPointer_C<Function>
>::type::GetBoundPointer(f);
// return FunctionPointer(true, boost::bind( & BoostRPCInvoker<Function>::template apply<boost::fusion::nil>, f, _1, boost::fusion::nil() ) );
}
}
}
#endif