Init
This commit is contained in:
28
Source/include/slikenet/AutopatcherPatchContext.h
Normal file
28
Source/include/slikenet/AutopatcherPatchContext.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AUTOPATCHER_PATCH_CONTEXT_H
|
||||
#define __AUTOPATCHER_PATCH_CONTEXT_H
|
||||
|
||||
enum PatchContext
|
||||
{
|
||||
PC_HASH_1_WITH_PATCH,
|
||||
PC_HASH_2_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
|
||||
82
Source/include/slikenet/AutopatcherRepositoryInterface.h
Normal file
82
Source/include/slikenet/AutopatcherRepositoryInterface.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
///
|
||||
/// \file AutopatcherRepositoryInterface.h
|
||||
/// \brief An interface used by AutopatcherServer to get the data necessary to run an autopatcher.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __AUTOPATCHER_REPOSITORY_INTERFACE_H
|
||||
#define __AUTOPATCHER_REPOSITORY_INTERFACE_H
|
||||
|
||||
#include "IncrementalReadInterface.h"
|
||||
#include "SimpleMutex.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class FileList;
|
||||
class BitStream;
|
||||
|
||||
/// 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 *addedOrModifiedFilesWithHashData, FileList *deletedFiles, double sinceDate)=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 1 on success, 0 on database failure, -1 on tried to download original unmodified file
|
||||
virtual int GetPatches(const char *applicationName, FileList *input, bool allowDownloadOfOriginalUnmodifiedFiles, FileList *patchList)=0;
|
||||
|
||||
/// For the most recent update, return files that were patched, added, or deleted. For files that were patched, return both the patch in \a patchedFiles and the current version in \a updatedFiles
|
||||
/// \param[in,out] applicationName Name of the application to get patches for. If empty, uses the most recently updated application, and the string will be updated to reflect this name.
|
||||
/// \param[out] patchedFiles A list of patched files with op PC_HASH_2_WITH_PATCH. It has 2 hashes, the priorHash and the currentHash. The currentHash is checked on the client after patching for patch success. The priorHash is checked in AutopatcherServer::OnGetPatch() to see if the client is able to hash with the version they currently have
|
||||
/// \param[out] patchedFiles A list of new files. It contains the actual data in addition to the filename
|
||||
/// \param[out] addedOrModifiedFileHashes A list of file hashes that were either modified or new. This is returned to the client when replying to ID_AUTOPATCHER_CREATION_LIST, which tells the client what files have changed on the server since a certain date
|
||||
/// \param[out] deletedFiles A list of the current versions of filenames that were deleted in the most recent patch
|
||||
/// \param[out] whenPatched time in seconds since epoch when patched. Use time() function to get this in C
|
||||
/// \return true on success, false on failure
|
||||
virtual bool GetMostRecentChangelistWithPatches(
|
||||
SLNet::RakString &applicationName,
|
||||
FileList *patchedFiles,
|
||||
FileList *updatedFiles,
|
||||
FileList *addedOrModifiedFileHashes,
|
||||
FileList *deletedFiles,
|
||||
double *priorRowPatchTime,
|
||||
double *mostRecentRowPatchTime)=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;
|
||||
|
||||
/// \return Passed to FileListTransfer::Send() as the _chunkSize parameter.
|
||||
virtual const int GetIncrementalReadChunkSize(void) const=0;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
26
Source/include/slikenet/Base64Encoder.h
Normal file
26
Source/include/slikenet/Base64Encoder.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BASE_64_ENCODER_H
|
||||
#define __BASE_64_ENCODER_H
|
||||
|
||||
#include "Export.h"
|
||||
|
||||
extern "C" {
|
||||
/// \brief Returns how many bytes were written.
|
||||
// outputData should be at least the size of inputData * 2 + 6
|
||||
int Base64Encoding(const unsigned char *inputData, int dataLength, char *outputData);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
const char *Base64Map(void);
|
||||
}
|
||||
|
||||
#endif
|
||||
1885
Source/include/slikenet/BitStream.h
Normal file
1885
Source/include/slikenet/BitStream.h
Normal file
File diff suppressed because it is too large
Load Diff
225
Source/include/slikenet/CCRakNetSlidingWindow.h
Normal file
225
Source/include/slikenet/CCRakNetSlidingWindow.h
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html
|
||||
|
||||
cwnd=max bytes allowed on wire at once
|
||||
|
||||
Start:
|
||||
cwnd=mtu
|
||||
ssthresh=unlimited
|
||||
|
||||
Slow start:
|
||||
On ack cwnd*=2
|
||||
|
||||
congestion avoidance:
|
||||
On ack during new period
|
||||
cwnd+=mtu*mtu/cwnd
|
||||
|
||||
on loss or duplicate ack during period:
|
||||
sshtresh=cwnd/2
|
||||
cwnd=MTU
|
||||
This reenters slow start
|
||||
|
||||
If cwnd < ssthresh, then use slow start
|
||||
else use congestion avoidance
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL==1
|
||||
|
||||
#ifndef __CONGESTION_CONTROL_SLIDING_WINDOW_H
|
||||
#define __CONGESTION_CONTROL_SLIDING_WINDOW_H
|
||||
|
||||
#include "NativeTypes.h"
|
||||
#include "time.h"
|
||||
#include "types.h"
|
||||
#include "DS_Queue.h"
|
||||
|
||||
/// Sizeof an UDP header in byte
|
||||
#define UDP_HEADER_SIZE 28
|
||||
|
||||
#define CC_DEBUG_PRINTF_1(x)
|
||||
#define CC_DEBUG_PRINTF_2(x,y)
|
||||
#define CC_DEBUG_PRINTF_3(x,y,z)
|
||||
#define CC_DEBUG_PRINTF_4(x,y,z,a)
|
||||
#define CC_DEBUG_PRINTF_5(x,y,z,a,b)
|
||||
//#define CC_DEBUG_PRINTF_1(x) printf(x)
|
||||
//#define CC_DEBUG_PRINTF_2(x,y) printf(x,y)
|
||||
//#define CC_DEBUG_PRINTF_3(x,y,z) printf(x,y,z)
|
||||
//#define CC_DEBUG_PRINTF_4(x,y,z,a) printf(x,y,z,a)
|
||||
//#define CC_DEBUG_PRINTF_5(x,y,z,a,b) printf(x,y,z,a,b)
|
||||
|
||||
/// Set to 4 if you are using the iPod Touch TG. See http://www.jenkinssoftware.com/forum/index.php?topic=2717.0
|
||||
#define CC_TIME_TYPE_BYTES 8
|
||||
|
||||
#if CC_TIME_TYPE_BYTES==8
|
||||
typedef SLNet::TimeUS CCTimeType;
|
||||
#else
|
||||
typedef SLNet::TimeMS CCTimeType;
|
||||
#endif
|
||||
|
||||
typedef SLNet::uint24_t DatagramSequenceNumberType;
|
||||
typedef double BytesPerMicrosecond;
|
||||
typedef double BytesPerSecond;
|
||||
typedef double MicrosecondsPerByte;
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
class CCRakNetSlidingWindow
|
||||
{
|
||||
public:
|
||||
|
||||
CCRakNetSlidingWindow();
|
||||
~CCRakNetSlidingWindow();
|
||||
|
||||
/// Reset all variables to their initial states, for a new connection
|
||||
void Init(CCTimeType curTime, uint32_t maxDatagramPayload);
|
||||
|
||||
/// Update over time
|
||||
void Update(CCTimeType curTime, bool hasDataToSendOrResend);
|
||||
|
||||
int GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
|
||||
int GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
|
||||
|
||||
/// Acks do not have to be sent immediately. Instead, they can be buffered up such that groups of acks are sent at a time
|
||||
/// This reduces overall bandwidth usage
|
||||
/// How long they can be buffered depends on the retransmit time of the sender
|
||||
/// Should call once per update tick, and send if needed
|
||||
bool ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick);
|
||||
|
||||
/// Every data packet sent must contain a sequence number
|
||||
/// Call this function to get it. The sequence number is passed into OnGotPacketPair()
|
||||
DatagramSequenceNumberType GetAndIncrementNextDatagramSequenceNumber(void);
|
||||
DatagramSequenceNumberType GetNextDatagramSequenceNumber(void);
|
||||
|
||||
/// Call this when you send packets
|
||||
/// Every 15th and 16th packets should be sent as a packet pair if possible
|
||||
/// When packets marked as a packet pair arrive, pass to OnGotPacketPair()
|
||||
/// When any packets arrive, (additionally) pass to OnGotPacket
|
||||
/// Packets should contain our system time, so we can pass rtt to OnNonDuplicateAck()
|
||||
void OnSendBytes(CCTimeType curTime, uint32_t numBytes);
|
||||
|
||||
/// Call this when you get a packet pair
|
||||
void OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime);
|
||||
|
||||
/// Call this when you get a packet (including packet pairs)
|
||||
/// If the DatagramSequenceNumberType is out of order, skippedMessageCount will be non-zero
|
||||
/// In that case, send a NAK for every sequence number up to that count
|
||||
bool OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount);
|
||||
|
||||
/// Call when you get a NAK, with the sequence number of the lost message
|
||||
/// Affects the congestion control
|
||||
void OnResend(CCTimeType curTime, SLNet::TimeUS nextActionTime);
|
||||
void OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber);
|
||||
|
||||
/// Call this when an ACK arrives.
|
||||
/// hasBAndAS are possibly written with the ack, see OnSendAck()
|
||||
/// B and AS are used in the calculations in UpdateWindowSizeAndAckOnAckPerSyn
|
||||
/// B and AS are updated at most once per SYN
|
||||
void OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber );
|
||||
void OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber );
|
||||
|
||||
/// Call when you send an ack, to see if the ack should have the B and AS parameters transmitted
|
||||
/// Call before calling OnSendAck()
|
||||
void OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS);
|
||||
|
||||
/// Call when we send an ack, to write B and AS if needed
|
||||
/// B and AS are only written once per SYN, to prevent slow calculations
|
||||
/// Also updates SND, the period between sends, since data is written out
|
||||
/// Be sure to call OnSendAckGetBAndAS() before calling OnSendAck(), since whether you write it or not affects \a numBytes
|
||||
void OnSendAck(CCTimeType curTime, uint32_t numBytes);
|
||||
|
||||
/// Call when we send a NACK
|
||||
/// Also updates SND, the period between sends, since data is written out
|
||||
void OnSendNACK(CCTimeType curTime, uint32_t numBytes);
|
||||
|
||||
/// Retransmission time out for the sender
|
||||
/// If the time difference between when a message was last transmitted, and the current time is greater than RTO then packet is eligible for retransmission, pending congestion control
|
||||
/// RTO = (RTT + 4 * RTTVar) + SYN
|
||||
/// If we have been continuously sending for the last RTO, and no ACK or NAK at all, SND*=2;
|
||||
/// This is per message, which is different from UDT, but RakNet supports packetloss with continuing data where UDT is only RELIABLE_ORDERED
|
||||
/// Minimum value is 100 milliseconds
|
||||
CCTimeType GetRTOForRetransmission(unsigned char timesSent) const;
|
||||
|
||||
/// Set the maximum amount of data that can be sent in one datagram
|
||||
/// Default to MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE
|
||||
void SetMTU(uint32_t bytes);
|
||||
|
||||
/// Return what was set by SetMTU()
|
||||
uint32_t GetMTU(void) const;
|
||||
|
||||
/// Query for statistics
|
||||
BytesPerMicrosecond GetLocalSendRate(void) const {return 0;}
|
||||
BytesPerMicrosecond GetLocalReceiveRate(CCTimeType currentTime) const;
|
||||
BytesPerMicrosecond GetRemoveReceiveRate(void) const {return 0;}
|
||||
//BytesPerMicrosecond GetEstimatedBandwidth(void) const {return B;}
|
||||
BytesPerMicrosecond GetEstimatedBandwidth(void) const {return GetLinkCapacityBytesPerSecond()*1000000.0;}
|
||||
double GetLinkCapacityBytesPerSecond(void) const {return 0;}
|
||||
|
||||
/// Query for statistics
|
||||
double GetRTT(void) const;
|
||||
|
||||
bool GetIsInSlowStart(void) const {return IsInSlowStart();}
|
||||
uint32_t GetCWNDLimit(void) const {return (uint32_t) 0;}
|
||||
|
||||
|
||||
/// Is a > b, accounting for variable overflow?
|
||||
static bool GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
|
||||
/// Is a < b, accounting for variable overflow?
|
||||
static bool LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
|
||||
// void SetTimeBetweenSendsLimit(unsigned int bitsPerSecond);
|
||||
uint64_t GetBytesPerSecondLimitByCongestionControl(void) const;
|
||||
|
||||
protected:
|
||||
|
||||
// Maximum amount of bytes that the user can send, e.g. the size of one full datagram
|
||||
uint32_t MAXIMUM_MTU_INCLUDING_UDP_HEADER;
|
||||
|
||||
double cwnd; // max bytes on wire
|
||||
double ssThresh; // Threshhold between slow start and congestion avoidance
|
||||
|
||||
/// When we get an ack, if oldestUnsentAck==0, set it to the current time
|
||||
/// When we send out acks, set oldestUnsentAck to 0
|
||||
CCTimeType oldestUnsentAck;
|
||||
|
||||
CCTimeType GetSenderRTOForACK(void) const;
|
||||
|
||||
/// Every outgoing datagram is assigned a sequence number, which increments by 1 every assignment
|
||||
DatagramSequenceNumberType nextDatagramSequenceNumber;
|
||||
DatagramSequenceNumberType nextCongestionControlBlock;
|
||||
bool backoffThisBlock, speedUpThisBlock;
|
||||
/// Track which datagram sequence numbers have arrived.
|
||||
/// If a sequence number is skipped, send a NAK for all skipped messages
|
||||
DatagramSequenceNumberType expectedNextSequenceNumber;
|
||||
|
||||
bool _isContinuousSend;
|
||||
|
||||
bool IsInSlowStart(void) const;
|
||||
|
||||
double lastRtt, estimatedRTT, deviationRtt;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
409
Source/include/slikenet/CCRakNetUDT.h
Normal file
409
Source/include/slikenet/CCRakNetUDT.h
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL!=1
|
||||
|
||||
#ifndef __CONGESTION_CONTROL_UDT_H
|
||||
#define __CONGESTION_CONTROL_UDT_H
|
||||
|
||||
#include "NativeTypes.h"
|
||||
#include "time.h"
|
||||
#include "types.h"
|
||||
#include "DS_Queue.h"
|
||||
|
||||
/// Set to 4 if you are using the iPod Touch TG. See http://www.jenkinssoftware.com/forum/index.php?topic=2717.0
|
||||
#define CC_TIME_TYPE_BYTES 8
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
#if CC_TIME_TYPE_BYTES==8
|
||||
typedef uint64_t CCTimeType;
|
||||
#else
|
||||
typedef uint32_t CCTimeType;
|
||||
#endif
|
||||
|
||||
typedef uint24_t DatagramSequenceNumberType;
|
||||
typedef double BytesPerMicrosecond;
|
||||
typedef double BytesPerSecond;
|
||||
typedef double MicrosecondsPerByte;
|
||||
|
||||
/// CC_RAKNET_UDT_PACKET_HISTORY_LENGTH should be a power of 2 for the writeIndex variables to wrap properly
|
||||
#define CC_RAKNET_UDT_PACKET_HISTORY_LENGTH 64
|
||||
#define RTT_HISTORY_LENGTH 64
|
||||
|
||||
/// Sizeof an UDP header in byte
|
||||
#define UDP_HEADER_SIZE 28
|
||||
|
||||
#define CC_DEBUG_PRINTF_1(x)
|
||||
#define CC_DEBUG_PRINTF_2(x,y)
|
||||
#define CC_DEBUG_PRINTF_3(x,y,z)
|
||||
#define CC_DEBUG_PRINTF_4(x,y,z,a)
|
||||
#define CC_DEBUG_PRINTF_5(x,y,z,a,b)
|
||||
//#define CC_DEBUG_PRINTF_1(x) printf(x)
|
||||
//#define CC_DEBUG_PRINTF_2(x,y) printf(x,y)
|
||||
//#define CC_DEBUG_PRINTF_3(x,y,z) printf(x,y,z)
|
||||
//#define CC_DEBUG_PRINTF_4(x,y,z,a) printf(x,y,z,a)
|
||||
//#define CC_DEBUG_PRINTF_5(x,y,z,a,b) printf(x,y,z,a,b)
|
||||
|
||||
/// \brief Encapsulates UDT congestion control, as used by RakNet
|
||||
/// Requirements:
|
||||
/// <OL>
|
||||
/// <LI>Each datagram is no more than MAXIMUM_MTU_SIZE, after accounting for the UDP header
|
||||
/// <LI>Each datagram containing a user message has a sequence number which is set after calling OnSendBytes(). Set it by calling GetAndIncrementNextDatagramSequenceNumber()
|
||||
/// <LI>System is designed to be used from a single thread.
|
||||
/// <LI>Each packet should have a timeout time based on GetSenderRTOForACK(). If this time elapses, add the packet to the head of the send list for retransmission.
|
||||
/// </OL>
|
||||
///
|
||||
/// Recommended:
|
||||
/// <OL>
|
||||
/// <LI>Call sendto in its own thread. This takes a significant amount of time in high speed networks.
|
||||
/// </OL>
|
||||
///
|
||||
/// Algorithm:
|
||||
/// <OL>
|
||||
/// <LI>On a new connection, call Init()
|
||||
/// <LI>On a periodic interval (SYN time is the best) call Update(). Also call ShouldSendACKs(), and send buffered ACKS if it returns true.
|
||||
/// <LI>Call OnSendAck() when sending acks.
|
||||
/// <LI>When you want to send or resend data, call GetNumberOfBytesToSend(). It will return you enough bytes to keep you busy for \a estimatedTimeToNextTick. You can send more than this to fill out a datagram, or to send packet pairs
|
||||
/// <LI>Call OnSendBytes() when sending datagrams.
|
||||
/// <LI>When data arrives, record the sequence number and buffer an ACK for it, to be sent from Update() if ShouldSendACKs() returns true
|
||||
/// <LI>Every 16 packets that you send, send two of them back to back (a packet pair) as long as both packets are the same size. If you don't have two packets the same size, it is fine to defer this until you do.
|
||||
/// <LI>When you get a packet, call OnGotPacket(). If the packet is also either of a packet pair, call OnGotPacketPair()
|
||||
/// <LI>If you get a packet, and the sequence number is not 1 + the last sequence number, send a NAK. On the remote system, call OnNAK() and resend that message.
|
||||
/// <LI>If you get an ACK, remove that message from retransmission. Call OnNonDuplicateAck().
|
||||
/// <LI>If a message is not ACKed for GetRTOForRetransmission(), resend it.
|
||||
/// </OL>
|
||||
class CCRakNetUDT
|
||||
{
|
||||
public:
|
||||
|
||||
CCRakNetUDT();
|
||||
~CCRakNetUDT();
|
||||
|
||||
/// Reset all variables to their initial states, for a new connection
|
||||
void Init(CCTimeType curTime, uint32_t maxDatagramPayload);
|
||||
|
||||
/// Update over time
|
||||
void Update(CCTimeType curTime, bool hasDataToSendOrResend);
|
||||
|
||||
int GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
|
||||
int GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
|
||||
|
||||
/// Acks do not have to be sent immediately. Instead, they can be buffered up such that groups of acks are sent at a time
|
||||
/// This reduces overall bandwidth usage
|
||||
/// How long they can be buffered depends on the retransmit time of the sender
|
||||
/// Should call once per update tick, and send if needed
|
||||
bool ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick);
|
||||
|
||||
/// Every data packet sent must contain a sequence number
|
||||
/// Call this function to get it. The sequence number is passed into OnGotPacketPair()
|
||||
DatagramSequenceNumberType GetAndIncrementNextDatagramSequenceNumber(void);
|
||||
DatagramSequenceNumberType GetNextDatagramSequenceNumber(void);
|
||||
|
||||
/// Call this when you send packets
|
||||
/// Every 15th and 16th packets should be sent as a packet pair if possible
|
||||
/// When packets marked as a packet pair arrive, pass to OnGotPacketPair()
|
||||
/// When any packets arrive, (additionally) pass to OnGotPacket
|
||||
/// Packets should contain our system time, so we can pass rtt to OnNonDuplicateAck()
|
||||
void OnSendBytes(CCTimeType curTime, uint32_t numBytes);
|
||||
|
||||
/// Call this when you get a packet pair
|
||||
void OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime);
|
||||
|
||||
/// Call this when you get a packet (including packet pairs)
|
||||
/// If the DatagramSequenceNumberType is out of order, skippedMessageCount will be non-zero
|
||||
/// In that case, send a NAK for every sequence number up to that count
|
||||
bool OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount);
|
||||
|
||||
/// Call when you get a NAK, with the sequence number of the lost message
|
||||
/// Affects the congestion control
|
||||
void OnResend(CCTimeType curTime, SLNet::TimeUS nextActionTime);
|
||||
void OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber);
|
||||
|
||||
/// Call this when an ACK arrives.
|
||||
/// hasBAndAS are possibly written with the ack, see OnSendAck()
|
||||
/// B and AS are used in the calculations in UpdateWindowSizeAndAckOnAckPerSyn
|
||||
/// B and AS are updated at most once per SYN
|
||||
void OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber );
|
||||
void OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber ) {}
|
||||
|
||||
/// Call when you send an ack, to see if the ack should have the B and AS parameters transmitted
|
||||
/// Call before calling OnSendAck()
|
||||
void OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS);
|
||||
|
||||
/// Call when we send an ack, to write B and AS if needed
|
||||
/// B and AS are only written once per SYN, to prevent slow calculations
|
||||
/// Also updates SND, the period between sends, since data is written out
|
||||
/// Be sure to call OnSendAckGetBAndAS() before calling OnSendAck(), since whether you write it or not affects \a numBytes
|
||||
void OnSendAck(CCTimeType curTime, uint32_t numBytes);
|
||||
|
||||
/// Call when we send a NACK
|
||||
/// Also updates SND, the period between sends, since data is written out
|
||||
void OnSendNACK(CCTimeType curTime, uint32_t numBytes);
|
||||
|
||||
/// Retransmission time out for the sender
|
||||
/// If the time difference between when a message was last transmitted, and the current time is greater than RTO then packet is eligible for retransmission, pending congestion control
|
||||
/// RTO = (RTT + 4 * RTTVar) + SYN
|
||||
/// If we have been continuously sending for the last RTO, and no ACK or NAK at all, SND*=2;
|
||||
/// This is per message, which is different from UDT, but RakNet supports packetloss with continuing data where UDT is only RELIABLE_ORDERED
|
||||
/// Minimum value is 100 milliseconds
|
||||
CCTimeType GetRTOForRetransmission(unsigned char timesSent) const;
|
||||
|
||||
/// Set the maximum amount of data that can be sent in one datagram
|
||||
/// Default to MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE
|
||||
void SetMTU(uint32_t bytes);
|
||||
|
||||
/// Return what was set by SetMTU()
|
||||
uint32_t GetMTU(void) const;
|
||||
|
||||
/// Query for statistics
|
||||
BytesPerMicrosecond GetLocalSendRate(void) const {return 1.0 / SND;}
|
||||
BytesPerMicrosecond GetLocalReceiveRate(CCTimeType currentTime) const;
|
||||
BytesPerMicrosecond GetRemoveReceiveRate(void) const {return AS;}
|
||||
//BytesPerMicrosecond GetEstimatedBandwidth(void) const {return B;}
|
||||
BytesPerMicrosecond GetEstimatedBandwidth(void) const {return GetLinkCapacityBytesPerSecond()*1000000.0;}
|
||||
double GetLinkCapacityBytesPerSecond(void) const {return estimatedLinkCapacityBytesPerSecond;};
|
||||
|
||||
/// Query for statistics
|
||||
double GetRTT(void) const;
|
||||
|
||||
bool GetIsInSlowStart(void) const {return isInSlowStart;}
|
||||
uint32_t GetCWNDLimit(void) const {return (uint32_t) (CWND*MAXIMUM_MTU_INCLUDING_UDP_HEADER);}
|
||||
|
||||
|
||||
/// Is a > b, accounting for variable overflow?
|
||||
static bool GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
|
||||
/// Is a < b, accounting for variable overflow?
|
||||
static bool LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
|
||||
// void SetTimeBetweenSendsLimit(unsigned int bitsPerSecond);
|
||||
uint64_t GetBytesPerSecondLimitByCongestionControl(void) const;
|
||||
|
||||
protected:
|
||||
// --------------------------- PROTECTED VARIABLES ---------------------------
|
||||
/// time interval between bytes, in microseconds.
|
||||
/// Only used when slowStart==false
|
||||
/// Increased over time as we continually get messages
|
||||
/// Decreased on NAK and timeout
|
||||
/// Starts at 0 (invalid)
|
||||
MicrosecondsPerByte SND;
|
||||
|
||||
/// Supportive window mechanism, controlling the maximum number of in-flight packets
|
||||
/// Used both during and after slow-start, but primarily during slow-start
|
||||
/// Starts at 2, which is also the low threshhold
|
||||
/// Max is the socket receive buffer / MTU
|
||||
/// CWND = AS * (RTT + SYN) + 16
|
||||
double CWND;
|
||||
|
||||
/// When we do an update process on the SYN interval, nextSYNUpdate is set to the next time we should update
|
||||
/// Normally this is nextSYNUpdate+=SYN, in order to update on a consistent schedule
|
||||
/// However, if this would result in an immediate update yet again, it is set to SYN microseconds past the current time (in case the thread did not update for a long time)
|
||||
CCTimeType nextSYNUpdate;
|
||||
|
||||
|
||||
/// Index into packetPairRecieptHistory where we will next write
|
||||
/// The history is always full (starting with default values) so no read index is needed
|
||||
int packetPairRecieptHistoryWriteIndex;
|
||||
|
||||
/// Sent to the sender by the receiver from packetPairRecieptHistory whenever a back to back packet arrives on the receiver
|
||||
/// Updated by B = B * .875 + incomingB * .125
|
||||
//BytesPerMicrosecond B;
|
||||
|
||||
/// Running round trip time (ping*2)
|
||||
/// Only sender needs to know this
|
||||
/// Initialized to UNSET
|
||||
/// Set to rtt on first calculation
|
||||
/// Updated gradually by RTT = RTT * 0.875 + rtt * 0.125
|
||||
double RTT;
|
||||
|
||||
/// Round trip time variance
|
||||
/// Only sender needs to know this
|
||||
/// Initialized to UNSET
|
||||
/// Set to rtt on first calculation
|
||||
// double RTTVar;
|
||||
/// Update: Use min/max, RTTVar follows current variance too closely resulting in packetloss
|
||||
double minRTT, maxRTT;
|
||||
|
||||
/// Used to calculate packet arrival rate (in UDT) but data arrival rate (in RakNet, where not all datagrams are the same size)
|
||||
/// Filter is used to cull lowest half of values for bytesPerMicrosecond, to discount spikes and inactivity
|
||||
/// Referred to in the documentation as AS, data arrival rate
|
||||
/// AS is sent to the sender and calculated every 10th ack
|
||||
/// Each node represents (curTime-lastPacketArrivalTime)/bytes
|
||||
/// Used with ReceiverCalculateDataArrivalRate();
|
||||
BytesPerMicrosecond packetArrivalHistory[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH];
|
||||
BytesPerMicrosecond packetArrivalHistoryContinuousGaps[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH];
|
||||
unsigned char packetArrivalHistoryContinuousGapsIndex;
|
||||
uint64_t continuousBytesReceived;
|
||||
CCTimeType continuousBytesReceivedStartTime;
|
||||
unsigned int packetArrivalHistoryWriteCount;
|
||||
|
||||
/// Index into packetArrivalHistory where we will next write
|
||||
/// The history is always full (starting with default values) so no read index is needed
|
||||
int packetArrivalHistoryWriteIndex;
|
||||
|
||||
/// Tracks the time the last packet that arrived, so BytesPerMicrosecond can be calculated for packetArrivalHistory when a new packet arrives
|
||||
CCTimeType lastPacketArrivalTime;
|
||||
|
||||
/// Data arrival rate from the sender to the receiver, as told to us by the receiver
|
||||
/// Used to calculate initial sending rate when slow start stops
|
||||
BytesPerMicrosecond AS;
|
||||
|
||||
/// When the receiver last calculated and send B and AS, from packetArrivalHistory and packetPairRecieptHistory
|
||||
/// Used to prevent it from being calculated and send too frequently, as they are slow operations
|
||||
CCTimeType lastTransmitOfBAndAS;
|
||||
|
||||
/// New connections start in slow start
|
||||
/// During slow start, SND is not used, only CWND
|
||||
/// Slow start ends when we get a NAK, or the maximum size of CWND is reached
|
||||
/// SND is initialized to the inverse of the receiver's packet arrival rate when slow start ends
|
||||
bool isInSlowStart;
|
||||
|
||||
/// How many NAKs arrived this congestion period
|
||||
/// Initialized to 1 when the congestion period starts
|
||||
uint32_t NAKCount;
|
||||
|
||||
/// How many NAKs do you get on average during a congestion period?
|
||||
/// Starts at 1
|
||||
/// Used to generate a random number, DecRandom, between 1 and AvgNAKNum
|
||||
uint32_t AvgNAKNum;
|
||||
|
||||
/// How many times we have decremented SND this congestion period. Used to limit the number of decrements to 5
|
||||
uint32_t DecCount;
|
||||
|
||||
/// Every DecInterval NAKs per congestion period, we decrease the send rate
|
||||
uint32_t DecInterval;
|
||||
|
||||
/// Every outgoing datagram is assigned a sequence number, which increments by 1 every assignment
|
||||
DatagramSequenceNumberType nextDatagramSequenceNumber;
|
||||
|
||||
/// If a packet is marked as a packet pair, lastPacketPairPacketArrivalTime is set to the time it arrives
|
||||
/// This is used so when the 2nd packet of the pair arrives, we can calculate the time interval between the two
|
||||
CCTimeType lastPacketPairPacketArrivalTime;
|
||||
|
||||
/// If a packet is marked as a packet pair, lastPacketPairSequenceNumber is checked to see if the last packet we got
|
||||
/// was the packet immediately before the one that arrived
|
||||
/// If so, we can use lastPacketPairPacketArrivalTime to get the time between the two packets, and thus estimate the link capacity
|
||||
/// Initialized to -1, so the first packet of a packet pair won't be treated as the second
|
||||
DatagramSequenceNumberType lastPacketPairSequenceNumber;
|
||||
|
||||
/// Used to cap UpdateWindowSizeAndAckOnAckPerSyn() to once speed increase per SYN
|
||||
/// This is to prevent speeding up faster than congestion control can compensate for
|
||||
CCTimeType lastUpdateWindowSizeAndAck;
|
||||
|
||||
/// Every time SND is halved due to timeout, the RTO is increased
|
||||
/// This is to prevent massive retransmissions to an unresponsive system
|
||||
/// Reset on any data arriving
|
||||
double ExpCount;
|
||||
|
||||
/// Total number of user data bytes sent
|
||||
/// Used to adjust the window size, on ACK, during slow start
|
||||
uint64_t totalUserDataBytesSent;
|
||||
|
||||
/// When we get an ack, if oldestUnsentAck==0, set it to the current time
|
||||
/// When we send out acks, set oldestUnsentAck to 0
|
||||
CCTimeType oldestUnsentAck;
|
||||
|
||||
// Maximum amount of bytes that the user can send, e.g. the size of one full datagram
|
||||
uint32_t MAXIMUM_MTU_INCLUDING_UDP_HEADER;
|
||||
|
||||
// Max window size
|
||||
double CWND_MAX_THRESHOLD;
|
||||
|
||||
/// Track which datagram sequence numbers have arrived.
|
||||
/// If a sequence number is skipped, send a NAK for all skipped messages
|
||||
DatagramSequenceNumberType expectedNextSequenceNumber;
|
||||
|
||||
// How many times have we sent B and AS? Used to force it to send at least CC_RAKNET_UDT_PACKET_HISTORY_LENGTH times
|
||||
// Otherwise, the default values in the array generate inaccuracy
|
||||
uint32_t sendBAndASCount;
|
||||
|
||||
/// Most recent values read into the corresponding lists
|
||||
/// Used during the beginning of a connection, when the median filter is still inaccurate
|
||||
BytesPerMicrosecond mostRecentPacketArrivalHistory;
|
||||
|
||||
bool hasWrittenToPacketPairReceiptHistory;
|
||||
|
||||
// uint32_t rttHistory[RTT_HISTORY_LENGTH];
|
||||
// uint32_t rttHistoryIndex;
|
||||
// uint32_t rttHistoryWriteCount;
|
||||
// uint32_t rttSum, rttLow;
|
||||
// CCTimeType lastSndUpdateTime;
|
||||
double estimatedLinkCapacityBytesPerSecond;
|
||||
|
||||
// --------------------------- PROTECTED METHODS ---------------------------
|
||||
/// Update nextSYNUpdate by SYN, or the same amount past the current time if no updates have occurred for a long time
|
||||
void SetNextSYNUpdate(CCTimeType currentTime);
|
||||
|
||||
/// Returns the rate of data arrival, based on packets arriving on the sender.
|
||||
BytesPerMicrosecond ReceiverCalculateDataArrivalRate(CCTimeType curTime) const;
|
||||
/// Returns the median of the data arrival rate
|
||||
BytesPerMicrosecond ReceiverCalculateDataArrivalRateMedian(void) const;
|
||||
|
||||
/// Calculates the median an array of BytesPerMicrosecond
|
||||
static BytesPerMicrosecond CalculateListMedianRecursive(const BytesPerMicrosecond inputList[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH], int inputListLength, int lessThanSum, int greaterThanSum);
|
||||
// static uint32_t CalculateListMedianRecursive(const uint32_t inputList[RTT_HISTORY_LENGTH], int inputListLength, int lessThanSum, int greaterThanSum);
|
||||
|
||||
/// Same as GetRTOForRetransmission, but does not factor in ExpCount
|
||||
/// This is because the receiver does not know ExpCount for the sender, and even if it did, acks shouldn't be delayed for this reason
|
||||
CCTimeType GetSenderRTOForACK(void) const;
|
||||
|
||||
/// Stop slow start, and enter normal transfer rate
|
||||
void EndSlowStart(void);
|
||||
|
||||
/// Does the named conversion
|
||||
inline double BytesPerMicrosecondToPacketsPerMillisecond(BytesPerMicrosecond in);
|
||||
|
||||
/// Update the round trip time, from ACK or ACK2
|
||||
//void UpdateRTT(CCTimeType rtt);
|
||||
|
||||
/// Update the corresponding variables pre-slow start
|
||||
void UpdateWindowSizeAndAckOnAckPreSlowStart(double totalUserDataBytesAcked);
|
||||
|
||||
/// Update the corresponding variables post-slow start
|
||||
void UpdateWindowSizeAndAckOnAckPerSyn(CCTimeType curTime, CCTimeType rtt, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber);
|
||||
|
||||
|
||||
/// Sets halveSNDOnNoDataTime to the future, and also resets ExpCount, which is used to multiple the RTO on no data arriving at all
|
||||
void ResetOnDataArrivalHalveSNDOnNoDataTime(CCTimeType curTime);
|
||||
|
||||
// Init array
|
||||
void InitPacketArrivalHistory(void);
|
||||
|
||||
// Printf
|
||||
void PrintLowBandwidthWarning(void);
|
||||
|
||||
// Bug: SND can sometimes get super high - have seen 11693
|
||||
void CapMinSnd(const char *file, int line);
|
||||
|
||||
void DecreaseTimeBetweenSends(void);
|
||||
void IncreaseTimeBetweenSends(void);
|
||||
|
||||
int bytesCanSendThisTick;
|
||||
|
||||
CCTimeType lastRttOnIncreaseSendRate;
|
||||
CCTimeType lastRtt;
|
||||
|
||||
DatagramSequenceNumberType nextCongestionControlBlock;
|
||||
bool hadPacketlossThisBlock;
|
||||
DataStructures::Queue<CCTimeType> pingsLastInterval;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
68
Source/include/slikenet/CheckSum.h
Normal file
68
Source/include/slikenet/CheckSum.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
///
|
||||
/// \file CheckSum.cpp
|
||||
/// \brief [Internal] CheckSum implementation from http://www.flounder.com/checksum.htm
|
||||
///
|
||||
|
||||
#ifndef __CHECKSUM_H
|
||||
#define __CHECKSUM_H
|
||||
|
||||
#include "memoryoverride.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
|
||||
176
Source/include/slikenet/CloudClient.h
Normal file
176
Source/include/slikenet/CloudClient.h
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file CloudClient.h
|
||||
/// \brief Queries CloudMemoryServer to download data that other clients have uploaded
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_CloudClient==1
|
||||
|
||||
#ifndef __CLOUD_CLIENT_H
|
||||
#define __CLOUD_CLIENT_H
|
||||
|
||||
#include "PluginInterface2.h"
|
||||
#include "CloudCommon.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "DS_Hash.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
class CloudClientCallback;
|
||||
|
||||
/// \defgroup CLOUD_GROUP CloudComputing
|
||||
/// \brief Contains the CloudClient and CloudServer plugins
|
||||
/// \details The CloudServer plugins operates on requests from the CloudClient plugin. The servers are in a fully connected mesh topology, which the clients are connected to any server. Clients can interact with each other by posting and subscribing to memory updates, without being directly connected or even knowing about each other.
|
||||
/// \ingroup PLUGINS_GROUP
|
||||
|
||||
/// \brief Performs Post() and Get() operations on CloudMemoryServer
|
||||
/// \details A CloudClient is a computer connected to one or more servers in a cloud configuration. Operations by one CloudClient can be received and subscribed to by other instances of CloudClient, without those clients being connected, even on different servers.
|
||||
/// \ingroup CLOUD_GROUP
|
||||
class RAK_DLL_EXPORT CloudClient : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(CloudClient)
|
||||
|
||||
CloudClient();
|
||||
virtual ~CloudClient();
|
||||
|
||||
/// \brief Set the default callbacks for OnGetReponse(), OnSubscriptionNotification(), and OnSubscriptionDataDeleted()
|
||||
/// \details Pointers to CloudAllocator and CloudClientCallback can be stored by the system if desired. If a callback is not provided to OnGetReponse(), OnSubscriptionNotification(), OnSubscriptionDataDeleted(), the callback passed here will be used instead.
|
||||
/// \param[in] _allocator An instance of CloudAllocator
|
||||
/// \param[in] _callback An instance of CloudClientCallback
|
||||
virtual void SetDefaultCallbacks(CloudAllocator *_allocator, CloudClientCallback *_callback);
|
||||
|
||||
/// \brief Uploads data to the cloud
|
||||
/// \details Data uploaded to the cloud will be stored by the server sent to, identified by \a systemIdentifier.
|
||||
/// As long as you are connected to this server, the data will persist. Queries for that data by the Get() operation will
|
||||
/// return the RakNetGUID and SystemAddress of the uploader, as well as the data itself.
|
||||
/// Furthermore, if any clients are subscribed to the particular CloudKey passed, those clients will get update notices that the data has changed
|
||||
/// Passing data with the same \a cloudKey more than once will overwrite the prior value.
|
||||
/// This call will silently fail if CloudServer::SetMaxUploadBytesPerClient() is exceeded
|
||||
/// \param[in] cloudKey Identifies the data being uploaded
|
||||
/// \param[in] data A pointer to data to upload. This pointer does not need to persist past the call
|
||||
/// \param[in] dataLengthBytes The length in bytes of \a data
|
||||
/// \param[in] systemIdentifier A remote system running CloudServer that we are already connected to.
|
||||
virtual void Post(CloudKey *cloudKey, const unsigned char *data, uint32_t dataLengthBytes, RakNetGUID systemIdentifier);
|
||||
|
||||
/// \brief Releases one or more data previously uploaded with Post()
|
||||
/// \details If a remote system has subscribed to one or more of the \a keys uploaded, they will get ID_CLOUD_SUBSCRIPTION_NOTIFICATION notifications containing the last value uploaded before deletions
|
||||
/// \param[in] cloudKey Identifies the data to release. It is possible to remove uploads from multiple Post() calls at once.
|
||||
/// \param[in] systemIdentifier A remote system running CloudServer that we are already connected to.
|
||||
virtual void Release(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier);
|
||||
|
||||
/// \brief Gets data from the cloud
|
||||
/// \details For a given query containing one or more keys, return data that matches those keys.
|
||||
/// The values will be returned in the ID_CLOUD_GET_RESPONSE packet, which should be passed to OnGetReponse() and will invoke CloudClientCallback::OnGet()
|
||||
/// CloudQuery::startingRowIndex is used to skip the first n values that would normally be returned..
|
||||
/// CloudQuery::maxRowsToReturn is used to limit the number of rows returned. The number of rows returned may also be limited by CloudServer::SetMaxBytesPerDownload();
|
||||
/// CloudQuery::subscribeToResults if set to true, will cause ID_CLOUD_SUBSCRIPTION_NOTIFICATION to be returned to us when any of the keys in the query are updated or are deleted.
|
||||
/// ID_CLOUD_GET_RESPONSE will be returned even if subscribing to the result list. Only later updates will return ID_CLOUD_SUBSCRIPTION_NOTIFICATION.
|
||||
/// Calling Get() with CloudQuery::subscribeToResults false, when you are already subscribed, does not remove the subscription. Use Unsubscribe() for this.
|
||||
/// Resubscribing using the same CloudKey but a different or no \a specificSystems overwrites the subscribed systems for those keys.
|
||||
/// \param[in] cloudQuery One or more keys, and optional parameters to perform with the Get
|
||||
/// \param[in] systemIdentifier A remote system running CloudServer that we are already connected to.
|
||||
/// \param[in] specificSystems It is possible to get or subscribe to updates only for specific uploading CloudClient instances. Pass the desired instances here. The overload that does not have the specificSystems parameter is treated as subscribing to all updates from all clients.
|
||||
virtual bool Get(CloudQuery *cloudQuery, RakNetGUID systemIdentifier);
|
||||
virtual bool Get(CloudQuery *cloudQuery, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier);
|
||||
virtual bool Get(CloudQuery *cloudQuery, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier);
|
||||
|
||||
/// \brief Unsubscribe from updates previously subscribed to using Get() with the CloudQuery::subscribeToResults set to true
|
||||
/// The \a keys and \a specificSystems parameters are logically treated as AND when checking subscriptions on the server
|
||||
/// The overload that does not take specificSystems unsubscribes to all passed keys, regardless of system
|
||||
/// You cannot unsubscribe specific systems when previously subscribed to updates from any system. To do this, first Unsubscribe() from all systems, and call Get() with the \a specificSystems parameter explicilty listing the systems you want to subscribe to.
|
||||
virtual void Unsubscribe(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier);
|
||||
virtual void Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier);
|
||||
virtual void Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier);
|
||||
|
||||
/// \brief Call this when you get ID_CLOUD_GET_RESPONSE
|
||||
/// If \a callback or \a allocator are 0, the default callbacks passed to SetDefaultCallbacks() are used
|
||||
/// \param[in] packet Packet structure returned from RakPeerInterface
|
||||
/// \param[in] _callback Callback to be called from the function containing output parameters. If 0, default is used.
|
||||
/// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used.
|
||||
virtual void OnGetReponse(Packet *packet, CloudClientCallback *_callback=0, CloudAllocator *_allocator=0);
|
||||
|
||||
/// \brief Call this when you get ID_CLOUD_GET_RESPONSE
|
||||
/// Different form of OnGetReponse that returns to a structure that you pass, instead of using a callback
|
||||
/// You are responsible for deallocation with this form
|
||||
/// If \a allocator is 0, the default callback passed to SetDefaultCallbacks() are used
|
||||
/// \param[out] cloudQueryResult A pointer to a structure that will be filled out with data
|
||||
/// \param[in] packet Packet structure returned from RakPeerInterface
|
||||
/// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used.
|
||||
virtual void OnGetReponse(CloudQueryResult *cloudQueryResult, Packet *packet, CloudAllocator *_allocator=0);
|
||||
|
||||
/// \brief Call this when you get ID_CLOUD_SUBSCRIPTION_NOTIFICATION
|
||||
/// If \a callback or \a allocator are 0, the default callbacks passed to SetDefaultCallbacks() are used
|
||||
/// \param[in] packet Packet structure returned from RakPeerInterface
|
||||
/// \param[in] _callback Callback to be called from the function containing output parameters. If 0, default is used.
|
||||
/// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used.
|
||||
virtual void OnSubscriptionNotification(Packet *packet, CloudClientCallback *_callback=0, CloudAllocator *_allocator=0);
|
||||
|
||||
/// \brief Call this when you get ID_CLOUD_SUBSCRIPTION_NOTIFICATION
|
||||
/// Different form of OnSubscriptionNotification that returns to a structure that you pass, instead of using a callback
|
||||
/// You are responsible for deallocation with this form
|
||||
/// If \a allocator is 0, the default callback passed to SetDefaultCallbacks() are used
|
||||
/// \param[out] wasUpdated If true, the row was updated. If false, it was deleted. \a result will contain the last value just before deletion
|
||||
/// \param[out] row A pointer to a structure that will be filled out with data
|
||||
/// \param[in] packet Packet structure returned from RakPeerInterface
|
||||
/// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used.
|
||||
virtual void OnSubscriptionNotification(bool *wasUpdated, CloudQueryRow *row, Packet *packet, CloudAllocator *_allocator=0);
|
||||
|
||||
/// If you never specified an allocator, and used the non-callback form of OnGetReponse(), deallocate cloudQueryResult with this function
|
||||
virtual void DeallocateWithDefaultAllocator(CloudQueryResult *cloudQueryResult);
|
||||
|
||||
/// If you never specified an allocator, and used the non-callback form of OnSubscriptionNotification(), deallocate row with this function
|
||||
virtual void DeallocateWithDefaultAllocator(CloudQueryRow *row);
|
||||
|
||||
protected:
|
||||
PluginReceiveResult OnReceive(Packet *packet);
|
||||
|
||||
CloudClientCallback *callback;
|
||||
CloudAllocator *allocator;
|
||||
|
||||
CloudAllocator unsetDefaultAllocator;
|
||||
};
|
||||
|
||||
/// \ingroup CLOUD_GROUP
|
||||
/// Parses ID_CLOUD_GET_RESPONSE and ID_CLOUD_SUBSCRIPTION_NOTIFICATION in a convenient callback form
|
||||
class RAK_DLL_EXPORT CloudClientCallback
|
||||
{
|
||||
public:
|
||||
CloudClientCallback() {}
|
||||
virtual ~CloudClientCallback() {}
|
||||
|
||||
/// \brief Called in response to ID_CLOUD_GET_RESPONSE
|
||||
/// \param[out] result Contains the original query passed to Get(), and a list of rows returned.
|
||||
/// \param[out] deallocateRowsAfterReturn CloudQueryResult::rowsReturned will be deallocated after the function returns by default. Set to false to not deallocate these pointers. The pointers are allocated through CloudAllocator.
|
||||
virtual void OnGet(SLNet::CloudQueryResult *result, bool *deallocateRowsAfterReturn) {(void) result; (void) deallocateRowsAfterReturn;}
|
||||
|
||||
/// \brief Called in response to ID_CLOUD_SUBSCRIPTION_NOTIFICATION
|
||||
/// \param[out] result Contains the row updated
|
||||
/// \param[out] wasUpdated If true, the row was updated. If false, it was deleted. \a result will contain the last value just before deletion
|
||||
/// \param[out] deallocateRowAfterReturn \a result will be deallocated after the function returns by default. Set to false to not deallocate these pointers. The pointers are allocated through CloudAllocator.
|
||||
virtual void OnSubscriptionNotification(SLNet::CloudQueryRow *result, bool wasUpdated, bool *deallocateRowAfterReturn) {(void) result; (void) wasUpdated; (void) deallocateRowAfterReturn;}
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
155
Source/include/slikenet/CloudCommon.h
Normal file
155
Source/include/slikenet/CloudCommon.h
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_CloudClient==1 || _RAKNET_SUPPORT_CloudServer==1
|
||||
|
||||
#ifndef __CLOUD_COMMON_H
|
||||
#define __CLOUD_COMMON_H
|
||||
|
||||
#include "types.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
class BitStream;
|
||||
struct CloudQueryRow;
|
||||
|
||||
/// Allocates CloudQueryRow and the row data. Override to use derived classes or different allocators
|
||||
/// \ingroup CLOUD_GROUP
|
||||
class RAK_DLL_EXPORT CloudAllocator
|
||||
{
|
||||
public:
|
||||
CloudAllocator() {}
|
||||
virtual ~CloudAllocator() {}
|
||||
|
||||
/// \brief Allocate a row
|
||||
virtual CloudQueryRow* AllocateCloudQueryRow(void);
|
||||
/// \brief Free a row
|
||||
virtual void DeallocateCloudQueryRow(CloudQueryRow *row);
|
||||
/// \brief Allocate CloudQueryRow::data
|
||||
virtual unsigned char *AllocateRowData(uint32_t bytesNeededForData);
|
||||
/// \brief Free CloudQueryRow::data
|
||||
virtual void DeallocateRowData(void *data);
|
||||
};
|
||||
|
||||
/// Serves as a key to identify data uploaded to or queried from the server.
|
||||
/// \ingroup CLOUD_GROUP
|
||||
struct RAK_DLL_EXPORT CloudKey
|
||||
{
|
||||
CloudKey() {}
|
||||
CloudKey(SLNet::RakString _primaryKey, uint32_t _secondaryKey) : primaryKey(_primaryKey), secondaryKey(_secondaryKey) {}
|
||||
~CloudKey() {}
|
||||
|
||||
/// Identifies the primary key. This is intended to be a major category, such as the name of the application
|
||||
/// Must be non-empty
|
||||
SLNet::RakString primaryKey;
|
||||
|
||||
/// Identifies the secondary key. This is intended to be a subcategory enumeration, such as PLAYER_LIST or RUNNING_SCORES
|
||||
uint32_t secondaryKey;
|
||||
|
||||
/// \internal
|
||||
void Serialize(bool writeToBitstream, BitStream *bitStream);
|
||||
};
|
||||
|
||||
/// \internal
|
||||
int CloudKeyComp(const CloudKey &key, const CloudKey &data);
|
||||
|
||||
/// Data members used to query the cloud
|
||||
/// \ingroup CLOUD_GROUP
|
||||
struct RAK_DLL_EXPORT CloudQuery
|
||||
{
|
||||
CloudQuery() {startingRowIndex=0; maxRowsToReturn=0; subscribeToResults=false;}
|
||||
|
||||
/// List of keys to query. Must be at least of length 1.
|
||||
/// This query is run on uploads from all clients, and those that match the combination of primaryKey and secondaryKey are potentially returned
|
||||
/// If you pass more than one key at a time, the results are concatenated so if you need to differentiate between queries then send two different queries
|
||||
DataStructures::List<CloudKey> keys;
|
||||
|
||||
/// If limiting the number of rows to return, this is the starting offset into the list. Has no effect unless maxRowsToReturn is > 0
|
||||
uint32_t startingRowIndex;
|
||||
|
||||
/// Maximum number of rows to return. Actual number may still be less than this. Pass 0 to mean no-limit.
|
||||
uint32_t maxRowsToReturn;
|
||||
|
||||
/// If true, automatically get updates as the results returned to you change. Unsubscribe with CloudMemoryClient::Unsubscribe()
|
||||
bool subscribeToResults;
|
||||
|
||||
/// \internal
|
||||
void Serialize(bool writeToBitstream, BitStream *bitStream);
|
||||
};
|
||||
|
||||
/// \ingroup CLOUD_GROUP
|
||||
struct RAK_DLL_EXPORT CloudQueryRow
|
||||
{
|
||||
/// Key used to identify this data
|
||||
CloudKey key;
|
||||
|
||||
/// Data uploaded
|
||||
unsigned char *data;
|
||||
|
||||
/// Length of data uploaded
|
||||
uint32_t length;
|
||||
|
||||
/// System address of server that is holding this data, and the client is connected to
|
||||
SystemAddress serverSystemAddress;
|
||||
|
||||
/// System address of client that uploaded this data
|
||||
SystemAddress clientSystemAddress;
|
||||
|
||||
/// RakNetGUID of server that is holding this data, and the client is connected to
|
||||
RakNetGUID serverGUID;
|
||||
|
||||
/// RakNetGUID of client that uploaded this data
|
||||
RakNetGUID clientGUID;
|
||||
|
||||
/// \internal
|
||||
void Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator);
|
||||
};
|
||||
|
||||
/// \ingroup CLOUD_GROUP
|
||||
struct RAK_DLL_EXPORT CloudQueryResult
|
||||
{
|
||||
/// Query originally passed to Download()
|
||||
CloudQuery cloudQuery;
|
||||
|
||||
/// Results returned from query. If there were multiple keys in CloudQuery::keys then see resultKeyIndices
|
||||
DataStructures::List<CloudQueryRow*> rowsReturned;
|
||||
|
||||
/// If there were multiple keys in CloudQuery::keys, then each key is processed in order and the result concatenated to rowsReturned
|
||||
/// The starting index of each query is written to resultKeyIndices
|
||||
/// For example, if CloudQuery::keys had 4 keys, returning 3 rows, 0, rows, 5 rows, and 12 rows then
|
||||
/// resultKeyIndices would be 0, 3, 3, 8
|
||||
DataStructures::List<uint32_t> resultKeyIndices;
|
||||
|
||||
/// Whatever was passed to CloudClient::Get() as CloudQuery::subscribeToResults
|
||||
bool subscribeToResults;
|
||||
|
||||
/// \internal
|
||||
void Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator);
|
||||
/// \internal
|
||||
void SerializeHeader(bool writeToBitstream, BitStream *bitStream);
|
||||
/// \internal
|
||||
void SerializeNumRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream);
|
||||
/// \internal
|
||||
void SerializeCloudQueryRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream, CloudAllocator *allocator);
|
||||
};
|
||||
|
||||
} // Namespace SLikeNet
|
||||
|
||||
#endif // __CLOUD_COMMON_H
|
||||
|
||||
#endif // #if _RAKNET_SUPPORT_CloudClient==1 || _RAKNET_SUPPORT_CloudServer==1
|
||||
388
Source/include/slikenet/CloudServer.h
Normal file
388
Source/include/slikenet/CloudServer.h
Normal file
@ -0,0 +1,388 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file CloudServer.h
|
||||
/// \brief Stores client data, and allows cross-server communication to retrieve this data
|
||||
/// \details TODO
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_CloudServer==1
|
||||
|
||||
#ifndef __CLOUD_SERVER_H
|
||||
#define __CLOUD_SERVER_H
|
||||
|
||||
#include "PluginInterface2.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "NativeTypes.h"
|
||||
#include "string.h"
|
||||
#include "DS_Hash.h"
|
||||
#include "CloudCommon.h"
|
||||
#include "DS_OrderedList.h"
|
||||
|
||||
/// If the data is smaller than this value, an allocation is avoid. However, this value exists for every row
|
||||
#define CLOUD_SERVER_DATA_STACK_SIZE 32
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
|
||||
/// \brief Zero or more instances of CloudServerQueryFilter can be attached to CloudServer to restrict client queries
|
||||
/// All attached instances of CloudServerQueryFilter on each corresponding operation, from all directly connected clients
|
||||
/// If any attached instance returns false for a given operation, that operation is silently rejected
|
||||
/// \ingroup CLOUD_GROUP
|
||||
class RAK_DLL_EXPORT CloudServerQueryFilter
|
||||
{
|
||||
public:
|
||||
CloudServerQueryFilter() {}
|
||||
virtual ~CloudServerQueryFilter() {}
|
||||
|
||||
/// Called when a local client wants to post data
|
||||
/// \return true to allow, false to reject
|
||||
virtual bool OnPostRequest(RakNetGUID clientGuid, SystemAddress clientAddress, CloudKey key, uint32_t dataLength, const char *data)=0;
|
||||
|
||||
/// Called when a local client wants to release data that it has previously uploaded
|
||||
/// \return true to allow, false to reject
|
||||
virtual bool OnReleaseRequest(RakNetGUID clientGuid, SystemAddress clientAddress, DataStructures::List<CloudKey> &cloudKeys)=0;
|
||||
|
||||
/// Called when a local client wants to query data
|
||||
/// If you return false, the client will get no response at all
|
||||
/// \return true to allow, false to reject
|
||||
virtual bool OnGetRequest(RakNetGUID clientGuid, SystemAddress clientAddress, CloudQuery &query, DataStructures::List<RakNetGUID> &specificSystems)=0;
|
||||
|
||||
/// Called when a local client wants to stop getting updates for data
|
||||
/// If you return false, the client will keep getting updates for that data
|
||||
/// \return true to allow, false to reject
|
||||
virtual bool OnUnsubscribeRequest(RakNetGUID clientGuid, SystemAddress clientAddress, DataStructures::List<CloudKey> &cloudKeys, DataStructures::List<RakNetGUID> &specificSystems)=0;
|
||||
};
|
||||
|
||||
/// \brief Stores client data, and allows cross-server communication to retrieve this data
|
||||
/// \ingroup CLOUD_GROUP
|
||||
class RAK_DLL_EXPORT CloudServer : public PluginInterface2, CloudAllocator
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(CloudServer)
|
||||
|
||||
CloudServer();
|
||||
virtual ~CloudServer();
|
||||
|
||||
/// \brief Max bytes a client can upload
|
||||
/// Data in excess of this value is silently ignored
|
||||
/// defaults to 0 (unlimited)
|
||||
/// \param[in] bytes Max bytes a client can upload. 0 means unlimited.
|
||||
void SetMaxUploadBytesPerClient(uint64_t bytes);
|
||||
|
||||
/// \brief Max bytes returned by a download. If the number of bytes would exceed this amount, the returned list is truncated
|
||||
/// However, if this would result in no rows downloaded, then one row will be returned.
|
||||
/// \param[in] bytes Max bytes a client can download from a single Get(). 0 means unlimited.
|
||||
void SetMaxBytesPerDownload(uint64_t bytes);
|
||||
|
||||
/// \brief Add a server, which is assumed to be connected in a fully connected mesh to all other servers and also running the CloudServer plugin
|
||||
/// The other system must also call AddServer before getting the subscription data, or it will be rejected.
|
||||
/// Sending a message telling the other system to call AddServer(), followed by calling AddServer() locally, would be sufficient for this to work.
|
||||
/// \note This sends subscription data to the other system, using RELIABLE_ORDERED on channel 0
|
||||
/// \param[in] systemIdentifier Identifier of the remote system
|
||||
void AddServer(RakNetGUID systemIdentifier);
|
||||
|
||||
/// \brief Removes a server added through AddServer()
|
||||
/// \param[in] systemIdentifier Identifier of the remote system
|
||||
void RemoveServer(RakNetGUID systemIdentifier);
|
||||
|
||||
/// Return list of servers added with AddServer()
|
||||
/// \param[out] remoteServers List of servers added
|
||||
void GetRemoteServers(DataStructures::List<RakNetGUID> &remoteServersOut);
|
||||
|
||||
/// \brief Frees all memory. Does not remove query filters
|
||||
void Clear(void);
|
||||
|
||||
/// \brief Report the specified SystemAddress to client queries, rather than what RakPeer reads.
|
||||
/// This is useful if you already know your public IP
|
||||
/// This only applies to future updates, so call it before updating to apply to all queries
|
||||
/// \param[in] forcedAddress The systmeAddress to return in queries. Use UNASSIGNED_SYSTEM_ADDRESS (default) to use what RakPeer returns
|
||||
void ForceExternalSystemAddress(SystemAddress forcedAddress);
|
||||
|
||||
/// \brief Adds a callback called on each query. If all filters returns true for an operation, the operation is allowed.
|
||||
/// If the filter was already added, the function silently fails
|
||||
/// \param[in] filter An externally allocated instance of CloudServerQueryFilter. The instance must remain valid until it is removed with RemoveQueryFilter() or RemoveAllQueryFilters()
|
||||
void AddQueryFilter(CloudServerQueryFilter* filter);
|
||||
|
||||
/// \brief Removes a callback added with AddQueryFilter()
|
||||
/// The instance is not deleted, only unreferenced. It is up to the user to delete the instance, if necessary
|
||||
/// \param[in] filter An externally allocated instance of CloudServerQueryFilter. The instance must remain valid until it is removed with RemoveQueryFilter() or RemoveAllQueryFilters()
|
||||
void RemoveQueryFilter(CloudServerQueryFilter* filter);
|
||||
|
||||
/// \brief Removes all instances of CloudServerQueryFilter added with AddQueryFilter().
|
||||
/// The instances are not deleted, only unreferenced. It is up to the user to delete the instances, if necessary
|
||||
void RemoveAllQueryFilters(void);
|
||||
|
||||
protected:
|
||||
virtual void Update(void);
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
virtual void OnRakPeerShutdown(void);
|
||||
|
||||
|
||||
virtual void OnPostRequest(Packet *packet);
|
||||
virtual void OnReleaseRequest(Packet *packet);
|
||||
virtual void OnGetRequest(Packet *packet);
|
||||
virtual void OnUnsubscribeRequest(Packet *packet);
|
||||
virtual void OnServerToServerGetRequest(Packet *packet);
|
||||
virtual void OnServerToServerGetResponse(Packet *packet);
|
||||
|
||||
uint64_t maxUploadBytesPerClient, maxBytesPerDowload;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// For a given data key, quickly look up one or all systems that have uploaded
|
||||
// ----------------------------------------------------------------------------
|
||||
struct CloudData
|
||||
{
|
||||
CloudData() {}
|
||||
~CloudData() {if (allocatedData) rakFree_Ex(allocatedData, _FILE_AND_LINE_);}
|
||||
bool IsUnused(void) const {return isUploaded==false && specificSubscribers.Size()==0;}
|
||||
void Clear(void) {if (dataPtr==allocatedData) rakFree_Ex(allocatedData, _FILE_AND_LINE_); allocatedData=0; dataPtr=0; dataLengthBytes=0; isUploaded=false;}
|
||||
|
||||
unsigned char stackData[CLOUD_SERVER_DATA_STACK_SIZE];
|
||||
unsigned char *allocatedData; // Uses allocatedData instead of stackData if length of data exceeds CLOUD_SERVER_DATA_STACK_SIZE
|
||||
unsigned char *dataPtr; // Points to either stackData or allocatedData
|
||||
uint32_t dataLengthBytes;
|
||||
bool isUploaded;
|
||||
|
||||
/// System address of server that is holding this data, and the client is connected to
|
||||
SystemAddress serverSystemAddress;
|
||||
|
||||
/// System address of client that uploaded this data
|
||||
SystemAddress clientSystemAddress;
|
||||
|
||||
/// RakNetGUID of server that is holding this data, and the client is connected to
|
||||
RakNetGUID serverGUID;
|
||||
|
||||
/// RakNetGUID of client that uploaded this data
|
||||
RakNetGUID clientGUID;
|
||||
|
||||
/// When the key data changes from this particular system, notify these subscribers
|
||||
/// This list mutually exclusive with CloudDataList::nonSpecificSubscribers
|
||||
DataStructures::OrderedList<RakNetGUID, RakNetGUID> specificSubscribers;
|
||||
};
|
||||
void WriteCloudQueryRowFromResultList(unsigned int i, DataStructures::List<CloudData*> &cloudDataResultList, DataStructures::List<CloudKey> &cloudKeyResultList, BitStream *bsOut);
|
||||
void WriteCloudQueryRowFromResultList(DataStructures::List<CloudData*> &cloudDataResultList, DataStructures::List<CloudKey> &cloudKeyResultList, BitStream *bsOut);
|
||||
|
||||
static int KeyDataPtrComp( const RakNetGUID &key, CloudData* const &data );
|
||||
struct CloudDataList
|
||||
{
|
||||
bool IsUnused(void) const {return keyData.Size()==0 && nonSpecificSubscribers.Size()==0;}
|
||||
bool IsNotUploaded(void) const {return uploaderCount==0;}
|
||||
bool RemoveSubscriber(RakNetGUID g) {
|
||||
bool objectExists;
|
||||
unsigned int index;
|
||||
index = nonSpecificSubscribers.GetIndexFromKey(g, &objectExists);
|
||||
if (objectExists)
|
||||
{
|
||||
subscriberCount--;
|
||||
nonSpecificSubscribers.RemoveAtIndex(index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int uploaderCount, subscriberCount;
|
||||
CloudKey key;
|
||||
|
||||
// Data uploaded from or subscribed to for various systems
|
||||
DataStructures::OrderedList<RakNetGUID, CloudData*, CloudServer::KeyDataPtrComp> keyData;
|
||||
|
||||
/// When the key data changes from any system, notify these subscribers
|
||||
/// This list mutually exclusive with CloudData::specificSubscribers
|
||||
DataStructures::OrderedList<RakNetGUID, RakNetGUID> nonSpecificSubscribers;
|
||||
};
|
||||
|
||||
static int KeyDataListComp( const CloudKey &key, CloudDataList * const &data );
|
||||
DataStructures::OrderedList<CloudKey, CloudDataList*, CloudServer::KeyDataListComp> dataRepository;
|
||||
|
||||
struct KeySubscriberID
|
||||
{
|
||||
CloudKey key;
|
||||
DataStructures::OrderedList<RakNetGUID, RakNetGUID> specificSystemsSubscribedTo;
|
||||
};
|
||||
static int KeySubscriberIDComp(const CloudKey &key, KeySubscriberID * const &data );
|
||||
|
||||
// Remote systems
|
||||
struct RemoteCloudClient
|
||||
{
|
||||
bool IsUnused(void) const {return uploadedKeys.Size()==0 && subscribedKeys.Size()==0;}
|
||||
|
||||
DataStructures::OrderedList<CloudKey,CloudKey,CloudKeyComp> uploadedKeys;
|
||||
DataStructures::OrderedList<CloudKey,KeySubscriberID*,CloudServer::KeySubscriberIDComp> subscribedKeys;
|
||||
uint64_t uploadedBytes;
|
||||
};
|
||||
DataStructures::Hash<RakNetGUID, RemoteCloudClient*, 2048, RakNetGUID::ToUint32> remoteSystems;
|
||||
|
||||
// For a given user, release all subscribed and uploaded keys
|
||||
void ReleaseSystem(RakNetGUID clientAddress );
|
||||
|
||||
// For a given user, release a set of keys
|
||||
void ReleaseKeys(RakNetGUID clientAddress, DataStructures::List<CloudKey> &keys );
|
||||
|
||||
void NotifyClientSubscribersOfDataChange( CloudData *cloudData, CloudKey &key, DataStructures::OrderedList<RakNetGUID, RakNetGUID> &subscribers, bool wasUpdated );
|
||||
void NotifyClientSubscribersOfDataChange( CloudQueryRow *row, DataStructures::OrderedList<RakNetGUID, RakNetGUID> &subscribers, bool wasUpdated );
|
||||
void NotifyServerSubscribersOfDataChange( CloudData *cloudData, CloudKey &key, bool wasUpdated );
|
||||
|
||||
struct RemoteServer
|
||||
{
|
||||
RakNetGUID serverAddress;
|
||||
// This server needs to know about these keys when they are updated or deleted
|
||||
DataStructures::OrderedList<CloudKey,CloudKey,CloudKeyComp> subscribedKeys;
|
||||
// This server has uploaded these keys, and needs to know about Get() requests
|
||||
DataStructures::OrderedList<CloudKey,CloudKey,CloudKeyComp> uploadedKeys;
|
||||
|
||||
// Just for processing
|
||||
bool workingFlag;
|
||||
|
||||
// If false, we don't know what keys they have yet, so send everything
|
||||
bool gotSubscribedAndUploadedKeys;
|
||||
};
|
||||
|
||||
static int RemoteServerComp(const RakNetGUID &key, RemoteServer* const &data );
|
||||
DataStructures::OrderedList<RakNetGUID, RemoteServer*, CloudServer::RemoteServerComp> remoteServers;
|
||||
|
||||
struct BufferedGetResponseFromServer
|
||||
{
|
||||
void Clear(CloudAllocator *allocator);
|
||||
|
||||
RakNetGUID serverAddress;
|
||||
CloudQueryResult queryResult;
|
||||
bool gotResult;
|
||||
};
|
||||
|
||||
struct CloudQueryWithAddresses
|
||||
{
|
||||
// Inputs
|
||||
CloudQuery cloudQuery;
|
||||
DataStructures::List<RakNetGUID> specificSystems;
|
||||
|
||||
void Serialize(bool writeToBitstream, BitStream *bitStream);
|
||||
};
|
||||
|
||||
static int BufferedGetResponseFromServerComp(const RakNetGUID &key, BufferedGetResponseFromServer* const &data );
|
||||
struct GetRequest
|
||||
{
|
||||
void Clear(CloudAllocator *allocator);
|
||||
bool AllRemoteServersHaveResponded(void) const;
|
||||
CloudQueryWithAddresses cloudQueryWithAddresses;
|
||||
|
||||
// When request started. If takes too long for a response from another system, can abort remaining systems
|
||||
SLNet::Time requestStartTime;
|
||||
|
||||
// Assigned by server that gets the request to identify response. See nextGetRequestId
|
||||
uint32_t requestId;
|
||||
|
||||
RakNetGUID requestingClient;
|
||||
|
||||
DataStructures::OrderedList<RakNetGUID, BufferedGetResponseFromServer*, CloudServer::BufferedGetResponseFromServerComp> remoteServerResponses;
|
||||
};
|
||||
static int GetRequestComp(const uint32_t &key, GetRequest* const &data );
|
||||
DataStructures::OrderedList<uint32_t, GetRequest*, CloudServer::GetRequestComp> getRequests;
|
||||
SLNet::Time nextGetRequestsCheck;
|
||||
|
||||
uint32_t nextGetRequestId;
|
||||
|
||||
void ProcessAndTransmitGetRequest(GetRequest *getRequest);
|
||||
|
||||
void ProcessCloudQueryWithAddresses(
|
||||
CloudServer::CloudQueryWithAddresses &cloudQueryWithAddresses,
|
||||
DataStructures::List<CloudData*> &cloudDataResultList,
|
||||
DataStructures::List<CloudKey> &cloudKeyResultList
|
||||
);
|
||||
|
||||
void SendUploadedAndSubscribedKeysToServer( RakNetGUID systemAddress );
|
||||
void SendUploadedKeyToServers( CloudKey &cloudKey );
|
||||
void SendSubscribedKeyToServers( CloudKey &cloudKey );
|
||||
void RemoveUploadedKeyFromServers( CloudKey &cloudKey );
|
||||
void RemoveSubscribedKeyFromServers( CloudKey &cloudKey );
|
||||
|
||||
void OnSendUploadedAndSubscribedKeysToServer( Packet *packet );
|
||||
void OnSendUploadedKeyToServers( Packet *packet );
|
||||
void OnSendSubscribedKeyToServers( Packet *packet );
|
||||
void OnRemoveUploadedKeyFromServers( Packet *packet );
|
||||
void OnRemoveSubscribedKeyFromServers( Packet *packet );
|
||||
void OnServerDataChanged( Packet *packet );
|
||||
|
||||
void GetServersWithUploadedKeys(
|
||||
DataStructures::List<CloudKey> &keys,
|
||||
DataStructures::List<RemoteServer*> &remoteServersWithData
|
||||
);
|
||||
|
||||
CloudServer::CloudDataList *GetOrAllocateCloudDataList(CloudKey key, bool *dataRepositoryExists, unsigned int &dataRepositoryIndex);
|
||||
|
||||
void UnsubscribeFromKey(RemoteCloudClient *remoteCloudClient, RakNetGUID remoteCloudClientGuid, unsigned int keySubscriberIndex, CloudKey &cloudKey, DataStructures::List<RakNetGUID> &specificSystems);
|
||||
void RemoveSpecificSubscriber(RakNetGUID specificSubscriber, CloudDataList *cloudDataList, RakNetGUID remoteCloudClientGuid);
|
||||
|
||||
DataStructures::List<CloudServerQueryFilter*> queryFilters;
|
||||
|
||||
SystemAddress forceAddress;
|
||||
};
|
||||
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Key subscription
|
||||
//
|
||||
// A given system can subscribe to one or more keys.
|
||||
// The subscription can be further be defined as only subscribing to keys uploaded by or changed by a given system.
|
||||
// It is possible to subscribe to keys not yet uploaded, or uploaded to another system
|
||||
//
|
||||
// Operations:
|
||||
//
|
||||
// 1. SubscribeToKey() - Get() operation with subscription
|
||||
// A. Add to key subscription list for the client, which contains a keyId / specificUploaderList pair
|
||||
// B. Send to remote servers that for this key, they should send us updates
|
||||
// C. (Done, get operation returns current values)
|
||||
//
|
||||
// 2. UpdateData() - Post() operation
|
||||
// A. Find all subscribers to this data, for the uploading system.
|
||||
// B. Send them the uploaded data
|
||||
// C. Find all servers that subscribe to this data
|
||||
// D. Send them the uploaded data
|
||||
//
|
||||
// 3. DeleteData() - Release() operation
|
||||
// A. Find all subscribers to this data, for the deleting system.
|
||||
// B. Inform them of the deletion
|
||||
// C. Find all servers that subscribe to this data
|
||||
// D. Inform them of the deletion
|
||||
//
|
||||
// 4. Unsubscribe()
|
||||
// A. Find this subscriber, and remove their subscription
|
||||
// B. If no one else is subscribing to this key for any system, notify remote servers we no longer need subscription updates
|
||||
//
|
||||
// Internal operations:
|
||||
//
|
||||
// 1. Find if any connected client has subscribed to a given key
|
||||
// A. This is used add and remove our subscription for this key to remote servers
|
||||
//
|
||||
// 2. For a given key and updating address, find all connected clients that care
|
||||
// A. First find connected clients that have subscribed to this key, regardless of address
|
||||
// B. Then find connected clients that have subscribed to this key for this particular address
|
||||
//
|
||||
// 3. Find all remote servers that have subscribed to a given key
|
||||
// A. This is so when the key is updated or deleted, we know who to send it to
|
||||
//
|
||||
// 4. For a given client (such as on disconnect), remove all records of their subscriptions
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
152
Source/include/slikenet/CommandParserInterface.h
Normal file
152
Source/include/slikenet/CommandParserInterface.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file CommandParserInterface.h
|
||||
/// \brief Contains CommandParserInterface , from which you derive custom command parsers
|
||||
///
|
||||
|
||||
|
||||
#ifndef __COMMAND_PARSER_INTERFACE
|
||||
#define __COMMAND_PARSER_INTERFACE
|
||||
|
||||
#include "memoryoverride.h"
|
||||
#include "types.h"
|
||||
#include "DS_OrderedList.h"
|
||||
#include "Export.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
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 );
|
||||
|
||||
/// \brief The interface used by command parsers.
|
||||
/// \details 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.
|
||||
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;
|
||||
|
||||
/// \brief 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(const SystemAddress &systemAddress, TransportInterface *transport);
|
||||
|
||||
/// \brief 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(const SystemAddress &systemAddress, TransportInterface *transport);
|
||||
|
||||
/// \brief 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, const SystemAddress &systemAddress)=0;
|
||||
|
||||
/// \brief 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, const SystemAddress &systemAddress, const char *originalString)=0;
|
||||
|
||||
/// \brief This is called every time transport interface is registered.
|
||||
/// \details 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, const SystemAddress &systemAddress);
|
||||
|
||||
static const unsigned char VARIABLE_NUMBER_OF_PARAMETERS;
|
||||
|
||||
// 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);
|
||||
|
||||
/// \brief Just writes a string to the remote system based on the result ( \a res ) of your operation
|
||||
/// \details 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, const SystemAddress &systemAddress);
|
||||
virtual void ReturnResult(char *res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress);
|
||||
virtual void ReturnResult(SystemAddress res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress);
|
||||
virtual void ReturnResult(int res, const char *command,TransportInterface *transport, const SystemAddress &systemAddress);
|
||||
|
||||
/// \brief Just writes a string to the remote system when you are calling a function that has no return value.
|
||||
/// \details 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, const SystemAddress &systemAddress);
|
||||
|
||||
protected:
|
||||
DataStructures::OrderedList<const char*, RegisteredCommand, RegisteredCommandComp> commandList;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
131
Source/include/slikenet/ConnectionGraph2.h
Normal file
131
Source/include/slikenet/ConnectionGraph2.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file ConnectionGraph2.h
|
||||
/// \brief Connection graph plugin, version 2. Tells new systems about existing and new connections
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_ConnectionGraph2==1
|
||||
|
||||
#ifndef __CONNECTION_GRAPH_2_H
|
||||
#define __CONNECTION_GRAPH_2_H
|
||||
|
||||
#include "memoryoverride.h"
|
||||
#include "types.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "DS_List.h"
|
||||
#include "DS_WeightedGraph.h"
|
||||
#include "GetTime.h"
|
||||
#include "Export.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
|
||||
/// \brief A one hop connection graph.
|
||||
/// \details Sends ID_REMOTE_CONNECTION_LOST, ID_REMOTE_DISCONNECTION_NOTIFICATION, ID_REMOTE_NEW_INCOMING_CONNECTION<BR>
|
||||
/// All identifiers are followed by SystemAddress, then RakNetGUID
|
||||
/// Also stores the list for you, which you can access with GetConnectionListForRemoteSystem
|
||||
/// \ingroup CONNECTION_GRAPH_GROUP
|
||||
class RAK_DLL_EXPORT ConnectionGraph2 : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(ConnectionGraph2)
|
||||
|
||||
ConnectionGraph2();
|
||||
~ConnectionGraph2();
|
||||
|
||||
/// \brief Given a remote system identified by RakNetGUID, return the list of SystemAddresses and RakNetGUIDs they are connected to
|
||||
/// \param[in] remoteSystemGuid Which system we are referring to. This only works for remote systems, not ourselves.
|
||||
/// \param[out] saOut A preallocated array to hold the output list of SystemAddress. Can be 0 if you don't care.
|
||||
/// \param[out] guidOut A preallocated array to hold the output list of RakNetGUID. Can be 0 if you don't care.
|
||||
/// \param[in,out] outLength On input, the size of \a saOut and \a guidOut. On output, modified to reflect the number of elements actually written
|
||||
/// \return True if \a remoteSystemGuid was found. Otherwise false, and \a saOut, \a guidOut remain unchanged. \a outLength will be set to 0.
|
||||
bool GetConnectionListForRemoteSystem(RakNetGUID remoteSystemGuid, SystemAddress *saOut, RakNetGUID *guidOut, unsigned int *outLength);
|
||||
|
||||
/// Returns if g1 is connected to g2
|
||||
bool ConnectionExists(RakNetGUID g1, RakNetGUID g2);
|
||||
|
||||
/// Returns the average ping between two systems in the connection graph. Returns -1 if no connection exists between those systems
|
||||
uint16_t GetPingBetweenSystems(RakNetGUID g1, RakNetGUID g2) const;
|
||||
|
||||
/// Returns the system with the lowest average ping among all its connections.
|
||||
/// If you need one system in the peer to peer group to relay data, have the FullyConnectedMesh2 host call this function after host migration, and use that system
|
||||
RakNetGUID GetLowestAveragePingSystem(void) const;
|
||||
|
||||
/// \brief If called with false, then new connections are only added to the connection graph when you call ProcessNewConnection();
|
||||
/// \details This is useful if you want to perform validation before connecting a system to a mesh, or if you want a submesh (for example a server cloud)
|
||||
/// \param[in] b True to automatically call ProcessNewConnection() on any new connection, false to not do so. Defaults to true.
|
||||
void SetAutoProcessNewConnections(bool b);
|
||||
|
||||
/// \brief Returns value passed to SetAutoProcessNewConnections()
|
||||
/// \return Value passed to SetAutoProcessNewConnections(), or the default of true if it was never called
|
||||
bool GetAutoProcessNewConnections(void) const;
|
||||
|
||||
/// \brief If you call SetAutoProcessNewConnections(false);, then you will need to manually call ProcessNewConnection() on new connections
|
||||
/// \details On ID_NEW_INCOMING_CONNECTION or ID_CONNECTION_REQUEST_ACCEPTED, adds that system to the graph
|
||||
/// Do not call ProcessNewConnection() manually otherwise
|
||||
/// \param[in] The packet->SystemAddress member
|
||||
/// \param[in] The packet->guid member
|
||||
void AddParticipant(const SystemAddress &systemAddress, RakNetGUID rakNetGUID);
|
||||
|
||||
/// Get the participants added with AddParticipant()
|
||||
/// \param[out] participantList Participants added with AddParticipant();
|
||||
void GetParticipantList(DataStructures::OrderedList<RakNetGUID, RakNetGUID> &participantList);
|
||||
|
||||
/// \internal
|
||||
struct SystemAddressAndGuid
|
||||
{
|
||||
SystemAddress systemAddress;
|
||||
RakNetGUID guid;
|
||||
uint16_t sendersPingToThatSystem;
|
||||
};
|
||||
/// \internal
|
||||
static int SystemAddressAndGuidComp( const SystemAddressAndGuid &key, const SystemAddressAndGuid &data );
|
||||
|
||||
/// \internal
|
||||
struct RemoteSystem
|
||||
{
|
||||
DataStructures::OrderedList<SystemAddressAndGuid,SystemAddressAndGuid,ConnectionGraph2::SystemAddressAndGuidComp> remoteConnections;
|
||||
RakNetGUID guid;
|
||||
};
|
||||
/// \internal
|
||||
static int RemoteSystemComp( const RakNetGUID &key, RemoteSystem * const &data );
|
||||
|
||||
protected:
|
||||
/// \internal
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
/// \internal
|
||||
virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);
|
||||
/// \internal
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
|
||||
// List of systems I am connected to, which in turn stores which systems they are connected to
|
||||
DataStructures::OrderedList<RakNetGUID, RemoteSystem*, ConnectionGraph2::RemoteSystemComp> remoteSystems;
|
||||
|
||||
bool autoProcessNewConnections;
|
||||
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif // #ifndef __CONNECTION_GRAPH_2_H
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
89
Source/include/slikenet/ConsoleServer.h
Normal file
89
Source/include/slikenet/ConsoleServer.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file ConsoleServer.h
|
||||
/// \brief Contains ConsoleServer , used to plugin to your game to accept remote console-based connections
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_ConsoleServer==1
|
||||
|
||||
#ifndef __CONSOLE_SERVER_H
|
||||
#define __CONSOLE_SERVER_H
|
||||
|
||||
#include "memoryoverride.h"
|
||||
#include "DS_List.h"
|
||||
#include "types.h"
|
||||
#include "Export.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class TransportInterface;
|
||||
class CommandParserInterface;
|
||||
|
||||
|
||||
/// \brief The main entry point for the server portion of your remote console application support.
|
||||
/// \details 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:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(ConsoleServer)
|
||||
|
||||
ConsoleServer();
|
||||
~ConsoleServer();
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
/// \brief Add an implementation of CommandParserInterface to the list of command parsers.
|
||||
/// \param[in] commandParserInterface The command parser referred to
|
||||
void AddCommandParser(CommandParserInterface *commandParserInterface);
|
||||
|
||||
/// \brief Remove an implementation of CommandParserInterface previously added with AddCommandParser().
|
||||
/// \param[in] commandParserInterface The command parser referred to
|
||||
void RemoveCommandParser(CommandParserInterface *commandParserInterface);
|
||||
|
||||
/// \brief Call update to read packet sent from your TransportInterface.
|
||||
/// You should do this fairly frequently.
|
||||
void Update(void);
|
||||
|
||||
/// \brief Sets a prompt to show when waiting for user input.
|
||||
/// \details Pass an empty string to clear the prompt
|
||||
/// Defaults to no prompt
|
||||
/// \param[in] _prompt Null-terminated string of the prompt to use. If you want a newline, be sure to use /r/n
|
||||
void SetPrompt(const char *_prompt);
|
||||
|
||||
protected:
|
||||
void ListParsers(SystemAddress systemAddress);
|
||||
void ShowPrompt(SystemAddress systemAddress);
|
||||
TransportInterface *transport;
|
||||
DataStructures::List<CommandParserInterface *> commandParserList;
|
||||
char* password[256];
|
||||
char *prompt;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
311
Source/include/slikenet/DR_SHA1.h
Normal file
311
Source/include/slikenet/DR_SHA1.h
Normal file
@ -0,0 +1,311 @@
|
||||
/*
|
||||
100% free public domain implementation of the SHA-1 algorithm
|
||||
by Dominik Reichl <dominik.reichl@t-online.de>
|
||||
Web: http://www.dominik-reichl.de/
|
||||
|
||||
Version 2.1 - 2012-06-19
|
||||
- Deconstructor (resetting internal variables) is now only
|
||||
implemented if SHA1_WIPE_VARIABLES is defined (which is the
|
||||
default).
|
||||
- Renamed inclusion guard to contain a GUID.
|
||||
- Demo application is now using C++/STL objects and functions.
|
||||
- Unicode build of the demo application now outputs the hashes of both
|
||||
the ANSI and Unicode representations of strings.
|
||||
- Various other demo application improvements.
|
||||
|
||||
Version 2.0 - 2012-06-14
|
||||
- Added 'limits.h' include.
|
||||
- Renamed inclusion guard and macros for compliancy (names beginning
|
||||
with an underscore are reserved).
|
||||
|
||||
Version 1.9 - 2011-11-10
|
||||
- Added Unicode test vectors.
|
||||
- Improved support for hashing files using the HashFile method that
|
||||
are larger than 4 GB.
|
||||
- Improved file hashing performance (by using a larger buffer).
|
||||
- Disabled unnecessary compiler warnings.
|
||||
- Internal variables are now private.
|
||||
|
||||
Version 1.8 - 2009-03-16
|
||||
- Converted project files to Visual Studio 2008 format.
|
||||
- Added Unicode support for HashFile utility method.
|
||||
- Added support for hashing files using the HashFile method that are
|
||||
larger than 2 GB.
|
||||
- HashFile now returns an error code instead of copying an error
|
||||
message into the output buffer.
|
||||
- GetHash now returns an error code and validates the input parameter.
|
||||
- Added ReportHashStl STL utility method.
|
||||
- Added REPORT_HEX_SHORT reporting mode.
|
||||
- Improved Linux compatibility of test program.
|
||||
|
||||
Version 1.7 - 2006-12-21
|
||||
- Fixed buffer underrun warning that appeared when compiling with
|
||||
Borland C Builder (thanks to Rex Bloom and Tim Gallagher for the
|
||||
patch).
|
||||
- Breaking change: ReportHash writes the final hash to the start
|
||||
of the buffer, i.e. it's not appending it to the string anymore.
|
||||
- Made some function parameters const.
|
||||
- Added Visual Studio 2005 project files to demo project.
|
||||
|
||||
Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
|
||||
- You can set the endianness in your files, no need to modify the
|
||||
header file of the CSHA1 class anymore.
|
||||
- Aligned data support.
|
||||
- Made support/compilation of the utility functions (ReportHash and
|
||||
HashFile) optional (useful when bytes count, for example in embedded
|
||||
environments).
|
||||
|
||||
Version 1.5 - 2005-01-01
|
||||
- 64-bit compiler compatibility added.
|
||||
- Made variable wiping optional (define SHA1_WIPE_VARIABLES).
|
||||
- Removed unnecessary variable initializations.
|
||||
- ROL32 improvement for the Microsoft compiler (using _rotl).
|
||||
|
||||
Version 1.4 - 2004-07-22
|
||||
- CSHA1 now compiles fine with GCC 3.3 under Mac OS X (thanks to Larry
|
||||
Hastings).
|
||||
|
||||
Version 1.3 - 2003-08-17
|
||||
- Fixed a small memory bug and made a buffer array a class member to
|
||||
ensure correct working when using multiple CSHA1 class instances at
|
||||
one time.
|
||||
|
||||
Version 1.2 - 2002-11-16
|
||||
- Borlands C++ compiler seems to have problems with string addition
|
||||
using sprintf. Fixed the bug which caused the digest report function
|
||||
not to work properly. CSHA1 is now Borland compatible.
|
||||
|
||||
Version 1.1 - 2002-10-11
|
||||
- Removed two unnecessary header file includes and changed BOOL to
|
||||
bool. Fixed some minor bugs in the web page contents.
|
||||
|
||||
Version 1.0 - 2002-06-20
|
||||
- First official release.
|
||||
|
||||
================ Test Vectors ================
|
||||
|
||||
SHA1("abc" in ANSI) =
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
SHA1("abc" in Unicode LE) =
|
||||
9F04F41A 84851416 2050E3D6 8C1A7ABB 441DC2B5
|
||||
|
||||
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
in ANSI) =
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
in Unicode LE) =
|
||||
51D7D876 9AC72C40 9C5B0E3F 69C60ADC 9A039014
|
||||
|
||||
SHA1(A million repetitions of "a" in ANSI) =
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
SHA1(A million repetitions of "a" in Unicode LE) =
|
||||
C4609560 A108A0C6 26AA7F2B 38A65566 739353C5
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file was taken from RakNet 4.082.
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications in this file are put under the public domain.
|
||||
* Alternatively you are permitted to license the modifications under the MIT license, if you so desire. The
|
||||
* license can be found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifndef SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
|
||||
#define SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
|
||||
|
||||
// KevinJ:
|
||||
#include "memoryoverride.h"
|
||||
#include <stdio.h> // Needed for file access
|
||||
|
||||
#include <memory.h> // Needed for memset and memcpy
|
||||
|
||||
#include <string.h> // Needed for strcat and strcpy
|
||||
#include "Export.h"
|
||||
//#define MAX_FILE_READ_BUFFER 8000
|
||||
#define SHA1_LENGTH 20
|
||||
|
||||
|
||||
|
||||
#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
|
||||
#define SHA1_UTILITY_FUNCTIONS
|
||||
#endif
|
||||
|
||||
#if !defined(SHA1_STL_FUNCTIONS) && !defined(SHA1_NO_STL_FUNCTIONS)
|
||||
#define SHA1_STL_FUNCTIONS
|
||||
#if !defined(SHA1_UTILITY_FUNCTIONS)
|
||||
#error STL functions require SHA1_UTILITY_FUNCTIONS.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef SHA1_STL_FUNCTIONS
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
// You can define the endian mode in your files without modifying the SHA-1
|
||||
// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
|
||||
// in your files, before including the DR_SHA1.h header file. If you don't
|
||||
// define anything, the class defaults to little endian.
|
||||
#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
|
||||
#define SHA1_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
// If you want variable wiping, #define SHA1_WIPE_VARIABLES, if not,
|
||||
// #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
|
||||
// defaults to wiping.
|
||||
#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
|
||||
#define SHA1_WIPE_VARIABLES
|
||||
#endif
|
||||
|
||||
#if defined(SHA1_HAS_TCHAR)
|
||||
#include <tchar.h>
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#include <tchar.h>
|
||||
#else
|
||||
#ifndef TCHAR
|
||||
#define TCHAR char
|
||||
#endif
|
||||
#ifndef _T
|
||||
#define _T(__x) (__x)
|
||||
#define _tmain main
|
||||
#define _tprintf printf
|
||||
#define _getts gets
|
||||
#define _tcslen strlen
|
||||
#define _tfopen fopen
|
||||
#define _tcscpy strcpy
|
||||
#define _tcscat strcat
|
||||
#define _sntprintf snprintf
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Define variable types
|
||||
|
||||
#ifndef UINT_8
|
||||
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||
#define UINT_8 unsigned __int8
|
||||
#else // !_MSC_VER
|
||||
#define UINT_8 unsigned char
|
||||
#endif // _MSC_VER
|
||||
#endif
|
||||
|
||||
#ifndef UINT_32
|
||||
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||
#define UINT_32 unsigned __int32
|
||||
#else // !_MSC_VER
|
||||
#if (ULONG_MAX == 0xFFFFFFFFUL)
|
||||
#define UINT_32 unsigned long
|
||||
#else
|
||||
#define UINT_32 unsigned int
|
||||
#endif
|
||||
#endif // _MSC_VER
|
||||
#endif // UINT_32
|
||||
|
||||
#ifndef INT_64
|
||||
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||
#define INT_64 __int64
|
||||
#else // !_MSC_VER
|
||||
#define INT_64 long long
|
||||
#endif // _MSC_VER
|
||||
#endif // INT_64
|
||||
|
||||
#ifndef UINT_64
|
||||
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||
#define UINT_64 unsigned __int64
|
||||
#else // !_MSC_VER
|
||||
#define UINT_64 unsigned long long
|
||||
#endif // _MSC_VER
|
||||
#endif // UINT_64
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Declare SHA-1 workspace
|
||||
|
||||
typedef union
|
||||
{
|
||||
UINT_8 c[64];
|
||||
UINT_32 l[16];
|
||||
} SHA1_WORKSPACE_BLOCK;
|
||||
|
||||
class RAK_DLL_EXPORT CSHA1
|
||||
{
|
||||
public:
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
// Different formats for ReportHash(Stl)
|
||||
enum REPORT_TYPE
|
||||
{
|
||||
REPORT_HEX = 0,
|
||||
REPORT_DIGIT = 1,
|
||||
REPORT_HEX_SHORT = 2
|
||||
};
|
||||
#endif
|
||||
|
||||
// Constructor and destructor
|
||||
CSHA1();
|
||||
|
||||
#ifdef SHA1_WIPE_VARIABLES
|
||||
~CSHA1();
|
||||
#endif
|
||||
|
||||
void Reset();
|
||||
|
||||
// Hash in binary data and strings
|
||||
void Update(const UINT_8* pbData, UINT_32 uLen);
|
||||
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
// Hash in file contents
|
||||
bool HashFile(const TCHAR* tszFileName);
|
||||
#endif
|
||||
|
||||
// Finalize hash; call it before using ReportHash(Stl)
|
||||
void Final();
|
||||
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
bool ReportHash(TCHAR* tszReport, REPORT_TYPE rtReportType = REPORT_HEX) const;
|
||||
#endif
|
||||
|
||||
#ifdef SHA1_STL_FUNCTIONS
|
||||
bool ReportHashStl(std::basic_string<TCHAR>& strOut, REPORT_TYPE rtReportType =
|
||||
REPORT_HEX) const;
|
||||
#endif
|
||||
|
||||
// Get the raw message digest (20 bytes)
|
||||
bool GetHash(UINT_8* pbDest20) const;
|
||||
|
||||
unsigned char * GetHash( void ) const;
|
||||
// KevinJ: http://cseweb.ucsd.edu/~mihir/papers/hmac-cb.pdf
|
||||
static void HMAC(unsigned char *sharedKey, int sharedKeyLength, unsigned char *data, int dataLength, unsigned char output[SHA1_LENGTH]);
|
||||
|
||||
private:
|
||||
// Private SHA-1 transformation
|
||||
void Transform(UINT_32* pState, const UINT_8* pBuffer);
|
||||
|
||||
// Member variables
|
||||
UINT_32 m_state[5];
|
||||
UINT_32 m_count[2];
|
||||
UINT_32 m_reserved0[1]; // Memory alignment padding
|
||||
UINT_8 m_buffer[64];
|
||||
UINT_8 m_digest[20];
|
||||
UINT_32 m_reserved1[3]; // Memory alignment padding
|
||||
|
||||
UINT_8 m_workspace[64];
|
||||
SHA1_WORKSPACE_BLOCK* m_block; // SHA1 pointer to the byte array above
|
||||
};
|
||||
|
||||
#endif // SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
|
||||
1157
Source/include/slikenet/DS_BPlusTree.h
Normal file
1157
Source/include/slikenet/DS_BPlusTree.h
Normal file
File diff suppressed because it is too large
Load Diff
1132
Source/include/slikenet/DS_BinarySearchTree.h
Normal file
1132
Source/include/slikenet/DS_BinarySearchTree.h
Normal file
File diff suppressed because it is too large
Load Diff
59
Source/include/slikenet/DS_BytePool.h
Normal file
59
Source/include/slikenet/DS_BytePool.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_BytePool.h
|
||||
///
|
||||
|
||||
|
||||
#ifndef __BYTE_POOL_H
|
||||
#define __BYTE_POOL_H
|
||||
|
||||
#include "memoryoverride.h"
|
||||
#include "DS_MemoryPool.h"
|
||||
#include "Export.h"
|
||||
#include "SimpleMutex.h"
|
||||
#include "assert.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, const char *file, unsigned int line);
|
||||
void Release(unsigned char *data, const char *file, unsigned int line);
|
||||
void Clear(const char *file, unsigned int line);
|
||||
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
|
||||
52
Source/include/slikenet/DS_ByteQueue.h
Normal file
52
Source/include/slikenet/DS_ByteQueue.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_ByteQueue.h
|
||||
/// \internal
|
||||
/// \brief Byte queue
|
||||
///
|
||||
|
||||
|
||||
#ifndef __BYTE_QUEUE_H
|
||||
#define __BYTE_QUEUE_H
|
||||
|
||||
#include "memoryoverride.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, const char *file, unsigned int line);
|
||||
bool ReadBytes(char *out, unsigned maxLengthToRead, bool peek);
|
||||
unsigned GetBytesWritten(void) const;
|
||||
char* PeekContiguousBytes(unsigned int *outLength) const;
|
||||
void IncrementReadOffset(unsigned length);
|
||||
void DecrementReadOffset(unsigned length);
|
||||
void Clear(const char *file, unsigned int line);
|
||||
void Print(void);
|
||||
|
||||
protected:
|
||||
char *data;
|
||||
unsigned readOffset, writeOffset, lengthAllocated;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
362
Source/include/slikenet/DS_Hash.h
Normal file
362
Source/include/slikenet/DS_Hash.h
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \internal
|
||||
/// \brief Hashing container
|
||||
///
|
||||
|
||||
|
||||
#ifndef __HASH_H
|
||||
#define __HASH_H
|
||||
|
||||
#include "assert.h"
|
||||
#include <string.h> // memmove
|
||||
#include "Export.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "string.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
|
||||
{
|
||||
struct HashIndex
|
||||
{
|
||||
unsigned int primaryIndex;
|
||||
unsigned int secondaryIndex;
|
||||
bool IsInvalid(void) const {return primaryIndex==(unsigned int) -1;}
|
||||
void SetInvalid(void) {primaryIndex=(unsigned int) -1; secondaryIndex=(unsigned int) -1;}
|
||||
};
|
||||
|
||||
/// \brief Using a string as a identifier for a node, store an allocated pointer to that node
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
class RAK_DLL_EXPORT Hash
|
||||
{
|
||||
public:
|
||||
/// Default constructor
|
||||
Hash();
|
||||
|
||||
// Destructor
|
||||
~Hash();
|
||||
|
||||
void Push(key_type key, const data_type &input, const char *file, unsigned int line );
|
||||
data_type* Peek(key_type key );
|
||||
bool Pop(data_type& out, key_type key, const char *file, unsigned int line );
|
||||
bool RemoveAtIndex(HashIndex index, const char *file, unsigned int line );
|
||||
bool Remove(key_type key, const char *file, unsigned int line );
|
||||
HashIndex GetIndexOf(key_type key);
|
||||
bool HasData(key_type key);
|
||||
data_type& ItemAtIndex(const HashIndex &index);
|
||||
key_type KeyAtIndex(const HashIndex &index);
|
||||
void GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const;
|
||||
unsigned int Size(void) const;
|
||||
|
||||
/// \brief Clear the list
|
||||
void Clear( const char *file, unsigned int line );
|
||||
|
||||
struct Node
|
||||
{
|
||||
Node(key_type strIn, const data_type &_data) {string=strIn; data=_data;}
|
||||
key_type string;
|
||||
data_type data;
|
||||
// Next in the list for this key
|
||||
Node *next;
|
||||
};
|
||||
|
||||
protected:
|
||||
void ClearIndex(unsigned int index,const char *file, unsigned int line);
|
||||
Node **nodeList;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
Hash<key_type, data_type, HASH_SIZE, hashFunction>::Hash()
|
||||
{
|
||||
nodeList=0;
|
||||
size=0;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
Hash<key_type, data_type, HASH_SIZE, hashFunction>::~Hash()
|
||||
{
|
||||
Clear(_FILE_AND_LINE_);
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Push(key_type key, const data_type &input, const char *file, unsigned int line )
|
||||
{
|
||||
unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
|
||||
if (nodeList==0)
|
||||
{
|
||||
nodeList= SLNet::OP_NEW_ARRAY<Node *>(HASH_SIZE,file,line);
|
||||
memset(nodeList,0,sizeof(Node *)*HASH_SIZE);
|
||||
}
|
||||
|
||||
Node *newNode= SLNet::OP_NEW_2<Node>(file,line,key,input);
|
||||
newNode->next=nodeList[hashIndex];
|
||||
nodeList[hashIndex]=newNode;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
data_type* Hash<key_type, data_type, HASH_SIZE, hashFunction>::Peek(key_type key )
|
||||
{
|
||||
if (nodeList==0)
|
||||
return 0;
|
||||
|
||||
unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
|
||||
Node *node = nodeList[hashIndex];
|
||||
while (node!=0)
|
||||
{
|
||||
if (node->string==key)
|
||||
return &node->data;
|
||||
node=node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Pop(data_type& out, key_type key, const char *file, unsigned int line )
|
||||
{
|
||||
if (nodeList==0)
|
||||
return false;
|
||||
|
||||
unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
|
||||
Node *node = nodeList[hashIndex];
|
||||
if (node==0)
|
||||
return false;
|
||||
if (node->next==0)
|
||||
{
|
||||
// Only one item.
|
||||
if (node->string==key)
|
||||
{
|
||||
// Delete last item
|
||||
out=node->data;
|
||||
ClearIndex(hashIndex,_FILE_AND_LINE_);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Single item doesn't match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (node->string==key)
|
||||
{
|
||||
// First item does match, but more than one item
|
||||
out=node->data;
|
||||
nodeList[hashIndex]=node->next;
|
||||
SLNet::OP_DELETE(node,file,line);
|
||||
size--;
|
||||
return true;
|
||||
}
|
||||
|
||||
Node *last=node;
|
||||
node=node->next;
|
||||
|
||||
while (node!=0)
|
||||
{
|
||||
// First item does not match, but subsequent item might
|
||||
if (node->string==key)
|
||||
{
|
||||
out=node->data;
|
||||
// Skip over subsequent item
|
||||
last->next=node->next;
|
||||
// Delete existing item
|
||||
SLNet::OP_DELETE(node,file,line);
|
||||
size--;
|
||||
return true;
|
||||
}
|
||||
last=node;
|
||||
node=node->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::RemoveAtIndex(HashIndex index, const char *file, unsigned int line )
|
||||
{
|
||||
if (index.IsInvalid())
|
||||
return false;
|
||||
|
||||
Node *node = nodeList[index.primaryIndex];
|
||||
if (node==0)
|
||||
return false;
|
||||
if (node->next==0)
|
||||
{
|
||||
// Delete last item
|
||||
ClearIndex(index.primaryIndex,file,line);
|
||||
return true;
|
||||
}
|
||||
else if (index.secondaryIndex==0)
|
||||
{
|
||||
// First item does match, but more than one item
|
||||
nodeList[index.primaryIndex]=node->next;
|
||||
SLNet::OP_DELETE(node,file,line);
|
||||
size--;
|
||||
return true;
|
||||
}
|
||||
|
||||
Node *last=node;
|
||||
node=node->next;
|
||||
--index.secondaryIndex;
|
||||
|
||||
while (index.secondaryIndex!=0)
|
||||
{
|
||||
last=node;
|
||||
node=node->next;
|
||||
--index.secondaryIndex;
|
||||
}
|
||||
|
||||
// Skip over subsequent item
|
||||
last->next=node->next;
|
||||
// Delete existing item
|
||||
SLNet::OP_DELETE(node,file,line);
|
||||
size--;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Remove(key_type key, const char *file, unsigned int line )
|
||||
{
|
||||
return RemoveAtIndex(GetIndexOf(key),file,line);
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
HashIndex Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetIndexOf(key_type key)
|
||||
{
|
||||
if (nodeList==0)
|
||||
{
|
||||
HashIndex temp;
|
||||
temp.SetInvalid();
|
||||
return temp;
|
||||
}
|
||||
HashIndex idx;
|
||||
idx.primaryIndex=(*hashFunction)(key) % HASH_SIZE;
|
||||
Node *node = nodeList[idx.primaryIndex];
|
||||
if (node==0)
|
||||
{
|
||||
idx.SetInvalid();
|
||||
return idx;
|
||||
}
|
||||
idx.secondaryIndex=0;
|
||||
while (node!=0)
|
||||
{
|
||||
if (node->string==key)
|
||||
{
|
||||
return idx;
|
||||
}
|
||||
node=node->next;
|
||||
idx.secondaryIndex++;
|
||||
}
|
||||
|
||||
idx.SetInvalid();
|
||||
return idx;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::HasData(key_type key)
|
||||
{
|
||||
return GetIndexOf(key).IsInvalid()==false;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
data_type& Hash<key_type, data_type, HASH_SIZE, hashFunction>::ItemAtIndex(const HashIndex &index)
|
||||
{
|
||||
Node *node = nodeList[index.primaryIndex];
|
||||
RakAssert(node);
|
||||
unsigned int i;
|
||||
for (i=0; i < index.secondaryIndex; i++)
|
||||
{
|
||||
node=node->next;
|
||||
RakAssert(node);
|
||||
}
|
||||
return node->data;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
key_type Hash<key_type, data_type, HASH_SIZE, hashFunction>::KeyAtIndex(const HashIndex &index)
|
||||
{
|
||||
Node *node = nodeList[index.primaryIndex];
|
||||
RakAssert(node);
|
||||
unsigned int i;
|
||||
for (i=0; i < index.secondaryIndex; i++)
|
||||
{
|
||||
node=node->next;
|
||||
RakAssert(node);
|
||||
}
|
||||
return node->string;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Clear(const char *file, unsigned int line)
|
||||
{
|
||||
if (nodeList)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i=0; i < HASH_SIZE; i++)
|
||||
ClearIndex(i,file,line);
|
||||
SLNet::OP_DELETE_ARRAY(nodeList,file,line);
|
||||
nodeList=0;
|
||||
size=0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
void Hash<key_type, data_type, HASH_SIZE, hashFunction>::ClearIndex(unsigned int index,const char *file, unsigned int line)
|
||||
{
|
||||
Node *node = nodeList[index];
|
||||
Node *next;
|
||||
while (node)
|
||||
{
|
||||
next=node->next;
|
||||
SLNet::OP_DELETE(node,file,line);
|
||||
node=next;
|
||||
size--;
|
||||
}
|
||||
nodeList[index]=0;
|
||||
}
|
||||
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
void Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const
|
||||
{
|
||||
if (nodeList==0)
|
||||
return;
|
||||
itemList.Clear(false,_FILE_AND_LINE_);
|
||||
keyList.Clear(false,_FILE_AND_LINE_);
|
||||
|
||||
Node *node;
|
||||
unsigned int i;
|
||||
for (i=0; i < HASH_SIZE; i++)
|
||||
{
|
||||
if (nodeList[i])
|
||||
{
|
||||
node=nodeList[i];
|
||||
while (node)
|
||||
{
|
||||
itemList.Push(node->data,file,line);
|
||||
keyList.Push(node->string,file,line);
|
||||
node=node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
|
||||
unsigned int Hash<key_type, data_type, HASH_SIZE, hashFunction>::Size(void) const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
310
Source/include/slikenet/DS_Heap.h
Normal file
310
Source/include/slikenet/DS_Heap.h
Normal file
@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_Heap.h
|
||||
/// \internal
|
||||
/// \brief Heap (Also serves as a priority queue)
|
||||
///
|
||||
|
||||
|
||||
|
||||
#ifndef __RAKNET_HEAP_H
|
||||
#define __RAKNET_HEAP_H
|
||||
|
||||
#include "memoryoverride.h"
|
||||
#include "DS_List.h"
|
||||
#include "Export.h"
|
||||
#include "assert.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, const char *file, unsigned int line);
|
||||
/// Call before calling PushSeries, for a new series of items
|
||||
void StartSeries(void) {optimizeNextSeriesPush=false;}
|
||||
/// If you are going to push a list of items, where the weights of the items on the list are in order and follow the heap order, PushSeries is faster than Push()
|
||||
void PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line);
|
||||
data_type Pop(const unsigned startingIndex);
|
||||
data_type Peek(const unsigned startingIndex=0) const;
|
||||
weight_type PeekWeight(const unsigned startingIndex=0) const;
|
||||
void Clear(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line);
|
||||
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;
|
||||
bool optimizeNextSeriesPush;
|
||||
};
|
||||
|
||||
template <class weight_type, class data_type, bool isMaxHeap>
|
||||
Heap<weight_type, data_type, isMaxHeap>::Heap()
|
||||
{
|
||||
optimizeNextSeriesPush=false;
|
||||
}
|
||||
|
||||
template <class weight_type, class data_type, bool isMaxHeap>
|
||||
Heap<weight_type, data_type, isMaxHeap>::~Heap()
|
||||
{
|
||||
//Clear(true, _FILE_AND_LINE_);
|
||||
}
|
||||
|
||||
template <class weight_type, class data_type, bool isMaxHeap>
|
||||
void Heap<weight_type, data_type, isMaxHeap>::PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line)
|
||||
{
|
||||
if (optimizeNextSeriesPush==false)
|
||||
{
|
||||
// If the weight of what we are inserting is greater than / less than in order of the heap of every sibling and sibling of parent, then can optimize next push
|
||||
unsigned currentIndex = heap.Size();
|
||||
unsigned parentIndex;
|
||||
if (currentIndex>0)
|
||||
{
|
||||
for (parentIndex = Parent(currentIndex); parentIndex < currentIndex; parentIndex++)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
if (isMaxHeap)
|
||||
{
|
||||
// Every child is less than its parent
|
||||
if (weight>heap[parentIndex].weight)
|
||||
{
|
||||
// Can't optimize
|
||||
Push(weight,data,file,line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Every child is greater than than its parent
|
||||
if (weight<heap[parentIndex].weight)
|
||||
{
|
||||
// Can't optimize
|
||||
Push(weight,data,file,line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parent's subsequent siblings and this row's siblings all are less than / greater than inserted element. Can insert all further elements straight to the end
|
||||
heap.Insert(HeapNode(weight, data), file, line);
|
||||
optimizeNextSeriesPush=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
heap.Insert(HeapNode(weight, data), file, line);
|
||||
}
|
||||
}
|
||||
|
||||
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, const char *file, unsigned int line)
|
||||
{
|
||||
unsigned currentIndex = heap.Size();
|
||||
unsigned parentIndex;
|
||||
heap.Insert(HeapNode(weight, data), file, line);
|
||||
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
|
||||
for(;;)
|
||||
{
|
||||
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>
|
||||
inline 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>
|
||||
inline 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(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line)
|
||||
{
|
||||
heap.Clear(doNotDeallocateSmallBlocks, file, line);
|
||||
}
|
||||
|
||||
template <class weight_type, class data_type, bool isMaxHeap>
|
||||
inline 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>
|
||||
inline 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>
|
||||
inline 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>
|
||||
inline 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
|
||||
79
Source/include/slikenet/DS_HuffmanEncodingTree.h
Normal file
79
Source/include/slikenet/DS_HuffmanEncodingTree.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_HuffmanEncodingTree.h
|
||||
/// \brief \b [Internal] Generates a huffman encoding tree, used for string and global compression.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __HUFFMAN_ENCODING_TREE
|
||||
#define __HUFFMAN_ENCODING_TREE
|
||||
|
||||
#include "memoryoverride.h"
|
||||
#include "DS_HuffmanEncodingTreeNode.h"
|
||||
#include "BitStream.h"
|
||||
#include "Export.h"
|
||||
#include "DS_LinkedList.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
/// 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();
|
||||
|
||||
/// \brief 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, SLNet::BitStream * output );
|
||||
|
||||
// \brief Decodes an array encoded by EncodeArray().
|
||||
unsigned DecodeArray(SLNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output );
|
||||
void DecodeArray( unsigned char *input, BitSize_t sizeInBits, SLNet::BitStream * output );
|
||||
|
||||
/// \brief Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree.
|
||||
void GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] );
|
||||
|
||||
/// \brief 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;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
69
Source/include/slikenet/DS_HuffmanEncodingTreeFactory.h
Normal file
69
Source/include/slikenet/DS_HuffmanEncodingTreeFactory.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_HuffmanEncodingTreeFactory.h
|
||||
/// \internal
|
||||
/// \brief Creates instances of the class HuffmanEncodingTree
|
||||
///
|
||||
|
||||
|
||||
#ifndef __HUFFMAN_ENCODING_TREE_FACTORY
|
||||
#define __HUFFMAN_ENCODING_TREE_FACTORY
|
||||
|
||||
#include "memoryoverride.h"
|
||||
|
||||
namespace SLNet {
|
||||
/// Forward declarations
|
||||
class HuffmanEncodingTree;
|
||||
|
||||
/// \brief Creates instances of the class HuffmanEncodingTree
|
||||
/// \details This class takes a frequency table and given that frequence table, will generate an instance of HuffmanEncodingTree
|
||||
class HuffmanEncodingTreeFactory
|
||||
{
|
||||
public:
|
||||
/// Default constructor
|
||||
HuffmanEncodingTreeFactory();
|
||||
|
||||
/// \brief Reset the frequency table.
|
||||
/// \details You don't need to call this unless you want to reuse the class for a new tree
|
||||
void Reset( void );
|
||||
|
||||
/// \brief 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 );
|
||||
|
||||
/// \brief 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 ] );
|
||||
|
||||
/// \brief Returns the frequency table as a pointer.
|
||||
/// \return the address of the frenquency table
|
||||
unsigned int * GetFrequencyTable( void );
|
||||
|
||||
/// \brief Generate a HuffmanEncodingTree.
|
||||
/// \details 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 ];
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
27
Source/include/slikenet/DS_HuffmanEncodingTreeNode.h
Normal file
27
Source/include/slikenet/DS_HuffmanEncodingTreeNode.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief \b [Internal] A single node in the Huffman Encoding Tree.
|
||||
///
|
||||
|
||||
#ifndef __HUFFMAN_ENCODING_TREE_NODE
|
||||
#define __HUFFMAN_ENCODING_TREE_NODE
|
||||
|
||||
struct HuffmanEncodingTreeNode
|
||||
{
|
||||
unsigned char value;
|
||||
unsigned weight;
|
||||
HuffmanEncodingTreeNode *left;
|
||||
HuffmanEncodingTreeNode *right;
|
||||
HuffmanEncodingTreeNode *parent;
|
||||
};
|
||||
|
||||
#endif
|
||||
1249
Source/include/slikenet/DS_LinkedList.h
Normal file
1249
Source/include/slikenet/DS_LinkedList.h
Normal file
File diff suppressed because it is too large
Load Diff
525
Source/include/slikenet/DS_List.h
Normal file
525
Source/include/slikenet/DS_List.h
Normal file
@ -0,0 +1,525 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017-2018, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_List.h
|
||||
/// \internal
|
||||
/// \brief Array based list.
|
||||
/// \details Usually the Queue class is used instead, since it has all the same functionality and is only worse at random access.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __LIST_H
|
||||
#define __LIST_H
|
||||
|
||||
#include "assert.h"
|
||||
#include <string.h> // memmove
|
||||
#include "Export.h"
|
||||
#include "memoryoverride.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();
|
||||
|
||||
/// \brief Copy constructor.
|
||||
/// \param[in] original_copy The list to duplicate
|
||||
List( const List& original_copy );
|
||||
|
||||
/// \brief Assign one list to another.
|
||||
List& operator= ( const List& original_copy );
|
||||
|
||||
/// \brief 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;
|
||||
|
||||
/// \brief 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;
|
||||
|
||||
/// \brief Push an element at the end of the stack.
|
||||
/// \param[in] input The new element.
|
||||
void Push(const list_type &input, const char *file, unsigned int line );
|
||||
|
||||
/// \brief Pop an element from the end of the stack.
|
||||
/// \pre Size()>0
|
||||
/// \return The element at the end.
|
||||
list_type& Pop(void);
|
||||
|
||||
/// \brief 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, const char *file, unsigned int line );
|
||||
|
||||
/// \brief Insert at the end of the list.
|
||||
/// \param[in] input The new element.
|
||||
void Insert( const list_type &input, const char *file, unsigned int line );
|
||||
|
||||
/// \brief Replace the value at \a position by \a input.
|
||||
/// \details 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, const char *file, unsigned int line );
|
||||
|
||||
/// \brief 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 );
|
||||
|
||||
/// \brief Delete the element at position \a position.
|
||||
/// \param[in] position The index of the element to delete
|
||||
void RemoveAtIndex( const unsigned int position );
|
||||
|
||||
/// \brief 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 );
|
||||
|
||||
/// \brief Delete the element at the end of the list.
|
||||
void RemoveFromEnd(const unsigned num=1);
|
||||
|
||||
/// \brief 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;
|
||||
|
||||
/// \brief Clear the list
|
||||
void Clear( bool doNotDeallocateSmallBlocks, const char *file, unsigned int line );
|
||||
|
||||
/// \brief Preallocate the list, so it needs fewer reallocations at runtime.
|
||||
void Preallocate( unsigned countNeeded, const char *file, unsigned int line );
|
||||
|
||||
/// \brief Frees overallocated members, to use the minimum memory necessary.
|
||||
/// \attention
|
||||
/// This is a slow operation
|
||||
void Compress( const char *file, unsigned int line );
|
||||
|
||||
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)
|
||||
SLNet::OP_DELETE_ARRAY(listArray, _FILE_AND_LINE_);
|
||||
}
|
||||
|
||||
|
||||
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 = SLNet::OP_NEW_ARRAY<list_type >( original_copy.list_size , _FILE_AND_LINE_ );
|
||||
|
||||
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( false, _FILE_AND_LINE_ );
|
||||
|
||||
// Allocate memory for copy
|
||||
|
||||
if ( original_copy.list_size == 0 )
|
||||
{
|
||||
list_size = 0;
|
||||
allocation_size = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
listArray = SLNet::OP_NEW_ARRAY<list_type >( original_copy.list_size , _FILE_AND_LINE_ );
|
||||
|
||||
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, const char *file, unsigned int line)
|
||||
{
|
||||
Insert(input, file, line);
|
||||
}
|
||||
|
||||
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, const char *file, unsigned int line )
|
||||
{
|
||||
RakAssert( position <= list_size );
|
||||
|
||||
// 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 = SLNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
|
||||
|
||||
// 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
|
||||
SLNet::OP_DELETE_ARRAY(listArray, file, line);
|
||||
|
||||
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, const char *file, unsigned int line )
|
||||
{
|
||||
// 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 = SLNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
|
||||
|
||||
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
|
||||
SLNet::OP_DELETE_ARRAY(listArray, file, line);
|
||||
}
|
||||
|
||||
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, const char *file, unsigned int line )
|
||||
{
|
||||
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 = SLNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
|
||||
|
||||
// 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
|
||||
SLNet::OP_DELETE_ARRAY(listArray, file, line);
|
||||
|
||||
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, const char *file, unsigned int line )
|
||||
{
|
||||
if ( allocation_size == 0 )
|
||||
return;
|
||||
|
||||
if (allocation_size>512 || doNotDeallocateSmallBlocks==false)
|
||||
{
|
||||
SLNet::OP_DELETE_ARRAY(listArray, file, line);
|
||||
allocation_size = 0;
|
||||
listArray = 0;
|
||||
}
|
||||
list_size = 0;
|
||||
}
|
||||
|
||||
template <class list_type>
|
||||
void List<list_type>::Compress( const char *file, unsigned int line )
|
||||
{
|
||||
list_type * new_array;
|
||||
|
||||
if ( allocation_size == 0 )
|
||||
return ;
|
||||
|
||||
new_array = SLNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
|
||||
|
||||
// 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
|
||||
SLNet::OP_DELETE_ARRAY(listArray, file, line);
|
||||
|
||||
listArray = new_array;
|
||||
}
|
||||
|
||||
template <class list_type>
|
||||
void List<list_type>::Preallocate( unsigned countNeeded, const char *file, unsigned int line )
|
||||
{
|
||||
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 = SLNet::OP_NEW_ARRAY< list_type >( allocation_size , file, line );
|
||||
|
||||
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
|
||||
SLNet::OP_DELETE_ARRAY(listArray, file, line);
|
||||
}
|
||||
|
||||
listArray = new_array;
|
||||
}
|
||||
}
|
||||
|
||||
} // End namespace
|
||||
|
||||
#endif
|
||||
330
Source/include/slikenet/DS_Map.h
Normal file
330
Source/include/slikenet/DS_Map.h
Normal file
@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_Map.h
|
||||
/// \internal
|
||||
/// \brief Map
|
||||
///
|
||||
|
||||
|
||||
#ifndef __RAKNET_MAP_H
|
||||
#define __RAKNET_MAP_H
|
||||
|
||||
#include "DS_OrderedList.h"
|
||||
#include "Export.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "assert.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)
|
||||
{
|
||||
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, _FILE_AND_LINE_));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
bool objectExists;
|
||||
mapNodeList.GetIndexFromKey(key, &objectExists);
|
||||
RakAssert(objectExists==false);
|
||||
#endif
|
||||
SaveLastSearch(key,mapNodeList.Insert(key,MapNode(key,data), true, _FILE_AND_LINE_));
|
||||
}
|
||||
|
||||
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(false, _FILE_AND_LINE_);
|
||||
}
|
||||
|
||||
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
|
||||
358
Source/include/slikenet/DS_MemoryPool.h
Normal file
358
Source/include/slikenet/DS_MemoryPool.h
Normal file
@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_MemoryPool.h
|
||||
///
|
||||
|
||||
|
||||
#ifndef __MEMORY_POOL_H
|
||||
#define __MEMORY_POOL_H
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Use stdlib and not malloc for compatibility
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include "assert.h"
|
||||
#include "Export.h"
|
||||
|
||||
#include "memoryoverride.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 bytes
|
||||
MemoryBlockType *Allocate(const char *file, unsigned int line);
|
||||
void Release(MemoryBlockType *m, const char *file, unsigned int line);
|
||||
void Clear(const char *file, unsigned int line);
|
||||
|
||||
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, const char *file, unsigned int line);
|
||||
|
||||
// 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(_FILE_AND_LINE_);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class MemoryBlockType>
|
||||
void MemoryPool<MemoryBlockType>::SetPageSize(int size)
|
||||
{
|
||||
memoryPoolPageSize=size;
|
||||
}
|
||||
|
||||
template<class MemoryBlockType>
|
||||
MemoryBlockType* MemoryPool<MemoryBlockType>::Allocate(const char *file, unsigned int line)
|
||||
{
|
||||
#ifdef _DISABLE_MEMORY_POOL
|
||||
return (MemoryBlockType*) rakMalloc_Ex(sizeof(MemoryBlockType), file, line);
|
||||
#else
|
||||
|
||||
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_Ex(sizeof(Page), file, line);
|
||||
if (availablePages==0)
|
||||
return 0;
|
||||
availablePagesSize=1;
|
||||
if (InitPage(availablePages, availablePages, file, line)==false)
|
||||
return 0;
|
||||
// If this assert hits, we couldn't allocate even 1 block per page. Increase the page size
|
||||
RakAssert(availablePages->availableStackSize>1);
|
||||
|
||||
return (MemoryBlockType *) availablePages->availableStack[--availablePages->availableStackSize];
|
||||
#endif
|
||||
}
|
||||
template<class MemoryBlockType>
|
||||
void MemoryPool<MemoryBlockType>::Release(MemoryBlockType *m, const char *file, unsigned int line)
|
||||
{
|
||||
#ifdef _DISABLE_MEMORY_POOL
|
||||
rakFree_Ex(m, file, line);
|
||||
return;
|
||||
#else
|
||||
// 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_Ex(curPage->availableStack, file, line );
|
||||
rakFree_Ex(curPage->block, file, line );
|
||||
rakFree_Ex(curPage, file, line );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
template<class MemoryBlockType>
|
||||
void MemoryPool<MemoryBlockType>::Clear(const char *file, unsigned int line)
|
||||
{
|
||||
#ifdef _DISABLE_MEMORY_POOL
|
||||
return;
|
||||
#else
|
||||
Page *cur, *freed;
|
||||
|
||||
if (availablePagesSize>0)
|
||||
{
|
||||
cur = availablePages;
|
||||
for (;;)
|
||||
// do
|
||||
{
|
||||
rakFree_Ex(cur->availableStack, file, line );
|
||||
rakFree_Ex(cur->block, file, line );
|
||||
freed=cur;
|
||||
cur=cur->next;
|
||||
if (cur==availablePages)
|
||||
{
|
||||
rakFree_Ex(freed, file, line );
|
||||
break;
|
||||
}
|
||||
rakFree_Ex(freed, file, line );
|
||||
}// while(cur!=availablePages);
|
||||
}
|
||||
|
||||
if (unavailablePagesSize>0)
|
||||
{
|
||||
cur = unavailablePages;
|
||||
for(;;)
|
||||
//do
|
||||
{
|
||||
rakFree_Ex(cur->availableStack, file, line );
|
||||
rakFree_Ex(cur->block, file, line );
|
||||
freed=cur;
|
||||
cur=cur->next;
|
||||
if (cur==unavailablePages)
|
||||
{
|
||||
rakFree_Ex(freed, file, line );
|
||||
break;
|
||||
}
|
||||
rakFree_Ex(freed, file, line );
|
||||
} // while(cur!=unavailablePages);
|
||||
}
|
||||
|
||||
availablePagesSize=0;
|
||||
unavailablePagesSize=0;
|
||||
#endif
|
||||
}
|
||||
template<class MemoryBlockType>
|
||||
int MemoryPool<MemoryBlockType>::BlocksPerPage(void) const
|
||||
{
|
||||
return memoryPoolPageSize / sizeof(MemoryWithPage);
|
||||
}
|
||||
template<class MemoryBlockType>
|
||||
bool MemoryPool<MemoryBlockType>::InitPage(Page *page, Page *prev, const char *file, unsigned int line)
|
||||
{
|
||||
int i=0;
|
||||
const int bpp = BlocksPerPage();
|
||||
page->block=(MemoryWithPage*) rakMalloc_Ex(memoryPoolPageSize, file, line);
|
||||
if (page->block==0)
|
||||
return false;
|
||||
page->availableStack=(MemoryWithPage**)rakMalloc_Ex(sizeof(MemoryWithPage*)*bpp, file, line);
|
||||
if (page->availableStack==0)
|
||||
{
|
||||
rakFree_Ex(page->block, file, line );
|
||||
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
|
||||
|
||||
/*
|
||||
#include "DS_MemoryPool.h"
|
||||
#include "DS_List.h"
|
||||
|
||||
struct TestMemoryPool
|
||||
{
|
||||
int allocationId;
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
DataStructures::MemoryPool<TestMemoryPool> memoryPool;
|
||||
DataStructures::List<TestMemoryPool*> returnList;
|
||||
|
||||
for (int i=0; i < 100000; i++)
|
||||
returnList.Push(memoryPool.Allocate(_FILE_AND_LINE_), _FILE_AND_LINE_);
|
||||
for (int i=0; i < returnList.Size(); i+=2)
|
||||
{
|
||||
memoryPool.Release(returnList[i], _FILE_AND_LINE_);
|
||||
returnList.RemoveAtIndexFast(i);
|
||||
}
|
||||
for (int i=0; i < 100000; i++)
|
||||
returnList.Push(memoryPool.Allocate(_FILE_AND_LINE_), _FILE_AND_LINE_);
|
||||
while (returnList.Size())
|
||||
{
|
||||
memoryPool.Release(returnList[returnList.Size()-1], _FILE_AND_LINE_);
|
||||
returnList.RemoveAtIndex(returnList.Size()-1);
|
||||
}
|
||||
for (int i=0; i < 100000; i++)
|
||||
returnList.Push(memoryPool.Allocate(_FILE_AND_LINE_), _FILE_AND_LINE_);
|
||||
while (returnList.Size())
|
||||
{
|
||||
memoryPool.Release(returnList[returnList.Size()-1], _FILE_AND_LINE_);
|
||||
returnList.RemoveAtIndex(returnList.Size()-1);
|
||||
}
|
||||
for (int i=0; i < 100000; i++)
|
||||
returnList.Push(memoryPool.Allocate(_FILE_AND_LINE_), _FILE_AND_LINE_);
|
||||
for (int i=100000-1; i <= 0; i-=2)
|
||||
{
|
||||
memoryPool.Release(returnList[i], _FILE_AND_LINE_);
|
||||
returnList.RemoveAtIndexFast(i);
|
||||
}
|
||||
for (int i=0; i < 100000; i++)
|
||||
returnList.Push(memoryPool.Allocate(_FILE_AND_LINE_), _FILE_AND_LINE_);
|
||||
while (returnList.Size())
|
||||
{
|
||||
memoryPool.Release(returnList[returnList.Size()-1], _FILE_AND_LINE_);
|
||||
returnList.RemoveAtIndex(returnList.Size()-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
1660
Source/include/slikenet/DS_Multilist.h
Normal file
1660
Source/include/slikenet/DS_Multilist.h
Normal file
File diff suppressed because it is too large
Load Diff
256
Source/include/slikenet/DS_OrderedChannelHeap.h
Normal file
256
Source/include/slikenet/DS_OrderedChannelHeap.h
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_OrderedChannelHeap.h
|
||||
/// \internal
|
||||
/// \brief Ordered Channel Heap . This is a heap where you add to it on multiple ordered channels, with each channel having a different weight.
|
||||
///
|
||||
|
||||
|
||||
#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 "assert.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 = SLNet::OP_NEW<QueueAndWeight>( _FILE_AND_LINE_ );
|
||||
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)
|
||||
{
|
||||
SLNet::OP_DELETE(map[i], _FILE_AND_LINE_);
|
||||
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++)
|
||||
SLNet::OP_DELETE(map[i], _FILE_AND_LINE_);
|
||||
map.Clear(_FILE_AND_LINE_);
|
||||
heap.Clear(_FILE_AND_LINE_);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
280
Source/include/slikenet/DS_OrderedList.h
Normal file
280
Source/include/slikenet/DS_OrderedList.h
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_OrderedList.h
|
||||
/// \internal
|
||||
/// \brief Quicksort ordered list.
|
||||
///
|
||||
|
||||
#include "DS_List.h"
|
||||
#include "memoryoverride.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, const char *file, unsigned int line, 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, const char *file, unsigned int line);
|
||||
void InsertAtEnd(const data_type &data, const char *file, unsigned int line);
|
||||
void RemoveFromEnd(const unsigned num=1);
|
||||
void Clear(bool doNotDeallocate, const char *file, unsigned int line);
|
||||
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(false, _FILE_AND_LINE_);
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
res = cf(key,orderedList[index]);
|
||||
if (res==0)
|
||||
{
|
||||
*objectExists=true;
|
||||
return (unsigned)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 (unsigned)lowerBound; // No match
|
||||
}
|
||||
|
||||
if (index < 0 || index >= (int) orderedList.Size())
|
||||
{
|
||||
// This should never hit unless the comparison function was inconsistent
|
||||
RakAssert(index && 0);
|
||||
*objectExists=false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, const char *file, unsigned int line, 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!
|
||||
RakAssert(assertOnDuplicate==false);
|
||||
return (unsigned)-1;
|
||||
}
|
||||
|
||||
if (index>=orderedList.Size())
|
||||
{
|
||||
orderedList.Insert(data, file, line);
|
||||
return orderedList.Size()-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
orderedList.Insert(data, index, file, line);
|
||||
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, const char *file, unsigned int line)
|
||||
{
|
||||
orderedList.Insert(data, index, file, line);
|
||||
}
|
||||
|
||||
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, const char *file, unsigned int line)
|
||||
{
|
||||
orderedList.Insert(data, file, line);
|
||||
}
|
||||
|
||||
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, const char *file, unsigned int line)
|
||||
{
|
||||
orderedList.Clear(doNotDeallocate, file, line);
|
||||
}
|
||||
|
||||
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
|
||||
466
Source/include/slikenet/DS_Queue.h
Normal file
466
Source/include/slikenet/DS_Queue.h
Normal file
@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_Queue.h
|
||||
/// \internal
|
||||
/// \brief A queue used by RakNet.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __QUEUE_H
|
||||
#define __QUEUE_H
|
||||
|
||||
// Template classes have to have all the code in the header file
|
||||
#include "assert.h"
|
||||
#include "Export.h"
|
||||
#include "memoryoverride.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( const Queue& original_copy );
|
||||
bool operator= ( const Queue& original_copy );
|
||||
void Push( const queue_type& input, const char *file, unsigned int line );
|
||||
void PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line );
|
||||
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 queue_type PopTail( void );
|
||||
// Debug: Set pointer to 0, for memory leak detection
|
||||
inline queue_type PopDeref( void );
|
||||
inline unsigned int Size( void ) const;
|
||||
inline bool IsEmpty(void) const;
|
||||
inline unsigned int AllocationSize( void ) const;
|
||||
inline void Clear( const char *file, unsigned int line );
|
||||
void Compress( const char *file, unsigned int line );
|
||||
bool Find ( const queue_type& q );
|
||||
void ClearAndForceAllocation( int size, const char *file, unsigned int line ); // 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 = SLNet::OP_NEW_ARRAY<queue_type>(allocation_size, _FILE_AND_LINE_ );
|
||||
allocation_size = 0;
|
||||
array=0;
|
||||
head = 0;
|
||||
tail = 0;
|
||||
}
|
||||
|
||||
template <class queue_type>
|
||||
Queue<queue_type>::~Queue()
|
||||
{
|
||||
if (allocation_size>0)
|
||||
SLNet::OP_DELETE_ARRAY(array, _FILE_AND_LINE_);
|
||||
}
|
||||
|
||||
template <class queue_type>
|
||||
inline queue_type Queue<queue_type>::Pop( void )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
RakAssert( 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>
|
||||
inline queue_type Queue<queue_type>::PopTail( void )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
RakAssert( head != tail );
|
||||
#endif
|
||||
if (tail!=0)
|
||||
{
|
||||
--tail;
|
||||
return ( queue_type ) array[ tail ];
|
||||
}
|
||||
else
|
||||
{
|
||||
tail=allocation_size-1;
|
||||
return ( queue_type ) array[ tail ];
|
||||
}
|
||||
}
|
||||
|
||||
template <class queue_type>
|
||||
inline queue_type Queue<queue_type>::PopDeref( void )
|
||||
{
|
||||
if ( ++head == allocation_size )
|
||||
head = 0;
|
||||
|
||||
queue_type q;
|
||||
if ( head == 0 )
|
||||
{
|
||||
q=array[ allocation_size -1 ];
|
||||
array[ allocation_size -1 ]=0;
|
||||
return q;
|
||||
}
|
||||
|
||||
q=array[ head -1 ];
|
||||
array[ head -1 ]=0;
|
||||
return q;
|
||||
}
|
||||
|
||||
template <class queue_type>
|
||||
void Queue<queue_type>::PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line )
|
||||
{
|
||||
RakAssert(index <= Size());
|
||||
|
||||
// Just force a reallocation, will be overwritten
|
||||
Push(input, file, line );
|
||||
|
||||
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 );
|
||||
#endif
|
||||
|
||||
return ( queue_type ) array[ head ];
|
||||
}
|
||||
|
||||
template <class queue_type>
|
||||
inline queue_type Queue<queue_type>::PeekTail( void ) const
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
RakAssert( head != tail );
|
||||
#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, const char *file, unsigned int line )
|
||||
{
|
||||
if ( allocation_size == 0 )
|
||||
{
|
||||
array = SLNet::OP_NEW_ARRAY<queue_type>(16, file, line );
|
||||
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 = SLNet::OP_NEW_ARRAY<queue_type>((int)allocation_size * 2, file, line );
|
||||
#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
|
||||
SLNet::OP_DELETE_ARRAY(array, file, line);
|
||||
|
||||
array = new_array;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class queue_type>
|
||||
Queue<queue_type>::Queue( const Queue& original_copy )
|
||||
{
|
||||
// Allocate memory for copy
|
||||
|
||||
if ( original_copy.Size() == 0 )
|
||||
{
|
||||
allocation_size = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
array = SLNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ );
|
||||
|
||||
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(_FILE_AND_LINE_);
|
||||
|
||||
// Allocate memory for copy
|
||||
if ( original_copy.Size() == 0 )
|
||||
{
|
||||
allocation_size = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
array = SLNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ );
|
||||
|
||||
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 ( const char *file, unsigned int line )
|
||||
{
|
||||
if ( allocation_size == 0 )
|
||||
return ;
|
||||
|
||||
if (allocation_size > 32)
|
||||
{
|
||||
SLNet::OP_DELETE_ARRAY(array, file, line);
|
||||
allocation_size = 0;
|
||||
}
|
||||
|
||||
head = 0;
|
||||
tail = 0;
|
||||
}
|
||||
|
||||
template <class queue_type>
|
||||
void Queue<queue_type>::Compress ( const char *file, unsigned int line )
|
||||
{
|
||||
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 = SLNet::OP_NEW_ARRAY<queue_type >(newAllocationSize, file, line );
|
||||
|
||||
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
|
||||
SLNet::OP_DELETE_ARRAY(array, file, line);
|
||||
array=new_array;
|
||||
}
|
||||
|
||||
template <class queue_type>
|
||||
bool Queue<queue_type>::Find ( const 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, const char *file, unsigned int line )
|
||||
{
|
||||
SLNet::OP_DELETE_ARRAY(array, file, line);
|
||||
if (size>0)
|
||||
array = SLNet::OP_NEW_ARRAY<queue_type>(size, file, line );
|
||||
else
|
||||
array=0;
|
||||
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
|
||||
|
||||
115
Source/include/slikenet/DS_QueueLinkedList.h
Normal file
115
Source/include/slikenet/DS_QueueLinkedList.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_QueueLinkedList.h
|
||||
/// \internal
|
||||
/// \brief A queue implemented as a linked list.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __QUEUE_LINKED_LIST_H
|
||||
#define __QUEUE_LINKED_LIST_H
|
||||
|
||||
#include "DS_LinkedList.h"
|
||||
#include "Export.h"
|
||||
#include "memoryoverride.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
|
||||
290
Source/include/slikenet/DS_RangeList.h
Normal file
290
Source/include/slikenet/DS_RangeList.h
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017-2018, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_RangeList.h
|
||||
/// \internal
|
||||
/// \brief A queue implemented as a linked list.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __RANGE_LIST_H
|
||||
#define __RANGE_LIST_H
|
||||
|
||||
#include "DS_OrderedList.h"
|
||||
#include "BitStream.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "assert.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.maxIndex) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class range_type>
|
||||
class RAK_DLL_EXPORT RangeList
|
||||
{
|
||||
public:
|
||||
RangeList();
|
||||
~RangeList();
|
||||
void Insert(range_type index);
|
||||
void Clear(void);
|
||||
bool IsWithinRange(range_type value) const;
|
||||
unsigned Size(void) const;
|
||||
unsigned RangeSum(void) const;
|
||||
SLNet::BitSize_t Serialize(SLNet::BitStream *in, SLNet::BitSize_t maxBits, bool clearSerialized);
|
||||
bool Deserialize(SLNet::BitStream *out);
|
||||
|
||||
DataStructures::OrderedList<range_type, RangeNode<range_type>, RangeNodeComp<range_type>> ranges;
|
||||
|
||||
// internal helpers
|
||||
private:
|
||||
static bool DeserializeSingleRange(SLNet::BitStream *out, range_type& min, range_type& max);
|
||||
};
|
||||
|
||||
template <class range_type>
|
||||
SLNet::BitSize_t RangeList<range_type>::Serialize(SLNet::BitStream *in, SLNet::BitSize_t maxBits, bool clearSerialized)
|
||||
{
|
||||
RakAssert(ranges.Size() < (unsigned short)-1);
|
||||
SLNet::BitStream tempBS;
|
||||
SLNet::BitSize_t bitsWritten;
|
||||
unsigned short countWritten;
|
||||
unsigned i;
|
||||
countWritten=0;
|
||||
bitsWritten=0;
|
||||
for (i=0; i < ranges.Size(); i++) {
|
||||
// #med - review this calculation --- shouldn't this be +8 rather than +1 due to minEqualsMax being 1 byte?
|
||||
if ((int)sizeof(unsigned short)*8+bitsWritten+(int)sizeof(range_type)*8*2+1>maxBits) {
|
||||
break;
|
||||
}
|
||||
unsigned char minEqualsMax;
|
||||
if (ranges[i].minIndex==ranges[i].maxIndex) {
|
||||
minEqualsMax=1;
|
||||
} else {
|
||||
minEqualsMax=0;
|
||||
}
|
||||
tempBS.Write(minEqualsMax); // Use one byte, instead of one bit, for speed, as this is done a lot
|
||||
tempBS.Write(ranges[i].minIndex);
|
||||
bitsWritten+=sizeof(range_type)*8+8;
|
||||
if (ranges[i].minIndex!=ranges[i].maxIndex) {
|
||||
tempBS.Write(ranges[i].maxIndex);
|
||||
bitsWritten+=sizeof(range_type)*8;
|
||||
}
|
||||
countWritten++;
|
||||
}
|
||||
|
||||
in->AlignWriteToByteBoundary();
|
||||
SLNet::BitSize_t before=in->GetWriteOffset();
|
||||
in->Write(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(SLNet::BitStream *out)
|
||||
{
|
||||
ranges.Clear(true, _FILE_AND_LINE_);
|
||||
unsigned short count;
|
||||
out->AlignReadToByteBoundary();
|
||||
if (!out->Read(count)) {
|
||||
return false;
|
||||
}
|
||||
range_type absMin;
|
||||
range_type min, max;
|
||||
|
||||
if (count == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!DeserializeSingleRange(out, min, max)) {
|
||||
return false;
|
||||
}
|
||||
ranges.InsertAtEnd(RangeNode<range_type>(min, max), _FILE_AND_LINE_);
|
||||
|
||||
for (unsigned short i = 1; i < count; i++) {
|
||||
absMin = max;
|
||||
|
||||
if (!DeserializeSingleRange(out, min, max)) {
|
||||
return false;
|
||||
}
|
||||
if (min <= absMin) {
|
||||
return false;
|
||||
}
|
||||
ranges.InsertAtEnd(RangeNode<range_type>(min, max), _FILE_AND_LINE_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class range_type>
|
||||
bool RangeList<range_type>::DeserializeSingleRange(SLNet::BitStream *out, range_type& min, range_type& max)
|
||||
{
|
||||
unsigned char maxEqualToMin;
|
||||
|
||||
if (!out->Read(maxEqualToMin)) {
|
||||
return false;
|
||||
}
|
||||
if (!out->Read(min)) {
|
||||
return false;
|
||||
}
|
||||
if (maxEqualToMin == 0) {
|
||||
if (!out->Read(max)) {
|
||||
return false;
|
||||
}
|
||||
if (max <= min) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
max = min;
|
||||
}
|
||||
|
||||
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, _FILE_AND_LINE_);
|
||||
return;
|
||||
}
|
||||
|
||||
bool objectExists;
|
||||
unsigned insertionIndex=ranges.GetIndexFromKey(index, &objectExists);
|
||||
if (objectExists) {
|
||||
return; // index already covered by a range entry - do not create a duplicated entry
|
||||
}
|
||||
|
||||
// index > maxIndex on entire range list
|
||||
if (insertionIndex==ranges.Size()) {
|
||||
if (index == ranges[insertionIndex-1].maxIndex+(range_type)1) {
|
||||
ranges[insertionIndex-1].maxIndex++;
|
||||
} else if (index > ranges[insertionIndex-1].maxIndex+(range_type)1) {
|
||||
// Insert at end
|
||||
ranges.Insert(index, RangeNode<range_type>(index, index), true, _FILE_AND_LINE_);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// verify it's really not within the current range (otherwise objectExists should have been true)
|
||||
RakAssert(index < ranges[insertionIndex].minIndex || index > ranges[insertionIndex].maxIndex);
|
||||
|
||||
if (index < ranges[insertionIndex].minIndex-(range_type)1)
|
||||
{
|
||||
// Insert here
|
||||
ranges.InsertAtIndex(RangeNode<range_type>(index, index), insertionIndex, _FILE_AND_LINE_);
|
||||
return;
|
||||
}
|
||||
|
||||
if (index == ranges[insertionIndex].minIndex-(range_type)1)
|
||||
{
|
||||
// Decrease minIndex and join left
|
||||
ranges[insertionIndex].minIndex--;
|
||||
if (insertionIndex>0 && ranges[insertionIndex-1].maxIndex+(range_type)1==ranges[insertionIndex].minIndex)
|
||||
{
|
||||
ranges[insertionIndex-1].maxIndex=ranges[insertionIndex].maxIndex;
|
||||
ranges.RemoveAtIndex(insertionIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (index == ranges[insertionIndex].maxIndex+(range_type)1)
|
||||
{
|
||||
// Increase maxIndex and join right
|
||||
ranges[insertionIndex].maxIndex++;
|
||||
if (insertionIndex<ranges.Size()-1 && ranges[insertionIndex+(range_type)1].minIndex==ranges[insertionIndex].maxIndex+(range_type)1)
|
||||
{
|
||||
ranges[insertionIndex+1].minIndex=ranges[insertionIndex].minIndex;
|
||||
ranges.RemoveAtIndex(insertionIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class range_type>
|
||||
void RangeList<range_type>::Clear(void)
|
||||
{
|
||||
ranges.Clear(true, _FILE_AND_LINE_);
|
||||
}
|
||||
|
||||
template <class range_type>
|
||||
bool RangeList<range_type>::IsWithinRange(range_type value) const
|
||||
{
|
||||
bool objectExists;
|
||||
// not interested in the return value
|
||||
(void)ranges.GetIndexFromKey(value, &objectExists);
|
||||
return objectExists;
|
||||
}
|
||||
|
||||
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
|
||||
350
Source/include/slikenet/DS_Table.h
Normal file
350
Source/include/slikenet/DS_Table.h
Normal file
@ -0,0 +1,350 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_Table.h
|
||||
///
|
||||
|
||||
|
||||
#ifndef __TABLE_H
|
||||
#define __TABLE_H
|
||||
|
||||
#include "DS_List.h"
|
||||
#include "DS_BPlusTree.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "Export.h"
|
||||
#include "string.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.
|
||||
/// \details The table data structure is useful if you want to store a set of structures and perform queries on those structures.<BR>
|
||||
/// This is a relatively simple and fast implementation of the types of tables commonly used in databases.<BR>
|
||||
/// See TableSerializer to serialize data members of the table.<BR>
|
||||
/// 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
|
||||
// Note: If this structure is changed the struct in the swig files need to be changed as well
|
||||
struct RAK_DLL_EXPORT Cell
|
||||
{
|
||||
Cell();
|
||||
~Cell();
|
||||
Cell(double numericValue, char *charValue, void *ptr, ColumnType type);
|
||||
void SetByType(double numericValue, char *charValue, void *inPtr, 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);
|
||||
void Get(char *output, size_t outputLength);
|
||||
|
||||
/// Binary
|
||||
void Get(char *output, int *outputLength);
|
||||
|
||||
SLNet::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
|
||||
// Note: If this structure is changed the struct in the swig files need to be changed as well
|
||||
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
|
||||
// Note: If this structure is changed the struct in the swig files need to be changed as well
|
||||
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.
|
||||
// Note: If this structure is changed the struct in the swig files need to be changed as well
|
||||
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
|
||||
// Note: If this structure is changed the struct in the swig files need to be changed as well
|
||||
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
|
||||
/// \details 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]) const;
|
||||
unsigned ColumnIndex(const char *columnName) const;
|
||||
|
||||
/// \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
|
||||
/// \details 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);
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
/// \brief Removes all the rows with IDs that the specified table also has.
|
||||
/// \param[in] tableContainingRowIDs The IDs of the rows
|
||||
void RemoveRows(Table *tableContainingRowIDs);
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
/// \brief 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, size_t outputLength);
|
||||
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output, int *outputLength);
|
||||
|
||||
/// \brief 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;
|
||||
|
||||
/// \brief 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
|
||||
/// \details 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);
|
||||
|
||||
/// \brief Frees all memory in the table.
|
||||
void Clear(void);
|
||||
|
||||
/// \brief 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;
|
||||
|
||||
/// \brief 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;
|
||||
|
||||
/// \brief Direct access to make things easier.
|
||||
const DataStructures::List<ColumnDescriptor>& GetColumns(void) const;
|
||||
|
||||
/// \brief Direct access to make things easier.
|
||||
const DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER>& GetRows(void) const;
|
||||
|
||||
/// \brief Get the head of a linked list containing all the row data.
|
||||
DataStructures::Page<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER> * GetListHead(void);
|
||||
|
||||
/// \brief 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;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
189
Source/include/slikenet/DS_ThreadsafeAllocatingQueue.h
Normal file
189
Source/include/slikenet/DS_ThreadsafeAllocatingQueue.h
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_ThreadsafeAllocatingQueue.h
|
||||
/// \internal
|
||||
/// A threadsafe queue, that also uses a memory pool for allocation
|
||||
|
||||
#ifndef __THREADSAFE_ALLOCATING_QUEUE
|
||||
#define __THREADSAFE_ALLOCATING_QUEUE
|
||||
|
||||
#include "DS_Queue.h"
|
||||
#include "SimpleMutex.h"
|
||||
#include "DS_MemoryPool.h"
|
||||
|
||||
// #if defined(new)
|
||||
// #pragma push_macro("new")
|
||||
// #undef new
|
||||
// #define RMO_NEW_UNDEF_ALLOCATING_QUEUE
|
||||
// #endif
|
||||
|
||||
namespace DataStructures
|
||||
{
|
||||
|
||||
template <class structureType>
|
||||
class RAK_DLL_EXPORT ThreadsafeAllocatingQueue
|
||||
{
|
||||
public:
|
||||
// Queue operations
|
||||
void Push(structureType *s);
|
||||
structureType *PopInaccurate(void);
|
||||
structureType *Pop(void);
|
||||
void SetPageSize(int size);
|
||||
bool IsEmpty(void);
|
||||
structureType * operator[] ( unsigned int position );
|
||||
void RemoveAtIndex( unsigned int position );
|
||||
unsigned int Size( void );
|
||||
|
||||
// Memory pool operations
|
||||
structureType *Allocate(const char *file, unsigned int line);
|
||||
void Deallocate(structureType *s, const char *file, unsigned int line);
|
||||
void Clear(const char *file, unsigned int line);
|
||||
protected:
|
||||
|
||||
mutable MemoryPool<structureType> memoryPool;
|
||||
SLNet::SimpleMutex memoryPoolMutex;
|
||||
Queue<structureType*> queue;
|
||||
SLNet::SimpleMutex queueMutex;
|
||||
};
|
||||
|
||||
template <class structureType>
|
||||
void ThreadsafeAllocatingQueue<structureType>::Push(structureType *s)
|
||||
{
|
||||
queueMutex.Lock();
|
||||
queue.Push(s, _FILE_AND_LINE_ );
|
||||
queueMutex.Unlock();
|
||||
}
|
||||
|
||||
template <class structureType>
|
||||
structureType *ThreadsafeAllocatingQueue<structureType>::PopInaccurate(void)
|
||||
{
|
||||
structureType *s;
|
||||
if (queue.IsEmpty())
|
||||
return 0;
|
||||
queueMutex.Lock();
|
||||
if (queue.IsEmpty()==false)
|
||||
s=queue.Pop();
|
||||
else
|
||||
s=0;
|
||||
queueMutex.Unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class structureType>
|
||||
structureType *ThreadsafeAllocatingQueue<structureType>::Pop(void)
|
||||
{
|
||||
structureType *s;
|
||||
queueMutex.Lock();
|
||||
if (queue.IsEmpty())
|
||||
{
|
||||
queueMutex.Unlock();
|
||||
return 0;
|
||||
}
|
||||
s=queue.Pop();
|
||||
queueMutex.Unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class structureType>
|
||||
structureType *ThreadsafeAllocatingQueue<structureType>::Allocate(const char *file, unsigned int line)
|
||||
{
|
||||
structureType *s;
|
||||
memoryPoolMutex.Lock();
|
||||
s=memoryPool.Allocate(file, line);
|
||||
memoryPoolMutex.Unlock();
|
||||
// Call new operator, memoryPool doesn't do this
|
||||
s = new ((void*)s) structureType;
|
||||
return s;
|
||||
}
|
||||
template <class structureType>
|
||||
void ThreadsafeAllocatingQueue<structureType>::Deallocate(structureType *s, const char *file, unsigned int line)
|
||||
{
|
||||
// Call delete operator, memory pool doesn't do this
|
||||
s->~structureType();
|
||||
memoryPoolMutex.Lock();
|
||||
memoryPool.Release(s, file, line);
|
||||
memoryPoolMutex.Unlock();
|
||||
}
|
||||
|
||||
template <class structureType>
|
||||
void ThreadsafeAllocatingQueue<structureType>::Clear(const char *file, unsigned int line)
|
||||
{
|
||||
memoryPoolMutex.Lock();
|
||||
for (unsigned int i=0; i < queue.Size(); i++)
|
||||
{
|
||||
queue[i]->~structureType();
|
||||
memoryPool.Release(queue[i], file, line);
|
||||
}
|
||||
queue.Clear(file, line);
|
||||
memoryPoolMutex.Unlock();
|
||||
memoryPoolMutex.Lock();
|
||||
memoryPool.Clear(file, line);
|
||||
memoryPoolMutex.Unlock();
|
||||
}
|
||||
|
||||
template <class structureType>
|
||||
void ThreadsafeAllocatingQueue<structureType>::SetPageSize(int size)
|
||||
{
|
||||
memoryPool.SetPageSize(size);
|
||||
}
|
||||
|
||||
template <class structureType>
|
||||
bool ThreadsafeAllocatingQueue<structureType>::IsEmpty(void)
|
||||
{
|
||||
bool isEmpty;
|
||||
queueMutex.Lock();
|
||||
isEmpty=queue.IsEmpty();
|
||||
queueMutex.Unlock();
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
template <class structureType>
|
||||
structureType * ThreadsafeAllocatingQueue<structureType>::operator[] ( unsigned int position )
|
||||
{
|
||||
structureType *s;
|
||||
queueMutex.Lock();
|
||||
s=queue[position];
|
||||
queueMutex.Unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class structureType>
|
||||
void ThreadsafeAllocatingQueue<structureType>::RemoveAtIndex( unsigned int position )
|
||||
{
|
||||
queueMutex.Lock();
|
||||
queue.RemoveAtIndex(position);
|
||||
queueMutex.Unlock();
|
||||
}
|
||||
|
||||
template <class structureType>
|
||||
unsigned int ThreadsafeAllocatingQueue<structureType>::Size( void )
|
||||
{
|
||||
unsigned int s;
|
||||
queueMutex.Lock();
|
||||
s=queue.Size();
|
||||
queueMutex.Unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// #if defined(RMO_NEW_UNDEF_ALLOCATING_QUEUE)
|
||||
// #pragma pop_macro("new")
|
||||
// #undef RMO_NEW_UNDEF_ALLOCATING_QUEUE
|
||||
// #endif
|
||||
|
||||
#endif
|
||||
111
Source/include/slikenet/DS_Tree.h
Normal file
111
Source/include/slikenet/DS_Tree.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_Tree.h
|
||||
/// \internal
|
||||
/// \brief Just a regular tree
|
||||
///
|
||||
|
||||
|
||||
|
||||
#ifndef __DS_TREE_H
|
||||
#define __DS_TREE_H
|
||||
|
||||
#include "Export.h"
|
||||
#include "DS_List.h"
|
||||
#include "DS_Queue.h"
|
||||
#include "memoryoverride.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()
|
||||
{
|
||||
DeleteDecendants();
|
||||
}
|
||||
|
||||
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, _FILE_AND_LINE_);
|
||||
for (i=0; i < node->children.Size(); i++)
|
||||
queue.Push(node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <class TreeType>
|
||||
void Tree<TreeType>::AddChild(TreeType &newData)
|
||||
{
|
||||
children.Insert(SLNet::OP_NEW<Tree>(newData, _FILE_AND_LINE_));
|
||||
}
|
||||
|
||||
template <class TreeType>
|
||||
void Tree<TreeType>::DeleteDecendants(void)
|
||||
{
|
||||
/*
|
||||
DataStructures::List<Tree*> output;
|
||||
LevelOrderTraversal(output);
|
||||
unsigned i;
|
||||
for (i=0; i < output.Size(); i++)
|
||||
SLNet::OP_DELETE(output[i], _FILE_AND_LINE_);
|
||||
*/
|
||||
|
||||
// Already recursive to do this
|
||||
unsigned int i;
|
||||
for (i=0; i < children.Size(); i++)
|
||||
SLNet::OP_DELETE(children[i], _FILE_AND_LINE_);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
546
Source/include/slikenet/DS_WeightedGraph.h
Normal file
546
Source/include/slikenet/DS_WeightedGraph.h
Normal file
@ -0,0 +1,546 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DS_WeightedGraph.h
|
||||
/// \internal
|
||||
/// \brief Weighted graph.
|
||||
/// \details I'm assuming the indices are complex map types, rather than sequential numbers (which could be implemented much more efficiently).
|
||||
///
|
||||
|
||||
|
||||
#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 "assert.h"
|
||||
#include "memoryoverride.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 = SLNet::OP_NEW_ARRAY<weight_type>(costMatrixIndices.Size() * costMatrixIndices.Size(), _FILE_AND_LINE_ );
|
||||
leastNodeArray = SLNet::OP_NEW_ARRAY<node_type>(costMatrixIndices.Size(), _FILE_AND_LINE_ );
|
||||
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 = SLNet::OP_NEW_ARRAY<weight_type>(costMatrixIndices.Size() * costMatrixIndices.Size(), _FILE_AND_LINE_ );
|
||||
leastNodeArray = SLNet::OP_NEW_ARRAY<node_type>(costMatrixIndices.Size(), _FILE_AND_LINE_ );
|
||||
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, SLNet::OP_NEW<DataStructures::Map<node_type, weight_type> >( _FILE_AND_LINE_) );
|
||||
}
|
||||
|
||||
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, _FILE_AND_LINE_ );
|
||||
while (removeNodeQueue.Size())
|
||||
{
|
||||
SLNet::OP_DELETE(adjacencyLists.Pop(removeNodeQueue.Pop()), _FILE_AND_LINE_);
|
||||
|
||||
// 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), _FILE_AND_LINE_ );
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
SLNet::OP_DELETE(adjacencyLists[i], _FILE_AND_LINE_);
|
||||
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(false, _FILE_AND_LINE_);
|
||||
if (startNode==endNode)
|
||||
{
|
||||
path.Insert(startNode, _FILE_AND_LINE_);
|
||||
path.Insert(endNode, _FILE_AND_LINE_);
|
||||
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, _FILE_AND_LINE_);
|
||||
path.Insert(endNode, _FILE_AND_LINE_);
|
||||
return true;
|
||||
}
|
||||
currentWeight=costMatrix[row*adjacencyLists.Size() + col];
|
||||
if (currentWeight==INFINITE_WEIGHT)
|
||||
{
|
||||
// No path
|
||||
return true;
|
||||
}
|
||||
vertex=endNode;
|
||||
outputQueue.PushAtHead(vertex, 0, _FILE_AND_LINE_);
|
||||
row--;
|
||||
for(;;)
|
||||
{
|
||||
while (costMatrix[row*adjacencyLists.Size() + col] == currentWeight)
|
||||
{
|
||||
if (row==0)
|
||||
{
|
||||
path.Insert(startNode, _FILE_AND_LINE_);
|
||||
while(!outputQueue.IsEmpty())
|
||||
path.Insert(outputQueue.Pop(), _FILE_AND_LINE_);
|
||||
return true;
|
||||
}
|
||||
--row;
|
||||
}
|
||||
|
||||
vertex=leastNodeArray[row];
|
||||
outputQueue.PushAtHead(vertex, 0, _FILE_AND_LINE_);
|
||||
if (row==0)
|
||||
break;
|
||||
col=costMatrixIndices.GetIndexFromKey(vertex, &objectExists);
|
||||
currentWeight=costMatrix[row*adjacencyLists.Size() + col];
|
||||
}
|
||||
|
||||
path.Insert(startNode, _FILE_AND_LINE_);
|
||||
while(!outputQueue.IsEmpty())
|
||||
path.Insert(outputQueue.Pop(), _FILE_AND_LINE_);
|
||||
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 && path.Size()>0)
|
||||
{
|
||||
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= SLNet::OP_NEW<DataStructures::Tree<node_type> >( _FILE_AND_LINE_ );
|
||||
nap2.node->data=adjacencyList->GetKeyAtIndex(i);
|
||||
nap2.parent=current;
|
||||
nodesToProcess.Push(nap2, _FILE_AND_LINE_ );
|
||||
current->children.Insert(nap2.node, _FILE_AND_LINE_);
|
||||
}
|
||||
|
||||
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= SLNet::OP_NEW<DataStructures::Tree<node_type> >( _FILE_AND_LINE_ );
|
||||
nap2.node->data=key;
|
||||
nap2.parent=current;
|
||||
nodesToProcess.Push(nap2, _FILE_AND_LINE_ );
|
||||
current->children.Insert(nap2.node, _FILE_AND_LINE_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 = SLNet::OP_NEW_ARRAY<weight_type>(adjacencyLists.Size() * adjacencyLists.Size(), _FILE_AND_LINE_ );
|
||||
leastNodeArray = SLNet::OP_NEW_ARRAY<node_type>(adjacencyLists.Size(), _FILE_AND_LINE_ );
|
||||
|
||||
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, _FILE_AND_LINE_);
|
||||
}
|
||||
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(true,_FILE_AND_LINE_);
|
||||
for (openSetIndex=0; openSetIndex < openSet.Size(); openSetIndex++)
|
||||
minHeap.Push(openSet[openSetIndex], openSet.GetKeyAtIndex(openSetIndex),_FILE_AND_LINE_);
|
||||
|
||||
/*
|
||||
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;
|
||||
SLNet::OP_DELETE_ARRAY(costMatrix, _FILE_AND_LINE_);
|
||||
SLNet::OP_DELETE_ARRAY(leastNodeArray, _FILE_AND_LINE_);
|
||||
costMatrixIndices.Clear(false, _FILE_AND_LINE_);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
45
Source/include/slikenet/DataCompressor.h
Normal file
45
Source/include/slikenet/DataCompressor.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DataCompressor.h
|
||||
/// \brief DataCompressor does compression on a block of data.
|
||||
/// \details Not very good compression, but it's small and fast so is something you can use per-message at runtime.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __DATA_COMPRESSOR_H
|
||||
#define __DATA_COMPRESSOR_H
|
||||
|
||||
#include "memoryoverride.h"
|
||||
#include "DS_HuffmanEncodingTree.h"
|
||||
#include "Export.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
/// \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:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(DataCompressor)
|
||||
|
||||
static void Compress( unsigned char *userData, unsigned sizeInBytes, SLNet::BitStream * output );
|
||||
static unsigned DecompressAndAllocate(SLNet::BitStream * input, unsigned char **output );
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
177
Source/include/slikenet/DirectoryDeltaTransfer.h
Normal file
177
Source/include/slikenet/DirectoryDeltaTransfer.h
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DirectoryDeltaTransfer.h
|
||||
/// \brief Simple class to send changes between directories.
|
||||
/// \details In essence, a simple autopatcher that can be used for transmitting levels, skins, etc.
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_DirectoryDeltaTransfer==1 && _RAKNET_SUPPORT_FileOperations==1
|
||||
|
||||
#ifndef __DIRECTORY_DELTA_TRANSFER_H
|
||||
#define __DIRECTORY_DELTA_TRANSFER_H
|
||||
|
||||
#include "memoryoverride.h"
|
||||
#include "types.h"
|
||||
#include "Export.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "DS_Map.h"
|
||||
#include "PacketPriority.h"
|
||||
|
||||
/// \defgroup DIRECTORY_DELTA_TRANSFER_GROUP DirectoryDeltaTransfer
|
||||
/// \brief Simple class to send changes between directories
|
||||
/// \details
|
||||
/// \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.
|
||||
/// \details
|
||||
/// \sa AutopatcherClient 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/"<BR>
|
||||
/// To allow other systems to download files, call AddUploadsFromSubdirectory, where the parameter is a path relative<BR>
|
||||
/// to the path to your application. This includes subdirectories.<BR>
|
||||
/// For example:<BR>
|
||||
/// SetApplicationDirectory("C:/Games/MyRPG/");<BR>
|
||||
/// AddUploadsFromSubdirectory("Mods/Skins/");<BR>
|
||||
/// would allow downloads from<BR>
|
||||
/// "C:/Games/MyRPG/Mods/Skins/*.*" as well as "C:/Games/MyRPG/Mods/Skins/Level1/*.*"<BR>
|
||||
/// It would NOT allow downloads from C:/Games/MyRPG/Levels, nor would it allow downloads from C:/Windows<BR>
|
||||
/// While pathToApplication can be anything you want, applicationSubdirectory must match either partially or fully between systems.
|
||||
/// \ingroup DIRECTORY_DELTA_TRANSFER_GROUP
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
class FileList;
|
||||
struct Packet;
|
||||
struct InternalPacket;
|
||||
struct DownloadRequest;
|
||||
class FileListTransfer;
|
||||
class FileListTransferCBInterface;
|
||||
class FileListProgress;
|
||||
class IncrementalReadInterface;
|
||||
|
||||
class RAK_DLL_EXPORT DirectoryDeltaTransfer : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(DirectoryDeltaTransfer)
|
||||
|
||||
// Constructor
|
||||
DirectoryDeltaTransfer();
|
||||
|
||||
// Destructor
|
||||
virtual ~DirectoryDeltaTransfer();
|
||||
|
||||
/// \brief This plugin has a dependency on the FileListTransfer plugin, which it uses to actually send the files.
|
||||
/// \details 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);
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
/// \brief Add all files in the specified subdirectory recursively.
|
||||
/// \details \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);
|
||||
|
||||
/// \brief Downloads files from the matching parameter \a subdir in AddUploadsFromSubdirectory.
|
||||
/// \details \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
|
||||
/// \note Blocking. Will block while hashes of the local files are generated
|
||||
/// \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);
|
||||
|
||||
/// \brief Downloads files from the matching parameter \a subdir in AddUploadsFromSubdirectory.
|
||||
/// \details \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
|
||||
/// \note Nonblocking, but requires call to GenerateHashes()
|
||||
/// \param[in] localFiles Hashes of local files already on the harddrive. Populate with GenerateHashes(), which you may wish to call from a thread
|
||||
/// \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(FileList &localFiles, const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb);
|
||||
|
||||
/// Hash files already on the harddrive, in preparation for a call to DownloadFromSubdirectory(). Passed to second version of DownloadFromSubdirectory()
|
||||
/// This is slow, and it is exposed so you can call it from a thread before calling DownloadFromSubdirectory()
|
||||
/// \param[out] localFiles List of hashed files populated from \a outputSubdir and \a prependAppDirToOutputSubdir
|
||||
/// \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.
|
||||
void GenerateHashes(FileList &localFiles, const char *outputSubdir, bool prependAppDirToOutputSubdir);
|
||||
|
||||
/// \brief Clear all allowed uploads previously set with AddUploadsFromSubdirectory
|
||||
void ClearUploads(void);
|
||||
|
||||
/// \brief Returns how many files are available for upload
|
||||
/// \return How many files are available for upload
|
||||
unsigned GetNumberOfFilesForUpload(void) const;
|
||||
|
||||
/// \brief Normally, if a remote system requests files, those files are all loaded into memory and sent immediately.
|
||||
/// \details 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 PluginReceiveResult OnReceive(Packet *packet);
|
||||
protected:
|
||||
void OnDownloadRequest(Packet *packet);
|
||||
|
||||
char applicationDirectory[512];
|
||||
FileListTransfer *fileListTransfer;
|
||||
FileList *availableUploads;
|
||||
PacketPriority priority;
|
||||
char orderingChannel;
|
||||
IncrementalReadInterface *incrementalReadInterface;
|
||||
unsigned int chunkSize;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
115
Source/include/slikenet/DynDNS.h
Normal file
115
Source/include/slikenet/DynDNS.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file DynDNS.h
|
||||
/// \brief Helper to class to update DynDNS
|
||||
/// This can be used to determine what permissions are should be allowed to the other system
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_DynDNS==1 && _RAKNET_SUPPORT_TCPInterface==1
|
||||
|
||||
#ifndef __DYN_DNS_H
|
||||
#define __DYN_DNS_H
|
||||
|
||||
#include "string.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
class TCPInterface;
|
||||
|
||||
enum DynDnsResultCode
|
||||
{
|
||||
// ----- Success -----
|
||||
RC_SUCCESS,
|
||||
RC_DNS_ALREADY_SET, // RakNet detects no action is needed
|
||||
|
||||
// ----- Ignorable failure (treat same as success) -----
|
||||
RC_NO_CHANGE, // DynDNS detects no action is needed (treated as abuse though)
|
||||
|
||||
// ----- User error -----
|
||||
RC_NOT_DONATOR, // You have to pay to do this
|
||||
RC_NO_HOST, // This host does not exist at all
|
||||
RC_BAD_AUTH, // You set the wrong password
|
||||
RC_NOT_YOURS, // This is not your host
|
||||
|
||||
// ----- Permanent failure -----
|
||||
RC_ABUSE, // Your host has been blocked, too many failures disable your account
|
||||
RC_TCP_FAILED_TO_START, // TCP port already in use
|
||||
RC_TCP_DID_NOT_CONNECT, // DynDNS down?
|
||||
RC_UNKNOWN_RESULT, // DynDNS returned a result code that was not documented as of 12/4/2010 on http://www.dyndns.com/developers/specs/flow.pdf
|
||||
RC_PARSING_FAILURE, // Can't read the result returned, format change?
|
||||
RC_CONNECTION_LOST_WITHOUT_RESPONSE, // Lost the connection to DynDNS while communicating
|
||||
RC_BAD_AGENT, // ???
|
||||
RC_BAD_SYS, // ???
|
||||
RC_DNS_ERROR, // ???
|
||||
RC_NOT_FQDN, // ???
|
||||
RC_NUM_HOST, // ???
|
||||
RC_911, // ???
|
||||
RC_DYNDNS_TIMEOUT // DynDNS did not respond
|
||||
};
|
||||
|
||||
// Can only process one at a time with the current implementation
|
||||
class RAK_DLL_EXPORT DynDNS
|
||||
{
|
||||
public:
|
||||
DynDNS();
|
||||
~DynDNS();
|
||||
|
||||
// Pass 0 for newIPAddress to autodetect whatever you are uploading from
|
||||
// usernameAndPassword should be in the format username:password
|
||||
void UpdateHostIPAsynch(const char *dnsHost, const char *newIPAddress, const char *usernameAndPassword );
|
||||
void Update(void);
|
||||
|
||||
// Output
|
||||
bool IsRunning(void) const {return connectPhase!=CP_IDLE;}
|
||||
bool IsCompleted(void) const {return connectPhase==CP_IDLE;}
|
||||
SLNet::DynDnsResultCode GetCompletedResultCode(void) {return result;}
|
||||
const char *GetCompletedDescription(void) const {return resultDescription;}
|
||||
bool WasResultSuccessful(void) const {return result==RC_SUCCESS || result==RC_DNS_ALREADY_SET || result==RC_NO_CHANGE;}
|
||||
char *GetMyPublicIP(void) const {return (char*) myIPStr;} // We get our public IP as part of the process. This is valid once completed
|
||||
|
||||
protected:
|
||||
void Stop(void);
|
||||
void SetCompleted(SLNet::DynDnsResultCode _result, const char *_resultDescription) {Stop(); result=_result; resultDescription=_resultDescription;}
|
||||
|
||||
enum ConnectPhase
|
||||
{
|
||||
CP_CONNECTING_TO_CHECKIP,
|
||||
CP_WAITING_FOR_CHECKIP_RESPONSE,
|
||||
CP_CONNECTING_TO_DYNDNS,
|
||||
CP_WAITING_FOR_DYNDNS_RESPONSE,
|
||||
CP_IDLE
|
||||
};
|
||||
|
||||
TCPInterface *tcp;
|
||||
SLNet::RakString getString;
|
||||
SystemAddress serverAddress;
|
||||
ConnectPhase connectPhase;
|
||||
SLNet::RakString host;
|
||||
SLNet::Time phaseTimeout;
|
||||
SystemAddress checkIpAddress;
|
||||
const char *resultDescription;
|
||||
SLNet::DynDnsResultCode result;
|
||||
char myIPStr[32];
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif // __DYN_DNS_H
|
||||
|
||||
#endif // _RAKNET_SUPPORT_DynDNS
|
||||
70
Source/include/slikenet/EmailSender.h
Normal file
70
Source/include/slikenet/EmailSender.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file EmailSender.h
|
||||
/// \brief Rudimentary class to send email from code. Don't expect anything fancy.
|
||||
///
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_EmailSender==1 && _RAKNET_SUPPORT_TCPInterface==1 && _RAKNET_SUPPORT_FileOperations==1
|
||||
|
||||
#ifndef __EMAIL_SENDER_H
|
||||
#define __EMAIL_SENDER_H
|
||||
|
||||
#include "types.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "Export.h"
|
||||
#include "Rand.h"
|
||||
#include "TCPInterface.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class FileList;
|
||||
class TCPInterface;
|
||||
|
||||
/// \brief Rudimentary class to send email from code.
|
||||
class RAK_DLL_EXPORT EmailSender
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(EmailSender)
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
protected:
|
||||
const char *GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf);
|
||||
RakNetRandom rakNetRandom;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
6
Source/include/slikenet/EmptyHeader.h
Normal file
6
Source/include/slikenet/EmptyHeader.h
Normal file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* This file was taken from RakNet 4.082 without any modifications.
|
||||
* Please see licenses/RakNet license.txt for the underlying license and related copyright.
|
||||
*/
|
||||
|
||||
// This is here to remove Missing #include header? in the Unreal Engine
|
||||
24
Source/include/slikenet/EpochTimeToString.h
Normal file
24
Source/include/slikenet/EpochTimeToString.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/// \file EpochTimeToString.h
|
||||
///
|
||||
|
||||
|
||||
#ifndef __EPOCH_TIME_TO_STRING_H
|
||||
#define __EPOCH_TIME_TO_STRING_H
|
||||
|
||||
#include "Export.h"
|
||||
|
||||
RAK_DLL_EXPORT char * EpochTimeToString(long long time);
|
||||
|
||||
#endif
|
||||
|
||||
28
Source/include/slikenet/Export.h
Normal file
28
Source/include/slikenet/Export.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#if defined(_WIN32) && !(defined(__GNUC__) || defined(__GCCXML__)) && !defined(_RAKNET_LIB) && defined(_RAKNET_DLL)
|
||||
#define RAK_DLL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define RAK_DLL_EXPORT
|
||||
#endif
|
||||
|
||||
#define STATIC_FACTORY_DECLARATIONS(x) static x* GetInstance(void); \
|
||||
static void DestroyInstance( x *i);
|
||||
|
||||
#define STATIC_FACTORY_DEFINITIONS(x,y) x* x::GetInstance(void) {return SLNet::OP_NEW<y>( _FILE_AND_LINE_ );} \
|
||||
void x::DestroyInstance( x *i) {SLNet::OP_DELETE(( y* ) i, _FILE_AND_LINE_);}
|
||||
264
Source/include/slikenet/FileList.h
Normal file
264
Source/include/slikenet/FileList.h
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file FileList.h
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_FileOperations==1
|
||||
|
||||
#ifndef __FILE_LIST
|
||||
#define __FILE_LIST
|
||||
|
||||
#include "Export.h"
|
||||
#include "DS_List.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "types.h"
|
||||
#include "FileListNodeContext.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
class BitStream;
|
||||
}
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
class FileList;
|
||||
|
||||
|
||||
/// Represents once instance of a file
|
||||
struct FileListNode
|
||||
{
|
||||
/// Name of the file
|
||||
SLNet::RakString filename;
|
||||
|
||||
/// Full path to the file, which may be different than filename
|
||||
SLNet::RakString fullPathToFile;
|
||||
|
||||
/// 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;
|
||||
};
|
||||
|
||||
/// Callback interface set with FileList::SetCallback() in case you want progress notifications when FileList::AddFilesFromDirectory() is called
|
||||
class RAK_DLL_EXPORT FileListProgress
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(FileListProgress)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// \brief 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, unsigned short setId)
|
||||
{
|
||||
(void) fileName;
|
||||
(void) fileLengthBytes;
|
||||
(void) offset;
|
||||
(void) bytesBeingSent;
|
||||
(void) done;
|
||||
(void) targetSystem;
|
||||
(void) setId;
|
||||
}
|
||||
|
||||
/// \brief This function is called when all files have been read and are being transferred to a remote system
|
||||
virtual void OnFilePushesComplete( SystemAddress systemAddress, unsigned short setId )
|
||||
{
|
||||
(void) systemAddress;
|
||||
(void) setId;
|
||||
}
|
||||
|
||||
/// \brief This function is called when a send to a system was aborted (probably due to disconnection)
|
||||
virtual void OnSendAborted( SystemAddress systemAddress )
|
||||
{
|
||||
(void) systemAddress;
|
||||
}
|
||||
};
|
||||
|
||||
/// Implementation of FileListProgress to use RAKNET_DEBUG_PRINTF
|
||||
class RAK_DLL_EXPORT FLP_Printf : public FileListProgress
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(FLP_Printf)
|
||||
|
||||
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);
|
||||
|
||||
/// \brief This function is called when all files have been transferred to a particular remote system
|
||||
virtual void OnFilePushesComplete( SystemAddress systemAddress, unsigned short setID );
|
||||
|
||||
/// \brief This function is called when a send to a system was aborted (probably due to disconnection)
|
||||
virtual void OnSendAborted( SystemAddress systemAddress );
|
||||
};
|
||||
|
||||
class RAK_DLL_EXPORT FileList
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(FileList)
|
||||
|
||||
FileList();
|
||||
~FileList();
|
||||
/// \brief 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 4 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(SLNet::BitStream *outBitStream);
|
||||
|
||||
/// Read all encoded data from a bitstream. Clear() is called before deserializing.
|
||||
bool Deserialize(SLNet::BitStream *inBitStream);
|
||||
|
||||
/// \brief Given the existing set of files, search applicationDirectory for the same files.
|
||||
/// \details 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);
|
||||
|
||||
/// \brief Return the files that need to be written to make \a input match this current FileList.
|
||||
/// \details 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);
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
/// \brief Write all files to disk, prefixing the paths with applicationDirectory
|
||||
/// \param[in] applicationDirectory path prefix
|
||||
void WriteDataToDisk(const char *applicationDirectory);
|
||||
|
||||
/// \brief 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] fullPathToFile Full path to the file on disk
|
||||
/// \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
|
||||
/// \param[in] takeDataPointer If true, do not allocate dataLength. Just take the pointer passed to the \a data parameter
|
||||
void AddFile(const char *filename, const char *fullPathToFile, const char *data, const unsigned dataLength, const unsigned fileLength, FileListNodeContext context, bool isAReference=false, bool takeDataPointer=false);
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
/// \brief Adds 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 AddCallback(FileListProgress *cb);
|
||||
|
||||
/// \brief Removes a callback
|
||||
/// \param[in] cb A pointer to an externally defined instance of FileListProgress that was previously added with AddCallback()
|
||||
void RemoveCallback(FileListProgress *cb);
|
||||
|
||||
/// \brief Removes all callbacks
|
||||
void ClearCallbacks(void);
|
||||
|
||||
/// Returns all callbacks added with AddCallback()
|
||||
/// \param[out] callbacks The list is set to the list of callbacks
|
||||
void GetCallbacks(DataStructures::List<FileListProgress*> &callbacks);
|
||||
|
||||
// Here so you can read it, but don't modify it
|
||||
DataStructures::List<FileListNode> fileList;
|
||||
|
||||
static bool FixEndingSlash(char *str);
|
||||
static bool FixEndingSlash(char *str, size_t strLength);
|
||||
protected:
|
||||
DataStructures::List<FileListProgress*> fileListProgressCallbacks;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_FileOperations
|
||||
62
Source/include/slikenet/FileListNodeContext.h
Normal file
62
Source/include/slikenet/FileListNodeContext.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file FileListNodeContext.h
|
||||
///
|
||||
|
||||
|
||||
#ifndef __FILE_LIST_NODE_CONTEXT_H
|
||||
#define __FILE_LIST_NODE_CONTEXT_H
|
||||
|
||||
#include "BitStream.h"
|
||||
|
||||
struct FileListNodeContext
|
||||
{
|
||||
FileListNodeContext() {dataPtr=0; dataLength=0;}
|
||||
FileListNodeContext(unsigned char o, uint32_t f1, uint32_t f2, uint32_t f3) : op(o), flnc_extraData1(f1), flnc_extraData2(f2), flnc_extraData3(f3) {dataPtr=0; dataLength=0;}
|
||||
~FileListNodeContext() {}
|
||||
|
||||
unsigned char op;
|
||||
uint32_t flnc_extraData1;
|
||||
uint32_t flnc_extraData2;
|
||||
uint32_t flnc_extraData3;
|
||||
void *dataPtr;
|
||||
unsigned int dataLength;
|
||||
};
|
||||
|
||||
inline SLNet::BitStream& operator<<(SLNet::BitStream& out, FileListNodeContext& in)
|
||||
{
|
||||
out.Write(in.op);
|
||||
out.Write(in.flnc_extraData1);
|
||||
out.Write(in.flnc_extraData2);
|
||||
out.Write(in.flnc_extraData3);
|
||||
return out;
|
||||
}
|
||||
inline SLNet::BitStream& operator>>(SLNet::BitStream& in, FileListNodeContext& out)
|
||||
{
|
||||
in.Read(out.op);
|
||||
bool success = in.Read(out.flnc_extraData1);
|
||||
(void) success;
|
||||
assert(success);
|
||||
success = in.Read(out.flnc_extraData2);
|
||||
(void) success;
|
||||
assert(success);
|
||||
success = in.Read(out.flnc_extraData3);
|
||||
(void) success;
|
||||
assert(success);
|
||||
return in;
|
||||
}
|
||||
|
||||
#endif
|
||||
190
Source/include/slikenet/FileListTransfer.h
Normal file
190
Source/include/slikenet/FileListTransfer.h
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file FileListTransfer.h
|
||||
/// \brief A plugin to provide a simple way to compress and incrementally send the files in the FileList structure.
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_FileListTransfer==1 && _RAKNET_SUPPORT_FileOperations==1
|
||||
|
||||
#ifndef __FILE_LIST_TRANFER_H
|
||||
#define __FILE_LIST_TRANFER_H
|
||||
|
||||
#include "types.h"
|
||||
#include "Export.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "DS_Map.h"
|
||||
#include "types.h"
|
||||
#include "PacketPriority.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "FileList.h"
|
||||
#include "DS_Queue.h"
|
||||
#include "SimpleMutex.h"
|
||||
#include "ThreadPool.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class IncrementalReadInterface;
|
||||
class FileListTransferCBInterface;
|
||||
class FileListProgress;
|
||||
struct FileListReceiver;
|
||||
|
||||
/// \defgroup FILE_LIST_TRANSFER_GROUP FileListTransfer
|
||||
/// \brief A plugin to provide a simple way to compress and incrementally send the files in the FileList structure.
|
||||
/// \details
|
||||
/// \ingroup PLUGINS_GROUP
|
||||
|
||||
/// \brief A plugin to provide a simple way to compress and incrementally send the files in the FileList structure.
|
||||
/// \details 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()<BR>
|
||||
/// is the setID that is allowed.<BR>
|
||||
/// 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.<BR>
|
||||
/// The other system should then prepare a FileList and call FileListTransfer::Send(), passing the return value of FileListTransfer::SetupReceive()<BR>
|
||||
/// as the \a setID parameter to FileListTransfer::Send()
|
||||
/// \ingroup FILE_LIST_TRANSFER_GROUP
|
||||
class RAK_DLL_EXPORT FileListTransfer : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(FileListTransfer)
|
||||
|
||||
FileListTransfer();
|
||||
virtual ~FileListTransfer();
|
||||
|
||||
/// \brief Optionally start worker threads when using _incrementalReadInterface for the Send() operation
|
||||
/// \param[in] numThreads how many worker threads to start
|
||||
/// \param[in] threadPriority Passed to the thread creation routine. Use THREAD_PRIORITY_NORMAL for Windows. For Linux based systems, you MUST pass something reasonable based on the thread priorities for your application.
|
||||
void StartIncrementalReadThreads(int numThreads, int threadPriority=-99999);
|
||||
|
||||
/// \brief 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);
|
||||
|
||||
/// \brief 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. Pass 0 to use the instance the plugin is attached to
|
||||
/// \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] _incrementalReadInterface If a file in \a fileList has no data, _incrementalReadInterface 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 read/send at once. Large values use more memory but transfer slightly faster.
|
||||
void Send(FileList *fileList, SLNet::RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, IncrementalReadInterface *_incrementalReadInterface=0, unsigned int _chunkSize=262144*4*16);
|
||||
|
||||
/// Return number of files waiting to go out to a particular address
|
||||
unsigned int GetPendingFilesToAddress(SystemAddress recipient);
|
||||
|
||||
/// \brief Stop a download.
|
||||
void CancelReceive(unsigned short inSetId);
|
||||
|
||||
/// \brief Remove all handlers associated with a particular system address.
|
||||
void RemoveReceiver(SystemAddress systemAddress);
|
||||
|
||||
/// \brief Is a handler passed to SetupReceive still running?
|
||||
bool IsHandlerActive(unsigned short inSetId);
|
||||
|
||||
/// \brief Adds 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 AddCallback(FileListProgress *cb);
|
||||
|
||||
/// \brief Removes a callback
|
||||
/// \param[in] cb A pointer to an externally defined instance of FileListProgress that was previously added with AddCallback()
|
||||
void RemoveCallback(FileListProgress *cb);
|
||||
|
||||
/// \brief Removes all callbacks
|
||||
void ClearCallbacks(void);
|
||||
|
||||
/// Returns all callbacks added with AddCallback()
|
||||
/// \param[out] callbacks The list is set to the list of callbacks
|
||||
void GetCallbacks(DataStructures::List<FileListProgress*> &callbacks);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
/// \internal For plugin handling
|
||||
virtual void OnRakPeerShutdown(void);
|
||||
/// \internal For plugin handling
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
/// \internal For plugin handling
|
||||
virtual void Update(void);
|
||||
|
||||
protected:
|
||||
bool DecodeSetHeader(Packet *packet);
|
||||
bool DecodeFile(Packet *packet, bool fullFile);
|
||||
|
||||
void Clear(void);
|
||||
|
||||
void OnReferencePush(Packet *packet, bool fullFile);
|
||||
void OnReferencePushAck(Packet *packet);
|
||||
void SendIRIToAddress(SystemAddress systemAddress, unsigned short inSetId);
|
||||
|
||||
DataStructures::Map<unsigned short, FileListReceiver*> fileListReceivers;
|
||||
unsigned short setId;
|
||||
DataStructures::List<FileListProgress*> fileListProgressCallbacks;
|
||||
|
||||
struct FileToPush
|
||||
{
|
||||
FileListNode fileListNode;
|
||||
PacketPriority packetPriority;
|
||||
char orderingChannel;
|
||||
unsigned int currentOffset;
|
||||
////unsigned short setID;
|
||||
unsigned int setIndex;
|
||||
IncrementalReadInterface *incrementalReadInterface;
|
||||
unsigned int chunkSize;
|
||||
};
|
||||
struct FileToPushRecipient
|
||||
{
|
||||
unsigned int refCount;
|
||||
SimpleMutex refCountMutex;
|
||||
void DeleteThis(void);
|
||||
void AddRef(void);
|
||||
void Deref(void);
|
||||
|
||||
SystemAddress systemAddress;
|
||||
unsigned short setId;
|
||||
|
||||
//// SimpleMutex filesToPushMutex;
|
||||
DataStructures::Queue<FileToPush*> filesToPush;
|
||||
};
|
||||
DataStructures::List< FileToPushRecipient* > fileToPushRecipientList;
|
||||
SimpleMutex fileToPushRecipientListMutex;
|
||||
void RemoveFromList(FileToPushRecipient *ftpr);
|
||||
|
||||
struct ThreadData
|
||||
{
|
||||
FileListTransfer *fileListTransfer;
|
||||
SystemAddress systemAddress;
|
||||
unsigned short setId;
|
||||
};
|
||||
|
||||
ThreadPool<ThreadData, int> threadPool;
|
||||
|
||||
friend int SendIRIToAddressCB(FileListTransfer::ThreadData threadData, bool *returnOutput, void* perThreadData);
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
159
Source/include/slikenet/FileListTransferCBInterface.h
Normal file
159
Source/include/slikenet/FileListTransferCBInterface.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file FileListTransferCBInterface.h
|
||||
///
|
||||
|
||||
|
||||
#ifndef __FILE_LIST_TRANSFER_CALLBACK_INTERFACE_H
|
||||
#define __FILE_LIST_TRANSFER_CALLBACK_INTERFACE_H
|
||||
|
||||
#include "memoryoverride.h"
|
||||
#include "FileListNodeContext.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
/// \brief Used by FileListTransfer plugin as a callback for when we get a file.
|
||||
/// \details You get the last file when fileIndex==numberOfFilesInThisSet
|
||||
/// \sa FileListTransfer
|
||||
class FileListTransferCBInterface
|
||||
{
|
||||
public:
|
||||
// Note: If this structure is changed the struct in the swig files need to be changed as well
|
||||
struct OnFileStruct
|
||||
{
|
||||
/// \brief The index into the set of files, from 0 to numberOfFilesInThisSet
|
||||
unsigned fileIndex;
|
||||
|
||||
/// \brief The name of the file
|
||||
char fileName[512];
|
||||
|
||||
/// \brief The data pointed to by the file
|
||||
char *fileData;
|
||||
|
||||
/// \brief The amount of data to be downloaded for this file
|
||||
BitSize_t byteLengthOfThisFile;
|
||||
|
||||
/// \brief How many bytes of this file has been downloaded
|
||||
BitSize_t bytesDownloadedForThisFile;
|
||||
|
||||
/// \brief Files are transmitted in sets, where more than one set of files can be transmitted at the same time.
|
||||
/// \details This is the identifier for the set, which is returned by FileListTransfer::SetupReceive
|
||||
unsigned short setID;
|
||||
|
||||
/// \brief The number of files that are in this set.
|
||||
unsigned numberOfFilesInThisSet;
|
||||
|
||||
/// \brief The total length of the transmitted files for this set, after being uncompressed
|
||||
unsigned byteLengthOfThisSet;
|
||||
|
||||
/// \brief The total length, in bytes, downloaded for this set.
|
||||
unsigned bytesDownloadedForThisSet;
|
||||
|
||||
/// \brief User data passed to one of the functions in the FileList class.
|
||||
/// \details However, on error, this is instead changed to one of the enumerations in the PatchContext structure.
|
||||
FileListNodeContext context;
|
||||
|
||||
/// \brief Who sent this file
|
||||
SystemAddress senderSystemAddress;
|
||||
|
||||
/// \brief Who sent this file. Not valid when using TCP, only RakPeer (UDP)
|
||||
RakNetGUID senderGuid;
|
||||
};
|
||||
|
||||
// Note: If this structure is changed the struct in the swig files need to be changed as well
|
||||
struct FileProgressStruct
|
||||
{
|
||||
/// \param[out] 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.
|
||||
OnFileStruct *onFileStruct;
|
||||
/// \param[out] partCount The zero based index into partTotal. The percentage complete done of this file is 100 * (partCount+1)/partTotal
|
||||
unsigned int partCount;
|
||||
/// \param[out] 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
|
||||
unsigned int partTotal;
|
||||
/// \param[out] dataChunkLength How many bytes long firstDataChunk and iriDataChunk are
|
||||
unsigned int dataChunkLength;
|
||||
/// \param[out] 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
|
||||
char *firstDataChunk;
|
||||
/// \param[out] iriDataChunk If the remote system is sending this file using IncrementalReadInterface, then this is the chunk we just downloaded. It will not exist in memory after this callback. You should either store this to disk, or in memory. If it is 0, then the file is smaller than one chunk, and will be held in memory automatically
|
||||
char *iriDataChunk;
|
||||
/// \param[out] iriWriteOffset Offset in bytes from the start of the file for the data pointed to by iriDataChunk
|
||||
unsigned int iriWriteOffset;
|
||||
/// \param[out] Who sent this file
|
||||
SystemAddress senderSystemAddress;
|
||||
/// \param[out] Who sent this file. Not valid when using TCP, only RakPeer (UDP)
|
||||
RakNetGUID senderGuid;
|
||||
/// \param[in] allocateIrIDataChunkAutomatically If true, then RakNet will hold iriDataChunk for you and return it in OnFile. Defaults to true
|
||||
bool allocateIrIDataChunkAutomatically;
|
||||
};
|
||||
|
||||
struct DownloadCompleteStruct
|
||||
{
|
||||
/// \brief Files are transmitted in sets, where more than one set of files can be transmitted at the same time.
|
||||
/// \details This is the identifier for the set, which is returned by FileListTransfer::SetupReceive
|
||||
unsigned short setID;
|
||||
|
||||
/// \brief The number of files that are in this set.
|
||||
unsigned numberOfFilesInThisSet;
|
||||
|
||||
/// \brief The total length of the transmitted files for this set, after being uncompressed
|
||||
unsigned byteLengthOfThisSet;
|
||||
|
||||
/// \brief Who sent this file
|
||||
SystemAddress senderSystemAddress;
|
||||
|
||||
/// \brief Who sent this file. Not valid when using TCP, only RakPeer (UDP)
|
||||
RakNetGUID senderGuid;
|
||||
};
|
||||
|
||||
FileListTransferCBInterface() {}
|
||||
virtual ~FileListTransferCBInterface() {}
|
||||
|
||||
/// \brief Got a file.
|
||||
/// \details 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;
|
||||
|
||||
/// \brief Got part of a big file internally in RakNet
|
||||
/// \details This is called in one of two circumstances: Either the transport layer is returning ID_PROGRESS_NOTIFICATION, or you got a block via IncrementalReadInterface
|
||||
/// If the transport layer is returning ID_PROGRESS_NOTIFICATION (see RakPeer::SetSplitMessageProgressInterval()) then FileProgressStruct::iriDataChunk will be 0.
|
||||
/// If this is a block via IncrementalReadInterface, then iriDataChunk will point to the block just downloaded.
|
||||
/// If not using IncrementalReadInterface, then you only care about partCount and partTotal to tell how far the download has progressed. YOu can use firstDataChunk to read the first part of the file if desired. The file is usable when you get the OnFile callback.
|
||||
/// If using IncrementalReadInterface and you let RakNet buffer the files in memory (default), then it is the same as above. The file is usable when you get the OnFile callback.
|
||||
/// If using IncrementalReadInterface and you do not let RakNet buffer the files in memory, then set allocateIrIDataChunkAutomatically to false. Write the file to disk whenever you get OnFileProgress and iriDataChunk is not 0, and ignore OnFile.
|
||||
virtual void OnFileProgress(FileProgressStruct *fps)=0;
|
||||
|
||||
/// \brief Called while the handler is active by FileListTransfer
|
||||
/// \details 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;}
|
||||
|
||||
/// \brief Called when the download is completed.
|
||||
/// \details 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(DownloadCompleteStruct *dcs) {(void) dcs; return false;}
|
||||
|
||||
/// \brief This function is called when this instance is about to be dereferenced by the FileListTransfer plugin.
|
||||
/// \details 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) {}
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
32
Source/include/slikenet/FileOperations.h
Normal file
32
Source/include/slikenet/FileOperations.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
/// \file FileOperations.h
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_FileOperations==1
|
||||
|
||||
#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
|
||||
|
||||
#endif // _RAKNET_SUPPORT_FileOperations
|
||||
30
Source/include/slikenet/FormatString.h
Normal file
30
Source/include/slikenet/FormatString.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
/// \file FormatString.h
|
||||
///
|
||||
|
||||
|
||||
#ifndef __FORMAT_STRING_H
|
||||
#define __FORMAT_STRING_H
|
||||
|
||||
#include "Export.h"
|
||||
|
||||
extern "C" {
|
||||
char * FormatString(const char *format, ...);
|
||||
}
|
||||
// Threadsafe
|
||||
extern "C" {
|
||||
char * FormatStringTS(char *output, const char *format, ...);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
429
Source/include/slikenet/FullyConnectedMesh2.h
Normal file
429
Source/include/slikenet/FullyConnectedMesh2.h
Normal file
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file FullyConnectedMesh2.h
|
||||
/// \brief Fully connected mesh plugin, revision 2.
|
||||
/// \details This will connect RakPeer to all connecting peers, and all peers the connecting peer knows about.
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_FullyConnectedMesh2==1
|
||||
|
||||
#ifndef __FULLY_CONNECTED_MESH_2_H
|
||||
#define __FULLY_CONNECTED_MESH_2_H
|
||||
|
||||
#include "PluginInterface2.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "NativeTypes.h"
|
||||
#include "DS_List.h"
|
||||
#include "string.h"
|
||||
#include "BitStream.h"
|
||||
|
||||
typedef int64_t FCM2Guid;
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
|
||||
/// \brief Fully connected mesh plugin, revision 2
|
||||
/// \details This will connect RakPeer to all connecting peers, and all peers the connecting peer knows about.<BR>
|
||||
/// It will also calculate which system has been running longest, to find out who should be host, if you need one system to act as a host
|
||||
/// \pre You must also install the ConnectionGraph2 plugin in order to use SetConnectOnNewRemoteConnection()
|
||||
/// \ingroup FULLY_CONNECTED_MESH_GROUP
|
||||
class RAK_DLL_EXPORT FullyConnectedMesh2 : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(FullyConnectedMesh2)
|
||||
|
||||
FullyConnectedMesh2();
|
||||
virtual ~FullyConnectedMesh2();
|
||||
|
||||
/// When the message ID_REMOTE_NEW_INCOMING_CONNECTION arrives, we try to connect to that system
|
||||
/// If \a attemptConnection is false, you can manually connect to all systems listed in ID_REMOTE_NEW_INCOMING_CONNECTION with ConnectToRemoteNewIncomingConnections()
|
||||
/// \note This will not work on any console. It will also not work if NAT punchthrough is needed. Generally, this should be false and you should connect manually. It is here for legacy reasons.
|
||||
/// \param[in] attemptConnection If true, we try to connect to any systems we are notified about with ID_REMOTE_NEW_INCOMING_CONNECTION, which comes from the ConnectionGraph2 plugin. Defaults to true.
|
||||
/// \param[in] pw The password to use to connect with. Only used if \a attemptConnection is true
|
||||
void SetConnectOnNewRemoteConnection(bool attemptConnection, SLNet::RakString pw);
|
||||
|
||||
/// \brief The connected host is whichever system we are connected to that has been running the longest.
|
||||
/// \details Will return UNASSIGNED_RAKNET_GUID if we are not connected to anyone, or if we are connected and are calculating the host
|
||||
/// If includeCalculating is true, will return the estimated calculated host as long as the calculation is nearly complete
|
||||
/// includeCalculating should be true if you are taking action based on another system becoming host, because not all host calculations may complete at the exact same time
|
||||
/// \sa ConnectionGraph2::GetLowestAveragePingSystem() . If you need one system in the peer to peer group to relay data, have the host call this function after host migration, and use that system
|
||||
/// \return System address of whichever system is host.
|
||||
RakNetGUID GetConnectedHost(void) const;
|
||||
SystemAddress GetConnectedHostAddr(void) const;
|
||||
|
||||
/// \return System address of whichever system is host. Always returns something, even though it may be our own system.
|
||||
RakNetGUID GetHostSystem(void) const;
|
||||
|
||||
/// \return If our system is host
|
||||
bool IsHostSystem(void) const;
|
||||
|
||||
/// Get the list of connected systems, from oldest connected to newest
|
||||
/// This is also the order that the hosts will be chosen in
|
||||
void GetHostOrder(DataStructures::List<RakNetGUID> &hostList);
|
||||
|
||||
/// \param[in] includeCalculating If true, and we are currently calculating a new host, return the new host if the calculation is nearly complete
|
||||
/// \return If our system is host
|
||||
bool IsConnectedHost(void) const;
|
||||
|
||||
/// \brief Automatically add new connections to the fully connected mesh.
|
||||
/// Each remote system that you want to check should be added as a participant, either through SetAutoparticipateConnections() or by calling this function
|
||||
/// \details Defaults to true.
|
||||
/// \param[in] b As stated
|
||||
void SetAutoparticipateConnections(bool b);
|
||||
|
||||
/// Clear our own host order, and recalculate as if we had just reconnected
|
||||
/// Call this to reset the running time of the host just before joining/creating a game room for networking
|
||||
void ResetHostCalculation(void);
|
||||
|
||||
/// \brief if SetAutoparticipateConnections() is called with false, then you need to use AddParticipant before these systems will be added to the mesh
|
||||
/// FullyConnectedMesh2 will track who is the who host among a fully connected mesh of participants
|
||||
/// Each remote system that you want to check should be added as a participant, either through SetAutoparticipateConnections() or by calling this function
|
||||
/// \param[in] participant The new participant
|
||||
/// \param[in] userContext Static data to be passed around with each participant, which can be queried with GetParticipantData().
|
||||
/// \sa StartVerifiedJoin()
|
||||
void AddParticipant(RakNetGUID rakNetGuid);
|
||||
|
||||
/// Get the participants added with AddParticipant()
|
||||
/// \param[out] participantList Participants added with AddParticipant();
|
||||
void GetParticipantList(DataStructures::List<RakNetGUID> &participantList);
|
||||
|
||||
/// \brief Returns if a participant is in the participant list
|
||||
/// \param[in] RakNetGUID of the participant to query
|
||||
/// \return True if in the list
|
||||
bool HasParticipant(RakNetGUID participantGuid);
|
||||
|
||||
/// \brief Reads userData written with SetMyContext()
|
||||
/// \param[in] RakNetGUID of the participant to query
|
||||
/// \param[out] userContext Pointer to BitStream to be written to
|
||||
/// \return True if data was written
|
||||
// bool GetParticipantContext(RakNetGUID participantGuid, BitStream *userContext);
|
||||
|
||||
/// Set data for other systems to read with GetParticipantContext
|
||||
/// \param[in] userContext Pointer to BitStream to be read from
|
||||
// void SetMyContext(BitStream *userContext);
|
||||
|
||||
/// Connect to all systems from ID_REMOTE_NEW_INCOMING_CONNECTION
|
||||
/// You can call this if SetConnectOnNewRemoteConnection is false
|
||||
/// \param[in] packet The packet containing ID_REMOTE_NEW_INCOMING_CONNECTION
|
||||
/// \param[in] connectionPassword Password passed to RakPeerInterface::Connect()
|
||||
/// \param[in] connectionPasswordLength Password length passed to RakPeerInterface::Connect()
|
||||
void ConnectToRemoteNewIncomingConnections(Packet *packet);
|
||||
|
||||
/// \brief Clear all memory and reset everything
|
||||
void Clear(void);
|
||||
|
||||
unsigned int GetParticipantCount(void) const;
|
||||
void GetParticipantCount(unsigned int *participantListSize) const;
|
||||
|
||||
/// In the simple case of forming a peer to peer mesh:
|
||||
///
|
||||
/// 1. AddParticipant() is called on the host whenever you get a new connection
|
||||
/// 2. The host sends all participants to the new client
|
||||
/// 3. The client connects to the participant list
|
||||
///
|
||||
/// However, the above steps assumes connections to all systems in the mesh always complete.
|
||||
/// When there is a risk of failure, such as if relying on NATPunchthroughClient, you may not want to call AddParticipant() until are connections have completed to all other particpants
|
||||
/// StartVerifiedJoin() can manage the overhead of the negotiation involved so the programmer only has to deal with overall success or failure
|
||||
///
|
||||
/// Processing:
|
||||
/// 1. Send the RakNetGUID and SystemAddress values of GetParticipantList() to the client with ID_FCM2_VERIFIED_JOIN_START
|
||||
/// 2. The client, on ID_FCM2_VERIFIED_JOIN_START, can execute NatPunchthroughClient::OpenNAT() (optional), followed by RakPeerInterface::Connect() if punchthrough success, for each system returned from GetVerifiedJoinRequiredProcessingList()
|
||||
/// 3. After all participants in step 2 have connected, failed to connect, or failed NatPunchthrough, the client automatically sends the results to the server.
|
||||
/// 4. The server compares the results of the operations in step 2 with the values from GetParticpantList().
|
||||
/// 4A. If the client failed to connect to a current participant, return ID_FCM2_VERIFIED_JOIN_FAILED to the client. CloseConnection() is automatically called on the client for the failed participants.
|
||||
/// 4B. If AddParticipant() was called between steps 1 and 4, go back to step 1, transmitting new participants.
|
||||
/// 4C. If the client successfully connected to all participants, the server gets ID_FCM2_VERIFIED_JOIN_CAPABLE. The server programmer, on the same frame, should execute RespondOnVerifiedJoinCapable() to either accept or reject the client.
|
||||
/// 5. If the client got ID_FCM2_VERIFIED_JOIN_ACCEPTED, AddParticipant() is automatically called for each system in the mesh.
|
||||
/// 6. If the client got ID_FCM2_VERIFIED_JOIN_REJECTED, CloseConnection() is automatically called for each system in the mesh. The connection is NOT automatically closed to the original host that sent StartVerifiedJoin().
|
||||
/// 7. If the client's connection to the server was lost before getting ID_FCM2_VERIFIED_JOIN_ACCEPTED or ID_FCM2_VERIFIED_JOIN_REJECTED, return to the programmer ID_FCM2_VERIFIED_JOIN_FAILED and call RakPeerInterface::CloseConnection()
|
||||
///
|
||||
/// \brief Notify the client of GetParticipantList() in order to connect to each of those systems until the mesh has been completed
|
||||
/// \param[in] client The system to send ID_FCM2_VERIFIED_JOIN_START to
|
||||
virtual void StartVerifiedJoin(RakNetGUID client);
|
||||
|
||||
/// \brief On ID_FCM2_VERIFIED_JOIN_CAPABLE , accept or reject the new connection
|
||||
/// \code
|
||||
/// fullyConnectedMesh->RespondOnVerifiedJoinCapable(packet, true, 0);
|
||||
/// \endcode
|
||||
/// \param[in] packet The system that sent ID_FCM2_VERIFIED_JOIN_CAPABLE. Based on \accept, ID_FCM2_VERIFIED_JOIN_ACCEPTED or ID_FCM2_VERIFIED_JOIN_REJECTED will be sent in reply
|
||||
/// \param[in] accept True to accept, and thereby automatically call AddParticipant() on all systems on the mesh. False to reject, and call CloseConnection() to all mesh systems on the target
|
||||
/// \param[in] additionalData Any additional data you want to add to the ID_FCM2_VERIFIED_JOIN_ACCEPTED or ID_FCM2_VERIFIED_JOIN_REJECTED messages
|
||||
/// \sa WriteVJCUserData()
|
||||
virtual void RespondOnVerifiedJoinCapable(Packet *packet, bool accept, BitStream *additionalData);
|
||||
|
||||
/// \brief On ID_FCM2_VERIFIED_JOIN_START, read the SystemAddress and RakNetGUID values of each system to connect to
|
||||
/// \code
|
||||
/// DataStructures::List<SystemAddress> addresses;
|
||||
/// DataStructures::List<RakNetGUID> guids;
|
||||
/// fullyConnectedMesh->GetVerifiedJoinRequiredProcessingList(packet->guid, addresses, guids);
|
||||
/// for (unsigned int i=0; i < addresses.Size(); i++)
|
||||
/// rakPeer[i]->Connect(addresses[i].ToString(false), addresses[i].GetPort(), 0, 0);
|
||||
/// \endcode
|
||||
/// \param[in] host Which system sent ID_FCM2_VERIFIED_JOIN_START
|
||||
/// \param[out] addresses SystemAddress values of systems to connect to. List has the same number and order as \a guids
|
||||
/// \param[out] guids RakNetGUID values of systems to connect to. List has the same number and order as \a guids
|
||||
/// \param[out] userData What was written with WriteVJSUserData
|
||||
virtual void GetVerifiedJoinRequiredProcessingList(RakNetGUID host,
|
||||
DataStructures::List<SystemAddress> &addresses,
|
||||
DataStructures::List<RakNetGUID> &guids,
|
||||
DataStructures::List<BitStream*> &userData);
|
||||
|
||||
/// \brief On ID_FCM2_VERIFIED_JOIN_ACCEPTED, read additional data passed to RespondOnVerifiedJoinCapable()
|
||||
/// \code
|
||||
/// bool thisSystemAccepted;
|
||||
/// DataStructures::List<RakNetGUID> systemsAccepted;
|
||||
/// SLNet::BitStream additionalData;
|
||||
/// fullyConnectedMesh->GetVerifiedJoinAcceptedAdditionalData(packet, &thisSystemAccepted, systemsAccepted, &additionalData);
|
||||
/// \endcode
|
||||
/// \param[in] packet Packet containing the ID_FCM2_VERIFIED_JOIN_ACCEPTED message
|
||||
/// \param[out] thisSystemAccepted If true, it was this instance of RakPeerInterface that was accepted. If false, this is notification for another system
|
||||
/// \param[out] systemsAccepted Which system(s) were added with AddParticipant(). If \a thisSystemAccepted is false, this list will only have length 1
|
||||
/// \param[out] additionalData \a additionalData parameter passed to RespondOnVerifiedJoinCapable()
|
||||
virtual void GetVerifiedJoinAcceptedAdditionalData(Packet *packet, bool *thisSystemAccepted, DataStructures::List<RakNetGUID> &systemsAccepted, BitStream *additionalData);
|
||||
|
||||
/// \brief On ID_FCM2_VERIFIED_JOIN_REJECTED, read additional data passed to RespondOnVerifiedJoinCapable()
|
||||
/// \details This does not automatically close the connection. The following code will do so:
|
||||
/// \code
|
||||
/// rakPeer[i]->CloseConnection(packet->guid, true);
|
||||
/// \endcode
|
||||
/// \param[in] packet Packet containing the ID_FCM2_VERIFIED_JOIN_REJECTED message
|
||||
/// \param[out] additionalData \a additionalData parameter passed to RespondOnVerifiedJoinCapable().
|
||||
virtual void GetVerifiedJoinRejectedAdditionalData(Packet *packet, BitStream *additionalData);
|
||||
|
||||
/// Override to write data when ID_FCM2_VERIFIED_JOIN_CAPABLE is sent
|
||||
virtual void WriteVJCUserData(SLNet::BitStream *bsOut) {(void) bsOut;}
|
||||
|
||||
/// Use to read data written from WriteVJCUserData()
|
||||
/// \code
|
||||
/// SLNet::BitStream bsIn(packet->data,packet->length,false);
|
||||
/// FullyConnectedMesh2::SkipToVJCUserData(&bsIn);
|
||||
/// // Your code here
|
||||
static void SkipToVJCUserData(SLNet::BitStream *bsIn);
|
||||
|
||||
/// Write custom user data to be sent with ID_FCM2_VERIFIED_JOIN_START, per user
|
||||
/// \param[out] bsOut Write your data here, if any. Has to match what is read by ReadVJSUserData
|
||||
/// \param[in] userGuid The RakNetGuid of the user you are writing for
|
||||
/// \param[in] userContext The data set with SetMyContext() for that system. May be empty. To properly write userContext, you will need to first write userContext->GetNumberOfBitsUsed(), followed by bsOut->Write(userContext);
|
||||
//virtual void WriteVJSUserData(SLNet::BitStream *bsOut, RakNetGUID userGuid, BitStream *userContext) {(void) bsOut; (void) userGuid; (void) userContext;}
|
||||
virtual void WriteVJSUserData(SLNet::BitStream *bsOut, RakNetGUID userGuid) {(void) bsOut; (void) userGuid;}
|
||||
|
||||
/// \internal
|
||||
SLNet::TimeUS GetElapsedRuntime(void);
|
||||
|
||||
/// \internal
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
/// \internal
|
||||
virtual void OnRakPeerStartup(void);
|
||||
/// \internal
|
||||
virtual void OnAttach(void);
|
||||
/// \internal
|
||||
virtual void OnRakPeerShutdown(void);
|
||||
/// \internal
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
/// \internal
|
||||
virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);
|
||||
/// \internal
|
||||
virtual void OnFailedConnectionAttempt(Packet *packet, PI2_FailedConnectionAttemptReason failedConnectionAttemptReason);
|
||||
|
||||
/// \internal
|
||||
struct FCM2Participant
|
||||
{
|
||||
FCM2Participant() {}
|
||||
FCM2Participant(const FCM2Guid &_fcm2Guid, const RakNetGUID &_rakNetGuid) : fcm2Guid(_fcm2Guid), rakNetGuid(_rakNetGuid) {}
|
||||
|
||||
// Low half is a random number.
|
||||
// High half is the order we connected in (totalConnectionCount)
|
||||
FCM2Guid fcm2Guid;
|
||||
RakNetGUID rakNetGuid;
|
||||
// BitStream userContext;
|
||||
};
|
||||
|
||||
enum JoinInProgressState
|
||||
{
|
||||
JIPS_PROCESSING,
|
||||
JIPS_FAILED,
|
||||
JIPS_CONNECTED,
|
||||
JIPS_UNNECESSARY,
|
||||
};
|
||||
|
||||
struct VerifiedJoinInProgressMember
|
||||
{
|
||||
SystemAddress systemAddress;
|
||||
RakNetGUID guid;
|
||||
JoinInProgressState joinInProgressState;
|
||||
BitStream *userData;
|
||||
|
||||
bool workingFlag;
|
||||
};
|
||||
|
||||
/// \internal
|
||||
struct VerifiedJoinInProgress
|
||||
{
|
||||
RakNetGUID requester;
|
||||
DataStructures::List<VerifiedJoinInProgressMember> vjipMembers;
|
||||
//bool sentResults;
|
||||
};
|
||||
|
||||
/// \internal for debugging
|
||||
unsigned int GetTotalConnectionCount(void) const;
|
||||
|
||||
protected:
|
||||
void PushNewHost(const RakNetGUID &guid, RakNetGUID oldHost);
|
||||
void SendOurFCMGuid(SystemAddress addr);
|
||||
void SendFCMGuidRequest(RakNetGUID rakNetGuid);
|
||||
void SendConnectionCountResponse(SystemAddress addr, unsigned int responseTotalConnectionCount);
|
||||
void OnRequestFCMGuid(Packet *packet);
|
||||
//void OnUpdateUserContext(Packet *packet);
|
||||
void OnRespondConnectionCount(Packet *packet);
|
||||
void OnInformFCMGuid(Packet *packet);
|
||||
void OnUpdateMinTotalConnectionCount(Packet *packet);
|
||||
void AssignOurFCMGuid(void);
|
||||
void CalculateHost(RakNetGUID *rakNetGuid, FCM2Guid *fcm2Guid);
|
||||
// bool AddParticipantInternal( RakNetGUID rakNetGuid, FCM2Guid theirFCMGuid, BitStream *userContext );
|
||||
bool AddParticipantInternal( RakNetGUID rakNetGuid, FCM2Guid theirFCMGuid );
|
||||
void CalculateAndPushHost(void);
|
||||
bool ParticipantListComplete(void);
|
||||
void IncrementTotalConnectionCount(unsigned int i);
|
||||
PluginReceiveResult OnVerifiedJoinStart(Packet *packet);
|
||||
PluginReceiveResult OnVerifiedJoinCapable(Packet *packet);
|
||||
virtual void OnVerifiedJoinFailed(RakNetGUID hostGuid, bool callCloseConnection);
|
||||
virtual void OnVerifiedJoinAccepted(Packet *packet);
|
||||
virtual void OnVerifiedJoinRejected(Packet *packet);
|
||||
unsigned int GetJoinsInProgressIndex(RakNetGUID requester) const;
|
||||
void UpdateVerifiedJoinInProgressMember(const AddressOrGUID systemIdentifier, RakNetGUID guidToAssign, JoinInProgressState newState);
|
||||
bool ProcessVerifiedJoinInProgressIfCompleted(VerifiedJoinInProgress *vjip);
|
||||
void ReadVerifiedJoinInProgressMember(SLNet::BitStream *bsIn, VerifiedJoinInProgressMember *vjipm);
|
||||
unsigned int GetVerifiedJoinInProgressMemberIndex(const AddressOrGUID systemIdentifier, VerifiedJoinInProgress *vjip);
|
||||
void DecomposeJoinCapable(Packet *packet, VerifiedJoinInProgress *vjip);
|
||||
void WriteVerifiedJoinCapable(SLNet::BitStream *bsOut, VerifiedJoinInProgress *vjip);
|
||||
void CategorizeVJIP(VerifiedJoinInProgress *vjip,
|
||||
DataStructures::List<RakNetGUID> &participatingMembersOnClientSucceeded,
|
||||
DataStructures::List<RakNetGUID> &participatingMembersOnClientFailed,
|
||||
DataStructures::List<RakNetGUID> &participatingMembersNotOnClient,
|
||||
DataStructures::List<RakNetGUID> &clientMembersNotParticipatingSucceeded,
|
||||
DataStructures::List<RakNetGUID> &clientMembersNotParticipatingFailed);
|
||||
|
||||
// Used to track how long RakNet has been running. This is so we know who has been running longest
|
||||
SLNet::TimeUS startupTime;
|
||||
|
||||
// Option for SetAutoparticipateConnections
|
||||
bool autoParticipateConnections;
|
||||
|
||||
// totalConnectionCount is roughly maintained across all systems, and increments by 1 each time a new system connects to the mesh
|
||||
// It is always kept at the highest known value
|
||||
// It is used as the high 4 bytes for new FCMGuids. This causes newer values of FCM2Guid to be higher than lower values. The lowest value is the host.
|
||||
unsigned int totalConnectionCount;
|
||||
|
||||
// Our own ourFCMGuid. Starts at unassigned (0). Assigned once we send ID_FCM2_REQUEST_FCMGUID and get back ID_FCM2_RESPOND_CONNECTION_COUNT
|
||||
FCM2Guid ourFCMGuid;
|
||||
|
||||
/// List of systems we know the FCM2Guid for
|
||||
DataStructures::List<FCM2Participant*> fcm2ParticipantList;
|
||||
|
||||
RakNetGUID lastPushedHost;
|
||||
|
||||
// Optimization: Store last calculated host in these variables.
|
||||
RakNetGUID hostRakNetGuid;
|
||||
FCM2Guid hostFCM2Guid;
|
||||
|
||||
SLNet::RakString connectionPassword;
|
||||
bool connectOnNewRemoteConnections;
|
||||
|
||||
DataStructures::List<VerifiedJoinInProgress*> joinsInProgress;
|
||||
BitStream myContext;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
/*
|
||||
Startup()
|
||||
ourFCMGuid=unknown
|
||||
totalConnectionCount=0
|
||||
Set startupTime
|
||||
|
||||
AddParticipant()
|
||||
if (sender by guid is a participant)
|
||||
return;
|
||||
AddParticipantInternal(guid);
|
||||
if (ourFCMGuid==unknown)
|
||||
Send to that system a request for their fcmGuid, totalConnectionCount. Inform startupTime.
|
||||
else
|
||||
Send to that system a request for their fcmGuid. Inform total connection count, our fcmGuid
|
||||
|
||||
OnRequestGuid()
|
||||
if (sender by guid is not a participant)
|
||||
{
|
||||
// They added us as a participant, but we didn't add them. This can be caused by lag where both participants are not added at the same time.
|
||||
// It doesn't affect the outcome as long as we still process the data
|
||||
AddParticipantInternal(guid);
|
||||
}
|
||||
if (ourFCMGuid==unknown)
|
||||
{
|
||||
if (includedStartupTime)
|
||||
{
|
||||
// Nobody has a fcmGuid
|
||||
|
||||
if (their startup time is greater than our startup time)
|
||||
ReplyConnectionCount(1);
|
||||
else
|
||||
ReplyConnectionCount(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// They have a fcmGuid, we do not
|
||||
|
||||
SetMaxTotalConnectionCount(remoteCount);
|
||||
AssignTheirGuid()
|
||||
GenerateOurGuid();
|
||||
SendOurGuid(all);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (includedStartupTime)
|
||||
{
|
||||
// We have a fcmGuid they do not
|
||||
|
||||
ReplyConnectionCount(totalConnectionCount+1);
|
||||
SendOurGuid(sender);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We both have fcmGuids
|
||||
|
||||
SetMaxTotalConnectionCount(remoteCount);
|
||||
AssignTheirGuid();
|
||||
SendOurGuid(sender);
|
||||
}
|
||||
}
|
||||
|
||||
OnReplyConnectionCount()
|
||||
SetMaxTotalConnectionCount(remoteCount);
|
||||
GenerateOurGuid();
|
||||
SendOurGuid(allParticipants);
|
||||
|
||||
OnReceiveTheirGuid()
|
||||
AssignTheirGuid()
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
47
Source/include/slikenet/GetTime.h
Normal file
47
Source/include/slikenet/GetTime.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file GetTime.h
|
||||
/// \brief Returns the value from QueryPerformanceCounter. This is the function RakNet uses to represent time. This time won't match the time returned by GetTimeCount(). See http://www.jenkinssoftware.com/forum/index.php?topic=2798.0
|
||||
///
|
||||
|
||||
|
||||
#ifndef __GET_TIME_H
|
||||
#define __GET_TIME_H
|
||||
|
||||
#include "Export.h"
|
||||
#include "time.h" // For SLNet::TimeMS
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Same as GetTimeMS
|
||||
/// Holds the time in either a 32 or 64 bit variable, depending on __GET_TIME_64BIT
|
||||
SLNet::Time RAK_DLL_EXPORT GetTime( void );
|
||||
|
||||
/// Return the time as 32 bit
|
||||
/// \note The maximum delta between returned calls is 1 second - however, RakNet calls this constantly anyway. See NormalizeTime() in the cpp.
|
||||
SLNet::TimeMS RAK_DLL_EXPORT GetTimeMS( void );
|
||||
|
||||
/// Return the time as 64 bit
|
||||
/// \note The maximum delta between returned calls is 1 second - however, RakNet calls this constantly anyway. See NormalizeTime() in the cpp.
|
||||
SLNet::TimeUS RAK_DLL_EXPORT GetTimeUS( void );
|
||||
|
||||
/// a > b?
|
||||
extern RAK_DLL_EXPORT bool GreaterThan(SLNet::Time a, SLNet::Time b);
|
||||
/// a < b?
|
||||
extern RAK_DLL_EXPORT bool LessThan(SLNet::Time a, SLNet::Time b);
|
||||
}
|
||||
|
||||
#endif
|
||||
24
Source/include/slikenet/Getche.h
Normal file
24
Source/include/slikenet/Getche.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <conio.h> /* _getche() */
|
||||
|
||||
#else
|
||||
#include <termios.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
char _getche();
|
||||
#endif
|
||||
24
Source/include/slikenet/Gets.h
Normal file
24
Source/include/slikenet/Gets.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GETS__H_
|
||||
#define __GETS__H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
char * Gets ( char * str, int num );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
83
Source/include/slikenet/GridSectorizer.h
Normal file
83
Source/include/slikenet/GridSectorizer.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifndef _GRID_SECTORIZER_H
|
||||
#define _GRID_SECTORIZER_H
|
||||
|
||||
//#define _USE_ORDERED_LIST
|
||||
|
||||
#include "memoryoverride.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
|
||||
180
Source/include/slikenet/HTTPConnection.h
Normal file
180
Source/include/slikenet/HTTPConnection.h
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017-2020, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file HTTPConnection.h
|
||||
/// \brief Contains HTTPConnection, used to communicate with web servers
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_HTTPConnection==1 && _RAKNET_SUPPORT_TCPInterface==1
|
||||
|
||||
#ifndef __HTTP_CONNECTION
|
||||
#define __HTTP_CONNECTION
|
||||
|
||||
#include "Export.h"
|
||||
#include "string.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "types.h"
|
||||
#include "DS_Queue.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class TCPInterface;
|
||||
struct SystemAddress;
|
||||
|
||||
/// \brief Use HTTPConnection to communicate with a web server.
|
||||
/// \details 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.
|
||||
/// \deprecated, use HTTPConnection2
|
||||
class RAK_DLL_EXPORT HTTPConnection
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(HTTPConnection)
|
||||
|
||||
/// Returns a HTTP object associated with this tcp connection
|
||||
HTTPConnection();
|
||||
virtual ~HTTPConnection();
|
||||
|
||||
/// \pre tcp should already be started
|
||||
void Init(TCPInterface *_tcp, const char *host, unsigned short port=80);
|
||||
|
||||
/// 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 "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 a file from a webserver
|
||||
/// \param path the path on the remote server you want to GET from. For example "index.html"
|
||||
void Get(const char *path);
|
||||
|
||||
/// Is there a Read result ready?
|
||||
bool HasRead(void) const;
|
||||
|
||||
/// Get one result from the server
|
||||
/// \pre HasResult must return true
|
||||
SLNet::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 nullptr or a packet associated with our host and port
|
||||
void ProcessTCPPacket(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; }
|
||||
|
||||
SLNet::RakString data;
|
||||
int code; // ResponseCodes
|
||||
};
|
||||
|
||||
/// Queued events of failed exchanges with the HTTP server
|
||||
bool HasBadResponse(int *code, SLNet::RakString *data);
|
||||
|
||||
/// Returns false if the connection is not doing anything else
|
||||
bool IsBusy(void) const;
|
||||
|
||||
/// \internal
|
||||
int GetState(void) const;
|
||||
|
||||
struct OutgoingCommand
|
||||
{
|
||||
SLNet::RakString remotePath;
|
||||
SLNet::RakString data;
|
||||
SLNet::RakString contentType;
|
||||
bool isPost;
|
||||
};
|
||||
|
||||
DataStructures::Queue<OutgoingCommand> outgoingCommand;
|
||||
OutgoingCommand currentProcessingCommand;
|
||||
|
||||
private:
|
||||
SystemAddress server;
|
||||
TCPInterface *tcp;
|
||||
SLNet::RakString host;
|
||||
unsigned short port;
|
||||
DataStructures::Queue<BadResponse> badResponses;
|
||||
|
||||
enum ConnectionState
|
||||
{
|
||||
CS_NONE,
|
||||
CS_DISCONNECTING,
|
||||
CS_CONNECTING,
|
||||
CS_CONNECTED,
|
||||
CS_PROCESSING,
|
||||
} connectionState;
|
||||
|
||||
SLNet::RakString incomingData;
|
||||
DataStructures::Queue<SLNet::RakString> results;
|
||||
|
||||
void CloseConnection();
|
||||
|
||||
/*
|
||||
enum { RAK_HTTP_INITIAL,
|
||||
RAK_HTTP_STARTING,
|
||||
RAK_HTTP_CONNECTING,
|
||||
RAK_HTTP_ESTABLISHED,
|
||||
RAK_HTTP_REQUEST_SENT,
|
||||
RAK_HTTP_IDLE } state;
|
||||
|
||||
SLNet::RakString outgoing, incoming, path, contentType;
|
||||
void Process(Packet *packet); // the workhorse
|
||||
|
||||
// this helps check the various status lists in TCPInterface
|
||||
typedef SystemAddress (TCPInterface::*StatusCheckFunction)(void);
|
||||
bool InList(StatusCheckFunction func);
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
129
Source/include/slikenet/HTTPConnection2.h
Normal file
129
Source/include/slikenet/HTTPConnection2.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file HTTPConnection2.h
|
||||
/// \brief Contains HTTPConnection2, used to communicate with web servers
|
||||
///
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_HTTPConnection2==1 && _RAKNET_SUPPORT_TCPInterface==1
|
||||
|
||||
#ifndef __HTTP_CONNECTION_2
|
||||
#define __HTTP_CONNECTION_2
|
||||
|
||||
#include "Export.h"
|
||||
#include "string.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "types.h"
|
||||
#include "DS_List.h"
|
||||
#include "DS_Queue.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "SimpleMutex.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class TCPInterface;
|
||||
struct SystemAddress;
|
||||
|
||||
/// \brief Use HTTPConnection2 to communicate with a web server.
|
||||
/// \details Start an instance of TCPInterface via the Start() command.
|
||||
/// This class will handle connecting to transmit a request
|
||||
class RAK_DLL_EXPORT HTTPConnection2 : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(HTTPConnection2)
|
||||
|
||||
HTTPConnection2();
|
||||
virtual ~HTTPConnection2();
|
||||
|
||||
/// \brief Connect to, then transmit a request to a TCP based server
|
||||
/// \param[in] tcp An instance of TCPInterface that previously had TCPInterface::Start() called
|
||||
/// \param[in] stringToTransmit What string to transmit. See RakString::FormatForPOST(), RakString::FormatForGET(), RakString::FormatForDELETE()
|
||||
/// \param[in] host The IP address to connect to
|
||||
/// \param[in] port The port to connect to
|
||||
/// \param[in] useSSL If to use SSL to connect. OPEN_SSL_CLIENT_SUPPORT must be defined to 1 in defines.h or defineoverrides.h
|
||||
/// \param[in] ipVersion 4 for IPV4, 6 for IPV6
|
||||
/// \param[in] useAddress Assume we are connected to this address and send to it, rather than do a lookup
|
||||
/// \param[in] userData
|
||||
/// \return false if host is not a valid IP address or domain name
|
||||
bool TransmitRequest(const char* stringToTransmit, const char* host, unsigned short port=80, bool useSSL=false, int ipVersion=4, SystemAddress useAddress=UNASSIGNED_SYSTEM_ADDRESS, void *userData=0);
|
||||
|
||||
/// \brief Check for and return a response from a prior call to TransmitRequest()
|
||||
/// As TCP is stream based, you may get a webserver reply over several calls to TCPInterface::Receive()
|
||||
/// HTTPConnection2 will store Packet::data and return the response to you either when the connection to the webserver is lost, or enough data has been received()
|
||||
/// This will only potentially return true after a call to ProcessTCPPacket() or OnLostConnection()
|
||||
/// \param[out] stringTransmitted The original string transmitted
|
||||
/// \param[out] hostTransmitted The parameter of the same name passed to TransmitRequest()
|
||||
/// \param[out] responseReceived The response, if any
|
||||
/// \param[out] hostReceived The SystemAddress from ProcessTCPPacket() or OnLostConnection()
|
||||
/// \param[out] contentOffset The offset from the start of responseReceived to the data body. Equivalent to searching for \r\n\r\n in responseReceived.
|
||||
/// \param[out] userData Whatever you passed to TransmitRequest
|
||||
/// \return true if there was a response. false if not.
|
||||
bool GetResponse( RakString &stringTransmitted, RakString &hostTransmitted, RakString &responseReceived, SystemAddress &hostReceived, ptrdiff_t &contentOffset, void **userData );
|
||||
bool GetResponse( RakString &stringTransmitted, RakString &hostTransmitted, RakString &responseReceived, SystemAddress &hostReceived, ptrdiff_t &contentOffset );
|
||||
|
||||
/// \brief Return if any requests are pending
|
||||
bool IsBusy(void) const;
|
||||
|
||||
/// \brief Return if any requests are waiting to be read by the user
|
||||
bool HasResponse(void) const;
|
||||
|
||||
struct Request
|
||||
{
|
||||
RakString stringToTransmit;
|
||||
RakString stringReceived;
|
||||
RakString host;
|
||||
SystemAddress hostEstimatedAddress;
|
||||
SystemAddress hostCompletedAddress;
|
||||
unsigned short port;
|
||||
bool useSSL;
|
||||
ptrdiff_t contentOffset;
|
||||
int contentLength;
|
||||
int ipVersion;
|
||||
void *userData;
|
||||
bool chunked;
|
||||
size_t thisChunkSize;
|
||||
size_t bytesReadForThisChunk;
|
||||
};
|
||||
|
||||
/// \internal
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);
|
||||
virtual void OnFailedConnectionAttempt(Packet *packet, PI2_FailedConnectionAttemptReason failedConnectionAttemptReason);
|
||||
|
||||
protected:
|
||||
|
||||
bool IsConnected(SystemAddress sa);
|
||||
void SendRequest(Request *request);
|
||||
void RemovePendingRequest(SystemAddress sa);
|
||||
void SendNextPendingRequest(void);
|
||||
void SendPendingRequestToConnectedSystem(SystemAddress sa);
|
||||
|
||||
DataStructures::Queue<Request*> pendingRequests;
|
||||
DataStructures::List<Request*> sentRequests;
|
||||
DataStructures::List<Request*> completedRequests;
|
||||
|
||||
SimpleMutex pendingRequestsMutex, sentRequestsMutex, completedRequestsMutex;
|
||||
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
43
Source/include/slikenet/IncrementalReadInterface.h
Normal file
43
Source/include/slikenet/IncrementalReadInterface.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifndef __INCREMENTAL_READ_INTERFACE_H
|
||||
#define __INCREMENTAL_READ_INTERFACE_H
|
||||
|
||||
#include "FileListNodeContext.h"
|
||||
#include "Export.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
class RAK_DLL_EXPORT IncrementalReadInterface
|
||||
{
|
||||
public:
|
||||
IncrementalReadInterface() {}
|
||||
virtual ~IncrementalReadInterface() {}
|
||||
|
||||
/// 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( const char *filename, unsigned int startReadBytes, unsigned int numBytesToRead, void *preallocatedDestination, FileListNodeContext context);
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
135
Source/include/slikenet/InternalPacket.h
Normal file
135
Source/include/slikenet/InternalPacket.h
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief \b [Internal] A class which stores a user message, and all information associated with sending and receiving that message.
|
||||
///
|
||||
|
||||
#ifndef __INTERNAL_PACKET_H
|
||||
#define __INTERNAL_PACKET_H
|
||||
|
||||
#include "PacketPriority.h"
|
||||
#include "types.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "defines.h"
|
||||
#include "NativeTypes.h"
|
||||
#include "defines.h"
|
||||
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL!=1
|
||||
#include "CCRakNetUDT.h"
|
||||
#else
|
||||
#include "CCRakNetSlidingWindow.h"
|
||||
#endif
|
||||
|
||||
namespace SLNet {
|
||||
|
||||
typedef uint16_t SplitPacketIdType;
|
||||
typedef uint32_t 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
|
||||
/// Internally assumed to be 4 bytes, but written as 3 bytes in ReliabilityLayer::WriteToBitStreamFromInternalPacket
|
||||
typedef uint24_t 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 SLNet::TimeUS RemoteSystemTimeType;
|
||||
|
||||
struct InternalPacketFixedSizeTransmissionHeader
|
||||
{
|
||||
/// A unique numerical identifier given to this user message. Used to identify reliable messages on the network
|
||||
MessageNumberType reliableMessageNumber;
|
||||
///The ID used as identification for ordering messages. Also included in sequenced messages
|
||||
OrderingIndexType orderingIndex;
|
||||
// Used only with sequenced messages
|
||||
OrderingIndexType sequencingIndex;
|
||||
///What ordering channel this packet is on, if the reliability type uses ordering channels
|
||||
unsigned char orderingChannel;
|
||||
///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;;
|
||||
///How many bits long the data is
|
||||
BitSize_t dataBitLength;
|
||||
///What type of reliability algorithm to use with this packet
|
||||
PacketReliability reliability;
|
||||
// Not endian safe
|
||||
// unsigned char priority : 3;
|
||||
// unsigned char reliability : 5;
|
||||
};
|
||||
|
||||
/// Used in InternalPacket when pointing to sharedDataBlock, rather than allocating itself
|
||||
struct InternalPacketRefCountedData
|
||||
{
|
||||
unsigned char *sharedDataBlock;
|
||||
unsigned int refCount;
|
||||
};
|
||||
|
||||
/// Holds a user message, and related information
|
||||
/// Don't use a constructor or destructor, due to the memory pool I am using
|
||||
struct InternalPacket : public InternalPacketFixedSizeTransmissionHeader
|
||||
{
|
||||
/// 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;
|
||||
/// Was this packet number used this update to track windowing drops or increases? Each packet number is only used once per update.
|
||||
// bool allowWindowUpdate;
|
||||
///When this packet was created
|
||||
SLNet::TimeUS creationTime;
|
||||
///The resendNext time to take action on this packet
|
||||
SLNet::TimeUS nextActionTime;
|
||||
// For debugging
|
||||
SLNet::TimeUS retransmissionTime;
|
||||
// Size of the header when encoded into a bitstream
|
||||
BitSize_t headerLength;
|
||||
/// Buffer is a pointer to the actual data, assuming this packet has data at all
|
||||
unsigned char *data;
|
||||
/// How to alloc and delete the data member
|
||||
enum AllocationScheme
|
||||
{
|
||||
/// Data is allocated using rakMalloc. Just free it
|
||||
NORMAL,
|
||||
|
||||
/// data points to a larger block of data, where the larger block is reference counted. internalPacketRefCountedData is used in this case
|
||||
REF_COUNTED,
|
||||
|
||||
/// If allocation scheme is STACK, data points to stackData and should not be deallocated
|
||||
/// This is only used when sending. Received packets are deallocated in RakPeer
|
||||
STACK
|
||||
} allocationScheme;
|
||||
InternalPacketRefCountedData *refCountedData;
|
||||
/// How many attempts we made at sending this message
|
||||
unsigned char timesSent;
|
||||
/// The priority level of this packet
|
||||
PacketPriority priority;
|
||||
/// If the reliability type requires a receipt, then return this number with it
|
||||
uint32_t sendReceiptSerial;
|
||||
|
||||
// Used for the resend queue
|
||||
// Linked list implementation so I can remove from the list via a pointer, without finding it in the list
|
||||
InternalPacket *resendPrev, *resendNext,*unreliablePrev,*unreliableNext;
|
||||
|
||||
unsigned char stackData[128];
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
25
Source/include/slikenet/Itoa.h
Normal file
25
Source/include/slikenet/Itoa.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RAK_ITOA_H
|
||||
#define __RAK_ITOA_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
char* Itoa( int value, char* result, int base );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
92
Source/include/slikenet/Kbhit.h
Normal file
92
Source/include/slikenet/Kbhit.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*****************************************************************************
|
||||
_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.
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* Modified work: Copyright (c) 2016-2020, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications in this file are put under the public domain.
|
||||
* Alternatively you are permitted to license the modifications under the MIT license, if you so desire. The
|
||||
* license can be found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32)
|
||||
#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, nullptr, nullptr, &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
|
||||
|
||||
|
||||
41
Source/include/slikenet/LinuxStrings.h
Normal file
41
Source/include/slikenet/LinuxStrings.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifndef _GCC_WIN_STRINGS
|
||||
#define _GCC_WIN_STRINGS
|
||||
|
||||
#if defined(__native_client__)
|
||||
#ifndef _stricmp
|
||||
int _stricmp(const char* s1, const char* s2);
|
||||
#endif
|
||||
int _strnicmp(const char* s1, const char* s2, size_t n);
|
||||
char *_strlwr(char * str );
|
||||
#else
|
||||
#if (defined(__GNUC__) || defined(__GCCXML__) || defined(__S3E__) ) && !defined(_WIN32)
|
||||
#ifndef _stricmp
|
||||
int _stricmp(const char* s1, const char* s2);
|
||||
#endif
|
||||
int _strnicmp(const char* s1, const char* s2, size_t n);
|
||||
// http://www.jenkinssoftware.com/forum/index.php?topic=5010.msg20920#msg20920
|
||||
#ifndef __APPLE__
|
||||
char *_strlwr(char * str ); //this won't compile on OSX for some reason
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // _GCC_WIN_STRINGS
|
||||
55
Source/include/slikenet/LocklessTypes.h
Normal file
55
Source/include/slikenet/LocklessTypes.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifndef __LOCKLESS_TYPES_H
|
||||
#define __LOCKLESS_TYPES_H
|
||||
|
||||
#include "Export.h"
|
||||
#include "NativeTypes.h"
|
||||
#include "WindowsIncludes.h"
|
||||
#if defined(ANDROID) || defined(__S3E__) || defined(__APPLE__)
|
||||
// __sync_fetch_and_add not supported apparently
|
||||
#include "SimpleMutex.h"
|
||||
#endif
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
class RAK_DLL_EXPORT LocklessUint32_t
|
||||
{
|
||||
public:
|
||||
LocklessUint32_t();
|
||||
explicit LocklessUint32_t(uint32_t initial);
|
||||
// Returns variable value after changing it
|
||||
uint32_t Increment(void);
|
||||
// Returns variable value after changing it
|
||||
uint32_t Decrement(void);
|
||||
uint32_t GetValue(void) const {return value;}
|
||||
|
||||
protected:
|
||||
#ifdef _WIN32
|
||||
volatile LONG value;
|
||||
#elif defined(ANDROID) || defined(__S3E__) || defined(__APPLE__)
|
||||
// __sync_fetch_and_add not supported apparently
|
||||
SimpleMutex mutex;
|
||||
uint32_t value;
|
||||
#else
|
||||
volatile uint32_t value;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
132
Source/include/slikenet/LogCommandParser.h
Normal file
132
Source/include/slikenet/LogCommandParser.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Contains LogCommandParser , Used to send logs to connected consoles
|
||||
///
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_LogCommandParser==1
|
||||
|
||||
#ifndef __LOG_COMMAND_PARSER
|
||||
#define __LOG_COMMAND_PARSER
|
||||
|
||||
#include "CommandParserInterface.h"
|
||||
#include "Export.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
|
||||
/// \brief Adds the ability to send logging output to a remote console
|
||||
class RAK_DLL_EXPORT LogCommandParser : public CommandParserInterface
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(LogCommandParser)
|
||||
|
||||
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, const 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, const 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(const 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(const 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(const 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(const 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(const 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;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
38
Source/include/slikenet/MTUSize.h
Normal file
38
Source/include/slikenet/MTUSize.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief \b [Internal] Defines the default maximum transfer unit.
|
||||
///
|
||||
|
||||
|
||||
#ifndef MAXIMUM_MTU_SIZE
|
||||
|
||||
/// \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.
|
||||
/// The largest value for an UDP datagram
|
||||
|
||||
|
||||
|
||||
#define MAXIMUM_MTU_SIZE 1492
|
||||
|
||||
|
||||
#define MINIMUM_MTU_SIZE 400
|
||||
|
||||
#endif
|
||||
203
Source/include/slikenet/MessageFilter.h
Normal file
203
Source/include/slikenet/MessageFilter.h
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Message filter plugin. Assigns systems to FilterSets. Each FilterSet limits what messages are allowed. This is a security related plugin.
|
||||
///
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_MessageFilter==1
|
||||
|
||||
#ifndef __MESSAGE_FILTER_PLUGIN_H
|
||||
#define __MESSAGE_FILTER_PLUGIN_H
|
||||
|
||||
#include "types.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "DS_OrderedList.h"
|
||||
#include "DS_Hash.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
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
|
||||
/// \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;
|
||||
SLNet::TimeMS disallowedMessageBanTimeMS;
|
||||
SLNet::TimeMS timeExceedBanTimeMS;
|
||||
SLNet::TimeMS maxMemberTimeMS;
|
||||
void (*invalidMessageCallback)(RakPeerInterface *peer, AddressOrGUID systemAddress, int filterSetID, void *userData, unsigned char messageID);
|
||||
void *disallowedCallbackUserData;
|
||||
void (*timeoutCallback)(RakPeerInterface *peer, AddressOrGUID systemAddress, int filterSetID, void *userData);
|
||||
void *timeoutUserData;
|
||||
int filterSetID;
|
||||
bool allowedIDs[MESSAGE_FILTER_MAX_MESSAGE_ID];
|
||||
DataStructures::OrderedList<SLNet::RakString, SLNet::RakString> allowedRPC4;
|
||||
};
|
||||
|
||||
/// \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
|
||||
{
|
||||
FilterSet *filter;
|
||||
SLNet::TimeMS timeEnteredThisSet;
|
||||
};
|
||||
|
||||
/// \defgroup MESSAGEFILTER_GROUP MessageFilter
|
||||
/// \brief Remote incoming packets from unauthorized systems
|
||||
/// \details
|
||||
/// \ingroup PLUGINS_GROUP
|
||||
|
||||
/// \brief Assigns systems to FilterSets. Each FilterSet limits what kinds of messages are allowed.
|
||||
/// \details The MessageFilter plugin is used for security where you limit what systems can send what kind of messages.<BR>
|
||||
/// You implicitly define FilterSets, and add allowed message IDs to these FilterSets.<BR>
|
||||
/// You then add systems to these filters, such that those systems are limited to sending what the filters allows.<BR>
|
||||
/// You can automatically assign systems to a filter.<BR>
|
||||
/// You can automatically kick and possibly ban users that stay in a filter too long, or send the wrong message.<BR>
|
||||
/// Each system is a member of either zero or one filters.<BR>
|
||||
/// 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 PluginInterface2
|
||||
{
|
||||
public:
|
||||
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(MessageFilter)
|
||||
|
||||
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 a specific RPC4 call
|
||||
/// \pre MessageFilter must be attached before RPC4
|
||||
/// \param[in] uniqueID Identifier passed to RegisterFunction()
|
||||
/// \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 SetAllowRPC4(bool allow, const char* uniqueID, 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, SLNet::TimeMS 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, AddressOrGUID addressOrGUID, 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, AddressOrGUID addressOrGUID, 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, SLNet::TimeMS banTimeMS, int filterSetID);
|
||||
|
||||
/// Get the filterSetID a system is using. Returns -1 for none.
|
||||
/// \param[in] addressOrGUID The system we are referring to
|
||||
int GetSystemFilterSet(AddressOrGUID addressOrGUID);
|
||||
|
||||
/// 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] addressOrGUID 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(AddressOrGUID addressOrGUID, 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 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 Update(void);
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
|
||||
protected:
|
||||
|
||||
void Clear(void);
|
||||
void DeallocateFilterSet(FilterSet *filterSet);
|
||||
FilterSet* GetFilterSetByID(int filterSetID);
|
||||
void OnInvalidMessage(FilterSet *filterSet, AddressOrGUID systemAddress, unsigned char messageID);
|
||||
|
||||
DataStructures::OrderedList<int, FilterSet*, FilterSetComp> filterList;
|
||||
// Change to guid
|
||||
DataStructures::Hash<AddressOrGUID, FilteredSystem, 2048, AddressOrGUID::ToInteger> systemList;
|
||||
|
||||
int autoAddNewConnectionsToFilter;
|
||||
SLNet::Time whenLastTimeoutCheck;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
442
Source/include/slikenet/MessageIdentifiers.h
Normal file
442
Source/include/slikenet/MessageIdentifiers.h
Normal file
@ -0,0 +1,442 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief All the message identifiers used by RakNet. Message identifiers comprise the first byte of any message.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __MESSAGE_IDENTIFIERS_H
|
||||
#define __MESSAGE_IDENTIFIERS_H
|
||||
|
||||
#if defined(RAKNET_USE_CUSTOM_PACKET_IDS)
|
||||
#include "CustomPacketIdentifiers.h"
|
||||
#else
|
||||
|
||||
enum OutOfBandIdentifiers
|
||||
{
|
||||
ID_NAT_ESTABLISH_UNIDIRECTIONAL,
|
||||
ID_NAT_ESTABLISH_BIDIRECTIONAL,
|
||||
ID_NAT_TYPE_DETECT,
|
||||
ID_ROUTER_2_REPLY_TO_SENDER_PORT,
|
||||
ID_ROUTER_2_REPLY_TO_SPECIFIED_PORT,
|
||||
ID_ROUTER_2_MINI_PUNCH_REPLY,
|
||||
ID_ROUTER_2_MINI_PUNCH_REPLY_BOUNCE,
|
||||
ID_XBOX_360_VOICE,
|
||||
ID_XBOX_360_GET_NETWORK_ROOM,
|
||||
ID_XBOX_360_RETURN_NETWORK_ROOM,
|
||||
ID_NAT_PING,
|
||||
ID_NAT_PONG,
|
||||
};
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// \code
|
||||
/// enum {
|
||||
/// ID_MYPROJECT_MSG_1 = ID_USER_PACKET_ENUM,
|
||||
/// ID_MYPROJECT_MSG_2,
|
||||
/// ...
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// \note All these enumerations should be casted to (unsigned char) before writing them to SLNet::BitStream
|
||||
enum DefaultMessageIDTypes
|
||||
{
|
||||
//
|
||||
// RESERVED TYPES - DO NOT CHANGE THESE
|
||||
// All types from RakPeer
|
||||
//
|
||||
/// These types are never returned to the user.
|
||||
/// Ping from a connected system. Update timestamps (internal use only)
|
||||
ID_CONNECTED_PING,
|
||||
/// Ping from an unconnected system. Reply but do not update timestamps. (internal use only)
|
||||
ID_UNCONNECTED_PING,
|
||||
/// Ping from an unconnected system. Only reply if we have open connections. Do not update timestamps. (internal use only)
|
||||
ID_UNCONNECTED_PING_OPEN_CONNECTIONS,
|
||||
/// Pong from a connected system. Update timestamps (internal use only)
|
||||
ID_CONNECTED_PONG,
|
||||
/// A reliable packet to detect lost connections (internal use only)
|
||||
ID_DETECT_LOST_CONNECTIONS,
|
||||
/// C2S: Initial query: Header(1), OfflineMesageID(16), Protocol number(1), Pad(toMTU), sent with no fragment set.
|
||||
/// If protocol fails on server, returns ID_INCOMPATIBLE_PROTOCOL_VERSION to client
|
||||
ID_OPEN_CONNECTION_REQUEST_1,
|
||||
/// S2C: Header(1), OfflineMesageID(16), server GUID(8), HasSecurity(1), Cookie(4, if HasSecurity)
|
||||
/// , public key (if do security is true), MTU(2). If public key fails on client, returns ID_PUBLIC_KEY_MISMATCH
|
||||
ID_OPEN_CONNECTION_REPLY_1,
|
||||
/// C2S: Header(1), OfflineMesageID(16), Cookie(4, if HasSecurity is true on the server), clientSupportsSecurity(1 bit),
|
||||
/// handshakeChallenge (if has security on both server and client), remoteBindingAddress(6), MTU(2), client GUID(8)
|
||||
/// Connection slot allocated if cookie is valid, server is not full, GUID and IP not already in use.
|
||||
ID_OPEN_CONNECTION_REQUEST_2,
|
||||
/// S2C: Header(1), OfflineMesageID(16), server GUID(8), mtu(2), doSecurity(1 bit), handshakeAnswer (if do security is true)
|
||||
ID_OPEN_CONNECTION_REPLY_2,
|
||||
/// C2S: Header(1), GUID(8), Timestamp, HasSecurity(1), Proof(32)
|
||||
ID_CONNECTION_REQUEST,
|
||||
/// RakPeer - Remote system requires secure connections, pass a public key to RakPeerInterface::Connect()
|
||||
ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY,
|
||||
/// RakPeer - We passed a public key to RakPeerInterface::Connect(), but the other system did not have security turned on
|
||||
ID_OUR_SYSTEM_REQUIRES_SECURITY,
|
||||
/// RakPeer - Wrong public key passed to RakPeerInterface::Connect()
|
||||
ID_PUBLIC_KEY_MISMATCH,
|
||||
/// 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,
|
||||
/// If RakPeerInterface::Send() is called where PacketReliability contains _WITH_ACK_RECEIPT, then on a later call to
|
||||
/// RakPeerInterface::Receive() you will get ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS. The message will be 5 bytes long,
|
||||
/// and bytes 1-4 inclusive will contain a number in native order containing a number that identifies this message.
|
||||
/// This number will be returned by RakPeerInterface::Send() or RakPeerInterface::SendList(). ID_SND_RECEIPT_ACKED means that
|
||||
/// the message arrived
|
||||
ID_SND_RECEIPT_ACKED,
|
||||
/// If RakPeerInterface::Send() is called where PacketReliability contains UNRELIABLE_WITH_ACK_RECEIPT, then on a later call to
|
||||
/// RakPeerInterface::Receive() you will get ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS. The message will be 5 bytes long,
|
||||
/// and bytes 1-4 inclusive will contain a number in native order containing a number that identifies this message. This number
|
||||
/// will be returned by RakPeerInterface::Send() or RakPeerInterface::SendList(). ID_SND_RECEIPT_LOSS means that an ack for the
|
||||
/// message did not arrive (it may or may not have been delivered, probably not). On disconnect or shutdown, you will not get
|
||||
/// ID_SND_RECEIPT_LOSS for unsent messages, you should consider those messages as all lost.
|
||||
ID_SND_RECEIPT_LOSS,
|
||||
|
||||
|
||||
//
|
||||
// USER TYPES - DO NOT CHANGE THESE
|
||||
//
|
||||
|
||||
/// 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.
|
||||
ID_CONNECTION_ATTEMPT_FAILED,
|
||||
/// RakPeer - Sent a connect request to a system we are currently connected to.
|
||||
ID_ALREADY_CONNECTED,
|
||||
/// RakPeer - A remote system has successfully connected.
|
||||
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.
|
||||
ID_DISCONNECTION_NOTIFICATION,
|
||||
/// 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 are banned from the system we attempted to connect to.
|
||||
ID_CONNECTION_BANNED,
|
||||
/// RakPeer - The remote system is using a password and has refused our connection because we did not set the correct password.
|
||||
ID_INVALID_PASSWORD,
|
||||
// RAKNET_PROTOCOL_VERSION in version.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,
|
||||
// Means that this IP address connected recently, and can't connect again as a security measure. See
|
||||
/// RakPeer::SetLimitIPConnectionFrequency()
|
||||
ID_IP_RECENTLY_CONNECTED,
|
||||
/// RakPeer - The sizeof(RakNetTime) bytes following this byte represent a value which is automatically modified by the difference
|
||||
/// in system times between the sender and the recipient. Requires that you call SetOccasionalPing.
|
||||
ID_TIMESTAMP,
|
||||
/// RakPeer - Pong from an unconnected system. First byte is ID_UNCONNECTED_PONG, second sizeof(SLNet::TimeMS) bytes is the ping,
|
||||
/// following bytes is system specific enumeration data.
|
||||
/// Read using bitstreams
|
||||
ID_UNCONNECTED_PONG,
|
||||
/// RakPeer - Inform a remote system of our IP/Port. On the recipient, all data past ID_ADVERTISE_SYSTEM is whatever was passed to
|
||||
/// the data parameter
|
||||
ID_ADVERTISE_SYSTEM,
|
||||
// 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,
|
||||
|
||||
/// ConnectionGraph2 plugin - In a client/server environment, a client other than ourselves has disconnected gracefully.
|
||||
/// Packet::systemAddress is modified to reflect the systemAddress of this client.
|
||||
ID_REMOTE_DISCONNECTION_NOTIFICATION,
|
||||
/// ConnectionGraph2 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,
|
||||
/// ConnectionGraph2 plugin: Bytes 1-4 = count. for (count items) contains {SystemAddress, RakNetGUID, 2 byte ping}
|
||||
ID_REMOTE_NEW_INCOMING_CONNECTION,
|
||||
|
||||
/// FileListTransfer plugin - Setup data
|
||||
ID_FILE_LIST_TRANSFER_HEADER,
|
||||
/// FileListTransfer plugin - A file
|
||||
ID_FILE_LIST_TRANSFER_FILE,
|
||||
// Ack for reference push, to send more of the file
|
||||
ID_FILE_LIST_REFERENCE_PUSH_ACK,
|
||||
|
||||
/// DirectoryDeltaTransfer plugin - Request from a remote system for a download of a directory
|
||||
ID_DDT_DOWNLOAD_REQUEST,
|
||||
|
||||
/// RakNetTransport plugin - Transport provider message, used for remote console
|
||||
ID_TRANSPORT_STRING,
|
||||
|
||||
/// ReplicaManager plugin - Create an object
|
||||
ID_REPLICA_MANAGER_CONSTRUCTION,
|
||||
/// ReplicaManager plugin - Changed scope of an object
|
||||
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,
|
||||
|
||||
/// RakVoice plugin - Open a communication channel
|
||||
ID_RAKVOICE_OPEN_CHANNEL_REQUEST,
|
||||
/// RakVoice plugin - Communication channel accepted
|
||||
ID_RAKVOICE_OPEN_CHANNEL_REPLY,
|
||||
/// RakVoice plugin - Close a communication channel
|
||||
ID_RAKVOICE_CLOSE_CHANNEL,
|
||||
/// RakVoice plugin - Voice data
|
||||
ID_RAKVOICE_DATA,
|
||||
|
||||
/// Autopatcher plugin - Get a list of files that have changed since a certain date
|
||||
ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE,
|
||||
/// Autopatcher plugin - A list of files to create
|
||||
ID_AUTOPATCHER_CREATION_LIST,
|
||||
/// Autopatcher plugin - A list of files to delete
|
||||
ID_AUTOPATCHER_DELETION_LIST,
|
||||
/// Autopatcher plugin - A list of files to get patches for
|
||||
ID_AUTOPATCHER_GET_PATCH,
|
||||
/// Autopatcher plugin - A list of patches for a list of files
|
||||
ID_AUTOPATCHER_PATCH_LIST,
|
||||
/// Autopatcher plugin - Returned to the user: An error from the database repository for the autopatcher.
|
||||
ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR,
|
||||
/// Autopatcher plugin - Returned to the user: The server does not allow downloading unmodified game files.
|
||||
ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES,
|
||||
/// Autopatcher plugin - Finished getting all files from the autopatcher
|
||||
ID_AUTOPATCHER_FINISHED_INTERNAL,
|
||||
ID_AUTOPATCHER_FINISHED,
|
||||
/// Autopatcher plugin - Returned to the user: You must restart the application to finish patching.
|
||||
ID_AUTOPATCHER_RESTART_APPLICATION,
|
||||
|
||||
/// NATPunchthrough plugin: internal
|
||||
ID_NAT_PUNCHTHROUGH_REQUEST,
|
||||
/// NATPunchthrough plugin: internal
|
||||
//ID_NAT_GROUP_PUNCHTHROUGH_REQUEST,
|
||||
/// NATPunchthrough plugin: internal
|
||||
//ID_NAT_GROUP_PUNCHTHROUGH_REPLY,
|
||||
/// NATPunchthrough plugin: internal
|
||||
ID_NAT_CONNECT_AT_TIME,
|
||||
/// NATPunchthrough plugin: internal
|
||||
ID_NAT_GET_MOST_RECENT_PORT,
|
||||
/// NATPunchthrough plugin: internal
|
||||
ID_NAT_CLIENT_READY,
|
||||
/// NATPunchthrough plugin: internal
|
||||
//ID_NAT_GROUP_PUNCHTHROUGH_FAILURE_NOTIFICATION,
|
||||
|
||||
/// NATPunchthrough plugin: Destination system is not connected to the server. Bytes starting at offset 1 contains the
|
||||
/// RakNetGUID destination field of NatPunchthroughClient::OpenNAT().
|
||||
ID_NAT_TARGET_NOT_CONNECTED,
|
||||
/// NATPunchthrough plugin: Destination system is not responding to ID_NAT_GET_MOST_RECENT_PORT. Possibly the plugin is not installed.
|
||||
/// Bytes starting at offset 1 contains the RakNetGUID destination field of NatPunchthroughClient::OpenNAT().
|
||||
ID_NAT_TARGET_UNRESPONSIVE,
|
||||
/// NATPunchthrough plugin: The server lost the connection to the destination system while setting up punchthrough.
|
||||
/// Possibly the plugin is not installed. Bytes starting at offset 1 contains the RakNetGUID destination
|
||||
/// field of NatPunchthroughClient::OpenNAT().
|
||||
ID_NAT_CONNECTION_TO_TARGET_LOST,
|
||||
/// NATPunchthrough plugin: This punchthrough is already in progress. Possibly the plugin is not installed.
|
||||
/// Bytes starting at offset 1 contains the RakNetGUID destination field of NatPunchthroughClient::OpenNAT().
|
||||
ID_NAT_ALREADY_IN_PROGRESS,
|
||||
/// NATPunchthrough plugin: This message is generated on the local system, and does not come from the network.
|
||||
/// packet::guid contains the destination field of NatPunchthroughClient::OpenNAT(). Byte 1 contains 1 if you are the sender, 0 if not
|
||||
ID_NAT_PUNCHTHROUGH_FAILED,
|
||||
/// NATPunchthrough plugin: Punchthrough succeeded. See packet::systemAddress and packet::guid. Byte 1 contains 1 if you are the sender,
|
||||
/// 0 if not. You can now use RakPeer::Connect() or other calls to communicate with this system.
|
||||
ID_NAT_PUNCHTHROUGH_SUCCEEDED,
|
||||
|
||||
/// ReadyEvent plugin - Set the ready state for a particular system
|
||||
/// First 4 bytes after the message contains the id
|
||||
ID_READY_EVENT_SET,
|
||||
/// ReadyEvent plugin - Unset the ready state for a particular system
|
||||
/// First 4 bytes after the message contains the id
|
||||
ID_READY_EVENT_UNSET,
|
||||
/// All systems are in state ID_READY_EVENT_SET
|
||||
/// First 4 bytes after the message contains the id
|
||||
ID_READY_EVENT_ALL_SET,
|
||||
/// \internal, do not process in your game
|
||||
/// 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,
|
||||
|
||||
// RPC3, RPC4 error
|
||||
ID_RPC_REMOTE_ERROR,
|
||||
/// Plugin based replacement for RPC system
|
||||
ID_RPC_PLUGIN,
|
||||
|
||||
/// 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,
|
||||
|
||||
/// Informs user of a new host GUID. Packet::Guid contains this new host RakNetGuid. The old host can be read out using BitStream->Read(RakNetGuid) starting on byte 1
|
||||
/// This is not returned until connected to a remote system
|
||||
/// If the oldHost is UNASSIGNED_RAKNET_GUID, then this is the first time the host has been determined
|
||||
ID_FCM2_NEW_HOST,
|
||||
/// \internal For FullyConnectedMesh2 plugin
|
||||
ID_FCM2_REQUEST_FCMGUID,
|
||||
/// \internal For FullyConnectedMesh2 plugin
|
||||
ID_FCM2_RESPOND_CONNECTION_COUNT,
|
||||
/// \internal For FullyConnectedMesh2 plugin
|
||||
ID_FCM2_INFORM_FCMGUID,
|
||||
/// \internal For FullyConnectedMesh2 plugin
|
||||
ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT,
|
||||
/// A remote system (not necessarily the host) called FullyConnectedMesh2::StartVerifiedJoin() with our system as the client
|
||||
/// Use FullyConnectedMesh2::GetVerifiedJoinRequiredProcessingList() to read systems
|
||||
/// For each system, attempt NatPunchthroughClient::OpenNAT() and/or RakPeerInterface::Connect()
|
||||
/// When this has been done for all systems, the remote system will automatically be informed of the results
|
||||
/// \note Only the designated client gets this message
|
||||
/// \note You won't get this message if you are already connected to all target systems
|
||||
/// \note If you fail to connect to a system, this does not automatically mean you will get ID_FCM2_VERIFIED_JOIN_FAILED as that system may have been shutting down from the host too
|
||||
/// \sa FullyConnectedMesh2::StartVerifiedJoin()
|
||||
ID_FCM2_VERIFIED_JOIN_START,
|
||||
/// \internal The client has completed processing for all systems designated in ID_FCM2_VERIFIED_JOIN_START
|
||||
ID_FCM2_VERIFIED_JOIN_CAPABLE,
|
||||
/// Client failed to connect to a required systems notified via FullyConnectedMesh2::StartVerifiedJoin()
|
||||
/// RakPeerInterface::CloseConnection() was automatically called for all systems connected due to ID_FCM2_VERIFIED_JOIN_START
|
||||
/// Programmer should inform the player via the UI that they cannot join this session, and to choose a different session
|
||||
/// \note Server normally sends us this message, however if connection to the server was lost, message will be returned locally
|
||||
/// \note Only the designated client gets this message
|
||||
ID_FCM2_VERIFIED_JOIN_FAILED,
|
||||
/// The system that called StartVerifiedJoin() got ID_FCM2_VERIFIED_JOIN_CAPABLE from the client and then called RespondOnVerifiedJoinCapable() with true
|
||||
/// AddParticipant() has automatically been called for this system
|
||||
/// Use GetVerifiedJoinAcceptedAdditionalData() to read any additional data passed to RespondOnVerifiedJoinCapable()
|
||||
/// \note All systems in the mesh get this message
|
||||
/// \sa RespondOnVerifiedJoinCapable()
|
||||
ID_FCM2_VERIFIED_JOIN_ACCEPTED,
|
||||
/// The system that called StartVerifiedJoin() got ID_FCM2_VERIFIED_JOIN_CAPABLE from the client and then called RespondOnVerifiedJoinCapable() with false
|
||||
/// CloseConnection() has been automatically called for each system connected to since ID_FCM2_VERIFIED_JOIN_START.
|
||||
/// The connection is NOT automatically closed to the original host that sent StartVerifiedJoin()
|
||||
/// Use GetVerifiedJoinRejectedAdditionalData() to read any additional data passed to RespondOnVerifiedJoinCapable()
|
||||
/// \note Only the designated client gets this message
|
||||
/// \sa RespondOnVerifiedJoinCapable()
|
||||
ID_FCM2_VERIFIED_JOIN_REJECTED,
|
||||
|
||||
/// UDP proxy messages. Second byte indicates type.
|
||||
ID_UDP_PROXY_GENERAL,
|
||||
|
||||
/// SQLite3Plugin - execute
|
||||
ID_SQLite3_EXEC,
|
||||
/// SQLite3Plugin - Remote database is unknown
|
||||
ID_SQLite3_UNKNOWN_DB,
|
||||
/// Events happening with SQLiteClientLoggerPlugin
|
||||
ID_SQLLITE_LOGGER,
|
||||
|
||||
/// Sent to NatTypeDetectionServer
|
||||
ID_NAT_TYPE_DETECTION_REQUEST,
|
||||
/// Sent to NatTypeDetectionClient. Byte 1 contains the type of NAT detected.
|
||||
ID_NAT_TYPE_DETECTION_RESULT,
|
||||
|
||||
/// Used by the router2 plugin
|
||||
ID_ROUTER_2_INTERNAL,
|
||||
/// No path is available or can be established to the remote system
|
||||
/// Packet::guid contains the endpoint guid that we were trying to reach
|
||||
ID_ROUTER_2_FORWARDING_NO_PATH,
|
||||
/// \brief You can now call connect, ping, or other operations to the destination system.
|
||||
///
|
||||
/// Connect as follows:
|
||||
///
|
||||
/// SLNet::BitStream bs(packet->data, packet->length, false);
|
||||
/// bs.IgnoreBytes(sizeof(MessageID));
|
||||
/// RakNetGUID endpointGuid;
|
||||
/// bs.Read(endpointGuid);
|
||||
/// unsigned short sourceToDestPort;
|
||||
/// bs.Read(sourceToDestPort);
|
||||
/// char ipAddressString[32];
|
||||
/// packet->systemAddress.ToString(false, ipAddressString);
|
||||
/// rakPeerInterface->Connect(ipAddressString, sourceToDestPort, 0,0);
|
||||
ID_ROUTER_2_FORWARDING_ESTABLISHED,
|
||||
/// The IP address for a forwarded connection has changed
|
||||
/// Read endpointGuid and port as per ID_ROUTER_2_FORWARDING_ESTABLISHED
|
||||
ID_ROUTER_2_REROUTED,
|
||||
|
||||
/// \internal Used by the team balancer plugin
|
||||
ID_TEAM_BALANCER_INTERNAL,
|
||||
/// Cannot switch to the desired team because it is full. However, if someone on that team leaves, you will
|
||||
/// get ID_TEAM_BALANCER_TEAM_ASSIGNED later.
|
||||
/// For TeamBalancer: Byte 1 contains the team you requested to join. Following bytes contain NetworkID of which member
|
||||
ID_TEAM_BALANCER_REQUESTED_TEAM_FULL,
|
||||
/// Cannot switch to the desired team because all teams are locked. However, if someone on that team leaves,
|
||||
/// you will get ID_TEAM_BALANCER_SET_TEAM later.
|
||||
/// For TeamBalancer: Byte 1 contains the team you requested to join.
|
||||
ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED,
|
||||
ID_TEAM_BALANCER_TEAM_REQUESTED_CANCELLED,
|
||||
/// Team balancer plugin informing you of your team. Byte 1 contains the team you requested to join. Following bytes contain NetworkID of which member.
|
||||
ID_TEAM_BALANCER_TEAM_ASSIGNED,
|
||||
|
||||
/// Gamebryo Lightspeed integration
|
||||
ID_LIGHTSPEED_INTEGRATION,
|
||||
|
||||
/// XBOX integration
|
||||
ID_XBOX_LOBBY,
|
||||
|
||||
/// The password we used to challenge the other system passed, meaning the other system has called TwoWayAuthentication::AddPassword() with the same password we passed to TwoWayAuthentication::Challenge()
|
||||
/// You can read the identifier used to challenge as follows:
|
||||
/// SLNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(SLNet::MessageID)); SLNet::RakString password; bs.Read(password);
|
||||
ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_SUCCESS,
|
||||
ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS,
|
||||
/// A remote system sent us a challenge using TwoWayAuthentication::Challenge(), and the challenge failed.
|
||||
/// If the other system must pass the challenge to stay connected, you should call RakPeer::CloseConnection() to terminate the connection to the other system.
|
||||
ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE,
|
||||
/// The other system did not add the password we used to TwoWayAuthentication::AddPassword()
|
||||
/// You can read the identifier used to challenge as follows:
|
||||
/// SLNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(MessageID)); SLNet::RakString password; bs.Read(password);
|
||||
ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE,
|
||||
/// The other system did not respond within a timeout threshhold. Either the other system is not running the plugin or the other system was blocking on some operation for a long time.
|
||||
/// You can read the identifier used to challenge as follows:
|
||||
/// SLNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(MessageID)); SLNet::RakString password; bs.Read(password);
|
||||
ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_TIMEOUT,
|
||||
/// \internal
|
||||
ID_TWO_WAY_AUTHENTICATION_NEGOTIATION,
|
||||
|
||||
/// CloudClient / CloudServer
|
||||
ID_CLOUD_POST_REQUEST,
|
||||
ID_CLOUD_RELEASE_REQUEST,
|
||||
ID_CLOUD_GET_REQUEST,
|
||||
ID_CLOUD_GET_RESPONSE,
|
||||
ID_CLOUD_UNSUBSCRIBE_REQUEST,
|
||||
ID_CLOUD_SERVER_TO_SERVER_COMMAND,
|
||||
ID_CLOUD_SUBSCRIPTION_NOTIFICATION,
|
||||
|
||||
// LibVoice
|
||||
ID_LIB_VOICE,
|
||||
|
||||
ID_RELAY_PLUGIN,
|
||||
ID_NAT_REQUEST_BOUND_ADDRESSES,
|
||||
ID_NAT_RESPOND_BOUND_ADDRESSES,
|
||||
ID_FCM2_UPDATE_USER_CONTEXT,
|
||||
ID_RESERVED_3,
|
||||
ID_RESERVED_4,
|
||||
ID_RESERVED_5,
|
||||
ID_RESERVED_6,
|
||||
ID_RESERVED_7,
|
||||
ID_RESERVED_8,
|
||||
ID_RESERVED_9,
|
||||
|
||||
// For the user to use. Start your first enumeration at this value.
|
||||
ID_USER_PACKET_ENUM
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
};
|
||||
|
||||
#endif // RAKNET_USE_CUSTOM_PACKET_IDS
|
||||
|
||||
#endif
|
||||
311
Source/include/slikenet/NatPunchthroughClient.h
Normal file
311
Source/include/slikenet/NatPunchthroughClient.h
Normal file
@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Contains the NAT-punchthrough plugin for the client.
|
||||
///
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_NatPunchthroughClient==1
|
||||
|
||||
#ifndef __NAT_PUNCHTHROUGH_CLIENT_H
|
||||
#define __NAT_PUNCHTHROUGH_CLIENT_H
|
||||
|
||||
#include "types.h"
|
||||
#include "Export.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "PacketPriority.h"
|
||||
#include "SocketIncludes.h"
|
||||
#include "DS_List.h"
|
||||
#include "string.h"
|
||||
#include "DS_Queue.h"
|
||||
|
||||
// Trendnet TEW-632BRP sometimes starts at port 1024 and increments sequentially.
|
||||
// Zonnet zsr1134we. Replies go out on the net, but are always absorbed by the remote router??
|
||||
// Dlink ebr2310 to Trendnet ok
|
||||
// Trendnet TEW-652BRP to Trendnet 632BRP OK
|
||||
// Trendnet TEW-632BRP to Trendnet 632BRP OK
|
||||
// Buffalo WHR-HP-G54 OK
|
||||
// Netgear WGR614 ok
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
struct Packet;
|
||||
#if _RAKNET_SUPPORT_PacketLogger==1
|
||||
class PacketLogger;
|
||||
#endif
|
||||
|
||||
/// \ingroup NAT_PUNCHTHROUGH_GROUP
|
||||
struct RAK_DLL_EXPORT PunchthroughConfiguration
|
||||
{
|
||||
/// internal: (15 ms * 2 tries + 30 wait) * 5 ports * 8 players = 2.4 seconds
|
||||
/// external: (50 ms * 8 sends + 200 wait) * 2 port * 8 players = 9.6 seconds
|
||||
/// Total: 8 seconds
|
||||
PunchthroughConfiguration() {
|
||||
TIME_BETWEEN_PUNCH_ATTEMPTS_INTERNAL=15;
|
||||
TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL=50;
|
||||
UDP_SENDS_PER_PORT_INTERNAL=2;
|
||||
UDP_SENDS_PER_PORT_EXTERNAL=8;
|
||||
INTERNAL_IP_WAIT_AFTER_ATTEMPTS=30;
|
||||
MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK=5; /// set to 0 to not do lan connects
|
||||
MAX_PREDICTIVE_PORT_RANGE=2;
|
||||
EXTERNAL_IP_WAIT_BETWEEN_PORTS=200;
|
||||
EXTERNAL_IP_WAIT_AFTER_FIRST_TTL=100;
|
||||
EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS=EXTERNAL_IP_WAIT_BETWEEN_PORTS;
|
||||
retryOnFailure=false;
|
||||
}
|
||||
|
||||
/// How much time between each UDP send
|
||||
SLNet::Time TIME_BETWEEN_PUNCH_ATTEMPTS_INTERNAL;
|
||||
SLNet::Time TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL;
|
||||
|
||||
/// How many tries for one port before giving up and going to the next port
|
||||
int UDP_SENDS_PER_PORT_INTERNAL;
|
||||
int UDP_SENDS_PER_PORT_EXTERNAL;
|
||||
|
||||
/// After giving up on one internal port, how long to wait before trying the next port
|
||||
int INTERNAL_IP_WAIT_AFTER_ATTEMPTS;
|
||||
|
||||
/// How many external ports to try past the last known starting port
|
||||
int MAX_PREDICTIVE_PORT_RANGE;
|
||||
|
||||
/// After sending TTL, how long to wait until first punch attempt
|
||||
int EXTERNAL_IP_WAIT_AFTER_FIRST_TTL;
|
||||
|
||||
/// After giving up on one external port, how long to wait before trying the next port
|
||||
int EXTERNAL_IP_WAIT_BETWEEN_PORTS;
|
||||
|
||||
/// After trying all external ports, how long to wait before returning ID_NAT_PUNCHTHROUGH_FAILED
|
||||
int EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS;
|
||||
|
||||
/// Maximum number of internal IP address to try to connect to.
|
||||
/// Cannot be greater than MAXIMUM_NUMBER_OF_INTERNAL_IDS
|
||||
/// Should be high enough to try all internal IP addresses on the majority of computers
|
||||
int MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK;
|
||||
|
||||
/// If the first punchthrough attempt fails, try again
|
||||
/// This sometimes works because the remote router was looking for an incoming message on a higher numbered port before responding to a lower numbered port from the other system
|
||||
bool retryOnFailure;
|
||||
};
|
||||
|
||||
/// \ingroup NAT_PUNCHTHROUGH_GROUP
|
||||
struct RAK_DLL_EXPORT NatPunchthroughDebugInterface
|
||||
{
|
||||
NatPunchthroughDebugInterface() {}
|
||||
virtual ~NatPunchthroughDebugInterface() {}
|
||||
virtual void OnClientMessage(const char *msg)=0;
|
||||
};
|
||||
|
||||
/// \ingroup NAT_PUNCHTHROUGH_GROUP
|
||||
struct RAK_DLL_EXPORT NatPunchthroughDebugInterface_Printf : public NatPunchthroughDebugInterface
|
||||
{
|
||||
virtual void OnClientMessage(const char *msg);
|
||||
};
|
||||
|
||||
#if _RAKNET_SUPPORT_PacketLogger==1
|
||||
/// \ingroup NAT_PUNCHTHROUGH_GROUP
|
||||
struct RAK_DLL_EXPORT NatPunchthroughDebugInterface_PacketLogger : public NatPunchthroughDebugInterface
|
||||
{
|
||||
// Set to non-zero to write to the packetlogger!
|
||||
PacketLogger *pl;
|
||||
|
||||
NatPunchthroughDebugInterface_PacketLogger() {pl=0;}
|
||||
~NatPunchthroughDebugInterface_PacketLogger() {}
|
||||
virtual void OnClientMessage(const char *msg);
|
||||
};
|
||||
#endif
|
||||
|
||||
/// \brief Client code for NATPunchthrough
|
||||
/// \details Maintain connection to NatPunchthroughServer to process incoming connection attempts through NatPunchthroughClient<BR>
|
||||
/// Client will send datagrams to port to estimate next port<BR>
|
||||
/// Will simultaneously connect with another client once ports are estimated.
|
||||
/// \sa NatTypeDetectionClient
|
||||
/// See also http://www.jenkinssoftware.com/raknet/manual/natpunchthrough.html
|
||||
/// \ingroup NAT_PUNCHTHROUGH_GROUP
|
||||
class RAK_DLL_EXPORT NatPunchthroughClient : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(NatPunchthroughClient)
|
||||
|
||||
NatPunchthroughClient();
|
||||
~NatPunchthroughClient();
|
||||
|
||||
/// If the instance of RakPeer running NATPunchthroughServer was bound to two IP addresses, then you can call FindRouterPortStride()
|
||||
/// This will determine the stride that your router uses when assigning ports, if your router is full-cone
|
||||
/// This function is also called automatically when you call OpenNAT - however, calling it earlier when you are connected to the facilitator will speed up the process
|
||||
/// \param[in] destination The system to punch. Must already be connected to \a facilitator
|
||||
void FindRouterPortStride(const SystemAddress &facilitator);
|
||||
|
||||
/// Punchthrough a NAT. Doesn't connect, just tries to setup the routing table
|
||||
/// \param[in] destination The system to punch. Must already be connected to \a facilitator
|
||||
/// \param[in] facilitator A system we are already connected to running the NatPunchthroughServer plugin
|
||||
/// \sa OpenNATGroup()
|
||||
/// You will get ID_NAT_PUNCHTHROUGH_SUCCEEDED on success
|
||||
/// You will get ID_NAT_TARGET_NOT_CONNECTED, ID_NAT_TARGET_UNRESPONSIVE, ID_NAT_CONNECTION_TO_TARGET_LOST, ID_NAT_ALREADY_IN_PROGRESS, or ID_NAT_PUNCHTHROUGH_FAILED on failures of various types
|
||||
/// However, if you lose connection to the facilitator, you may not necessarily get above
|
||||
bool OpenNAT(RakNetGUID destination, const SystemAddress &facilitator);
|
||||
|
||||
/*
|
||||
/// \deprecated See FullyConnectedMesh2::StartVerifiedJoin() which is more flexible
|
||||
/// Same as calling OpenNAT for a list of systems, but reply is delayed until all systems pass.
|
||||
/// This is useful for peer to peer games where you want to connect to every system in the remote session, not just one particular system
|
||||
/// \note For cloud computing, all systems in the group must be connected to the same facilitator since we're only specifying one
|
||||
/// You will get ID_NAT_GROUP_PUNCH_SUCCEEDED on success
|
||||
/// You will get ID_NAT_TARGET_NOT_CONNECTED, ID_NAT_ALREADY_IN_PROGRESS, or ID_NAT_GROUP_PUNCH_FAILED on failures of various types
|
||||
/// However, if you lose connection to the facilitator, you may not necessarily get above
|
||||
bool OpenNATGroup(DataStructures::List<RakNetGUID> destinationSystems, const SystemAddress &facilitator);
|
||||
*/
|
||||
|
||||
/// Modify the system configuration if desired
|
||||
/// Don't modify the variables in the structure while punchthrough is in progress
|
||||
PunchthroughConfiguration* GetPunchthroughConfiguration(void);
|
||||
|
||||
/// Sets a callback to be called with debug messages
|
||||
/// \param[in] i Pointer to an interface. The pointer is stored, so don't delete it while in progress. Pass 0 to clear.
|
||||
void SetDebugInterface(NatPunchthroughDebugInterface *i);
|
||||
|
||||
/// Get the port mappings you should pass to UPNP (for miniupnpc-1.6.20120410, for the function UPNP_AddPortMapping)
|
||||
void GetUPNPPortMappings(char *externalPort, char *internalPort, const SystemAddress &natPunchthroughServerAddress);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual void Update(void);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
|
||||
virtual void OnAttach(void);
|
||||
virtual void OnDetach(void);
|
||||
virtual void OnRakPeerShutdown(void);
|
||||
void Clear(void);
|
||||
|
||||
struct SendPing
|
||||
{
|
||||
SLNet::Time nextActionTime;
|
||||
SystemAddress targetAddress;
|
||||
SystemAddress facilitator;
|
||||
SystemAddress internalIds[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
|
||||
RakNetGUID targetGuid;
|
||||
bool weAreSender;
|
||||
int attemptCount;
|
||||
int retryCount;
|
||||
int punchingFixedPortAttempts; // only used for TestMode::PUNCHING_FIXED_PORT
|
||||
uint16_t sessionId;
|
||||
bool sentTTL;
|
||||
// Give priority to internal IP addresses because if we are on a LAN, we don't want to try to connect through the internet
|
||||
enum TestMode
|
||||
{
|
||||
TESTING_INTERNAL_IPS,
|
||||
WAITING_FOR_INTERNAL_IPS_RESPONSE,
|
||||
//SEND_WITH_TTL,
|
||||
TESTING_EXTERNAL_IPS_FACILITATOR_PORT_TO_FACILITATOR_PORT,
|
||||
TESTING_EXTERNAL_IPS_1024_TO_FACILITATOR_PORT,
|
||||
TESTING_EXTERNAL_IPS_FACILITATOR_PORT_TO_1024,
|
||||
TESTING_EXTERNAL_IPS_1024_TO_1024,
|
||||
WAITING_AFTER_ALL_ATTEMPTS,
|
||||
|
||||
// The trendnet remaps the remote port to 1024.
|
||||
// If you continue punching on a different port for the same IP it bans you and the communication becomes unidirectioal
|
||||
PUNCHING_FIXED_PORT,
|
||||
|
||||
// try port 1024-1028
|
||||
} testMode;
|
||||
} sp;
|
||||
|
||||
protected:
|
||||
unsigned short mostRecentExternalPort;
|
||||
//void OnNatGroupPunchthroughRequest(Packet *packet);
|
||||
void OnFailureNotification(Packet *packet);
|
||||
//void OnNatGroupPunchthroughReply(Packet *packet);
|
||||
void OnGetMostRecentPort(Packet *packet);
|
||||
void OnConnectAtTime(Packet *packet);
|
||||
unsigned int GetPendingOpenNATIndex(RakNetGUID destination, const SystemAddress &facilitator);
|
||||
void SendPunchthrough(RakNetGUID destination, const SystemAddress &facilitator);
|
||||
void QueueOpenNAT(RakNetGUID destination, const SystemAddress &facilitator);
|
||||
void SendQueuedOpenNAT(void);
|
||||
void SendTTL(const SystemAddress &sa);
|
||||
void SendOutOfBand(SystemAddress sa, MessageID oobId);
|
||||
void OnPunchthroughFailure(void);
|
||||
void OnReadyForNextPunchthrough(void);
|
||||
void PushFailure(void);
|
||||
bool RemoveFromFailureQueue(void);
|
||||
void PushSuccess(void);
|
||||
|
||||
PunchthroughConfiguration pc;
|
||||
NatPunchthroughDebugInterface *natPunchthroughDebugInterface;
|
||||
|
||||
// The first time we fail a NAT attempt, we add it to failedAttemptList and try again, since sometimes trying again later fixes the problem
|
||||
// The second time we fail, we return ID_NAT_PUNCHTHROUGH_FAILED
|
||||
struct AddrAndGuid
|
||||
{
|
||||
SystemAddress addr;
|
||||
RakNetGUID guid;
|
||||
};
|
||||
DataStructures::List<AddrAndGuid> failedAttemptList;
|
||||
|
||||
struct DSTAndFac
|
||||
{
|
||||
RakNetGUID destination;
|
||||
SystemAddress facilitator;
|
||||
};
|
||||
DataStructures::Queue<DSTAndFac> queuedOpenNat;
|
||||
|
||||
void IncrementExternalAttemptCount(SLNet::Time time, SLNet::Time delta);
|
||||
unsigned short portStride;
|
||||
enum
|
||||
{
|
||||
HAS_PORT_STRIDE,
|
||||
UNKNOWN_PORT_STRIDE,
|
||||
CALCULATING_PORT_STRIDE,
|
||||
INCAPABLE_PORT_STRIDE
|
||||
} hasPortStride;
|
||||
SLNet::Time portStrideCalTimeout;
|
||||
|
||||
/*
|
||||
struct TimeAndGuid
|
||||
{
|
||||
SLNet::Time time;
|
||||
RakNetGUID guid;
|
||||
};
|
||||
DataStructures::List<TimeAndGuid> groupRequestsInProgress;
|
||||
|
||||
struct GroupPunchRequest
|
||||
{
|
||||
SystemAddress facilitator;
|
||||
DataStructures::List<RakNetGUID> pendingList;
|
||||
DataStructures::List<RakNetGUID> passedListGuid;
|
||||
DataStructures::List<SystemAddress> passedListAddress;
|
||||
DataStructures::List<RakNetGUID> failedList;
|
||||
DataStructures::List<RakNetGUID> ignoredList;
|
||||
};
|
||||
DataStructures::List<GroupPunchRequest*> groupPunchRequests;
|
||||
void UpdateGroupPunchOnNatResult(SystemAddress facilitator, RakNetGUID targetSystem, SystemAddress targetSystemAddress, int result); // 0=failed, 1=success, 2=ignore
|
||||
*/
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
161
Source/include/slikenet/NatPunchthroughServer.h
Normal file
161
Source/include/slikenet/NatPunchthroughServer.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Contains the NAT-punchthrough plugin for the server.
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_NatPunchthroughServer==1
|
||||
|
||||
#ifndef __NAT_PUNCHTHROUGH_SERVER_H
|
||||
#define __NAT_PUNCHTHROUGH_SERVER_H
|
||||
|
||||
#include "types.h"
|
||||
#include "Export.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "PacketPriority.h"
|
||||
#include "SocketIncludes.h"
|
||||
#include "DS_OrderedList.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
struct Packet;
|
||||
#if _RAKNET_SUPPORT_PacketLogger==1
|
||||
class PacketLogger;
|
||||
#endif
|
||||
|
||||
/// \defgroup NAT_PUNCHTHROUGH_GROUP NatPunchthrough
|
||||
/// \brief Connect systems despite both systems being behind a router
|
||||
/// \details
|
||||
/// \ingroup PLUGINS_GROUP
|
||||
|
||||
/// \ingroup NAT_PUNCHTHROUGH_GROUP
|
||||
struct RAK_DLL_EXPORT NatPunchthroughServerDebugInterface
|
||||
{
|
||||
NatPunchthroughServerDebugInterface() {}
|
||||
virtual ~NatPunchthroughServerDebugInterface() {}
|
||||
virtual void OnServerMessage(const char *msg)=0;
|
||||
};
|
||||
|
||||
/// \ingroup NAT_PUNCHTHROUGH_GROUP
|
||||
struct RAK_DLL_EXPORT NatPunchthroughServerDebugInterface_Printf : public NatPunchthroughServerDebugInterface
|
||||
{
|
||||
virtual void OnServerMessage(const char *msg);
|
||||
};
|
||||
|
||||
#if _RAKNET_SUPPORT_PacketLogger==1
|
||||
/// \ingroup NAT_PUNCHTHROUGH_GROUP
|
||||
struct RAK_DLL_EXPORT NatPunchthroughServerDebugInterface_PacketLogger : public NatPunchthroughServerDebugInterface
|
||||
{
|
||||
// Set to non-zero to write to the packetlogger!
|
||||
PacketLogger *pl;
|
||||
|
||||
NatPunchthroughServerDebugInterface_PacketLogger() {pl=0;}
|
||||
~NatPunchthroughServerDebugInterface_PacketLogger() {}
|
||||
virtual void OnServerMessage(const char *msg);
|
||||
};
|
||||
#endif
|
||||
|
||||
/// \brief Server code for NATPunchthrough
|
||||
/// \details Maintain connection to NatPunchthroughServer to process incoming connection attempts through NatPunchthroughClient<BR>
|
||||
/// Server maintains two sockets clients can connect to so as to estimate the next port choice<BR>
|
||||
/// Server tells other client about port estimate, current public port to the server, and a time to start connection attempts
|
||||
/// \sa NatTypeDetectionClient
|
||||
/// See also http://www.jenkinssoftware.com/raknet/manual/natpunchthrough.html
|
||||
/// \ingroup NAT_PUNCHTHROUGH_GROUP
|
||||
class RAK_DLL_EXPORT NatPunchthroughServer : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
|
||||
STATIC_FACTORY_DECLARATIONS(NatPunchthroughServer)
|
||||
|
||||
// Constructor
|
||||
NatPunchthroughServer();
|
||||
|
||||
// Destructor
|
||||
virtual ~NatPunchthroughServer();
|
||||
|
||||
/// Sets a callback to be called with debug messages
|
||||
/// \param[in] i Pointer to an interface. The pointer is stored, so don't delete it while in progress. Pass 0 to clear.
|
||||
void SetDebugInterface(NatPunchthroughServerDebugInterface *i);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual void Update(void);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);
|
||||
|
||||
// Each connected user has a ready state. Ready means ready for nat punchthrough.
|
||||
struct User;
|
||||
struct ConnectionAttempt
|
||||
{
|
||||
ConnectionAttempt() {sender=0; recipient=0; startTime=0; attemptPhase=NAT_ATTEMPT_PHASE_NOT_STARTED;}
|
||||
User *sender, *recipient;
|
||||
uint16_t sessionId;
|
||||
SLNet::Time startTime;
|
||||
enum
|
||||
{
|
||||
NAT_ATTEMPT_PHASE_NOT_STARTED,
|
||||
NAT_ATTEMPT_PHASE_GETTING_RECENT_PORTS,
|
||||
} attemptPhase;
|
||||
};
|
||||
struct User
|
||||
{
|
||||
RakNetGUID guid;
|
||||
SystemAddress systemAddress;
|
||||
unsigned short mostRecentPort;
|
||||
bool isReady;
|
||||
DataStructures::OrderedList<RakNetGUID,RakNetGUID> groupPunchthroughRequests;
|
||||
|
||||
DataStructures::List<ConnectionAttempt *> connectionAttempts;
|
||||
bool HasConnectionAttemptToUser(User *user);
|
||||
void DerefConnectionAttempt(ConnectionAttempt *ca);
|
||||
void DeleteConnectionAttempt(ConnectionAttempt *ca);
|
||||
void LogConnectionAttempts(SLNet::RakString &rs);
|
||||
};
|
||||
SLNet::Time lastUpdate;
|
||||
static int NatPunchthroughUserComp( const RakNetGUID &key, User * const &data );
|
||||
protected:
|
||||
void OnNATPunchthroughRequest(Packet *packet);
|
||||
DataStructures::OrderedList<RakNetGUID, User*, NatPunchthroughServer::NatPunchthroughUserComp> users;
|
||||
|
||||
void OnGetMostRecentPort(Packet *packet);
|
||||
void OnClientReady(Packet *packet);
|
||||
|
||||
void SendTimestamps(void);
|
||||
void StartPendingPunchthrough(void);
|
||||
void StartPunchthroughForUser(User*user);
|
||||
uint16_t sessionId;
|
||||
NatPunchthroughServerDebugInterface *natPunchthroughServerDebugInterface;
|
||||
|
||||
SystemAddress boundAddresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
|
||||
unsigned char boundAddressCount;
|
||||
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
102
Source/include/slikenet/NatTypeDetectionClient.h
Normal file
102
Source/include/slikenet/NatTypeDetectionClient.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Contains the NAT-type detection code for the client
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_NatTypeDetectionClient==1
|
||||
|
||||
#ifndef __NAT_TYPE_DETECTION_CLIENT_H
|
||||
#define __NAT_TYPE_DETECTION_CLIENT_H
|
||||
|
||||
#include "types.h"
|
||||
#include "Export.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "PacketPriority.h"
|
||||
#include "SocketIncludes.h"
|
||||
#include "DS_OrderedList.h"
|
||||
#include "string.h"
|
||||
#include "NatTypeDetectionCommon.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
struct Packet;
|
||||
|
||||
/// \brief Client code for NatTypeDetection
|
||||
/// \details See NatTypeDetectionServer.h for algorithm
|
||||
/// To use, just connect to the server, and call DetectNAT
|
||||
/// You will get back ID_NAT_TYPE_DETECTION_RESULT with one of the enumerated values of NATTypeDetectionResult found in NATTypeDetectionCommon.h
|
||||
/// See also http://www.jenkinssoftware.com/raknet/manual/natpunchthrough.html
|
||||
/// \sa NatPunchthroughClient
|
||||
/// \sa NatTypeDetectionServer
|
||||
/// \ingroup NAT_TYPE_DETECTION_GROUP
|
||||
class RAK_DLL_EXPORT NatTypeDetectionClient : public PluginInterface2, public RNS2EventHandler
|
||||
{
|
||||
public:
|
||||
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(NatTypeDetectionClient)
|
||||
|
||||
// Constructor
|
||||
NatTypeDetectionClient();
|
||||
|
||||
// Destructor
|
||||
virtual ~NatTypeDetectionClient();
|
||||
|
||||
/// Send the message to the server to detect the nat type
|
||||
/// Server must be running NatTypeDetectionServer
|
||||
/// We must already be connected to the server
|
||||
/// \param[in] serverAddress address of the server
|
||||
void DetectNATType(SystemAddress _serverAddress);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual void Update(void);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
virtual void OnRakPeerShutdown(void);
|
||||
virtual void OnDetach(void);
|
||||
|
||||
virtual void OnRNS2Recv(RNS2RecvStruct *recvStruct);
|
||||
virtual void DeallocRNS2RecvStruct(RNS2RecvStruct *s, const char *file, unsigned int line);
|
||||
virtual RNS2RecvStruct *AllocRNS2RecvStruct(const char *file, unsigned int line);
|
||||
protected:
|
||||
DataStructures::Queue<RNS2RecvStruct*> bufferedPackets;
|
||||
SimpleMutex bufferedPacketsMutex;
|
||||
|
||||
RakNetSocket2* c2;
|
||||
//unsigned short c2Port;
|
||||
void Shutdown(void);
|
||||
void OnCompletion(NATTypeDetectionResult result);
|
||||
bool IsInProgress(void) const;
|
||||
|
||||
void OnTestPortRestricted(Packet *packet);
|
||||
SystemAddress serverAddress;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
84
Source/include/slikenet/NatTypeDetectionCommon.h
Normal file
84
Source/include/slikenet/NatTypeDetectionCommon.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \defgroup NAT_TYPE_DETECTION_GROUP NatTypeDetection
|
||||
/// \brief Use a remote server with multiple IP addresses to determine what type of NAT your router is using
|
||||
/// \details
|
||||
/// \ingroup PLUGINS_GROUP
|
||||
|
||||
#ifndef __NAT_TYPE_DETECTION_COMMON_H
|
||||
#define __NAT_TYPE_DETECTION_COMMON_H
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
|
||||
#if _RAKNET_SUPPORT_NatTypeDetectionServer==1 || _RAKNET_SUPPORT_NatTypeDetectionClient==1
|
||||
|
||||
#include "SocketIncludes.h"
|
||||
#include "types.h"
|
||||
#include "socket2.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
/// All possible types of NATs (except NAT_TYPE_COUNT, which is an internal value)
|
||||
enum NATTypeDetectionResult
|
||||
{
|
||||
/// Works with anyone
|
||||
NAT_TYPE_NONE,
|
||||
/// Accepts any datagrams to a port that has been previously used. Will accept the first datagram from the remote peer.
|
||||
NAT_TYPE_FULL_CONE,
|
||||
/// Accepts datagrams to a port as long as the datagram source IP address is a system we have already sent to. Will accept the first datagram if both systems send simultaneously. Otherwise, will accept the first datagram after we have sent one datagram.
|
||||
NAT_TYPE_ADDRESS_RESTRICTED,
|
||||
/// Same as address-restricted cone NAT, but we had to send to both the correct remote IP address and correct remote port. The same source address and port to a different destination uses the same mapping.
|
||||
NAT_TYPE_PORT_RESTRICTED,
|
||||
/// A different port is chosen for every remote destination. The same source address and port to a different destination uses a different mapping. Since the port will be different, the first external punchthrough attempt will fail. For this to work it requires port-prediction (MAX_PREDICTIVE_PORT_RANGE>1) and that the router chooses ports sequentially.
|
||||
NAT_TYPE_SYMMETRIC,
|
||||
/// Hasn't been determined. NATTypeDetectionClient does not use this, but other plugins might
|
||||
NAT_TYPE_UNKNOWN,
|
||||
/// In progress. NATTypeDetectionClient does not use this, but other plugins might
|
||||
NAT_TYPE_DETECTION_IN_PROGRESS,
|
||||
/// Didn't bother figuring it out, as we support UPNP, so it is equivalent to NAT_TYPE_NONE. NATTypeDetectionClient does not use this, but other plugins might
|
||||
NAT_TYPE_SUPPORTS_UPNP,
|
||||
/// \internal Must be last
|
||||
NAT_TYPE_COUNT
|
||||
};
|
||||
|
||||
/// \return Can one system with NATTypeDetectionResult \a type1 connect to \a type2
|
||||
bool RAK_DLL_EXPORT CanConnect(NATTypeDetectionResult type1, NATTypeDetectionResult type2);
|
||||
|
||||
/// Return a technical string representin the enumeration
|
||||
RAK_DLL_EXPORT const char * NATTypeDetectionResultToString(NATTypeDetectionResult type);
|
||||
|
||||
/// Return a friendly string representing the enumeration
|
||||
/// None and relaxed can connect to anything
|
||||
/// Moderate can connect to moderate or less
|
||||
/// Strict can connect to relaxed or less
|
||||
RAK_DLL_EXPORT const char * NATTypeDetectionResultToStringFriendly(NATTypeDetectionResult type);
|
||||
|
||||
/// \internal
|
||||
RAK_DLL_EXPORT RakNetSocket2* CreateNonblockingBoundSocket(const char *bindAddr
|
||||
#ifdef __native_client__
|
||||
,_PP_Instance_ chromeInstance
|
||||
#endif
|
||||
, RNS2EventHandler *eventHandler
|
||||
);
|
||||
|
||||
/// \internal
|
||||
//int NatTypeRecvFrom(char *data, RakNetSocket2* socket, SystemAddress &sender, RNS2EventHandler *eventHandler);
|
||||
}
|
||||
|
||||
#endif // #if _RAKNET_SUPPORT_NatTypeDetectionServer==1 || _RAKNET_SUPPORT_NatTypeDetectionClient==1
|
||||
|
||||
#endif
|
||||
142
Source/include/slikenet/NatTypeDetectionServer.h
Normal file
142
Source/include/slikenet/NatTypeDetectionServer.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Contains the NAT-type detection code for the server
|
||||
///
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_NatTypeDetectionServer==1
|
||||
|
||||
#ifndef __NAT_TYPE_DETECTION_SERVER_H
|
||||
#define __NAT_TYPE_DETECTION_SERVER_H
|
||||
|
||||
#include "types.h"
|
||||
#include "Export.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "PacketPriority.h"
|
||||
#include "SocketIncludes.h"
|
||||
#include "DS_OrderedList.h"
|
||||
#include "string.h"
|
||||
#include "NatTypeDetectionCommon.h"
|
||||
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
struct Packet;
|
||||
|
||||
/// \brief Server code for NatTypeDetection
|
||||
/// \details
|
||||
/// Sends to a remote system on certain ports and addresses to determine what type of router, if any, that client is behind
|
||||
/// Requires that the server have 4 external IP addresses
|
||||
/// <OL>
|
||||
/// <LI>Server has 1 instance of RakNet. Server has four external ip addresses S1 to S4. Five ports are used in total P1 to P5. RakNet is bound to S1P1. Sockets are bound to S1P2, S2P3, S3P4, S4P5
|
||||
/// <LI>Client with one port using RakNet (C1). Another port not using anything (C2).
|
||||
/// <LI>C1 connects to S1P1 for normal communication.
|
||||
/// <LI>S4P5 sends to C2. If arrived, no NAT. Done. (If didn't arrive, S4P5 potentially banned, do not use again).
|
||||
/// <LI>S2P3 sends to C1 (Different address, different port, to previously used port on client). If received, Full-cone nat. Done. (If didn't arrive, S2P3 potentially banned, do not use again).
|
||||
/// <LI>S1P2 sends to C1 (Same address, different port, to previously used port on client). If received, address-restricted cone nat. Done.
|
||||
/// <LI>Server via RakNet connection tells C1 to send to to S3P4. If address of C1 as seen by S3P4 is the same as the address of C1 as seen by S1P1 (RakNet connection), then port-restricted cone nat. Done
|
||||
/// <LI>Else symmetric nat. Done.
|
||||
/// </OL>
|
||||
/// See also http://www.jenkinssoftware.com/raknet/manual/natpunchthrough.html
|
||||
/// \sa NatPunchthroughServer
|
||||
/// \sa NatTypeDetectionClient
|
||||
/// \ingroup NAT_TYPE_DETECTION_GROUP
|
||||
class RAK_DLL_EXPORT NatTypeDetectionServer : public PluginInterface2, public RNS2EventHandler
|
||||
{
|
||||
public:
|
||||
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(NatTypeDetectionServer)
|
||||
|
||||
// Constructor
|
||||
NatTypeDetectionServer();
|
||||
|
||||
// Destructor
|
||||
virtual ~NatTypeDetectionServer();
|
||||
|
||||
/// Start the system, binding to 3 external IPs not already in useS
|
||||
/// \param[in] nonRakNetIP2 First unused external IP
|
||||
/// \param[in] nonRakNetIP3 Second unused external IP
|
||||
/// \param[in] nonRakNetIP4 Third unused external IP
|
||||
void Startup(
|
||||
const char *nonRakNetIP2,
|
||||
const char *nonRakNetIP3,
|
||||
const char *nonRakNetIP4
|
||||
#ifdef __native_client__
|
||||
,_PP_Instance_ chromeInstance
|
||||
#endif
|
||||
);
|
||||
|
||||
// Releases the sockets created in Startup();
|
||||
void Shutdown(void);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual void Update(void);
|
||||
|
||||
/// \internal For plugin handling
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
|
||||
enum NATDetectionState
|
||||
{
|
||||
STATE_NONE,
|
||||
STATE_TESTING_NONE_1,
|
||||
STATE_TESTING_NONE_2,
|
||||
STATE_TESTING_FULL_CONE_1,
|
||||
STATE_TESTING_FULL_CONE_2,
|
||||
STATE_TESTING_ADDRESS_RESTRICTED_1,
|
||||
STATE_TESTING_ADDRESS_RESTRICTED_2,
|
||||
STATE_TESTING_PORT_RESTRICTED_1,
|
||||
STATE_TESTING_PORT_RESTRICTED_2,
|
||||
STATE_DONE,
|
||||
};
|
||||
|
||||
struct NATDetectionAttempt
|
||||
{
|
||||
SystemAddress systemAddress;
|
||||
NATDetectionState detectionState;
|
||||
SLNet::TimeMS nextStateTime;
|
||||
SLNet::TimeMS timeBetweenAttempts;
|
||||
unsigned short c2Port;
|
||||
RakNetGUID guid;
|
||||
};
|
||||
|
||||
virtual void OnRNS2Recv(RNS2RecvStruct *recvStruct);
|
||||
virtual void DeallocRNS2RecvStruct(RNS2RecvStruct *s, const char *file, unsigned int line);
|
||||
virtual RNS2RecvStruct *AllocRNS2RecvStruct(const char *file, unsigned int line);
|
||||
protected:
|
||||
DataStructures::Queue<RNS2RecvStruct*> bufferedPackets;
|
||||
SimpleMutex bufferedPacketsMutex;
|
||||
|
||||
void OnDetectionRequest(Packet *packet);
|
||||
DataStructures::List<NATDetectionAttempt> natDetectionAttempts;
|
||||
unsigned int GetDetectionAttemptIndex(const SystemAddress &sa);
|
||||
unsigned int GetDetectionAttemptIndex(RakNetGUID guid);
|
||||
|
||||
// s1p1 is rakpeer itself
|
||||
RakNetSocket2 *s1p2,*s2p3,*s3p4,*s4p5;
|
||||
//unsigned short s1p2Port, s2p3Port, s3p4Port, s4p5Port;
|
||||
char s3p4Address[64];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
206
Source/include/slikenet/NativeFeatureIncludes.h
Normal file
206
Source/include/slikenet/NativeFeatureIncludes.h
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
// If you want to change these defines, put them in NativeFeatureIncludesOverrides so your changes are not lost when updating RakNet
|
||||
// The user should not edit this file
|
||||
#include "NativeFeatureIncludesOverrides.h"
|
||||
|
||||
#ifndef __NATIVE_FEATURE_INCLDUES_H
|
||||
#define __NATIVE_FEATURE_INCLDUES_H
|
||||
|
||||
// Uncomment below defines, and paste to NativeFeatureIncludesOverrides.h, to exclude plugins that you do not want to build into the static library, or DLL
|
||||
// These are not all the plugins, only those that are in the core library
|
||||
// Other plugins are located in DependentExtensions
|
||||
// #define _RAKNET_SUPPORT_ConnectionGraph2 0
|
||||
// #define _RAKNET_SUPPORT_DirectoryDeltaTransfer 0
|
||||
// #define _RAKNET_SUPPORT_FileListTransfer 0
|
||||
// #define _RAKNET_SUPPORT_FullyConnectedMesh2 0
|
||||
// #define _RAKNET_SUPPORT_MessageFilter 0
|
||||
// #define _RAKNET_SUPPORT_NatPunchthroughClient 0
|
||||
// #define _RAKNET_SUPPORT_NatPunchthroughServer 0
|
||||
// #define _RAKNET_SUPPORT_NatTypeDetectionClient 0
|
||||
// #define _RAKNET_SUPPORT_NatTypeDetectionServer 0
|
||||
// #define _RAKNET_SUPPORT_PacketLogger 0
|
||||
// #define _RAKNET_SUPPORT_ReadyEvent 0
|
||||
// #define _RAKNET_SUPPORT_ReplicaManager3 0
|
||||
// #define _RAKNET_SUPPORT_Router2 0
|
||||
// #define _RAKNET_SUPPORT_RPC4Plugin 0
|
||||
// #define _RAKNET_SUPPORT_TeamBalancer 0
|
||||
// #define _RAKNET_SUPPORT_TeamManager 0
|
||||
// #define _RAKNET_SUPPORT_UDPProxyClient 0
|
||||
// #define _RAKNET_SUPPORT_UDPProxyCoordinator 0
|
||||
// #define _RAKNET_SUPPORT_UDPProxyServer 0
|
||||
// #define _RAKNET_SUPPORT_ConsoleServer 0
|
||||
// #define _RAKNET_SUPPORT_RakNetTransport 0
|
||||
// #define _RAKNET_SUPPORT_TelnetTransport 0
|
||||
// #define _RAKNET_SUPPORT_TCPInterface 0
|
||||
// #define _RAKNET_SUPPORT_LogCommandParser 0
|
||||
// #define _RAKNET_SUPPORT_RakNetCommandParser 0
|
||||
// #define _RAKNET_SUPPORT_EmailSender 0
|
||||
// #define _RAKNET_SUPPORT_HTTPConnection 0
|
||||
// #define _RAKNET_SUPPORT_HTTPConnection2 0
|
||||
// #define _RAKNET_SUPPORT_PacketizedTCP 0
|
||||
// #define _RAKNET_SUPPORT_TwoWayAuthentication 0
|
||||
|
||||
// SET DEFAULTS IF UNDEFINED
|
||||
#ifndef LIBCAT_SECURITY
|
||||
#define LIBCAT_SECURITY 0
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_ConnectionGraph2
|
||||
#define _RAKNET_SUPPORT_ConnectionGraph2 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_DirectoryDeltaTransfer
|
||||
#define _RAKNET_SUPPORT_DirectoryDeltaTransfer 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_FileListTransfer
|
||||
#define _RAKNET_SUPPORT_FileListTransfer 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_FullyConnectedMesh
|
||||
#define _RAKNET_SUPPORT_FullyConnectedMesh 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_FullyConnectedMesh2
|
||||
#define _RAKNET_SUPPORT_FullyConnectedMesh2 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_MessageFilter
|
||||
#define _RAKNET_SUPPORT_MessageFilter 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_NatPunchthroughClient
|
||||
#define _RAKNET_SUPPORT_NatPunchthroughClient 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_NatPunchthroughServer
|
||||
#define _RAKNET_SUPPORT_NatPunchthroughServer 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_NatTypeDetectionClient
|
||||
#define _RAKNET_SUPPORT_NatTypeDetectionClient 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_NatTypeDetectionServer
|
||||
#define _RAKNET_SUPPORT_NatTypeDetectionServer 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_PacketLogger
|
||||
#define _RAKNET_SUPPORT_PacketLogger 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_ReadyEvent
|
||||
#define _RAKNET_SUPPORT_ReadyEvent 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_ReplicaManager3
|
||||
#define _RAKNET_SUPPORT_ReplicaManager3 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_Router2
|
||||
#define _RAKNET_SUPPORT_Router2 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_RPC4Plugin
|
||||
#define _RAKNET_SUPPORT_RPC4Plugin 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_TeamBalancer
|
||||
#define _RAKNET_SUPPORT_TeamBalancer 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_TeamManager
|
||||
#define _RAKNET_SUPPORT_TeamManager 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_UDPProxyClient
|
||||
#define _RAKNET_SUPPORT_UDPProxyClient 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_UDPProxyCoordinator
|
||||
#define _RAKNET_SUPPORT_UDPProxyCoordinator 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_UDPProxyServer
|
||||
#define _RAKNET_SUPPORT_UDPProxyServer 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_ConsoleServer
|
||||
#define _RAKNET_SUPPORT_ConsoleServer 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_RakNetTransport
|
||||
#define _RAKNET_SUPPORT_RakNetTransport 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_TelnetTransport
|
||||
#define _RAKNET_SUPPORT_TelnetTransport 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_TCPInterface
|
||||
#define _RAKNET_SUPPORT_TCPInterface 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_LogCommandParser
|
||||
#define _RAKNET_SUPPORT_LogCommandParser 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_RakNetCommandParser
|
||||
#define _RAKNET_SUPPORT_RakNetCommandParser 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_EmailSender
|
||||
#define _RAKNET_SUPPORT_EmailSender 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_HTTPConnection
|
||||
#define _RAKNET_SUPPORT_HTTPConnection 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_HTTPConnection2
|
||||
#define _RAKNET_SUPPORT_HTTPConnection2 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_PacketizedTCP
|
||||
#define _RAKNET_SUPPORT_PacketizedTCP 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_TwoWayAuthentication
|
||||
#define _RAKNET_SUPPORT_TwoWayAuthentication 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_CloudClient
|
||||
#define _RAKNET_SUPPORT_CloudClient 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_CloudServer
|
||||
#define _RAKNET_SUPPORT_CloudServer 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_DynDNS
|
||||
#define _RAKNET_SUPPORT_DynDNS 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_Rackspace
|
||||
#define _RAKNET_SUPPORT_Rackspace 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_FileOperations
|
||||
#define _RAKNET_SUPPORT_FileOperations 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_UDPForwarder
|
||||
#define _RAKNET_SUPPORT_UDPForwarder 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_StatisticsHistory
|
||||
#define _RAKNET_SUPPORT_StatisticsHistory 1
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_LibVoice
|
||||
#define _RAKNET_SUPPORT_LibVoice 0
|
||||
#endif
|
||||
#ifndef _RAKNET_SUPPORT_RelayPlugin
|
||||
#define _RAKNET_SUPPORT_RelayPlugin 1
|
||||
#endif
|
||||
|
||||
// Take care of dependencies
|
||||
#if _RAKNET_SUPPORT_DirectoryDeltaTransfer==1
|
||||
#undef _RAKNET_SUPPORT_FileListTransfer
|
||||
#define _RAKNET_SUPPORT_FileListTransfer 1
|
||||
#endif
|
||||
#if _RAKNET_SUPPORT_FullyConnectedMesh2==1
|
||||
#undef _RAKNET_SUPPORT_ConnectionGraph2
|
||||
#define _RAKNET_SUPPORT_ConnectionGraph2 1
|
||||
#endif
|
||||
#if _RAKNET_SUPPORT_TelnetTransport==1
|
||||
#undef _RAKNET_SUPPORT_PacketizedTCP
|
||||
#define _RAKNET_SUPPORT_PacketizedTCP 1
|
||||
#endif
|
||||
#if _RAKNET_SUPPORT_PacketizedTCP==1 || _RAKNET_SUPPORT_EmailSender==1 || _RAKNET_SUPPORT_HTTPConnection==1
|
||||
#undef _RAKNET_SUPPORT_TCPInterface
|
||||
#define _RAKNET_SUPPORT_TCPInterface 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // __NATIVE_FEATURE_INCLDUES_H
|
||||
19
Source/include/slikenet/NativeFeatureIncludesOverrides.h
Normal file
19
Source/include/slikenet/NativeFeatureIncludesOverrides.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
// USER EDITABLE FILE
|
||||
// See NativeFeatureIncludes.h
|
||||
|
||||
#ifndef __NATIVE_FEATURE_INCLDUES_OVERRIDES_H
|
||||
#define __NATIVE_FEATURE_INCLDUES_OVERRIDES_H
|
||||
|
||||
//#define LIBCAT_SECURITY 1
|
||||
|
||||
#endif
|
||||
33
Source/include/slikenet/NativeTypes.h
Normal file
33
Source/include/slikenet/NativeTypes.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifndef __NATIVE_TYPES_H
|
||||
#define __NATIVE_TYPES_H
|
||||
|
||||
#if defined(__GNUC__) || defined(__GCCXML__) || defined(__SNC__) || defined(__S3E__)
|
||||
#include <stdint.h>
|
||||
#elif !defined(_STDINT_H) && !defined(_SN_STDINT_H) && !defined(_SYS_STDINT_H_) && !defined(_STDINT) && !defined(_MACHTYPES_H_) && !defined(_STDINT_H_)
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned long long int uint64_t;
|
||||
typedef signed long long int64_t;
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
85
Source/include/slikenet/NetworkIDManager.h
Normal file
85
Source/include/slikenet/NetworkIDManager.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
///
|
||||
|
||||
|
||||
#ifndef __NETWORK_ID_MANAGER_H
|
||||
#define __NETWORK_ID_MANAGER_H
|
||||
|
||||
#include "types.h"
|
||||
#include "Export.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "NetworkIDObject.h"
|
||||
#include "Rand.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
/// Increase this value if you plan to have many persistent objects
|
||||
/// This value must match on all systems
|
||||
#define NETWORK_ID_MANAGER_HASH_LENGTH 1024
|
||||
|
||||
/// 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:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(NetworkIDManager)
|
||||
|
||||
NetworkIDManager();
|
||||
virtual ~NetworkIDManager(void);
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
// Stop tracking all NetworkID objects
|
||||
void Clear(void);
|
||||
|
||||
/// \internal
|
||||
NetworkIDObject *GET_BASE_OBJECT_FROM_ID(NetworkID x);
|
||||
|
||||
protected:
|
||||
/// \internal
|
||||
void TrackNetworkIDObject(NetworkIDObject *networkIdObject);
|
||||
void StopTrackingNetworkIDObject(NetworkIDObject *networkIdObject);
|
||||
|
||||
friend class NetworkIDObject;
|
||||
|
||||
NetworkIDObject *networkIdHash[NETWORK_ID_MANAGER_HASH_LENGTH];
|
||||
unsigned int NetworkIDToHashIndex(NetworkID networkId);
|
||||
uint64_t startingOffset;
|
||||
/// \internal
|
||||
NetworkID GetNewNetworkID(void);
|
||||
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
94
Source/include/slikenet/NetworkIDObject.h
Normal file
94
Source/include/slikenet/NetworkIDObject.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \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.
|
||||
///
|
||||
|
||||
|
||||
#if !defined(__NETWORK_ID_GENERATOR)
|
||||
#define __NETWORK_ID_GENERATOR
|
||||
|
||||
#include "types.h"
|
||||
#include "memoryoverride.h"
|
||||
#include "Export.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class NetworkIDManager;
|
||||
|
||||
typedef uint32_t NetworkIDType;
|
||||
|
||||
/// \brief Unique shared ids for each object instance
|
||||
/// \details 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 ) const;
|
||||
|
||||
/// 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;
|
||||
|
||||
protected:
|
||||
|
||||
/// The network ID of this object
|
||||
// networkID is assigned when networkIDManager is set.
|
||||
NetworkID networkID;
|
||||
NetworkIDManager *networkIDManager;
|
||||
|
||||
/// The parent set by SetParent()
|
||||
void *parent;
|
||||
|
||||
/// \internal, used by NetworkIDManager
|
||||
friend class NetworkIDManager;
|
||||
NetworkIDObject *nextInstanceForNetworkIDManager;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
79
Source/include/slikenet/PS3Includes.h
Normal file
79
Source/include/slikenet/PS3Includes.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file was taken from RakNet 4.082 without any modifications.
|
||||
* Please see licenses/RakNet license.txt for the underlying license and related copyright.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
50
Source/include/slikenet/PS4Includes.h
Normal file
50
Source/include/slikenet/PS4Includes.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file was taken from RakNet 4.082 without any modifications.
|
||||
* Please see licenses/RakNet license.txt for the underlying license and related copyright.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
50
Source/include/slikenet/PacketConsoleLogger.h
Normal file
50
Source/include/slikenet/PacketConsoleLogger.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief This will write all incoming and outgoing network messages to the log command parser, which can be accessed through Telnet
|
||||
///
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_LogCommandParser==1 && _RAKNET_SUPPORT_PacketLogger==1
|
||||
|
||||
#ifndef __PACKET_CONSOLE_LOGGER_H_
|
||||
#define __PACKET_CONSOLE_LOGGER_H_
|
||||
|
||||
#include "PacketLogger.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
53
Source/include/slikenet/PacketFileLogger.h
Normal file
53
Source/include/slikenet/PacketFileLogger.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief This will write all incoming and outgoing network messages to a file
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_PacketLogger==1
|
||||
|
||||
#ifndef __PACKET_FILE_LOGGER_H_
|
||||
#define __PACKET_FILE_LOGGER_H_
|
||||
|
||||
#include "PacketLogger.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
/// \ingroup PACKETLOGGER_GROUP
|
||||
/// \brief Packetlogger that outputs to a file
|
||||
class RAK_DLL_EXPORT PacketFileLogger : public PacketLogger
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(PacketFileLogger)
|
||||
|
||||
PacketFileLogger();
|
||||
virtual ~PacketFileLogger();
|
||||
void StartLog(const char *filenamePrefix);
|
||||
virtual void WriteLog(const char *str);
|
||||
protected:
|
||||
FILE *packetLogFile;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
120
Source/include/slikenet/PacketLogger.h
Normal file
120
Source/include/slikenet/PacketLogger.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief This will write all incoming and outgoing network messages to the local console screen. See derived functions for other outputs
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_PacketLogger==1
|
||||
|
||||
#ifndef __PACKET_LOGGER_H
|
||||
#define __PACKET_LOGGER_H
|
||||
|
||||
#include "types.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "Export.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
|
||||
/// \defgroup PACKETLOGGER_GROUP PacketLogger
|
||||
/// \brief Print out incoming messages to a target destination
|
||||
/// \details
|
||||
/// \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 PluginInterface2
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(PacketLogger)
|
||||
|
||||
PacketLogger();
|
||||
virtual ~PacketLogger();
|
||||
|
||||
// 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, size_t intoLength, const char* dir, const char* type, unsigned int reliableMessageNumber, unsigned int frame
|
||||
, unsigned char id, 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 reliableMessageNumber, unsigned int frame
|
||||
, unsigned char id, 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, size_t intoLength, const char* dir, const char* type, unsigned int reliableMessageNumber, 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);
|
||||
virtual void FormatLine(char* into, const char* dir, const char* type, unsigned int reliableMessageNumber, 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 OnReliabilityLayerNotification(const char *errorMessage, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress, bool isError);
|
||||
virtual void OnInternalPacket(InternalPacket *internalPacket, unsigned frameNumber, SystemAddress remoteSystemAddress, SLNet::TimeMS time, int isSend);
|
||||
virtual void OnAck(unsigned int messageNumber, SystemAddress remoteSystemAddress, SLNet::TimeMS time);
|
||||
virtual void OnPushBackPacket(const char *data, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress);
|
||||
|
||||
/// 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);
|
||||
|
||||
// Write informational messages
|
||||
virtual void WriteMiscellaneous(const char *type, const char *msg);
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
/// Log the direct sends and receives or not. Default true
|
||||
void SetLogDirectMessages(bool send);
|
||||
protected:
|
||||
|
||||
virtual bool UsesReliabilityLayer(void) const {return true;}
|
||||
const char* IDTOString(unsigned char Id);
|
||||
virtual void AddToLog(const char *str);
|
||||
// Users should override this
|
||||
virtual const char* UserIDTOString(unsigned char Id);
|
||||
void GetLocalTime(char buffer[128]);
|
||||
bool logDirectMessages;
|
||||
|
||||
bool printId, printAcks;
|
||||
char prefix[256];
|
||||
char suffix[256];
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
47
Source/include/slikenet/PacketOutputWindowLogger.h
Normal file
47
Source/include/slikenet/PacketOutputWindowLogger.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief This will write all incoming and outgoing network messages to a file
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_PacketLogger==1
|
||||
|
||||
#ifndef __PACKET_OUTPUT_WINDOW_LOGGER_H_
|
||||
#define __PACKET_OUTPUT_WINDOW_LOGGER_H_
|
||||
|
||||
#include "PacketLogger.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
/// \ingroup PACKETLOGGER_GROUP
|
||||
/// \brief Packetlogger that outputs to the output window in the debugger. Windows only.
|
||||
class RAK_DLL_EXPORT PacketOutputWindowLogger : public PacketLogger
|
||||
{
|
||||
public:
|
||||
PacketOutputWindowLogger();
|
||||
virtual ~PacketOutputWindowLogger();
|
||||
virtual void WriteLog(const char *str);
|
||||
protected:
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
6
Source/include/slikenet/PacketPool.h
Normal file
6
Source/include/slikenet/PacketPool.h
Normal file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* This file was taken from RakNet 4.082 without any modifications.
|
||||
* Please see licenses/RakNet license.txt for the underlying license and related copyright.
|
||||
*/
|
||||
|
||||
// REMOVEME
|
||||
87
Source/include/slikenet/PacketPriority.h
Normal file
87
Source/include/slikenet/PacketPriority.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief This file contains enumerations for packet priority and reliability enumerations.
|
||||
///
|
||||
|
||||
|
||||
|
||||
#ifndef __PACKET_PRIORITY_H
|
||||
#define __PACKET_PRIORITY_H
|
||||
|
||||
/// These enumerations are used to describe when packets are delivered.
|
||||
enum PacketPriority
|
||||
{
|
||||
/// The highest possible priority. These message trigger sends immediately, and are generally not buffered or aggregated into a single datagram.
|
||||
IMMEDIATE_PRIORITY,
|
||||
|
||||
/// For every 2 IMMEDIATE_PRIORITY messages, 1 HIGH_PRIORITY will be sent.
|
||||
/// Messages at this priority and lower are buffered to be sent in groups at 10 millisecond intervals to reduce UDP overhead and better measure congestion control.
|
||||
HIGH_PRIORITY,
|
||||
|
||||
/// For every 2 HIGH_PRIORITY messages, 1 MEDIUM_PRIORITY will be sent.
|
||||
/// Messages at this priority and lower are buffered to be sent in groups at 10 millisecond intervals to reduce UDP overhead and better measure congestion control.
|
||||
MEDIUM_PRIORITY,
|
||||
|
||||
/// For every 2 MEDIUM_PRIORITY messages, 1 LOW_PRIORITY will be sent.
|
||||
/// Messages at this priority and lower are buffered to be sent in groups at 10 millisecond intervals to reduce UDP overhead and better measure congestion control.
|
||||
LOW_PRIORITY,
|
||||
|
||||
/// \internal
|
||||
NUMBER_OF_PRIORITIES
|
||||
};
|
||||
|
||||
/// These enumerations are used to describe how packets are delivered.
|
||||
/// \note Note to self: I write this with 3 bits in the stream. If I add more remember to change that
|
||||
/// \note In ReliabilityLayer::WriteToBitStreamFromInternalPacket I assume there are 5 major types
|
||||
/// \note Do not reorder, I check on >= UNRELIABLE_WITH_ACK_RECEIPT
|
||||
enum PacketReliability
|
||||
{
|
||||
/// 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.
|
||||
/// Sequenced and ordered messages sent on the same channel will arrive in the order sent.
|
||||
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.
|
||||
/// Sequenced and ordered messages sent on the same channel will arrive in the order sent.
|
||||
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.
|
||||
/// Sequenced and ordered messages sent on the same channel will arrive in the order sent.
|
||||
RELIABLE_SEQUENCED,
|
||||
|
||||
/// Same as UNRELIABLE, however the user will get either ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS based on the result of sending this message when calling RakPeerInterface::Receive(). Bytes 1-4 will contain the number returned from the Send() function. On disconnect or shutdown, all messages not previously acked should be considered lost.
|
||||
UNRELIABLE_WITH_ACK_RECEIPT,
|
||||
|
||||
/// Same as UNRELIABLE_SEQUENCED, however the user will get either ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS based on the result of sending this message when calling RakPeerInterface::Receive(). Bytes 1-4 will contain the number returned from the Send() function. On disconnect or shutdown, all messages not previously acked should be considered lost.
|
||||
/// 05/04/10 You can't have sequenced and ack receipts, because you don't know if the other system discarded the message, meaning you don't know if the message was processed
|
||||
// UNRELIABLE_SEQUENCED_WITH_ACK_RECEIPT,
|
||||
|
||||
/// Same as RELIABLE. The user will also get ID_SND_RECEIPT_ACKED after the message is delivered when calling RakPeerInterface::Receive(). ID_SND_RECEIPT_ACKED is returned when the message arrives, not necessarily the order when it was sent. Bytes 1-4 will contain the number returned from the Send() function. On disconnect or shutdown, all messages not previously acked should be considered lost. This does not return ID_SND_RECEIPT_LOSS.
|
||||
RELIABLE_WITH_ACK_RECEIPT,
|
||||
|
||||
/// Same as RELIABLE_ORDERED_ACK_RECEIPT. The user will also get ID_SND_RECEIPT_ACKED after the message is delivered when calling RakPeerInterface::Receive(). ID_SND_RECEIPT_ACKED is returned when the message arrives, not necessarily the order when it was sent. Bytes 1-4 will contain the number returned from the Send() function. On disconnect or shutdown, all messages not previously acked should be considered lost. This does not return ID_SND_RECEIPT_LOSS.
|
||||
RELIABLE_ORDERED_WITH_ACK_RECEIPT,
|
||||
|
||||
/// Same as RELIABLE_SEQUENCED. The user will also get ID_SND_RECEIPT_ACKED after the message is delivered when calling RakPeerInterface::Receive(). Bytes 1-4 will contain the number returned from the Send() function. On disconnect or shutdown, all messages not previously acked should be considered lost.
|
||||
/// 05/04/10 You can't have sequenced and ack receipts, because you don't know if the other system discarded the message, meaning you don't know if the message was processed
|
||||
// RELIABLE_SEQUENCED_WITH_ACK_RECEIPT,
|
||||
|
||||
/// \internal
|
||||
NUMBER_OF_RELIABILITIES
|
||||
};
|
||||
|
||||
#endif
|
||||
91
Source/include/slikenet/PacketizedTCP.h
Normal file
91
Source/include/slikenet/PacketizedTCP.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief A simple TCP based server allowing sends and receives. Can be connected by any TCP client, including telnet.
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_PacketizedTCP==1 && _RAKNET_SUPPORT_TCPInterface==1
|
||||
|
||||
#ifndef __PACKETIZED_TCP
|
||||
#define __PACKETIZED_TCP
|
||||
|
||||
#include "TCPInterface.h"
|
||||
#include "DS_ByteQueue.h"
|
||||
#include "DS_Map.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
class RAK_DLL_EXPORT PacketizedTCP : public TCPInterface
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(PacketizedTCP)
|
||||
|
||||
PacketizedTCP();
|
||||
virtual ~PacketizedTCP();
|
||||
|
||||
/// Stops the TCP server
|
||||
void Stop(void);
|
||||
|
||||
/// Sends a byte stream
|
||||
void Send( const char *data, unsigned length, const SystemAddress &systemAddress, bool broadcast );
|
||||
|
||||
// Sends a concatenated list of byte streams
|
||||
bool SendList( const char **data, const unsigned int *lengths, const int numParameters, const SystemAddress &systemAddress, bool broadcast );
|
||||
|
||||
/// Returns data received
|
||||
Packet* Receive( void );
|
||||
|
||||
/// Disconnects a player/address
|
||||
void CloseConnection( SystemAddress systemAddress );
|
||||
|
||||
/// Has a previous call to connect succeeded?
|
||||
/// \return UNASSIGNED_SYSTEM_ADDRESS = no. Anything else means yes.
|
||||
SystemAddress HasCompletedConnectionAttempt(void);
|
||||
|
||||
/// Has a previous call to connect failed?
|
||||
/// \return UNASSIGNED_SYSTEM_ADDRESS = no. Anything else means yes.
|
||||
SystemAddress HasFailedConnectionAttempt(void);
|
||||
|
||||
/// Queued events of new incoming connections
|
||||
SystemAddress HasNewIncomingConnection(void);
|
||||
|
||||
/// Queued events of lost connections
|
||||
SystemAddress HasLostConnection(void);
|
||||
|
||||
protected:
|
||||
void ClearAllConnections(void);
|
||||
void RemoveFromConnectionList(const SystemAddress &sa);
|
||||
void AddToConnectionList(const SystemAddress &sa);
|
||||
void PushNotificationsToQueues(void);
|
||||
Packet *ReturnOutgoingPacket(void);
|
||||
|
||||
// A single TCP recieve may generate multiple split packets. They are stored in the waitingPackets list until Receive is called
|
||||
DataStructures::Queue<Packet*> waitingPackets;
|
||||
DataStructures::Map<SystemAddress, DataStructures::ByteQueue *> connections;
|
||||
|
||||
// Mirrors single producer / consumer, but processes them in Receive() before returning to user
|
||||
DataStructures::Queue<SystemAddress> _newIncomingConnections, _lostConnections, _failedConnectionAttempts, _completedConnectionAttempts;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
216
Source/include/slikenet/PluginInterface2.h
Normal file
216
Source/include/slikenet/PluginInterface2.h
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief \b RakNet's plugin functionality system, version 2. You can derive from this to create your own plugins.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __PLUGIN_INTERFACE_2_H
|
||||
#define __PLUGIN_INTERFACE_2_H
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#include "types.h"
|
||||
#include "Export.h"
|
||||
#include "PacketPriority.h"
|
||||
|
||||
namespace SLNet {
|
||||
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
class TCPInterface;
|
||||
struct Packet;
|
||||
struct InternalPacket;
|
||||
|
||||
/// \defgroup PLUGIN_INTERFACE_GROUP PluginInterface2
|
||||
|
||||
/// \defgroup PLUGINS_GROUP Plugins
|
||||
/// \ingroup PLUGIN_INTERFACE_GROUP
|
||||
|
||||
/// For each message that arrives on an instance of RakPeer, the plugins get an opportunity to process them first. This enumeration represents what to do with the message
|
||||
/// \ingroup PLUGIN_INTERFACE_GROUP
|
||||
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
|
||||
};
|
||||
|
||||
/// Reasons why a connection was lost
|
||||
/// \ingroup PLUGIN_INTERFACE_GROUP
|
||||
enum PI2_LostConnectionReason
|
||||
{
|
||||
/// Called RakPeer::CloseConnection()
|
||||
LCR_CLOSED_BY_USER,
|
||||
|
||||
/// Got ID_DISCONNECTION_NOTIFICATION
|
||||
LCR_DISCONNECTION_NOTIFICATION,
|
||||
|
||||
/// GOT ID_CONNECTION_LOST
|
||||
LCR_CONNECTION_LOST
|
||||
};
|
||||
|
||||
/// Returns why a connection attempt failed
|
||||
/// \ingroup PLUGIN_INTERFACE_GROUP
|
||||
enum PI2_FailedConnectionAttemptReason
|
||||
{
|
||||
FCAR_CONNECTION_ATTEMPT_FAILED,
|
||||
FCAR_ALREADY_CONNECTED,
|
||||
FCAR_NO_FREE_INCOMING_CONNECTIONS,
|
||||
FCAR_SECURITY_PUBLIC_KEY_MISMATCH,
|
||||
FCAR_CONNECTION_BANNED,
|
||||
FCAR_INVALID_PASSWORD,
|
||||
FCAR_INCOMPATIBLE_PROTOCOL,
|
||||
FCAR_IP_RECENTLY_CONNECTED,
|
||||
FCAR_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY,
|
||||
FCAR_OUR_SYSTEM_REQUIRES_SECURITY,
|
||||
FCAR_PUBLIC_KEY_MISMATCH
|
||||
};
|
||||
|
||||
/// RakNet's plugin system. Each plugin processes the following events:
|
||||
/// -Connection attempts
|
||||
/// -The result of connection attempts
|
||||
/// -Each incoming message
|
||||
/// -Updates over time, when RakPeer::Receive() is called
|
||||
///
|
||||
/// \ingroup PLUGIN_INTERFACE_GROUP
|
||||
class RAK_DLL_EXPORT PluginInterface2
|
||||
{
|
||||
public:
|
||||
PluginInterface2();
|
||||
virtual ~PluginInterface2();
|
||||
|
||||
/// Called when the interface is attached
|
||||
virtual void OnAttach(void) {}
|
||||
|
||||
/// Called when the interface is detached
|
||||
virtual void OnDetach(void) {}
|
||||
|
||||
/// Update is called every time a packet is checked for .
|
||||
virtual void Update(void) {}
|
||||
|
||||
/// OnReceive is called for every packet.
|
||||
/// \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(Packet *packet) {(void) packet; return RR_CONTINUE_PROCESSING;}
|
||||
|
||||
/// Called when RakPeer is initialized
|
||||
virtual void OnRakPeerStartup(void) {}
|
||||
|
||||
/// Called when RakPeer is shutdown
|
||||
virtual void OnRakPeerShutdown(void) {}
|
||||
|
||||
/// Called when a connection is dropped because the user called RakPeer::CloseConnection() for a particular system
|
||||
/// \param[in] systemAddress The system whose connection was closed
|
||||
/// \param[in] rakNetGuid The guid of the specified system
|
||||
/// \param[in] lostConnectionReason How the connection was closed: manually, connection lost, or notification of disconnection
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ){(void) systemAddress; (void) rakNetGUID; (void) lostConnectionReason;}
|
||||
|
||||
/// Called when we got a new connection
|
||||
/// \param[in] systemAddress Address of the new connection
|
||||
/// \param[in] rakNetGuid The guid of the specified system
|
||||
/// \param[in] isIncoming If true, this is ID_NEW_INCOMING_CONNECTION, or the equivalent
|
||||
virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming) {(void) systemAddress; (void) rakNetGUID; (void) isIncoming;}
|
||||
|
||||
/// Called when a connection attempt fails
|
||||
/// \param[in] packet Packet to be returned to the user
|
||||
/// \param[in] failedConnectionReason Why the connection failed
|
||||
virtual void OnFailedConnectionAttempt(Packet *packet, PI2_FailedConnectionAttemptReason failedConnectionAttemptReason) {(void) packet; (void) failedConnectionAttemptReason;}
|
||||
|
||||
/// Queried when attached to RakPeer
|
||||
/// Return true to call OnDirectSocketSend(), OnDirectSocketReceive(), OnReliabilityLayerNotification(), OnInternalPacket(), and OnAck()
|
||||
/// If true, then you cannot call RakPeer::AttachPlugin() or RakPeer::DetachPlugin() for this plugin, while RakPeer is active
|
||||
virtual bool UsesReliabilityLayer(void) const {return false;}
|
||||
|
||||
/// Called on a send to the socket, per datagram, that does not go through the reliability layer
|
||||
/// \pre To be called, UsesReliabilityLayer() must return true
|
||||
/// \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) {(void) data; (void) bitsUsed; (void) remoteSystemAddress;}
|
||||
|
||||
/// Called on a receive from the socket, per datagram, that does not go through the reliability layer
|
||||
/// \pre To be called, UsesReliabilityLayer() must return true
|
||||
/// \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) {(void) data; (void) bitsUsed; (void) remoteSystemAddress;}
|
||||
|
||||
/// Called when the reliability layer rejects a send or receive
|
||||
/// \pre To be called, UsesReliabilityLayer() must return true
|
||||
/// \param[in] bitsUsed How many bits long \a data is
|
||||
/// \param[in] remoteSystemAddress Which system this message is being sent to
|
||||
virtual void OnReliabilityLayerNotification(const char *errorMessage, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress, bool isError) {(void) errorMessage; (void) bitsUsed; (void) remoteSystemAddress; (void) isError;}
|
||||
|
||||
/// Called on a send or receive of a message within the reliability layer
|
||||
/// \pre To be called, UsesReliabilityLayer() must return true
|
||||
/// \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 SLNet::GetTimeMS()
|
||||
/// \param[in] isSend Is this callback representing a send event or receive event?
|
||||
virtual void OnInternalPacket(InternalPacket *internalPacket, unsigned frameNumber, SystemAddress remoteSystemAddress, SLNet::TimeMS time, int isSend) {(void) internalPacket; (void) frameNumber; (void) remoteSystemAddress; (void) time; (void) isSend;}
|
||||
|
||||
/// Called when we get an ack for a message we reliably sent
|
||||
/// \pre To be called, UsesReliabilityLayer() must return true
|
||||
/// \param[in] messageNumber The numerical identifier for which message this is
|
||||
/// \param[in] remoteSystemAddress The player we sent or got this packet from
|
||||
/// \param[in] time The current time as returned by SLNet::GetTimeMS()
|
||||
virtual void OnAck(unsigned int messageNumber, SystemAddress remoteSystemAddress, SLNet::TimeMS time) {(void) messageNumber; (void) remoteSystemAddress; (void) time;}
|
||||
|
||||
/// System called RakPeerInterface::PushBackPacket
|
||||
/// \param[in] data The data being sent
|
||||
/// \param[in] bitsUsed How many bits long \a data is
|
||||
/// \param[in] remoteSystemAddress The player we sent or got this packet from
|
||||
virtual void OnPushBackPacket(const char *data, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress) {(void) data; (void) bitsUsed; (void) remoteSystemAddress;}
|
||||
|
||||
RakPeerInterface *GetRakPeerInterface(void) const {return rakPeerInterface;}
|
||||
|
||||
RakNetGUID GetMyGUIDUnified(void) const;
|
||||
|
||||
/// \internal
|
||||
void SetRakPeerInterface( RakPeerInterface *ptr );
|
||||
|
||||
#if _RAKNET_SUPPORT_TCPInterface==1
|
||||
/// \internal
|
||||
void SetTCPInterface( TCPInterface *ptr );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Send through either rakPeerInterface or tcpInterface, whichever is available
|
||||
void SendUnified( const SLNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast );
|
||||
void SendUnified( const char * data, const int length, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast );
|
||||
bool SendListUnified( const char **data, const int *lengths, const int numParameters, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast );
|
||||
|
||||
Packet *AllocatePacketUnified(unsigned dataSize);
|
||||
void PushBackPacketUnified(Packet *packet, bool pushAtHead);
|
||||
void DeallocPacketUnified(Packet *packet);
|
||||
|
||||
// Filled automatically in when attached
|
||||
RakPeerInterface *rakPeerInterface;
|
||||
#if _RAKNET_SUPPORT_TCPInterface==1
|
||||
TCPInterface *tcpInterface;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
241
Source/include/slikenet/RPC4Plugin.h
Normal file
241
Source/include/slikenet/RPC4Plugin.h
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Remote procedure call, supporting C functions only. No external dependencies required.
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_RPC4Plugin==1
|
||||
|
||||
#ifndef __RPC_4_PLUGIN_H
|
||||
#define __RPC_4_PLUGIN_H
|
||||
|
||||
#include "PluginInterface2.h"
|
||||
#include "PacketPriority.h"
|
||||
#include "types.h"
|
||||
#include "BitStream.h"
|
||||
#include "string.h"
|
||||
#include "NetworkIDObject.h"
|
||||
#include "DS_Hash.h"
|
||||
#include "DS_OrderedList.h"
|
||||
|
||||
/// \defgroup RPC_PLUGIN_GROUP RPC
|
||||
/// \brief Remote procedure calls, without external dependencies.
|
||||
/// \details This should not be used at the same time as RPC3. This is a less functional version of RPC3, and is here for users that do not want the Boost dependency of RPC3.
|
||||
/// \ingroup PLUGINS_GROUP
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
class NetworkIDManager;
|
||||
|
||||
/// \brief Error codes returned by a remote system as to why an RPC function call cannot execute
|
||||
/// \details Error code follows packet ID ID_RPC_REMOTE_ERROR, that is packet->data[1]<BR>
|
||||
/// Name of the function will be appended starting at packet->data[2]
|
||||
/// \ingroup RPC_PLUGIN_GROUP
|
||||
enum RPCErrorCodes
|
||||
{
|
||||
/// Named function was not registered with RegisterFunction(). Check your spelling.
|
||||
RPC_ERROR_FUNCTION_NOT_REGISTERED,
|
||||
};
|
||||
|
||||
/// \brief Instantiate this class globally if you want to register a function with RPC4 at the global space
|
||||
class RAK_DLL_EXPORT RPC4GlobalRegistration
|
||||
{
|
||||
public:
|
||||
/// \brief Queue a call to RPC4::RegisterFunction() globally. Actual call occurs once RPC4 is attached to an instance of RakPeer or TCPInterface.
|
||||
RPC4GlobalRegistration(const char* uniqueID, void ( *functionPointer ) (SLNet::BitStream *userData, Packet *packet ));
|
||||
|
||||
/// \brief Queue a call to RPC4::RegisterSlot() globally. Actual call occurs once RPC4 is attached to an instance of RakPeer or TCPInterface.
|
||||
RPC4GlobalRegistration(const char* uniqueID, void ( *functionPointer ) (SLNet::BitStream *userData, Packet *packet ), int callPriority);
|
||||
|
||||
/// \brief Queue a call to RPC4::RegisterBlockingFunction() globally. Actual call occurs once RPC4 is attached to an instance of RakPeer or TCPInterface.
|
||||
RPC4GlobalRegistration(const char* uniqueID, void ( *functionPointer ) (SLNet::BitStream *userData, SLNet::BitStream *returnData, Packet *packet ));
|
||||
|
||||
/// \brief Queue a call to RPC4::RegisterLocalCallback() globally. Actual call occurs once RPC4 is attached to an instance of RakPeer or TCPInterface.
|
||||
RPC4GlobalRegistration(const char* uniqueID, MessageID messageId);
|
||||
};
|
||||
|
||||
/// \brief The RPC4 plugin is just an association between a C function pointer and a string.
|
||||
/// \details It is for users that want to use RPC, but do not want to use boost.
|
||||
/// You do not have the automatic serialization or other features of RPC3, and C++ member calls are not supported.
|
||||
/// \note You cannot use RPC4 at the same time as RPC3Plugin
|
||||
/// \ingroup RPC_PLUGIN_GROUP
|
||||
class RAK_DLL_EXPORT RPC4 : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(RPC4)
|
||||
|
||||
// Constructor
|
||||
RPC4();
|
||||
|
||||
// Destructor
|
||||
virtual ~RPC4();
|
||||
|
||||
/// \deprecated Use RegisterSlot
|
||||
/// \brief Register a function pointer to be callable from a remote system
|
||||
/// \details The hash of the function name will be stored as an association with the function pointer
|
||||
/// When a call is made to call this function from the \a Call() or CallLoopback() function, the function pointer will be invoked with the passed bitStream to Call() and the actual Packet that RakNet got.
|
||||
/// \sa RegisterPacketCallback()
|
||||
/// \param[in] uniqueID Identifier to be associated with \a functionPointer. If this identifier is already in use, the call will return false.
|
||||
/// \param[in] functionPointer C function pointer to be called
|
||||
/// \return True if the hash of uniqueID is not in use, false otherwise.
|
||||
bool RegisterFunction(const char* uniqueID, void ( *functionPointer ) (SLNet::BitStream *userData, Packet *packet ));
|
||||
|
||||
/// Register a slot, which is a function pointer to one or more implementations that supports this function signature
|
||||
/// When a signal occurs, all slots with the same identifier are called.
|
||||
/// \param[in] sharedIdentifier A string to identify the slot. Recommended to be the same as the name of the function.
|
||||
/// \param[in] functionPtr Pointer to the function. For C, just pass the name of the function. For C++, use ARPC_REGISTER_CPP_FUNCTION
|
||||
/// \param[in] callPriority Slots are called by order of the highest callPriority first. For slots with the same priority, they are called in the order they are registered
|
||||
void RegisterSlot(const char *sharedIdentifier, void ( *functionPointer ) (SLNet::BitStream *userData, Packet *packet ), int callPriority);
|
||||
|
||||
/// \brief Same as \a RegisterFunction, but is called with CallBlocking() instead of Call() and returns a value to the caller
|
||||
bool RegisterBlockingFunction(const char* uniqueID, void ( *functionPointer ) (SLNet::BitStream *userData, SLNet::BitStream *returnData, Packet *packet ));
|
||||
|
||||
/// \deprecated Use RegisterSlot and invoke on self only when the packet you want arrives
|
||||
/// When a RakNet Packet with the specified identifier is returned, execute CallLoopback() on a function previously registered with RegisterFunction()
|
||||
/// For example, you could call "OnClosedConnection" whenever you get ID_DISCONNECTION_NOTIFICATION or ID_CONNECTION_LOST
|
||||
/// \param[in] uniqueID Identifier passed to RegisterFunction()
|
||||
/// \param[in] messageId What RakNet packet ID to call on, for example ID_DISCONNECTION_NOTIFICATION or ID_CONNECTION_LOST
|
||||
void RegisterLocalCallback(const char* uniqueID, MessageID messageId);
|
||||
|
||||
/// \brief Unregister a function pointer previously registered with RegisterFunction()
|
||||
/// \param[in] Identifier originally passed to RegisterFunction()
|
||||
/// \return True if the hash of uniqueID was in use, and hence removed. false otherwise.
|
||||
bool UnregisterFunction(const char* uniqueID);
|
||||
|
||||
/// \brief Same as UnregisterFunction, except for a blocking function
|
||||
bool UnregisterBlockingFunction(const char* uniqueID);
|
||||
|
||||
/// Remove the association created with RegisterPacketCallback()
|
||||
/// \param[in] uniqueID Identifier passed as uniqueID to RegisterLocalCallback()
|
||||
/// \param[in] messageId Identifier passed as messageId to RegisterLocalCallback()
|
||||
/// \return True if the combination of uniqueID and messageId was in use, and hence removed
|
||||
bool UnregisterLocalCallback(const char* uniqueID, MessageID messageId);
|
||||
|
||||
/// Remove the association created with RegisterSlot()
|
||||
/// \param[in] sharedIdentifier Identifier passed as sharedIdentifier to RegisterSlot()
|
||||
bool UnregisterSlot(const char* sharedIdentifier);
|
||||
|
||||
/// \deprecated Use RegisterSlot() and Signal() with your own RakNetGUID as the send target
|
||||
/// Send to the attached instance of RakPeer. See RakPeerInterface::SendLoopback()
|
||||
/// \param[in] Identifier originally passed to RegisterFunction() on the local system
|
||||
/// \param[in] bitStream bitStream encoded data to send to the function callback
|
||||
void CallLoopback( const char* uniqueID, SLNet::BitStream * bitStream );
|
||||
|
||||
/// \deprecated, use Signal()
|
||||
/// Send to the specified remote instance of RakPeer.
|
||||
/// \param[in] uniqueID Identifier originally passed to RegisterFunction() on the remote system(s)
|
||||
/// \param[in] bitStream bitStream encoded data to send to the function callback
|
||||
/// \param[in] priority See RakPeerInterface::Send()
|
||||
/// \param[in] reliability See RakPeerInterface::Send()
|
||||
/// \param[in] orderingChannel See RakPeerInterface::Send()
|
||||
/// \param[in] systemIdentifier See RakPeerInterface::Send()
|
||||
/// \param[in] broadcast See RakPeerInterface::Send()
|
||||
void Call( const char* uniqueID, SLNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast );
|
||||
|
||||
/// \brief Same as call, but don't return until the remote system replies.
|
||||
/// Broadcasting parameter does not exist, this can only call one remote system
|
||||
/// \note This function does not return until the remote system responds, disconnects, or was never connected to begin with
|
||||
/// \param[in] Identifier originally passed to RegisterBlockingFunction() on the remote system(s)
|
||||
/// \param[in] bitStream bitStream encoded data to send to the function callback
|
||||
/// \param[in] priority See RakPeerInterface::Send()
|
||||
/// \param[in] reliability See RakPeerInterface::Send()
|
||||
/// \param[in] orderingChannel See RakPeerInterface::Send()
|
||||
/// \param[in] systemIdentifier See RakPeerInterface::Send()
|
||||
/// \param[out] returnData Written to by the function registered with RegisterBlockingFunction.
|
||||
/// \return true if successfully called. False on disconnect, function not registered, or not connected to begin with
|
||||
bool CallBlocking( const char* uniqueID, SLNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, SLNet::BitStream *returnData );
|
||||
|
||||
/// Calls zero or more functions identified by sharedIdentifier registered with RegisterSlot()
|
||||
/// \param[in] sharedIdentifier parameter of the same name passed to RegisterSlot() on the remote system
|
||||
/// \param[in] bitStream bitStream encoded data to send to the function callback
|
||||
/// \param[in] priority See RakPeerInterface::Send()
|
||||
/// \param[in] reliability See RakPeerInterface::Send()
|
||||
/// \param[in] orderingChannel See RakPeerInterface::Send()
|
||||
/// \param[in] systemIdentifier See RakPeerInterface::Send()
|
||||
/// \param[in] broadcast See RakPeerInterface::Send()
|
||||
/// \param[in] invokeLocal If true, also sends to self.
|
||||
void Signal(const char *sharedIdentifier, SLNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, bool invokeLocal);
|
||||
|
||||
/// If called while processing a slot, no further slots for the currently executing signal will be executed
|
||||
void InterruptSignal(void);
|
||||
|
||||
/// \internal
|
||||
struct LocalCallback
|
||||
{
|
||||
MessageID messageId;
|
||||
DataStructures::OrderedList<SLNet::RakString, SLNet::RakString> functions;
|
||||
};
|
||||
static int LocalCallbackComp(const MessageID &key, LocalCallback* const &data );
|
||||
|
||||
/// \internal
|
||||
// Callable object, along with priority to call relative to other objects
|
||||
struct LocalSlotObject
|
||||
{
|
||||
LocalSlotObject() {}
|
||||
LocalSlotObject(unsigned int _registrationCount,int _callPriority, void ( *_functionPointer ) (SLNet::BitStream *userData, Packet *packet ))
|
||||
{registrationCount=_registrationCount;callPriority=_callPriority;functionPointer=_functionPointer;}
|
||||
~LocalSlotObject() {}
|
||||
|
||||
// Used so slots are called in the order they are registered
|
||||
unsigned int registrationCount;
|
||||
int callPriority;
|
||||
void ( *functionPointer ) (SLNet::BitStream *userData, Packet *packet );
|
||||
};
|
||||
|
||||
static int LocalSlotObjectComp( const LocalSlotObject &key, const LocalSlotObject &data );
|
||||
|
||||
/// \internal
|
||||
struct LocalSlot
|
||||
{
|
||||
DataStructures::OrderedList<LocalSlotObject,LocalSlotObject,LocalSlotObjectComp> slotObjects;
|
||||
};
|
||||
DataStructures::Hash<SLNet::RakString, LocalSlot*,256, SLNet::RakString::ToInteger> localSlots;
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Packet handling functions
|
||||
// --------------------------------------------------------------------------------------------
|
||||
virtual void OnAttach(void);
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
|
||||
DataStructures::Hash<SLNet::RakString, void ( * ) (SLNet::BitStream *, Packet * ),64, SLNet::RakString::ToInteger> registeredNonblockingFunctions;
|
||||
DataStructures::Hash<SLNet::RakString, void ( * ) (SLNet::BitStream *, SLNet::BitStream *, Packet * ),64, SLNet::RakString::ToInteger> registeredBlockingFunctions;
|
||||
DataStructures::OrderedList<MessageID,LocalCallback*,RPC4::LocalCallbackComp> localCallbacks;
|
||||
|
||||
SLNet::BitStream blockingReturnValue;
|
||||
bool gotBlockingReturnValue;
|
||||
|
||||
DataStructures::HashIndex GetLocalSlotIndex(const char *sharedIdentifier);
|
||||
|
||||
/// Used so slots are called in the order they are registered
|
||||
unsigned int nextSlotRegistrationCount;
|
||||
|
||||
bool interruptSignal;
|
||||
|
||||
void InvokeSignal(DataStructures::HashIndex functionIndex, SLNet::BitStream *serializedParameters, Packet *packet);
|
||||
};
|
||||
|
||||
} // End namespace
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
418
Source/include/slikenet/Rackspace.h
Normal file
418
Source/include/slikenet/Rackspace.h
Normal file
@ -0,0 +1,418 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file Rackspace.h
|
||||
/// \brief Helper to class to manage Rackspace servers
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
|
||||
#if _RAKNET_SUPPORT_Rackspace==1 && _RAKNET_SUPPORT_TCPInterface==1
|
||||
|
||||
#include "Export.h"
|
||||
#include "DS_List.h"
|
||||
#include "types.h"
|
||||
#include "DS_Queue.h"
|
||||
#include "string.h"
|
||||
|
||||
#ifndef __RACKSPACE_H
|
||||
#define __RACKSPACE_H
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
class TCPInterface;
|
||||
struct Packet;
|
||||
|
||||
/// \brief Result codes for Rackspace commands
|
||||
/// /sa Rackspace::EventTypeToString()
|
||||
enum RackspaceEventType
|
||||
{
|
||||
RET_Success_200,
|
||||
RET_Success_201,
|
||||
RET_Success_202,
|
||||
RET_Success_203,
|
||||
RET_Success_204,
|
||||
RET_Cloud_Servers_Fault_500,
|
||||
RET_Service_Unavailable_503,
|
||||
RET_Unauthorized_401,
|
||||
RET_Bad_Request_400,
|
||||
RET_Over_Limit_413,
|
||||
RET_Bad_Media_Type_415,
|
||||
RET_Item_Not_Found_404,
|
||||
RET_Build_In_Progress_409,
|
||||
RET_Resize_Not_Allowed_403,
|
||||
RET_Connection_Closed_Without_Reponse,
|
||||
RET_Unknown_Failure,
|
||||
};
|
||||
|
||||
/// \internal
|
||||
enum RackspaceOperationType
|
||||
{
|
||||
RO_CONNECT_AND_AUTHENTICATE,
|
||||
RO_LIST_SERVERS,
|
||||
RO_LIST_SERVERS_WITH_DETAILS,
|
||||
RO_CREATE_SERVER,
|
||||
RO_GET_SERVER_DETAILS,
|
||||
RO_UPDATE_SERVER_NAME_OR_PASSWORD,
|
||||
RO_DELETE_SERVER,
|
||||
RO_LIST_SERVER_ADDRESSES,
|
||||
RO_SHARE_SERVER_ADDRESS,
|
||||
RO_DELETE_SERVER_ADDRESS,
|
||||
RO_REBOOT_SERVER,
|
||||
RO_REBUILD_SERVER,
|
||||
RO_RESIZE_SERVER,
|
||||
RO_CONFIRM_RESIZED_SERVER,
|
||||
RO_REVERT_RESIZED_SERVER,
|
||||
RO_LIST_FLAVORS,
|
||||
RO_GET_FLAVOR_DETAILS,
|
||||
RO_LIST_IMAGES,
|
||||
RO_CREATE_IMAGE,
|
||||
RO_GET_IMAGE_DETAILS,
|
||||
RO_DELETE_IMAGE,
|
||||
RO_LIST_SHARED_IP_GROUPS,
|
||||
RO_LIST_SHARED_IP_GROUPS_WITH_DETAILS,
|
||||
RO_CREATE_SHARED_IP_GROUP,
|
||||
RO_GET_SHARED_IP_GROUP_DETAILS,
|
||||
RO_DELETE_SHARED_IP_GROUP,
|
||||
|
||||
RO_NONE,
|
||||
};
|
||||
|
||||
/// \brief Callback interface to receive the results of operations
|
||||
class RAK_DLL_EXPORT Rackspace2EventCallback
|
||||
{
|
||||
public:
|
||||
Rackspace2EventCallback() {}
|
||||
virtual ~Rackspace2EventCallback() {}
|
||||
virtual void OnAuthenticationResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnListServersResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnListServersWithDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnCreateServerResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnGetServerDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnUpdateServerNameOrPassword(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnDeleteServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnListServerAddresses(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnShareServerAddress(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnDeleteServerAddress(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnRebootServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnRebuildServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnResizeServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnConfirmResizedServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnRevertResizedServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnListFlavorsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnGetFlavorDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnListImagesResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnCreateImageResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnGetImageDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnDeleteImageResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnListSharedIPGroups(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnListSharedIPGroupsWithDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnCreateSharedIPGroup(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnGetSharedIPGroupDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
virtual void OnDeleteSharedIPGroup(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0;
|
||||
|
||||
virtual void OnConnectionAttemptFailure(RackspaceOperationType operationType, const char *url)=0;
|
||||
};
|
||||
|
||||
/// \brief Callback interface to receive the results of operations, with a default result
|
||||
class RAK_DLL_EXPORT RackspaceEventCallback_Default : public Rackspace2EventCallback
|
||||
{
|
||||
public:
|
||||
virtual void ExecuteDefault(const char *callbackName, RackspaceEventType eventType, const char *htmlAdditionalInfo) {(void) callbackName; (void) eventType; (void) htmlAdditionalInfo;}
|
||||
|
||||
virtual void OnAuthenticationResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnAuthenticationResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnListServersResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListServersResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnListServersWithDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListServersWithDetailsResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnCreateServerResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnCreateServerResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnGetServerDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnGetServerDetails", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnUpdateServerNameOrPassword(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnUpdateServerNameOrPassword", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnDeleteServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnDeleteServer", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnListServerAddresses(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListServerAddresses", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnShareServerAddress(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnShareServerAddress", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnDeleteServerAddress(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnDeleteServerAddress", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnRebootServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnRebootServer", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnRebuildServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnRebuildServer", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnResizeServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnResizeServer", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnConfirmResizedServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnConfirmResizedServer", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnRevertResizedServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnRevertResizedServer", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnListFlavorsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListFlavorsResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnGetFlavorDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnGetFlavorDetailsResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnListImagesResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListImagesResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnCreateImageResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnCreateImageResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnGetImageDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnGetImageDetailsResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnDeleteImageResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnDeleteImageResult", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnListSharedIPGroups(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListSharedIPGroups", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnListSharedIPGroupsWithDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListSharedIPGroupsWithDetails", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnCreateSharedIPGroup(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnCreateSharedIPGroup", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnGetSharedIPGroupDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnGetSharedIPGroupDetails", eventType, htmlAdditionalInfo);}
|
||||
virtual void OnDeleteSharedIPGroup(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnDeleteSharedIPGroup", eventType, htmlAdditionalInfo);}
|
||||
|
||||
virtual void OnConnectionAttemptFailure(RackspaceOperationType operationType, const char *url) {(void) operationType; (void) url;}
|
||||
};
|
||||
|
||||
/// \brief Code that uses the TCPInterface class to communicate with the Rackspace API servers
|
||||
/// \pre Compile RakNet with OPEN_SSL_CLIENT_SUPPORT set to 1
|
||||
/// \pre Packets returned from TCPInterface::OnReceive() must be passed to Rackspace::OnReceive()
|
||||
/// \pre Packets returned from TCPInterface::HasLostConnection() must be passed to Rackspace::OnClosedConnection()
|
||||
class RAK_DLL_EXPORT Rackspace
|
||||
{
|
||||
public:
|
||||
Rackspace();
|
||||
~Rackspace();
|
||||
|
||||
/// \brief Authenticate with Rackspace servers, required before executing any commands.
|
||||
/// \details All requests to authenticate and operate against Cloud Servers are performed using SSL over HTTP (HTTPS) on TCP port 443.
|
||||
/// Times out after 24 hours - if you get RET_Authenticate_Unauthorized in the RackspaceEventCallback callback, call again
|
||||
/// \sa RackspaceEventCallback::OnAuthenticationResult()
|
||||
/// \param[in] _tcpInterface An instance of TCPInterface, build with OPEN_SSL_CLIENT_SUPPORT 1 and already started
|
||||
/// \param[in] _authenticationURL See http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf . US-based accounts authenticate through auth.api.rackspacecloud.com. UK-based accounts authenticate through lon.auth.api.rackspacecloud.com
|
||||
/// \param[in] _rackspaceCloudUsername Username you registered with Rackspace on their website
|
||||
/// \param[in] _apiAccessKey Obtain your API access key from the Rackspace Cloud Control Panel in the Your Account API Access section.
|
||||
/// \return The address of the authentication server, or UNASSIGNED_SYSTEM_ADDRESS if the connection attempt failed
|
||||
SystemAddress Authenticate(TCPInterface *_tcpInterface, const char *_authenticationURL, const char *_rackspaceCloudUsername, const char *_apiAccessKey);
|
||||
|
||||
/// \brief Get a list of running servers
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnListServersResult()
|
||||
void ListServers(void);
|
||||
|
||||
/// \brief Get a list of running servers, with extended details on each server
|
||||
/// \sa GetServerDetails()
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnListServersWithDetailsResult()
|
||||
void ListServersWithDetails(void);
|
||||
|
||||
/// \brief Create a server
|
||||
/// \details Create a server with a given image (harddrive contents) and flavor (hardware configuration)
|
||||
/// Get the available images with ListImages()
|
||||
/// Get the available flavors with ListFlavors()
|
||||
/// It is possible to configure the server in more detail. See the XML schema at http://docs.rackspacecloud.com/servers/api/v1.0
|
||||
/// You can execute such a custom command by calling AddOperation() manually. See the implementation of CreateServer for how to do so.
|
||||
/// The server takes a while to build. Call GetServerDetails() to get the current build status. Server id to pass to GetServerDetails() is returned in the field <server ... id="1234">
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnCreateServerResult()
|
||||
/// \param[in] name Name of the server. Only alphanumeric characters, periods, and hyphens are valid. Server Name cannot start or end with a period or hyphen.
|
||||
/// \param[in] imageId Which image (harddrive contents, including OS) to use
|
||||
/// \param[in] flavorId Which flavor (hardware config) to use, primarily how much memory is available.
|
||||
void CreateServer(SLNet::RakString name, SLNet::RakString imageId, SLNet::RakString flavorId);
|
||||
|
||||
/// \brief Get details on a particular server
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnGetServerDetailsResult()
|
||||
/// \param[in] serverId Which server to get details on. You can call ListServers() to get the list of active servers.
|
||||
void GetServerDetails(SLNet::RakString serverId);
|
||||
|
||||
/// \brief Changes the name or password for a server
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnUpdateServerNameOrPasswordResult()
|
||||
/// \param[in] serverId Which server to get details on. You can call ListServers() to get the list of active servers.
|
||||
/// \param[in] newName The new server name. Leave blank to leave unchanged. Only alphanumeric characters, periods, and hyphens are valid. Server Name cannot start or end with a period or hyphen.
|
||||
/// \param[in] newPassword The new server password. Leave blank to leave unchanged.
|
||||
void UpdateServerNameOrPassword(SLNet::RakString serverId, SLNet::RakString newName, SLNet::RakString newPassword);
|
||||
|
||||
/// \brief Deletes a server
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnDeleteServerResult()
|
||||
/// \param[in] serverId Which server to get details on. You can call ListServers() to get the list of active servers.
|
||||
void DeleteServer(SLNet::RakString serverId);
|
||||
|
||||
/// \brief Lists the IP addresses available to a server
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnListServerAddressesResult()
|
||||
/// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers.
|
||||
void ListServerAddresses(SLNet::RakString serverId);
|
||||
|
||||
/// \brief Shares an IP address with a server
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnShareServerAddressResult()
|
||||
/// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers.
|
||||
/// \param[in] ipAddress Which IP address. You can call ListServerAddresses() to get the list of addresses for the specified server
|
||||
void ShareServerAddress(SLNet::RakString serverId, SLNet::RakString ipAddress);
|
||||
|
||||
/// \brief Stops sharing an IP address with a server
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnDeleteServerAddressResult()
|
||||
/// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers.
|
||||
/// \param[in] ipAddress Which IP address. You can call ListServerAddresses() to get the list of addresses for the specified server
|
||||
void DeleteServerAddress(SLNet::RakString serverId, SLNet::RakString ipAddress);
|
||||
|
||||
/// \brief Reboots a server
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnRebootServerResult()
|
||||
/// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers.
|
||||
/// \param[in] rebootType Should be either "HARD" or "SOFT"
|
||||
void RebootServer(SLNet::RakString serverId, SLNet::RakString rebootType);
|
||||
|
||||
/// \brief Rebuilds a server with a different image (harddrive contents)
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnRebuildServerResult()
|
||||
/// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers.
|
||||
/// \param[in] imageId Which image (harddrive contents, including OS) to use
|
||||
void RebuildServer(SLNet::RakString serverId, SLNet::RakString imageId);
|
||||
|
||||
/// \brief Changes the hardware configuration of a server. This does not take effect until you call ConfirmResizedServer()
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnResizeServerResult()
|
||||
/// \sa RevertResizedServer()
|
||||
/// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers.
|
||||
/// \param[in] flavorId Which flavor (hardware config) to use, primarily how much memory is available.
|
||||
void ResizeServer(SLNet::RakString serverId, SLNet::RakString flavorId);
|
||||
|
||||
/// \brief Confirm a resize for the specified server
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnConfirmResizedServerResult()
|
||||
/// \sa ResizeServer()
|
||||
/// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers.
|
||||
void ConfirmResizedServer(SLNet::RakString serverId);
|
||||
|
||||
/// \brief Reverts a resize for the specified server
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnRevertResizedServerResult()
|
||||
/// \sa ResizeServer()
|
||||
/// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers.
|
||||
void RevertResizedServer(SLNet::RakString serverId);
|
||||
|
||||
/// \brief List all flavors (hardware configs, primarily memory)
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnListFlavorsResult()
|
||||
void ListFlavors(void);
|
||||
|
||||
/// \brief Get extended details about a specific flavor
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnGetFlavorDetailsResult()
|
||||
/// \sa ListFlavors()
|
||||
/// \param[in] flavorId Which flavor (hardware config)
|
||||
void GetFlavorDetails(SLNet::RakString flavorId);
|
||||
|
||||
/// \brief List all images (software configs, including operating systems), which includes images you create yourself
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnListImagesResult()
|
||||
/// \sa CreateImage()
|
||||
void ListImages(void);
|
||||
|
||||
/// \brief Images a running server. This essentially copies the harddrive, and lets you start a server with the same harddrive contents later
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnCreateImageResult()
|
||||
/// \sa ListImages()
|
||||
/// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers.
|
||||
/// \param[in] imageName What to call this image
|
||||
void CreateImage(SLNet::RakString serverId, SLNet::RakString imageName);
|
||||
|
||||
/// \brief Get extended details about a particular image
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnGetImageDetailsResult()
|
||||
/// \sa ListImages()
|
||||
/// \param[in] imageId Which image
|
||||
void GetImageDetails(SLNet::RakString imageId);
|
||||
|
||||
/// \brief Delete a custom image created with CreateImage()
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnDeleteImageResult()
|
||||
/// \sa ListImages()
|
||||
/// \param[in] imageId Which image
|
||||
void DeleteImage(SLNet::RakString imageId);
|
||||
|
||||
/// \brief List IP groups
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnListSharedIPGroupsResult()
|
||||
void ListSharedIPGroups(void);
|
||||
|
||||
/// \brief List IP groups with extended details
|
||||
/// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf
|
||||
/// \sa RackspaceEventCallback::OnListSharedIPGroupsWithDetailsResult()
|
||||
void ListSharedIPGroupsWithDetails(void);
|
||||
|
||||
// I don't know what this does
|
||||
void CreateSharedIPGroup(SLNet::RakString name, SLNet::RakString optionalServerId);
|
||||
// I don't know what this does
|
||||
void GetSharedIPGroupDetails(SLNet::RakString groupId);
|
||||
// I don't know what this does
|
||||
void DeleteSharedIPGroup(SLNet::RakString groupId);
|
||||
|
||||
/// \brief Adds a callback to the list of callbacks to be called when any of the above functions finish executing
|
||||
/// The callbacks are called in the order they are added
|
||||
void AddEventCallback(Rackspace2EventCallback *callback);
|
||||
/// \brief Removes a callback from the list of callbacks to be called when any of the above functions finish executing
|
||||
/// The callbacks are called in the order they are added
|
||||
void RemoveEventCallback(Rackspace2EventCallback *callback);
|
||||
/// \brief Removes all callbacks
|
||||
void ClearEventCallbacks(void);
|
||||
|
||||
/// Call this anytime TCPInterface returns a packet
|
||||
void OnReceive(Packet *packet);
|
||||
|
||||
/// Call this when TCPInterface returns something other than UNASSIGNED_SYSTEM_ADDRESS from HasLostConnection()
|
||||
void OnClosedConnection(SystemAddress systemAddress);
|
||||
|
||||
/// String representation of each RackspaceEventType
|
||||
static const char * EventTypeToString(RackspaceEventType eventType);
|
||||
|
||||
/// \brief Mostly for internal use, but you can use it to execute an operation with more complex xml if desired
|
||||
/// See the Rackspace.cpp on how to use it
|
||||
void AddOperation(RackspaceOperationType type, SLNet::RakString httpCommand, SLNet::RakString operation, SLNet::RakString xml);
|
||||
protected:
|
||||
|
||||
DataStructures::List<Rackspace2EventCallback*> eventCallbacks;
|
||||
|
||||
struct RackspaceOperation
|
||||
{
|
||||
RackspaceOperationType type;
|
||||
// SLNet::RakString stringInfo;
|
||||
SystemAddress connectionAddress;
|
||||
bool isPendingAuthentication;
|
||||
SLNet::RakString incomingStream;
|
||||
SLNet::RakString httpCommand;
|
||||
SLNet::RakString operation;
|
||||
SLNet::RakString xml;
|
||||
};
|
||||
|
||||
TCPInterface *tcpInterface;
|
||||
|
||||
// RackspaceOperationType currentOperation;
|
||||
// DataStructures::Queue<RackspaceOperation> nextOperationQueue;
|
||||
|
||||
DataStructures::List<RackspaceOperation> operations;
|
||||
bool HasOperationOfType(RackspaceOperationType t);
|
||||
unsigned int GetOperationOfTypeIndex(RackspaceOperationType t);
|
||||
|
||||
SLNet::RakString serverManagementURL;
|
||||
SLNet::RakString serverManagementDomain;
|
||||
SLNet::RakString serverManagementPath;
|
||||
SLNet::RakString storageURL;
|
||||
SLNet::RakString storageDomain;
|
||||
SLNet::RakString storagePath;
|
||||
SLNet::RakString cdnManagementURL;
|
||||
SLNet::RakString cdnManagementDomain;
|
||||
SLNet::RakString cdnManagementPath;
|
||||
|
||||
SLNet::RakString storageToken;
|
||||
SLNet::RakString authToken;
|
||||
SLNet::RakString rackspaceCloudUsername;
|
||||
SLNet::RakString apiAccessKey;
|
||||
|
||||
bool ExecuteOperation(RackspaceOperation &ro);
|
||||
void ReadLine(const char *data, const char *stringStart, SLNet::RakString &output);
|
||||
bool ConnectToServerManagementDomain(RackspaceOperation &ro);
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif // __RACKSPACE_API_H
|
||||
|
||||
#endif // _RAKNET_SUPPORT_Rackspace
|
||||
72
Source/include/slikenet/Rand.h
Normal file
72
Source/include/slikenet/Rand.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief \b [Internal] Random number generator
|
||||
///
|
||||
|
||||
|
||||
|
||||
#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 );
|
||||
|
||||
namespace SLNet {
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
63
Source/include/slikenet/RandSync.h
Normal file
63
Source/include/slikenet/RandSync.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief \b [Internal] Random number generator
|
||||
///
|
||||
|
||||
|
||||
|
||||
#ifndef __RAND_SYNC_H
|
||||
#define __RAND_SYNC_H
|
||||
|
||||
#include "Export.h"
|
||||
#include "Rand.h"
|
||||
#include "DS_Queue.h"
|
||||
#include "NativeTypes.h"
|
||||
|
||||
namespace SLNet {
|
||||
|
||||
class BitStream;
|
||||
|
||||
class RAK_DLL_EXPORT RakNetRandomSync
|
||||
{
|
||||
public:
|
||||
RakNetRandomSync();
|
||||
virtual ~RakNetRandomSync();
|
||||
void SeedMT( uint32_t _seed );
|
||||
void SeedMT( uint32_t _seed, uint32_t skipValues );
|
||||
float FrandomMT( void );
|
||||
unsigned int RandomMT( void );
|
||||
uint32_t GetSeed( void ) const;
|
||||
uint32_t GetCallCount( void ) const;
|
||||
void SetCallCount( uint32_t i );
|
||||
|
||||
virtual void SerializeConstruction(SLNet::BitStream *constructionBitstream);
|
||||
virtual bool DeserializeConstruction(SLNet::BitStream *constructionBitstream);
|
||||
virtual void Serialize(SLNet::BitStream *outputBitstream);
|
||||
virtual void Deserialize(SLNet::BitStream *outputBitstream);
|
||||
|
||||
protected:
|
||||
void Skip( uint32_t count );
|
||||
DataStructures::Queue<unsigned int> usedValues;
|
||||
uint32_t seed;
|
||||
uint32_t callCount;
|
||||
uint32_t usedValueBufferCount;
|
||||
RakNetRandom rnr;
|
||||
};
|
||||
} // namespace SLNet
|
||||
|
||||
|
||||
#endif
|
||||
247
Source/include/slikenet/ReadyEvent.h
Normal file
247
Source/include/slikenet/ReadyEvent.h
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \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
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_ReadyEvent==1
|
||||
|
||||
#ifndef __READY_EVENT_H
|
||||
#define __READY_EVENT_H
|
||||
|
||||
#include "PluginInterface2.h"
|
||||
#include "DS_OrderedList.h"
|
||||
|
||||
namespace SLNet {
|
||||
|
||||
class RakPeerInterface;
|
||||
|
||||
/// \defgroup READY_EVENT_GROUP ReadyEvent
|
||||
/// \brief Peer to peer synchronized ready and unready events
|
||||
/// \details
|
||||
/// \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,
|
||||
};
|
||||
|
||||
/// \brief Peer to peer synchronized ready and unready events
|
||||
/// \details For peer to peer networks in a fully connected mesh.<BR>
|
||||
/// Solves the problem of how to tell if all peers, relative to all other peers, are in a certain ready state.<BR>
|
||||
/// For example, if A is connected to B and C, A may see that B and C are ready, but does not know if B is ready to C, or vice-versa.<BR>
|
||||
/// This plugin uses two stages to solve that problem, first, everyone I know about is ready. Second, everyone I know about is ready to everyone they know about.<BR>
|
||||
/// The user will get ID_READY_EVENT_SET and ID_READY_EVENT_UNSET as the signal flag is set or unset<BR>
|
||||
/// 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.<BR>
|
||||
/// \sa FullyConnectedMesh2
|
||||
/// \ingroup READY_EVENT_GROUP
|
||||
class ReadyEvent : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(ReadyEvent)
|
||||
|
||||
// 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 False if event status is ID_READY_EVENT_FORCE_ALL_SET, or if we are setting to a status we are already in (no change). Otherwise true
|
||||
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
|
||||
void 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] guid 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)
|
||||
bool AddToWaitList(int eventId, RakNetGUID guid);
|
||||
|
||||
/// 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] guid The system to remove from the wait list. Pass UNASSIGNED_RAKNET_GUID for all currently connected systems.
|
||||
/// \return True on success, false on unknown eventId (this should be considered an error)
|
||||
bool RemoveFromWaitList(int eventId, RakNetGUID guid);
|
||||
|
||||
/// Returns if a particular system is waiting on a particular event.
|
||||
/// \param[in] eventId A user-defined identifier
|
||||
/// \param[in] guid The system we are checking up on
|
||||
/// \return True if this system is waiting on this event, false otherwise.
|
||||
bool IsInWaitList(int eventId, RakNetGUID guid);
|
||||
|
||||
/// 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.
|
||||
RakNetGUID 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] guid Which system we are checking up on
|
||||
/// \return The status of this system, for this particular event. \sa ReadyEventSystemStatus
|
||||
ReadyEventSystemStatus GetReadyStatus(int eventId, RakNetGUID guid);
|
||||
|
||||
/// 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;
|
||||
RakNetGUID rakNetGuid;
|
||||
};
|
||||
static int RemoteSystemCompByGuid( const RakNetGUID &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<RakNetGUID,RemoteSystem,ReadyEvent::RemoteSystemCompByGuid> systemList;
|
||||
};
|
||||
static int ReadyEventNodeComp( const int &key, ReadyEvent::ReadyEventNode * const &data );
|
||||
|
||||
|
||||
protected:
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Packet handling functions
|
||||
// --------------------------------------------------------------------------------------------
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
virtual void OnRakPeerShutdown(void);
|
||||
|
||||
void Clear(void);
|
||||
/*
|
||||
bool AnyWaitersCompleted(unsigned eventIndex) const;
|
||||
bool AllWaitersCompleted(unsigned eventIndex) const;
|
||||
bool AllWaitersReady(unsigned eventIndex) const;
|
||||
void SendAllReady(unsigned eventId, RakNetGUID guid);
|
||||
void BroadcastAllReady(unsigned eventIndex);
|
||||
void SendReadyStateQuery(unsigned eventId, RakNetGUID guid);
|
||||
void BroadcastReadyUpdate(unsigned eventIndex);
|
||||
bool AddToWaitListInternal(unsigned eventIndex, RakNetGUID guid);
|
||||
bool IsLocked(unsigned eventIndex) const;
|
||||
bool IsAllReadyByIndex(unsigned eventIndex) const;
|
||||
*/
|
||||
|
||||
void SendReadyStateQuery(unsigned eventId, RakNetGUID guid);
|
||||
void SendReadyUpdate(unsigned eventIndex, unsigned systemIndex, bool forceIfNotDefault);
|
||||
void BroadcastReadyUpdate(unsigned eventIndex, bool forceIfNotDefault);
|
||||
void RemoveFromAllLists(RakNetGUID guid);
|
||||
void OnReadyEventQuery(Packet *packet);
|
||||
void PushCompletionPacket(unsigned eventId);
|
||||
bool AddToWaitListInternal(unsigned eventIndex, RakNetGUID guid);
|
||||
void OnReadyEventForceAllSet(Packet *packet);
|
||||
void OnReadyEventPacketUpdate(Packet *packet);
|
||||
void UpdateReadyStatus(unsigned eventIndex);
|
||||
bool IsEventCompletedByIndex(unsigned eventIndex) const;
|
||||
unsigned CreateNewEvent(int eventId, bool isReady);
|
||||
bool SetEventByIndex(int eventIndex, bool isReady);
|
||||
|
||||
DataStructures::OrderedList<int, ReadyEventNode*, ReadyEvent::ReadyEventNodeComp> readyEventNodeList;
|
||||
unsigned char channel;
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
38
Source/include/slikenet/RefCountedObj.h
Normal file
38
Source/include/slikenet/RefCountedObj.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief \b Reference counted object. Very simple class for quick and dirty uses.
|
||||
///
|
||||
|
||||
|
||||
|
||||
#ifndef __REF_COUNTED_OBJ_H
|
||||
#define __REF_COUNTED_OBJ_H
|
||||
|
||||
#include "memoryoverride.h"
|
||||
|
||||
/// World's simplest class :)
|
||||
class RefCountedObj
|
||||
{
|
||||
public:
|
||||
RefCountedObj() {refCount=1;}
|
||||
virtual ~RefCountedObj() {}
|
||||
void AddRef(void) {refCount++;}
|
||||
void Deref(void) {if (--refCount==0) SLNet::OP_DELETE(this, _FILE_AND_LINE_);}
|
||||
int refCount;
|
||||
};
|
||||
|
||||
#endif
|
||||
163
Source/include/slikenet/RelayPlugin.h
Normal file
163
Source/include/slikenet/RelayPlugin.h
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Contains the class RelayPlugin
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_RelayPlugin==1
|
||||
|
||||
#ifndef __RELAY_PLUGIN_H
|
||||
#define __RELAY_PLUGIN_H
|
||||
|
||||
#include "PluginInterface2.h"
|
||||
#include "string.h"
|
||||
#include "DS_Hash.h"
|
||||
|
||||
/// \defgroup RELAY_PLUGIN_GROUP RelayPlugin
|
||||
/// \brief A simple class to relay messages from one system to another through an intermediary
|
||||
/// \ingroup PLUGINS_GROUP
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
|
||||
enum RelayPluginEnums
|
||||
{
|
||||
// Server handled messages
|
||||
RPE_MESSAGE_TO_SERVER_FROM_CLIENT,
|
||||
RPE_ADD_CLIENT_REQUEST_FROM_CLIENT,
|
||||
RPE_REMOVE_CLIENT_REQUEST_FROM_CLIENT,
|
||||
RPE_GROUP_MESSAGE_FROM_CLIENT,
|
||||
RPE_JOIN_GROUP_REQUEST_FROM_CLIENT,
|
||||
RPE_LEAVE_GROUP_REQUEST_FROM_CLIENT,
|
||||
RPE_GET_GROUP_LIST_REQUEST_FROM_CLIENT,
|
||||
// Client handled messages
|
||||
RPE_MESSAGE_TO_CLIENT_FROM_SERVER,
|
||||
RPE_ADD_CLIENT_NOT_ALLOWED,
|
||||
RPE_ADD_CLIENT_TARGET_NOT_CONNECTED,
|
||||
RPE_ADD_CLIENT_NAME_ALREADY_IN_USE,
|
||||
RPE_ADD_CLIENT_SUCCESS,
|
||||
RPE_USER_ENTERED_ROOM,
|
||||
RPE_USER_LEFT_ROOM,
|
||||
RPE_GROUP_MSG_FROM_SERVER,
|
||||
RPE_GET_GROUP_LIST_REPLY_FROM_SERVER,
|
||||
RPE_JOIN_GROUP_SUCCESS,
|
||||
RPE_JOIN_GROUP_FAILURE,
|
||||
};
|
||||
|
||||
/// \brief A simple class to relay messages from one system to another, identifying remote systems by a string.
|
||||
/// \ingroup RELAY_PLUGIN_GROUP
|
||||
class RAK_DLL_EXPORT RelayPlugin : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(RelayPlugin)
|
||||
|
||||
/// Constructor
|
||||
RelayPlugin();
|
||||
|
||||
/// Destructor
|
||||
virtual ~RelayPlugin();
|
||||
|
||||
/// \brief Forward messages from any system, to the system specified by the combination of key and guid. The sending system only needs to know the key.
|
||||
/// \param[in] key A string to identify the target's RakNetGUID. This is so the sending system does not need to know the RakNetGUID of the target system. The key should be unique among all guids added. If the key is not unique, only one system will be sent to (at random).
|
||||
/// \param[in] guid The RakNetGuid of the system to send to. If this system disconnects, it is removed from the internal hash
|
||||
/// \return RPE_ADD_CLIENT_TARGET_NOT_CONNECTED, RPE_ADD_CLIENT_NAME_ALREADY_IN_USE, or RPE_ADD_CLIENT_OK
|
||||
RelayPluginEnums AddParticipantOnServer(const RakString &key, const RakNetGUID &guid);
|
||||
|
||||
/// \brief Remove a chat participant
|
||||
void RemoveParticipantOnServer(const RakNetGUID &guid);
|
||||
|
||||
/// \brief If true, then if the client calls AddParticipantRequestFromClient(), the server will call AddParticipantOnServer() automatically
|
||||
/// Defaults to false
|
||||
/// \param[in] accept true to accept, false to not.
|
||||
void SetAcceptAddParticipantRequests(bool accept);
|
||||
|
||||
/// \brief Request from the client for the server to call AddParticipantOnServer()
|
||||
/// \pre The server must have called SetAcceptAddParticipantRequests(true) or the request will be ignored
|
||||
/// \param[in] key A string to identify out system. Passed to \a key on AddParticipantOnServer()
|
||||
/// \param[in] relayPluginServerGuid the RakNetGUID of the system running RelayPlugin
|
||||
void AddParticipantRequestFromClient(const RakString &key, const RakNetGUID &relayPluginServerGuid);
|
||||
|
||||
/// \brief Remove yourself as a participant
|
||||
void RemoveParticipantRequestFromClient(const RakNetGUID &relayPluginServerGuid);
|
||||
|
||||
/// \brief Request that the server relay \a bitStream to the system designated by \a key
|
||||
/// \param[in] relayPluginServerGuid the RakNetGUID of the system running RelayPlugin
|
||||
/// \param[in] destinationGuid The key value passed to AddParticipant() earlier on the server. If this was not done, the server will not relay the message (it will be silently discarded).
|
||||
/// \param[in] bitStream The data to relay
|
||||
/// \param[in] priority See the parameter of the same name in RakPeerInterface::Send()
|
||||
/// \param[in] reliability See the parameter of the same name in RakPeerInterface::Send()
|
||||
/// \param[in] orderingChannel See the parameter of the same name in RakPeerInterface::Send()
|
||||
void SendToParticipant(const RakNetGUID &relayPluginServerGuid, const RakString &destinationGuid, BitStream *bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel);
|
||||
|
||||
void SendGroupMessage(const RakNetGUID &relayPluginServerGuid, BitStream *bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel);
|
||||
void JoinGroupRequest(const RakNetGUID &relayPluginServerGuid, RakString groupName);
|
||||
void LeaveGroup(const RakNetGUID &relayPluginServerGuid);
|
||||
void GetGroupList(const RakNetGUID &relayPluginServerGuid);
|
||||
|
||||
/// \internal
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
/// \internal
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
|
||||
struct StrAndGuidAndRoom
|
||||
{
|
||||
RakString str;
|
||||
RakNetGUID guid;
|
||||
RakString currentRoom;
|
||||
};
|
||||
|
||||
struct StrAndGuid
|
||||
{
|
||||
RakString str;
|
||||
RakNetGUID guid;
|
||||
};
|
||||
|
||||
struct RP_Group
|
||||
{
|
||||
RakString roomName;
|
||||
DataStructures::List<StrAndGuid> usersInRoom;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
RelayPlugin::RP_Group* JoinGroup(RakNetGUID userGuid, RakString roomName);
|
||||
RelayPlugin::RP_Group* JoinGroup(RP_Group* room, StrAndGuidAndRoom **strAndGuidSender);
|
||||
void LeaveGroup(StrAndGuidAndRoom **strAndGuidSender);
|
||||
void NotifyUsersInRoom(RP_Group *room, int msg, const RakString& message);
|
||||
void SendMessageToRoom(StrAndGuidAndRoom **strAndGuidSender, BitStream* message);
|
||||
void SendChatRoomsList(RakNetGUID target);
|
||||
void OnGroupMessageFromClient(Packet *packet);
|
||||
void OnJoinGroupRequestFromClient(Packet *packet);
|
||||
void OnLeaveGroupRequestFromClient(Packet *packet);
|
||||
|
||||
DataStructures::Hash<RakString, StrAndGuidAndRoom*, 8096, SLNet::RakString::ToInteger> strToGuidHash;
|
||||
DataStructures::Hash<RakNetGUID, StrAndGuidAndRoom*, 8096, SLNet::RakNetGUID::ToUint32> guidToStrHash;
|
||||
DataStructures::List<RP_Group*> chatRooms;
|
||||
bool acceptAddParticipantRequests;
|
||||
|
||||
};
|
||||
|
||||
} // End namespace
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
648
Source/include/slikenet/ReliabilityLayer.h
Normal file
648
Source/include/slikenet/ReliabilityLayer.h
Normal file
@ -0,0 +1,648 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief \b [Internal] Datagram reliable, ordered, unordered and sequenced sends. Flow control. Message splitting, reassembly, and coalescence.
|
||||
///
|
||||
|
||||
|
||||
#ifndef __RELIABILITY_LAYER_H
|
||||
#define __RELIABILITY_LAYER_H
|
||||
|
||||
#include "memoryoverride.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 "statistics.h"
|
||||
#include "DR_SHA1.h"
|
||||
#include "DS_OrderedList.h"
|
||||
#include "DS_RangeList.h"
|
||||
#include "DS_BPlusTree.h"
|
||||
#include "DS_MemoryPool.h"
|
||||
#include "defines.h"
|
||||
#include "DS_Heap.h"
|
||||
#include "BitStream.h"
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#include "SecureHandshake.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "Rand.h"
|
||||
#include "socket2.h"
|
||||
|
||||
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL!=1
|
||||
#include "CCRakNetUDT.h"
|
||||
#define INCLUDE_TIMESTAMP_WITH_DATAGRAMS 1
|
||||
#else
|
||||
#include "CCRakNetSlidingWindow.h"
|
||||
#define INCLUDE_TIMESTAMP_WITH_DATAGRAMS 0
|
||||
#endif
|
||||
|
||||
/// 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
|
||||
|
||||
namespace SLNet {
|
||||
|
||||
/// Forward declarations
|
||||
class PluginInterface2;
|
||||
class RakNetRandom;
|
||||
typedef uint64_t reliabilityHeapWeightType;
|
||||
|
||||
// #med - consider a more suitable name for the class / maybe even make an internal class to SplitPacketChannel?
|
||||
class SplitPacketSort
|
||||
{
|
||||
// member variables
|
||||
private:
|
||||
InternalPacket **m_data;
|
||||
size_t m_allocationSize;
|
||||
unsigned int m_addedPacketsCount;
|
||||
SplitPacketIdType m_packetId;
|
||||
|
||||
// construction/destruction
|
||||
public:
|
||||
SplitPacketSort();
|
||||
~SplitPacketSort();
|
||||
|
||||
// initialization
|
||||
public:
|
||||
void Preallocate(InternalPacket *internalPacket, const char *file, unsigned int line);
|
||||
|
||||
// accessors
|
||||
public:
|
||||
bool AllPacketsAdded() const;
|
||||
size_t GetAllocSize() const;
|
||||
unsigned int GetNumAddedPackets() const;
|
||||
SplitPacketIdType GetPacketId() const;
|
||||
|
||||
// operators
|
||||
public:
|
||||
InternalPacket*& operator[](size_t index);
|
||||
|
||||
// container operations
|
||||
public:
|
||||
bool Add(InternalPacket *internalPacket);
|
||||
};
|
||||
|
||||
// int SplitPacketIndexComp( SplitPacketIndexType const &key, InternalPacket* const &data );
|
||||
struct SplitPacketChannel//<SplitPacketChannel>
|
||||
{
|
||||
CCTimeType lastUpdateTime;
|
||||
|
||||
SplitPacketSort splitPacketList;
|
||||
|
||||
#if PREALLOCATE_LARGE_MESSAGES==1
|
||||
InternalPacket *returnedPacket;
|
||||
bool gotFirstPacket;
|
||||
unsigned int stride;
|
||||
unsigned int splitPacketsArrived;
|
||||
#else
|
||||
// This is here for progress notifications, since progress notifications return the first packet data, if available
|
||||
InternalPacket *firstPacket;
|
||||
#endif
|
||||
|
||||
};
|
||||
int RAK_DLL_EXPORT SplitPacketChannelComp( SplitPacketIdType const &key, SplitPacketChannel* const &data );
|
||||
|
||||
// Helper class
|
||||
struct BPSTracker
|
||||
{
|
||||
BPSTracker();
|
||||
~BPSTracker();
|
||||
void Reset(const char *file, unsigned int line);
|
||||
inline void Push1(CCTimeType time, uint64_t value1) {dataQueue.Push(TimeAndValue2(time,value1),_FILE_AND_LINE_); total1+=value1; lastSec1+=value1;}
|
||||
// void Push2(SLNet::TimeUS time, uint64_t value1, uint64_t value2);
|
||||
inline uint64_t GetBPS1(CCTimeType time) {(void) time; return lastSec1;}
|
||||
inline uint64_t GetBPS1Threadsafe(CCTimeType time) {(void) time; return lastSec1;}
|
||||
// uint64_t GetBPS2(RakNetTimeUS time);
|
||||
// void GetBPS1And2(RakNetTimeUS time, uint64_t &out1, uint64_t &out2);
|
||||
uint64_t GetTotal1(void) const;
|
||||
// uint64_t GetTotal2(void) const;
|
||||
|
||||
struct TimeAndValue2
|
||||
{
|
||||
TimeAndValue2();
|
||||
~TimeAndValue2();
|
||||
TimeAndValue2(CCTimeType t, uint64_t v1);
|
||||
// TimeAndValue2(SLNet::TimeUS t, uint64_t v1, uint64_t v2);
|
||||
// uint64_t value1, value2;
|
||||
uint64_t value1;
|
||||
CCTimeType time;
|
||||
};
|
||||
|
||||
uint64_t total1, lastSec1;
|
||||
// uint64_t total2, lastSec2;
|
||||
DataStructures::Queue<TimeAndValue2> dataQueue;
|
||||
void ClearExpired1(CCTimeType time);
|
||||
// void ClearExpired2(SLNet::TimeUS time);
|
||||
};
|
||||
|
||||
/// 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, int mtuSize, bool _useSecurity);
|
||||
|
||||
/// 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(SLNet::TimeMS time);
|
||||
|
||||
/// Returns the value passed to SetTimeoutTime. or the default if it was never called
|
||||
/// \param[out] the value passed to SetTimeoutTime
|
||||
SLNet::TimeMS 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<PluginInterface2*> &messageHandlerList, int mtuSize,
|
||||
RakNetSocket2 *s, RakNetRandom *rnr, CCTimeType timeRead, BitStream &updateBitStream);
|
||||
|
||||
/// 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 SLNet::GetTimeMS()
|
||||
/// \param[in] receipt This number will be returned back with ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS and is only returned with the reliability types that contain RECEIPT in the name
|
||||
/// \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, CCTimeType currentTime, uint32_t receipt );
|
||||
|
||||
/// 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( RakNetSocket2 *s, SystemAddress &systemAddress, int MTUSize, CCTimeType time,
|
||||
unsigned bitsPerSecondLimit,
|
||||
DataStructures::List<PluginInterface2*> &messageHandlerList,
|
||||
RakNetRandom *rnr, BitStream &updateBitStream );
|
||||
|
||||
// #med 0.2.0 - review whether we'd rather have this defined as a private method and declare RakPeer a friend of ReliabilityLayer
|
||||
/// @since 0.2.0: added
|
||||
/// Same as \see Update() except that outstanding ACKs are ensured to be sent.
|
||||
void UpdateAndForceACKs( RakNetSocket2 *s, SystemAddress &systemAddress, int MTUSize, CCTimeType time,
|
||||
unsigned bitsPerSecondLimit,
|
||||
DataStructures::List<PluginInterface2*> &messageHandlerList,
|
||||
RakNetRandom *rnr, BitStream &updateBitStream );
|
||||
|
||||
/// 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 * GetStatistics( RakNetStatistics *rns );
|
||||
|
||||
///Are we waiting for any data to be sent out or be processed by the player?
|
||||
bool IsOutgoingDataWaiting(void);
|
||||
bool AreAcksWaiting(void);
|
||||
|
||||
// Set outgoing lag and packet loss properties
|
||||
void ApplyNetworkSimulator( double _maxSendBPS, SLNet::TimeMS _minExtraPing, SLNet::TimeMS _extraPingVariance );
|
||||
|
||||
/// Returns if you previously called ApplyNetworkSimulator
|
||||
/// \return If you previously called ApplyNetworkSimulator
|
||||
bool IsNetworkSimulatorActive( void );
|
||||
|
||||
void SetSplitMessageProgressInterval(int interval);
|
||||
void SetUnreliableTimeout(SLNet::TimeMS timeoutMS);
|
||||
/// Has a lot of time passed since the last ack
|
||||
bool AckTimeout(SLNet::Time curTime);
|
||||
CCTimeType GetNextSendTime(void) const;
|
||||
CCTimeType GetTimeBetweenPackets(void) const;
|
||||
#if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1
|
||||
CCTimeType GetAckPing(void) const;
|
||||
#endif
|
||||
SLNet::TimeMS GetTimeLastDatagramArrived(void) const {return timeLastDatagramArrived;}
|
||||
|
||||
// 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(SLNet::BitStream *messages, int MTUSize);
|
||||
|
||||
private:
|
||||
/// 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( RakNetSocket2 *s, SystemAddress &systemAddress, SLNet::BitStream *bitStream, RakNetRandom *rnr, CCTimeType currentTime);
|
||||
|
||||
///Parse an internalPacket and create a bitstream to represent this data
|
||||
/// \return Returns number of bits used
|
||||
BitSize_t WriteToBitStreamFromInternalPacket(SLNet::BitStream *bitStream, const InternalPacket *const internalPacket, CCTimeType curTime );
|
||||
|
||||
|
||||
/// Parse a bitstream and create an internal packet to represent this data
|
||||
InternalPacket* CreateInternalPacketFromBitStream(SLNet::BitStream *bitStream, CCTimeType time );
|
||||
|
||||
/// Does what the function name says
|
||||
unsigned RemovePacketFromResendListAndDeleteOlderReliableSequenced( const MessageNumberType messageNumber, CCTimeType time, DataStructures::List<PluginInterface2*> &messageHandlerList, const SystemAddress &systemAddress );
|
||||
|
||||
/// Acknowledge receipt of the packet with the specified messageNumber
|
||||
void SendAcknowledgementPacket( const DatagramSequenceNumberType messageNumber, CCTimeType time);
|
||||
|
||||
/// This will return true if we should not send at this time
|
||||
bool IsSendThrottled( int MTUSize );
|
||||
|
||||
/// We lost a packet
|
||||
void UpdateWindowFromPacketloss( CCTimeType time );
|
||||
|
||||
/// Increase the window size
|
||||
void UpdateWindowFromAck( CCTimeType time );
|
||||
|
||||
/// Parse an internalPacket and figure out how many header bits would be written. Returns that number
|
||||
BitSize_t GetMaxMessageHeaderLengthBits( void );
|
||||
BitSize_t GetMessageHeaderLengthBits( 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 );
|
||||
|
||||
/// Insert a packet into the split packet list
|
||||
void InsertIntoSplitPacketList( InternalPacket * internalPacket, CCTimeType 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 inSplitPacketId, CCTimeType time,
|
||||
RakNetSocket2 *s, SystemAddress &systemAddress, RakNetRandom *rnr, BitStream &updateBitStream);
|
||||
InternalPacket * BuildPacketFromSplitPacketList( SplitPacketChannel *splitPacketChannel, CCTimeType time );
|
||||
|
||||
/// Delete any unreliable split packets that have long since expired
|
||||
//void DeleteOldUnreliableSplitPackets( CCTimeType 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, CCTimeType 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, CCTimeType time, bool firstResend, bool modifyUnacknowledgedBytes );
|
||||
|
||||
/// Memory handling
|
||||
void FreeMemory( bool freeAllImmediately );
|
||||
|
||||
/// 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, CCTimeType currentTime) const;
|
||||
|
||||
// Make it so we don't do resends within a minimum threshold of time
|
||||
void UpdateNextActionTime(void);
|
||||
|
||||
void UpdateInternal( RakNetSocket2 *s, SystemAddress &systemAddress, int MTUSize, CCTimeType time,
|
||||
unsigned bitsPerSecondLimit,
|
||||
DataStructures::List<PluginInterface2*> &messageHandlerList,
|
||||
RakNetRandom *rnr, BitStream &updateBitStream, bool forceSendACKs );
|
||||
|
||||
/// Does this packet number represent a packet that was skipped (out of order?)
|
||||
//unsigned int IsReceivedPacketHole(unsigned int input, SLNet::TimeMS 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;
|
||||
int splitMessageProgressInterval;
|
||||
CCTimeType unreliableTimeout;
|
||||
|
||||
struct MessageNumberNode
|
||||
{
|
||||
DatagramSequenceNumberType messageNumber;
|
||||
MessageNumberNode *next;
|
||||
};
|
||||
struct DatagramHistoryNode
|
||||
{
|
||||
DatagramHistoryNode() {}
|
||||
DatagramHistoryNode(MessageNumberNode *_head, CCTimeType ts
|
||||
) :
|
||||
head(_head), timeSent(ts)
|
||||
{}
|
||||
MessageNumberNode *head;
|
||||
CCTimeType timeSent;
|
||||
};
|
||||
// Queue length is programmatically restricted to DATAGRAM_MESSAGE_ID_ARRAY_LENGTH
|
||||
// This is essentially an O(1) lookup to get a DatagramHistoryNode given an index
|
||||
// datagramHistory holds a linked list of MessageNumberNode. Each MessageNumberNode refers to one element in resendList which can be cleared on an ack.
|
||||
DataStructures::Queue<DatagramHistoryNode> datagramHistory;
|
||||
DataStructures::MemoryPool<MessageNumberNode> datagramHistoryMessagePool;
|
||||
|
||||
struct UnreliableWithAckReceiptNode
|
||||
{
|
||||
UnreliableWithAckReceiptNode() {}
|
||||
UnreliableWithAckReceiptNode(DatagramSequenceNumberType _datagramNumber, uint32_t _sendReceiptSerial, SLNet::TimeUS _nextActionTime) :
|
||||
datagramNumber(_datagramNumber), sendReceiptSerial(_sendReceiptSerial), nextActionTime(_nextActionTime)
|
||||
{}
|
||||
DatagramSequenceNumberType datagramNumber;
|
||||
uint32_t sendReceiptSerial;
|
||||
SLNet::TimeUS nextActionTime;
|
||||
};
|
||||
DataStructures::List<UnreliableWithAckReceiptNode> unreliableWithAckReceiptHistory;
|
||||
|
||||
void RemoveFromDatagramHistory(DatagramSequenceNumberType index);
|
||||
MessageNumberNode* GetMessageNumberNodeByDatagramIndex(DatagramSequenceNumberType index, CCTimeType *timeSent);
|
||||
void AddFirstToDatagramHistory(DatagramSequenceNumberType datagramNumber, CCTimeType timeSent);
|
||||
MessageNumberNode* AddFirstToDatagramHistory(DatagramSequenceNumberType datagramNumber, DatagramSequenceNumberType messageNumber, CCTimeType timeSent);
|
||||
MessageNumberNode* AddSubsequentToDatagramHistory(MessageNumberNode *messageNumberNode, DatagramSequenceNumberType messageNumber);
|
||||
DatagramSequenceNumberType datagramHistoryPopCount;
|
||||
|
||||
DataStructures::MemoryPool<InternalPacket> internalPacketPool;
|
||||
// DataStructures::BPlusTree<DatagramSequenceNumberType, InternalPacket*, RESEND_TREE_ORDER> resendTree;
|
||||
InternalPacket *resendBuffer[RESEND_BUFFER_ARRAY_LENGTH];
|
||||
InternalPacket *resendLinkedListHead;
|
||||
InternalPacket *unreliableLinkedListHead;
|
||||
void RemoveFromUnreliableLinkedList(InternalPacket *internalPacket);
|
||||
void AddToUnreliableLinkedList(InternalPacket *internalPacket);
|
||||
// unsigned int numPacketsOnResendBuffer;
|
||||
//unsigned int blockWindowIncreaseUntilTime;
|
||||
// DataStructures::RangeList<DatagramSequenceNumberType> acknowlegements;
|
||||
// Resend list is a tree of packets we need to resend
|
||||
|
||||
// Set to the current time when the resend queue is no longer empty
|
||||
// Set to zero when it becomes empty
|
||||
// Set to the current time if it is not zero, and we get incoming data
|
||||
// If the current time - timeResendQueueNonEmpty is greater than a threshold, we are disconnected
|
||||
// CCTimeType timeResendQueueNonEmpty;
|
||||
SLNet::TimeMS timeLastDatagramArrived;
|
||||
|
||||
|
||||
// If we backoff due to packetloss, don't remeasure until all waiting resends have gone out or else we overcount
|
||||
// bool packetlossThisSample;
|
||||
// int backoffThisSample;
|
||||
// unsigned packetlossThisSampleResendCount;
|
||||
// CCTimeType lastPacketlossTime;
|
||||
|
||||
//DataStructures::Queue<InternalPacket*> sendPacketSet[ NUMBER_OF_PRIORITIES ];
|
||||
DataStructures::Heap<reliabilityHeapWeightType, InternalPacket*, false> outgoingPacketBuffer;
|
||||
reliabilityHeapWeightType outgoingPacketBufferNextWeights[NUMBER_OF_PRIORITIES];
|
||||
void InitHeapWeights(void);
|
||||
reliabilityHeapWeightType GetNextWeight(int priorityLevel);
|
||||
// unsigned int messageInSendBuffer[NUMBER_OF_PRIORITIES];
|
||||
// double bytesInSendBuffer[NUMBER_OF_PRIORITIES];
|
||||
|
||||
|
||||
DataStructures::OrderedList<SplitPacketIdType, SplitPacketChannel*, SplitPacketChannelComp> splitPacketChannelList;
|
||||
|
||||
MessageNumberType sendReliableMessageNumberIndex;
|
||||
MessageNumberType internalOrderIndex;
|
||||
//unsigned int windowSize;
|
||||
//SLNet::BitStream updateBitStream;
|
||||
bool deadConnection, cheater;
|
||||
SplitPacketIdType splitPacketId;
|
||||
SLNet::TimeMS 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;
|
||||
RakNetStatistics statistics;
|
||||
|
||||
// Algorithm for blending ordered and sequenced on the same channel:
|
||||
// 1. Each ordered message transmits OrderingIndexType orderedWriteIndex. There are NUMBER_OF_ORDERED_STREAMS independent values of these. The value
|
||||
// starts at 0. Every time an ordered message is sent, the value increments by 1
|
||||
// 2. Each sequenced message contains the current value of orderedWriteIndex for that channel, and additionally OrderingIndexType sequencedWriteIndex.
|
||||
// sequencedWriteIndex resets to 0 every time orderedWriteIndex increments. It increments by 1 every time a sequenced message is sent.
|
||||
// 3. The receiver maintains the next expected value for the orderedWriteIndex, stored in orderedReadIndex.
|
||||
// 4. As messages arrive:
|
||||
// If a message has the current ordering index, and is sequenced, and is < the current highest sequence value, discard
|
||||
// If a message has the current ordering index, and is sequenced, and is >= the current highest sequence value, return immediately
|
||||
// If a message has a greater ordering index, and is sequenced or ordered, buffer it
|
||||
// If a message has the current ordering index, and is ordered, buffer, then push off messages from buffer
|
||||
// 5. Pushing off messages from buffer:
|
||||
// Messages in buffer are put in a minheap. The value of each node is calculated such that messages are returned:
|
||||
// A. (lowest ordering index, lowest sequence index)
|
||||
// B. (lowest ordering index, no sequence index)
|
||||
// Messages are pushed off until the heap is empty, or the next message to be returned does not preserve the ordered index
|
||||
// For an empty heap, the heap weight should start at the lowest value based on the next expected ordering index, to avoid variable overflow
|
||||
|
||||
// Sender increments this by 1 for every ordered message sent
|
||||
OrderingIndexType orderedWriteIndex[NUMBER_OF_ORDERED_STREAMS];
|
||||
// Sender increments by 1 for every sequenced message sent. Resets to 0 when an ordered message is sent
|
||||
OrderingIndexType sequencedWriteIndex[NUMBER_OF_ORDERED_STREAMS];
|
||||
// Next expected index for ordered messages.
|
||||
OrderingIndexType orderedReadIndex[NUMBER_OF_ORDERED_STREAMS];
|
||||
// Highest value received for sequencedWriteIndex for the current value of orderedReadIndex on the same channel.
|
||||
OrderingIndexType highestSequencedReadIndex[NUMBER_OF_ORDERED_STREAMS];
|
||||
DataStructures::Heap<reliabilityHeapWeightType, InternalPacket*, false> orderingHeaps[NUMBER_OF_ORDERED_STREAMS];
|
||||
OrderingIndexType heapIndexOffsets[NUMBER_OF_ORDERED_STREAMS];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// CCTimeType 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<CCTimeType> hasReceivedPacketQueue;
|
||||
DataStructures::Queue<bool> hasReceivedPacketQueue;
|
||||
DatagramSequenceNumberType receivedPacketsBaseIndex;
|
||||
bool resetReceivedPackets;
|
||||
|
||||
CCTimeType lastUpdateTime;
|
||||
CCTimeType timeBetweenPackets, nextSendTime;
|
||||
#if INCLUDE_TIMESTAMP_WITH_DATAGRAMS==1
|
||||
CCTimeType ackPing;
|
||||
#endif
|
||||
// CCTimeType ackPingSamples[ACK_PING_SAMPLES_SIZE]; // Must be range of unsigned char to wrap ackPingIndex properly
|
||||
CCTimeType ackPingSum;
|
||||
unsigned char ackPingIndex;
|
||||
//CCTimeType nextLowestPingReset;
|
||||
RemoteSystemTimeType remoteSystemTime;
|
||||
// bool continuousSend;
|
||||
// CCTimeType 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.
|
||||
CCTimeType nextAllowedThroughputSample;
|
||||
bool bandwidthExceededStatistic;
|
||||
|
||||
// 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;
|
||||
|
||||
unsigned receivePacketCount;
|
||||
|
||||
#ifdef _DEBUG
|
||||
struct DataAndTime//<InternalPacket>
|
||||
{
|
||||
RakNetSocket2 *s;
|
||||
char data[ MAXIMUM_MTU_SIZE ];
|
||||
unsigned int length;
|
||||
SLNet::TimeMS sendTime;
|
||||
// SystemAddress systemAddress;
|
||||
unsigned short remotePortRakNetWasStartedOn_PS3;
|
||||
unsigned int extraSocketOptions;
|
||||
};
|
||||
DataStructures::Queue<DataAndTime*> delayList;
|
||||
|
||||
// Internet simulator
|
||||
double packetloss;
|
||||
SLNet::TimeMS minExtraPing, extraPingVariance;
|
||||
#endif
|
||||
|
||||
CCTimeType elapsedTimeSinceLastUpdate;
|
||||
|
||||
CCTimeType nextAckTimeToSend;
|
||||
|
||||
|
||||
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL==1
|
||||
SLNet::CCRakNetSlidingWindow congestionManager;
|
||||
#else
|
||||
SLNet::CCRakNetUDT congestionManager;
|
||||
#endif
|
||||
|
||||
|
||||
uint32_t unacknowledgedBytes;
|
||||
|
||||
bool ResendBufferOverflow(void) const;
|
||||
void ValidateResendList(void) const;
|
||||
void ResetPacketsAndDatagrams(void);
|
||||
void PushPacket(CCTimeType time, InternalPacket *internalPacket, bool isReliable);
|
||||
void PushDatagram(void);
|
||||
bool TagMostRecentPushAsSecondOfPacketPair(void);
|
||||
void ClearPacketsAndDatagrams(void);
|
||||
void MoveToListHead(InternalPacket *internalPacket);
|
||||
void RemoveFromList(InternalPacket *internalPacket, bool modifyUnacknowledgedBytes);
|
||||
void AddToListTail(InternalPacket *internalPacket, bool modifyUnacknowledgedBytes);
|
||||
void PopListHead(bool modifyUnacknowledgedBytes);
|
||||
bool IsResendQueueEmpty(void) const;
|
||||
void SortSplitPacketList(DataStructures::List<InternalPacket*> &data, unsigned int leftEdge, unsigned int rightEdge) const;
|
||||
void SendACKs(RakNetSocket2 *s, SystemAddress &systemAddress, CCTimeType time, RakNetRandom *rnr, BitStream &updateBitStream);
|
||||
|
||||
DataStructures::List<InternalPacket*> packetsToSendThisUpdate;
|
||||
DataStructures::List<bool> packetsToDeallocThisUpdate;
|
||||
// boundary is in packetsToSendThisUpdate, inclusive
|
||||
DataStructures::List<unsigned int> packetsToSendThisUpdateDatagramBoundaries;
|
||||
DataStructures::List<bool> datagramsToSendThisUpdateIsPair;
|
||||
DataStructures::List<unsigned int> datagramSizesInBytes;
|
||||
BitSize_t datagramSizeSoFar;
|
||||
BitSize_t allDatagramSizesSoFar;
|
||||
double totalUserDataBytesAcked;
|
||||
CCTimeType timeOfLastContinualSend;
|
||||
CCTimeType timeToNextUnreliableCull;
|
||||
|
||||
// This doesn't need to be a member, but I do it to avoid reallocations
|
||||
DataStructures::RangeList<DatagramSequenceNumberType> incomingAcks;
|
||||
|
||||
// Every 16 datagrams, we make sure the 17th datagram goes out the same update tick, and is the same size as the 16th
|
||||
int countdownToNextPacketPair;
|
||||
InternalPacket* AllocateFromInternalPacketPool(void);
|
||||
void ReleaseToInternalPacketPool(InternalPacket *ip);
|
||||
|
||||
DataStructures::RangeList<DatagramSequenceNumberType> acknowlegements;
|
||||
DataStructures::RangeList<DatagramSequenceNumberType> NAKs;
|
||||
bool remoteSystemNeedsBAndAS;
|
||||
|
||||
unsigned int GetMaxDatagramSizeExcludingMessageHeaderBytes(void);
|
||||
BitSize_t GetMaxDatagramSizeExcludingMessageHeaderBits(void);
|
||||
|
||||
// ourOffset refers to a section within externallyAllocatedPtr. Do not deallocate externallyAllocatedPtr until all references are lost
|
||||
void AllocInternalPacketData(InternalPacket *internalPacket, InternalPacketRefCountedData **refCounter, unsigned char *externallyAllocatedPtr, unsigned char *ourOffset);
|
||||
// Set the data pointer to externallyAllocatedPtr, do not allocate
|
||||
void AllocInternalPacketData(InternalPacket *internalPacket, unsigned char *externallyAllocatedPtr);
|
||||
// Allocate new
|
||||
void AllocInternalPacketData(InternalPacket *internalPacket, unsigned int numBytes, bool allowStack, const char *file, unsigned int line);
|
||||
void FreeInternalPacketData(InternalPacket *internalPacket, const char *file, unsigned int line);
|
||||
DataStructures::MemoryPool<InternalPacketRefCountedData> refCountedDataPool;
|
||||
|
||||
BPSTracker bpsMetrics[RNS_PER_SECOND_METRICS_COUNT];
|
||||
CCTimeType lastBpsClear;
|
||||
|
||||
#if LIBCAT_SECURITY==1
|
||||
public:
|
||||
cat::AuthenticatedEncryption* GetAuthenticatedEncryption(void) { return &auth_enc; }
|
||||
|
||||
protected:
|
||||
cat::AuthenticatedEncryption auth_enc;
|
||||
bool useSecurity;
|
||||
#endif // LIBCAT_SECURITY
|
||||
};
|
||||
|
||||
} // namespace SLNet
|
||||
|
||||
#endif
|
||||
51
Source/include/slikenet/ReplicaEnums.h
Normal file
51
Source/include/slikenet/ReplicaEnums.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Contains enumerations used by the ReplicaManager system. This file is a lightweight header, so you can include it without worrying about linking in lots of other crap
|
||||
///
|
||||
|
||||
|
||||
|
||||
#ifndef __REPLICA_ENUMS_H
|
||||
#define __REPLICA_ENUMS_H
|
||||
|
||||
/// Replica interface flags, used to enable and disable function calls on the Replica object
|
||||
/// Passed to ReplicaManager::EnableReplicaInterfaces and ReplicaManager::DisableReplicaInterfaces
|
||||
enum
|
||||
{
|
||||
REPLICA_RECEIVE_DESTRUCTION=1<<0,
|
||||
REPLICA_RECEIVE_SERIALIZE=1<<1,
|
||||
REPLICA_RECEIVE_SCOPE_CHANGE=1<<2,
|
||||
REPLICA_SEND_CONSTRUCTION=1<<3,
|
||||
REPLICA_SEND_DESTRUCTION=1<<4,
|
||||
REPLICA_SEND_SCOPE_CHANGE=1<<5,
|
||||
REPLICA_SEND_SERIALIZE=1<<6,
|
||||
REPLICA_SET_ALL = 0xFF // Allow all of the above
|
||||
};
|
||||
|
||||
enum ReplicaReturnResult
|
||||
{
|
||||
/// This means call the function again later, with the same parameters
|
||||
REPLICA_PROCESS_LATER,
|
||||
/// This means we are done processing (the normal result to return)
|
||||
REPLICA_PROCESSING_DONE,
|
||||
/// This means cancel the processing - don't send any network messages and don't change the current state.
|
||||
REPLICA_CANCEL_PROCESS,
|
||||
/// Same as REPLICA_PROCESSING_DONE, where a message is sent, but does not clear the send bit.
|
||||
/// Useful for multi-part sends with different reliability levels.
|
||||
/// Only currently used by Replica::Serialize
|
||||
REPLICA_PROCESS_AGAIN,
|
||||
/// Only returned from the Replica::SendConstruction interface, means act as if the other system had this object but don't actually
|
||||
/// Send a construction packet. This way you will still send scope and serialize packets to that system
|
||||
REPLICA_PROCESS_IMPLICIT
|
||||
};
|
||||
|
||||
#endif
|
||||
1147
Source/include/slikenet/ReplicaManager3.h
Normal file
1147
Source/include/slikenet/ReplicaManager3.h
Normal file
File diff suppressed because it is too large
Load Diff
208
Source/include/slikenet/Router2.h
Normal file
208
Source/include/slikenet/Router2.h
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/// \file
|
||||
/// \brief Router2 plugin. Allows you to connect to a system by routing packets through another system that is connected to both you and the destination. Useful for getting around NATs.
|
||||
///
|
||||
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
#if _RAKNET_SUPPORT_Router2==1 && _RAKNET_SUPPORT_UDPForwarder==1
|
||||
|
||||
#ifndef __ROUTER_2_PLUGIN_H
|
||||
#define __ROUTER_2_PLUGIN_H
|
||||
|
||||
#include "types.h"
|
||||
#include "PluginInterface2.h"
|
||||
#include "PacketPriority.h"
|
||||
#include "Export.h"
|
||||
#include "UDPForwarder.h"
|
||||
#include "MessageIdentifiers.h"
|
||||
#include "DS_List.h"
|
||||
#include "SimpleMutex.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
/// Forward declarations
|
||||
class RakPeerInterface;
|
||||
|
||||
struct Router2DebugInterface
|
||||
{
|
||||
Router2DebugInterface() {}
|
||||
virtual ~Router2DebugInterface() {}
|
||||
virtual void ShowFailure(const char *message);
|
||||
virtual void ShowDiagnostic(const char *message);
|
||||
};
|
||||
|
||||
/// \defgroup ROUTER_2_GROUP Router2
|
||||
/// \brief Part of the NAT punchthrough solution, allowing you to connect to systems by routing through a shared connection.
|
||||
/// \details Router2 routes datagrams between two systems that are not directly connected by using the bandwidth of a third system, to which the other two systems were connected
|
||||
/// It is of benefit when a fully connected mesh topology is desired, but could not be completely established due to routers and/or firewalls
|
||||
/// As the system address of a remote system will be the system address of the intermediary, it is necessary to use the RakNetGUID object to refer to systems, including with other plugins
|
||||
/// \ingroup PLUGINS_GROUP
|
||||
|
||||
/// \ingroup ROUTER_2_GROUP
|
||||
/// \brief Class interface for the Router2 system
|
||||
/// \details
|
||||
class RAK_DLL_EXPORT Router2 : public PluginInterface2
|
||||
{
|
||||
public:
|
||||
// GetInstance() and DestroyInstance(instance*)
|
||||
STATIC_FACTORY_DECLARATIONS(Router2)
|
||||
|
||||
Router2();
|
||||
virtual ~Router2();
|
||||
|
||||
/// Sets the socket family to use, either IPV4 or IPV6
|
||||
/// \param[in] socketFamily For IPV4, use AF_INET (default). For IPV6, use AF_INET6. To autoselect, use AF_UNSPEC.
|
||||
void SetSocketFamily(unsigned short _socketFamily);
|
||||
|
||||
/// \brief Query all connected systems to connect through them to a third system.
|
||||
/// System will return ID_ROUTER_2_FORWARDING_NO_PATH if unable to connect.
|
||||
/// Else you will get ID_ROUTER_2_FORWARDING_ESTABLISHED
|
||||
///
|
||||
/// On ID_ROUTER_2_FORWARDING_ESTABLISHED, EstablishRouting as follows:
|
||||
///
|
||||
/// SLNet::BitStream bs(packet->data, packet->length, false);
|
||||
/// bs.IgnoreBytes(sizeof(MessageID));
|
||||
/// RakNetGUID endpointGuid;
|
||||
/// bs.Read(endpointGuid);
|
||||
/// unsigned short sourceToDestPort;
|
||||
/// bs.Read(sourceToDestPort);
|
||||
/// char ipAddressString[32];
|
||||
/// packet->systemAddress.ToString(false, ipAddressString);
|
||||
/// rakPeerInterface->EstablishRouting(ipAddressString, sourceToDestPort, 0,0);
|
||||
///
|
||||
/// \note The SystemAddress for a connection should not be used - always use RakNetGuid as the address can change at any time.
|
||||
/// When the address changes, you will get ID_ROUTER_2_REROUTED
|
||||
void EstablishRouting(RakNetGUID endpointGuid);
|
||||
|
||||
/// Set the maximum number of bidirectional connections this system will support
|
||||
/// Defaults to 0
|
||||
void SetMaximumForwardingRequests(int max);
|
||||
|
||||
/// For testing and debugging
|
||||
void SetDebugInterface(Router2DebugInterface *_debugInterface);
|
||||
|
||||
/// Get the pointer passed to SetDebugInterface()
|
||||
Router2DebugInterface *GetDebugInterface(void) const;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Packet handling functions
|
||||
// --------------------------------------------------------------------------------------------
|
||||
virtual PluginReceiveResult OnReceive(Packet *packet);
|
||||
virtual void Update(void);
|
||||
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
|
||||
virtual void OnFailedConnectionAttempt(Packet *packet, PI2_FailedConnectionAttemptReason failedConnectionAttemptReason);
|
||||
virtual void OnRakPeerShutdown(void);
|
||||
|
||||
|
||||
enum Router2RequestStates
|
||||
{
|
||||
R2RS_REQUEST_STATE_QUERY_FORWARDING,
|
||||
REQUEST_STATE_REQUEST_FORWARDING,
|
||||
};
|
||||
|
||||
struct ConnectionRequestSystem
|
||||
{
|
||||
RakNetGUID guid;
|
||||
int pingToEndpoint;
|
||||
unsigned short usedForwardingEntries;
|
||||
};
|
||||
|
||||
struct ConnnectRequest
|
||||
{
|
||||
ConnnectRequest();
|
||||
~ConnnectRequest();
|
||||
|
||||
DataStructures::List<ConnectionRequestSystem> connectionRequestSystems;
|
||||
SimpleMutex connectionRequestSystemsMutex;
|
||||
Router2RequestStates requestState;
|
||||
SLNet::TimeMS pingTimeout;
|
||||
RakNetGUID endpointGuid;
|
||||
RakNetGUID lastRequestedForwardingSystem;
|
||||
bool returnConnectionLostOnFailure;
|
||||
unsigned int GetGuidIndex(RakNetGUID guid);
|
||||
};
|
||||
|
||||
unsigned int GetConnectionRequestIndex(RakNetGUID endpointGuid);
|
||||
|
||||
struct MiniPunchRequest
|
||||
{
|
||||
RakNetGUID endpointGuid;
|
||||
SystemAddress endpointAddress;
|
||||
bool gotReplyFromEndpoint;
|
||||
RakNetGUID sourceGuid;
|
||||
SystemAddress sourceAddress;
|
||||
bool gotReplyFromSource;
|
||||
SLNet::TimeMS timeout;
|
||||
SLNet::TimeMS nextAction;
|
||||
unsigned short forwardingPort;
|
||||
__UDPSOCKET__ forwardingSocket;
|
||||
};
|
||||
|
||||
struct ForwardedConnection
|
||||
{
|
||||
RakNetGUID endpointGuid;
|
||||
RakNetGUID intermediaryGuid;
|
||||
SystemAddress intermediaryAddress;
|
||||
bool returnConnectionLostOnFailure;
|
||||
bool weInitiatedForwarding;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
bool UpdateForwarding(ConnnectRequest* connectionRequest);
|
||||
void RemoveConnectionRequest(unsigned int connectionRequestIndex);
|
||||
void RequestForwarding(ConnnectRequest* connectionRequest);
|
||||
void OnQueryForwarding(Packet *packet);
|
||||
void OnQueryForwardingReply(Packet *packet);
|
||||
void OnRequestForwarding(Packet *packet);
|
||||
void OnRerouted(Packet *packet);
|
||||
void OnMiniPunchReply(Packet *packet);
|
||||
void OnMiniPunchReplyBounce(Packet *packet);
|
||||
bool OnForwardingSuccess(Packet *packet);
|
||||
int GetLargestPingAmongConnectedSystems(void) const;
|
||||
void ReturnToUser(MessageID messageId, RakNetGUID endpointGuid, const SystemAddress &systemAddress, bool wasGeneratedLocally);
|
||||
bool ConnectInternal(RakNetGUID endpointGuid, bool returnConnectionLostOnFailure);
|
||||
|
||||
UDPForwarder *udpForwarder;
|
||||
int maximumForwardingRequests;
|
||||
SimpleMutex connectionRequestsMutex, miniPunchesInProgressMutex, forwardedConnectionListMutex;
|
||||
DataStructures::List<ConnnectRequest*> connectionRequests;
|
||||
DataStructures::List<MiniPunchRequest> miniPunchesInProgress;
|
||||
// Forwarding we have initiated
|
||||
DataStructures::List<ForwardedConnection> forwardedConnectionList;
|
||||
|
||||
void ClearConnectionRequests(void);
|
||||
void ClearMinipunches(void);
|
||||
void ClearForwardedConnections(void);
|
||||
void ClearAll(void);
|
||||
int ReturnFailureOnCannotForward(RakNetGUID sourceGuid, RakNetGUID endpointGuid);
|
||||
void SendFailureOnCannotForward(RakNetGUID sourceGuid, RakNetGUID endpointGuid);
|
||||
void SendForwardingSuccess(MessageID messageId, RakNetGUID sourceGuid, RakNetGUID endpointGuid, unsigned short sourceToDstPort);
|
||||
void SendOOBFromRakNetPort(OutOfBandIdentifiers oob, BitStream *extraData, SystemAddress sa);
|
||||
void SendOOBFromSpecifiedSocket(OutOfBandIdentifiers oob, SystemAddress sa, __UDPSOCKET__ socket);
|
||||
void SendOOBMessages(MiniPunchRequest *mpr);
|
||||
|
||||
Router2DebugInterface *debugInterface;
|
||||
unsigned short socketFamily;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _RAKNET_SUPPORT_*
|
||||
41
Source/include/slikenet/SecureHandshake.h
Normal file
41
Source/include/slikenet/SecureHandshake.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
/// \file
|
||||
///
|
||||
|
||||
|
||||
#ifndef SECURE_HANDSHAKE_H
|
||||
#define SECURE_HANDSHAKE_H
|
||||
|
||||
#include "NativeFeatureIncludes.h"
|
||||
|
||||
#if LIBCAT_SECURITY==1
|
||||
|
||||
// If building a RakNet DLL, be sure to tweak the CAT_EXPORT macro meaning
|
||||
#if !defined(_RAKNET_LIB) && defined(_RAKNET_DLL)
|
||||
# define CAT_BUILD_DLL
|
||||
#else
|
||||
# define CAT_NEUTER_EXPORT
|
||||
#endif
|
||||
|
||||
// Include DependentExtensions in your path to include this
|
||||
#ifdef _M_X64
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4838)
|
||||
#endif
|
||||
#include "cat/AllTunnel.hpp"
|
||||
#ifdef _M_X64
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // LIBCAT_SECURITY
|
||||
|
||||
#endif // SECURE_HANDSHAKE_H
|
||||
62
Source/include/slikenet/SendToThread.h
Normal file
62
Source/include/slikenet/SendToThread.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
||||
*
|
||||
*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifndef __SENDTO_THREAD
|
||||
#define __SENDTO_THREAD
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#ifdef USE_THREADED_SEND
|
||||
|
||||
#include "InternalPacket.h"
|
||||
#include "SocketLayer.h"
|
||||
#include "DS_ThreadsafeAllocatingQueue.h"
|
||||
#include "ThreadPool.h"
|
||||
|
||||
namespace SLNet
|
||||
{
|
||||
class SendToThread
|
||||
{
|
||||
public:
|
||||
SendToThread();
|
||||
~SendToThread();
|
||||
|
||||
struct SendToThreadBlock
|
||||
{
|
||||
SOCKET s;
|
||||
SystemAddress systemAddress;
|
||||
unsigned short remotePortRakNetWasStartedOn_PS3;
|
||||
unsigned int extraSocketOptions;
|
||||
char data[MAXIMUM_MTU_SIZE];
|
||||
unsigned short dataWriteOffset;
|
||||
};
|
||||
|
||||
static SendToThreadBlock* AllocateBlock(void);
|
||||
static void ProcessBlock(SendToThreadBlock* threadedSend);
|
||||
|
||||
static void AddRef(void);
|
||||
static void Deref(void);
|
||||
static DataStructures::ThreadsafeAllocatingQueue<SendToThreadBlock> objectQueue;
|
||||
protected:
|
||||
static int refCount;
|
||||
static ThreadPool<SendToThreadBlock*,SendToThreadBlock*> threadPool;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user