Updated RaknetLib.lib to version 3.4

Added all raknet headers for full raknet support
Added Testclass "TestCB.cpp" which is a test implementation for raknet plugin "File List Transfer". We will use this plugin for file transfer in multiplayer

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@2638 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Wanne
2009-03-28 15:30:07 +00:00
parent 6a740eb82b
commit e383a4080c
129 changed files with 22483 additions and 284 deletions
+91
View File
@@ -0,0 +1,91 @@
/// \file
/// \brief \b [Internal] Depreciated, used for windows back when I supported IO completion ports.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
// No longer used as I no longer support IO Completion ports
/*
#ifdef __USE_IO_COMPLETION_PORTS
#ifndef __ASYNCHRONOUS_FILE_IO_H
#define __ASYNCHRONOUS_FILE_IO_H
#ifdef _XBOX
#elif defined(_WIN32)
// IP_DONTFRAGMENT is different between winsock 1 and winsock 2. Therefore, Winsock2.h must be linked againt Ws2_32.lib
// winsock.h must be linked against WSock32.lib. If these two are mixed up the flag won't work correctly
//#include <winsock2.h>
//#include <windows.h>
#endif
#include "SimpleMutex.h"
struct ExtendedOverlappedStruct;
/// Provides asynch file input and ouput, either for sockets or files
class AsynchronousFileIO
{
public:
/// Default Constructor
AsynchronousFileIO();
/// Destructor
~AsynchronousFileIO();
/// Associate a socket with a completion port
/// \param[in] socket the socket used for communication
/// \param[in] dwCompletionKey the completion port key
bool AssociateSocketWithCompletionPort( SOCKET socket, DWORD dwCompletionKey );if
/// Singleton instance
static inline AsynchronousFileIO* Instance()
{
return & I;
}
/// Increase the number of users of this instance
void IncreaseUserCount( void );
/// Decrease the number of users of this instance
void DecreaseUserCount( void );
/// Stop using asynchronous IO
void Shutdown( void );
/// Get the number of user of the instance
int GetUserCount( void );
unsigned threadCount;
bool killThreads;
private:
HANDLE completionPort;
SimpleMutex userCountMutex;
SYSTEM_INFO systemInfo;
int userCount;
static AsynchronousFileIO I;
};
unsigned __stdcall ThreadPoolFunc( LPVOID arguments );
void WriteAsynch( HANDLE handle, ExtendedOverlappedStruct *extended );
BOOL ReadAsynch( HANDLE handle, ExtendedOverlappedStruct *extended );
#endif
*/
+651
View File
@@ -0,0 +1,651 @@
/// \file
/// \brief Automatically serializing and deserializing RPC system. More advanced RPC, but possibly not cross-platform
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __AUTO_RPC_H
#define __AUTO_RPC_H
class RakPeerInterface;
class NetworkIDManager;
#include "PluginInterface.h"
#include "DS_Map.h"
#include "PacketPriority.h"
#include "RakNetTypes.h"
#include "BitStream.h"
#include "Gen_RPC8.h"
#include "RakString.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// \defgroup AUTO_RPC_GROUP AutoRPC
/// \ingroup PLUGINS_GROUP
namespace RakNet
{
/// Maximum amount of data that can be passed on the stack in a function call
#define ARPC_MAX_STACK_SIZE 65536
#if defined (_WIN32)
/// Easier way to get a pointer to a function member of a C++ class
/// \note Recommended you use ARPC_REGISTER_CPP_FUNCTION0 to ARPC_REGISTER_CPP_FUNCTION9 (below)
/// \note ARPC_REGISTER_CPP_FUNCTION is not Linux compatible, and cannot validate the number of parameters is correctly passed.
/// \param[in] autoRPCInstance A pointer to an instance of AutoRPC
/// \param[in] _IDENTIFIER_ C string identifier to use on the remote system to call the function
/// \param[in] _RETURN_ Return value of the function
/// \param[in] _CLASS_ Base-most class of the containing class that contains your function
/// \param[in] _FUNCTION_ Name of the function
/// \param[in] _PARAMS_ Parameter list, include parenthesis
#define ARPC_REGISTER_CPP_FUNCTION(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS_) \
{ \
union \
{ \
_RETURN_ (AUTO_RPC_CALLSPEC _CLASS_::*__memberFunctionPtr)_PARAMS_; \
void* __voidFunc; \
}; \
__memberFunctionPtr=&_CLASS_::_FUNCTION_; \
(autoRPCInstance)->RegisterFunction(_IDENTIFIER_, __voidFunc, true, -1); \
}
/// \internal Used by ARPC_REGISTER_CPP_FUNCTION0 to ARPC_REGISTER_CPP_FUNCTION9
#define ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS_, _PARAM_COUNT_) \
{ \
union \
{ \
_RETURN_ (AUTO_RPC_CALLSPEC _CLASS_::*__memberFunctionPtr)_PARAMS_; \
void* __voidFunc; \
}; \
__memberFunctionPtr=&_CLASS_::_FUNCTION_; \
(autoRPCInstance)->RegisterFunction(_IDENTIFIER_, __voidFunc, true, _PARAM_COUNT_); \
}
/// Same as ARPC_REGISTER_CPP_FUNCTION, but specifies how many parameters the function has
#define ARPC_REGISTER_CPP_FUNCTION0(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_) (autoRPCInstance)->RegisterFunction(_IDENTIFIER_, __voidFunc, true, 0);
#define ARPC_REGISTER_CPP_FUNCTION1(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_) ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance,_IDENTIFIER_,_RETURN_,_CLASS_,_FUNCTION_,(_PARAMS1_), 0)
#define ARPC_REGISTER_CPP_FUNCTION2(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_) ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance,_IDENTIFIER_,_RETURN_,_CLASS_,_FUNCTION_,(_PARAMS1_,_PARAMS2_), 1)
#define ARPC_REGISTER_CPP_FUNCTION3(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_) ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance,_IDENTIFIER_,_RETURN_,_CLASS_,_FUNCTION_,(_PARAMS1_,_PARAMS2_,_PARAMS3_), 2)
#define ARPC_REGISTER_CPP_FUNCTION4(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_) ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance,_IDENTIFIER_,_RETURN_,_CLASS_,_FUNCTION_,(_PARAMS1_,_PARAMS2_,_PARAMS3_,_PARAMS4_), 3)
#define ARPC_REGISTER_CPP_FUNCTION5(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_) ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance,_IDENTIFIER_,_RETURN_,_CLASS_,_FUNCTION_,(_PARAMS1_,_PARAMS2_,_PARAMS3_,_PARAMS4_,_PARAMS5_), 4)
#define ARPC_REGISTER_CPP_FUNCTION6(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_) ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance,_IDENTIFIER_,_RETURN_,_CLASS_,_FUNCTION_,(_PARAMS1_,_PARAMS2_,_PARAMS3_,_PARAMS4_,_PARAMS5_,_PARAMS6_), 5)
#define ARPC_REGISTER_CPP_FUNCTION7(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_, _PARAMS7_) ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance,_IDENTIFIER_,_RETURN_,_CLASS_,_FUNCTION_,(_PARAMS1_,_PARAMS2_,_PARAMS3_,_PARAMS4_,_PARAMS5_,_PARAMS6_,_PARAMS7_), 6)
#define ARPC_REGISTER_CPP_FUNCTION8(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_, _PARAMS7_, _PARAMS8_) ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance,_IDENTIFIER_,_RETURN_,_CLASS_,_FUNCTION_,(_PARAMS1_,_PARAMS2_,_PARAMS3_,_PARAMS4_,_PARAMS5_,_PARAMS6_,_PARAMS7_,_PARAMS8_), 7)
#define ARPC_REGISTER_CPP_FUNCTION9(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_, _PARAMS7_, _PARAMS8_, _PARAMS9_) ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance,_IDENTIFIER_,_RETURN_,_CLASS_,_FUNCTION_,(_PARAMS1_,_PARAMS2_,_PARAMS3_,_PARAMS4_,_PARAMS5_,_PARAMS6_,_PARAMS7_,_PARAMS8_,_PARAMS9_), 8)
#else
#define ARPC_REGISTER_CPP_FUNCTION0(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*)) &_CLASS_::_FUNCTION_, true, 0 );
#define ARPC_REGISTER_CPP_FUNCTION1(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*, _PARAMS1_ )) &_CLASS_::_FUNCTION_, true, 0 );
#define ARPC_REGISTER_CPP_FUNCTION2(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*, _PARAMS1_, _PARAMS2_ )) &_CLASS_::_FUNCTION_, true, 1 );
#define ARPC_REGISTER_CPP_FUNCTION3(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*, _PARAMS1_, _PARAMS2_, _PARAMS3_ )) &_CLASS_::_FUNCTION_, true, 2 );
#define ARPC_REGISTER_CPP_FUNCTION4(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_ )) &_CLASS_::_FUNCTION_, true, 3 );
#define ARPC_REGISTER_CPP_FUNCTION5(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_ )) &_CLASS_::_FUNCTION_, true, 4 );
#define ARPC_REGISTER_CPP_FUNCTION6(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_ )) &_CLASS_::_FUNCTION_, true, 5 );
#define ARPC_REGISTER_CPP_FUNCTION7(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_, _PARAMS7_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_, _PARAMS7_ )) &_CLASS_::_FUNCTION_, true, 6 );
#define ARPC_REGISTER_CPP_FUNCTION8(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_, _PARAMS7_, _PARAMS8_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_, _PARAMS7_, _PARAMS8_ )) &_CLASS_::_FUNCTION_, true, 7 );
#define ARPC_REGISTER_CPP_FUNCTION9(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_, _PARAMS7_, _PARAMS8_, _PARAMS9_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), (void*)(_RETURN_ (*) (_CLASS_*, _PARAMS1_, _PARAMS2_, _PARAMS3_, _PARAMS4_, _PARAMS5_, _PARAMS6_, _PARAMS7_, _PARAMS8_, _PARAMS9_ )) &_CLASS_::_FUNCTION_, true, 8 );
#endif
/// Error codes returned by a remote system as to why an RPC function call cannot execute
/// Follows packet ID ID_RPC_REMOTE_ERROR
/// Name of the function will be appended, if available. Read as follows:
/// char outputBuff[256];
/// stringCompressor->DecodeString(outputBuff,256,&RakNet::BitStream(p->data+sizeof(MessageID)+1,p->length-sizeof(MessageID)-1,false),0);
/// printf("Function: %s\n", outputBuff);
enum RPCErrorCodes
{
/// AutoRPC::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 RegisterFunction() was called with isObjectMember=true
/// If you intended to call a CPP 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,
/// Internal error, passed stack is bigger than current stack. Check that the version is the same on both systems.
RPC_ERROR_STACK_TOO_SMALL,
/// Internal error, formatting error with how the stack was serialized
RPC_ERROR_STACK_DESERIALIZATION_FAILED,
/// The \a parameterCount parameter passed to RegisterFunction() on this system does not match the \a parameterCount parameter passed to SendCall() on the remote system.
RPC_ERROR_INCORRECT_NUMBER_OF_PARAMETERS,
};
/// The AutoRPC plugin allows you to call remote functions as if they were local functions, using the standard function call syntax
/// No serialization or deserialization is needed.
/// Advantages are that this is easier to use than regular RPC system.
/// Disadvantages is that all parameters must be passable on the stack using memcpy (shallow copy). For other types of parameters, use SetOutgoingExtraData() and GetIncomingExtraData()
/// Pointers are automatically dereferenced and the contents copied with memcpy
/// Use the old system, or regular message passing, if you need greater flexibility
/// \ingroup AUTO_RPC_GROUP
class AutoRPC : public PluginInterface
{
public:
/// Constructor
AutoRPC();
/// Destructor
virtual ~AutoRPC();
/// 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);
/// Registers a function pointer to be callable given an identifier for the pointer
/// \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
/// \param[in] isObjectMember false if a C function. True if a member function of an object (C++)
/// \param[in] parameterCount Optional parameter to tell the system how many parameters this function has. If specified, and the wrong number of parameters are called by the remote system, the call is rejected. -1 indicates undefined
/// \return True on success, false on uniqueIdentifier already used
bool RegisterFunction(const char *uniqueIdentifier, void *functionPtr, bool isObjectMember, char parameterCount=-1);
/// Unregisters a function pointer to be callable given an identifier for the pointer
/// \note This is not safe to call while connected
/// \param[in] uniqueIdentifier String identifying the function.
/// \param[in] isObjectMember false if a C function. True if a member function of an object (C++)
/// \return True on success, false on function was not previously or is not currently registered.
bool UnregisterFunction(const char *uniqueIdentifier, bool isObjectMember);
/// 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(RakNetTime 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 UNASSIGNED_SYSTEM_ADDRESS, broadcast=true
/// \param[in] systemAddress See RakPeer::Send()
/// \param[in] broadcast See RakPeer::Send()
void SetRecipientAddress(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);
/// Write extra data to pass for all following calls to Call()
/// Use BitStream::Reset to clear extra data. Don't forget to do this or you will waste bandwidth.
/// \return A bitstream you can write to to send extra data with each following call to Call()
RakNet::BitStream *SetOutgoingExtraData(void);
/// 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
RakNetTime 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;
/// 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;
/// Gets the bitstream written to via SetOutgoingExtraData().
/// Data is updated with each incoming function call
/// \return A bitstream you can read from with extra data that was written with SetOutgoingExtraData();
RakNet::BitStream *GetIncomingExtraData(void);
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
bool Call(const char *uniqueIdentifier){
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 0);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1>
bool Call(const char *uniqueIdentifier, P1 p1) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 1);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 2);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2, class P3>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2, P3 p3 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 3);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2, class P3, class P4>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2, P3 p3, P4 p4 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 4);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
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 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 5);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
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 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 6);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
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 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, p7, true, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 7);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
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 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, p7, p8, true, true, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 8);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \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, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID){
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 0);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \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()
template <class P1>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 1);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \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()
template <class P1, class P2>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 2);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \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()
template <class P1, class P2, class P3>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 3);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \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()
template <class P1, class P2, class P3, class P4>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 4);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \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()
template <class P1, class P2, class P3, class P4, class P5>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 5);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \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()
template <class P1, class P2, class P3, class P4, class P5, class P6>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 6);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \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()
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, p7, true, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 7);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \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()
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, p7, p8, true, true, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 8);
}
// If you need more than 8 parameters, just add it here...
// ---------------------------- ALL INTERNAL AFTER HERE ----------------------------
/// \internal
/// Identifies an RPC function, by string identifier and if it is a C or C++ function
struct RPCIdentifier
{
char *uniqueIdentifier;
bool isObjectMember;
};
/// \internal
/// The RPC identifier, and a pointer to the function
struct LocalRPCFunction
{
RPCIdentifier identifier;
void *functionPtr;
char parameterCount;
};
/// \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 stack
bool SendCall(const char *uniqueIdentifier, const char *stack, unsigned int bytesOnStack, char parameterCount);
protected:
// --------------------------------------------------------------------------------------------
// Packet handling functions
// --------------------------------------------------------------------------------------------
void OnAttach(RakPeerInterface *peer);
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
virtual void OnAutoRPCCall(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes);
virtual void OnRPCRemoteIndex(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes);
virtual void OnRPCUnknownRemoteIndex(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes, RakNetTime timestamp);
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
virtual void OnShutdown(RakPeerInterface *peer);
void Clear(void);
void SendError(SystemAddress target, unsigned char errorCode, const char *functionName);
unsigned GetLocalFunctionIndex(RPCIdentifier identifier);
bool GetRemoteFunctionIndex(SystemAddress systemAddress, RPCIdentifier identifier, unsigned int *outerIndex, unsigned int *innerIndex);
DataStructures::List<LocalRPCFunction> localFunctions;
DataStructures::Map<SystemAddress, DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp> *> remoteFunctions;
RakNetTime outgoingTimestamp;
PacketPriority outgoingPriority;
PacketReliability outgoingReliability;
char outgoingOrderingChannel;
SystemAddress outgoingSystemAddress;
bool outgoingBroadcast;
NetworkID outgoingNetworkID;
RakNet::BitStream outgoingExtraData;
RakNetTime incomingTimeStamp;
SystemAddress incomingSystemAddress;
RakNet::BitStream incomingExtraData;
RakPeerInterface *rakPeer;
NetworkIDManager *networkIdManager;
char currentExecution[512];
};
} // End namespace
#endif
#ifdef _MSC_VER
#pragma warning( pop )
#endif
@@ -0,0 +1,17 @@
#ifndef __AUTOPATCHER_PATCH_CONTEXT_H
#define __AUTOPATCHER_PATCH_CONTEXT_H
enum PatchContext
{
PC_HASH_WITH_PATCH,
PC_WRITE_FILE,
PC_ERROR_FILE_WRITE_FAILURE,
PC_ERROR_PATCH_TARGET_MISSING,
PC_ERROR_PATCH_APPLICATION_FAILURE,
PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE,
PC_NOTICE_WILL_COPY_ON_RESTART,
PC_NOTICE_FILE_DOWNLOADED,
PC_NOTICE_FILE_DOWNLOADED_PATCH,
};
#endif
@@ -0,0 +1,55 @@
/// \file
/// \brief An interface used by AutopatcherServer to get the data necessary to run an autopatcher.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __AUTOPATCHER_REPOSITORY_INTERFACE_H
#define __AUTOPATCHER_REPOSITORY_INTERFACE_H
class FileList;
namespace RakNet
{
class BitStream;
}
#include "IncrementalReadInterface.h"
/// An interface used by AutopatcherServer to get the data necessary to run an autopatcher. This is up to you to implement for custom repository solutions.
class AutopatcherRepositoryInterface : public IncrementalReadInterface
{
public:
/// Get list of files added and deleted since a certain date. This is used by AutopatcherServer and not usually explicitly called.
/// \param[in] applicationName A null terminated string identifying the application
/// \param[out] addedFiles A list of the current versions of filenames with hashes as their data that were created after \a sinceData
/// \param[out] deletedFiles A list of the current versions of filenames that were deleted after \a sinceData
/// \param[in] An input date, in whatever format your repository uses
/// \param[out] currentDate The current server date, in whatever format your repository uses
/// \return True on success, false on failure.
virtual bool GetChangelistSinceDate(const char *applicationName, FileList *addedFiles, FileList *deletedFiles, const char *sinceDate, char currentDate[64])=0;
/// Get patches (or files) for every file in input, assuming that input has a hash for each of those files.
/// \param[in] applicationName A null terminated string identifying the application
/// \param[in] input A list of files with SHA1_LENGTH byte hashes to get from the database.
/// \param[out] patchList You should return list of files with either the filedata or the patch. This is a subset of \a input. The context data for each file will be either PC_WRITE_FILE (to just write the file) or PC_HASH_WITH_PATCH (to patch). If PC_HASH_WITH_PATCH, then the file contains a SHA1_LENGTH byte patch followed by the hash. The datalength is patchlength + SHA1_LENGTH
/// \param[out] currentDate The current server date, in whatever format your repository uses
/// \return True on success, false on failure.
virtual bool GetPatches(const char *applicationName, FileList *input, FileList *patchList, char currentDate[64])=0;
/// \return Whatever this function returns is sent from the AutopatcherServer to the AutopatcherClient when one of the above functions returns false.
virtual const char *GetLastError(void) const=0;
};
#endif
+353
View File
@@ -0,0 +1,353 @@
/*
* BigInts are stored as 32-bit integer arrays.
* Each integer in the array is referred to as a limb ala GMP.
* Lower numbered limbs are less significant to the number represented.
* eg, limb 0 is the least significant limb.
* Also known as little-endian digit order
*/
#ifndef BIG_INT_HPP
#define BIG_INT_HPP
#include "Platform.h"
//#include <string>
namespace big
{
// returns the degree of the base 2 monic polynomial
// (the number of bits used to represent the number)
// eg, 0 0 0 0 1 0 1 1 ... => 28 out of 32 used
uint32_t Degree(uint32_t v);
// returns the number of limbs that are actually used
int LimbDegree(const uint32_t *n, int limbs);
// return bits used
uint32_t Degree(const uint32_t *n, int limbs);
// lhs = rhs (unequal limbs)
void Set(uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs);
// lhs = rhs (equal limbs)
void Set(uint32_t *lhs, int limbs, const uint32_t *rhs);
// lhs = rhs (32-bit extension)
void Set32(uint32_t *lhs, int lhs_limbs, const uint32_t rhs);
// Comparisons where both operands have the same number of limbs
bool Less(int limbs, const uint32_t *lhs, const uint32_t *rhs);
bool Greater(int limbs, const uint32_t *lhs, const uint32_t *rhs);
bool Equal(int limbs, const uint32_t *lhs, const uint32_t *rhs);
// lhs < rhs
bool Less(const uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs);
// lhs >= rhs
inline bool GreaterOrEqual(const uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs)
{
return !Less(lhs, lhs_limbs, rhs, rhs_limbs);
}
// lhs > rhs
bool Greater(const uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs);
// lhs <= rhs
inline bool LessOrEqual(const uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs)
{
return !Greater(lhs, lhs_limbs, rhs, rhs_limbs);
}
// lhs == rhs
bool Equal(const uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs);
// lhs == rhs
bool Equal32(const uint32_t *lhs, int lhs_limbs, uint32_t rhs);
// n >>= shift*32
void LimbShiftRight(uint32_t *n, int limbs, int rhs_shift);
// n <<= shift*32
void LimbShiftLeft(uint32_t *n, int limbs, int rhs_shift);
// lhs = rhs >>> shift
// Precondition: 0 <= shift < 31
void BitShiftRight(uint32_t *result, int result_limbs, const uint32_t *lhs, int lhs_limbs, int rhs_shift);
// lhs = rhs <<< shift
// Precondition: 0 <= shift < 31
void BitShiftLeft(uint32_t *result, int result_limbs, const uint32_t *lhs, int lhs_limbs, int rhs_shift);
// lhs += rhs, return carry out
// precondition: lhs_limbs >= rhs_limbs
uint32_t Add(uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs);
// out = lhs + rhs, return carry out
// precondition: lhs_limbs >= rhs_limbs
uint32_t Add(uint32_t *out, const uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs);
// lhs += rhs, return carry out
// precondition: lhs_limbs > 0
uint32_t Add32(uint32_t *lhs, int lhs_limbs, uint32_t rhs);
// lhs -= rhs, return borrow out
// precondition: lhs_limbs >= rhs_limbs
int32_t Subtract(uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs);
// out = lhs - rhs, return borrow out
// precondition: lhs_limbs >= rhs_limbs
int32_t Subtract(uint32_t *out, const uint32_t *lhs, int lhs_limbs, const uint32_t *rhs, int rhs_limbs);
// lhs -= rhs, return borrow out
// precondition: lhs_limbs > 0, result limbs = lhs_limbs
int32_t Subtract32(uint32_t *lhs, int lhs_limbs, uint32_t rhs);
// n = -n
void Negate(uint32_t *n, int limbs);
// n = ~n, only invert bits up to the MSB, but none above that
void BitNot(uint32_t *n, int limbs);
// n = ~n, invert all bits, even ones above MSB
void LimbNot(uint32_t *n, int limbs);
// Return the carry out from A += B << S
uint32_t AddLeftShift32(
int limbs, // Number of limbs in parameter A and B
uint32_t *A, // Large number
const uint32_t *B, // Large number
uint32_t S); // 32-bit number
// Return the carry out from result = A * B
uint32_t Multiply32(
int limbs, // Number of limbs in parameter A, result
uint32_t *result, // Large number
const uint32_t *A, // Large number
uint32_t B); // 32-bit number
// Return the carry out from X = X * M + A
uint32_t MultiplyAdd32(
int limbs, // Number of limbs in parameter A and B
uint32_t *X, // Large number
uint32_t M, // Large number
uint32_t A); // 32-bit number
// Return the carry out from A += B * M
uint32_t AddMultiply32(
int limbs, // Number of limbs in parameter A and B
uint32_t *A, // Large number
const uint32_t *B, // Large number
uint32_t M); // 32-bit number
// product = x * y
void SimpleMultiply(
int limbs, // Number of limbs in parameters x, y
uint32_t *product, // Large number; buffer size = limbs*2
const uint32_t *x, // Large number
const uint32_t *y); // Large number
// product = x ^ 2
void SimpleSquare(
int limbs, // Number of limbs in parameter x
uint32_t *product, // Large number; buffer size = limbs*2
const uint32_t *x); // Large number
/*
* Multiply two large numbers using the Schoolbook method
* Only produces the low y_limbs of the result
*
* The product buffer may not be pointed to by x or y
*/
void HalfSchoolbookMultiply(
uint32_t *product, // Buffer size = x_limbs+y_limbs
const uint32_t *x, // Number to multiply, buffer size = x_limbs
int x_limbs, // Size of x
const uint32_t *y, // Number to multiply, buffer size = y_limbs
int y_limbs); // Size of y
/*
* Multiply two large numbers using the Schoolbook method
*
* The product buffer may not be pointed to by x or y
*/
void SchoolbookMultiply(
uint32_t *product, // Buffer size = x_limbs+y_limbs
const uint32_t *x, // Number to multiply, buffer size = x_limbs
int x_limbs, // Size of x
const uint32_t *y, // Number to multiply, buffer size = y_limbs
int y_limbs); // Size of y
// product = xy
// memory space for product may not overlap with x,y
void Multiply(
int limbs, // Number of limbs in x,y
uint32_t *product, // Product; buffer size = limbs*2
const uint32_t *x, // Large number; buffer size = limbs
const uint32_t *y); // Large number; buffer size = limbs
// product = low half of x * y product
void SimpleMultiplyLowHalf(
int limbs, // Number of limbs in parameters x, y
uint32_t *product, // Large number; buffer size = limbs
const uint32_t *x, // Large number
const uint32_t *y); // Large number
// product = x^2
// memory space for product may not overlap with x
void Square(
int limbs, // Number of limbs in x
uint32_t *product, // Product; buffer size = limbs*2
const uint32_t *x); // Large number; buffer size = limbs
// Multiply two large, 2's complement signed numbers: result = a0 * b0
void SignedMultiply(
int limbs, // Number of limbs in parameters a0,b0
uint32_t *result, // Output, buffer size = limbs*2
const uint32_t *a0, // Large number, buffer size = limbs
const uint32_t *b0); // Large number, buffer size = limbs
// Returns the remainder of N / divisor for a 32-bit divisor
uint32_t Modulus32(
int limbs, // Number of limbs in parameter N
const uint32_t *N, // Large number, buffer size = limbs
uint32_t divisor); // 32-bit number
/*
* 'A' is overwritten with the quotient of the operation
* Returns the remainder of 'A' / divisor for a 32-bit divisor
*
* Does not check for divide-by-zero
*/
uint32_t Divide32(
int limbs, // Number of limbs in parameter A
uint32_t *A, // Large number, buffer size = limbs
uint32_t divisor); // 32-bit number
// returns (n ^ -1) Mod 2^32
uint32_t MulInverseGF32(uint32_t n);
/*
* Schoolbook division algorithm
*
* Returns true on success and false on failure (like divide by 0)
*
* Quotient and Remainder pointers can be the same as any other
*/
bool SchoolbookDivide(
const uint32_t *dividend, // Large number (numerator), buffer size = dividend_limbs
int dividend_limbs, // Dividend limbs
const uint32_t *divisor, // Large number (denominator), buffer size = divisor_limbs
int divisor_limbs, // Divisor limbs
uint32_t *quotient, // Quotient of division, buffer size = dividend_limbs
uint32_t *remainder); // Remainder of division, buffer size = divisor_limbs
// Convert bigint to string
//std::string ToStr(const uint32_t *n, int limbs, int base = 10);
// Convert string to bigint
// Return 0 if string contains non-digit characters, else number of limbs used
int ToInt(uint32_t *lhs, int max_limbs, const char *rhs, uint32_t base = 10);
/*
* Computes: result = (n ^ -1) (Mod modulus)
* Such that: result * n (Mod modulus) = 1
* Using Extended Euclid's Algorithm (GCDe)
*
* This is not always possible, so it will return false iff not possible.
*/
bool InvMod(
const uint32_t *n, // Large number, buffer size = n_limbs
int n_limbs, // Size of n
const uint32_t *modulus, // Large number, buffer size = limbs
int limbs, // Size of modulus
uint32_t *result); // Large number, buffer size = limbs
/*
* Computes: result = GCD(a, b) (greatest common divisor)
*
* Length of result is the length of the smallest argument
*/
void GCD(
const uint32_t *a, // Large number, buffer size = a_limbs
int a_limbs, // Size of a
const uint32_t *b, // Large number, buffer size = b_limbs
int b_limbs, // Size of b
uint32_t *result); // Large number, buffer size = min(a, b)
// Calculates mod_inv from low limb of modulus
uint32_t MonModInv(uint32_t modulus0);
// Compute n_residue for Montgomery reduction
void MonInputResidue(
const uint32_t *n, // Large number, buffer size = n_limbs
int n_limbs, // Number of limbs in n
const uint32_t *modulus, // Large number, buffer size = m_limbs
int m_limbs, // Number of limbs in modulus
uint32_t *n_residue); // Result, buffer size = m_limbs
// result = a * b * r^-1 (Mod modulus) in Montgomery domain
void MonPro(
int limbs, // Number of limbs in each parameter
const uint32_t *a_residue, // Large number, buffer size = limbs
const uint32_t *b_residue, // Large number, buffer size = limbs
const uint32_t *modulus, // Large number, buffer size = limbs
uint32_t mod_inv, // MonModInv() return
uint32_t *result); // Large number, buffer size = limbs
// result = a * r^-1 (Mod modulus) in Montgomery domain
// The result may be greater than the modulus, but this is okay since
// the result is still in the RNS. MonFinish() corrects this at the end.
void MonReduce(
int limbs, // Number of limbs in each parameter
uint32_t *s, // Large number, buffer size = limbs*2, gets clobbered
const uint32_t *modulus, // Large number, buffer size = limbs
uint32_t mod_inv, // MonModInv() return
uint32_t *result); // Large number, buffer size = limbs
// result = a * r^-1 (Mod modulus) in Montgomery domain
void MonFinish(
int limbs, // Number of limbs in each parameter
uint32_t *n, // Large number, buffer size = limbs
const uint32_t *modulus, // Large number, buffer size = limbs
uint32_t mod_inv); // MonModInv() return
// Computes: result = base ^ exponent (Mod modulus)
// Using Montgomery multiplication with simple squaring method
// Base parameter must be a Montgomery Residue created with MonInputResidue()
void MonExpMod(
const uint32_t *base, // Base for exponentiation, buffer size = mod_limbs
const uint32_t *exponent,// Exponent, buffer size = exponent_limbs
int exponent_limbs, // Number of limbs in exponent
const uint32_t *modulus, // Modulus, buffer size = mod_limbs
int mod_limbs, // Number of limbs in modulus
uint32_t mod_inv, // MonModInv() return
uint32_t *result); // Result, buffer size = mod_limbs
// Computes: result = base ^ exponent (Mod modulus)
// Using Montgomery multiplication with simple squaring method
void ExpMod(
const uint32_t *base, // Base for exponentiation, buffer size = base_limbs
int base_limbs, // Number of limbs in base
const uint32_t *exponent,// Exponent, buffer size = exponent_limbs
int exponent_limbs, // Number of limbs in exponent
const uint32_t *modulus, // Modulus, buffer size = mod_limbs
int mod_limbs, // Number of limbs in modulus
uint32_t mod_inv, // MonModInv() return
uint32_t *result); // Result, buffer size = mod_limbs
// Computes: result = base ^ exponent (Mod modulus=mod_p*mod_q)
// Using Montgomery multiplication with Chinese Remainder Theorem
void ExpCRT(
const uint32_t *base, // Base for exponentiation, buffer size = base_limbs
int base_limbs, // Number of limbs in base
const uint32_t *exponent,// Exponent, buffer size = exponent_limbs
int exponent_limbs, // Number of limbs in exponent
const uint32_t *mod_p, // Large number, factorization of modulus, buffer size = p_limbs
uint32_t p_inv, // MonModInv() return
const uint32_t *mod_q, // Large number, factorization of modulus, buffer size = q_limbs
uint32_t q_inv, // MonModInv() return
const uint32_t *pinvq, // Large number, InvMod(p, q) precalculated, buffer size = phi_limbs
int mod_limbs, // Number of limbs in p, q and phi
uint32_t *result); // Result, buffer size = mod_limbs*2
}
#endif // include guard
File diff suppressed because it is too large Load Diff
+784
View File
@@ -0,0 +1,784 @@
/// \file
/// \brief This class allows you to write and read native types as a string of bits. BitStream is used extensively throughout RakNet and is designed to be used by users as well.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#if defined(_MSC_VER) && _MSC_VER < 1299 // VC6 doesn't support template specialization
#ifndef __BITSTREAM_H
#define __BITSTREAM_H
#include "RakMemoryOverride.h"
#include "RakNetDefines.h"
#include "Export.h"
#include "RakNetTypes.h"
#include "RakAssert.h"
#if defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3)
#include <math.h>
#else
#include <cmath>
#endif
#include <float.h>
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// Arbitrary size, just picking something likely to be larger than most packets
#define BITSTREAM_STACK_ALLOCATION_SIZE 256
/// The namespace RakNet is not consistently used. It's only purpose is to avoid compiler errors for classes whose names are very common.
/// For the most part I've tried to avoid this simply by using names very likely to be unique for my classes.
namespace RakNet
{
/// This class allows you to write and read native types as a string of bits. BitStream is used extensively throughout RakNet and is designed to be used by users as well.
/// \sa BitStreamSample.txt
class RAK_DLL_EXPORT BitStream
{
public:
/// Default Constructor
BitStream();
/// Create the bitstream, with some number of bytes to immediately allocate.
/// There is no benefit to calling this, unless you know exactly how many bytes you need and it is greater than BITSTREAM_STACK_ALLOCATION_SIZE.
/// In that case all it does is save you one or more realloc calls.
/// \param[in] initialBytesToAllocate the number of bytes to pre-allocate.
BitStream( int initialBytesToAllocate );
/// Initialize the BitStream, immediately setting the data it contains to a predefined pointer.
/// Set \a _copyData to true if you want to make an internal copy of the data you are passing. Set it to false to just save a pointer to the data.
/// You shouldn't call Write functions with \a _copyData as false, as this will write to unallocated memory
/// 99% of the time you will use this function to cast Packet::data to a bitstream for reading, in which case you should write something as follows:
/// \code
/// RakNet::BitStream bs(packet->data, packet->length, false);
/// \endcode
/// \param[in] _data An array of bytes.
/// \param[in] lengthInBytes Size of the \a _data.
/// \param[in] _copyData true or false to make a copy of \a _data or not.
BitStream( unsigned char* _data, unsigned int lengthInBytes, bool _copyData );
/// Destructor
~BitStream();
/// Resets the bitstream for reuse.
void Reset( void );
/// Bidirectional serialize/deserialize any integral type to/from a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] var The value to write
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool Serialize(bool writeToBitstream, bool &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned char &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, char &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned short &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, short &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned int &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, int &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned long &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, long &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, long long &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned long long &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, float &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, double &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, long double &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
/// Bidirectional serialize/deserialize any integral type to/from a bitstream. If the current value is different from the last value
/// the current value will be written. Otherwise, a single bit will be written
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] currentValue The current value to write
/// \param[in] lastValue The last value to compare against. Only used if \a writeToBitstream is true.
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeDelta(bool writeToBitstream, bool &currentValue, bool lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned char &currentValue, unsigned char lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, char &currentValue, char lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned short &currentValue, unsigned short lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, short &currentValue, short lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned int &currentValue, unsigned int lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, int &currentValue, int lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned long &currentValue, unsigned long lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, long long &currentValue, long long lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned long long &currentValue, unsigned long long lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, float &currentValue, float lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, double &currentValue, double lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, long double &currentValue, long double lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
/// Bidirectional version of SerializeDelta when you don't know what the last value is, or there is no last value.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] currentValue The current value to write
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeDelta(bool writeToBitstream, bool &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned char &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, char &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned short &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, short &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned int &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, int &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned long &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, long long &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned long long &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, float &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, double &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, long double &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
/// Bidirectional serialize/deserialize any integral type to/from a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] var The value to write
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeCompressed(bool writeToBitstream, bool &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned char &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, char &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned short &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, short &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned int &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, int &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned long &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, long &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, long long &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned long long &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, float &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, double &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, long double &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
/// Bidirectional serialize/deserialize any integral type to/from a bitstream. If the current value is different from the last value
/// the current value will be written. Otherwise, a single bit will be written
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] currentValue The current value to write
/// \param[in] lastValue The last value to compare against. Only used if \a writeToBitstream is true.
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeCompressedDelta(bool writeToBitstream, bool &currentValue, bool lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned char &currentValue, unsigned char lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, char &currentValue, char lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned short &currentValue, unsigned short lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, short &currentValue, short lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned int &currentValue, unsigned int lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, int &currentValue, int lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned long &currentValue, unsigned long lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long long &currentValue, long long lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned long long &currentValue, unsigned long long lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, float &currentValue, float lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, double &currentValue, double lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long double &currentValue, long double lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
/// Save as SerializeCompressedDelta(templateType &currentValue, templateType lastValue) when we have an unknown second parameter
bool SerializeCompressedDelta(bool writeToBitstream, bool &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned char &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, char &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned short &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, short &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned int &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, int &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned long &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long long &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned long long &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, float &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, double &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long double &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
/// Bidirectional serialize/deserialize an array or casted stream or raw data. This does NOT do endian swapping.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] input a byte buffer
/// \param[in] numberOfBytes the size of \a input in bytes
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool Serialize(bool writeToBitstream, char* input, const int numberOfBytes );
/// Bidirectional serialize/deserialize a normalized 3D vector, using (at most) 4 bytes + 3 bits instead of 12-24 bytes. Will further compress y or z axis aligned vectors.
/// Accurate to 1/32767.5.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeNormVector(bool writeToBitstream, float &x, float &y, float z ){if (writeToBitstream) WriteNormVector(x,y,z); else return ReadNormVector(x,y,z); return true;}
bool SerializeNormVector(bool writeToBitstream, double &x, double &y, double &z ){if (writeToBitstream) WriteNormVector(x,y,z); else return ReadNormVector(x,y,z); return true;}
/// Bidirectional serialize/deserialize a vector, using 10 bytes instead of 12.
/// Loses accuracy to about 3/10ths and only saves 2 bytes, so only use if accuracy is not important.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeVector(bool writeToBitstream, float &x, float &y, float &z ){if (writeToBitstream) WriteVector(x,y,z); else return ReadVector(x,y,z); return true;}
bool SerializeVector(bool writeToBitstream, double &x, double &y, double &z ){if (writeToBitstream) WriteVector(x,y,z); else return ReadVector(x,y,z); return true;}
/// Bidirectional serialize/deserialize a normalized quaternion in 6 bytes + 4 bits instead of 16 bytes. Slightly lossy.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] w w
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeNormQuat(bool writeToBitstream, float &w, float &x, float &y, float &z){if (writeToBitstream) WriteNormQuat(w,x,y,z); else return ReadNormQuat(w,x,y,z); return true;}
bool SerializeNormQuat(bool writeToBitstream, double &w, double &x, double &y, double &z){if (writeToBitstream) WriteNormQuat(w,x,y,z); else return ReadNormQuat(w,x,y,z); return true;}
/// Bidirectional serialize/deserialize an orthogonal matrix by creating a quaternion, and writing 3 components of the quaternion in 2 bytes each
/// for 6 bytes instead of 36
/// Lossy, although the result is renormalized
bool SerializeOrthMatrix(
bool writeToBitstream,
float &m00, float &m01, float &m02,
float &m10, float &m11, float &m12,
float &m20, float &m21, float &m22 ){if (writeToBitstream) WriteOrthMatrix(m00,m01,m02,m10,m11,m12,m20,m21,m22); else return ReadOrthMatrix(m00,m01,m02,m10,m11,m12,m20,m21,m22); return true;}
bool SerializeOrthMatrix(
bool writeToBitstream,
double &m00, double &m01, double &m02,
double &m10, double &m11, double &m12,
double &m20, double &m21, double &m22 ){if (writeToBitstream) WriteOrthMatrix(m00,m01,m02,m10,m11,m12,m20,m21,m22); else return ReadOrthMatrix(m00,m01,m02,m10,m11,m12,m20,m21,m22); return true;}
/// Bidirectional serialize/deserialize numberToSerialize bits to/from the input. Right aligned
/// data means in the case of a partial byte, the bits are aligned
/// from the right (bit 0) rather than the left (as in the normal
/// internal representation) You would set this to true when
/// writing user data, and false when copying bitstream data, such
/// as writing one bitstream to another
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] input The data
/// \param[in] numberOfBitsToSerialize The number of bits to write
/// \param[in] rightAlignedBits if true data will be right aligned
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeBits(bool writeToBitstream, unsigned char* input, int numberOfBitsToSerialize, const bool rightAlignedBits = true );
/// Write any integral type to a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// \param[in] var The value to write
void Write(bool var){if ( var ) Write1(); else Write0();}
void Write(unsigned char var){WriteBits( ( unsigned char* ) & var, sizeof( unsigned char ) * 8, true );}
void Write(char var){WriteBits( ( unsigned char* ) & var, sizeof( char ) * 8, true );}
void Write(unsigned short var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned short)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned short)); WriteBits( ( unsigned char* ) output, sizeof(unsigned short) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(unsigned short) * 8, true );}
void Write(short var) {if (DoEndianSwap()){unsigned char output[sizeof(short)]; ReverseBytes((unsigned char*)&var, output, sizeof(short)); WriteBits( ( unsigned char* ) output, sizeof(short) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(short) * 8, true );}
void Write(unsigned int var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned int)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned int)); WriteBits( ( unsigned char* ) output, sizeof(unsigned int) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(unsigned int) * 8, true );}
void Write(int var) {if (DoEndianSwap()){unsigned char output[sizeof(int)]; ReverseBytes((unsigned char*)&var, output, sizeof(int)); WriteBits( ( unsigned char* ) output, sizeof(int) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(int) * 8, true );}
void Write(unsigned long var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned long)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned long)); WriteBits( ( unsigned char* ) output, sizeof(unsigned long) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(unsigned long) * 8, true );}
void Write(long var) {if (DoEndianSwap()){unsigned char output[sizeof(long)]; ReverseBytes((unsigned char*)&var, output, sizeof(long)); WriteBits( ( unsigned char* ) output, sizeof(long) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(long) * 8, true );}
void Write(long long var) {if (DoEndianSwap()){unsigned char output[sizeof(long long)]; ReverseBytes((unsigned char*)&var, output, sizeof(long long)); WriteBits( ( unsigned char* ) output, sizeof(long long) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(long long) * 8, true );}
void Write(unsigned long long var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned long long)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned long long)); WriteBits( ( unsigned char* ) output, sizeof(unsigned long long) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(unsigned long long) * 8, true );}
void Write(float var) {if (DoEndianSwap()){unsigned char output[sizeof(float)]; ReverseBytes((unsigned char*)&var, output, sizeof(float)); WriteBits( ( unsigned char* ) output, sizeof(float) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(float) * 8, true );}
void Write(double var) {if (DoEndianSwap()){unsigned char output[sizeof(double)]; ReverseBytes((unsigned char*)&var, output, sizeof(double)); WriteBits( ( unsigned char* ) output, sizeof(double) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(double) * 8, true );}
void Write(long double var) {if (DoEndianSwap()){unsigned char output[sizeof(long double)]; ReverseBytes((unsigned char*)&var, output, sizeof(long double)); WriteBits( ( unsigned char* ) output, sizeof(long double) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(long double) * 8, true );}
void Write(void* var) {if (DoEndianSwap()){unsigned char output[sizeof(void*)]; ReverseBytes((unsigned char*)&var, output, sizeof(void*)); WriteBits( ( unsigned char* ) output, sizeof(void*) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(void*) * 8, true );}
void Write(SystemAddress var){WriteBits( ( unsigned char* ) & var.binaryAddress, sizeof(var.binaryAddress) * 8, true ); Write(var.port);}
void Write(NetworkID var){if (NetworkID::IsPeerToPeerMode()) Write(var.systemAddress); Write(var.localSystemAddress);}
/// Write any integral type to a bitstream. If the current value is different from the last value
/// the current value will be written. Otherwise, a single bit will be written
/// \param[in] currentValue The current value to write
/// \param[in] lastValue The last value to compare against
void WriteDelta(bool currentValue, bool lastValue){
#pragma warning(disable:4100) // warning C4100: 'peer' : unreferenced formal parameter
Write(currentValue);
}
void WriteDelta(unsigned char currentValue, unsigned char lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(char currentValue, char lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(unsigned short currentValue, unsigned short lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(short currentValue, short lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(unsigned int currentValue, unsigned int lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(int currentValue, int lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(unsigned long currentValue, unsigned long lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(long currentValue, long lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(long long currentValue, long long lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(unsigned long long currentValue, unsigned long long lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(float currentValue, float lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(double currentValue, double lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(long double currentValue, long double lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(SystemAddress currentValue, SystemAddress lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(NetworkID currentValue, NetworkID lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
/// WriteDelta when you don't know what the last value is, or there is no last value.
/// \param[in] currentValue The current value to write
void WriteDelta(bool var){Write(var);}
void WriteDelta(unsigned char var){Write(true); Write(var);}
void WriteDelta(char var){Write(true); Write(var);}
void WriteDelta(unsigned short var){Write(true); Write(var);}
void WriteDelta(short var){Write(true); Write(var);}
void WriteDelta(unsigned int var){Write(true); Write(var);}
void WriteDelta(int var){Write(true); Write(var);}
void WriteDelta(unsigned long var){Write(true); Write(var);}
void WriteDelta(long var){Write(true); Write(var);}
void WriteDelta(long long var){Write(true); Write(var);}
void WriteDelta(unsigned long long var){Write(true); Write(var);}
void WriteDelta(float var){Write(true); Write(var);}
void WriteDelta(double var){Write(true); Write(var);}
void WriteDelta(long double var){Write(true); Write(var);}
void WriteDelta(SystemAddress var){Write(true); Write(var);}
void WriteDelta(NetworkID var){Write(true); Write(var);}
/// Write any integral type to a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// \param[in] var The value to write
void WriteCompressed(bool var) {Write(var);}
void WriteCompressed(unsigned char var) {WriteCompressed( ( unsigned char* ) & var, sizeof( unsigned char ) * 8, true );}
void WriteCompressed(char var) {WriteCompressed( (unsigned char* ) & var, sizeof( unsigned char ) * 8, true );}
void WriteCompressed(unsigned short var) {if (DoEndianSwap()) {unsigned char output[sizeof(unsigned short)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned short)); WriteCompressed( ( unsigned char* ) output, sizeof(unsigned short) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(unsigned short) * 8, true );}
void WriteCompressed(short var) {if (DoEndianSwap()) {unsigned char output[sizeof(short)]; ReverseBytes((unsigned char*)&var, output, sizeof(short)); WriteCompressed( ( unsigned char* ) output, sizeof(short) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(short) * 8, true );}
void WriteCompressed(unsigned int var) {if (DoEndianSwap()) {unsigned char output[sizeof(unsigned int)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned int)); WriteCompressed( ( unsigned char* ) output, sizeof(unsigned int) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(unsigned int) * 8, true );}
void WriteCompressed(int var) {if (DoEndianSwap()) { unsigned char output[sizeof(int)]; ReverseBytes((unsigned char*)&var, output, sizeof(int)); WriteCompressed( ( unsigned char* ) output, sizeof(int) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(int) * 8, true );}
void WriteCompressed(unsigned long var) {if (DoEndianSwap()) {unsigned char output[sizeof(unsigned long)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned long)); WriteCompressed( ( unsigned char* ) output, sizeof(unsigned long) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(unsigned long) * 8, true );}
void WriteCompressed(long var) {if (DoEndianSwap()) {unsigned char output[sizeof(long)]; ReverseBytes((unsigned char*)&var, output, sizeof(long)); WriteCompressed( ( unsigned char* ) output, sizeof(long) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(long) * 8, true );}
void WriteCompressed(long long var) {if (DoEndianSwap()) {unsigned char output[sizeof(long long)]; ReverseBytes((unsigned char*)&var, output, sizeof(long long)); WriteCompressed( ( unsigned char* ) output, sizeof(long long) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(long long) * 8, true );}
void WriteCompressed(unsigned long long var) {if (DoEndianSwap()) { unsigned char output[sizeof(unsigned long long)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned long long)); WriteCompressed( ( unsigned char* ) output, sizeof(unsigned long long) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(unsigned long long) * 8, true );}
void WriteCompressed(float var) {RakAssert(var > -1.01f && var < 1.01f); if (var < -1.0f) var=-1.0f; if (var > 1.0f) var=1.0f; Write((unsigned short)((var+1.0f)*32767.5f));}
void WriteCompressed(double var) {RakAssert(var > -1.01 && var < 1.01); if (var < -1.0) var=-1.0; if (var > 1.0) var=1.0; Write((unsigned long)((var+1.0)*2147483648.0));}
void WriteCompressed(long double var) {RakAssert(var > -1.01 && var < 1.01); if (var < -1.0) var=-1.0; if (var > 1.0) var=1.0; Write((unsigned long)((var+1.0)*2147483648.0));}
/// Write any integral type to a bitstream. If the current value is different from the last value
/// the current value will be written. Otherwise, a single bit will be written
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// \param[in] currentValue The current value to write
/// \param[in] lastValue The last value to compare against
void WriteCompressedDelta(bool currentValue, bool lastValue)
{
#pragma warning(disable:4100) // warning C4100: 'peer' : unreferenced formal parameter
Write(currentValue);
}
void WriteCompressedDelta(unsigned char currentValue, unsigned char lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(char currentValue, char lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(unsigned short currentValue, unsigned short lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(short currentValue, short lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(unsigned int currentValue, unsigned int lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(int currentValue, int lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(unsigned long currentValue, unsigned long lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(long currentValue, long lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(long long currentValue, long long lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(unsigned long long currentValue, unsigned long long lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(float currentValue, float lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(double currentValue, double lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(long double currentValue, long double lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
/// Save as WriteCompressedDelta(templateType currentValue, templateType lastValue) when we have an unknown second parameter
void WriteCompressedDelta(bool var) {Write(var);}
void WriteCompressedDelta(unsigned char var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(char var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(unsigned short var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(short var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(unsigned int var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(int var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(unsigned long var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(long var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(long long var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(unsigned long long var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(float var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(double var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(long double var) { Write(true); WriteCompressed(var); }
/// Read any integral type from a bitstream. Define __BITSTREAM_NATIVE_END if you need endian swapping.
/// \param[in] var The value to read
bool Read(bool &var){if ( readOffset + 1 > numberOfBitsUsed ) return false;
if ( data[ readOffset >> 3 ] & ( 0x80 >> ( readOffset & 7 ) ) )
var = true;
else
var = false;
// Has to be on a different line for Mac
readOffset++;
return true;
}
bool Read(unsigned char &var) {return ReadBits( ( unsigned char* ) &var, sizeof(unsigned char) * 8, true );}
bool Read(char &var) {return ReadBits( ( unsigned char* ) &var, sizeof(char) * 8, true );}
bool Read(unsigned short &var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned short)]; if (ReadBits( ( unsigned char* ) output, sizeof(unsigned short) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned short)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(unsigned short) * 8, true );}
bool Read(short &var) {if (DoEndianSwap()){unsigned char output[sizeof(short)]; if (ReadBits( ( unsigned char* ) output, sizeof(short) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(short)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(short) * 8, true );}
bool Read(unsigned int &var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned int)]; if (ReadBits( ( unsigned char* ) output, sizeof(unsigned int) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned int)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(unsigned int) * 8, true );}
bool Read(int &var) {if (DoEndianSwap()){unsigned char output[sizeof(int)]; if (ReadBits( ( unsigned char* ) output, sizeof(int) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(int)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(int) * 8, true );}
bool Read(unsigned long &var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned long)]; if (ReadBits( ( unsigned char* ) output, sizeof(unsigned long) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned long)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(unsigned long) * 8, true );}
bool Read(long &var) {if (DoEndianSwap()){unsigned char output[sizeof(long)]; if (ReadBits( ( unsigned char* ) output, sizeof(long) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(long)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(long) * 8, true );}
bool Read(long long &var) {if (DoEndianSwap()){unsigned char output[sizeof(long long)]; if (ReadBits( ( unsigned char* ) output, sizeof(long long) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(long long)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(long long) * 8, true );}
bool Read(unsigned long long &var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned long long)]; if (ReadBits( ( unsigned char* ) output, sizeof(unsigned long long) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned long long)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(unsigned long long) * 8, true );}
bool Read(float &var) {if (DoEndianSwap()){unsigned char output[sizeof(float)]; if (ReadBits( ( unsigned char* ) output, sizeof(float) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(float)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(float) * 8, true );}
bool Read(double &var) {if (DoEndianSwap()){unsigned char output[sizeof(double)]; if (ReadBits( ( unsigned char* ) output, sizeof(double) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(double)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(double) * 8, true );}
bool Read(long double &var) {if (DoEndianSwap()){unsigned char output[sizeof(long double)]; if (ReadBits( ( unsigned char* ) output, sizeof(long double) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(long double)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(long double) * 8, true );}
bool Read(void* &var) {if (DoEndianSwap()){unsigned char output[sizeof(void*)]; if (ReadBits( ( unsigned char* ) output, sizeof(void*) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(void*)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(void*) * 8, true );}
bool Read(SystemAddress &var){ReadBits( ( unsigned char* ) & var.binaryAddress, sizeof(var.binaryAddress) * 8, true ); return Read(var.port);}
bool Read(NetworkID &var){if (NetworkID::IsPeerToPeerMode()) Read(var.systemAddress); return Read(var.localSystemAddress);}
/// Read any integral type from a bitstream. If the written value differed from the value compared against in the write function,
/// var will be updated. Otherwise it will retain the current value.
/// ReadDelta is only valid from a previous call to WriteDelta
/// \param[in] var The value to read
bool ReadDelta(bool &var) {return Read(var);}
bool ReadDelta(unsigned char &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(char &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(unsigned short &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(short &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(unsigned int &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(int &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(unsigned long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(long long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(unsigned long long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(float &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(double &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(long double &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(SystemAddress &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(NetworkID &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
/// Read any integral type from a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// \param[in] var The value to read
bool ReadCompressed(bool &var) {return Read(var);}
bool ReadCompressed(unsigned char &var) {return ReadCompressed( ( unsigned char* ) &var, sizeof(unsigned char) * 8, true );}
bool ReadCompressed(char &var) {return ReadCompressed( ( unsigned char* ) &var, sizeof(unsigned char) * 8, true );}
bool ReadCompressed(unsigned short &var){if (DoEndianSwap()){unsigned char output[sizeof(unsigned short)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(unsigned short) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned short)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(unsigned short) * 8, true );}
bool ReadCompressed(short &var){if (DoEndianSwap()){unsigned char output[sizeof(short)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(short) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(short)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(short) * 8, true );}
bool ReadCompressed(unsigned int &var){if (DoEndianSwap()){unsigned char output[sizeof(unsigned int)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(unsigned int) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned int)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(unsigned int) * 8, true );}
bool ReadCompressed(int &var){if (DoEndianSwap()){unsigned char output[sizeof(int)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(int) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(int)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(int) * 8, true );}
bool ReadCompressed(unsigned long &var){if (DoEndianSwap()){unsigned char output[sizeof(unsigned long)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(unsigned long) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned long)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(unsigned long) * 8, true );}
bool ReadCompressed(long &var){if (DoEndianSwap()){unsigned char output[sizeof(long)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(long) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(long)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(long) * 8, true );}
bool ReadCompressed(long long &var){if (DoEndianSwap()){unsigned char output[sizeof(long long)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(long long) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(long long)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(long long) * 8, true );}
bool ReadCompressed(unsigned long long &var){if (DoEndianSwap()){unsigned char output[sizeof(unsigned long long)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(unsigned long long) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned long long)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(unsigned long long) * 8, true );}
bool ReadCompressed(float &var){unsigned short compressedFloat; if (Read(compressedFloat)) { var = ((float)compressedFloat / 32767.5f - 1.0f); return true;} return false;}
bool ReadCompressed(double &var) {unsigned long compressedFloat; if (Read(compressedFloat)) { var = ((double)compressedFloat / 2147483648.0 - 1.0); return true; } return false;}
bool ReadCompressed(long double &var) {unsigned long compressedFloat; if (Read(compressedFloat)) { var = ((long double)compressedFloat / 2147483648.0 - 1.0); return true; } return false;}
bool ReadCompressed(SystemAddress &var) {return Read(var);}
bool ReadCompressed(NetworkID &var) {return Read(var);}
/// Read any integral type from a bitstream. If the written value differed from the value compared against in the write function,
/// var will be updated. Otherwise it will retain the current value.
/// the current value will be updated.
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// ReadCompressedDelta is only valid from a previous call to WriteDelta
/// \param[in] var The value to read
bool ReadCompressedDelta(bool &var) {return Read(var);}
bool ReadCompressedDelta(unsigned char &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(char &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(unsigned short &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(short &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(unsigned int &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(int &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(unsigned long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(long long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(unsigned long long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(float &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(double &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(long double &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
/// Write an array or casted stream or raw data. This does NOT do endian swapping.
/// \param[in] input a byte buffer
/// \param[in] numberOfBytes the size of \a input in bytes
void Write( const char* input, const int numberOfBytes );
/// Write one bitstream to another
/// \param[in] numberOfBits bits to write
/// \param bitStream the bitstream to copy from
void Write( BitStream *bitStream, int numberOfBits );
void Write( BitStream *bitStream );
/// Read a normalized 3D vector, using (at most) 4 bytes + 3 bits instead of 12-24 bytes. Will further compress y or z axis aligned vectors.
/// Accurate to 1/32767.5.
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
void WriteNormVector( float x, float y, float z );
void WriteNormVector( double x, double y, double z ) {WriteNormVector((float)x,(float)y,(float)z);}
/// Write a vector, using 10 bytes instead of 12.
/// Loses accuracy to about 3/10ths and only saves 2 bytes, so only use if accuracy is not important.
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
void WriteVector( float x, float y, float z );
void WriteVector( double x, double y, double z ) {WriteVector((float)x, (float)y, (float)z);}
/// Write a normalized quaternion in 6 bytes + 4 bits instead of 16 bytes. Slightly lossy.
/// \param[in] w w
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
void WriteNormQuat( float w, float x, float y, float z);
void WriteNormQuat( double w, double x, double y, double z) {WriteNormQuat((float)w, (float) x, (float) y, (float) z);}
/// Write an orthogonal matrix by creating a quaternion, and writing 3 components of the quaternion in 2 bytes each
/// for 6 bytes instead of 36
/// Lossy, although the result is renormalized
void WriteOrthMatrix(
float m00, float m01, float m02,
float m10, float m11, float m12,
float m20, float m21, float m22 )
{
WriteOrthMatrix((double)m00,(double)m01,(double)m02,
(double)m10,(double)m11,(double)m12,
(double)m20,(double)m21,(double)m22);
}
void WriteOrthMatrix(
double m00, double m01, double m02,
double m10, double m11, double m12,
double m20, double m21, double m22 );
/// Read an array or casted stream of byte. The array
/// is raw data. There is no automatic endian conversion with this function
/// \param[in] output The result byte array. It should be larger than @em numberOfBytes.
/// \param[in] numberOfBytes The number of byte to read
/// \return true on success false if there is some missing bytes.
bool Read( char* output, const int numberOfBytes );
/// Read a normalized 3D vector, using (at most) 4 bytes + 3 bits instead of 12-24 bytes. Will further compress y or z axis aligned vectors.
/// Accurate to 1/32767.5.
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
bool ReadNormVector( float &x, float &y, float &z );
bool ReadNormVector( double &x, double &y, double &z ) {float fx, fy, fz; bool b = ReadNormVector(fx, fy, fz); x=fx; y=fy; z=fz; return b;}
/// Read 3 floats or doubles, using 10 bytes, where those float or doubles comprise a vector
/// Loses accuracy to about 3/10ths and only saves 2 bytes, so only use if accuracy is not important.
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
bool ReadVector( float x, float y, float z );
bool ReadVector( double &x, double &y, double &z ) {return ReadVector((float)x, (float)y, (float)z);}
/// Read a normalized quaternion in 6 bytes + 4 bits instead of 16 bytes.
/// \param[in] w w
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
bool ReadNormQuat( float &w, float &x, float &y, float &z){double dw, dx, dy, dz; bool b=ReadNormQuat(dw, dx, dy, dz); w=(float)dw; x=(float)dx; y=(float)dy; z=(float)dz; return b;}
bool ReadNormQuat( double &w, double &x, double &y, double &z);
/// Read an orthogonal matrix from a quaternion, reading 3 components of the quaternion in 2 bytes each and extrapolating the 4th.
/// for 6 bytes instead of 36
/// Lossy, although the result is renormalized
bool ReadOrthMatrix(
float &m00, float &m01, float &m02,
float &m10, float &m11, float &m12,
float &m20, float &m21, float &m22 );
bool ReadOrthMatrix(
double &m00, double &m01, double &m02,
double &m10, double &m11, double &m12,
double &m20, double &m21, double &m22 );
///Sets the read pointer back to the beginning of your data.
void ResetReadPointer( void );
/// Sets the write pointer back to the beginning of your data.
void ResetWritePointer( void );
///This is good to call when you are done with the stream to make
/// sure you didn't leave any data left over void
void AssertStreamEmpty( void );
/// RAKNET_DEBUG_PRINTF the bits in the stream. Great for debugging.
void PrintBits( void ) const;
/// Ignore data we don't intend to read
/// \param[in] numberOfBits The number of bits to ignore
void IgnoreBits( const int numberOfBits );
/// Ignore data we don't intend to read
/// \param[in] numberOfBits The number of bytes to ignore
void IgnoreBytes( const int numberOfBytes );
///Move the write pointer to a position on the array.
/// \param[in] offset the offset from the start of the array.
/// \attention
/// Dangerous if you don't know what you are doing!
/// For efficiency reasons you can only write mid-stream if your data is byte aligned.
void SetWriteOffset( const int offset );
/// Returns the length in bits of the stream
inline int GetNumberOfBitsUsed( void ) const {return GetWriteOffset();}
inline int GetWriteOffset( void ) const {return numberOfBitsUsed;}
///Returns the length in bytes of the stream
inline int GetNumberOfBytesUsed( void ) const {return BITS_TO_BYTES( numberOfBitsUsed );}
///Returns the number of bits into the stream that we have read
inline int GetReadOffset( void ) const {return readOffset;}
// Sets the read bit index
inline void SetReadOffset( int newReadOffset ) {readOffset=newReadOffset;}
///Returns the number of bits left in the stream that haven't been read
inline int GetNumberOfUnreadBits( void ) const {return numberOfBitsUsed - readOffset;}
/// Makes a copy of the internal data for you \a _data will point to
/// the stream. Returns the length in bits of the stream. Partial
/// bytes are left aligned
/// \param[out] _data The allocated copy of GetData()
int CopyData( unsigned char** _data ) const;
/// Set the stream to some initial data.
/// \internal
void SetData( unsigned char *input );
/// Gets the data that BitStream is writing to / reading from
/// Partial bytes are left aligned.
/// \return A pointer to the internal state
inline unsigned char* GetData( void ) const {return data;}
/// Write numberToWrite bits from the input source Right aligned
/// data means in the case of a partial byte, the bits are aligned
/// from the right (bit 0) rather than the left (as in the normal
/// internal representation) You would set this to true when
/// writing user data, and false when copying bitstream data, such
/// as writing one bitstream to another
/// \param[in] input The data
/// \param[in] numberOfBitsToWrite The number of bits to write
/// \param[in] rightAlignedBits if true data will be right aligned
void WriteBits( const unsigned char* input, int numberOfBitsToWrite, const bool rightAlignedBits = true );
/// Align the bitstream to the byte boundary and then write the
/// specified number of bits. This is faster than WriteBits but
/// wastes the bits to do the alignment and requires you to call
/// ReadAlignedBits at the corresponding read position.
/// \param[in] input The data
/// \param[in] numberOfBytesToWrite The size of input.
void WriteAlignedBytes( void *input, const int numberOfBytesToWrite );
/// Aligns the bitstream, writes inputLength, and writes input. Won't write beyond maxBytesToWrite
/// \param[in] input The data
/// \param[in] inputLength The size of input.
/// \param[in] maxBytesToWrite Max bytes to write
void WriteAlignedBytesSafe( void *input, const int inputLength, const int maxBytesToWrite );
/// Read bits, starting at the next aligned bits. Note that the
/// modulus 8 starting offset of the sequence must be the same as
/// was used with WriteBits. This will be a problem with packet
/// coalescence unless you byte align the coalesced packets.
/// \param[in] output The byte array larger than @em numberOfBytesToRead
/// \param[in] numberOfBytesToRead The number of byte to read from the internal state
/// \return true if there is enough byte.
bool ReadAlignedBytes( void *output, const int numberOfBytesToRead );
/// Reads what was written by WriteAlignedBytesSafe
/// \param[in] input The data
/// \param[in] maxBytesToRead Maximum number of bytes to read
bool ReadAlignedBytesSafe( void *input, int &inputLength, const int maxBytesToRead );
/// Same as ReadAlignedBytesSafe() but allocates the memory for you using new, rather than assuming it is safe to write to
/// \param[in] input input will be deleted if it is not a pointer to 0
bool ReadAlignedBytesSafeAlloc( char **input, int &inputLength, const int maxBytesToRead );
/// Align the next write and/or read to a byte boundary. This can
/// be used to 'waste' bits to byte align for efficiency reasons It
/// can also be used to force coalesced bitstreams to start on byte
/// boundaries so so WriteAlignedBits and ReadAlignedBits both
/// calculate the same offset when aligning.
void AlignWriteToByteBoundary( void );
/// Align the next write and/or read to a byte boundary. This can
/// be used to 'waste' bits to byte align for efficiency reasons It
/// can also be used to force coalesced bitstreams to start on byte
/// boundaries so so WriteAlignedBits and ReadAlignedBits both
/// calculate the same offset when aligning.
void AlignReadToByteBoundary( void );
/// Read \a numberOfBitsToRead bits to the output source
/// alignBitsToRight should be set to true to convert internal
/// bitstream data to userdata. It should be false if you used
/// WriteBits with rightAlignedBits false
/// \param[in] output The resulting bits array
/// \param[in] numberOfBitsToRead The number of bits to read
/// \param[in] alignBitsToRight if true bits will be right aligned.
/// \return true if there is enough bits to read
bool ReadBits( unsigned char *output, int numberOfBitsToRead, const bool alignBitsToRight = true );
/// Write a 0
void Write0( void );
/// Write a 1
void Write1( void );
/// Reads 1 bit and returns true if that bit is 1 and false if it is 0
bool ReadBit( void );
/// If we used the constructor version with copy data off, this
/// *makes sure it is set to on and the data pointed to is copied.
void AssertCopyData( void );
/// Use this if you pass a pointer copy to the constructor
/// *(_copyData==false) and want to overallocate to prevent
/// *reallocation
void SetNumberOfBitsAllocated( const unsigned int lengthInBits );
/// Reallocates (if necessary) in preparation of writing numberOfBitsToWrite
void AddBitsAndReallocate( const int numberOfBitsToWrite );
/// \internal
/// \return How many bits have been allocated internally
unsigned int GetNumberOfBitsAllocated(void) const;
static bool DoEndianSwap(void);
static bool IsBigEndian(void);
static bool IsNetworkOrder(void);
static void ReverseBytes(unsigned char *input, unsigned char *output, int length);
static void ReverseBytesInPlace(unsigned char *data, int length);
private:
BitStream( const BitStream &invalid) {
#ifdef _MSC_VER
#pragma warning(disable:4100)
// warning C4100: 'invalid' : unreferenced formal parameter
#endif
}
/// Assume the input source points to a native type, compress and write it.
void WriteCompressed( const unsigned char* input, const int size, const bool unsignedData );
/// Assume the input source points to a compressed native type. Decompress and read it.
bool ReadCompressed( unsigned char* output, const int size, const bool unsignedData );
int numberOfBitsUsed;
int numberOfBitsAllocated;
int readOffset;
unsigned char *data;
/// true if the internal buffer is copy of the data passed to the constructor
bool copyData;
/// BitStreams that use less than BITSTREAM_STACK_ALLOCATION_SIZE use the stack, rather than the heap to store data. It switches over if BITSTREAM_STACK_ALLOCATION_SIZE is exceeded
unsigned char stackData[BITSTREAM_STACK_ALLOCATION_SIZE];
};
inline bool BitStream::SerializeBits(bool writeToBitstream, unsigned char* input, int numberOfBitsToSerialize, const bool rightAlignedBits )
{
if (writeToBitstream)
WriteBits(input,numberOfBitsToSerialize,rightAlignedBits);
else
return ReadBits(input,numberOfBitsToSerialize,rightAlignedBits);
return true;
}
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif // VC6
#endif
+54
View File
@@ -0,0 +1,54 @@
/// \file
/// \brief \b [Internal] Generates and validates checksums
///
/// \note I didn't write this, but took it from http://www.flounder.com/checksum.htm
///
#ifndef __CHECKSUM_H
#define __CHECKSUM_H
#include "RakMemoryOverride.h"
/// Generates and validates checksums
class CheckSum
{
public:
/// Default constructor
CheckSum()
{
Clear();
}
void Clear()
{
sum = 0;
r = 55665;
c1 = 52845;
c2 = 22719;
}
void Add ( unsigned int w );
void Add ( unsigned short w );
void Add ( unsigned char* b, unsigned int length );
void Add ( unsigned char b );
unsigned int Get ()
{
return sum;
}
protected:
unsigned short r;
unsigned short c1;
unsigned short c2;
unsigned int sum;
};
#endif
+50
View File
@@ -0,0 +1,50 @@
/// \file
/// \brief \b [Internal] Depreciated, back from when I supported IO Completion ports.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __CLIENT_CONTEXT_STRUCT_H
#define __CLIENT_CONTEXT_STRUCT_H
#if defined(_XBOX) || defined(X360)
#elif defined(_WIN32)
//#include <windows.h>
#endif
#include "RakNetTypes.h"
#include "MTUSize.h"
class RakPeer;
#ifdef __USE_IO_COMPLETION_PORTS
struct ClientContextStruct
{
HANDLE handle; // The socket, also used as a file handle
};
struct ExtendedOverlappedStruct
{
OVERLAPPED overlapped;
char data[ MAXIMUM_MTU_SIZE ]; // Used to hold data to send
int length; // Length of the actual data to send, always under MAXIMUM_MTU_SIZE
unsigned int binaryAddress;
unsigned short port;
RakPeer *rakPeer;
bool read; // Set to true for reads, false for writes
};
#endif
#endif
+149
View File
@@ -0,0 +1,149 @@
/// \file
/// \brief Contains CommandParserInterface , from which you derive custom command parsers
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __COMMAND_PARSER_INTERFACE
#define __COMMAND_PARSER_INTERFACE
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#include "DS_OrderedList.h"
#include "Export.h"
class TransportInterface;
/// \internal
/// Contains the information related to one command registered with RegisterCommand()
/// Implemented so I can have an automatic help system via SendCommandList()
struct RAK_DLL_EXPORT RegisteredCommand
{
const char *command;
const char *commandHelp;
unsigned char parameterCount;
};
/// List of commands registered with RegisterCommand()
int RAK_DLL_EXPORT RegisteredCommandComp( const char* const & key, const RegisteredCommand &data );
/// CommandParserInterface provides a set of functions and interfaces that plug into the ConsoleServer class.
/// Each CommandParserInterface works at the same time as other interfaces in the system.
/// \brief The interface used by command parsers.
class RAK_DLL_EXPORT CommandParserInterface
{
public:
CommandParserInterface();
virtual ~CommandParserInterface();
/// You are responsible for overriding this function and returning a static string, which will identifier your parser.
/// This should return a static string
/// \return The name that you return.
virtual const char *GetName(void) const=0;
/// A callback for when \a systemAddress has connected to us.
/// \param[in] systemAddress The player that has connected.
/// \param[in] transport The transport interface that sent us this information. Can be used to send messages to this or other players.
virtual void OnNewIncomingConnection(SystemAddress systemAddress, TransportInterface *transport);
/// A callback for when \a systemAddress has disconnected, either gracefully or forcefully
/// \param[in] systemAddress The player that has disconnected.
/// \param[in] transport The transport interface that sent us this information.
virtual void OnConnectionLost(SystemAddress systemAddress, TransportInterface *transport);
/// A callback for when you are expected to send a brief description of your parser to \a systemAddress
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that requested help.
virtual void SendHelp(TransportInterface *transport, SystemAddress systemAddress)=0;
/// Given \a command with parameters \a parameterList , do whatever processing you wish.
/// \param[in] command The command to process
/// \param[in] numParameters How many parameters were passed along with the command
/// \param[in] parameterList The list of parameters. parameterList[0] is the first parameter and so on.
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that sent this command.
/// \param[in] originalString The string that was actually sent over the network, in case you want to do your own parsing
virtual bool OnCommand(const char *command, unsigned numParameters, char **parameterList, TransportInterface *transport, SystemAddress systemAddress, const char *originalString)=0;
/// This is called every time transport interface is registered. If you want to save a copy of the TransportInterface pointer
/// This is the place to do it
/// \param[in] transport The new TransportInterface
virtual void OnTransportChange(TransportInterface *transport);
/// \internal
/// Scan commandList and return the associated array
/// \param[in] command The string to find
/// \param[out] rc Contains the result of this operation
/// \return True if we found the command, false otherwise
virtual bool GetRegisteredCommand(const char *command, RegisteredCommand *rc);
/// \internal
/// Goes through str, replacing the delineating character with 0's.
/// \param[in] str The string sent by the transport interface
/// \param[in] delineator The character to scan for to use as a delineator
/// \param[in] delineatorToggle When encountered the delineator replacement is toggled on and off
/// \param[out] numParameters How many pointers were written to \a parameterList
/// \param[out] parameterList An array of pointers to characters. Will hold pointers to locations inside \a str
/// \param[in] parameterListLength How big the \a parameterList array is
static void ParseConsoleString(char *str, const char delineator, unsigned char delineatorToggle, unsigned *numParameters, char **parameterList, unsigned parameterListLength);
/// \internal
/// Goes through the variable commandList and sends the command portion of each struct
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player to write to
virtual void SendCommandList(TransportInterface *transport, SystemAddress systemAddress);
static const unsigned char VARIABLE_NUMBER_OF_PARAMETERS;
protected:
// Currently only takes static strings - doesn't make a copy of what you pass.
// parameterCount is the number of parameters that the sender has to include with the command.
// Pass 255 to parameterCount to indicate variable number of parameters
/// Registers a command.
/// \param[in] parameterCount How many parameters your command requires. If you want to accept a variable number of commands, pass CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS
/// \param[in] command A pointer to a STATIC string that has your command. I keep a copy of the pointer here so don't deallocate the string.
/// \param[in] commandHelp A pointer to a STATIC string that has the help information for your command. I keep a copy of the pointer here so don't deallocate the string.
virtual void RegisterCommand(unsigned char parameterCount, const char *command, const char *commandHelp);
/// Just writes a string to the remote system based on the result ( \a res )of your operation
/// This is not necessary to call, but makes it easier to return results of function calls
/// \param[in] res The result to write
/// \param[in] command The command that this result came from
/// \param[in] transport The transport interface that will be written to
/// \param[in] systemAddress The player this result will be sent to
virtual void ReturnResult(bool res, const char *command, TransportInterface *transport, SystemAddress systemAddress);
virtual void ReturnResult(char *res, const char *command, TransportInterface *transport, SystemAddress systemAddress);
virtual void ReturnResult(SystemAddress res, const char *command, TransportInterface *transport, SystemAddress systemAddress);
virtual void ReturnResult(int res, const char *command,TransportInterface *transport, SystemAddress systemAddress);
/// Just writes a string to the remote system when you are calling a function that has no return value
/// This is not necessary to call, but makes it easier to return results of function calls
/// \param[in] res The result to write
/// \param[in] command The command that this result came from
/// \param[in] transport The transport interface that will be written to
/// \param[in] systemAddress The player this result will be sent to
virtual void ReturnResult(const char *command,TransportInterface *transport, SystemAddress systemAddress);
/// Since there's no way to specify a systemAddress directly, the user needs to specify both the binary address and port.
/// Given those parameters, this returns the corresponding SystemAddress
/// \param[in] binaryAddress The binaryAddress portion of SystemAddress
/// \param[in] port The port portion of SystemAddress
SystemAddress IntegersToSystemAddress(int binaryAddress, int port);
DataStructures::OrderedList<const char*, RegisteredCommand, RegisteredCommandComp> commandList;
};
#endif
+168
View File
@@ -0,0 +1,168 @@
/// \file
/// \brief Connection graph plugin. This maintains a graph of connections for the entire network, so every peer knows about every other peer.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __CONNECTION_GRAPH_H
#define __CONNECTION_GRAPH_H
class RakPeerInterface;
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#include "PluginInterface.h"
#include "DS_List.h"
#include "DS_WeightedGraph.h"
#include "GetTime.h"
#include "Export.h"
// If you need more than 255 groups just change this typedef
typedef unsigned char ConnectionGraphGroupID;
/// \defgroup CONNECTION_GRAPH_GROUP ConnectionGraph
/// \ingroup PLUGINS_GROUP
/// \ingroup CONNECTION_GRAPH_GROUP
/// \brief A connection graph. Each peer will know about all other peers.
class RAK_DLL_EXPORT ConnectionGraph : public PluginInterface
{
public:
ConnectionGraph();
virtual ~ConnectionGraph();
/// A node in the connection graph
struct RAK_DLL_EXPORT SystemAddressAndGroupId
{
SystemAddressAndGroupId();
~SystemAddressAndGroupId();
SystemAddressAndGroupId(SystemAddress _systemAddress, ConnectionGraphGroupID _groupID, RakNetGUID _guid);
SystemAddress systemAddress;
ConnectionGraphGroupID groupId;
RakNetGUID guid;
bool operator==( const SystemAddressAndGroupId& right ) const;
bool operator!=( const SystemAddressAndGroupId& right ) const;
bool operator > ( const SystemAddressAndGroupId& right ) const;
bool operator < ( const SystemAddressAndGroupId& right ) const;
};
// --------------------------------------------------------------------------------------------
// User functions
// --------------------------------------------------------------------------------------------
/// Plaintext encoding of the password, or 0 for none. If you use a password, use secure connections
void SetPassword(const char *password);
/// Returns the connection graph
/// \return The connection graph, stored as map of adjacency lists
DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false> *GetGraph(void);
/// Automatically add new connections to the connection graph
/// Defaults to true
/// If true, then the system will automatically add all new connections for you, assigning groupId 0 to these systems.
/// If you want more control, you should call SetAutoAddNewConnections(false);
/// When false, it is up to you to call RequestConnectionGraph and AddNewConnection to complete the graph
/// However, this way you can choose which nodes are on the graph for this system and can assign groupIds to those nodes
/// \param[in] autoAdd true to automatically add new connections to the connection graph. False to not do so.
void SetAutoAddNewConnections(bool autoAdd);
/// Requests the connection graph from another system
/// Only necessary to call if SetAutoAddNewConnections(false) is called.
/// You should call this sometime after getting ID_CONNECTION_REQUEST_ACCEPTED and \a systemAddress is or should be a node on the connection graph
/// \param[in] peer The instance of RakPeer to send through
/// \param[in] systemAddress The system to send to
void RequestConnectionGraph(RakPeerInterface *peer, SystemAddress systemAddress);
/// Adds a new connection to the connection graph from this system to the specified system. Also assigns a group identifier for that system
/// Only used and valid when SetAutoAddNewConnections(false) is called.
/// Call this for this system sometime after getting ID_NEW_INCOMING_CONNECTION or ID_CONNECTION_REQUEST_ACCEPTED for systems that contain a connection graph
/// Groups are sets of one or more nodes in the total graph
/// We only add to the graph groups which we subscribe to
/// \param[in] peer The instance of RakPeer to send through
/// \param[in] systemAddress The system that is connected to us.
/// \param[in] guid The system that is connected to us.
/// \param[in] groupId Just a number representing a group. Important: 0 is reserved to mean unassigned group ID and is assigned to all systems added with SetAutoAddNewConnections(true)
void AddNewConnection(RakPeerInterface *peer, SystemAddress systemAddress, RakNetGUID guid, ConnectionGraphGroupID groupId);
/// Sets our own group ID
/// Only used and valid when SetAutoAddNewConnections(false) is called.
/// Defaults to 0
/// \param[in] groupId Our group ID
void SetGroupId(ConnectionGraphGroupID groupId);
/// Allows adding to the connection graph nodes with this groupId.
/// By default, you subscribe to group 0, which are all systems automatically added with SetAutoAddNewConnections(true)
/// Calling this does not add nodes which were previously rejected due to an unsubscribed group - it only allows addition of nodes after the fact
/// \param[in] groupId Just a number representing a group. 0 is reserved to mean unassigned group ID, automatically added with SetAutoAddNewConnections(true)
void SubscribeToGroup(ConnectionGraphGroupID groupId);
/// Disables addition of graph nodes with this groupId
/// Calling this does not add remove nodes with this groupId which are already present in the graph. It only disables addition of nodes after the fact
/// \param[in] groupId Just a number representing a group. 0 is reserved to mean unassigned group ID, automatically added with SetAutoAddNewConnections(true)
void UnsubscribeFromGroup(ConnectionGraphGroupID groupId);
// --------------------------------------------------------------------------------------------
// Packet handling functions
// --------------------------------------------------------------------------------------------
/// \internal
virtual void OnShutdown(RakPeerInterface *peer);
/// \internal
virtual void Update(RakPeerInterface *peer);
/// \internal
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// \internal
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
protected:
void HandleDroppedConnection(RakPeerInterface *peer, SystemAddress systemAddress, unsigned char packetId);
void DeleteFromPeerList(SystemAddress systemAddress);
void OnNewIncomingConnection(RakPeerInterface *peer, Packet *packet);
void OnConnectionRequestAccepted(RakPeerInterface *peer, Packet *packet);
void OnConnectionGraphRequest(RakPeerInterface *peer, Packet *packet);
void OnConnectionGraphReply(RakPeerInterface *peer, Packet *packet);
void OnConnectionGraphUpdate(RakPeerInterface *peer, Packet *packet);
void OnNewConnection(RakPeerInterface *peer, Packet *packet);
bool OnConnectionLost(RakPeerInterface *peer, Packet *packet, unsigned char packetId);
void OnConnectionAddition(RakPeerInterface *peer, Packet *packet);
void OnConnectionRemoval(RakPeerInterface *peer, Packet *packet);
void SendConnectionGraph(SystemAddress target, unsigned char packetId, RakPeerInterface *peer);
void SerializeWeightedGraph(RakNet::BitStream *out, const DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false> &g) const;
bool DeserializeWeightedGraph(RakNet::BitStream *inBitstream, RakPeerInterface *peer);
void AddAndRelayConnection(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, const SystemAddressAndGroupId &conn1, const SystemAddressAndGroupId &conn2, unsigned short ping, RakPeerInterface *peer);
bool RemoveAndRelayConnection(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, unsigned char packetId, const SystemAddress node1, const SystemAddress node2, RakPeerInterface *peer);
void RemoveParticipant(SystemAddress systemAddress);
void AddParticipant(SystemAddress systemAddress);
void BroadcastGraphUpdate(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, RakPeerInterface *peer);
void NotifyUserOfRemoteConnection(const SystemAddressAndGroupId &conn1, const SystemAddressAndGroupId &conn2,unsigned short ping, RakPeerInterface *peer);
bool IsNewRemoteConnection(const SystemAddressAndGroupId &conn1, const SystemAddressAndGroupId &conn2,RakPeerInterface *peer);
bool DeserializeIgnoreList(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, RakNet::BitStream *inBitstream );
void SerializeIgnoreListAndBroadcast(RakNet::BitStream *outBitstream, DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, RakPeerInterface *peer);
RakNetTime nextWeightUpdate;
char *pw;
DataStructures::OrderedList<SystemAddress, SystemAddress> participantList;
DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false> graph;
bool autoAddNewConnections;
ConnectionGraphGroupID myGroupId;
DataStructures::OrderedList<ConnectionGraphGroupID, ConnectionGraphGroupID> subscribedGroups;
// Used to broadcast new connections after some time so the pings are correct
//RakNetTime forceBroadcastTime;
};
#endif
+63
View File
@@ -0,0 +1,63 @@
/// \file
/// \brief Contains ConsoleServer , used to plugin to your game to accept remote console-based connections
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __CONSOLE_SERVER_H
#define __CONSOLE_SERVER_H
class TransportInterface;
class CommandParserInterface;
#include "RakMemoryOverride.h"
#include "DS_List.h"
#include "RakNetTypes.h"
#include "Export.h"
/// \brief The main entry point for the server portion of your remote console application support.
/// ConsoleServer takes one TransportInterface and one or more CommandParserInterface (s)
/// The TransportInterface will be used to send data between the server and the client. The connecting client must support the
/// protocol used by your derivation of TransportInterface . TelnetTransport and RakNetTransport are two such derivations .
/// When a command is sent by a remote console, it will be processed by your implementations of CommandParserInterface
class RAK_DLL_EXPORT ConsoleServer
{
public:
ConsoleServer();
~ConsoleServer();
/// Call this with a derivation of TransportInterface so that the console server can send and receive commands
/// \param[in] transportInterface Your interface to use.
/// \param[in] port The port to host on. Telnet uses port 23 by default. RakNet can use whatever you want.
void SetTransportProvider(TransportInterface *transportInterface, unsigned short port);
/// Add an implementation of CommandParserInterface to the list of command parsers.
/// \param[in] commandParserInterface The command parser referred to
void AddCommandParser(CommandParserInterface *commandParserInterface);
/// Remove an implementation of CommandParserInterface previously added with AddCommandParser()
/// \param[in] commandParserInterface The command parser referred to
void RemoveCommandParser(CommandParserInterface *commandParserInterface);
/// Call update to read packet sent from your TransportInterface.
/// You should do this fairly frequently.
void Update(void);
protected:
void ListParsers(SystemAddress systemAddress);
TransportInterface *transport;
DataStructures::List<CommandParserInterface *> commandParserList;
char* password[256];
};
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+40
View File
@@ -0,0 +1,40 @@
#ifndef __BYTE_POOL_H
#define __BYTE_POOL_H
#include "RakMemoryOverride.h"
#include "DS_MemoryPool.h"
#include "Export.h"
#include "SimpleMutex.h"
#include "RakAssert.h"
// #define _DISABLE_BYTE_POOL
// #define _THREADSAFE_BYTE_POOL
namespace DataStructures
{
// Allocate some number of bytes from pools. Uses the heap if necessary.
class RAK_DLL_EXPORT BytePool
{
public:
BytePool();
~BytePool();
// Should be at least 8 times bigger than 8192
void SetPageSize(int size);
unsigned char* Allocate(int bytesWanted);
void Release(unsigned char *data);
void Clear(void);
protected:
MemoryPool<unsigned char[128]> pool128;
MemoryPool<unsigned char[512]> pool512;
MemoryPool<unsigned char[2048]> pool2048;
MemoryPool<unsigned char[8192]> pool8192;
#ifdef _THREADSAFE_BYTE_POOL
SimpleMutex mutex128;
SimpleMutex mutex512;
SimpleMutex mutex2048;
SimpleMutex mutex8192;
#endif
};
}
#endif
+46
View File
@@ -0,0 +1,46 @@
/// \file
/// \brief \b [Internal] Byte queue
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __BYTE_QUEUE_H
#define __BYTE_QUEUE_H
#include "RakMemoryOverride.h"
#include "Export.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
class ByteQueue
{
public:
ByteQueue();
~ByteQueue();
void WriteBytes(const char *in, unsigned length);
bool ReadBytes(char *out, unsigned length, bool peek);
unsigned GetBytesWritten(void) const;
void IncrementReadOffset(unsigned length);
void Clear(void);
void Print(void);
protected:
char *data;
unsigned readOffset, writeOffset, lengthAllocated;
};
}
#endif
+251
View File
@@ -0,0 +1,251 @@
/// \file
/// \brief \b [Internal] Heap (Also serves as a priority queue)
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAKNET_HEAP_H
#define __RAKNET_HEAP_H
#include "RakMemoryOverride.h"
#include "DS_List.h"
#include "Export.h"
#include "RakAssert.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
template <class weight_type, class data_type, bool isMaxHeap>
class RAK_DLL_EXPORT Heap
{
public:
struct HeapNode
{
HeapNode() {}
HeapNode(const weight_type &w, const data_type &d) : weight(w), data(d) {}
weight_type weight; // I'm assuming key is a native numerical type - float or int
data_type data;
};
Heap();
~Heap();
void Push(const weight_type &weight, const data_type &data);
data_type Pop(const unsigned startingIndex);
data_type Peek(const unsigned startingIndex=0) const;
weight_type PeekWeight(const unsigned startingIndex=0) const;
void Clear(void);
data_type& operator[] ( const unsigned int position ) const;
unsigned Size(void) const;
protected:
unsigned LeftChild(const unsigned i) const;
unsigned RightChild(const unsigned i) const;
unsigned Parent(const unsigned i) const;
void Swap(const unsigned i, const unsigned j);
DataStructures::List<HeapNode> heap;
};
template <class weight_type, class data_type, bool isMaxHeap>
Heap<weight_type, data_type, isMaxHeap>::Heap()
{
}
template <class weight_type, class data_type, bool isMaxHeap>
Heap<weight_type, data_type, isMaxHeap>::~Heap()
{
Clear();
}
template <class weight_type, class data_type, bool isMaxHeap>
void Heap<weight_type, data_type, isMaxHeap>::Push(const weight_type &weight, const data_type &data)
{
unsigned currentIndex = heap.Size();
unsigned parentIndex;
heap.Insert(HeapNode(weight, data));
while (currentIndex!=0)
{
parentIndex = Parent(currentIndex);
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
if (isMaxHeap)
{
if (heap[parentIndex].weight < weight)
{
Swap(currentIndex, parentIndex);
currentIndex=parentIndex;
}
else
break;
}
else
{
if (heap[parentIndex].weight > weight)
{
Swap(currentIndex, parentIndex);
currentIndex=parentIndex;
}
else
break;
}
}
}
template <class weight_type, class data_type, bool isMaxHeap>
data_type Heap<weight_type, data_type, isMaxHeap>::Pop(const unsigned startingIndex)
{
// While we have children, swap out with the larger of the two children.
// This line will assert on an empty heap
data_type returnValue=heap[startingIndex].data;
// Move the last element to the head, and re-heapify
heap[startingIndex]=heap[heap.Size()-1];
unsigned currentIndex,leftChild,rightChild;
weight_type currentWeight;
currentIndex=startingIndex;
currentWeight=heap[startingIndex].weight;
heap.RemoveFromEnd();
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while (1)
{
leftChild=LeftChild(currentIndex);
rightChild=RightChild(currentIndex);
if (leftChild >= heap.Size())
{
// Done
return returnValue;
}
if (rightChild >= heap.Size())
{
// Only left node.
if ((isMaxHeap==true && currentWeight < heap[leftChild].weight) ||
(isMaxHeap==false && currentWeight > heap[leftChild].weight))
Swap(leftChild, currentIndex);
return returnValue;
}
else
{
// Swap with the bigger/smaller of the two children and continue
if (isMaxHeap)
{
if (heap[leftChild].weight <= currentWeight && heap[rightChild].weight <= currentWeight)
return returnValue;
if (heap[leftChild].weight > heap[rightChild].weight)
{
Swap(leftChild, currentIndex);
currentIndex=leftChild;
}
else
{
Swap(rightChild, currentIndex);
currentIndex=rightChild;
}
}
else
{
if (heap[leftChild].weight >= currentWeight && heap[rightChild].weight >= currentWeight)
return returnValue;
if (heap[leftChild].weight < heap[rightChild].weight)
{
Swap(leftChild, currentIndex);
currentIndex=leftChild;
}
else
{
Swap(rightChild, currentIndex);
currentIndex=rightChild;
}
}
}
}
}
template <class weight_type, class data_type, bool isMaxHeap>
data_type Heap<weight_type, data_type, isMaxHeap>::Peek(const unsigned startingIndex) const
{
return heap[startingIndex].data;
}
template <class weight_type, class data_type, bool isMaxHeap>
weight_type Heap<weight_type, data_type, isMaxHeap>::PeekWeight(const unsigned startingIndex) const
{
return heap[startingIndex].weight;
}
template <class weight_type, class data_type, bool isMaxHeap>
void Heap<weight_type, data_type, isMaxHeap>::Clear(void)
{
heap.Clear();
}
template <class weight_type, class data_type, bool isMaxHeap>
data_type& Heap<weight_type, data_type, isMaxHeap>::operator[] ( const unsigned int position ) const
{
return heap[position].data;
}
template <class weight_type, class data_type, bool isMaxHeap>
unsigned Heap<weight_type, data_type, isMaxHeap>::Size(void) const
{
return heap.Size();
}
template <class weight_type, class data_type, bool isMaxHeap>
unsigned Heap<weight_type, data_type, isMaxHeap>::LeftChild(const unsigned i) const
{
return i*2+1;
}
template <class weight_type, class data_type, bool isMaxHeap>
unsigned Heap<weight_type, data_type, isMaxHeap>::RightChild(const unsigned i) const
{
return i*2+2;
}
template <class weight_type, class data_type, bool isMaxHeap>
unsigned Heap<weight_type, data_type, isMaxHeap>::Parent(const unsigned i) const
{
#ifdef _DEBUG
RakAssert(i!=0);
#endif
return (i-1)/2;
}
template <class weight_type, class data_type, bool isMaxHeap>
void Heap<weight_type, data_type, isMaxHeap>::Swap(const unsigned i, const unsigned j)
{
HeapNode temp;
temp=heap[i];
heap[i]=heap[j];
heap[j]=temp;
}
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif
@@ -0,0 +1,71 @@
/// \file
/// \brief \b [Internal] Generates a huffman encoding tree, used for string and global compression.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __HUFFMAN_ENCODING_TREE
#define __HUFFMAN_ENCODING_TREE
#include "RakMemoryOverride.h"
#include "DS_HuffmanEncodingTreeNode.h"
#include "BitStream.h"
#include "Export.h"
#include "DS_LinkedList.h"
/// This generates special cases of the huffman encoding tree using 8 bit keys with the additional condition that unused combinations of 8 bits are treated as a frequency of 1
class RAK_DLL_EXPORT HuffmanEncodingTree
{
public:
HuffmanEncodingTree();
~HuffmanEncodingTree();
/// Pass an array of bytes to array and a preallocated BitStream to receive the output
/// \param [in] input Array of bytes to encode
/// \param [in] sizeInBytes size of \a input
/// \param [out] output The bitstream to write to
void EncodeArray( unsigned char *input, size_t sizeInBytes, RakNet::BitStream * output );
// Decodes an array encoded by EncodeArray()
unsigned DecodeArray( RakNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output );
void DecodeArray( unsigned char *input, BitSize_t sizeInBits, RakNet::BitStream * output );
/// Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree
void GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] );
/// Free the memory used by the tree
void FreeMemory( void );
private:
/// The root node of the tree
HuffmanEncodingTreeNode *root;
/// Used to hold bit encoding for one character
struct CharacterEncoding
{
unsigned char* encoding;
unsigned short bitLength;
};
CharacterEncoding encodingTable[ 256 ];
void InsertNodeIntoSortedList( HuffmanEncodingTreeNode * node, DataStructures::LinkedList<HuffmanEncodingTreeNode *> *huffmanEncodingTreeNodeList ) const;
};
#endif
@@ -0,0 +1,61 @@
/// \file
/// \brief \b [Internal] Creates instances of the class HuffmanEncodingTree
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __HUFFMAN_ENCODING_TREE_FACTORY
#define __HUFFMAN_ENCODING_TREE_FACTORY
#include "RakMemoryOverride.h"
class HuffmanEncodingTree;
/// \brief Creates instances of the class HuffmanEncodingTree
///
/// This class takes a frequency table and given that frequence table, will generate an instance of HuffmanEncodingTree
class HuffmanEncodingTreeFactory
{
public:
/// Default constructor
HuffmanEncodingTreeFactory();
/// Reset the frequency table. You don't need to call this unless you want to reuse the class for a new tree
void Reset( void );
/// Pass an array of bytes to this to add those elements to the frequency table
/// \param[in] array the data to insert into the frequency table
/// \param[in] size the size of the data to insert
void AddToFrequencyTable( unsigned char *array, int size );
/// Copies the frequency table to the array passed
/// Retrieve the frequency table
/// \param[in] _frequency The frequency table used currently
void GetFrequencyTable( unsigned int _frequency[ 256 ] );
/// Returns the frequency table as a pointer
/// \return the address of the frenquency table
unsigned int * GetFrequencyTable( void );
/// Generate a HuffmanEncodingTree.
/// You can also use GetFrequencyTable and GenerateFromFrequencyTable in the tree itself
/// \return The generated instance of HuffmanEncodingTree
HuffmanEncodingTree * GenerateTree( void );
private:
/// Frequency table
unsigned int frequency[ 256 ];
};
#endif
@@ -0,0 +1,30 @@
/// \file
/// \brief \b [Internal] A single node in the Huffman Encoding Tree.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __HUFFMAN_ENCODING_TREE_NODE
#define __HUFFMAN_ENCODING_TREE_NODE
struct HuffmanEncodingTreeNode
{
unsigned char value;
unsigned weight;
HuffmanEncodingTreeNode *left;
HuffmanEncodingTreeNode *right;
HuffmanEncodingTreeNode *parent;
};
#endif
File diff suppressed because it is too large Load Diff
+525
View File
@@ -0,0 +1,525 @@
/// \file
/// \brief \b [Internal] Array based list. Usually the Queue class is used instead, since it has all the same functionality and is only worse at random access.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __LIST_H
#define __LIST_H
#include "RakAssert.h"
#include <string.h> // memmove
#include "Export.h"
#include "RakMemoryOverride.h"
/// Maximum unsigned long
static const unsigned int MAX_UNSIGNED_LONG = 4294967295U;
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
/// \brief Array based implementation of a list.
/// \note ONLY USE THIS FOR SHALLOW COPIES. I don't bother with operator= to improve performance.
template <class list_type>
class RAK_DLL_EXPORT List
{
public:
/// Default constructor
List();
/// Destructor
~List();
/// Copy constructor
/// \param[in] original_copy The list to duplicate
List( const List& original_copy );
/// Assign one list to another
List& operator= ( const List& original_copy );
/// Access an element by its index in the array
/// \param[in] position The index into the array.
/// \return The element at position \a position.
list_type& operator[] ( const unsigned int position ) const;
/// Access an element by its index in the array
/// \param[in] position The index into the array.
/// \return The element at position \a position.
list_type& Get ( const unsigned int position ) const;
/// Push an element at the end of the stack
/// \param[in] input The new element.
void Push(const list_type input);
/// Pop an element from the end of the stack
/// \pre Size()>0
/// \return The element at the end.
list_type& Pop(void);
/// Insert an element at position \a position in the list
/// \param[in] input The new element.
/// \param[in] position The position of the new element.
void Insert( const list_type input, const unsigned int position );
/// Insert at the end of the list.
/// \param[in] input The new element.
void Insert( const list_type input );
/// Replace the value at \a position by \a input. If the size of
/// the list is less than @em position, it increase the capacity of
/// the list and fill slot with @em filler.
/// \param[in] input The element to replace at position @em position.
/// \param[in] filler The element use to fill new allocated capacity.
/// \param[in] position The position of input in the list.
void Replace( const list_type input, const list_type filler, const unsigned int position );
/// Replace the last element of the list by \a input .
/// \param[in] input The element used to replace the last element.
void Replace( const list_type input );
/// Delete the element at position \a position.
/// \param[in] position The index of the element to delete
void RemoveAtIndex( const unsigned int position );
/// Delete the element at position \a position.
/// \note - swaps middle with end of list, only use if list order does not matter
/// \param[in] position The index of the element to delete
void RemoveAtIndexFast( const unsigned int position );
/// Delete the element at the end of the list
void RemoveFromEnd(const unsigned num=1);
/// Returns the index of the specified item or MAX_UNSIGNED_LONG if not found
/// \param[in] input The element to check for
/// \return The index or position of @em input in the list.
/// \retval MAX_UNSIGNED_LONG The object is not in the list
/// \retval [Integer] The index of the element in the list
unsigned int GetIndexOf( const list_type input ) const;
/// \return The number of elements in the list
unsigned int Size( void ) const;
/// Clear the list
void Clear( bool doNotDeallocateSmallBlocks=false );
// Preallocate the list, so it needs fewer reallocations at runtime
void Preallocate( unsigned countNeeded );
/// Frees overallocated members, to use the minimum memory necessary
/// \attention
/// This is a slow operation
void Compress( void );
private:
/// An array of user values
list_type* listArray;
/// Number of elements in the list
unsigned int list_size;
/// Size of \a array
unsigned int allocation_size;
};
template <class list_type>
List<list_type>::List()
{
allocation_size = 0;
listArray = 0;
list_size = 0;
}
template <class list_type>
List<list_type>::~List()
{
if (allocation_size>0)
RakNet::OP_DELETE_ARRAY(listArray);
}
template <class list_type>
List<list_type>::List( const List& original_copy )
{
// Allocate memory for copy
if ( original_copy.list_size == 0 )
{
list_size = 0;
allocation_size = 0;
}
else
{
listArray = RakNet::OP_NEW_ARRAY<list_type >( original_copy.list_size );
for ( unsigned int counter = 0; counter < original_copy.list_size; ++counter )
listArray[ counter ] = original_copy.listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(listArray, original_copy.listArray, original_copy.list_size*sizeof(list_type));
list_size = allocation_size = original_copy.list_size;
}
}
template <class list_type>
List<list_type>& List<list_type>::operator= ( const List& original_copy )
{
if ( ( &original_copy ) != this )
{
Clear();
// Allocate memory for copy
if ( original_copy.list_size == 0 )
{
list_size = 0;
allocation_size = 0;
}
else
{
listArray = RakNet::OP_NEW_ARRAY<list_type >( original_copy.list_size );
for ( unsigned int counter = 0; counter < original_copy.list_size; ++counter )
listArray[ counter ] = original_copy.listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(listArray, original_copy.listArray, original_copy.list_size*sizeof(list_type));
list_size = allocation_size = original_copy.list_size;
}
}
return *this;
}
template <class list_type>
inline list_type& List<list_type>::operator[] ( const unsigned int position ) const
{
#ifdef _DEBUG
if (position>=list_size)
{
RakAssert ( position < list_size );
}
#endif
return listArray[ position ];
}
// Just here for debugging
template <class list_type>
inline list_type& List<list_type>::Get ( const unsigned int position ) const
{
return listArray[ position ];
}
template <class list_type>
void List<list_type>::Push(const list_type input)
{
Insert(input);
}
template <class list_type>
inline list_type& List<list_type>::Pop(void)
{
#ifdef _DEBUG
RakAssert(list_size>0);
#endif
--list_size;
return listArray[list_size];
}
template <class list_type>
void List<list_type>::Insert( const list_type input, const unsigned int position )
{
#ifdef _DEBUG
if (position>list_size)
{
RakAssert( position <= list_size );
}
#endif
// Reallocate list if necessary
if ( list_size == allocation_size )
{
// allocate twice the currently allocated memory
list_type * new_array;
if ( allocation_size == 0 )
allocation_size = 16;
else
allocation_size *= 2;
new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size );
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated and twice as large array
RakNet::OP_DELETE_ARRAY(listArray);
listArray = new_array;
}
// Move the elements in the list to make room
for ( unsigned int counter = list_size; counter != position; counter-- )
listArray[ counter ] = listArray[ counter - 1 ];
// Don't call constructors, assignment operators, etc.
//memmove(listArray+position+1, listArray+position, (list_size-position)*sizeof(list_type));
// Insert the new item at the correct spot
listArray[ position ] = input;
++list_size;
}
template <class list_type>
void List<list_type>::Insert( const list_type input )
{
// Reallocate list if necessary
if ( list_size == allocation_size )
{
// allocate twice the currently allocated memory
list_type * new_array;
if ( allocation_size == 0 )
allocation_size = 16;
else
allocation_size *= 2;
new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size );
if (listArray)
{
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated and twice as large array
RakNet::OP_DELETE_ARRAY(listArray);
}
listArray = new_array;
}
// Insert the new item at the correct spot
listArray[ list_size ] = input;
++list_size;
}
template <class list_type>
inline void List<list_type>::Replace( const list_type input, const list_type filler, const unsigned int position )
{
if ( ( list_size > 0 ) && ( position < list_size ) )
{
// Direct replacement
listArray[ position ] = input;
}
else
{
if ( position >= allocation_size )
{
// Reallocate the list to size position and fill in blanks with filler
list_type * new_array;
allocation_size = position + 1;
new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size );
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated array
RakNet::OP_DELETE_ARRAY(listArray);
listArray = new_array;
}
// Fill in holes with filler
while ( list_size < position )
listArray[ list_size++ ] = filler;
// Fill in the last element with the new item
listArray[ list_size++ ] = input;
#ifdef _DEBUG
RakAssert( list_size == position + 1 );
#endif
}
}
template <class list_type>
inline void List<list_type>::Replace( const list_type input )
{
if ( list_size > 0 )
listArray[ list_size - 1 ] = input;
}
template <class list_type>
void List<list_type>::RemoveAtIndex( const unsigned int position )
{
#ifdef _DEBUG
if (position >= list_size)
{
RakAssert( position < list_size );
return;
}
#endif
if ( position < list_size )
{
// Compress the array
for ( unsigned int counter = position; counter < list_size - 1 ; ++counter )
listArray[ counter ] = listArray[ counter + 1 ];
// Don't call constructors, assignment operators, etc.
// memmove(listArray+position, listArray+position+1, (list_size-1-position) * sizeof(list_type));
RemoveFromEnd();
}
}
template <class list_type>
void List<list_type>::RemoveAtIndexFast( const unsigned int position )
{
#ifdef _DEBUG
if (position >= list_size)
{
RakAssert( position < list_size );
return;
}
#endif
--list_size;
listArray[position]=listArray[list_size];
}
template <class list_type>
inline void List<list_type>::RemoveFromEnd( const unsigned num )
{
// Delete the last elements on the list. No compression needed
#ifdef _DEBUG
RakAssert(list_size>=num);
#endif
list_size-=num;
}
template <class list_type>
unsigned int List<list_type>::GetIndexOf( const list_type input ) const
{
for ( unsigned int i = 0; i < list_size; ++i )
if ( listArray[ i ] == input )
return i;
return MAX_UNSIGNED_LONG;
}
template <class list_type>
inline unsigned int List<list_type>::Size( void ) const
{
return list_size;
}
template <class list_type>
void List<list_type>::Clear( bool doNotDeallocateSmallBlocks )
{
if ( allocation_size == 0 )
return;
if (allocation_size>512 || doNotDeallocateSmallBlocks==false)
{
RakNet::OP_DELETE_ARRAY(listArray);
allocation_size = 0;
listArray = 0;
}
list_size = 0;
}
template <class list_type>
void List<list_type>::Compress( void )
{
list_type * new_array;
if ( allocation_size == 0 )
return ;
new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size );
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated array
RakNet::OP_DELETE_ARRAY(listArray);
listArray = new_array;
}
template <class list_type>
void List<list_type>::Preallocate( unsigned countNeeded )
{
unsigned amountToAllocate = allocation_size;
if (allocation_size==0)
amountToAllocate=16;
while (amountToAllocate < countNeeded)
amountToAllocate<<=1;
if ( allocation_size < amountToAllocate)
{
// allocate twice the currently allocated memory
list_type * new_array;
allocation_size=amountToAllocate;
new_array = RakNet::OP_NEW_ARRAY< list_type >( allocation_size );
if (listArray)
{
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated and twice as large array
RakNet::OP_DELETE_ARRAY(listArray);
}
listArray = new_array;
}
}
} // End namespace
#endif
+330
View File
@@ -0,0 +1,330 @@
/// \file
/// \brief \b [Internal] Map
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAKNET_MAP_H
#define __RAKNET_MAP_H
#include "DS_OrderedList.h"
#include "Export.h"
#include "RakMemoryOverride.h"
#include "RakAssert.h"
// If I want to change this to a red-black tree, this is a good site: http://www.cs.auckland.ac.nz/software/AlgAnim/red_black.html
// This makes insertions and deletions faster. But then traversals are slow, while they are currently fast.
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
/// The default comparison has to be first so it can be called as a default parameter.
/// It then is followed by MapNode, followed by NodeComparisonFunc
template <class key_type>
int defaultMapKeyComparison(const key_type &a, const key_type &b)
{
if (a<b) return -1; if (a==b) return 0; return 1;
}
/// \note IMPORTANT! If you use defaultMapKeyComparison then call IMPLEMENT_DEFAULT_COMPARISON or you will get an unresolved external linker error.
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&, const key_type&)=defaultMapKeyComparison<key_type> >
class RAK_DLL_EXPORT Map
{
public:
static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultMapKeyComparison<key_type>(key_type(),key_type());}
struct MapNode
{
MapNode() {}
MapNode(key_type _key, data_type _data) : mapNodeKey(_key), mapNodeData(_data) {}
MapNode& operator = ( const MapNode& input ) {mapNodeKey=input.mapNodeKey; mapNodeData=input.mapNodeData; return *this;}
MapNode( const MapNode & input) {mapNodeKey=input.mapNodeKey; mapNodeData=input.mapNodeData;}
key_type mapNodeKey;
data_type mapNodeData;
};
// Has to be a static because the comparison callback for DataStructures::OrderedList is a C function
static int NodeComparisonFunc(const key_type &a, const MapNode &b)
{
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
return key_comparison_func(a, b.mapNodeKey);
}
Map();
~Map();
Map( const Map& original_copy );
Map& operator= ( const Map& original_copy );
data_type& Get(const key_type &key) const;
data_type Pop(const key_type &key);
// Add if needed
void Set(const key_type &key, const data_type &data);
// Must already exist
void SetExisting(const key_type &key, const data_type &data);
// Must add
void SetNew(const key_type &key, const data_type &data);
bool Has(const key_type &key) const;
bool Delete(const key_type &key);
data_type& operator[] ( const unsigned int position ) const;
key_type GetKeyAtIndex( const unsigned int position ) const;
unsigned GetIndexAtKey( const key_type &key );
void RemoveAtIndex(const unsigned index);
void Clear(void);
unsigned Size(void) const;
protected:
DataStructures::OrderedList< key_type,MapNode,Map::NodeComparisonFunc > mapNodeList;
void SaveLastSearch(const key_type &key, unsigned index) const;
bool HasSavedSearchResult(const key_type &key) const;
unsigned lastSearchIndex;
key_type lastSearchKey;
bool lastSearchIndexValid;
};
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
Map<key_type, data_type, key_comparison_func>::Map()
{
lastSearchIndexValid=false;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
Map<key_type, data_type, key_comparison_func>::~Map()
{
Clear();
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
Map<key_type, data_type, key_comparison_func>::Map( const Map& original_copy )
{
mapNodeList=original_copy.mapNodeList;
lastSearchIndex=original_copy.lastSearchIndex;
lastSearchKey=original_copy.lastSearchKey;
lastSearchIndexValid=original_copy.lastSearchIndexValid;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
Map<key_type, data_type, key_comparison_func>& Map<key_type, data_type, key_comparison_func>::operator= ( const Map& original_copy )
{
mapNodeList=original_copy.mapNodeList;
lastSearchIndex=original_copy.lastSearchIndex;
lastSearchKey=original_copy.lastSearchKey;
lastSearchIndexValid=original_copy.lastSearchIndexValid;
return *this;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
data_type& Map<key_type, data_type, key_comparison_func>::Get(const key_type &key) const
{
if (HasSavedSearchResult(key))
return mapNodeList[lastSearchIndex].mapNodeData;
bool objectExists;
unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists);
RakAssert(objectExists);
SaveLastSearch(key,index);
return mapNodeList[index].mapNodeData;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
unsigned Map<key_type, data_type, key_comparison_func>::GetIndexAtKey( const key_type &key )
{
if (HasSavedSearchResult(key))
return lastSearchIndex;
bool objectExists;
unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists==false)
{
RakAssert(objectExists);
}
SaveLastSearch(key,index);
return index;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::RemoveAtIndex(const unsigned index)
{
mapNodeList.RemoveAtIndex(index);
lastSearchIndexValid=false;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
data_type Map<key_type, data_type, key_comparison_func>::Pop(const key_type &key)
{
bool objectExists;
unsigned index;
if (HasSavedSearchResult(key))
index=lastSearchIndex;
else
{
index=mapNodeList.GetIndexFromKey(key, &objectExists);
RakAssert(objectExists);
}
data_type tmp = mapNodeList[index].mapNodeData;
mapNodeList.RemoveAtIndex(index);
lastSearchIndexValid=false;
return tmp;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::Set(const key_type &key, const data_type &data)
{
bool objectExists;
unsigned index;
if (HasSavedSearchResult(key))
{
mapNodeList[lastSearchIndex].mapNodeData=data;
return;
}
index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists)
{
SaveLastSearch(key,index);
mapNodeList[index].mapNodeData=data;
}
else
{
SaveLastSearch(key,mapNodeList.Insert(key,MapNode(key,data), true));
}
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::SetExisting(const key_type &key, const data_type &data)
{
bool objectExists;
unsigned index;
if (HasSavedSearchResult(key))
{
index=lastSearchIndex;
}
else
{
index=mapNodeList.GetIndexFromKey(key, &objectExists);
RakAssert(objectExists);
SaveLastSearch(key,index);
}
mapNodeList[index].mapNodeData=data;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::SetNew(const key_type &key, const data_type &data)
{
#ifdef _DEBUG
unsigned index;
bool objectExists;
index=mapNodeList.GetIndexFromKey(key, &objectExists);
RakAssert(objectExists==false);
#endif
SaveLastSearch(key,mapNodeList.Insert(key,MapNode(key,data), true));
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
bool Map<key_type, data_type, key_comparison_func>::Has(const key_type &key) const
{
if (HasSavedSearchResult(key))
return true;
bool objectExists;
unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists)
SaveLastSearch(key,index);
return objectExists;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
bool Map<key_type, data_type, key_comparison_func>::Delete(const key_type &key)
{
if (HasSavedSearchResult(key))
{
lastSearchIndexValid=false;
mapNodeList.RemoveAtIndex(lastSearchIndex);
return true;
}
bool objectExists;
unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists)
{
lastSearchIndexValid=false;
mapNodeList.RemoveAtIndex(index);
return true;
}
else
return false;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::Clear(void)
{
lastSearchIndexValid=false;
mapNodeList.Clear();
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
data_type& Map<key_type, data_type, key_comparison_func>::operator[]( const unsigned int position ) const
{
return mapNodeList[position].mapNodeData;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
key_type Map<key_type, data_type, key_comparison_func>::GetKeyAtIndex( const unsigned int position ) const
{
return mapNodeList[position].mapNodeKey;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
unsigned Map<key_type, data_type, key_comparison_func>::Size(void) const
{
return mapNodeList.Size();
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::SaveLastSearch(const key_type &key, const unsigned index) const
{
(void) key;
(void) index;
/*
lastSearchIndex=index;
lastSearchKey=key;
lastSearchIndexValid=true;
*/
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
bool Map<key_type, data_type, key_comparison_func>::HasSavedSearchResult(const key_type &key) const
{
(void) key;
// Not threadsafe!
return false;
// return lastSearchIndexValid && key_comparison_func(key,lastSearchKey)==0;
}
}
#endif
+285
View File
@@ -0,0 +1,285 @@
#ifndef __MEMORY_POOL_H
#define __MEMORY_POOL_H
#ifndef __APPLE__
// Use stdlib and not malloc for compatibility
#include <stdlib.h>
#endif
#include "RakAssert.h"
#include "Export.h"
#include "RakMemoryOverride.h"
// DS_MEMORY_POOL_MAX_FREE_PAGES must be > 1
#define DS_MEMORY_POOL_MAX_FREE_PAGES 4
// #define _DISABLE_MEMORY_POOL
namespace DataStructures
{
/// Very fast memory pool for allocating and deallocating structures that don't have constructors or destructors.
/// Contains a list of pages, each of which has an array of the user structures
template <class MemoryBlockType>
class RAK_DLL_EXPORT MemoryPool
{
public:
struct Page;
struct MemoryWithPage
{
MemoryBlockType userMemory;
Page *parentPage;
};
struct Page
{
MemoryWithPage** availableStack;
int availableStackSize;
MemoryWithPage* block;
Page *next, *prev;
};
MemoryPool();
~MemoryPool();
void SetPageSize(int size); // Defaults to 16384
MemoryBlockType *Allocate(void);
void Release(MemoryBlockType *m);
void Clear(void);
int GetAvailablePagesSize(void) const {return availablePagesSize;}
int GetUnavailablePagesSize(void) const {return unavailablePagesSize;}
int GetMemoryPoolPageSize(void) const {return memoryPoolPageSize;}
protected:
int BlocksPerPage(void) const;
void AllocateFirst(void);
bool InitPage(Page *page, Page *prev);
// availablePages contains pages which have room to give the user new blocks. We return these blocks from the head of the list
// unavailablePages are pages which are totally full, and from which we do not return new blocks.
// Pages move from the head of unavailablePages to the tail of availablePages, and from the head of availablePages to the tail of unavailablePages
Page *availablePages, *unavailablePages;
int availablePagesSize, unavailablePagesSize;
int memoryPoolPageSize;
};
template<class MemoryBlockType>
MemoryPool<MemoryBlockType>::MemoryPool()
{
#ifndef _DISABLE_MEMORY_POOL
//AllocateFirst();
availablePagesSize=0;
unavailablePagesSize=0;
memoryPoolPageSize=16384;
#endif
}
template<class MemoryBlockType>
MemoryPool<MemoryBlockType>::~MemoryPool()
{
#ifndef _DISABLE_MEMORY_POOL
Clear();
#endif
}
template<class MemoryBlockType>
void MemoryPool<MemoryBlockType>::SetPageSize(int size)
{
memoryPoolPageSize=size;
}
template<class MemoryBlockType>
MemoryBlockType* MemoryPool<MemoryBlockType>::Allocate(void)
{
#ifdef _DISABLE_MEMORY_POOL
return new MemoryBlockType;
#endif
if (availablePagesSize>0)
{
MemoryBlockType *retVal;
Page *curPage;
curPage=availablePages;
retVal = (MemoryBlockType*) curPage->availableStack[--(curPage->availableStackSize)];
if (curPage->availableStackSize==0)
{
--availablePagesSize;
availablePages=curPage->next;
RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0);
curPage->next->prev=curPage->prev;
curPage->prev->next=curPage->next;
if (unavailablePagesSize++==0)
{
unavailablePages=curPage;
curPage->next=curPage;
curPage->prev=curPage;
}
else
{
curPage->next=unavailablePages;
curPage->prev=unavailablePages->prev;
unavailablePages->prev->next=curPage;
unavailablePages->prev=curPage;
}
}
RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0);
return retVal;
}
availablePages = (Page *) rakMalloc(sizeof(Page));
if (availablePages==0)
return 0;
availablePagesSize=1;
if (InitPage(availablePages, availablePages)==false)
return 0;
RakAssert(availablePages->availableStackSize>1);
return (MemoryBlockType *) availablePages->availableStack[--availablePages->availableStackSize];
}
template<class MemoryBlockType>
void MemoryPool<MemoryBlockType>::Release(MemoryBlockType *m)
{
#ifdef _DISABLE_MEMORY_POOL
RakNet::OP_DELETE(m);
return;
#endif
// Find the page this block is in and return it.
Page *curPage;
MemoryWithPage *memoryWithPage = (MemoryWithPage*)m;
curPage=memoryWithPage->parentPage;
if (curPage->availableStackSize==0)
{
// The page is in the unavailable list so move it to the available list
curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
unavailablePagesSize--;
// As this page is no longer totally empty, move it to the end of available pages
curPage->next->prev=curPage->prev;
curPage->prev->next=curPage->next;
if (unavailablePagesSize>0 && curPage==unavailablePages)
unavailablePages=unavailablePages->next;
if (availablePagesSize++==0)
{
availablePages=curPage;
curPage->next=curPage;
curPage->prev=curPage;
}
else
{
curPage->next=availablePages;
curPage->prev=availablePages->prev;
availablePages->prev->next=curPage;
availablePages->prev=curPage;
}
}
else
{
curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
if (curPage->availableStackSize==BlocksPerPage() &&
availablePagesSize>=DS_MEMORY_POOL_MAX_FREE_PAGES)
{
// After a certain point, just deallocate empty pages rather than keep them around
if (curPage==availablePages)
{
availablePages=curPage->next;
RakAssert(availablePages->availableStackSize>0);
}
curPage->prev->next=curPage->next;
curPage->next->prev=curPage->prev;
availablePagesSize--;
rakFree(curPage->availableStack);
rakFree(curPage->block);
rakFree(curPage);
}
}
}
template<class MemoryBlockType>
void MemoryPool<MemoryBlockType>::Clear(void)
{
#ifdef _DISABLE_MEMORY_POOL
return;
#endif
Page *cur, *freed;
if (availablePagesSize>0)
{
cur = availablePages;
#ifdef _MSC_VER
#pragma warning(disable:4127) // conditional expression is constant
#endif
while (true)
// do
{
rakFree(cur->availableStack);
rakFree(cur->block);
freed=cur;
cur=cur->next;
if (cur==availablePages)
{
rakFree(freed);
break;
}
rakFree(freed);
}// while(cur!=availablePages);
}
if (unavailablePagesSize>0)
{
cur = unavailablePages;
while (1)
//do
{
rakFree(cur->availableStack);
rakFree(cur->block);
freed=cur;
cur=cur->next;
if (cur==unavailablePages)
{
rakFree(freed);
break;
}
rakFree(freed);
} // while(cur!=unavailablePages);
}
availablePagesSize=0;
unavailablePagesSize=0;
}
template<class MemoryBlockType>
int MemoryPool<MemoryBlockType>::BlocksPerPage(void) const
{
return memoryPoolPageSize / sizeof(MemoryWithPage);
}
template<class MemoryBlockType>
bool MemoryPool<MemoryBlockType>::InitPage(Page *page, Page *prev)
{
int i=0;
const int bpp = BlocksPerPage();
page->block=(MemoryWithPage*) rakMalloc(memoryPoolPageSize);
if (page->block==0)
return false;
page->availableStack=(MemoryWithPage**)rakMalloc(sizeof(MemoryWithPage*)*bpp);
if (page->availableStack==0)
{
rakFree(page->block);
return false;
}
MemoryWithPage *curBlock = page->block;
MemoryWithPage **curStack = page->availableStack;
while (i < bpp)
{
curBlock->parentPage=page;
curStack[i]=curBlock++;
i++;
}
page->availableStackSize=bpp;
page->next=availablePages;
page->prev=prev;
return true;
}
}
#endif
+252
View File
@@ -0,0 +1,252 @@
/// \file
/// \brief \b [Internal] Ordered Channel Heap . This is a heap where you add to it on multiple ordered channels, with each channel having a different weight.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAKNET_ORDERED_CHANNEL_HEAP_H
#define __RAKNET_ORDERED_CHANNEL_HEAP_H
#include "DS_Heap.h"
#include "DS_Map.h"
#include "DS_Queue.h"
#include "Export.h"
#include "RakAssert.h"
#include "Rand.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)=defaultMapKeyComparison<channel_key_type> >
class RAK_DLL_EXPORT OrderedChannelHeap
{
public:
static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultMapKeyComparison<channel_key_type>(channel_key_type(),channel_key_type());}
OrderedChannelHeap();
~OrderedChannelHeap();
void Push(const channel_key_type &channelID, const heap_data_type &data);
void PushAtHead(const unsigned index, const channel_key_type &channelID, const heap_data_type &data);
heap_data_type Pop(const unsigned startingIndex=0);
heap_data_type Peek(const unsigned startingIndex) const;
void AddChannel(const channel_key_type &channelID, const double weight);
void RemoveChannel(channel_key_type channelID);
void Clear(void);
heap_data_type& operator[] ( const unsigned int position ) const;
unsigned ChannelSize(const channel_key_type &channelID);
unsigned Size(void) const;
struct QueueAndWeight
{
DataStructures::Queue<double> randResultQueue;
double weight;
bool signalDeletion;
};
struct HeapChannelAndData
{
HeapChannelAndData() {}
HeapChannelAndData(const channel_key_type &_channel, const heap_data_type &_data) : data(_data), channel(_channel) {}
heap_data_type data;
channel_key_type channel;
};
protected:
DataStructures::Map<channel_key_type, QueueAndWeight*, channel_key_comparison_func> map;
DataStructures::Heap<double, HeapChannelAndData, true> heap;
void GreatestRandResult(void);
};
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::OrderedChannelHeap()
{
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::~OrderedChannelHeap()
{
Clear();
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Push(const channel_key_type &channelID, const heap_data_type &data)
{
PushAtHead(MAX_UNSIGNED_LONG, channelID, data);
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::GreatestRandResult(void)
{
double greatest;
unsigned i;
greatest=0.0;
for (i=0; i < map.Size(); i++)
{
if (map[i]->randResultQueue.Size() && map[i]->randResultQueue[0]>greatest)
greatest=map[i]->randResultQueue[0];
}
return greatest;
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::PushAtHead(const unsigned index, const channel_key_type &channelID, const heap_data_type &data)
{
// If an assert hits here then this is an unknown channel. Call AddChannel first.
QueueAndWeight *queueAndWeight=map.Get(channelID);
double maxRange, minRange, rnd;
if (queueAndWeight->randResultQueue.Size()==0)
{
// Set maxRange to the greatest random number waiting to be returned, rather than 1.0 necessarily
// This is so weights are scaled similarly among channels. For example, if the head weight for a used channel was .25
// and then we added another channel, the new channel would need to choose between .25 and 0
// If we chose between 1.0 and 0, it would be 1/.25 (4x) more likely to be at the head of the heap than it should be
maxRange=GreatestRandResult();
if (maxRange==0.0)
maxRange=1.0;
minRange=0.0;
}
else if (index >= queueAndWeight->randResultQueue.Size())
{
maxRange=queueAndWeight->randResultQueue[queueAndWeight->randResultQueue.Size()-1]*.99999999;
minRange=0.0;
}
else
{
if (index==0)
{
maxRange=GreatestRandResult();
if (maxRange==queueAndWeight->randResultQueue[0])
maxRange=1.0;
}
else if (index >= queueAndWeight->randResultQueue.Size())
maxRange=queueAndWeight->randResultQueue[queueAndWeight->randResultQueue.Size()-1]*.99999999;
else
maxRange=queueAndWeight->randResultQueue[index-1]*.99999999;
minRange=maxRange=queueAndWeight->randResultQueue[index]*1.00000001;
}
#ifdef _DEBUG
RakAssert(maxRange!=0.0);
#endif
rnd=frandomMT() * (maxRange - minRange);
if (rnd==0.0)
rnd=maxRange/2.0;
if (index >= queueAndWeight->randResultQueue.Size())
queueAndWeight->randResultQueue.Push(rnd);
else
queueAndWeight->randResultQueue.PushAtHead(rnd, index);
heap.Push(rnd*queueAndWeight->weight, HeapChannelAndData(channelID, data));
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
heap_data_type OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Pop(const unsigned startingIndex)
{
RakAssert(startingIndex < heap.Size());
QueueAndWeight *queueAndWeight=map.Get(heap[startingIndex].channel);
if (startingIndex!=0)
{
// Ugly - have to count in the heap how many nodes have the same channel, so we know where to delete from in the queue
unsigned indiceCount=0;
unsigned i;
for (i=0; i < startingIndex; i++)
if (channel_key_comparison_func(heap[i].channel,heap[startingIndex].channel)==0)
indiceCount++;
queueAndWeight->randResultQueue.RemoveAtIndex(indiceCount);
}
else
{
// TODO - ordered channel heap uses progressively lower values as items are inserted. But this won't give relative ordering among channels. I have to renormalize after every pop.
queueAndWeight->randResultQueue.Pop();
}
// Try to remove the channel after every pop, because doing so is not valid while there are elements in the list.
if (queueAndWeight->signalDeletion)
RemoveChannel(heap[startingIndex].channel);
return heap.Pop(startingIndex).data;
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
heap_data_type OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Peek(const unsigned startingIndex) const
{
HeapChannelAndData heapChannelAndData = heap.Peek(startingIndex);
return heapChannelAndData.data;
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::AddChannel(const channel_key_type &channelID, const double weight)
{
QueueAndWeight *qaw = RakNet::OP_NEW<QueueAndWeight>();
qaw->weight=weight;
qaw->signalDeletion=false;
map.SetNew(channelID, qaw);
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::RemoveChannel(channel_key_type channelID)
{
if (map.Has(channelID))
{
unsigned i;
i=map.GetIndexAtKey(channelID);
if (map[i]->randResultQueue.Size()==0)
{
RakNet::OP_DELETE(map[i]);
map.RemoveAtIndex(i);
}
else
{
// Signal this channel for deletion later, because the heap has nodes with this channel right now
map[i]->signalDeletion=true;
}
}
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
unsigned OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Size(void) const
{
return heap.Size();
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
heap_data_type& OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::operator[]( const unsigned int position ) const
{
return heap[position].data;
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
unsigned OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::ChannelSize(const channel_key_type &channelID)
{
QueueAndWeight *queueAndWeight=map.Get(channelID);
return queueAndWeight->randResultQueue.Size();
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Clear(void)
{
unsigned i;
for (i=0; i < map.Size(); i++)
RakNet::OP_DELETE(map[i]);
map.Clear();
heap.Clear();
}
}
#endif
+272
View File
@@ -0,0 +1,272 @@
/// \file
/// \brief \b [Internal] Quicksort ordered list.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#include "DS_List.h"
#include "RakMemoryOverride.h"
#include "Export.h"
#ifndef __ORDERED_LIST_H
#define __ORDERED_LIST_H
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
template <class key_type, class data_type>
int defaultOrderedListComparison(const key_type &a, const data_type &b)
{
if (a<b) return -1; if (a==b) return 0; return 1;
}
/// \note IMPORTANT! If you use defaultOrderedListComparison then call IMPLEMENT_DEFAULT_COMPARISON or you will get an unresolved external linker error.
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)=defaultOrderedListComparison<key_type, data_type> >
class RAK_DLL_EXPORT OrderedList
{
public:
static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultOrderedListComparison<key_type, data_type>(key_type(),data_type());}
OrderedList();
~OrderedList();
OrderedList( const OrderedList& original_copy );
OrderedList& operator= ( const OrderedList& original_copy );
/// comparisonFunction must take a key_type and a data_type and return <0, ==0, or >0
/// If the data type has comparison operators already defined then you can just use defaultComparison
bool HasData(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
// GetIndexFromKey returns where the insert should go at the same time checks if it is there
unsigned GetIndexFromKey(const key_type &key, bool *objectExists, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
data_type GetElementFromKey(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
bool GetElementFromKey(const key_type &key, data_type &element, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
unsigned Insert(const key_type &key, const data_type &data, bool assertOnDuplicate, int (*cf)(const key_type&, const data_type&)=default_comparison_function);
unsigned Remove(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function);
unsigned RemoveIfExists(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function);
data_type& operator[] ( const unsigned int position ) const;
void RemoveAtIndex(const unsigned index);
void InsertAtIndex(const data_type &data, const unsigned index);
void InsertAtEnd(const data_type &data);
void RemoveFromEnd(const unsigned num=1);
void Clear(bool doNotDeallocate=false);
unsigned Size(void) const;
protected:
DataStructures::List<data_type> orderedList;
};
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>::OrderedList()
{
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>::~OrderedList()
{
Clear();
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>::OrderedList( const OrderedList& original_copy )
{
orderedList=original_copy.orderedList;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>& OrderedList<key_type, data_type, default_comparison_function>::operator= ( const OrderedList& original_copy )
{
orderedList=original_copy.orderedList;
return *this;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
bool OrderedList<key_type, data_type, default_comparison_function>::HasData(const key_type &key, int (*cf)(const key_type&, const data_type&)) const
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
return objectExists;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
data_type OrderedList<key_type, data_type, default_comparison_function>::GetElementFromKey(const key_type &key, int (*cf)(const key_type&, const data_type&)) const
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
RakAssert(objectExists);
return orderedList[index];
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
bool OrderedList<key_type, data_type, default_comparison_function>::GetElementFromKey(const key_type &key, data_type &element, int (*cf)(const key_type&, const data_type&)) const
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
if (objectExists)
element = orderedList[index];
return objectExists;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::GetIndexFromKey(const key_type &key, bool *objectExists, int (*cf)(const key_type&, const data_type&)) const
{
int index, upperBound, lowerBound;
int res;
if (orderedList.Size()==0)
{
*objectExists=false;
return 0;
}
upperBound=(int)orderedList.Size()-1;
lowerBound=0;
index = (int)orderedList.Size()/2;
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while (1)
{
res = cf(key,orderedList[index]);
if (res==0)
{
*objectExists=true;
return index;
}
else if (res<0)
{
upperBound=index-1;
}
else// if (res>0)
{
lowerBound=index+1;
}
index=lowerBound+(upperBound-lowerBound)/2;
if (lowerBound>upperBound)
{
*objectExists=false;
return lowerBound; // No match
}
}
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::Insert(const key_type &key, const data_type &data, bool assertOnDuplicate, int (*cf)(const key_type&, const data_type&))
{
(void) assertOnDuplicate;
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
// Don't allow duplicate insertion.
if (objectExists)
{
// This is usually a bug! Use InsertAllowDuplicate if you want duplicates
RakAssert(assertOnDuplicate==false);
return (unsigned)-1;
}
if (index>=orderedList.Size())
{
orderedList.Insert(data);
return orderedList.Size()-1;
}
else
{
orderedList.Insert(data,index);
return index;
}
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::Remove(const key_type &key, int (*cf)(const key_type&, const data_type&))
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
// Can't find the element to remove if this assert hits
// RakAssert(objectExists==true);
if (objectExists==false)
{
RakAssert(objectExists==true);
return 0;
}
orderedList.RemoveAtIndex(index);
return index;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::RemoveIfExists(const key_type &key, int (*cf)(const key_type&, const data_type&))
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
// Can't find the element to remove if this assert hits
if (objectExists==false)
return 0;
orderedList.RemoveAtIndex(index);
return index;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::RemoveAtIndex(const unsigned index)
{
orderedList.RemoveAtIndex(index);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::InsertAtIndex(const data_type &data, const unsigned index)
{
orderedList.Insert(data, index);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::InsertAtEnd(const data_type &data)
{
orderedList.Insert(data);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::RemoveFromEnd(const unsigned num)
{
orderedList.RemoveFromEnd(num);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::Clear(bool doNotDeallocate)
{
orderedList.Clear(doNotDeallocate);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
data_type& OrderedList<key_type, data_type, default_comparison_function>::operator[]( const unsigned int position ) const
{
return orderedList[position];
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::Size(void) const
{
return orderedList.Size();
}
}
#endif
+420
View File
@@ -0,0 +1,420 @@
/// \file
/// \brief \b [Internal] A queue used by RakNet.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __QUEUE_H
#define __QUEUE_H
// Template classes have to have all the code in the header file
#include "RakAssert.h"
#include "Export.h"
#include "RakMemoryOverride.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
/// \brief A queue implemented as an array with a read and write index.
template <class queue_type>
class RAK_DLL_EXPORT Queue
{
public:
Queue();
~Queue();
Queue( Queue& original_copy );
bool operator= ( const Queue& original_copy );
void Push( const queue_type& input );
void PushAtHead( const queue_type& input, unsigned index=0 );
queue_type& operator[] ( unsigned int position ) const; // Not a normal thing you do with a queue but can be used for efficiency
void RemoveAtIndex( unsigned int position ); // Not a normal thing you do with a queue but can be used for efficiency
inline queue_type Peek( void ) const;
inline queue_type PeekTail( void ) const;
inline queue_type Pop( void );
inline unsigned int Size( void ) const;
inline bool IsEmpty(void) const;
inline unsigned int AllocationSize( void ) const;
inline void Clear( void );
void Compress( void );
bool Find ( queue_type q );
void ClearAndForceAllocation( int size ); // Force a memory allocation to a certain larger size
private:
queue_type* array;
unsigned int head; // Array index for the head of the queue
unsigned int tail; // Array index for the tail of the queue
unsigned int allocation_size;
};
template <class queue_type>
inline unsigned int Queue<queue_type>::Size( void ) const
{
if ( head <= tail )
return tail -head;
else
return allocation_size -head + tail;
}
template <class queue_type>
inline bool Queue<queue_type>::IsEmpty(void) const
{
return head==tail;
}
template <class queue_type>
inline unsigned int Queue<queue_type>::AllocationSize( void ) const
{
return allocation_size;
}
template <class queue_type>
Queue<queue_type>::Queue()
{
allocation_size = 16;
//array = RakNet::PLACEMENT_NEW<queue_type>(allocation_size);
array = RakNet::OP_NEW_ARRAY<queue_type>(allocation_size);
head = 0;
tail = 0;
}
template <class queue_type>
Queue<queue_type>::~Queue()
{
if (allocation_size>0)
RakNet::OP_DELETE_ARRAY(array);
}
template <class queue_type>
inline queue_type Queue<queue_type>::Pop( void )
{
#ifdef _DEBUG
RakAssert( allocation_size > 0 && Size() >= 0 && head != tail);
#endif
//head=(head+1) % allocation_size;
if ( ++head == allocation_size )
head = 0;
if ( head == 0 )
return ( queue_type ) array[ allocation_size -1 ];
return ( queue_type ) array[ head -1 ];
}
template <class queue_type>
void Queue<queue_type>::PushAtHead( const queue_type& input, unsigned index )
{
RakAssert(index <= Size());
// Just force a reallocation, will be overwritten
Push(input);
if (Size()==1)
return;
unsigned writeIndex, readIndex, trueWriteIndex, trueReadIndex;
writeIndex=Size()-1;
readIndex=writeIndex-1;
while (readIndex >= index)
{
if ( head + writeIndex >= allocation_size )
trueWriteIndex = head + writeIndex - allocation_size;
else
trueWriteIndex = head + writeIndex;
if ( head + readIndex >= allocation_size )
trueReadIndex = head + readIndex - allocation_size;
else
trueReadIndex = head + readIndex;
array[trueWriteIndex]=array[trueReadIndex];
if (readIndex==0)
break;
writeIndex--;
readIndex--;
}
if ( head + index >= allocation_size )
trueWriteIndex = head + index - allocation_size;
else
trueWriteIndex = head + index;
array[trueWriteIndex]=input;
}
template <class queue_type>
inline queue_type Queue<queue_type>::Peek( void ) const
{
#ifdef _DEBUG
RakAssert( head != tail );
RakAssert( allocation_size > 0 && Size() >= 0 );
#endif
return ( queue_type ) array[ head ];
}
template <class queue_type>
inline queue_type Queue<queue_type>::PeekTail( void ) const
{
#ifdef _DEBUG
RakAssert( head != tail );
RakAssert( allocation_size > 0 && Size() >= 0 );
#endif
if (tail!=0)
return ( queue_type ) array[ tail-1 ];
else
return ( queue_type ) array[ allocation_size-1 ];
}
template <class queue_type>
void Queue<queue_type>::Push( const queue_type& input )
{
if ( allocation_size == 0 )
{
array = RakNet::OP_NEW_ARRAY<queue_type>(16);
head = 0;
tail = 1;
array[ 0 ] = input;
allocation_size = 16;
return ;
}
array[ tail++ ] = input;
if ( tail == allocation_size )
tail = 0;
if ( tail == head )
{
// unsigned int index=tail;
// Need to allocate more memory.
queue_type * new_array;
new_array = RakNet::OP_NEW_ARRAY<queue_type>(allocation_size * 2);
#ifdef _DEBUG
RakAssert( new_array );
#endif
if (new_array==0)
return;
for ( unsigned int counter = 0; counter < allocation_size; ++counter )
new_array[ counter ] = array[ ( head + counter ) % ( allocation_size ) ];
head = 0;
tail = allocation_size;
allocation_size *= 2;
// Delete the old array and move the pointer to the new array
RakNet::OP_DELETE_ARRAY(array);
array = new_array;
}
}
template <class queue_type>
Queue<queue_type>::Queue( Queue& original_copy )
{
// Allocate memory for copy
if ( original_copy.Size() == 0 )
{
allocation_size = 0;
}
else
{
array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 );
for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter )
array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ];
head = 0;
tail = original_copy.Size();
allocation_size = original_copy.Size() + 1;
}
}
template <class queue_type>
bool Queue<queue_type>::operator= ( const Queue& original_copy )
{
if ( ( &original_copy ) == this )
return false;
Clear();
// Allocate memory for copy
if ( original_copy.Size() == 0 )
{
allocation_size = 0;
}
else
{
array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 );
for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter )
array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ];
head = 0;
tail = original_copy.Size();
allocation_size = original_copy.Size() + 1;
}
return true;
}
template <class queue_type>
inline void Queue<queue_type>::Clear ( void )
{
if ( allocation_size == 0 )
return ;
if (allocation_size > 32)
{
RakNet::OP_DELETE_ARRAY(array);
allocation_size = 0;
}
head = 0;
tail = 0;
}
template <class queue_type>
void Queue<queue_type>::Compress ( void )
{
queue_type* new_array;
unsigned int newAllocationSize;
if (allocation_size==0)
return;
newAllocationSize=1;
while (newAllocationSize <= Size())
newAllocationSize<<=1; // Must be a better way to do this but I'm too dumb to figure it out quickly :)
new_array = RakNet::OP_NEW_ARRAY<queue_type >(newAllocationSize);
for (unsigned int counter=0; counter < Size(); ++counter)
new_array[counter] = array[(head + counter)%(allocation_size)];
tail=Size();
allocation_size=newAllocationSize;
head=0;
// Delete the old array and move the pointer to the new array
RakNet::OP_DELETE_ARRAY(array);
array=new_array;
}
template <class queue_type>
bool Queue<queue_type>::Find ( queue_type q )
{
if ( allocation_size == 0 )
return false;
unsigned int counter = head;
while ( counter != tail )
{
if ( array[ counter ] == q )
return true;
counter = ( counter + 1 ) % allocation_size;
}
return false;
}
template <class queue_type>
void Queue<queue_type>::ClearAndForceAllocation( int size )
{
RakNet::OP_DELETE_ARRAY(array);
array = RakNet::OP_NEW_ARRAY<queue_type>(size);
allocation_size = size;
head = 0;
tail = 0;
}
template <class queue_type>
inline queue_type& Queue<queue_type>::operator[] ( unsigned int position ) const
{
#ifdef _DEBUG
RakAssert( position < Size() );
#endif
//return array[(head + position) % allocation_size];
if ( head + position >= allocation_size )
return array[ head + position - allocation_size ];
else
return array[ head + position ];
}
template <class queue_type>
void Queue<queue_type>::RemoveAtIndex( unsigned int position )
{
#ifdef _DEBUG
RakAssert( position < Size() );
RakAssert( head != tail );
#endif
if ( head == tail || position >= Size() )
return ;
unsigned int index;
unsigned int next;
//index = (head + position) % allocation_size;
if ( head + position >= allocation_size )
index = head + position - allocation_size;
else
index = head + position;
//next = (index + 1) % allocation_size;
next = index + 1;
if ( next == allocation_size )
next = 0;
while ( next != tail )
{
// Overwrite the previous element
array[ index ] = array[ next ];
index = next;
//next = (next + 1) % allocation_size;
if ( ++next == allocation_size )
next = 0;
}
// Move the tail back
if ( tail == 0 )
tail = allocation_size - 1;
else
--tail;
}
} // End namespace
#endif
+111
View File
@@ -0,0 +1,111 @@
/// \file
/// \brief \b [Internal] A queue implemented as a linked list.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __QUEUE_LINKED_LIST_H
#define __QUEUE_LINKED_LIST_H
#include "DS_LinkedList.h"
#include "Export.h"
#include "RakMemoryOverride.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
/// \brief A queue implemented using a linked list. Rarely used.
template <class QueueType>
class RAK_DLL_EXPORT QueueLinkedList
{
public:
QueueLinkedList();
QueueLinkedList( const QueueLinkedList& original_copy );
bool operator= ( const QueueLinkedList& original_copy );
QueueType Pop( void );
QueueType& Peek( void );
QueueType& EndPeek( void );
void Push( const QueueType& input );
unsigned int Size( void );
void Clear( void );
void Compress( void );
private:
LinkedList<QueueType> data;
};
template <class QueueType>
QueueLinkedList<QueueType>::QueueLinkedList()
{
}
template <class QueueType>
inline unsigned int QueueLinkedList<QueueType>::Size()
{
return data.Size();
}
template <class QueueType>
inline QueueType QueueLinkedList<QueueType>::Pop( void )
{
data.Beginning();
return ( QueueType ) data.Pop();
}
template <class QueueType>
inline QueueType& QueueLinkedList<QueueType>::Peek( void )
{
data.Beginning();
return ( QueueType ) data.Peek();
}
template <class QueueType>
inline QueueType& QueueLinkedList<QueueType>::EndPeek( void )
{
data.End();
return ( QueueType ) data.Peek();
}
template <class QueueType>
void QueueLinkedList<QueueType>::Push( const QueueType& input )
{
data.End();
data.Add( input );
}
template <class QueueType>
QueueLinkedList<QueueType>::QueueLinkedList( const QueueLinkedList& original_copy )
{
data = original_copy.data;
}
template <class QueueType>
bool QueueLinkedList<QueueType>::operator= ( const QueueLinkedList& original_copy )
{
if ( ( &original_copy ) == this )
return false;
data = original_copy.data;
}
template <class QueueType>
void QueueLinkedList<QueueType>::Clear ( void )
{
data.Clear();
}
} // End namespace
#endif
+219
View File
@@ -0,0 +1,219 @@
#ifndef __RANGE_LIST_H
#define __RANGE_LIST_H
#include "DS_OrderedList.h"
#include "BitStream.h"
#include "RakMemoryOverride.h"
#include "RakAssert.h"
namespace DataStructures
{
template <class range_type>
struct RangeNode
{
RangeNode() {}
~RangeNode() {}
RangeNode(range_type min, range_type max) {minIndex=min; maxIndex=max;}
range_type minIndex;
range_type maxIndex;
};
template <class range_type>
int RangeNodeComp(const range_type &a, const RangeNode<range_type> &b)
{
if (a<b.minIndex)
return -1;
if (a==b.minIndex)
return 0;
return 1;
}
template <class range_type>
class RAK_DLL_EXPORT RangeList
{
public:
RangeList();
~RangeList();
void Insert(range_type index);
void Clear(void);
unsigned Size(void) const;
unsigned RangeSum(void) const;
BitSize_t Serialize(RakNet::BitStream *in, BitSize_t maxBits, bool clearSerialized);
bool Deserialize(RakNet::BitStream *out);
DataStructures::OrderedList<range_type, RangeNode<range_type> , RangeNodeComp<range_type> > ranges;
};
template <class range_type>
BitSize_t RangeList<range_type>::Serialize(RakNet::BitStream *in, BitSize_t maxBits, bool clearSerialized)
{
RakAssert(ranges.Size() < (unsigned short)-1);
RakNet::BitStream tempBS;
BitSize_t bitsWritten;
unsigned short countWritten;
unsigned i;
countWritten=0;
bitsWritten=0;
for (i=0; i < ranges.Size(); i++)
{
if ((int)sizeof(unsigned short)*8+bitsWritten+(int)sizeof(range_type)*8*2+1>maxBits)
break;
tempBS.Write(ranges[i].minIndex==ranges[i].maxIndex);
tempBS.Write(ranges[i].minIndex);
bitsWritten+=sizeof(range_type)*8+1;
if (ranges[i].minIndex!=ranges[i].maxIndex)
{
tempBS.Write(ranges[i].maxIndex);
bitsWritten+=sizeof(range_type)*8;
}
countWritten++;
}
BitSize_t before=in->GetWriteOffset();
in->WriteCompressed(countWritten);
bitsWritten+=in->GetWriteOffset()-before;
// RAKNET_DEBUG_PRINTF("%i ", in->GetNumberOfBitsUsed());
in->Write(&tempBS, tempBS.GetNumberOfBitsUsed());
// RAKNET_DEBUG_PRINTF("%i %i \n", tempBS.GetNumberOfBitsUsed(),in->GetNumberOfBitsUsed());
if (clearSerialized && countWritten)
{
unsigned rangeSize=ranges.Size();
for (i=0; i < rangeSize-countWritten; i++)
{
ranges[i]=ranges[i+countWritten];
}
ranges.RemoveFromEnd(countWritten);
}
return bitsWritten;
}
template <class range_type>
bool RangeList<range_type>::Deserialize(RakNet::BitStream *out)
{
ranges.Clear();
unsigned short count;
out->ReadCompressed(count);
unsigned short i;
range_type min,max;
bool maxEqualToMin=false;
for (i=0; i < count; i++)
{
out->Read(maxEqualToMin);
if (out->Read(min)==false)
return false;
if (maxEqualToMin==false)
{
if (out->Read(max)==false)
return false;
if (max<min)
return false;
}
else
max=min;
ranges.InsertAtEnd(RangeNode<range_type>(min,max));
}
return true;
}
template <class range_type>
RangeList<range_type>::RangeList()
{
RangeNodeComp<range_type>(0, RangeNode<range_type>());
}
template <class range_type>
RangeList<range_type>::~RangeList()
{
Clear();
}
template <class range_type>
void RangeList<range_type>::Insert(range_type index)
{
if (ranges.Size()==0)
{
ranges.Insert(index, RangeNode<range_type>(index, index), true);
return;
}
bool objectExists;
unsigned insertionIndex=ranges.GetIndexFromKey(index, &objectExists);
if (insertionIndex==ranges.Size())
{
if (index == ranges[insertionIndex-1].maxIndex+1)
ranges[insertionIndex-1].maxIndex++;
else if (index > ranges[insertionIndex-1].maxIndex+1)
{
// Insert at end
ranges.Insert(index, RangeNode<range_type>(index, index), true);
}
return;
}
if (index < ranges[insertionIndex].minIndex-1)
{
// Insert here
ranges.InsertAtIndex(RangeNode<range_type>(index, index), insertionIndex);
return;
}
else if (index == ranges[insertionIndex].minIndex-1)
{
// Decrease minIndex and join left
ranges[insertionIndex].minIndex--;
if (insertionIndex>0 && ranges[insertionIndex-1].maxIndex+1==ranges[insertionIndex].minIndex)
{
ranges[insertionIndex-1].maxIndex=ranges[insertionIndex].maxIndex;
ranges.RemoveAtIndex(insertionIndex);
}
return;
}
else if (index >= ranges[insertionIndex].minIndex && index <= ranges[insertionIndex].maxIndex)
{
// Already exists
return;
}
else if (index == ranges[insertionIndex].maxIndex+1)
{
// Increase maxIndex and join right
ranges[insertionIndex].maxIndex++;
if (insertionIndex<ranges.Size()-1 && ranges[insertionIndex+1].minIndex==ranges[insertionIndex].maxIndex+1)
{
ranges[insertionIndex+1].minIndex=ranges[insertionIndex].minIndex;
ranges.RemoveAtIndex(insertionIndex);
}
return;
}
}
template <class range_type>
void RangeList<range_type>::Clear(void)
{
ranges.Clear();
}
template <class range_type>
unsigned RangeList<range_type>::Size(void) const
{
return ranges.Size();
}
template <class range_type>
unsigned RangeList<range_type>::RangeSum(void) const
{
unsigned sum=0,i;
for (i=0; i < ranges.Size(); i++)
sum+=ranges[i].maxIndex-ranges[i].minIndex+1;
return sum;
}
}
#endif
+331
View File
@@ -0,0 +1,331 @@
#ifndef __TABLE_H
#define __TABLE_H
#ifdef _MSC_VER
#pragma warning( push )
#endif
#include "DS_List.h"
#include "DS_BPlusTree.h"
#include "RakMemoryOverride.h"
#include "Export.h"
#include "RakString.h"
#define _TABLE_BPLUS_TREE_ORDER 16
#define _TABLE_MAX_COLUMN_NAME_LENGTH 64
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
/// \brief Holds a set of columns, a set of rows, and rows times columns cells.
/// The table data structure is useful if you want to store a set of structures and perform queries on those structures
/// This is a relatively simple and fast implementation of the types of tables commonly used in databases
/// See TableSerializer to serialize data members of the table
/// See LightweightDatabaseClient and LightweightDatabaseServer to transmit the table over the network.
class RAK_DLL_EXPORT Table
{
public:
enum ColumnType
{
// Cell::i used
NUMERIC,
// Cell::c used to hold a null terminated string.
STRING,
// Cell::c holds data. Cell::i holds data length of c in bytes.
BINARY,
// Cell::c holds data. Not deallocated. Set manually by assigning ptr.
POINTER,
};
/// Holds the actual data in the table
struct RAK_DLL_EXPORT Cell
{
Cell();
~Cell();
Cell(double numericValue, char *charValue, void *ptr, ColumnType type);
void Clear(void);
/// Numeric
void Set(int input);
void Set(unsigned int input);
void Set(double input);
/// String
void Set(const char *input);
/// Binary
void Set(const char *input, int inputLength);
/// Pointer
void SetPtr(void* p);
/// Numeric
void Get(int *output);
void Get(double *output);
/// String
void Get(char *output);
/// Binary
void Get(char *output, int *outputLength);
RakNet::RakString ToString(ColumnType columnType);
// assignment operator and copy constructor
Cell& operator = ( const Cell& input );
Cell( const Cell & input);
ColumnType EstimateColumnType(void) const;
bool isEmpty;
double i;
char *c;
void *ptr;
};
/// Stores the name and type of the column
/// \internal
struct RAK_DLL_EXPORT ColumnDescriptor
{
ColumnDescriptor();
~ColumnDescriptor();
ColumnDescriptor(const char cn[_TABLE_MAX_COLUMN_NAME_LENGTH],ColumnType ct);
char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
ColumnType columnType;
};
/// Stores the list of cells for this row, and a special flag used for internal sorting
struct RAK_DLL_EXPORT Row
{
// list of cells
DataStructures::List<Cell*> cells;
/// Numeric
void UpdateCell(unsigned columnIndex, double value);
/// String
void UpdateCell(unsigned columnIndex, const char *str);
/// Binary
void UpdateCell(unsigned columnIndex, int byteLength, const char *data);
};
// Operations to perform for cell comparison
enum FilterQueryType
{
QF_EQUAL,
QF_NOT_EQUAL,
QF_GREATER_THAN,
QF_GREATER_THAN_EQ,
QF_LESS_THAN,
QF_LESS_THAN_EQ,
QF_IS_EMPTY,
QF_NOT_EMPTY,
};
// Compare the cell value for a row at columnName to the cellValue using operation.
struct RAK_DLL_EXPORT FilterQuery
{
FilterQuery();
~FilterQuery();
FilterQuery(unsigned column, Cell *cell, FilterQueryType op);
// If columnName is specified, columnIndex will be looked up using it.
char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
unsigned columnIndex;
Cell *cellValue;
FilterQueryType operation;
};
/// Increasing or decreasing sort order
enum SortQueryType
{
QS_INCREASING_ORDER,
QS_DECREASING_ORDER,
};
// Sort on increasing or decreasing order for a particular column
struct RAK_DLL_EXPORT SortQuery
{
/// The index of the table column we are sorting on
unsigned columnIndex;
/// See SortQueryType
SortQueryType operation;
};
/// Constructor
Table();
/// Destructor
~Table();
/// \brief Adds a column to the table
/// \param[in] columnName The name of the column
/// \param[in] columnType What type of data this column will hold
/// \return The index of the new column
unsigned AddColumn(const char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH], ColumnType columnType);
/// \brief Removes a column by index
/// \param[in] columnIndex The index of the column to remove
void RemoveColumn(unsigned columnIndex);
/// \brief Gets the index of a column by name
/// Column indices are stored in the order they are added.
/// \param[in] columnName The name of the column
/// \return The index of the column, or (unsigned)-1 if no such column
unsigned ColumnIndex(char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]);
unsigned ColumnIndex(const char *columnName);
/// \brief Gives the string name of the column at a certain index
/// \param[in] index The index of the column
/// \return The name of the column, or 0 if an invalid index
char* ColumnName(unsigned index) const;
/// \brief Returns the type of a column, referenced by index
/// \param[in] index The index of the column
/// \return The type of the column
ColumnType GetColumnType(unsigned index) const;
/// Returns the number of columns
/// \return The number of columns in the table
unsigned GetColumnCount(void) const;
/// Returns the number of rows
/// \return The number of rows in the table
unsigned GetRowCount(void) const;
/// \brief Adds a row to the table
/// New rows are added with empty values for all cells. However, if you specify initialCelLValues you can specify initial values
/// It's up to you to ensure that the values in the specific cells match the type of data used by that row
/// rowId can be considered the primary key for the row. It is much faster to lookup a row by its rowId than by searching keys.
/// rowId must be unique
/// Rows are stored in sorted order in the table, using rowId as the sort key
/// \param[in] rowId The UNIQUE primary key for the row. This can never be changed.
/// \param[in] initialCellValues Initial values to give the row (optional)
/// \return The newly added row
Table::Row* AddRow(unsigned rowId);
Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell> &initialCellValues);
Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell*> &initialCellValues, bool copyCells=false);
/// Removes a row specified by rowId
/// \param[in] rowId The ID of the row
/// \return true if the row was deleted. False if not.
bool RemoveRow(unsigned rowId);
/// Removes all the rows with IDs that the specified table also has
/// \param[in] tableContainingRowIDs The IDs of the rows
void RemoveRows(Table *tableContainingRowIDs);
/// Updates a particular cell in the table
/// \note If you are going to update many cells of a particular row, it is more efficient to call GetRow and perform the operations on the row directly.
/// \note Row pointers do not change, so you can also write directly to the rows for more efficiency.
/// \param[in] rowId The ID of the row
/// \param[in] columnIndex The column of the cell
/// \param[in] value The data to set
bool UpdateCell(unsigned rowId, unsigned columnIndex, int value);
bool UpdateCell(unsigned rowId, unsigned columnIndex, char *str);
bool UpdateCell(unsigned rowId, unsigned columnIndex, int byteLength, char *data);
bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int value);
bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, char *str);
bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int byteLength, char *data);
/// Note this is much less efficient to call than GetRow, then working with the cells directly
/// Numeric, string, binary
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, int *output);
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output);
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output, int *outputLength);
/// Gets a row. More efficient to do this and access Row::cells than to repeatedly call GetCell.
/// You can also update cells in rows from this function.
/// \param[in] rowId The ID of the row
/// \return The desired row, or 0 if no such row.
Row* GetRowByID(unsigned rowId) const;
/// Gets a row at a specific index
/// rowIndex should be less than GetRowCount()
/// \param[in] rowIndex The index of the row
/// \param[out] key The ID of the row returned
/// \return The desired row, or 0 if no such row.
Row* GetRowByIndex(unsigned rowIndex, unsigned *key) const;
/// \brief Queries the table, optionally returning only a subset of columns and rows.
/// \param[in] columnSubset An array of column indices. Only columns in this array are returned. Pass 0 for all columns
/// \param[in] numColumnSubset The number of elements in \a columnSubset
/// \param[in] inclusionFilters An array of FilterQuery. All filters must pass for the row to be returned.
/// \param[in] numInclusionFilters The number of elements in \a inclusionFilters
/// \param[in] rowIds An arrow of row IDs. Only these rows with these IDs are returned. Pass 0 for all rows.
/// \param[in] numRowIDs The number of elements in \a rowIds
/// \param[out] result The result of the query. If no rows are returned, the table will only have columns.
void QueryTable(unsigned *columnIndicesSubset, unsigned numColumnSubset, FilterQuery *inclusionFilters, unsigned numInclusionFilters, unsigned *rowIds, unsigned numRowIDs, Table *result);
/// \brief Sorts the table by rows
/// You can sort the table in ascending or descending order on one or more columns
/// Columns have precedence in the order they appear in the \a sortQueries array
/// If a row cell on column n has the same value as a a different row on column n, then the row will be compared on column n+1
/// \param[in] sortQueries A list of SortQuery structures, defining the sorts to perform on the table
/// \param[in] numColumnSubset The number of elements in \a numSortQueries
/// \param[out] out The address of an array of Rows, which will receive the sorted output. The array must be long enough to contain all returned rows, up to GetRowCount()
void SortTable(Table::SortQuery *sortQueries, unsigned numSortQueries, Table::Row** out);
/// Frees all memory in the table.
void Clear(void);
/// Prints out the names of all the columns
/// \param[out] out A pointer to an array of bytes which will hold the output.
/// \param[in] outLength The size of the \a out array
/// \param[in] columnDelineator What character to print to delineate columns
void PrintColumnHeaders(char *out, int outLength, char columnDelineator) const;
/// Writes a text representation of the row to \a out
/// \param[out] out A pointer to an array of bytes which will hold the output.
/// \param[in] outLength The size of the \a out array
/// \param[in] columnDelineator What character to print to delineate columns
/// \param[in] printDelineatorForBinary Binary output is not printed. True to still print the delineator.
/// \param[in] inputRow The row to print
void PrintRow(char *out, int outLength, char columnDelineator, bool printDelineatorForBinary, Table::Row* inputRow) const;
/// Direct access to make things easier
DataStructures::List<ColumnDescriptor>& GetColumns(void);
/// Direct access to make things easier
const DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER>& GetRows(void) const;
/// Get the head of a linked list containing all the row data
DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> * GetListHead(void);
/// Get the first free row id.
/// This could be made more efficient.
unsigned GetAvailableRowId(void) const;
Table& operator = ( const Table& input );
protected:
Table::Row* AddRowColumns(unsigned rowId, Row *row, DataStructures::List<unsigned> columnIndices);
void DeleteRow(Row *row);
void QueryRow(DataStructures::List<unsigned> &inclusionFilterColumnIndices, DataStructures::List<unsigned> &columnIndicesToReturn, unsigned key, Table::Row* row, FilterQuery *inclusionFilters, Table *result);
// 16 is arbitrary and is the order of the BPlus tree. Higher orders are better for searching while lower orders are better for
// Insertions and deletions.
DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER> rows;
// Columns in the table.
DataStructures::List<ColumnDescriptor> columns;
};
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif
+98
View File
@@ -0,0 +1,98 @@
/// \file
/// \brief \b [Internal] Just a regular tree
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __DS_TREE_H
#define __DS_TREE_H
#include "Export.h"
#include "DS_List.h"
#include "DS_Queue.h"
#include "RakMemoryOverride.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
template <class TreeType>
class RAK_DLL_EXPORT Tree
{
public:
Tree();
Tree(TreeType &inputData);
~Tree();
void LevelOrderTraversal(DataStructures::List<Tree*> &output);
void AddChild(TreeType &newData);
void DeleteDecendants(void);
TreeType data;
DataStructures::List<Tree *> children;
};
template <class TreeType>
Tree<TreeType>::Tree()
{
}
template <class TreeType>
Tree<TreeType>::Tree(TreeType &inputData)
{
data=inputData;
}
template <class TreeType>
Tree<TreeType>::~Tree()
{
}
template <class TreeType>
void Tree<TreeType>::LevelOrderTraversal(DataStructures::List<Tree*> &output)
{
unsigned i;
Tree<TreeType> *node;
DataStructures::Queue<Tree<TreeType>*> queue;
for (i=0; i < children.Size(); i++)
queue.Push(children[i]);
while (queue.Size())
{
node=queue.Pop();
output.Insert(node);
for (i=0; i < node->children.Size(); i++)
queue.Push(node->children[i]);
}
}
template <class TreeType>
void Tree<TreeType>::AddChild(TreeType &newData)
{
children.Insert(new Tree(newData));
}
template <class TreeType>
void Tree<TreeType>::DeleteDecendants(void)
{
DataStructures::List<Tree*> output;
LevelOrderTraversal(output);
unsigned i;
for (i=0; i < output.Size(); i++)
RakNet::OP_DELETE(output[i]);
}
}
#endif
+544
View File
@@ -0,0 +1,544 @@
/// \file
/// \brief \b [Internal] Weighted graph. I'm assuming the indices are complex map types, rather than sequential numbers (which could be implemented much more efficiently).
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __WEIGHTED_GRAPH_H
#define __WEIGHTED_GRAPH_H
#include "DS_OrderedList.h"
#include "DS_Map.h"
#include "DS_Heap.h"
#include "DS_Queue.h"
#include "DS_Tree.h"
#include "RakAssert.h"
#include "RakMemoryOverride.h"
#ifdef _DEBUG
#include <stdio.h>
#endif
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
template <class node_type, class weight_type, bool allow_unlinkedNodes>
class RAK_DLL_EXPORT WeightedGraph
{
public:
static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultMapKeyComparison<node_type>(node_type(),node_type());}
WeightedGraph();
~WeightedGraph();
WeightedGraph( const WeightedGraph& original_copy );
WeightedGraph& operator= ( const WeightedGraph& original_copy );
void AddNode(const node_type &node);
void RemoveNode(const node_type &node);
void AddConnection(const node_type &node1, const node_type &node2, weight_type weight);
void RemoveConnection(const node_type &node1, const node_type &node2);
bool HasConnection(const node_type &node1, const node_type &node2);
void Print(void);
void Clear(void);
bool GetShortestPath(DataStructures::List<node_type> &path, node_type startNode, node_type endNode, weight_type INFINITE_WEIGHT);
bool GetSpanningTree(DataStructures::Tree<node_type> &outTree, DataStructures::List<node_type> *inputNodes, node_type startNode, weight_type INFINITE_WEIGHT );
unsigned GetNodeCount(void) const;
unsigned GetConnectionCount(unsigned nodeIndex) const;
void GetConnectionAtIndex(unsigned nodeIndex, unsigned connectionIndex, node_type &outNode, weight_type &outWeight) const;
node_type GetNodeAtIndex(unsigned nodeIndex) const;
protected:
void ClearDijkstra(void);
void GenerateDisjktraMatrix(node_type startNode, weight_type INFINITE_WEIGHT);
DataStructures::Map<node_type, DataStructures::Map<node_type, weight_type> *> adjacencyLists;
// All these variables are for path finding with Dijkstra
// 08/23/06 Won't compile as a DLL inside this struct
// struct
// {
bool isValidPath;
node_type rootNode;
DataStructures::OrderedList<node_type, node_type> costMatrixIndices;
weight_type *costMatrix;
node_type *leastNodeArray;
// } dijkstra;
struct NodeAndParent
{
DataStructures::Tree<node_type>*node;
DataStructures::Tree<node_type>*parent;
};
};
template <class node_type, class weight_type, bool allow_unlinkedNodes>
WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::WeightedGraph()
{
isValidPath=false;
costMatrix=0;
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::~WeightedGraph()
{
Clear();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::WeightedGraph( const WeightedGraph& original_copy )
{
adjacencyLists=original_copy.adjacencyLists;
isValidPath=original_copy.isValidPath;
if (isValidPath)
{
rootNode=original_copy.rootNode;
costMatrixIndices=original_copy.costMatrixIndices;
costMatrix = RakNet::OP_NEW_ARRAY<weight_type>(costMatrixIndices.Size() * costMatrixIndices.Size());
leastNodeArray = RakNet::OP_NEW_ARRAY<node_type>(costMatrixIndices.Size());
memcpy(costMatrix, original_copy.costMatrix, costMatrixIndices.Size() * costMatrixIndices.Size() * sizeof(weight_type));
memcpy(leastNodeArray, original_copy.leastNodeArray, costMatrixIndices.Size() * sizeof(weight_type));
}
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
WeightedGraph<node_type, weight_type, allow_unlinkedNodes>& WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::operator=( const WeightedGraph& original_copy )
{
adjacencyLists=original_copy.adjacencyLists;
isValidPath=original_copy.isValidPath;
if (isValidPath)
{
rootNode=original_copy.rootNode;
costMatrixIndices=original_copy.costMatrixIndices;
costMatrix = RakNet::OP_NEW_ARRAY<weight_type>(costMatrixIndices.Size() * costMatrixIndices.Size());
leastNodeArray = RakNet::OP_NEW_ARRAY<node_type>(costMatrixIndices.Size());
memcpy(costMatrix, original_copy.costMatrix, costMatrixIndices.Size() * costMatrixIndices.Size() * sizeof(weight_type));
memcpy(leastNodeArray, original_copy.leastNodeArray, costMatrixIndices.Size() * sizeof(weight_type));
}
return *this;
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::AddNode(const node_type &node)
{
adjacencyLists.SetNew(node, RakNet::OP_NEW<DataStructures::Map<node_type, weight_type> >());
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::RemoveNode(const node_type &node)
{
unsigned i;
DataStructures::Queue<node_type> removeNodeQueue;
removeNodeQueue.Push(node);
while (removeNodeQueue.Size())
{
RakNet::OP_DELETE(adjacencyLists.Pop(removeNodeQueue.Pop()));
// Remove this node from all of the other lists as well
for (i=0; i < adjacencyLists.Size(); i++)
{
adjacencyLists[i]->Delete(node);
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
if (allow_unlinkedNodes==false && adjacencyLists[i]->Size()==0)
removeNodeQueue.Push(adjacencyLists.GetKeyAtIndex(i));
}
}
ClearDijkstra();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
bool WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::HasConnection(const node_type &node1, const node_type &node2)
{
if (node1==node2)
return false;
if (adjacencyLists.Has(node1)==false)
return false;
return adjacencyLists.Get(node1)->Has(node2);
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::AddConnection(const node_type &node1, const node_type &node2, weight_type weight)
{
if (node1==node2)
return;
if (adjacencyLists.Has(node1)==false)
AddNode(node1);
adjacencyLists.Get(node1)->Set(node2, weight);
if (adjacencyLists.Has(node2)==false)
AddNode(node2);
adjacencyLists.Get(node2)->Set(node1, weight);
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::RemoveConnection(const node_type &node1, const node_type &node2)
{
adjacencyLists.Get(node2)->Delete(node1);
adjacencyLists.Get(node1)->Delete(node2);
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
if (allow_unlinkedNodes==false) // If we do not allow _unlinked nodes, then if there are no connections, remove the node
{
if (adjacencyLists.Get(node1)->Size()==0)
RemoveNode(node1); // Will also remove node1 from the adjacency list of node2
if (adjacencyLists.Has(node2) && adjacencyLists.Get(node2)->Size()==0)
RemoveNode(node2);
}
ClearDijkstra();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::Clear(void)
{
unsigned i;
for (i=0; i < adjacencyLists.Size(); i++)
RakNet::OP_DELETE(adjacencyLists[i]);
adjacencyLists.Clear();
ClearDijkstra();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
bool WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetShortestPath(DataStructures::List<node_type> &path, node_type startNode, node_type endNode, weight_type INFINITE_WEIGHT)
{
path.Clear();
if (startNode==endNode)
{
path.Insert(startNode);
path.Insert(endNode);
return true;
}
if (isValidPath==false || rootNode!=startNode)
{
ClearDijkstra();
GenerateDisjktraMatrix(startNode, INFINITE_WEIGHT);
}
// return the results
bool objectExists;
unsigned col,row;
weight_type currentWeight;
DataStructures::Queue<node_type> outputQueue;
col=costMatrixIndices.GetIndexFromKey(endNode, &objectExists);
if (costMatrixIndices.Size()<2)
{
return false;
}
if (objectExists==false)
{
return false;
}
node_type vertex;
row=costMatrixIndices.Size()-2;
if (row==0)
{
path.Insert(startNode);
path.Insert(endNode);
return true;
}
currentWeight=costMatrix[row*adjacencyLists.Size() + col];
if (currentWeight==INFINITE_WEIGHT)
{
// No path
return true;
}
vertex=endNode;
outputQueue.PushAtHead(vertex);
row--;
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while (1)
{
while (costMatrix[row*adjacencyLists.Size() + col] == currentWeight)
{
if (row==0)
{
path.Insert(startNode);
for (col=0; outputQueue.Size(); col++)
path.Insert(outputQueue.Pop());
return true;
}
--row;
}
vertex=leastNodeArray[row];
outputQueue.PushAtHead(vertex);
if (row==0)
break;
col=costMatrixIndices.GetIndexFromKey(vertex, &objectExists);
currentWeight=costMatrix[row*adjacencyLists.Size() + col];
}
path.Insert(startNode);
for (col=0; outputQueue.Size(); col++)
path.Insert(outputQueue.Pop());
return true;
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
node_type WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetNodeAtIndex(unsigned nodeIndex) const
{
return adjacencyLists.GetKeyAtIndex(nodeIndex);
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
unsigned WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetNodeCount(void) const
{
return adjacencyLists.Size();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
unsigned WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetConnectionCount(unsigned nodeIndex) const
{
return adjacencyLists[nodeIndex]->Size();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetConnectionAtIndex(unsigned nodeIndex, unsigned connectionIndex, node_type &outNode, weight_type &outWeight) const
{
outWeight=adjacencyLists[nodeIndex]->operator[](connectionIndex);
outNode=adjacencyLists[nodeIndex]->GetKeyAtIndex(connectionIndex);
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
bool WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetSpanningTree(DataStructures::Tree<node_type> &outTree, DataStructures::List<node_type> *inputNodes, node_type startNode, weight_type INFINITE_WEIGHT )
{
// Find the shortest path from the start node to each of the input nodes. Add this path to a new WeightedGraph if the result is reachable
DataStructures::List<node_type> path;
DataStructures::WeightedGraph<node_type, weight_type, allow_unlinkedNodes> outGraph;
bool res;
unsigned i,j;
for (i=0; i < inputNodes->Size(); i++)
{
res=GetShortestPath(path, startNode, (*inputNodes)[i], INFINITE_WEIGHT);
if (res)
{
for (j=0; j < path.Size()-1; j++)
{
// Don't bother looking up the weight
outGraph.AddConnection(path[j], path[j+1], INFINITE_WEIGHT);
}
}
}
// Copy the graph to a tree.
DataStructures::Queue<NodeAndParent> nodesToProcess;
DataStructures::Tree<node_type> *current;
DataStructures::Map<node_type, weight_type> *adjacencyList;
node_type key;
NodeAndParent nap, nap2;
outTree.DeleteDecendants();
outTree.data=startNode;
current=&outTree;
if (outGraph.adjacencyLists.Has(startNode)==false)
return false;
adjacencyList = outGraph.adjacencyLists.Get(startNode);
for (i=0; i < adjacencyList->Size(); i++)
{
nap2.node=RakNet::OP_NEW<DataStructures::Tree<node_type> >();
nap2.node->data=adjacencyList->GetKeyAtIndex(i);
nap2.parent=current;
nodesToProcess.Push(nap2);
current->children.Insert(nap2.node);
}
while (nodesToProcess.Size())
{
nap=nodesToProcess.Pop();
current=nap.node;
adjacencyList = outGraph.adjacencyLists.Get(nap.node->data);
for (i=0; i < adjacencyList->Size(); i++)
{
key=adjacencyList->GetKeyAtIndex(i);
if (key!=nap.parent->data)
{
nap2.node=RakNet::OP_NEW<DataStructures::Tree<node_type> >();
nap2.node->data=key;
nap2.parent=current;
nodesToProcess.Push(nap2);
current->children.Insert(nap2.node);
}
}
}
return true;
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GenerateDisjktraMatrix(node_type startNode, weight_type INFINITE_WEIGHT)
{
if (adjacencyLists.Size()==0)
return;
costMatrix = RakNet::OP_NEW_ARRAY<weight_type>(adjacencyLists.Size() * adjacencyLists.Size());
leastNodeArray = RakNet::OP_NEW_ARRAY<node_type>(adjacencyLists.Size());
node_type currentNode;
unsigned col, row, row2, openSetIndex;
node_type adjacentKey;
unsigned adjacentIndex;
weight_type edgeWeight, currentNodeWeight, adjacentNodeWeight;
DataStructures::Map<node_type, weight_type> *adjacencyList;
DataStructures::Heap<weight_type, node_type, false> minHeap;
DataStructures::Map<node_type, weight_type> openSet;
for (col=0; col < adjacencyLists.Size(); col++)
{
// This should be already sorted, so it's a bit inefficient to do an insertion sort, but what the heck
costMatrixIndices.Insert(adjacencyLists.GetKeyAtIndex(col),adjacencyLists.GetKeyAtIndex(col), true);
}
for (col=0; col < adjacencyLists.Size() * adjacencyLists.Size(); col++)
costMatrix[col]=INFINITE_WEIGHT;
currentNode=startNode;
row=0;
currentNodeWeight=0;
rootNode=startNode;
// Clear the starting node column
if (adjacencyLists.Size())
{
adjacentIndex=adjacencyLists.GetIndexAtKey(startNode);
for (row2=0; row2 < adjacencyLists.Size(); row2++)
costMatrix[row2*adjacencyLists.Size() + adjacentIndex]=0;
}
while (row < adjacencyLists.Size()-1)
{
adjacencyList = adjacencyLists.Get(currentNode);
// Go through all connections from the current node. If the new weight is less than the current weight, then update that weight.
for (col=0; col < adjacencyList->Size(); col++)
{
edgeWeight=(*adjacencyList)[col];
adjacentKey=adjacencyList->GetKeyAtIndex(col);
adjacentIndex=adjacencyLists.GetIndexAtKey(adjacentKey);
adjacentNodeWeight=costMatrix[row*adjacencyLists.Size() + adjacentIndex];
if (currentNodeWeight + edgeWeight < adjacentNodeWeight)
{
// Update the weight for the adjacent node
for (row2=row; row2 < adjacencyLists.Size(); row2++)
costMatrix[row2*adjacencyLists.Size() + adjacentIndex]=currentNodeWeight + edgeWeight;
openSet.Set(adjacentKey, currentNodeWeight + edgeWeight);
}
}
// Find the lowest in the open set
minHeap.Clear();
for (openSetIndex=0; openSetIndex < openSet.Size(); openSetIndex++)
minHeap.Push(openSet[openSetIndex], openSet.GetKeyAtIndex(openSetIndex));
/*
unsigned i,j;
for (i=0; i < adjacencyLists.Size()-1; i++)
{
for (j=0; j < adjacencyLists.Size(); j++)
{
RAKNET_DEBUG_PRINTF("%2i ", costMatrix[i*adjacencyLists.Size() + j]);
}
RAKNET_DEBUG_PRINTF("Node=%i", leastNodeArray[i]);
RAKNET_DEBUG_PRINTF("\n");
}
*/
if (minHeap.Size()==0)
{
// Unreachable nodes
isValidPath=true;
return;
}
currentNodeWeight=minHeap.PeekWeight(0);
leastNodeArray[row]=minHeap.Pop(0);
currentNode=leastNodeArray[row];
openSet.Delete(currentNode);
row++;
}
/*
#ifdef _DEBUG
unsigned i,j;
for (i=0; i < adjacencyLists.Size()-1; i++)
{
for (j=0; j < adjacencyLists.Size(); j++)
{
RAKNET_DEBUG_PRINTF("%2i ", costMatrix[i*adjacencyLists.Size() + j]);
}
RAKNET_DEBUG_PRINTF("Node=%i", leastNodeArray[i]);
RAKNET_DEBUG_PRINTF("\n");
}
#endif
*/
isValidPath=true;
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::ClearDijkstra(void)
{
if (isValidPath)
{
isValidPath=false;
RakNet::OP_DELETE_ARRAY(costMatrix);
RakNet::OP_DELETE_ARRAY(leastNodeArray);
costMatrixIndices.Clear();
}
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::Print(void)
{
#ifdef _DEBUG
unsigned i,j;
for (i=0; i < adjacencyLists.Size(); i++)
{
//RAKNET_DEBUG_PRINTF("%i connected to ", i);
RAKNET_DEBUG_PRINTF("%s connected to ", adjacencyLists.GetKeyAtIndex(i).systemAddress.ToString());
if (adjacencyLists[i]->Size()==0)
RAKNET_DEBUG_PRINTF("<Empty>");
else
{
for (j=0; j < adjacencyLists[i]->Size(); j++)
// RAKNET_DEBUG_PRINTF("%i (%.2f) ", adjacencyLists.GetIndexAtKey(adjacencyLists[i]->GetKeyAtIndex(j)), (float) adjacencyLists[i]->operator[](j) );
RAKNET_DEBUG_PRINTF("%s (%.2f) ", adjacencyLists[i]->GetKeyAtIndex(j).systemAddress.ToString(), (float) adjacencyLists[i]->operator[](j) );
}
RAKNET_DEBUG_PRINTF("\n");
}
#endif
}
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif
+72
View File
@@ -0,0 +1,72 @@
/// \file
/// \brief \b [Internal] Encrypts and decrypts data blocks. Used as part of secure connections.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __DATA_BLOCK_ENCRYPTOR_H
#define __DATA_BLOCK_ENCRYPTOR_H
#include "Rijndael.h"
#include "RakMemoryOverride.h"
class RakNetRandom;
/// Encrypts and decrypts data blocks.
class DataBlockEncryptor
{
public:
/// Constructor
DataBlockEncryptor();
/// Destructor
~DataBlockEncryptor();
/// \return true if SetKey has been called previously
bool IsKeySet( void ) const;
/// Set the encryption key
/// \param[in] key The new encryption key
void SetKey( const unsigned char key[ 16 ] );
/// Unset the encryption key
void UnsetKey( void );
/// Encryption adds 6 data bytes and then pads the number of bytes to be a multiple of 16. Output should be large enough to hold this.
/// Output can be the same memory block as input
/// \param[in] input the input buffer to encrypt
/// \param[in] inputLength the size of the @em input buffer
/// \param[in] output the output buffer to store encrypted data
/// \param[in] outputLength the size of the output buffer
void Encrypt( unsigned char *input, unsigned int inputLength, unsigned char *output, unsigned int *outputLength, RakNetRandom *rnr );
/// Decryption removes bytes, as few as 6. Output should be large enough to hold this.
/// Output can be the same memory block as input
/// \param[in] input the input buffer to decrypt
/// \param[in] inputLength the size of the @em input buffer
/// \param[in] output the output buffer to store decrypted data
/// \param[in] outputLength the size of the @em output buffer
/// \return False on bad checksum or input, true on success
bool Decrypt( unsigned char *input, unsigned int inputLength, unsigned char *output, unsigned int *outputLength );
protected:
keyInstance keyEncrypt;
keyInstance keyDecrypt;
cipherInstance cipherInst;
bool keySet;
};
#endif
+34
View File
@@ -0,0 +1,34 @@
/// \file
/// \brief DataCompressor does compression on a block of data. Not very good compression, but it's small and fast so is something you can use per-message at runtime.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __DATA_COMPRESSOR_H
#define __DATA_COMPRESSOR_H
#include "RakMemoryOverride.h"
#include "DS_HuffmanEncodingTree.h"
#include "Export.h"
/// \brief Does compression on a block of data. Not very good compression, but it's small and fast so is something you can compute at runtime.
class RAK_DLL_EXPORT DataCompressor
{
public:
static void Compress( unsigned char *userData, unsigned sizeInBytes, RakNet::BitStream * output );
static unsigned DecompressAndAllocate( RakNet::BitStream * input, unsigned char **output );
};
#endif
+143
View File
@@ -0,0 +1,143 @@
/// \file
/// \brief Simple class to send changes between directories. In essence, a simple autopatcher that can be used for transmitting levels, skins, etc.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __DIRECTORY_DELTA_TRANSFER_H
#define __DIRECTORY_DELTA_TRANSFER_H
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#include "Export.h"
#include "PluginInterface.h"
#include "DS_Map.h"
#include "PacketPriority.h"
class RakPeerInterface;
class FileList;
struct Packet;
struct InternalPacket;
struct DownloadRequest;
class FileListTransfer;
class FileListTransferCBInterface;
class FileListProgress;
class IncrementalReadInterface;
/// \defgroup DIRECTORY_DELTA_TRANSFER_GROUP DirectoryDeltaTransfer
/// \ingroup PLUGINS_GROUP
/// \brief Simple class to send changes between directories. In essence, a simple autopatcher that can be used for transmitting levels, skins, etc.
/// \sa Autopatcher class for database driven patching, including binary deltas and search by date.
///
/// To use, first set the path to your application. For example "C:/Games/MyRPG/"
/// To allow other systems to download files, call AddUploadsFromSubdirectory, where the parameter is a path relative
/// to the path to your application. This includes subdirectories.
/// For example:
/// SetApplicationDirectory("C:/Games/MyRPG/");
/// AddUploadsFromSubdirectory("Mods/Skins/");
/// would allow downloads from
/// "C:/Games/MyRPG/Mods/Skins/*.*" as well as "C:/Games/MyRPG/Mods/Skins/Level1/*.*"
/// It would NOT allow downloads from C:/Games/MyRPG/Levels, nor would it allow downloads from C:/Windows
/// While pathToApplication can be anything you want, applicationSubdirectory must match either partially or fully between systems.
/// \ingroup DIRECTORY_DELTA_TRANSFER_GROUP
class RAK_DLL_EXPORT DirectoryDeltaTransfer : public PluginInterface
{
public:
/// Constructor
DirectoryDeltaTransfer();
/// Destructor
virtual ~DirectoryDeltaTransfer();
/// This plugin has a dependency on the FileListTransfer plugin, which it uses to actually send the files.
/// So you need an instance of that plugin registered with RakPeerInterface, and a pointer to that interface should be passed here.
/// \param[in] flt A pointer to a registered instance of FileListTransfer
void SetFileListTransferPlugin(FileListTransfer *flt);
/// Set the local root directory to base all file uploads and downloads off of.
/// \param[in] pathToApplication This path will be prepended to \a applicationSubdirectory in AddUploadsFromSubdirectory to find the actual path on disk.
void SetApplicationDirectory(const char *pathToApplication);
/// What parameters to use for the RakPeerInterface::Send() call when uploading files.
/// \param[in] _priority See RakPeerInterface::Send()
/// \param[in] _orderingChannel See RakPeerInterface::Send()
void SetUploadSendParameters(PacketPriority _priority, char _orderingChannel);
/// Add all files in the specified subdirectory recursively
/// \a subdir is appended to \a pathToApplication in SetApplicationDirectory().
/// All files in the resultant directory and subdirectories are then hashed so that users can download them.
/// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin
/// \param[in] subdir Concatenated with pathToApplication to form the final path from which to allow uploads.
void AddUploadsFromSubdirectory(const char *subdir);
/// Downloads files from the matching parameter \a subdir in AddUploadsFromSubdirectory.
/// \a subdir must contain all starting characters in \a subdir in AddUploadsFromSubdirectory
/// Therefore,
/// AddUploadsFromSubdirectory("Levels/Level1/"); would allow you to download using DownloadFromSubdirectory("Levels/Level1/Textures/"...
/// but it would NOT allow you to download from DownloadFromSubdirectory("Levels/"... or DownloadFromSubdirectory("Levels/Level2/"...
/// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin
/// \param[in] subdir A directory passed to AddUploadsFromSubdirectory on the remote system. The passed dir can be more specific than the remote dir.
/// \param[in] outputSubdir The directory to write the output to. Usually this will match \a subdir but it can be different if you want.
/// \param[in] prependAppDirToOutputSubdir True to prepend outputSubdir with pathToApplication when determining the final output path. Usually you want this to be true.
/// \param[in] host The address of the remote system to send the message to.
/// \param[in] onFileCallback Callback to call per-file (optional). When fileIndex+1==setCount in the callback then the download is done
/// \param[in] _priority See RakPeerInterface::Send()
/// \param[in] _orderingChannel See RakPeerInterface::Send()
/// \param[in] cb Callback to get progress updates. Pass 0 to not use.
/// \return A set ID, identifying this download set. Returns 65535 on host unreachable.
unsigned short DownloadFromSubdirectory(const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb);
/// Clear all allowed uploads previously set with AddUploadsFromSubdirectory
void ClearUploads(void);
/// Returns how many files are available for upload
/// \return How many files are available for upload
unsigned GetNumberOfFilesForUpload(void) const;
/// Set if we should compress outgoing sends or not
/// Defaults to false, because this results in a noticeable freeze on large requests
/// You can set this to true if you only send small files though
/// \param[in] compress True to compress, false to not.
void SetCompressOutgoingSends(bool compress);
/// Normally, if a remote system requests files, those files are all loaded into memory and sent immediately.
/// This function allows the files to be read in incremental chunks, saving memory
/// \param[in] _incrementalReadInterface If a file in \a fileList has no data, filePullInterface will be used to read the file in chunks of size \a chunkSize
/// \param[in] _chunkSize How large of a block of a file to send at once
void SetDownloadRequestIncrementalReadInterface(IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize);
/// \internal For plugin handling
virtual void OnAttach(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void Update(RakPeerInterface *peer);
/// \internal For plugin handling
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// \internal For plugin handling
virtual void OnShutdown(RakPeerInterface *peer);
protected:
void OnDownloadRequest(RakPeerInterface *peer, Packet *packet);
char applicationDirectory[512];
FileListTransfer *fileListTransfer;
FileList *availableUploads;
RakPeerInterface *rakPeer;
PacketPriority priority;
char orderingChannel;
bool compressOutgoingSends;
IncrementalReadInterface *incrementalReadInterface;
unsigned int chunkSize;
};
#endif
+51
View File
@@ -0,0 +1,51 @@
/// \file
/// \brief Rudimentary class to send email from code. Don't expect anything fancy.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __EMAIL_SENDER_H
#define __EMAIL_SENDER_H
class FileList;
class TCPInterface;
#include "RakNetTypes.h"
#include "RakMemoryOverride.h"
/// \brief Rudimentary class to send email from code.
class EmailSender
{
public:
/// Sends an email
/// \param[in] hostAddress The address of the email server.
/// \param[in] hostPort The port of the email server (usually 25)
/// \param[in] sender The email address you are sending from.
/// \param[in] recipient The email address you are sending to.
/// \param[in] senderName The email address you claim to be sending from
/// \param[in] recipientName The email address you claim to be sending to
/// \param[in] subject Email subject
/// \param[in] body Email body
/// \param[in] attachedFiles List of files to attach to the email. (Can be 0 to send none).
/// \param[in] doPrintf true to output SMTP info to console(for debugging?)
/// \param[in] password Used if the server uses AUTHENTICATE PLAIN over TLS (such as gmail)
/// \return 0 on success, otherwise a string indicating the error message
const char *Send(const char *hostAddress, unsigned short hostPort, const char *sender, const char *recipient, const char *senderName, const char *recipientName, const char *subject, const char *body, FileList *attachedFiles, bool doPrintf, const char *password);
// Returns how many bytes were written
int Base64Encoding(const char *inputData, int dataLength, char *outputData, const char *base64Map);
protected:
const char *GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf);
};
#endif
+9
View File
@@ -0,0 +1,9 @@
#ifndef __EPOCH_TIME_TO_STRING_H
#define __EPOCH_TIME_TO_STRING_H
#include "Export.h"
RAK_DLL_EXPORT char * EpochTimeToString(long long time);
#endif
@@ -0,0 +1,50 @@
/// \file
/// \brief \b [Depreciated] This was used for IO completion ports.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
// No longer used as I no longer support IO Completion ports
/*
#ifdef __USE_IO_COMPLETION_PORTS
#ifndef __EXTENDED_OVERLAPPED_POOL
#define __EXTENDED_OVERLAPPED_POOL
#include "SimpleMutex.h"
#include "ClientContextStruct.h"
#include "DS_Queue.h"
/// Depreciated - for IO completion ports
class ExtendedOverlappedPool
{
public:
ExtendedOverlappedPool();
~ExtendedOverlappedPool();
ExtendedOverlappedStruct* GetPointer( void );
void ReleasePointer( ExtendedOverlappedStruct *p );
static inline ExtendedOverlappedPool* Instance()
{
return & I;
}
private:
DataStructures::Queue<ExtendedOverlappedStruct*> pool;
SimpleMutex poolMutex;
static ExtendedOverlappedPool I;
};
#endif
#endif
*/
+139
View File
@@ -0,0 +1,139 @@
/// \file
/// \brief In a fully connected mesh, determines which system can act as a host. This generally is the system that has been connected to the mesh the longest.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __FCM_HOST_H
#define __FCM_HOST_H
#include "RakNetTypes.h"
#include "Export.h"
#include "PluginInterface.h"
#include "PacketPriority.h"
#include "DS_List.h"
#include "DS_Map.h"
class RakPeerInterface;
struct Packet;
typedef unsigned char FCMHostGroupID;
/// \defgroup FCM_HOST_GROUP FullyConnectedMeshHost
/// \ingroup PLUGINS_GROUP
/// \brief In a fully connected mesh of peers, allows all peers to agree that another peer is hot.
///
/// In peer to peer games it is often still useful to have one system act as a host / server
/// For example, if the game has AI, only the host / server should control the AI
/// This plugin automatically determines the host, changing the host as the prior host disconnects, and allowing all peers to agree on who is the host
///
/// Algorithm:
/// 1. Every system has a synchronized list of RakNetGuid, representing remote systems in the mesh
/// 2. The system at the head of the list is the host.
/// 3. New systems to join the mesh are added to the end of the list.
/// 4. To avoid contention, only the current host modifies or broadcasts the list. Modifications are broadcast to other systems.
/// 5. If the connection to the host is lost, the next connected system in the list becomes the host.
/// 6. If two meshes join each other, the host with the lower RakNetGuid takes precedence, and the lower priority mesh is appended.
///
/// \pre A fully connected mesh is required among the participants - e.g. all participants must eventually connect to all other participants. Otherwise the algorithm will not return the same host among all systems.
/// \note ID_FCM_HOST_CHANGED is returned to RakPeerInterface::Receive() every time the host changes.
/// \ingroup FCM_HOST_GROUP
class RAK_DLL_EXPORT FCMHost : public PluginInterface
{
public:
/// Constructor
FCMHost();
/// Destructor
virtual ~FCMHost();
/// Add a connected system to the list of systems to manage host tracking
/// \param[in] guid The system to add
/// \param[in] groupId Which group to assign this system to. Groups are used if you want to manage more than one list at a time. Use 0 if you don't care.
void AddParticipant(RakNetGUID guid, FCMHostGroupID groupId=0);
/// Remove a participant added with AddParticipant(), or automatically added with SetAutoAddNewConnections(), from all groups
/// \param[in] guid The system to remove
void RemoveParticipantFromAllGroups(RakNetGUID guid);
/// Remove a participant added with AddParticipant(), or automatically added with SetAutoAddNewConnections()
/// \param[in] guid The system to remove
/// \param[in] groupId Which group to remove this system from. Groups are used if you want to manage more than one list at a time. Use 0 if you don't care.
void RemoveParticipant(RakNetGUID guid, FCMHostGroupID groupId=0);
/// If set to true, all subsequent new connections will be added to \a groupId.
/// \param[in] autoAdd If true, removes the need to call AddParticipant() on ID_NEW_INCOMING_CONNECTION or ID_CONNECTION_REQUEST_ACCEPTED
/// Which group to automatically add systems to. Unused parameter if \a autoAdd is false
void SetAutoAddNewConnections(bool autoAdd, FCMHostGroupID groupId=0);
/// Get the current host. This will usually be the oldest system added with AddParticipant() or automatically added with SetAutoAddNewConnections()
/// \param[in] groupId Which group we are referring to.
/// \return A RakNetGuid representing which system should be the host. We are NOT necessarily connected to this system, if the mesh is not fully connected (yet?)
RakNetGUID GetHost(FCMHostGroupID groupId=0) const;
/// Convenience function to return if the attached instance of RakPeerInterface is the host
/// \param[in] groupId Which group we are referring to.
/// \return true if this system is the host, false otherwise.
bool AmIHost(FCMHostGroupID groupId=0) const;
/// Returns if we are connected to other systems, and one of those systems (possibly ourselves) is a host
/// If we are not connected to other systems, then our own system is always the host, and in a sense the host is undetermined
/// This function could also be named HasValidHost, or IsHostDetermined
/// \param[in] groupId Which group we are referring to.
/// \return true If there is a networked host
bool HasConnectedHost(FCMHostGroupID groupId=0) const;
/// Convenience function to return if the attached instance of RakPeerInterface is the host
/// Differs from AmIHost in that if this system is the only system in the mesh, returns false
/// \param[in] groupId Which group we are referring to.
/// \return true if this system is the host, false otherwise.
bool AmIConnectedHost(FCMHostGroupID groupId=0) const;
/// \internal For plugin handling
virtual void OnAttach(RakPeerInterface *peer);
/// \internal For plugin handling
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// \internal For plugin handling
virtual void OnShutdown(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
protected:
void Clear(void);
void OnAddParticipantRequest(RakPeerInterface *peer, Packet *packet);
void OnNewConnection(RakPeerInterface *peer, Packet *packet);
void OnHostListUpdate(RakPeerInterface *peer, Packet *packet);
void WriteHostListGroup(FCMHostGroupID groupId, RakNet::BitStream *bs);
void ReadHostListGroup(RakNet::BitStream *bs, DataStructures::List<RakNetGUID> *theList);
void BroadcastToGroup(FCMHostGroupID groupId, RakNet::BitStream *bs);
void BroadcastGroupList(FCMHostGroupID groupId);
void NotifyUserOfHost(FCMHostGroupID groupId, RakNetGUID guid);
void RemoveParticipantFromGroup(RakNetGUID guid, FCMHostGroupID groupId);
/// List of hosts, in a map of groupIDs
DataStructures::Map<FCMHostGroupID, DataStructures::List<RakNetGUID>* > hostListsGroup;
// All systems added with AddParticipant(). If we become the host, and a system is in this list and not in hostListsGroup,
// Then we add it.
DataStructures::Map<FCMHostGroupID, DataStructures::List<RakNetGUID>* > participantList;
RakPeerInterface *rakPeer;
bool autoAddConnections;
FCMHostGroupID autoAddConnectionsTargetGroup;
};
#endif
+197
View File
@@ -0,0 +1,197 @@
#ifndef __FILE_LIST
#define __FILE_LIST
#include "Export.h"
#include "DS_List.h"
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#include "FileListNodeContext.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
namespace RakNet
{
class BitStream;
}
/// Represents once instance of a file
struct FileListNode
{
/// Name of the file
char *filename;
/// File data (may be null if not ready)
char *data;
/// Length of \a data. May be greater than fileLength if prepended with a file hash
BitSize_t dataLengthBytes;
/// Length of the file
unsigned fileLengthBytes;
/// User specific data for whatever, describing this file.
FileListNodeContext context;
/// If true, data and dataLengthBytes should be empty. This is just storing the filename
bool isAReference;
};
//int RAK_DLL_EXPORT FileListNodeComp( char * const &key, const FileListNode &data );
class RakPeerInterface;
class FileList;
/// Callback interface set with FileList::SetCallback() in case you want progress notifications when FileList::AddFilesFromDirectory() is called
class RAK_DLL_EXPORT FileListProgress
{
public:
FileListProgress() {}
virtual ~FileListProgress() {}
/// First callback called when FileList::AddFilesFromDirectory() starts
virtual void OnAddFilesFromDirectoryStarted(FileList *fileList, char *dir) {
(void) fileList;
(void) dir;
}
/// Called for each directory, when that directory begins processing
virtual void OnDirectory(FileList *fileList, char *dir, unsigned int directoriesRemaining) {
(void) fileList;
(void) dir;
(void) directoriesRemaining;
}
/// Called for each file, when that file begins processing
virtual void OnFile(FileList *fileList, char *dir, char *fileName, unsigned int fileSize) {
(void) fileList;
(void) dir;
(void) fileName;
(void) fileSize;
}
/// This function is called when we are sending a file to a remote system
/// \param[in] fileName The name of the file being sent
/// \param[in] fileLengthBytes How long the file is
/// \param[in] offset The offset in bytes into the file that we are sending
/// \param[in] bytesBeingSent How many bytes we are sending this push
/// \param[in] done If this file is now done with this push
/// \param[in] targetSystem Who we are sending to
virtual void OnFilePush(const char *fileName, unsigned int fileLengthBytes, unsigned int offset, unsigned int bytesBeingSent, bool done, SystemAddress targetSystem)
{
(void) fileName;
(void) fileLengthBytes;
(void) offset;
(void) bytesBeingSent;
(void) done;
(void) targetSystem;
}
};
/// Implementation of FileListProgress to use RAKNET_DEBUG_PRINTF
class RAK_DLL_EXPORT FLP_Printf : public FileListProgress
{
public:
FLP_Printf() {}
virtual ~FLP_Printf() {}
/// First callback called when FileList::AddFilesFromDirectory() starts
virtual void OnAddFilesFromDirectoryStarted(FileList *fileList, char *dir);
/// Called for each directory, when that directory begins processing
virtual void OnDirectory(FileList *fileList, char *dir, unsigned int directoriesRemaining);
};
class RAK_DLL_EXPORT FileList
{
public:
FileList();
~FileList();
/// Add all the files at a given directory.
/// \param[in] applicationDirectory The first part of the path. This is not stored as part of the filename. Use \ as the path delineator.
/// \param[in] subDirectory The rest of the path to the file. This is stored as a prefix to the filename
/// \param[in] writeHash The first SHA1_LENGTH bytes is a hash of the file, with the remainder the actual file data (should \a writeData be true)
/// \param[in] writeData Write the contents of each file
/// \param[in] recursive Whether or not to visit subdirectories
/// \param[in] context User defined byte to store with each file. Use for whatever you want.
void AddFilesFromDirectory(const char *applicationDirectory, const char *subDirectory, bool writeHash, bool writeData, bool recursive, FileListNodeContext context);
/// Deallocate all memory
void Clear(void);
/// Write all encoded data into a bitstream
void Serialize(RakNet::BitStream *outBitStream);
/// Read all encoded data from a bitstream. Clear() is called before deserializing.
bool Deserialize(RakNet::BitStream *inBitStream);
/// Given the existing set of files, search applicationDirectory for the same files.
/// For each file that is missing or different, add that file to \a missingOrChangedFiles. Note: the file contents are not written, and only the hash if written if \a alwaysWriteHash is true
/// alwaysWriteHash and neverWriteHash are optimizations to avoid reading the file contents to generate the hash if not necessary because the file is missing or has different lengths anyway.
/// \param[in] applicationDirectory The first part of the path. This is not stored as part of the filename. Use \ as the path delineator.
/// \param[out] missingOrChangedFiles Output list written to
/// \param[in] alwaysWriteHash If true, and neverWriteHash is false, will hash the file content of the file on disk, and write that as the file data with a length of SHA1_LENGTH bytes. If false, if the file length is different, will only write the filename.
/// \param[in] neverWriteHash If true, will never write the hash, even if available. If false, will write the hash if the file lengths are the same and it was forced to do a comparison.
void ListMissingOrChangedFiles(const char *applicationDirectory, FileList *missingOrChangedFiles, bool alwaysWriteHash, bool neverWriteHash);
/// Return the files that need to be written to make \a input match this current FileList.
/// Specify dirSubset to only consider files that start with this path
/// specify remoteSubdir to assume that all filenames in input start with this path, so strip it off when comparing filenames.
/// \param[in] input Full list of files
/// \param[out] output Files that we need to match input
/// \param[in] dirSubset If the filename does not start with this path, just skip this file.
/// \param[in] remoteSubdir Remove this from the filenames of \a input when comparing to existing filenames.
void GetDeltaToCurrent(FileList *input, FileList *output, const char *dirSubset, const char *remoteSubdir);
/// Assuming FileList contains a list of filenames presumably without data, read the data for these filenames
/// \param[in] applicationDirectory Prepend this path to each filename. Trailing slash will be added if necessary. Use \ as the path delineator.
/// \param[in] writeFileData True to read and store the file data. The first SHA1_LENGTH bytes will contain the hash if \a writeFileHash is true
/// \param[in] writeFileHash True to read and store the hash of the file data. The first SHA1_LENGTH bytes will contain the hash if \a writeFileHash is true
/// \param[in] removeUnknownFiles If a file does not exist on disk but is in the file list, remove it from the file list?
void PopulateDataFromDisk(const char *applicationDirectory, bool writeFileData, bool writeFileHash, bool removeUnknownFiles);
/// By default, GetDeltaToCurrent tags files as non-references, meaning they are assumed to be populated later
/// This tags all files as references, required for IncrementalReadInterface to process them incrementally
void FlagFilesAsReferences(void);
/// Write all files to disk, prefixing the paths with applicationDirectory
/// \param[in] applicationDirectory path prefix
void WriteDataToDisk(const char *applicationDirectory);
/// Add a file, given data already in memory
/// \param[in] filename Name of a file, optionally prefixed with a partial or complete path. Use \ as the path delineator.
/// \param[in] data Contents to write
/// \param[in] dataLength length of the data, which may be greater than fileLength should you prefix extra data, such as the hash
/// \param[in] fileLength Length of the file
/// \param[in] context User defined byte to store with each file. Use for whatever you want.
/// \param[in] isAReference Means that this is just a reference to a file elsewhere - does not actually have any data
void AddFile(const char *filename, const char *data, const unsigned dataLength, const unsigned fileLength, FileListNodeContext context, bool isAReference=false);
/// Add a file, reading it from disk
/// \param[in] filepath Complete path to the file, including the filename itself
/// \param[in] filename filename to store internally, anything you want, but usually either the complete path or a subset of the complete path.
/// \param[in] context User defined byte to store with each file. Use for whatever you want.
void AddFile(const char *filepath, const char *filename, FileListNodeContext context);
/// Delete all files stored in the file list
/// \param[in] applicationDirectory Prefixed to the path to each filename. Use \ as the path delineator.
void DeleteFiles(const char *applicationDirectory);
/// Set a callback to get progress reports about what this class does
/// \param[in] cb A pointer to an externally defined instance of FileListProgress. This pointer is held internally, so should remain valid as long as this class is valid.
void SetCallback(FileListProgress *cb);
// Here so you can read it, but don't modify it
DataStructures::List<FileListNode> fileList;
static bool FixEndingSlash(char *str);
protected:
FileListProgress *callback;
};
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif
+14
View File
@@ -0,0 +1,14 @@
#ifndef __FILE_LIST_NODE_CONTEXT_H
#define __FILE_LIST_NODE_CONTEXT_H
struct FileListNodeContext
{
FileListNodeContext() {}
FileListNodeContext(unsigned char o, unsigned int f) : op(o), fileId(f) {}
~FileListNodeContext() {}
unsigned char op;
unsigned int fileId;
};
#endif
+130
View File
@@ -0,0 +1,130 @@
/// \file
/// \brief A plugin to provide a simple way to compress and incrementally send the files in the FileList structure.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __FILE_LIST_TRANFER_H
#define __FILE_LIST_TRANFER_H
#include "RakNetTypes.h"
#include "Export.h"
#include "PluginInterface.h"
#include "DS_Map.h"
#include "RakNetTypes.h"
#include "PacketPriority.h"
#include "RakMemoryOverride.h"
#include "FileList.h"
class IncrementalReadInterface;
class FileListTransferCBInterface;
class FileListProgress;
struct FileListReceiver;
/// \defgroup FILE_LIST_TRANSFER_GROUP FileListTransfer
/// \ingroup PLUGINS_GROUP
/// \brief A plugin to provide a simple way to compress and incrementally send the files in the FileList structure.
/// Similar to the DirectoryDeltaTransfer plugin, except that it doesn't send deltas based on pre-existing files or actually write the files to disk.
///
/// Usage:
/// Call SetupReceive to allow one file set to arrive. The value returned by FileListTransfer::SetupReceive()
/// is the setID that is allowed.
/// It's up to you to transmit this value to the other system, along with information indicating what kind of files you want to get.
/// The other system should then prepare a FileList and call FileListTransfer::Send(), passing the return value of FileListTransfer::SetupReceive()
/// as the \a setID parameter to FileListTransfer::Send()
/// \ingroup FILE_LIST_TRANSFER_GROUP
class RAK_DLL_EXPORT FileListTransfer : public PluginInterface
{
public:
FileListTransfer();
virtual ~FileListTransfer();
/// Allows one corresponding Send() call from another system to arrive.
/// \param[in] handler The class to call on each file
/// \param[in] deleteHandler True to delete the handler when it is no longer needed. False to not do so.
/// \param[in] allowedSender Which system to allow files from.
/// \return A set ID value, which should be passed as the \a setID value to the Send() call on the other system. This value will be returned in the callback and is unique per file set. Returns 65535 on failure (not connected to sender)
unsigned short SetupReceive(FileListTransferCBInterface *handler, bool deleteHandler, SystemAddress allowedSender);
/// Send the FileList structure to another system, which must have previously called SetupReceive()
/// \param[in] fileList A list of files. The data contained in FileList::data will be sent incrementally and compressed among all files in the set
/// \param[in] rakPeer The instance of RakNet to use to send the message
/// \param[in] recipient The address of the system to send to
/// \param[in] setID The return value of SetupReceive() which was previously called on \a recipient
/// \param[in] priority Passed to RakPeerInterface::Send()
/// \param[in] orderingChannel Passed to RakPeerInterface::Send()
/// \param[in] compressData Depreciated, unsupported
/// \param[in] _incrementalReadInterface If a file in \a fileList has no data, filePullInterface will be used to read the file in chunks of size \a chunkSize
/// \param[in] _chunkSize How large of a block of a file to send at once
void Send(FileList *fileList, RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, bool compressData, IncrementalReadInterface *_incrementalReadInterface=0, unsigned int _chunkSize=8388608);
/// Stop a download.
void CancelReceive(unsigned short setId);
/// Remove all handlers associated with a particular system address
void RemoveReceiver(SystemAddress systemAddress);
/// Is a handler passed to SetupReceive still running?
bool IsHandlerActive(unsigned short setId);
/// Set a callback to get progress reports about what the file list instances do
/// \param[in] cb A pointer to an externally defined instance of FileListProgress. This pointer is held internally, so should remain valid as long as this class is valid.
void SetCallback(FileListProgress *cb);
/// \returns what was sent to SetCallback
/// \return What was sent to SetCallback
FileListProgress *GetCallback(void) const;
/// \internal For plugin handling
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// \internal For plugin handling
virtual void OnShutdown(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
/// \internal For plugin handling
virtual void OnAttach(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void Update(RakPeerInterface *peer);
protected:
bool DecodeSetHeader(Packet *packet);
bool DecodeFile(Packet *packet, bool fullFile);
void Clear(void);
void OnReferencePush(Packet *packet, bool fullFile);
void StoreForPush(FileListNodeContext context, unsigned short _setID, const char *fileName, unsigned int _setIndex, unsigned fileLengthBytes, unsigned dataLengthBytes, SystemAddress recipient, PacketPriority packetPriority, char orderingChannel, IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize);
DataStructures::Map<unsigned short, FileListReceiver*> fileListReceivers;
unsigned short setId;
RakPeerInterface *rakPeer;
FileListProgress *callback;
struct FileToPush
{
FileListNode fileListNode;
SystemAddress systemAddress;
PacketPriority packetPriority;
char orderingChannel;
unsigned int currentOffset;
unsigned short setID;
unsigned int setIndex;
IncrementalReadInterface *incrementalReadInterface;
unsigned int chunkSize;
};
DataStructures::List<FileToPush> filesToPush;
};
#endif
@@ -0,0 +1,99 @@
#ifndef __FILE_LIST_TRANSFER_CALLBACK_INTERFACE_H
#define __FILE_LIST_TRANSFER_CALLBACK_INTERFACE_H
#include "RakMemoryOverride.h"
#include "FileListNodeContext.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// \brief Used by FileListTransfer plugin as a callback for when we get a file.
/// You get the last file when fileIndex==setCount
/// \sa FileListTransfer
class FileListTransferCBInterface
{
public:
struct OnFileStruct
{
/// The index into the set of files, from 0 to setCount
unsigned fileIndex;
/// The name of the file
char fileName[512];
/// The data pointed to by the file
char *fileData;
/// How many bytes this file took to send, if using compression.
unsigned compressedTransmissionLength;
/// The actual length of this file.
BitSize_t finalDataLength;
/// Files are transmitted in sets, where more than one set of files can be transmitted at the same time.
/// This is the identifier for the set, which is returned by FileListTransfer::SetupReceive
unsigned short setID;
/// The number of files that are in this set.
unsigned setCount;
/// The total length of the transmitted files for this set, with compression.
unsigned setTotalCompressedTransmissionLength;
/// The total length of the transmitted files for this set, after being uncompressed
unsigned setTotalFinalLength;
/// User data passed to one of the functions in the FileList class.
/// However, on error, this is instead changed to one of the enumerations in the PatchContext structure.
FileListNodeContext context;
};
FileListTransferCBInterface() {}
virtual ~FileListTransferCBInterface() {}
/// Got a file
/// This structure is only valid for the duration of this function call.
/// \return Return true to have RakNet delete the memory allocated to hold this file for this function call.
virtual bool OnFile(OnFileStruct *onFileStruct)=0;
/// Got part of a big file.
/// You can get these notifications by calling RakPeer::SetSplitMessageProgressInterval
/// Otherwise you will only get complete files.
/// \param[in] onFileStruct General information about this file, such as the filename and the first \a partLength bytes. You do NOT need to save this data yourself. The complete file will arrive normally.
/// \param[in] partCount The zero based index into partTotal. The percentage complete done of this file is 100 * (partCount+1)/partTotal
/// \param[in] partTotal The total number of parts this file was split into. Each part will be roughly the MTU size, minus the UDP header and RakNet headers
/// \param[in] partLength How many bytes long firstDataChunk is
/// \param[in] firstDataChunk The first \a partLength of the final file. If you store identifying information about the file in the first \a partLength bytes, you can read them while the download is taking place. If this hasn't arrived yet, firstDataChunk will be 0
virtual void OnFileProgress(OnFileStruct *onFileStruct,unsigned int partCount,unsigned int partTotal,unsigned int partLength, char *firstDataChunk) {
(void) onFileStruct;
(void) partCount;
(void) partTotal;
(void) partLength;
(void) firstDataChunk;
}
/// Called while the handler is active by FileListTransfer
/// Return false when you are done with the class
/// At that point OnDereference will be called and the class will no longer be maintained by the FileListTransfer plugin.
virtual bool Update(void) {return true;}
/// Called when the download is completed.
/// If you are finished with this class, return false
/// At that point OnDereference will be called and the class will no longer be maintained by the FileListTransfer plugin.
/// Otherwise return true, and Update will continue to be called.
virtual bool OnDownloadComplete(void) {return false;}
/// This function is called when this instance is about to be dereferenced by the FileListTransfer plugin.
/// Update will no longer be called.
/// It will will be deleted automatically if true was passed to FileListTransfer::SetupReceive::deleteHandler
/// Otherwise it is up to you to delete it yourself.
virtual void OnDereference(void) {}
};
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif
+13
View File
@@ -0,0 +1,13 @@
#ifndef __FILE_OPERATIONS_H
#define __FILE_OPERATIONS_H
#include "Export.h"
bool RAK_DLL_EXPORT WriteFileWithDirectories( const char *path, char *data, unsigned dataLength );
bool RAK_DLL_EXPORT IsSlash(unsigned char c);
void RAK_DLL_EXPORT AddSlash( char *input );
void RAK_DLL_EXPORT QuoteIfSpaces(char *str);
bool RAK_DLL_EXPORT DirectoryExists(const char *directory);
unsigned int RAK_DLL_EXPORT GetFileLength(const char *path);
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef __FORMAT_STRING_H
#define __FORMAT_STRING_H
#include "Export.h"
extern "C" {
char * FormatString(const char *format, ...);
}
#endif
+65
View File
@@ -0,0 +1,65 @@
/// \file
/// \brief Fully connected mesh plugin. This will connect RakPeer to all connecting peers, and all peers the connecting peer knows about.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __FULLY_CONNECTED_MESH_H
#define __FULLY_CONNECTED_MESH_H
class RakPeerInterface;
class NatPunchthrough;
#include "PluginInterface.h"
#include "RakMemoryOverride.h"
/// \defgroup FULLY_CONNECTED_MESH_GROUP FullyConnectedMesh
/// \ingroup PLUGINS_GROUP
/// Fully connected mesh plugin. This will connect RakPeer to all connecting peers, and all peers the connecting peer knows about.
/// \pre You must also install the ConnectionGraph plugin. If you want a password, set it there.
/// \ingroup FULLY_CONNECTED_MESH_GROUP
class FullyConnectedMesh : public PluginInterface
{
public:
FullyConnectedMesh();
virtual ~FullyConnectedMesh();
// --------------------------------------------------------------------------------------------
// User functions
// --------------------------------------------------------------------------------------------
/// Set the password to use to connect to the other systems
void Startup(const char *password, int _passwordLength);
/// Use the NAT punchthrough system to connect rather than calling directly
/// \param[in] np Pointer to an attached instance of the NatPunchthrough plugin
/// \param[in] _facilitator Address of the NAT punchthrough facilitator
void ConnectWithNatPunchthrough(NatPunchthrough *np, SystemAddress _facilitator);
// --------------------------------------------------------------------------------------------
// Packet handling functions
// --------------------------------------------------------------------------------------------
virtual void OnShutdown(RakPeerInterface *peer);
virtual void Update(RakPeerInterface *peer);
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
protected:
char *pw;
int passwordLength;
NatPunchthrough *natPunchthrough;
SystemAddress facilitator;
};
#endif
+130
View File
@@ -0,0 +1,130 @@
/// \file
/// \brief A set of classes to make it easier to perform asynchronous function processing.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __FUNCTION_THREAD_H
#define __FUNCTION_THREAD_H
#include "SingleProducerConsumer.h"
#include "ThreadPool.h"
#include "RakMemoryOverride.h"
#include "Export.h"
namespace RakNet
{
// Forward declarations
class Functor;
/// FunctionThread takes a stream of classes that implement a processing function, processes them in a thread, and calls a callback with the result.
/// It's a useful way to call blocking functions that you do not want to block, such as file writes and database operations.
class RAK_DLL_EXPORT FunctionThread
{
public:
FunctionThread();
~FunctionThread();
struct FunctorAndContext
{
Functor *functor;
void *context;
};
/// Starts the thread up.
void StartThreads(int numThreads);
/// Stop processing. Will also call FunctorResultHandler callbacks with /a wasCancelled set to true.
/// \param[in] blockOnCurrentProcessing Wait for the current processing to finish?
void StopThreads(bool blockOnCurrentProcessing);
/// Add a functor to the incoming stream of functors
/// \note functor MUST be a valid pointer until Functor::HandleResult() is called, at which point the pointer is returned to you.
/// \note For practical purposes this means the instance of functor you pass to this function has to be allocated using new and delete.
/// \note You should deallocate the pointer inside Functor::HandleResult()
/// \param[in] functor A pointer to an implemented Functor class
/// \param[in] If there is some context to this functor you want to look up to cancel it, you can set it here. Returned back to you in Functor::HandleResult
void Push(Functor *functor, void *context=0);
/// Call FunctorResultHandler callbacks
/// Normally you would call this once per update cycle, although you do not have to.
void CallResultHandlers(void);
/// If you want to cancel input and output functors associated with some context, you can pass a function to do that here
/// \param[in] cancelThisFunctor Function should return true to cancel the functor, false to let it process
/// \param[in] userData Pointer to whatever you want. Passed to the cancelThisFunctor call
void CancelFunctorsWithContext(bool (*cancelThisFunctor)(FunctorAndContext func, void *userData), void *userData);
/// If you want to automatically do some kind of processing on every functor after Functor::HandleResult is called, set it here.
/// Useful to cleanup FunctionThread::Push::context
/// \param[in] postResult pointer to a C function to do post-processing
void SetPostResultFunction(void (*postResult)(FunctorAndContext func));
protected:
void CancelInput(void);
ThreadPool<FunctorAndContext, FunctorAndContext> threadPool;
void (*pr)(FunctorAndContext func);
};
/// A functor is a single unit of processing to send to the Function thread.
/// Derive from it, add your data, and implement the processing function.
class Functor
{
public:
Functor() {}
virtual ~Functor() {}
/// Do whatever processing you want.
/// \param[in] context pointer passed to FunctionThread::Push::context
virtual void Process(void *context)=0;
/// Called from FunctionThread::CallResultHandlers with wasCancelled false OR
/// Called from FunctionThread::StopThread or FunctionThread::~FunctionThread with wasCancelled true
/// \param[in] wasCancelledTrue if CallResultHandlers was called, false if StopThreads or CancelInputWithContext was called before Functor::Process()
/// \param[in] context pointer passed to FunctionThread::Push::context
virtual void HandleResult(bool wasCancelled, void *context)=0;
};
class RAK_DLL_EXPORT FunctionThreadDependentClass
{
public:
FunctionThreadDependentClass();
virtual ~FunctionThreadDependentClass();
/// Assigns a function thread to process asynchronous calls. If you do not assign one then one will be created automatically.
/// \param[in] ft An instance of a running function thread class. This class can be shared and used for other functors as well.
virtual void AssignFunctionThread(FunctionThread *ft);
/// \return Returns the function thread held in the class
FunctionThread *GetFunctionThread(void) const;
/// \returns Whether or not this class allocated the function thread by itself
bool GetFunctionThreadWasAllocated(void) const;
/// Allocates and starts the thread if needed, and pushes the functor
/// \param[in] functor Functor to push
/// \param[in] context Sent to FunctionThread::Push::context
virtual void PushFunctor(Functor *functor, void *context=0);
protected:
/// Allocates and starts the function thread, if necessary
void StartFunctionThread();
FunctionThread *functionThread;
bool functionThreadWasAllocated;
};
}
#endif
+767
View File
@@ -0,0 +1,767 @@
#ifndef __GEN_RPC8_H
#define __GEN_RPC8_H
#include <stdlib.h>
#include <stdio.h>
#include <string.h> // memcpy
#include <typeinfo>
#if defined(_XBOX) || defined(X360)
#include <XBOX360Includes.h>
#elif defined (_WIN32)
#include <windows.h>
#endif
#include <stddef.h>
//#define ASSEMBLY_BLOCK asm
//#include "Types.h"
#include "BitStream.h"
// #define AUTO_RPC_NO_ASM
#ifdef _WIN64
#define AUTO_RPC_NO_ASM
#endif
namespace GenRPC
{
//#define __BITSTREAM_NATIVE_END 1
// -8<----8<----8<----BEGIN
//
// 0. References
// a. Calling conventions for different C++ compilers and operating systems [http://www.agner.org/optimize]
// b. System V Application Binary Interface AMD64 Architecture Processor Supplement
// Used by 64-bit MAC and 64-bit Linux.
// c. 32-bit PowerPC MAC calling conventions [http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/32bitPowerPC.html#//apple_ref/doc/uid/TP40002438-SW20]
// d. 32-bit IA MAC calling conventions [http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/IA32.html#//apple_ref/doc/uid/TP40002492-SW4]
// e. Calling conventions on 64-bit windows [http://msdn2.microsoft.com/en-us/library/zthk2dkh(VS.80).aspx]
// f. 64-bit PowerPC MAC calling conventions [http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/64bitPowerPC.html#//apple_ref/doc/uid/TP40002471]
//
// 1. General Introduction.
//
// Quite a lot of code we write hinges on hidden assumptions. For instance, most code tacitly
// assumes a char is 8 bits, even though it needn't be. And how much code relies on
// two's-a-compliment numbers, by, for example, assuming the only representation of zero
// is all bits clear? Yet this too isn't mandated by the C standard - which allows for non
// two's a compliment numbers.
// And the switch to 64-bit will see us discovering how
// much of our code assumes sizeof(int) == sizeof(long) == sizeof(void*)
//
// These tradeoffs and compromises are made because we know the architectures
// with CHAR_BITS != 8 are embedded systems of FPGAs and we don't extend our definition of
// portability to those systems. Or Windows code can
// assume its running on a little-endian machine, without loss of generality. In fact, it
// often impossible to test our code in situatiosn where assumptions are not true.
//
// The same is true of a lightweight RPC - to be possible at all, it will have make some
// assumptions about the architecture on (like CHAR_BITS == 8) which limit portability, but
// which are not unreasonable for the cases where its expected to run (modern personal computers)
// and hopefully can be extended easily to meet new cases.
//
// 2. Parameter passing - Introduction
//
// The C standard doesn't mandate how parameters are passed from one function to another.
// That's down to the particular archictecture, normally laid out in the Application Binary
// Interface (ABI).
//
// On some architecture (e.g. 32bit X86) the parameters are all passed on the stack;
// on some architectures (e.g. SPARC) there is no stack and they are all passed in register.
// Sometimes the function must be passed the exact number of args it expects (e.g. WIN32
// "stdcall"); somtimes it can take an arbitrary number of args (IA-32/64 linux).
//
// But whatever the case, the compiler knows about all the details - it sorts them out every
// time we write a call. So to make it portable we must ensure we pass the compiler *sufficient*
// information to be able to encode the call, in all the cases we're interested in. To do this
// we need some knowledge of the ABI, without getting our hands dirty writing assembler.
// Not only because we can't all be experts at every particularl architecture with its necessary
// prefetches, conditional moves and innate parralelism, but also because that allows the compiler to
// code for the exact processors - rather than using a lowest-common denominator.
//
//
// 3. Preparing parameters and assumptions
//
// We assume that the processor has a 32 bit or 64 bit "natural word size" - and that the
// registers, stack entries (if a stack exists) and pointers all have this natural word
// size. We further assume (1) parameters smaller than this have to be padded out to meet this
// size, and that (2) this can be done by zero-extended them, regardless of whether they are signed
// or unsigned quanitites.
//
// The SysV ABI for 64bit X86 [b] and that ABI for 64-bit windows [e] require that floating point
// parameters are passed in floating points registers - so to work with these types we need to know
// they are floats and alert the compiler. A similar arrangement is true for both 32-bit and 64-bit
// Power PC systems.
//
// This can extend to structures ("aggregate types") containing floating point numbers - where
// individual members can still be passed in register. (Although
// on 64-bit windows, aggregates of size > 8 bytes are passed on the stack, so,
// except for the pathological case of struct S { double F }; there are no problems with
// structures containing floats.)
//
// ---
//
// AUTO_RPC_MAX_PARAMS: Absolute number of stack words we can handle
// ABI: used to select features specific to ABI.
// AUTO_RPC_INT_REG_PARAMS: Number of parameters passed in integer registers. (Only used by SYSV ABI)
// AUTO_RPC_FLOAT_REG_PARAMS: Number of parameters passed in floating point registers.
// AUTO_RPC_INT_SHADOW_OF_FLOATS: Create a copy of the floats in the integer/stack space.
// AUTO_RPC_ALLOC_SEPARATE_FLOATS: Push floats to a separate contiguous floating point "stack".
// Ortherwise we rely on shadow.
//
// PARAMETER_REF_THRESHOLD: parameters bigger than this are replaced by a reference ( WIN64 )
//
//
#define AUTO_RPC_MAX_PARAMS 64
#define AUTO_RPC_ABI_NONE 0 // not supported - should fail.
#define AUTO_RPC_ABI_IA_32 1 // all parameters are passed on the stack.
// preserves: ebx,esi,edi,ebp
#define AUTO_RPC_ABI_WIN_AMD64 2 // first four parameters in either
// rcx|xmm0, rdx|xmm1,r8|xmm2,r9|xmm3
// preserves: rbx,rsi,rdi,rbp,r12-r15; xmm6-xmm15
// comments: aggregates > 8 passed by ref; reg params shadowed on stack
#define AUTO_RPC_ABI_SYSV_AMD64 3 // first six ints in: rdi,rsi,rdx,rcx,r8,r9
// first eight reals: in xmm0...xmm7
// preserves: rbx,rbp,r12-r15
// comments: aggregates > 16 bumped to stack
#define AUTO_RPC_ABI_PPC 4 // first 6 args (even if float) in int reg; first 13 floats in reg.
// parameter passing area with shadow area.
// Configure the parameters for the system.
#if defined(__i386__) || defined( _M_IX86 ) || defined( __INTEL__ )
// 32 bit system.
#define AUTO_RPC_AUTORPC_WORD 32
typedef unsigned int NaturalWord;
typedef double HardwareReal;
#define AUTO_RPC_INT_REG_PARAMS 0
#define AUTO_RPC_FLOAT_REG_PARAMS 0
#define AUTO_RPC_ABI AUTO_RPC_ABI_IA_32
#define AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD 0
#define AUTO_RPC_INT_SHADOW_OF_FLOATS 1
#define AUTO_RPC_ALLOC_SEPARATE_FLOATS 0
#define AUTO_RPC_CREATE_FLOAT_MAP 0
#elif defined( _M_X64 ) || defined( __x86_64__ ) || defined( _M_AMD64 )
#define AUTO_RPC_AUTORPC_WORD 64
#if defined( _WIN64 )
#define AUTO_RPC_FLOAT_REG_PARAMS 4
#define AUTO_RPC_INT_REG_PARAMS 4
#define AUTO_RPC_ABI AUTO_RPC_ABI_WIN_AMD64
#define AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD 8
#define AUTO_RPC_INT_SHADOW_OF_FLOATS 1
#define AUTO_RPC_ALLOC_SEPARATE_FLOATS 0
#define AUTO_RPC_CREATE_FLOAT_MAP 1
#else
#define AUTO_RPC_ABI AUTO_RPC_ABI_SYSV_AMD64
#define AUTO_RPC_INT_REG_PARAMS 6
#define AUTO_RPC_FLOAT_REG_PARAMS 8
#define AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD 0
#define AUTO_RPC_INT_SHADOW_OF_FLOATS 0
#define AUTO_RPC_ALLOC_SEPARATE_FLOATS 1
#define AUTO_RPC_CREATE_FLOAT_MAP 0
#endif
// NB OS's differ over.
typedef unsigned long long NaturalWord;
typedef double HardwareReal; // could be changed to __float128 on AMD64/nonwin
#elif defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3)
typedef double HardwareReal;
typedef unsigned long long NaturalWord;
#define AUTO_RPC_AUTORPC_WORD 64
#define AUTO_RPC_INT_REG_PARAMS 8
#define AUTO_RPC_FLOAT_REG_PARAMS 13
#define AUTO_RPC_INT_SHADOW_OF_FLOATS 1
#define AUTO_RPC_ALLOC_SEPARATE_FLOATS 1
#define AUTO_RPC_CREATE_FLOAT_MAP 0
#define AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD 0
#define AUTO_RPC_ABI AUTO_RPC_ABI_PPC
#elif defined(_M_PPC) || defined( __POWERPC__ )
#include <limits.h>
/// PPC Mac doesn't support sizeof( long ) in an #if statement
#if defined (LONG_BIT)
#if LONG_BIT == 64
#define AUTORPC_WORD 64
typedef double HardwareReal;
typedef unsigned long long NaturalWord;
#else
#define AUTORPC_WORD 32
typedef double HardwareReal;
typedef unsigned int NaturalWord;
#endif
#else
#if defined(_XBOX) || defined(X360)
#define AUTORPC_WORD 32
typedef double HardwareReal;
typedef unsigned int NaturalWord;
#else
#if sizeof( long ) == 8
#define AUTORPC_WORD 64
typedef double HardwareReal;
typedef unsigned long long NaturalWord;
#else
#define AUTORPC_WORD 32
typedef double HardwareReal;
typedef unsigned int NaturalWord;
#endif
#endif
#endif
#define AUTO_RPC_INT_REG_PARAMS 8
#define AUTO_RPC_FLOAT_REG_PARAMS 13
#define AUTO_RPC_INT_SHADOW_OF_FLOATS 1
#define AUTO_RPC_ALLOC_SEPARATE_FLOATS 1
#define AUTO_RPC_CREATE_FLOAT_MAP 0
#define AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD 0
#define AUTO_RPC_ABI AUTO_RPC_ABI_PPC
#else
#ifdef __GNUC__
// gcc won't implemented message - so use #warning
#warning Unknown Architecture
#else
#pragma message( Unknown architecture )
#endif
// defining AUTO_RPC_ABI_NONE, creates stub code that fails
#define AUTO_RPC_ABI AUTO_RPC_ABI_NONE
#endif
//
// Calling convention - we need to be explict on WIN32, so we do that here. Everybody else
// has only one fixed, calling convention.
//
#ifdef _WIN32
#define AUTO_RPC_CALLSPEC WINAPIV
#else
#define AUTO_RPC_CALLSPEC
#endif
//
// useful macros; could be rewritten inline/inline templates
//
#define AUTO_RPC__ALIGN_P2( len, bytes ) ( ( len + bytes - 1 ) & ~( bytes - 1 ) )
// Return len rounded-up to an integral number of sizeof(type) - provided sizeof(type) is a power of 2
#define AUTO_RPC_ALIGN_P2( len, type ) AUTO_RPC__ALIGN_P2( len, sizeof( type ) )
// Return ptr to end of 'array[xxx]'
#define AUTO_RPC_ARRAY_END( array ) &array[ sizeof( array ) / sizeof( array[0] ) ]
// strip floating point params if there are no float regs.
#if !AUTO_RPC_FLOAT_REG_PARAMS
#if AUTO_RPC_CREATE_FLOAT_MAP
#undef AUTO_RPC_CREATE_FLOAT_MAP
#define AUTO_RPC_CREATE_FLOAT_MAP 0
#endif
#if AUTO_RPC_ALLOC_SEPARATE_FLOATS
#undef AUTO_RPC_ALLOC_SEPARATE_FLOATS
#define AUTO_RPC_ALLOC_SEPARATE_FLOATS 0
#endif
#endif // FLOAT_REG_PARAM
#define AUTO_RPC_REF_ALIGN 16 // some structures must be memory aligned to 16 bytes, even, on 32-bit systems.
// stack simialrly must be aligned
#define AUTO_RPC_STACK_PADDING ( sizeof( NaturalWord ) / AUTO_RPC_REF_ALIGN )
// defining these externally makes the code a hell of a lot more readable.
#ifdef USE_VARADIC_CALL
#define AUTO_RPC_NW_3 ...
#define AUTO_RPC_NW_6 ...
#define AUTO_RPC_NW_9 ...
#define AUTO_RPC_NW_12 ...
#define AUTO_RPC_NW_64 ...
#else
#define AUTO_RPC_NW_3 NaturalWord,NaturalWord,NaturalWord
#define AUTO_RPC_NW_6 NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord
#define AUTO_RPC_NW_9 NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord
#define AUTO_RPC_NW_5 NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord
#define AUTO_RPC_NW_4_9 AUTO_RPC_NW_5
#define AUTO_RPC_NW_12 NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord
#define AUTO_RPC_NW_32 NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord
#define AUTO_RPC_NW_64 NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord
#define AUTO_RPC_NW_60 NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord,\
NaturalWord,NaturalWord,NaturalWord,NaturalWord
#define AUTO_RPC_NW_4_64 AUTO_RPC_NW_60
#endif // USE VARADIC
#define AUTO_RPC_INT_ARGS_3( call ) call.intParams[0],call.intParams[1],call.intParams[2]
#define AUTO_RPC_INT_ARGS_6( call ) call.intParams[0],call.intParams[1],call.intParams[2],call.intParams[3],\
call.intParams[4],call.intParams[5]
#define AUTO_RPC_INT_ARGS_9( call ) call.intParams[0],call.intParams[1],call.intParams[2],call.intParams[3],\
call.intParams[4],call.intParams[5],call.intParams[6],call.intParams[7],\
call.intParams[8]
#define AUTO_RPC_INT_ARGS_4_9( call ) call.intParams[4],call.intParams[5],call.intParams[6],call.intParams[7],\
call.intParams[8]
#define AUTO_RPC_INT_ARGS_12( call ) call.intParams[0],call.intParams[1],call.intParams[2],call.intParams[3],\
call.intParams[4],call.intParams[5],call.intParams[6],call.intParams[7],\
call.intParams[8],call.intParams[9],call.intParams[10],call.intParams[11]
#define AUTO_RPC_INT_ARGS_32( call ) call.intParams[0],call.intParams[1],call.intParams[2],call.intParams[3],\
call.intParams[4],call.intParams[5],call.intParams[6],call.intParams[7],\
call.intParams[8],call.intParams[9],call.intParams[10],call.intParams[11],\
call.intParams[12],call.intParams[13],call.intParams[14],call.intParams[15],\
call.intParams[16],call.intParams[17],call.intParams[18],call.intParams[19],\
call.intParams[20],call.intParams[21],call.intParams[22],call.intParams[23],\
call.intParams[24],call.intParams[25],call.intParams[26],call.intParams[27],\
call.intParams[28],call.intParams[29],call.intParams[30],call.intParams[31]
#define AUTO_RPC_INT_ARGS_4_64( call ) call.intParams[4],call.intParams[5],call.intParams[6],call.intParams[7],\
call.intParams[8],call.intParams[9],call.intParams[10],call.intParams[11],\
call.intParams[12],call.intParams[13],call.intParams[14],call.intParams[15],\
call.intParams[16],call.intParams[17],call.intParams[18],call.intParams[19],\
call.intParams[20],call.intParams[21],call.intParams[22],call.intParams[23],\
call.intParams[24],call.intParams[25],call.intParams[26],call.intParams[27],\
call.intParams[28],call.intParams[29],call.intParams[30],call.intParams[31],\
call.intParams[32],call.intParams[33],call.intParams[34],call.intParams[35],\
call.intParams[36],call.intParams[37],call.intParams[38],call.intParams[39],\
call.intParams[40],call.intParams[41],call.intParams[42],call.intParams[43],\
call.intParams[44],call.intParams[45],call.intParams[46],call.intParams[47],\
call.intParams[48],call.intParams[49],call.intParams[50],call.intParams[51],\
call.intParams[52],call.intParams[53],call.intParams[54],call.intParams[55],\
call.intParams[56],call.intParams[57],call.intParams[58],call.intParams[59],\
call.intParams[60],call.intParams[61],call.intParams[62],call.intParams[63]
#define AUTO_RPC_INT_ARGS_64( call ) call.intParams[0],call.intParams[1],call.intParams[2],call.intParams[3],\
call.intParams[4],call.intParams[5],call.intParams[6],call.intParams[7],\
call.intParams[8],call.intParams[9],call.intParams[10],call.intParams[11],\
call.intParams[12],call.intParams[13],call.intParams[14],call.intParams[15],\
call.intParams[16],call.intParams[17],call.intParams[18],call.intParams[19],\
call.intParams[20],call.intParams[21],call.intParams[22],call.intParams[23],\
call.intParams[24],call.intParams[25],call.intParams[26],call.intParams[27],\
call.intParams[28],call.intParams[29],call.intParams[30],call.intParams[31],\
call.intParams[32],call.intParams[33],call.intParams[34],call.intParams[35],\
call.intParams[36],call.intParams[37],call.intParams[38],call.intParams[39],\
call.intParams[40],call.intParams[41],call.intParams[42],call.intParams[43],\
call.intParams[44],call.intParams[45],call.intParams[46],call.intParams[47],\
call.intParams[48],call.intParams[49],call.intParams[50],call.intParams[51],\
call.intParams[52],call.intParams[53],call.intParams[54],call.intParams[55],\
call.intParams[56],call.intParams[57],call.intParams[58],call.intParams[59],\
call.intParams[60],call.intParams[61],call.intParams[62],call.intParams[63]
#if AUTO_RPC_ALLOC_SEPARATE_FLOATS
#if AUTO_RPC_FLOAT_REG_PARAMS == 8
#define AUTO_RPC_FLOAT_REG_TYPE HardwareReal,HardwareReal,HardwareReal,HardwareReal,\
HardwareReal,HardwareReal,HardwareReal,HardwareReal
#define AUTO_RPC_FLOAT_REG_ARGS( a ) a.realParams[0],a.realParams[1],a.realParams[2],a.realParams[3],\
a.realParams[4],a.realParams[5],a.realParams[6],a.realParams[7]
#elif AUTO_RPC_FLOAT_REG_PARAMS == 4
#define AUTO_RPC_FLOAT_REG_TYPE HardwareReal,HardwareReal,HardwareReal,HardwareReal
#define AUTO_RPC_FLOAT_REG_ARGS( a ) a.realParams[0],a.realParams[1],a.realParams[2],a.realParams[3]
#elif AUTO_RPC_FLOAT_REG_PARAMS == 13
#define AUTO_RPC_FLOAT_REG_TYPE HardwareReal,HardwareReal,HardwareReal,HardwareReal,\
HardwareReal,HardwareReal,HardwareReal,HardwareReal,\
HardwareReal,HardwareReal,HardwareReal,HardwareReal,HardwareReal
#define AUTO_RPC_FLOAT_REG_ARGS( a ) a.realParams[0],a.realParams[1],a.realParams[2],a.realParams[3],\
a.realParams[4],a.realParams[5],a.realParams[6],a.realParams[7],\
a.realParams[8],a.realParams[9],a.realParams[10],a.realParams[11],a.realParams[12]
#elif AUTO_RPC_FLOAT_REG_PARAMS
#error Need FLOAT_REG_TYPE and AUTO_RPC_FLOAT_REG_ARGS setup
#endif
#endif // AUTO_RPC_ALLOC_SEPARATE_FLOATS
/// \internal
/// Writes number of parameters to push on the stack
void SerializeHeader(char *&out, unsigned int numParams);
/// Builds up a function call and all parameters onto a stack
/// \param[out] Destination stack, which must be big enough to hold all parameters
unsigned int BuildStack(char *stack);
/// Builds up a function call and all parameters onto a stack
/// \param[out] Destination stack, which must be big enough to hold all parameters
template <class P1>
unsigned int BuildStack(char *stack, P1 p1,
bool es1=true)
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 1);
PushHeader(stackPtr, p1, es1);
Push( stackPtr, p1, es1 );
return (unsigned int)(stackPtr-stack);
}
/// Builds up a function call and all parameters onto a stack
/// \param[out] Destination stack, which must be big enough to hold all parameters
template <class P1, class P2>
unsigned int BuildStack(char *stack, P1 p1, P2 p2,
bool es1=true, bool es2=true)
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 2);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
return (unsigned int)(stackPtr-stack);
}
/// Builds up a function call and all parameters onto a stack
/// \param[out] Destination stack, which must be big enough to hold all parameters
template <class P1, class P2, class P3>
unsigned int BuildStack(char *stack, P1 p1, P2 p2, P3 p3,
bool es1=true, bool es2=true, bool es3=true )
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 3);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
return (unsigned int)(stackPtr-stack);
}
/// Builds up a function call and all parameters onto a stack
/// \param[out] Destination stack, which must be big enough to hold all parameters
template <class P1, class P2, class P3, class P4>
unsigned int BuildStack(char *stack, P1 p1, P2 p2, P3 p3, P4 p4,
bool es1=true, bool es2=true, bool es3=true, bool es4=true )
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 4);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
return (unsigned int)(stackPtr-stack);
}
/// Builds up a function call and all parameters onto a stack
/// \param[out] Destination stack, which must be big enough to hold all parameters
template <class P1, class P2, class P3, class P4, class P5>
unsigned int BuildStack(char *stack, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5,
bool es1=true, bool es2=true, bool es3=true, bool es4=true, bool es5=true )
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 5);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
PushHeader(stackPtr, p5, es5);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
Push( stackPtr, p5, es5 );
return (unsigned int)(stackPtr-stack);
}
/// Builds up a function call and all parameters onto a stack
/// \param[out] Destination stack, which must be big enough to hold all parameters
template <class P1, class P2, class P3, class P4, class P5, class P6>
unsigned int BuildStack(char *stack, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6,
bool es1=true, bool es2=true, bool es3=true, bool es4=true, bool es5=true, bool es6=true )
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 6);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
PushHeader(stackPtr, p5, es5);
PushHeader(stackPtr, p6, es6);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
Push( stackPtr, p5, es5 );
Push( stackPtr, p6, es6 );
return (unsigned int)(stackPtr-stack);
}
/// Builds up a function call and all parameters onto a stack
/// \param[out] Destination stack, which must be big enough to hold all parameters
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
unsigned int BuildStack(char *stack, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7,
bool es1=true, bool es2=true, bool es3=true, bool es4=true, bool es5=true, bool es6=true, bool es7=true )
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 7);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
PushHeader(stackPtr, p5, es5);
PushHeader(stackPtr, p6, es6);
PushHeader(stackPtr, p7, es7);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
Push( stackPtr, p5, es5 );
Push( stackPtr, p6, es6 );
Push( stackPtr, p7, es7 );
return (unsigned int)(stackPtr-stack);
}
/// Builds up a function call and all parameters onto a stack
/// \param[out] Destination stack, which must be big enough to hold all parameters
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
unsigned int BuildStack(char *stack, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8,
bool es1=true, bool es2=true, bool es3=true, bool es4=true, bool es5=true, bool es6=true, bool es7=true, bool es8=true )
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 8);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
PushHeader(stackPtr, p5, es5);
PushHeader(stackPtr, p6, es6);
PushHeader(stackPtr, p7, es7);
PushHeader(stackPtr, p8, es8);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
Push( stackPtr, p5, es5 );
Push( stackPtr, p6, es6 );
Push( stackPtr, p7, es7 );
Push( stackPtr, p8, es8 );
return (unsigned int)(stackPtr-stack);
}
/// \internal
template <class item>
void Push( char*& p, item const i, bool doEndianSwap ) {
memcpy( (void*)p, (void*)&i, sizeof( i ) );
if (doEndianSwap && RakNet::BitStream::DoEndianSwap())
RakNet::BitStream::ReverseBytesInPlace((unsigned char*) p,sizeof( i ));
p += sizeof( i );
}
/// \internal
template <class item>
void Push( char*& p, item*const i, bool doEndianSwap) {
memcpy( (void*)p, (void*)i, sizeof( *i ) );
if (doEndianSwap && RakNet::BitStream::DoEndianSwap())
RakNet::BitStream::ReverseBytesInPlace((unsigned char*) p,sizeof( i ));
p += sizeof( *i );
}
/// \internal
template <class item>
void Push( char*& p, item const*const i, bool doEndianSwap) {
memcpy( (void*)p, (void*)i, sizeof( *i ) );
if (doEndianSwap && RakNet::BitStream::DoEndianSwap())
RakNet::BitStream::ReverseBytesInPlace((unsigned char*) p,sizeof( i ));
p += sizeof( *i );
}
/// \internal
void Push( char*& p, char*const i, bool doEndianSwap);
/// \internal
void Push( char*& p, const char*const i, bool doEndianSwap );
// THIS STRUCTURE LAYOUT IS HARDCODED INTO THE ASSEMBLY. Unfortunately, that appears to be the
// only way to do it.
struct CallParams {
#if AUTO_RPC_ABI
#if AUTO_RPC_FLOAT_REG_PARAMS
// on most platforms, just a bool telling us whether we need any floats.
unsigned numRealParams;
#if AUTO_RPC_CREATE_FLOAT_MAP
//
// bitmask: bit(n) set indicate parameter n is a float, not an int.
//
unsigned realMap;
#endif
// N.B. these may not have type HardwareReal - they're not promoted or converted.
#if AUTO_RPC_ALLOC_SEPARATE_FLOATS
HardwareReal realParams[ AUTO_RPC_FLOAT_REG_PARAMS ];
#endif
#endif // AUTO_RPC_FLOAT_REG_PARAMS
unsigned numIntParams;
#if !AUTO_RPC_ALLOC_SEPARATE_FLOATS && AUTO_RPC_FLOAT_REG_PARAMS && AUTO_RPC_CREATE_FLOAT_MAP
union {
HardwareReal realParams[ AUTO_RPC_FLOAT_REG_PARAMS ];
#endif
NaturalWord intParams[ ( AUTO_RPC_MAX_PARAMS > AUTO_RPC_INT_REG_PARAMS ? AUTO_RPC_MAX_PARAMS : AUTO_RPC_INT_REG_PARAMS ) + AUTO_RPC_STACK_PADDING ];
#if !AUTO_RPC_ALLOC_SEPARATE_FLOATS && AUTO_RPC_FLOAT_REG_PARAMS && AUTO_RPC_CREATE_FLOAT_MAP
};
#endif
char refParams[ AUTO_RPC_MAX_PARAMS * AUTO_RPC_REF_ALIGN ];
#endif // AUTO_RPC_ABI
};
/// Given a stack, the length of the stack, a possible last parameter, and a possible this pointer, build a call to a C or C++ function
bool DeserializeParametersAndBuildCall(
CallParams &call,
char *in, unsigned int inLength,
void *lastParam, void *thisPtr);
// Given the output of DeserializeParametersAndBuildCall, actually call a function
bool CallWithStack( CallParams& call, void *functionPtr );
/// \internal
/// functions to return the size of the item.
template <class item>
size_t D_size( item const ) { return sizeof( item ); }
/// \internal
/// functions to return the size of the item.
template <class item>
size_t D_size( item const*const ) { return sizeof( item ); }
/// \internal
/// functions to return the size of the item.
template <class item>
size_t D_size( item*const ) { return sizeof( item ); }
/// \internal
size_t D_size( char*const str );
/// \internal
size_t D_size( char const*const str );
/// \internal
enum {
// to maintain binary compatibility with a historical decision, bit 1 is not used
// in defining the "well known param" types
PARAM_TYPE_MASK = 0x5,
INT_PARAM = 0, // pass by value an integer or structure composed of integers.
REAL_PARAM = 1, // pass by value a SINGLE floating point parameter.
REF_PARAM = 4, // pass a pointer or reference to data which must be aligned.
STR_PARAM = 5, // pass a pointer to this data, which need not be unaligned;
// but MUST be null terminated.
// OBJECT_PARAM = 8, // TODO: pass by value an object, object id as first uint32_t of serialized data?
// OBJECT_REF_PARAM = 9, // TODO: pass by reference an object, object id as first uint32_t of serialized data?
// SC == "Shift count" (Bit index); which is always useful.
ENDIAN_SWAP_SC = 1, DO_ENDIAN_SWAP = 1 << ENDIAN_SWAP_SC,
RESERVED_BITS = 0xf8,
};
/// \internal
template <class item>
unsigned D_type( item const ) { return INT_PARAM; }
/// \internal
template <class item>
unsigned D_type( item const*const ) { return REF_PARAM; }
/// \internal
template <class item>
unsigned D_type( item*const ) { return REF_PARAM; }
/// \internal
unsigned D_type( const char*const );
/// \internal
unsigned D_type( char*const );
/// \internal
unsigned D_type( float );
/// \internal
unsigned D_type( double );
/// \internal
unsigned D_type( long double );
/// \internal
template <class item>
void PushHeader( char*& p, item const i, bool endianSwap ) {
unsigned int s = (unsigned int) D_size( i );
unsigned char f = D_type( i ) | ( ((int) endianSwap) << ENDIAN_SWAP_SC );
Push( p, s, endianSwap );
Push( p, f, false );
}
}
#endif
+39
View File
@@ -0,0 +1,39 @@
/// \file
/// \brief Returns the value from QueryPerformanceCounter. This is the function RakNet uses to represent time.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __GET_TIME_H
#define __GET_TIME_H
#include "Export.h"
#include "RakNetTime.h" // For RakNetTime
/// The namespace RakNet is not consistently used. It's only purpose is to avoid compiler errors for classes whose names are very common.
/// For the most part I've tried to avoid this simply by using names very likely to be unique for my classes.
namespace RakNet
{
/// Returns the value from QueryPerformanceCounter. This is the function RakNet uses to represent time.
// Should be renamed GetTimeMS
RakNetTime RAK_DLL_EXPORT GetTime( void );
// Should be renamed GetTimeUS
RakNetTimeNS RAK_DLL_EXPORT GetTimeNS( void );
// Renames, for RakNet 4
inline RakNetTime RAK_DLL_EXPORT GetTimeMS( void ) {return GetTime();}
inline RakNetTimeNS RAK_DLL_EXPORT GetTimeUS( void ) {return GetTimeNS();}
}
#endif
+68
View File
@@ -0,0 +1,68 @@
#ifndef _GRID_SECTORIZER_H
#define _GRID_SECTORIZER_H
//#define _USE_ORDERED_LIST
#include "RakMemoryOverride.h"
#ifdef _USE_ORDERED_LIST
#include "DS_OrderedList.h"
#else
#include "DS_List.h"
#endif
class GridSectorizer
{
public:
GridSectorizer();
~GridSectorizer();
// _cellWidth, _cellHeight is the width and height of each cell in world units
// minX, minY, maxX, maxY are the world dimensions (can be changed to dynamically allocate later if needed)
void Init(const float _maxCellWidth, const float _maxCellHeight, const float minX, const float minY, const float maxX, const float maxY);
// Adds a pointer to the grid with bounding rectangle dimensions
void AddEntry(void *entry, const float minX, const float minY, const float maxX, const float maxY);
#ifdef _USE_ORDERED_LIST
// Removes a pointer, as above
void RemoveEntry(void *entry, const float minX, const float minY, const float maxX, const float maxY);
// Adds and removes in one pass, more efficient than calling both functions consecutively
void MoveEntry(void *entry, const float sourceMinX, const float sourceMinY, const float sourceMaxX, const float sourceMaxY,
const float destMinX, const float destMinY, const float destMaxX, const float destMaxY);
#endif
// Adds to intersectionList all entries in a certain radius
void GetEntries(DataStructures::List<void*>& intersectionList, const float minX, const float minY, const float maxX, const float maxY);
void Clear(void);
protected:
int WorldToCellX(const float input) const;
int WorldToCellY(const float input) const;
int WorldToCellXOffsetAndClamped(const float input) const;
int WorldToCellYOffsetAndClamped(const float input) const;
// Returns true or false if a position crosses cells in the grid. If false, you don't need to move entries
bool PositionCrossesCells(const float originX, const float originY, const float destinationX, const float destinationY) const;
float cellOriginX, cellOriginY;
float cellWidth, cellHeight;
float invCellWidth, invCellHeight;
float gridWidth, gridHeight;
int gridCellWidthCount, gridCellHeightCount;
// int gridWidth, gridHeight;
#ifdef _USE_ORDERED_LIST
DataStructures::OrderedList<void*, void*>* grid;
#else
DataStructures::List<void*>* grid;
#endif
};
#endif
+127
View File
@@ -0,0 +1,127 @@
/// \file
/// \brief Contains HTTPConnection, used to communicate with web servers
///
/// This file is part of RakNet Copyright 2008 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __HTTP_CONNECTION
#define __HTTP_CONNECTION
#include "Export.h"
#include "RakString.h"
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#include "DS_Queue.h"
class TCPInterface;
struct SystemAddress;
/// \brief Use HTTPConnection to communicate with a web server.
/// Start an instance of TCPInterface via the Start() command.
/// Instantiate a new instance of HTTPConnection, and associate TCPInterface with the class in the constructor.
/// Use Post() to send commands to the web server, and ProcessDataPacket() to update the connection with packets returned from TCPInterface that have the system address of the web server
/// This class will handle connecting and reconnecting as necessary.
///
/// Note that only one Post() can be handled at a time.
class RAK_DLL_EXPORT HTTPConnection
{
public:
/// Returns a HTTP object associated with this tcp connection
/// \pre tcp should already be started
HTTPConnection(TCPInterface& tcp, const char *host, unsigned short port=80);
virtual ~HTTPConnection();
/// Submit data to the HTTP server
/// HTTP only allows one request at a time per connection
///
/// \pre IsBusy()==false
/// \param path the path on the remote server you want to POST to. For example "mywebpage/index.html"
/// \param data A NULL terminated string to submit to the server
/// \param contentType "Content-Type:" passed to post.
void Post(const char *path, const char *data, const char *_contentType="application/x-www-form-urlencoded");
/// Get data returned by the HTTP server
/// If IsFinished()==false then this may be empty or a partial
/// response.
RakNet::RakString Read(void);
/// Call periodically to do time-based updates
void Update(void);
/// Returns the address of the server we are connected to
SystemAddress GetServerAddress(void) const;
/// Process an HTTP data packet returned from TCPInterface
/// Returns true when we have gotten all the data from the HTTP server.
/// If this returns true then it's safe to Post() another request
/// Deallocate the packet as usual via TCPInterface
/// \param packet NULL or a packet associated with our host and port
/// \return true when all data from one Post() has been read.
bool ProcessFinalTCPPacket(Packet *packet);
/// Results of HTTP requests. Standard response codes are < 999
/// ( define HTTP codes and our internal codes as needed )
enum ResponseCodes { NoBody=1001, OK=200, Deleted=1002 };
HTTPConnection& operator=(const HTTPConnection& rhs){(void) rhs; return *this;}
/// Encapsulates a raw HTTP response and response code
struct BadResponse
{
public:
BadResponse() {code=0;}
BadResponse(const unsigned char *_data, int _code)
: data((const char *)_data), code(_code) {}
BadResponse(const char *_data, int _code)
: data(_data), code(_code) {}
operator int () const { return code; }
RakNet::RakString data;
int code; // ResponseCodes
};
/// Queued events of failed exchanges with the HTTP server
bool HasBadResponse(int *code, RakNet::RakString *data);
/// Returns false if the connection is not doing anything else
bool IsBusy(void) const;
/// \internal
int GetState(void) const;
private:
SystemAddress server;
TCPInterface& tcp;
RakNet::RakString host;
unsigned short port;
enum { RAK_HTTP_INITIAL,
RAK_HTTP_STARTING,
RAK_HTTP_CONNECTING,
RAK_HTTP_ESTABLISHED,
RAK_HTTP_REQUEST_SENT,
RAK_HTTP_IDLE } state;
RakNet::RakString outgoing, incoming, path, contentType;
DataStructures::Queue<BadResponse> badResponses;
void Process(Packet *packet); // the workhorse
// this helps check the various status lists in TCPInterface
typedef SystemAddress (TCPInterface::*StatusCheckFunction)(void);
bool InList(StatusCheckFunction func);
};
#endif
@@ -0,0 +1,20 @@
#ifndef __INCREMENTAL_READ_INTERFACE_H
#define __INCREMENTAL_READ_INTERFACE_H
#include "FileListNodeContext.h"
#include "Export.h"
class RAK_DLL_EXPORT IncrementalReadInterface
{
public:
/// Read part of a file into \a destination
/// Return the number of bytes written. Return 0 when file is done.
/// \param[in] filename Filename to read
/// \param[in] startReadBytes What offset from the start of the file to read from
/// \param[in] numBytesToRead How many bytes to read. This is also how many bytes have been allocated to preallocatedDestination
/// \param[out] preallocatedDestination Write your data here
/// \return The number of bytes read, or 0 if none
virtual unsigned int GetFilePart( char *filename, unsigned int startReadBytes, unsigned int numBytesToRead, void *preallocatedDestination, FileListNodeContext context);
};
#endif
+61
View File
@@ -0,0 +1,61 @@
#include "FunctionThread.h"
#include "DS_List.h"
class InlineFunctorProcessor;
/// A base class to derive functors from for the InlineFunctorProcessor system
class InlineFunctor : public RakNet::Functor
{
protected:
/// \internal - Calls InlineFunctorProcessor to signal that the functor is done
virtual void HandleResult(bool wasCancelled, void *context);
/// Tracks the call depth when this functor was pushed. It allows the system to return from functions in the correct order
int callDepth;
/// Pointer to the calling instance of InlineFunctorProcessor
InlineFunctorProcessor *ifp;
friend class InlineFunctorProcessor;
};
/// A base class that will allow you to call YieldOnFunctor() from within a function, and continue with that function when the asynchronous processing has completed
class InlineFunctorProcessor
{
public:
InlineFunctorProcessor();
~InlineFunctorProcessor();
/// Start the threads. Should call this first
/// \param[in] numThreads How many worker threads to start
/// \note If only one thread is started, then the calls to YieldOnFunctor will process in that order
void StartThreads(int numThreads);
/// Stop the threads
/// \param[in] blockOnCurrentProcessing Wait for the current processing to finish?
void StopThreads(bool blockOnCurrentProcessing);
/// Yield processing in the current function, continuing with the function implemented by CallYieldFunction
/// When the functor completes, this function will return and the caller will continue processing
/// \param[in] inlineFunctor A class that implements Functor::Process() to perform processing that can work asynchronously, such as loading a file or doing a database call
void YieldOnFunctor(InlineFunctor *inlineFunctor);
/// \internal
/// If the functor is done, continue processing the caller
/// \return True if the topmost functor has completed, false otherwise
bool UpdateIFP(void);
/// \internal
/// Notify the caller that the functor is done
void Pop(int threadCallDepth);
protected:
/// Returns the number of functors that were passed to the system
unsigned GetCallDepth(void) const;
/// Used to create a thread that processes functors
RakNet::FunctionThread functionThread;
/// Tracks which threads have been completed
DataStructures::List<bool> completedThreads;
};
+93
View File
@@ -0,0 +1,93 @@
/// \file
/// \brief \b [Internal] A class which stores a user message, and all information associated with sending and receiving that message.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __INTERNAL_PACKET_H
#define __INTERNAL_PACKET_H
#include "PacketPriority.h"
#include "RakNetTypes.h"
#include "RakMemoryOverride.h"
typedef unsigned short SplitPacketIdType;
typedef unsigned int SplitPacketIndexType;
/// This is the counter used for holding packet numbers, so we can detect duplicate packets. It should be large enough that if the variables
/// were to wrap, the newly wrapped values would no longer be in use. Warning: Too large of a value wastes bandwidth!
/// Use the smallest possible value, such that you send no more than rangeof(MessageNumberType) / GetTimeoutTime() packets per second
/// For the default value of 10 seconds, this is
/// unsigned char - 25.5 packets per second
/// unsigned short - 6553.5 packets per second
/// unsigned int - You'll run out of memory first.
typedef unsigned int MessageNumberType;
/// This is the counter used for holding ordered packet numbers, so we can detect out-of-order packets. It should be large enough that if the variables
/// were to wrap, the newly wrapped values would no longer be in use. Warning: Too large of a value wastes bandwidth!
typedef MessageNumberType OrderingIndexType;
typedef RakNetTime RemoteSystemTimeType;
/// Holds a user message, and related information
/// Don't use a constructor or destructor, due to the memory pool I am using
struct InternalPacket//<InternalPacket>
{
///True if this is an acknowledgment packet
//bool isAcknowledgement;
/// A unique numerical identifier given to this user message. Used to identify messages on the network
MessageNumberType messageNumber;
/// Identifies the order in which this number was sent. Used locally
MessageNumberType messageInternalOrder;
/// Has this message number been assigned yet? We don't assign until the message is actually sent.
/// This fixes a bug where pre-determining message numbers and then sending a message on a different channel creates a huge gap.
/// This causes performance problems and causes those messages to timeout.
bool messageNumberAssigned;
/// Used only for tracking packetloss and windowing internally, this is the aggreggate packet number that a message was last sent in
unsigned packetNumber;
/// Was this packet number used this update to track windowing drops or increases? Each packet number is only used once per update.
// bool allowWindowUpdate;
///The priority level of this packet
PacketPriority priority;
///What type of reliability algorithm to use with this packet
PacketReliability reliability;
///What ordering channel this packet is on, if the reliability type uses ordering channels
unsigned char orderingChannel;
///The ID used as identification for ordering channels
OrderingIndexType orderingIndex;
///The ID of the split packet, if we have split packets. This is the maximum number of split messages we can send simultaneously per connection.
SplitPacketIdType splitPacketId;
///If this is a split packet, the index into the array of subsplit packets
SplitPacketIndexType splitPacketIndex;
///The size of the array of subsplit packets
SplitPacketIndexType splitPacketCount;
///When this packet was created
RakNetTimeNS creationTime;
///The next time to take action on this packet
RakNetTimeNS nextActionTime;
// If this was a reliable packet, it included the ping time, to be sent back in an ack
//RakNetTimeNS remoteSystemTime;
//RemoteSystemTimeType remoteSystemTime;
///How many bits the data is
BitSize_t dataBitLength;
///Buffer is a pointer to the actual data, assuming this packet has data at all
unsigned char *data;
// How many attempts we made at sending this message
unsigned char timesSent;
};
#endif
+8
View File
@@ -0,0 +1,8 @@
#ifndef __RAK_ITOA_H
#define __RAK_ITOA_H
#include "Export.h"
RAK_DLL_EXPORT char* Itoa( int value, char* result, int base );
#endif
+84
View File
@@ -0,0 +1,84 @@
/*****************************************************************************
kbhit() and getch() for Linux/UNIX
Chris Giese <geezer@execpc.com> http://my.execpc.com/~geezer
Release date: ?
This code is public domain (no copyright).
You can do whatever you want with it.
*****************************************************************************/
#if !defined(linux) && !defined(__GNUC__) && !defined(__GCCXML__)
#include <conio.h> /* kbhit(), getch() */
#else
#include <sys/time.h> /* struct timeval, select() */
/* ICANON, ECHO, TCSANOW, struct termios */
#include <termios.h> /* tcgetattr(), tcsetattr() */
#include <stdlib.h> /* atexit(), exit() */
#include <unistd.h> /* read() */
#include <stdio.h> /* printf() */
#include <string.h> /* memcpy */
static struct termios g_old_kbd_mode;
/*****************************************************************************
*****************************************************************************/
static void cooked(void)
{
tcsetattr(0, TCSANOW, &g_old_kbd_mode);
}
/*****************************************************************************
*****************************************************************************/
static void raw(void)
{
static char init;
/**/
struct termios new_kbd_mode;
if(init)
return;
/* put keyboard (stdin, actually) in raw, unbuffered mode */
tcgetattr(0, &g_old_kbd_mode);
memcpy(&new_kbd_mode, &g_old_kbd_mode, sizeof(struct termios));
new_kbd_mode.c_lflag &= ~(ICANON | ECHO);
new_kbd_mode.c_cc[VTIME] = 0;
new_kbd_mode.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &new_kbd_mode);
/* when we exit, go back to normal, "cooked" mode */
atexit(cooked);
init = 1;
}
/*****************************************************************************
*****************************************************************************/
static int kbhit(void)
{
struct timeval timeout;
fd_set read_handles;
int status;
raw();
/* check stdin (fd 0) for activity */
FD_ZERO(&read_handles);
FD_SET(0, &read_handles);
timeout.tv_sec = timeout.tv_usec = 0;
status = select(0 + 1, &read_handles, NULL, NULL, &timeout);
if(status < 0)
{
printf("select() failed in kbhit()\n");
exit(1);
}
return status;
}
/*****************************************************************************
*****************************************************************************/
static int getch(void)
{
unsigned char temp;
raw();
/* stdin = fd 0 */
if(read(0, &temp, 1) != 1)
return 0;
return temp;
}
#endif
@@ -0,0 +1,88 @@
/// \file
/// \brief Contains the client interface to the simple database included with RakNet, useful for a server browser or a lobby server.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __LIGHTWEIGHT_DATABASE_CLIENT_H
#define __LIGHTWEIGHT_DATABASE_CLIENT_H
#include "Export.h"
#include "PluginInterface.h"
#include "LightweightDatabaseCommon.h"
class RakPeerInterface;
struct Packet;
/// \defgroup SIMPLE_DATABSE_GROUP LightweightDatabase
/// \ingroup PLUGINS_GROUP
/// \brief The client interface to the simple database included with RakNet, useful for a server browser or a lobby server.
/// \ingroup SIMPLE_DATABSE_GROUP
class RAK_DLL_EXPORT LightweightDatabaseClient : public PluginInterface
{
public:
/// Constructor
LightweightDatabaseClient();
/// Destructor
virtual ~LightweightDatabaseClient();
/// Sends a query to a remote table.
/// The remote system should return ID_DATABASE_QUERY_REPLY, ID_DATABASE_UNKNOWN_TABLE, or ID_DATABASE_INCORRECT_PASSWORD
/// \note If the remote table uses a password and you send the wrong one you will be silently disconnected and banned for one second.
/// \param[in] tableName String name of the remote table. Case sensitive.
/// \param[in] queryPassword Password to query the remote table, if any.
/// \param[in] columnSubset An array of string names of the columns to query. The resulting table will return the columns in this same order. Pass 0 for all columns.
/// \param[in] numColumnSubset The number of elements in the columnSubset array
/// \param[in] filter Filters to apply to the query. For each row the filters are applied. All filters must be passed for the row to be returned. Pass 0 for no filters.
/// \param[in] numFilters The number of elements in the filter array
/// \param[in] rowIds Which particular rows to return. Pass 0 for all rows.
/// \param[in] numRowIDs The number of elements in the rowIds array
/// \param[in] systemAddress Which system to send to.
/// \param[in] broadcast Broadcast or not. Same as the parameter in RakPeer::Send
void QueryTable(const char *tableName, const char *queryPassword, const char **columnNamesSubset, unsigned char numColumnSubset, DatabaseFilter *filter, unsigned char numFilters, unsigned *rowIds, unsigned char numRowIDs, SystemAddress systemAddress, bool broadcast);
/// Sets one or more values in a new or existing row, assuming the server allows row creation and updates.
/// No response is returned by the server.
/// \param[in] tableName String name of the remote table. Case sensitive.
/// \param[in] updatePassword Password to update the remote table, if any.
/// \param[in] updateMode See RowUpdateMode in LightweightDatabaseCommon.h . This determines if to update an existing or new row.
/// \param[in] hasRowId True if a valid value was passed for \a rowId, false otherwise. If false, will lookup the row by system address. Required if adding a new row and the remote system does not automatically create rowIDs.
/// \param[in] rowId The rowID of the new or existing row.
/// \param[in] cellUpdates An array of DatabaseCellUpdate structures containing the values to write to the remote row.
/// \param[in] numCellUpdates The number of elements in the cellUpdates array
/// \param[in] systemAddress Which system to send to.
/// \param[in] broadcast Broadcast or not. Same as the parameter in RakPeer::Send
void UpdateRow(const char *tableName, const char *updatePassword, RowUpdateMode updateMode, bool hasRowId, unsigned rowId, DatabaseCellUpdate *cellUpdates, unsigned char numCellUpdates, SystemAddress systemAddress, bool broadcast);
/// Removes a remote row, assuming the server allows row removal.
/// No response is returned by the server.
/// \param[in] tableName String name of the remote table. Case sensitive.
/// \param[in] removePassword Password to remove rows from the remote table, if any.
/// \param[in] rowId The rowID of the existing row.
/// \param[in] systemAddress Which system to send to.
/// \param[in] broadcast Broadcast or not. Same as the parameter in RakPeer::Send
void RemoveRow(const char *tableName, const char *removePassword, unsigned rowId, SystemAddress systemAddress, bool broadcast);
/// \internal For plugin handling
void OnAttach(RakPeerInterface *peer);
/// \internal For plugin handling
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
protected:
RakPeerInterface *rakPeer;
};
#endif
@@ -0,0 +1,54 @@
#ifndef __SIMPLE_DATABASE_COMMON_H
#define __SIMPLE_DATABASE_COMMON_H
#include "DS_Table.h"
namespace RakNet
{
class BitStream;
};
#define _SIMPLE_DATABASE_PASSWORD_LENGTH 32
#define _SIMPLE_DATABASE_TABLE_NAME_LENGTH 32
#define SYSTEM_ID_COLUMN_NAME "__SystemAddress"
#define SYSTEM_GUID_COLUMN_NAME "__SystemGuid"
#define LAST_PING_RESPONSE_COLUMN_NAME "__lastPingResponseTime"
#define NEXT_PING_SEND_COLUMN_NAME "__nextPingSendTime"
struct DatabaseFilter
{
void Serialize(RakNet::BitStream *out);
bool Deserialize(RakNet::BitStream *in);
DataStructures::Table::Cell cellValue;
DataStructures::Table::FilterQueryType operation;
DataStructures::Table::ColumnType columnType;
char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
};
/// The value to write to a cell in a remote database.
struct DatabaseCellUpdate
{
void Serialize(RakNet::BitStream *out);
bool Deserialize(RakNet::BitStream *in);
DataStructures::Table::Cell cellValue;
DataStructures::Table::ColumnType columnType;
char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
};
enum RowUpdateMode
{
// Only update an existing row. rowId is required.
RUM_UPDATE_EXISTING_ROW,
// Update an existing row if present - otherwise add a new row. rowId is required.
RUM_UPDATE_OR_ADD_ROW,
// Add a new row. If rowId is passed then the row will only be added if this id doesn't already exist.
// If rowId is not passed and the table requires a rowId the creation fails.
RUM_ADD_NEW_ROW,
};
#endif
@@ -0,0 +1,149 @@
/// \file
/// \brief A simple flat database included with RakNet, useful for a server browser or a lobby server.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __LIGHTWEIGHT_DATABASE_SERVER_H
#define __LIGHTWEIGHT_DATABASE_SERVER_H
#include "Export.h"
#include "PluginInterface.h"
#include "LightweightDatabaseCommon.h"
#include "DS_Map.h"
class RakPeerInterface;
struct Packet;
/// \brief A simple flat database included with RakNet, useful for a server browser or a lobby server.
/// A flat database interface. Adds the ability to track IPs of row updaters and passwords for table read and write operations,
/// Best used for data in which queries which do not need to be updated in real-time
/// \ingroup SIMPLE_DATABSE_GROUP
class RAK_DLL_EXPORT LightweightDatabaseServer : public PluginInterface
{
public:
/// Constructor
LightweightDatabaseServer();
/// Destructor
virtual ~LightweightDatabaseServer();
/// Returns a table by name.
/// It is valid to read and write to the returned pointer.
/// \param[in] tableName The name of the table that was passed to AddTable
/// \return The requested table, or 0 if \a tableName cannot be found.
DataStructures::Table *GetTable(char *tableName);
/// Adds a new table
/// It is valid to read and write to the returned pointer.
/// \param[in] tableName Name of the new table to create. Remote systems will refer to this table by this name.
/// \param[in] allowRemoteQuery true to allow remote systems to query the table. false to not allow this.
/// \param[in] allowRemoteUpdate true to allow remote systems to update rows in the table. false to not allow this.
/// \param[in] allowRemoteRemove true to allow remote systems to remove rows from the table. false to not allow this.
/// \param[in] queryPassword The password required to query the table. Pass an empty string for no password.
/// \param[in] updatePassword The password required to update rows in the table. Pass an empty string for no password.
/// \param[in] removePassword The password required to remove rows from the table. Pass an empty string for no password.
/// \param[in] oneRowPerSystemAddress Only used if allowRemoteUpdate==true. This limits remote systems to one row.
/// \param[in] onlyUpdateOwnRows Only used if allowRemoteUpdate==true. This limits remote systems to only updating rows they created.
/// \param[in] removeRowOnPingFailure Only used if allowRemoteUpdate==true and removeRowOnDisconnect==false. If true, this will periodically ping disconnected systems and remove rows created by that system if that system does not respond to pings.
/// \param[in] removeRowOnDisconnect Only used if allowRemoteUpdate==true. This removes rows created by a system when that system disconnects.
/// \param[in] autogenerateRowIDs true to automatically generate row IDs. Rows are stored in order by row ID. If false, the clients must specify a unique row ID when adding rows. If they specify a row that already exists the addition is ignored.
/// \return The newly created table, or 0 on failure.
DataStructures::Table* AddTable(char *tableName,
bool allowRemoteQuery,
bool allowRemoteUpdate,
bool allowRemoteRemove,
const char *queryPassword,
const char *updatePassword,
const char *removePassword,
bool oneRowPerSystemAddress,
bool onlyUpdateOwnRows,
bool removeRowOnPingFailure,
bool removeRowOnDisconnect,
bool autogenerateRowIDs);
/// Removes a table by name.
/// \param[in] tableName The name of the table that was passed to AddTable
/// \return true on success, false on failure.
bool RemoveTable(char *tableName);
/// Clears all memory.
void Clear(void);
// Gets the next valid auto-generated rowId for a table and increments it.
unsigned GetAndIncrementRowID(char *tableName);
/// Returns a linked list of ordered lists containing the rows of a table, by name.
/// The returned structure is internal to the BPlus tree. See DS_BPlusTree
/// This is a convenience accessor, as you can also get this from the table returned from GetTable()
/// \param[in] tableName The name of the table that was passed to AddTable
/// \return The requested rows, or 0 if \a tableName cannot be found.
DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *GetTableRows(char *tableName);
/// \internal For plugin handling
virtual void OnAttach(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void Update(RakPeerInterface *peer);
/// \internal For plugin handling
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// \internal For plugin handling
virtual void OnShutdown(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
struct DatabaseTable
{
bool allowRemoteUpdate;
bool allowRemoteQuery;
bool allowRemoteRemove;
char updatePassword[_SIMPLE_DATABASE_PASSWORD_LENGTH];
char queryPassword[_SIMPLE_DATABASE_PASSWORD_LENGTH];
char removePassword[_SIMPLE_DATABASE_PASSWORD_LENGTH];
bool oneRowPerSystemAddress;
bool onlyUpdateOwnRows;
bool removeRowOnPingFailure;
bool removeRowOnDisconnect;
bool autogenerateRowIDs;
char tableName[_SIMPLE_DATABASE_TABLE_NAME_LENGTH];
// Used if autogenerateRowIDs==true
unsigned nextRowId;
unsigned SystemAddressColumnIndex;
unsigned SystemGuidColumnIndex;
unsigned lastPingResponseColumnIndex;
unsigned nextPingSendColumnIndex;
RakNetTime nextRowPingCheck;
DataStructures::Table table;
};
static int DatabaseTableComp( char* const &key1, char* const &key2 );
protected:
DataStructures::Map<char *, LightweightDatabaseServer::DatabaseTable*, LightweightDatabaseServer::DatabaseTableComp> database;
void OnQueryRequest(RakPeerInterface *peer, Packet *packet);
void OnUpdateRow(RakPeerInterface *peer, Packet *packet);
void OnRemoveRow(RakPeerInterface *peer, Packet *packet);
void OnPong(RakPeerInterface *peer, Packet *packet);
// mode 0 = query, mode 1 = update, mode 2 = remove
DatabaseTable * DeserializeClientHeader(RakNet::BitStream *inBitstream, RakPeerInterface *peer, Packet *packet, int mode);
DataStructures::Table::Row * GetRowFromIP(DatabaseTable *databaseTable, SystemAddress systemAddress, unsigned *rowId);
bool RowHasIP(DataStructures::Table::Row *row, SystemAddress systemAddress, unsigned SystemAddressColumnIndex);
DataStructures::Table::Row * AddRow(LightweightDatabaseServer::DatabaseTable *databaseTable, SystemAddress systemAddress, RakNetGUID guid, bool hasRowId, unsigned rowId);
void RemoveRowsFromIP(SystemAddress systemAddress);
};
#endif
+15
View File
@@ -0,0 +1,15 @@
#ifndef _GCC_WIN_STRINGS
#define _GCC_WIN_STRINGS
#if (defined(__GNUC__) || defined(__GCCXML__) || defined(_PS3)) && !defined(_WIN32)
int _stricmp(const char* s1, const char* s2);
int _strnicmp(const char* s1, const char* s2, size_t n);
char *_strlwr(char * str );
#ifndef _vsnprintf
#define _vsnprintf vsnprintf
#endif
#endif
#endif
+125
View File
@@ -0,0 +1,125 @@
#ifndef __LOBBY_CLIENT_INTERFACE_H
#define __LOBBY_CLIENT_INTERFACE_H
enum LobbyEvent
{
LOBBY_EVENT_COUNT
};
enum LobbyClientEvents
{
LCE_ADDED_FRIEND,
LCE_SENT_MESSAGE_SUCCESS,
LCE_BLOCK_USER_SUCCESS,
LCE_ALL_FRIENDS_DOWNLOADED,
LCE_FRIEND_REMOVED_FROM_LIST,
LCE_FRIEND_ADDED_DIFFERENT_GAME,
LCE_FRIEND_ADDED_SAME_GAME,
LCE_FRIEND_OFFLINE,
LCE_SAME_GAME_INSTANT_MESSAGE,
LCE_GAME_INVITATION,
LCE_GAME_GOT_MESSAGE_WITH_ATTACHMENT_GUI
};
#if defined(WIN32)
#include "[PC]LobbyClientTypes.h"
#else
#include "[PS3]LobbyClientTypes.h"
#endif
class LobbyClientCBInterface
{
public:
LobbyClientCBInterface() {}
virtual ~LobbyClientCBInterface() {}
virtual void AddedFriendSuccessfully(void) {}
virtual void SentMessageSuccessfully(void) {}
virtual void BlockedUserSuccessfully(void) {}
virtual void AllFriendsDownloaded(void) {}
virtual void FriendRemovedFromFriendsList(void *friendId, const char *friendName) {}
virtual void FriendAddedToFriendsList(void *friendId, const char *friendName, bool inSameGame) {}
virtual void FriendOffline(void *friendId, const char *friendName) {}
virtual void GotInstantMessage(void *friendId, const char *friendName, char *data, int dataLength) {}
virtual void GotGameInvitation(void *friendId, const char *friendName) {}
virtual void GameMessageWithAttachmentArrived(void *friendId, const char *friendName) {}
virtual void GotGameMessageWithAttachmentThroughGui(void *friendId, const char *friendName, char *data, int dataLength) {}
virtual void LeaveRoomComplete(void) {}
virtual void NewMemberJoinedRoom(void *memberId, const char *memberName) {}
virtual void MemberLeftRoom(void *memberId, const char *memberName) {}
virtual void RoomDisappeared(void) {}
virtual void RoomOwnershipGranted(void *newOwnerId, const char *newOwnerName) {}
virtual void RoomOwnershipChanged(void *newOwnerId, const char *newOwnerName) {}
virtual void RoomMemberKicked(void *memberId, const char *memberName) {}
virtual void KickedFromRoom(void) {}
virtual void RoomJoined(void) {}
virtual void RoomCreated(void) {}
virtual void RoomSearchJoined(void) {}
virtual void RoomQuickMatchJoined(void) {}
virtual void RoomQuickMatchCancelled(void) {}
virtual void RoomJoinInvitationSentConfirmation(void) {}
virtual void RoomJoinInvitationAccepted(void *roomId) {}
virtual void ReceivedRoomList(void) {}
virtual void ScoreSubmitted(unsigned int newRank);
virtual void GotScore(void *memberId, char *onlineName, unsigned int rank, unsigned int highestRank, unsigned long long score );
};
class LobbyClientInterface
{
public:
virtual bool StartLogin(const char *titleIdentifier){return false;}
virtual void Logoff(){}
virtual bool IsLoggedIn(void) const{return false;}
virtual bool IsFriendsListOpen(void) const{return false;}
virtual bool IsSendingMessage(void) const{return false;}
virtual bool IsReceivingStoredMessage(void) const{return false;}
virtual bool IsAddingFriend(void) const{return false;}
virtual bool IsCreatingRoom(void) const{return false;}
virtual bool IsSearchingAndJoiningRoom(void) const{return false;}
virtual bool IsDoingQuickMatch(void) const{return false;}
virtual bool IsGettingRoomList(void) const{return false;}
virtual bool IsInRoom(void) const{return false;}
virtual bool RecordScore(unsigned int scoreboardId, unsigned long long int score, const char *censoredComment, const char *gameData, unsigned int gamedataLength){return false;}
virtual bool GetScoreRanking(unsigned int scoreboardId, LobbyClientUserId* userId){return false;}
virtual void AbortScoreTransaction(void){}
virtual void Update(void){}
virtual bool ShowFriendsList(void){return false;}
virtual bool AddFriend(LobbyClientUserId* to, const char *body){return false;}
virtual unsigned GetNumFriends(void) const{return 0;}
virtual const LobbyClientUserId& GetFriendIDFromIndex(unsigned idx) const{return LobbyClientUserId();}
virtual bool GetFriendSameGameFromIndex(unsigned idx) const{return false;}
virtual unsigned GetIndexFromFriendId(LobbyClientUserId* id){return 0;}
virtual bool SendGameMessage(LobbyClientUserId* to, const void *data, int dataSize){return false;}
virtual bool SendStoredMessage(LobbyClientUserId* to, const char *subject, const char *body, const void *data, int dataSize){return false;}
virtual bool ReceiveStoredMessageWithAttachment(void){return false;}
virtual bool CreateRoom(int totalSlots, int privateSlots, bool kickMembersOnOwnerLeave, bool allowSearchesForRoom){return false;}
virtual unsigned GetNumRoomMembers(void) const{return 0;}
virtual const LobbyClientUserId& GetRoomMemberIDFromIndex(unsigned idx) const{return LobbyClientUserId();}
virtual unsigned GetIndexFromRoomMemberID(LobbyClientUserId* id) const{return 0;}
virtual unsigned GetNumRooms(void) const{return 0;}
virtual const LobbyClientRoomId & GetRoomIDFromIndex(unsigned idx) const{return LobbyClientRoomId();}
virtual unsigned GetIndexFromRoomID(LobbyClientRoomId *id) const{return 0;}
virtual bool GetRoomList(int requiredSlots){return false;}
virtual void SetRoomStealth(bool isHidden){}
virtual bool LeaveRoom(void){return false;}
virtual bool GrantRoomOwnership(LobbyClientUserId * userId){return false;}
virtual bool KickRoomMember(LobbyClientUserId * userId){return false;}
virtual bool SendRoomInvitation(LobbyClientUserId * userId, const char *subject, const char *body, bool inviteToPrivateSlot){return false;}
virtual bool SearchAndJoinRoom(int requiredSlots){return false;}
virtual bool QuickMatch(int requiredSlots, int timeoutInSeconds){return false;}
virtual bool BlockPlayer(LobbyClientUserId* to){return false;}
virtual unsigned GetNumBlockedPlayers(void) const{return 0;}
virtual const LobbyClientUserId& GetBlockedPlayerAtIndex(unsigned idx){return LobbyClientUserId();}
virtual bool AddToMetPlayerHistory(LobbyClientUserId* id, const char *description){return false;}
virtual void SetCallbackInterface(LobbyClientCBInterface *cbi){}
virtual const LobbyClientUserId* GetMyID(void) const{return 0;}
};
#if defined(WIN32)
#include "[PC]LobbyClient.h"
#else
#include "[PS3]LobbyClient.h"
#endif
#endif
+117
View File
@@ -0,0 +1,117 @@
/// \file
/// \brief Contains LogCommandParser , Used to send logs to connected consoles
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __LOG_COMMAND_PARSER
#define __LOG_COMMAND_PARSER
class RakPeerInterface;
#include "CommandParserInterface.h"
#include "Export.h"
/// \brief Adds the ability to send logging output to a remote console
class RAK_DLL_EXPORT LogCommandParser : public CommandParserInterface
{
public:
LogCommandParser();
~LogCommandParser();
/// Given \a command with parameters \a parameterList , do whatever processing you wish.
/// \param[in] command The command to process
/// \param[in] numParameters How many parameters were passed along with the command
/// \param[in] parameterList The list of parameters. parameterList[0] is the first parameter and so on.
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that sent this command.
/// \param[in] originalString The string that was actually sent over the network, in case you want to do your own parsing
bool OnCommand(const char *command, unsigned numParameters, char **parameterList, TransportInterface *transport, SystemAddress systemAddress, const char *originalString);
/// You are responsible for overriding this function and returning a static string, which will identifier your parser.
/// This should return a static string
/// \return The name that you return.
const char *GetName(void) const;
/// A callback for when you are expected to send a brief description of your parser to \a systemAddress
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that requested help.
void SendHelp(TransportInterface *transport, SystemAddress systemAddress);
/// All logs must be associated with a channel. This is a filter so that remote clients only get logs for a system they care about.
// If you call Log with a channel that is unknown, that channel will automatically be added
/// \param[in] channelName A persistent string naming the channel. Don't deallocate this string.
void AddChannel(const char *channelName);
/// Write a log to a channel.
/// Logs are not buffered, so only remote consoles connected and subscribing at the time you write will get the output.
/// \param[in] format Same as RAKNET_DEBUG_PRINTF()
/// \param[in] ... Same as RAKNET_DEBUG_PRINTF()
void WriteLog(const char *channelName, const char *format, ...);
/// A callback for when \a systemAddress has connected to us.
/// \param[in] systemAddress The player that has connected.
/// \param[in] transport The transport interface that sent us this information. Can be used to send messages to this or other players.
void OnNewIncomingConnection(SystemAddress systemAddress, TransportInterface *transport);
/// A callback for when \a systemAddress has disconnected, either gracefully or forcefully
/// \param[in] systemAddress The player that has disconnected.
/// \param[in] transport The transport interface that sent us this information.
void OnConnectionLost(SystemAddress systemAddress, TransportInterface *transport);
/// This is called every time transport interface is registered. If you want to save a copy of the TransportInterface pointer
/// This is the place to do it
/// \param[in] transport The new TransportInterface
void OnTransportChange(TransportInterface *transport);
protected:
/// Sends the currently active channels to the user
/// \param[in] systemAddress The player to send to
/// \param[in] transport The transport interface to use to send the channels
void PrintChannels(SystemAddress systemAddress, TransportInterface *transport) const;
/// Unsubscribe a user from a channel (or from all channels)
/// \param[in] systemAddress The player to unsubscribe to
/// \param[in] channelName If 0, then unsubscribe from all channels. Otherwise unsubscribe from the named channel
unsigned Unsubscribe(SystemAddress systemAddress, const char *channelName);
/// Subscribe a user to a channel (or to all channels)
/// \param[in] systemAddress The player to subscribe to
/// \param[in] channelName If 0, then subscribe from all channels. Otherwise subscribe to the named channel
unsigned Subscribe(SystemAddress systemAddress, const char *channelName);
/// Given the name of a channel, return the index into channelNames where it is located
/// \param[in] channelName The name of the channel
unsigned GetChannelIndexFromName(const char *channelName);
/// One of these structures is created per player
struct SystemAddressAndChannel
{
/// The ID of the player
SystemAddress systemAddress;
/// Bitwise representations of the channels subscribed to. If bit 0 is set, then we subscribe to channelNames[0] and so on.
unsigned channels;
};
/// The list of remote users. Added to when users subscribe, removed when they disconnect or unsubscribe
DataStructures::List<SystemAddressAndChannel> remoteUsers;
/// Names of the channels at each bit, or 0 for an unused channel
const char *channelNames[32];
/// This is so I can save the current transport provider, solely so I can use it without having the user pass it to Log
TransportInterface *trans;
};
#endif
+47
View File
@@ -0,0 +1,47 @@
/// \file
/// \brief \b [Internal] Defines the default maximum transfer unit.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef DEFAULT_MTU_SIZE
/// The MTU size to use if RakPeer::SetMTUSize() is not called.
/// \remarks I think many people forget to call RakPeer::SetMTUSize() so I'm setting this to 1500 by default for efficiency.
/// \li \em 17914 16 Mbit/Sec Token Ring
/// \li \em 4464 4 Mbits/Sec Token Ring
/// \li \em 4352 FDDI
/// \li \em 1500. The largest Ethernet packet size \b recommended. This is the typical setting for non-PPPoE, non-VPN connections. The default value for NETGEAR routers, adapters and switches.
/// \li \em 1492. The size PPPoE prefers.
/// \li \em 1472. Maximum size to use for pinging. (Bigger packets are fragmented.)
/// \li \em 1468. The size DHCP prefers.
/// \li \em 1460. Usable by AOL if you don't have large email attachments, etc.
/// \li \em 1430. The size VPN and PPTP prefer.
/// \li \em 1400. Maximum size for AOL DSL.
/// \li \em 576. Typical value to connect to dial-up ISPs.
#if defined(_XBOX) || defined(X360)
#define DEFAULT_MTU_SIZE 1264
#else
#define DEFAULT_MTU_SIZE 1492
#endif
/// The largest value for an UDP datagram
/// \sa RakPeer::SetMTUSize()
#if defined(_XBOX) || defined(X360)
#define MAXIMUM_MTU_SIZE 1264
#else
#define MAXIMUM_MTU_SIZE 1492
#endif
#endif
+193
View File
@@ -0,0 +1,193 @@
/// \file
/// \brief Message filter plugin. Assigns systems to FilterSets. Each FilterSet limits what messages are allowed. This is a security related plugin.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __MESSAGE_FILTER_PLUGIN_H
#define __MESSAGE_FILTER_PLUGIN_H
class RakPeerInterface;
#include "RakNetTypes.h"
#include "PluginInterface.h"
#include "DS_OrderedList.h"
#include "Export.h"
/// MessageIdentifier (ID_*) values shoudln't go higher than this. Change it if you do.
#define MESSAGE_FILTER_MAX_MESSAGE_ID 256
/// \internal Has to be public so some of the shittier compilers can use it.
int RAK_DLL_EXPORT MessageFilterStrComp( char *const &key,char *const &data );
/// \internal Has to be public so some of the shittier compilers can use it.
struct FilterSet
{
bool banOnFilterTimeExceed;
bool kickOnDisallowedMessage;
bool banOnDisallowedMessage;
RakNetTime disallowedMessageBanTimeMS;
RakNetTime timeExceedBanTimeMS;
RakNetTime maxMemberTimeMS;
void (*invalidMessageCallback)(RakPeerInterface *peer, SystemAddress systemAddress, int filterSetID, void *userData, unsigned char messageID);
void *disallowedCallbackUserData;
void (*timeoutCallback)(RakPeerInterface *peer, SystemAddress systemAddress, int filterSetID, void *userData);
void *timeoutUserData;
int filterSetID;
bool allowedIDs[MESSAGE_FILTER_MAX_MESSAGE_ID];
DataStructures::OrderedList<char *, char *, MessageFilterStrComp> allowedRPCs;
};
/// \internal Has to be public so some of the shittier compilers can use it.
int RAK_DLL_EXPORT FilterSetComp( const int &key, FilterSet * const &data );
/// \internal Has to be public so some of the shittier compilers can use it.
struct FilteredSystem
{
SystemAddress systemAddress;
FilterSet *filter;
RakNetTime timeEnteredThisSet;
};
/// \internal Has to be public so some of the shittier compilers can use it.
int RAK_DLL_EXPORT FilteredSystemComp( const SystemAddress &key, const FilteredSystem &data );
/// \defgroup MESSAGEFILTER_GROUP MessageFilter
/// \ingroup PLUGINS_GROUP
/// \brief Assigns systems to FilterSets. Each FilterSet limits what kinds of messages are allowed.
/// The MessageFilter plugin is used for security where you limit what systems can send what kind of messages.
/// You implicitly define FilterSets, and add allowed message IDs and RPC calls to these FilterSets.
/// You then add systems to these filters, such that those systems are limited to sending what the filters allows.
/// You can automatically assign systems to a filter.
/// You can automatically kick and possibly ban users that stay in a filter too long, or send the wrong message.
/// Each system is a member of either zero or one filters.
/// Add this plugin before any plugin you wish to filter (most likely just add this plugin before any other).
/// \ingroup MESSAGEFILTER_GROUP
class RAK_DLL_EXPORT MessageFilter : public PluginInterface
{
public:
MessageFilter();
virtual ~MessageFilter();
// --------------------------------------------------------------------------------------------
// User functions
// --------------------------------------------------------------------------------------------
/// Automatically add all new systems to a particular filter
/// Defaults to -1
/// \param[in] filterSetID Which filter to add new systems to. <0 for do not add.
void SetAutoAddNewConnectionsToFilter(int filterSetID);
/// Allow a range of message IDs
/// Always allowed by default: ID_CONNECTION_REQUEST_ACCEPTED through ID_DOWNLOAD_PROGRESS
/// Usually you specify a range to make it easier to add new enumerations without having to constantly refer back to this function.
/// \param[in] allow True to allow this message ID, false to disallow. By default, all messageIDs except the noted types are disallowed. This includes messages from other plugins!
/// \param[in] messageIDStart The first ID_* message to allow in the range. Inclusive.
/// \param[in] messageIDEnd The last ID_* message to allow in the range. Inclusive.
/// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings.
void SetAllowMessageID(bool allow, int messageIDStart, int messageIDEnd,int filterSetID);
/// Allow an RPC function, by name
/// \param[in] allow True to allow an RPC call with this function name, false to disallow. All RPCs are disabled by default.
/// \param[in] functionName the function name of the RPC call. Must match the function name exactly, including case.
/// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings.
void SetAllowRPC(bool allow, const char *functionName, int filterSetID);
/// What action to take on a disallowed message. You can kick or not. You can add them to the ban list for some time
/// By default no action is taken. The message is simply ignored.
/// param[in] 0 for permanent ban, >0 for ban time in milliseconds.
/// \param[in] kickOnDisallowed kick the system that sent a disallowed message.
/// \param[in] banOnDisallowed ban the system that sent a disallowed message. See \a banTimeMS for the ban duration
/// \param[in] banTimeMS Passed to the milliseconds parameter of RakPeer::AddToBanList.
/// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings.
void SetActionOnDisallowedMessage(bool kickOnDisallowed, bool banOnDisallowed, RakNetTime banTimeMS, int filterSetID);
/// Set a user callback to be called on an invalid message for a particular filterSet
/// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings.
/// \param[in] userData A pointer passed with the callback
/// \param[in] invalidMessageCallback A pointer to a C function to be called back with the specified parameters.
void SetDisallowedMessageCallback(int filterSetID, void *userData, void (*invalidMessageCallback)(RakPeerInterface *peer, SystemAddress systemAddress, int filterSetID, void *userData, unsigned char messageID));
/// Set a user callback to be called when a user is disconnected due to SetFilterMaxTime
/// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings.
/// \param[in] userData A pointer passed with the callback
/// \param[in] invalidMessageCallback A pointer to a C function to be called back with the specified parameters.
void SetTimeoutCallback(int filterSetID, void *userData, void (*invalidMessageCallback)(RakPeerInterface *peer, SystemAddress systemAddress, int filterSetID, void *userData));
/// Limit how long a connection can stay in a particular filterSetID. After this time, the connection is kicked and possibly banned.
/// By default there is no limit to how long a connection can stay in a particular filter set.
/// \param[in] allowedTimeMS How many milliseconds to allow a connection to stay in this filter set.
/// \param[in] banOnExceed True or false to ban the system, or not, when \a allowedTimeMS is exceeded
/// \param[in] banTimeMS Passed to the milliseconds parameter of RakPeer::AddToBanList.
/// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings.
void SetFilterMaxTime(int allowedTimeMS, bool banOnExceed, RakNetTime banTimeMS, int filterSetID);
/// Get the filterSetID a system is using. Returns -1 for none.
/// \param[in] systemAddress The system we are referring to
int GetSystemFilterSet(SystemAddress systemAddress);
/// Assign a system to a filter set.
/// Systems are automatically added to filter sets (or not) based on SetAutoAddNewConnectionsToFilter()
/// This function is used to change the filter set a system is using, to add it to a new filter set, or to remove it from all existin filter sets.
/// \param[in] systemAddress The system we are referring to
/// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings. If -1, the system will be removed from all filter sets.
void SetSystemFilterSet(SystemAddress systemAddress, int filterSetID);
/// Returns the number of systems subscribed to a particular filter set
/// Using anything other than -1 for \a filterSetID is slow, so you should store the returned value.
/// \param[in] filterSetID The filter set to limit to. Use -1 for none (just returns the total number of filter systems in that case).
unsigned GetSystemCount(int filterSetID) const;
/// Returns a system subscribed to a particular filter set,by index.
/// index should be between 0 and the GetSystemCount(filterSetID)-1;
/// \param[in] filterSetID The filter set to limit to. Use -1 for none (just indexes all the filtered systems in that case).
/// \param[in] index A number between 0 and GetSystemCount(filterSetID)-1;
SystemAddress GetSystemByIndex(int filterSetID, unsigned index);
/// Returns the total number of filter sets.
/// \return The total number of filter sets.
unsigned GetFilterSetCount(void) const;
/// Returns the ID of a filter set, by index
/// \param[in] An index between 0 and GetFilterSetCount()-1 inclusive
int GetFilterSetIDByIndex(unsigned index);
/// Delete a FilterSet. All systems formerly subscribed to this filter are now unrestricted.
/// \param[in] filterSetID The ID of the filter set to delete.
void DeleteFilterSet(int filterSetID);
// --------------------------------------------------------------------------------------------
// Packet handling functions
// --------------------------------------------------------------------------------------------
virtual void OnAttach(RakPeerInterface *peer);
virtual void OnDetach(RakPeerInterface *peer);
virtual void OnShutdown(RakPeerInterface *peer);
virtual void Update(RakPeerInterface *peer);
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
protected:
void Clear(void);
void DeallocateFilterSet(FilterSet *filterSet);
FilterSet* GetFilterSetByID(int filterSetID);
void OnInvalidMessage(RakPeerInterface *peer, FilterSet *filterSet, SystemAddress systemAddress, unsigned char messageID);
DataStructures::OrderedList<int, FilterSet*, FilterSetComp> filterList;
DataStructures::OrderedList<SystemAddress, FilteredSystem, FilteredSystemComp> systemList;
int autoAddNewConnectionsToFilter;
};
#endif
+67 -9
View File
@@ -8,7 +8,7 @@
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.rakkarsoft.com/SingleApplicationLicense.html
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
@@ -18,6 +18,10 @@
#ifndef __MESSAGE_IDENTIFIERS_H
#define __MESSAGE_IDENTIFIERS_H
#if defined(RAKNET_USE_CUSTOM_PACKET_IDS)
#include "CustomPacketIdentifiers.h"
#else
/// You should not edit the file MessageIdentifiers.h as it is a part of RakNet static library
/// To define your own message id, define an enum following the code example that follows.
///
@@ -30,7 +34,7 @@
/// \endcode
///
/// \note All these enumerations should be casted to (unsigned char) before writing them to RakNet::BitStream
enum
enum DefaultMessageIDTypes
{
//
// RESERVED TYPES - DO NOT CHANGE THESE
@@ -63,6 +67,9 @@ enum
ID_RPC,
/// Remote procedure call reply, for RPCs that return data (internal use only)
ID_RPC_REPLY,
/// RakPeer - Same as ID_ADVERTISE_SYSTEM, but intended for internal use rather than being passed to the user. Second byte indicates type. Used currently for NAT punchthrough for receiver port advertisement. See ID_NAT_ADVERTISE_RECIPIENT_PORT
ID_OUT_OF_BAND_INTERNAL,
//
// USER TYPES - DO NOT CHANGE THESE
@@ -70,7 +77,7 @@ enum
/// RakPeer - In a client/server environment, our connection request to the server has been accepted.
ID_CONNECTION_REQUEST_ACCEPTED,
/// RakPeer - Sent to the player when a connection request cannot be completed due to inability to connect.
/// RakPeer - Sent to the player when a connection request cannot be completed due to inability to connect.
ID_CONNECTION_ATTEMPT_FAILED,
/// RakPeer - Sent a connect request to a system we are currently connected to.
ID_ALREADY_CONNECTED,
@@ -78,9 +85,9 @@ enum
ID_NEW_INCOMING_CONNECTION,
/// RakPeer - The system we attempted to connect to is not accepting new connections.
ID_NO_FREE_INCOMING_CONNECTIONS,
/// RakPeer - The system specified in Packet::systemAddress has disconnected from us. For the client, this would mean the server has shutdown.
/// RakPeer - The system specified in Packet::systemAddress has disconnected from us. For the client, this would mean the server has shutdown.
ID_DISCONNECTION_NOTIFICATION,
/// RakPeer - Reliable packets cannot be delivered to the system specified in Packet::systemAddress. The connection to that system has been closed.
/// RakPeer - Reliable packets cannot be delivered to the system specified in Packet::systemAddress. The connection to that system has been closed.
ID_CONNECTION_LOST,
/// RakPeer - We preset an RSA public key which does not match what the system we connected to is using.
ID_RSA_PUBLIC_KEY_MISMATCH,
@@ -100,11 +107,11 @@ enum
ID_REMOTE_DISCONNECTION_NOTIFICATION,
/// ConnectionGraph plugin - In a client/server environment, a client other than ourselves has been forcefully dropped. Packet::systemAddress is modified to reflect the systemAddress of this client.
ID_REMOTE_CONNECTION_LOST,
/// ConnectionGraph plugin - In a client/server environment, a client other than ourselves has connected. Packet::systemAddress is modified to reflect the systemAddress of this client.
/// ConnectionGraph plugin - In a client/server environment, a client other than ourselves has connected. Packet::systemAddress is modified to reflect the systemAddress of the client that is not connected directly to us. The packet encoding is SystemAddress 1, ConnectionGraphGroupID 1, SystemAddress 2, ConnectionGraphGroupID 2
ID_REMOTE_NEW_INCOMING_CONNECTION,
// RakPeer - Downloading a large message. Format is ID_DOWNLOAD_PROGRESS (MessageID), partCount (unsigned int), partTotal (unsigned int), partLength (unsigned int), first part data (length <= MAX_MTU_SIZE)
// RakPeer - Downloading a large message. Format is ID_DOWNLOAD_PROGRESS (MessageID), partCount (unsigned int), partTotal (unsigned int), partLength (unsigned int), first part data (length <= MAX_MTU_SIZE). See the three parameters partCount, partTotal and partLength in OnFileProgress in FileListTransferCBInterface.h
ID_DOWNLOAD_PROGRESS,
/// FileListTransfer plugin - Setup data
ID_FILE_LIST_TRANSFER_HEADER,
/// FileListTransfer plugin - A file
@@ -124,6 +131,8 @@ enum
ID_REPLICA_MANAGER_SCOPE_CHANGE,
/// ReplicaManager plugin - Serialized data of an object
ID_REPLICA_MANAGER_SERIALIZE,
/// ReplicaManager plugin - New connection, about to send all world objects
ID_REPLICA_MANAGER_DOWNLOAD_STARTED,
/// ReplicaManager plugin - Finished downloading all serialized objects
ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE,
@@ -180,6 +189,10 @@ enum
ID_NAT_CONNECT_AT_TIME,
/// NATPunchthrough plugin - Internal message to send a message (to punch through the nat) at a certain time
ID_NAT_SEND_OFFLINE_MESSAGE_AT_TIME,
/// NATPunchthrough plugin - The facilitator is already attempting this connection
ID_NAT_IN_PROGRESS,
/// NATPunchthrough plugin - Another system tried to connect to us, and failed. See guid and system address field in the Packet structure
ID_NAT_REMOTE_CONNECTION_ATTEMPT_FAILED,
/// LightweightDatabase plugin - Query
ID_DATABASE_QUERY_REQUEST,
@@ -202,11 +215,56 @@ enum
ID_READY_EVENT_ALL_SET,
/// ReadyEvent plugin - Request of ready event state - used for pulling data when newly connecting
ID_READY_EVENT_QUERY,
/// Lobby packets. Second byte indicates type.
ID_LOBBY_GENERAL,
/// Auto RPC procedure call
ID_AUTO_RPC_CALL,
/// Auto RPC functionName to index mapping
ID_AUTO_RPC_REMOTE_INDEX,
/// Auto RPC functionName to index mapping, lookup failed. Will try to auto recover
ID_AUTO_RPC_UNKNOWN_REMOTE_INDEX,
/// Auto RPC error code
/// See AutoRPC.h for codes, stored in packet->data[1]
ID_RPC_REMOTE_ERROR,
/// FileListTransfer transferring large files in chunks that are read only when needed, to save memory
ID_FILE_LIST_REFERENCE_PUSH,
/// Force the ready event to all set
ID_READY_EVENT_FORCE_ALL_SET,
/// Rooms function
ID_ROOMS_EXECUTE_FUNC,
ID_ROOMS_LOGON_STATUS,
ID_ROOMS_HANDLE_CHANGE,
/// Lobby2 message
ID_LOBBY2_SEND_MESSAGE,
ID_LOBBY2_SERVER_ERROR,
// RAKNET_PROTOCOL_VERSION in RakNetVersion.h does not match on the remote system what we have on our system
// This means the two systems cannot communicate.
// The 2nd byte of the message contains the value of RAKNET_PROTOCOL_VERSION for the remote system
ID_INCOMPATIBLE_PROTOCOL_VERSION,
/// FCMHost plugin telling another system we are adding them as a participant
ID_FCM_HOST_ADD_PARTICIPANT_REQUEST,
/// FCMHost plugin notifying the user that the host has changed. 2nd byte is FCMHostGroupID
ID_FCM_HOST_CHANGED,
// FCMHost plugin sent us a new list
ID_FCM_HOST_LIST_UPDATE,
// For the user to use. Start your first enumeration at this value.
ID_USER_PACKET_ENUM,
//-------------------------------------------------------------------------------------------------------------
};
#endif // RAKNET_USE_CUSTOM_PACKET_IDS
#endif
+193
View File
@@ -0,0 +1,193 @@
/// \file
/// \brief Contains the NAT-punchthrough plugin
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __NAT_PUNCHTHROUGH_H
#define __NAT_PUNCHTHROUGH_H
#include "RakNetTypes.h"
#include "Export.h"
#include "PluginInterface.h"
#include "PacketPriority.h"
#include "DS_List.h"
class RakPeerInterface;
struct Packet;
/// \defgroup NAT_PUNCHTHROUGH_GROUP NatPunchthrough
/// \ingroup PLUGINS_GROUP
/// \ingroup NAT_PUNCHTHROUGH_GROUP
/// \brief Prints logging output for NatPunchthrough
class RAK_DLL_EXPORT NatPunchthroughLogger
{
public:
NatPunchthroughLogger() {}
virtual ~NatPunchthroughLogger() {}
virtual void OnMessage(const char *str);
};
/// \brief The NatPunchthrough class implements the NAT punch through technique, allowing two systems to connect to each other that are both behind NATs.
///
/// A NAT (Network Address Translator) is a system that will makes it so your system's IP address is different from the IP address exposed to the internet.
/// This provides some security and allows multiple computers, each with a different IP address, to share one IP address as seen by the internet.
///
/// The problem is that NATs also ignore packets sent to them unless they sent a packet to the sender first.
/// If two systems are both behind NATs, then neither system can connect to each other.
/// Furthermore, some NATs will impose a temporary ban on an IP address that send unsolicited packets to them.
///
/// This can be solved by using a third system, a facilitator, that is not behind a NAT and that both systems are already connected to.
/// It will synchronize a send between both NAT systems such that the routers will both consider themselves as handling a reply to a message, when in
/// fact they are handing an initial message. As replies are allowed, both systems get their corresponding messages and the connection takes place.
/// S = system that wants to connect
/// F = facilitator
/// R = system to get the connection request.
///
/// S knows IP of R in advance.
/// 1. S->F facilitate connection request to R
/// 2. if (R is not is connected) F->S ID_NAT_TARGET_NOT_CONNECTED. Exit.
/// 3. F -> (Ping S, Ping R), every X ms Y times. Wait Max(Ping(s), Ping(r) * multiple ms more, then go to step 4.
/// 4. F picks time highest(ave of Ping R,S) * N from now and sends this time RELIABLE and timestamped to R,S.
/// 5. At time picked in (4), S attempts to connect to R. R sends offline ping to S.
/// 6. If R disconnects before or at step 4, tell this to S via ID_NAT_TARGET_CONNECTION_LOST
///
/// Rebinding instances of RakPeer:
/// If after connecting two instances of RakPeer, you want to use the now open ports on the router with another instance of RakPeer, follow these steps
/// A. Connect the two systems by NAT punchthrough. Store the IP address of the system you connected to. You can get this with SystemAddress::ToString(false)
/// B. Once you get ID_CONNECTION_REQUEST_ACCEPTED or ID_NEW_INCOMING_CONNECTION, call RakPeer::Shutdown(0). This will stop RakNet without telling the other system.
/// C. Wait about double the ping time to make sure the other system had the opportunity to call RakPeer::Shutdown(0).
/// D. Recreate on the receiver the instance of RakPeer, in the new application. If you originally used port 1234, call Startup() again with that port. If you used port 0, you will need to know what port the socket was bound on. Use GetInternalID(UNASSIGNED_SYSTEM_ADDRESS).port anytime after calling Startup()
/// E. Recreate on the sender the instance of RakPeer in the new application, using the same port as originally used in the last instance of RakPeer on the sender.
/// F. Connect the sender to the receiver, using the port returned by NatPunchthrough::GetLastPortUsedToConnect()
///
/// \note Timing is important with this plugin. You need to call RakPeer::Receive frequently.
/// \ingroup NAT_PUNCHTHROUGH_GROUP
class RAK_DLL_EXPORT NatPunchthrough : public PluginInterface
{
public:
/// Constructor
NatPunchthrough();
/// Destructor
virtual ~NatPunchthrough();
/// Call with true to allow other systems to use this system as a NAT punch through facilitator. This takes a little bandwidth but
/// otherwise there is no reason to disallow it.
/// Defaults to true
/// \param[in] allow True to allow, false to disallow.
void FacilitateConnections(bool allow);
/// Call this to start to connect to the specified host (ip or domain name) and server port using \a facilitator to punch through a NAT
/// This is a non-blocking operation
/// You know the connection is successful when you get the message ID_CONNECTION_ACCEPTED.
/// You know the connection failed when you get the message ID_CONNECTION_ATTEMPT_FAILED, ID_CONNECTION_BANNED, or ID_NAT_TARGET_NOT_CONNECTED
/// Both you and the host must be connected to the facilitator.
/// \pre Requires that you first call Initialize
/// \pre Both \a host and this system must already be connected to the system at the address \a facilitator and facilitator must be running NatPunchthrough with FacilitateConnections(true) previously called.
/// \param[in] destination Either a dotted IP address or a domain name of the system you ultimately want to connect to.
/// \param[in] remotePort Which port to connect to of the system you ultimately want to connect to.
/// \param[in] passwordData A data block that must match the data block on the \a host. This can be just a password, or can be a stream of data
/// \param[in] passwordDataLength The length in bytes of passwordData
/// \return If you are not connected to the facilitator this function returns false. Otherwise it returns true.
bool Connect(const char* destination, unsigned short remotePort, const char *passwordData, int passwordDataLength, SystemAddress facilitator);
/// Same as above, but takes a SystemAddress for a host
/// \param[in] destination The address of the host to connect to.
/// \param[in] remotePort Which port to connect to of the system you ultimately want to connect to.
/// \param[in] passwordData A data block that must match the data block on the \a host. This can be just a password, or can be a stream of data
/// \param[in] passwordDataLength The length in bytes of passwordData
/// \return If you are not connected to the facilitator this function returns false. Otherwise it returns true.
bool Connect(SystemAddress destination, const char *passwordData, int passwordDataLength, SystemAddress facilitator);
/// Free internal memory.
void Clear(void);
/// Sets the log output to print messages to
void SetLogger(NatPunchthroughLogger *l);
/// Returns the last port we tried to connect on.
/// If at some point we get ID_CONNECTION_REQUEST_ACCEPTED, the remote router should be open on this port,
/// and should forward messages send on this port to the remotely bound port.
/// Returns 0 if none.
unsigned short GetLastPortUsedToConnect(void) const;
/// \internal For plugin handling
virtual void OnAttach(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void Update(RakPeerInterface *peer);
/// \internal For plugin handling
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// \internal For plugin handling
virtual void OnShutdown(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
struct ConnectionRequest
{
// Used by all
// 0 means unset. non-zero means send a connection request or offline message at that time.
// If the sender is set, then we send an offline message. If the reciever is set, we send a connection request.
RakNetTime nextActionTime;
// Used by sender and facilitator
bool facilitatingConnection;
SystemAddress receiverPublic;
SystemAddress receiverPrivate[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
// Used to remove old connection Requests
RakNetTime timeoutTime;
RakNetGUID receiverGuid;
// Used only by sender
SystemAddress facilitator;
char* passwordData;
int passwordDataLength;
SystemAddress advertisedAddress;
SystemAddress lastAddressAttempted;
// Used only by facilitator
SystemAddress senderPublic;
SystemAddress senderPrivate[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
unsigned char pingCount;
RakNetGUID senderGuid;
// Used by recipient
int recipientOfflineCount;
bool attemptedConnection;
void GetAddressList(RakPeerInterface *rakPeer, DataStructures::List<SystemAddress> &fallbackAddresses, SystemAddress publicAddress, SystemAddress privateAddress[MAXIMUM_NUMBER_OF_INTERNAL_IDS], bool excludeConnected);
};
protected:
void OnPunchthroughRequest(RakPeerInterface *peer, Packet *packet);
void OnNATAdvertiseRecipientPort(RakPeerInterface *peer, Packet *packet);
void OnConnectAtTime(RakPeerInterface *peer, Packet *packet);
void OnSendOfflineMessageAtTime(RakPeerInterface *peer, Packet *packet);
void RemoveRequestByFacilitator(SystemAddress systemAddress);
void LogOut(const char *l);
PluginReceiveResult OnConnectionAttemptFailed(Packet *packet);
void RemoveFromConnectionRequestList(SystemAddress systemAddress, RakNetGUID guid);
PluginReceiveResult OnNewIncomingConnection(Packet *packet);
bool allowFacilitation;
RakPeerInterface *rakPeer;
DataStructures::List<ConnectionRequest*> connectionRequestList;
NatPunchthroughLogger *log;
// This is updated every time Connect() is called. You need to know it if you want to reconnect to that system without
// Running NAT punchthrough again
unsigned short lastPortUsedToConnect;
};
#endif
+24
View File
@@ -0,0 +1,24 @@
#ifndef __NATIVE_TYPES_H
#define __NATIVE_TYPES_H
#if (defined(__GNUC__) || defined(__GCCXML__) || defined(__SNC__))
#include <stdint.h>
#endif
#if !defined(_STDINT_H) && !defined(_SN_STDINT_H)
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
#if defined(_MSC_VER) && _MSC_VER < 1300
typedef unsigned __int64 uint64_t;
typedef signed __int64 int64_t;
#else
typedef unsigned long long int uint64_t;
typedef signed long long int64_t;
#endif
#endif
#endif
+128
View File
@@ -0,0 +1,128 @@
/// \file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __NETWORK_ID_MANAGER_H
#define __NETWORK_ID_MANAGER_H
#include "DS_BinarySearchTree.h"
#include "RakNetTypes.h"
#include "Export.h"
#include "RakMemoryOverride.h"
#include "NetworkIDObject.h"
/// \internal
/// \brief A node in the AVL tree that holds the mapping between NetworkID and pointers.
struct RAK_DLL_EXPORT NetworkIDNode
{
NetworkID networkID;
NetworkIDObject *object;
NetworkIDNode();
NetworkIDNode( NetworkID _networkID, NetworkIDObject *_object );
bool operator==( const NetworkIDNode& right ) const;
bool operator > ( const NetworkIDNode& right ) const;
bool operator < ( const NetworkIDNode& right ) const;
};
/// This class is simply used to generate a unique number for a group of instances of NetworkIDObject
/// An instance of this class is required to use the ObjectID to pointer lookup system
/// You should have one instance of this class per game instance.
/// Call SetIsNetworkIDAuthority before using any functions of this class, or of NetworkIDObject
class RAK_DLL_EXPORT NetworkIDManager
{
public:
NetworkIDManager(void);
virtual ~NetworkIDManager(void);
/// For every group of systems, one system needs to be responsible for creating unique IDs for all objects created on all systems.
/// This way, systems can send that id in packets to refer to objects (you can't send pointers because the memory allocations may be different).
/// In a client/server environment, the system that creates unique IDs would be the server.
/// If you are using peer to peer or other situations where you don't have a single system to assign ids,
/// set this to true, and be sure NETWORK_ID_SUPPORTS_PEER_TO_PEER is defined in RakNetDefines.h
void SetIsNetworkIDAuthority(bool isAuthority);
/// \return Returns what was passed to SetIsNetworkIDAuthority()
bool IsNetworkIDAuthority(void) const;
/// \Depreciated. Use SetGuid and GetGuid instead
/// Necessary for peer to peer, as NetworkIDs are then composed of your external player Id (doesn't matter which, as long as unique)
/// plus the usual object ID number.
/// Get this from RakPeer::GetExternalSystemAddress) one time, the first time you make a connection.
/// \pre You must first call SetNetworkIDManager before using this function
/// \param[in] systemAddress Your external systemAddress
void SetExternalSystemAddress(SystemAddress systemAddress);
SystemAddress GetExternalSystemAddress(void);
/// Necessary for peer to peer, as NetworkIDs are then composed of your external player Id (doesn't matter which, as long as unique)
/// plus the usual object ID number.
/// Get this from RakPeer::GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS) one time, the first time you make a connection.
/// \pre You must first call SetNetworkIDManager before using this function
void SetGuid(RakNetGUID g);
RakNetGUID GetGuid(void);
/// These function is only meant to be used when saving games as you
/// should save the HIGHEST value staticItemID has achieved upon save
/// and reload it upon load. Save AFTER you've created all the items
/// derived from this class you are going to create.
/// \return the HIGHEST Object Id currently used
unsigned short GetSharedNetworkID( void );
/// These function is only meant to be used when loading games. Load
/// BEFORE you create any new objects that are not SetIDed based on
/// the save data.
/// \param[in] i the highest number of NetworkIDObject reached.
void SetSharedNetworkID( unsigned short i );
/// If you use a parent, returns this instance rather than the parent object.
/// \pre You must first call SetNetworkIDManager before using this function
NetworkIDObject* GET_BASE_OBJECT_FROM_ID( NetworkID x );
/// Returns the parent object, or this instance if you don't use a parent.
/// \depreciated, use the template form. This form requires that NetworkIDObject is the basemost derived class
/// \pre You must first call SetNetworkIDManager before using this function
void* GET_OBJECT_FROM_ID( NetworkID x );
/// Returns the parent object, or this instance if you don't use a parent.
/// Supports NetworkIDObject anywhere in the inheritance hierarchy
/// \pre You must first call SetNetworkIDManager before using this function
template <class returnType>
returnType GET_OBJECT_FROM_ID(NetworkID x) {
NetworkIDObject *nio = GET_BASE_OBJECT_FROM_ID(x);
if (nio==0)
return 0;
if (nio->GetParent())
return (returnType) nio->GetParent();
return (returnType) nio;
}
protected:
RakNetGUID guid;
// Depreciated - use guid instead. This has the problem that it can be different between the LAN and the internet, or duplicated on different LANs
SystemAddress externalSystemAddress;
unsigned short sharedNetworkID;
bool isNetworkIDAuthority;
bool calledSetIsNetworkIDAuthority;
friend class NetworkIDObject;
#if ! defined(NETWORK_ID_USE_PTR_TABLE) || defined(NETWORK_ID_USE_HASH)
/// This AVL tree holds the pointer to NetworkID mappings
DataStructures::AVLBalancedBinarySearchTree<NetworkIDNode> IDTree;
#else
NetworkIDObject **IDArray;
#endif
};
#endif
+98
View File
@@ -0,0 +1,98 @@
/// \file
/// \brief A class you can derive from to make it easier to represent every networked object with an integer. This way you can refer to objects over the network.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#if !defined(__NETWORK_ID_GENERATOR)
#define __NETWORK_ID_GENERATOR
#include "RakNetTypes.h"
#include "RakMemoryOverride.h"
#include "Export.h"
class NetworkIDManager;
/// \brief Unique shared ids for each object instance
///
/// A class you can derive from to make it easier to represent every networked object with an integer. This way you can refer to objects over the network.
/// One system should return true for IsNetworkIDAuthority() and the rest should return false. When an object needs to be created, have the the one system create the object.
/// Then have that system send a message to all other systems, and include the value returned from GetNetworkID() in that packet. All other systems should then create the same
/// class of object, and call SetNetworkID() on that class with the NetworkID in the packet.
/// \see the manual for more information on this.
class RAK_DLL_EXPORT NetworkIDObject
{
public:
/// Constructor. NetworkIDs, if IsNetworkIDAuthority() is true, are created here.
NetworkIDObject();
/// Destructor. Used NetworkIDs, if any, are freed here.
virtual ~NetworkIDObject();
/// Sets the manager class from which to request unique network IDs
/// Unlike previous versions, the NetworkIDObject relies on a manager class to provide IDs, rather than using statics,
/// So you can have more than one set of IDs on the same system.
virtual void SetNetworkIDManager( NetworkIDManager *manager);
/// Returns what was passed to SetNetworkIDManager
virtual NetworkIDManager * GetNetworkIDManager( void );
/// Returns the NetworkID that you can use to refer to this object over the network.
/// \pre You must first call SetNetworkIDManager before using this function
/// \retval UNASSIGNED_NETWORK_ID UNASSIGNED_NETWORK_ID is returned IsNetworkIDAuthority() is false and SetNetworkID() was not previously called. This is also returned if you call this function in the constructor.
/// \retval 0-65534 Any other value is a valid NetworkID. NetworkIDs start at 0 and go to 65534, wrapping at that point.
virtual NetworkID GetNetworkID( void );
/// Sets the NetworkID for this instance. Usually this is called by the clients and determined from the servers. However, if you save multiplayer games you would likely use
/// This on load as well.
virtual void SetNetworkID( NetworkID id );
/// Your class does not have to derive from NetworkIDObject, although that is the easiest way to implement this.
/// If you want this to be a member object of another class, rather than inherit, then call SetParent() with a pointer to the parent class instance.
/// GET_OBJECT_FROM_ID will then return the parent rather than this instance.
virtual void SetParent( void *_parent );
/// Return what was passed to SetParent
/// \return The value passed to SetParent, or 0 if it was never called.
virtual void* GetParent( void ) const;
/// Overload this function and return true if you require that SetParent is called before this object is used.
/// This is a safety check you should do this if you want this to be
/// a member object of another class rather than derive from this class.
virtual bool RequiresSetParent(void) const;
/// Used so I can compare pointers in the ReplicaManager
unsigned int GetAllocationNumber(void) const;
protected:
/// The network ID of this object
NetworkID networkID;
/// The parent set by SetParent()
void *parent;
/// Used so I can compare pointers in the ReplicaManager
static unsigned int nextAllocationNumber;
unsigned int allocationNumber;
/// Internal function to generate an ID when needed. This is deferred until needed and is not called from the constructor.
void GenerateID(void);
/// This is crap but is necessary because virtual functions don't work in the constructor
bool callGenerationCode;
NetworkIDManager *networkIDManager;
};
#endif
+37
View File
@@ -0,0 +1,37 @@
/// \file
/// \brief This will write all incoming and outgoing network messages to the log command parser, which can be accessed through Telnet
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __PACKET_CONSOLE_LOGGER_H_
#define __PACKET_CONSOLE_LOGGER_H_
#include "PacketLogger.h"
class LogCommandParser;
/// \ingroup PACKETLOGGER_GROUP
/// \brief Packetlogger that logs to a remote command console
class RAK_DLL_EXPORT PacketConsoleLogger : public PacketLogger
{
public:
PacketConsoleLogger();
// Writes to the command parser used for logging, which is accessed through a secondary communication layer (such as Telnet or RakNet) - See ConsoleServer.h
virtual void SetLogCommandParser(LogCommandParser *lcp);
virtual void WriteLog(const char *str);
protected:
LogCommandParser *logCommandParser;
};
#endif
+37
View File
@@ -0,0 +1,37 @@
/// \file
/// \brief This will write all incoming and outgoing network messages to a file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __PACKET_FILE_LOGGER_H_
#define __PACKET_FILE_LOGGER_H_
#include "PacketLogger.h"
#include <stdio.h>
/// \ingroup PACKETLOGGER_GROUP
/// \brief Packetlogger that outputs to a file
class RAK_DLL_EXPORT PacketFileLogger : public PacketLogger
{
public:
PacketFileLogger();
virtual ~PacketFileLogger();
void StartLog(const char *filenamePrefix);
virtual void WriteLog(const char *str);
protected:
FILE *packetLogFile;
};
#endif
+86
View File
@@ -0,0 +1,86 @@
/// \file
/// \brief This will write all incoming and outgoing network messages to the local console screen. See derived functions for other outputs
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __PACKET_LOGGER_H
#define __PACKET_LOGGER_H
class RakPeerInterface;
#include "RakNetTypes.h"
#include "PluginInterface.h"
#include "Export.h"
/// \defgroup PACKETLOGGER_GROUP PacketLogger
/// \ingroup PLUGINS_GROUP
/// \brief Writes incoming and outgoing messages to the screen.
/// This will write all incoming and outgoing messages to the console window, or to a file if you override it and give it this functionality.
/// \ingroup PACKETLOGGER_GROUP
class RAK_DLL_EXPORT PacketLogger : public PluginInterface
{
public:
PacketLogger();
virtual ~PacketLogger();
virtual void OnAttach(RakPeerInterface *peer);
virtual void Update(RakPeerInterface *peer);
// Translate the supplied parameters into an output line - overloaded version that takes a MessageIdentifier
// and translates it into a string (numeric or textual representation based on printId); this calls the
// second version which takes a const char* argument for the messageIdentifier
virtual void FormatLine(char* into, const char* dir, const char* type, unsigned int packet, unsigned int frame
, unsigned char messageIdentifier, const BitSize_t bitLen, unsigned long long time, const SystemAddress& local, const SystemAddress& remote,
unsigned int splitPacketId, unsigned int splitPacketIndex, unsigned int splitPacketCount, unsigned int orderingIndex);
virtual void FormatLine(char* into, const char* dir, const char* type, unsigned int packet, unsigned int frame
, const char* idToPrint, const BitSize_t bitLen, unsigned long long time, const SystemAddress& local, const SystemAddress& remote,
unsigned int splitPacketId, unsigned int splitPacketIndex, unsigned int splitPacketCount, unsigned int orderingIndex);
/// Events on low level sends and receives. These functions may be called from different threads at the same time.
virtual void OnDirectSocketSend(const char *data, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress);
virtual void OnDirectSocketReceive(const char *data, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress);
virtual void OnInternalPacket(InternalPacket *internalPacket, unsigned frameNumber, SystemAddress remoteSystemAddress, RakNetTime time, bool isSend);
/// Logs out a header for all the data
virtual void LogHeader(void);
/// Override this to log strings to wherever. Log should be threadsafe
virtual void WriteLog(const char *str);
// Set to true to print ID_* instead of numbers
virtual void SetPrintID(bool print);
// Print or hide acks (clears up the screen not to print them but is worse for debugging)
virtual void SetPrintAcks(bool print);
/// Prepend this string to output logs.
virtual void SetPrefix(const char *_prefix);
/// Append this string to output logs. (newline is useful here)
virtual void SetSuffix(const char *_suffix);
static const char* BaseIDTOString(unsigned char Id);
protected:
const char* IDTOString(unsigned char Id);
virtual void AddToLog(const char *str);
// Users should override this
virtual const char* UserIDTOString(unsigned char Id);
RakPeerInterface *rakPeer;
bool printId, printAcks;
char prefix[256];
char suffix[256];
};
#endif
+1
View File
@@ -0,0 +1 @@
// REMOVEME
+31 -10
View File
@@ -8,7 +8,7 @@
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.rakkarsoft.com/SingleApplicationLicense.html
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
@@ -21,10 +21,19 @@
/// These enumerations are used to describe when packets are delivered.
enum PacketPriority
{
SYSTEM_PRIORITY, /// \internal Used by RakNet to send above-high priority messages.
HIGH_PRIORITY, /// High priority messages are send before medium priority messages.
MEDIUM_PRIORITY, /// Medium priority messages are send before low priority messages.
LOW_PRIORITY, /// Low priority messages are only sent when no other messages are waiting.
/// \internal Used by RakNet to send above-high priority messages.
SYSTEM_PRIORITY,
/// High priority messages are send before medium priority messages.
HIGH_PRIORITY,
/// Medium priority messages are send before low priority messages.
MEDIUM_PRIORITY,
/// Low priority messages are only sent when no other messages are waiting.
LOW_PRIORITY,
/// \internal
NUMBER_OF_PRIORITIES
};
@@ -32,11 +41,23 @@ enum PacketPriority
/// \note Note to self: I write this with 3 bits in the stream. If I add more remember to change that
enum PacketReliability
{
UNRELIABLE, /// Same as regular UDP, except that it will also discard duplicate datagrams. RakNet adds (6 to 17) + 21 bits of overhead, 16 of which is used to detect duplicate packets and 6 to 17 of which is used for message length.
UNRELIABLE_SEQUENCED, /// Regular UDP with a sequence counter. Out of order messages will be discarded. This adds an additional 13 bits on top what is used for UNRELIABLE.
RELIABLE, /// The message is sent reliably, but not necessarily in any order. Same overhead as UNRELIABLE.
RELIABLE_ORDERED, /// This message is reliable and will arrive in the order you sent it. Messages will be delayed while waiting for out of order messages. Same overhead as UNRELIABLE_SEQUENCED.
RELIABLE_SEQUENCED /// This message is reliable and will arrive in the sequence you sent it. Out or order messages will be dropped. Same overhead as UNRELIABLE_SEQUENCED.
/// Same as regular UDP, except that it will also discard duplicate datagrams. RakNet adds (6 to 17) + 21 bits of overhead, 16 of which is used to detect duplicate packets and 6 to 17 of which is used for message length.
UNRELIABLE,
/// Regular UDP with a sequence counter. Out of order messages will be discarded. This adds an additional 13 bits on top what is used for UNRELIABLE.
UNRELIABLE_SEQUENCED,
/// The message is sent reliably, but not necessarily in any order. Same overhead as UNRELIABLE.
RELIABLE,
/// This message is reliable and will arrive in the order you sent it. Messages will be delayed while waiting for out of order messages. Same overhead as UNRELIABLE_SEQUENCED.
RELIABLE_ORDERED,
/// This message is reliable and will arrive in the sequence you sent it. Out or order messages will be dropped. Same overhead as UNRELIABLE_SEQUENCED.
RELIABLE_SEQUENCED,
/// \internal
NUMBER_OF_RELIABILITIES
};
#endif
+262
View File
@@ -0,0 +1,262 @@
#ifndef PLATFORM_HPP
#define PLATFORM_HPP
//// Platform tweaks ////
#include "RakNetTypes.h"
#ifdef _WIN32_WCE //makslane
# define _byteswap_ushort(s) ((s >> 8) | (s << 8))
# define _byteswap_ulong(s) (byteswap_ushort(s&0xffff)<<16) | (byteswap_ushort(s>>16))
# define byteswap_ushort _byteswap_ushort
# define byteswap_ulong _byteswap_ulong
#endif
#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
# if defined(__sparc) || defined(__sparc__) || defined(__powerpc__) || \
defined(__ppc__) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || \
defined(_M_PPC) || defined(_M_MPPC) || defined(_M_MRX000) || \
defined(__POWERPC) || defined(m68k) || defined(powerpc) || \
defined(sel) || defined(pyr) || defined(mc68000) || defined(is68k) || \
defined(tahoe) || defined(ibm032) || defined(ibm370) || defined(MIPSEB) || \
defined(__convex__) || defined(DGUX) || defined(hppa) || defined(apollo) || \
defined(_CRAY) || defined(__hp9000) || defined(__hp9000s300) || defined(_AIX) || \
defined(__AIX) || defined(__pyr__) || defined(hp9000s700) || defined(_IBMR2)
# define BIG_ENDIAN
# elif defined(__i386__) || defined(i386) || defined(intel) || defined(_M_IX86) || \
defined(__alpha__) || defined(__alpha) || defined(__ia64) || defined(__ia64__) || \
defined(_M_ALPHA) || defined(ns32000) || defined(__ns32000__) || defined(sequent) || \
defined(MIPSEL) || defined(_MIPSEL) || defined(sun386) || defined(__sun386__) || \
defined(x86_64) || defined(__x86_64)
# define LITTLE_ENDIAN
# else
# error "Add your platform to the list"
# endif
#endif
//// Compiler tweaks ////
// Structure packing syntax
#if defined(__GNUC__)
#ifndef PACKED
# define PACKED __attribute__((__packed__))
#endif
# define ASSEMBLY_ATT_SYNTAX
# define ASSEMBLY_BLOCK asm
#elif defined(_WIN32)
# define PACKED
# define PRAGMA_PACK /* pragma push/pop */
#ifndef DEBUG
# define DEBUG _DEBUG
#endif
# if !defined(_M_X64)
# define ASSEMBLY_INTEL_SYNTAX
# define ASSEMBLY_BLOCK __asm
# endif
#elif defined(__BORLANDC__) // Borland
# define ASSEMBLY_INTEL_SYNTAX
# define ASSEMBLY_BLOCK _asm
#else
# error "Fix code for your compiler's packing syntax"
#endif
// Stringize
#define STRINGIZE(X) DO_STRINGIZE(X)
#define DO_STRINGIZE(X) #X
//// Elementary types ////
struct u128 { uint32_t u[4]; };
union Float32 {
float f;
uint32_t i;
Float32(float n) { f = n; }
Float32(uint32_t n) { i = n; }
};
//// Coordinate system ////
// Order of vertices in any quad
enum QuadCoords
{
QUAD_UL, // upper left (0,0)
QUAD_LL, // lower left (0,1)
QUAD_LR, // lower right (1,1)
QUAD_UR, // upper right (1,0)
};
//// Rotation macros ////
#ifndef ROL8
#define ROL8(n, r) ( ((uint8_t)(n) << (r)) | ((uint8_t)(n) >> ( 8 - (r))) ) /* only works for uint8_t */
#endif
#ifndef ROR8
#define ROR8(n, r) ( ((uint8_t)(n) >> (r)) | ((uint8_t)(n) << ( 8 - (r))) ) /* only works for uint8_t */
#endif
#ifndef ROL16
#define ROL16(n, r) ( ((uint16_t)(n) << (r)) | ((uint16_t)(n) >> (16 - (r))) ) /* only works for uint16_t */
#endif
#ifndef ROR16
#define ROR16(n, r) ( ((uint16_t)(n) >> (r)) | ((uint16_t)(n) << (16 - (r))) ) /* only works for uint16_t */
#endif
#ifndef ROL32
#define ROL32(n, r) ( ((uint32_t)(n) << (r)) | ((uint32_t)(n) >> (32 - (r))) ) /* only works for uint32_t */
#endif
#ifndef ROR32
#define ROR32(n, r) ( ((uint32_t)(n) >> (r)) | ((uint32_t)(n) << (32 - (r))) ) /* only works for uint32_t */
#endif
#ifndef ROL64
#define ROL64(n, r) ( ((uint64_t)(n) << (r)) | ((uint64_t)(n) >> (64 - (r))) ) /* only works for uint64_t */
#endif
#ifndef ROR64
#define ROR64(n, r) ( ((uint64_t)(n) >> (r)) | ((uint64_t)(n) << (64 - (r))) ) /* only works for uint64_t */
#endif
//// Byte-order swapping ////
#ifndef BOSWAP16
#define BOSWAP16(n) ROL16(n, 8)
#endif
#ifndef BOSWAP32
#define BOSWAP32(n) ( (ROL32(n, 8) & 0x00ff00ff) | (ROL32(n, 24) & 0xff00ff00) )
#endif
#ifndef BOSWAP64
#define BOSWAP64(n) ( ((uint64_t)BOSWAP32((uint32_t)n) << 32) | BOSWAP32((uint32_t)(n >> 32)) )
#endif
//// Miscellaneous bitwise macros ////
#define BITCLRHI8(reg, count) ((uint8_t)((uint8_t)(reg) << (count)) >> (count)) /* sets to zero a number of high bits in a byte */
#define BITCLRLO8(reg, count) ((uint8_t)((uint8_t)(reg) >> (count)) << (count)) /* sets to zero a number of low bits in a byte */
#define BITCLRHI16(reg, count) ((uint16_t)((uint16_t)(reg) << (count)) >> (count)) /* sets to zero a number of high bits in a 16-bit word */
#define BITCLRLO16(reg, count) ((uint16_t)((uint16_t)(reg) >> (count)) << (count)) /* sets to zero a number of low bits in a 16-bit word */
#define BITCLRHI32(reg, count) ((uint32_t)((uint32_t)(reg) << (count)) >> (count)) /* sets to zero a number of high bits in a 32-bit word */
#define BITCLRLO32(reg, count) ((uint32_t)((uint32_t)(reg) >> (count)) << (count)) /* sets to zero a number of low bits in a 32-bit word */
//// Integer macros ////
#define AT_LEAST_2_BITS(n) ( (n) & ((n) - 1) )
#define LEAST_SIGNIFICANT_BIT(n) ( (n) & -(n) ) /* 0 -> 0 */
#define IS_POWER_OF_2(n) ( n && !AT_LEAST_2_BITS(n) )
// Bump 'n' to the next unit of 'width'
// 0=CEIL_UNIT(0, 16), 1=CEIL_UNIT(1, 16), 1=CEIL_UNIT(16, 16), 2=CEIL_UNIT(17, 16)
#define CEIL_UNIT(n, width) ( ( (n) + (width) - 1 ) / (width) )
// 0=CEIL(0, 16), 16=CEIL(1, 16), 16=CEIL(16, 16), 32=CEIL(17, 16)
#define CEIL(n, width) ( CEIL_UNIT(n, width) * (width) )
//// String and buffer macros ////
// Same as strncpy() in all ways except that the result is guaranteed to
// be a nul-terminated C string
#ifndef STRNCPY
# define STRNCPY(dest, src, size) { strncpy(dest, src, size); (dest)[(size)-1] = '\0'; }
#endif
// Because memory clearing is a frequent operation
#define MEMCLR(dest, size) memset(dest, 0, size)
// Works for arrays, also
#define OBJCLR(object) memset(&(object), 0, sizeof(object))
//// Intrinsics ////
#if defined(_MSC_VER)
# include <cstdlib>
# pragma intrinsic(_lrotl)
# pragma intrinsic(_lrotr)
# pragma intrinsic(_byteswap_ushort)
# pragma intrinsic(_byteswap_ulong)
# undef ROL32
# undef ROR32
# undef BOSWAP16
# undef BOSWAP32
# define ROL32(n, r) _lrotl(n, r)
# define ROR32(n, r) _lrotr(n, r)
# define BOSWAP16(n) _byteswap_ushort(n)
# define BOSWAP32(n) _byteswap_ulong(n)
#endif
// getLE() converts from little-endian word to native byte-order word
// getBE() converts from big-endian word to native byte-order word
#if defined(LITTLE_ENDIAN)
# define swapLE(n)
# define getLE(n) (n)
# define getLE16(n) (n)
# define getLE32(n) (n)
# define getLE64(n) (n)
inline void swapBE(uint16_t &n) { n = BOSWAP16(n); }
inline void swapBE(uint32_t &n) { n = BOSWAP32(n); }
inline void swapBE(uint64_t &n) { n = BOSWAP64(n); }
inline uint16_t getBE(uint16_t n) { return BOSWAP16(n); }
inline uint32_t getBE(uint32_t n) { return BOSWAP32(n); }
inline uint64_t getBE(uint64_t n) { return BOSWAP64(n); }
inline uint16_t getBE16(uint16_t n) { return BOSWAP16(n); }
inline uint32_t getBE32(uint32_t n) { return BOSWAP32(n); }
inline uint64_t getBE64(uint64_t n) { return BOSWAP64(n); }
inline void swapBE(int16_t &n) { n = BOSWAP16((uint16_t)n); }
inline void swapBE(int32_t &n) { n = BOSWAP32((uint32_t)n); }
inline void swapBE(int64_t &n) { n = BOSWAP64((uint64_t)n); }
inline int16_t getBE(int16_t n) { return BOSWAP16((uint16_t)n); }
inline int32_t getBE(int32_t n) { return BOSWAP32((uint32_t)n); }
inline int64_t getBE(int64_t n) { return BOSWAP64((uint64_t)n); }
inline float getBE(float n) {
Float32 c = n;
c.i = BOSWAP32(c.i);
return c.f;
}
#else
# define swapBE(n)
# define getBE(n) (n)
# define getBE16(n) (n)
# define getBE32(n) (n)
# define getBE64(n) (n)
inline void swapLE(uint16_t &n) { n = BOSWAP16(n); }
inline void swapLE(uint32_t &n) { n = BOSWAP32(n); }
inline void swapLE(uint64_t &n) { n = BOSWAP64(n); }
inline uint16_t getLE(uint16_t n) { return BOSWAP16(n); }
inline uint32_t getLE(uint32_t n) { return BOSWAP32(n); }
inline uint64_t getLE(uint64_t n) { return BOSWAP64(n); }
inline uint16_t getLE16(uint16_t n) { return BOSWAP16(n); }
inline uint32_t getLE32(uint32_t n) { return BOSWAP32(n); }
inline uint64_t getLE32(uint64_t n) { return BOSWAP64(n); }
inline void swapLE(int16_t &n) { n = BOSWAP16((uint16_t)n); }
inline void swapLE(int32_t &n) { n = BOSWAP32((uint32_t)n); }
inline void swapLE(int64_t &n) { n = BOSWAP64((uint64_t)n); }
inline int16_t getLE(int16_t n) { return BOSWAP16((uint16_t)n); }
inline int32_t getLE(int32_t n) { return BOSWAP32((uint32_t)n); }
inline int64_t getLE(int64_t n) { return BOSWAP64((uint64_t)n); }
inline float getLE(float n) {
Float32 c = n;
c.i = BOSWAP32(c.i);
return c.f;
}
#endif
#endif // include guard
+111
View File
@@ -0,0 +1,111 @@
/// \file
/// \brief \b RakNet's plugin functionality system. You can derive from this to create your own plugins.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __PLUGIN_INTERFACE_H
#define __PLUGIN_INTERFACE_H
class RakPeerInterface;
struct Packet;
struct InternalPacket;
enum PluginReceiveResult
{
// The plugin used this message and it shouldn't be given to the user.
RR_STOP_PROCESSING_AND_DEALLOCATE=0,
// This message will be processed by other plugins, and at last by the user.
RR_CONTINUE_PROCESSING,
// The plugin is going to hold on to this message. Do not deallocate it but do not pass it to other plugins either.
RR_STOP_PROCESSING,
};
#include "RakNetTypes.h"
#include "Export.h"
#include "RakMemoryOverride.h"
/// \defgroup PLUGINS_GROUP PluginInterface
/// \brief PluginInterface provides a mechanism to add functionality in a modular way.
/// MessageHandlers should derive from PluginInterface and be attached to RakPeer using the function AttachPlugin
/// On a user call to Receive, OnReceive is called for every PluginInterface, which can then take action based on the message
/// passed to it. This is used to transparently add game-independent functional modules, similar to browser plugins
///
/// \sa ReplicaManager
/// \sa FullyConnectedMesh
/// \sa PacketLogger
/// \ingroup PLUGINS_GROUP
class RAK_DLL_EXPORT PluginInterface
{
public:
PluginInterface();
virtual ~PluginInterface();
/// Called when the interface is attached
/// \param[in] peer the instance of RakPeer that is calling Receive
virtual void OnAttach(RakPeerInterface *peer);
/// Called when the interface is detached
/// \param[in] peer the instance of RakPeer that is calling Receive
virtual void OnDetach(RakPeerInterface *peer);
/// Called when RakPeer is initialized
/// \param[in] peer the instance of RakPeer that is calling Receive
virtual void OnStartup(RakPeerInterface *peer);
/// Update is called every time a packet is checked for .
/// \param[in] peer - the instance of RakPeer that is calling Receive
virtual void Update(RakPeerInterface *peer);
/// OnReceive is called for every packet.
/// \param[in] peer the instance of RakPeer that is calling Receive
/// \param[in] packet the packet that is being returned to the user
/// \return True to allow the game and other plugins to get this message, false to absorb it
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// Called when RakPeer is shutdown
/// \param[in] peer the instance of RakPeer that is calling Receive
virtual void OnShutdown(RakPeerInterface *peer);
/// Called when a connection is dropped because the user called RakPeer::CloseConnection() for a particular system
/// \param[in] peer the instance of RakPeer that is calling Receive
/// \param[in] systemAddress The system whose connection was closed
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
/// Called on a send to the socket, per datagram, that does not go through the reliability layer
/// \param[in] data The data being sent
/// \param[in] bitsUsed How many bits long \a data is
/// \param[in] remoteSystemAddress Which system this message is being sent to
virtual void OnDirectSocketSend(const char *data, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress);
/// Called on a receive from the socket, per datagram, that does not go through the reliability layer
/// \param[in] data The data being sent
/// \param[in] bitsUsed How many bits long \a data is
/// \param[in] remoteSystemAddress Which system this message is being sent to
virtual void OnDirectSocketReceive(const char *data, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress);
/// Called on a send or recieve within the reliability layer
/// \param[in] internalPacket The user message, along with all send data.
/// \param[in] frameNumber The number of frames sent or received so far for this player depending on \a isSend . Indicates the frame of this user message.
/// \param[in] remoteSystemAddress The player we sent or got this packet from
/// \param[in] time The current time as returned by RakNet::GetTime()
/// \param[in] isSend Is this callback representing a send event or receive event?
virtual void OnInternalPacket(InternalPacket *internalPacket, unsigned frameNumber, SystemAddress remoteSystemAddress, RakNetTime time, bool isSend);
};
#endif
+49
View File
@@ -0,0 +1,49 @@
/// \file
/// \brief \b [Internal] A container class for a list of RPCNodes
///
/// \ingroup RAKNET_RPC
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RPC_MAP
#define __RPC_MAP
#include "RakMemoryOverride.h"
#include "RPCNode.h"
#include "DS_List.h"
#include "RakNetTypes.h"
#include "Export.h"
/// \ingroup RAKNET_RPC
/// \internal
/// \brief A container class for a list of RPCNodes
struct RAK_DLL_EXPORT RPCMap
{
public:
RPCMap();
~RPCMap();
void Clear(void);
RPCNode *GetNodeFromIndex(RPCIndex index);
RPCNode *GetNodeFromFunctionName(const char *uniqueIdentifier);
RPCIndex GetIndexFromFunctionName(const char *uniqueIdentifier);
void AddIdentifierWithFunction(const char *uniqueIdentifier, void *functionPointer, bool isPointerToMember);
void AddIdentifierAtIndex(const char *uniqueIdentifier, RPCIndex insertionIndex);
void RemoveNode(const char *uniqueIdentifier);
protected:
DataStructures::List<RPCNode *> rpcSet;
};
#endif
+61
View File
@@ -0,0 +1,61 @@
/// \file
/// \brief \b [Internal] Holds information related to a RPC
///
/// \ingroup RAKNET_RPC
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RPC_NODE
#define __RPC_NODE
#include "RakNetTypes.h"
#include "Export.h"
class RakPeerInterface;
/// \defgroup RAKNET_RPC Remote Procedure Call Subsystem
/// \brief A system to call C or object member procudures on other systems, and even to return return values.
/// \ingroup RAKNET_RPC
/// \internal
///
/// \brief Map registered procedure inside of a peer.
///
struct RAK_DLL_EXPORT RPCNode
{
/// String identifier of the RPC
char *uniqueIdentifier;
/// Force casting of member functions to void *
union
{
void ( *staticFunctionPointer ) ( RPCParameters *rpcParms );
#if (defined(__GNUC__) || defined(__GCCXML__))
void (*memberFunctionPointer)(void* _this, RPCParameters *rpcParms);
#else
void (__cdecl *memberFunctionPointer)(void* _this, RPCParameters *rpcParms);
#endif
void *functionPointer;
};
/// Is this a member function pointer? True if so. If false it's a regular C function.
bool isPointerToMember;
};
#endif
+47
View File
@@ -0,0 +1,47 @@
#ifndef RSA_CRYPT_HPP
#define RSA_CRYPT_HPP
#include "Platform.h"
#include "Export.h"
bool primeTest(const uint32_t *n, int limbs, uint32_t k);
void generateStrongPseudoPrime(uint32_t *n, int limbs);
class RAK_DLL_EXPORT RSACrypt
{
uint32_t *p, p_inv, *q, q_inv, *pinvq, factor_limbs;
uint32_t *d, e;
uint32_t *modulus, mod_inv, mod_limbs;
void cleanup();
bool generateExponents(const uint32_t *p, const uint32_t *q, int limbs, uint32_t &e, uint32_t *d);
public:
RSACrypt();
~RSACrypt();
public:
bool setPrivateKey(const uint32_t *p, const uint32_t *q, int halfFactorLimbs);
bool setPublicKey(const uint32_t *modulus, int mod_limbs, uint32_t e);
public:
// Bitsize is limbs * 32
// Private key size is limbs/2 words
bool generatePrivateKey(uint32_t limbs); // limbs must be a multiple of 2
public:
uint32_t getFactorLimbs();
void getPrivateP(uint32_t *p); // p buffer has factor_limbs
void getPrivateQ(uint32_t *q); // q buffer has factor_limbs
uint32_t getModLimbs();
void getPublicModulus(uint32_t *modulus); // modulus buffer has mod_limbs
uint32_t getPublicExponent();
public:
bool encrypt(uint32_t *ct, const uint32_t *pt); // pt limbs = mod_limbs
bool decrypt(uint32_t *pt, const uint32_t *ct); // ct limbs = mod_limbs
};
#endif // RSA_CRYPT_HPP
+16
View File
@@ -0,0 +1,16 @@
#ifndef __RAK_ASSERT_H
#define __RAK_ASSERT_H
/*
// So stupid Linux doesn't assert in release
#if defined(_DEBUG) && !defined(_XBOX)
#define RakAssert(x) assert(x);
#else
*/
#define RakAssert(x)
/*
#endif
*/
#endif
+136
View File
@@ -0,0 +1,136 @@
/// \file
/// \brief If _USE_RAK_MEMORY_OVERRIDE is defined, memory allocations go through rakMalloc, rakRealloc, and rakFree
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAK_MEMORY_H
#define __RAK_MEMORY_H
#include "Export.h"
#include "RakNetDefines.h"
#include <new>
#if defined(_XBOX) || defined(X360)
#elif defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3)
// Causes linker errors
// #include <stdlib.h>
typedef unsigned int size_t;
#elif defined ( __APPLE__ ) || defined ( __APPLE_CC__ )
#include <malloc/malloc.h>
#elif defined(_WIN32)
#include <malloc.h>
#else
#if !defined ( __FreeBSD__ )
#include <alloca.h>
#endif
#include <stdlib.h>
#endif
#if defined(_USE_RAK_MEMORY_OVERRIDE)
#if defined(new)
#pragma push_macro("new")
#undef new
#define RMO_NEW_UNDEF
#endif
#endif
// These pointers are statically and globally defined in RakMemoryOverride.cpp
// Change them to point to your own allocators if you want.
extern "C" {
extern void* (*rakMalloc) (size_t size);
extern void* (*rakRealloc) (void *p, size_t size);
extern void (*rakFree) (void *p);
extern void (*notifyOutOfMemory) (const char *file, const long line);
}
namespace RakNet
{
template <class Type>
Type* OP_NEW(void)
{
#if defined(_USE_RAK_MEMORY_OVERRIDE)
char *buffer = (char *) rakMalloc(sizeof(Type));
Type *t = new (buffer) Type;
return t;
#else
return new Type;
#endif
}
template <class Type>
Type* OP_NEW_ARRAY(const int count)
{
#if defined(_USE_RAK_MEMORY_OVERRIDE)
Type *t;
char *buffer = (char *) rakMalloc(sizeof(int)+sizeof(Type)*count);
((int*)buffer)[0]=count;
for (int i=0; i<count; i++)
{
t = new(buffer+sizeof(int)+i*sizeof(Type)) Type;
}
return (Type *) (buffer+sizeof(int));
#else
return new Type[count];
#endif
}
template <class Type>
void OP_DELETE(Type *buff)
{
#if defined(_USE_RAK_MEMORY_OVERRIDE)
if (buff==0) return;
buff->~Type();
rakFree((char*)buff);
#else
delete buff;
#endif
}
template <class Type>
void OP_DELETE_ARRAY(Type *buff)
{
#if defined(_USE_RAK_MEMORY_OVERRIDE)
if (buff==0) return;
int count = ((int*)((char*)buff-sizeof(int)))[0];
Type *t;
for (int i=0; i<count; i++)
{
t = buff+i;
t->~Type();
}
rakFree((char*)buff-sizeof(int));
#else
delete [] buff;
#endif
}
void* _RakMalloc (size_t size);
void* _RakRealloc (void *p, size_t size);
void _RakFree (void *p);
}
#if defined(_USE_RAK_MEMORY_OVERRIDE)
#if defined(RMO_NEW_UNDEF)
#pragma pop_macro("new")
#undef RMO_NEW_UNDEF
#endif
#endif
#endif
+60
View File
@@ -0,0 +1,60 @@
/// \file
/// \brief Contains RakNetCommandParser , used to send commands to an instance of RakPeer
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAKNET_COMMAND_PARSER
#define __RAKNET_COMMAND_PARSER
#include "CommandParserInterface.h"
#include "Export.h"
class RakPeerInterface;
/// \brief This allows a console client to call most of the functions in RakPeer
class RAK_DLL_EXPORT RakNetCommandParser : public CommandParserInterface
{
public:
RakNetCommandParser();
~RakNetCommandParser();
/// Given \a command with parameters \a parameterList , do whatever processing you wish.
/// \param[in] command The command to process
/// \param[in] numParameters How many parameters were passed along with the command
/// \param[in] parameterList The list of parameters. parameterList[0] is the first parameter and so on.
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that sent this command.
/// \param[in] originalString The string that was actually sent over the network, in case you want to do your own parsing
bool OnCommand(const char *command, unsigned numParameters, char **parameterList, TransportInterface *transport, SystemAddress systemAddress, const char *originalString);
/// You are responsible for overriding this function and returning a static string, which will identifier your parser.
/// This should return a static string
/// \return The name that you return.
const char *GetName(void) const;
/// A callback for when you are expected to send a brief description of your parser to \a systemAddress
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that requested help.
void SendHelp(TransportInterface *transport, SystemAddress systemAddress);
/// Records the instance of RakPeer to perform the desired commands on
/// \param[in] rakPeer The RakPeer instance, or a derived class (e.g. RakPeer or RakPeer)
void SetRakPeerInterface(RakPeerInterface *rakPeer);
protected:
/// Which instance of RakPeer we are working on. Set from SetRakPeerInterface()
RakPeerInterface *peer;
};
#endif
+42 -4
View File
@@ -1,3 +1,6 @@
#ifndef __RAKNET_DEFINES_H
#define __RAKNET_DEFINES_H
/// Define __GET_TIME_64BIT to have RakNetTime use a 64, rather than 32 bit value. A 32 bit value will overflow after about 5 weeks.
/// However, this doubles the bandwidth use for sending times, so don't do it unless you have a reason to.
/// Disabled by default.
@@ -12,9 +15,9 @@
/// Define __BITSTREAM_NATIVE_END to NOT support endian swapping in the BitStream class. This is faster and is what you should use
/// unless you actually plan to have different endianness systems connect to each other
/// Enabled by default.
#define __BITSTREAM_NATIVE_END
// #define __BITSTREAM_NATIVE_END
#if defined(_CONSOLE_2)
#if defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3)
#undef __BITSTREAM_NATIVE_END
#endif
@@ -24,7 +27,42 @@
// Use WaitForSingleObject instead of sleep.
// Defining it plays nicer with other systems, and uses less CPU, but gives worse RakNet performance
// Undefining it uses more CPU time, but is more responsive and faster.
#ifndef _WIN32_WCE
#define USE_WAIT_FOR_MULTIPLE_EVENTS
#endif
// If you need it
#define RAKNET_VERSION "3.0 09/07/07"
/// Uncomment to use RakMemoryOverride for custom memory tracking
/// See RakMemoryOverride.h.
#define _USE_RAK_MEMORY_OVERRIDE
/// If defined, RakNet will automatically try to determine available bandwidth and buffer accordingly (recommended)
/// If commented out, you will probably not be able to send large files and will get increased packetloss. However, responsiveness for the first 10 seconds or so will be improved.
#define _ENABLE_FLOW_CONTROL
/// If defined, OpenSSL is enabled for the class TCPInterface
/// This is necessary to use the SendEmail class with Google POP servers
/// Note that OpenSSL carries its own license restrictions that you should be aware of. If you don't agree, don't enable this define
/// This also requires that you enable header search paths to DependentExtensions\openssl-0.9.8g
/// #define OPEN_SSL_CLIENT_SUPPORT
/// Threshold at which to do a malloc / free rather than pushing data onto a fixed stack for the bitstream class
/// Arbitrary size, just picking something likely to be larger than most packets
#define BITSTREAM_STACK_ALLOCATION_SIZE 1024
// Redefine if you want to disable or change the target for debug RAKNET_DEBUG_PRINTF
#define RAKNET_DEBUG_PRINTF printf
// 16 * 4 * 8 = 512 bit. Used for InitializeSecurity()
#define RAKNET_RSA_FACTOR_LIMBS 16
// Enable to support peer to peer with NetworkIDs. Disable to save memory if doing client/server only
#define NETWORK_ID_SUPPORTS_PEER_TO_PEER
// O(1) instead of O(log2n) but takes more memory if less than 1/3 of the mappings are used.
// Only supported if NETWORK_ID_SUPPORTS_PEER_TO_PEER is commented out
// #define NETWORK_ID_USE_PTR_TABLE
// Maximum number of local IP addresses supported
#define MAXIMUM_NUMBER_OF_INTERNAL_IDS 5
#endif
Binary file not shown.
Binary file not shown.
+15 -15
View File
@@ -8,7 +8,7 @@
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.rakkarsoft.com/SingleApplicationLicense.html
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
@@ -33,28 +33,28 @@ struct RAK_DLL_EXPORT RakNetStatistics
/// Number of messages sent (high, medium, low priority)
unsigned messagesSent[ NUMBER_OF_PRIORITIES ];
/// Number of data bits used for user messages
unsigned messageDataBitsSent[ NUMBER_OF_PRIORITIES ];
uint64_t messageDataBitsSent[ NUMBER_OF_PRIORITIES ];
/// Number of total bits used for user messages, including headers
unsigned messageTotalBitsSent[ NUMBER_OF_PRIORITIES ];
uint64_t messageTotalBitsSent[ NUMBER_OF_PRIORITIES ];
/// Number of packets sent containing only acknowledgements
/// Number of packets sent containing only acknowledgments
unsigned packetsContainingOnlyAcknowlegements;
/// Number of acknowledgements sent
/// Number of acknowledgments sent
unsigned acknowlegementsSent;
/// Number of acknowledgements waiting to be sent
/// Number of acknowledgments waiting to be sent
unsigned acknowlegementsPending;
/// Number of acknowledgements bits sent
unsigned acknowlegementBitsSent;
/// Number of acknowledgments bits sent
uint64_t acknowlegementBitsSent;
/// Number of packets containing only acknowledgements and resends
/// Number of packets containing only acknowledgments and resends
unsigned packetsContainingOnlyAcknowlegementsAndResends;
/// Number of messages resent
unsigned messageResends;
/// Number of bits resent of actual data
unsigned messageDataBitsResent;
uint64_t messageDataBitsResent;
/// Total number of bits resent, including headers
unsigned messagesTotalBitsResent;
uint64_t messagesTotalBitsResent;
/// Number of messages waiting for ack (// TODO - rename this)
unsigned messagesOnResendQueue;
@@ -69,9 +69,9 @@ struct RAK_DLL_EXPORT RakNetStatistics
unsigned packetsSent;
/// Number of bits added by encryption
unsigned encryptionBitsSent;
uint64_t encryptionBitsSent;
/// total bits sent
unsigned totalBitsSent;
uint64_t totalBitsSent;
/// Number of sequenced messages arrived out of order
unsigned sequencedMessagesOutOfOrder;
@@ -88,9 +88,9 @@ struct RAK_DLL_EXPORT RakNetStatistics
/// Packets with a bad CRC received
unsigned packetsWithBadCRCReceived;
/// Bits with a good CRC received
unsigned bitsReceived;
uint64_t bitsReceived;
/// Bits with a bad CRC received
unsigned bitsWithBadCRCReceived;
uint64_t bitsWithBadCRCReceived;
/// Number of acknowledgement messages received for packets we are resending
unsigned acknowlegementsReceived;
/// Number of acknowledgement messages received for packets we are not resending
+30
View File
@@ -0,0 +1,30 @@
#ifndef __RAKNET_TIME_H
#define __RAKNET_TIME_H
// Define __GET_TIME_64BIT if you want to use large types for GetTime (takes more bandwidth when you transmit time though!)
// You would want to do this if your system is going to run long enough to overflow the millisecond counter (over a month)
#ifdef __GET_TIME_64BIT
#if defined(_MSC_VER) && _MSC_VER < 1300
typedef unsigned __int64 RakNetTime;
typedef unsigned __int64 RakNetTimeNS;
typedef unsigned __int64 RakNetTimeMS;
typedef unsigned __int64 RakNetTimeUS;
#else
typedef unsigned long long RakNetTime;
typedef unsigned long long RakNetTimeNS;
typedef unsigned long long RakNetTimeMS;
typedef unsigned long long RakNetTimeUS;
#endif
#else
typedef unsigned int RakNetTime;
typedef unsigned int RakNetTimeMS;
#if defined(_MSC_VER) && _MSC_VER < 1300
typedef unsigned __int64 RakNetTimeNS;
typedef unsigned __int64 RakNetTimeUS;
#else
typedef unsigned long long RakNetTimeNS;
typedef unsigned long long RakNetTimeUS;
#endif
#endif
#endif
+130
View File
@@ -0,0 +1,130 @@
/// \file
/// \brief Contains RakNetTransportCommandParser and RakNetTransport used to provide a secure console connection.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAKNET_TRANSPORT
#define __RAKNET_TRANSPORT
#include "TransportInterface.h"
#include "DS_Queue.h"
#include "CommandParserInterface.h"
#include "Export.h"
class RakPeerInterface;
class RakNetTransport;
namespace RakNet
{
class BitStream;
}
/// \brief RakNetTransport has its own command parser to enable remote users to change the command console's password.
class RAK_DLL_EXPORT RakNetTransportCommandParser : public CommandParserInterface
{
public:
RakNetTransportCommandParser();
~RakNetTransportCommandParser();
/// Given \a command with parameters \a parameterList , do whatever processing you wish.
/// \param[in] command The command to process
/// \param[in] numParameters How many parameters were passed along with the command
/// \param[in] parameterList The list of parameters. parameterList[0] is the first parameter and so on.
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that sent this command.
/// \param[in] originalString The string that was actually sent over the network, in case you want to do your own parsing
bool OnCommand(const char *command, unsigned numParameters, char **parameterList, TransportInterface *transport, SystemAddress systemAddress, const char *originalString);
/// You are responsible for overriding this function and returning a static string, which will identifier your parser.
/// This should return a static string
/// \return The name that you return.
const char* GetName(void) const;
/// A callback for when you are expected to send a brief description of your parser to \a systemAddress
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that requested help.
void SendHelp(TransportInterface *transport, SystemAddress systemAddress);
protected:
};
/// \brief Use RakNetTransport if you need a secure connection between the client and the console server.
/// RakNetTransport automatically initializes security for the system. Use the project CommandConsoleClient to connect
/// To the ConsoleServer if you use RakNetTransport
class RAK_DLL_EXPORT RakNetTransport : public TransportInterface
{
public:
RakNetTransport();
virtual ~RakNetTransport();
/// Start the transport provider on the indicated port.
/// \param[in] port The port to start the transport provider on
/// \param[in] serverMode If true, you should allow incoming connections (I don't actually use this anywhere)
/// \return Return true on success, false on failure.
bool Start(unsigned short port, bool serverMode);
/// Stop the transport provider. You can clear memory and shutdown threads here.
void Stop(void);
/// Send a null-terminated string to \a systemAddress
/// If your transport method requires particular formatting of the outgoing data (e.g. you don't just send strings) you can do it here
/// and parse it out in Receive().
/// \param[in] systemAddress The player to send the string to
/// \param[in] data format specifier - same as RAKNET_DEBUG_PRINTF
/// \param[in] ... format specification arguments - same as RAKNET_DEBUG_PRINTF
void Send( SystemAddress systemAddress, const char *data, ... );
/// Return a string. The string should be allocated and written to Packet::data .
/// The byte length should be written to Packet::length . The player/address should be written to Packet::systemAddress
/// If your transport protocol adds special formatting to the data stream you should parse it out before returning it in the packet
/// and thus only return a string in Packet::data
/// \return The packet structure containing the result of Receive, or 0 if no data is available
Packet* Receive( void );
/// Deallocate the Packet structure returned by Receive
/// \param[in] The packet to deallocate
void DeallocatePacket( Packet *packet );
/// Disconnect \a systemAddress . The binary address and port defines the SystemAddress structure.
/// \param[in] systemAddress The player/address to disconnect
void CloseConnection( SystemAddress systemAddress );
/// If a new system connects to you, you should queue that event and return the systemAddress/address of that player in this function.
/// \return The SystemAddress/address of the system
SystemAddress HasNewConnection(void);
/// If a system loses the connection, you should queue that event and return the systemAddress/address of that player in this function.
/// \return The SystemAddress/address of the system
SystemAddress HasLostConnection(void);
/// Sets the password which incoming connections must match.
/// While not required, it is highly recommended you set this in a real game environment or anyone can login and control your server.
/// Don't set it to a fixed value, but instead require that the server admin sets it when you start the application server
/// \param[in] password Null-terminated string to use as a password.
void SetIncomingPassword(const char *password);
/// Returns the password set by SetIncomingPassword().
/// \return The password set by SetIncomingPassword()
char * GetIncomingPassword(void);
/// Returns RakNetTransportCommandParser so the console admin can change the password
CommandParserInterface* GetCommandParser(void);
protected:
RakPeerInterface *rakPeer;
void AutoAllocate(void);
DataStructures::Queue<SystemAddress> newConnections, lostConnections;
RakNetTransportCommandParser rakNetTransportCommandParser;
};
#endif
+140 -66
View File
@@ -8,7 +8,7 @@
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.rakkarsoft.com/SingleApplicationLicense.html
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
@@ -19,7 +19,12 @@
#define __NETWORK_TYPES_H
#include "RakNetDefines.h"
#include "NativeTypes.h"
#include "RakNetTime.h"
#include "Export.h"
#if !defined(_WIN32) && ((defined(__GNUC__) || defined(__GCCXML__)))
#include "stdint.h"
#endif
/// Forward declaration
namespace RakNet
@@ -41,31 +46,34 @@ const int UNDEFINED_RPC_INDEX=((RPCIndex)-1);
/// First byte of a network message
typedef unsigned char MessageID;
// Define __GET_TIME_64BIT if you want to use large types for GetTime (takes more bandwidth when you transmit time though!)
// You would want to do this if your system is going to run long enough to overflow the millisecond counter (over a month)
#ifdef __GET_TIME_64BIT
typedef long long RakNetTime;
typedef long long RakNetTimeNS;
typedef unsigned int BitSize_t;
#if defined(_MSC_VER) && _MSC_VER > 0
#define PRINTF_TIME_MODIFIER "I64"
#else
typedef unsigned int RakNetTime;
typedef long long RakNetTimeNS;
#define PRINTF_TIME_MODIFIER "ll"
#endif
/// Describes the local socket to use for RakPeer::Startup
struct RAK_DLL_EXPORT SocketDescriptor
{
SocketDescriptor();
SocketDescriptor(unsigned short _port, const char *_hostAddress);
SocketDescriptor(unsigned short _port, const char *_hostAddress, bool _isPS3LobbySocket=false);
/// The local port to bind to. Pass 0 to have the OS autoassign a port.
unsigned short port;
/// The local network card address to bind to, such as "127.0.0.1". Pass an empty string to use INADDR_ANY.
char hostAddress[32];
/// \internal
bool isPS3LobbySocket;
};
/// \brief Unique identifier for a system.
/// \brief Network address for a system
/// Corresponds to a network address
/// This is not necessarily a unique identifier. For example, if a system has both LAN and internet connections, the system may be identified by either one, depending on who is communicating
/// Use RakNetGUID for a unique per-instance of RakPeer to identify systems
struct RAK_DLL_EXPORT SystemAddress
{
///The peer address from inet_addr.
@@ -74,8 +82,14 @@ struct RAK_DLL_EXPORT SystemAddress
unsigned short port;
// Return the systemAddress as a string in the format <IP>:<Port>
// Note - returns a static string. Not thread-safe or safe for multiple calls per line.
char *ToString(bool writePort=true) const;
// Returns a static string
// NOT THREADSAFE
const char *ToString(bool writePort=true) const;
// Return the systemAddress as a string in the format <IP>:<Port>
// dest must be large enough to hold the output
// THREADSAFE
void ToString(bool writePort, char *dest) const;
// Sets the binary address part from a string. Doesn't set the port
void SetBinaryAddress(const char *str);
@@ -93,66 +107,21 @@ struct RAK_DLL_EXPORT SystemAddress
bool operator < ( const SystemAddress& right ) const;
};
struct RAK_DLL_EXPORT NetworkID
{
// Set this to true to use peer to peer mode for NetworkIDs.
// Obviously the value of this must match on all systems.
// True, and this will write the systemAddress portion with network sends. Takes more bandwidth, but NetworkIDs can be locally generated
// False, and only localSystemAddress is used.
static bool peerToPeerMode;
// In peer to peer, we use both systemAddress and localSystemAddress
// In client / server, we only use localSystemAddress
SystemAddress systemAddress;
unsigned short localSystemAddress;
NetworkID& operator = ( const NetworkID& input );
static bool IsPeerToPeerMode(void);
static void SetPeerToPeerMode(bool isPeerToPeer);
bool operator==( const NetworkID& right ) const;
bool operator!=( const NetworkID& right ) const;
bool operator > ( const NetworkID& right ) const;
bool operator < ( const NetworkID& right ) const;
};
/// Size of SystemAddress data
#define SystemAddress_Size 6
/// This represents a user message from another system.
struct Packet
{
/// Server only - this is the index into the player array that this systemAddress maps to
SystemIndex systemIndex;
/// The system that send this packet.
SystemAddress systemAddress;
/// The length of the data in bytes
/// \deprecated You should use bitSize.
unsigned int length;
/// The length of the data in bits
unsigned int bitSize;
/// The data from the sender
unsigned char* data;
/// @internal
/// Indicates whether to delete the data, or to simply delete the packet.
bool deleteData;
};
class RakPeerInterface;
/// All RPC functions have the same parameter list - this structure.
/// \depreciated Use the AutoRPC or RPC3 plugin instead
struct RPCParameters
{
/// The data from the remote system
unsigned char *input;
/// How many bits long \a input is
unsigned int numberOfBitsOfData;
BitSize_t numberOfBitsOfData;
/// Which system called this RPC
SystemAddress sender;
@@ -172,8 +141,36 @@ struct RPCParameters
RakNet::BitStream *replyToSender;
};
/// Index of an unassigned player
const SystemIndex UNASSIGNED_PLAYER_INDEX = 65535;
/// Uniquely identifies an instance of RakPeer. Use RakPeer::GetGuidFromSystemAddress() and RakPeer::GetSystemAddressFromGuid() to go between SystemAddress and RakNetGUID
/// Use RakPeer::GetGuidFromSystemAddress(UNASSIGNED_SYSTSEM_ADDRESS) to get your own GUID
struct RAK_DLL_EXPORT RakNetGUID
{
uint32_t g[4];
// Return the GUID as a string
// Returns a static string
// NOT THREADSAFE
const char *ToString(void) const;
// Return the GUID as a string
// dest must be large enough to hold the output
// THREADSAFE
void ToString(char *dest) const;
RakNetGUID& operator = ( const RakNetGUID& input )
{
g[0]=input.g[0];
g[1]=input.g[1];
g[2]=input.g[2];
g[3]=input.g[3];
return *this;
}
bool operator==( const RakNetGUID& right ) const;
bool operator!=( const RakNetGUID& right ) const;
bool operator > ( const RakNetGUID& right ) const;
bool operator < ( const RakNetGUID& right ) const;
};
/// Index of an invalid SystemAddress
const SystemAddress UNASSIGNED_SYSTEM_ADDRESS =
@@ -181,12 +178,85 @@ const SystemAddress UNASSIGNED_SYSTEM_ADDRESS =
0xFFFFFFFF, 0xFFFF
};
/// Unassigned object ID
const NetworkID UNASSIGNED_NETWORK_ID =
const RakNetGUID UNASSIGNED_RAKNET_GUID =
{
{0xFFFFFFFF, 0xFFFF}, 65535
{0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}
};
struct RAK_DLL_EXPORT NetworkID
{
NetworkID()
{
#if defined NETWORK_ID_SUPPORTS_PEER_TO_PEER
guid = UNASSIGNED_RAKNET_GUID;
systemAddress=UNASSIGNED_SYSTEM_ADDRESS;
#endif
localSystemAddress=65535;
}
~NetworkID() {}
/// \depreciated. Use NETWORK_ID_SUPPORTS_PEER_TO_PEER in RakNetDefines.h
// Set this to true to use peer to peer mode for NetworkIDs.
// Obviously the value of this must match on all systems.
// True, and this will write the systemAddress portion with network sends. Takes more bandwidth, but NetworkIDs can be locally generated
// False, and only localSystemAddress is used.
// static bool peerToPeerMode;
#if defined NETWORK_ID_SUPPORTS_PEER_TO_PEER
// Depreciated: Use guid instead
// In peer to peer, we use both systemAddress and localSystemAddress
// In client / server, we only use localSystemAddress
SystemAddress systemAddress;
RakNetGUID guid;
#endif
unsigned short localSystemAddress;
NetworkID& operator = ( const NetworkID& input );
static bool IsPeerToPeerMode(void);
static void SetPeerToPeerMode(bool isPeerToPeer);
bool operator==( const NetworkID& right ) const;
bool operator!=( const NetworkID& right ) const;
bool operator > ( const NetworkID& right ) const;
bool operator < ( const NetworkID& right ) const;
};
/// This represents a user message from another system.
struct Packet
{
/// Server only - this is the index into the player array that this systemAddress maps to
SystemIndex systemIndex;
/// The system that send this packet.
SystemAddress systemAddress;
/// A unique identifier for the system that sent this packet, regardless of IP address (internal / external / remote system)
/// Only valid once a connection has been established (ID_CONNECTION_REQUEST_ACCEPTED, or ID_NEW_INCOMING_CONNECTION)
/// Until that time, will be UNASSIGNED_RAKNET_GUID
RakNetGUID guid;
/// The length of the data in bytes
/// \deprecated You should use bitSize.
unsigned int length;
/// The length of the data in bits
BitSize_t bitSize;
/// The data from the sender
unsigned char* data;
/// @internal
/// Indicates whether to delete the data, or to simply delete the packet.
bool deleteData;
};
/// Index of an unassigned player
const SystemIndex UNASSIGNED_PLAYER_INDEX = 65535;
/// Unassigned object ID
const NetworkID UNASSIGNED_NETWORK_ID;
const int PING_TIMES_ARRAY_SIZE = 5;
/// \brief RPC Function Implementation
@@ -221,6 +291,7 @@ const int PING_TIMES_ARRAY_SIZE = 5;
/// \def REGISTER_STATIC_RPC
/// \ingroup RAKNET_RPC
/// \depreciated Use the AutoRPC plugin instead
/// Register a C function as a Remote procedure.
/// \param[in] networkObject Your instance of RakPeer, RakPeer, or RakPeer
/// \param[in] functionName The name of the C function to call
@@ -231,9 +302,11 @@ const int PING_TIMES_ARRAY_SIZE = 5;
/// \def CLASS_MEMBER_ID
/// \ingroup RAKNET_RPC
/// \depreciated Use the AutoRPC plugin instead
/// \brief Concatenate two strings
/// \def REGISTER_CLASS_MEMBER_RPC
/// \depreciated Use the AutoRPC plugin instead
/// \ingroup RAKNET_RPC
/// \brief Register a member function of an instantiated object as a Remote procedure call.
/// RPC member Functions MUST be marked __cdecl!
@@ -247,11 +320,12 @@ const int PING_TIMES_ARRAY_SIZE = 5;
#define REGISTER_CLASS_MEMBER_RPC(networkObject, className, functionName) {union {void (__cdecl className::*cFunc)( RPCParameters *rpcParms ); void* voidFunc;}; cFunc=&className::functionName; networkObject->RegisterClassMemberRPC(CLASS_MEMBER_ID(className, functionName),voidFunc);}
/// \def UNREGISTER_AS_REMOTE_PROCEDURE_CALL
/// \depreciated
/// \brief Only calls UNREGISTER_STATIC_RPC
/// \depreciated Use the AutoRPC plugin instead
/// \def UNREGISTER_STATIC_RPC
/// \ingroup RAKNET_RPC
/// \depreciated Use the AutoRPC plugin instead
/// Unregisters a remote procedure call
/// RPC member Functions MUST be marked __cdecl! See the ObjectMemberRPC example.
/// \param[in] networkObject The object that manages the function
@@ -263,6 +337,7 @@ const int PING_TIMES_ARRAY_SIZE = 5;
/// \def UNREGISTER_CLASS_INST_RPC
/// \ingroup RAKNET_RPC
/// \depreciated Use the AutoRPC plugin instead
/// \brief Unregisters a member function of an instantiated object as a Remote procedure call.
/// \param[in] networkObject The object that manages the function
/// \param[in] className The className that was originally passed to REGISTER_AS_REMOTE_PROCEDURE_CALL
@@ -270,4 +345,3 @@ const int PING_TIMES_ARRAY_SIZE = 5;
#define UNREGISTER_CLASS_MEMBER_RPC(networkObject, className, functionName) (networkObject)->UnregisterAsRemoteProcedureCall((#className "_" #functionName))
#endif
+9
View File
@@ -0,0 +1,9 @@
#define RAKNET_VERSION "3.401"
#define RAKNET_REVISION "$Revision$"
#define RAKNET_DATE "2/10/2009"
// What compatible protocol version RakNet is using. When this value changes, it indicates this version of RakNet cannot connection to an older version.
// ID_INCOMPATIBLE_PROTOCOL_VERSION will be returned on connection attempt in this case
#define RAKNET_PROTOCOL_VERSION 3
+1 -1
View File
@@ -8,7 +8,7 @@
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.rakkarsoft.com/SingleApplicationLicense.html
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
+953
View File
@@ -0,0 +1,953 @@
/// \file
/// \brief The main class used for data transmission and most of RakNet's functionality.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAK_PEER_H
#define __RAK_PEER_H
#include "ReliabilityLayer.h"
#include "RakPeerInterface.h"
#include "RPCNode.h"
#include "RSACrypt.h"
#include "BitStream.h"
#include "SingleProducerConsumer.h"
#include "RPCMap.h"
#include "SimpleMutex.h"
#include "DS_OrderedList.h"
#include "Export.h"
#include "RakString.h"
#include "RakThread.h"
class HuffmanEncodingTree;
class PluginInterface;
// Sucks but this struct has to be outside the class. Inside and DevCPP won't let you refer to the struct as RakPeer::SystemAddressAndIndex while GCC
// forces you to do RakPeer::SystemAddressAndIndex
struct SystemAddressAndIndex{SystemAddress systemAddress;unsigned index;};
int RAK_DLL_EXPORT SystemAddressAndIndexComp( const SystemAddress &key, const SystemAddressAndIndex &data ); // GCC requires RakPeer::SystemAddressAndIndex or it won't compile
/// The primary interface for RakNet, RakPeer contains all major functions for the library.
/// See the individual functions for what the class can do.
/// \brief The main interface for network communications
class RAK_DLL_EXPORT RakPeer : public RakPeerInterface
{
public:
///Constructor
RakPeer();
///Destructor
virtual ~RakPeer();
// --------------------------------------------------------------------------------------------Major Low Level Functions - Functions needed by most users--------------------------------------------------------------------------------------------
/// \brief Starts the network threads, opens the listen port.
/// You must call this before calling Connect().
/// Multiple calls while already active are ignored. To call this function again with different settings, you must first call Shutdown().
/// \note Call SetMaximumIncomingConnections if you want to accept incoming connections
/// \note Set _RAKNET_THREADSAFE in RakNetDefines.h if you want to call RakNet functions from multiple threads (not recommended, as it is much slower and RakNet is already asynchronous).
/// \param[in] maxConnections The maximum number of connections between this instance of RakPeer and another instance of RakPeer. Required so the network can preallocate and for thread safety. A pure client would set this to 1. A pure server would set it to the number of allowed clients.- A hybrid would set it to the sum of both types of connections
/// \param[in] localPort The port to listen for connections on.
/// \param[in] _threadSleepTimer How many ms to Sleep each internal update cycle (30 to give the game priority, 0 for regular (recommended)
/// \param[in] socketDescriptors An array of SocketDescriptor structures to force RakNet to listen on a particular IP address or port (or both). Each SocketDescriptor will represent one unique socket. Do not pass redundant structures. To listen on a specific port, you can pass SocketDescriptor(myPort,0); such as for a server. For a client, it is usually OK to just pass SocketDescriptor();
/// \param[in] socketDescriptorCount The size of the \a socketDescriptors array. Pass 1 if you are not sure what to pass.
/// \return False on failure (can't create socket or thread), true on success.
bool Startup( unsigned short maxConnections, int _threadSleepTimer, SocketDescriptor *socketDescriptors, unsigned socketDescriptorCount );
/// Secures connections though a combination of SHA1, AES128, SYN Cookies, and RSA to prevent connection spoofing, replay attacks, data eavesdropping, packet tampering, and MitM attacks.
/// There is a significant amount of processing and a slight amount of bandwidth overhead for this feature.
/// If you accept connections, you must call this or else secure connections will not be enabled for incoming connections.
/// If you are connecting to another system, you can call this with values for the (e and p,q) public keys before connecting to prevent MitM
/// Define how many bits are used in RakNetDefines.h with RAKNET_RSA_FACTOR_LIMBS
/// \pre Must be called before Initialize
/// \param[in] pubKeyE A pointer to the public keys from the RSACrypt class.
/// \param[in] pubKeyN A pointer to the public keys from the RSACrypt class.
/// \param[in] privKeyP Public key generated from the RSACrypt class.
/// \param[in] privKeyQ Public key generated from the RSACrypt class. If the private keys are 0, then a new key will be generated when this function is called@see the Encryption sample
void InitializeSecurity(const char *pubKeyE, const char *pubKeyN, const char *privKeyP, const char *privKeyQ );
/// Disables all security.
/// \note Must be called while offline
void DisableSecurity( void );
/// If secure connections are on, do not use secure connections for a specific IP address.
/// This is useful if you have a fixed-address internal server behind a LAN.
/// \note Secure connections are determined by the recipient of an incoming connection. This has no effect if called on the system attempting to connect.
/// \param[in] ip IP address to add. * wildcards are supported.
void AddToSecurityExceptionList(const char *ip);
/// Remove a specific connection previously added via AddToSecurityExceptionList
/// \param[in] ip IP address to remove. Pass 0 to remove all IP addresses. * wildcards are supported.
void RemoveFromSecurityExceptionList(const char *ip);
/// Checks to see if a given IP is in the security exception list
/// \param[in] IP address to check.
bool IsInSecurityExceptionList(const char *ip);
/// Sets how many incoming connections are allowed. If this is less than the number of players currently connected,
/// no more players will be allowed to connect. If this is greater than the maximum number of peers allowed,
/// it will be reduced to the maximum number of peers allowed.
/// Defaults to 0, meaning by default, nobody can connect to you
/// \param[in] numberAllowed Maximum number of incoming connections allowed.
void SetMaximumIncomingConnections( unsigned short numberAllowed );
/// Returns the value passed to SetMaximumIncomingConnections()
/// \return the maximum number of incoming connections, which is always <= maxConnections
unsigned short GetMaximumIncomingConnections( void ) const;
/// Returns how many open connections there are at this time
/// \return the number of open connections
unsigned short NumberOfConnections(void) const;
/// Sets the password incoming connections must match in the call to Connect (defaults to none). Pass 0 to passwordData to specify no password
/// This is a way to set a low level password for all incoming connections. To selectively reject connections, implement your own scheme using CloseConnection() to remove unwanted connections
/// \param[in] passwordData A data block that incoming connections must match. This can be just a password, or can be a stream of data. Specify 0 for no password data
/// \param[in] passwordDataLength The length in bytes of passwordData
void SetIncomingPassword( const char* passwordData, int passwordDataLength );
/// Gets the password passed to SetIncomingPassword
/// \param[out] passwordData Should point to a block large enough to hold the password data you passed to SetIncomingPassword()
/// \param[in,out] passwordDataLength Maximum size of the array passwordData. Modified to hold the number of bytes actually written
void GetIncomingPassword( char* passwordData, int *passwordDataLength );
/// \brief Connect to the specified host (ip or domain name) and server port.
/// Calling Connect and not calling SetMaximumIncomingConnections acts as a dedicated client.
/// Calling both acts as a true peer. This is a non-blocking connection.
/// You know the connection is successful when IsConnected() returns true or Receive() gets a message with the type identifier ID_CONNECTION_ACCEPTED.
/// If the connection is not successful, such as a rejected connection or no response then neither of these things will happen.
/// \pre Requires that you first call Initialize
/// \param[in] host Either a dotted IP address or a domain name
/// \param[in] remotePort Which port to connect to on the remote machine.
/// \param[in] passwordData A data block that must match the data block on the server passed to SetIncomingPassword. This can be a string or can be a stream of data. Use 0 for no password.
/// \param[in] passwordDataLength The length in bytes of passwordData
/// \param[in] connectionSocketIndex Index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to send on.
/// \return True on successful initiation. False on incorrect parameters, internal error, or too many existing peers. Returning true does not mean you connected!
bool Connect( const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, unsigned connectionSocketIndex=0 );
/// \brief Connect to the specified network ID (Platform specific console function)
/// Does built-in NAT traversal
/// \param[in] networkServiceId Network ID structure for the online service
/// \param[in] passwordData A data block that must match the data block on the server passed to SetIncomingPassword. This can be a string or can be a stream of data. Use 0 for no password.
/// \param[in] passwordDataLength The length in bytes of passwordData
//bool Console2LobbyConnect( void *networkServiceId, const char *passwordData, int passwordDataLength );
/// \brief Stops the network threads and closes all connections.
/// \param[in] blockDuration How long, in milliseconds, you should wait for all remaining messages to go out, including ID_DISCONNECTION_NOTIFICATION. If 0, it doesn't wait at all.
/// \param[in] orderingChannel If blockDuration > 0, ID_DISCONNECTION_NOTIFICATION will be sent on this channel
/// If you set it to 0 then the disconnection notification won't be sent
void Shutdown( unsigned int blockDuration, unsigned char orderingChannel=0 );
/// Returns if the network thread is running
/// \return true if the network thread is running, false otherwise
bool IsActive( void ) const;
/// Fills the array remoteSystems with the SystemAddress of all the systems we are connected to
/// \param[out] remoteSystems An array of SystemAddress structures to be filled with the SystemAddresss of the systems we are connected to. Pass 0 to remoteSystems to only get the number of systems we are connected to
/// \param[in, out] numberOfSystems As input, the size of remoteSystems array. As output, the number of elements put into the array
bool GetConnectionList( SystemAddress *remoteSystems, unsigned short *numberOfSystems ) const;
/// Sends a block of data to the specified system that you are connected to.
/// This function only works while the connected
/// The first byte should be a message identifier starting at ID_USER_PACKET_ENUM
/// \param[in] data The block of data to send
/// \param[in] length The size in bytes of the data to send
/// \param[in] priority What priority level to send on. See PacketPriority.h
/// \param[in] reliability How reliability to send this data. See PacketPriority.h
/// \param[in] orderingChannel When using ordered or sequenced messages, what channel to order these on. Messages are only ordered relative to other messages on the same stream
/// \param[in] systemAddress Who to send this packet to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_SYSTEM_ADDRESS to specify none
/// \param[in] broadcast True to send this packet to all connected systems. If true, then systemAddress specifies who not to send the packet to.
/// \return False if we are not connected to the specified recipient. True otherwise
bool Send( const char *data, const int length, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast );
/// "Send" to yourself rather than a remote system. The message will be processed through the plugins and returned to the game as usual
/// This function works anytime
/// The first byte should be a message identifier starting at ID_USER_PACKET_ENUM
/// \param[in] data The block of data to send
/// \param[in] length The size in bytes of the data to send
void SendLoopback( const char *data, const int length );
/// Sends a block of data to the specified system that you are connected to. Same as the above version, but takes a BitStream as input.
/// \param[in] bitStream The bitstream to send
/// \param[in] priority What priority level to send on. See PacketPriority.h
/// \param[in] reliability How reliability to send this data. See PacketPriority.h
/// \param[in] orderingChannel When using ordered or sequenced messages, what channel to order these on. Messages are only ordered relative to other messages on the same stream
/// \param[in] systemAddress Who to send this packet to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_SYSTEM_ADDRESS to specify none
/// \param[in] broadcast True to send this packet to all connected systems. If true, then systemAddress specifies who not to send the packet to.
/// \return False if we are not connected to the specified recipient. True otherwise
/// \note COMMON MISTAKE: When writing the first byte, bitStream->Write((unsigned char) ID_MY_TYPE) be sure it is casted to a byte, and you are not writing a 4 byte enumeration.
bool Send( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast );
/// Sends multiple blocks of data, concatenating them automatically.
///
/// This is equivalent to:
/// RakNet::BitStream bs;
/// bs.WriteAlignedBytes(block1, blockLength1);
/// bs.WriteAlignedBytes(block2, blockLength2);
/// bs.WriteAlignedBytes(block3, blockLength3);
/// Send(&bs, ...)
///
/// This function only works while the connected
/// \param[in] data An array of pointers to blocks of data
/// \param[in] lengths An array of integers indicating the length of each block of data
/// \param[in] numParameters Length of the arrays data and lengths
/// \param[in] priority What priority level to send on. See PacketPriority.h
/// \param[in] reliability How reliability to send this data. See PacketPriority.h
/// \param[in] orderingChannel When using ordered or sequenced messages, what channel to order these on. Messages are only ordered relative to other messages on the same stream
/// \param[in] systemAddress Who to send this packet to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_SYSTEM_ADDRESS to specify none
/// \param[in] broadcast True to send this packet to all connected systems. If true, then systemAddress specifies who not to send the packet to.
/// \return False if we are not connected to the specified recipient. True otherwise
/// \note Doesn't support the router plugin
bool SendList( char **data, const int *lengths, const int numParameters, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast );
/// Gets a message from the incoming message queue.
/// Use DeallocatePacket() to deallocate the message after you are done with it.
/// User-thread functions, such as RPC calls and the plugin function PluginInterface::Update occur here.
/// \return 0 if no packets are waiting to be handled, otherwise a pointer to a packet.
/// \note COMMON MISTAKE: Be sure to call this in a loop, once per game tick, until it returns 0. If you only process one packet per game tick they will buffer up.
/// sa RakNetTypes.h contains struct Packet
Packet* Receive( void );
/// Call this to deallocate a message returned by Receive() when you are done handling it.
/// \param[in] packet The message to deallocate.
void DeallocatePacket( Packet *packet );
/// Return the total number of connections we are allowed
unsigned short GetMaximumNumberOfPeers( void ) const;
// --------------------------------------------------------------------------------------------Remote Procedure Call Functions - Functions to initialize and perform RPC--------------------------------------------------------------------------------------------
/// \ingroup RAKNET_RPC
/// Register a C or static member function as available for calling as a remote procedure call
/// \param[in] uniqueID A null-terminated unique string to identify this procedure. See RegisterClassMemberRPC() for class member functions.
/// \param[in] functionPointer(...) The name of the function to be used as a function pointer. This can be called whether active or not, and registered functions stay registered unless unregistered
void RegisterAsRemoteProcedureCall( const char* uniqueID, void ( *functionPointer ) ( RPCParameters *rpcParms ) );
/// \ingroup RAKNET_RPC
/// Register a C++ member function as available for calling as a remote procedure call.
/// \param[in] uniqueID A null terminated string to identify this procedure. Recommended you use the macro REGISTER_CLASS_MEMBER_RPC to create the string. Use RegisterAsRemoteProcedureCall() for static functions.
/// \param[in] functionPointer The name of the function to be used as a function pointer. This can be called whether active or not, and registered functions stay registered unless unregistered with UnregisterAsRemoteProcedureCall
/// \sa The sample ObjectMemberRPC.cpp
void RegisterClassMemberRPC( const char* uniqueID, void *functionPointer );
/// \ingroup RAKNET_RPC
/// Unregisters a C function as available for calling as a remote procedure call that was formerly registered with RegisterAsRemoteProcedureCall. Only call offline.
/// \param[in] uniqueID A string of only letters to identify this procedure. Recommended you use the macro CLASS_MEMBER_ID for class member functions.
void UnregisterAsRemoteProcedureCall( const char* uniqueID );
/// \ingroup RAKNET_RPC
/// Used by Object member RPC to lookup objects given that object's ID
/// Also used by the ReplicaManager plugin
/// \param[in] An instance of NetworkIDManager to use for the loookup.
void SetNetworkIDManager( NetworkIDManager *manager );
/// \return Returns the value passed to SetNetworkIDManager or 0 if never called.
NetworkIDManager *GetNetworkIDManager(void) const;
/// \ingroup RAKNET_RPC
/// Calls a C function on the remote system that was already registered using RegisterAsRemoteProcedureCall().
/// \pre To use object member RPC (networkID!=UNASSIGNED_OBJECT_ID), The recipient must have called SetNetworkIDManager so the system can handle the object lookups
/// \param[in] uniqueID A NULL terminated string identifying the function to call. Recommended you use the macro CLASS_MEMBER_ID for class member functions.
/// \param[in] data The data to send
/// \param[in] bitLength The number of bits of \a data
/// \param[in] priority What priority level to send on. See PacketPriority.h.
/// \param[in] reliability How reliability to send this data. See PacketPriority.h.
/// \param[in] orderingChannel When using ordered or sequenced message, what channel to order these on.
/// \param[in] systemAddress Who to send this message to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_SYSTEM_ADDRESS to specify none
/// \param[in] broadcast True to send this packet to all connected systems. If true, then systemAddress specifies who not to send the packet to.
/// \param[in] includedTimestamp Pass a timestamp if you wish, to be adjusted in the usual fashion as per ID_TIMESTAMP. Pass 0 to not include a timestamp.
/// \param[in] networkID For static functions, pass UNASSIGNED_NETWORK_ID. For member functions, you must derive from NetworkIDObject and pass the value returned by NetworkIDObject::GetNetworkID for that object.
/// \param[in] replyFromTarget If 0, this function is non-blocking. Otherwise it will block while waiting for a reply from the target procedure, which should be remotely written to RPCParameters::replyToSender and copied to replyFromTarget. The block will return early on disconnect or if the sent packet is unreliable and more than 3X the ping has elapsed.
/// \return True on a successful packet send (this does not indicate the recipient performed the call), false on failure
bool RPC( const char* uniqueID, const char *data, BitSize_t bitLength, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, RakNetTime *includedTimestamp, NetworkID networkID, RakNet::BitStream *replyFromTarget );
/// \ingroup RAKNET_RPC
/// Calls a C function on the remote system that was already registered using RegisterAsRemoteProcedureCall.
/// If you want that function to return data you should call RPC from that system in the same wayReturns true on a successful packet
/// send (this does not indicate the recipient performed the call), false on failure
/// \pre To use object member RPC (networkID!=UNASSIGNED_OBJECT_ID), The recipient must have called SetNetworkIDManager so the system can handle the object lookups
/// \param[in] uniqueID A NULL terminated string identifying the function to call. Recommended you use the macro CLASS_MEMBER_ID for class member functions.
/// \param[in] data The data to send
/// \param[in] bitLength The number of bits of \a data
/// \param[in] priority What priority level to send on. See PacketPriority.h.
/// \param[in] reliability How reliability to send this data. See PacketPriority.h.
/// \param[in] orderingChannel When using ordered or sequenced message, what channel to order these on.
/// \param[in] systemAddress Who to send this message to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_SYSTEM_ADDRESS to specify none
/// \param[in] broadcast True to send this packet to all connected systems. If true, then systemAddress specifies who not to send the packet to.
/// \param[in] includedTimestamp Pass a timestamp if you wish, to be adjusted in the usual fashion as per ID_TIMESTAMP. Pass 0 to not include a timestamp.
/// \param[in] networkID For static functions, pass UNASSIGNED_NETWORK_ID. For member functions, you must derive from NetworkIDObject and pass the value returned by NetworkIDObject::GetNetworkID for that object.
/// \param[in] replyFromTarget If 0, this function is non-blocking. Otherwise it will block while waiting for a reply from the target procedure, which should be remotely written to RPCParameters::replyToSender and copied to replyFromTarget. The block will return early on disconnect or if the sent packet is unreliable and more than 3X the ping has elapsed.
/// \return True on a successful packet send (this does not indicate the recipient performed the call), false on failure
bool RPC( const char* uniqueID, const RakNet::BitStream *bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, RakNetTime *includedTimestamp, NetworkID networkID, RakNet::BitStream *replyFromTarget );
// -------------------------------------------------------------------------------------------- Connection Management Functions--------------------------------------------------------------------------------------------
/// Close the connection to another host (if we initiated the connection it will disconnect, if they did it will kick them out).
/// \param[in] target Which system to close the connection to.
/// \param[in] sendDisconnectionNotification True to send ID_DISCONNECTION_NOTIFICATION to the recipient. False to close it silently.
/// \param[in] channel Which ordering channel to send the disconnection notification on, if any
void CloseConnection( const SystemAddress target, bool sendDisconnectionNotification, unsigned char orderingChannel=0 );
/// Cancel a pending connection attempt
/// If we are already connected, the connection stays open
/// \param[in] target Which system to cancel
void CancelConnectionAttempt( const SystemAddress target );
/// Returns if a particular systemAddress is connected to us (this also returns true if we are in the process of connecting)
/// \param[in] systemAddress The SystemAddress we are referring to
/// \param[in] includeInProgress If true, also return true for connections that are in progress but haven't completed
/// \param[in] includeDisconnecting If true, also return true for connections that are in the process of disconnecting
/// \return True if this system is connected and active, false otherwise.
bool IsConnected(const SystemAddress systemAddress, bool includeInProgress=false, bool includeDisconnecting=false);
/// Given a systemAddress, returns an index from 0 to the maximum number of players allowed - 1.
/// This includes systems which were formerly connected, but are not now connected
/// \param[in] systemAddress The SystemAddress we are referring to
/// \return The index of this SystemAddress or -1 on system not found.
int GetIndexFromSystemAddress( const SystemAddress systemAddress );
/// This function is only useful for looping through all systems
/// Given an index, will return a SystemAddress.
/// \param[in] index Index should range between 0 and the maximum number of players allowed - 1.
/// \return The SystemAddress
SystemAddress GetSystemAddressFromIndex( int index );
/// Bans an IP from connecting. Banned IPs persist between connections but are not saved on shutdown nor loaded on startup.
/// param[in] IP Dotted IP address. Can use * as a wildcard, such as 128.0.0.* will ban all IP addresses starting with 128.0.0
/// \param[in] milliseconds how many ms for a temporary ban. Use 0 for a permanent ban
void AddToBanList( const char *IP, RakNetTime milliseconds=0 );
/// Allows a previously banned IP to connect.
/// param[in] Dotted IP address. Can use * as a wildcard, such as 128.0.0.* will banAll IP addresses starting with 128.0.0
void RemoveFromBanList( const char *IP );
/// Allows all previously banned IPs to connect.
void ClearBanList( void );
/// Returns true or false indicating if a particular IP is banned.
/// \param[in] IP - Dotted IP address.
/// \return true if IP matches any IPs in the ban list, accounting for any wildcards. False otherwise.
bool IsBanned( const char *IP );
// --------------------------------------------------------------------------------------------Pinging Functions - Functions dealing with the automatic ping mechanism--------------------------------------------------------------------------------------------
/// Send a ping to the specified connected system.
/// \pre The sender and recipient must already be started via a successful call to Startup()
/// \param[in] target Which system to ping
void Ping( const SystemAddress target );
/// Send a ping to the specified unconnected system. The remote system, if it is Initialized, will respond with ID_PONG followed by sizeof(RakNetTime) containing the system time the ping was sent.(Default is 4 bytes - See __GET_TIME_64BIT in RakNetTypes.h
/// \param[in] host Either a dotted IP address or a domain name. Can be 255.255.255.255 for LAN broadcast.
/// \param[in] remotePort Which port to connect to on the remote machine.
/// \param[in] onlyReplyOnAcceptingConnections Only request a reply if the remote system is accepting connections
/// \param[in] connectionSocketIndex Index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to send on.
/// \return true on success, false on failure (unknown hostname)
bool Ping( const char* host, unsigned short remotePort, bool onlyReplyOnAcceptingConnections, unsigned connectionSocketIndex=0 );
/// Returns the average of all ping times read for the specific system or -1 if none read yet
/// \param[in] systemAddress Which system we are referring to
/// \return The ping time for this system, or -1
int GetAveragePing( const SystemAddress systemAddress );
/// Returns the last ping time read for the specific system or -1 if none read yet
/// \param[in] systemAddress Which system we are referring to
/// \return The last ping time for this system, or -1
int GetLastPing( const SystemAddress systemAddress ) const;
/// Returns the lowest ping time read or -1 if none read yet
/// \param[in] systemAddress Which system we are referring to
/// \return The lowest ping time for this system, or -1
int GetLowestPing( const SystemAddress systemAddress ) const;
/// Ping the remote systems every so often, or not. This is off by default. Can be called anytime.
/// \param[in] doPing True to start occasional pings. False to stop them.
void SetOccasionalPing( bool doPing );
// --------------------------------------------------------------------------------------------Static Data Functions - Functions dealing with API defined synchronized memory--------------------------------------------------------------------------------------------
/// Sets the data to send along with a LAN server discovery or offline ping reply.
/// \a length should be under 400 bytes, as a security measure against flood attacks
/// \param[in] data a block of data to store, or 0 for none
/// \param[in] length The length of data in bytes, or 0 for none
/// \sa Ping.cpp
void SetOfflinePingResponse( const char *data, const unsigned int length );
/// Returns pointers to a copy of the data passed to SetOfflinePingResponse
/// \param[out] data A pointer to a copy of the data passed to \a SetOfflinePingResponse()
/// \param[out] length A pointer filled in with the length parameter passed to SetOfflinePingResponse()
/// \sa SetOfflinePingResponse
void GetOfflinePingResponse( char **data, unsigned int *length );
//--------------------------------------------------------------------------------------------Network Functions - Functions dealing with the network in general--------------------------------------------------------------------------------------------
/// Return the unique address identifier that represents you or another system on the the network and is based on your local IP / port.
/// \param[in] systemAddress Use UNASSIGNED_SYSTEM_ADDRESS to get your behind-LAN address. Use a connected system to get their behind-LAN address
/// \param[in] index When you have multiple internal IDs, which index to return? Currently limited to MAXIMUM_NUMBER_OF_INTERNAL_IDS (so the maximum value of this variable is MAXIMUM_NUMBER_OF_INTERNAL_IDS-1)
/// \return the identifier of your system internally, which may not be how other systems see if you if you are behind a NAT or proxy
SystemAddress GetInternalID( const SystemAddress systemAddress=UNASSIGNED_SYSTEM_ADDRESS, const int index=0 ) const;
/// Return the unique address identifier that represents you on the the network and is based on your externalIP / port
/// (the IP / port the specified player uses to communicate with you)
/// \param[in] target Which remote system you are referring to for your external ID. Usually the same for all systems, unless you have two or more network cards.
SystemAddress GetExternalID( const SystemAddress target ) const;
/// Given a connected system, give us the unique GUID representing that instance of RakPeer.
/// This will be the same on all systems connected to that instance of RakPeer, even if the external system addresses are different
/// O(log2(n))
/// If \a input is UNASSIGNED_SYSTEM_ADDRESS, will return your own GUID
/// \pre Call Startup() first, or the function will return UNASSIGNED_RAKNET_GUID
/// \param[in] input The system address of the system we are connected to
RakNetGUID GetGuidFromSystemAddress( const SystemAddress input ) const;
/// Given the GUID of a connected system, give us the system address of that system.
/// The GUID will be the same on all systems connected to that instance of RakPeer, even if the external system addresses are different
/// Currently O(log(n)), but this may be improved in the future
/// If \a input is UNASSIGNED_RAKNET_GUID, will return UNASSIGNED_SYSTEM_ADDRESS
/// \param[in] input The RakNetGUID of the system we are checking to see if we are connected to
SystemAddress GetSystemAddressFromGuid( const RakNetGUID input ) const;
/// Set the time, in MS, to use before considering ourselves disconnected after not being able to deliver a reliable message.
/// Default time is 10,000 or 10 seconds in release and 30,000 or 30 seconds in debug.
/// \param[in] timeMS Time, in MS
/// \param[in] target Which system to do this for. Pass UNASSIGNED_SYSTEM_ADDRESS for all systems.
void SetTimeoutTime( RakNetTime timeMS, const SystemAddress target );
/// Set the MTU per datagram. It's important to set this correctly - otherwise packets will be needlessly split, decreasing performance and throughput.
/// Maximum allowed size is MAXIMUM_MTU_SIZE.
/// Too high of a value will cause packets not to arrive at worst and be fragmented at best.
/// Too low of a value will split packets unnecessarily.
/// Recommended size is 1500
/// sa MTUSize.h
/// \param[in] size The MTU size
/// \param[in] target Which system to set this for. UNASSIGNED_SYSTEM_ADDRESS to set the default, for new systems
/// \pre Can only be called when not connected.
/// \return false on failure (we are connected), else true
bool SetMTUSize( int size, const SystemAddress target );
/// Returns the current MTU size
/// \param[in] target Which system to get this for. UNASSIGNED_SYSTEM_ADDRESS to get the default
/// \return The current MTU size
int GetMTUSize( const SystemAddress target ) const;
/// Returns the number of IP addresses this system has internally. Get the actual addresses from GetLocalIP()
unsigned GetNumberOfAddresses( void );
/// Returns an IP address at index 0 to GetNumberOfAddresses-1
/// \param[in] index index into the list of IP addresses
/// \return The local IP address at this index
const char* GetLocalIP( unsigned int index );
/// Is this a local IP?
/// \param[in] An IP address to check, excluding the port
/// \return True if this is one of the IP addresses returned by GetLocalIP
bool IsLocalIP( const char *ip );
/// Allow or disallow connection responses from any IP. Normally this should be false, but may be necessary
/// when connecting to servers with multiple IP addresses.
/// \param[in] allow - True to allow this behavior, false to not allow. Defaults to false. Value persists between connections
void AllowConnectionResponseIPMigration( bool allow );
/// Sends a one byte message ID_ADVERTISE_SYSTEM to the remote unconnected system.
/// This will tell the remote system our external IP outside the LAN along with some user data.
/// \pre The sender and recipient must already be started via a successful call to Initialize
/// \param[in] host Either a dotted IP address or a domain name
/// \param[in] remotePort Which port to connect to on the remote machine.
/// \param[in] data Optional data to append to the packet.
/// \param[in] dataLength length of data in bytes. Use 0 if no data.
/// \param[in] connectionSocketIndex Index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to send on.
/// \return false if IsActive()==false or the host is unresolvable. True otherwise
bool AdvertiseSystem( const char *host, unsigned short remotePort, const char *data, int dataLength, unsigned connectionSocketIndex=0 );
/// Controls how often to return ID_DOWNLOAD_PROGRESS for large message downloads.
/// ID_DOWNLOAD_PROGRESS is returned to indicate a new partial message chunk, roughly the MTU size, has arrived
/// As it can be slow or cumbersome to get this notification for every chunk, you can set the interval at which it is returned.
/// Defaults to 0 (never return this notification)
/// \param[in] interval How many messages to use as an interval
void SetSplitMessageProgressInterval(int interval);
/// Returns what was passed to SetSplitMessageProgressInterval()
/// \return What was passed to SetSplitMessageProgressInterval(). Default to 0.
int GetSplitMessageProgressInterval(void) const;
/// Set how long to wait before giving up on sending an unreliable message
/// Useful if the network is clogged up.
/// Set to 0 or less to never timeout. Defaults to 0.
/// \param[in] timeoutMS How many ms to wait before simply not sending an unreliable message.
void SetUnreliableTimeout(RakNetTime timeoutMS);
/// Send a message to host, with the IP socket option TTL set to 3
/// This message will not reach the host, but will open the router.
/// \param[in] ttl Max hops of datagram
/// Used for NAT-Punchthrough
void SendTTL( const char* host, unsigned short remotePort, int ttl, unsigned connectionSocketIndex=0 );
// --------------------------------------------------------------------------------------------Compression Functions - Functions related to the compression layer--------------------------------------------------------------------------------------------
/// Enables or disables frequency table tracking. This is required to get a frequency table, which is used in GenerateCompressionLayer()
/// This value persists between connect calls and defaults to false (no frequency tracking)
/// \pre You can call this at any time - however you SHOULD only call it when disconnected. Otherwise you will only trackpart of the values sent over the network.
/// \param[in] doCompile True to enable tracking
void SetCompileFrequencyTable( bool doCompile );
/// Returns the frequency of outgoing bytes into output frequency table
/// The purpose is to save to file as either a master frequency table from a sample game session for passing to
/// GenerateCompressionLayer()
/// \pre You should only call this when disconnected. Requires that you first enable data frequency tracking by calling SetCompileFrequencyTable(true)
/// \param[out] outputFrequencyTable The frequency of each corresponding byte
/// \return False (failure) if connected or if frequency table tracking is not enabled. Otherwise true (success)
bool GetOutgoingFrequencyTable( unsigned int outputFrequencyTable[ 256 ] );
/// This is an optional function to generate the compression layer based on the input frequency table.
/// If you want to use it you should call this twice - once with inputLayer as true and once as false.
/// The frequency table passed here with inputLayer=true should match the frequency table on the recipient with inputLayer=false.
/// Likewise, the frequency table passed here with inputLayer=false should match the frequency table on the recipient with inputLayer=true.
/// Calling this function when there is an existing layer will overwrite the old layer.
/// \pre You should only call this when disconnected
/// \param[in] inputFrequencyTable A frequency table for your data
/// \param[in] inputLayer Is this the input layer?
/// \return false (failure) if connected. Otherwise true (success)
/// \sa Compression.cpp
bool GenerateCompressionLayer( unsigned int inputFrequencyTable[ 256 ], bool inputLayer );
/// Delete the output or input layer as specified. This is not necessary to call and is only valuable for freeing memory.
/// \pre You should only call this when disconnected
/// \param[in] inputLayer True to mean the inputLayer, false to mean the output layer
/// \return false (failure) if connected. Otherwise true (success)
bool DeleteCompressionLayer( bool inputLayer );
/// Returns the compression ratio. A low compression ratio is good. Compression is for outgoing data
/// \return The compression ratio
float GetCompressionRatio( void ) const;
///Returns the decompression ratio. A high decompression ratio is good. Decompression is for incoming data
/// \return The decompression ratio
float GetDecompressionRatio( void ) const;
// -------------------------------------------------------------------------------------------- Plugin Functions--------------------------------------------------------------------------------------------
/// Attatches a Plugin interface to run code automatically on message receipt in the Receive call
/// \note If plugins have dependencies on each other then the order does matter - for example the router plugin should go first because it might route messages for other plugins
/// \param[in] messageHandler Pointer to a plugin to attach
void AttachPlugin( PluginInterface *plugin );
/// Detaches a Plugin interface to run code automatically on message receipt
/// \param[in] messageHandler Pointer to a plugin to detach
void DetachPlugin( PluginInterface *messageHandler );
// --------------------------------------------------------------------------------------------Miscellaneous Functions--------------------------------------------------------------------------------------------
/// Put a message back at the end of the receive queue in case you don't want to deal with it immediately
/// \param[in] packet The packet you want to push back.
/// \param[in] pushAtHead True to push the packet so that the next receive call returns it. False to push it at the end of the queue (obviously pushing it at the end makes the packets out of order)
void PushBackPacket( Packet *packet, bool pushAtHead );
/// \Internal
// \param[in] routerInterface The router to use to route messages to systems not directly connected to this system.
void SetRouterInterface( RouterInterface *routerInterface );
/// \Internal
// \param[in] routerInterface The router to use to route messages to systems not directly connected to this system.
void RemoveRouterInterface( RouterInterface *routerInterface );
/// \returns a packet for you to write to if you want to create a Packet for some reason.
/// You can add it to the receive buffer with PushBackPacket
/// \param[in] dataSize How many bytes to allocate for the buffer
/// \return A packet you can write to
Packet* AllocatePacket(unsigned dataSize);
// --------------------------------------------------------------------------------------------Network Simulator Functions--------------------------------------------------------------------------------------------
/// Adds simulated ping and packet loss to the outgoing data flow.
/// To simulate bi-directional ping and packet loss, you should call this on both the sender and the recipient, with half the total ping and maxSendBPS value on each.
/// You can exclude network simulator code with the _RELEASE #define to decrease code size
/// \depreciated Use http://www.jenkinssoftware.com/raknet/forum/index.php?topic=1671.0 instead.
/// \param[in] maxSendBPS Maximum bits per second to send. Packetloss grows linearly. 0 to disable. (CURRENTLY BROKEN - ALWAYS DISABLED)
/// \param[in] minExtraPing The minimum time to delay sends.
/// \param[in] extraPingVariance The additional random time to delay sends.
void ApplyNetworkSimulator( double maxSendBPS, unsigned short minExtraPing, unsigned short extraPingVariance);
/// Limits how much outgoing bandwidth can be sent per-connection.
/// This limit does not apply to the sum of all connections!
/// Exceeding the limit queues up outgoing traffic
/// \param[in] maxBitsPerSecond Maximum bits per second to send. Use 0 for unlimited (default). Once set, it takes effect immedately and persists until called again.
void SetPerConnectionOutgoingBandwidthLimit( unsigned maxBitsPerSecond );
/// Returns if you previously called ApplyNetworkSimulator
/// \return If you previously called ApplyNetworkSimulator
bool IsNetworkSimulatorActive( void );
// -------------------------------------------------------------------------------------------- Socket Functions--------------------------------------------------------------------------------------------
/// Have RakNet use a socket you created yourself
/// The socket should not be in use - it is up to you to either shutdown or close the connections using it. Otherwise existing connections on that socket will eventually disconnect
/// This socket will be forgotten after calling Shutdown(), so rebind again if you need to.
/// \param[in] s The socket to rebind.
/// \param[in] haveRakNetCloseSocket If true, RakNet will call closeSocket on shutdown for this socket.
/// \param[in] connectionSocketIndex Index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to send on.
void UseUserSocket( int socket, bool haveRakNetCloseSocket, unsigned connectionSocketIndex);
/// Have RakNet recreate a socket using a different port.
/// The socket should not be in use - it is up to you to either shutdown or close the connections using it. Otherwise existing connections on that socket will eventually disconnect
/// \param[in] connectionSocketIndex Index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to send on.
/// \param[in] sd Address to bind on
void RebindSocketAddress(unsigned connectionSocketIndex, SocketDescriptor &sd);
// --------------------------------------------------------------------------------------------Statistical Functions - Functions dealing with API performance--------------------------------------------------------------------------------------------
/// Returns a structure containing a large set of network statistics for the specified system.
/// You can map this data to a string using the C style StatisticsToString() function
/// \param[in] systemAddress: Which connected system to get statistics for
/// \param[in] rns If you supply this structure, it will be written to it. Otherwise it will use a static struct, which is not threadsafe
/// \return 0 on can't find the specified system. A pointer to a set of data otherwise.
/// \sa RakNetStatistics.h
RakNetStatistics * const GetStatistics( const SystemAddress systemAddress, RakNetStatistics *rns=0 );
// --------------------------------------------------------------------------------------------EVERYTHING AFTER THIS COMMENT IS FOR INTERNAL USE ONLY--------------------------------------------------------------------------------------------
/// \internal
char *GetRPCString( const char *data, const BitSize_t bitSize, const SystemAddress systemAddress);
/// \internal
bool SendOutOfBand(const char *host, unsigned short remotePort, MessageID header, const char *data, BitSize_t dataLength, unsigned connectionSocketIndex=0 );
/// \internal
/// \brief Holds the clock differences between systems, along with the ping
struct PingAndClockDifferential
{
unsigned short pingTime;
RakNetTime clockDifferential;
};
/// \internal
/// \brief All the information representing a connected system system
struct RemoteSystemStruct
{
bool isActive; // Is this structure in use?
SystemAddress systemAddress; /// Their external IP on the internet
SystemAddress myExternalSystemAddress; /// Your external IP on the internet, from their perspective
SystemAddress theirInternalSystemAddress[MAXIMUM_NUMBER_OF_INTERNAL_IDS]; /// Their internal IP, behind the LAN
ReliabilityLayer reliabilityLayer; /// The reliability layer associated with this player
bool weInitiatedTheConnection; /// True if we started this connection via Connect. False if someone else connected to us.
PingAndClockDifferential pingAndClockDifferential[ PING_TIMES_ARRAY_SIZE ]; /// last x ping times and calculated clock differentials with it
int pingAndClockDifferentialWriteIndex; /// The index we are writing into the pingAndClockDifferential circular buffer
unsigned short lowestPing; ///The lowest ping value encountered
RakNetTime nextPingTime; /// When to next ping this player
RakNetTime lastReliableSend; /// When did the last reliable send occur. Reliable sends must occur at least once every timeoutTime/2 units to notice disconnects
RakNetTime connectionTime; /// connection time, if active.
unsigned char AESKey[ 16 ]; /// Security key.
bool setAESKey; /// true if security is enabled.
int connectionSocketIndex; // index into connectionSockets to send back on.
RPCMap rpcMap; /// Mapping of RPC calls to single byte integers to save transmission bandwidth.
RakNetGUID guid;
int MTUSize;
#if defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3)
// void *onlineServiceId;
// unsigned int connectionId;
#endif
enum ConnectMode {NO_ACTION, DISCONNECT_ASAP, DISCONNECT_ASAP_SILENTLY, DISCONNECT_ON_NO_ACK, REQUESTED_CONNECTION, HANDLING_CONNECTION_REQUEST, UNVERIFIED_SENDER, SET_ENCRYPTION_ON_MULTIPLE_16_BYTE_PACKET, CONNECTED} connectMode;
};
protected:
friend RAK_THREAD_DECLARATION(UpdateNetworkLoop);
/*
#ifdef _WIN32
// friend unsigned __stdcall RecvFromNetworkLoop(LPVOID arguments);
friend void __stdcall ProcessPortUnreachable( const unsigned int binaryAddress, const unsigned short port, RakPeer *rakPeer );
friend void __stdcall ProcessNetworkPacket( const unsigned int binaryAddress, const unsigned short port, const char *data, const int length, RakPeer *rakPeer, unsigned connectionSocketIndex );
friend unsigned __stdcall UpdateNetworkLoop( LPVOID arguments );
#else
// friend void* RecvFromNetworkLoop( void* arguments );
friend void ProcessPortUnreachable( const unsigned int binaryAddress, const unsigned short port, RakPeer *rakPeer );
friend void ProcessNetworkPacket( const unsigned int binaryAddress, const unsigned short port, const char *data, const int length, RakPeer *rakPeer, unsigned connectionSocketIndex );
friend void* UpdateNetworkLoop( void* arguments );
#endif
*/
friend void ProcessPortUnreachable( const unsigned int binaryAddress, const unsigned short port, RakPeer *rakPeer );
friend void ProcessNetworkPacket( const unsigned int binaryAddress, const unsigned short port, const char *data, const int length, RakPeer *rakPeer, unsigned connectionSocketIndex );
// This is done to provide custom RPC handling when in a blocking RPC
Packet* ReceiveIgnoreRPC( void );
int GetIndexFromSystemAddress( const SystemAddress systemAddress, bool calledFromNetworkThread );
//void RemoveFromRequestedConnectionsList( const SystemAddress systemAddress );
bool SendConnectionRequest( const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, unsigned connectionSocketIndex, unsigned int extraData );
///Get the reliability layer associated with a systemAddress.
/// \param[in] systemAddress The player identifier
/// \return 0 if none
RemoteSystemStruct *GetRemoteSystemFromSystemAddress( const SystemAddress systemAddress, bool calledFromNetworkThread, bool onlyActive ) const;
///Parse out a connection request packet
void ParseConnectionRequestPacket( RakPeer::RemoteSystemStruct *remoteSystem, SystemAddress systemAddress, const char *data, int byteSize);
///When we get a connection request from an ip / port, accept it unless full
void OnConnectionRequest( RakPeer::RemoteSystemStruct *remoteSystem, unsigned char *AESKey, bool setAESKey );
void SendConnectionRequestAccepted(RakPeer::RemoteSystemStruct *remoteSystem);
///Send a reliable disconnect packet to this player and disconnect them when it is delivered
void NotifyAndFlagForShutdown( const SystemAddress systemAddress, bool performImmediate, unsigned char orderingChannel );
///Returns how many remote systems initiated a connection to us
unsigned short GetNumberOfRemoteInitiatedConnections( void ) const;
///Get a free remote system from the list and assign our systemAddress to it. Should only be called from the update thread - not the user thread
RemoteSystemStruct * AssignSystemAddressToRemoteSystemList( const SystemAddress systemAddress, RemoteSystemStruct::ConnectMode connectionMode, unsigned connectionSocketIndex );
///An incoming packet has a timestamp, so adjust it to be relative to this system
void ShiftIncomingTimestamp( unsigned char *data, SystemAddress systemAddress ) const;
///Get the most probably accurate clock differential for a certain player
RakNetTime GetBestClockDifferential( const SystemAddress systemAddress ) const;
//void PushPortRefused( const SystemAddress target );
///Handles an RPC packet. This is sending an RPC request
/// \param[in] data A packet returned from Receive with the ID ID_RPC
/// \param[in] length The size of the packet data
/// \param[in] systemAddress The sender of the packet
/// \return true on success, false on a bad packet or an unregistered function
bool HandleRPCPacket( const char *data, int length, SystemAddress systemAddress );
///Handles an RPC reply packet. This is data returned from an RPC call
/// \param[in] data A packet returned from Receive with the ID ID_RPC
/// \param[in] length The size of the packet data
/// \param[in] systemAddress The sender of the packet
void HandleRPCReplyPacket( const char *data, int length, SystemAddress systemAddress );
///Set this to true to terminate the Peer thread execution
volatile bool endThreads;
///true if the peer thread is active.
volatile bool isMainLoopThreadActive;
bool occasionalPing; /// Do we occasionally ping the other systems?*/
///Store the maximum number of peers allowed to connect
unsigned short maximumNumberOfPeers;
//05/02/06 Just using maximumNumberOfPeers instead
///Store the maximum number of peers able to connect, including reserved connection slots for pings, etc.
//unsigned short remoteSystemListSize;
///Store the maximum incoming connection allowed
unsigned short maximumIncomingConnections;
RakNet::BitStream offlinePingResponse;
///Local Player ID
SystemAddress mySystemAddress[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
char incomingPassword[256];
unsigned char incomingPasswordLength;
/// This is an array of pointers to RemoteSystemStruct
/// This allows us to preallocate the list when starting, so we don't have to allocate or delete at runtime.
/// Another benefit is that is lets us add and remove active players simply by setting systemAddress
/// and moving elements in the list by copying pointers variables without affecting running threads, even if they are in the reliability layer
RemoteSystemStruct* remoteSystemList;
// remoteSystemLookup is only used in the network thread or when single threaded. Not safe to use this in the user thread
// A list of SystemAddressAndIndex sorted by systemAddress. This way, given a SystemAddress, we can quickly get the index into remoteSystemList to find this player.
// This is an optimization to avoid scanning the remoteSystemList::systemAddress member when doing targeted sends
// Improves speed of a targeted send to every player from O(n^2) to O(n * log2(n)).
// For an MMOG with 1000 players:
// The original method takes 1000^2=1,000,000 calls
// The new method takes:
// logbx = (logax) / (logab)
// log2(x) = log10(x) / log10(2)
// log2(1000) = log10(1000) / log10(2)
// log2(1000) = 9.965
// 9.965 * 1000 = 9965
// For 1000 players this optimization improves the speed by over 1000 times.
DataStructures::OrderedList<SystemAddress, SystemAddressAndIndex, SystemAddressAndIndexComp> remoteSystemLookup;
enum
{
// Only put these mutexes in user thread functions!
#ifdef _RAKNET_THREADSAFE
transferToPacketQueue_Mutex,
packetPool_Mutex,
bufferedCommands_Mutex,
requestedConnectionList_Mutex,
#endif
offlinePingResponse_Mutex,
NUMBER_OF_RAKPEER_MUTEXES
};
SimpleMutex rakPeerMutexes[ NUMBER_OF_RAKPEER_MUTEXES ];
///RunUpdateCycle is not thread safe but we don't need to mutex calls. Just skip calls if it is running already
bool updateCycleIsRunning;
///The list of people we have tried to connect to recently
//DataStructures::Queue<RequestedConnectionStruct*> requestedConnectionsList;
///Data that both the client and the server needs
unsigned int bytesSentPerSecond, bytesReceivedPerSecond;
// bool isSocketLayerBlocking;
// bool continualPing,isRecvfromThreadActive,isMainLoopThreadActive, endThreads, isSocketLayerBlocking;
unsigned int validationInteger;
SimpleMutex incomingQueueMutex, banListMutex; //,synchronizedMemoryQueueMutex, automaticVariableSynchronizationMutex;
//DataStructures::Queue<Packet *> incomingpacketSingleProducerConsumer; //, synchronizedMemorypacketSingleProducerConsumer;
// BitStream enumerationData;
struct BanStruct
{
char *IP;
RakNetTime timeout; // 0 for none
};
struct RequestedConnectionStruct
{
SystemAddress systemAddress;
RakNetTime nextRequestTime;
unsigned char requestsMade;
char *data;
unsigned short dataLength;
char outgoingPassword[256];
unsigned char outgoingPasswordLength;
unsigned socketIndex;
unsigned int extraData;
enum {CONNECT=1, /*PING=2, PING_OPEN_CONNECTIONS=4,*/ /*ADVERTISE_SYSTEM=2*/} actionToTake;
};
//DataStructures::List<DataStructures::List<MemoryBlock>* > automaticVariableSynchronizationList;
DataStructures::List<BanStruct*> banList;
DataStructures::List<PluginInterface*> messageHandlerList;
// DataStructures::SingleProducerConsumer<RequestedConnectionStruct> requestedConnectionList;
DataStructures::Queue<RequestedConnectionStruct*> requestedConnectionQueue;
SimpleMutex requestedConnectionQueueMutex;
/// Compression stuff
unsigned int frequencyTable[ 256 ];
HuffmanEncodingTree *inputTree, *outputTree;
unsigned int rawBytesSent, rawBytesReceived, compressedBytesSent, compressedBytesReceived;
// void DecompressInput(RakNet::BitStream *bitStream);
// void UpdateOutgoingFrequencyTable(RakNet::BitStream * bitStream);
void GenerateSYNCookieRandomNumber( void );
void SecuredConnectionResponse( const SystemAddress systemAddress );
void SecuredConnectionConfirmation( RakPeer::RemoteSystemStruct * remoteSystem, char* data );
bool RunUpdateCycle( void );
// void RunMutexedUpdateCycle(void);
struct BufferedCommandStruct
{
BitSize_t numberOfBitsToSend;
PacketPriority priority;
PacketReliability reliability;
char orderingChannel;
SystemAddress systemAddress;
bool broadcast;
RemoteSystemStruct::ConnectMode connectionMode;
NetworkID networkID;
bool blockingCommand; // Only used for RPC
char *data;
bool haveRakNetCloseSocket;
unsigned connectionSocketIndex;
bool isPS3LobbySocket;
SOCKET socket;
unsigned short port;
enum {BCS_SEND, BCS_CLOSE_CONNECTION, BCS_USE_USER_SOCKET, BCS_REBIND_SOCKET_ADDRESS, /*BCS_RPC, BCS_RPC_SHIFT,*/ BCS_DO_NOTHING} command;
};
// Single producer single consumer queue using a linked list
//BufferedCommandStruct* bufferedCommandReadIndex, bufferedCommandWriteIndex;
DataStructures::SingleProducerConsumer<BufferedCommandStruct> bufferedCommands;
bool AllowIncomingConnections(void) const;
void PingInternal( const SystemAddress target, bool performImmediate, PacketReliability reliability );
bool ValidSendTarget(SystemAddress systemAddress, bool broadcast);
// This stores the user send calls to be handled by the update thread. This way we don't have thread contention over systemAddresss
void CloseConnectionInternal( const SystemAddress target, bool sendDisconnectionNotification, bool performImmediate, unsigned char orderingChannel );
void SendBuffered( const char *data, BitSize_t numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, RemoteSystemStruct::ConnectMode connectionMode );
void SendBufferedList( char **data, const int *lengths, const int numParameters, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, RemoteSystemStruct::ConnectMode connectionMode );
bool SendImmediate( char *data, BitSize_t numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, bool useCallerDataAllocation, RakNetTimeNS currentTime );
//bool HandleBufferedRPC(BufferedCommandStruct *bcs, RakNetTime time);
void ClearBufferedCommands(void);
void ClearRequestedConnectionList(void);
void AddPacketToProducer(Packet *p);
unsigned int GenerateSeedFromGuid(void);
SimpleMutex securityExceptionMutex;
//DataStructures::AVLBalancedBinarySearchTree<RPCNode> rpcTree;
RPCMap rpcMap; // Can't use StrPtrHash because runtime insertions will screw up the indices
int defaultMTUSize;
bool trackFrequencyTable;
int threadSleepTimer;
struct RakNetSocket
{
SOCKET s;
bool isPS3LobbySocket;
bool haveRakNetCloseSocket;
} *connectionSockets;
// SOCKET *connectionSockets;
// bool *haveRakNetCloseSocket; // array of bools, to dealloc connectionSockets into the same index
unsigned connectionSocketsLength;
#if defined (_WIN32) && defined(USE_WAIT_FOR_MULTIPLE_EVENTS)
WSAEVENT recvEvent;
#endif
// Used for RPC replies
RakNet::BitStream *replyFromTargetBS;
SystemAddress replyFromTargetPlayer;
bool replyFromTargetBroadcast;
RakNetTime defaultTimeoutTime;
// Problem:
// Waiting in function A:
// Wait function gets RPC B:
//
bool blockOnRPCReply;
// For redirecting sends through the router plugin. Unfortunate I have to use this architecture.
RouterInterface *router;
// Generate and store a unique GUID
void GenerateGUID(void);
RakNetGUID guid;
unsigned maxOutgoingBPS;
// Nobody would use the internet simulator in a final build.
#ifndef _RELEASE
double _maxSendBPS;
unsigned short _minExtraPing, _extraPingVariance;
#endif
#if !defined(_XBOX) && !defined(_WIN32_WCE) && !defined(X360)
/// Encryption and security
RSACrypt rsacrypt;
uint32_t publicKeyE;
uint32_t publicKeyN[RAKNET_RSA_FACTOR_LIMBS];
bool keysLocallyGenerated, usingSecurity;
RakNetTime randomNumberExpirationTime;
unsigned char newRandomNumber[ 20 ], oldRandomNumber[ 20 ];
/*
big::RSACrypt<RSA_BIT_SIZE> rsacrypt;
big::u32 publicKeyE;
RSA_BIT_SIZE publicKeyN;
bool keysLocallyGenerated, usingSecurity;
RakNetTime randomNumberExpirationTime;
unsigned char newRandomNumber[ 20 ], oldRandomNumber[ 20 ];
*/
#endif
///How long it has been since things were updated by a call to receiveUpdate thread uses this to determine how long to sleep for
//unsigned int lastUserUpdateCycle;
/// True to allow connection accepted packets from anyone. False to only allow these packets from servers we requested a connection to.
bool allowConnectionResponseIPMigration;
SystemAddress firstExternalID;
int splitMessageProgressInterval;
RakNetTime unreliableTimeout;
#if defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3)
// unsigned int console2ContextId;
#endif
// The packetSingleProducerConsumer transfers the packets from the network thread to the user thread. The pushedBackPacket holds packets that couldn't be processed
// immediately while waiting on blocked RPCs
DataStructures::SingleProducerConsumer<Packet*> packetSingleProducerConsumer;
//DataStructures::Queue<Packet*> pushedBackPacket, outOfOrderDeallocatedPacket;
// A free-list of packets, to reduce memory fragmentation
DataStructures::Queue<Packet*> packetPool;
// Used for object lookup for RPC (actually depreciated, since RPC is depreciated)
NetworkIDManager *networkIDManager;
// Systems in this list will not go through the secure connection process, even when secure connections are turned on. Wildcards are accepted.
DataStructures::List<RakNet::RakString> securityExceptionList;
};
#endif
+134 -19
View File
@@ -8,7 +8,7 @@
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.rakkarsoft.com/SingleApplicationLicense.html
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
@@ -20,6 +20,7 @@
#include "PacketPriority.h"
#include "RakNetTypes.h"
#include "RakMemoryOverride.h"
#include "Export.h"
// Forward declarations
@@ -47,6 +48,7 @@ public:
/// You must call this before calling Connect().
/// Multiple calls while already active are ignored. To call this function again with different settings, you must first call Shutdown().
/// \note Call SetMaximumIncomingConnections if you want to accept incoming connections
/// \note Set _RAKNET_THREADSAFE in RakNetDefines.h if you want to call RakNet functions from multiple threads (not recommended, as it is much slower and RakNet is already asynchronous).
/// \param[in] maxConnections The maximum number of connections between this instance of RakPeer and another instance of RakPeer. Required so the network can preallocate and for thread safety. A pure client would set this to 1. A pure server would set it to the number of allowed clients.- A hybrid would set it to the sum of both types of connections
/// \param[in] localPort The port to listen for connections on.
/// \param[in] _threadSleepTimer How many ms to Sleep each internal update cycle (30 to give the game priority, 0 for regular (recommended)
@@ -70,9 +72,24 @@ public:
/// \note Must be called while offline
virtual void DisableSecurity( void )=0;
/// If secure connections are on, do not use secure connections for a specific IP address.
/// This is useful if you have a fixed-address internal server behind a LAN.
/// \note Secure connections are determined by the recipient of an incoming connection. This has no effect if called on the system attempting to connect.
/// \param[in] ip IP address to add. * wildcards are supported.
virtual void AddToSecurityExceptionList(const char *ip)=0;
/// Remove a specific connection previously added via AddToSecurityExceptionList
/// \param[in] ip IP address to remove. Pass 0 to remove all IP addresses. * wildcards are supported.
virtual void RemoveFromSecurityExceptionList(const char *ip)=0;
/// Checks to see if a given IP is in the security exception list
/// \param[in] IP address to check.
virtual bool IsInSecurityExceptionList(const char *ip)=0;
/// Sets how many incoming connections are allowed. If this is less than the number of players currently connected,
/// no more players will be allowed to connect. If this is greater than the maximum number of peers allowed,
/// it will be reduced to the maximum number of peers allowed. Defaults to 0.
/// it will be reduced to the maximum number of peers allowed.
/// Defaults to 0, meaning by default, nobody can connect to you
/// \param[in] numberAllowed Maximum number of incoming connections allowed.
virtual void SetMaximumIncomingConnections( unsigned short numberAllowed )=0;
@@ -113,7 +130,7 @@ public:
/// Does built-in NAt traversal
/// \param[in] passwordData A data block that must match the data block on the server passed to SetIncomingPassword. This can be a string or can be a stream of data. Use 0 for no password.
/// \param[in] passwordDataLength The length in bytes of passwordData
virtual bool Console2Connect( void *networkServiceId, const char *passwordData, int passwordDataLength )=0;
//virtual bool Console2LobbyConnect( void *networkServiceId, const char *passwordData, int passwordDataLength )=0;
/// \brief Stops the network threads and closes all connections.
/// \param[in] blockDuration How long, in milliseconds, you should wait for all remaining messages to go out, including ID_DISCONNECTION_NOTIFICATION. If 0, it doesn't wait at all.
@@ -132,6 +149,7 @@ public:
/// Sends a block of data to the specified system that you are connected to.
/// This function only works while the connected
/// The first byte should be a message identifier starting at ID_USER_PACKET_ENUM
/// \param[in] data The block of data to send
/// \param[in] length The size in bytes of the data to send
/// \param[in] priority What priority level to send on. See PacketPriority.h
@@ -142,6 +160,13 @@ public:
/// \return False if we are not connected to the specified recipient. True otherwise
virtual bool Send( const char *data, const int length, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast )=0;
/// "Send" to yourself rather than a remote system. The message will be processed through the plugins and returned to the game as usual
/// This function works anytime
/// The first byte should be a message identifier starting at ID_USER_PACKET_ENUM
/// \param[in] data The block of data to send
/// \param[in] length The size in bytes of the data to send
virtual void SendLoopback( const char *data, const int length )=0;
/// Sends a block of data to the specified system that you are connected to. Same as the above version, but takes a BitStream as input.
/// \param[in] bitStream The bitstream to send
/// \param[in] priority What priority level to send on. See PacketPriority.h
@@ -150,12 +175,35 @@ public:
/// \param[in] systemAddress Who to send this packet to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_SYSTEM_ADDRESS to specify none
/// \param[in] broadcast True to send this packet to all connected systems. If true, then systemAddress specifies who not to send the packet to.
/// \return False if we are not connected to the specified recipient. True otherwise
/// \note COMMON MISTAKE: When writing the first byte, bitStream->Write((unsigned char) ID_MY_TYPE) be sure it is casted to a byte, and you are not writing a 4 byte enumeration.
virtual bool Send( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast )=0;
/// Sends multiple blocks of data, concatenating them automatically.
///
/// This is equivalent to:
/// RakNet::BitStream bs;
/// bs.WriteAlignedBytes(block1, blockLength1);
/// bs.WriteAlignedBytes(block2, blockLength2);
/// bs.WriteAlignedBytes(block3, blockLength3);
/// Send(&bs, ...)
///
/// This function only works while the connected
/// \param[in] data An array of pointers to blocks of data
/// \param[in] lengths An array of integers indicating the length of each block of data
/// \param[in] numParameters Length of the arrays data and lengths
/// \param[in] priority What priority level to send on. See PacketPriority.h
/// \param[in] reliability How reliability to send this data. See PacketPriority.h
/// \param[in] orderingChannel When using ordered or sequenced messages, what channel to order these on. Messages are only ordered relative to other messages on the same stream
/// \param[in] systemAddress Who to send this packet to, or in the case of broadcasting who not to send it to. Use UNASSIGNED_SYSTEM_ADDRESS to specify none
/// \param[in] broadcast True to send this packet to all connected systems. If true, then systemAddress specifies who not to send the packet to.
/// \return False if we are not connected to the specified recipient. True otherwise
virtual bool SendList( char **data, const int *lengths, const int numParameters, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast )=0;
/// Gets a message from the incoming message queue.
/// Use DeallocatePacket() to deallocate the message after you are done with it.
/// User-thread functions, such as RPC calls and the plugin function PluginInterface::Update occur here.
/// \return 0 if no packets are waiting to be handled, otherwise a pointer to a packet.
/// \note COMMON MISTAKE: Be sure to call this in a loop, once per game tick, until it returns 0. If you only process one packet per game tick they will buffer up.
/// sa RakNetTypes.h contains struct Packet
virtual Packet* Receive( void )=0;
@@ -169,12 +217,14 @@ public:
// --------------------------------------------------------------------------------------------Remote Procedure Call Functions - Functions to initialize and perform RPC--------------------------------------------------------------------------------------------
/// \ingroup RAKNET_RPC
/// \depreciated Use the AutoRPC plugin instead
/// Register a C or static member function as available for calling as a remote procedure call
/// \param[in] uniqueID A null-terminated unique string to identify this procedure. See RegisterClassMemberRPC() for class member functions.
/// \param[in] functionPointer(...) The name of the function to be used as a function pointer. This can be called whether active or not, and registered functions stay registered unless unregistered
virtual void RegisterAsRemoteProcedureCall( const char* uniqueID, void ( *functionPointer ) ( RPCParameters *rpcParms ) )=0;
/// \ingroup RAKNET_RPC
/// \depreciated Use the AutoRPC plugin instead
/// Register a C++ member function as available for calling as a remote procedure call.
/// \param[in] uniqueID A null terminated string to identify this procedure. Recommended you use the macro REGISTER_CLASS_MEMBER_RPC to create the string. Use RegisterAsRemoteProcedureCall() for static functions.
/// \param[in] functionPointer The name of the function to be used as a function pointer. This can be called whether active or not, and registered functions stay registered unless unregistered with UnregisterAsRemoteProcedureCall
@@ -182,6 +232,7 @@ public:
virtual void RegisterClassMemberRPC( const char* uniqueID, void *functionPointer )=0;
/// \ingroup RAKNET_RPC
/// \depreciated Use the AutoRPC plugin instead
/// Unregisters a C function as available for calling as a remote procedure call that was formerly registered with RegisterAsRemoteProcedureCall. Only call offline.
/// \param[in] uniqueID A string of only letters to identify this procedure. Recommended you use the macro CLASS_MEMBER_ID for class member functions.
virtual void UnregisterAsRemoteProcedureCall( const char* uniqueID )=0;
@@ -209,8 +260,8 @@ public:
/// \param[in] networkID For static functions, pass UNASSIGNED_NETWORK_ID. For member functions, you must derive from NetworkIDObject and pass the value returned by NetworkIDObject::GetNetworkID for that object.
/// \param[in] replyFromTarget If 0, this function is non-blocking. Otherwise it will block while waiting for a reply from the target procedure, which should be remotely written to RPCParameters::replyToSender and copied to replyFromTarget. The block will return early on disconnect or if the sent packet is unreliable and more than 3X the ping has elapsed.
/// \return True on a successful packet send (this does not indicate the recipient performed the call), false on failure
virtual bool RPC( const char* uniqueID, const char *data, unsigned int bitLength, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, RakNetTime *includedTimestamp, NetworkID networkID, RakNet::BitStream *replyFromTarget )=0;
virtual bool RPC( const char* uniqueID, const char *data, BitSize_t bitLength, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, RakNetTime *includedTimestamp, NetworkID networkID, RakNet::BitStream *replyFromTarget )=0;
/// \ingroup RAKNET_RPC
/// Calls a C function on the remote system that was already registered using RegisterAsRemoteProcedureCall.
/// If you want that function to return data you should call RPC from that system in the same wayReturns true on a successful packet
@@ -228,7 +279,7 @@ public:
/// \param[in] replyFromTarget If 0, this function is non-blocking. Otherwise it will block while waiting for a reply from the target procedure, which should be remotely written to RPCParameters::replyToSender and copied to replyFromTarget. The block will return early on disconnect or if the sent packet is unreliable and more than 3X the ping has elapsed.
/// \return True on a successful packet send (this does not indicate the recipient performed the call), false on failure
virtual bool RPC( const char* uniqueID, const RakNet::BitStream *bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, RakNetTime *includedTimestamp, NetworkID networkID, RakNet::BitStream *replyFromTarget )=0;
// -------------------------------------------------------------------------------------------- Connection Management Functions--------------------------------------------------------------------------------------------
/// Close the connection to another host (if we initiated the connection it will disconnect, if they did it will kick them out).
/// \param[in] target Which system to close the connection to.
@@ -236,10 +287,17 @@ public:
/// \param[in] channel Which ordering channel to send the disconnection notification on, if any
virtual void CloseConnection( const SystemAddress target, bool sendDisconnectionNotification, unsigned char orderingChannel=0 )=0;
/// Returns if a particular systemAddress is connected to us
/// Cancel a pending connection attempt
/// If we are already connected, the connection stays open
/// \param[in] target Which system to cancel
virtual void CancelConnectionAttempt( const SystemAddress target )=0;
/// Returns if a particular systemAddress is connected to us (this also returns true if we are in the process of connecting)
/// \param[in] systemAddress The SystemAddress we are referring to
/// \param[in] includeInProgress If true, also return true for connections that are in progress but haven't completed
/// \param[in] includeDisconnecting If true, also return true for connections that are in the process of disconnecting
/// \return True if this system is connected and active, false otherwise.
virtual bool IsConnected(const SystemAddress systemAddress)=0;
virtual bool IsConnected(const SystemAddress systemAddress, bool includeInProgress=false, bool includeDisconnecting=false)=0;
/// Given a systemAddress, returns an index from 0 to the maximum number of players allowed - 1.
/// \param[in] systemAddress The SystemAddress we are referring to
@@ -280,7 +338,8 @@ public:
/// \param[in] remotePort Which port to connect to on the remote machine.
/// \param[in] onlyReplyOnAcceptingConnections Only request a reply if the remote system is accepting connections
/// \param[in] connectionSocketIndex Index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to send on.
virtual void Ping( const char* host, unsigned short remotePort, bool onlyReplyOnAcceptingConnections, unsigned connectionSocketIndex=0 )=0;
/// \return true on success, false on failure (unknown hostname)
virtual bool Ping( const char* host, unsigned short remotePort, bool onlyReplyOnAcceptingConnections, unsigned connectionSocketIndex=0 )=0;
/// Returns the average of all ping times read for the specific system or -1 if none read yet
/// \param[in] systemAddress Which system we are referring to
@@ -309,20 +368,43 @@ public:
/// \sa Ping.cpp
virtual void SetOfflinePingResponse( const char *data, const unsigned int length )=0;
/// Returns pointers to a copy of the data passed to SetOfflinePingResponse
/// \param[out] data A pointer to a copy of the data passed to \a SetOfflinePingResponse()
/// \param[out] length A pointer filled in with the length parameter passed to SetOfflinePingResponse()
/// \sa SetOfflinePingResponse
virtual void GetOfflinePingResponse( char **data, unsigned int *length )=0;
//--------------------------------------------------------------------------------------------Network Functions - Functions dealing with the network in general--------------------------------------------------------------------------------------------
/// Return the unique address identifier that represents you on the the network and is based on your local IP / port.
/// Return the unique address identifier that represents you or another system on the the network and is based on your local IP / port.
/// \param[in] systemAddress Use UNASSIGNED_SYSTEM_ADDRESS to get your behind-LAN address. Use a connected system to get their behind-LAN address
/// \param[in] index When you have multiple internal IDs, which index to return? Currently limited to MAXIMUM_NUMBER_OF_INTERNAL_IDS (so the maximum value of this variable is MAXIMUM_NUMBER_OF_INTERNAL_IDS-1)
/// \return the identifier of your system internally, which may not be how other systems see if you if you are behind a NAT or proxy
virtual SystemAddress GetInternalID( const SystemAddress systemAddress=UNASSIGNED_SYSTEM_ADDRESS ) const=0;
virtual SystemAddress GetInternalID( const SystemAddress systemAddress=UNASSIGNED_SYSTEM_ADDRESS, const int index=0 ) const=0;
/// Return the unique address identifier that represents you on the the network and is based on your externalIP / port
/// (the IP / port the specified player uses to communicate with you)
/// \param[in] target Which remote system you are referring to for your external ID. Usually the same for all systems, unless you have two or more network cards.
virtual SystemAddress GetExternalID( const SystemAddress target ) const=0;
/// Given a connected system, give us the unique GUID representing that instance of RakPeer.
/// This will be the same on all systems connected to that instance of RakPeer, even if the external system addresses are different
/// Currently O(log(n)), but this may be improved in the future. If you use this frequently, you may want to cache the value as it won't change.
/// If \a input is UNASSIGNED_SYSTEM_ADDRESS, will return your own GUID
/// \pre Call Startup() first, or the function will return UNASSIGNED_RAKNET_GUID
/// \param[in] input The system address of the system we are connected to
virtual RakNetGUID GetGuidFromSystemAddress( const SystemAddress input ) const=0;
/// Given the GUID of a connected system, give us the system address of that system.
/// The GUID will be the same on all systems connected to that instance of RakPeer, even if the external system addresses are different
/// Currently O(log(n)), but this may be improved in the future. If you use this frequently, you may want to cache the value as it won't change.
/// If \a input is UNASSIGNED_RAKNET_GUID, will return UNASSIGNED_SYSTEM_ADDRESS
/// \param[in] input The RakNetGUID of the system we are checking to see if we are connected to
virtual SystemAddress GetSystemAddressFromGuid( const RakNetGUID input ) const=0;
/// Set the time, in MS, to use before considering ourselves disconnected after not being able to deliver a reliable message.
/// Default time is 10,000 or 10 seconds in release and 30,000 or 30 seconds in debug.
/// \param[in] timeMS Time, in MS
/// \param[in] target Which system to do this for
/// \param[in] target Which system to do this for. Pass UNASSIGNED_SYSTEM_ADDRESS for all systems.
virtual void SetTimeoutTime( RakNetTime timeMS, const SystemAddress target )=0;
/// Set the MTU per datagram. It's important to set this correctly - otherwise packets will be needlessly split, decreasing performance and throughput.
@@ -332,9 +414,10 @@ public:
/// Recommended size is 1500
/// sa MTUSize.h
/// \param[in] size The MTU size
/// \param[in] target Which system to set this for. UNASSIGNED_SYSTEM_ADDRESS to set the default, for new systems
/// \pre Can only be called when not connected.
/// \return false on failure (we are connected), else true
virtual bool SetMTUSize( int size )=0;
virtual bool SetMTUSize( int size, const SystemAddress target=UNASSIGNED_SYSTEM_ADDRESS )=0;
/// Returns the current MTU size
/// \param[in] target Which system to get this for. UNASSIGNED_SYSTEM_ADDRESS to get the default
@@ -345,8 +428,15 @@ public:
virtual unsigned GetNumberOfAddresses( void )=0;
/// Returns an IP address at index 0 to GetNumberOfAddresses-1
/// \param[in] index index into the list of IP addresses
/// \return The local IP address at this index
virtual const char* GetLocalIP( unsigned int index )=0;
/// Is this a local IP?
/// \param[in] An IP address to check, excluding the port
/// \return True if this is one of the IP addresses returned by GetLocalIP
virtual bool IsLocalIP( const char *ip )=0;
/// Allow or disallow connection responses from any IP. Normally this should be false, but may be necessary
/// when connecting to servers with multiple IP addresses.
/// \param[in] allow - True to allow this behavior, false to not allow. Defaults to false. Value persists between connections
@@ -360,7 +450,8 @@ public:
/// \param[in] data Optional data to append to the packet.
/// \param[in] dataLength length of data in bytes. Use 0 if no data.
/// \param[in] connectionSocketIndex Index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to send on.
virtual void AdvertiseSystem( const char *host, unsigned short remotePort, const char *data, int dataLength, unsigned connectionSocketIndex=0 )=0;
/// \return false if IsActive()==false or the host is unresolvable. True otherwise
virtual bool AdvertiseSystem( const char *host, unsigned short remotePort, const char *data, int dataLength, unsigned connectionSocketIndex=0 )=0;
/// Controls how often to return ID_DOWNLOAD_PROGRESS for large message downloads.
/// ID_DOWNLOAD_PROGRESS is returned to indicate a new partial message chunk, roughly the MTU size, has arrived
@@ -369,16 +460,20 @@ public:
/// \param[in] interval How many messages to use as an interval
virtual void SetSplitMessageProgressInterval(int interval)=0;
/// Returns what was passed to SetSplitMessageProgressInterval()
/// \return What was passed to SetSplitMessageProgressInterval(). Default to 0.
virtual int GetSplitMessageProgressInterval(void) const=0;
/// Set how long to wait before giving up on sending an unreliable message
/// Useful if the network is clogged up.
/// Set to 0 or less to never timeout. Defaults to 0.
/// \param[in] timeoutMS How many ms to wait before simply not sending an unreliable message.
virtual void SetUnreliableTimeout(RakNetTime timeoutMS)=0;
/// Send a message to host, with the IP socket option TTL set to 1
/// Send a message to host, with the IP socket option TTL set to 3
/// This message will not reach the host, but will open the router.
/// Used for NAT-Punchthrough
virtual void SendTTL1( const char* host, unsigned short remotePort, unsigned connectionSocketIndex=0 )=0;
virtual void SendTTL( const char* host, unsigned short remotePort, int ttl, unsigned connectionSocketIndex=0 )=0;
// --------------------------------------------------------------------------------------------Compression Functions - Functions related to the compression layer--------------------------------------------------------------------------------------------
/// Enables or disables frequency table tracking. This is required to get a frequency table, which is used in GenerateCompressionLayer()
@@ -445,7 +540,7 @@ public:
// \param[in] routerInterface The router to use to route messages to systems not directly connected to this system.
virtual void RemoveRouterInterface( RouterInterface *routerInterface )=0;
/// \Returns a packet for you to write to if you want to create a Packet for some reason.
/// \returns a packet for you to write to if you want to create a Packet for some reason.
/// You can add it to the receive buffer with PushBackPacket
/// \param[in] dataSize How many bytes to allocate for the buffer
/// \return A packet you can write to
@@ -455,8 +550,10 @@ public:
/// Adds simulated ping and packet loss to the outgoing data flow.
/// To simulate bi-directional ping and packet loss, you should call this on both the sender and the recipient, with half the total ping and maxSendBPS value on each.
/// You can exclude network simulator code with the _RELEASE #define to decrease code size
/// \depreciated Use http://www.jenkinssoftware.com/raknet/forum/index.php?topic=1671.0 instead.
/// \param[in] maxSendBPS Maximum bits per second to send. Packetloss grows linearly. 0 to disable. (CURRENTLY BROKEN - ALWAYS DISABLED)
/// \param[in] minExtraPing The minimum time to delay sends.
/// \param[in] extraPingVariance The additional random time to delay sends.
virtual void ApplyNetworkSimulator( double maxSendBPS, unsigned short minExtraPing, unsigned short extraPingVariance)=0;
/// Limits how much outgoing bandwidth can be sent per-connection.
@@ -469,19 +566,37 @@ public:
/// \return If you previously called ApplyNetworkSimulator
virtual bool IsNetworkSimulatorActive( void )=0;
// -------------------------------------------------------------------------------------------- Socket Functions--------------------------------------------------------------------------------------------
/// Have RakNet use a socket you created yourself
/// The socket should not be in use - it is up to you to either shutdown or close the connections using it. Otherwise existing connections on that socket will eventually disconnect
/// This socket will be forgotten after calling Shutdown(), so rebind again if you need to.
/// \param[in] s The socket to rebind.
/// \param[in] haveRakNetCloseSocket If true, RakNet will call closeSocket on shutdown for this socket.
/// \param[in] connectionSocketIndex Index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to send on.
virtual void UseUserSocket( int socket, bool haveRakNetCloseSocket, unsigned connectionSocketIndex)=0;
/// Have RakNet recreate a socket using a different port.
/// The socket should not be in use - it is up to you to either shutdown or close the connections using it. Otherwise existing connections on that socket will eventually disconnect
/// \param[in] connectionSocketIndex Index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to send on.
/// \param[in] sd Address to bind on
virtual void RebindSocketAddress(unsigned connectionSocketIndex, SocketDescriptor &sd)=0;
// --------------------------------------------------------------------------------------------Statistical Functions - Functions dealing with API performance--------------------------------------------------------------------------------------------
/// Returns a structure containing a large set of network statistics for the specified system.
/// You can map this data to a string using the C style StatisticsToString() function
/// \param[in] systemAddress: Which connected system to get statistics for
/// \param[in] rns If you supply this structure, it will be written to it. Otherwise it will use a static struct, which is not threadsafe
/// \return 0 on can't find the specified system. A pointer to a set of data otherwise.
/// \sa RakNetStatistics.h
virtual RakNetStatistics * const GetStatistics( const SystemAddress systemAddress )=0;
virtual RakNetStatistics * const GetStatistics( const SystemAddress systemAddress, RakNetStatistics *rns=0 )=0;
// --------------------------------------------------------------------------------------------EVERYTHING AFTER THIS COMMENT IS FOR INTERNAL USE ONLY--------------------------------------------------------------------------------------------
/// \internal
virtual char *GetRPCString( const char *data, const unsigned int bitSize, const SystemAddress systemAddress)=0;
virtual char *GetRPCString( const char *data, const BitSize_t bitSize, const SystemAddress systemAddress)=0;
/// \internal
virtual bool SendOutOfBand(const char *host, unsigned short remotePort, MessageID header, const char *data, BitSize_t dataLength, unsigned connectionSocketIndex=0 )=0;
};
+3 -1
View File
@@ -1,6 +1,8 @@
#ifndef __RAK_SLEEP_H
#define __RAK_SLEEP_H
void RakSleep(unsigned int ms);
#include "Export.h"
void RAK_DLL_EXPORT RakSleep(unsigned int ms);
#endif
+231
View File
@@ -0,0 +1,231 @@
#ifndef __RAK_STRING_H
#define __RAK_STRING_H
#include "Export.h"
#include "DS_List.h"
#include "RakNetTypes.h" // int64_t
#include <stdio.h>
namespace RakNet
{
class BitStream;
/// \brief String class
/// Has the following improvements over std::string
/// Reference counting: Suitable to store in lists
/// Varidic assignment operator
/// Doesn't cause linker errors
class RAK_DLL_EXPORT RakString
{
public:
/// Constructors
RakString();
RakString(char input);
RakString(unsigned char input);
RakString(const unsigned char *format, ...);
RakString(const char *format, ...);
~RakString();
RakString( const RakString & rhs);
/// Implicit return of const char*
operator const char* () const {return sharedString->c_str;}
/// Same as std::string::c_str
const char *C_String(void) const {return sharedString->c_str;}
// Lets you modify the string. Do not make the string longer - however, you can make it shorter, or change the contents.
char *C_StringUnsafe(void) {Clone(); return sharedString->c_str;}
/// Assigment operators
RakString& operator = ( const RakString& rhs );
RakString& operator = ( const char *str );
RakString& operator = ( char *str );
RakString& operator = ( const char c );
/// Concatenation
RakString& operator +=( const RakString& rhs);
RakString& operator += ( const char *str );
RakString& operator += ( char *str );
RakString& operator += ( const char c );
/// Character index. Do not use to change the string however.
unsigned char operator[] ( const unsigned int position ) const;
/// Equality
bool operator==(const RakString &rhs) const;
bool operator==(const char *str) const;
bool operator==(char *str) const;
// Comparison
bool operator < ( const RakString& right ) const;
bool operator <= ( const RakString& right ) const;
bool operator > ( const RakString& right ) const;
bool operator >= ( const RakString& right ) const;
/// Inequality
bool operator!=(const RakString &rhs) const;
/// Change all characters to lowercase
const char * ToLower(void);
/// Change all characters to uppercase
const char * ToUpper(void);
/// Set the value of the string
void Set(const char *format, ...);
/// Returns if the string is empty. Also, C_String() would return ""
bool IsEmpty(void) const;
/// Returns the length of the string
size_t GetLength(void) const;
/// Replace character(s) in starting at index, for count, with c
void Replace(unsigned index, unsigned count, unsigned char c);
/// Replace character at index with c
void SetChar( unsigned index, unsigned char c );
/// Replace character at index with string s
void SetChar( unsigned index, RakNet::RakString s );
// Gets the substring starting at index for count characters
RakString SubStr(unsigned int index, unsigned int count) const;
/// Erase characters out of the string at index for count
void Erase(unsigned int index, unsigned int count);
/// Compare strings (case sensitive)
int StrCmp(const RakString &rhs) const;
/// Compare strings (not case sensitive)
int StrICmp(const RakString &rhs) const;
/// Clear the string
void Clear(void);
/// Print the string to the screen
void Printf(void);
/// Print the string to a file
void FPrintf(FILE *fp);
/// Does the given IP address match the IP address encoded into this string, accounting for wildcards?
bool IPAddressMatch(const char *IP);
/// Does the string contain non-printable characters other than spaces?
bool ContainsNonprintableExceptSpaces(void) const;
/// Is this a valid email address?
bool IsEmailAddress(void) const;
/// URL Encode the string. See http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4029/
void URLEncode(void);
/// RakString uses a freeList of old no-longer used strings
/// Call this function to clear this memory on shutdown
static void FreeMemory(void);
/// \internal
static void FreeMemoryNoMutex(void);
/// Serialize to a bitstream, uncompressed (slightly faster)
/// \param[out] bs Bitstream to serialize to
void Serialize(BitStream *bs);
/// Static version of the Serialize function
static void Serialize(const char *str, BitStream *bs);
/// Serialize to a bitstream, compressed (better bandwidth usage)
/// \param[out] bs Bitstream to serialize to
/// \param[in] languageId languageId to pass to the StringCompressor class
/// \param[in] writeLanguageId encode the languageId variable in the stream. If false, 0 is assumed, and DeserializeCompressed will not look for this variable in the stream (saves bandwidth)
/// \pre StringCompressor::AddReference must have been called to instantiate the class (Happens automatically from RakPeer::Startup())
void SerializeCompressed(BitStream *bs, int languageId=0, bool writeLanguageId=false);
/// Static version of the SerializeCompressed function
static void SerializeCompressed(const char *str, BitStream *bs, int languageId=0, bool writeLanguageId=false);
/// Deserialize what was written by Serialize
/// \param[in] bs Bitstream to serialize from
/// \return true if the deserialization was successful
bool Deserialize(BitStream *bs);
/// Static version of the Deserialize() function
static bool Deserialize(char *str, BitStream *bs);
/// Deserialize compressed string, written by SerializeCompressed
/// \param[in] bs Bitstream to serialize from
/// \param[in] readLanguageId If true, looks for the variable langaugeId in the data stream. Must match what was passed to SerializeCompressed
/// \return true if the deserialization was successful
/// \pre StringCompressor::AddReference must have been called to instantiate the class (Happens automatically from RakPeer::Startup())
bool DeserializeCompressed(BitStream *bs, bool readLanguageId=false);
/// Static version of the DeserializeCompressed() function
static bool DeserializeCompressed(char *str, BitStream *bs, bool readLanguageId=false);
static const char *ToString(int64_t i);
static const char *ToString(uint64_t i);
/// \internal
static size_t GetSizeToAllocate(size_t bytes)
{
const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
if (bytes<=smallStringSize)
return smallStringSize;
else
return bytes*2;
}
/// \internal
struct SharedString
{
unsigned int refCount;
size_t bytesUsed;
char *bigString;
char *c_str;
char smallString[128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2];
};
/// \internal
RakString( SharedString *_sharedString );
/// \internal
SharedString *sharedString;
// static SimpleMutex poolMutex;
// static DataStructures::MemoryPool<SharedString> pool;
/// \internal
static SharedString emptyString;
//static SharedString *sharedStringFreeList;
//static unsigned int sharedStringFreeListAllocationCount;
/// \internal
/// List of free objects to reduce memory reallocations
static DataStructures::List<SharedString*> freeList;
/// Means undefined position
static unsigned int nPos;
static int RakStringComp( RakString const &key, RakString const &data );
static void LockMutex(void);
static void UnlockMutex(void);
protected:
void Allocate(size_t len);
void Assign(const char *str);
void Clone(void);
void Free(void);
unsigned char ToLower(unsigned char c);
unsigned char ToUpper(unsigned char c);
void Realloc(SharedString *sharedString, size_t bytes);
};
}
const RakNet::RakString operator+(const RakNet::RakString &lhs, const RakNet::RakString &rhs);
#endif
+40
View File
@@ -0,0 +1,40 @@
#ifndef __RAK_THREAD_H
#define __RAK_THREAD_H
#if defined(_WIN32_WCE)
#include <windows.h>
#endif
namespace RakNet
{
/// To define a thread, use RAK_THREAD_DECLARATION(functionName);
#if defined(_WIN32_WCE)
#define RAK_THREAD_DECLARATION(functionName) DWORD WINAPI functionName(LPVOID arguments)
#elif defined(_WIN32)
#define RAK_THREAD_DECLARATION(functionName) unsigned __stdcall functionName( void* arguments )
#else
#define RAK_THREAD_DECLARATION(functionName) void* functionName( void* arguments )
#endif
class RakThread
{
public:
/// Create a thread, simplified to be cross platform without all the extra junk
/// To then start that thread, call RakCreateThread(functionName, arguments);
/// \param[in] start_address Function you want to call
/// \param[in] arglist Arguments to pass to the function
/// \return 0=success. >0 = error code
#if defined(_WIN32_WCE)
static int Create( LPTHREAD_START_ROUTINE start_address, void *arglist);
#elif defined(_WIN32)
static int Create( unsigned __stdcall start_address( void* ), void *arglist);
#else
static int Create( void* start_address( void* ), void *arglist);
#endif
};
}
#endif
+65
View File
@@ -0,0 +1,65 @@
/// \file
/// \brief \b [Internal] Random number generator
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAND_H
#define __RAND_H
#include "Export.h"
/// Initialise seed for Random Generator
/// \note not threadSafe, use an instance of RakNetRandom if necessary per thread
/// \param[in] seed The seed value for the random number generator.
extern void RAK_DLL_EXPORT seedMT( unsigned int seed );
/// \internal
/// \note not threadSafe, use an instance of RakNetRandom if necessary per thread
extern unsigned int RAK_DLL_EXPORT reloadMT( void );
/// Gets a random unsigned int
/// \note not threadSafe, use an instance of RakNetRandom if necessary per thread
/// \return an integer random value.
extern unsigned int RAK_DLL_EXPORT randomMT( void );
/// Gets a random float
/// \note not threadSafe, use an instance of RakNetRandom if necessary per thread
/// \return 0 to 1.0f, inclusive
extern float RAK_DLL_EXPORT frandomMT( void );
/// Randomizes a buffer
/// \note not threadSafe, use an instance of RakNetRandom if necessary per thread
extern void RAK_DLL_EXPORT fillBufferMT( void *buffer, unsigned int bytes );
// Same thing as above functions, but not global
class RAK_DLL_EXPORT RakNetRandom
{
public:
RakNetRandom();
~RakNetRandom();
void SeedMT( unsigned int seed );
unsigned int ReloadMT( void );
unsigned int RandomMT( void );
float FrandomMT( void );
void FillBufferMT( void *buffer, unsigned int bytes );
protected:
unsigned int state[ 624 + 1 ];
unsigned int *next;
int left;
};
#endif
+228
View File
@@ -0,0 +1,228 @@
/// \file
/// \brief Ready event plugin. This enables a set of systems to create a signal event, set this signal as ready or unready, and to trigger the event when all systems are ready
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __READY_EVENT_H
#define __READY_EVENT_H
class RakPeerInterface;
#include "PluginInterface.h"
#include "DS_OrderedList.h"
/// \defgroup READY_EVENT_GROUP ReadyEvent
/// \ingroup PLUGINS_GROUP
/// \ingroup READY_EVENT_GROUP
/// Returns the status of a remote system when querying with ReadyEvent::GetReadyStatus
enum ReadyEventSystemStatus
{
/// ----------- Normal states ---------------
/// The remote system is not in the wait list, and we have never gotten a ready or complete message from it.
/// This is the default state for valid events
RES_NOT_WAITING,
/// We are waiting for this remote system to call SetEvent(thisEvent,true).
RES_WAITING,
/// The remote system called SetEvent(thisEvent,true), but it still waiting for other systems before completing the ReadyEvent.
RES_READY,
/// The remote system called SetEvent(thisEvent,true), and is no longer waiting for any other systems.
/// This remote system has completed the ReadyEvent
RES_ALL_READY,
/// Error code, we couldn't look up the system because the event was unknown
RES_UNKNOWN_EVENT,
};
/// Ready event plugin
/// Used to signal event completion when a set of systems all set a signal flag to true.
/// This is usually used for lobby systems, or peer to peer turn based environments.
/// The user will get ID_READY_EVENT_SET and ID_READY_EVENT_UNSET as the signal flag is set or unset
/// The user will get ID_READY_EVENT_ALL_SET when all systems are done waiting for all other systems, in which case the event is considered complete, and no longer tracked.
/// \ingroup READY_EVENT_GROUP
class ReadyEvent : public PluginInterface
{
public:
/// Constructor
ReadyEvent();
/// Destructor
virtual ~ReadyEvent();
// --------------------------------------------------------------------------------------------
// User functions
// --------------------------------------------------------------------------------------------
/// Sets or updates the initial ready state for our local system.
/// If eventId is an unknown event the event is created.
/// If eventId was previously used and you want to reuse it, call DeleteEvent first, or else you will keep the same event signals from before
/// Systems previously or later added through AddToWaitList() with the same \a eventId when isReady=true will get ID_READY_EVENT_SET
/// Systems previously added through AddToWaitList with the same \a eventId will get ID_READY_EVENT_UNSET
/// For both ID_READY_EVENT_SET and ID_READY_EVENT_UNSET, eventId is encoded in bytes 1 through 1+sizeof(int)
/// \param[in] eventId A user-defined identifier to wait on. This can be a sequence counter, an event identifier, or anything else you want.
/// \param[in] isReady True to signal we are ready to proceed with this event, false to unsignal
/// \return True on success. False (failure) on unknown eventId
bool SetEvent(int eventId, bool isReady);
/// When systems can call SetEvent() with isReady==false, it is possible for one system to return true from IsEventCompleted() while the other systems return false
/// This can occur if a system SetEvent() with isReady==false while the completion message is still being transmitted.
/// If your game has the situation where some action should be taken on all systems when IsEventCompleted() is true for any system, then call ForceCompletion() when the action begins.
/// This will force all systems to return true from IsEventCompleted().
/// \param[in] eventId A user-defined identifier to immediately set as completed
bool ForceCompletion(int eventId);
/// Deletes an event. We will no longer wait for this event, and any systems that we know have set the event will be forgotten.
/// Call this to clear memory when events are completed and you know you will never need them again.
/// \param[in] eventId A user-defined identifier
/// \return True on success. False (failure) on unknown eventId
bool DeleteEvent(int eventId);
/// Returns what was passed to SetEvent()
/// \return The value of isReady passed to SetEvent(). Also returns false on unknown event.
bool IsEventSet(int eventId);
/// Returns if the event is about to be ready and we are negotiating the final packets.
/// This will usually only be true for a very short time, after which IsEventCompleted should return true.
/// While this is true you cannot add to the wait list, or SetEvent() isReady to false anymore.
/// \param[in] eventId A user-defined identifier
/// \return True if any other system has completed processing. Will always be true if IsEventCompleted() is true
bool IsEventCompletionProcessing(int eventId) const;
/// Returns if the wait list is a subset of the completion list.
/// Call this after all systems you want to wait for have been added with AddToWaitList
/// If you are waiting for a specific number of systems (such as players later connecting), also check GetRemoteWaitListSize(eventId) to be equal to 1 less than the total number of participants.
/// \param[in] eventId A user-defined identifier
/// \return True on completion. False (failure) on unknown eventId, or the set is not completed.
bool IsEventCompleted(int eventId) const;
/// Returns if this is a known event.
/// Events may be known even if we never ourselves referenced them with SetEvent, because other systems created them via ID_READY_EVENT_SET.
/// \param[in] eventId A user-defined identifier
/// \return true if we have this event, false otherwise
bool HasEvent(int eventId);
/// Returns the total number of events stored in the system.
/// \return The total number of events stored in the system.
unsigned GetEventListSize(void) const;
/// Returns the event ID stored at a particular index. EventIDs are stored sorted from least to greatest.
/// \param[in] index Index into the array, from 0 to GetEventListSize()
/// \return The event ID stored at a particular index
int GetEventAtIndex(unsigned index) const;
/// Adds a system to wait for to signal an event before considering the event complete and returning ID_READY_EVENT_ALL_SET.
/// As we add systems, if this event was previously set to true with SetEvent, these systems will get ID_READY_EVENT_SET.
/// As these systems disconnect (directly or indirectly through the router) they are removed.
/// \note If the event completion process has already started, you cannot add more systems, as this would cause the completion process to fail
/// \param[in] eventId A user-defined number previously passed to SetEvent that has not yet completed
/// \param[in] addressArray An address to wait for event replies from. Pass UNASSIGNED_SYSTEM_ADDRESS for all currently connected systems. Until all systems in this list have called SetEvent with this ID and true, and have this system in the list, we won't get ID_READY_EVENT_COMPLETE
/// \return True on success, false on unknown eventId (this should be considered an error), or if the completion process has already started.
bool AddToWaitList(int eventId, SystemAddress address);
/// Removes systems from the wait list, which should have been previously added with AddToWaitList
/// \note Systems that directly or indirectly disconnect from us are automatically removed from the wait list
/// \param[in] address The system to remove from the wait list. Pass UNASSIGNED_SYSTEM_ADDRESS for all currently connected systems.
/// \return True on success, false on unknown eventId (this should be considered an error)
bool RemoveFromWaitList(int eventId, SystemAddress address);
/// Returns if a particular system is waiting on a particular event.
/// \param[in] eventId A user-defined identifier
/// \param[in] The address of the system we are checking up on
/// \return True if this system is waiting on this event, false otherwise.
bool IsInWaitList(int eventId, SystemAddress address);
/// Returns the total number of systems we are waiting on for this event.
/// Does not include yourself
/// \param[in] eventId A user-defined identifier
/// \return The total number of systems we are waiting on for this event.
unsigned GetRemoteWaitListSize(int eventId) const;
/// Returns the system address of a system at a particular index, for this event.
/// \param[in] eventId A user-defined identifier
/// \param[in] index Index into the array, from 0 to GetWaitListSize()
/// \return The system address of a system at a particular index, for this event.
SystemAddress GetFromWaitListAtIndex(int eventId, unsigned index) const;
/// For a remote system, find out what their ready status is (waiting, signaled, complete).
/// \param[in] eventId A user-defined identifier
/// \param[in] address Which system we are checking up on
/// \return The status of this system, for this particular event. \sa ReadyEventSystemStatus
ReadyEventSystemStatus GetReadyStatus(int eventId, SystemAddress address);
/// This channel will be used for all RakPeer::Send calls
/// \param[in] newChannel The channel to use for internal RakPeer::Send calls from this system. Defaults to 0.
void SetSendChannel(unsigned char newChannel);
// ---------------------------- ALL INTERNAL AFTER HERE ----------------------------
/// \internal
/// Status of a remote system
struct RemoteSystem
{
MessageID lastSentStatus, lastReceivedStatus;
SystemAddress systemAddress;
};
static int RemoteSystemCompBySystemAddress( const SystemAddress &key, const RemoteSystem &data );
/// \internal
/// An event, with a set of systems we are waiting for, a set of systems that are signaled, and a set of systems with completed events
struct ReadyEventNode
{
int eventId; // Sorted on this
MessageID eventStatus;
DataStructures::OrderedList<SystemAddress,RemoteSystem,ReadyEvent::RemoteSystemCompBySystemAddress> systemList;
};
static int ReadyEventNodeComp( const int &key, ReadyEvent::ReadyEventNode * const &data );
protected:
// --------------------------------------------------------------------------------------------
// Packet handling functions
// --------------------------------------------------------------------------------------------
void OnAttach(RakPeerInterface *peer);
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
virtual void OnShutdown(RakPeerInterface *peer);
void Clear(void);
/*
bool AnyWaitersCompleted(unsigned eventIndex) const;
bool AllWaitersCompleted(unsigned eventIndex) const;
bool AllWaitersReady(unsigned eventIndex) const;
void SendAllReady(unsigned eventId, SystemAddress address);
void BroadcastAllReady(unsigned eventIndex);
void SendReadyStateQuery(unsigned eventId, SystemAddress address);
void BroadcastReadyUpdate(unsigned eventIndex);
bool AddToWaitListInternal(unsigned eventIndex, SystemAddress address);
bool IsLocked(unsigned eventIndex) const;
bool IsAllReadyByIndex(unsigned eventIndex) const;
*/
void SendReadyStateQuery(unsigned eventId, SystemAddress address);
void SendReadyUpdate(unsigned eventIndex, unsigned systemIndex, bool forceIfNotDefault);
void BroadcastReadyUpdate(unsigned eventIndex, bool forceIfNotDefault);
void RemoveFromAllLists(SystemAddress address);
void OnReadyEventQuery(RakPeerInterface *peer, Packet *packet);
void PushCompletionPacket(unsigned eventId);
bool AddToWaitListInternal(unsigned eventIndex, SystemAddress address);
void OnReadyEventForceAllSet(RakPeerInterface *peer, Packet *packet);
void OnReadyEventPacketUpdate(RakPeerInterface *peer, Packet *packet);
void UpdateReadyStatus(unsigned eventIndex);
bool IsEventCompletedByIndex(unsigned eventIndex) const;
unsigned CreateEvent(int eventId, bool isReady);
bool SetEventByIndex(int eventIndex, bool isReady);
DataStructures::OrderedList<int, ReadyEventNode*, ReadyEvent::ReadyEventNodeComp> readyEventNodeList;
unsigned char channel;
RakPeerInterface *rakPeer;
};
#endif
+34
View File
@@ -0,0 +1,34 @@
/// \file
/// \brief \b Reference counted object. Very simple class for quick and dirty uses.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __REF_COUNTED_OBJ_H
#define __REF_COUNTED_OBJ_H
#include "RakMemoryOverride.h"
/// World's simplest class :)
class RefCountedObj
{
public:
RefCountedObj() {refCount=1;}
virtual ~RefCountedObj() {}
void AddRef(void) {refCount++;}
void Deref(void) {if (--refCount==0) RakNet::OP_DELETE(this);}
int refCount;
};
#endif
+378
View File
@@ -0,0 +1,378 @@
/// \file
/// \brief \b [Internal] Datagram reliable, ordered, unordered and sequenced sends. Flow control. Message splitting, reassembly, and coalescence.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RELIABILITY_LAYER_H
#define __RELIABILITY_LAYER_H
#include "RakMemoryOverride.h"
#include "MTUSize.h"
#include "DS_LinkedList.h"
#include "DS_List.h"
#include "SocketLayer.h"
#include "PacketPriority.h"
#include "DS_Queue.h"
#include "BitStream.h"
#include "InternalPacket.h"
#include "DataBlockEncryptor.h"
#include "RakNetStatistics.h"
#include "SHA1.h"
#include "DS_OrderedList.h"
#include "DS_RangeList.h"
#include "DS_BPlusTree.h"
#include "DS_MemoryPool.h"
class PluginInterface;
class RakNetRandom;
/// Sizeof an UDP header in byte
#define UDP_HEADER_SIZE 28
/// Number of ordered streams available. You can use up to 32 ordered streams
#define NUMBER_OF_ORDERED_STREAMS 32 // 2^5
#define RESEND_TREE_ORDER 32
#include "BitStream.h"
int SplitPacketIndexComp( SplitPacketIndexType const &key, InternalPacket* const &data );
struct SplitPacketChannel//<SplitPacketChannel>
{
RakNetTimeNS lastUpdateTime;
DataStructures::OrderedList<SplitPacketIndexType, InternalPacket*, SplitPacketIndexComp> splitPacketList;
};
int RAK_DLL_EXPORT SplitPacketChannelComp( SplitPacketIdType const &key, SplitPacketChannel* const &data );
/// Datagram reliable, ordered, unordered and sequenced sends. Flow control. Message splitting, reassembly, and coalescence.
class ReliabilityLayer//<ReliabilityLayer>
{
public:
/// Constructor
ReliabilityLayer();
/// Destructor
~ReliabilityLayer();
/// Resets the layer for reuse
void Reset( bool resetVariables );
///Sets the encryption key. Doing so will activate secure connections
/// \param[in] key Byte stream for the encryption key
void SetEncryptionKey( const unsigned char *key );
/// Set the time, in MS, to use before considering ourselves disconnected after not being able to deliver a reliable packet
/// Default time is 10,000 or 10 seconds in release and 30,000 or 30 seconds in debug.
/// \param[in] time Time, in MS
void SetTimeoutTime( RakNetTime time );
/// Returns the value passed to SetTimeoutTime. or the default if it was never called
/// \param[out] the value passed to SetTimeoutTime
RakNetTime GetTimeoutTime(void);
/// Packets are read directly from the socket layer and skip the reliability layer because unconnected players do not use the reliability layer
/// This function takes packet data after a player has been confirmed as connected.
/// \param[in] buffer The socket data
/// \param[in] length The length of the socket data
/// \param[in] systemAddress The player that this data is from
/// \param[in] messageHandlerList A list of registered plugins
/// \param[in] MTUSize maximum datagram size
/// \retval true Success
/// \retval false Modified packet
bool HandleSocketReceiveFromConnectedPlayer( const char *buffer, unsigned int length, SystemAddress systemAddress, DataStructures::List<PluginInterface*> &messageHandlerList, int MTUSize );
/// This allocates bytes and writes a user-level message to those bytes.
/// \param[out] data The message
/// \return Returns number of BITS put into the buffer
BitSize_t Receive( unsigned char**data );
/// Puts data on the send queue
/// \param[in] data The data to send
/// \param[in] numberOfBitsToSend The length of \a data in bits
/// \param[in] priority The priority level for the send
/// \param[in] reliability The reliability type for the send
/// \param[in] orderingChannel 0 to 31. Specifies what channel to use, for relational ordering and sequencing of packets.
/// \param[in] makeDataCopy If true \a data will be copied. Otherwise, only a pointer will be stored.
/// \param[in] MTUSize maximum datagram size
/// \param[in] currentTime Current time, as per RakNet::GetTime()
/// \return True or false for success or failure.
bool Send( char *data, BitSize_t numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, unsigned char orderingChannel, bool makeDataCopy, int MTUSize, RakNetTimeNS currentTime );
/// Call once per game cycle. Handles internal lists and actually does the send.
/// \param[in] s the communication end point
/// \param[in] systemAddress The Unique Player Identifier who shouldhave sent some packets
/// \param[in] MTUSize maximum datagram size
/// \param[in] time current system time
/// \param[in] maxBitsPerSecond if non-zero, enforces that outgoing bandwidth does not exceed this amount
/// \param[in] messageHandlerList A list of registered plugins
void Update( SOCKET s, SystemAddress systemAddress, int MTUSize, RakNetTimeNS time, unsigned maxBitsPerSecond, DataStructures::List<PluginInterface*> &messageHandlerList, RakNetRandom *rnr, bool isPS3LobbySocket );
/// If Read returns -1 and this returns true then a modified packetwas detected
/// \return true when a modified packet is detected
bool IsCheater( void ) const;
/// Were you ever unable to deliver a packet despite retries?
/// \return true means the connection has been lost. Otherwise not.
bool IsDeadConnection( void ) const;
/// Causes IsDeadConnection to return true
void KillConnection(void);
/// Get Statistics
/// \return A pointer to a static struct, filled out with current statistical information.
RakNetStatistics * const GetStatistics( RakNetStatistics *rns );
///Are we waiting for any data to be sent out or be processed by the player?
bool IsOutgoingDataWaiting(void);
bool IsReliableOutgoingDataWaiting(void);
bool AreAcksWaiting(void);
// Set outgoing lag and packet loss properties
void ApplyNetworkSimulator( double _maxSendBPS, RakNetTime _minExtraPing, RakNetTime _extraPingVariance );
/// Returns if you previously called ApplyNetworkSimulator
/// \return If you previously called ApplyNetworkSimulator
bool IsNetworkSimulatorActive( void );
void SetSplitMessageProgressInterval(int interval);
void SetUnreliableTimeout(RakNetTime timeoutMS);
/// Has a lot of time passed since the last ack
bool AckTimeout(RakNetTimeNS curTime);
RakNetTimeNS GetNextSendTime(void) const;
RakNetTimeNS GetTimeBetweenPackets(void) const;
RakNetTimeNS GetLastTimeBetweenPacketsDecrease(void) const;
RakNetTimeNS GetLastTimeBetweenPacketsIncrease(void) const;
RakNetTimeNS GetAckPing(void) const;
// If true, will update time between packets quickly based on ping calculations
//void SetDoFastThroughputReactions(bool fast);
// Encoded as numMessages[unsigned int], message1BitLength[unsigned int], message1Data (aligned), ...
//void GetUndeliveredMessages(RakNet::BitStream *messages, int MTUSize);
private:
/// Generates a datagram (coalesced packets)
/// \param[out] output The resulting BitStream
/// \param[in] Current MTU size
/// \param[out] reliableDataSent Set to true or false as a return value as to if reliable data was sent.
/// \param[in] time Current time
/// \param[in] systemAddress Who we are sending to
/// \param[in] messageHandlerList A list of registered plugins
/// \return If any data was sent
bool GenerateDatagram( RakNet::BitStream *output, int MTUSize, bool *reliableDataSent, RakNetTimeNS time, SystemAddress systemAddress, bool *hitMTUCap, DataStructures::List<PluginInterface*> &messageHandlerList );
/// Send the contents of a bitstream to the socket
/// \param[in] s The socket used for sending data
/// \param[in] systemAddress The address and port to send to
/// \param[in] bitStream The data to send.
void SendBitStream( SOCKET s, SystemAddress systemAddress, RakNet::BitStream *bitStream, RakNetRandom *rnr, bool isPS3LobbySocket);
///Parse an internalPacket and create a bitstream to represent this data
/// \return Returns number of bits used
BitSize_t WriteToBitStreamFromInternalPacket( RakNet::BitStream *bitStream, const InternalPacket *const internalPacket, RakNetTimeNS curTime );
/// Parse a bitstream and create an internal packet to represent this data
InternalPacket* CreateInternalPacketFromBitStream( RakNet::BitStream *bitStream, RakNetTimeNS time );
/// Does what the function name says
unsigned RemovePacketFromResendListAndDeleteOlderReliableSequenced( const MessageNumberType messageNumber, RakNetTimeNS time );
/// Acknowledge receipt of the packet with the specified messageNumber
void SendAcknowledgementPacket( const MessageNumberType messageNumber, RakNetTimeNS time );
/// This will return true if we should not send at this time
bool IsSendThrottled( int MTUSize );
/// We lost a packet
void UpdateWindowFromPacketloss( RakNetTimeNS time );
/// Increase the window size
void UpdateWindowFromAck( RakNetTimeNS time );
/// Parse an internalPacket and figure out how many header bits would be written. Returns that number
int GetBitStreamHeaderLength( const InternalPacket *const internalPacket );
/// Get the SHA1 code
void GetSHA1( unsigned char * const buffer, unsigned int nbytes, char code[ SHA1_LENGTH ] );
/// Check the SHA1 code
bool CheckSHA1( char code[ SHA1_LENGTH ], unsigned char * const buffer, unsigned int nbytes );
/// Search the specified list for sequenced packets on the specified ordering channel, optionally skipping those with splitPacketId, and delete them
void DeleteSequencedPacketsInList( unsigned char orderingChannel, DataStructures::List<InternalPacket*>&theList, int splitPacketId = -1 );
/// Search the specified list for sequenced packets with a value less than orderingIndex and delete them
void DeleteSequencedPacketsInList( unsigned char orderingChannel, DataStructures::Queue<InternalPacket*>&theList );
/// Returns true if newPacketOrderingIndex is older than the waitingForPacketOrderingIndex
bool IsOlderOrderedPacket( OrderingIndexType newPacketOrderingIndex, OrderingIndexType waitingForPacketOrderingIndex );
/// Split the passed packet into chunks under MTU_SIZE bytes (including headers) and save those new chunks
void SplitPacket( InternalPacket *internalPacket, int MTUSize );
/// Insert a packet into the split packet list
void InsertIntoSplitPacketList( InternalPacket * internalPacket, RakNetTimeNS time );
/// Take all split chunks with the specified splitPacketId and try to reconstruct a packet. If we can, allocate and return it. Otherwise return 0
InternalPacket * BuildPacketFromSplitPacketList( SplitPacketIdType splitPacketId, RakNetTimeNS time );
/// Delete any unreliable split packets that have long since expired
void DeleteOldUnreliableSplitPackets( RakNetTimeNS time );
/// Creates a copy of the specified internal packet with data copied from the original starting at dataByteOffset for dataByteLength bytes.
/// Does not copy any split data parameters as that information is always generated does not have any reason to be copied
InternalPacket * CreateInternalPacketCopy( InternalPacket *original, int dataByteOffset, int dataByteLength, RakNetTimeNS time );
/// Get the specified ordering list
DataStructures::LinkedList<InternalPacket*> *GetOrderingListAtOrderingStream( unsigned char orderingChannel );
/// Add the internal packet to the ordering list in order based on order index
void AddToOrderingList( InternalPacket * internalPacket );
/// Inserts a packet into the resend list in order
void InsertPacketIntoResendList( InternalPacket *internalPacket, RakNetTimeNS time, bool makeCopyOfInternalPacket, bool firstResend );
/// Memory handling
void FreeMemory( bool freeAllImmediately );
/// Memory handling
void FreeThreadedMemory( void );
/// Memory handling
void FreeThreadSafeMemory( void );
// Initialize the variables
void InitializeVariables( void );
/// Given the current time, is this time so old that we should consider it a timeout?
bool IsExpiredTime(unsigned int input, RakNetTimeNS currentTime) const;
// Make it so we don't do resends within a minimum threshold of time
void UpdateNextActionTime(void);
/// Does this packet number represent a packet that was skipped (out of order?)
//unsigned int IsReceivedPacketHole(unsigned int input, RakNetTime currentTime) const;
/// Skip an element in the received packets list
//unsigned int MakeReceivedPacketHole(unsigned int input) const;
/// How many elements are waiting to be resent?
unsigned int GetResendListDataSize(void) const;
/// Update all memory which is not threadsafe
void UpdateThreadedMemory(void);
void CalculateHistogramAckSize(void);
// Used ONLY for RELIABLE_ORDERED
// RELIABLE_SEQUENCED just returns the newest one
DataStructures::List<DataStructures::LinkedList<InternalPacket*>*> orderingList;
DataStructures::Queue<InternalPacket*> outputQueue;
DataStructures::RangeList<MessageNumberType> acknowlegements;
int splitMessageProgressInterval;
RakNetTimeNS unreliableTimeout;
// Resend list is a tree of packets we need to resend
DataStructures::BPlusTree<MessageNumberType, InternalPacket*, RESEND_TREE_ORDER> resendList;
// resend Queue holds the same pointers, but in order of when to send them. nextActionTime is set to 0 when the packet is no longer needed.
DataStructures::Queue<InternalPacket*> resendQueue;
DataStructures::Queue<InternalPacket*> sendPacketSet[ NUMBER_OF_PRIORITIES ];
DataStructures::OrderedList<SplitPacketIdType, SplitPacketChannel*, SplitPacketChannelComp> splitPacketChannelList;
MessageNumberType sendMessageNumberIndex, internalOrderIndex;
//unsigned int windowSize;
RakNetTimeNS lastAckTime;
RakNet::BitStream updateBitStream;
OrderingIndexType waitingForOrderedPacketWriteIndex[ NUMBER_OF_ORDERED_STREAMS ], waitingForSequencedPacketWriteIndex[ NUMBER_OF_ORDERED_STREAMS ];
// STUFF TO NOT MUTEX HERE (called from non-conflicting threads, or value is not important)
OrderingIndexType waitingForOrderedPacketReadIndex[ NUMBER_OF_ORDERED_STREAMS ], waitingForSequencedPacketReadIndex[ NUMBER_OF_ORDERED_STREAMS ];
bool deadConnection, cheater;
// unsigned int lastPacketSendTime,retransmittedFrames, sentPackets, sentFrames, receivedPacketsCount, bytesSent, bytesReceived,lastPacketReceivedTime;
SplitPacketIdType splitPacketId;
RakNetTime timeoutTime; // How long to wait in MS before timing someone out
//int MAX_AVERAGE_PACKETS_PER_SECOND; // Name says it all
// int RECEIVED_PACKET_LOG_LENGTH, requestedReceivedPacketLogLength; // How big the receivedPackets array is
// unsigned int *receivedPackets;
unsigned int blockWindowIncreaseUntilTime;
RakNetStatistics statistics;
RakNetTimeNS histogramStart;
unsigned histogramBitsSent;
/// Memory-efficient receivedPackets algorithm:
/// receivedPacketsBaseIndex is the packet number we are expecting
/// Everything under receivedPacketsBaseIndex is a packet we already got
/// Everything over receivedPacketsBaseIndex is stored in hasReceivedPacketQueue
/// It stores the time to stop waiting for a particular packet number, where the packet number is receivedPacketsBaseIndex + the index into the queue
/// If 0, we got got that packet. Otherwise, the time to give up waiting for that packet.
/// If we get a packet number where (receivedPacketsBaseIndex-packetNumber) is less than half the range of receivedPacketsBaseIndex then it is a duplicate
/// Otherwise, it is a duplicate packet (and ignore it).
DataStructures::Queue<RakNetTimeNS> hasReceivedPacketQueue;
MessageNumberType receivedPacketsBaseIndex;
bool resetReceivedPackets;
RakNetTimeNS lastUpdateTime;
RakNetTimeNS timeBetweenPackets, nextSendTime, ackPing;
RakNetTimeNS ackPingSamples[256]; // Must be range of unsigned char to wrap ackPingIndex properly
RakNetTimeNS ackPingSum;
unsigned char ackPingIndex;
//RakNetTimeNS nextLowestPingReset;
RemoteSystemTimeType remoteSystemTime;
bool continuousSend;
RakNetTimeNS lastTimeBetweenPacketsIncrease,lastTimeBetweenPacketsDecrease;
// Limit changes in throughput to once per ping - otherwise even if lag starts we don't know about it
// In the meantime the connection is flooded and overrun.
RakNetTimeNS nextAllowedThroughputSample;
// If Update::maxBitsPerSecond > 0, then throughputCapCountdown is used as a timer to prevent sends for some amount of time after each send, depending on
// the amount of data sent
long long throughputCapCountdown;
DataBlockEncryptor encryptor;
unsigned sendPacketCount, receivePacketCount;
///This variable is so that free memory can be called by only the update thread so we don't have to mutex things so much
bool freeThreadedMemoryOnNextUpdate;
// If we backoff due to packetloss, don't remeasure until all waiting resends have gone out or else we overcount
bool packetlossThisSample, backoffThisSample;
unsigned packetlossThisSampleResendCount;
RakNetTimeNS lastPacketlossTime;
//long double timeBetweenPacketsIncreaseMultiplier, timeBetweenPacketsDecreaseMultiplier;
#ifndef _RELEASE
struct DataAndTime//<InternalPacket>
{
char data[ MAXIMUM_MTU_SIZE ];
unsigned int length;
RakNetTimeNS sendTime;
};
DataStructures::List<DataAndTime*> delayList;
// Internet simulator
double maxSendBPS;
RakNetTime minExtraPing, extraPingVariance;
#endif
// This has to be a member because it's not threadsafe when I removed the mutexes
DataStructures::MemoryPool<InternalPacket> internalPacketPool;
};
#endif

Some files were not shown because too many files have changed in this diff Show More