Public release of the DLU server code!

Have fun!
This commit is contained in:
Unknown
2021-12-05 18:54:36 +01:00
parent 5f7270e4ad
commit 0545adfac3
1146 changed files with 368646 additions and 1 deletions

1597
thirdparty/SQLite/CppSQLite3.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

326
thirdparty/SQLite/CppSQLite3.h vendored Normal file
View File

@@ -0,0 +1,326 @@
////////////////////////////////////////////////////////////////////////////////
// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.
//
// Copyright (c) 2004..2007 Rob Groves. All Rights Reserved. rob.groves@btinternet.com
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement, is hereby granted, provided that the above copyright notice,
// this paragraph and the following two paragraphs appear in all copies,
// modifications, and distributions.
//
// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
//
// V3.0 03/08/2004 -Initial Version for sqlite3
//
// V3.1 16/09/2004 -Implemented getXXXXField using sqlite3 functions
// -Added CppSQLiteDB3::tableExists()
//
// V3.2 01/07/2005 -Fixed execScalar to handle a NULL result
// 12/07/2007 -Added CppSQLiteDB::IsAutoCommitOn()
// -Added int64 functions to CppSQLite3Query
// -Added Name based parameter binding to CppSQLite3Statement.
////////////////////////////////////////////////////////////////////////////////
#ifndef _CppSQLite3_H_
#define _CppSQLite3_H_
#include "sqlite3.h"
#include <cstdio>
#include <cstring>
#define CPPSQLITE_ERROR 1000
class CppSQLite3Exception
{
public:
CppSQLite3Exception(const int nErrCode,
char* szErrMess,
bool bDeleteMsg=true);
CppSQLite3Exception(const CppSQLite3Exception& e);
virtual ~CppSQLite3Exception();
const int errorCode() { return mnErrCode; }
const char* errorMessage() { return mpszErrMess; }
static const char* errorCodeAsString(int nErrCode);
private:
int mnErrCode;
char* mpszErrMess;
};
class CppSQLite3Buffer
{
public:
CppSQLite3Buffer();
~CppSQLite3Buffer();
const char* format(const char* szFormat, ...);
operator const char*() { return mpBuf; }
void clear();
private:
char* mpBuf;
};
class CppSQLite3Binary
{
public:
CppSQLite3Binary();
~CppSQLite3Binary();
void setBinary(const unsigned char* pBuf, int nLen);
void setEncoded(const unsigned char* pBuf);
const unsigned char* getEncoded();
const unsigned char* getBinary();
int getBinaryLength();
unsigned char* allocBuffer(int nLen);
void clear();
private:
unsigned char* mpBuf;
int mnBinaryLen;
int mnBufferLen;
int mnEncodedLen;
bool mbEncoded;
};
class CppSQLite3Query
{
public:
CppSQLite3Query();
CppSQLite3Query(const CppSQLite3Query& rQuery);
CppSQLite3Query(sqlite3* pDB,
sqlite3_stmt* pVM,
bool bEof,
bool bOwnVM=true);
CppSQLite3Query& operator=(const CppSQLite3Query& rQuery);
virtual ~CppSQLite3Query();
int numFields();
int fieldIndex(const char* szField);
const char* fieldName(int nCol);
const char* fieldDeclType(int nCol);
int fieldDataType(int nCol);
const char* fieldValue(int nField);
const char* fieldValue(const char* szField);
int getIntField(int nField, int nNullValue=0);
int getIntField(const char* szField, int nNullValue=0);
sqlite_int64 getInt64Field(int nField, sqlite_int64 nNullValue=0);
sqlite_int64 getInt64Field(const char* szField, sqlite_int64 nNullValue=0);
double getFloatField(int nField, double fNullValue=0.0);
double getFloatField(const char* szField, double fNullValue=0.0);
const char* getStringField(int nField, const char* szNullValue="");
const char* getStringField(const char* szField, const char* szNullValue="");
const unsigned char* getBlobField(int nField, int& nLen);
const unsigned char* getBlobField(const char* szField, int& nLen);
bool fieldIsNull(int nField);
bool fieldIsNull(const char* szField);
bool eof();
void nextRow();
void finalize();
private:
void checkVM();
sqlite3* mpDB;
sqlite3_stmt* mpVM;
bool mbEof;
int mnCols;
bool mbOwnVM;
};
class CppSQLite3Table
{
public:
CppSQLite3Table();
CppSQLite3Table(const CppSQLite3Table& rTable);
CppSQLite3Table(char** paszResults, int nRows, int nCols);
virtual ~CppSQLite3Table();
CppSQLite3Table& operator=(const CppSQLite3Table& rTable);
int numFields();
int numRows();
const char* fieldName(int nCol);
const char* fieldValue(int nField);
const char* fieldValue(const char* szField);
int getIntField(int nField, int nNullValue=0);
int getIntField(const char* szField, int nNullValue=0);
double getFloatField(int nField, double fNullValue=0.0);
double getFloatField(const char* szField, double fNullValue=0.0);
const char* getStringField(int nField, const char* szNullValue="");
const char* getStringField(const char* szField, const char* szNullValue="");
bool fieldIsNull(int nField);
bool fieldIsNull(const char* szField);
void setRow(int nRow);
void finalize();
private:
void checkResults();
int mnCols;
int mnRows;
int mnCurrentRow;
char** mpaszResults;
};
class CppSQLite3Statement
{
public:
CppSQLite3Statement();
CppSQLite3Statement(const CppSQLite3Statement& rStatement);
CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM);
virtual ~CppSQLite3Statement();
CppSQLite3Statement& operator=(const CppSQLite3Statement& rStatement);
int execDML();
CppSQLite3Query execQuery();
void bind(int nParam, const char* szValue);
void bind(int nParam, const int nValue);
void bind(int nParam, const double dwValue);
void bind(int nParam, const unsigned char* blobValue, int nLen);
void bindNull(int nParam);
int bindParameterIndex(const char* szParam);
void bind(const char* szParam, const char* szValue);
void bind(const char* szParam, const int nValue);
void bind(const char* szParam, const double dwValue);
void bind(const char* szParam, const unsigned char* blobValue, int nLen);
void bindNull(const char* szParam);
void reset();
void finalize();
private:
void checkDB();
void checkVM();
sqlite3* mpDB;
sqlite3_stmt* mpVM;
};
class CppSQLite3DB
{
public:
CppSQLite3DB();
virtual ~CppSQLite3DB();
void open(const char* szFile);
void close();
bool tableExists(const char* szTable);
int execDML(const char* szSQL);
CppSQLite3Query execQuery(const char* szSQL);
int execScalar(const char* szSQL, int nNullValue=0);
CppSQLite3Table getTable(const char* szSQL);
CppSQLite3Statement compileStatement(const char* szSQL);
sqlite_int64 lastRowId();
void interrupt() { sqlite3_interrupt(mpDB); }
void setBusyTimeout(int nMillisecs);
static const char* SQLiteVersion() { return SQLITE_VERSION; }
static const char* SQLiteHeaderVersion() { return SQLITE_VERSION; }
static const char* SQLiteLibraryVersion() { return sqlite3_libversion(); }
static int SQLiteLibraryVersionNumber() { return sqlite3_libversion_number(); }
bool IsAutoCommitOn();
private:
CppSQLite3DB(const CppSQLite3DB& db);
CppSQLite3DB& operator=(const CppSQLite3DB& db);
sqlite3_stmt* compile(const char* szSQL);
void checkDB();
sqlite3* mpDB;
int mnBusyTimeoutMs;
};
#endif

196843
thirdparty/SQLite/sqlite3.c vendored Normal file

File diff suppressed because it is too large Load Diff

2679
thirdparty/SQLite/sqlite3.h vendored Normal file

File diff suppressed because it is too large Load Diff

78
thirdparty/cpplinq/License.html vendored Normal file
View File

@@ -0,0 +1,78 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
</head>
<body>
<br>
<br>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<h1>
Microsoft Public License (Ms-PL)
</h1>
<p>
This license governs use of the accompanying software. If you use the software,
you accept this license. If you do not accept the license, do not use the software.</p>
<h2>
1. Definitions
</h2>
<p>
The terms &quot;reproduce,&quot; &quot;reproduction,&quot; &quot;derivative works,&quot;
and &quot;distribution&quot; have the same meaning here as under U.S. copyright
law. A &quot;contribution&quot; is the original software, or any additions or changes
to the software. A &quot;contributor&quot; is any person that distributes its contribution
under this license. &quot;Licensed patents&quot; are a contributor's patent claims
that read directly on its contribution.</p>
<h2>
2. Grant of Rights
</h2>
<p>
(A) Copyright Grant- Subject to the terms of this license, including the license
conditions and limitations in section 3, each contributor grants you a non-exclusive,
worldwide, royalty-free copyright license to reproduce its contribution, prepare
derivative works of its contribution, and distribute its contribution or any derivative
works that you create.
</p>
<p>
(B) Patent Grant- Subject to the terms of this license, including the license conditions
and limitations in section 3, each contributor grants you a non-exclusive, worldwide,
royalty-free license under its licensed patents to make, have made, use, sell, offer
for sale, import, and/or otherwise dispose of its contribution in the software or
derivative works of the contribution in the software.
</p>
<h2>
3. Conditions and Limitations
</h2>
<p>
(A) No Trademark License- This license does not grant you rights to use any contributors'
name, logo, or trademarks.
</p>
<p>
(B) If you bring a patent claim against any contributor over patents that you claim
are infringed by the software, your patent license from such contributor to the
software ends automatically.
</p>
<p>
(C) If you distribute any portion of the software, you must retain all copyright,
patent, trademark, and attribution notices that are present in the software.
</p>
<p>
(D) If you distribute any portion of the software in source code form, you may do
so only under this license by including a complete copy of this license with your
distribution. If you distribute any portion of the software in compiled or object
code form, you may only do so under a license that complies with this license.
</p>
<p>
(E) The software is licensed &quot;as-is.&quot; You bear the risk of using it. The
contributors give no express warranties, guarantees or conditions. You may have
additional consumer rights under your local laws which this license cannot change.
To the extent permitted under your local laws, the contributors exclude the implied
warranties of merchantability, fitness for a particular purpose and non-infringement.
</p>
</td>
</tr>
</table>
</body>
</html>

5568
thirdparty/cpplinq/cpplinq.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

87
thirdparty/raknet/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,87 @@
PROJECT(RakNetStaticLib)
SET(RAKNET_SOURCES
Source/AsynchronousFileIO.cpp Source/FormatString.cpp Source/RakNetTypes.cpp
Source/AutoRPC.cpp Source/FullyConnectedMesh.cpp Source/RakNetworkFactory.cpp
Source/BitStream.cpp Source/FunctionThread.cpp Source/RakPeer.cpp
Source/BitStream_NoTemplate.cpp Source/Gen_RPC8.cpp Source/RakSleep.cpp
Source/CheckSum.cpp Source/GetTime.cpp Source/RakString.cpp
Source/CommandParserInterface.cpp Source/GridSectorizer.cpp Source/Rand.cpp
Source/ConnectionGraph.cpp Source/LightweightDatabaseClient.cpp Source/ReadyEvent.cpp
Source/ConsoleServer.cpp Source/LightweightDatabaseCommon.cpp Source/ReliabilityLayer.cpp
Source/DataBlockEncryptor.cpp Source/LightweightDatabaseServer.cpp Source/ReplicaManager2.cpp
Source/DataCompressor.cpp Source/LinuxStrings.cpp Source/ReplicaManager.cpp
Source/DirectoryDeltaTransfer.cpp Source/LogCommandParser.cpp Source/rijndael.cpp
Source/DS_BytePool.cpp Source/MessageFilter.cpp Source/Router.cpp
Source/DS_ByteQueue.cpp Source/NatPunchthrough.cpp Source/RPCMap.cpp
Source/DS_HuffmanEncodingTree.cpp Source/NetworkIDManager.cpp Source/SHA1.cpp
Source/DS_Table.cpp Source/NetworkIDObject.cpp Source/SimpleMutex.cpp
Source/EmailSender.cpp Source/PacketConsoleLogger.cpp Source/SocketLayer.cpp
Source/EncodeClassName.cpp Source/PacketFileLogger.cpp Source/StringCompressor.cpp
Source/EpochTimeToString.cpp Source/PacketLogger.cpp Source/StringTable.cpp
Source/ExtendedOverlappedPool.cpp Source/PluginInterface.cpp Source/SystemAddressList.cpp
Source/FileList.cpp Source/RakMemoryOverride.cpp Source/TableSerializer.cpp
Source/FileListTransfer.cpp Source/RakNetCommandParser.cpp Source/TCPInterface.cpp
Source/FileOperations.cpp Source/RakNetStatistics.cpp Source/TelnetTransport.cpp
Source/_FindFirst.cpp Source/RakNetTransport.cpp Source/ThreadsafePacketLogger.cpp
Source/RakThread.cpp Source/SuperFastHash.cpp Source/Itoa.cpp
Source/HTTPConnection.cpp
)
set(RAKNET_HEADERS
Source/AsynchronousFileIO.h Source/Export.h Source/RakNetTypes.h
Source/AutopatcherPatchContext.h Source/ExtendedOverlappedPool.h Source/RakNetVersion.h
Source/AutopatcherRepositoryInterface.h Source/FileList.h Source/RakNetworkFactory.h
Source/AutoRPC.h Source/FileListTransferCBInterface.h Source/RakPeer.h
Source/BigTypes.h Source/FileListTransfer.h Source/RakPeerInterface.h
Source/BitStream.h Source/FileOperations.h Source/RakSleep.h
Source/BitStream_NoTemplate.h Source/_FindFirst.h Source/RakString.h
Source/CheckSum.h Source/FormatString.h Source/Rand.h
Source/ClientContextStruct.h Source/FullyConnectedMesh.h Source/ReadyEvent.h
Source/CommandParserInterface.h Source/FunctionThread.h Source/RefCountedObj.h
Source/ConnectionGraph.h Source/Gen_RPC8.h Source/ReliabilityLayer.h
Source/ConsoleServer.h Source/GetTime.h Source/ReplicaEnums.h
Source/DataBlockEncryptor.h Source/GridSectorizer.h Source/Replica.h
Source/DataCompressor.h Source/InternalPacket.h Source/ReplicaManager2.h
Source/DirectoryDeltaTransfer.h Source/LightweightDatabaseClient.h Source/ReplicaManager.h
Source/DS_BinarySearchTree.h Source/LightweightDatabaseCommon.h Source/Rijndael-Boxes.h
Source/DS_BPlusTree.h Source/LightweightDatabaseServer.h Source/Rijndael.h
Source/DS_BytePool.h Source/LinuxStrings.h Source/Router.h
Source/DS_ByteQueue.h Source/LogCommandParser.h Source/RouterInterface.h
Source/DS_Heap.h Source/MessageFilter.h Source/RPCMap.h
Source/DS_HuffmanEncodingTreeFactory.h Source/MessageIdentifiers.h Source/RPCNode.h
Source/DS_HuffmanEncodingTree.h Source/MTUSize.h Source/RSACrypt.h
Source/DS_HuffmanEncodingTreeNode.h Source/NatPunchthrough.h Source/SHA1.h
Source/DS_LinkedList.h Source/NetworkIDManager.h Source/SimpleMutex.h
Source/DS_List.h Source/NetworkIDObject.h Source/SimpleTCPServer.h
Source/DS_Map.h Source/PacketConsoleLogger.h Source/SingleProducerConsumer.h
Source/DS_MemoryPool.h Source/PacketFileLogger.h Source/SocketLayer.h
Source/DS_OrderedChannelHeap.h Source/PacketLogger.h Source/StringCompressor.h
Source/DS_OrderedList.h Source/PacketPool.h Source/StringTable.h
Source/DS_Queue.h Source/PacketPriority.h Source/SystemAddressList.h
Source/DS_QueueLinkedList.h Source/PluginInterface.h Source/TableSerializer.h
Source/DS_RangeList.h Source/RakAssert.h Source/TCPInterface.h
Source/DS_Table.h Source/RakMemoryOverride.h Source/TelnetTransport.h
Source/DS_Tree.h Source/RakNetCommandParser.h Source/ThreadPool.h
Source/DS_WeightedGraph.h Source/RakNetDefines.h Source/ThreadsafePacketLogger.h
Source/EmailSender.h Source/RakNetStatistics.h Source/TransportInterface.h
Source/EpochTimeToString.h Source/RakNetTransport.h Source/Types.h
Source/RakThread.h Source/SuperFastHash.h Source/Itoa.h
Source/HTTPConnection.h Kbhit.h\
)
ADD_LIBRARY(RakNet STATIC ${RAKNET_SOURCES})
INSTALL(TARGETS RakNet
DESTINATION lib)
INSTALL(FILES ${RAKNET_HEADERS}
DESTINATION include/raknet)

61
thirdparty/raknet/Lib/DLL/DLL.rc vendored Normal file
View File

@@ -0,0 +1,61 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE 9, 1
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

686
thirdparty/raknet/Lib/DLL/DLL.vcproj vendored Normal file
View File

@@ -0,0 +1,686 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="DLL"
ProjectGUID="{BC75CD23-CB75-4233-A305-B7328825A9A5}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="./../../Source"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_RAKNET_DLL"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)/../../RakNetDebug"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
OutputFile="$(OutDir)/../../RakNetDebug.dll"
LinkIncremental="2"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/../../RakNetDebug.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/../../RakNetDLLDebug.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="./../../Source"
PreprocessorDefinitions="WIN32;_RELEASE;_WINDOWS;_RAKNET_DLL"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)/../../RakNet"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
OutputFile="$(OutDir)/../../RakNet.dll"
LinkIncremental="1"
GenerateDebugInformation="FALSE"
ProgramDatabaseFile="$(OutDir)/../../RakNet.pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/../../RakNetDLL.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="..\..\Source\_FindFirst.cpp">
</File>
<File
RelativePath="..\..\Source\AsynchronousFileIO.cpp">
</File>
<File
RelativePath="..\..\Source\BitStream.cpp">
</File>
<File
RelativePath="..\..\Source\BitStream_NoTemplate.cpp">
</File>
<File
RelativePath="..\..\Source\CheckSum.cpp">
</File>
<File
RelativePath="..\..\Source\CommandParserInterface.cpp">
</File>
<File
RelativePath="..\..\Source\ConnectionGraph.cpp">
</File>
<File
RelativePath="..\..\Source\ConsoleServer.cpp">
</File>
<File
RelativePath="..\..\Source\DataBlockEncryptor.cpp">
</File>
<File
RelativePath="..\..\Source\DataCompressor.cpp">
</File>
<File
RelativePath="..\..\Source\DirectoryDeltaTransfer.cpp">
</File>
<File
RelativePath="..\..\Source\DS_BytePool.cpp">
</File>
<File
RelativePath="..\..\Source\DS_ByteQueue.cpp">
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTree.cpp">
</File>
<File
RelativePath="..\..\Source\DS_Table.cpp">
</File>
<File
RelativePath="..\..\Source\EmailSender.cpp">
</File>
<File
RelativePath="..\..\Source\EncodeClassName.cpp">
</File>
<File
RelativePath="..\..\Source\EpochTimeToString.cpp">
</File>
<File
RelativePath="..\..\Source\ExtendedOverlappedPool.cpp">
</File>
<File
RelativePath="..\..\Source\FileList.cpp">
</File>
<File
RelativePath="..\..\Source\FileListTransfer.cpp">
</File>
<File
RelativePath="..\..\Source\FileOperations.cpp">
</File>
<File
RelativePath="..\..\Source\FormatString.cpp">
</File>
<File
RelativePath="..\..\Source\FullyConnectedMesh.cpp">
</File>
<File
RelativePath="..\..\Source\FunctionThread.cpp">
</File>
<File
RelativePath="..\..\Source\GetTime.cpp">
</File>
<File
RelativePath="..\..\Source\GridSectorizer.cpp">
</File>
<File
RelativePath="..\..\Source\HTTPConnection.h">
</File>
<File
RelativePath="..\..\Source\InternalPacket.h">
</File>
<File
RelativePath="..\..\Source\Itoa.h">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseClient.cpp">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseCommon.cpp">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseServer.cpp">
</File>
<File
RelativePath="..\..\Source\LinuxStrings.cpp">
</File>
<File
RelativePath="..\..\Source\LogCommandParser.cpp">
</File>
<File
RelativePath="..\..\Source\MessageFilter.cpp">
</File>
<File
RelativePath="..\..\Source\NatPunchthrough.cpp">
</File>
<File
RelativePath="..\..\Source\NetworkIDManager.cpp">
</File>
<File
RelativePath="..\..\Source\NetworkIDObject.cpp">
</File>
<File
RelativePath="..\..\Source\PacketConsoleLogger.cpp">
</File>
<File
RelativePath="..\..\Source\PacketFileLogger.cpp">
</File>
<File
RelativePath="..\..\Source\PacketLogger.cpp">
</File>
<File
RelativePath="..\..\Source\PluginInterface.cpp">
</File>
<File
RelativePath="..\..\Source\RakMemoryOverride.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetCommandParser.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetStatistics.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetTransport.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetTypes.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetworkFactory.cpp">
</File>
<File
RelativePath="..\..\Source\RakPeer.cpp">
</File>
<File
RelativePath="..\..\Source\RakSleep.cpp">
</File>
<File
RelativePath="..\..\Source\RakString.cpp">
</File>
<File
RelativePath="..\..\Source\RakThread.cpp">
</File>
<File
RelativePath="..\..\Source\Rand.cpp">
</File>
<File
RelativePath="..\..\Source\ReadyEvent.cpp">
</File>
<File
RelativePath="..\..\Source\ReliabilityLayer.cpp">
</File>
<File
RelativePath="..\..\Source\ReplicaManager.cpp">
</File>
<File
RelativePath="..\..\Source\ReplicaManager2.cpp">
</File>
<File
RelativePath="..\..\Source\rijndael.cpp">
</File>
<File
RelativePath="..\..\Source\Router.cpp">
</File>
<File
RelativePath="..\..\Source\RPCMap.cpp">
</File>
<File
RelativePath="..\..\Source\SHA1.cpp">
</File>
<File
RelativePath="..\..\Source\SimpleMutex.cpp">
</File>
<File
RelativePath="..\..\Source\SocketLayer.cpp">
</File>
<File
RelativePath="..\..\Source\StringCompressor.cpp">
</File>
<File
RelativePath="..\..\Source\StringTable.cpp">
</File>
<File
RelativePath="..\..\Source\SuperFastHash.cpp">
</File>
<File
RelativePath="..\..\Source\SystemAddressList.cpp">
</File>
<File
RelativePath="..\..\Source\TableSerializer.cpp">
</File>
<File
RelativePath="..\..\Source\TCPInterface.cpp">
</File>
<File
RelativePath="..\..\Source\TelnetTransport.cpp">
</File>
<File
RelativePath="..\..\Source\ThreadsafePacketLogger.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath="..\..\Source\_FindFirst.h">
</File>
<File
RelativePath="..\..\Source\AsynchronousFileIO.h">
</File>
<File
RelativePath="..\..\Source\AutopatcherPatchContext.h">
</File>
<File
RelativePath="..\..\Source\AutopatcherRepositoryInterface.h">
</File>
<File
RelativePath="..\..\Source\BigTypes.h">
</File>
<File
RelativePath="..\..\Source\BitStream.h">
</File>
<File
RelativePath="..\..\Source\CheckSum.h">
</File>
<File
RelativePath="..\..\Source\ClientContextStruct.h">
</File>
<File
RelativePath="..\..\Source\CommandParserInterface.h">
</File>
<File
RelativePath="..\..\Source\ConnectionGraph.h">
</File>
<File
RelativePath="..\..\Source\ConsoleServer.h">
</File>
<File
RelativePath="..\..\Source\DataBlockEncryptor.h">
</File>
<File
RelativePath="..\..\Source\DataCompressor.h">
</File>
<File
RelativePath="..\..\Source\DirectoryDeltaTransfer.h">
</File>
<File
RelativePath="..\..\Source\DS_BinarySearchTree.h">
</File>
<File
RelativePath="..\..\Source\DS_BPlusTree.h">
</File>
<File
RelativePath="..\..\Source\DS_BytePool.h">
</File>
<File
RelativePath="..\..\Source\DS_ByteQueue.h">
</File>
<File
RelativePath="..\..\Source\DS_Heap.h">
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTree.h">
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTreeFactory.h">
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTreeNode.h">
</File>
<File
RelativePath="..\..\Source\DS_LinkedList.h">
</File>
<File
RelativePath="..\..\Source\DS_List.h">
</File>
<File
RelativePath="..\..\Source\DS_Map.h">
</File>
<File
RelativePath="..\..\Source\DS_MemoryPool.h">
</File>
<File
RelativePath="..\..\Source\DS_OrderedChannelHeap.h">
</File>
<File
RelativePath="..\..\Source\DS_OrderedList.h">
</File>
<File
RelativePath="..\..\Source\DS_Queue.h">
</File>
<File
RelativePath="..\..\Source\DS_QueueLinkedList.h">
</File>
<File
RelativePath="..\..\Source\DS_RangeList.h">
</File>
<File
RelativePath="..\..\Source\DS_Table.h">
</File>
<File
RelativePath="..\..\Source\DS_Tree.h">
</File>
<File
RelativePath="..\..\Source\DS_WeightedGraph.h">
</File>
<File
RelativePath="..\..\Source\EmailSender.h">
</File>
<File
RelativePath="..\..\Source\EpochTimeToString.h">
</File>
<File
RelativePath="..\..\Source\Export.h">
</File>
<File
RelativePath="..\..\Source\ExtendedOverlappedPool.h">
</File>
<File
RelativePath="..\..\Source\FileList.h">
</File>
<File
RelativePath="..\..\Source\FileListTransfer.h">
</File>
<File
RelativePath="..\..\Source\FileListTransferCBInterface.h">
</File>
<File
RelativePath="..\..\Source\FileOperations.h">
</File>
<File
RelativePath="..\..\Source\FormatString.h">
</File>
<File
RelativePath="..\..\Source\FullyConnectedMesh.h">
</File>
<File
RelativePath="..\..\Source\FunctionThread.h">
</File>
<File
RelativePath="..\..\Source\GetTime.h">
</File>
<File
RelativePath="..\..\Source\GridSectorizer.h">
</File>
<File
RelativePath="..\..\Source\HTTPConnection.h">
</File>
<File
RelativePath="..\..\Source\InternalPacket.h">
</File>
<File
RelativePath="..\..\Source\Itoa.h">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseClient.h">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseCommon.h">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseServer.h">
</File>
<File
RelativePath="..\..\Source\LinuxStrings.h">
</File>
<File
RelativePath="..\..\Source\LogCommandParser.h">
</File>
<File
RelativePath="..\..\Source\MessageFilter.h">
</File>
<File
RelativePath="..\..\Source\MessageIdentifiers.h">
</File>
<File
RelativePath="..\..\Source\MTUSize.h">
</File>
<File
RelativePath="..\..\Source\NatPunchthrough.h">
</File>
<File
RelativePath="..\..\Source\NetworkIDManager.h">
</File>
<File
RelativePath="..\..\Source\NetworkIDObject.h">
</File>
<File
RelativePath="..\..\Source\PacketConsoleLogger.h">
</File>
<File
RelativePath="..\..\Source\PacketFileLogger.h">
</File>
<File
RelativePath="..\..\Source\PacketLogger.h">
</File>
<File
RelativePath="..\..\Source\PacketPool.h">
</File>
<File
RelativePath="..\..\Source\PacketPriority.h">
</File>
<File
RelativePath="..\..\Source\PluginInterface.h">
</File>
<File
RelativePath="..\..\Source\RakAssert.h">
</File>
<File
RelativePath="..\..\Source\RakMemoryOverride.h">
</File>
<File
RelativePath="..\..\Source\RakNetCommandParser.h">
</File>
<File
RelativePath="..\..\Source\RakNetDefines.h">
</File>
<File
RelativePath="..\..\Source\RakNetStatistics.h">
</File>
<File
RelativePath="..\..\Source\RakNetTransport.h">
</File>
<File
RelativePath="..\..\Source\RakNetTypes.h">
</File>
<File
RelativePath="..\..\Source\RakNetVersion.h">
</File>
<File
RelativePath="..\..\Source\RakNetworkFactory.h">
</File>
<File
RelativePath="..\..\Source\RakPeer.h">
</File>
<File
RelativePath="..\..\Source\RakPeerInterface.h">
</File>
<File
RelativePath="..\..\Source\RakSleep.h">
</File>
<File
RelativePath="..\..\Source\RakString.h">
</File>
<File
RelativePath="..\..\Source\RakThread.h">
</File>
<File
RelativePath="..\..\Source\Rand.h">
</File>
<File
RelativePath="..\..\Source\ReadyEvent.h">
</File>
<File
RelativePath="..\..\Source\RefCountedObj.h">
</File>
<File
RelativePath="..\..\Source\ReliabilityLayer.h">
</File>
<File
RelativePath="..\..\Source\Replica.h">
</File>
<File
RelativePath="..\..\Source\ReplicaEnums.h">
</File>
<File
RelativePath="..\..\Source\ReplicaManager.h">
</File>
<File
RelativePath="..\..\Source\ReplicaManager2.h">
</File>
<File
RelativePath="..\..\Source\Rijndael-Boxes.h">
</File>
<File
RelativePath="..\..\Source\Rijndael.h">
</File>
<File
RelativePath="..\..\Source\Router.h">
</File>
<File
RelativePath="..\..\Source\RouterInterface.h">
</File>
<File
RelativePath="..\..\Source\RPCMap.h">
</File>
<File
RelativePath="..\..\Source\RPCNode.h">
</File>
<File
RelativePath="..\..\Source\RSACrypt.h">
</File>
<File
RelativePath="..\..\Source\SHA1.h">
</File>
<File
RelativePath="..\..\Source\SimpleMutex.h">
</File>
<File
RelativePath="..\..\Source\SimpleTCPServer.h">
</File>
<File
RelativePath="..\..\Source\SingleProducerConsumer.h">
</File>
<File
RelativePath="..\..\Source\SocketLayer.h">
</File>
<File
RelativePath="..\..\Source\StringCompressor.h">
</File>
<File
RelativePath="..\..\Source\StringTable.h">
</File>
<File
RelativePath="..\..\Source\SuperFastHash.h">
</File>
<File
RelativePath="..\..\Source\SystemAddressList.h">
</File>
<File
RelativePath="..\..\Source\TableSerializer.h">
</File>
<File
RelativePath="..\..\Source\TCPInterface.h">
</File>
<File
RelativePath="..\..\Source\TelnetTransport.h">
</File>
<File
RelativePath="..\..\Source\ThreadPool.h">
</File>
<File
RelativePath="..\..\Source\ThreadsafePacketLogger.h">
</File>
<File
RelativePath="..\..\Source\TransportInterface.h">
</File>
<File
RelativePath="..\..\Source\Types.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

965
thirdparty/raknet/Lib/DLL/DLL_vc8.vcproj vendored Normal file
View File

@@ -0,0 +1,965 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="DLL"
ProjectGUID="{BC75CD23-CB75-4233-A305-B7328825A9A5}"
RootNamespace="DLL"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="./../../Source;./../../DependentExtensions/openssl-0.9.8g"
PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;WIN32;_DEBUG;_RAKNET_DLL;_CRT_NONSTDC_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)/../../RakNetDebug"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
OutputFile="$(OutDir)/../../RakNetDebug.dll"
LinkIncremental="2"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/../../RakNetDebug.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/../../RakNetDLLDebug.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="./../../Source;./../../DependentExtensions/openssl-0.9.8g"
PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;WIN32;_RELEASE;_RAKNET_DLL;_CRT_NONSTDC_NO_DEPRECATE"
RuntimeLibrary="2"
BufferSecurityCheck="false"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)/../../RakNet"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
OutputFile="$(OutDir)/../../RakNet.dll"
LinkIncremental="1"
GenerateDebugInformation="false"
ProgramDatabaseFile="$(OutDir)/../../RakNet.pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/../../RakNetDLL.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\..\Source\_FindFirst.cpp"
>
</File>
<File
RelativePath="..\..\Source\AsynchronousFileIO.cpp"
>
</File>
<File
RelativePath="..\..\Source\AutoRPC.cpp"
>
</File>
<File
RelativePath="..\..\Source\BitStream.cpp"
>
</File>
<File
RelativePath="..\..\Source\BitStream_NoTemplate.cpp"
>
</File>
<File
RelativePath="..\..\Source\CheckSum.cpp"
>
</File>
<File
RelativePath="..\..\Source\CommandParserInterface.cpp"
>
</File>
<File
RelativePath="..\..\Source\ConnectionGraph.cpp"
>
</File>
<File
RelativePath="..\..\Source\ConsoleServer.cpp"
>
</File>
<File
RelativePath="..\..\Source\DataBlockEncryptor.cpp"
>
</File>
<File
RelativePath="..\..\Source\DataCompressor.cpp"
>
</File>
<File
RelativePath="..\..\Source\DirectoryDeltaTransfer.cpp"
>
</File>
<File
RelativePath="..\..\Source\DS_BytePool.cpp"
>
</File>
<File
RelativePath="..\..\Source\DS_ByteQueue.cpp"
>
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTree.cpp"
>
</File>
<File
RelativePath="..\..\Source\DS_Table.cpp"
>
</File>
<File
RelativePath="..\..\Source\EmailSender.cpp"
>
</File>
<File
RelativePath="..\..\Source\EncodeClassName.cpp"
>
</File>
<File
RelativePath="..\..\Source\EpochTimeToString.cpp"
>
</File>
<File
RelativePath="..\..\Source\ExtendedOverlappedPool.cpp"
>
</File>
<File
RelativePath="..\..\Source\FileList.cpp"
>
</File>
<File
RelativePath="..\..\Source\FileListTransfer.cpp"
>
</File>
<File
RelativePath="..\..\Source\FileOperations.cpp"
>
</File>
<File
RelativePath="..\..\Source\FormatString.cpp"
>
</File>
<File
RelativePath="..\..\Source\FullyConnectedMesh.cpp"
>
</File>
<File
RelativePath="..\..\Source\FunctionThread.cpp"
>
</File>
<File
RelativePath="..\..\Source\Gen_RPC8.cpp"
>
</File>
<File
RelativePath="..\..\Source\GetTime.cpp"
>
</File>
<File
RelativePath="..\..\Source\GridSectorizer.cpp"
>
</File>
<File
RelativePath="..\..\Source\HTTPConnection.cpp"
>
</File>
<File
RelativePath="..\..\Source\Itoa.cpp"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseClient.cpp"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseCommon.cpp"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseServer.cpp"
>
</File>
<File
RelativePath="..\..\Source\LinuxStrings.cpp"
>
</File>
<File
RelativePath="..\..\Source\LogCommandParser.cpp"
>
</File>
<File
RelativePath="..\..\Source\MessageFilter.cpp"
>
</File>
<File
RelativePath="..\..\Source\NatPunchthrough.cpp"
>
</File>
<File
RelativePath="..\..\Source\NetworkIDManager.cpp"
>
</File>
<File
RelativePath="..\..\Source\NetworkIDObject.cpp"
>
</File>
<File
RelativePath="..\..\Source\PacketConsoleLogger.cpp"
>
</File>
<File
RelativePath="..\..\Source\PacketFileLogger.cpp"
>
</File>
<File
RelativePath="..\..\Source\PacketLogger.cpp"
>
</File>
<File
RelativePath="..\..\Source\PluginInterface.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakMemoryOverride.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetCommandParser.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetStatistics.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetTransport.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetTypes.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetworkFactory.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakPeer.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakSleep.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakString.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakThread.cpp"
>
</File>
<File
RelativePath="..\..\Source\Rand.cpp"
>
</File>
<File
RelativePath="..\..\Source\ReadyEvent.cpp"
>
</File>
<File
RelativePath="..\..\Source\ReliabilityLayer.cpp"
>
</File>
<File
RelativePath="..\..\Source\ReplicaManager.cpp"
>
</File>
<File
RelativePath="..\..\Source\ReplicaManager2.cpp"
>
</File>
<File
RelativePath="..\..\Source\rijndael.cpp"
>
</File>
<File
RelativePath="..\..\Source\Router.cpp"
>
</File>
<File
RelativePath="..\..\Source\RPCMap.cpp"
>
</File>
<File
RelativePath="..\..\Source\SHA1.cpp"
>
</File>
<File
RelativePath="..\..\Source\SimpleMutex.cpp"
>
</File>
<File
RelativePath="..\..\Source\SocketLayer.cpp"
>
</File>
<File
RelativePath="..\..\Source\StringCompressor.cpp"
>
</File>
<File
RelativePath="..\..\Source\StringTable.cpp"
>
</File>
<File
RelativePath="..\..\Source\SuperFastHash.cpp"
>
</File>
<File
RelativePath="..\..\Source\SystemAddressList.cpp"
>
</File>
<File
RelativePath="..\..\Source\TableSerializer.cpp"
>
</File>
<File
RelativePath="..\..\Source\TCPInterface.cpp"
>
</File>
<File
RelativePath="..\..\Source\TelnetTransport.cpp"
>
</File>
<File
RelativePath="..\..\Source\ThreadsafePacketLogger.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\..\Source\_FindFirst.h"
>
</File>
<File
RelativePath="..\..\Source\AsynchronousFileIO.h"
>
</File>
<File
RelativePath="..\..\Source\AutopatcherPatchContext.h"
>
</File>
<File
RelativePath="..\..\Source\AutopatcherRepositoryInterface.h"
>
</File>
<File
RelativePath="..\..\Source\AutoRPC.h"
>
</File>
<File
RelativePath="..\..\Source\BigTypes.h"
>
</File>
<File
RelativePath="..\..\Source\BitStream.h"
>
</File>
<File
RelativePath="..\..\Source\BitStream_NoTemplate.h"
>
</File>
<File
RelativePath="..\..\Source\CheckSum.h"
>
</File>
<File
RelativePath="..\..\Source\ClientContextStruct.h"
>
</File>
<File
RelativePath="..\..\Source\CommandParserInterface.h"
>
</File>
<File
RelativePath="..\..\Source\ConnectionGraph.h"
>
</File>
<File
RelativePath="..\..\Source\ConsoleServer.h"
>
</File>
<File
RelativePath="..\..\Source\DataBlockEncryptor.h"
>
</File>
<File
RelativePath="..\..\Source\DataCompressor.h"
>
</File>
<File
RelativePath="..\..\Source\DirectoryDeltaTransfer.h"
>
</File>
<File
RelativePath="..\..\Source\DS_BinarySearchTree.h"
>
</File>
<File
RelativePath="..\..\Source\DS_BPlusTree.h"
>
</File>
<File
RelativePath="..\..\Source\DS_BytePool.h"
>
</File>
<File
RelativePath="..\..\Source\DS_ByteQueue.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Heap.h"
>
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTree.h"
>
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTreeFactory.h"
>
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTreeNode.h"
>
</File>
<File
RelativePath="..\..\Source\DS_LinkedList.h"
>
</File>
<File
RelativePath="..\..\Source\DS_List.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Map.h"
>
</File>
<File
RelativePath="..\..\Source\DS_MemoryPool.h"
>
</File>
<File
RelativePath="..\..\Source\DS_OrderedChannelHeap.h"
>
</File>
<File
RelativePath="..\..\Source\DS_OrderedList.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Queue.h"
>
</File>
<File
RelativePath="..\..\Source\DS_QueueLinkedList.h"
>
</File>
<File
RelativePath="..\..\Source\DS_RangeList.h"
>
</File>
<File
RelativePath="..\..\Source\DS_String.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Table.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Tree.h"
>
</File>
<File
RelativePath="..\..\Source\DS_WeightedGraph.h"
>
</File>
<File
RelativePath="..\..\Source\EmailSender.h"
>
</File>
<File
RelativePath="..\..\Source\EpochTimeToString.h"
>
</File>
<File
RelativePath="..\..\Source\Export.h"
>
</File>
<File
RelativePath="..\..\Source\ExtendedOverlappedPool.h"
>
</File>
<File
RelativePath="..\..\Source\FileList.h"
>
</File>
<File
RelativePath="..\..\Source\FileListTransfer.h"
>
</File>
<File
RelativePath="..\..\Source\FileListTransferCBInterface.h"
>
</File>
<File
RelativePath="..\..\Source\FileOperations.h"
>
</File>
<File
RelativePath="..\..\Source\FormatString.h"
>
</File>
<File
RelativePath="..\..\Source\FullyConnectedMesh.h"
>
</File>
<File
RelativePath="..\..\Source\FunctionThread.h"
>
</File>
<File
RelativePath="..\..\Source\Gen_RPC8.h"
>
</File>
<File
RelativePath="..\..\Source\GetTime.h"
>
</File>
<File
RelativePath="..\..\Source\GridSectorizer.h"
>
</File>
<File
RelativePath="..\..\Source\HTTPConnection.h"
>
</File>
<File
RelativePath="..\..\Source\InternalPacket.h"
>
</File>
<File
RelativePath="..\..\Source\Itoa.h"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseClient.h"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseCommon.h"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseServer.h"
>
</File>
<File
RelativePath="..\..\Source\LinuxStrings.h"
>
</File>
<File
RelativePath="..\..\Source\LogCommandParser.h"
>
</File>
<File
RelativePath="..\..\Source\MessageFilter.h"
>
</File>
<File
RelativePath="..\..\Source\MessageIdentifiers.h"
>
</File>
<File
RelativePath="..\..\Source\MTUSize.h"
>
</File>
<File
RelativePath="..\..\Source\NatPunchthrough.h"
>
</File>
<File
RelativePath="..\..\Source\NetworkIDManager.h"
>
</File>
<File
RelativePath="..\..\Source\NetworkIDObject.h"
>
</File>
<File
RelativePath="..\..\Source\PacketConsoleLogger.h"
>
</File>
<File
RelativePath="..\..\Source\PacketFileLogger.h"
>
</File>
<File
RelativePath="..\..\Source\PacketLogger.h"
>
</File>
<File
RelativePath="..\..\Source\PacketPool.h"
>
</File>
<File
RelativePath="..\..\Source\PacketPriority.h"
>
</File>
<File
RelativePath="..\..\Source\PluginInterface.h"
>
</File>
<File
RelativePath="..\..\Source\RakAssert.h"
>
</File>
<File
RelativePath="..\..\Source\RakMemory.h"
>
</File>
<File
RelativePath="..\..\Source\RakMemoryOverride.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetCommandParser.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetDefines.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetStatistics.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetTransport.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetTypes.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetVersion.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetworkFactory.h"
>
</File>
<File
RelativePath="..\..\Source\RakPeer.h"
>
</File>
<File
RelativePath="..\..\Source\RakPeerInterface.h"
>
</File>
<File
RelativePath="..\..\Source\RakSleep.h"
>
</File>
<File
RelativePath="..\..\Source\RakString.h"
>
</File>
<File
RelativePath="..\..\Source\RakThread.h"
>
</File>
<File
RelativePath="..\..\Source\Rand.h"
>
</File>
<File
RelativePath="..\..\Source\ReadyEvent.h"
>
</File>
<File
RelativePath="..\..\Source\RefCountedObj.h"
>
</File>
<File
RelativePath="..\..\Source\ReliabilityLayer.h"
>
</File>
<File
RelativePath="..\..\Source\Replica.h"
>
</File>
<File
RelativePath="..\..\Source\ReplicaEnums.h"
>
</File>
<File
RelativePath="..\..\Source\ReplicaManager.h"
>
</File>
<File
RelativePath="..\..\Source\ReplicaManager2.h"
>
</File>
<File
RelativePath="..\..\Source\Rijndael-Boxes.h"
>
</File>
<File
RelativePath="..\..\Source\Rijndael.h"
>
</File>
<File
RelativePath="..\..\Source\Router.h"
>
</File>
<File
RelativePath="..\..\Source\RouterInterface.h"
>
</File>
<File
RelativePath="..\..\Source\RPCMap.h"
>
</File>
<File
RelativePath="..\..\Source\RPCNode.h"
>
</File>
<File
RelativePath="..\..\Source\RSACrypt.h"
>
</File>
<File
RelativePath="..\..\Source\SHA1.h"
>
</File>
<File
RelativePath="..\..\Source\SimpleMutex.h"
>
</File>
<File
RelativePath="..\..\Source\SimpleTCPServer.h"
>
</File>
<File
RelativePath="..\..\Source\SingleProducerConsumer.h"
>
</File>
<File
RelativePath="..\..\Source\SocketLayer.h"
>
</File>
<File
RelativePath="..\..\Source\StringCompressor.h"
>
</File>
<File
RelativePath="..\..\Source\StringTable.h"
>
</File>
<File
RelativePath="..\..\Source\SuperFastHash.h"
>
</File>
<File
RelativePath="..\..\Source\SystemAddressList.h"
>
</File>
<File
RelativePath="..\..\Source\TableSerializer.h"
>
</File>
<File
RelativePath="..\..\Source\TCPInterface.h"
>
</File>
<File
RelativePath="..\..\Source\TelnetTransport.h"
>
</File>
<File
RelativePath="..\..\Source\ThreadPool.h"
>
</File>
<File
RelativePath="..\..\Source\ThreadsafePacketLogger.h"
>
</File>
<File
RelativePath="..\..\Source\TransportInterface.h"
>
</File>
<File
RelativePath="..\..\Source\Types.h"
>
</File>
</Filter>
<File
RelativePath=".\readme.txt"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

14
thirdparty/raknet/Lib/DLL/resource.h vendored Normal file
View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by DLL.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,666 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="LibStatic"
ProjectGUID="{6533BDAE-0F0C-45E4-8FE7-ADD0F37FE063}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="./../../Source"
PreprocessorDefinitions="WIN32;_DEBUG;_RAKNET_LIB"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
DisableLanguageExtensions="FALSE"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)/../../RakNetLibStaticDebug"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/../../RakNetLibStaticDebug.lib"
IgnoreDefaultLibraryNames="LIBCD.lib LIBCMTD.lib MSVCRT.lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="./../../Source"
PreprocessorDefinitions="WIN32;_RELEASE;_RAKNET_LIB"
RuntimeLibrary="0"
BufferSecurityCheck="FALSE"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)/../../RakNetLibStatic"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/../../RakNetLibStatic.lib"
IgnoreDefaultLibraryNames="LIBC.lib LIBCMT.lib MSVCRT.lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="..\..\Source\_FindFirst.cpp">
</File>
<File
RelativePath="..\..\Source\AsynchronousFileIO.cpp">
</File>
<File
RelativePath="..\..\Source\BitStream.cpp">
</File>
<File
RelativePath="..\..\Source\BitStream_NoTemplate.cpp">
</File>
<File
RelativePath="..\..\Source\CheckSum.cpp">
</File>
<File
RelativePath="..\..\Source\CommandParserInterface.cpp">
</File>
<File
RelativePath="..\..\Source\ConnectionGraph.cpp">
</File>
<File
RelativePath="..\..\Source\ConsoleServer.cpp">
</File>
<File
RelativePath="..\..\Source\DataBlockEncryptor.cpp">
</File>
<File
RelativePath="..\..\Source\DataCompressor.cpp">
</File>
<File
RelativePath="..\..\Source\DirectoryDeltaTransfer.cpp">
</File>
<File
RelativePath="..\..\Source\DS_BytePool.cpp">
</File>
<File
RelativePath="..\..\Source\DS_ByteQueue.cpp">
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTree.cpp">
</File>
<File
RelativePath="..\..\Source\DS_Table.cpp">
</File>
<File
RelativePath="..\..\Source\EmailSender.cpp">
</File>
<File
RelativePath="..\..\Source\EncodeClassName.cpp">
</File>
<File
RelativePath="..\..\Source\EpochTimeToString.cpp">
</File>
<File
RelativePath="..\..\Source\ExtendedOverlappedPool.cpp">
</File>
<File
RelativePath="..\..\Source\FileList.cpp">
</File>
<File
RelativePath="..\..\Source\FileListTransfer.cpp">
</File>
<File
RelativePath="..\..\Source\FileOperations.cpp">
</File>
<File
RelativePath="..\..\Source\FormatString.cpp">
</File>
<File
RelativePath="..\..\Source\FullyConnectedMesh.cpp">
</File>
<File
RelativePath="..\..\Source\FunctionThread.cpp">
</File>
<File
RelativePath="..\..\Source\GetTime.cpp">
</File>
<File
RelativePath="..\..\Source\GridSectorizer.cpp">
</File>
<File
RelativePath="..\..\Source\HTTPConnection.cpp">
</File>
<File
RelativePath="..\..\Source\Itoa.cpp">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseClient.cpp">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseCommon.cpp">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseServer.cpp">
</File>
<File
RelativePath="..\..\Source\LinuxStrings.cpp">
</File>
<File
RelativePath="..\..\Source\LogCommandParser.cpp">
</File>
<File
RelativePath="..\..\Source\MessageFilter.cpp">
</File>
<File
RelativePath="..\..\Source\NatPunchthrough.cpp">
</File>
<File
RelativePath="..\..\Source\NetworkIDManager.cpp">
</File>
<File
RelativePath="..\..\Source\NetworkIDObject.cpp">
</File>
<File
RelativePath="..\..\Source\PacketConsoleLogger.cpp">
</File>
<File
RelativePath="..\..\Source\PacketFileLogger.cpp">
</File>
<File
RelativePath="..\..\Source\PacketLogger.cpp">
</File>
<File
RelativePath="..\..\Source\PluginInterface.cpp">
</File>
<File
RelativePath="..\..\Source\RakMemoryOverride.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetCommandParser.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetStatistics.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetTransport.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetTypes.cpp">
</File>
<File
RelativePath="..\..\Source\RakNetworkFactory.cpp">
</File>
<File
RelativePath="..\..\Source\RakPeer.cpp">
</File>
<File
RelativePath="..\..\Source\RakSleep.cpp">
</File>
<File
RelativePath="..\..\Source\RakString.cpp">
</File>
<File
RelativePath="..\..\Source\RakThread.cpp">
</File>
<File
RelativePath="..\..\Source\Rand.cpp">
</File>
<File
RelativePath="..\..\Source\ReadyEvent.cpp">
</File>
<File
RelativePath="..\..\Source\ReliabilityLayer.cpp">
</File>
<File
RelativePath="..\..\Source\ReplicaManager.cpp">
</File>
<File
RelativePath="..\..\Source\ReplicaManager2.cpp">
</File>
<File
RelativePath="..\..\Source\rijndael.cpp">
</File>
<File
RelativePath="..\..\Source\Router.cpp">
</File>
<File
RelativePath="..\..\Source\RPCMap.cpp">
</File>
<File
RelativePath="..\..\Source\SHA1.cpp">
</File>
<File
RelativePath="..\..\Source\SimpleMutex.cpp">
</File>
<File
RelativePath="..\..\Source\SocketLayer.cpp">
</File>
<File
RelativePath="..\..\Source\StringCompressor.cpp">
</File>
<File
RelativePath="..\..\Source\StringTable.cpp">
</File>
<File
RelativePath="..\..\Source\SuperFastHash.cpp">
</File>
<File
RelativePath="..\..\Source\SystemAddressList.cpp">
</File>
<File
RelativePath="..\..\Source\TableSerializer.cpp">
</File>
<File
RelativePath="..\..\Source\TCPInterface.cpp">
</File>
<File
RelativePath="..\..\Source\TelnetTransport.cpp">
</File>
<File
RelativePath="..\..\Source\ThreadsafePacketLogger.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath="..\..\Source\_FindFirst.h">
</File>
<File
RelativePath="..\..\Source\AsynchronousFileIO.h">
</File>
<File
RelativePath="..\..\Source\AutopatcherPatchContext.h">
</File>
<File
RelativePath="..\..\Source\AutopatcherRepositoryInterface.h">
</File>
<File
RelativePath="..\..\Source\BigTypes.h">
</File>
<File
RelativePath="..\..\Source\BitStream.h">
</File>
<File
RelativePath="..\..\Source\CheckSum.h">
</File>
<File
RelativePath="..\..\Source\ClientContextStruct.h">
</File>
<File
RelativePath="..\..\Source\CommandParserInterface.h">
</File>
<File
RelativePath="..\..\Source\ConnectionGraph.h">
</File>
<File
RelativePath="..\..\Source\ConsoleServer.h">
</File>
<File
RelativePath="..\..\Source\DataBlockEncryptor.h">
</File>
<File
RelativePath="..\..\Source\DataCompressor.h">
</File>
<File
RelativePath="..\..\Source\DirectoryDeltaTransfer.h">
</File>
<File
RelativePath="..\..\Source\DS_BinarySearchTree.h">
</File>
<File
RelativePath="..\..\Source\DS_BPlusTree.h">
</File>
<File
RelativePath="..\..\Source\DS_BytePool.h">
</File>
<File
RelativePath="..\..\Source\DS_ByteQueue.h">
</File>
<File
RelativePath="..\..\Source\DS_Heap.h">
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTree.h">
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTreeFactory.h">
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTreeNode.h">
</File>
<File
RelativePath="..\..\Source\DS_LinkedList.h">
</File>
<File
RelativePath="..\..\Source\DS_List.h">
</File>
<File
RelativePath="..\..\Source\DS_Map.h">
</File>
<File
RelativePath="..\..\Source\DS_MemoryPool.h">
</File>
<File
RelativePath="..\..\Source\DS_OrderedChannelHeap.h">
</File>
<File
RelativePath="..\..\Source\DS_OrderedList.h">
</File>
<File
RelativePath="..\..\Source\DS_Queue.h">
</File>
<File
RelativePath="..\..\Source\DS_QueueLinkedList.h">
</File>
<File
RelativePath="..\..\Source\DS_RangeList.h">
</File>
<File
RelativePath="..\..\Source\DS_Table.h">
</File>
<File
RelativePath="..\..\Source\DS_Tree.h">
</File>
<File
RelativePath="..\..\Source\DS_WeightedGraph.h">
</File>
<File
RelativePath="..\..\Source\EmailSender.h">
</File>
<File
RelativePath="..\..\Source\EpochTimeToString.h">
</File>
<File
RelativePath="..\..\Source\Export.h">
</File>
<File
RelativePath="..\..\Source\ExtendedOverlappedPool.h">
</File>
<File
RelativePath="..\..\Source\FileList.h">
</File>
<File
RelativePath="..\..\Source\FileListTransfer.h">
</File>
<File
RelativePath="..\..\Source\FileListTransferCBInterface.h">
</File>
<File
RelativePath="..\..\Source\FileOperations.h">
</File>
<File
RelativePath="..\..\Source\FormatString.h">
</File>
<File
RelativePath="..\..\Source\FullyConnectedMesh.h">
</File>
<File
RelativePath="..\..\Source\FunctionThread.h">
</File>
<File
RelativePath="..\..\Source\GetTime.h">
</File>
<File
RelativePath="..\..\Source\GridSectorizer.h">
</File>
<File
RelativePath="..\..\Source\HTTPConnection.h">
</File>
<File
RelativePath="..\..\Source\InternalPacket.h">
</File>
<File
RelativePath="..\..\Source\Itoa.h">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseClient.h">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseCommon.h">
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseServer.h">
</File>
<File
RelativePath="..\..\Source\LinuxStrings.h">
</File>
<File
RelativePath="..\..\Source\LogCommandParser.h">
</File>
<File
RelativePath="..\..\Source\MessageFilter.h">
</File>
<File
RelativePath="..\..\Source\MessageIdentifiers.h">
</File>
<File
RelativePath="..\..\Source\MTUSize.h">
</File>
<File
RelativePath="..\..\Source\NatPunchthrough.h">
</File>
<File
RelativePath="..\..\Source\NetworkIDManager.h">
</File>
<File
RelativePath="..\..\Source\NetworkIDObject.h">
</File>
<File
RelativePath="..\..\Source\PacketConsoleLogger.h">
</File>
<File
RelativePath="..\..\Source\PacketFileLogger.h">
</File>
<File
RelativePath="..\..\Source\PacketLogger.h">
</File>
<File
RelativePath="..\..\Source\PacketPool.h">
</File>
<File
RelativePath="..\..\Source\PacketPriority.h">
</File>
<File
RelativePath="..\..\Source\PluginInterface.h">
</File>
<File
RelativePath="..\..\Source\RakAssert.h">
</File>
<File
RelativePath="..\..\Source\RakMemoryOverride.h">
</File>
<File
RelativePath="..\..\Source\RakNetCommandParser.h">
</File>
<File
RelativePath="..\..\Source\RakNetDefines.h">
</File>
<File
RelativePath="..\..\Source\RakNetStatistics.h">
</File>
<File
RelativePath="..\..\Source\RakNetTransport.h">
</File>
<File
RelativePath="..\..\Source\RakNetTypes.h">
</File>
<File
RelativePath="..\..\Source\RakNetVersion.h">
</File>
<File
RelativePath="..\..\Source\RakNetworkFactory.h">
</File>
<File
RelativePath="..\..\Source\RakPeer.h">
</File>
<File
RelativePath="..\..\Source\RakPeerInterface.h">
</File>
<File
RelativePath="..\..\Source\RakSleep.h">
</File>
<File
RelativePath="..\..\Source\RakString.h">
</File>
<File
RelativePath="..\..\Source\RakThread.h">
</File>
<File
RelativePath="..\..\Source\Rand.h">
</File>
<File
RelativePath="..\..\Source\ReadyEvent.h">
</File>
<File
RelativePath="..\..\Source\RefCountedObj.h">
</File>
<File
RelativePath="..\..\Source\ReliabilityLayer.h">
</File>
<File
RelativePath="..\..\Source\Replica.h">
</File>
<File
RelativePath="..\..\Source\ReplicaEnums.h">
</File>
<File
RelativePath="..\..\Source\ReplicaManager.h">
</File>
<File
RelativePath="..\..\Source\ReplicaManager2.h">
</File>
<File
RelativePath="..\..\Source\Rijndael-Boxes.h">
</File>
<File
RelativePath="..\..\Source\Rijndael.h">
</File>
<File
RelativePath="..\..\Source\Router.h">
</File>
<File
RelativePath="..\..\Source\RouterInterface.h">
</File>
<File
RelativePath="..\..\Source\RPCMap.h">
</File>
<File
RelativePath="..\..\Source\RPCNode.h">
</File>
<File
RelativePath="..\..\Source\RSACrypt.h">
</File>
<File
RelativePath="..\..\Source\SHA1.h">
</File>
<File
RelativePath="..\..\Source\SimpleMutex.h">
</File>
<File
RelativePath="..\..\Source\SimpleTCPServer.h">
</File>
<File
RelativePath="..\..\Source\SingleProducerConsumer.h">
</File>
<File
RelativePath="..\..\Source\SocketLayer.h">
</File>
<File
RelativePath="..\..\Source\StringCompressor.h">
</File>
<File
RelativePath="..\..\Source\StringTable.h">
</File>
<File
RelativePath="..\..\Source\SuperFastHashTable.h">
</File>
<File
RelativePath="..\..\Source\SystemAddressList.h">
</File>
<File
RelativePath="..\..\Source\TableSerializer.h">
</File>
<File
RelativePath="..\..\Source\TCPInterface.h">
</File>
<File
RelativePath="..\..\Source\TelnetTransport.h">
</File>
<File
RelativePath="..\..\Source\ThreadPool.h">
</File>
<File
RelativePath="..\..\Source\ThreadsafePacketLogger.h">
</File>
<File
RelativePath="..\..\Source\TransportInterface.h">
</File>
<File
RelativePath="..\..\Source\Types.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,926 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="LibStatic"
ProjectGUID="{6533BDAE-0F0C-45E4-8FE7-ADD0F37FE063}"
RootNamespace="LibStatic"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="./../../Source;./../../DependentExtensions/openssl-0.9.8g"
PreprocessorDefinitions="WIN32;_DEBUG;_RAKNET_LIB;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
DisableLanguageExtensions="false"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)/../../RakNetLibStaticDebug"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/../../RakNetLibStaticDebug.lib"
IgnoreDefaultLibraryNames="LIBCD.lib LIBCMTD.lib MSVCRT.lib"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="./../../Source;./../../DependentExtensions/openssl-0.9.8g"
PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;WIN32;_RELEASE;_RAKNET_LIB;_CRT_NONSTDC_NO_DEPRECATE"
RuntimeLibrary="0"
BufferSecurityCheck="false"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)/../../RakNetLibStatic"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/../../RakNetLibStatic.lib"
IgnoreDefaultLibraryNames="LIBC.lib LIBCMT.lib MSVCRT.lib"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\..\Source\_FindFirst.cpp"
>
</File>
<File
RelativePath="..\..\Source\AsynchronousFileIO.cpp"
>
</File>
<File
RelativePath="..\..\Source\AutoRPC.cpp"
>
</File>
<File
RelativePath="..\..\Source\BitStream.cpp"
>
</File>
<File
RelativePath="..\..\Source\BitStream_NoTemplate.cpp"
>
</File>
<File
RelativePath="..\..\Source\CheckSum.cpp"
>
</File>
<File
RelativePath="..\..\Source\CommandParserInterface.cpp"
>
</File>
<File
RelativePath="..\..\Source\ConnectionGraph.cpp"
>
</File>
<File
RelativePath="..\..\Source\ConsoleServer.cpp"
>
</File>
<File
RelativePath="..\..\Source\DataBlockEncryptor.cpp"
>
</File>
<File
RelativePath="..\..\Source\DataCompressor.cpp"
>
</File>
<File
RelativePath="..\..\Source\DirectoryDeltaTransfer.cpp"
>
</File>
<File
RelativePath="..\..\Source\DS_BytePool.cpp"
>
</File>
<File
RelativePath="..\..\Source\DS_ByteQueue.cpp"
>
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTree.cpp"
>
</File>
<File
RelativePath="..\..\Source\DS_Table.cpp"
>
</File>
<File
RelativePath="..\..\Source\EmailSender.cpp"
>
</File>
<File
RelativePath="..\..\Source\EncodeClassName.cpp"
>
</File>
<File
RelativePath="..\..\Source\EpochTimeToString.cpp"
>
</File>
<File
RelativePath="..\..\Source\ExtendedOverlappedPool.cpp"
>
</File>
<File
RelativePath="..\..\Source\FileList.cpp"
>
</File>
<File
RelativePath="..\..\Source\FileListTransfer.cpp"
>
</File>
<File
RelativePath="..\..\Source\FileOperations.cpp"
>
</File>
<File
RelativePath="..\..\Source\FormatString.cpp"
>
</File>
<File
RelativePath="..\..\Source\FullyConnectedMesh.cpp"
>
</File>
<File
RelativePath="..\..\Source\FunctionThread.cpp"
>
</File>
<File
RelativePath="..\..\Source\Gen_RPC8.cpp"
>
</File>
<File
RelativePath="..\..\Source\GetTime.cpp"
>
</File>
<File
RelativePath="..\..\Source\GridSectorizer.cpp"
>
</File>
<File
RelativePath="..\..\Source\HTTPConnection.cpp"
>
</File>
<File
RelativePath="..\..\Source\Itoa.cpp"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseClient.cpp"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseCommon.cpp"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseServer.cpp"
>
</File>
<File
RelativePath="..\..\Source\LinuxStrings.cpp"
>
</File>
<File
RelativePath="..\..\Source\LogCommandParser.cpp"
>
</File>
<File
RelativePath="..\..\Source\MessageFilter.cpp"
>
</File>
<File
RelativePath="..\..\Source\NatPunchthrough.cpp"
>
</File>
<File
RelativePath="..\..\Source\NetworkIDManager.cpp"
>
</File>
<File
RelativePath="..\..\Source\NetworkIDObject.cpp"
>
</File>
<File
RelativePath="..\..\Source\PacketConsoleLogger.cpp"
>
</File>
<File
RelativePath="..\..\Source\PacketFileLogger.cpp"
>
</File>
<File
RelativePath="..\..\Source\PacketLogger.cpp"
>
</File>
<File
RelativePath="..\..\Source\PluginInterface.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakMemoryOverride.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetCommandParser.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetStatistics.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetTransport.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetTypes.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakNetworkFactory.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakPeer.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakSleep.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakString.cpp"
>
</File>
<File
RelativePath="..\..\Source\RakThread.cpp"
>
</File>
<File
RelativePath="..\..\Source\Rand.cpp"
>
</File>
<File
RelativePath="..\..\Source\ReadyEvent.cpp"
>
</File>
<File
RelativePath="..\..\Source\ReliabilityLayer.cpp"
>
</File>
<File
RelativePath="..\..\Source\ReplicaManager.cpp"
>
</File>
<File
RelativePath="..\..\Source\ReplicaManager2.cpp"
>
</File>
<File
RelativePath="..\..\Source\rijndael.cpp"
>
</File>
<File
RelativePath="..\..\Source\Router.cpp"
>
</File>
<File
RelativePath="..\..\Source\RPCMap.cpp"
>
</File>
<File
RelativePath="..\..\Source\SHA1.cpp"
>
</File>
<File
RelativePath="..\..\Source\SimpleMutex.cpp"
>
</File>
<File
RelativePath="..\..\Source\SocketLayer.cpp"
>
</File>
<File
RelativePath="..\..\Source\StringCompressor.cpp"
>
</File>
<File
RelativePath="..\..\Source\StringTable.cpp"
>
</File>
<File
RelativePath="..\..\Source\SuperFastHash.cpp"
>
</File>
<File
RelativePath="..\..\Source\SystemAddressList.cpp"
>
</File>
<File
RelativePath="..\..\Source\TableSerializer.cpp"
>
</File>
<File
RelativePath="..\..\Source\TCPInterface.cpp"
>
</File>
<File
RelativePath="..\..\Source\TelnetTransport.cpp"
>
</File>
<File
RelativePath="..\..\Source\ThreadsafePacketLogger.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\..\Source\_FindFirst.h"
>
</File>
<File
RelativePath="..\..\Source\AsynchronousFileIO.h"
>
</File>
<File
RelativePath="..\..\Source\AutopatcherPatchContext.h"
>
</File>
<File
RelativePath="..\..\Source\AutopatcherRepositoryInterface.h"
>
</File>
<File
RelativePath="..\..\Source\AutoRPC.h"
>
</File>
<File
RelativePath="..\..\Source\BigTypes.h"
>
</File>
<File
RelativePath="..\..\Source\BitStream.h"
>
</File>
<File
RelativePath="..\..\Source\BitStream_NoTemplate.h"
>
</File>
<File
RelativePath="..\..\Source\CheckSum.h"
>
</File>
<File
RelativePath="..\..\Source\ClientContextStruct.h"
>
</File>
<File
RelativePath="..\..\Source\CommandParserInterface.h"
>
</File>
<File
RelativePath="..\..\Source\ConnectionGraph.h"
>
</File>
<File
RelativePath="..\..\Source\ConsoleServer.h"
>
</File>
<File
RelativePath="..\..\Source\DataBlockEncryptor.h"
>
</File>
<File
RelativePath="..\..\Source\DataCompressor.h"
>
</File>
<File
RelativePath="..\..\Source\DirectoryDeltaTransfer.h"
>
</File>
<File
RelativePath="..\..\Source\DS_BinarySearchTree.h"
>
</File>
<File
RelativePath="..\..\Source\DS_BPlusTree.h"
>
</File>
<File
RelativePath="..\..\Source\DS_BytePool.h"
>
</File>
<File
RelativePath="..\..\Source\DS_ByteQueue.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Heap.h"
>
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTree.h"
>
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTreeFactory.h"
>
</File>
<File
RelativePath="..\..\Source\DS_HuffmanEncodingTreeNode.h"
>
</File>
<File
RelativePath="..\..\Source\DS_LinkedList.h"
>
</File>
<File
RelativePath="..\..\Source\DS_List.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Map.h"
>
</File>
<File
RelativePath="..\..\Source\DS_MemoryPool.h"
>
</File>
<File
RelativePath="..\..\Source\DS_OrderedChannelHeap.h"
>
</File>
<File
RelativePath="..\..\Source\DS_OrderedList.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Queue.h"
>
</File>
<File
RelativePath="..\..\Source\DS_QueueLinkedList.h"
>
</File>
<File
RelativePath="..\..\Source\DS_RangeList.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Table.h"
>
</File>
<File
RelativePath="..\..\Source\DS_Tree.h"
>
</File>
<File
RelativePath="..\..\Source\DS_WeightedGraph.h"
>
</File>
<File
RelativePath="..\..\Source\EmailSender.h"
>
</File>
<File
RelativePath="..\..\Source\EpochTimeToString.h"
>
</File>
<File
RelativePath="..\..\Source\Export.h"
>
</File>
<File
RelativePath="..\..\Source\ExtendedOverlappedPool.h"
>
</File>
<File
RelativePath="..\..\Source\FileList.h"
>
</File>
<File
RelativePath="..\..\Source\FileListTransfer.h"
>
</File>
<File
RelativePath="..\..\Source\FileListTransferCBInterface.h"
>
</File>
<File
RelativePath="..\..\Source\FileOperations.h"
>
</File>
<File
RelativePath="..\..\Source\FormatString.h"
>
</File>
<File
RelativePath="..\..\Source\FullyConnectedMesh.h"
>
</File>
<File
RelativePath="..\..\Source\FunctionThread.h"
>
</File>
<File
RelativePath="..\..\Source\Gen_RPC8.h"
>
</File>
<File
RelativePath="..\..\Source\GetTime.h"
>
</File>
<File
RelativePath="..\..\Source\GridSectorizer.h"
>
</File>
<File
RelativePath="..\..\Source\HTTPConnection.h"
>
</File>
<File
RelativePath="..\..\Source\InternalPacket.h"
>
</File>
<File
RelativePath="..\..\Source\Itoa.h"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseClient.h"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseCommon.h"
>
</File>
<File
RelativePath="..\..\Source\LightweightDatabaseServer.h"
>
</File>
<File
RelativePath="..\..\Source\LinuxStrings.h"
>
</File>
<File
RelativePath="..\..\Source\LogCommandParser.h"
>
</File>
<File
RelativePath="..\..\Source\MessageFilter.h"
>
</File>
<File
RelativePath="..\..\Source\MessageIdentifiers.h"
>
</File>
<File
RelativePath="..\..\Source\MTUSize.h"
>
</File>
<File
RelativePath="..\..\Source\NatPunchthrough.h"
>
</File>
<File
RelativePath="..\..\Source\NetworkIDManager.h"
>
</File>
<File
RelativePath="..\..\Source\NetworkIDObject.h"
>
</File>
<File
RelativePath="..\..\Source\PacketConsoleLogger.h"
>
</File>
<File
RelativePath="..\..\Source\PacketFileLogger.h"
>
</File>
<File
RelativePath="..\..\Source\PacketLogger.h"
>
</File>
<File
RelativePath="..\..\Source\PacketPool.h"
>
</File>
<File
RelativePath="..\..\Source\PacketPriority.h"
>
</File>
<File
RelativePath="..\..\Source\PluginInterface.h"
>
</File>
<File
RelativePath="..\..\Source\RakAssert.h"
>
</File>
<File
RelativePath="..\..\Source\RakMemoryOverride.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetCommandParser.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetDefines.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetStatistics.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetTransport.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetTypes.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetVersion.h"
>
</File>
<File
RelativePath="..\..\Source\RakNetworkFactory.h"
>
</File>
<File
RelativePath="..\..\Source\RakPeer.h"
>
</File>
<File
RelativePath="..\..\Source\RakPeerInterface.h"
>
</File>
<File
RelativePath="..\..\Source\RakSleep.h"
>
</File>
<File
RelativePath="..\..\Source\RakString.h"
>
</File>
<File
RelativePath="..\..\Source\RakThread.h"
>
</File>
<File
RelativePath="..\..\Source\Rand.h"
>
</File>
<File
RelativePath="..\..\Source\ReadyEvent.h"
>
</File>
<File
RelativePath="..\..\Source\RefCountedObj.h"
>
</File>
<File
RelativePath="..\..\Source\ReliabilityLayer.h"
>
</File>
<File
RelativePath="..\..\Source\Replica.h"
>
</File>
<File
RelativePath="..\..\Source\ReplicaEnums.h"
>
</File>
<File
RelativePath="..\..\Source\ReplicaManager.h"
>
</File>
<File
RelativePath="..\..\Source\ReplicaManager2.h"
>
</File>
<File
RelativePath="..\..\Source\Rijndael-Boxes.h"
>
</File>
<File
RelativePath="..\..\Source\Rijndael.h"
>
</File>
<File
RelativePath="..\..\Source\Router.h"
>
</File>
<File
RelativePath="..\..\Source\RouterInterface.h"
>
</File>
<File
RelativePath="..\..\Source\RPCMap.h"
>
</File>
<File
RelativePath="..\..\Source\RPCNode.h"
>
</File>
<File
RelativePath="..\..\Source\RSACrypt.h"
>
</File>
<File
RelativePath="..\..\Source\SHA1.h"
>
</File>
<File
RelativePath="..\..\Source\SimpleMutex.h"
>
</File>
<File
RelativePath="..\..\Source\SimpleTCPServer.h"
>
</File>
<File
RelativePath="..\..\Source\SingleProducerConsumer.h"
>
</File>
<File
RelativePath="..\..\Source\SocketLayer.h"
>
</File>
<File
RelativePath="..\..\Source\StringCompressor.h"
>
</File>
<File
RelativePath="..\..\Source\StringTable.h"
>
</File>
<File
RelativePath="..\..\Source\SuperFastHash.h"
>
</File>
<File
RelativePath="..\..\Source\SystemAddressList.h"
>
</File>
<File
RelativePath="..\..\Source\TableSerializer.h"
>
</File>
<File
RelativePath="..\..\Source\TCPInterface.h"
>
</File>
<File
RelativePath="..\..\Source\TelnetTransport.h"
>
</File>
<File
RelativePath="..\..\Source\ThreadPool.h"
>
</File>
<File
RelativePath="..\..\Source\ThreadsafePacketLogger.h"
>
</File>
<File
RelativePath="..\..\Source\TransportInterface.h"
>
</File>
<File
RelativePath="..\..\Source\Types.h"
>
</File>
</Filter>
<File
RelativePath=".\readme.txt"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

BIN
thirdparty/raknet/Lib/libRakNet.a vendored Normal file

Binary file not shown.

BIN
thirdparty/raknet/Lib/libRakNetRegular.a vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,323 @@
/// \file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
// No longer used as I no longer support IO Completion ports
/*
#ifdef __USE_IO_COMPLETION_PORTS
#include "AsynchronousFileIO.h"
#include "ClientContextStruct.h"
#include <process.h>
#include "ExtendedOverlappedPool.h"
#include <stdio.h>
#include <assert.h>
// All these are used for the Read callback. For general Asynch file IO you would change these
#include "RakNetTypes.h"
class RakPeer;
#ifdef _WIN32
extern void __stdcall ProcessNetworkPacket( unsigned int binaryAddress, unsigned short port, const char *data, int length, RakPeer *rakPeer );
#else
extern void ProcessNetworkPacket( unsigned int binaryAddress, unsigned short port, const char *data, int length, RakPeer *rakPeer );
#endif
AsynchronousFileIO AsynchronousFileIO::I;
AsynchronousFileIO::AsynchronousFileIO()
{
userCount = 0;
threadCount = 0;
completionPort = NULL;
// Determine how many processors are on the system.
GetSystemInfo( &systemInfo );
}
void AsynchronousFileIO::IncreaseUserCount()
{
userCountMutex.Lock();
++userCount;
if ( userCount == 1 )
{
// Create the completion port that will be used by all the worker
// threads.
completionPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, systemInfo.dwNumberOfProcessors * 2 );
if ( completionPort == NULL )
{
userCount = 0;
userCountMutex.Unlock();
return ;
}
UINT nThreadID;
HANDLE workerHandle;
// Create worker threads
// One worker thread per processor
for ( DWORD i = 0; i < systemInfo.dwNumberOfProcessors * 2; i++ )
// In debug just make one worker thread so it's easier to trace
//for ( i = 0; i < systemInfo.dwNumberOfProcessors * 1; i++ )
{
workerHandle = ( HANDLE ) _beginthreadex( NULL, // Security
0, // Stack size - use default
ThreadPoolFunc, // Thread fn entry point
( void* ) completionPort, // Param for thread
0, // Init flag
&nThreadID ); // Thread address
// Feel free to comment this out for regular thread priority
SetThreadPriority( workerHandle, THREAD_PRIORITY_HIGHEST );
CloseHandle( workerHandle );
}
// Wait for the threads to start
while ( threadCount < systemInfo.dwNumberOfProcessors * 2 )
Sleep( 0 );
}
userCountMutex.Unlock();
}
void AsynchronousFileIO::DecreaseUserCount()
{
userCountMutex.Lock();
assert( userCount > 0 );
if ( userCount == 0 )
return ;
userCount--;
if ( userCount == 0 )
Shutdown();
userCountMutex.Unlock();
}
void AsynchronousFileIO::Shutdown( void )
{
killThreads = true;
if ( completionPort != NULL )
for ( DWORD i = 0; i < systemInfo.dwNumberOfProcessors * 2; i++ )
PostQueuedCompletionStatus( completionPort, 0, 0 , 0 );
// Kill worker threads
while ( threadCount > 0 )
Sleep( 0 );
if ( completionPort != NULL )
CloseHandle( completionPort );
}
int AsynchronousFileIO::GetUserCount( void )
{
return userCount;
}
AsynchronousFileIO::~AsynchronousFileIO()
{
if ( threadCount > 0 )
Shutdown();
}
bool AsynchronousFileIO::AssociateSocketWithCompletionPort( SOCKET socket, DWORD dwCompletionKey )
{
HANDLE h = CreateIoCompletionPort( ( HANDLE ) socket, completionPort, dwCompletionKey, 0 );
return h == completionPort;
}
BOOL ReadAsynch( HANDLE handle, ExtendedOverlappedStruct *extended )
{
BOOL success;
extended->read = true;
success = ReadFile( handle, extended->data, extended->length, 0, ( LPOVERLAPPED ) extended );
if ( !success )
{
DWORD dwErrCode = GetLastError();
if ( dwErrCode != ERROR_IO_PENDING )
{
#if defined(_WIN32) && !defined(_XBOX360) && defined(_DEBUG)
LPVOID messageBuffer;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwErrCode, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
( LPTSTR ) & messageBuffer, 0, NULL );
// something has gone wrong here...
printf( "ReadFile failed:Error code - %d\n%s", dwErrCode, messageBuffer );
//Free the buffer.
LocalFree( messageBuffer );
#endif
return FALSE;
}
}
return TRUE;
}
void WriteAsynch( HANDLE handle, ExtendedOverlappedStruct *extended )
{
//printf("Beginning asynch write of %i bytes.\n",extended->length);
//for (int i=0; i < extended->length && i < 10; i++)
// printf("%i ", extended->data[i]);
//printf("\n\n");
BOOL success;
extended->read = false;
success = WriteFile( handle, extended->data, extended->length, 0, ( LPOVERLAPPED ) extended );
if ( !success )
{
DWORD dwErrCode = GetLastError();
if ( dwErrCode != ERROR_IO_PENDING )
{
#if defined(_WIN32) && !defined(_XBOX360) && defined(_DEBUG)
LPVOID messageBuffer;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwErrCode, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
( LPTSTR ) & messageBuffer, 0, NULL );
// something has gone wrong here...
printf( "WriteFile failed:Error code - %d\n%s", dwErrCode, messageBuffer );
//Free the buffer.
LocalFree( messageBuffer );
#endif
}
}
}
unsigned __stdcall ThreadPoolFunc( LPVOID arguments )
{
DWORD dwIoSize;
ClientContextStruct* lpClientContext;
ExtendedOverlappedStruct* lpOverlapped;
LPOVERLAPPED temp;
BOOL bError;
HANDLE *completionPort = ( HANDLE * ) arguments;
AsynchronousFileIO::Instance()->threadCount++;
while ( 1 )
{
// Get a completed IO request.
BOOL returnValue = GetQueuedCompletionStatus(
completionPort,
&dwIoSize,
( LPDWORD ) & lpClientContext,
&temp, INFINITE );
lpOverlapped = ( ExtendedOverlappedStruct* ) temp;
DWORD dwIOError = GetLastError();
if ( lpOverlapped == 0 )
break; // Cancelled thread
if ( !returnValue && dwIOError != WAIT_TIMEOUT )
{
if ( dwIOError != ERROR_OPERATION_ABORTED )
{
// Print all but this very common error message
#if defined(_WIN32) && !defined(_XBOX360) && defined(_DEBUG)
LPVOID messageBuffer;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwIOError, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
( LPTSTR ) & messageBuffer, 0, NULL );
// something has gone wrong here...
printf( "GetQueuedCompletionStatus failed:Error code - %d\n%s", dwIOError, messageBuffer );
//Free the buffer.
LocalFree( messageBuffer );
#endif
}
HANDLE_ERROR:
// Some kind of error. Erase the data for this call
bError = true;
// This socket is no longer used
if ( lpOverlapped )
delete lpOverlapped;
if ( lpClientContext )
delete lpClientContext;
// If we are killing the threads, then we keep posting fake completion statuses until we get a fake one through the queue (i.e. lpOverlapped==0 as above)
// This way we delete all the data from the real calls before exiting the thread
if ( AsynchronousFileIO::Instance()->killThreads )
{
PostQueuedCompletionStatus( completionPort, 0, 0, 0 );
}
}
else
bError = false;
if ( !bError )
{
if ( returnValue && NULL != lpOverlapped && NULL != lpClientContext )
{
if ( lpOverlapped->read == true )
{
assert( dwIoSize > 0 );
ProcessNetworkPacket( lpOverlapped->binaryAddress, lpOverlapped->port, lpOverlapped->data, dwIoSize, lpOverlapped->rakPeer );
// Issue a new read so we always have one outstanding read per socket
// Finished a read. Reuse the overlapped pointer
bError = ReadAsynch( lpClientContext->handle, lpOverlapped );
if ( !bError )
goto HANDLE_ERROR; // Windows is super unreliable!
}
else
{
// AsynchronousFileIO::Instance()->Write(lpClientContext);
// Finished a write
ExtendedOverlappedPool::Instance()->ReleasePointer( lpOverlapped );
}
}
else
assert( 0 );
}
}
AsynchronousFileIO::Instance()->threadCount--;
return 0;
}
#endif
*/

View File

@@ -0,0 +1,91 @@
/// \file
/// \brief \b [Internal] Depreciated, used for windows back when I supported IO completion ports.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
// No longer used as I no longer support IO Completion ports
/*
#ifdef __USE_IO_COMPLETION_PORTS
#ifndef __ASYNCHRONOUS_FILE_IO_H
#define __ASYNCHRONOUS_FILE_IO_H
#ifdef _XBOX360
#elif defined(_WIN32)
// IP_DONTFRAGMENT is different between winsock 1 and winsock 2. Therefore, Winsock2.h must be linked againt Ws2_32.lib
// winsock.h must be linked against WSock32.lib. If these two are mixed up the flag won't work correctly
//#include <winsock2.h>
//#include <windows.h>
#endif
#include "SimpleMutex.h"
struct ExtendedOverlappedStruct;
/// Provides asynch file input and ouput, either for sockets or files
class AsynchronousFileIO
{
public:
/// Default Constructor
AsynchronousFileIO();
/// Destructor
~AsynchronousFileIO();
/// Associate a socket with a completion port
/// \param[in] socket the socket used for communication
/// \param[in] dwCompletionKey the completion port key
bool AssociateSocketWithCompletionPort( SOCKET socket, DWORD dwCompletionKey );if
/// Singleton instance
static inline AsynchronousFileIO* Instance()
{
return & I;
}
/// Increase the number of users of this instance
void IncreaseUserCount( void );
/// Decrease the number of users of this instance
void DecreaseUserCount( void );
/// Stop using asynchronous IO
void Shutdown( void );
/// Get the number of user of the instance
int GetUserCount( void );
unsigned threadCount;
bool killThreads;
private:
HANDLE completionPort;
SimpleMutex userCountMutex;
SYSTEM_INFO systemInfo;
int userCount;
static AsynchronousFileIO I;
};
unsigned __stdcall ThreadPoolFunc( LPVOID arguments );
void WriteAsynch( HANDLE handle, ExtendedOverlappedStruct *extended );
BOOL ReadAsynch( HANDLE handle, ExtendedOverlappedStruct *extended );
#endif
*/

717
thirdparty/raknet/Source/AutoRPC.cpp vendored Normal file
View File

@@ -0,0 +1,717 @@
#include "AutoRPC.h"
#include "RakMemoryOverride.h"
#include "RakAssert.h"
#include "StringCompressor.h"
#include "BitStream.h"
#include "Types.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "NetworkIDObject.h"
#include "NetworkIDManager.h"
#include <stdlib.h>
using namespace RakNet;
#ifdef _MSC_VER
#pragma warning( push )
#endif
int AutoRPC::RemoteRPCFunctionComp( const RPCIdentifier &key, const RemoteRPCFunction &data )
{
if (key.isObjectMember==false && data.identifier.isObjectMember==true)
return -1;
if (key.isObjectMember==true && data.identifier.isObjectMember==false)
return 1;
return strcmp(key.uniqueIdentifier, data.identifier.uniqueIdentifier);
}
AutoRPC::AutoRPC()
{
currentExecution[0]=0;
rakPeer=0;
networkIdManager=0;
outgoingTimestamp=0;
outgoingPriority=HIGH_PRIORITY;
outgoingReliability=RELIABLE_ORDERED;
outgoingOrderingChannel=0;
outgoingBroadcast=true;
incomingTimeStamp=0;
DataStructures::Map<SystemAddress, DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp> *>::IMPLEMENT_DEFAULT_COMPARISON();
}
AutoRPC::~AutoRPC()
{
Clear();
}
void AutoRPC::SetNetworkIDManager(NetworkIDManager *idMan)
{
networkIdManager=idMan;
}
bool AutoRPC::RegisterFunction(const char *uniqueIdentifier, void* functionPtr, bool isObjectMember, char parameterCount)
{
return RegisterFunction( uniqueIdentifier, GenRPC::PMF( functionPtr ), isObjectMember, parameterCount );
}
bool AutoRPC::RegisterFunction(const char *uniqueIdentifier, GenRPC::PMF functionPtr, bool isObjectMember, char parameterCount)
{
if (uniqueIdentifier==0 || functionPtr==0)
{
RakAssert(0);
return false;
}
RPCIdentifier identifier;
identifier.isObjectMember=isObjectMember;
identifier.uniqueIdentifier=(char*) uniqueIdentifier;
unsigned localIndex = GetLocalFunctionIndex(identifier);
// Already registered?
if (localIndex!=(unsigned)-1 && localFunctions[localIndex].functionPtr!=0)
return false;
if (localIndex!=(unsigned)-1)
{
// Reenable existing
localFunctions[localIndex].functionPtr=functionPtr;
localFunctions[localIndex].parameterCount=parameterCount;
}
else
{
// Add new
LocalRPCFunction func;
func.functionPtr=functionPtr;
func.identifier.isObjectMember=isObjectMember;
func.identifier.uniqueIdentifier = (char*) rakMalloc(strlen(uniqueIdentifier)+1);
func.parameterCount=parameterCount;
strcpy(func.identifier.uniqueIdentifier, uniqueIdentifier);
localFunctions.Insert(func);
}
return true;
}
bool AutoRPC::UnregisterFunction(const char *uniqueIdentifier, bool isObjectMember)
{
if (uniqueIdentifier==0)
{
RakAssert(0);
return false;
}
RPCIdentifier identifier;
identifier.isObjectMember=isObjectMember;
identifier.uniqueIdentifier=(char*) uniqueIdentifier;
unsigned localIndex = GetLocalFunctionIndex(identifier);
// Not registered?
if (localIndex==(unsigned)-1)
return false;
// Leave the id in, in case the function is set again later. That way we keep the same remote index
localFunctions[localIndex].functionPtr=0;
return true;
}
void AutoRPC::SetTimestamp(RakNetTime timeStamp)
{
outgoingTimestamp=timeStamp;
}
void AutoRPC::SetSendParams(PacketPriority priority, PacketReliability reliability, char orderingChannel)
{
outgoingPriority=priority;
outgoingReliability=reliability;
outgoingOrderingChannel=orderingChannel;
}
void AutoRPC::SetRecipientAddress(SystemAddress systemAddress, bool broadcast)
{
outgoingSystemAddress=systemAddress;
outgoingBroadcast=broadcast;
}
void AutoRPC::SetRecipientObject(NetworkID networkID)
{
outgoingNetworkID=networkID;
}
RakNet::BitStream *AutoRPC::SetOutgoingExtraData(void)
{
return &outgoingExtraData;
}
RakNetTime AutoRPC::GetLastSenderTimestamp(void) const
{
return incomingTimeStamp;
}
SystemAddress AutoRPC::GetLastSenderAddress(void) const
{
return incomingSystemAddress;
}
RakPeerInterface *AutoRPC::GetRakPeer(void) const
{
return rakPeer;
}
const char *AutoRPC::GetCurrentExecution(void) const
{
return (const char *) currentExecution;
}
RakNet::BitStream *AutoRPC::GetIncomingExtraData(void)
{
return &incomingExtraData;
}
bool AutoRPC::SendCall(const char *uniqueIdentifier, const char *stack, unsigned int bytesOnStack, char parameterCount)
{
SystemAddress systemAddr;
RPCIdentifier identifier;
unsigned int outerIndex;
unsigned int innerIndex;
if (uniqueIdentifier==0)
return false;
identifier.uniqueIdentifier=(char*) uniqueIdentifier;
identifier.isObjectMember=(outgoingNetworkID!=UNASSIGNED_NETWORK_ID);
RakNet::BitStream bs;
if (outgoingTimestamp!=0)
{
bs.Write((MessageID)ID_TIMESTAMP);
bs.Write(outgoingTimestamp);
}
bs.Write((MessageID)ID_AUTO_RPC_CALL);
if (parameterCount>=0)
{
bs.Write(true);
bs.Write(parameterCount);
}
else
{
bs.Write(false);
}
bs.WriteCompressed(outgoingExtraData.GetNumberOfBitsUsed());
bs.Write(&outgoingExtraData);
if (outgoingNetworkID!=UNASSIGNED_NETWORK_ID)
{
bs.Write(true);
bs.Write(outgoingNetworkID);
}
else
{
bs.Write(false);
}
// This is so the call SetWriteOffset works
bs.AlignWriteToByteBoundary();
BitSize_t writeOffset = bs.GetWriteOffset();
if (outgoingBroadcast)
{
unsigned systemIndex;
for (systemIndex=0; systemIndex < rakPeer->GetMaximumNumberOfPeers(); systemIndex++)
{
systemAddr=rakPeer->GetSystemAddressFromIndex(systemIndex);
if (systemAddr!=UNASSIGNED_SYSTEM_ADDRESS && systemAddr!=outgoingSystemAddress)
{
if (GetRemoteFunctionIndex(systemAddr, identifier, &outerIndex, &innerIndex))
{
// Write a number to identify the function if possible, for faster lookup and less bandwidth
bs.Write(true);
bs.WriteCompressed(remoteFunctions[outerIndex]->operator [](innerIndex).functionIndex);
}
else
{
bs.Write(false);
stringCompressor->EncodeString(uniqueIdentifier, 512, &bs, 0);
}
bs.WriteCompressed(bytesOnStack);
bs.WriteAlignedBytes((const unsigned char*) stack, bytesOnStack);
rakPeer->Send(&bs, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddr, false);
// Start writing again after ID_AUTO_RPC_CALL
bs.SetWriteOffset(writeOffset);
}
}
}
else
{
systemAddr = outgoingSystemAddress;
if (systemAddr!=UNASSIGNED_SYSTEM_ADDRESS)
{
if (GetRemoteFunctionIndex(systemAddr, identifier, &outerIndex, &innerIndex))
{
// Write a number to identify the function if possible, for faster lookup and less bandwidth
bs.Write(true);
bs.WriteCompressed(remoteFunctions[outerIndex]->operator [](innerIndex).functionIndex);
}
else
{
bs.Write(false);
stringCompressor->EncodeString(uniqueIdentifier, 512, &bs, 0);
}
bs.WriteCompressed(bytesOnStack);
bs.WriteAlignedBytes((const unsigned char*) stack, bytesOnStack);
rakPeer->Send(&bs, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddr, false);
}
else
return false;
}
return true;
}
void AutoRPC::OnAttach(RakPeerInterface *peer)
{
rakPeer=peer;
outgoingSystemAddress=UNASSIGNED_SYSTEM_ADDRESS;
outgoingNetworkID=UNASSIGNED_NETWORK_ID;
incomingSystemAddress=UNASSIGNED_SYSTEM_ADDRESS;
}
PluginReceiveResult AutoRPC::OnReceive(RakPeerInterface *peer, Packet *packet)
{
RakNetTime timestamp=0;
unsigned char packetIdentifier, packetDataOffset;
if ( ( unsigned char ) packet->data[ 0 ] == ID_TIMESTAMP )
{
if ( packet->length > sizeof( unsigned char ) + sizeof( RakNetTime ) )
{
packetIdentifier = ( unsigned char ) packet->data[ sizeof( unsigned char ) + sizeof( RakNetTime ) ];
// Required for proper endian swapping
RakNet::BitStream tsBs(packet->data+sizeof(MessageID),packet->length-1,false);
tsBs.Read(timestamp);
packetDataOffset=sizeof( unsigned char )*2 + sizeof( RakNetTime );
}
else
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
else
{
packetIdentifier = ( unsigned char ) packet->data[ 0 ];
packetDataOffset=sizeof( unsigned char );
}
switch (packetIdentifier)
{
case ID_DISCONNECTION_NOTIFICATION:
case ID_CONNECTION_LOST:
OnCloseConnection(peer, packet->systemAddress);
return RR_CONTINUE_PROCESSING;
case ID_AUTO_RPC_CALL:
incomingTimeStamp=timestamp;
incomingSystemAddress=packet->systemAddress;
OnAutoRPCCall(packet->systemAddress, packet->data+packetDataOffset, packet->length-packetDataOffset);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
case ID_AUTO_RPC_REMOTE_INDEX:
OnRPCRemoteIndex(packet->systemAddress, packet->data+packetDataOffset, packet->length-packetDataOffset);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
case ID_AUTO_RPC_UNKNOWN_REMOTE_INDEX:
OnRPCUnknownRemoteIndex(packet->systemAddress, packet->data+packetDataOffset, packet->length-packetDataOffset, timestamp);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
return RR_CONTINUE_PROCESSING;
}
void AutoRPC::OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress)
{
(void) peer;
if (remoteFunctions.Has(systemAddress))
{
DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp> *theList = remoteFunctions.Get(systemAddress);
unsigned i;
for (i=0; i < theList->Size(); i++)
{
if (theList->operator [](i).identifier.uniqueIdentifier)
rakFree(theList->operator [](i).identifier.uniqueIdentifier);
}
delete theList;
remoteFunctions.Delete(systemAddress);
}
}
void AutoRPC::OnAutoRPCCall(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes)
{
RakNet::BitStream bs(data,lengthInBytes,false);
bool hasParameterCount=false;
char parameterCount;
char inputStack[ARPC_MAX_STACK_SIZE];
NetworkIDObject *networkIdObject;
NetworkID networkId;
bool hasNetworkId=false;
bool hasFunctionIndex=false;
unsigned int functionIndex;
unsigned int bytesOnStack;
char strIdentifier[512];
int numberOfBitsUsed;
incomingExtraData.Reset();
bs.Read(hasParameterCount);
if (hasParameterCount)
bs.Read(parameterCount);
else
parameterCount=-1;
bs.ReadCompressed(numberOfBitsUsed);
if (numberOfBitsUsed > (int) incomingExtraData.GetNumberOfBitsAllocated())
incomingExtraData.AddBitsAndReallocate(numberOfBitsUsed-(int) incomingExtraData.GetNumberOfBitsAllocated());
bs.ReadBits(incomingExtraData.GetData(), numberOfBitsUsed, false);
incomingExtraData.SetWriteOffset(numberOfBitsUsed);
// const unsigned int outputStackSize = ARPC_MAX_STACK_SIZE+128*4; // Enough padding to round up to 4 for each parameter, max 128 parameters
// char outputStack[outputStackSize];
bs.Read(hasNetworkId);
if (hasNetworkId)
{
bs.Read(networkId);
if (networkIdManager==0 && (networkIdManager=rakPeer->GetNetworkIDManager())==0)
{
// Failed - Tried to call object member, however, networkIDManager system was never registered
SendError(systemAddress, RPC_ERROR_NETWORK_ID_MANAGER_UNAVAILABLE, "");
return;
}
networkIdObject = (NetworkIDObject*) networkIdManager->GET_OBJECT_FROM_ID(networkId);
if (networkIdObject==0)
{
// Failed - Tried to call object member, object does not exist (deleted?)
SendError(systemAddress, RPC_ERROR_OBJECT_DOES_NOT_EXIST, "");
return;
}
}
else
{
networkIdObject=0;
}
bs.AlignReadToByteBoundary();
bs.Read(hasFunctionIndex);
if (hasFunctionIndex)
bs.ReadCompressed(functionIndex);
else
stringCompressor->DecodeString(strIdentifier,512,&bs,0);
bs.ReadCompressed(bytesOnStack);
bs.ReadAlignedBytes((unsigned char *) inputStack,bytesOnStack);
if (hasFunctionIndex)
{
if (functionIndex>localFunctions.Size())
{
// Failed - other system specified a totally invalid index
// Possible causes: Bugs, attempts to crash the system, requested function not registered
SendError(systemAddress, RPC_ERROR_FUNCTION_INDEX_OUT_OF_RANGE, "");
return;
}
// it was actually a mistake to implement ID_AUTO_RPC_UNKNOWN_REMOTE_INDEX. This hides the more relevant return code RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED and more importantly can result in the calls being out of order since it takes extra communication steps.
/*
if (localFunctions[functionIndex].functionPtr==0)
{
// Failed - Function index lookup failure. Try passing back what was sent to us, and requesting the string
RakNet::BitStream out;
if (incomingTimeStamp!=0)
{
out.Write((MessageID)ID_TIMESTAMP);
out.Write(incomingTimeStamp);
}
out.Write((MessageID)ID_AUTO_RPC_UNKNOWN_REMOTE_INDEX);
if (parameterCount>=0)
{
out.Write(true);
out.Write(parameterCount);
}
else
{
out.Write(false);
}
out.WriteCompressed(functionIndex);
out.WriteCompressed(numberOfBitsUsed);
out.Write(&incomingExtraData);
out.Write(hasNetworkId);
if (hasNetworkId)
out.Write(networkId);
out.WriteCompressed(bytesOnStack);
out.WriteAlignedBytes((const unsigned char*) inputStack, bytesOnStack);
rakPeer->Send(&out, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemAddress, false);
return;
}
*/
}
else
{
// Find the registered function with this str
for (functionIndex=0; functionIndex < localFunctions.Size(); functionIndex++)
{
if (localFunctions[functionIndex].identifier.isObjectMember == (networkIdObject!=0) &&
strcmp(localFunctions[functionIndex].identifier.uniqueIdentifier, strIdentifier)==0)
{
// SEND RPC MAPPING
RakNet::BitStream outgoingBitstream;
outgoingBitstream.Write((MessageID)ID_AUTO_RPC_REMOTE_INDEX);
outgoingBitstream.Write(hasNetworkId);
outgoingBitstream.WriteCompressed(functionIndex);
stringCompressor->EncodeString(strIdentifier,512,&outgoingBitstream,0);
rakPeer->Send(&outgoingBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemAddress, false);
break;
}
}
if (functionIndex==localFunctions.Size())
{
for (functionIndex=0; functionIndex < localFunctions.Size(); functionIndex++)
{
if (strcmp(localFunctions[functionIndex].identifier.uniqueIdentifier, strIdentifier)==0)
{
if (localFunctions[functionIndex].identifier.isObjectMember==true && networkIdObject==0)
{
// Failed - Calling C++ function as C function
SendError(systemAddress, RPC_ERROR_CALLING_CPP_AS_C, strIdentifier);
return;
}
if (localFunctions[functionIndex].identifier.isObjectMember==false && networkIdObject!=0)
{
// Failed - Calling C function as C++ function
SendError(systemAddress, RPC_ERROR_CALLING_C_AS_CPP, strIdentifier);
return;
}
}
}
SendError(systemAddress, RPC_ERROR_FUNCTION_NOT_REGISTERED, strIdentifier);
return;
}
}
if (localFunctions[functionIndex].functionPtr==0)
{
// Failed - Function was previously registered, but isn't registered any longer
SendError(systemAddress, RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED, localFunctions[functionIndex].identifier.uniqueIdentifier);
return;
}
if (bytesOnStack > ARPC_MAX_STACK_SIZE)
{
// Failed - Not enough bytes on predetermined stack. Shouldn't hit this since the sender also uses this value
SendError(systemAddress, RPC_ERROR_STACK_TOO_SMALL, localFunctions[functionIndex].identifier.uniqueIdentifier);
return;
}
if (localFunctions[functionIndex].parameterCount>=0 && parameterCount>=0 && parameterCount!=localFunctions[functionIndex].parameterCount)
{
// Failed - The number of parameters that this function has was explicitly specified, and does not match up.
SendError(systemAddress, RPC_ERROR_INCORRECT_NUMBER_OF_PARAMETERS, localFunctions[functionIndex].identifier.uniqueIdentifier);
return;
}
// unsigned int bytesWritten;
// unsigned char numParameters;
// unsigned int parameterLengths[64]; // 64 is arbitrary, just needs to be more than whatever might be serialized
GenRPC::CallParams call;
// this is the dynamic cast error handling
void* deserialized_this = localFunctions[functionIndex].functionPtr.computeThis( networkIdObject );
#ifdef AUTO_RPC_USE_DYNAMIC_CAST
if ( networkIdObject && !deserialized_this )
{
// This needs its only error message - this happens when dynamic_cast<YourClass*>( networdIdObject )
// fails - i.e. you don't inherit from NetworkIDObject.
SendError(systemAddress, RPC_ERROR_STACK_DESERIALIZATION_FAILED, strIdentifier);
return;
}
#endif
if ( !DeserializeParametersAndBuildCall(call, inputStack, bytesOnStack, this, deserialized_this ) )
{
// Failed - Couldn't deserialize
SendError(systemAddress, RPC_ERROR_STACK_DESERIALIZATION_FAILED, strIdentifier);
return;
}
strncpy(currentExecution, localFunctions[functionIndex].identifier.uniqueIdentifier, sizeof(currentExecution)-1);
if (!CallWithStack( call, localFunctions[functionIndex].functionPtr.computeFuncAddr( networkIdObject ))) {
// Failed - Couldn't deserialize
SendError(systemAddress, RPC_ERROR_STACK_DESERIALIZATION_FAILED, strIdentifier);
return;
}
currentExecution[0]=0;
}
void AutoRPC::OnRPCRemoteIndex(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes)
{
// A remote system has given us their internal index for a particular function.
// Store it and use it from now on, to save bandwidth and search time
bool objectExists;
char strIdentifier[512];
unsigned int insertionIndex;
unsigned int remoteIndex;
RemoteRPCFunction newRemoteFunction;
RakNet::BitStream bs(data,lengthInBytes,false);
RPCIdentifier identifier;
bs.Read(identifier.isObjectMember);
bs.ReadCompressed(remoteIndex);
stringCompressor->DecodeString(strIdentifier,512,&bs,0);
identifier.uniqueIdentifier=strIdentifier;
if (strIdentifier[0]==0)
return;
DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp> *theList;
if (remoteFunctions.Has(systemAddress))
{
theList = remoteFunctions.Get(systemAddress);
insertionIndex=theList->GetIndexFromKey(identifier, &objectExists);
if (objectExists==false)
{
newRemoteFunction.functionIndex=remoteIndex;
newRemoteFunction.identifier.isObjectMember=identifier.isObjectMember;
newRemoteFunction.identifier.uniqueIdentifier = (char*) rakMalloc(strlen(strIdentifier)+1);
strcpy(newRemoteFunction.identifier.uniqueIdentifier, strIdentifier);
theList->InsertAtIndex(newRemoteFunction, insertionIndex);
}
}
else
{
theList = new DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp>;
newRemoteFunction.functionIndex=remoteIndex;
newRemoteFunction.identifier.isObjectMember=identifier.isObjectMember;
newRemoteFunction.identifier.uniqueIdentifier = (char*) rakMalloc(strlen(strIdentifier)+1);
strcpy(newRemoteFunction.identifier.uniqueIdentifier, strIdentifier);
theList->InsertAtEnd(newRemoteFunction);
remoteFunctions.SetNew(systemAddress,theList);
}
}
void AutoRPC::OnRPCUnknownRemoteIndex(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes, RakNetTime timestamp)
{
char inputStack[ARPC_MAX_STACK_SIZE];
NetworkID networkId;
bool hasNetworkId=false;
unsigned int functionIndex;
unsigned int bytesOnStack;
int numberOfBitsUsed;
char parameterCount;
bool hasParameterCount=false;
RakNet::BitStream extraData;
RakNet::BitStream bs(data,lengthInBytes,false);
bs.Read(hasParameterCount);
if (hasParameterCount)
bs.Read(parameterCount);
bs.ReadCompressed(functionIndex);
bs.ReadCompressed(numberOfBitsUsed);
extraData.AddBitsAndReallocate(numberOfBitsUsed);
bs.ReadBits(extraData.GetData(), numberOfBitsUsed, false);
extraData.SetWriteOffset(numberOfBitsUsed);
bs.Read(hasNetworkId);
if (hasNetworkId)
bs.Read(networkId);
bs.ReadCompressed(bytesOnStack);
bs.ReadAlignedBytes((unsigned char*) inputStack, bytesOnStack);
unsigned outerIndex;
if (remoteFunctions.Has(systemAddress))
{
outerIndex = remoteFunctions.GetIndexAtKey(systemAddress);
DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp> *theList = remoteFunctions[outerIndex];
unsigned i;
for (i=0; i < theList->Size(); i++)
{
if (theList->operator [](i).functionIndex==functionIndex)
{
RakNet::BitStream out;
// Recover by resending the RPC with the function identifier string this time
if (timestamp!=0)
{
out.Write((MessageID)ID_TIMESTAMP);
out.Write(timestamp);
}
out.Write((MessageID)ID_AUTO_RPC_CALL);
if (parameterCount>=0)
{
out.Write(true);
out.Write(parameterCount);
}
else
{
out.Write(false);
}
out.WriteCompressed(numberOfBitsUsed);
out.Write(&extraData);
out.Write(hasNetworkId);
if (hasNetworkId)
out.Write(networkId);
out.AlignWriteToByteBoundary();
out.Write(false);
stringCompressor->EncodeString(theList->operator [](i).identifier.uniqueIdentifier, 512, &out, 0);
out.WriteCompressed(bytesOnStack);
out.WriteAlignedBytes((const unsigned char*) inputStack, bytesOnStack);
rakPeer->Send(&out, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddress, false);
return;
}
}
}
// Failed to recover, inform the user
Packet *p = rakPeer->AllocatePacket(sizeof(MessageID)+sizeof(unsigned char));
RakNet::BitStream bs2(p->data, sizeof(MessageID)+sizeof(unsigned char), false);
bs2.SetWriteOffset(0);
bs2.Write((MessageID)ID_RPC_REMOTE_ERROR);
bs2.Write((unsigned char)RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED);
stringCompressor->EncodeString("",256,&bs,0);
p->systemAddress=systemAddress;
rakPeer->PushBackPacket(p, false);
}
void AutoRPC::SendError(SystemAddress target, unsigned char errorCode, const char *functionName)
{
RakNet::BitStream bs;
bs.Write((MessageID)ID_RPC_REMOTE_ERROR);
bs.Write(errorCode);
stringCompressor->EncodeString(functionName,256,&bs,0);
rakPeer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, target, false);
}
void AutoRPC::OnShutdown(RakPeerInterface *peer)
{
(void) peer;
Clear();
}
void AutoRPC::Clear(void)
{
unsigned i,j;
for (j=0; j < remoteFunctions.Size(); j++)
{
DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp> *theList = remoteFunctions[j];
for (i=0; i < theList->Size(); i++)
{
if (theList->operator [](i).identifier.uniqueIdentifier)
rakFree(theList->operator [](i).identifier.uniqueIdentifier);
}
delete theList;
}
for (i=0; i < localFunctions.Size(); i++)
{
if (localFunctions[i].identifier.uniqueIdentifier)
rakFree(localFunctions[i].identifier.uniqueIdentifier);
}
localFunctions.Clear();
remoteFunctions.Clear();
outgoingExtraData.Reset();
incomingExtraData.Reset();
}
unsigned AutoRPC::GetLocalFunctionIndex(AutoRPC::RPCIdentifier identifier)
{
unsigned i;
for (i=0; i < localFunctions.Size(); i++)
{
if (localFunctions[i].identifier.isObjectMember==identifier.isObjectMember &&
strcmp(localFunctions[i].identifier.uniqueIdentifier,identifier.uniqueIdentifier)==0)
return i;
}
return (unsigned) -1;
}
bool AutoRPC::GetRemoteFunctionIndex(SystemAddress systemAddress, AutoRPC::RPCIdentifier identifier, unsigned int *outerIndex, unsigned int *innerIndex)
{
bool objectExists=false;
if (remoteFunctions.Has(systemAddress))
{
*outerIndex = remoteFunctions.GetIndexAtKey(systemAddress);
DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp> *theList = remoteFunctions[*outerIndex];
*innerIndex = theList->GetIndexFromKey(identifier, &objectExists);
}
return objectExists;
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

653
thirdparty/raknet/Source/AutoRPC.h vendored Normal file
View File

@@ -0,0 +1,653 @@
/// \file
/// \brief Automatically serializing and deserializing RPC system. More advanced RPC, but possibly not cross-platform
/// \note Semi-depreciated. RPC3 found at DependentExtensions/RPC3 has more features and is easier to use. But if you do not want to link with Boost this version still works.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __AUTO_RPC_H
#define __AUTO_RPC_H
class RakPeerInterface;
class NetworkIDManager;
#include "PluginInterface.h"
#include "DS_Map.h"
#include "PacketPriority.h"
#include "RakNetTypes.h"
#include "BitStream.h"
#include "Gen_RPC8.h"
#include "RakString.h"
#include "NetworkIDObject.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// \defgroup AUTO_RPC_GROUP AutoRPC
/// \ingroup PLUGINS_GROUP
namespace RakNet
{
/// Maximum amount of data that can be passed on the stack in a function call
#define ARPC_MAX_STACK_SIZE 65536
/// Get a pointer to a function member of a C++ class.
/// \note Recommended you use ARPC_REGISTER_CPP_FUNCTION0 to ARPC_REGISTER_CPP_FUNCTION9 (below)
/// \note Cannot validate the number of parameters is correctly passed.
/// \note You must use one of these macros, or the code will be broken.
/// \param[in] autoRPCInstance A pointer to an instance of AutoRPC
/// \param[in] _IDENTIFIER_ C string identifier to use on the remote system to call the function
/// \param[in] _RETURN_ Return value of the function
/// \param[in] _CLASS_ Base-most class of the containing class that contains your function
/// \param[in] _FUNCTION_ Name of the function
/// \param[in] _PARAMS_ Parameter list, include parenthesis
#define ARPC_REGISTER_CPP_FUNCTION(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS_) \
(autoRPCInstance)->RegisterFunction( (_IDENTIFIER_), GenRPC::PMFWrapper<_CLASS_, _RETURN_(AUTO_RPC_CALLSPEC _CLASS_::*) _PARAMS_ >( &_CLASS_::_FUNCTION_), true, -1 )
/// Get a pointer to a function member of a C++ class.
/// \note Recommended you use ARPC_REGISTER_CPP_FUNCTION0 to ARPC_REGISTER_CPP_FUNCTION9 (below)
/// \note Cannot validate the number of parameters is correctly passed.
/// \note You must use one of these macros, or the code will be broken.
/// \param[in] autoRPCInstance A pointer to an instance of AutoRPC
/// \param[in] _IDENTIFIER_ C string identifier to use on the remote system to call the function
/// \param[in] _RETURN_ Return value of the function
/// \param[in] _CLASS_ Base-most class of the containing class that contains your function
/// \param[in] _FUNCTION_ Name of the function
/// \param[in] _PARAMS_ Parameter list, include parenthesis
/// \param[in] _PARAM_COUNT_ Number of parameters.
#define ARPC_REGISTER_CPP_FUNCTIONX(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, _PARAMS_, _PARAM_COUNT_) \
(autoRPCInstance)->RegisterFunction( (_IDENTIFIER_), GenRPC::PMFWrapper<_CLASS_, _RETURN_(AUTO_RPC_CALLSPEC _CLASS_::*) _PARAMS_>( &_CLASS_::_FUNCTION_), true, _PARAM_COUNT_ )
// These uses the ISO C99 varadic macros, so, in theory, *should* be 100% standards compliant.
#define ARPC_REGISTER_CPP_FUNCTION0(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_) \
(autoRPCInstance)->RegisterFunction((_IDENTIFIER_), GenRPC::PMFWrapper<_CLASS_, _RETURN_(AUTO_RPC_CALLSPEC _CLASS_::*)()>( &_CLASS_::_FUNCTION_ ), true, 0 )
/// Get a pointer to a function member of a C++ class
/// \param[in] autoRPCInstance A pointer to an instance of AutoRPC
/// \param[in] _IDENTIFIER_ C string identifier to use on the remote system to call the function
/// \param[in] _RETURN_ Return value of the function
/// \param[in] _CLASS_ Base-most class of the containing class that contains your function
/// \param[in] _FUNCTION_ Name of the function
// NB I have no idea why the "-1" is here - it may be a bug, but it was present in the original macros.
#define ARPC_REGISTER_CPP_FUNCTION_N(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
(autoRPCInstance)->RegisterFunction( (_IDENTIFIER_), GenRPC::PMFWrapper<_CLASS_, _RETURN_(AUTO_RPC_CALLSPEC _CLASS_::*)(__VA_ARGS__)>( &_CLASS_::_FUNCTION_), true, GenRPC::countFuncArgs( &_CLASS_::_FUNCTION_ ) - 1 )
// These are historic - you can just use the ARPC_REGISTER_CPP_FUNCTION_N
#define ARPC_REGISTER_CPP_FUNCTION1(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
ARPC_REGISTER_CPP_FUNCTION_N( autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, __VA_ARGS__)
#define ARPC_REGISTER_CPP_FUNCTION2(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
ARPC_REGISTER_CPP_FUNCTION_N( autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, __VA_ARGS__)
#define ARPC_REGISTER_CPP_FUNCTION3(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
ARPC_REGISTER_CPP_FUNCTION_N( autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, __VA_ARGS__)
#define ARPC_REGISTER_CPP_FUNCTION4(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
ARPC_REGISTER_CPP_FUNCTION_N( autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, __VA_ARGS__)
#define ARPC_REGISTER_CPP_FUNCTION5(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
ARPC_REGISTER_CPP_FUNCTION_N( autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, __VA_ARGS__)
#define ARPC_REGISTER_CPP_FUNCTION6(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
ARPC_REGISTER_CPP_FUNCTION_N( autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, __VA_ARGS__)
#define ARPC_REGISTER_CPP_FUNCTION7(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
ARPC_REGISTER_CPP_FUNCTION_N( autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, __VA_ARGS__)
#define ARPC_REGISTER_CPP_FUNCTION8(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
ARPC_REGISTER_CPP_FUNCTION_N( autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, __VA_ARGS__)
#define ARPC_REGISTER_CPP_FUNCTION9(autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, ...) \
ARPC_REGISTER_CPP_FUNCTION_N( autoRPCInstance, _IDENTIFIER_, _RETURN_, _CLASS_, _FUNCTION_, __VA_ARGS__)
/// Error codes returned by a remote system as to why an RPC function call cannot execute
/// Follows packet ID ID_RPC_REMOTE_ERROR
/// Name of the function will be appended, if available. Read as follows:
/// char outputBuff[256];
/// stringCompressor->DecodeString(outputBuff,256,&RakNet::BitStream(p->data+sizeof(MessageID)+1,p->length-sizeof(MessageID)-1,false),0);
/// printf("Function: %s\n", outputBuff);
enum RPCErrorCodes
{
/// AutoRPC::SetNetworkIDManager() was not called, and it must be called to call a C++ object member
RPC_ERROR_NETWORK_ID_MANAGER_UNAVAILABLE,
/// Cannot execute C++ object member call because the object specified by SetRecipientObject() does not exist on this system
RPC_ERROR_OBJECT_DOES_NOT_EXIST,
/// Internal error, index optimization for function lookup does not exist
RPC_ERROR_FUNCTION_INDEX_OUT_OF_RANGE,
/// Named function was not registered with RegisterFunction(). Check your spelling.
RPC_ERROR_FUNCTION_NOT_REGISTERED,
/// Named function was registered, but later unregistered with UnregisterFunction() and can no longer be called.
RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED,
/// SetRecipientObject() was not called before Call(), but RegisterFunction() was called with isObjectMember=true
/// If you intended to call a CPP function, call SetRecipientObject() with a valid object first.
RPC_ERROR_CALLING_CPP_AS_C,
/// SetRecipientObject() was called before Call(), but RegisterFunction() was called with isObjectMember=false
/// If you intended to call a C function, call SetRecipientObject(UNASSIGNED_NETWORK_ID) first.
RPC_ERROR_CALLING_C_AS_CPP,
/// Internal error, passed stack is bigger than current stack. Check that the version is the same on both systems.
RPC_ERROR_STACK_TOO_SMALL,
/// Internal error, formatting error with how the stack was serialized
RPC_ERROR_STACK_DESERIALIZATION_FAILED,
/// The \a parameterCount parameter passed to RegisterFunction() on this system does not match the \a parameterCount parameter passed to SendCall() on the remote system.
RPC_ERROR_INCORRECT_NUMBER_OF_PARAMETERS,
};
/// The AutoRPC plugin allows you to call remote functions as if they were local functions, using the standard function call syntax
/// No serialization or deserialization is needed.
/// Advantages are that this is easier to use than regular RPC system.
/// Disadvantages is that all parameters must be passable on the stack using memcpy (shallow copy). For other types of parameters, use SetOutgoingExtraData() and GetIncomingExtraData()
/// Pointers are automatically dereferenced and the contents copied with memcpy
/// Use the old system, or regular message passing, if you need greater flexibility
/// \note Semi-depreciated. Use DependentExtensions\RPC3 unless you do not want to link with Boost
/// \ingroup AUTO_RPC_GROUP
class AutoRPC : public PluginInterface
{
public:
/// Constructor
AutoRPC();
/// Destructor
virtual ~AutoRPC();
/// Sets the network ID manager to use for object lookup
/// Required to call C++ object member functions via SetRecipientObject()
/// \param[in] idMan Pointer to the network ID manager to use
void SetNetworkIDManager(NetworkIDManager *idMan);
/// Registers a function pointer to be callable given an identifier for the pointer.
/// \param[in] uniqueIdentifier String identifying the function. Recommended that this is the name of the function
/// \param[in] functionPtr Pointer to the function. For C, just pass the name of the function. For C++, use ARPC_REGISTER_CPP_FUNCTION
/// \param[in] isObjectMember false if a C function. True if a member function of an object (C++)
/// \param[in] parameterCount Optional parameter to tell the system how many parameters this function has. If specified, and the wrong number of parameters are called by the remote system, the call is rejected. -1 indicates undefined
/// \return True on success, false on uniqueIdentifier already used
/// \note Only use this for C functions; for C++ use one of the ARPC_REGISTER_CPP_FUNCTION_XXX macros
bool RegisterFunction(const char *uniqueIdentifier, void *functionPtr, bool isObjectMember, char parameterCount=-1);
/// \internal Registers a function - using a PMF structure.
bool RegisterFunction(const char *uniqueIdentifier, GenRPC::PMF pmf, bool isObjectMember, char parameterCount=-1);
/// Unregisters a function pointer to be callable given an identifier for the pointer
/// \note This is not safe to call while connected
/// \param[in] uniqueIdentifier String identifying the function.
/// \param[in] isObjectMember false if a C function. True if a member function of an object (C++)
/// \return True on success, false on function was not previously or is not currently registered.
bool UnregisterFunction(const char *uniqueIdentifier, bool isObjectMember);
/// Send or stop sending a timestamp with all following calls to Call()
/// Use GetLastSenderTimestamp() to read the timestamp.
/// \param[in] timeStamp Non-zero to pass this timestamp using the ID_TIMESTAMP system. 0 to clear passing a timestamp.
void SetTimestamp(RakNetTime timeStamp);
/// Set parameters to pass to RakPeer::Send() for all following calls to Call()
/// Deafults to HIGH_PRIORITY, RELIABLE_ORDERED, ordering channel 0
/// \param[in] priority See RakPeer::Send()
/// \param[in] reliability See RakPeer::Send()
/// \param[in] orderingChannel See RakPeer::Send()
void SetSendParams(PacketPriority priority, PacketReliability reliability, char orderingChannel);
/// Set system to send to for all following calls to Call()
/// Defaults to UNASSIGNED_SYSTEM_ADDRESS, broadcast=true
/// \param[in] systemAddress See RakPeer::Send()
/// \param[in] broadcast See RakPeer::Send()
void SetRecipientAddress(SystemAddress systemAddress, bool broadcast);
/// Set the NetworkID to pass for all following calls to Call()
/// Defaults to UNASSIGNED_NETWORK_ID (none)
/// If set, the remote function will be considered a C++ function, e.g. an object member function
/// If set to UNASSIGNED_NETWORK_ID (none), the remote function will be considered a C function
/// If this is set incorrectly, you will get back either RPC_ERROR_CALLING_C_AS_CPP or RPC_ERROR_CALLING_CPP_AS_C
/// \sa NetworkIDManager
/// \param[in] networkID Returned from NetworkIDObject::GetNetworkID()
void SetRecipientObject(NetworkID networkID);
/// Write extra data to pass for all following calls to Call()
/// Use BitStream::Reset to clear extra data. Don't forget to do this or you will waste bandwidth.
/// \return A bitstream you can write to to send extra data with each following call to Call()
RakNet::BitStream *SetOutgoingExtraData(void);
/// If the last received function call has a timestamp included, it is stored and can be retrieved with this function.
/// \return 0 if the last call did not have a timestamp, else non-zero
RakNetTime GetLastSenderTimestamp(void) const;
/// Returns the system address of the last system to send us a received function call
/// Equivalent to the old system RPCParameters::sender
/// \return Last system to send an RPC call using this system
SystemAddress GetLastSenderAddress(void) const;
/// Returns the instance of RakPeer this plugin was attached to
RakPeerInterface *GetRakPeer(void) const;
/// Returns the currently running RPC call identifier, set from RegisterFunction::uniqueIdentifier
/// Returns an empty string "" if none
/// \Return which RPC call is currently running
const char *GetCurrentExecution(void) const;
/// Gets the bitstream written to via SetOutgoingExtraData().
/// Data is updated with each incoming function call
/// \return A bitstream you can read from with extra data that was written with SetOutgoingExtraData();
RakNet::BitStream *GetIncomingExtraData(void);
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
bool Call(const char *uniqueIdentifier){
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 0);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1>
bool Call(const char *uniqueIdentifier, P1 p1) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 1);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 2);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2, class P3>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2, P3 p3 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 3);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2, class P3, class P4>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2, P3 p3, P4 p4 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 4);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2, class P3, class P4, class P5>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 5);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2, class P3, class P4, class P5, class P6>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 6);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, p7, true, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 7);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
bool Call(const char *uniqueIdentifier, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8 ) {
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, p7, p8, true, true, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 8);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID){
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 0);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
template <class P1>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 1);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
template <class P1, class P2>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 2);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
template <class P1, class P2, class P3>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 3);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
template <class P1, class P2, class P3, class P4>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 4);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
template <class P1, class P2, class P3, class P4, class P5>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 5);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
template <class P1, class P2, class P3, class P4, class P5, class P6>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 6);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, p7, true, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 7);
}
/// Calls a remote function, using whatever was last passed to SetTimestamp(), SetSendParams(), SetRecipientAddress(), and SetRecipientObject()
/// Passed parameter(s), if any, are passed via memcpy and pushed on the stack for the remote function
/// \note This ONLY works with variables that are passable via memcpy! If you need more flexibility, use SetOutgoingExtraData() and GetIncomingExtraData()
/// \note The this pointer, for this instance of AutoRPC, is pushed as the last parameter on the stack. See AutoRPCSample.ccp for an example of this
/// \param[in] uniqueIdentifier parameter of the same name passed to RegisterFunction() on the remote system
/// \param[in] timeStamp See SetTimestamp()
/// \param[in] priority See SetSendParams()
/// \param[in] reliability See SetSendParams()
/// \param[in] orderingChannel See SetSendParams()
/// \param[in] systemAddress See SetRecipientAddress()
/// \param[in] broadcast See SetRecipientAddress()
/// \param[in] networkID See SetRecipientObject()
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
bool CallExplicit(const char *uniqueIdentifier, RakNetTime timeStamp, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress systemAddress, bool broadcast, NetworkID networkID, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8 ) {
SetTimestamp(timeStamp);
SetSendParams(priority, reliability, orderingChannel);
SetRecipientAddress(systemAddress, broadcast);
SetRecipientObject(networkID);
char stack[ARPC_MAX_STACK_SIZE];
unsigned int bytesOnStack = GenRPC::BuildStack(stack, p1, p2, p3, p4, p5, p6, p7, p8, true, true, true, true, true, true, true, true);
return SendCall(uniqueIdentifier, stack, bytesOnStack, 8);
}
// If you need more than 8 parameters, just add it here...
// ---------------------------- ALL INTERNAL AFTER HERE ----------------------------
/// \internal
/// Identifies an RPC function, by string identifier and if it is a C or C++ function
struct RPCIdentifier
{
char *uniqueIdentifier;
bool isObjectMember;
};
/// \internal
/// The RPC identifier, and a pointer to the function
struct LocalRPCFunction
{
RPCIdentifier identifier;
GenRPC::PMF functionPtr;
char parameterCount;
};
/// \internal
/// The RPC identifier, and the index of the function on a remote system
struct RemoteRPCFunction
{
RPCIdentifier identifier;
unsigned int functionIndex;
};
/// \internal
static int RemoteRPCFunctionComp( const RPCIdentifier &key, const RemoteRPCFunction &data );
/// \internal
/// Sends the RPC call, with a given serialized stack
bool SendCall(const char *uniqueIdentifier, const char *stack, unsigned int bytesOnStack, char parameterCount);
protected:
// --------------------------------------------------------------------------------------------
// Packet handling functions
// --------------------------------------------------------------------------------------------
void OnAttach(RakPeerInterface *peer);
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
virtual void OnAutoRPCCall(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes);
virtual void OnRPCRemoteIndex(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes);
virtual void OnRPCUnknownRemoteIndex(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes, RakNetTime timestamp);
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
virtual void OnShutdown(RakPeerInterface *peer);
void Clear(void);
void SendError(SystemAddress target, unsigned char errorCode, const char *functionName);
unsigned GetLocalFunctionIndex(RPCIdentifier identifier);
bool GetRemoteFunctionIndex(SystemAddress systemAddress, RPCIdentifier identifier, unsigned int *outerIndex, unsigned int *innerIndex);
DataStructures::List<LocalRPCFunction> localFunctions;
DataStructures::Map<SystemAddress, DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp> *> remoteFunctions;
RakNetTime outgoingTimestamp;
PacketPriority outgoingPriority;
PacketReliability outgoingReliability;
char outgoingOrderingChannel;
SystemAddress outgoingSystemAddress;
bool outgoingBroadcast;
NetworkID outgoingNetworkID;
RakNet::BitStream outgoingExtraData;
RakNetTime incomingTimeStamp;
SystemAddress incomingSystemAddress;
RakNet::BitStream incomingExtraData;
RakPeerInterface *rakPeer;
NetworkIDManager *networkIdManager;
char currentExecution[512];
};
} // End namespace
#endif
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@@ -0,0 +1,17 @@
#ifndef __AUTOPATCHER_PATCH_CONTEXT_H
#define __AUTOPATCHER_PATCH_CONTEXT_H
enum PatchContext
{
PC_HASH_WITH_PATCH,
PC_WRITE_FILE,
PC_ERROR_FILE_WRITE_FAILURE,
PC_ERROR_PATCH_TARGET_MISSING,
PC_ERROR_PATCH_APPLICATION_FAILURE,
PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE,
PC_NOTICE_WILL_COPY_ON_RESTART,
PC_NOTICE_FILE_DOWNLOADED,
PC_NOTICE_FILE_DOWNLOADED_PATCH,
};
#endif

View File

@@ -0,0 +1,53 @@
/// \file
/// \brief An interface used by AutopatcherServer to get the data necessary to run an autopatcher.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __AUTOPATCHER_REPOSITORY_INTERFACE_H
#define __AUTOPATCHER_REPOSITORY_INTERFACE_H
class FileList;
namespace RakNet
{
class BitStream;
}
/// 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:
/// Get list of files added and deleted since a certain date. This is used by AutopatcherServer and not usually explicitly called.
/// \param[in] applicationName A null terminated string identifying the application
/// \param[out] addedFiles A list of the current versions of filenames with hashes as their data that were created after \a sinceData
/// \param[out] deletedFiles A list of the current versions of filenames that were deleted after \a sinceData
/// \param[in] An input date, in whatever format your repository uses
/// \param[out] currentDate The current server date, in whatever format your repository uses
/// \return True on success, false on failure.
virtual bool GetChangelistSinceDate(const char *applicationName, FileList *addedFiles, FileList *deletedFiles, const char *sinceDate, char currentDate[64])=0;
/// Get patches (or files) for every file in input, assuming that input has a hash for each of those files.
/// \param[in] applicationName A null terminated string identifying the application
/// \param[in] input A list of files with SHA1_LENGTH byte hashes to get from the database.
/// \param[out] patchList You should return list of files with either the filedata or the patch. This is a subset of \a input. The context data for each file will be either PC_WRITE_FILE (to just write the file) or PC_HASH_WITH_PATCH (to patch). If PC_HASH_WITH_PATCH, then the file contains a SHA1_LENGTH byte patch followed by the hash. The datalength is patchlength + SHA1_LENGTH
/// \param[out] currentDate The current server date, in whatever format your repository uses
/// \return True on success, false on failure.
virtual bool GetPatches(const char *applicationName, FileList *input, FileList *patchList, char currentDate[64])=0;
/// \return Whatever this function returns is sent from the AutopatcherServer to the AutopatcherClient when one of the above functions returns false.
virtual const char *GetLastError(void) const=0;
};
#endif

1824
thirdparty/raknet/Source/BigTypes.h vendored Normal file

File diff suppressed because it is too large Load Diff

915
thirdparty/raknet/Source/BitStream.cpp vendored Normal file
View File

@@ -0,0 +1,915 @@
/// \file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#if defined(_MSC_VER) && _MSC_VER < 1299 // VC6 doesn't support template specialization
#include "BitStream_NoTemplate.cpp"
#else
#include "BitStream.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef _XBOX360
#include "Console1Includes.h"
#elif defined(_WIN32)
#include <winsock2.h> // htonl
#include <memory.h>
#include <cmath>
#include <float.h>
#elif defined(_PS3)
#include "Console2Includes.h"
#else
#include <arpa/inet.h>
#include <memory.h>
#include <cmath>
#include <float.h>
#endif
// MSWin uses _copysign, others use copysign...
#ifndef _WIN32
#define _copysign copysign
#endif
using namespace RakNet;
#ifdef _MSC_VER
#pragma warning( push )
#endif
BitStream::BitStream()
{
numberOfBitsUsed = 0;
//numberOfBitsAllocated = 32 * 8;
numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE * 8;
readOffset = 0;
//data = ( unsigned char* ) rakMalloc( 32 );
data = ( unsigned char* ) stackData;
#ifdef _DEBUG
// assert( data );
#endif
//memset(data, 0, 32);
copyData = true;
}
BitStream::BitStream( const unsigned int initialBytesToAllocate )
{
numberOfBitsUsed = 0;
readOffset = 0;
if (initialBytesToAllocate <= BITSTREAM_STACK_ALLOCATION_SIZE)
{
data = ( unsigned char* ) stackData;
numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE * 8;
}
else
{
data = ( unsigned char* ) rakMalloc( (size_t) initialBytesToAllocate );
numberOfBitsAllocated = initialBytesToAllocate << 3;
}
#ifdef _DEBUG
assert( data );
#endif
// memset(data, 0, initialBytesToAllocate);
copyData = true;
}
BitStream::BitStream( unsigned char* _data, const unsigned int lengthInBytes, bool _copyData )
{
numberOfBitsUsed = lengthInBytes << 3;
readOffset = 0;
copyData = _copyData;
numberOfBitsAllocated = lengthInBytes << 3;
if ( copyData )
{
if ( lengthInBytes > 0 )
{
if (lengthInBytes < BITSTREAM_STACK_ALLOCATION_SIZE)
{
data = ( unsigned char* ) stackData;
numberOfBitsAllocated = BITSTREAM_STACK_ALLOCATION_SIZE << 3;
}
else
{
data = ( unsigned char* ) rakMalloc( (size_t) lengthInBytes );
}
#ifdef _DEBUG
assert( data );
#endif
memcpy( data, _data, (size_t) lengthInBytes );
}
else
data = 0;
}
else
data = ( unsigned char* ) _data;
}
// Use this if you pass a pointer copy to the constructor (_copyData==false) and want to overallocate to prevent reallocation
void BitStream::SetNumberOfBitsAllocated( const BitSize_t lengthInBits )
{
#ifdef _DEBUG
assert( lengthInBits >= ( BitSize_t ) numberOfBitsAllocated );
#endif
numberOfBitsAllocated = lengthInBits;
}
BitStream::~BitStream()
{
if ( copyData && numberOfBitsAllocated > (BITSTREAM_STACK_ALLOCATION_SIZE << 3))
RakFree( data ); // Use realloc and free so we are more efficient than delete and new for resizing
}
void BitStream::Reset( void )
{
// Note: Do NOT reallocate memory because BitStream is used
// in places to serialize/deserialize a buffer. Reallocation
// is a dangerous operation (may result in leaks).
if ( numberOfBitsUsed > 0 )
{
// memset(data, 0, BITS_TO_BYTES(numberOfBitsUsed));
}
// Don't free memory here for speed efficiency
//free(data); // Use realloc and free so we are more efficient than delete and new for resizing
numberOfBitsUsed = 0;
//numberOfBitsAllocated=8;
readOffset = 0;
//data=(unsigned char*)rakMalloc(1);
// if (numberOfBitsAllocated>0)
// memset(data, 0, BITS_TO_BYTES(numberOfBitsAllocated));
}
// Write an array or casted stream
void BitStream::Write( const char* input, const unsigned int numberOfBytes )
{
if (numberOfBytes==0)
return;
// Optimization:
if ((numberOfBitsUsed & 7) == 0)
{
AddBitsAndReallocate( BYTES_TO_BITS(numberOfBytes) );
memcpy(data+BITS_TO_BYTES(numberOfBitsUsed), input, (size_t) numberOfBytes);
numberOfBitsUsed+=BYTES_TO_BITS(numberOfBytes);
}
else
{
WriteBits( ( unsigned char* ) input, numberOfBytes * 8, true );
}
}
void BitStream::Write( BitStream *bitStream)
{
Write(bitStream, bitStream->GetNumberOfBitsUsed());
}
void BitStream::Write( BitStream *bitStream, BitSize_t numberOfBits )
{
AddBitsAndReallocate( numberOfBits );
BitSize_t numberOfBitsMod8;
while (numberOfBits-->0 && bitStream->readOffset + 1 <= bitStream->numberOfBitsUsed)
{
numberOfBitsMod8 = numberOfBitsUsed & 7;
if ( numberOfBitsMod8 == 0 )
{
// New byte
if (bitStream->data[ bitStream->readOffset >> 3 ] & ( 0x80 >> ( bitStream->readOffset & 7 ) ) )
{
// Write 1
data[ numberOfBitsUsed >> 3 ] = 0x80;
}
else
{
// Write 0
data[ numberOfBitsUsed >> 3 ] = 0;
}
}
else
{
// Existing byte
if (bitStream->data[ bitStream->readOffset >> 3 ] & ( 0x80 >> ( bitStream->readOffset & 7 ) ) )
data[ numberOfBitsUsed >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1
// else 0, do nothing
}
bitStream->readOffset++;
numberOfBitsUsed++;
}
}
void BitStream::Write( BitStream &bitStream, BitSize_t numberOfBits )
{
Write(&bitStream, numberOfBits);
}
void BitStream::Write( BitStream &bitStream )
{
Write(&bitStream);
}
bool BitStream::Read( BitStream *bitStream, BitSize_t numberOfBits )
{
if (GetNumberOfUnreadBits() < numberOfBits)
return false;
bitStream->Write(this, numberOfBits);
return true;
}
bool BitStream::Read( BitStream *bitStream )
{
bitStream->Write(this);
return true;
}
bool BitStream::Read( BitStream &bitStream, BitSize_t numberOfBits )
{
if (GetNumberOfUnreadBits() < numberOfBits)
return false;
bitStream.Write(this, numberOfBits);
return true;
}
bool BitStream::Read( BitStream &bitStream )
{
bitStream.Write(this);
return true;
}
// Read an array or casted stream
bool BitStream::Read( char* output, const unsigned int numberOfBytes )
{
// Optimization:
if ((readOffset & 7) == 0)
{
if ( readOffset + ( numberOfBytes << 3 ) > numberOfBitsUsed )
return false;
// Write the data
memcpy( output, data + ( readOffset >> 3 ), (size_t) numberOfBytes );
readOffset += numberOfBytes << 3;
return true;
}
else
{
return ReadBits( ( unsigned char* ) output, numberOfBytes * 8 );
}
}
// Sets the read pointer back to the beginning of your data.
void BitStream::ResetReadPointer( void )
{
readOffset = 0;
}
// Sets the write pointer back to the beginning of your data.
void BitStream::ResetWritePointer( void )
{
numberOfBitsUsed = 0;
}
// Write a 0
void BitStream::Write0( void )
{
AddBitsAndReallocate( 1 );
// New bytes need to be zeroed
if ( ( numberOfBitsUsed & 7 ) == 0 )
data[ numberOfBitsUsed >> 3 ] = 0;
numberOfBitsUsed++;
}
// Write a 1
void BitStream::Write1( void )
{
AddBitsAndReallocate( 1 );
BitSize_t numberOfBitsMod8 = numberOfBitsUsed & 7;
if ( numberOfBitsMod8 == 0 )
data[ numberOfBitsUsed >> 3 ] = 0x80;
else
data[ numberOfBitsUsed >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1
numberOfBitsUsed++;
}
// Returns true if the next data read is a 1, false if it is a 0
bool BitStream::ReadBit( void )
{
bool result = ( data[ readOffset >> 3 ] & ( 0x80 >> ( readOffset & 7 ) ) ) !=0;
readOffset++;
return result;
}
// Align the bitstream to the byte boundary and then write the specified number of bits.
// This is faster than WriteBits but wastes the bits to do the alignment and requires you to call
// SetReadToByteAlignment at the corresponding read position
void BitStream::WriteAlignedBytes( const unsigned char* input, const unsigned int numberOfBytesToWrite )
{
#ifdef _DEBUG
if (numberOfBytesToWrite<=0)
{
assert( numberOfBytesToWrite > 0 );
}
#endif
AlignWriteToByteBoundary();
Write((const char*) input, numberOfBytesToWrite);
}
/// Aligns the bitstream, writes inputLength, and writes input. Won't write beyond maxBytesToWrite
void BitStream::WriteAlignedBytesSafe( const char *input, const unsigned int inputLength, const unsigned int maxBytesToWrite )
{
if (input==0 || inputLength==0)
{
WriteCompressed((unsigned int)0);
return;
}
WriteCompressed(inputLength);
WriteAlignedBytes((const unsigned char*) input, inputLength < maxBytesToWrite ? inputLength : maxBytesToWrite);
}
// Read bits, starting at the next aligned bits. Note that the modulus 8 starting offset of the
// sequence must be the same as was used with WriteBits. This will be a problem with packet coalescence
// unless you byte align the coalesced packets.
bool BitStream::ReadAlignedBytes( unsigned char* output, const unsigned int numberOfBytesToRead )
{
#ifdef _DEBUG
assert( numberOfBytesToRead > 0 );
#endif
if ( numberOfBytesToRead <= 0 )
return false;
// Byte align
AlignReadToByteBoundary();
if ( readOffset + ( numberOfBytesToRead << 3 ) > numberOfBitsUsed )
return false;
// Write the data
memcpy( output, data + ( readOffset >> 3 ), (size_t) numberOfBytesToRead );
readOffset += numberOfBytesToRead << 3;
return true;
}
bool BitStream::ReadAlignedBytesSafe( char *input, int &inputLength, const int maxBytesToRead )
{
return ReadAlignedBytesSafe(input,(unsigned int&) inputLength,(unsigned int)maxBytesToRead);
}
bool BitStream::ReadAlignedBytesSafe( char *input, unsigned int &inputLength, const unsigned int maxBytesToRead )
{
if (ReadCompressed(inputLength)==false)
return false;
if (inputLength > maxBytesToRead)
inputLength=maxBytesToRead;
if (inputLength==0)
return true;
return ReadAlignedBytes((unsigned char*) input, inputLength);
}
bool BitStream::ReadAlignedBytesSafeAlloc( char **input, int &inputLength, const unsigned int maxBytesToRead )
{
return ReadAlignedBytesSafeAlloc(input,(unsigned int&) inputLength, maxBytesToRead);
}
bool BitStream::ReadAlignedBytesSafeAlloc( char **input, unsigned int &inputLength, const unsigned int maxBytesToRead )
{
rakFree(*input);
*input=0;
if (ReadCompressed(inputLength)==false)
return false;
if (inputLength > maxBytesToRead)
inputLength=maxBytesToRead;
if (inputLength==0)
return true;
*input = (char*) rakMalloc( (size_t) BITS_TO_BYTES( inputLength ) );
return ReadAlignedBytes((unsigned char*) *input, inputLength);
}
// Align the next write and/or read to a byte boundary. This can be used to 'waste' bits to byte align for efficiency reasons
void BitStream::AlignWriteToByteBoundary( void )
{
if ( numberOfBitsUsed )
numberOfBitsUsed += 8 - ( (( numberOfBitsUsed - 1 ) & 7) + 1 );
}
// Align the next write and/or read to a byte boundary. This can be used to 'waste' bits to byte align for efficiency reasons
void BitStream::AlignReadToByteBoundary( void )
{
if ( readOffset )
readOffset += 8 - ( (( readOffset - 1 ) & 7 ) + 1 );
}
// Write numberToWrite bits from the input source
void BitStream::WriteBits( const unsigned char* input, BitSize_t numberOfBitsToWrite, const bool rightAlignedBits )
{
if (numberOfBitsToWrite<=0)
return;
AddBitsAndReallocate( numberOfBitsToWrite );
BitSize_t offset = 0;
unsigned char dataByte;
BitSize_t numberOfBitsUsedMod8;
numberOfBitsUsedMod8 = numberOfBitsUsed & 7;
// Faster to put the while at the top surprisingly enough
while ( numberOfBitsToWrite > 0 )
//do
{
dataByte = *( input + offset );
if ( numberOfBitsToWrite < 8 && rightAlignedBits ) // rightAlignedBits means in the case of a partial byte, the bits are aligned from the right (bit 0) rather than the left (as in the normal internal representation)
dataByte <<= 8 - numberOfBitsToWrite; // shift left to get the bits on the left, as in our internal representation
// Writing to a new byte each time
if ( numberOfBitsUsedMod8 == 0 )
* ( data + ( numberOfBitsUsed >> 3 ) ) = dataByte;
else
{
// Copy over the new data.
*( data + ( numberOfBitsUsed >> 3 ) ) |= dataByte >> ( numberOfBitsUsedMod8 ); // First half
if ( 8 - ( numberOfBitsUsedMod8 ) < 8 && 8 - ( numberOfBitsUsedMod8 ) < numberOfBitsToWrite ) // If we didn't write it all out in the first half (8 - (numberOfBitsUsed%8) is the number we wrote in the first half)
{
*( data + ( numberOfBitsUsed >> 3 ) + 1 ) = (unsigned char) ( dataByte << ( 8 - ( numberOfBitsUsedMod8 ) ) ); // Second half (overlaps byte boundary)
}
}
if ( numberOfBitsToWrite >= 8 )
numberOfBitsUsed += 8;
else
numberOfBitsUsed += numberOfBitsToWrite;
if (numberOfBitsToWrite>=8)
numberOfBitsToWrite -= 8;
else
numberOfBitsToWrite=0;
offset++;
}
// } while(numberOfBitsToWrite>0);
}
// Set the stream to some initial data. For internal use
void BitStream::SetData( unsigned char *input )
{
data=input;
copyData=false;
}
// Assume the input source points to a native type, compress and write it
void BitStream::WriteCompressed( const unsigned char* input,
const unsigned int size, const bool unsignedData )
{
BitSize_t currentByte = ( size >> 3 ) - 1; // PCs
unsigned char byteMatch;
if ( unsignedData )
{
byteMatch = 0;
}
else
{
byteMatch = 0xFF;
}
// Write upper bytes with a single 1
// From high byte to low byte, if high byte is a byteMatch then write a 1 bit. Otherwise write a 0 bit and then write the remaining bytes
while ( currentByte > 0 )
{
if ( input[ currentByte ] == byteMatch ) // If high byte is byteMatch (0 of 0xff) then it would have the same value shifted
{
bool b = true;
Write( b );
}
else
{
// Write the remainder of the data after writing 0
bool b = false;
Write( b );
WriteBits( input, ( currentByte + 1 ) << 3, true );
// currentByte--;
return ;
}
currentByte--;
}
// If the upper half of the last byte is a 0 (positive) or 16 (negative) then write a 1 and the remaining 4 bits. Otherwise write a 0 and the 8 bites.
if ( ( unsignedData && ( ( *( input + currentByte ) ) & 0xF0 ) == 0x00 ) ||
( unsignedData == false && ( ( *( input + currentByte ) ) & 0xF0 ) == 0xF0 ) )
{
bool b = true;
Write( b );
WriteBits( input + currentByte, 4, true );
}
else
{
bool b = false;
Write( b );
WriteBits( input + currentByte, 8, true );
}
}
// Read numberOfBitsToRead bits to the output source
// alignBitsToRight should be set to true to convert internal bitstream data to userdata
// It should be false if you used WriteBits with rightAlignedBits false
bool BitStream::ReadBits( unsigned char *output, BitSize_t numberOfBitsToRead, const bool alignBitsToRight )
{
#ifdef _DEBUG
// assert( numberOfBitsToRead > 0 );
#endif
if (numberOfBitsToRead<=0)
return false;
if ( readOffset + numberOfBitsToRead > numberOfBitsUsed )
return false;
BitSize_t readOffsetMod8;
BitSize_t offset = 0;
memset( output, 0, (size_t) BITS_TO_BYTES( numberOfBitsToRead ) );
readOffsetMod8 = readOffset & 7;
while ( numberOfBitsToRead > 0 )
{
*( output + offset ) |= *( data + ( readOffset >> 3 ) ) << ( readOffsetMod8 ); // First half
if ( readOffsetMod8 > 0 && numberOfBitsToRead > 8 - ( readOffsetMod8 ) ) // If we have a second half, we didn't read enough bytes in the first half
*( output + offset ) |= *( data + ( readOffset >> 3 ) + 1 ) >> ( 8 - ( readOffsetMod8 ) ); // Second half (overlaps byte boundary)
if (numberOfBitsToRead>=8)
{
numberOfBitsToRead -= 8;
readOffset += 8;
offset++;
}
else
{
int neg = (int) numberOfBitsToRead - 8;
if ( neg < 0 ) // Reading a partial byte for the last byte, shift right so the data is aligned on the right
{
if ( alignBitsToRight )
* ( output + offset ) >>= -neg;
readOffset += 8 + neg;
}
else
readOffset += 8;
offset++;
numberOfBitsToRead=0;
}
}
return true;
}
// Assume the input source points to a compressed native type. Decompress and read it
bool BitStream::ReadCompressed( unsigned char* output,
const unsigned int size, const bool unsignedData )
{
unsigned int currentByte = ( size >> 3 ) - 1;
unsigned char byteMatch, halfByteMatch;
if ( unsignedData )
{
byteMatch = 0;
halfByteMatch = 0;
}
else
{
byteMatch = 0xFF;
halfByteMatch = 0xF0;
}
// Upper bytes are specified with a single 1 if they match byteMatch
// From high byte to low byte, if high byte is a byteMatch then write a 1 bit. Otherwise write a 0 bit and then write the remaining bytes
while ( currentByte > 0 )
{
// If we read a 1 then the data is byteMatch.
bool b;
if ( Read( b ) == false )
return false;
if ( b ) // Check that bit
{
output[ currentByte ] = byteMatch;
currentByte--;
}
else
{
// Read the rest of the bytes
if ( ReadBits( output, ( currentByte + 1 ) << 3 ) == false )
return false;
return true;
}
}
// All but the first bytes are byteMatch. If the upper half of the last byte is a 0 (positive) or 16 (negative) then what we read will be a 1 and the remaining 4 bits.
// Otherwise we read a 0 and the 8 bytes
//assert(readOffset+1 <=numberOfBitsUsed); // If this assert is hit the stream wasn't long enough to read from
if ( readOffset + 1 > numberOfBitsUsed )
return false;
bool b;
if ( Read( b ) == false )
return false;
if ( b ) // Check that bit
{
if ( ReadBits( output + currentByte, 4 ) == false )
return false;
output[ currentByte ] |= halfByteMatch; // We have to set the high 4 bits since these are set to 0 by ReadBits
}
else
{
if ( ReadBits( output + currentByte, 8 ) == false )
return false;
}
return true;
}
// Reallocates (if necessary) in preparation of writing numberOfBitsToWrite
void BitStream::AddBitsAndReallocate( const BitSize_t numberOfBitsToWrite )
{
if (numberOfBitsToWrite <= 0)
return;
BitSize_t newNumberOfBitsAllocated = numberOfBitsToWrite + numberOfBitsUsed;
if ( numberOfBitsToWrite + numberOfBitsUsed > 0 && ( ( numberOfBitsAllocated - 1 ) >> 3 ) < ( ( newNumberOfBitsAllocated - 1 ) >> 3 ) ) // If we need to allocate 1 or more new bytes
{
#ifdef _DEBUG
// If this assert hits then we need to specify true for the third parameter in the constructor
// It needs to reallocate to hold all the data and can't do it unless we allocated to begin with
// Often hits if you call Write or Serialize on a read-only bitstream
assert( copyData == true );
#endif
// Less memory efficient but saves on news and deletes
/// Cap to 1 meg buffer to save on huge allocations
newNumberOfBitsAllocated = ( numberOfBitsToWrite + numberOfBitsUsed ) * 2;
if (newNumberOfBitsAllocated - ( numberOfBitsToWrite + numberOfBitsUsed ) > 1048576 )
newNumberOfBitsAllocated = numberOfBitsToWrite + numberOfBitsUsed + 1048576;
// BitSize_t newByteOffset = BITS_TO_BYTES( numberOfBitsAllocated );
// Use realloc and free so we are more efficient than delete and new for resizing
BitSize_t amountToAllocate = BITS_TO_BYTES( newNumberOfBitsAllocated );
if (data==(unsigned char*)stackData)
{
if (amountToAllocate > BITSTREAM_STACK_ALLOCATION_SIZE)
{
data = ( unsigned char* ) rakMalloc( (size_t) amountToAllocate );
// need to copy the stack data over to our new memory area too
memcpy ((void *)data, (void *)stackData, (size_t) BITS_TO_BYTES( numberOfBitsAllocated ));
}
}
else
{
data = ( unsigned char* ) RakRealloc( data, (size_t) amountToAllocate );
}
#ifdef _DEBUG
assert( data ); // Make sure realloc succeeded
#endif
// memset(data+newByteOffset, 0, ((newNumberOfBitsAllocated-1)>>3) - ((numberOfBitsAllocated-1)>>3)); // Set the new data block to 0
}
if ( newNumberOfBitsAllocated > numberOfBitsAllocated )
numberOfBitsAllocated = newNumberOfBitsAllocated;
}
BitSize_t BitStream::GetNumberOfBitsAllocated(void) const
{
return numberOfBitsAllocated;
}
// Should hit if reads didn't match writes
void BitStream::AssertStreamEmpty( void )
{
assert( readOffset == numberOfBitsUsed );
}
void BitStream::PrintBits( void ) const
{
if ( numberOfBitsUsed <= 0 )
{
printf( "No bits\n" );
return ;
}
for ( BitSize_t counter = 0; counter < BITS_TO_BYTES( numberOfBitsUsed ); counter++ )
{
BitSize_t stop;
if ( counter == ( numberOfBitsUsed - 1 ) >> 3 )
stop = 8 - ( ( ( numberOfBitsUsed - 1 ) & 7 ) + 1 );
else
stop = 0;
for ( BitSize_t counter2 = 7; counter2 >= stop; counter2-- )
{
if ( ( data[ counter ] >> counter2 ) & 1 )
putchar( '1' );
else
putchar( '0' );
if (counter2==0)
break;
}
putchar( ' ' );
}
putchar( '\n' );
}
// Exposes the data for you to look at, like PrintBits does.
// Data will point to the stream. Returns the length in bits of the stream.
BitSize_t BitStream::CopyData( unsigned char** _data ) const
{
#ifdef _DEBUG
assert( numberOfBitsUsed > 0 );
#endif
*_data = (unsigned char*) rakMalloc( (size_t) BITS_TO_BYTES( numberOfBitsUsed ) );
memcpy( *_data, data, sizeof(unsigned char) * (size_t) ( BITS_TO_BYTES( numberOfBitsUsed ) ) );
return numberOfBitsUsed;
}
// Ignore data we don't intend to read
void BitStream::IgnoreBits( const BitSize_t numberOfBits )
{
readOffset += numberOfBits;
}
void BitStream::IgnoreBytes( const unsigned int numberOfBytes )
{
IgnoreBits(BYTES_TO_BITS(numberOfBytes));
}
// Move the write pointer to a position on the array. Dangerous if you don't know what you are doing!
// Doesn't work with non-aligned data!
void BitStream::SetWriteOffset( const BitSize_t offset )
{
numberOfBitsUsed = offset;
}
/*
BitSize_t BitStream::GetWriteOffset( void ) const
{
return numberOfBitsUsed;
}
// Returns the length in bits of the stream
BitSize_t BitStream::GetNumberOfBitsUsed( void ) const
{
return GetWriteOffset();
}
// Returns the length in bytes of the stream
BitSize_t BitStream::GetNumberOfBytesUsed( void ) const
{
return BITS_TO_BYTES( numberOfBitsUsed );
}
// Returns the number of bits into the stream that we have read
BitSize_t BitStream::GetReadOffset( void ) const
{
return readOffset;
}
// Sets the read bit index
void BitStream::SetReadOffset( const BitSize_t newReadOffset )
{
readOffset=newReadOffset;
}
// Returns the number of bits left in the stream that haven't been read
BitSize_t BitStream::GetNumberOfUnreadBits( void ) const
{
return numberOfBitsUsed - readOffset;
}
// Exposes the internal data
unsigned char* BitStream::GetData( void ) const
{
return data;
}
*/
// If we used the constructor version with copy data off, this makes sure it is set to on and the data pointed to is copied.
void BitStream::AssertCopyData( void )
{
if ( copyData == false )
{
copyData = true;
if ( numberOfBitsAllocated > 0 )
{
unsigned char * newdata = ( unsigned char* ) rakMalloc( (size_t) BITS_TO_BYTES( numberOfBitsAllocated ) );
#ifdef _DEBUG
assert( data );
#endif
memcpy( newdata, data, (size_t) BITS_TO_BYTES( numberOfBitsAllocated ) );
data = newdata;
}
else
data = 0;
}
}
void BitStream::ReverseBytes(unsigned char *input, unsigned char *output, const unsigned int length)
{
for (BitSize_t i=0; i < length; i++)
output[i]=input[length-i-1];
}
void BitStream::ReverseBytesInPlace(unsigned char *data,const unsigned int length)
{
unsigned char temp;
BitSize_t i;
for (i=0; i < (length>>1); i++)
{
temp = data[i];
data[i]=data[length-i-1];
data[length-i-1]=temp;
}
}
bool BitStream::DoEndianSwap(void)
{
#ifndef __BITSTREAM_NATIVE_END
return IsNetworkOrder()==false;
#else
return false;
#endif
}
bool BitStream::IsBigEndian(void)
{
return IsNetworkOrder();
}
bool BitStream::IsNetworkOrder(void)
{
#if defined(_PS3)
return true;
#else
static bool isNetworkOrder=(htonl(12345) == 12345);
return isNetworkOrder;
#endif
}
bool BitStream::Read(char *var)
{
return RakString::Deserialize(var,this);
}
bool BitStream::Read(unsigned char *var)
{
return RakString::Deserialize((char*) var,this);
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif // #if _MSC_VER < 1299

1696
thirdparty/raknet/Source/BitStream.h vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,784 @@
/// \file
/// \brief This class allows you to write and read native types as a string of bits. BitStream is used extensively throughout RakNet and is designed to be used by users as well.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#if defined(_MSC_VER) && _MSC_VER < 1299 // VC6 doesn't support template specialization
#ifndef __BITSTREAM_H
#define __BITSTREAM_H
#include "RakMemoryOverride.h"
#include "RakNetDefines.h"
#include "Export.h"
#include "RakNetTypes.h"
#include <assert.h>
#if defined(_PS3)
#include <math.h>
#else
#include <cmath>
#endif
#include <float.h>
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// Arbitrary size, just picking something likely to be larger than most packets
#define BITSTREAM_STACK_ALLOCATION_SIZE 256
/// The namespace RakNet is not consistently used. It's only purpose is to avoid compiler errors for classes whose names are very common.
/// For the most part I've tried to avoid this simply by using names very likely to be unique for my classes.
namespace RakNet
{
/// This class allows you to write and read native types as a string of bits. BitStream is used extensively throughout RakNet and is designed to be used by users as well.
/// \sa BitStreamSample.txt
class RAK_DLL_EXPORT BitStream : public RakNet::RakMemoryOverride
{
public:
/// Default Constructor
BitStream();
/// Create the bitstream, with some number of bytes to immediately allocate.
/// There is no benefit to calling this, unless you know exactly how many bytes you need and it is greater than BITSTREAM_STACK_ALLOCATION_SIZE.
/// In that case all it does is save you one or more realloc calls.
/// \param[in] initialBytesToAllocate the number of bytes to pre-allocate.
BitStream( int initialBytesToAllocate );
/// Initialize the BitStream, immediately setting the data it contains to a predefined pointer.
/// Set \a _copyData to true if you want to make an internal copy of the data you are passing. Set it to false to just save a pointer to the data.
/// You shouldn't call Write functions with \a _copyData as false, as this will write to unallocated memory
/// 99% of the time you will use this function to cast Packet::data to a bitstream for reading, in which case you should write something as follows:
/// \code
/// RakNet::BitStream bs(packet->data, packet->length, false);
/// \endcode
/// \param[in] _data An array of bytes.
/// \param[in] lengthInBytes Size of the \a _data.
/// \param[in] _copyData true or false to make a copy of \a _data or not.
BitStream( unsigned char* _data, unsigned int lengthInBytes, bool _copyData );
/// Destructor
~BitStream();
/// Resets the bitstream for reuse.
void Reset( void );
/// Bidirectional serialize/deserialize any integral type to/from a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] var The value to write
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool Serialize(bool writeToBitstream, bool &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned char &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, char &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned short &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, short &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned int &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, int &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned long &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, long &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, long long &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, unsigned long long &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, float &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, double &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
bool Serialize(bool writeToBitstream, long double &var){if (writeToBitstream)Write(var);else return Read(var); return true;}
/// Bidirectional serialize/deserialize any integral type to/from a bitstream. If the current value is different from the last value
/// the current value will be written. Otherwise, a single bit will be written
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] currentValue The current value to write
/// \param[in] lastValue The last value to compare against. Only used if \a writeToBitstream is true.
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeDelta(bool writeToBitstream, bool &currentValue, bool lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned char &currentValue, unsigned char lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, char &currentValue, char lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned short &currentValue, unsigned short lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, short &currentValue, short lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned int &currentValue, unsigned int lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, int &currentValue, int lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned long &currentValue, unsigned long lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, long long &currentValue, long long lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned long long &currentValue, unsigned long long lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, float &currentValue, float lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, double &currentValue, double lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, long double &currentValue, long double lastValue){if (writeToBitstream) WriteDelta(currentValue, lastValue); else return ReadDelta(currentValue);return true;}
/// Bidirectional version of SerializeDelta when you don't know what the last value is, or there is no last value.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] currentValue The current value to write
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeDelta(bool writeToBitstream, bool &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned char &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, char &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned short &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, short &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned int &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, int &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned long &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, long long &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, unsigned long long &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, float &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, double &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
bool SerializeDelta(bool writeToBitstream, long double &currentValue){if (writeToBitstream) WriteDelta(currentValue); else return ReadDelta(currentValue);return true;}
/// Bidirectional serialize/deserialize any integral type to/from a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] var The value to write
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeCompressed(bool writeToBitstream, bool &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned char &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, char &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned short &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, short &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned int &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, int &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned long &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, long &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, long long &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, unsigned long long &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, float &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, double &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
bool SerializeCompressed(bool writeToBitstream, long double &var){if (writeToBitstream)WriteCompressed(var);else return ReadCompressed(var); return true;}
/// Bidirectional serialize/deserialize any integral type to/from a bitstream. If the current value is different from the last value
/// the current value will be written. Otherwise, a single bit will be written
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] currentValue The current value to write
/// \param[in] lastValue The last value to compare against. Only used if \a writeToBitstream is true.
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeCompressedDelta(bool writeToBitstream, bool &currentValue, bool lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned char &currentValue, unsigned char lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, char &currentValue, char lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned short &currentValue, unsigned short lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, short &currentValue, short lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned int &currentValue, unsigned int lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, int &currentValue, int lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned long &currentValue, unsigned long lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long long &currentValue, long long lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned long long &currentValue, unsigned long long lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, float &currentValue, float lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, double &currentValue, double lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long double &currentValue, long double lastValue){if (writeToBitstream) WriteCompressedDelta(currentValue, lastValue); else return ReadCompressedDelta(currentValue);return true;}
/// Save as SerializeCompressedDelta(templateType &currentValue, templateType lastValue) when we have an unknown second parameter
bool SerializeCompressedDelta(bool writeToBitstream, bool &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned char &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, char &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned short &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, short &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned int &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, int &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned long &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long long &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, unsigned long long &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, float &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, double &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
bool SerializeCompressedDelta(bool writeToBitstream, long double &var){if (writeToBitstream)WriteCompressedDelta(var);else return ReadCompressedDelta(var); return true;}
/// Bidirectional serialize/deserialize an array or casted stream or raw data. This does NOT do endian swapping.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] input a byte buffer
/// \param[in] numberOfBytes the size of \a input in bytes
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool Serialize(bool writeToBitstream, char* input, const int numberOfBytes );
/// Bidirectional serialize/deserialize a normalized 3D vector, using (at most) 4 bytes + 3 bits instead of 12-24 bytes. Will further compress y or z axis aligned vectors.
/// Accurate to 1/32767.5.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeNormVector(bool writeToBitstream, float &x, float &y, float z ){if (writeToBitstream) WriteNormVector(x,y,z); else return ReadNormVector(x,y,z); return true;}
bool SerializeNormVector(bool writeToBitstream, double &x, double &y, double &z ){if (writeToBitstream) WriteNormVector(x,y,z); else return ReadNormVector(x,y,z); return true;}
/// Bidirectional serialize/deserialize a vector, using 10 bytes instead of 12.
/// Loses accuracy to about 3/10ths and only saves 2 bytes, so only use if accuracy is not important.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeVector(bool writeToBitstream, float &x, float &y, float &z ){if (writeToBitstream) WriteVector(x,y,z); else return ReadVector(x,y,z); return true;}
bool SerializeVector(bool writeToBitstream, double &x, double &y, double &z ){if (writeToBitstream) WriteVector(x,y,z); else return ReadVector(x,y,z); return true;}
/// Bidirectional serialize/deserialize a normalized quaternion in 6 bytes + 4 bits instead of 16 bytes. Slightly lossy.
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] w w
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeNormQuat(bool writeToBitstream, float &w, float &x, float &y, float &z){if (writeToBitstream) WriteNormQuat(w,x,y,z); else return ReadNormQuat(w,x,y,z); return true;}
bool SerializeNormQuat(bool writeToBitstream, double &w, double &x, double &y, double &z){if (writeToBitstream) WriteNormQuat(w,x,y,z); else return ReadNormQuat(w,x,y,z); return true;}
/// Bidirectional serialize/deserialize an orthogonal matrix by creating a quaternion, and writing 3 components of the quaternion in 2 bytes each
/// for 6 bytes instead of 36
/// Lossy, although the result is renormalized
bool SerializeOrthMatrix(
bool writeToBitstream,
float &m00, float &m01, float &m02,
float &m10, float &m11, float &m12,
float &m20, float &m21, float &m22 ){if (writeToBitstream) WriteOrthMatrix(m00,m01,m02,m10,m11,m12,m20,m21,m22); else return ReadOrthMatrix(m00,m01,m02,m10,m11,m12,m20,m21,m22); return true;}
bool SerializeOrthMatrix(
bool writeToBitstream,
double &m00, double &m01, double &m02,
double &m10, double &m11, double &m12,
double &m20, double &m21, double &m22 ){if (writeToBitstream) WriteOrthMatrix(m00,m01,m02,m10,m11,m12,m20,m21,m22); else return ReadOrthMatrix(m00,m01,m02,m10,m11,m12,m20,m21,m22); return true;}
/// Bidirectional serialize/deserialize numberToSerialize bits to/from the input. Right aligned
/// data means in the case of a partial byte, the bits are aligned
/// from the right (bit 0) rather than the left (as in the normal
/// internal representation) You would set this to true when
/// writing user data, and false when copying bitstream data, such
/// as writing one bitstream to another
/// \param[in] writeToBitstream true to write from your data to this bitstream. False to read from this bitstream and write to your data
/// \param[in] input The data
/// \param[in] numberOfBitsToSerialize The number of bits to write
/// \param[in] rightAlignedBits if true data will be right aligned
/// \return true if \a writeToBitstream is true. true if \a writeToBitstream is false and the read was successful. false if \a writeToBitstream is false and the read was not successful.
bool SerializeBits(bool writeToBitstream, unsigned char* input, int numberOfBitsToSerialize, const bool rightAlignedBits = true );
/// Write any integral type to a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// \param[in] var The value to write
void Write(bool var){if ( var ) Write1(); else Write0();}
void Write(unsigned char var){WriteBits( ( unsigned char* ) & var, sizeof( unsigned char ) * 8, true );}
void Write(char var){WriteBits( ( unsigned char* ) & var, sizeof( char ) * 8, true );}
void Write(unsigned short var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned short)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned short)); WriteBits( ( unsigned char* ) output, sizeof(unsigned short) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(unsigned short) * 8, true );}
void Write(short var) {if (DoEndianSwap()){unsigned char output[sizeof(short)]; ReverseBytes((unsigned char*)&var, output, sizeof(short)); WriteBits( ( unsigned char* ) output, sizeof(short) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(short) * 8, true );}
void Write(unsigned int var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned int)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned int)); WriteBits( ( unsigned char* ) output, sizeof(unsigned int) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(unsigned int) * 8, true );}
void Write(int var) {if (DoEndianSwap()){unsigned char output[sizeof(int)]; ReverseBytes((unsigned char*)&var, output, sizeof(int)); WriteBits( ( unsigned char* ) output, sizeof(int) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(int) * 8, true );}
void Write(unsigned long var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned long)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned long)); WriteBits( ( unsigned char* ) output, sizeof(unsigned long) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(unsigned long) * 8, true );}
void Write(long var) {if (DoEndianSwap()){unsigned char output[sizeof(long)]; ReverseBytes((unsigned char*)&var, output, sizeof(long)); WriteBits( ( unsigned char* ) output, sizeof(long) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(long) * 8, true );}
void Write(long long var) {if (DoEndianSwap()){unsigned char output[sizeof(long long)]; ReverseBytes((unsigned char*)&var, output, sizeof(long long)); WriteBits( ( unsigned char* ) output, sizeof(long long) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(long long) * 8, true );}
void Write(unsigned long long var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned long long)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned long long)); WriteBits( ( unsigned char* ) output, sizeof(unsigned long long) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(unsigned long long) * 8, true );}
void Write(float var) {if (DoEndianSwap()){unsigned char output[sizeof(float)]; ReverseBytes((unsigned char*)&var, output, sizeof(float)); WriteBits( ( unsigned char* ) output, sizeof(float) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(float) * 8, true );}
void Write(double var) {if (DoEndianSwap()){unsigned char output[sizeof(double)]; ReverseBytes((unsigned char*)&var, output, sizeof(double)); WriteBits( ( unsigned char* ) output, sizeof(double) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(double) * 8, true );}
void Write(long double var) {if (DoEndianSwap()){unsigned char output[sizeof(long double)]; ReverseBytes((unsigned char*)&var, output, sizeof(long double)); WriteBits( ( unsigned char* ) output, sizeof(long double) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(long double) * 8, true );}
void Write(void* var) {if (DoEndianSwap()){unsigned char output[sizeof(void*)]; ReverseBytes((unsigned char*)&var, output, sizeof(void*)); WriteBits( ( unsigned char* ) output, sizeof(void*) * 8, true );} WriteBits( ( unsigned char* ) & var, sizeof(void*) * 8, true );}
void Write(SystemAddress var){WriteBits( ( unsigned char* ) & var.binaryAddress, sizeof(var.binaryAddress) * 8, true ); Write(var.port);}
void Write(NetworkID var){if (NetworkID::IsPeerToPeerMode()) Write(var.systemAddress); Write(var.localSystemAddress);}
/// Write any integral type to a bitstream. If the current value is different from the last value
/// the current value will be written. Otherwise, a single bit will be written
/// \param[in] currentValue The current value to write
/// \param[in] lastValue The last value to compare against
void WriteDelta(bool currentValue, bool lastValue){
#pragma warning(disable:4100) // warning C4100: 'peer' : unreferenced formal parameter
Write(currentValue);
}
void WriteDelta(unsigned char currentValue, unsigned char lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(char currentValue, char lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(unsigned short currentValue, unsigned short lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(short currentValue, short lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(unsigned int currentValue, unsigned int lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(int currentValue, int lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(unsigned long currentValue, unsigned long lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(long currentValue, long lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(long long currentValue, long long lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(unsigned long long currentValue, unsigned long long lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(float currentValue, float lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(double currentValue, double lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(long double currentValue, long double lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(SystemAddress currentValue, SystemAddress lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
void WriteDelta(NetworkID currentValue, NetworkID lastValue){if (currentValue==lastValue) {Write(false);} else {Write(true); Write(currentValue);}}
/// WriteDelta when you don't know what the last value is, or there is no last value.
/// \param[in] currentValue The current value to write
void WriteDelta(bool var){Write(var);}
void WriteDelta(unsigned char var){Write(true); Write(var);}
void WriteDelta(char var){Write(true); Write(var);}
void WriteDelta(unsigned short var){Write(true); Write(var);}
void WriteDelta(short var){Write(true); Write(var);}
void WriteDelta(unsigned int var){Write(true); Write(var);}
void WriteDelta(int var){Write(true); Write(var);}
void WriteDelta(unsigned long var){Write(true); Write(var);}
void WriteDelta(long var){Write(true); Write(var);}
void WriteDelta(long long var){Write(true); Write(var);}
void WriteDelta(unsigned long long var){Write(true); Write(var);}
void WriteDelta(float var){Write(true); Write(var);}
void WriteDelta(double var){Write(true); Write(var);}
void WriteDelta(long double var){Write(true); Write(var);}
void WriteDelta(SystemAddress var){Write(true); Write(var);}
void WriteDelta(NetworkID var){Write(true); Write(var);}
/// Write any integral type to a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// \param[in] var The value to write
void WriteCompressed(bool var) {Write(var);}
void WriteCompressed(unsigned char var) {WriteCompressed( ( unsigned char* ) & var, sizeof( unsigned char ) * 8, true );}
void WriteCompressed(char var) {WriteCompressed( (unsigned char* ) & var, sizeof( unsigned char ) * 8, true );}
void WriteCompressed(unsigned short var) {if (DoEndianSwap()) {unsigned char output[sizeof(unsigned short)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned short)); WriteCompressed( ( unsigned char* ) output, sizeof(unsigned short) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(unsigned short) * 8, true );}
void WriteCompressed(short var) {if (DoEndianSwap()) {unsigned char output[sizeof(short)]; ReverseBytes((unsigned char*)&var, output, sizeof(short)); WriteCompressed( ( unsigned char* ) output, sizeof(short) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(short) * 8, true );}
void WriteCompressed(unsigned int var) {if (DoEndianSwap()) {unsigned char output[sizeof(unsigned int)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned int)); WriteCompressed( ( unsigned char* ) output, sizeof(unsigned int) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(unsigned int) * 8, true );}
void WriteCompressed(int var) {if (DoEndianSwap()) { unsigned char output[sizeof(int)]; ReverseBytes((unsigned char*)&var, output, sizeof(int)); WriteCompressed( ( unsigned char* ) output, sizeof(int) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(int) * 8, true );}
void WriteCompressed(unsigned long var) {if (DoEndianSwap()) {unsigned char output[sizeof(unsigned long)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned long)); WriteCompressed( ( unsigned char* ) output, sizeof(unsigned long) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(unsigned long) * 8, true );}
void WriteCompressed(long var) {if (DoEndianSwap()) {unsigned char output[sizeof(long)]; ReverseBytes((unsigned char*)&var, output, sizeof(long)); WriteCompressed( ( unsigned char* ) output, sizeof(long) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(long) * 8, true );}
void WriteCompressed(long long var) {if (DoEndianSwap()) {unsigned char output[sizeof(long long)]; ReverseBytes((unsigned char*)&var, output, sizeof(long long)); WriteCompressed( ( unsigned char* ) output, sizeof(long long) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(long long) * 8, true );}
void WriteCompressed(unsigned long long var) {if (DoEndianSwap()) { unsigned char output[sizeof(unsigned long long)]; ReverseBytes((unsigned char*)&var, output, sizeof(unsigned long long)); WriteCompressed( ( unsigned char* ) output, sizeof(unsigned long long) * 8, true );} else WriteCompressed( ( unsigned char* ) & var, sizeof(unsigned long long) * 8, true );}
void WriteCompressed(float var) {assert(var > -1.01f && var < 1.01f); if (var < -1.0f) var=-1.0f; if (var > 1.0f) var=1.0f; Write((unsigned short)((var+1.0f)*32767.5f));}
void WriteCompressed(double var) {assert(var > -1.01 && var < 1.01); if (var < -1.0) var=-1.0; if (var > 1.0) var=1.0; Write((unsigned long)((var+1.0)*2147483648.0));}
void WriteCompressed(long double var) {assert(var > -1.01 && var < 1.01); if (var < -1.0) var=-1.0; if (var > 1.0) var=1.0; Write((unsigned long)((var+1.0)*2147483648.0));}
/// Write any integral type to a bitstream. If the current value is different from the last value
/// the current value will be written. Otherwise, a single bit will be written
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// \param[in] currentValue The current value to write
/// \param[in] lastValue The last value to compare against
void WriteCompressedDelta(bool currentValue, bool lastValue)
{
#pragma warning(disable:4100) // warning C4100: 'peer' : unreferenced formal parameter
Write(currentValue);
}
void WriteCompressedDelta(unsigned char currentValue, unsigned char lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(char currentValue, char lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(unsigned short currentValue, unsigned short lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(short currentValue, short lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(unsigned int currentValue, unsigned int lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(int currentValue, int lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(unsigned long currentValue, unsigned long lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(long currentValue, long lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(long long currentValue, long long lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(unsigned long long currentValue, unsigned long long lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(float currentValue, float lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(double currentValue, double lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
void WriteCompressedDelta(long double currentValue, long double lastValue){if (currentValue==lastValue) {Write(false);} else { Write(true); WriteCompressed(currentValue);}}
/// Save as WriteCompressedDelta(templateType currentValue, templateType lastValue) when we have an unknown second parameter
void WriteCompressedDelta(bool var) {Write(var);}
void WriteCompressedDelta(unsigned char var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(char var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(unsigned short var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(short var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(unsigned int var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(int var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(unsigned long var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(long var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(long long var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(unsigned long long var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(float var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(double var) { Write(true); WriteCompressed(var); }
void WriteCompressedDelta(long double var) { Write(true); WriteCompressed(var); }
/// Read any integral type from a bitstream. Define __BITSTREAM_NATIVE_END if you need endian swapping.
/// \param[in] var The value to read
bool Read(bool &var){if ( readOffset + 1 > numberOfBitsUsed ) return false;
if ( data[ readOffset >> 3 ] & ( 0x80 >> ( readOffset & 7 ) ) )
var = true;
else
var = false;
// Has to be on a different line for Mac
readOffset++;
return true;
}
bool Read(unsigned char &var) {return ReadBits( ( unsigned char* ) &var, sizeof(unsigned char) * 8, true );}
bool Read(char &var) {return ReadBits( ( unsigned char* ) &var, sizeof(char) * 8, true );}
bool Read(unsigned short &var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned short)]; if (ReadBits( ( unsigned char* ) output, sizeof(unsigned short) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned short)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(unsigned short) * 8, true );}
bool Read(short &var) {if (DoEndianSwap()){unsigned char output[sizeof(short)]; if (ReadBits( ( unsigned char* ) output, sizeof(short) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(short)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(short) * 8, true );}
bool Read(unsigned int &var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned int)]; if (ReadBits( ( unsigned char* ) output, sizeof(unsigned int) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned int)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(unsigned int) * 8, true );}
bool Read(int &var) {if (DoEndianSwap()){unsigned char output[sizeof(int)]; if (ReadBits( ( unsigned char* ) output, sizeof(int) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(int)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(int) * 8, true );}
bool Read(unsigned long &var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned long)]; if (ReadBits( ( unsigned char* ) output, sizeof(unsigned long) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned long)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(unsigned long) * 8, true );}
bool Read(long &var) {if (DoEndianSwap()){unsigned char output[sizeof(long)]; if (ReadBits( ( unsigned char* ) output, sizeof(long) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(long)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(long) * 8, true );}
bool Read(long long &var) {if (DoEndianSwap()){unsigned char output[sizeof(long long)]; if (ReadBits( ( unsigned char* ) output, sizeof(long long) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(long long)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(long long) * 8, true );}
bool Read(unsigned long long &var) {if (DoEndianSwap()){unsigned char output[sizeof(unsigned long long)]; if (ReadBits( ( unsigned char* ) output, sizeof(unsigned long long) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned long long)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(unsigned long long) * 8, true );}
bool Read(float &var) {if (DoEndianSwap()){unsigned char output[sizeof(float)]; if (ReadBits( ( unsigned char* ) output, sizeof(float) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(float)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(float) * 8, true );}
bool Read(double &var) {if (DoEndianSwap()){unsigned char output[sizeof(double)]; if (ReadBits( ( unsigned char* ) output, sizeof(double) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(double)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(double) * 8, true );}
bool Read(long double &var) {if (DoEndianSwap()){unsigned char output[sizeof(long double)]; if (ReadBits( ( unsigned char* ) output, sizeof(long double) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(long double)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(long double) * 8, true );}
bool Read(void* &var) {if (DoEndianSwap()){unsigned char output[sizeof(void*)]; if (ReadBits( ( unsigned char* ) output, sizeof(void*) * 8, true )) { ReverseBytes(output, (unsigned char*)&var, sizeof(void*)); return true;} return false;} else return ReadBits( ( unsigned char* ) & var, sizeof(void*) * 8, true );}
bool Read(SystemAddress &var){ReadBits( ( unsigned char* ) & var.binaryAddress, sizeof(var.binaryAddress) * 8, true ); return Read(var.port);}
bool Read(NetworkID &var){if (NetworkID::IsPeerToPeerMode()) Read(var.systemAddress); return Read(var.localSystemAddress);}
/// Read any integral type from a bitstream. If the written value differed from the value compared against in the write function,
/// var will be updated. Otherwise it will retain the current value.
/// ReadDelta is only valid from a previous call to WriteDelta
/// \param[in] var The value to read
bool ReadDelta(bool &var) {return Read(var);}
bool ReadDelta(unsigned char &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(char &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(unsigned short &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(short &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(unsigned int &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(int &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(unsigned long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(long long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(unsigned long long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(float &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(double &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(long double &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(SystemAddress &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
bool ReadDelta(NetworkID &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=Read(var); return success;}
/// Read any integral type from a bitstream. Undefine __BITSTREAM_NATIVE_END if you need endian swapping.
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// \param[in] var The value to read
bool ReadCompressed(bool &var) {return Read(var);}
bool ReadCompressed(unsigned char &var) {return ReadCompressed( ( unsigned char* ) &var, sizeof(unsigned char) * 8, true );}
bool ReadCompressed(char &var) {return ReadCompressed( ( unsigned char* ) &var, sizeof(unsigned char) * 8, true );}
bool ReadCompressed(unsigned short &var){if (DoEndianSwap()){unsigned char output[sizeof(unsigned short)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(unsigned short) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned short)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(unsigned short) * 8, true );}
bool ReadCompressed(short &var){if (DoEndianSwap()){unsigned char output[sizeof(short)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(short) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(short)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(short) * 8, true );}
bool ReadCompressed(unsigned int &var){if (DoEndianSwap()){unsigned char output[sizeof(unsigned int)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(unsigned int) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned int)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(unsigned int) * 8, true );}
bool ReadCompressed(int &var){if (DoEndianSwap()){unsigned char output[sizeof(int)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(int) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(int)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(int) * 8, true );}
bool ReadCompressed(unsigned long &var){if (DoEndianSwap()){unsigned char output[sizeof(unsigned long)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(unsigned long) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned long)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(unsigned long) * 8, true );}
bool ReadCompressed(long &var){if (DoEndianSwap()){unsigned char output[sizeof(long)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(long) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(long)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(long) * 8, true );}
bool ReadCompressed(long long &var){if (DoEndianSwap()){unsigned char output[sizeof(long long)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(long long) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(long long)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(long long) * 8, true );}
bool ReadCompressed(unsigned long long &var){if (DoEndianSwap()){unsigned char output[sizeof(unsigned long long)]; if (ReadCompressed( ( unsigned char* ) output, sizeof(unsigned long long) * 8, true )){ReverseBytes(output, (unsigned char*)&var, sizeof(unsigned long long)); return true;} return false;}else return ReadCompressed( ( unsigned char* ) & var, sizeof(unsigned long long) * 8, true );}
bool ReadCompressed(float &var){unsigned short compressedFloat; if (Read(compressedFloat)) { var = ((float)compressedFloat / 32767.5f - 1.0f); return true;} return false;}
bool ReadCompressed(double &var) {unsigned long compressedFloat; if (Read(compressedFloat)) { var = ((double)compressedFloat / 2147483648.0 - 1.0); return true; } return false;}
bool ReadCompressed(long double &var) {unsigned long compressedFloat; if (Read(compressedFloat)) { var = ((long double)compressedFloat / 2147483648.0 - 1.0); return true; } return false;}
bool ReadCompressed(SystemAddress &var) {return Read(var);}
bool ReadCompressed(NetworkID &var) {return Read(var);}
/// Read any integral type from a bitstream. If the written value differed from the value compared against in the write function,
/// var will be updated. Otherwise it will retain the current value.
/// the current value will be updated.
/// For floating point, this is lossy, using 2 bytes for a float and 4 for a double. The range must be between -1 and +1.
/// For non-floating point, this is lossless, but only has benefit if you use less than half the range of the type
/// If you are not using __BITSTREAM_NATIVE_END the opposite is true for types larger than 1 byte
/// ReadCompressedDelta is only valid from a previous call to WriteDelta
/// \param[in] var The value to read
bool ReadCompressedDelta(bool &var) {return Read(var);}
bool ReadCompressedDelta(unsigned char &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(char &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(unsigned short &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(short &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(unsigned int &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(int &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(unsigned long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(long long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(unsigned long long &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(float &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(double &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
bool ReadCompressedDelta(long double &var){bool dataWritten; bool success; success=Read(dataWritten); if (dataWritten) success=ReadCompressed(var); return success;}
/// Write an array or casted stream or raw data. This does NOT do endian swapping.
/// \param[in] input a byte buffer
/// \param[in] numberOfBytes the size of \a input in bytes
void Write( const char* input, const int numberOfBytes );
/// Write one bitstream to another
/// \param[in] numberOfBits bits to write
/// \param bitStream the bitstream to copy from
void Write( BitStream *bitStream, int numberOfBits );
void Write( BitStream *bitStream );
/// Read a normalized 3D vector, using (at most) 4 bytes + 3 bits instead of 12-24 bytes. Will further compress y or z axis aligned vectors.
/// Accurate to 1/32767.5.
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
void WriteNormVector( float x, float y, float z );
void WriteNormVector( double x, double y, double z ) {WriteNormVector((float)x,(float)y,(float)z);}
/// Write a vector, using 10 bytes instead of 12.
/// Loses accuracy to about 3/10ths and only saves 2 bytes, so only use if accuracy is not important.
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
void WriteVector( float x, float y, float z );
void WriteVector( double x, double y, double z ) {WriteVector((float)x, (float)y, (float)z);}
/// Write a normalized quaternion in 6 bytes + 4 bits instead of 16 bytes. Slightly lossy.
/// \param[in] w w
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
void WriteNormQuat( float w, float x, float y, float z);
void WriteNormQuat( double w, double x, double y, double z) {WriteNormQuat((float)w, (float) x, (float) y, (float) z);}
/// Write an orthogonal matrix by creating a quaternion, and writing 3 components of the quaternion in 2 bytes each
/// for 6 bytes instead of 36
/// Lossy, although the result is renormalized
void WriteOrthMatrix(
float m00, float m01, float m02,
float m10, float m11, float m12,
float m20, float m21, float m22 )
{
WriteOrthMatrix((double)m00,(double)m01,(double)m02,
(double)m10,(double)m11,(double)m12,
(double)m20,(double)m21,(double)m22);
}
void WriteOrthMatrix(
double m00, double m01, double m02,
double m10, double m11, double m12,
double m20, double m21, double m22 );
/// Read an array or casted stream of byte. The array
/// is raw data. There is no automatic endian conversion with this function
/// \param[in] output The result byte array. It should be larger than @em numberOfBytes.
/// \param[in] numberOfBytes The number of byte to read
/// \return true on success false if there is some missing bytes.
bool Read( char* output, const int numberOfBytes );
/// Read a normalized 3D vector, using (at most) 4 bytes + 3 bits instead of 12-24 bytes. Will further compress y or z axis aligned vectors.
/// Accurate to 1/32767.5.
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
bool ReadNormVector( float &x, float &y, float &z );
bool ReadNormVector( double &x, double &y, double &z ) {float fx, fy, fz; bool b = ReadNormVector(fx, fy, fz); x=fx; y=fy; z=fz; return b;}
/// Read 3 floats or doubles, using 10 bytes, where those float or doubles comprise a vector
/// Loses accuracy to about 3/10ths and only saves 2 bytes, so only use if accuracy is not important.
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
bool ReadVector( float x, float y, float z );
bool ReadVector( double &x, double &y, double &z ) {return ReadVector((float)x, (float)y, (float)z);}
/// Read a normalized quaternion in 6 bytes + 4 bits instead of 16 bytes.
/// \param[in] w w
/// \param[in] x x
/// \param[in] y y
/// \param[in] z z
bool ReadNormQuat( float &w, float &x, float &y, float &z){double dw, dx, dy, dz; bool b=ReadNormQuat(dw, dx, dy, dz); w=(float)dw; x=(float)dx; y=(float)dy; z=(float)dz; return b;}
bool ReadNormQuat( double &w, double &x, double &y, double &z);
/// Read an orthogonal matrix from a quaternion, reading 3 components of the quaternion in 2 bytes each and extrapolating the 4th.
/// for 6 bytes instead of 36
/// Lossy, although the result is renormalized
bool ReadOrthMatrix(
float &m00, float &m01, float &m02,
float &m10, float &m11, float &m12,
float &m20, float &m21, float &m22 );
bool ReadOrthMatrix(
double &m00, double &m01, double &m02,
double &m10, double &m11, double &m12,
double &m20, double &m21, double &m22 );
///Sets the read pointer back to the beginning of your data.
void ResetReadPointer( void );
/// Sets the write pointer back to the beginning of your data.
void ResetWritePointer( void );
///This is good to call when you are done with the stream to make
/// sure you didn't leave any data left over void
void AssertStreamEmpty( void );
/// printf the bits in the stream. Great for debugging.
void PrintBits( void ) const;
/// Ignore data we don't intend to read
/// \param[in] numberOfBits The number of bits to ignore
void IgnoreBits( const int numberOfBits );
/// Ignore data we don't intend to read
/// \param[in] numberOfBits The number of bytes to ignore
void IgnoreBytes( const int numberOfBytes );
///Move the write pointer to a position on the array.
/// \param[in] offset the offset from the start of the array.
/// \attention
/// Dangerous if you don't know what you are doing!
/// For efficiency reasons you can only write mid-stream if your data is byte aligned.
void SetWriteOffset( const int offset );
/// Returns the length in bits of the stream
inline int GetNumberOfBitsUsed( void ) const {return GetWriteOffset();}
inline int GetWriteOffset( void ) const {return numberOfBitsUsed;}
///Returns the length in bytes of the stream
inline int GetNumberOfBytesUsed( void ) const {return BITS_TO_BYTES( numberOfBitsUsed );}
///Returns the number of bits into the stream that we have read
inline int GetReadOffset( void ) const {return readOffset;}
// Sets the read bit index
inline void SetReadOffset( int newReadOffset ) {readOffset=newReadOffset;}
///Returns the number of bits left in the stream that haven't been read
inline int GetNumberOfUnreadBits( void ) const {return numberOfBitsUsed - readOffset;}
/// Makes a copy of the internal data for you \a _data will point to
/// the stream. Returns the length in bits of the stream. Partial
/// bytes are left aligned
/// \param[out] _data The allocated copy of GetData()
int CopyData( unsigned char** _data ) const;
/// Set the stream to some initial data.
/// \internal
void SetData( unsigned char *input );
/// Gets the data that BitStream is writing to / reading from
/// Partial bytes are left aligned.
/// \return A pointer to the internal state
inline unsigned char* GetData( void ) const {return data;}
/// Write numberToWrite bits from the input source Right aligned
/// data means in the case of a partial byte, the bits are aligned
/// from the right (bit 0) rather than the left (as in the normal
/// internal representation) You would set this to true when
/// writing user data, and false when copying bitstream data, such
/// as writing one bitstream to another
/// \param[in] input The data
/// \param[in] numberOfBitsToWrite The number of bits to write
/// \param[in] rightAlignedBits if true data will be right aligned
void WriteBits( const unsigned char* input, int numberOfBitsToWrite, const bool rightAlignedBits = true );
/// Align the bitstream to the byte boundary and then write the
/// specified number of bits. This is faster than WriteBits but
/// wastes the bits to do the alignment and requires you to call
/// ReadAlignedBits at the corresponding read position.
/// \param[in] input The data
/// \param[in] numberOfBytesToWrite The size of input.
void WriteAlignedBytes( void *input, const int numberOfBytesToWrite );
/// Aligns the bitstream, writes inputLength, and writes input. Won't write beyond maxBytesToWrite
/// \param[in] input The data
/// \param[in] inputLength The size of input.
/// \param[in] maxBytesToWrite Max bytes to write
void WriteAlignedBytesSafe( void *input, const int inputLength, const int maxBytesToWrite );
/// Read bits, starting at the next aligned bits. Note that the
/// modulus 8 starting offset of the sequence must be the same as
/// was used with WriteBits. This will be a problem with packet
/// coalescence unless you byte align the coalesced packets.
/// \param[in] output The byte array larger than @em numberOfBytesToRead
/// \param[in] numberOfBytesToRead The number of byte to read from the internal state
/// \return true if there is enough byte.
bool ReadAlignedBytes( void *output, const int numberOfBytesToRead );
/// Reads what was written by WriteAlignedBytesSafe
/// \param[in] input The data
/// \param[in] maxBytesToRead Maximum number of bytes to read
bool ReadAlignedBytesSafe( void *input, int &inputLength, const int maxBytesToRead );
/// Same as ReadAlignedBytesSafe() but allocates the memory for you using new, rather than assuming it is safe to write to
/// \param[in] input input will be deleted if it is not a pointer to 0
bool ReadAlignedBytesSafeAlloc( char **input, int &inputLength, const int maxBytesToRead );
/// Align the next write and/or read to a byte boundary. This can
/// be used to 'waste' bits to byte align for efficiency reasons It
/// can also be used to force coalesced bitstreams to start on byte
/// boundaries so so WriteAlignedBits and ReadAlignedBits both
/// calculate the same offset when aligning.
void AlignWriteToByteBoundary( void );
/// Align the next write and/or read to a byte boundary. This can
/// be used to 'waste' bits to byte align for efficiency reasons It
/// can also be used to force coalesced bitstreams to start on byte
/// boundaries so so WriteAlignedBits and ReadAlignedBits both
/// calculate the same offset when aligning.
void AlignReadToByteBoundary( void );
/// Read \a numberOfBitsToRead bits to the output source
/// alignBitsToRight should be set to true to convert internal
/// bitstream data to userdata. It should be false if you used
/// WriteBits with rightAlignedBits false
/// \param[in] output The resulting bits array
/// \param[in] numberOfBitsToRead The number of bits to read
/// \param[in] alignBitsToRight if true bits will be right aligned.
/// \return true if there is enough bits to read
bool ReadBits( unsigned char *output, int numberOfBitsToRead, const bool alignBitsToRight = true );
/// Write a 0
void Write0( void );
/// Write a 1
void Write1( void );
/// Reads 1 bit and returns true if that bit is 1 and false if it is 0
bool ReadBit( void );
/// If we used the constructor version with copy data off, this
/// *makes sure it is set to on and the data pointed to is copied.
void AssertCopyData( void );
/// Use this if you pass a pointer copy to the constructor
/// *(_copyData==false) and want to overallocate to prevent
/// *reallocation
void SetNumberOfBitsAllocated( const unsigned int lengthInBits );
/// Reallocates (if necessary) in preparation of writing numberOfBitsToWrite
void AddBitsAndReallocate( const int numberOfBitsToWrite );
/// \internal
/// \return How many bits have been allocated internally
unsigned int GetNumberOfBitsAllocated(void) const;
static bool DoEndianSwap(void);
static bool IsBigEndian(void);
static bool IsNetworkOrder(void);
static void ReverseBytes(unsigned char *input, unsigned char *output, int length);
static void ReverseBytesInPlace(unsigned char *data, int length);
private:
BitStream( const BitStream &invalid) {
#ifdef _MSC_VER
#pragma warning(disable:4100)
// warning C4100: 'invalid' : unreferenced formal parameter
#endif
}
/// Assume the input source points to a native type, compress and write it.
void WriteCompressed( const unsigned char* input, const int size, const bool unsignedData );
/// Assume the input source points to a compressed native type. Decompress and read it.
bool ReadCompressed( unsigned char* output, const int size, const bool unsignedData );
int numberOfBitsUsed;
int numberOfBitsAllocated;
int readOffset;
unsigned char *data;
/// true if the internal buffer is copy of the data passed to the constructor
bool copyData;
/// BitStreams that use less than BITSTREAM_STACK_ALLOCATION_SIZE use the stack, rather than the heap to store data. It switches over if BITSTREAM_STACK_ALLOCATION_SIZE is exceeded
unsigned char stackData[BITSTREAM_STACK_ALLOCATION_SIZE];
};
inline bool BitStream::SerializeBits(bool writeToBitstream, unsigned char* input, int numberOfBitsToSerialize, const bool rightAlignedBits )
{
if (writeToBitstream)
WriteBits(input,numberOfBitsToSerialize,rightAlignedBits);
else
return ReadBits(input,numberOfBitsToSerialize,rightAlignedBits);
return true;
}
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif // VC6
#endif

97
thirdparty/raknet/Source/CheckSum.cpp vendored Normal file
View File

@@ -0,0 +1,97 @@
/**
* @file
* @brief CheckSum implementation from http://www.flounder.com/checksum.htm
*
*/
#include "CheckSum.h"
/****************************************************************************
* CheckSum::add
* Inputs:
* unsigned int d: word to add
* Result: void
*
* Effect:
* Adds the bytes of the unsigned int to the CheckSum
****************************************************************************/
void CheckSum::Add ( unsigned int value )
{
union
{
unsigned int value;
unsigned char bytes[ 4 ];
}
data;
data.value = value;
for ( unsigned int i = 0; i < sizeof( data.bytes ); i++ )
Add ( data.bytes[ i ] )
;
} // CheckSum::add(unsigned int)
/****************************************************************************
* CheckSum::add
* Inputs:
* unsigned short value:
* Result: void
*
* Effect:
* Adds the bytes of the unsigned short value to the CheckSum
****************************************************************************/
void CheckSum::Add ( unsigned short value )
{
union
{
unsigned short value;
unsigned char bytes[ 2 ];
}
data;
data.value = value;
for ( unsigned int i = 0; i < sizeof( data.bytes ); i++ )
Add ( data.bytes[ i ] )
;
} // CheckSum::add(unsigned short)
/****************************************************************************
* CheckSum::add
* Inputs:
* unsigned char value:
* Result: void
*
* Effect:
* Adds the byte to the CheckSum
****************************************************************************/
void CheckSum::Add ( unsigned char value )
{
unsigned char cipher = (unsigned char)( value ^ ( r >> 8 ) );
r = ( cipher + r ) * c1 + c2;
sum += cipher;
} // CheckSum::add(unsigned char)
/****************************************************************************
* CheckSum::add
* Inputs:
* LPunsigned char b: pointer to byte array
* unsigned int length: count
* Result: void
*
* Effect:
* Adds the bytes to the CheckSum
****************************************************************************/
void CheckSum::Add ( unsigned char *b, unsigned int length )
{
for ( unsigned int i = 0; i < length; i++ )
Add ( b[ i ] )
;
} // CheckSum::add(LPunsigned char, unsigned int)

54
thirdparty/raknet/Source/CheckSum.h vendored Normal file
View File

@@ -0,0 +1,54 @@
/// \file
/// \brief \b [Internal] Generates and validates checksums
///
/// \note I didn't write this, but took it from http://www.flounder.com/checksum.htm
///
#ifndef __CHECKSUM_H
#define __CHECKSUM_H
#include "RakMemoryOverride.h"
/// Generates and validates checksums
class CheckSum : public RakNet::RakMemoryOverride
{
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

View File

@@ -0,0 +1,50 @@
/// \file
/// \brief \b [Internal] Depreciated, back from when I supported IO Completion ports.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __CLIENT_CONTEXT_STRUCT_H
#define __CLIENT_CONTEXT_STRUCT_H
#ifdef _XBOX360
#elif defined(_WIN32)
//#include <windows.h>
#endif
#include "RakNetTypes.h"
#include "MTUSize.h"
class RakPeer;
#ifdef __USE_IO_COMPLETION_PORTS
struct ClientContextStruct
{
HANDLE handle; // The socket, also used as a file handle
};
struct ExtendedOverlappedStruct
{
OVERLAPPED overlapped;
char data[ MAXIMUM_MTU_SIZE ]; // Used to hold data to send
int length; // Length of the actual data to send, always under MAXIMUM_MTU_SIZE
unsigned int binaryAddress;
unsigned short port;
RakPeer *rakPeer;
bool read; // Set to true for reads, false for writes
};
#endif
#endif

View File

@@ -0,0 +1,168 @@
#include "CommandParserInterface.h"
#include "TransportInterface.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
#ifdef _XBOX360
#include "Console1Includes.h"
#elif defined(_WIN32)
// IP_DONTFRAGMENT is different between winsock 1 and winsock 2. Therefore, Winsock2.h must be linked againt Ws2_32.lib
// winsock.h must be linked against WSock32.lib. If these two are mixed up the flag won't work correctly
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "LinuxStrings.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
const unsigned char CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS=255;
int RegisteredCommandComp( const char* const & key, const RegisteredCommand &data )
{
return _stricmp(key,data.command);
}
CommandParserInterface::CommandParserInterface() {}
CommandParserInterface::~CommandParserInterface() {}
void CommandParserInterface::ParseConsoleString(char *str, const char delineator, unsigned char delineatorToggle, unsigned *numParameters, char **parameterList, unsigned parameterListLength)
{
unsigned strIndex, parameterListIndex;
unsigned strLen;
bool replaceDelineator=true;
strLen = (unsigned) strlen(str);
// Replace every instance of delineator, \n, \r with 0
for (strIndex=0; strIndex < strLen; strIndex++)
{
if (str[strIndex]==delineator && replaceDelineator)
str[strIndex]=0;
if (str[strIndex]=='\n' || str[strIndex]=='\r')
str[strIndex]=0;
if (str[strIndex]==delineatorToggle)
{
str[strIndex]=0;
replaceDelineator=!replaceDelineator;
}
}
// Fill up parameterList starting at each non-0
for (strIndex=0, parameterListIndex=0; strIndex < strLen; )
{
if (str[strIndex]!=0)
{
parameterList[parameterListIndex]=str+strIndex;
parameterListIndex++;
assert(parameterListIndex < parameterListLength);
if (parameterListIndex >= parameterListLength)
break;
strIndex++;
while (str[strIndex]!=0 && strIndex < strLen)
strIndex++;
}
else
strIndex++;
}
parameterList[parameterListIndex]=0;
*numParameters=parameterListIndex;
}
void CommandParserInterface::SendCommandList(TransportInterface *transport, SystemAddress systemAddress)
{
unsigned i;
if (commandList.Size())
{
for (i=0; i < commandList.Size(); i++)
{
transport->Send(systemAddress, "%s", commandList[i].command);
if (i < commandList.Size()-1)
transport->Send(systemAddress, ", ");
}
transport->Send(systemAddress, "\r\n");
}
else
transport->Send(systemAddress, "No registered commands\r\n");
}
void CommandParserInterface::RegisterCommand(unsigned char parameterCount, const char *command, const char *commandHelp)
{
RegisteredCommand rc;
rc.command=command;
rc.commandHelp=commandHelp;
rc.parameterCount=parameterCount;
commandList.Insert( command, rc, true);
}
bool CommandParserInterface::GetRegisteredCommand(const char *command, RegisteredCommand *rc)
{
bool objectExists;
unsigned index;
index=commandList.GetIndexFromKey(command, &objectExists);
if (objectExists)
*rc=commandList[index];
return objectExists;
}
void CommandParserInterface::OnTransportChange(TransportInterface *transport)
{
(void) transport;
}
void CommandParserInterface::OnNewIncomingConnection(SystemAddress systemAddress, TransportInterface *transport)
{
(void) systemAddress;
(void) transport;
}
void CommandParserInterface::OnConnectionLost(SystemAddress systemAddress, TransportInterface *transport)
{
(void) systemAddress;
(void) transport;
}
void CommandParserInterface::ReturnResult(bool res, const char *command,TransportInterface *transport, SystemAddress systemAddress)
{
if (res)
transport->Send(systemAddress, "%s returned true.\r\n", command);
else
transport->Send(systemAddress, "%s returned false.\r\n", command);
}
void CommandParserInterface::ReturnResult(int res, const char *command,TransportInterface *transport, SystemAddress systemAddress)
{
transport->Send(systemAddress, "%s returned %i.\r\n", command, res);
}
void CommandParserInterface::ReturnResult(const char *command, TransportInterface *transport, SystemAddress systemAddress)
{
transport->Send(systemAddress, "Successfully called %s.\r\n", command);
}
void CommandParserInterface::ReturnResult(char *res, const char *command, TransportInterface *transport, SystemAddress systemAddress)
{
transport->Send(systemAddress, "%s returned %s.\r\n", command, res);
}
void CommandParserInterface::ReturnResult(SystemAddress res, const char *command, TransportInterface *transport, SystemAddress systemAddress)
{
#if !defined(_XBOX360)
in_addr in;
in.s_addr = systemAddress.binaryAddress;
inet_ntoa( in );
transport->Send(systemAddress, "%s returned %s %i:%i\r\n", command,inet_ntoa( in ),res.binaryAddress, res.port);
#else
transport->Send(systemAddress, "%s returned %i:%i\r\n", command,res.binaryAddress, res.port);
#endif
}
SystemAddress CommandParserInterface::IntegersToSystemAddress(int binaryAddress, int port)
{
SystemAddress systemAddress;
systemAddress.binaryAddress=binaryAddress;
systemAddress.port=(unsigned short)port;
return systemAddress;
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@@ -0,0 +1,149 @@
/// \file
/// \brief Contains CommandParserInterface , from which you derive custom command parsers
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __COMMAND_PARSER_INTERFACE
#define __COMMAND_PARSER_INTERFACE
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#include "DS_OrderedList.h"
#include "Export.h"
class TransportInterface;
/// \internal
/// Contains the information related to one command registered with RegisterCommand()
/// Implemented so I can have an automatic help system via SendCommandList()
struct RAK_DLL_EXPORT RegisteredCommand
{
const char *command;
const char *commandHelp;
unsigned char parameterCount;
};
/// List of commands registered with RegisterCommand()
int RAK_DLL_EXPORT RegisteredCommandComp( const char* const & key, const RegisteredCommand &data );
/// CommandParserInterface provides a set of functions and interfaces that plug into the ConsoleServer class.
/// Each CommandParserInterface works at the same time as other interfaces in the system.
/// \brief The interface used by command parsers.
class RAK_DLL_EXPORT CommandParserInterface : public RakNet::RakMemoryOverride
{
public:
CommandParserInterface();
virtual ~CommandParserInterface();
/// You are responsible for overriding this function and returning a static string, which will identifier your parser.
/// This should return a static string
/// \return The name that you return.
virtual const char *GetName(void) const=0;
/// A callback for when \a systemAddress has connected to us.
/// \param[in] systemAddress The player that has connected.
/// \param[in] transport The transport interface that sent us this information. Can be used to send messages to this or other players.
virtual void OnNewIncomingConnection(SystemAddress systemAddress, TransportInterface *transport);
/// A callback for when \a systemAddress has disconnected, either gracefully or forcefully
/// \param[in] systemAddress The player that has disconnected.
/// \param[in] transport The transport interface that sent us this information.
virtual void OnConnectionLost(SystemAddress systemAddress, TransportInterface *transport);
/// A callback for when you are expected to send a brief description of your parser to \a systemAddress
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that requested help.
virtual void SendHelp(TransportInterface *transport, SystemAddress systemAddress)=0;
/// Given \a command with parameters \a parameterList , do whatever processing you wish.
/// \param[in] command The command to process
/// \param[in] numParameters How many parameters were passed along with the command
/// \param[in] parameterList The list of parameters. parameterList[0] is the first parameter and so on.
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that sent this command.
/// \param[in] originalString The string that was actually sent over the network, in case you want to do your own parsing
virtual bool OnCommand(const char *command, unsigned numParameters, char **parameterList, TransportInterface *transport, SystemAddress systemAddress, const char *originalString)=0;
/// This is called every time transport interface is registered. If you want to save a copy of the TransportInterface pointer
/// This is the place to do it
/// \param[in] transport The new TransportInterface
virtual void OnTransportChange(TransportInterface *transport);
/// \internal
/// Scan commandList and return the associated array
/// \param[in] command The string to find
/// \param[out] rc Contains the result of this operation
/// \return True if we found the command, false otherwise
virtual bool GetRegisteredCommand(const char *command, RegisteredCommand *rc);
/// \internal
/// Goes through str, replacing the delineating character with 0's.
/// \param[in] str The string sent by the transport interface
/// \param[in] delineator The character to scan for to use as a delineator
/// \param[in] delineatorToggle When encountered the delineator replacement is toggled on and off
/// \param[out] numParameters How many pointers were written to \a parameterList
/// \param[out] parameterList An array of pointers to characters. Will hold pointers to locations inside \a str
/// \param[in] parameterListLength How big the \a parameterList array is
static void ParseConsoleString(char *str, const char delineator, unsigned char delineatorToggle, unsigned *numParameters, char **parameterList, unsigned parameterListLength);
/// \internal
/// Goes through the variable commandList and sends the command portion of each struct
/// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player to write to
virtual void SendCommandList(TransportInterface *transport, SystemAddress systemAddress);
static const unsigned char VARIABLE_NUMBER_OF_PARAMETERS;
protected:
// Currently only takes static strings - doesn't make a copy of what you pass.
// parameterCount is the number of parameters that the sender has to include with the command.
// Pass 255 to parameterCount to indicate variable number of parameters
/// Registers a command.
/// \param[in] parameterCount How many parameters your command requires. If you want to accept a variable number of commands, pass CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS
/// \param[in] command A pointer to a STATIC string that has your command. I keep a copy of the pointer here so don't deallocate the string.
/// \param[in] commandHelp A pointer to a STATIC string that has the help information for your command. I keep a copy of the pointer here so don't deallocate the string.
virtual void RegisterCommand(unsigned char parameterCount, const char *command, const char *commandHelp);
/// Just writes a string to the remote system based on the result ( \a res )of your operation
/// This is not necessary to call, but makes it easier to return results of function calls
/// \param[in] res The result to write
/// \param[in] command The command that this result came from
/// \param[in] transport The transport interface that will be written to
/// \param[in] systemAddress The player this result will be sent to
virtual void ReturnResult(bool res, const char *command, TransportInterface *transport, SystemAddress systemAddress);
virtual void ReturnResult(char *res, const char *command, TransportInterface *transport, SystemAddress systemAddress);
virtual void ReturnResult(SystemAddress res, const char *command, TransportInterface *transport, SystemAddress systemAddress);
virtual void ReturnResult(int res, const char *command,TransportInterface *transport, SystemAddress systemAddress);
/// Just writes a string to the remote system when you are calling a function that has no return value
/// This is not necessary to call, but makes it easier to return results of function calls
/// \param[in] res The result to write
/// \param[in] command The command that this result came from
/// \param[in] transport The transport interface that will be written to
/// \param[in] systemAddress The player this result will be sent to
virtual void ReturnResult(const char *command,TransportInterface *transport, SystemAddress systemAddress);
/// Since there's no way to specify a systemAddress directly, the user needs to specify both the binary address and port.
/// Given those parameters, this returns the corresponding SystemAddress
/// \param[in] binaryAddress The binaryAddress portion of SystemAddress
/// \param[in] port The port portion of SystemAddress
SystemAddress IntegersToSystemAddress(int binaryAddress, int port);
DataStructures::OrderedList<const char*, RegisteredCommand, RegisteredCommandComp> commandList;
};
#endif

View File

@@ -0,0 +1,617 @@
/// \file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#include "ConnectionGraph.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "BitStream.h"
#include "StringCompressor.h"
#include "GetTime.h"
#include <string.h>
#include "RakAssert.h"
#include "SHA1.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
static const int connectionGraphChannel=31;
ConnectionGraph::SystemAddressAndGroupId::SystemAddressAndGroupId()
{
}
ConnectionGraph::SystemAddressAndGroupId::~SystemAddressAndGroupId()
{
}
ConnectionGraph::SystemAddressAndGroupId::SystemAddressAndGroupId(SystemAddress _systemAddress, ConnectionGraphGroupID _groupID)
{
systemAddress=_systemAddress;
groupId=_groupID;
}
bool ConnectionGraph::SystemAddressAndGroupId::operator==( const ConnectionGraph::SystemAddressAndGroupId& right ) const
{
return systemAddress==right.systemAddress;
}
bool ConnectionGraph::SystemAddressAndGroupId::operator!=( const ConnectionGraph::SystemAddressAndGroupId& right ) const
{
return systemAddress!=right.systemAddress;
}
bool ConnectionGraph::SystemAddressAndGroupId::operator > ( const ConnectionGraph::SystemAddressAndGroupId& right ) const
{
return systemAddress>right.systemAddress;
}
bool ConnectionGraph::SystemAddressAndGroupId::operator < ( const ConnectionGraph::SystemAddressAndGroupId& right ) const
{
return systemAddress<right.systemAddress;
}
ConnectionGraph::ConnectionGraph()
{
pw=0;
myGroupId=0;
autoAddNewConnections=true;
// forceBroadcastTime=0;
DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false>::IMPLEMENT_DEFAULT_COMPARISON();
DataStructures::OrderedList<SystemAddress, SystemAddress>::IMPLEMENT_DEFAULT_COMPARISON();
DataStructures::OrderedList<ConnectionGraph::SystemAddressAndGroupId, ConnectionGraph::SystemAddressAndGroupId>::IMPLEMENT_DEFAULT_COMPARISON();
DataStructures::OrderedList<ConnectionGraphGroupID, ConnectionGraphGroupID>::IMPLEMENT_DEFAULT_COMPARISON();
subscribedGroups.Insert(0,0, true);
}
ConnectionGraph::~ConnectionGraph()
{
if (pw)
delete [] pw;
}
void ConnectionGraph::SetPassword(const char *password)
{
if (pw)
{
delete [] pw;
pw=0;
}
if (password && password[0])
{
assert(strlen(password)<256);
pw=(char*) rakMalloc( strlen(password)+1 );
strcpy(pw, password);
}
}
DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false> *ConnectionGraph::GetGraph(void)
{
return &graph;
}
void ConnectionGraph::SetAutoAddNewConnections(bool autoAdd)
{
autoAddNewConnections=autoAdd;
}
void ConnectionGraph::OnShutdown(RakPeerInterface *peer)
{
(void) peer;
graph.Clear();
participantList.Clear();
// forceBroadcastTime=0;
}
void ConnectionGraph::Update(RakPeerInterface *peer)
{
(void) peer;
// RakNetTime time = RakNet::GetTime();
// If the time is past the next weight update time, then refresh all pings of all connected participants and send these out if substantially different.
// if (forceBroadcastTime && time > forceBroadcastTime)
// {
// DataStructures::OrderedList<SystemAddress,SystemAddress> none;
// BroadcastGraphUpdate(none, peer);
// forceBroadcastTime=0;
// }
}
PluginReceiveResult ConnectionGraph::OnReceive(RakPeerInterface *peer, Packet *packet)
{
switch (packet->data[0])
{
case ID_NEW_INCOMING_CONNECTION:
OnNewIncomingConnection(peer, packet);
return RR_CONTINUE_PROCESSING;
case ID_CONNECTION_REQUEST_ACCEPTED:
OnConnectionRequestAccepted(peer, packet);
return RR_CONTINUE_PROCESSING;
case ID_CONNECTION_GRAPH_REQUEST:
OnConnectionGraphRequest(peer, packet);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
case ID_CONNECTION_GRAPH_REPLY:
OnConnectionGraphReply(peer, packet);
return RR_CONTINUE_PROCESSING;
case ID_CONNECTION_GRAPH_UPDATE:
OnConnectionGraphUpdate(peer, packet);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
case ID_CONNECTION_GRAPH_NEW_CONNECTION:
OnNewConnection(peer, packet);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
// Remove connection lost
case ID_CONNECTION_GRAPH_CONNECTION_LOST:
case ID_CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION:
if (OnConnectionLost(peer, packet, packet->data[0]))
{
if (packet->data[0]==ID_CONNECTION_GRAPH_CONNECTION_LOST)
packet->data[0]=ID_REMOTE_CONNECTION_LOST;
else
packet->data[0]=ID_REMOTE_DISCONNECTION_NOTIFICATION;
return RR_CONTINUE_PROCESSING; // Return this packet to the user
}
return RR_STOP_PROCESSING_AND_DEALLOCATE;
// Local connection lost
case ID_CONNECTION_LOST:
case ID_DISCONNECTION_NOTIFICATION:
{
unsigned char packetId;
// Change to remote connection lost and relay the message
if (packet->data[0]==ID_CONNECTION_LOST)
packetId=ID_CONNECTION_GRAPH_CONNECTION_LOST;
else
packetId=ID_CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION;
HandleDroppedConnection(peer, packet->systemAddress, packetId);
}
}
return RR_CONTINUE_PROCESSING;
}
void ConnectionGraph::OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress)
{
HandleDroppedConnection(peer, systemAddress, ID_CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION);
}
void ConnectionGraph::HandleDroppedConnection(RakPeerInterface *peer, SystemAddress systemAddress, unsigned char packetId)
{
assert(peer);
RemoveParticipant(systemAddress);
DataStructures::OrderedList<SystemAddress,SystemAddress> ignoreList;
RemoveAndRelayConnection(ignoreList, packetId, systemAddress, peer->GetExternalID(systemAddress), peer);
}
void ConnectionGraph::OnNewIncomingConnection(RakPeerInterface *peer, Packet *packet)
{
if (autoAddNewConnections==false)
return;
// 0 is the default groupId
AddNewConnection(peer, packet->systemAddress, 0);
}
void ConnectionGraph::OnConnectionRequestAccepted(RakPeerInterface *peer, Packet *packet)
{
if (autoAddNewConnections==false)
return;
RequestConnectionGraph(peer, packet->systemAddress);
// 0 is the default groupId
AddNewConnection(peer, packet->systemAddress, 0);
}
void ConnectionGraph::SetGroupId(ConnectionGraphGroupID groupId)
{
myGroupId=groupId;
}
void ConnectionGraph::AddNewConnection(RakPeerInterface *peer, SystemAddress systemAddress, ConnectionGraphGroupID groupId)
{
if (autoAddNewConnections==false && subscribedGroups.HasData(groupId)==false)
return;
DataStructures::OrderedList<SystemAddress,SystemAddress> ignoreList;
SystemAddressAndGroupId first, second;
first.systemAddress=systemAddress;
first.groupId=groupId;
second.systemAddress=peer->GetExternalID(systemAddress);
second.groupId=myGroupId;
AddAndRelayConnection(ignoreList, first, second, (unsigned short)peer->GetAveragePing(systemAddress), peer);
}
void ConnectionGraph::SubscribeToGroup(ConnectionGraphGroupID groupId)
{
subscribedGroups.Insert(groupId, groupId, true);
}
void ConnectionGraph::UnsubscribeFromGroup(ConnectionGraphGroupID groupId)
{
subscribedGroups.Remove(groupId);
}
void ConnectionGraph::RequestConnectionGraph(RakPeerInterface *peer, SystemAddress systemAddress)
{
RakNet::BitStream outBitstream;
outBitstream.Write((MessageID)ID_CONNECTION_GRAPH_REQUEST);
stringCompressor->EncodeString(pw,256,&outBitstream);
peer->Send(&outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, systemAddress, false);
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
printf("ID_CONNECTION_GRAPH_REQUEST from %i to %i\n", peer->GetInternalID().port, systemAddress.port);
#endif
}
void ConnectionGraph::OnConnectionGraphRequest(RakPeerInterface *peer, Packet *packet)
{
char password[256];
RakNet::BitStream inBitstream(packet->data, packet->length, false);
inBitstream.IgnoreBits(8);
stringCompressor->DecodeString(password,256,&inBitstream);
if (pw && pw[0] && strcmp(pw, password)!=0)
return;
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
printf("ID_CONNECTION_GRAPH_REPLY ");
#endif
RakNet::BitStream outBitstream;
outBitstream.Write((MessageID)ID_CONNECTION_GRAPH_REPLY);
stringCompressor->EncodeString(pw,256,&outBitstream);
SerializeWeightedGraph(&outBitstream, graph);
peer->Send(&outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, packet->systemAddress, false);
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
printf("from %i to %i\n", peer->GetInternalID().port, packet->systemAddress.port);
#endif
// Add packet->systemAddress to the participant list if it is not already there
AddParticipant(packet->systemAddress);
}
void ConnectionGraph::OnConnectionGraphReply(RakPeerInterface *peer, Packet *packet)
{
unsigned char password[256];
RakNet::BitStream inBitstream(packet->data, packet->length, false);
inBitstream.IgnoreBits(8);
stringCompressor->DecodeString((char*)password,256,&inBitstream);
if (pw && pw[0] && strcmp(pw, (const char*)password)!=0)
return;
// Serialize the weighted graph and send it to them
RakNet::BitStream outBitstream;
outBitstream.Write((MessageID)ID_CONNECTION_GRAPH_UPDATE);
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
printf("ID_CONNECTION_GRAPH_UPDATE ");
#endif
// Send our current graph to the sender
SerializeWeightedGraph(&outBitstream, graph);
// Write the systems that have processed this graph so we don't resend to these systems
outBitstream.Write((unsigned short) 1);
outBitstream.Write(peer->GetExternalID(packet->systemAddress));
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
printf("from %i to %i\n", peer->GetInternalID().port, packet->systemAddress.port);
#endif
peer->Send(&outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, packet->systemAddress, false);
// Add packet->systemAddress to the participant list if it is not already there
AddParticipant(packet->systemAddress);
if (DeserializeWeightedGraph(&inBitstream, peer)==false)
return;
// Forward the updated graph to all current participants
DataStructures::OrderedList<SystemAddress,SystemAddress> ignoreList;
ignoreList.Insert(packet->systemAddress,packet->systemAddress, true);
BroadcastGraphUpdate(ignoreList, peer);
}
void ConnectionGraph::OnConnectionGraphUpdate(RakPeerInterface *peer, Packet *packet)
{
// Only accept from participants
if (participantList.HasData(packet->systemAddress)==false)
return;
RakNet::BitStream inBitstream(packet->data, packet->length, false);
inBitstream.IgnoreBits(8);
if (DeserializeWeightedGraph(&inBitstream, peer)==false)
return;
DataStructures::OrderedList<SystemAddress,SystemAddress> ignoreList;
DeserializeIgnoreList(ignoreList, &inBitstream);
// Forward the updated graph to all participants.
ignoreList.Insert(packet->systemAddress,packet->systemAddress, false);
BroadcastGraphUpdate(ignoreList, peer);
}
void ConnectionGraph::OnNewConnection(RakPeerInterface *peer, Packet *packet)
{
// Only accept from participants
if (participantList.HasData(packet->systemAddress)==false)
return;
SystemAddressAndGroupId node1, node2;
unsigned short ping;
RakNet::BitStream inBitstream(packet->data, packet->length, false);
inBitstream.IgnoreBits(8);
inBitstream.Read(node1.systemAddress);
inBitstream.Read(node1.groupId);
inBitstream.Read(node2.systemAddress);
inBitstream.Read(node2.groupId);
if (inBitstream.Read(ping)==false)
return;
DataStructures::OrderedList<SystemAddress,SystemAddress> ignoreList;
DeserializeIgnoreList(ignoreList, &inBitstream);
ignoreList.Insert(packet->systemAddress,packet->systemAddress, false);
AddAndRelayConnection(ignoreList, node1, node2, ping, peer);
}
bool ConnectionGraph::OnConnectionLost(RakPeerInterface *peer, Packet *packet, unsigned char packetId)
{
// Only accept from participants
if (participantList.HasData(packet->systemAddress)==false)
return false;
SystemAddress node1, node2;
RakNet::BitStream inBitstream(packet->data, packet->length, false);
inBitstream.IgnoreBits(8);
// This is correct - group IDs are not written for removal, only addition.
inBitstream.Read(node1);
if (inBitstream.Read(node2)==false)
return false;
DataStructures::OrderedList<SystemAddress,SystemAddress> ignoreList;
DeserializeIgnoreList(ignoreList, &inBitstream);
ignoreList.Insert(packet->systemAddress, packet->systemAddress, false);
return RemoveAndRelayConnection(ignoreList, packetId, node1, node2, peer);
}
bool ConnectionGraph::DeserializeIgnoreList(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, RakNet::BitStream *inBitstream )
{
unsigned short count;
SystemAddress temp;
unsigned i;
inBitstream->Read(count);
for (i=0; i < count; i++)
{
if (inBitstream->Read(temp)==false)
{
assert(0);
return false;
}
ignoreList.Insert(temp,temp, true);
}
return true;
}
void ConnectionGraph::SerializeWeightedGraph(RakNet::BitStream *out, const DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false> &g) const
{
unsigned nodeIndex, connectionIndex;
BitSize_t countOffset, oldOffset;
unsigned short count;
SystemAddressAndGroupId node1, node2;
unsigned short weight;
out->WriteCompressed(g.GetNodeCount());
for (nodeIndex=0; nodeIndex < g.GetNodeCount(); nodeIndex++)
{
// Write the node
node1=g.GetNodeAtIndex(nodeIndex);
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
printf("[%i] ", node1.systemAddress.port);
#endif
out->Write(node1.systemAddress);
out->Write(node1.groupId);
// Write the adjacency list count
count=(unsigned short)g.GetConnectionCount(nodeIndex);
out->AlignWriteToByteBoundary();
countOffset=out->GetWriteOffset();
out->Write(count);
count=0;
for (connectionIndex=0; connectionIndex < g.GetConnectionCount(nodeIndex); connectionIndex++)
{
g.GetConnectionAtIndex(nodeIndex, connectionIndex, node2, weight);
// For efficiencies' sake, only serialize the upper half of the connection pairs
if (node2 > node1)
{
count++;
out->Write(node2.systemAddress);
out->Write(node2.groupId);
out->Write(weight);
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
printf("(%i) ", node2.systemAddress.port);
#endif
}
}
// Go back and change how many elements were written
oldOffset=out->GetWriteOffset();
out->SetWriteOffset(countOffset);
out->Write(count);
out->SetWriteOffset(oldOffset);
}
}
bool ConnectionGraph::DeserializeWeightedGraph(RakNet::BitStream *inBitstream, RakPeerInterface *peer)
{
unsigned nodeCount, nodeIndex, connectionIndex;
unsigned short connectionCount;
SystemAddressAndGroupId node, connection;
bool anyConnectionsNew=false;
unsigned short weight;
inBitstream->ReadCompressed(nodeCount);
for (nodeIndex=0; nodeIndex < nodeCount; nodeIndex++)
{
inBitstream->Read(node.systemAddress);
inBitstream->Read(node.groupId);
inBitstream->AlignReadToByteBoundary();
if (inBitstream->Read(connectionCount)==false)
{
assert(0);
return false;
}
for (connectionIndex=0; connectionIndex < connectionCount; connectionIndex++)
{
inBitstream->Read(connection.systemAddress);
inBitstream->Read(connection.groupId);
if (inBitstream->Read(weight)==false)
{
assert(0);
return false;
}
if (subscribedGroups.HasData(connection.groupId)==false ||
subscribedGroups.HasData(node.groupId)==false)
continue;
RakAssert(node.systemAddress!=UNASSIGNED_SYSTEM_ADDRESS);
RakAssert(connection.systemAddress!=UNASSIGNED_SYSTEM_ADDRESS);
if (IsNewRemoteConnection(node,connection,peer))
NotifyUserOfRemoteConnection(node,connection,weight,peer);
if (graph.HasConnection(node,connection)==false)
anyConnectionsNew=true;
graph.AddConnection(node,connection,weight);
}
}
return anyConnectionsNew;
}
void ConnectionGraph::RemoveParticipant(SystemAddress systemAddress)
{
unsigned index;
bool objectExists;
index=participantList.GetIndexFromKey(systemAddress, &objectExists);
if (objectExists)
participantList.RemoveAtIndex(index);
}
void ConnectionGraph::AddParticipant(SystemAddress systemAddress)
{
participantList.Insert(systemAddress,systemAddress, false);
}
void ConnectionGraph::AddAndRelayConnection(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, const SystemAddressAndGroupId &conn1, const SystemAddressAndGroupId &conn2, unsigned short ping, RakPeerInterface *peer)
{
if (graph.HasConnection(conn1,conn2))
return;
if (ping==65535)
ping=0;
assert(conn1.systemAddress!=UNASSIGNED_SYSTEM_ADDRESS);
assert(conn2.systemAddress!=UNASSIGNED_SYSTEM_ADDRESS);
if (IsNewRemoteConnection(conn1,conn2,peer))
{
NotifyUserOfRemoteConnection(conn1,conn2,ping,peer);
// What was this return here for?
// return;
}
graph.AddConnection(conn1,conn2,ping);
RakNet::BitStream outBitstream;
outBitstream.Write((MessageID)ID_CONNECTION_GRAPH_NEW_CONNECTION);
outBitstream.Write(conn1.systemAddress);
outBitstream.Write(conn1.groupId);
outBitstream.Write(conn2.systemAddress);
outBitstream.Write(conn2.groupId);
outBitstream.Write(ping);
ignoreList.Insert(conn2.systemAddress,conn2.systemAddress, false);
ignoreList.Insert(conn1.systemAddress,conn1.systemAddress, false);
SerializeIgnoreListAndBroadcast(&outBitstream, ignoreList, peer);
}
bool ConnectionGraph::RemoveAndRelayConnection(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, unsigned char packetId, const SystemAddress node1, const SystemAddress node2, RakPeerInterface *peer)
{
SystemAddressAndGroupId n1, n2;
n1.systemAddress=node1;
n2.systemAddress=node2;
if (graph.HasConnection(n1,n2)==false)
return false;
graph.RemoveConnection(n1,n2);
RakNet::BitStream outBitstream;
outBitstream.Write(packetId);
outBitstream.Write(node1);
outBitstream.Write(node2);
ignoreList.Insert(node1,node1, false);
ignoreList.Insert(node2,node2, false);
SerializeIgnoreListAndBroadcast(&outBitstream, ignoreList, peer);
return true;
}
void ConnectionGraph::BroadcastGraphUpdate(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, RakPeerInterface *peer)
{
RakNet::BitStream outBitstream;
outBitstream.Write((MessageID)ID_CONNECTION_GRAPH_UPDATE);
SerializeWeightedGraph(&outBitstream, graph);
SerializeIgnoreListAndBroadcast(&outBitstream, ignoreList, peer);
}
void ConnectionGraph::SerializeIgnoreListAndBroadcast(RakNet::BitStream *outBitstream, DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, RakPeerInterface *peer)
{
DataStructures::List<SystemAddress> sendList;
unsigned i;
for (i=0; i < participantList.Size(); i++)
{
if (ignoreList.HasData(participantList[i])==false)
sendList.Insert(participantList[i]);
}
if (sendList.Size()==0)
return;
SystemAddress self = peer->GetExternalID(sendList[0]);
ignoreList.Insert(self,self, false);
outBitstream->Write((unsigned short) (ignoreList.Size()+sendList.Size()));
for (i=0; i < ignoreList.Size(); i++)
outBitstream->Write(ignoreList[i]);
for (i=0; i < sendList.Size(); i++)
outBitstream->Write(sendList[i]);
for (i=0; i < sendList.Size(); i++)
{
peer->Send(outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, sendList[i], false);
}
}
bool ConnectionGraph::IsNewRemoteConnection(const SystemAddressAndGroupId &conn1, const SystemAddressAndGroupId &conn2,RakPeerInterface *peer)
{
if (graph.HasConnection(conn1,conn2)==false &&
subscribedGroups.HasData(conn1.groupId) &&
subscribedGroups.HasData(conn2.groupId) &&
(peer->IsConnected(conn1.systemAddress)==false || peer->IsConnected(conn2.systemAddress)==false))
{
SystemAddress externalId1, externalId2;
externalId1=peer->GetExternalID(conn1.systemAddress);
externalId2=peer->GetExternalID(conn2.systemAddress);
return (externalId1!=conn1.systemAddress && externalId1!=conn2.systemAddress &&
externalId2!=conn1.systemAddress && externalId2!=conn2.systemAddress);
}
return false;
}
void ConnectionGraph::NotifyUserOfRemoteConnection(const SystemAddressAndGroupId &conn1, const SystemAddressAndGroupId &conn2,unsigned short ping, RakPeerInterface *peer)
{
// Create a packet to tell the user of this event
static const int length=sizeof(MessageID) + (sizeof(SystemAddress) + sizeof(ConnectionGraphGroupID)) * 2 + sizeof(unsigned short);
Packet *p = peer->AllocatePacket(length);
RakNet::BitStream b(p->data, length, false);
p->bitSize=p->length*8;
b.SetWriteOffset(0);
b.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION);
b.Write(conn1.systemAddress);
b.Write(conn1.groupId);
b.Write(conn2.systemAddress);
b.Write(conn2.groupId);
b.Write(ping);
if (peer->IsConnected(conn2.systemAddress)==false)
p->systemAddress=conn2.systemAddress;
else
p->systemAddress=conn1.systemAddress;
peer->PushBackPacket(p, false);
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@@ -0,0 +1,166 @@
/// \file
/// \brief Connection graph plugin. This maintains a graph of connections for the entire network, so every peer knows about every other peer.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __CONNECTION_GRAPH_H
#define __CONNECTION_GRAPH_H
class RakPeerInterface;
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#include "PluginInterface.h"
#include "DS_List.h"
#include "DS_WeightedGraph.h"
#include "GetTime.h"
#include "Export.h"
// If you need more than 255 groups just change this typedef
typedef unsigned char ConnectionGraphGroupID;
/// \defgroup CONNECTION_GRAPH_GROUP ConnectionGraph
/// \ingroup PLUGINS_GROUP
/// \ingroup CONNECTION_GRAPH_GROUP
/// \brief A connection graph. Each peer will know about all other peers.
class RAK_DLL_EXPORT ConnectionGraph : public PluginInterface
{
public:
ConnectionGraph();
virtual ~ConnectionGraph();
/// A node in the connection graph
struct RAK_DLL_EXPORT SystemAddressAndGroupId
{
SystemAddressAndGroupId();
~SystemAddressAndGroupId();
SystemAddressAndGroupId(SystemAddress _systemAddress, ConnectionGraphGroupID _groupID);
SystemAddress systemAddress;
ConnectionGraphGroupID groupId;
bool operator==( const SystemAddressAndGroupId& right ) const;
bool operator!=( const SystemAddressAndGroupId& right ) const;
bool operator > ( const SystemAddressAndGroupId& right ) const;
bool operator < ( const SystemAddressAndGroupId& right ) const;
};
// --------------------------------------------------------------------------------------------
// User functions
// --------------------------------------------------------------------------------------------
/// Plaintext encoding of the password, or 0 for none. If you use a password, use secure connections
void SetPassword(const char *password);
/// Returns the connection graph
/// \return The connection graph, stored as map of adjacency lists
DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false> *GetGraph(void);
/// Automatically add new connections to the connection graph
/// Defaults to true
/// If true, then the system will automatically add all new connections for you, assigning groupId 0 to these systems.
/// If you want more control, you should call SetAutoAddNewConnections(false);
/// When false, it is up to you to call RequestConnectionGraph and AddNewConnection to complete the graph
/// However, this way you can choose which nodes are on the graph for this system and can assign groupIds to those nodes
/// \param[in] autoAdd true to automatically add new connections to the connection graph. False to not do so.
void SetAutoAddNewConnections(bool autoAdd);
/// Requests the connection graph from another system
/// Only necessary to call if SetAutoAddNewConnections(false) is called.
/// You should call this sometime after getting ID_CONNECTION_REQUEST_ACCEPTED and \a systemAddress is or should be a node on the connection graph
/// \param[in] peer The instance of RakPeer to send through
/// \param[in] systemAddress The system to send to
void RequestConnectionGraph(RakPeerInterface *peer, SystemAddress systemAddress);
/// Adds a new connection to the connection graph from this system to the specified system. Also assigns a group identifier for that system
/// Only used and valid when SetAutoAddNewConnections(false) is called.
/// Call this for this system sometime after getting ID_NEW_INCOMING_CONNECTION or ID_CONNECTION_REQUEST_ACCEPTED for systems that contain a connection graph
/// Groups are sets of one or more nodes in the total graph
/// We only add to the graph groups which we subscribe to
/// \param[in] peer The instance of RakPeer to send through
/// \param[in] systemAddress The system that is connected to us.
/// \param[in] groupId Just a number representing a group. Important: 0 is reserved to mean unassigned group ID and is assigned to all systems added with SetAutoAddNewConnections(true)
void AddNewConnection(RakPeerInterface *peer, SystemAddress systemAddress, ConnectionGraphGroupID groupId);
/// Sets our own group ID
/// Only used and valid when SetAutoAddNewConnections(false) is called.
/// Defaults to 0
/// \param[in] groupId Our group ID
void SetGroupId(ConnectionGraphGroupID groupId);
/// Allows adding to the connection graph nodes with this groupId.
/// By default, you subscribe to group 0, which are all systems automatically added with SetAutoAddNewConnections(true)
/// Calling this does not add nodes which were previously rejected due to an unsubscribed group - it only allows addition of nodes after the fact
/// \param[in] groupId Just a number representing a group. 0 is reserved to mean unassigned group ID, automatically added with SetAutoAddNewConnections(true)
void SubscribeToGroup(ConnectionGraphGroupID groupId);
/// Disables addition of graph nodes with this groupId
/// Calling this does not add remove nodes with this groupId which are already present in the graph. It only disables addition of nodes after the fact
/// \param[in] groupId Just a number representing a group. 0 is reserved to mean unassigned group ID, automatically added with SetAutoAddNewConnections(true)
void UnsubscribeFromGroup(ConnectionGraphGroupID groupId);
// --------------------------------------------------------------------------------------------
// Packet handling functions
// --------------------------------------------------------------------------------------------
/// \internal
virtual void OnShutdown(RakPeerInterface *peer);
/// \internal
virtual void Update(RakPeerInterface *peer);
/// \internal
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// \internal
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
protected:
void HandleDroppedConnection(RakPeerInterface *peer, SystemAddress systemAddress, unsigned char packetId);
void DeleteFromPeerList(SystemAddress systemAddress);
void OnNewIncomingConnection(RakPeerInterface *peer, Packet *packet);
void OnConnectionRequestAccepted(RakPeerInterface *peer, Packet *packet);
void OnConnectionGraphRequest(RakPeerInterface *peer, Packet *packet);
void OnConnectionGraphReply(RakPeerInterface *peer, Packet *packet);
void OnConnectionGraphUpdate(RakPeerInterface *peer, Packet *packet);
void OnNewConnection(RakPeerInterface *peer, Packet *packet);
bool OnConnectionLost(RakPeerInterface *peer, Packet *packet, unsigned char packetId);
void OnConnectionAddition(RakPeerInterface *peer, Packet *packet);
void OnConnectionRemoval(RakPeerInterface *peer, Packet *packet);
void SendConnectionGraph(SystemAddress target, unsigned char packetId, RakPeerInterface *peer);
void SerializeWeightedGraph(RakNet::BitStream *out, const DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false> &g) const;
bool DeserializeWeightedGraph(RakNet::BitStream *inBitstream, RakPeerInterface *peer);
void AddAndRelayConnection(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, const SystemAddressAndGroupId &conn1, const SystemAddressAndGroupId &conn2, unsigned short ping, RakPeerInterface *peer);
bool RemoveAndRelayConnection(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, unsigned char packetId, const SystemAddress node1, const SystemAddress node2, RakPeerInterface *peer);
void RemoveParticipant(SystemAddress systemAddress);
void AddParticipant(SystemAddress systemAddress);
void BroadcastGraphUpdate(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, RakPeerInterface *peer);
void NotifyUserOfRemoteConnection(const SystemAddressAndGroupId &conn1, const SystemAddressAndGroupId &conn2,unsigned short ping, RakPeerInterface *peer);
bool IsNewRemoteConnection(const SystemAddressAndGroupId &conn1, const SystemAddressAndGroupId &conn2,RakPeerInterface *peer);
bool DeserializeIgnoreList(DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, RakNet::BitStream *inBitstream );
void SerializeIgnoreListAndBroadcast(RakNet::BitStream *outBitstream, DataStructures::OrderedList<SystemAddress,SystemAddress> &ignoreList, RakPeerInterface *peer);
RakNetTime nextWeightUpdate;
char *pw;
DataStructures::OrderedList<SystemAddress, SystemAddress> participantList;
DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false> graph;
bool autoAddNewConnections;
ConnectionGraphGroupID myGroupId;
DataStructures::OrderedList<ConnectionGraphGroupID, ConnectionGraphGroupID> subscribedGroups;
// Used to broadcast new connections after some time so the pings are correct
//RakNetTime forceBroadcastTime;
};
#endif

View File

@@ -0,0 +1,277 @@
#include "ConsoleServer.h"
#include "TransportInterface.h"
#include "CommandParserInterface.h"
#include <string.h>
#include <stdlib.h>
#define COMMAND_DELINATOR ' '
#define COMMAND_DELINATOR_TOGGLE '"'
#include "LinuxStrings.h"
ConsoleServer::ConsoleServer()
{
transport=0;
password[0]=0;
}
ConsoleServer::~ConsoleServer()
{
}
void ConsoleServer::SetTransportProvider(TransportInterface *transportInterface, unsigned short port)
{
// Replace the current TransportInterface, stopping the old one, if present, and starting the new one.
if (transportInterface)
{
if (transport)
{
RemoveCommandParser(transport->GetCommandParser());
transport->Stop();
}
transport=transportInterface;
transport->Start(port, true);
unsigned i;
for (i=0; i < commandParserList.Size(); i++)
commandParserList[i]->OnTransportChange(transport);
// The transport itself might have a command parser - for example password for the RakNet transport
AddCommandParser(transport->GetCommandParser());
}
}
void ConsoleServer::AddCommandParser(CommandParserInterface *commandParserInterface)
{
if (commandParserInterface==0)
return;
// Non-duplicate insertion
unsigned i;
for (i=0; i < commandParserList.Size(); i++)
{
if (commandParserList[i]==commandParserInterface)
return;
if (_stricmp(commandParserList[i]->GetName(), commandParserInterface->GetName())==0)
{
// Naming conflict between two command parsers
assert(0);
return;
}
}
commandParserList.Insert(commandParserInterface);
if (transport)
commandParserInterface->OnTransportChange(transport);
}
void ConsoleServer::RemoveCommandParser(CommandParserInterface *commandParserInterface)
{
if (commandParserInterface==0)
return;
// Overwrite the element we are removing from the back of the list and delete the back of the list
unsigned i;
for (i=0; i < commandParserList.Size(); i++)
{
if (commandParserList[i]==commandParserInterface)
{
commandParserList[i]=commandParserList[commandParserList.Size()-1];
commandParserList.RemoveFromEnd();
return;
}
}
}
void ConsoleServer::Update(void)
{
unsigned i;
char *parameterList[20]; // Up to 20 parameters
unsigned numParameters;
SystemAddress newOrLostConnectionId;
Packet *p;
RegisteredCommand rc;
p = transport->Receive();
newOrLostConnectionId=transport->HasNewConnection();
if (newOrLostConnectionId!=UNASSIGNED_SYSTEM_ADDRESS)
{
for (i=0; i < commandParserList.Size(); i++)
{
commandParserList[i]->OnNewIncomingConnection(newOrLostConnectionId, transport);
}
transport->Send(newOrLostConnectionId, "Connected to remote command console.\r\nType 'help' for help.\r\n");
ListParsers(newOrLostConnectionId);
}
newOrLostConnectionId=transport->HasLostConnection();
if (newOrLostConnectionId!=UNASSIGNED_SYSTEM_ADDRESS)
{
for (i=0; i < commandParserList.Size(); i++)
commandParserList[i]->OnConnectionLost(newOrLostConnectionId, transport);
}
while (p)
{
bool commandParsed=false;
char copy[REMOTE_MAX_TEXT_INPUT];
memcpy(copy, p->data, p->length);
copy[p->length]=0;
CommandParserInterface::ParseConsoleString((char*)p->data, COMMAND_DELINATOR, COMMAND_DELINATOR_TOGGLE, &numParameters, parameterList, 20); // Up to 20 parameters
if (numParameters==0)
{
transport->DeallocatePacket(p);
p = transport->Receive();
continue;
}
if (_stricmp(*parameterList, "help")==0 && numParameters<=2)
{
// Find the parser specified and display help for it
if (numParameters==1)
{
transport->Send(p->systemAddress, "\r\nINSTRUCTIONS:\r\n");
transport->Send(p->systemAddress, "Enter commands on your keyboard, using spaces to delineate parameters.\r\n");
transport->Send(p->systemAddress, "You can use quotation marks to toggle space delineation.\r\n");
transport->Send(p->systemAddress, "You can connect multiple times from the same computer.\r\n");
transport->Send(p->systemAddress, "You can direct commands to a parser by prefixing the parser name or number.\r\n");
transport->Send(p->systemAddress, "COMMANDS:\r\n");
transport->Send(p->systemAddress, "help Show this display.\r\n");
transport->Send(p->systemAddress, "help <ParserName> Show help on a particular parser.\r\n");
transport->Send(p->systemAddress, "help <CommandName> Show help on a particular command.\r\n");
transport->Send(p->systemAddress, "quit Disconnects from the server.\r\n");
transport->Send(p->systemAddress, "[<ParserName>] <Command> [<Parameters>] Execute a command\r\n");
transport->Send(p->systemAddress, "[<ParserNumber>] <Command> [<Parameters>] Execute a command\r\n");
ListParsers(p->systemAddress);
}
else // numParameters == 2, including the help tag
{
for (i=0; i < commandParserList.Size(); i++)
{
if (_stricmp(parameterList[1], commandParserList[i]->GetName())==0)
{
commandParsed=true;
commandParserList[i]->SendHelp(transport, p->systemAddress);
transport->Send(p->systemAddress, "COMMAND LIST:\r\n");
commandParserList[i]->SendCommandList(transport, p->systemAddress);
transport->Send(p->systemAddress, "\r\n");
break;
}
}
if (commandParsed==false)
{
// Try again, for all commands for all parsers.
RegisteredCommand rc;
for (i=0; i < commandParserList.Size(); i++)
{
if (commandParserList[i]->GetRegisteredCommand(parameterList[1], &rc))
{
if (rc.parameterCount==CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS)
transport->Send(p->systemAddress, "(Variable parms): %s %s\r\n", rc.command, rc.commandHelp);
else
transport->Send(p->systemAddress, "(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp);
commandParsed=true;
break;
}
}
}
if (commandParsed==false)
{
// Don't know what to do
transport->Send(p->systemAddress, "Unknown help topic: %s.\r\n", parameterList[1]);
}
}
}
else if (_stricmp(*parameterList, "quit")==0 && numParameters==1)
{
transport->Send(p->systemAddress, "Goodbye!");
transport->CloseConnection(p->systemAddress);
}
else
{
bool tryAllParsers=true;
bool failed=false;
if (numParameters >=2) // At minimum <CommandParserName> <Command>
{
unsigned commandParserIndex=(unsigned)-1;
// Prefixing with numbers directs to a particular parser
if (**parameterList>='0' && **parameterList<='9')
{
commandParserIndex=atoi(*parameterList); // Use specified parser unless it's an invalid number
commandParserIndex--; // Subtract 1 since we displayed numbers starting at index+1
if (commandParserIndex >= commandParserList.Size())
{
transport->Send(p->systemAddress, "Invalid index.\r\n");
failed=true;
}
}
else
{
// // Prefixing with the name of a command parser directs to that parser. See if the first word matches a parser
for (i=0; i < commandParserList.Size(); i++)
{
if (_stricmp(parameterList[0], commandParserList[i]->GetName())==0)
{
commandParserIndex=i; // Matches parser at index i
break;
}
}
}
if (failed==false)
{
// -1 means undirected, so otherwise this is directed to a target
if (commandParserIndex!=(unsigned)-1)
{
// Only this parser should use this command
tryAllParsers=false;
if (commandParserList[commandParserIndex]->GetRegisteredCommand(parameterList[1], &rc))
{
commandParsed=true;
if (rc.parameterCount==CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS || rc.parameterCount==numParameters-2)
commandParserList[commandParserIndex]->OnCommand(rc.command, numParameters-2, parameterList+2, transport, p->systemAddress, copy);
else
transport->Send(p->systemAddress, "Invalid parameter count.\r\n(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp);
}
}
}
}
if (failed == false && tryAllParsers)
{
for (i=0; i < commandParserList.Size(); i++)
{
// Undirected command. Try all the parsers to see if they understand the command
// Pass the 1nd element as the command, and the remainder as the parameter list
if (commandParserList[i]->GetRegisteredCommand(parameterList[0], &rc))
{
commandParsed=true;
if (rc.parameterCount==CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS || rc.parameterCount==numParameters-1)
commandParserList[i]->OnCommand(rc.command, numParameters-1, parameterList+1, transport, p->systemAddress, copy);
else
transport->Send(p->systemAddress, "Invalid parameter count.\r\n(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp);
}
}
}
if (commandParsed==false && commandParserList.Size() > 0)
{
transport->Send(p->systemAddress, "Unknown command: Type 'help' for help.\r\n");
}
}
transport->DeallocatePacket(p);
p = transport->Receive();
}
}
void ConsoleServer::ListParsers(SystemAddress systemAddress)
{
transport->Send(systemAddress,"INSTALLED PARSERS:\r\n");
unsigned i;
for (i=0; i < commandParserList.Size(); i++)
{
transport->Send(systemAddress, "%i. %s\r\n", i+1, commandParserList[i]->GetName());
}
}

View File

@@ -0,0 +1,63 @@
/// \file
/// \brief Contains ConsoleServer , used to plugin to your game to accept remote console-based connections
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __CONSOLE_SERVER_H
#define __CONSOLE_SERVER_H
class TransportInterface;
class CommandParserInterface;
#include "RakMemoryOverride.h"
#include "DS_List.h"
#include "RakNetTypes.h"
#include "Export.h"
/// \brief The main entry point for the server portion of your remote console application support.
/// ConsoleServer takes one TransportInterface and one or more CommandParserInterface (s)
/// The TransportInterface will be used to send data between the server and the client. The connecting client must support the
/// protocol used by your derivation of TransportInterface . TelnetTransport and RakNetTransport are two such derivations .
/// When a command is sent by a remote console, it will be processed by your implementations of CommandParserInterface
class RAK_DLL_EXPORT ConsoleServer : public RakNet::RakMemoryOverride
{
public:
ConsoleServer();
~ConsoleServer();
/// Call this with a derivation of TransportInterface so that the console server can send and receive commands
/// \param[in] transportInterface Your interface to use.
/// \param[in] port The port to host on. Telnet uses port 23 by default. RakNet can use whatever you want.
void SetTransportProvider(TransportInterface *transportInterface, unsigned short port);
/// Add an implementation of CommandParserInterface to the list of command parsers.
/// \param[in] commandParserInterface The command parser referred to
void AddCommandParser(CommandParserInterface *commandParserInterface);
/// Remove an implementation of CommandParserInterface previously added with AddCommandParser()
/// \param[in] commandParserInterface The command parser referred to
void RemoveCommandParser(CommandParserInterface *commandParserInterface);
/// Call update to read packet sent from your TransportInterface.
/// You should do this fairly frequently.
void Update(void);
protected:
void ListParsers(SystemAddress systemAddress);
TransportInterface *transport;
DataStructures::List<CommandParserInterface *> commandParserList;
char* password[256];
};
#endif

1162
thirdparty/raknet/Source/DS_BPlusTree.h vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

146
thirdparty/raknet/Source/DS_BytePool.cpp vendored Normal file
View File

@@ -0,0 +1,146 @@
#include "DS_BytePool.h"
#include <assert.h>
#ifndef __APPLE__
// Use stdlib and not malloc for compatibility
#include <stdlib.h>
#endif
using namespace DataStructures;
BytePool::BytePool()
{
pool128.SetPageSize(8192*4);
pool512.SetPageSize(8192*4);
pool2048.SetPageSize(8192*4);
pool8192.SetPageSize(8192*4);
}
BytePool::~BytePool()
{
}
void BytePool::SetPageSize(int size)
{
pool128.SetPageSize(size);
pool512.SetPageSize(size);
pool2048.SetPageSize(size);
pool8192.SetPageSize(size);
}
unsigned char *BytePool::Allocate(int bytesWanted)
{
#ifdef _DISABLE_BYTE_POOL
return rakMalloc(bytesWanted);
#endif
unsigned char *out;
if (bytesWanted <= 127)
{
#ifdef _THREADSAFE_BYTE_POOL
mutex128.Lock();
#endif
out = (unsigned char*) pool128.Allocate();
#ifdef _THREADSAFE_BYTE_POOL
mutex128.Unlock();
#endif
out[0]=0;
return ((unsigned char*) out)+1;
}
if (bytesWanted <= 511)
{
#ifdef _THREADSAFE_BYTE_POOL
mutex512.Lock();
#endif
out = (unsigned char*) pool512.Allocate();
#ifdef _THREADSAFE_BYTE_POOL
mutex512.Unlock();
#endif
out[0]=1;
return ((unsigned char*) out)+1;
}
if (bytesWanted <= 2047)
{
#ifdef _THREADSAFE_BYTE_POOL
mutex2048.Lock();
#endif
out = (unsigned char*) pool2048.Allocate();
#ifdef _THREADSAFE_BYTE_POOL
mutex2048.Unlock();
#endif
out[0]=2;
return ((unsigned char*) out)+1;
}
if (bytesWanted <= 8191)
{
#ifdef _THREADSAFE_BYTE_POOL
mutex8192.Lock();
#endif
out = (unsigned char*) pool8192.Allocate();
#ifdef _THREADSAFE_BYTE_POOL
mutex8192.Unlock();
#endif
out[0]=3;
return ((unsigned char*) out)+1;
}
out = (unsigned char*) rakMalloc(bytesWanted+1);
out[0]=(unsigned char)255;
return out+1;
}
void BytePool::Release(unsigned char *data)
{
#ifdef _DISABLE_BYTE_POOL
RakFree(data);
#endif
unsigned char *realData = data-1;
switch (realData[0])
{
case 0:
#ifdef _THREADSAFE_BYTE_POOL
mutex128.Lock();
#endif
pool128.Release((unsigned char(*)[128]) realData );
#ifdef _THREADSAFE_BYTE_POOL
mutex128.Unlock();
#endif
break;
case 1:
#ifdef _THREADSAFE_BYTE_POOL
mutex512.Lock();
#endif
pool512.Release((unsigned char(*)[512]) realData );
#ifdef _THREADSAFE_BYTE_POOL
mutex512.Unlock();
#endif
break;
case 2:
#ifdef _THREADSAFE_BYTE_POOL
mutex2048.Lock();
#endif
pool2048.Release((unsigned char(*)[2048]) realData );
#ifdef _THREADSAFE_BYTE_POOL
mutex2048.Unlock();
#endif
break;
case 3:
#ifdef _THREADSAFE_BYTE_POOL
mutex8192.Lock();
#endif
pool8192.Release((unsigned char(*)[8192]) realData );
#ifdef _THREADSAFE_BYTE_POOL
mutex8192.Unlock();
#endif
break;
case 255:
rakFree(realData);
break;
default:
assert(0);
break;
}
}
void BytePool::Clear(void)
{
#ifdef _THREADSAFE_BYTE_POOL
pool128.Clear();
pool512.Clear();
pool2048.Clear();
pool8192.Clear();
#endif
}

40
thirdparty/raknet/Source/DS_BytePool.h vendored Normal file
View File

@@ -0,0 +1,40 @@
#ifndef __BYTE_POOL_H
#define __BYTE_POOL_H
#include "RakMemoryOverride.h"
#include "DS_MemoryPool.h"
#include "Export.h"
#include "SimpleMutex.h"
#include <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 RakNet::RakMemoryOverride
{
public:
BytePool();
~BytePool();
// Should be at least 8 times bigger than 8192
void SetPageSize(int size);
unsigned char* Allocate(int bytesWanted);
void Release(unsigned char *data);
void Clear(void);
protected:
MemoryPool<unsigned char[128]> pool128;
MemoryPool<unsigned char[512]> pool512;
MemoryPool<unsigned char[2048]> pool2048;
MemoryPool<unsigned char[8192]> pool8192;
#ifdef _THREADSAFE_BYTE_POOL
SimpleMutex mutex128;
SimpleMutex mutex512;
SimpleMutex mutex2048;
SimpleMutex mutex8192;
#endif
};
}
#endif

View File

@@ -0,0 +1,101 @@
#include "DS_ByteQueue.h"
#include <string.h> // Memmove
#include <stdlib.h> // realloc
#include <stdio.h>
using namespace DataStructures;
ByteQueue::ByteQueue()
{
readOffset=writeOffset=lengthAllocated=0;
data=0;
}
ByteQueue::~ByteQueue()
{
Clear();
}
void ByteQueue::WriteBytes(const char *in, unsigned length)
{
unsigned bytesWritten;
bytesWritten=GetBytesWritten();
if (lengthAllocated==0 || length > lengthAllocated-bytesWritten-1)
{
unsigned oldLengthAllocated=lengthAllocated;
unsigned newAmountToAllocate=length*2;
if (newAmountToAllocate<256)
newAmountToAllocate=256;
lengthAllocated=lengthAllocated + newAmountToAllocate;
data=(char*)rakRealloc(data, lengthAllocated);
if (writeOffset < readOffset)
{
if (writeOffset <= newAmountToAllocate)
{
memcpy(data + oldLengthAllocated, data, writeOffset);
writeOffset=readOffset+bytesWritten;
}
else
{
memcpy(data + oldLengthAllocated, data, newAmountToAllocate);
memmove(data, data+newAmountToAllocate, writeOffset-newAmountToAllocate);
writeOffset-=newAmountToAllocate;
}
}
}
if (length <= lengthAllocated-writeOffset)
memcpy(data+writeOffset, in, length);
else
{
// Wrap
memcpy(data+writeOffset, in, lengthAllocated-writeOffset);
memcpy(data, in+(lengthAllocated-writeOffset), length-(lengthAllocated-writeOffset));
}
writeOffset=(writeOffset+length) % lengthAllocated;
}
bool ByteQueue::ReadBytes(char *out, unsigned length, bool peek)
{
if (GetBytesWritten() < length)
return false;
if (length <= lengthAllocated-readOffset)
memcpy(out, data+readOffset, length);
else
{
// Wrap
memcpy(out, data+readOffset, lengthAllocated-readOffset);
memcpy(out+(lengthAllocated-readOffset), data, length-(lengthAllocated-readOffset));
}
if (peek==false)
IncrementReadOffset(length);
return true;
}
void ByteQueue::Clear(void)
{
if (lengthAllocated)
rakFree(data);
readOffset=writeOffset=lengthAllocated=0;
data=0;
}
unsigned ByteQueue::GetBytesWritten(void) const
{
if (writeOffset>=readOffset)
return writeOffset-readOffset;
else
return (writeOffset-1)+(lengthAllocated-readOffset);
}
void ByteQueue::IncrementReadOffset(unsigned length)
{
readOffset=(readOffset+length) % lengthAllocated;
}
void ByteQueue::Print(void)
{
unsigned i;
for (i=readOffset; i!=writeOffset; i++)
printf("%i ", data[i]);
printf("\n");
}

46
thirdparty/raknet/Source/DS_ByteQueue.h vendored Normal file
View File

@@ -0,0 +1,46 @@
/// \file
/// \brief \b [Internal] Byte queue
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __BYTE_QUEUE_H
#define __BYTE_QUEUE_H
#include "RakMemoryOverride.h"
#include "Export.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
class ByteQueue : public RakNet::RakMemoryOverride
{
public:
ByteQueue();
~ByteQueue();
void WriteBytes(const char *in, unsigned length);
bool ReadBytes(char *out, unsigned length, bool peek);
unsigned GetBytesWritten(void) const;
void IncrementReadOffset(unsigned length);
void Clear(void);
void Print(void);
protected:
char *data;
unsigned readOffset, writeOffset, lengthAllocated;
};
}
#endif

251
thirdparty/raknet/Source/DS_Heap.h vendored Normal file
View File

@@ -0,0 +1,251 @@
/// \file
/// \brief \b [Internal] Heap (Also serves as a priority queue)
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAKNET_HEAP_H
#define __RAKNET_HEAP_H
#include "RakMemoryOverride.h"
#include "DS_List.h"
#include "Export.h"
#include <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 RakNet::RakMemoryOverride
{
public:
struct HeapNode
{
HeapNode() {}
HeapNode(const weight_type &w, const data_type &d) : weight(w), data(d) {}
weight_type weight; // I'm assuming key is a native numerical type - float or int
data_type data;
};
Heap();
~Heap();
void Push(const weight_type &weight, const data_type &data);
data_type Pop(const unsigned startingIndex);
data_type Peek(const unsigned startingIndex=0) const;
weight_type PeekWeight(const unsigned startingIndex=0) const;
void Clear(void);
data_type& operator[] ( const unsigned int position ) const;
unsigned Size(void) const;
protected:
unsigned LeftChild(const unsigned i) const;
unsigned RightChild(const unsigned i) const;
unsigned Parent(const unsigned i) const;
void Swap(const unsigned i, const unsigned j);
DataStructures::List<HeapNode> heap;
};
template <class weight_type, class data_type, bool isMaxHeap>
Heap<weight_type, data_type, isMaxHeap>::Heap()
{
}
template <class weight_type, class data_type, bool isMaxHeap>
Heap<weight_type, data_type, isMaxHeap>::~Heap()
{
Clear();
}
template <class weight_type, class data_type, bool isMaxHeap>
void Heap<weight_type, data_type, isMaxHeap>::Push(const weight_type &weight, const data_type &data)
{
unsigned currentIndex = heap.Size();
unsigned parentIndex;
heap.Insert(HeapNode(weight, data));
while (currentIndex!=0)
{
parentIndex = Parent(currentIndex);
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
if (isMaxHeap)
{
if (heap[parentIndex].weight < weight)
{
Swap(currentIndex, parentIndex);
currentIndex=parentIndex;
}
else
break;
}
else
{
if (heap[parentIndex].weight > weight)
{
Swap(currentIndex, parentIndex);
currentIndex=parentIndex;
}
else
break;
}
}
}
template <class weight_type, class data_type, bool isMaxHeap>
data_type Heap<weight_type, data_type, isMaxHeap>::Pop(const unsigned startingIndex)
{
// While we have children, swap out with the larger of the two children.
// This line will assert on an empty heap
data_type returnValue=heap[0].data;
// Move the last element to the head, and re-heapify
heap[startingIndex]=heap[heap.Size()-1];
unsigned currentIndex,leftChild,rightChild;
weight_type currentWeight;
currentIndex=startingIndex;
currentWeight=heap[startingIndex].weight;
heap.RemoveFromEnd();
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while (1)
{
leftChild=LeftChild(currentIndex);
rightChild=RightChild(currentIndex);
if (leftChild >= heap.Size())
{
// Done
return returnValue;
}
if (rightChild >= heap.Size())
{
// Only left node.
if ((isMaxHeap==true && currentWeight < heap[leftChild].weight) ||
(isMaxHeap==false && currentWeight > heap[leftChild].weight))
Swap(leftChild, currentIndex);
return returnValue;
}
else
{
// Swap with the bigger/smaller of the two children and continue
if (isMaxHeap)
{
if (heap[leftChild].weight <= currentWeight && heap[rightChild].weight <= currentWeight)
return returnValue;
if (heap[leftChild].weight > heap[rightChild].weight)
{
Swap(leftChild, currentIndex);
currentIndex=leftChild;
}
else
{
Swap(rightChild, currentIndex);
currentIndex=rightChild;
}
}
else
{
if (heap[leftChild].weight >= currentWeight && heap[rightChild].weight >= currentWeight)
return returnValue;
if (heap[leftChild].weight < heap[rightChild].weight)
{
Swap(leftChild, currentIndex);
currentIndex=leftChild;
}
else
{
Swap(rightChild, currentIndex);
currentIndex=rightChild;
}
}
}
}
}
template <class weight_type, class data_type, bool isMaxHeap>
data_type Heap<weight_type, data_type, isMaxHeap>::Peek(const unsigned startingIndex) const
{
return heap[startingIndex].data;
}
template <class weight_type, class data_type, bool isMaxHeap>
weight_type Heap<weight_type, data_type, isMaxHeap>::PeekWeight(const unsigned startingIndex) const
{
return heap[startingIndex].weight;
}
template <class weight_type, class data_type, bool isMaxHeap>
void Heap<weight_type, data_type, isMaxHeap>::Clear(void)
{
heap.Clear();
}
template <class weight_type, class data_type, bool isMaxHeap>
data_type& Heap<weight_type, data_type, isMaxHeap>::operator[] ( const unsigned int position ) const
{
return heap[position].data;
}
template <class weight_type, class data_type, bool isMaxHeap>
unsigned Heap<weight_type, data_type, isMaxHeap>::Size(void) const
{
return heap.Size();
}
template <class weight_type, class data_type, bool isMaxHeap>
unsigned Heap<weight_type, data_type, isMaxHeap>::LeftChild(const unsigned i) const
{
return i*2+1;
}
template <class weight_type, class data_type, bool isMaxHeap>
unsigned Heap<weight_type, data_type, isMaxHeap>::RightChild(const unsigned i) const
{
return i*2+2;
}
template <class weight_type, class data_type, bool isMaxHeap>
unsigned Heap<weight_type, data_type, isMaxHeap>::Parent(const unsigned i) const
{
#ifdef _DEBUG
assert(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

View File

@@ -0,0 +1,306 @@
/// \file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#include "DS_HuffmanEncodingTree.h"
#include "DS_Queue.h"
#include "BitStream.h"
#include <assert.h>
#ifdef _MSC_VER
#pragma warning( push )
#endif
HuffmanEncodingTree::HuffmanEncodingTree()
{
root = 0;
}
HuffmanEncodingTree::~HuffmanEncodingTree()
{
FreeMemory();
}
void HuffmanEncodingTree::FreeMemory( void )
{
if ( root == 0 )
return ;
// Use an in-order traversal to delete the tree
DataStructures::Queue<HuffmanEncodingTreeNode *> nodeQueue;
HuffmanEncodingTreeNode *node;
nodeQueue.Push( root );
while ( nodeQueue.Size() > 0 )
{
node = nodeQueue.Pop();
if ( node->left )
nodeQueue.Push( node->left );
if ( node->right )
nodeQueue.Push( node->right );
delete node;
}
// Delete the encoding table
for ( int i = 0; i < 256; i++ )
rakFree(encodingTable[ i ].encoding);
root = 0;
}
////#include <stdio.h>
// Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree
void HuffmanEncodingTree::GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] )
{
int counter;
HuffmanEncodingTreeNode * node;
HuffmanEncodingTreeNode *leafList[ 256 ]; // Keep a copy of the pointers to all the leaves so we can generate the encryption table bottom-up, which is easier
// 1. Make 256 trees each with a weight equal to the frequency of the corresponding character
DataStructures::LinkedList<HuffmanEncodingTreeNode *> huffmanEncodingTreeNodeList;
FreeMemory();
for ( counter = 0; counter < 256; counter++ )
{
node = new HuffmanEncodingTreeNode;
node->left = 0;
node->right = 0;
node->value = (unsigned char) counter;
node->weight = frequencyTable[ counter ];
if ( node->weight == 0 )
node->weight = 1; // 0 weights are illegal
leafList[ counter ] = node; // Used later to generate the encryption table
InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList ); // Insert and maintain sort order.
}
// 2. While there is more than one tree, take the two smallest trees and merge them so that the two trees are the left and right
// children of a new node, where the new node has the weight the sum of the weight of the left and right child nodes.
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while ( 1 )
{
huffmanEncodingTreeNodeList.Beginning();
HuffmanEncodingTreeNode *lesser, *greater;
lesser = huffmanEncodingTreeNodeList.Pop();
greater = huffmanEncodingTreeNodeList.Pop();
node = new HuffmanEncodingTreeNode;
node->left = lesser;
node->right = greater;
node->weight = lesser->weight + greater->weight;
lesser->parent = node; // This is done to make generating the encryption table easier
greater->parent = node; // This is done to make generating the encryption table easier
if ( huffmanEncodingTreeNodeList.Size() == 0 )
{
// 3. Assign the one remaining node in the list to the root node.
root = node;
root->parent = 0;
break;
}
// Put the new node back into the list at the correct spot to maintain the sort. Linear search time
InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList );
}
bool tempPath[ 256 ]; // Maximum path length is 256
unsigned short tempPathLength;
HuffmanEncodingTreeNode *currentNode;
RakNet::BitStream bitStream;
// Generate the encryption table. From before, we have an array of pointers to all the leaves which contain pointers to their parents.
// This can be done more efficiently but this isn't bad and it's way easier to program and debug
for ( counter = 0; counter < 256; counter++ )
{
// Already done at the end of the loop and before it!
tempPathLength = 0;
// Set the current node at the leaf
currentNode = leafList[ counter ];
do
{
if ( currentNode->parent->left == currentNode ) // We're storing the paths in reverse order.since we are going from the leaf to the root
tempPath[ tempPathLength++ ] = false;
else
tempPath[ tempPathLength++ ] = true;
currentNode = currentNode->parent;
}
while ( currentNode != root );
// Write to the bitstream in the reverse order that we stored the path, which gives us the correct order from the root to the leaf
while ( tempPathLength-- > 0 )
{
if ( tempPath[ tempPathLength ] ) // Write 1's and 0's because writing a bool will write the BitStream TYPE_CHECKING validation bits if that is defined along with the actual data bit, which is not what we want
bitStream.Write1();
else
bitStream.Write0();
}
// Read data from the bitstream, which is written to the encoding table in bits and bitlength. Note this function allocates the encodingTable[counter].encoding pointer
encodingTable[ counter ].bitLength = ( unsigned char ) bitStream.CopyData( &encodingTable[ counter ].encoding );
// Reset the bitstream for the next iteration
bitStream.Reset();
}
}
// Pass an array of bytes to array and a preallocated BitStream to receive the output
void HuffmanEncodingTree::EncodeArray( unsigned char *input, size_t sizeInBytes, RakNet::BitStream * output )
{
unsigned counter;
// For each input byte, Write out the corresponding series of 1's and 0's that give the encoded representation
for ( counter = 0; counter < sizeInBytes; counter++ )
{
output->WriteBits( encodingTable[ input[ counter ] ].encoding, encodingTable[ input[ counter ] ].bitLength, false ); // Data is left aligned
}
// Byte align the output so the unassigned remaining bits don't equate to some actual value
if ( output->GetNumberOfBitsUsed() % 8 != 0 )
{
// Find an input that is longer than the remaining bits. Write out part of it to pad the output to be byte aligned.
unsigned char remainingBits = (unsigned char) ( 8 - ( output->GetNumberOfBitsUsed() % 8 ) );
for ( counter = 0; counter < 256; counter++ )
if ( encodingTable[ counter ].bitLength > remainingBits )
{
output->WriteBits( encodingTable[ counter ].encoding, remainingBits, false ); // Data is left aligned
break;
}
#ifdef _DEBUG
assert( counter != 256 ); // Given 256 elements, we should always be able to find an input that would be >= 7 bits
#endif
}
}
unsigned HuffmanEncodingTree::DecodeArray( RakNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output )
{
HuffmanEncodingTreeNode * currentNode;
unsigned outputWriteIndex;
outputWriteIndex = 0;
currentNode = root;
// For each bit, go left if it is a 0 and right if it is a 1. When we reach a leaf, that gives us the desired value and we restart from the root
for ( unsigned counter = 0; counter < sizeInBits; counter++ )
{
if ( input->ReadBit() == false ) // left!
currentNode = currentNode->left;
else
currentNode = currentNode->right;
if ( currentNode->left == 0 && currentNode->right == 0 ) // Leaf
{
if ( outputWriteIndex < maxCharsToWrite )
output[ outputWriteIndex ] = currentNode->value;
outputWriteIndex++;
currentNode = root;
}
}
return outputWriteIndex;
}
// Pass an array of encoded bytes to array and a preallocated BitStream to receive the output
void HuffmanEncodingTree::DecodeArray( unsigned char *input, BitSize_t sizeInBits, RakNet::BitStream * output )
{
HuffmanEncodingTreeNode * currentNode;
if ( sizeInBits <= 0 )
return ;
RakNet::BitStream bitStream( input, BITS_TO_BYTES(sizeInBits), false );
currentNode = root;
// For each bit, go left if it is a 0 and right if it is a 1. When we reach a leaf, that gives us the desired value and we restart from the root
for ( unsigned counter = 0; counter < sizeInBits; counter++ )
{
if ( bitStream.ReadBit() == false ) // left!
currentNode = currentNode->left;
else
currentNode = currentNode->right;
if ( currentNode->left == 0 && currentNode->right == 0 ) // Leaf
{
output->WriteBits( &( currentNode->value ), sizeof( char ) * 8, true ); // Use WriteBits instead of Write(char) because we want to avoid TYPE_CHECKING
currentNode = root;
}
}
}
// Insertion sort. Slow but easy to write in this case
void HuffmanEncodingTree::InsertNodeIntoSortedList( HuffmanEncodingTreeNode * node, DataStructures::LinkedList<HuffmanEncodingTreeNode *> *huffmanEncodingTreeNodeList ) const
{
if ( huffmanEncodingTreeNodeList->Size() == 0 )
{
huffmanEncodingTreeNodeList->Insert( node );
return ;
}
huffmanEncodingTreeNodeList->Beginning();
unsigned counter = 0;
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while ( 1 )
{
if ( huffmanEncodingTreeNodeList->Peek()->weight < node->weight )
++( *huffmanEncodingTreeNodeList );
else
{
huffmanEncodingTreeNodeList->Insert( node );
break;
}
// Didn't find a spot in the middle - add to the end
if ( ++counter == huffmanEncodingTreeNodeList->Size() )
{
huffmanEncodingTreeNodeList->End();
huffmanEncodingTreeNodeList->Add( node )
; // Add to the end
break;
}
}
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@@ -0,0 +1,71 @@
/// \file
/// \brief \b [Internal] Generates a huffman encoding tree, used for string and global compression.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __HUFFMAN_ENCODING_TREE
#define __HUFFMAN_ENCODING_TREE
#include "RakMemoryOverride.h"
#include "DS_HuffmanEncodingTreeNode.h"
#include "BitStream.h"
#include "Export.h"
#include "DS_LinkedList.h"
/// This generates special cases of the huffman encoding tree using 8 bit keys with the additional condition that unused combinations of 8 bits are treated as a frequency of 1
class RAK_DLL_EXPORT HuffmanEncodingTree : public RakNet::RakMemoryOverride
{
public:
HuffmanEncodingTree();
~HuffmanEncodingTree();
/// Pass an array of bytes to array and a preallocated BitStream to receive the output
/// \param [in] input Array of bytes to encode
/// \param [in] sizeInBytes size of \a input
/// \param [out] output The bitstream to write to
void EncodeArray( unsigned char *input, size_t sizeInBytes, RakNet::BitStream * output );
// Decodes an array encoded by EncodeArray()
unsigned DecodeArray( RakNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output );
void DecodeArray( unsigned char *input, BitSize_t sizeInBits, RakNet::BitStream * output );
/// Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree
void GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] );
/// Free the memory used by the tree
void FreeMemory( void );
private:
/// The root node of the tree
HuffmanEncodingTreeNode *root;
/// Used to hold bit encoding for one character
struct CharacterEncoding
{
unsigned char* encoding;
unsigned short bitLength;
};
CharacterEncoding encodingTable[ 256 ];
void InsertNodeIntoSortedList( HuffmanEncodingTreeNode * node, DataStructures::LinkedList<HuffmanEncodingTreeNode *> *huffmanEncodingTreeNodeList ) const;
};
#endif

View File

@@ -0,0 +1,61 @@
/// \file
/// \brief \b [Internal] Creates instances of the class HuffmanEncodingTree
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __HUFFMAN_ENCODING_TREE_FACTORY
#define __HUFFMAN_ENCODING_TREE_FACTORY
#include "RakMemoryOverride.h"
class HuffmanEncodingTree;
/// \brief Creates instances of the class HuffmanEncodingTree
///
/// This class takes a frequency table and given that frequence table, will generate an instance of HuffmanEncodingTree
class HuffmanEncodingTreeFactory : public RakNet::RakMemoryOverride
{
public:
/// Default constructor
HuffmanEncodingTreeFactory();
/// Reset the frequency table. You don't need to call this unless you want to reuse the class for a new tree
void Reset( void );
/// Pass an array of bytes to this to add those elements to the frequency table
/// \param[in] array the data to insert into the frequency table
/// \param[in] size the size of the data to insert
void AddToFrequencyTable( unsigned char *array, int size );
/// Copies the frequency table to the array passed
/// Retrieve the frequency table
/// \param[in] _frequency The frequency table used currently
void GetFrequencyTable( unsigned int _frequency[ 256 ] );
/// Returns the frequency table as a pointer
/// \return the address of the frenquency table
unsigned int * GetFrequencyTable( void );
/// Generate a HuffmanEncodingTree.
/// You can also use GetFrequencyTable and GenerateFromFrequencyTable in the tree itself
/// \return The generated instance of HuffmanEncodingTree
HuffmanEncodingTree * GenerateTree( void );
private:
/// Frequency table
unsigned int frequency[ 256 ];
};
#endif

View File

@@ -0,0 +1,30 @@
/// \file
/// \brief \b [Internal] A single node in the Huffman Encoding Tree.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __HUFFMAN_ENCODING_TREE_NODE
#define __HUFFMAN_ENCODING_TREE_NODE
struct HuffmanEncodingTreeNode
{
unsigned char value;
unsigned weight;
HuffmanEncodingTreeNode *left;
HuffmanEncodingTreeNode *right;
HuffmanEncodingTreeNode *parent;
};
#endif

1259
thirdparty/raknet/Source/DS_LinkedList.h vendored Normal file

File diff suppressed because it is too large Load Diff

512
thirdparty/raknet/Source/DS_List.h vendored Normal file
View File

@@ -0,0 +1,512 @@
/// \file
/// \brief \b [Internal] Array based list. Usually the Queue class is used instead, since it has all the same functionality and is only worse at random access.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __LIST_H
#define __LIST_H
#include <assert.h>
#include <string.h> // memmove
#include "Export.h"
/// Maximum unsigned long
static const unsigned int MAX_UNSIGNED_LONG = 4294967295U;
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
/// \brief Array based implementation of a list.
/// \note ONLY USE THIS FOR SHALLOW COPIES. I don't bother with operator= to improve performance.
template <class list_type>
class RAK_DLL_EXPORT List
{
public:
/// Default constructor
List();
/// Destructor
~List();
/// Copy constructor
/// \param[in] original_copy The list to duplicate
List( const List& original_copy );
/// Assign one list to another
List& operator= ( const List& original_copy );
/// Access an element by its index in the array
/// \param[in] position The index into the array.
/// \return The element at position \a position.
list_type& operator[] ( const unsigned int position ) const;
/// Push an element at the end of the stack
/// \param[in] input The new element.
void Push(const list_type input);
/// Pop an element from the end of the stack
/// \pre Size()>0
/// \return The element at the end.
list_type& Pop(void);
/// Insert an element at position \a position in the list
/// \param[in] input The new element.
/// \param[in] position The position of the new element.
void Insert( const list_type input, const unsigned int position );
/// Insert at the end of the list.
/// \param[in] input The new element.
void Insert( const list_type input );
/// Replace the value at \a position by \a input. If the size of
/// the list is less than @em position, it increase the capacity of
/// the list and fill slot with @em filler.
/// \param[in] input The element to replace at position @em position.
/// \param[in] filler The element use to fill new allocated capacity.
/// \param[in] position The position of input in the list.
void Replace( const list_type input, const list_type filler, const unsigned int position );
/// Replace the last element of the list by \a input .
/// \param[in] input The element used to replace the last element.
void Replace( const list_type input );
/// Delete the element at position \a position.
/// \param[in] position The index of the element to delete
void RemoveAtIndex( const unsigned int position );
/// Delete the element at position \a position.
/// \note - swaps middle with end of list, only use if list order does not matter
/// \param[in] position The index of the element to delete
void RemoveAtIndexFast( const unsigned int position );
/// Delete the element at the end of the list
void RemoveFromEnd(const unsigned num=1);
/// Returns the index of the specified item or MAX_UNSIGNED_LONG if not found
/// \param[in] input The element to check for
/// \return The index or position of @em input in the list.
/// \retval MAX_UNSIGNED_LONG The object is not in the list
/// \retval [Integer] The index of the element in the list
unsigned int GetIndexOf( const list_type input ) const;
/// \return The number of elements in the list
unsigned int Size( void ) const;
/// Clear the list
void Clear( bool doNotDeallocateSmallBlocks=false );
// Preallocate the list, so it needs fewer reallocations at runtime
void Preallocate( unsigned countNeeded );
/// Frees overallocated members, to use the minimum memory necessary
/// \attention
/// This is a slow operation
void Compress( void );
private:
/// An array of user values
list_type* listArray;
/// Number of elements in the list
unsigned int list_size;
/// Size of \a array
unsigned int allocation_size;
};
template <class list_type>
List<list_type>::List()
{
allocation_size = 0;
listArray = 0;
list_size = 0;
}
template <class list_type>
List<list_type>::~List()
{
if (allocation_size>0)
delete [] listArray;
}
template <class list_type>
List<list_type>::List( const List& original_copy )
{
// Allocate memory for copy
if ( original_copy.list_size == 0 )
{
list_size = 0;
allocation_size = 0;
}
else
{
listArray = new list_type [ original_copy.list_size ];
for ( unsigned int counter = 0; counter < original_copy.list_size; ++counter )
listArray[ counter ] = original_copy.listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(listArray, original_copy.listArray, original_copy.list_size*sizeof(list_type));
list_size = allocation_size = original_copy.list_size;
}
}
template <class list_type>
List<list_type>& List<list_type>::operator= ( const List& original_copy )
{
if ( ( &original_copy ) != this )
{
Clear();
// Allocate memory for copy
if ( original_copy.list_size == 0 )
{
list_size = 0;
allocation_size = 0;
}
else
{
listArray = new list_type [ original_copy.list_size ];
for ( unsigned int counter = 0; counter < original_copy.list_size; ++counter )
listArray[ counter ] = original_copy.listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(listArray, original_copy.listArray, original_copy.list_size*sizeof(list_type));
list_size = allocation_size = original_copy.list_size;
}
}
return *this;
}
template <class list_type>
inline list_type& List<list_type>::operator[] ( const unsigned int position ) const
{
#ifdef _DEBUG
if (position>=list_size)
{
assert ( position < list_size );
}
#endif
return listArray[ position ];
}
template <class list_type>
void List<list_type>::Push(const list_type input)
{
Insert(input);
}
template <class list_type>
inline list_type& List<list_type>::Pop(void)
{
#ifdef _DEBUG
assert(list_size>0);
#endif
--list_size;
return listArray[list_size];
}
template <class list_type>
void List<list_type>::Insert( const list_type input, const unsigned int position )
{
#ifdef _DEBUG
if (position>list_size)
{
assert( position <= list_size );
}
#endif
// Reallocate list if necessary
if ( list_size == allocation_size )
{
// allocate twice the currently allocated memory
list_type * new_array;
if ( allocation_size == 0 )
allocation_size = 16;
else
allocation_size *= 2;
new_array = new list_type [ allocation_size ];
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated and twice as large array
delete[] listArray;
listArray = new_array;
}
// Move the elements in the list to make room
for ( unsigned int counter = list_size; counter != position; counter-- )
listArray[ counter ] = listArray[ counter - 1 ];
// Don't call constructors, assignment operators, etc.
//memmove(listArray+position+1, listArray+position, (list_size-position)*sizeof(list_type));
// Insert the new item at the correct spot
listArray[ position ] = input;
++list_size;
}
template <class list_type>
void List<list_type>::Insert( const list_type input )
{
// Reallocate list if necessary
if ( list_size == allocation_size )
{
// allocate twice the currently allocated memory
list_type * new_array;
if ( allocation_size == 0 )
allocation_size = 16;
else
allocation_size *= 2;
new_array = new list_type [ allocation_size ];
if (listArray)
{
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated and twice as large array
delete[] listArray;
}
listArray = new_array;
}
// Insert the new item at the correct spot
listArray[ list_size ] = input;
++list_size;
}
template <class list_type>
inline void List<list_type>::Replace( const list_type input, const list_type filler, const unsigned int position )
{
if ( ( list_size > 0 ) && ( position < list_size ) )
{
// Direct replacement
listArray[ position ] = input;
}
else
{
if ( position >= allocation_size )
{
// Reallocate the list to size position and fill in blanks with filler
list_type * new_array;
allocation_size = position + 1;
new_array = new list_type [ allocation_size ];
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated array
delete[] listArray;
listArray = new_array;
}
// Fill in holes with filler
while ( list_size < position )
listArray[ list_size++ ] = filler;
// Fill in the last element with the new item
listArray[ list_size++ ] = input;
#ifdef _DEBUG
assert( 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)
{
assert( 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)
{
assert( 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
assert(list_size>=num);
#endif
list_size-=num;
}
template <class list_type>
unsigned int List<list_type>::GetIndexOf( const list_type input ) const
{
for ( unsigned int i = 0; i < list_size; ++i )
if ( listArray[ i ] == input )
return i;
return MAX_UNSIGNED_LONG;
}
template <class list_type>
inline unsigned int List<list_type>::Size( void ) const
{
return list_size;
}
template <class list_type>
void List<list_type>::Clear( bool doNotDeallocateSmallBlocks )
{
if ( allocation_size == 0 )
return;
if (allocation_size>512 || doNotDeallocateSmallBlocks==false)
{
delete [] listArray;
allocation_size = 0;
listArray = 0;
}
list_size = 0;
}
template <class list_type>
void List<list_type>::Compress( void )
{
list_type * new_array;
if ( allocation_size == 0 )
return ;
new_array = new list_type [ allocation_size ];
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated array
delete[] listArray;
listArray = new_array;
}
template <class list_type>
void List<list_type>::Preallocate( unsigned countNeeded )
{
unsigned amountToAllocate = allocation_size;
if (allocation_size==0)
amountToAllocate=16;
while (amountToAllocate < countNeeded)
amountToAllocate<<=1;
if ( allocation_size < amountToAllocate)
{
// allocate twice the currently allocated memory
list_type * new_array;
allocation_size=amountToAllocate;
new_array = new list_type [ allocation_size ];
if (listArray)
{
// copy old array over
for ( unsigned int counter = 0; counter < list_size; ++counter )
new_array[ counter ] = listArray[ counter ];
// Don't call constructors, assignment operators, etc.
//memcpy(new_array, listArray, list_size*sizeof(list_type));
// set old array to point to the newly allocated and twice as large array
delete[] listArray;
}
listArray = new_array;
}
}
} // End namespace
#endif

319
thirdparty/raknet/Source/DS_Map.h vendored Normal file
View File

@@ -0,0 +1,319 @@
/// \file
/// \brief \b [Internal] Map
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAKNET_MAP_H
#define __RAKNET_MAP_H
#include "DS_OrderedList.h"
#include "Export.h"
// 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 RakNet::RakMemoryOverride
{
public:
static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultMapKeyComparison<key_type>(key_type(),key_type());}
struct MapNode
{
MapNode() {}
MapNode(key_type _key, data_type _data) : mapNodeKey(_key), mapNodeData(_data) {}
MapNode& operator = ( const MapNode& input ) {mapNodeKey=input.mapNodeKey; mapNodeData=input.mapNodeData; return *this;}
MapNode( const MapNode & input) {mapNodeKey=input.mapNodeKey; mapNodeData=input.mapNodeData;}
key_type mapNodeKey;
data_type mapNodeData;
};
// Has to be a static because the comparison callback for DataStructures::OrderedList is a C function
static int NodeComparisonFunc(const key_type &a, const MapNode &b)
{
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
return key_comparison_func(a, b.mapNodeKey);
}
Map();
~Map();
Map( const Map& original_copy );
Map& operator= ( const Map& original_copy );
data_type& Get(const key_type &key);
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);
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);
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)
{
if (HasSavedSearchResult(key))
return mapNodeList[lastSearchIndex].mapNodeData;
bool objectExists;
unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists);
assert(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)
{
assert(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);
assert(objectExists);
}
data_type tmp = mapNodeList[index].mapNodeData;
mapNodeList.RemoveAtIndex(index);
lastSearchIndexValid=false;
return tmp;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::Set(const key_type &key, const data_type &data)
{
bool objectExists;
unsigned index;
if (HasSavedSearchResult(key))
{
mapNodeList[lastSearchIndex].mapNodeData=data;
return;
}
index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists)
{
SaveLastSearch(key,index);
mapNodeList[index].mapNodeData=data;
}
else
{
SaveLastSearch(key,mapNodeList.Insert(key,MapNode(key,data), true));
}
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::SetExisting(const key_type &key, const data_type &data)
{
bool objectExists;
unsigned index;
if (HasSavedSearchResult(key))
{
index=lastSearchIndex;
}
else
{
index=mapNodeList.GetIndexFromKey(key, &objectExists);
assert(objectExists);
SaveLastSearch(key,index);
}
mapNodeList[index].mapNodeData=data;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::SetNew(const key_type &key, const data_type &data)
{
#ifdef _DEBUG
unsigned index;
bool objectExists;
index=mapNodeList.GetIndexFromKey(key, &objectExists);
assert(objectExists==false);
#endif
SaveLastSearch(key,mapNodeList.Insert(key,MapNode(key,data), true));
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
bool Map<key_type, data_type, key_comparison_func>::Has(const key_type &key)
{
if (HasSavedSearchResult(key))
return true;
bool objectExists;
unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists)
SaveLastSearch(key,index);
return objectExists;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
bool Map<key_type, data_type, key_comparison_func>::Delete(const key_type &key)
{
if (HasSavedSearchResult(key))
{
lastSearchIndexValid=false;
mapNodeList.RemoveAtIndex(lastSearchIndex);
return true;
}
bool objectExists;
unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists)
{
lastSearchIndexValid=false;
mapNodeList.RemoveAtIndex(index);
return true;
}
else
return false;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::Clear(void)
{
lastSearchIndexValid=false;
mapNodeList.Clear();
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
data_type& Map<key_type, data_type, key_comparison_func>::operator[]( const unsigned int position ) const
{
return mapNodeList[position].mapNodeData;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
key_type Map<key_type, data_type, key_comparison_func>::GetKeyAtIndex( const unsigned int position ) const
{
return mapNodeList[position].mapNodeKey;
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
unsigned Map<key_type, data_type, key_comparison_func>::Size(void) const
{
return mapNodeList.Size();
}
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::SaveLastSearch(const key_type &key, const unsigned index)
{
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
{
return lastSearchIndexValid && key_comparison_func(key,lastSearchKey)==0;
}
}
#endif

285
thirdparty/raknet/Source/DS_MemoryPool.h vendored Normal file
View File

@@ -0,0 +1,285 @@
#ifndef __MEMORY_POOL_H
#define __MEMORY_POOL_H
#ifndef __APPLE__
// Use stdlib and not malloc for compatibility
#include <stdlib.h>
#endif
#include <assert.h>
#include "Export.h"
#include "RakMemoryOverride.h"
// DS_MEMORY_POOL_MAX_FREE_PAGES must be > 1
#define DS_MEMORY_POOL_MAX_FREE_PAGES 4
// #define _DISABLE_MEMORY_POOL
namespace DataStructures
{
/// Very fast memory pool for allocating and deallocating structures that don't have constructors or destructors.
/// Contains a list of pages, each of which has an array of the user structures
template <class MemoryBlockType>
class RAK_DLL_EXPORT MemoryPool : public RakNet::RakMemoryOverride
{
public:
struct Page;
struct MemoryWithPage
{
MemoryBlockType userMemory;
Page *parentPage;
};
struct Page
{
MemoryWithPage** availableStack;
int availableStackSize;
MemoryWithPage* block;
Page *next, *prev;
};
MemoryPool();
~MemoryPool();
void SetPageSize(int size); // Defaults to 16384
MemoryBlockType *Allocate(void);
void Release(MemoryBlockType *m);
void Clear(void);
int GetAvailablePagesSize(void) const {return availablePagesSize;}
int GetUnavailablePagesSize(void) const {return unavailablePagesSize;}
int GetMemoryPoolPageSize(void) const {return memoryPoolPageSize;}
protected:
int BlocksPerPage(void) const;
void AllocateFirst(void);
bool InitPage(Page *page, Page *prev);
// availablePages contains pages which have room to give the user new blocks. We return these blocks from the head of the list
// unavailablePages are pages which are totally full, and from which we do not return new blocks.
// Pages move from the head of unavailablePages to the tail of availablePages, and from the head of availablePages to the tail of unavailablePages
Page *availablePages, *unavailablePages;
int availablePagesSize, unavailablePagesSize;
int memoryPoolPageSize;
};
template<class MemoryBlockType>
MemoryPool<MemoryBlockType>::MemoryPool()
{
#ifndef _DISABLE_MEMORY_POOL
//AllocateFirst();
availablePagesSize=0;
unavailablePagesSize=0;
memoryPoolPageSize=16384;
#endif
}
template<class MemoryBlockType>
MemoryPool<MemoryBlockType>::~MemoryPool()
{
#ifndef _DISABLE_MEMORY_POOL
Clear();
#endif
}
template<class MemoryBlockType>
void MemoryPool<MemoryBlockType>::SetPageSize(int size)
{
memoryPoolPageSize=size;
}
template<class MemoryBlockType>
MemoryBlockType* MemoryPool<MemoryBlockType>::Allocate(void)
{
#ifdef _DISABLE_MEMORY_POOL
return new MemoryBlockType;
#endif
if (availablePagesSize>0)
{
MemoryBlockType *retVal;
Page *curPage;
curPage=availablePages;
retVal = (MemoryBlockType*) curPage->availableStack[--(curPage->availableStackSize)];
if (curPage->availableStackSize==0)
{
--availablePagesSize;
availablePages=curPage->next;
assert(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;
}
}
assert(availablePagesSize==0 || availablePages->availableStackSize>0);
return retVal;
}
availablePages = (Page *) rakMalloc(sizeof(Page));
if (availablePages==0)
return 0;
availablePagesSize=1;
if (InitPage(availablePages, availablePages)==false)
return 0;
assert(availablePages->availableStackSize>1);
return (MemoryBlockType *) availablePages->availableStack[--availablePages->availableStackSize];
}
template<class MemoryBlockType>
void MemoryPool<MemoryBlockType>::Release(MemoryBlockType *m)
{
#ifdef _DISABLE_MEMORY_POOL
delete m;
return;
#endif
// Find the page this block is in and return it.
Page *curPage;
MemoryWithPage *memoryWithPage = (MemoryWithPage*)m;
curPage=memoryWithPage->parentPage;
if (curPage->availableStackSize==0)
{
// The page is in the unavailable list so move it to the available list
curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
unavailablePagesSize--;
// As this page is no longer totally empty, move it to the end of available pages
curPage->next->prev=curPage->prev;
curPage->prev->next=curPage->next;
if (unavailablePagesSize>0 && curPage==unavailablePages)
unavailablePages=unavailablePages->next;
if (availablePagesSize++==0)
{
availablePages=curPage;
curPage->next=curPage;
curPage->prev=curPage;
}
else
{
curPage->next=availablePages;
curPage->prev=availablePages->prev;
availablePages->prev->next=curPage;
availablePages->prev=curPage;
}
}
else
{
curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
if (curPage->availableStackSize==BlocksPerPage() &&
availablePagesSize>=DS_MEMORY_POOL_MAX_FREE_PAGES)
{
// After a certain point, just deallocate empty pages rather than keep them around
if (curPage==availablePages)
{
availablePages=curPage->next;
assert(availablePages->availableStackSize>0);
}
curPage->prev->next=curPage->next;
curPage->next->prev=curPage->prev;
availablePagesSize--;
rakFree(curPage->availableStack);
rakFree(curPage->block);
rakFree(curPage);
}
}
}
template<class MemoryBlockType>
void MemoryPool<MemoryBlockType>::Clear(void)
{
#ifdef _DISABLE_MEMORY_POOL
return;
#endif
Page *cur, *freed;
if (availablePagesSize>0)
{
cur = availablePages;
#ifdef _MSC_VER
#pragma warning(disable:4127) // conditional expression is constant
#endif
while (true)
// do
{
rakFree(cur->availableStack);
rakFree(cur->block);
freed=cur;
cur=cur->next;
if (cur==availablePages)
{
rakFree(freed);
break;
}
rakFree(freed);
}// while(cur!=availablePages);
}
if (unavailablePagesSize>0)
{
cur = unavailablePages;
while (1)
//do
{
rakFree(cur->availableStack);
rakFree(cur->block);
freed=cur;
cur=cur->next;
if (cur==unavailablePages)
{
rakFree(freed);
break;
}
rakFree(freed);
} // while(cur!=unavailablePages);
}
availablePagesSize=0;
unavailablePagesSize=0;
}
template<class MemoryBlockType>
int MemoryPool<MemoryBlockType>::BlocksPerPage(void) const
{
return memoryPoolPageSize / sizeof(MemoryWithPage);
}
template<class MemoryBlockType>
bool MemoryPool<MemoryBlockType>::InitPage(Page *page, Page *prev)
{
int i=0;
const int bpp = BlocksPerPage();
page->block=(MemoryWithPage*) rakMalloc(memoryPoolPageSize);
if (page->block==0)
return false;
page->availableStack=(MemoryWithPage**)rakMalloc(sizeof(MemoryWithPage*)*bpp);
if (page->availableStack==0)
{
rakFree(page->block);
return false;
}
MemoryWithPage *curBlock = page->block;
MemoryWithPage **curStack = page->availableStack;
while (i < bpp)
{
curBlock->parentPage=page;
curStack[i]=curBlock++;
i++;
}
page->availableStackSize=bpp;
page->next=availablePages;
page->prev=prev;
return true;
}
}
#endif

View File

@@ -0,0 +1,252 @@
/// \file
/// \brief \b [Internal] Ordered Channel Heap . This is a heap where you add to it on multiple ordered channels, with each channel having a different weight.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __RAKNET_ORDERED_CHANNEL_HEAP_H
#define __RAKNET_ORDERED_CHANNEL_HEAP_H
#include "DS_Heap.h"
#include "DS_Map.h"
#include "DS_Queue.h"
#include "Export.h"
#include <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 RakNet::RakMemoryOverride
{
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
assert(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)
{
assert(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 = new QueueAndWeight;
qaw->weight=weight;
qaw->signalDeletion=false;
map.SetNew(channelID, qaw);
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::RemoveChannel(channel_key_type channelID)
{
if (map.Has(channelID))
{
unsigned i;
i=map.GetIndexAtKey(channelID);
if (map[i]->randResultQueue.Size()==0)
{
delete map[i];
map.RemoveAtIndex(i);
}
else
{
// Signal this channel for deletion later, because the heap has nodes with this channel right now
map[i]->signalDeletion=true;
}
}
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
unsigned OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Size(void) const
{
return heap.Size();
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
heap_data_type& OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::operator[]( const unsigned int position ) const
{
return heap[position].data;
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
unsigned OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::ChannelSize(const channel_key_type &channelID)
{
QueueAndWeight *queueAndWeight=map.Get(channelID);
return queueAndWeight->randResultQueue.Size();
}
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Clear(void)
{
unsigned i;
for (i=0; i < map.Size(); i++)
delete map[i];
map.Clear();
heap.Clear();
}
}
#endif

View File

@@ -0,0 +1,271 @@
/// \file
/// \brief \b [Internal] Quicksort ordered list.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#include "DS_List.h"
#include "RakMemoryOverride.h"
#include "Export.h"
#ifndef __ORDERED_LIST_H
#define __ORDERED_LIST_H
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
template <class key_type, class data_type>
int defaultOrderedListComparison(const key_type &a, const data_type &b)
{
if (a<b) return -1; if (a==b) return 0; return 1;
}
/// \note IMPORTANT! If you use defaultOrderedListComparison then call IMPLEMENT_DEFAULT_COMPARISON or you will get an unresolved external linker error.
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)=defaultOrderedListComparison<key_type, data_type> >
class RAK_DLL_EXPORT OrderedList : public RakNet::RakMemoryOverride
{
public:
static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultOrderedListComparison<key_type, data_type>(key_type(),data_type());}
OrderedList();
~OrderedList();
OrderedList( const OrderedList& original_copy );
OrderedList& operator= ( const OrderedList& original_copy );
/// comparisonFunction must take a key_type and a data_type and return <0, ==0, or >0
/// If the data type has comparison operators already defined then you can just use defaultComparison
bool HasData(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
// GetIndexFromKey returns where the insert should go at the same time checks if it is there
unsigned GetIndexFromKey(const key_type &key, bool *objectExists, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
data_type GetElementFromKey(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
bool GetElementFromKey(const key_type &key, data_type &element, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
unsigned Insert(const key_type &key, const data_type &data, bool assertOnDuplicate, int (*cf)(const key_type&, const data_type&)=default_comparison_function);
unsigned Remove(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function);
unsigned RemoveIfExists(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function);
data_type& operator[] ( const unsigned int position ) const;
void RemoveAtIndex(const unsigned index);
void InsertAtIndex(const data_type &data, const unsigned index);
void InsertAtEnd(const data_type &data);
void RemoveFromEnd(const unsigned num=1);
void Clear(bool doNotDeallocate=false);
unsigned Size(void) const;
protected:
DataStructures::List<data_type> orderedList;
};
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>::OrderedList()
{
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>::~OrderedList()
{
Clear();
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>::OrderedList( const OrderedList& original_copy )
{
orderedList=original_copy.orderedList;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>& OrderedList<key_type, data_type, default_comparison_function>::operator= ( const OrderedList& original_copy )
{
orderedList=original_copy.orderedList;
return *this;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
bool OrderedList<key_type, data_type, default_comparison_function>::HasData(const key_type &key, int (*cf)(const key_type&, const data_type&)) const
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
return objectExists;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
data_type OrderedList<key_type, data_type, default_comparison_function>::GetElementFromKey(const key_type &key, int (*cf)(const key_type&, const data_type&)) const
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
assert(objectExists);
return orderedList[index];
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
bool OrderedList<key_type, data_type, default_comparison_function>::GetElementFromKey(const key_type &key, data_type &element, int (*cf)(const key_type&, const data_type&)) const
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
if (objectExists)
element = orderedList[index];
return objectExists;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::GetIndexFromKey(const key_type &key, bool *objectExists, int (*cf)(const key_type&, const data_type&)) const
{
int index, upperBound, lowerBound;
int res;
if (orderedList.Size()==0)
{
*objectExists=false;
return 0;
}
upperBound=(int)orderedList.Size()-1;
lowerBound=0;
index = (int)orderedList.Size()/2;
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while (1)
{
res = cf(key,orderedList[index]);
if (res==0)
{
*objectExists=true;
return index;
}
else if (res<0)
{
upperBound=index-1;
}
else// if (res>0)
{
lowerBound=index+1;
}
index=lowerBound+(upperBound-lowerBound)/2;
if (lowerBound>upperBound)
{
*objectExists=false;
return lowerBound; // No match
}
}
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::Insert(const key_type &key, const data_type &data, bool assertOnDuplicate, int (*cf)(const key_type&, const data_type&))
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
// Don't allow duplicate insertion.
if (objectExists)
{
// This is usually a bug! Use InsertAllowDuplicate if you want duplicates
assert(assertOnDuplicate==false);
return (unsigned)-1;
}
if (index>=orderedList.Size())
{
orderedList.Insert(data);
return orderedList.Size()-1;
}
else
{
orderedList.Insert(data,index);
return index;
}
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::Remove(const key_type &key, int (*cf)(const key_type&, const data_type&))
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
// Can't find the element to remove if this assert hits
// assert(objectExists==true);
if (objectExists==false)
{
assert(objectExists==true);
return 0;
}
orderedList.RemoveAtIndex(index);
return index;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::RemoveIfExists(const key_type &key, int (*cf)(const key_type&, const data_type&))
{
bool objectExists;
unsigned index;
index = GetIndexFromKey(key, &objectExists, cf);
// Can't find the element to remove if this assert hits
if (objectExists==false)
return 0;
orderedList.RemoveAtIndex(index);
return index;
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::RemoveAtIndex(const unsigned index)
{
orderedList.RemoveAtIndex(index);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::InsertAtIndex(const data_type &data, const unsigned index)
{
orderedList.Insert(data, index);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::InsertAtEnd(const data_type &data)
{
orderedList.Insert(data);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::RemoveFromEnd(const unsigned num)
{
orderedList.RemoveFromEnd(num);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::Clear(bool doNotDeallocate)
{
orderedList.Clear(doNotDeallocate);
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
data_type& OrderedList<key_type, data_type, default_comparison_function>::operator[]( const unsigned int position ) const
{
return orderedList[position];
}
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::Size(void) const
{
return orderedList.Size();
}
}
#endif

418
thirdparty/raknet/Source/DS_Queue.h vendored Normal file
View File

@@ -0,0 +1,418 @@
/// \file
/// \brief \b [Internal] A queue used by RakNet.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __QUEUE_H
#define __QUEUE_H
// Template classes have to have all the code in the header file
#include <assert.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
{
/// \brief A queue implemented as an array with a read and write index.
template <class queue_type>
class RAK_DLL_EXPORT Queue
{
public:
Queue();
~Queue();
Queue( Queue& original_copy );
bool operator= ( const Queue& original_copy );
void Push( const queue_type& input );
void PushAtHead( const queue_type& input, unsigned index=0 );
queue_type& operator[] ( unsigned int position ) const; // Not a normal thing you do with a queue but can be used for efficiency
void RemoveAtIndex( unsigned int position ); // Not a normal thing you do with a queue but can be used for efficiency
inline queue_type Peek( void ) const;
inline queue_type PeekTail( void ) const;
inline queue_type Pop( void );
inline unsigned int Size( void ) const;
inline bool IsEmpty(void) const;
inline unsigned int AllocationSize( void ) const;
inline void Clear( void );
void Compress( void );
bool Find ( queue_type q );
void ClearAndForceAllocation( int size ); // Force a memory allocation to a certain larger size
private:
queue_type* array;
unsigned int head; // Array index for the head of the queue
unsigned int tail; // Array index for the tail of the queue
unsigned int allocation_size;
};
template <class queue_type>
inline unsigned int Queue<queue_type>::Size( void ) const
{
if ( head <= tail )
return tail -head;
else
return allocation_size -head + tail;
}
template <class queue_type>
inline bool Queue<queue_type>::IsEmpty(void) const
{
return head==tail;
}
template <class queue_type>
inline unsigned int Queue<queue_type>::AllocationSize( void ) const
{
return allocation_size;
}
template <class queue_type>
Queue<queue_type>::Queue()
{
allocation_size = 16;
array = new queue_type[ allocation_size ];
head = 0;
tail = 0;
}
template <class queue_type>
Queue<queue_type>::~Queue()
{
if (allocation_size>0)
delete [] array;
}
template <class queue_type>
inline queue_type Queue<queue_type>::Pop( void )
{
#ifdef _DEBUG
assert( allocation_size > 0 && Size() >= 0 && head != tail);
#endif
//head=(head+1) % allocation_size;
if ( ++head == allocation_size )
head = 0;
if ( head == 0 )
return ( queue_type ) array[ allocation_size -1 ];
return ( queue_type ) array[ head -1 ];
}
template <class queue_type>
void Queue<queue_type>::PushAtHead( const queue_type& input, unsigned index )
{
assert(index <= Size());
// Just force a reallocation, will be overwritten
Push(input);
if (Size()==1)
return;
unsigned writeIndex, readIndex, trueWriteIndex, trueReadIndex;
writeIndex=Size()-1;
readIndex=writeIndex-1;
while (readIndex >= index)
{
if ( head + writeIndex >= allocation_size )
trueWriteIndex = head + writeIndex - allocation_size;
else
trueWriteIndex = head + writeIndex;
if ( head + readIndex >= allocation_size )
trueReadIndex = head + readIndex - allocation_size;
else
trueReadIndex = head + readIndex;
array[trueWriteIndex]=array[trueReadIndex];
if (readIndex==0)
break;
writeIndex--;
readIndex--;
}
if ( head + index >= allocation_size )
trueWriteIndex = head + index - allocation_size;
else
trueWriteIndex = head + index;
array[trueWriteIndex]=input;
}
template <class queue_type>
inline queue_type Queue<queue_type>::Peek( void ) const
{
#ifdef _DEBUG
assert( head != tail );
assert( allocation_size > 0 && Size() >= 0 );
#endif
return ( queue_type ) array[ head ];
}
template <class queue_type>
inline queue_type Queue<queue_type>::PeekTail( void ) const
{
#ifdef _DEBUG
assert( head != tail );
assert( allocation_size > 0 && Size() >= 0 );
#endif
if (tail!=0)
return ( queue_type ) array[ tail-1 ];
else
return ( queue_type ) array[ allocation_size-1 ];
}
template <class queue_type>
void Queue<queue_type>::Push( const queue_type& input )
{
if ( allocation_size == 0 )
{
array = new queue_type[ 16 ];
head = 0;
tail = 1;
array[ 0 ] = input;
allocation_size = 16;
return ;
}
array[ tail++ ] = input;
if ( tail == allocation_size )
tail = 0;
if ( tail == head )
{
// unsigned int index=tail;
// Need to allocate more memory.
queue_type * new_array;
new_array = new queue_type[ allocation_size * 2 ];
#ifdef _DEBUG
assert( 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
delete [] array;
array = new_array;
}
}
template <class queue_type>
Queue<queue_type>::Queue( Queue& original_copy )
{
// Allocate memory for copy
if ( original_copy.Size() == 0 )
{
allocation_size = 0;
}
else
{
array = new queue_type [ original_copy.Size() + 1 ];
for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter )
array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ];
head = 0;
tail = original_copy.Size();
allocation_size = original_copy.Size() + 1;
}
}
template <class queue_type>
bool Queue<queue_type>::operator= ( const Queue& original_copy )
{
if ( ( &original_copy ) == this )
return false;
Clear();
// Allocate memory for copy
if ( original_copy.Size() == 0 )
{
allocation_size = 0;
}
else
{
array = new queue_type [ original_copy.Size() + 1 ];
for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter )
array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ];
head = 0;
tail = original_copy.Size();
allocation_size = original_copy.Size() + 1;
}
return true;
}
template <class queue_type>
inline void Queue<queue_type>::Clear ( void )
{
if ( allocation_size == 0 )
return ;
if (allocation_size > 32)
{
delete[] array;
allocation_size = 0;
}
head = 0;
tail = 0;
}
template <class queue_type>
void Queue<queue_type>::Compress ( void )
{
queue_type* new_array;
unsigned int newAllocationSize;
if (allocation_size==0)
return;
newAllocationSize=1;
while (newAllocationSize <= Size())
newAllocationSize<<=1; // Must be a better way to do this but I'm too dumb to figure it out quickly :)
new_array = new queue_type [newAllocationSize];
for (unsigned int counter=0; counter < Size(); ++counter)
new_array[counter] = array[(head + counter)%(allocation_size)];
tail=Size();
allocation_size=newAllocationSize;
head=0;
// Delete the old array and move the pointer to the new array
delete [] array;
array=new_array;
}
template <class queue_type>
bool Queue<queue_type>::Find ( queue_type q )
{
if ( allocation_size == 0 )
return false;
unsigned int counter = head;
while ( counter != tail )
{
if ( array[ counter ] == q )
return true;
counter = ( counter + 1 ) % allocation_size;
}
return false;
}
template <class queue_type>
void Queue<queue_type>::ClearAndForceAllocation( int size )
{
delete [] array;
array = new queue_type[ size ];
allocation_size = size;
head = 0;
tail = 0;
}
template <class queue_type>
inline queue_type& Queue<queue_type>::operator[] ( unsigned int position ) const
{
#ifdef _DEBUG
assert( 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
assert( position < Size() );
assert( 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

View File

@@ -0,0 +1,111 @@
/// \file
/// \brief \b [Internal] A queue implemented as a linked list.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __QUEUE_LINKED_LIST_H
#define __QUEUE_LINKED_LIST_H
#include "DS_LinkedList.h"
#include "Export.h"
#include "RakMemoryOverride.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
/// \brief A queue implemented using a linked list. Rarely used.
template <class QueueType>
class RAK_DLL_EXPORT QueueLinkedList : public RakNet::RakMemoryOverride
{
public:
QueueLinkedList();
QueueLinkedList( const QueueLinkedList& original_copy );
bool operator= ( const QueueLinkedList& original_copy );
QueueType Pop( void );
QueueType& Peek( void );
QueueType& EndPeek( void );
void Push( const QueueType& input );
unsigned int Size( void );
void Clear( void );
void Compress( void );
private:
LinkedList<QueueType> data;
};
template <class QueueType>
QueueLinkedList<QueueType>::QueueLinkedList()
{
}
template <class QueueType>
inline unsigned int QueueLinkedList<QueueType>::Size()
{
return data.Size();
}
template <class QueueType>
inline QueueType QueueLinkedList<QueueType>::Pop( void )
{
data.Beginning();
return ( QueueType ) data.Pop();
}
template <class QueueType>
inline QueueType& QueueLinkedList<QueueType>::Peek( void )
{
data.Beginning();
return ( QueueType ) data.Peek();
}
template <class QueueType>
inline QueueType& QueueLinkedList<QueueType>::EndPeek( void )
{
data.End();
return ( QueueType ) data.Peek();
}
template <class QueueType>
void QueueLinkedList<QueueType>::Push( const QueueType& input )
{
data.End();
data.Add( input );
}
template <class QueueType>
QueueLinkedList<QueueType>::QueueLinkedList( const QueueLinkedList& original_copy )
{
data = original_copy.data;
}
template <class QueueType>
bool QueueLinkedList<QueueType>::operator= ( const QueueLinkedList& original_copy )
{
if ( ( &original_copy ) == this )
return false;
data = original_copy.data;
}
template <class QueueType>
void QueueLinkedList<QueueType>::Clear ( void )
{
data.Clear();
}
} // End namespace
#endif

219
thirdparty/raknet/Source/DS_RangeList.h vendored Normal file
View File

@@ -0,0 +1,219 @@
#ifndef __RANGE_LIST_H
#define __RANGE_LIST_H
#include "DS_OrderedList.h"
#include "BitStream.h"
#include "RakMemoryOverride.h"
#include <assert.h>
namespace DataStructures
{
template <class range_type>
struct RangeNode : public RakNet::RakMemoryOverride
{
RangeNode() {}
~RangeNode() {}
RangeNode(range_type min, range_type max) {minIndex=min; maxIndex=max;}
range_type minIndex;
range_type maxIndex;
};
template <class range_type>
int RangeNodeComp(const range_type &a, const RangeNode<range_type> &b)
{
if (a<b.minIndex)
return -1;
if (a==b.minIndex)
return 0;
return 1;
}
template <class range_type>
class RAK_DLL_EXPORT RangeList : public RakNet::RakMemoryOverride
{
public:
RangeList();
~RangeList();
void Insert(range_type index);
void Clear(void);
unsigned Size(void) const;
unsigned RangeSum(void) const;
BitSize_t Serialize(RakNet::BitStream *in, BitSize_t maxBits, bool clearSerialized);
bool Deserialize(RakNet::BitStream *out);
DataStructures::OrderedList<range_type, RangeNode<range_type> , RangeNodeComp<range_type> > ranges;
};
template <class range_type>
BitSize_t RangeList<range_type>::Serialize(RakNet::BitStream *in, BitSize_t maxBits, bool clearSerialized)
{
assert(ranges.Size() < (unsigned short)-1);
RakNet::BitStream tempBS;
BitSize_t bitsWritten;
unsigned short countWritten;
unsigned i;
countWritten=0;
bitsWritten=0;
for (i=0; i < ranges.Size(); i++)
{
if ((int)sizeof(unsigned short)*8+bitsWritten+(int)sizeof(range_type)*8*2+1>maxBits)
break;
tempBS.Write(ranges[i].minIndex==ranges[i].maxIndex);
tempBS.Write(ranges[i].minIndex);
bitsWritten+=sizeof(range_type)*8+1;
if (ranges[i].minIndex!=ranges[i].maxIndex)
{
tempBS.Write(ranges[i].maxIndex);
bitsWritten+=sizeof(range_type)*8;
}
countWritten++;
}
BitSize_t before=in->GetWriteOffset();
in->WriteCompressed(countWritten);
bitsWritten+=in->GetWriteOffset()-before;
// printf("%i ", in->GetNumberOfBitsUsed());
in->Write(&tempBS, tempBS.GetNumberOfBitsUsed());
// printf("%i %i \n", tempBS.GetNumberOfBitsUsed(),in->GetNumberOfBitsUsed());
if (clearSerialized && countWritten)
{
unsigned rangeSize=ranges.Size();
for (i=0; i < rangeSize-countWritten; i++)
{
ranges[i]=ranges[i+countWritten];
}
ranges.RemoveFromEnd(countWritten);
}
return bitsWritten;
}
template <class range_type>
bool RangeList<range_type>::Deserialize(RakNet::BitStream *out)
{
ranges.Clear();
unsigned short count;
out->ReadCompressed(count);
unsigned short i;
range_type min,max;
bool maxEqualToMin=false;
for (i=0; i < count; i++)
{
out->Read(maxEqualToMin);
if (out->Read(min)==false)
return false;
if (maxEqualToMin==false)
{
if (out->Read(max)==false)
return false;
if (max<min)
return false;
}
else
max=min;
ranges.InsertAtEnd(RangeNode<range_type>(min,max));
}
return true;
}
template <class range_type>
RangeList<range_type>::RangeList()
{
RangeNodeComp<range_type>(0, RangeNode<range_type>());
}
template <class range_type>
RangeList<range_type>::~RangeList()
{
Clear();
}
template <class range_type>
void RangeList<range_type>::Insert(range_type index)
{
if (ranges.Size()==0)
{
ranges.Insert(index, RangeNode<range_type>(index, index), true);
return;
}
bool objectExists;
unsigned insertionIndex=ranges.GetIndexFromKey(index, &objectExists);
if (insertionIndex==ranges.Size())
{
if (index == ranges[insertionIndex-1].maxIndex+1)
ranges[insertionIndex-1].maxIndex++;
else if (index > ranges[insertionIndex-1].maxIndex+1)
{
// Insert at end
ranges.Insert(index, RangeNode<range_type>(index, index), true);
}
return;
}
if (index < ranges[insertionIndex].minIndex-1)
{
// Insert here
ranges.InsertAtIndex(RangeNode<range_type>(index, index), insertionIndex);
return;
}
else if (index == ranges[insertionIndex].minIndex-1)
{
// Decrease minIndex and join left
ranges[insertionIndex].minIndex--;
if (insertionIndex>0 && ranges[insertionIndex-1].maxIndex+1==ranges[insertionIndex].minIndex)
{
ranges[insertionIndex-1].maxIndex=ranges[insertionIndex].maxIndex;
ranges.RemoveAtIndex(insertionIndex);
}
return;
}
else if (index >= ranges[insertionIndex].minIndex && index <= ranges[insertionIndex].maxIndex)
{
// Already exists
return;
}
else if (index == ranges[insertionIndex].maxIndex+1)
{
// Increase maxIndex and join right
ranges[insertionIndex].maxIndex++;
if (insertionIndex<ranges.Size()-1 && ranges[insertionIndex+1].minIndex==ranges[insertionIndex].maxIndex+1)
{
ranges[insertionIndex+1].minIndex=ranges[insertionIndex].minIndex;
ranges.RemoveAtIndex(insertionIndex);
}
return;
}
}
template <class range_type>
void RangeList<range_type>::Clear(void)
{
ranges.Clear();
}
template <class range_type>
unsigned RangeList<range_type>::Size(void) const
{
return ranges.Size();
}
template <class range_type>
unsigned RangeList<range_type>::RangeSum(void) const
{
unsigned sum=0,i;
for (i=0; i < ranges.Size(); i++)
sum+=ranges[i].maxIndex-ranges[i].minIndex+1;
return sum;
}
}
#endif

1027
thirdparty/raknet/Source/DS_Table.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

322
thirdparty/raknet/Source/DS_Table.h vendored Normal file
View File

@@ -0,0 +1,322 @@
#ifndef __TABLE_H
#define __TABLE_H
#ifdef _MSC_VER
#pragma warning( push )
#endif
#include "DS_List.h"
#include "DS_BPlusTree.h"
#include "RakMemoryOverride.h"
#include "Export.h"
#include "RakString.h"
#define _TABLE_BPLUS_TREE_ORDER 16
#define _TABLE_MAX_COLUMN_NAME_LENGTH 32
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
/// \brief Holds a set of columns, a set of rows, and rows times columns cells.
/// The table data structure is useful if you want to store a set of structures and perform queries on those structures
/// This is a relatively simple and fast implementation of the types of tables commonly used in databases
/// See TableSerializer to serialize data members of the table
/// See LightweightDatabaseClient and LightweightDatabaseServer to transmit the table over the network.
class RAK_DLL_EXPORT Table : public RakNet::RakMemoryOverride
{
public:
enum ColumnType
{
// Cell::i used
NUMERIC,
// Cell::c used to hold a null terminated string.
STRING,
// Cell::c holds data. Cell::i holds data length of c in bytes.
BINARY,
// Cell::c holds data. Not deallocated. Set manually by assigning ptr.
POINTER,
};
/// Holds the actual data in the table
struct RAK_DLL_EXPORT Cell
{
Cell();
~Cell();
Cell(int intValue, char *charValue, void *ptr, ColumnType type);
void Clear(void);
/// Numeric
void Set(int 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);
/// String
void Get(char *output);
/// Binary
void Get(char *output, int *outputLength);
RakNet::RakString ToString(ColumnType columnType);
// assignment operator and copy constructor
Cell& operator = ( const Cell& input );
Cell( const Cell & input);
bool isEmpty;
int i;
char *c;
void *ptr;
};
/// Stores the name and type of the column
/// \internal
struct RAK_DLL_EXPORT ColumnDescriptor
{
ColumnDescriptor();
~ColumnDescriptor();
ColumnDescriptor(const char cn[_TABLE_MAX_COLUMN_NAME_LENGTH],ColumnType ct);
char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
ColumnType columnType;
};
/// Stores the list of cells for this row, and a special flag used for internal sorting
struct RAK_DLL_EXPORT Row
{
// list of cells
DataStructures::List<Cell*> cells;
/// Numeric
void UpdateCell(unsigned columnIndex, int value);
/// String
void UpdateCell(unsigned columnIndex, const char *str);
/// Binary
void UpdateCell(unsigned columnIndex, int byteLength, const char *data);
};
// Operations to perform for cell comparison
enum FilterQueryType
{
QF_EQUAL,
QF_NOT_EQUAL,
QF_GREATER_THAN,
QF_GREATER_THAN_EQ,
QF_LESS_THAN,
QF_LESS_THAN_EQ,
QF_IS_EMPTY,
QF_NOT_EMPTY,
};
// Compare the cell value for a row at columnName to the cellValue using operation.
struct RAK_DLL_EXPORT FilterQuery
{
FilterQuery();
~FilterQuery();
FilterQuery(unsigned column, Cell *cell, FilterQueryType op);
// If columnName is specified, columnIndex will be looked up using it.
char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
unsigned columnIndex;
Cell *cellValue;
FilterQueryType operation;
};
/// Increasing or decreasing sort order
enum SortQueryType
{
QS_INCREASING_ORDER,
QS_DECREASING_ORDER,
};
// Sort on increasing or decreasing order for a particular column
struct RAK_DLL_EXPORT SortQuery
{
/// The index of the table column we are sorting on
unsigned columnIndex;
/// See SortQueryType
SortQueryType operation;
};
/// Constructor
Table();
/// Destructor
~Table();
/// \brief Adds a column to the table
/// \param[in] columnName The name of the column
/// \param[in] columnType What type of data this column will hold
/// \return The index of the new column
unsigned AddColumn(const char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH], ColumnType columnType);
/// \brief Removes a column by index
/// \param[in] columnIndex The index of the column to remove
void RemoveColumn(unsigned columnIndex);
/// \brief Gets the index of a column by name
/// Column indices are stored in the order they are added.
/// \param[in] columnName The name of the column
/// \return The index of the column, or (unsigned)-1 if no such column
unsigned ColumnIndex(char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]);
unsigned ColumnIndex(const char *columnName);
/// \brief Gives the string name of the column at a certain index
/// \param[in] index The index of the column
/// \return The name of the column, or 0 if an invalid index
char* ColumnName(unsigned index);
/// \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);
/// Returns the number of columns
/// \return The number of columns in the table
unsigned GetColumnCount(void) const;
/// Returns the number of rows
/// \return The number of rows in the table
unsigned GetRowCount(void) const;
/// \brief Adds a row to the table
/// New rows are added with empty values for all cells. However, if you specify initialCelLValues you can specify initial values
/// It's up to you to ensure that the values in the specific cells match the type of data used by that row
/// rowId can be considered the primary key for the row. It is much faster to lookup a row by its rowId than by searching keys.
/// rowId must be unique
/// Rows are stored in sorted order in the table, using rowId as the sort key
/// \param[in] rowId The UNIQUE primary key for the row. This can never be changed.
/// \param[in] initialCellValues Initial values to give the row (optional)
/// \return The newly added row
Table::Row* AddRow(unsigned rowId);
Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell> &initialCellValues);
/// Removes a row specified by rowId
/// \param[in] rowId The ID of the row
void RemoveRow(unsigned rowId);
/// Removes all the rows with IDs that the specified table also has
/// \param[in] tableContainingRowIDs The IDs of the rows
void RemoveRows(Table *tableContainingRowIDs);
/// Updates a particular cell in the table
/// \note If you are going to update many cells of a particular row, it is more efficient to call GetRow and perform the operations on the row directly.
/// \note Row pointers do not change, so you can also write directly to the rows for more efficiency.
/// \param[in] rowId The ID of the row
/// \param[in] columnIndex The column of the cell
/// \param[in] value The data to set
bool UpdateCell(unsigned rowId, unsigned columnIndex, int value);
bool UpdateCell(unsigned rowId, unsigned columnIndex, char *str);
bool UpdateCell(unsigned rowId, unsigned columnIndex, int byteLength, char *data);
bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int value);
bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, char *str);
bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int byteLength, char *data);
/// Note this is much less efficient to call than GetRow, then working with the cells directly
/// Numeric, string, binary
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, int *output);
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output);
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output, int *outputLength);
/// Gets a row. More efficient to do this and access Row::cells than to repeatedly call GetCell.
/// You can also update cells in rows from this function.
/// \param[in] rowId The ID of the row
/// \return The desired row, or 0 if no such row.
Row* GetRowByID(unsigned rowId) const;
/// Gets a row at a specific index
/// rowIndex should be less than GetRowCount()
/// \param[in] rowIndex The index of the row
/// \param[out] key The ID of the row returned
/// \return The desired row, or 0 if no such row.
Row* GetRowByIndex(unsigned rowIndex, unsigned *key) const;
/// \brief Queries the table, optionally returning only a subset of columns and rows.
/// \param[in] columnSubset An array of column indices. Only columns in this array are returned. Pass 0 for all columns
/// \param[in] numColumnSubset The number of elements in \a columnSubset
/// \param[in] inclusionFilters An array of FilterQuery. All filters must pass for the row to be returned.
/// \param[in] numInclusionFilters The number of elements in \a inclusionFilters
/// \param[in] rowIds An arrow of row IDs. Only these rows with these IDs are returned. Pass 0 for all rows.
/// \param[in] numRowIDs The number of elements in \a rowIds
/// \param[out] result The result of the query. If no rows are returned, the table will only have columns.
void QueryTable(unsigned *columnIndicesSubset, unsigned numColumnSubset, FilterQuery *inclusionFilters, unsigned numInclusionFilters, unsigned *rowIds, unsigned numRowIDs, Table *result);
/// \brief Sorts the table by rows
/// You can sort the table in ascending or descending order on one or more columns
/// Columns have precedence in the order they appear in the \a sortQueries array
/// If a row cell on column n has the same value as a a different row on column n, then the row will be compared on column n+1
/// \param[in] sortQueries A list of SortQuery structures, defining the sorts to perform on the table
/// \param[in] numColumnSubset The number of elements in \a numSortQueries
/// \param[out] out The address of an array of Rows, which will receive the sorted output. The array must be long enough to contain all returned rows, up to GetRowCount()
void SortTable(Table::SortQuery *sortQueries, unsigned numSortQueries, Table::Row** out);
/// Frees all memory in the table.
void Clear(void);
/// Prints out the names of all the columns
/// \param[out] out A pointer to an array of bytes which will hold the output.
/// \param[in] outLength The size of the \a out array
/// \param[in] columnDelineator What character to print to delineate columns
void PrintColumnHeaders(char *out, int outLength, char columnDelineator) const;
/// Writes a text representation of the row to \a out
/// \param[out] out A pointer to an array of bytes which will hold the output.
/// \param[in] outLength The size of the \a out array
/// \param[in] columnDelineator What character to print to delineate columns
/// \param[in] printDelineatorForBinary Binary output is not printed. True to still print the delineator.
/// \param[in] inputRow The row to print
void PrintRow(char *out, int outLength, char columnDelineator, bool printDelineatorForBinary, Table::Row* inputRow) const;
/// Direct access to make things easier
DataStructures::List<ColumnDescriptor>& GetColumns(void);
/// Direct access to make things easier
DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER>& GetRows(void);
/// Get the head of a linked list containing all the row data
DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> * GetListHead(void);
/// Get the first free row id.
/// This could be made more efficient.
unsigned GetAvailableRowId(void) const;
protected:
Table::Row* AddRowColumns(unsigned rowId, Row *row, DataStructures::List<unsigned> columnIndices);
void DeleteRow(Row *row);
void QueryRow(DataStructures::List<unsigned> &inclusionFilterColumnIndices, DataStructures::List<unsigned> &columnIndicesToReturn, unsigned key, Table::Row* row, FilterQuery *inclusionFilters, Table *result);
// 16 is arbitrary and is the order of the BPlus tree. Higher orders are better for searching while lower orders are better for
// Insertions and deletions.
DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER> rows;
// Columns in the table.
DataStructures::List<ColumnDescriptor> columns;
};
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif

98
thirdparty/raknet/Source/DS_Tree.h vendored Normal file
View File

@@ -0,0 +1,98 @@
/// \file
/// \brief \b [Internal] Just a regular tree
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __DS_TREE_H
#define __DS_TREE_H
#include "Export.h"
#include "DS_List.h"
#include "DS_Queue.h"
#include "RakMemoryOverride.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
template <class TreeType>
class RAK_DLL_EXPORT Tree : public RakNet::RakMemoryOverride
{
public:
Tree();
Tree(TreeType &inputData);
~Tree();
void LevelOrderTraversal(DataStructures::List<Tree*> &output);
void AddChild(TreeType &newData);
void DeleteDecendants(void);
TreeType data;
DataStructures::List<Tree *> children;
};
template <class TreeType>
Tree<TreeType>::Tree()
{
}
template <class TreeType>
Tree<TreeType>::Tree(TreeType &inputData)
{
data=inputData;
}
template <class TreeType>
Tree<TreeType>::~Tree()
{
}
template <class TreeType>
void Tree<TreeType>::LevelOrderTraversal(DataStructures::List<Tree*> &output)
{
unsigned i;
Tree<TreeType> *node;
DataStructures::Queue<Tree<TreeType>*> queue;
for (i=0; i < children.Size(); i++)
queue.Push(children[i]);
while (queue.Size())
{
node=queue.Pop();
output.Insert(node);
for (i=0; i < node->children.Size(); i++)
queue.Push(node->children[i]);
}
}
template <class TreeType>
void Tree<TreeType>::AddChild(TreeType &newData)
{
children.Insert(new Tree(newData));
}
template <class TreeType>
void Tree<TreeType>::DeleteDecendants(void)
{
DataStructures::List<Tree*> output;
LevelOrderTraversal(output);
unsigned i;
for (i=0; i < output.Size(); i++)
delete output[i];
}
}
#endif

View File

@@ -0,0 +1,544 @@
/// \file
/// \brief \b [Internal] Weighted graph. I'm assuming the indices are complex map types, rather than sequential numbers (which could be implemented much more efficiently).
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __WEIGHTED_GRAPH_H
#define __WEIGHTED_GRAPH_H
#include "DS_OrderedList.h"
#include "DS_Map.h"
#include "DS_Heap.h"
#include "DS_Queue.h"
#include "DS_Tree.h"
#include <assert.h>
#include "RakMemoryOverride.h"
#ifdef _DEBUG
#include <stdio.h>
#endif
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
template <class node_type, class weight_type, bool allow_unlinkedNodes>
class RAK_DLL_EXPORT WeightedGraph : public RakNet::RakMemoryOverride
{
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 = new weight_type[costMatrixIndices.Size() * costMatrixIndices.Size()];
leastNodeArray = new node_type[costMatrixIndices.Size()];
memcpy(costMatrix, original_copy.costMatrix, costMatrixIndices.Size() * costMatrixIndices.Size() * sizeof(weight_type));
memcpy(leastNodeArray, original_copy.leastNodeArray, costMatrixIndices.Size() * sizeof(weight_type));
}
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
WeightedGraph<node_type, weight_type, allow_unlinkedNodes>& WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::operator=( const WeightedGraph& original_copy )
{
adjacencyLists=original_copy.adjacencyLists;
isValidPath=original_copy.isValidPath;
if (isValidPath)
{
rootNode=original_copy.rootNode;
costMatrixIndices=original_copy.costMatrixIndices;
costMatrix = new weight_type[costMatrixIndices.Size() * costMatrixIndices.Size()];
leastNodeArray = new node_type[costMatrixIndices.Size()];
memcpy(costMatrix, original_copy.costMatrix, costMatrixIndices.Size() * costMatrixIndices.Size() * sizeof(weight_type));
memcpy(leastNodeArray, original_copy.leastNodeArray, costMatrixIndices.Size() * sizeof(weight_type));
}
return *this;
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::AddNode(const node_type &node)
{
adjacencyLists.SetNew(node, new DataStructures::Map<node_type, weight_type>);
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::RemoveNode(const node_type &node)
{
unsigned i;
DataStructures::Queue<node_type> removeNodeQueue;
removeNodeQueue.Push(node);
while (removeNodeQueue.Size())
{
delete adjacencyLists.Pop(removeNodeQueue.Pop());
// Remove this node from all of the other lists as well
for (i=0; i < adjacencyLists.Size(); i++)
{
adjacencyLists[i]->Delete(node);
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
if (allow_unlinkedNodes==false && adjacencyLists[i]->Size()==0)
removeNodeQueue.Push(adjacencyLists.GetKeyAtIndex(i));
}
}
ClearDijkstra();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
bool WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::HasConnection(const node_type &node1, const node_type &node2)
{
if (node1==node2)
return false;
if (adjacencyLists.Has(node1)==false)
return false;
return adjacencyLists.Get(node1)->Has(node2);
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::AddConnection(const node_type &node1, const node_type &node2, weight_type weight)
{
if (node1==node2)
return;
if (adjacencyLists.Has(node1)==false)
AddNode(node1);
adjacencyLists.Get(node1)->Set(node2, weight);
if (adjacencyLists.Has(node2)==false)
AddNode(node2);
adjacencyLists.Get(node2)->Set(node1, weight);
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::RemoveConnection(const node_type &node1, const node_type &node2)
{
adjacencyLists.Get(node2)->Delete(node1);
adjacencyLists.Get(node1)->Delete(node2);
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
if (allow_unlinkedNodes==false) // If we do not allow _unlinked nodes, then if there are no connections, remove the node
{
if (adjacencyLists.Get(node1)->Size()==0)
RemoveNode(node1); // Will also remove node1 from the adjacency list of node2
if (adjacencyLists.Has(node2) && adjacencyLists.Get(node2)->Size()==0)
RemoveNode(node2);
}
ClearDijkstra();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::Clear(void)
{
unsigned i;
for (i=0; i < adjacencyLists.Size(); i++)
delete adjacencyLists[i];
adjacencyLists.Clear();
ClearDijkstra();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
bool WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetShortestPath(DataStructures::List<node_type> &path, node_type startNode, node_type endNode, weight_type INFINITE_WEIGHT)
{
path.Clear();
if (startNode==endNode)
{
path.Insert(startNode);
path.Insert(endNode);
return true;
}
if (isValidPath==false || rootNode!=startNode)
{
ClearDijkstra();
GenerateDisjktraMatrix(startNode, INFINITE_WEIGHT);
}
// return the results
bool objectExists;
unsigned col,row;
weight_type currentWeight;
DataStructures::Queue<node_type> outputQueue;
col=costMatrixIndices.GetIndexFromKey(endNode, &objectExists);
if (costMatrixIndices.Size()<2)
{
return false;
}
if (objectExists==false)
{
return false;
}
node_type vertex;
row=costMatrixIndices.Size()-2;
if (row==0)
{
path.Insert(startNode);
path.Insert(endNode);
return true;
}
currentWeight=costMatrix[row*adjacencyLists.Size() + col];
if (currentWeight==INFINITE_WEIGHT)
{
// No path
return true;
}
vertex=endNode;
outputQueue.PushAtHead(vertex);
row--;
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while (1)
{
while (costMatrix[row*adjacencyLists.Size() + col] == currentWeight)
{
if (row==0)
{
path.Insert(startNode);
for (col=0; outputQueue.Size(); col++)
path.Insert(outputQueue.Pop());
return true;
}
--row;
}
vertex=leastNodeArray[row];
outputQueue.PushAtHead(vertex);
if (row==0)
break;
col=costMatrixIndices.GetIndexFromKey(vertex, &objectExists);
currentWeight=costMatrix[row*adjacencyLists.Size() + col];
}
path.Insert(startNode);
for (col=0; outputQueue.Size(); col++)
path.Insert(outputQueue.Pop());
return true;
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
node_type WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetNodeAtIndex(unsigned nodeIndex) const
{
return adjacencyLists.GetKeyAtIndex(nodeIndex);
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
unsigned WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetNodeCount(void) const
{
return adjacencyLists.Size();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
unsigned WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetConnectionCount(unsigned nodeIndex) const
{
return adjacencyLists[nodeIndex]->Size();
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetConnectionAtIndex(unsigned nodeIndex, unsigned connectionIndex, node_type &outNode, weight_type &outWeight) const
{
outWeight=adjacencyLists[nodeIndex]->operator[](connectionIndex);
outNode=adjacencyLists[nodeIndex]->GetKeyAtIndex(connectionIndex);
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
bool WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GetSpanningTree(DataStructures::Tree<node_type> &outTree, DataStructures::List<node_type> *inputNodes, node_type startNode, weight_type INFINITE_WEIGHT )
{
// Find the shortest path from the start node to each of the input nodes. Add this path to a new WeightedGraph if the result is reachable
DataStructures::List<node_type> path;
DataStructures::WeightedGraph<node_type, weight_type, allow_unlinkedNodes> outGraph;
bool res;
unsigned i,j;
for (i=0; i < inputNodes->Size(); i++)
{
res=GetShortestPath(path, startNode, (*inputNodes)[i], INFINITE_WEIGHT);
if (res)
{
for (j=0; j < path.Size()-1; j++)
{
// Don't bother looking up the weight
outGraph.AddConnection(path[j], path[j+1], INFINITE_WEIGHT);
}
}
}
// Copy the graph to a tree.
DataStructures::Queue<NodeAndParent> nodesToProcess;
DataStructures::Tree<node_type> *current;
DataStructures::Map<node_type, weight_type> *adjacencyList;
node_type key;
NodeAndParent nap, nap2;
outTree.DeleteDecendants();
outTree.data=startNode;
current=&outTree;
if (outGraph.adjacencyLists.Has(startNode)==false)
return false;
adjacencyList = outGraph.adjacencyLists.Get(startNode);
for (i=0; i < adjacencyList->Size(); i++)
{
nap2.node=new DataStructures::Tree<node_type>;
nap2.node->data=adjacencyList->GetKeyAtIndex(i);
nap2.parent=current;
nodesToProcess.Push(nap2);
current->children.Insert(nap2.node);
}
while (nodesToProcess.Size())
{
nap=nodesToProcess.Pop();
current=nap.node;
adjacencyList = outGraph.adjacencyLists.Get(nap.node->data);
for (i=0; i < adjacencyList->Size(); i++)
{
key=adjacencyList->GetKeyAtIndex(i);
if (key!=nap.parent->data)
{
nap2.node=new DataStructures::Tree<node_type>;
nap2.node->data=key;
nap2.parent=current;
nodesToProcess.Push(nap2);
current->children.Insert(nap2.node);
}
}
}
return true;
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::GenerateDisjktraMatrix(node_type startNode, weight_type INFINITE_WEIGHT)
{
if (adjacencyLists.Size()==0)
return;
costMatrix = new weight_type[adjacencyLists.Size() * adjacencyLists.Size()];
leastNodeArray = new node_type[adjacencyLists.Size()];
node_type currentNode;
unsigned col, row, row2, openSetIndex;
node_type adjacentKey;
unsigned adjacentIndex;
weight_type edgeWeight, currentNodeWeight, adjacentNodeWeight;
DataStructures::Map<node_type, weight_type> *adjacencyList;
DataStructures::Heap<weight_type, node_type, false> minHeap;
DataStructures::Map<node_type, weight_type> openSet;
for (col=0; col < adjacencyLists.Size(); col++)
{
// This should be already sorted, so it's a bit inefficient to do an insertion sort, but what the heck
costMatrixIndices.Insert(adjacencyLists.GetKeyAtIndex(col),adjacencyLists.GetKeyAtIndex(col), true);
}
for (col=0; col < adjacencyLists.Size() * adjacencyLists.Size(); col++)
costMatrix[col]=INFINITE_WEIGHT;
currentNode=startNode;
row=0;
currentNodeWeight=0;
rootNode=startNode;
// Clear the starting node column
if (adjacencyLists.Size())
{
adjacentIndex=adjacencyLists.GetIndexAtKey(startNode);
for (row2=0; row2 < adjacencyLists.Size(); row2++)
costMatrix[row2*adjacencyLists.Size() + adjacentIndex]=0;
}
while (row < adjacencyLists.Size()-1)
{
adjacencyList = adjacencyLists.Get(currentNode);
// Go through all connections from the current node. If the new weight is less than the current weight, then update that weight.
for (col=0; col < adjacencyList->Size(); col++)
{
edgeWeight=(*adjacencyList)[col];
adjacentKey=adjacencyList->GetKeyAtIndex(col);
adjacentIndex=adjacencyLists.GetIndexAtKey(adjacentKey);
adjacentNodeWeight=costMatrix[row*adjacencyLists.Size() + adjacentIndex];
if (currentNodeWeight + edgeWeight < adjacentNodeWeight)
{
// Update the weight for the adjacent node
for (row2=row; row2 < adjacencyLists.Size(); row2++)
costMatrix[row2*adjacencyLists.Size() + adjacentIndex]=currentNodeWeight + edgeWeight;
openSet.Set(adjacentKey, currentNodeWeight + edgeWeight);
}
}
// Find the lowest in the open set
minHeap.Clear();
for (openSetIndex=0; openSetIndex < openSet.Size(); openSetIndex++)
minHeap.Push(openSet[openSetIndex], openSet.GetKeyAtIndex(openSetIndex));
/*
unsigned i,j;
for (i=0; i < adjacencyLists.Size()-1; i++)
{
for (j=0; j < adjacencyLists.Size(); j++)
{
printf("%2i ", costMatrix[i*adjacencyLists.Size() + j]);
}
printf("Node=%i", leastNodeArray[i]);
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++)
{
printf("%2i ", costMatrix[i*adjacencyLists.Size() + j]);
}
printf("Node=%i", leastNodeArray[i]);
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;
delete [] costMatrix;
delete [] leastNodeArray;
costMatrixIndices.Clear();
}
}
template <class node_type, class weight_type, bool allow_unlinkedNodes>
void WeightedGraph<node_type, weight_type, allow_unlinkedNodes>::Print(void)
{
#ifdef _DEBUG
unsigned i,j;
for (i=0; i < adjacencyLists.Size(); i++)
{
//printf("%i connected to ", i);
printf("%s connected to ", adjacencyLists.GetKeyAtIndex(i).systemAddress.ToString());
if (adjacencyLists[i]->Size()==0)
printf("<Empty>");
else
{
for (j=0; j < adjacencyLists[i]->Size(); j++)
// printf("%i (%.2f) ", adjacencyLists.GetIndexAtKey(adjacencyLists[i]->GetKeyAtIndex(j)), (float) adjacencyLists[i]->operator[](j) );
printf("%s (%.2f) ", adjacencyLists[i]->GetKeyAtIndex(j).systemAddress.ToString(), (float) adjacencyLists[i]->operator[](j) );
}
printf("\n");
}
#endif
}
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif

View File

@@ -0,0 +1,206 @@
/// \file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#include "DataBlockEncryptor.h"
#include "CheckSum.h"
#include "GetTime.h"
#include "Rand.h"
#include <assert.h>
#include <string.h>
#include "Rijndael.h"
#include "Types.h"
DataBlockEncryptor::DataBlockEncryptor()
{
keySet = false;
}
DataBlockEncryptor::~DataBlockEncryptor()
{}
bool DataBlockEncryptor::IsKeySet( void ) const
{
return keySet;
}
void DataBlockEncryptor::SetKey( const unsigned char key[ 16 ] )
{
keySet = true;
//secretKeyAES128.set_key( key );
makeKey(&keyEncrypt, DIR_ENCRYPT, 16, (char*)key);
makeKey(&keyDecrypt, DIR_DECRYPT, 16, (char*)key);
cipherInit(&cipherInst, MODE_ECB, 0); // ECB is not secure except that I chain manually farther down.
}
void DataBlockEncryptor::UnsetKey( void )
{
keySet = false;
}
void DataBlockEncryptor::Encrypt( unsigned char *input, unsigned int inputLength, unsigned char *output, unsigned int *outputLength )
{
unsigned index, byteIndex, lastBlock;
unsigned int checkSum;
unsigned char paddingBytes;
unsigned char encodedPad;
unsigned char randomChar;
CheckSum checkSumCalculator;
#ifdef _DEBUG
assert( keySet );
#endif
assert( input && inputLength );
// randomChar will randomize the data so the same data sent twice will not look the same
randomChar = (unsigned char) randomMT();
// 16-(((x-1) % 16)+1)
// # of padding bytes is 16 -(((input_length + extra_data -1) % 16)+1)
paddingBytes = (unsigned char) ( 16 - ( ( ( inputLength + sizeof( randomChar ) + sizeof( checkSum ) + sizeof( encodedPad ) - 1 ) % 16 ) + 1 ) );
// Randomize the pad size variable
encodedPad = (unsigned char) randomMT();
encodedPad <<= 4;
encodedPad |= paddingBytes;
*outputLength = inputLength + sizeof( randomChar ) + sizeof( checkSum ) + sizeof( encodedPad ) + paddingBytes;
// Write the data first, in case we are overwriting ourselves
if ( input == output )
memmove( output + sizeof( checkSum ) + sizeof( randomChar ) + sizeof( encodedPad ) + paddingBytes, input, inputLength );
else
memcpy( output + sizeof( checkSum ) + sizeof( randomChar ) + sizeof( encodedPad ) + paddingBytes, input, inputLength );
// Write the random char
memcpy( output + sizeof( checkSum ), ( char* ) & randomChar, sizeof( randomChar ) );
// Write the pad size variable
memcpy( output + sizeof( checkSum ) + sizeof( randomChar ), ( char* ) & encodedPad, sizeof( encodedPad ) );
// Write the padding
for ( index = 0; index < paddingBytes; index++ )
*( output + sizeof( checkSum ) + sizeof( randomChar ) + sizeof( encodedPad ) + index ) = (unsigned char) randomMT();
// Calculate the checksum on the data
checkSumCalculator.Add( output + sizeof( checkSum ), inputLength + sizeof( randomChar ) + sizeof( encodedPad ) + paddingBytes );
checkSum = checkSumCalculator.Get();
// Write checksum
#ifdef HOST_ENDIAN_IS_BIG
output[0] = checkSum&0xFF;
output[1] = (checkSum>>8)&0xFF;
output[2] = (checkSum>>16)&0xFF;
output[3] = (checkSum>>24)&0xFF;
#else
memcpy( output, ( char* ) & checkSum, sizeof( checkSum ) );
#endif
// AES on the first block
// secretKeyAES128.encrypt16( output );
blockEncrypt(&cipherInst, &keyEncrypt, output, 16, output);
lastBlock = 0;
// Now do AES on every other block from back to front
for ( index = *outputLength - 16; index >= 16; index -= 16 )
{
for ( byteIndex = 0; byteIndex < 16; byteIndex++ )
output[ index + byteIndex ] ^= output[ lastBlock + byteIndex ];
//secretKeyAES128.encrypt16( output + index );
blockEncrypt(&cipherInst, &keyEncrypt, output+index, 16, output+index);
lastBlock = index;
}
}
bool DataBlockEncryptor::Decrypt( unsigned char *input, unsigned int inputLength, unsigned char *output, unsigned int *outputLength )
{
unsigned index, byteIndex, lastBlock;
unsigned int checkSum;
unsigned char paddingBytes;
unsigned char encodedPad;
unsigned char randomChar;
CheckSum checkSumCalculator;
#ifdef _DEBUG
assert( keySet );
#endif
if ( input == 0 || inputLength < 16 || ( inputLength % 16 ) != 0 )
{
return false;
}
// Unchain in reverse order
for ( index = 16; index <= inputLength - 16;index += 16 )
{
// secretKeyAES128.decrypt16( input + index );
blockDecrypt(&cipherInst, &keyDecrypt, input + index, 16, output + index);
for ( byteIndex = 0; byteIndex < 16; byteIndex++ )
{
if ( index + 16 == ( unsigned ) inputLength )
output[ index + byteIndex ] ^= input[ byteIndex ];
else
output[ index + byteIndex ] ^= input[ index + 16 + byteIndex ];
}
lastBlock = index;
};
// Decrypt the first block
//secretKeyAES128.decrypt16( input );
blockDecrypt(&cipherInst, &keyDecrypt, input, 16, output);
// Read checksum
#ifdef HOST_ENDIAN_IS_BIG
checkSum = (unsigned int)output[0] | (unsigned int)(output[1]<<8) |
(unsigned int)(output[2]<<16)|(unsigned int)(output[3]<<24);
#else
memcpy( ( char* ) & checkSum, output, sizeof( checkSum ) );
#endif
// Read the pad size variable
memcpy( ( char* ) & encodedPad, output + sizeof( randomChar ) + sizeof( checkSum ), sizeof( encodedPad ) );
// Ignore the high 4 bytes
paddingBytes = encodedPad & 0x0F;
// Get the data length
*outputLength = inputLength - sizeof( randomChar ) - sizeof( checkSum ) - sizeof( encodedPad ) - paddingBytes;
// Calculate the checksum on the data.
checkSumCalculator.Add( output + sizeof( checkSum ), *outputLength + sizeof( randomChar ) + sizeof( encodedPad ) + paddingBytes );
if ( checkSum != checkSumCalculator.Get() )
return false;
// Read the data
//if ( input == output )
memmove( output, output + sizeof( randomChar ) + sizeof( checkSum ) + sizeof( encodedPad ) + paddingBytes, *outputLength );
//else
// memcpy( output, input + sizeof( randomChar ) + sizeof( checkSum ) + sizeof( encodedPad ) + paddingBytes, *outputLength );
return true;
}

View File

@@ -0,0 +1,71 @@
/// \file
/// \brief \b [Internal] Encrypts and decrypts data blocks. Used as part of secure connections.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __DATA_BLOCK_ENCRYPTOR_H
#define __DATA_BLOCK_ENCRYPTOR_H
#include "Rijndael.h"
#include "RakMemoryOverride.h"
/// Encrypts and decrypts data blocks.
class DataBlockEncryptor : public RakNet::RakMemoryOverride
{
public:
/// Constructor
DataBlockEncryptor();
/// Destructor
~DataBlockEncryptor();
/// \return true if SetKey has been called previously
bool IsKeySet( void ) const;
/// Set the encryption key
/// \param[in] key The new encryption key
void SetKey( const unsigned char key[ 16 ] );
/// Unset the encryption key
void UnsetKey( void );
/// Encryption adds 6 data bytes and then pads the number of bytes to be a multiple of 16. Output should be large enough to hold this.
/// Output can be the same memory block as input
/// \param[in] input the input buffer to encrypt
/// \param[in] inputLength the size of the @em input buffer
/// \param[in] output the output buffer to store encrypted data
/// \param[in] outputLength the size of the output buffer
void Encrypt( unsigned char *input, unsigned int inputLength, unsigned char *output, unsigned int *outputLength );
/// Decryption removes bytes, as few as 6. Output should be large enough to hold this.
/// Output can be the same memory block as input
/// \param[in] input the input buffer to decrypt
/// \param[in] inputLength the size of the @em input buffer
/// \param[in] output the output buffer to store decrypted data
/// \param[in] outputLength the size of the @em output buffer
/// \return False on bad checksum or input, true on success
bool Decrypt( unsigned char *input, unsigned int inputLength, unsigned char *output, unsigned int *outputLength );
protected:
keyInstance keyEncrypt;
keyInstance keyDecrypt;
cipherInstance cipherInst;
bool keySet;
};
#endif

View File

@@ -0,0 +1,58 @@
#include "DataCompressor.h"
#include "DS_HuffmanEncodingTree.h"
#include <assert.h>
#include <string.h> // Use string.h rather than memory.h for a console
void DataCompressor::Compress( unsigned char *userData, unsigned sizeInBytes, RakNet::BitStream * output )
{
// Don't use this for small files as you will just make them bigger!
assert(sizeInBytes > 2048);
unsigned int frequencyTable[ 256 ];
unsigned int i;
memset(frequencyTable,0,256*sizeof(unsigned int));
for (i=0; i < sizeInBytes; i++)
++frequencyTable[userData[i]];
HuffmanEncodingTree tree;
BitSize_t writeOffset1, writeOffset2, bitsUsed1, bitsUsed2;
tree.GenerateFromFrequencyTable(frequencyTable);
output->WriteCompressed(sizeInBytes);
for (i=0; i < 256; i++)
output->WriteCompressed(frequencyTable[i]);
output->AlignWriteToByteBoundary();
writeOffset1=output->GetWriteOffset();
output->Write((unsigned int)0); // Dummy value
bitsUsed1=output->GetNumberOfBitsUsed();
tree.EncodeArray(userData, sizeInBytes, output);
bitsUsed2=output->GetNumberOfBitsUsed();
writeOffset2=output->GetWriteOffset();
output->SetWriteOffset(writeOffset1);
output->Write(bitsUsed2-bitsUsed1); // Go back and write how many bits were used for the encoding
output->SetWriteOffset(writeOffset2);
}
unsigned DataCompressor::DecompressAndAllocate( RakNet::BitStream * input, unsigned char **output )
{
HuffmanEncodingTree tree;
unsigned int bitsUsed, destinationSizeInBytes, decompressedBytes;
unsigned int frequencyTable[ 256 ];
unsigned i;
input->ReadCompressed(destinationSizeInBytes);
for (i=0; i < 256; i++)
input->ReadCompressed(frequencyTable[i]);
input->AlignReadToByteBoundary();
if (input->Read(bitsUsed)==false)
{
// Read error
#ifdef _DEBUG
assert(0);
#endif
return 0;
}
*output = (unsigned char*) rakMalloc(destinationSizeInBytes);
tree.GenerateFromFrequencyTable(frequencyTable);
decompressedBytes=tree.DecodeArray(input, bitsUsed, destinationSizeInBytes, *output );
assert(decompressedBytes==destinationSizeInBytes);
return destinationSizeInBytes;
}

View File

@@ -0,0 +1,34 @@
/// \file
/// \brief DataCompressor does compression on a block of data. Not very good compression, but it's small and fast so is something you can use per-message at runtime.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __DATA_COMPRESSOR_H
#define __DATA_COMPRESSOR_H
#include "RakMemoryOverride.h"
#include "DS_HuffmanEncodingTree.h"
#include "Export.h"
/// \brief Does compression on a block of data. Not very good compression, but it's small and fast so is something you can compute at runtime.
class RAK_DLL_EXPORT DataCompressor : public RakNet::RakMemoryOverride
{
public:
static void Compress( unsigned char *userData, unsigned sizeInBytes, RakNet::BitStream * output );
static unsigned DecompressAndAllocate( RakNet::BitStream * input, unsigned char **output );
};
#endif

View File

@@ -0,0 +1,216 @@
#include "DirectoryDeltaTransfer.h"
#include "FileList.h"
#include "StringCompressor.h"
#include "RakPeerInterface.h"
#include "FileListTransfer.h"
#include "FileListTransferCBInterface.h"
#include "BitStream.h"
#include "MessageIdentifiers.h"
#include "FileOperations.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
class DDTCallback : public FileListTransferCBInterface
{
public:
unsigned subdirLen;
char outputSubdir[512];
FileListTransferCBInterface *onFileCallback;
DDTCallback() {}
virtual ~DDTCallback() {}
virtual bool OnFile(OnFileStruct *onFileStruct)
{
char fullPathToDir[1024];
if (onFileStruct->fileName && onFileStruct->fileData && subdirLen < strlen(onFileStruct->fileName))
{
strcpy(fullPathToDir, outputSubdir);
strcat(fullPathToDir, onFileStruct->fileName+subdirLen);
WriteFileWithDirectories(fullPathToDir, (char*)onFileStruct->fileData, (unsigned int ) onFileStruct->finalDataLength);
}
else
fullPathToDir[0]=0;
return onFileCallback->OnFile(onFileStruct);
}
virtual void OnFileProgress(OnFileStruct *onFileStruct,unsigned int partCount,unsigned int partTotal,unsigned int partLength, char *firstDataChunk)
{
char fullPathToDir[1024];
if (onFileStruct->fileName && subdirLen < strlen(onFileStruct->fileName))
{
strcpy(fullPathToDir, outputSubdir);
strcat(fullPathToDir, onFileStruct->fileName+subdirLen);
}
else
fullPathToDir[0]=0;
onFileCallback->OnFileProgress(onFileStruct, partCount, partTotal, partLength, firstDataChunk);
}
virtual bool OnDownloadComplete(void)
{
return onFileCallback->OnDownloadComplete();
}
};
DirectoryDeltaTransfer::DirectoryDeltaTransfer()
{
applicationDirectory[0]=0;
fileListTransfer=0;
availableUploads = new FileList;
rakPeer=0;
priority=HIGH_PRIORITY;
orderingChannel=0;
compressOutgoingSends=false;
}
DirectoryDeltaTransfer::~DirectoryDeltaTransfer()
{
delete availableUploads;
}
void DirectoryDeltaTransfer::SetFileListTransferPlugin(FileListTransfer *flt)
{
fileListTransfer=flt;
if (flt)
availableUploads->SetCallback(flt->GetCallback());
else
availableUploads->SetCallback(0);
}
void DirectoryDeltaTransfer::SetApplicationDirectory(const char *pathToApplication)
{
if (pathToApplication==0 || pathToApplication[0]==0)
applicationDirectory[0]=0;
else
{
strncpy(applicationDirectory, pathToApplication, 510);
if (applicationDirectory[strlen(applicationDirectory)-1]!='/' && applicationDirectory[strlen(applicationDirectory)-1]!='\\')
strcat(applicationDirectory, "/");
applicationDirectory[511]=0;
}
}
void DirectoryDeltaTransfer::SetUploadSendParameters(PacketPriority _priority, char _orderingChannel)
{
priority=_priority;
orderingChannel=_orderingChannel;
}
void DirectoryDeltaTransfer::AddUploadsFromSubdirectory(const char *subdir)
{
availableUploads->AddFilesFromDirectory(applicationDirectory, subdir, true, false, true, 0);
}
unsigned short DirectoryDeltaTransfer::DownloadFromSubdirectory(const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb)
{
if (rakPeer->IsConnected(host)==false)
return (unsigned short) -1;
DDTCallback *transferCallback;
FileList localFiles;
localFiles.SetCallback(cb);
// Get a hash of all the files that we already have (if any)
localFiles.AddFilesFromDirectory(prependAppDirToOutputSubdir ? applicationDirectory : 0, outputSubdir, true, false, true, 0);
// Prepare the callback data
transferCallback = new DDTCallback;
if (subdir && subdir[0])
{
transferCallback->subdirLen=(unsigned int)strlen(subdir);
if (subdir[transferCallback->subdirLen-1]!='/' && subdir[transferCallback->subdirLen-1]!='\\')
transferCallback->subdirLen++;
}
else
transferCallback->subdirLen=0;
if (prependAppDirToOutputSubdir)
strcpy(transferCallback->outputSubdir, applicationDirectory);
else
transferCallback->outputSubdir[0]=0;
if (outputSubdir)
strcat(transferCallback->outputSubdir, outputSubdir);
if (transferCallback->outputSubdir[strlen(transferCallback->outputSubdir)-1]!='/' && transferCallback->outputSubdir[strlen(transferCallback->outputSubdir)-1]!='\\')
strcat(transferCallback->outputSubdir, "/");
transferCallback->onFileCallback=onFileCallback;
// Setup the transfer plugin to get the response to this download request
unsigned short setId = fileListTransfer->SetupReceive(transferCallback, true, host);
// Send to the host, telling it to process this request
RakNet::BitStream outBitstream;
outBitstream.Write((MessageID)ID_DDT_DOWNLOAD_REQUEST);
outBitstream.Write(setId);
stringCompressor->EncodeString(subdir, 256, &outBitstream);
stringCompressor->EncodeString(outputSubdir, 256, &outBitstream);
localFiles.Serialize(&outBitstream);
rakPeer->Send(&outBitstream, _priority, RELIABLE_ORDERED, _orderingChannel, host, false);
return setId;
}
void DirectoryDeltaTransfer::ClearUploads(void)
{
availableUploads->Clear();
}
void DirectoryDeltaTransfer::OnDownloadRequest(RakPeerInterface *peer, Packet *packet)
{
(void) peer;
char subdir[256];
char remoteSubdir[256];
RakNet::BitStream inBitstream(packet->data, packet->length, false);
FileList remoteFileHash;
FileList delta;
unsigned short setId;
inBitstream.IgnoreBits(8);
inBitstream.Read(setId);
stringCompressor->DecodeString(subdir, 256, &inBitstream);
stringCompressor->DecodeString(remoteSubdir, 256, &inBitstream);
if (remoteFileHash.Deserialize(&inBitstream)==false)
{
#ifdef _DEBUG
assert(0);
#endif
return;
}
availableUploads->GetDeltaToCurrent(&remoteFileHash, &delta, subdir, remoteSubdir);
delta.PopulateDataFromDisk(applicationDirectory, true, false, true);
// This will call the ddtCallback interface that was passed to FileListTransfer::SetupReceive on the remote system
fileListTransfer->Send(&delta, rakPeer, packet->systemAddress, setId, priority, orderingChannel, compressOutgoingSends);
}
void DirectoryDeltaTransfer::OnAttach(RakPeerInterface *peer)
{
rakPeer=peer;
}
void DirectoryDeltaTransfer::Update(RakPeerInterface *peer)
{
(void) peer;
}
PluginReceiveResult DirectoryDeltaTransfer::OnReceive(RakPeerInterface *peer, Packet *packet)
{
switch (packet->data[0])
{
case ID_DDT_DOWNLOAD_REQUEST:
OnDownloadRequest(peer, packet);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
return RR_CONTINUE_PROCESSING;
}
void DirectoryDeltaTransfer::OnShutdown(RakPeerInterface *peer)
{
(void) peer;
}
unsigned DirectoryDeltaTransfer::GetNumberOfFilesForUpload(void) const
{
return availableUploads->fileList.Size();
}
void DirectoryDeltaTransfer::SetCompressOutgoingSends(bool compress)
{
compressOutgoingSends=compress;
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@@ -0,0 +1,134 @@
/// \file
/// \brief Simple class to send changes between directories. In essence, a simple autopatcher that can be used for transmitting levels, skins, etc.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __DIRECTORY_DELTA_TRANSFER_H
#define __DIRECTORY_DELTA_TRANSFER_H
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#include "Export.h"
#include "PluginInterface.h"
#include "DS_Map.h"
#include "PacketPriority.h"
class RakPeerInterface;
class FileList;
struct Packet;
struct InternalPacket;
struct DownloadRequest;
class FileListTransfer;
class FileListTransferCBInterface;
class FileListProgress;
/// \defgroup DIRECTORY_DELTA_TRANSFER_GROUP DirectoryDeltaTransfer
/// \ingroup PLUGINS_GROUP
/// \brief Simple class to send changes between directories. In essence, a simple autopatcher that can be used for transmitting levels, skins, etc.
/// \sa Autopatcher class for database driven patching, including binary deltas and search by date.
///
/// To use, first set the path to your application. For example "C:/Games/MyRPG/"
/// To allow other systems to download files, call AddUploadsFromSubdirectory, where the parameter is a path relative
/// to the path to your application. This includes subdirectories.
/// For example:
/// SetApplicationDirectory("C:/Games/MyRPG/");
/// AddUploadsFromSubdirectory("Mods/Skins/");
/// would allow downloads from
/// "C:/Games/MyRPG/Mods/Skins/*.*" as well as "C:/Games/MyRPG/Mods/Skins/Level1/*.*"
/// It would NOT allow downloads from C:/Games/MyRPG/Levels, nor would it allow downloads from C:/Windows
/// While pathToApplication can be anything you want, applicationSubdirectory must match either partially or fully between systems.
/// \ingroup DIRECTORY_DELTA_TRANSFER_GROUP
class RAK_DLL_EXPORT DirectoryDeltaTransfer : public PluginInterface
{
public:
/// Constructor
DirectoryDeltaTransfer();
/// Destructor
virtual ~DirectoryDeltaTransfer();
/// This plugin has a dependency on the FileListTransfer plugin, which it uses to actually send the files.
/// So you need an instance of that plugin registered with RakPeerInterface, and a pointer to that interface should be passed here.
/// \param[in] flt A pointer to a registered instance of FileListTransfer
void SetFileListTransferPlugin(FileListTransfer *flt);
/// Set the local root directory to base all file uploads and downloads off of.
/// \param[in] pathToApplication This path will be prepended to \a applicationSubdirectory in AddUploadsFromSubdirectory to find the actual path on disk.
void SetApplicationDirectory(const char *pathToApplication);
/// What parameters to use for the RakPeerInterface::Send() call when uploading files.
/// \param[in] _priority See RakPeerInterface::Send()
/// \param[in] _orderingChannel See RakPeerInterface::Send()
void SetUploadSendParameters(PacketPriority _priority, char _orderingChannel);
/// Add all files in the specified subdirectory recursively
/// \a subdir is appended to \a pathToApplication in SetApplicationDirectory().
/// All files in the resultant directory and subdirectories are then hashed so that users can download them.
/// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin
/// \param[in] subdir Concatenated with pathToApplication to form the final path from which to allow uploads.
void AddUploadsFromSubdirectory(const char *subdir);
/// Downloads files from the matching parameter \a subdir in AddUploadsFromSubdirectory.
/// \a subdir must contain all starting characters in \a subdir in AddUploadsFromSubdirectory
/// Therefore,
/// AddUploadsFromSubdirectory("Levels/Level1/"); would allow you to download using DownloadFromSubdirectory("Levels/Level1/Textures/"...
/// but it would NOT allow you to download from DownloadFromSubdirectory("Levels/"... or DownloadFromSubdirectory("Levels/Level2/"...
/// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin
/// \param[in] subdir A directory passed to AddUploadsFromSubdirectory on the remote system. The passed dir can be more specific than the remote dir.
/// \param[in] outputSubdir The directory to write the output to. Usually this will match \a subdir but it can be different if you want.
/// \param[in] prependAppDirToOutputSubdir True to prepend outputSubdir with pathToApplication when determining the final output path. Usually you want this to be true.
/// \param[in] host The address of the remote system to send the message to.
/// \param[in] onFileCallback Callback to call per-file (optional). When fileIndex+1==setCount in the callback then the download is done
/// \param[in] _priority See RakPeerInterface::Send()
/// \param[in] _orderingChannel See RakPeerInterface::Send()
/// \param[in] cb Callback to get progress updates. Pass 0 to not use.
/// \return A set ID, identifying this download set. Returns 65535 on host unreachable.
unsigned short DownloadFromSubdirectory(const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb);
/// Clear all allowed uploads previously set with AddUploadsFromSubdirectory
void ClearUploads(void);
/// Returns how many files are available for upload
/// \return How many files are available for upload
unsigned GetNumberOfFilesForUpload(void) const;
/// Set if we should compress outgoing sends or not
/// Defaults to false, because this results in a noticeable freeze on large requests
/// You can set this to true if you only send small files though
/// \param[in] compress True to compress, false to not.
void SetCompressOutgoingSends(bool compress);
/// \internal For plugin handling
virtual void OnAttach(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void Update(RakPeerInterface *peer);
/// \internal For plugin handling
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// \internal For plugin handling
virtual void OnShutdown(RakPeerInterface *peer);
protected:
void OnDownloadRequest(RakPeerInterface *peer, Packet *packet);
char applicationDirectory[512];
FileListTransfer *fileListTransfer;
FileList *availableUploads;
RakPeerInterface *rakPeer;
PacketPriority priority;
char orderingChannel;
bool compressOutgoingSends;
};
#endif

409
thirdparty/raknet/Source/EmailSender.cpp vendored Normal file
View File

@@ -0,0 +1,409 @@
// Useful sites
// http://www.faqs.org\rfcs\rfc2821.html
// http://en.wikipedia.org/wiki/Base64
// http://www2.rad.com\networks/1995/mime/examples.htm
#include "EmailSender.h"
#include "TCPInterface.h"
#include "GetTime.h"
#include "Rand.h"
#include "FileList.h"
#include "BitStream.h"
#include <stdio.h>
#if defined(_XBOX360)
#include "Console1Includes.h"
#endif
#include "RakSleep.h"
static const char base64Map[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char *EmailSender::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)
{
Packet *packet;
char query[1024];
TCPInterface tcpInterface;
SystemAddress emailServer;
if (tcpInterface.Start(0, 0)==false)
return "Unknown error starting TCP";
emailServer=tcpInterface.Connect(hostAddress, hostPort,true);
if (emailServer==UNASSIGNED_SYSTEM_ADDRESS)
return "Failed to connect to host";
RakNetTime timeoutTime = RakNet::GetTime()+3000;
packet=0;
while (RakNet::GetTime() < timeoutTime)
{
packet = tcpInterface.Receive();
if (packet)
{
if (doPrintf)
printf("%s", packet->data);
break;
}
RakSleep(250);
}
if (packet==0)
return "Timeout while waiting for initial data from server.";
tcpInterface.Send("EHLO\r\n", 6, emailServer);
const char *response;
bool authenticate=false;
#ifdef _MSC_VER
#pragma warning(disable:4127) // conditional expression is constant
#endif
while (1)
{
response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0 && strcmp(response, "AUTHENTICATE")==0)
{
authenticate=true;
break;
}
// Something other than continue?
if (response!=0 && strcmp(response, "CONTINUE")!=0)
return response;
// Success?
if (response==0)
break;
}
if (authenticate)
{
sprintf(query, "EHLO %s\r\n", sender);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0)
return response;
if (password==0)
return "Password needed";
char *outputData = new char [(strlen(sender)+strlen(password)+2)*3];
RakNet::BitStream bs;
char zero=0;
bs.Write(&zero,1);
bs.Write(sender,(const unsigned int)strlen(sender));
//bs.Write("jms1@jms1.net",(const unsigned int)strlen("jms1@jms1.net"));
bs.Write(&zero,1);
bs.Write(password,(const unsigned int)strlen(password));
bs.Write(&zero,1);
//bs.Write("not.my.real.password",(const unsigned int)strlen("not.my.real.password"));
Base64Encoding((const char*)bs.GetData(), bs.GetNumberOfBytesUsed(), outputData, base64Map);
sprintf(query, "AUTH PLAIN %s", outputData);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0)
return response;
}
if (sender)
sprintf(query, "MAIL From: <%s>\r\n", sender);
else
sprintf(query, "MAIL From: <>\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
if (recipient)
sprintf(query, "RCPT TO: <%s>\r\n", recipient);
else
sprintf(query, "RCPT TO: <>\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0)
return response;
tcpInterface.Send("DATA\r\n", (unsigned int)strlen("DATA\r\n"), emailServer);
response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0)
return response;
if (subject)
{
sprintf(query, "Subject: %s\r\n", subject);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
}
if (senderName)
{
sprintf(query, "From: %s\r\n", senderName);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
}
if (recipientName)
{
sprintf(query, "To: %s\r\n", recipientName);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
}
const int boundarySize=60;
char boundary[boundarySize+1];
int i,j;
if (attachedFiles && attachedFiles->fileList.Size())
{
seedMT(RakNet::GetTime());
// Random multipart message boundary
for (i=0; i < boundarySize; i++)
boundary[i]=base64Map[randomMT()%64];
boundary[boundarySize]=0;
}
sprintf(query, "MIME-version: 1.0\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
if (attachedFiles && attachedFiles->fileList.Size())
{
sprintf(query, "Content-type: multipart/mixed; BOUNDARY=\"%s\"\r\n\r\n", boundary);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
sprintf(query, "This is a multi-part message in MIME format.\r\n\r\n--%s\r\n", boundary);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
}
sprintf(query, "Content-Type: text/plain; charset=\"US-ASCII\"\r\n\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
// Write the body of the email, doing some lame shitty shit where I have to make periods at the start of a newline have a second period.
char *newBody;
int bodyLength;
bodyLength=(int)strlen(body);
newBody = (char*) rakMalloc( bodyLength*3 );
if (bodyLength>0)
newBody[0]=body[0];
for (i=1, j=1; i < bodyLength; i++)
{
// Transform \n . \r \n into \n . . \r \n
if (i < bodyLength-2 &&
body[i-1]=='\n' &&
body[i+0]=='.' &&
body[i+1]=='\r' &&
body[i+2]=='\n')
{
newBody[j++]='.';
newBody[j++]='.';
newBody[j++]='\r';
newBody[j++]='\n';
i+=2;
}
// Transform \n . . \r \n into \n . . . \r \n
// Having to process .. is a bug in the mail server - the spec says ONLY \r\n.\r\n should be transformed
else if (i <= bodyLength-3 &&
body[i-1]=='\n' &&
body[i+0]=='.' &&
body[i+1]=='.' &&
body[i+2]=='\r' &&
body[i+3]=='\n')
{
newBody[j++]='.';
newBody[j++]='.';
newBody[j++]='.';
newBody[j++]='\r';
newBody[j++]='\n';
i+=3;
}
// Transform \n . \n into \n . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does)
else if (i < bodyLength-1 &&
body[i-1]=='\n' &&
body[i+0]=='.' &&
body[i+1]=='\n')
{
newBody[j++]='.';
newBody[j++]='.';
newBody[j++]='\r';
newBody[j++]='\n';
i+=1;
}
// Transform \n . . \n into \n . . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does)
// In fact having to process .. is a bug too - because the spec says ONLY \r\n.\r\n should be transformed
else if (i <= bodyLength-2 &&
body[i-1]=='\n' &&
body[i+0]=='.' &&
body[i+1]=='.' &&
body[i+2]=='\n')
{
newBody[j++]='.';
newBody[j++]='.';
newBody[j++]='.';
newBody[j++]='\r';
newBody[j++]='\n';
i+=2;
}
else
newBody[j++]=body[i];
}
newBody[j++]='\r';
newBody[j++]='\n';
tcpInterface.Send(newBody, j, emailServer);
rakFree(newBody);
int outputOffset;
// What a pain in the rear. I have to map the binary to printable characters using 6 bits per character.
if (attachedFiles && attachedFiles->fileList.Size())
{
for (i=0; i < (int) attachedFiles->fileList.Size(); i++)
{
// Write boundary
sprintf(query, "\r\n--%s\r\n", boundary);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
sprintf(query, "Content-Type: APPLICATION/Octet-Stream; SizeOnDisk=%i; name=\"%s\"\r\nContent-Transfer-Encoding: BASE64\r\nContent-Description: %s\r\n\r\n", attachedFiles->fileList[i].dataLengthBytes, attachedFiles->fileList[i].filename, attachedFiles->fileList[i].filename);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
newBody = (char*) rakMalloc( (size_t) (attachedFiles->fileList[i].dataLengthBytes*3)/2 );
outputOffset=Base64Encoding(attachedFiles->fileList[i].data, (int) attachedFiles->fileList[i].dataLengthBytes, newBody, base64Map);
// Send the base64 mapped file.
tcpInterface.Send(newBody, outputOffset, emailServer);
rakFree(newBody);
}
// Write last boundary
sprintf(query, "\r\n--%s--\r\n", boundary);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
}
sprintf(query, "\r\n.\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer);
response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0)
return response;
tcpInterface.Send("QUIT\r\n", (unsigned int)strlen("QUIT\r\n"), emailServer);
RakSleep(30);
if (doPrintf)
{
packet = tcpInterface.Receive();
while (packet)
{
printf("%s", packet->data);
packet = tcpInterface.Receive();
}
}
tcpInterface.Stop();
return 0; // Success
}
const char *EmailSender::GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf)
{
Packet *packet;
RakNetTime timeout;
timeout=RakNet::GetTime()+5000;
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while (1)
{
if (tcpInterface->HasLostConnection()==emailServer)
return "Connection to server lost.";
packet = tcpInterface->Receive();
if (packet)
{
if (doPrintf)
{
printf("%s", packet->data);
}
#if defined(OPEN_SSL_CLIENT_SUPPORT)
if (strstr((const char*)packet->data, "220"))
{
tcpInterface->StartSSLClient(packet->systemAddress);
return "AUTHENTICATE"; // OK
}
#endif
if (strstr((const char*)packet->data, "235"))
return 0; // Authentication accepted
if (strstr((const char*)packet->data, "354"))
return 0; // OK
#if defined(OPEN_SSL_CLIENT_SUPPORT)
if (strstr((const char*)packet->data, "250-STARTTLS"))
{
tcpInterface->Send("STARTTLS\r\n", (unsigned int) strlen("STARTTLS\r\n"), packet->systemAddress);
return "CONTINUE";
}
#endif
if (strstr((const char*)packet->data, "250"))
return 0; // OK
if (strstr((const char*)packet->data, "550"))
return "Failed on error code 550";
if (strstr((const char*)packet->data, "553"))
return "Failed on error code 553";
}
if (RakNet::GetTime() > timeout)
return "Timed out";
RakSleep(100);
}
}
int EmailSender::Base64Encoding(const char *inputData, int dataLength, char *outputData, const char *base64Map)
{
int outputOffset, charCount;
int write3Count;
outputOffset=0;
charCount=0;
int j;
write3Count=dataLength/3;
for (j=0; j < write3Count; j++)
{
// 6 leftmost bits from first byte, shifted to bits 7,8 are 0
outputData[outputOffset++]=base64Map[inputData[j*3+0] >> 2];
if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
// Remaining 2 bits from first byte, placed in position, and 4 high bits from the second byte, masked to ignore bits 7,8
outputData[outputOffset++]=base64Map[((inputData[j*3+0] << 4) | (inputData[j*3+1] >> 4)) & 63];
if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
// 4 low bits from the second byte and the two high bits from the third byte, masked to ignore bits 7,8
outputData[outputOffset++]=base64Map[((inputData[j*3+1] << 2) | (inputData[j*3+2] >> 6)) & 63]; // Third 6 bits
if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
// Last 6 bits from the third byte, masked to ignore bits 7,8
outputData[outputOffset++]=base64Map[inputData[j*3+2] & 63];
if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
}
if (dataLength % 3==1)
{
// One input byte remaining
outputData[outputOffset++]=base64Map[inputData[j*3+0] >> 2];
if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
// Pad with two equals
outputData[outputOffset++]='=';
outputData[outputOffset++]='=';
}
else if (dataLength % 3==2)
{
// Two input bytes remaining
// 6 leftmost bits from first byte, shifted to bits 7,8 are 0
outputData[outputOffset++]=base64Map[inputData[j*3+0] >> 2];
if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
// Remaining 2 bits from first byte, placed in position, and 4 high bits from the second byte, masked to ignore bits 7,8
outputData[outputOffset++]=base64Map[((inputData[j*3+0] << 4) | (inputData[j*3+1] >> 4)) & 63];
if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
// 4 low bits from the second byte, followed by 00
outputData[outputOffset++]=base64Map[(inputData[j*3+1] << 2) & 63]; // Third 6 bits
if ((++charCount % 76)==0) {outputData[outputOffset++]='\r'; outputData[outputOffset++]='\n'; charCount=0;}
// Pad with one equal
outputData[outputOffset++]='=';
//outputData[outputOffset++]='=';
}
// Append \r\n
outputData[outputOffset++]='\r';
outputData[outputOffset++]='\n';
outputData[outputOffset]=0;
return outputOffset;
}

51
thirdparty/raknet/Source/EmailSender.h vendored Normal file
View File

@@ -0,0 +1,51 @@
/// \file
/// \brief Rudimentary class to send email from code. Don't expect anything fancy.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __EMAIL_SENDER_H
#define __EMAIL_SENDER_H
class FileList;
class TCPInterface;
#include "RakNetTypes.h"
#include "RakMemoryOverride.h"
/// \brief Rudimentary class to send email from code.
class EmailSender : public RakNet::RakMemoryOverride
{
public:
/// Sends an email
/// \param[in] hostAddress The address of the email server.
/// \param[in] hostPort The port of the email server (usually 25)
/// \param[in] sender The email address you are sending from.
/// \param[in] recipient The email address you are sending to.
/// \param[in] senderName The email address you claim to be sending from
/// \param[in] recipientName The email address you claim to be sending to
/// \param[in] subject Email subject
/// \param[in] body Email body
/// \param[in] attachedFiles List of files to attach to the email. (Can be 0 to send none).
/// \param[in] doPrintf true to output SMTP info to console(for debugging?)
/// \param[in] password Used if the server uses AUTHENTICATE PLAIN over TLS (such as gmail)
/// \return 0 on success, otherwise a string indicating the error message
const char *Send(const char *hostAddress, unsigned short hostPort, const char *sender, const char *recipient, const char *senderName, const char *recipientName, const char *subject, const char *body, FileList *attachedFiles, bool doPrintf, const char *password);
// Returns how many bytes were written
int Base64Encoding(const char *inputData, int dataLength, char *outputData, const char *base64Map);
protected:
const char *GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf);
};
#endif

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,35 @@
#include "FormatString.h"
#include "EpochTimeToString.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
// localtime
#include <time.h>
#include "LinuxStrings.h"
char * EpochTimeToString(long long time)
{
static int textIndex=0;
static char text[4][64];
if (++textIndex==4)
textIndex=0;
struct tm * timeinfo;
time_t t = time;
timeinfo = localtime ( &t );
strftime (text[textIndex],64,"%c.",timeinfo);
/*
time_t
// Copied from the docs
struct tm *newtime;
newtime = _localtime64(& time);
asctime_s( text[textIndex], sizeof(text[textIndex]), newtime );
while (text[textIndex][0] && (text[textIndex][strlen(text[textIndex])-1]=='\n' || text[textIndex][strlen(text[textIndex])-1]=='\r'))
text[textIndex][strlen(text[textIndex])-1]=0;
*/
return text[textIndex];
}

View File

@@ -0,0 +1,9 @@
#ifndef __EPOCH_TIME_TO_STRING_H
#define __EPOCH_TIME_TO_STRING_H
#include "Export.h"
RAK_DLL_EXPORT char * EpochTimeToString(long long time);
#endif

6
thirdparty/raknet/Source/Export.h vendored Normal file
View File

@@ -0,0 +1,6 @@
// Fuck it, GCC won't compile with exports. Someone else can fix this if they want
#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

View File

@@ -0,0 +1,67 @@
/// \file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
// No longer used as I no longer support IO Completion ports
/*
#ifdef __USE_IO_COMPLETION_PORTS
#include "ExtendedOverlappedPool.h"
ExtendedOverlappedPool ExtendedOverlappedPool::I;
ExtendedOverlappedPool::ExtendedOverlappedPool()
{}
ExtendedOverlappedPool::~ExtendedOverlappedPool()
{
// The caller better have returned all the packets!
ExtendedOverlappedStruct * p;
poolMutex.Lock();
while ( pool.Size() )
{
p = pool.Pop();
delete p;
}
poolMutex.Unlock();
}
ExtendedOverlappedStruct* ExtendedOverlappedPool::GetPointer( void )
{
ExtendedOverlappedStruct * p = 0;
poolMutex.Lock();
if ( pool.Size() )
p = pool.Pop();
poolMutex.Unlock();
if ( p )
return p;
return new ExtendedOverlappedStruct;
}
void ExtendedOverlappedPool::ReleasePointer( ExtendedOverlappedStruct *p )
{
poolMutex.Lock();
pool.Push( p );
poolMutex.Unlock();
}
#endif
*/

View File

@@ -0,0 +1,50 @@
/// \file
/// \brief \b [Depreciated] This was used for IO completion ports.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
// No longer used as I no longer support IO Completion ports
/*
#ifdef __USE_IO_COMPLETION_PORTS
#ifndef __EXTENDED_OVERLAPPED_POOL
#define __EXTENDED_OVERLAPPED_POOL
#include "SimpleMutex.h"
#include "ClientContextStruct.h"
#include "DS_Queue.h"
/// Depreciated - for IO completion ports
class ExtendedOverlappedPool
{
public:
ExtendedOverlappedPool();
~ExtendedOverlappedPool();
ExtendedOverlappedStruct* GetPointer( void );
void ReleasePointer( ExtendedOverlappedStruct *p );
static inline ExtendedOverlappedPool* Instance()
{
return & I;
}
private:
DataStructures::Queue<ExtendedOverlappedStruct*> pool;
SimpleMutex poolMutex;
static ExtendedOverlappedPool I;
};
#endif
#endif
*/

692
thirdparty/raknet/Source/FileList.cpp vendored Normal file
View File

@@ -0,0 +1,692 @@
#include "FileList.h"
#include <stdio.h> // printf
#include <assert.h>
#if defined(_WIN32) || defined(__CYGWIN__)
#include <io.h>
#elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ )
#include <sys/io.h>
#endif
#include "DS_Queue.h"
#ifdef _WIN32
// For mkdir
#include <direct.h>
#else
#include <sys/stat.h>
#endif
//#include "SHA1.h"
#include "StringCompressor.h"
#include "BitStream.h"
#include "FileOperations.h"
#include "SuperFastHash.h"
#include "RakAssert.h"
#include "LinuxStrings.h"
#define MAX_FILENAME_LENGTH 512
static const unsigned HASH_LENGTH=sizeof(unsigned int);
// alloca
#ifdef _XBOX360
#elif defined(_WIN32)
#include <malloc.h>
#else
#if !defined ( __FreeBSD__ )
#include <alloca.h>
#endif
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "_FindFirst.h"
#include <stdint.h> //defines intptr_t
#endif
//int RAK_DLL_EXPORT FileListNodeComp( char * const &key, const FileListNode &data )
//{
// return strcmp(key, data.filename);
//}
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// First callback called when FileList::AddFilesFromDirectory() starts
void FLP_Printf::OnAddFilesFromDirectoryStarted(FileList *fileList, char *dir) {
(void) fileList;
printf("Adding files from directory %s\n",dir);}
/// Called for each directory, when that directory begins processing
void FLP_Printf::OnDirectory(FileList *fileList, char *dir, unsigned int directoriesRemaining) {
(void) fileList;
printf("Adding %s. %i remaining.\n", dir, directoriesRemaining);}
FileList::FileList()
{
callback=0;
}
FileList::~FileList()
{
Clear();
}
void FileList::AddFile(const char *filepath, const char *filename, unsigned char context)
{
if (filepath==0 || filename==0)
return;
char *data;
//std::fstream file;
//file.open(filename, std::ios::in | std::ios::binary);
FILE *fp = fopen(filepath, "rb");
if (fp==0)
return;
fseek(fp, 0, SEEK_END);
int length = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (length > (int) ((unsigned int)-1 / 8))
{
// If this assert hits, split up your file. You could also change BitSize_t in RakNetTypes.h to unsigned long long but this is not recommended for performance reasons
assert("Cannot add files over 536 MB" && 0);
fclose(fp);
return;
}
#if !defined(_XBOX360)
bool usedAlloca=false;
if (length < MAX_ALLOCA_STACK_ALLOCATION)
{
data = ( char* ) alloca( length );
usedAlloca=true;
}
else
#endif
{
data = (char*) rakMalloc( length );
}
fread(data, 1, length, fp);
AddFile(filename, data, length, length, context);
fclose(fp);
#if !defined(_XBOX360)
if (usedAlloca==false)
#endif
rakFree(data);
}
void FileList::AddFile(const char *filename, const char *data, const unsigned dataLength, const unsigned fileLength, unsigned char context)
{
if (filename==0)
return;
if (strlen(filename)>MAX_FILENAME_LENGTH)
{
// Should be enough for anyone
assert(0);
return;
}
// Avoid duplicate insertions unless the data is different, in which case overwrite the old data
unsigned i;
for (i=0; i<fileList.Size();i++)
{
if (strcmp(fileList[i].filename, filename)==0)
{
if (fileList[i].fileLengthBytes==fileLength && fileList[i].dataLengthBytes==dataLength &&
(dataLength==0 || memcmp(fileList[i].data, data, dataLength)==0))
// Exact same file already here
return;
// File of the same name, but different contents, so overwrite
rakFree(fileList[i].data);
rakFree(fileList[i].filename);
fileList.RemoveAtIndex(i);
break;
}
}
FileListNode n;
n.filename=(char*) rakMalloc( strlen(filename)+1 );
if (dataLength)
{
n.data=(char*) rakMalloc( dataLength );
memcpy(n.data, data, dataLength);
}
else
n.data=0;
n.dataLengthBytes=dataLength;
n.fileLengthBytes=fileLength;
n.context=context;
strcpy(n.filename, filename);
fileList.Insert(n);
}
void FileList::AddFilesFromDirectory(const char *applicationDirectory, const char *subDirectory, bool writeHash, bool writeData, bool recursive, unsigned char context)
{
DataStructures::Queue<char*> dirList;
char root[260];
char fullPath[520];
_finddata_t fileInfo;
intptr_t dir;
FILE *fp;
char *dirSoFar, *fileData;
dirSoFar=(char*) rakMalloc( 520 );
if (applicationDirectory)
strcpy(root, applicationDirectory);
else
root[0]=0;
int rootLen=(int)strlen(root);
if (rootLen)
{
strcpy(dirSoFar, root);
if (FixEndingSlash(dirSoFar))
rootLen++;
}
else
dirSoFar[0]=0;
if (subDirectory)
{
strcat(dirSoFar, subDirectory);
FixEndingSlash(dirSoFar);
}
if (callback)
callback->OnAddFilesFromDirectoryStarted(this, dirSoFar);
// printf("Adding files from directory %s\n",dirSoFar);
dirList.Push(dirSoFar);
while (dirList.Size())
{
dirSoFar=dirList.Pop();
strcpy(fullPath, dirSoFar);
// Changed from *.* to * for Linux compatibility
strcat(fullPath, "*");
dir=_findfirst(fullPath, &fileInfo );
if (dir==-1)
{
_findclose(dir);
rakFree(dirSoFar);
unsigned i;
for (i=0; i < dirList.Size(); i++)
rakFree(dirList[i]);
return;
}
// printf("Adding %s. %i remaining.\n", fullPath, dirList.Size());
if (callback)
callback->OnDirectory(this, fullPath, dirList.Size());
do
{
// no guarantee these entries are first...
if (strcmp("." , fileInfo.name) == 0 ||
strcmp("..", fileInfo.name) == 0)
{
continue;
}
if ((fileInfo.attrib & (_A_HIDDEN | _A_SUBDIR | _A_SYSTEM))==0)
{
strcpy(fullPath, dirSoFar);
strcat(fullPath, fileInfo.name);
fileData=0;
if (callback)
callback->OnFile(this, dirSoFar, fileInfo.name, fileInfo.size);
if (writeData && writeHash)
{
fileData= (char*) rakMalloc( fileInfo.size+HASH_LENGTH );
fp = fopen(fullPath, "rb");
fread(fileData+HASH_LENGTH, fileInfo.size, 1, fp);
fclose(fp);
unsigned int hash = SuperFastHash(fileData+HASH_LENGTH, fileInfo.size);
memcpy(fileData, &hash, HASH_LENGTH);
// sha1.Reset();
// sha1.Update( ( unsigned char* ) fileData+HASH_LENGTH, fileInfo.size );
// sha1.Final();
// memcpy(fileData, sha1.GetHash(), HASH_LENGTH);
// File data and hash
AddFile((const char*)fullPath+rootLen, fileData, fileInfo.size+HASH_LENGTH, fileInfo.size, context);
}
else if (writeHash)
{
// sha1.Reset();
// sha1.HashFile((char*)fullPath);
// sha1.Final();
unsigned int hash = SuperFastHashFile(fullPath);
// Hash only
// AddFile((const char*)fullPath+rootLen, (const char*)sha1.GetHash(), HASH_LENGTH, fileInfo.size, context);
AddFile((const char*)fullPath+rootLen, (const char*)&hash, HASH_LENGTH, fileInfo.size, context);
}
else if (writeData)
{
fileData= (char*) rakMalloc( fileInfo.size );
fp = fopen(fullPath, "rb");
fread(fileData, fileInfo.size, 1, fp);
fclose(fp);
// File data only
AddFile(fullPath+rootLen, fileData, fileInfo.size, fileInfo.size, context);
}
else
{
// Just the filename
AddFile(fullPath+rootLen, 0, 0, fileInfo.size, context);
}
if (fileData)
rakFree(fileData);
}
else if ((fileInfo.attrib & _A_SUBDIR) && (fileInfo.attrib & (_A_HIDDEN | _A_SYSTEM))==0 && recursive)
{
char *newDir=(char*) rakMalloc( 520 );
strcpy(newDir, dirSoFar);
strcat(newDir, fileInfo.name);
strcat(newDir, "/");
dirList.Push(newDir);
}
} while (_findnext(dir, &fileInfo ) != -1);
_findclose(dir);
rakFree(dirSoFar);
}
}
void FileList::Clear(void)
{
unsigned i;
for (i=0; i<fileList.Size(); i++)
{
rakFree(fileList[i].data);
rakFree(fileList[i].filename);
}
fileList.Clear();
}
void FileList::Serialize(RakNet::BitStream *outBitStream)
{
outBitStream->WriteCompressed(fileList.Size());
unsigned i;
for (i=0; i < fileList.Size(); i++)
{
outBitStream->WriteCompressed(fileList[i].context);
stringCompressor->EncodeString(fileList[i].filename, MAX_FILENAME_LENGTH, outBitStream);
outBitStream->Write((bool)(fileList[i].dataLengthBytes>0==true));
if (fileList[i].dataLengthBytes>0)
{
outBitStream->WriteCompressed(fileList[i].dataLengthBytes);
outBitStream->Write(fileList[i].data, fileList[i].dataLengthBytes);
}
outBitStream->Write((bool)(fileList[i].fileLengthBytes==fileList[i].dataLengthBytes));
if (fileList[i].fileLengthBytes!=fileList[i].dataLengthBytes)
outBitStream->WriteCompressed(fileList[i].fileLengthBytes);
}
}
bool FileList::Deserialize(RakNet::BitStream *inBitStream)
{
bool b, dataLenNonZero=false, fileLenMatchesDataLen=false;
char filename[512];
unsigned int fileListSize;
FileListNode n;
b=inBitStream->ReadCompressed(fileListSize);
#ifdef _DEBUG
assert(b);
assert(fileListSize < 10000);
#endif
if (b==false || fileListSize > 10000)
return false; // Sanity check
Clear();
unsigned i;
for (i=0; i < fileListSize; i++)
{
inBitStream->ReadCompressed(n.context);
stringCompressor->DecodeString((char*)filename, MAX_FILENAME_LENGTH, inBitStream);
inBitStream->Read(dataLenNonZero);
if (dataLenNonZero)
{
inBitStream->ReadCompressed(n.dataLengthBytes);
// sanity check
if (n.dataLengthBytes>2000000000)
{
#ifdef _DEBUG
assert(n.dataLengthBytes<=2000000000);
#endif
return false;
}
n.data=(char*) rakMalloc( (size_t) n.dataLengthBytes );
inBitStream->Read(n.data, n.dataLengthBytes);
}
else
{
n.dataLengthBytes=0;
n.data=0;
}
b=inBitStream->Read(fileLenMatchesDataLen);
if (fileLenMatchesDataLen)
n.fileLengthBytes=(unsigned) n.dataLengthBytes;
else
b=inBitStream->ReadCompressed(n.fileLengthBytes);
#ifdef _DEBUG
assert(b);
#endif
if (b==0)
{
Clear();
return false;
}
n.filename=(char*) rakMalloc( strlen(filename)+1 );
strcpy(n.filename, filename);
fileList.Insert(n);
}
return true;
}
void FileList::GetDeltaToCurrent(FileList *input, FileList *output, const char *dirSubset, const char *remoteSubdir)
{
// For all files in this list that do not match the input list, write them to the output list.
// dirSubset allows checking only a portion of the files in this list.
unsigned thisIndex, inputIndex;
unsigned dirSubsetLen, localPathLen, remoteSubdirLen;
bool match;
if (dirSubset)
dirSubsetLen = (unsigned int) strlen(dirSubset);
else
dirSubsetLen = 0;
if (remoteSubdir && remoteSubdir[0])
{
remoteSubdirLen=(unsigned int) strlen(remoteSubdir);
if (IsSlash(remoteSubdir[remoteSubdirLen-1]))
remoteSubdirLen--;
}
else
remoteSubdirLen=0;
for (thisIndex=0; thisIndex < fileList.Size(); thisIndex++)
{
localPathLen = (unsigned int) strlen(fileList[thisIndex].filename);
while (localPathLen>0)
{
if (IsSlash(fileList[thisIndex].filename[localPathLen-1]))
{
localPathLen--;
break;
}
localPathLen--;
}
// fileList[thisIndex].filename has to match dirSubset and be shorter or equal to it in length.
if (dirSubsetLen>0 &&
(localPathLen<dirSubsetLen ||
_strnicmp(fileList[thisIndex].filename, dirSubset, dirSubsetLen)!=0 ||
(localPathLen>dirSubsetLen && IsSlash(fileList[thisIndex].filename[dirSubsetLen])==false)))
continue;
match=false;
for (inputIndex=0; inputIndex < input->fileList.Size(); inputIndex++)
{
// If the filenames, hashes, and lengths match then skip this element in fileList. Otherwise write it to output
if (_stricmp(input->fileList[inputIndex].filename+remoteSubdirLen,fileList[thisIndex].filename+dirSubsetLen)==0)
{
match=true;
if (input->fileList[inputIndex].fileLengthBytes==fileList[thisIndex].fileLengthBytes &&
input->fileList[inputIndex].dataLengthBytes==fileList[thisIndex].dataLengthBytes &&
memcmp(input->fileList[inputIndex].data,fileList[thisIndex].data,(size_t) fileList[thisIndex].dataLengthBytes)==0)
{
// File exists on both machines and is the same.
break;
}
else
{
// File exists on both machines and is not the same.
output->AddFile(fileList[thisIndex].filename, 0,0, fileList[thisIndex].fileLengthBytes, 0);
break;
}
}
}
if (match==false)
{
// Other system does not have the file at all
output->AddFile(fileList[thisIndex].filename, 0,0, fileList[thisIndex].fileLengthBytes, 0);
}
}
}
void FileList::ListMissingOrChangedFiles(const char *applicationDirectory, FileList *missingOrChangedFiles, bool alwaysWriteHash, bool neverWriteHash)
{
unsigned fileLength;
// CSHA1 sha1;
FILE *fp;
char fullPath[512];
unsigned i;
// char *fileData;
for (i=0; i < fileList.Size(); i++)
{
strcpy(fullPath, applicationDirectory);
FixEndingSlash(fullPath);
strcat(fullPath,fileList[i].filename);
fp=fopen(fullPath, "rb");
if (fp==0)
{
missingOrChangedFiles->AddFile(fileList[i].filename, 0, 0, 0, 0);
}
else
{
fseek(fp, 0, SEEK_END);
fileLength = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (fileLength != fileList[i].fileLengthBytes && alwaysWriteHash==false)
{
missingOrChangedFiles->AddFile(fileList[i].filename, 0, 0, fileLength, 0);
}
else
{
// fileData= (char*) rakMalloc( fileLength );
// fread(fileData, fileLength, 1, fp);
// sha1.Reset();
// sha1.Update( ( unsigned char* ) fileData, fileLength );
// sha1.Final();
// rakFree(fileData);
unsigned int hash = SuperFastHashFilePtr(fp);
//if (fileLength != fileList[i].fileLength || memcmp( sha1.GetHash(), fileList[i].data, HASH_LENGTH)!=0)
if (fileLength != fileList[i].fileLengthBytes || memcmp( &hash, fileList[i].data, HASH_LENGTH)!=0)
{
if (neverWriteHash==false)
// missingOrChangedFiles->AddFile((const char*)fileList[i].filename, (const char*)sha1.GetHash(), HASH_LENGTH, fileLength, 0);
missingOrChangedFiles->AddFile((const char*)fileList[i].filename, (const char *) &hash, HASH_LENGTH, fileLength, 0);
else
missingOrChangedFiles->AddFile((const char*)fileList[i].filename, 0, 0, fileLength, 0);
}
}
fclose(fp);
}
}
}
void FileList::PopulateDataFromDisk(const char *applicationDirectory, bool writeFileData, bool writeFileHash, bool removeUnknownFiles)
{
FILE *fp;
char fullPath[512];
unsigned i;
// CSHA1 sha1;
i=0;
while (i < fileList.Size())
{
rakFree(fileList[i].data);
strcpy(fullPath, applicationDirectory);
FixEndingSlash(fullPath);
strcat(fullPath,fileList[i].filename);
fp=fopen(fullPath, "rb");
if (fp)
{
if (writeFileHash || writeFileData)
{
fseek(fp, 0, SEEK_END);
fileList[i].fileLengthBytes = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (writeFileHash)
{
if (writeFileData)
{
// Hash + data so offset the data by HASH_LENGTH
fileList[i].data=(char*) rakMalloc( fileList[i].fileLengthBytes+HASH_LENGTH );
fread(fileList[i].data+HASH_LENGTH, fileList[i].fileLengthBytes, 1, fp);
// sha1.Reset();
// sha1.Update((unsigned char*)fileList[i].data+HASH_LENGTH, fileList[i].fileLength);
// sha1.Final();
unsigned int hash = SuperFastHash(fileList[i].data+HASH_LENGTH, fileList[i].fileLengthBytes);
// memcpy(fileList[i].data, sha1.GetHash(), HASH_LENGTH);
memcpy(fileList[i].data, &hash, HASH_LENGTH);
}
else
{
// Hash only
fileList[i].dataLengthBytes=HASH_LENGTH;
if (fileList[i].fileLengthBytes < HASH_LENGTH)
fileList[i].data=(char*) rakMalloc( HASH_LENGTH );
else
fileList[i].data=(char*) rakMalloc( fileList[i].fileLengthBytes );
fread(fileList[i].data, fileList[i].fileLengthBytes, 1, fp);
// sha1.Reset();
// sha1.Update((unsigned char*)fileList[i].data, fileList[i].fileLength);
// sha1.Final();
unsigned int hash = SuperFastHash(fileList[i].data, fileList[i].fileLengthBytes);
// memcpy(fileList[i].data, sha1.GetHash(), HASH_LENGTH);
memcpy(fileList[i].data, &hash, HASH_LENGTH);
}
}
else
{
// Data only
fileList[i].dataLengthBytes=fileList[i].fileLengthBytes;
fileList[i].data=(char*) rakMalloc( fileList[i].fileLengthBytes );
fread(fileList[i].data, fileList[i].fileLengthBytes, 1, fp);
}
fclose(fp);
i++;
}
else
{
fileList[i].data=0;
fileList[i].dataLengthBytes=0;
}
}
else
{
if (removeUnknownFiles)
{
rakFree(fileList[i].filename);
fileList.RemoveAtIndex(i);
}
else
i++;
}
}
}
void FileList::WriteDataToDisk(const char *applicationDirectory)
{
char fullPath[512];
unsigned i,j;
for (i=0; i < fileList.Size(); i++)
{
strcpy(fullPath, applicationDirectory);
FixEndingSlash(fullPath);
strcat(fullPath,fileList[i].filename);
// Security - Don't allow .. in the filename anywhere so you can't write outside of the root directory
for (j=1; j < strlen(fileList[i].filename); j++)
{
if (fileList[i].filename[j]=='.' && fileList[i].filename[j-1]=='.')
{
#ifdef _DEBUG
assert(0);
#endif
// Just cancel the write entirely
return;
}
}
WriteFileWithDirectories(fullPath, fileList[i].data, (unsigned int) fileList[i].dataLengthBytes);
}
}
#ifdef _MSC_VER
#pragma warning( disable : 4966 ) // unlink declared depreciated by Microsoft in order to make it harder to be cross platform. I don't agree it's depreciated.
#endif
void FileList::DeleteFiles(const char *applicationDirectory)
{
char fullPath[512];
unsigned i,j;
for (i=0; i < fileList.Size(); i++)
{
// The filename should not have .. in the path - if it does ignore it
for (j=1; j < strlen(fileList[i].filename); j++)
{
if (fileList[i].filename[j]=='.' && fileList[i].filename[j-1]=='.')
{
#ifdef _DEBUG
assert(0);
#endif
// Just cancel the deletion entirely
return;
}
}
strcpy(fullPath, applicationDirectory);
FixEndingSlash(fullPath);
strcat(fullPath, fileList[i].filename);
#ifdef _MSC_VER
#pragma warning( disable : 4966 ) // unlink declared depreciated by Microsoft in order to make it harder to be cross platform. I don't agree it's depreciated.
#endif
int result = unlink(fullPath);
if (result!=0)
{
printf("FileList::DeleteFiles: unlink (%s) failed.\n", fullPath);
}
}
}
void FileList::SetCallback(FileListProgress *cb)
{
callback=cb;
}
bool FileList::FixEndingSlash(char *str)
{
#ifdef _WIN32
if (str[strlen(str)-1]!='/' && str[strlen(str)-1]!='\\')
{
strcat(str, "\\"); // Only \ works with system commands, used by AutopatcherClient
return true;
}
#else
if (str[strlen(str)-1]!='\\' && str[strlen(str)-1]!='/')
{
strcat(str, "/"); // Only / works with Linux
return true;
}
#endif
return false;
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

171
thirdparty/raknet/Source/FileList.h vendored Normal file
View File

@@ -0,0 +1,171 @@
#ifndef __FILE_LIST
#define __FILE_LIST
#include "Export.h"
#include "DS_List.h"
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
namespace RakNet
{
class BitStream;
}
/// Represents once instance of a file
struct FileListNode : public RakNet::RakMemoryOverride
{
/// Name of the file
char *filename;
/// File data (may be null if not ready)
char *data;
/// Length of \a data. May be greater than fileLength if prepended with a file hash
BitSize_t dataLengthBytes;
/// Length of the file
unsigned fileLengthBytes;
/// User specific data for whatever, describing this file.
unsigned char context;
};
//int RAK_DLL_EXPORT FileListNodeComp( char * const &key, const FileListNode &data );
class RakPeerInterface;
class FileList;
/// Callback interface set with FileList::SetCallback() in case you want progress notifications when FileList::AddFilesFromDirectory() is called
class RAK_DLL_EXPORT FileListProgress
{
public:
FileListProgress() {}
virtual ~FileListProgress() {}
/// First callback called when FileList::AddFilesFromDirectory() starts
virtual void OnAddFilesFromDirectoryStarted(FileList *fileList, char *dir) {
(void) fileList;
(void) dir;
}
/// Called for each directory, when that directory begins processing
virtual void OnDirectory(FileList *fileList, char *dir, unsigned int directoriesRemaining) {
(void) fileList;
(void) dir;
(void) directoriesRemaining;
}
/// Called for each file, when that file begins processing
virtual void OnFile(FileList *fileList, char *dir, char *fileName, unsigned int fileSize) {
(void) fileList;
(void) dir;
(void) fileName;
(void) fileSize;
}
};
/// Implementation of FileListProgress to use printf
class RAK_DLL_EXPORT FLP_Printf : public FileListProgress
{
public:
FLP_Printf() {}
virtual ~FLP_Printf() {}
/// First callback called when FileList::AddFilesFromDirectory() starts
virtual void OnAddFilesFromDirectoryStarted(FileList *fileList, char *dir);
/// Called for each directory, when that directory begins processing
virtual void OnDirectory(FileList *fileList, char *dir, unsigned int directoriesRemaining);
};
class RAK_DLL_EXPORT FileList : public RakNet::RakMemoryOverride
{
public:
FileList();
~FileList();
/// Add all the files at a given directory.
/// \param[in] applicationDirectory The first part of the path. This is not stored as part of the filename. Use \ as the path delineator.
/// \param[in] subDirectory The rest of the path to the file. This is stored as a prefix to the filename
/// \param[in] writeHash The first SHA1_LENGTH bytes is a hash of the file, with the remainder the actual file data (should \a writeData be true)
/// \param[in] writeData Write the contents of each file
/// \param[in] recursive Whether or not to visit subdirectories
/// \param[in] context User defined byte to store with each file. Use for whatever you want.
void AddFilesFromDirectory(const char *applicationDirectory, const char *subDirectory, bool writeHash, bool writeData, bool recursive, unsigned char context);
/// Deallocate all memory
void Clear(void);
/// Write all encoded data into a bitstream
void Serialize(RakNet::BitStream *outBitStream);
/// Read all encoded data from a bitstream. Clear() is called before deserializing.
bool Deserialize(RakNet::BitStream *inBitStream);
/// Given the existing set of files, search applicationDirectory for the same files.
/// For each file that is missing or different, add that file to \a missingOrChangedFiles. Note: the file contents are not written, and only the hash if written if \a alwaysWriteHash is true
/// alwaysWriteHash and neverWriteHash are optimizations to avoid reading the file contents to generate the hash if not necessary because the file is missing or has different lengths anyway.
/// \param[in] applicationDirectory The first part of the path. This is not stored as part of the filename. Use \ as the path delineator.
/// \param[out] missingOrChangedFiles Output list written to
/// \param[in] alwaysWriteHash If true, and neverWriteHash is false, will hash the file content of the file on disk, and write that as the file data with a length of SHA1_LENGTH bytes. If false, if the file length is different, will only write the filename.
/// \param[in] neverWriteHash If true, will never write the hash, even if available. If false, will write the hash if the file lengths are the same and it was forced to do a comparison.
void ListMissingOrChangedFiles(const char *applicationDirectory, FileList *missingOrChangedFiles, bool alwaysWriteHash, bool neverWriteHash);
/// Return the files that need to be written to make \a input match this current FileList.
/// Specify dirSubset to only consider files that start with this path
/// specify remoteSubdir to assume that all filenames in input start with this path, so strip it off when comparing filenames.
/// \param[in] input Full list of files
/// \param[out] output Files that we need to match input
/// \param[in] dirSubset If the filename does not start with this path, just skip this file.
/// \param[in] remoteSubdir Remove this from the filenames of \a input when comparing to existing filenames.
void GetDeltaToCurrent(FileList *input, FileList *output, const char *dirSubset, const char *remoteSubdir);
/// Assuming FileList contains a list of filenames presumably without data, read the data for these filenames
/// \param[in] applicationDirectory Prepend this path to each filename. Trailing slash will be added if necessary. Use \ as the path delineator.
/// \param[in] writeFileData True to read and store the file data. The first SHA1_LENGTH bytes will contain the hash if \a writeFileHash is true
/// \param[in] writeFileHash True to read and store the hash of the file data. The first SHA1_LENGTH bytes will contain the hash if \a writeFileHash is true
/// \param[in] removeUnknownFiles If a file does not exist on disk but is in the file list, remove it from the file list?
void PopulateDataFromDisk(const char *applicationDirectory, bool writeFileData, bool writeFileHash, bool removeUnknownFiles);
/// Write all files to disk, prefixing the paths with applicationDirectory
/// \param[in] applicationDirectory path prefix
void WriteDataToDisk(const char *applicationDirectory);
/// Add a file, given data already in memory
/// \param[in] filename Name of a file, optionally prefixed with a partial or complete path. Use \ as the path delineator.
/// \param[in] data Contents to write
/// \param[in] dataLength length of the data, which may be greater than fileLength should you prefix extra data, such as the hash
/// \param[in] fileLength Length of the file
/// \param[in] context User defined byte to store with each file. Use for whatever you want.
void AddFile(const char *filename, const char *data, const unsigned dataLength, const unsigned fileLength, unsigned char context);
/// 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, unsigned char context);
/// Delete all files stored in the file list
/// \param[in] applicationDirectory Prefixed to the path to each filename. Use \ as the path delineator.
void DeleteFiles(const char *applicationDirectory);
/// Set a callback to get progress reports about what this class does
/// \param[in] cb A pointer to an externally defined instance of FileListProgress. This pointer is held internally, so should remain valid as long as this class is valid.
void SetCallback(FileListProgress *cb);
// Here so you can read it, but don't modify it
DataStructures::List<FileListNode> fileList;
static bool FixEndingSlash(char *str);
protected:
FileListProgress *callback;
};
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif

View File

@@ -0,0 +1,561 @@
#include "FileListTransfer.h"
#include "DS_HuffmanEncodingTree.h"
#include "FileListTransferCBInterface.h"
#include "StringCompressor.h"
#include "FileList.h"
#include "DS_Queue.h"
#include "MessageIdentifiers.h"
#include "RakNetTypes.h"
#include "RakPeerInterface.h"
#include <assert.h>
#ifdef _PS3
#include <alloca.h>
#endif
#ifdef _MSC_VER
#pragma warning( push )
#endif
struct FileListTransfer::FileListReceiver
{
FileListTransferCBInterface *downloadHandler;
SystemAddress allowedSender;
HuffmanEncodingTree tree;
unsigned short setID;
unsigned setCount;
unsigned setTotalCompressedTransmissionLength;
unsigned setTotalFinalLength;
bool gotSetHeader;
bool deleteDownloadHandler;
bool isCompressed;
};
FileListTransfer::FileListTransfer()
{
rakPeer=0;
setId=0;
callback=0;
DataStructures::Map<unsigned short, FileListReceiver*>::IMPLEMENT_DEFAULT_COMPARISON();
}
FileListTransfer::~FileListTransfer()
{
Clear();
}
unsigned short FileListTransfer::SetupReceive(FileListTransferCBInterface *handler, bool deleteHandler, SystemAddress allowedSender)
{
if (rakPeer->IsConnected(allowedSender)==false)
return (unsigned short)-1;
FileListReceiver *receiver;
if (fileListReceivers.Has(setId))
{
receiver=fileListReceivers.Get(setId);
receiver->downloadHandler->OnDereference();
if (receiver->deleteDownloadHandler)
delete receiver->downloadHandler;
delete receiver;
fileListReceivers.Delete(setId);
}
unsigned short oldId;
receiver = new FileListReceiver;
receiver->downloadHandler=handler;
receiver->allowedSender=allowedSender;
receiver->gotSetHeader=false;
receiver->deleteDownloadHandler=deleteHandler;
fileListReceivers.Set(setId, receiver);
oldId=setId;
if (++setId==(unsigned short)-1)
setId=0;
return oldId;
}
void FileListTransfer::Send(FileList *fileList, RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, bool compressData)
{
RakNet::BitStream outBitstream, encodedData;
HuffmanEncodingTree tree;
unsigned int frequencyTable[ 256 ];
unsigned int i,j;
unsigned totalCompressedLength, totalLength;
DataStructures::Queue<FileListNode> compressedFiles;
FileListNode n;
if (callback)
fileList->SetCallback(callback);
totalCompressedLength=totalLength=0;
if (compressData)
{
memset(frequencyTable,0,256*sizeof(unsigned int));
for (i=0; i < fileList->fileList.Size(); i++)
{
const FileListNode &fileListNode = fileList->fileList[i];
for (j=0; j < fileListNode.dataLengthBytes; j++)
{
++frequencyTable[(unsigned char)(fileListNode.data[j])];
}
}
tree.GenerateFromFrequencyTable(frequencyTable);
// Compress all the files, so we know the total compressed size to be sent
for (i=0; i < fileList->fileList.Size(); i++)
{
encodedData.Reset();
// Why send compressed chunks if we are not sending the whole file?
assert(fileList->fileList[i].fileLengthBytes==fileList->fileList[i].fileLengthBytes);
tree.EncodeArray((unsigned char*)fileList->fileList[i].data, (size_t) fileList->fileList[i].dataLengthBytes, &encodedData);
n.dataLengthBytes=encodedData.GetNumberOfBitsUsed(); // Temporarily actually storing bits
totalCompressedLength+=(unsigned int) BITS_TO_BYTES(n.dataLengthBytes);
totalLength+=fileList->fileList[i].fileLengthBytes;
n.data = (char*) rakMalloc( (size_t) BITS_TO_BYTES(n.dataLengthBytes) );
memcpy(n.data, encodedData.GetData(), (size_t) BITS_TO_BYTES(n.dataLengthBytes));
compressedFiles.Push(n);
}
}
else
{
for (i=0; i < fileList->fileList.Size(); i++)
{
const FileListNode &fileListNode = fileList->fileList[i];
totalLength+=fileListNode.fileLengthBytes;
}
}
// Write the chunk header, which contains the frequency table, the total number of files, and the total number of bytes
bool anythingToWrite;
outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_HEADER);
outBitstream.Write(setID);
anythingToWrite=fileList->fileList.Size()>0;
outBitstream.Write(anythingToWrite);
if (anythingToWrite)
{
if (compressData)
{
outBitstream.Write(true);
for (i=0; i < 256; i++)
outBitstream.WriteCompressed(frequencyTable[i]);
outBitstream.WriteCompressed(fileList->fileList.Size()); // SetCount
outBitstream.WriteCompressed(totalLength);
outBitstream.WriteCompressed(totalCompressedLength);
}
else
{
outBitstream.Write(false);
outBitstream.WriteCompressed(fileList->fileList.Size());
outBitstream.WriteCompressed(totalLength);
}
rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
// Next part arrives at FileListTransfer::DecodeFile
if (compressData)
{
// Send each possibly compressed file
for (i=0; i < compressedFiles.Size(); i++)
{
outBitstream.Reset();
outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE);
outBitstream.Write(fileList->fileList[i].context);
outBitstream.Write(setID);
outBitstream.WriteCompressed(i);
outBitstream.WriteCompressed(fileList->fileList[i].dataLengthBytes); // Original length
outBitstream.WriteCompressed(compressedFiles[i].dataLengthBytes); // Compressed bitlength (yes, not bytes)
stringCompressor->EncodeString(fileList->fileList[i].filename, 512, &outBitstream);
outBitstream.WriteBits((const unsigned char*)compressedFiles[i].data, compressedFiles[i].dataLengthBytes);
// rakFree(compressedFiles[i].data);
// rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
// This is much more efficient than the commented code, because it doesn't require writing the file to the bitstream just to pass to Send
char *dataBlocks[2];
int lengths[2];
dataBlocks[0]=(char*) outBitstream.GetData();
lengths[0]=outBitstream.GetNumberOfBytesUsed();
dataBlocks[1]=compressedFiles[i].data;
lengths[1]=BITS_TO_BYTES(compressedFiles[i].dataLengthBytes);
rakPeer->SendList(dataBlocks,lengths,2,priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
rakFree(compressedFiles[i].data);
}
}
else
{
for (i=0; i < fileList->fileList.Size(); i++)
{
outBitstream.Reset();
outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE);
outBitstream.Write(fileList->fileList[i].context);
outBitstream.Write(setID);
outBitstream.WriteCompressed(i);
outBitstream.WriteCompressed(fileList->fileList[i].dataLengthBytes); // Original length in bytes
stringCompressor->EncodeString(fileList->fileList[i].filename, 512, &outBitstream);
outBitstream.AlignWriteToByteBoundary();
// outBitstream.Write((const char*) fileList->fileList[i].data, fileList->fileList[i].dataLengthBytes);
// rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
// This is much more efficient than the commented code, because it doesn't require writing the file to the bitstream just to pass to Send
char *dataBlocks[2];
int lengths[2];
dataBlocks[0]=(char*) outBitstream.GetData();
lengths[0]=outBitstream.GetNumberOfBytesUsed();
dataBlocks[1]=fileList->fileList[i].data;
lengths[1]=fileList->fileList[i].dataLengthBytes;
rakPeer->SendList(dataBlocks,lengths,2,priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
}
}
}
else
rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
}
bool FileListTransfer::DecodeSetHeader(Packet *packet)
{
unsigned i;
unsigned int frequencyTable[ 256 ];
bool anythingToWrite=false;
unsigned short setID;
RakNet::BitStream inBitStream(packet->data, packet->length, false);
inBitStream.IgnoreBits(8);
inBitStream.Read(setID);
FileListReceiver *fileListReceiver;
if (fileListReceivers.Has(setID)==false)
{
#ifdef _DEBUG
assert(0);
#endif
return false;
}
fileListReceiver=fileListReceivers.Get(setID);
if (fileListReceiver->allowedSender!=packet->systemAddress)
{
#ifdef _DEBUG
assert(0);
#endif
return false;
}
#ifdef _DEBUG
assert(fileListReceiver->gotSetHeader==false);
#endif
inBitStream.Read(anythingToWrite);
if (anythingToWrite)
{
inBitStream.Read(fileListReceiver->isCompressed);
if (fileListReceiver->isCompressed)
{
for (i=0; i < 256; i++)
inBitStream.ReadCompressed(frequencyTable[i]);
fileListReceiver->tree.GenerateFromFrequencyTable(frequencyTable);
inBitStream.ReadCompressed(fileListReceiver->setCount);
inBitStream.ReadCompressed(fileListReceiver->setTotalFinalLength);
if (inBitStream.ReadCompressed(fileListReceiver->setTotalCompressedTransmissionLength))
{
fileListReceiver->gotSetHeader=true;
return true;
}
}
else
{
inBitStream.ReadCompressed(fileListReceiver->setCount);
if (inBitStream.ReadCompressed(fileListReceiver->setTotalFinalLength))
{
fileListReceiver->setTotalCompressedTransmissionLength=fileListReceiver->setTotalFinalLength;
fileListReceiver->gotSetHeader=true;
return true;
}
}
}
else
{
FileListTransferCBInterface::OnFileStruct s;
memset(&s,0,sizeof(FileListTransferCBInterface::OnFileStruct));
s.setID=setID;
fileListReceiver->downloadHandler->OnFile(&s);
return true;
}
return false;
}
bool FileListTransfer::DecodeFile(Packet *packet, bool fullFile)
{
FileListTransferCBInterface::OnFileStruct onFileStruct;
BitSize_t bitLength=0;
RakNet::BitStream inBitStream(packet->data, packet->length, false);
inBitStream.IgnoreBits(8);
unsigned int partCount=0;
unsigned int partTotal=0;
unsigned int partLength=0;
onFileStruct.fileData=0;
if (fullFile==false)
{
// Disable endian swapping on reading this, as it's generated locally in ReliabilityLayer.cpp
inBitStream.ReadBits( (unsigned char* ) &partCount, BYTES_TO_BITS(sizeof(partCount)), true );
inBitStream.ReadBits( (unsigned char* ) &partTotal, BYTES_TO_BITS(sizeof(partTotal)), true );
inBitStream.ReadBits( (unsigned char* ) &partLength, BYTES_TO_BITS(sizeof(partLength)), true );
inBitStream.IgnoreBits(8);
// The header is appended to every chunk, which we continue to read after this statement block
}
inBitStream.Read(onFileStruct.context);
inBitStream.Read(onFileStruct.setID);
FileListReceiver *fileListReceiver;
if (fileListReceivers.Has(onFileStruct.setID)==false)
{
return false;
}
fileListReceiver=fileListReceivers.Get(onFileStruct.setID);
if (fileListReceiver->allowedSender!=packet->systemAddress)
{
#ifdef _DEBUG
assert(0);
#endif
return false;
}
#ifdef _DEBUG
assert(fileListReceiver->gotSetHeader==true);
#endif
inBitStream.ReadCompressed(onFileStruct.fileIndex);
inBitStream.ReadCompressed(onFileStruct.finalDataLength);
if (fileListReceiver->isCompressed)
{
inBitStream.ReadCompressed(bitLength);
onFileStruct.compressedTransmissionLength=(unsigned int) BITS_TO_BYTES(bitLength);
}
else
{
// Read header uncompressed so the data is byte aligned, for speed
onFileStruct.compressedTransmissionLength=(unsigned int) onFileStruct.finalDataLength;
}
if (stringCompressor->DecodeString(onFileStruct.fileName, 512, &inBitStream)==false)
{
#ifdef _DEBUG
assert(0);
#endif
return false;
}
if (fullFile)
{
// Support SendLists
inBitStream.AlignReadToByteBoundary();
onFileStruct.fileData = (char*) rakMalloc( (size_t) onFileStruct.finalDataLength );
if (fileListReceiver->isCompressed)
{
BitSize_t len=fileListReceiver->tree.DecodeArray(&inBitStream, bitLength, (size_t) onFileStruct.finalDataLength, (unsigned char*) onFileStruct.fileData);
if (len!=onFileStruct.finalDataLength)
{
#ifdef _DEBUG
assert(0);
#endif
rakFree(onFileStruct.fileData);
return false;
}
}
else
{
inBitStream.Read((char*)onFileStruct.fileData, onFileStruct.finalDataLength);
}
}
onFileStruct.setCount=fileListReceiver->setCount;
onFileStruct.setTotalCompressedTransmissionLength=fileListReceiver->setTotalCompressedTransmissionLength;
onFileStruct.setTotalFinalLength=fileListReceiver->setTotalFinalLength;
// User callback for this file.
if (fullFile)
{
if (fileListReceiver->downloadHandler->OnFile(&onFileStruct))
rakFree(onFileStruct.fileData);
// If this set is done, free the memory for it.
if (fileListReceiver->setCount==onFileStruct.fileIndex+1)
{
if (fileListReceiver->downloadHandler->OnDownloadComplete()==false)
{
fileListReceiver->downloadHandler->OnDereference();
if (fileListReceiver->deleteDownloadHandler)
delete fileListReceiver->downloadHandler;
fileListReceivers.Delete(onFileStruct.setID);
delete fileListReceiver;
}
}
}
else
{
inBitStream.AlignReadToByteBoundary();
bool usedAlloca=false;
char *firstDataChunk;
unsigned int unreadBits = inBitStream.GetNumberOfUnreadBits();
unsigned int unreadBytes = BITS_TO_BYTES(unreadBits);
if (unreadBytes>0)
{
#if !defined(_XBOX360)
if (unreadBits < MAX_ALLOCA_STACK_ALLOCATION)
{
firstDataChunk = ( char* ) alloca( unreadBytes );
usedAlloca=true;
}
else
#endif
firstDataChunk = (char*) rakMalloc( unreadBytes );
// Read partLength bytes, reported to OnFileProgress
if (fileListReceiver->isCompressed)
fileListReceiver->tree.DecodeArray(&inBitStream, unreadBits, partLength, (unsigned char*) firstDataChunk);
else
inBitStream.Read((char*)firstDataChunk, unreadBytes );
}
else
firstDataChunk=0;
fileListReceiver->downloadHandler->OnFileProgress(&onFileStruct, partCount, partTotal, unreadBytes, firstDataChunk);
if (usedAlloca==false)
delete [] firstDataChunk;
}
return true;
}
PluginReceiveResult FileListTransfer::OnReceive(RakPeerInterface *peer, Packet *packet)
{
(void) peer;
switch (packet->data[0])
{
case ID_CONNECTION_LOST:
case ID_DISCONNECTION_NOTIFICATION:
RemoveReceiver(packet->systemAddress);
break;
case ID_FILE_LIST_TRANSFER_HEADER:
DecodeSetHeader(packet);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
case ID_FILE_LIST_TRANSFER_FILE:
DecodeFile(packet, true);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
case ID_DOWNLOAD_PROGRESS:
if (packet->length>sizeof(MessageID)+sizeof(unsigned int)*3 &&
packet->data[sizeof(MessageID)+sizeof(unsigned int)*3]==ID_FILE_LIST_TRANSFER_FILE)
{
DecodeFile(packet, false);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
break;
}
return RR_CONTINUE_PROCESSING;
}
void FileListTransfer::OnShutdown(RakPeerInterface *peer)
{
(void) peer;
Clear();
}
void FileListTransfer::Clear(void)
{
unsigned i;
for (i=0; i < fileListReceivers.Size(); i++)
{
fileListReceivers[i]->downloadHandler->OnDereference();
if (fileListReceivers[i]->deleteDownloadHandler)
{
delete fileListReceivers[i]->downloadHandler;
}
delete fileListReceivers[i];
}
fileListReceivers.Clear();
}
void FileListTransfer::OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress)
{
(void) peer;
RemoveReceiver(systemAddress);
}
void FileListTransfer::CancelReceive(unsigned short setId)
{
if (fileListReceivers.Has(setId)==false)
{
#ifdef _DEBUG
assert(0);
#endif
return;
}
FileListReceiver *fileListReceiver=fileListReceivers.Get(setId);
fileListReceiver->downloadHandler->OnDereference();
if (fileListReceiver->deleteDownloadHandler)
delete fileListReceiver->downloadHandler;
delete fileListReceiver;
fileListReceivers.Delete(setId);
}
void FileListTransfer::RemoveReceiver(SystemAddress systemAddress)
{
unsigned i;
i=0;
while (i < fileListReceivers.Size())
{
if (fileListReceivers[i]->allowedSender==systemAddress)
{
fileListReceivers[i]->downloadHandler->OnDereference();
if (fileListReceivers[i]->deleteDownloadHandler)
{
delete fileListReceivers[i]->downloadHandler;
}
delete fileListReceivers[i];
fileListReceivers.RemoveAtIndex(i);
}
else
i++;
}
}
bool FileListTransfer::IsHandlerActive(unsigned short setId)
{
return fileListReceivers.Has(setId);
}
void FileListTransfer::SetCallback(FileListProgress *cb)
{
callback=cb;
}
FileListProgress *FileListTransfer::GetCallback(void) const
{
return callback;
}
void FileListTransfer::OnAttach(RakPeerInterface *peer)
{
rakPeer=peer;
}
void FileListTransfer::Update(RakPeerInterface *peer)
{
(void) peer;
unsigned i;
i=0;
while (i < fileListReceivers.Size())
{
if (fileListReceivers[i]->downloadHandler->Update()==false)
{
fileListReceivers[i]->downloadHandler->OnDereference();
if (fileListReceivers[i]->deleteDownloadHandler)
delete fileListReceivers[i]->downloadHandler;
delete fileListReceivers[i];
fileListReceivers.RemoveAtIndex(i);
}
else
i++;
}
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@@ -0,0 +1,110 @@
/// \file
/// \brief A plugin to provide a simple way to compress and incrementally send the files in the FileList structure.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __FILE_LIST_TRANFER_H
#define __FILE_LIST_TRANFER_H
#include "RakNetTypes.h"
#include "Export.h"
#include "PluginInterface.h"
#include "DS_Map.h"
#include "RakNetTypes.h"
#include "PacketPriority.h"
#include "RakMemoryOverride.h"
class FileListTransferCBInterface;
class FileList;
class FileListProgress;
/// \defgroup FILE_LIST_TRANSFER_GROUP FileListTransfer
/// \ingroup PLUGINS_GROUP
/// \brief A plugin to provide a simple way to compress and incrementally send the files in the FileList structure.
/// Similar to the DirectoryDeltaTransfer plugin, except that it doesn't send deltas based on pre-existing files or actually write the files to disk.
///
/// Usage:
/// Call SetupReceive to allow one file set to arrive. The value returned by FileListTransfer::SetupReceive()
/// is the setID that is allowed.
/// It's up to you to transmit this value to the other system, along with information indicating what kind of files you want to get.
/// The other system should then prepare a FileList and call FileListTransfer::Send(), passing the return value of FileListTransfer::SetupReceive()
/// as the \a setID parameter to FileListTransfer::Send()
/// \ingroup FILE_LIST_TRANSFER_GROUP
class RAK_DLL_EXPORT FileListTransfer : public PluginInterface
{
public:
FileListTransfer();
virtual ~FileListTransfer();
/// Allows one corresponding Send() call from another system to arrive.
/// \param[in] handler The class to call on each file
/// \param[in] deleteHandler True to delete the handler when it is no longer needed. False to not do so.
/// \param[in] allowedSender Which system to allow files from
/// \return A set ID value, which should be passed as the \a setID value to the Send() call on the other system. This value will be returned in the callback and is unique per file set. Returns 65535 on failure (not connected to sender)
unsigned short SetupReceive(FileListTransferCBInterface *handler, bool deleteHandler, SystemAddress allowedSender);
/// Send the FileList structure to another system, which must have previously called SetupReceive()
/// \param[in] fileList A list of files. The data contained in FileList::data will be sent incrementally and compressed among all files in the set
/// \param[in] rakPeer The instance of RakNet to use to send the message
/// \param[in] recipient The address of the system to send to
/// \param[in] setID The return value of SetupReceive() which was previously called on \a recipient
/// \param[in] priority Passed to RakPeerInterface::Send()
/// \param[in] orderingChannel Passed to RakPeerInterface::Send()
/// \param[in] compressData Use a poor but fast compression algorithm. This makes your data larger if it is already compressed or if the amount of data to send is small so don't use it blindly.
void Send(FileList *fileList, RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, bool compressData);
/// Stop a download.
void CancelReceive(unsigned short setId);
/// Remove all handlers associated with a particular system address
void RemoveReceiver(SystemAddress systemAddress);
/// Is a handler passed to SetupReceive still running?
bool IsHandlerActive(unsigned short setId);
/// Set a callback to get progress reports about what the file list instances do
/// \param[in] cb A pointer to an externally defined instance of FileListProgress. This pointer is held internally, so should remain valid as long as this class is valid.
void SetCallback(FileListProgress *cb);
/// \Returns what was sent to SetCallback
/// \return What was sent to SetCallback
FileListProgress *GetCallback(void) const;
/// \internal For plugin handling
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
/// \internal For plugin handling
virtual void OnShutdown(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress);
/// \internal For plugin handling
virtual void OnAttach(RakPeerInterface *peer);
/// \internal For plugin handling
virtual void Update(RakPeerInterface *peer);
protected:
bool DecodeSetHeader(Packet *packet);
bool DecodeFile(Packet *packet, bool fullFile);
void Clear(void);
struct FileListReceiver;
DataStructures::Map<unsigned short, FileListReceiver*> fileListReceivers;
unsigned short setId;
RakPeerInterface *rakPeer;
FileListProgress *callback;
};
#endif

View File

@@ -0,0 +1,98 @@
#ifndef __FILE_LIST_TRANSFER_CALLBACK_INTERFACE_H
#define __FILE_LIST_TRANSFER_CALLBACK_INTERFACE_H
#include "RakMemoryOverride.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
/// \brief Used by FileListTransfer plugin as a callback for when we get a file.
/// You get the last file when fileIndex==setCount
/// \sa FileListTransfer
class FileListTransferCBInterface : public RakNet::RakMemoryOverride
{
public:
struct OnFileStruct
{
/// The index into the set of files, from 0 to setCount
unsigned fileIndex;
/// The name of the file
char fileName[512];
/// The data pointed to by the file
char *fileData;
/// How many bytes this file took to send, if using compression.
unsigned compressedTransmissionLength;
/// The actual length of this file.
BitSize_t finalDataLength;
/// Files are transmitted in sets, where more than one set of files can be transmitted at the same time.
/// This is the identifier for the set, which is returned by FileListTransfer::SetupReceive
unsigned short setID;
/// The number of files that are in this set.
unsigned setCount;
/// The total length of the transmitted files for this set, with compression.
unsigned setTotalCompressedTransmissionLength;
/// The total length of the transmitted files for this set, after being uncompressed
unsigned setTotalFinalLength;
/// User data passed to one of the functions in the FileList class.
/// However, on error, this is instead changed to one of the enumerations in the PatchContext structure.
unsigned char context;
};
FileListTransferCBInterface() {}
virtual ~FileListTransferCBInterface() {}
/// Got a file
/// This structure is only valid for the duration of this function call.
/// \return Return true to have RakNet delete the memory allocated to hold this file for this function call.
virtual bool OnFile(OnFileStruct *onFileStruct)=0;
/// Got part of a big file.
/// You can get these notifications by calling RakPeer::SetSplitMessageProgressInterval
/// Otherwise you will only get complete files.
/// \param[in] onFileStruct General information about this file, such as the filename and the first \a partLength bytes. You do NOT need to save this data yourself. The complete file will arrive normally.
/// \param[in] partCount The zero based index into partTotal. The percentage complete done of this file is 100 * (partCount+1)/partTotal
/// \param[in] partTotal The total number of parts this file was split into. Each part will be roughly the MTU size, minus the UDP header and RakNet headers
/// \param[in] partLength How many bytes long firstDataChunk is
/// \param[in] firstDataChunk The first \a partLength of the final file. If you store identifying information about the file in the first \a partLength bytes, you can read them while the download is taking place. If this hasn't arrived yet, firstDataChunk will be 0
virtual void OnFileProgress(OnFileStruct *onFileStruct,unsigned int partCount,unsigned int partTotal,unsigned int partLength, char *firstDataChunk) {
(void) onFileStruct;
(void) partCount;
(void) partTotal;
(void) partLength;
(void) firstDataChunk;
}
/// Called while the handler is active by FileListTransfer
/// Return false when you are done with the class
/// At that point OnDereference will be called and the class will no longer be maintained by the FileListTransfer plugin.
virtual bool Update(void) {return true;}
/// Called when the download is completed.
/// If you are finished with this class, return false
/// At that point OnDereference will be called and the class will no longer be maintained by the FileListTransfer plugin.
/// Otherwise return true, and Update will continue to be called.
virtual bool OnDownloadComplete(void) {return false;}
/// This function is called when this instance is about to be dereferenced by the FileListTransfer plugin.
/// Update will no longer be called.
/// It will will be deleted automatically if true was passed to FileListTransfer::SetupReceive::deleteHandler
/// Otherwise it is up to you to delete it yourself.
virtual void OnDereference(void) {}
};
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif

View File

@@ -0,0 +1,161 @@
#include "RakMemoryOverride.h"
#include "_FindFirst.h" // For linux
#include "FileOperations.h"
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
// For mkdir
#include <direct.h>
#include <io.h>
#else
#include <sys/stat.h>
#include <unistd.h>
#include "_FindFirst.h"
#endif
#include "errno.h"
#ifdef _MSC_VER
#pragma warning( push )
#endif
#ifdef _MSC_VER
#pragma warning( disable : 4966 ) // mkdir declared depreciated by Microsoft in order to make it harder to be cross platform. I don't agree it's depreciated.
#endif
bool WriteFileWithDirectories( const char *path, char *data, unsigned dataLength )
{
int index;
FILE *fp;
char *pathCopy;
int res;
if ( path == 0 || path[ 0 ] == 0 )
return false;
pathCopy = (char*) rakMalloc( strlen( path ) + 1 );
strcpy( pathCopy, path );
// Ignore first / if there is one
if (pathCopy[0])
{
index = 1;
while ( pathCopy[ index ] )
{
if ( pathCopy[ index ] == '/' || pathCopy[ index ] == '\\')
{
pathCopy[ index ] = 0;
#ifdef _WIN32
#pragma warning( disable : 4966 ) // mkdir declared depreciated by Microsoft in order to make it harder to be cross platform. I don't agree it's depreciated.
res = mkdir( pathCopy );
#else
res = mkdir( pathCopy, 0744 );
#endif
if (res<0 && errno!=EEXIST)
{
rakFree(pathCopy);
return false;
}
pathCopy[ index ] = '/';
}
index++;
}
}
if (data)
{
fp = fopen( path, "wb" );
if ( fp == 0 )
{
rakFree(pathCopy);
return false;
}
fwrite( data, 1, dataLength, fp );
fclose( fp );
}
else
{
#ifdef _WIN32
#pragma warning( disable : 4966 ) // mkdir declared depreciated by Microsoft in order to make it harder to be cross platform. I don't agree it's depreciated.
res = mkdir( pathCopy );
#else
res = mkdir( pathCopy, 0744 );
#endif
if (res<0 && errno!=EEXIST)
{
rakFree(pathCopy);
return false;
}
}
rakFree(pathCopy);
return true;
}
bool IsSlash(unsigned char c)
{
return c=='/' || c=='\\';
}
void AddSlash( char *input )
{
if (input==0 || input[0]==0)
return;
int lastCharIndex=(int) strlen(input)-1;
if (input[lastCharIndex]=='\\')
input[lastCharIndex]='/';
else if (input[lastCharIndex]!='/')
{
input[lastCharIndex+1]='/';
input[lastCharIndex+2]=0;
}
}
bool DirectoryExists(const char *directory)
{
_finddata_t fileInfo;
intptr_t dir;
char baseDirWithStars[560];
strcpy(baseDirWithStars, directory);
AddSlash(baseDirWithStars);
strcat(baseDirWithStars, "*.*");
dir=_findfirst(baseDirWithStars, &fileInfo );
if (dir==-1)
return false;
_findclose(dir);
return true;
}
void QuoteIfSpaces(char *str)
{
unsigned i;
bool hasSpace=false;
for (i=0; str[i]; i++)
{
if (str[i]==' ')
{
hasSpace=true;
break;
}
}
if (hasSpace)
{
int len=(int)strlen(str);
memmove(str+1, str, len);
str[0]='\"';
str[len]='\"';
str[len+1]=0;
}
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@@ -0,0 +1,12 @@
#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);
#endif

View File

@@ -0,0 +1,20 @@
#include "FormatString.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "LinuxStrings.h"
char * FormatString(const char *format, ...)
{
static int textIndex=0;
static char text[4][8096];
va_list ap;
va_start(ap, format);
if (++textIndex==4)
textIndex=0;
_vsnprintf(text[textIndex], 8096, format, ap);
va_end(ap);
text[textIndex][8096-1]=0;
return text[textIndex];
}

12
thirdparty/raknet/Source/FormatString.h vendored Normal file
View File

@@ -0,0 +1,12 @@
#ifndef __FORMAT_STRING_H
#define __FORMAT_STRING_H
#include "Export.h"
extern "C" {
char * FormatString(const char *format, ...);
}
#endif

View File

@@ -0,0 +1,114 @@
/// \file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#include "FullyConnectedMesh.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "BitStream.h"
#include "ConnectionGraph.h"
#include "NatPunchthrough.h"
#include <string.h>
#include <assert.h>
#ifdef _MSC_VER
#pragma warning( push )
#endif
FullyConnectedMesh::FullyConnectedMesh()
{
pw=0;
natPunchthrough=0;
}
FullyConnectedMesh::~FullyConnectedMesh()
{
if (pw)
rakFree(pw);
}
void FullyConnectedMesh::Startup(const char *password, int _passwordLength)
{
if (pw)
rakFree(pw);
if (password)
{
pw = (char*) rakMalloc( _passwordLength );
memcpy(pw, password, _passwordLength);
passwordLength=_passwordLength;
}
else
pw=0;
}
void FullyConnectedMesh::ConnectWithNatPunchthrough(NatPunchthrough *np, SystemAddress _facilitator)
{
natPunchthrough=np;
facilitator=_facilitator;
}
void FullyConnectedMesh::OnShutdown(RakPeerInterface *peer)
{
(void) peer;
}
void FullyConnectedMesh::Update(RakPeerInterface *peer)
{
(void) peer;
}
PluginReceiveResult FullyConnectedMesh::OnReceive(RakPeerInterface *peer, Packet *packet)
{
assert(packet);
assert(peer);
switch (packet->data[0])
{
case ID_REMOTE_NEW_INCOMING_CONNECTION: // This comes from the connection graph plugin
{
RakNet::BitStream b(packet->data, packet->length, false);
b.IgnoreBits(8);
ConnectionGraphGroupID group1, group2;
SystemAddress node1, node2;
b.Read(node1);
b.Read(group1);
if (peer->IsConnected(node1,true)==false)
{
if (natPunchthrough)
natPunchthrough->Connect(node1, pw, pw ? passwordLength : 0, facilitator);
else
peer->Connect(node1.ToString(false), node1.port, pw, pw ? passwordLength : 0);
}
b.Read(node2);
b.Read(group2);
if (peer->IsConnected(node2,true)==false)
{
if (natPunchthrough)
natPunchthrough->Connect(node2, pw, pw ? passwordLength : 0, facilitator);
else
peer->Connect(node2.ToString(false), node2.port, pw, pw ? passwordLength : 0);
}
break;
}
}
return RR_CONTINUE_PROCESSING;
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@@ -0,0 +1,65 @@
/// \file
/// \brief Fully connected mesh plugin. This will connect RakPeer to all connecting peers, and all peers the connecting peer knows about.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __FULLY_CONNECTED_MESH_H
#define __FULLY_CONNECTED_MESH_H
class RakPeerInterface;
class NatPunchthrough;
#include "PluginInterface.h"
#include "RakMemoryOverride.h"
/// \defgroup FULLY_CONNECTED_MESH_GROUP FullyConnectedMesh
/// \ingroup PLUGINS_GROUP
/// Fully connected mesh plugin. This will connect RakPeer to all connecting peers, and all peers the connecting peer knows about.
/// \pre You must also install the ConnectionGraph plugin. If you want a password, set it there.
/// \ingroup FULLY_CONNECTED_MESH_GROUP
class FullyConnectedMesh : public PluginInterface
{
public:
FullyConnectedMesh();
virtual ~FullyConnectedMesh();
// --------------------------------------------------------------------------------------------
// User functions
// --------------------------------------------------------------------------------------------
/// Set the password to use to connect to the other systems
void Startup(const char *password, int _passwordLength);
/// Use the NAT punchthrough system to connect rather than calling directly
/// \param[in] np Pointer to an attached instance of the NatPunchthrough plugin
/// \param[in] _facilitator Address of the NAT punchthrough facilitator
void ConnectWithNatPunchthrough(NatPunchthrough *np, SystemAddress _facilitator);
// --------------------------------------------------------------------------------------------
// Packet handling functions
// --------------------------------------------------------------------------------------------
virtual void OnShutdown(RakPeerInterface *peer);
virtual void Update(RakPeerInterface *peer);
virtual PluginReceiveResult OnReceive(RakPeerInterface *peer, Packet *packet);
protected:
char *pw;
int passwordLength;
NatPunchthrough *natPunchthrough;
SystemAddress facilitator;
};
#endif

View File

@@ -0,0 +1,147 @@
#include "FunctionThread.h"
#include "RakSleep.h"
using namespace RakNet;
#ifdef _MSC_VER
#pragma warning( push )
#endif
FunctionThread::FunctorAndContext WorkerThreadFunc(FunctionThread::FunctorAndContext input, bool *returnOutput, void* perThreadData)
{
(void) perThreadData;
FunctionThread::FunctorAndContext output;
input.functor->Process(input.context);
output.functor=input.functor;
output.context=input.context;
*returnOutput=true;
return output;
}
FunctionThread::FunctionThread()
{
pr=0;
}
FunctionThread::~FunctionThread()
{
StopThreads(false);
}
void FunctionThread::StartThreads(int numThreads)
{
threadPool.StartThreads(numThreads, 0);
}
void FunctionThread::StopThreads(bool blockOnCurrentProcessing)
{
// This ensures all waiting data is ultimately passed to a callback, so there are no leaks
CancelInput();
while (blockOnCurrentProcessing && threadPool.IsWorking())
{
CallResultHandlers();
RakSleep(30);
}
threadPool.StopThreads();
}
void FunctionThread::Push(Functor *functor, void *context)
{
FunctorAndContext input;
input.functor=functor;
input.context=context;
threadPool.AddInput(WorkerThreadFunc, input);
}
void FunctionThread::CallResultHandlers(void)
{
FunctorAndContext functorAndResult;
while (threadPool.HasOutputFast() && threadPool.HasOutput())
{
functorAndResult = threadPool.GetOutput();
functorAndResult.functor->HandleResult(false, functorAndResult.context);
if (pr) pr(functorAndResult);
}
}
void FunctionThread::CancelFunctorsWithContext(bool (*cancelThisFunctor)(FunctionThread::FunctorAndContext func, void *userData), void *userData)
{
FunctorAndContext functorAndResult;
unsigned i;
threadPool.LockInput();
for (i=0; i < threadPool.InputSize(); i++)
{
functorAndResult = threadPool.GetInputAtIndex(i);
if (cancelThisFunctor(functorAndResult, userData))
{
functorAndResult.functor->HandleResult(true, functorAndResult.context);
if (pr) pr(functorAndResult);
}
}
threadPool.ClearInput();
threadPool.UnlockInput();
}
void FunctionThread::SetPostResultFunction(void (*postResult)(FunctionThread::FunctorAndContext func))
{
pr=postResult;
}
void FunctionThread::CancelInput(void)
{
// We do it this way so that the callbacks get called so user-allocated data can be freed.
FunctorAndContext functorAndResult;
unsigned i;
threadPool.LockInput();
for (i=0; i < threadPool.InputSize(); i++)
{
functorAndResult = threadPool.GetInputAtIndex(i);
functorAndResult.functor->HandleResult(true, functorAndResult.context);
if (pr) pr(functorAndResult);
}
threadPool.ClearInput();
threadPool.UnlockInput();
}
FunctionThreadDependentClass::FunctionThreadDependentClass()
{
functionThreadWasAllocated=false;
functionThread=0;
}
FunctionThreadDependentClass::~FunctionThreadDependentClass()
{
if (functionThreadWasAllocated)
delete functionThread;
}
void FunctionThreadDependentClass::AssignFunctionThread(FunctionThread *ft)
{
if (functionThread && functionThreadWasAllocated)
{
functionThread->StopThreads(true);
delete functionThread;
}
functionThread=ft;
functionThreadWasAllocated=false;
}
void FunctionThreadDependentClass::StartFunctionThread(void)
{
if (functionThread==0)
{
functionThread = new FunctionThread;
functionThreadWasAllocated=true;
}
functionThread->StartThreads(1);
}
FunctionThread *FunctionThreadDependentClass::GetFunctionThread(void) const
{
return functionThread;
}
bool FunctionThreadDependentClass::GetFunctionThreadWasAllocated(void) const
{
return functionThreadWasAllocated;
}
void FunctionThreadDependentClass::PushFunctor(Functor *functor, void *context)
{
StartFunctionThread();
functionThread->Push(functor, context);
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@@ -0,0 +1,130 @@
/// \file
/// \brief A set of classes to make it easier to perform asynchronous function processing.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __FUNCTION_THREAD_H
#define __FUNCTION_THREAD_H
#include "SingleProducerConsumer.h"
#include "ThreadPool.h"
#include "RakMemoryOverride.h"
#include "Export.h"
namespace RakNet
{
// Forward declarations
class Functor;
/// FunctionThread takes a stream of classes that implement a processing function, processes them in a thread, and calls a callback with the result.
/// It's a useful way to call blocking functions that you do not want to block, such as file writes and database operations.
class RAK_DLL_EXPORT FunctionThread : public RakNet::RakMemoryOverride
{
public:
FunctionThread();
~FunctionThread();
struct FunctorAndContext
{
Functor *functor;
void *context;
};
/// Starts the thread up.
void StartThreads(int numThreads);
/// Stop processing. Will also call FunctorResultHandler callbacks with /a wasCancelled set to true.
/// \param[in] blockOnCurrentProcessing Wait for the current processing to finish?
void StopThreads(bool blockOnCurrentProcessing);
/// Add a functor to the incoming stream of functors
/// \note functor MUST be a valid pointer until Functor::HandleResult() is called, at which point the pointer is returned to you.
/// \note For practical purposes this means the instance of functor you pass to this function has to be allocated using new and delete.
/// \note You should deallocate the pointer inside Functor::HandleResult()
/// \param[in] functor A pointer to an implemented Functor class
/// \param[in] If there is some context to this functor you want to look up to cancel it, you can set it here. Returned back to you in Functor::HandleResult
void Push(Functor *functor, void *context=0);
/// Call FunctorResultHandler callbacks
/// Normally you would call this once per update cycle, although you do not have to.
void CallResultHandlers(void);
/// If you want to cancel input and output functors associated with some context, you can pass a function to do that here
/// \param[in] cancelThisFunctor Function should return true to cancel the functor, false to let it process
/// \param[in] userData Pointer to whatever you want. Passed to the cancelThisFunctor call
void CancelFunctorsWithContext(bool (*cancelThisFunctor)(FunctorAndContext func, void *userData), void *userData);
/// If you want to automatically do some kind of processing on every functor after Functor::HandleResult is called, set it here.
/// Useful to cleanup FunctionThread::Push::context
/// \param[in] postResult pointer to a C function to do post-processing
void SetPostResultFunction(void (*postResult)(FunctorAndContext func));
protected:
void CancelInput(void);
ThreadPool<FunctorAndContext, FunctorAndContext> threadPool;
void (*pr)(FunctorAndContext func);
};
/// A functor is a single unit of processing to send to the Function thread.
/// Derive from it, add your data, and implement the processing function.
class Functor : public RakNet::RakMemoryOverride
{
public:
Functor() {}
virtual ~Functor() {}
/// Do whatever processing you want.
/// \param[in] context pointer passed to FunctionThread::Push::context
virtual void Process(void *context)=0;
/// Called from FunctionThread::CallResultHandlers with wasCancelled false OR
/// Called from FunctionThread::StopThread or FunctionThread::~FunctionThread with wasCancelled true
/// \param[in] wasCancelledTrue if CallResultHandlers was called, false if StopThreads or CancelInputWithContext was called before Functor::Process()
/// \param[in] context pointer passed to FunctionThread::Push::context
virtual void HandleResult(bool wasCancelled, void *context)=0;
};
class RAK_DLL_EXPORT FunctionThreadDependentClass : public RakNet::RakMemoryOverride
{
public:
FunctionThreadDependentClass();
virtual ~FunctionThreadDependentClass();
/// Assigns a function thread to process asynchronous calls. If you do not assign one then one will be created automatically.
/// \param[in] ft An instance of a running function thread class. This class can be shared and used for other functors as well.
virtual void AssignFunctionThread(FunctionThread *ft);
/// \return Returns the function thread held in the class
FunctionThread *GetFunctionThread(void) const;
/// \returns Whether or not this class allocated the function thread by itself
bool GetFunctionThreadWasAllocated(void) const;
/// Allocates and starts the thread if needed, and pushes the functor
/// \param[in] functor Functor to push
/// \param[in] context Sent to FunctionThread::Push::context
virtual void PushFunctor(Functor *functor, void *context=0);
protected:
/// Allocates and starts the function thread, if necessary
void StartFunctionThread();
FunctionThread *functionThread;
bool functionThreadWasAllocated;
};
}
#endif

759
thirdparty/raknet/Source/Gen_RPC8.cpp vendored Normal file
View File

@@ -0,0 +1,759 @@
#include "Gen_RPC8.h"
unsigned int GenRPC::BuildStack(char *stack)
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 0);
return (unsigned int)(stackPtr-stack);
}
/// \internal
void GenRPC::Push( char*& p, char*const i, bool doEndianSwap) {
(void) doEndianSwap;
size_t len = strlen( i ) + 1;
memcpy( (void*)p, i, len );
p += len;
}
/// \internal
void GenRPC::Push( char*& p, const char*const i, bool doEndianSwap ) {
(void) doEndianSwap;
size_t len = strlen( i ) + 1;
memcpy( (void*)p, i, len );
p += len;
}
/// \internal
unsigned GenRPC::D_type( const char*const ) { return STR_PARAM; }
/// \internal
unsigned GenRPC::D_type( char*const ) { return STR_PARAM; }
/// \internal
unsigned GenRPC::D_type( float ) { return REAL_PARAM; }
/// \internal
unsigned GenRPC::D_type( double ) { return REAL_PARAM; }
/// \internal
unsigned GenRPC::D_type( long double ) { return REAL_PARAM; }
/// \internal
size_t GenRPC::D_size( char*const str ) { return strlen( str ) + 1; }
/// \internal
size_t GenRPC::D_size( char const *const str ){ return strlen( str ) + 1; }
void GenRPC::SerializeHeader(char *&out, unsigned int numParams)
{
*out = (char) numParams;
out++;
//out[*writeOffset]=(char) numParams;
//*writeOffset+=sizeof(unsigned char);
}
//
// @params
// call: [IN/OUT] workspace to build parameters that we will pass to function
// in: [IN/OUT] is the serialized buffer - used as a temporary working for swapping
// parameters.
// inLength: [IN] is the length of the above
// lastParam: [IN] final parameter, added onto the list
// thisPtr: [IN] if not zero - the value of this (added to start of list).
//
// @returns:
// true: parameter list created successfully.
// false: if deserialization fails for some reason.
//
bool GenRPC::DeserializeParametersAndBuildCall(
CallParams &call,
char *in, unsigned int inLength,
void *lastParam, void *thisPtr
) {
#if AUTO_RPC_ABI
NaturalWord *intCallParam = call.intParams;
char *refParam = call.refParams;
#if AUTO_RPC_ALLOC_SEPARATE_FLOATS
HardwareReal *realCallParam = call.realParams;
#endif
#if AUTO_RPC_CREATE_FLOAT_MAP
call.realMap = 0;
call.numRealParams = 0;
#endif
#if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
// large structure parameters have to be bumped up here - which corresponds with the start
// of the parameters that *are* passed on the stack.
NaturalWord *memParam = &call.intParams[ AUTO_RPC_INT_REG_PARAMS ];
#endif
// this is first arg - assume space ;-)
#pragma warning(disable:4311) // pointer truncation
if ( thisPtr )
*(intCallParam++) = reinterpret_cast<NaturalWord>( thisPtr );
unsigned int serializedArgs = *(unsigned char*)in;
unsigned char* header = (unsigned char*)in + 1;
unsigned char* data = &header[ serializedArgs * ( sizeof( unsigned int ) + 1 ) ];
// check we have the entire header in buffer
if ( data > (unsigned char*) &in[ inLength ] )
return 0;
for ( unsigned int i = 0; i < serializedArgs; i++ )
{
// read heade entry
int const plen = *(unsigned int*)header;
header += sizeof( unsigned int );
unsigned char const flags = *( header++ );
// Some bits are not used by the current implementation. So if we find them we bail because
// we clearly are not equipped to handle the data - and is there no safe way to "fail".
if ( flags & RESERVED_BITS )
return 0;
#ifndef __BITSTREAM_NATIVE_END
if (flags & DO_ENDIAN_SWAP)
{
RakNet::BitStream::ReverseBytesInPlace( (unsigned char*)&plen , sizeof( plen ) );
}
#endif
if ( !plen || data + plen > (unsigned char*)&in[ inLength ] )
return 0;
// handle null-terminated strings.
if ( ( flags & PARAM_TYPE_MASK ) == STR_PARAM )
{
if ( intCallParam + 1 >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
// Check this has some sort of null termination. NB this assumes string is genuine Ascii
// or UTF+8; using unicode (ie. UTF+16, UCS) could break this.
if ( data[ plen - 1 ] != 0 )
return 0;
// The string doesn't need to be aligned, so we leave it in place; saving a copy, and
// preventing clogging up of our buffers with data.
#pragma warning(disable:4311) // pointer truncation
*( intCallParam++ ) = reinterpret_cast<NaturalWord>( data );
data += plen;
continue;
}
#ifndef __BITSTREAM_NATIVE_END
if (flags & DO_ENDIAN_SWAP)
{
RakNet::BitStream::ReverseBytesInPlace( (unsigned char*)data , plen );
}
#endif
// convert pointer to ref.
if ( ( flags & PARAM_TYPE_MASK ) == REF_PARAM
#if AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD
|| plen > AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD
#endif
)
{
char *nextRefParam = refParam + AUTO_RPC__ALIGN_P2( plen, AUTO_RPC_REF_ALIGN );
if ( nextRefParam >= AUTO_RPC_ARRAY_END( call.refParams ) || intCallParam + 1 >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
memcpy( refParam, data, plen );
#pragma warning(disable:4311) // pointer truncation
*( intCallParam++ ) = reinterpret_cast<NaturalWord>( refParam );
refParam = nextRefParam;
data += plen;
continue;
}
// Guarantee we have space on the output stack to accommodate the parameter.
NaturalWord *nextParam = (NaturalWord*)( (char*)intCallParam + AUTO_RPC_ALIGN_P2( plen, NaturalWord ) );
if ( nextParam >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
#if AUTO_RPC_ALLOC_SEPARATE_FLOATS
if ( ( flags & PARAM_TYPE_MASK ) == REAL_PARAM
// long doubles, of various sizes (10, 16), all get passed on the stack
&& (size_t) plen <= sizeof(double)
// once we've allocated all our floats, they get treated as ordinary int params
&& realCallParam < AUTO_RPC_ARRAY_END( call.realParams )
)
{
if ( plen != sizeof( float ) && plen != sizeof( double ) ) {
printf("illegal float size %d\n", plen );
// We can't handle it - it's not a real real :lol:
return 0;
}
#ifdef __BIG_ENDIAN__
memcpy( (char*)( realCallParam + 1 ) - plen, data, plen );
#else
memcpy( (char*)realCallParam, data, plen );
#endif
#if !AUTO_RPC_INT_SHADOW_OF_FLOATS
// we didn't use the int slot, so don't allow an advance.
nextParam = intCallParam;
#endif
// next time, we use the next Real slot
realCallParam++;
}
#if !AUTO_RPC_INT_SHADOW_OF_FLOATS
else
#endif
#endif // AUTO_RPC_ALLOC_SEPARATE_FLOATS
{
// the processor can atomically zero-extend small types, so even with the test,
// it should be faster than memcpy+memset.
if ( plen == 1 )
*intCallParam = *(uint8_t*)data; // should resolve to movzx and a move
else if ( plen == 2 )
*intCallParam = *(uint16_t*)data; // if network order replace use htons(), and skip EndianSwap()
else if ( plen == 4 )
*intCallParam = *(uint32_t*)data; // if network order replace use htonl(), and skip EndianSwap()
#if AUTO_RPC_AUTORPC_WORD == 64
else if ( plen == 8 )
*intCallParam = *(uint64_t*)data;
#endif
#if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
//
// SYSV ABI: aggregates greater 16 bytes must go on the stack;
// in practice, that means they can't come below AUTO_RPC_INT_REG_PARAMS when we call a function.
//
else if ( plen > 16 || ( plen > 8 && intCallParam == &call.intParams[ AUTO_RPC_INT_REG_PARAMS - 1] ) || ( flags & REAL_PARAM ) )
{
if ( intCallParam < memParam )
{
NaturalWord*const nextMemParam = (NaturalWord*)( (char*)memParam + AUTO_RPC_ALIGN_P2( plen, NaturalWord ) );
if ( nextMemParam >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
memcpy( memParam, data, plen );
// prevent advancing the ptr slot, since we didn't use it.
nextParam = intCallParam;
// but advance the memparam
memParam = nextMemParam;
}
else
{
memcpy( (void*)intCallParam, data, plen );
}
}
#endif // AUTO_RPC_ABI_SYSV_AMD64
else
{
// We don't need to worry about alignment, because any type that's not a whole multiple
// of the natual word size will be an aggregate and that should be at the base of memory -
// this is true for some PowerPC systems (see [e]) but not all. But hey, you
// probably should be passing such structs by reference.
//
// Zeroing is also unecessary as code shouldn't be reading beyodn the bounds of the structure.
//
memcpy( (void*)intCallParam, data, plen );
}
}
#if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
// skip over any stored "class MEMORY" (see [b]) parameters.
if ( nextParam == &call.intParams[AUTO_RPC_INT_REG_PARAMS] )
intCallParam = memParam;
else
#endif
// advance to next output param
intCallParam = nextParam;
#if !AUTO_RPC_ALLOC_SEPARATE_FLOATS && AUTO_RPC_CREATE_FLOAT_MAP
if ( ( flags & PARAM_TYPE_MASK ) == REAL_PARAM && i < AUTO_RPC_FLOAT_REG_PARAMS && ( plen == sizeof( double ) || plen == sizeof( float ) ) )
{
call.numRealParams++;
call.realMap |= ( 1 << i );
}
#endif
// advance to next input arg.
data += plen;
}
// space for lastParam?
if ( &intCallParam[1] >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
#pragma warning(disable:4311) // pointer truncation
*( intCallParam++ ) = reinterpret_cast<NaturalWord >( lastParam );
#if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
// figure out how many args we have notched up.
if ( memParam > &call.intParams[AUTO_RPC_INT_REG_PARAMS] && memParam > intCallParam )
intCallParam = memParam;
#endif
// convert from ptrdif_t to unsigned int; should be small enough, even if its 64-bit pointers.
call.numIntParams = ( unsigned int )( intCallParam - call.intParams );
#if AUTO_RPC_FLOAT_REG_PARAMS && AUTO_RPC_ALLOC_SEPARATE_FLOATS
call.numRealParams = ( unsigned int )( realCallParam - call.realParams );
#endif
return 1;
#else // AUTO_RPC_ABI
return 0;
#endif
}
//
// @params
// callParams: [IN] parameter list
// functionPtr: [IN] function to call.
//
// @returns:
// true: function was called.
// false: too many parameters, probably.
//
bool GenRPC::CallWithStack( CallParams& call, void *functionPtr ) {
#if AUTO_RPC_ABI
// Are we x86-32?
#if !defined( AUTO_RPC_NO_ASM ) && ( defined(__i386__) || defined( _M_IX86 ) || defined( __INTEL__ ) )
#if !defined(__GNUC__)
// Intel dialect assembly
NaturalWord const paramc = call.numIntParams;
#pragma warning(disable:4311) // pointer truncation
NaturalWord const paramv = reinterpret_cast<NaturalWord>( call.intParams );
_asm
{
// Load numbytes.
mov ecx, paramc
// allocate space on the stack for all these params
lea edi,dword ptr[ecx * 4]
sub esp,edi
// setup source of copy
mov esi, paramv
// Setup the destination of the copy: the return stack.
mov edi,esp
// copy data
rep movs dword ptr es:[edi],dword ptr [esi]
// call the function
call functionPtr
// Restore the stack to its state, prior to our invocation.
//
// Detail: edi is one of the registers that must be preserved
// across function calls. (The compiler should be saving it for us.)
//
// We left edi pointing to the end of the block copied; i.e. the state
// of the stack prior to copying our params. So by loading it
// into the esp we can restore the return stack to the state prior
// to the copy.
//
mov esp,edi
};
#else
// GCC has its own form of asm block - so we'll always have to write two versions.
// Therefore, as we're writing it twice, we use the ATT dialect, because only later
// gcc support Intel dialect. This one also aligns the stack to a multiple of 16 bytes; which
// windows doesn't seem to care about.
// Be aware, we can't use offset of to get the address, as gcc insists on sticking.
// NaturalWord const paramv = reinterpret_cast<NaturalWord>( call.intParams );
asm (\
"lea 4(%%ecx),%%esi\n\
mov (%%ecx),%%ecx\n\
lea (,%%ecx,4),%%edi\n\
sub %%edi,%%esp\n\
mov $12,%%edx\n\
and %%esp,%%edx\n\
sub %%edx,%%esp\n\
mov %%esp,%%edi\n\
rep movsl %%ds:(%%esi),%%es:(%%edi)\n\
add %%edx,%%edi\n\
call *%1\n\
mov %%edi,%%esp"\
: /* no outputs */\
: "c" ( &call ), "m" (functionPtr)\
: "%edi" , "%esi", "%edx", "%eax"\
);
#endif // GNUC vs non GNUC
return 1;
#elif !defined( AUTO_RPC_NO_ASM ) && ( defined( _M_X64 ) || defined( __x86_64__ ) || defined( _M_AMD64 ) )
#if AUTO_RPC_ABI == AUTO_RPC_ABI_WIN_AMD64
NaturalWord const paramv = reinterpret_cast<NaturalWord>( call.intParams );
_asm {
// rcx := number of qwords to copy
mov rcx, paramc
// r9 := 0
sub r9,r9
// rsi => our parameter list.
mov rsi, paramv
// r9 := -(number of qwords to copy)
sub r9,rcx
// Preparation to align the stack to 16 byte boundary
mov rdx,8
// rdi => projected bottom of stack
lea rdi,dword ptr[rsp + r9 * 8]
// figure out if stack needs aligning
and rdx,rdi
// save stack into rbx
mov rbx,rsp
// align stack
sub rdi,rdx
mov rsp,rdi
// rdx => our parameter list
mov rdx,rsi
//
// copy data - we copy all parameters, because we have to
// create a shadow area; and this way its easiest.
//
rep movs qword ptr es:[edi],qword ptr [esi]
// load registers
// rcx|xmm0, rdx|xmm1,r8|xmm2,r9|xmm3
mov rcx,qword ptr [rdx]
mov r8,qword ptr 16[rdx]
movq xmm0,rcx
mov r9,qword ptr 24[rdx]
movq xmm2,r8
mov rdx,qword ptr 8[rdx]
movq xmm3,r9
movq xmm1,rdx
// call the function
call functionPtr
// Restore the stack to its state, prior to our invocation -
// saved in rbx.
mov rsp,rbx
}
#elif AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
//
// GCC won't generate a stack frame on higher optimization levels, so we don't touch it.
// on -O3 it inlines the code, breaking it because of the jump reference.
//
// I figure a 64-bit compiler will be recent enough to do Intel syntax. May need to change
// my mind on that. NB. Structure members are hard coded into this.
//
asm (\
".intel_syntax noprefix\n\
push rbx\n\
mov rax,rsi\n\
push r15\n\
mov ecx,dword ptr[rdi+8+8*8]\n\
lea rsi,[rdi+8+8*8+8]\n\
mov r15,rsp\n\
lea rbx,[rdi+8]\n\
sub r8,r8\n\
sub rsp,8\n\
sub rcx,6\n\
lea r9,[rsi + 6 * 8]\n\
jbe .L1\n\
sub r8,rcx\n\
mov rdx,8\n\
lea rdi,qword ptr[rsp + r8 * 8]\n\
and rdx,rdi\n\
mov rsi,r9\n\
sub rdi,rdx\n\
mov rsp,rdi\n\
rep movsq \n\
.L1:\n\
movq xmm0,[rbx]\n\
movq xmm1,[rbx+8]\n\
movq xmm2,[rbx+16]\n\
movq xmm3,[rbx+24]\n\
movq xmm4,[rbx+32]\n\
movq xmm5,[rbx+40]\n\
movq xmm6,[rbx+48]\n\
movq xmm7,[rbx+56]\n\
mov rdi,[r9-48]\n\
mov rsi,[r9-40]\n\
mov rdx,[r9-32]\n\
mov rcx,[r9-24]\n\
mov r8,[r9-16]\n\
mov r9,[r9-8]\n\
call rax\n\
mov rsp,r15\n\
pop r15\n\
pop rbx\n\
.att_syntax prefix"\
: /* no outputs */\
: "D" ( &call ), "S" (functionPtr)\
: "%rdx", "%rcx" , "%r8", "%r9", "%rax",\
"%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" );
// : "D", ( &call ), "c" ( &call.numIntParams ), "S" ( paramv ), "b" ( floatv ), "a" (functionPtr)
#else
#error unsupport ABI
#endif
return 1;
#else
// AUTO_RPC_NO_ASM or no x86-32/x86-64
//
// 4. Passing the parameters.
//
// The compiler knows how to call functions, so having sorted out the argument list,
// we just pass it to a function of the correct form - and let the compiler align stacks,
// load registers, place parameters where they should be.
//
// This is particularly important as GCC has control over the stack frame, and it can
// improperly frame it - for instance utilising red zones to save args, rather than pushing them.
// On PowerPC it must create the parameter passing area, too.
//
// The most brute force way, is to code a function call for every possible number of parameters
//
// switch( paramc ) {
// case 1: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord)) myfunc)( callParam[0] ); break;
// case 2: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord)) myfunc)( callParam[0], callParam[1] ); break;
// ...
// case 64: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord)) myfunc)( callParam[0], callParam[1], ... , callParam[63] ); break;
// }
//
// This is the only way to code WIN32 stdcall, for example, as the args must match exactly;
// and so the only way to call from C if you need to call WINAPI routines.
//
// 2) Fortunately most calling conventions allowing excessive args. So this means we could
// write something like below:
//
// ( (void(*)(...)) myfunc )( args[0],...,args[63] );
//
// And although this should work, its a huge performance penalty copying between memory
// locations for so many args.
//
// So we compromise - and do a stepped sequence. Noticing that the WIN64 ABI alwys requires
// space for three args anyway.
//
// And on SysV x64 systems, the first 6 args are passed in reg; so again, these are only
// copies into register, not memory copies. And finally that if we load word[n], word[n+1]
// is loaded into the cache - thus the overhead for loading is not as big as it might be.
//
// For most realistic cases, a dozen args would be excessive. Obviously, if you have
// a tested assembler equivalent, its probably better to use that.
//
//
#if AUTO_RPC_FLOAT_REG_PARAMS
if ( call.numRealParams == 0 )
#endif
{
if ( call.numIntParams <= 3 )
{
( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_3)) functionPtr )( AUTO_RPC_INT_ARGS_3( call ) );
return 1;
}
if ( call.numIntParams <= 6 )
{
( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_6)) functionPtr )( AUTO_RPC_INT_ARGS_6( call ) );
return 1;
}
if ( call.numIntParams <= 9 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_9))functionPtr)( AUTO_RPC_INT_ARGS_9( call ) );
return 1;
}
if ( call.numIntParams <= 12 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_12))functionPtr)( AUTO_RPC_INT_ARGS_12( call ) );
return 1;
}
if ( call.numIntParams <= 32 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_32))functionPtr)( AUTO_RPC_INT_ARGS_32( call ) );
return 1;
}
if ( call.numIntParams <= 64 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_64))functionPtr)( AUTO_RPC_INT_ARGS_64( call ) );
return 1;
}
}
#if AUTO_RPC_FLOAT_REG_PARAMS && !AUTO_RPC_ALLOC_SEPARATE_FLOATS
else
{
if ( call.numIntParams > 64 ) return 0;
switch( call.realMap )
{
// case 0: - no floats, never happens here.
case 1: ( (void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,NaturalWord,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.intParams[1], call.intParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 2:
((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,NaturalWord,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.realParams[1], call.intParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 3:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,NaturalWord,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.realParams[1], call.intParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 4: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.intParams[1], call.realParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 5:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.intParams[1], call.realParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 6:
((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.realParams[1], call.realParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 7:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.realParams[1], call.realParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 8: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.intParams[1], call.intParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 9:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.intParams[1], call.intParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 10:
((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.realParams[1], call.intParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 11:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.realParams[1], call.intParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 12: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.intParams[1], call.realParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 13:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.intParams[1], call.realParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 14:
((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.realParams[1], call.realParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 15:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.realParams[1], call.realParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
default: return 0;
}
}
#elif AUTO_RPC_FLOAT_REG_PARAMS
else
{
// we pass FLOAT args last for powerpc compatibility. And although it means we pass them twice,
// they should end up in the correct floating point register, with the rest of the integers in the
// correct place...
//
// NB if you want to write inline asm for powerpc, you'll have to be put it in a separate
// "naked" function to that uou can setup the parameter passing area and ensure its big enough.
// (GCC will delete functions that are unused - it will delete the body of functions that
// aren't called.)
//
if ( call.numIntParams <= 3 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_3,AUTO_RPC_FLOAT_REG_TYPE))functionPtr)( AUTO_RPC_INT_ARGS_3( call ), AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
if ( call.numIntParams <= 6 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_6,AUTO_RPC_FLOAT_REG_TYPE))functionPtr)( AUTO_RPC_INT_ARGS_6( call ),AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
if ( call.numIntParams <= 9 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_9,AUTO_RPC_FLOAT_REG_TYPE))functionPtr)( AUTO_RPC_INT_ARGS_9( call ),AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
if ( call.numIntParams <= 12 )
{
( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_12,AUTO_RPC_FLOAT_REG_TYPE)) functionPtr )( AUTO_RPC_INT_ARGS_12( call ), AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
if ( call.numIntParams <= 64 )
{
( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_64,AUTO_RPC_FLOAT_REG_TYPE)) functionPtr )( AUTO_RPC_INT_ARGS_64( call ), AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
}
#endif // AUTO_RPC_FLOAT_REG_PARAMS
return 0;
#endif // AUTO_RPC_NO_ASM
#else // AUTO_RPC_ABI
return 0;
#endif
}
// --8<---8<----8<----8<---END

1022
thirdparty/raknet/Source/Gen_RPC8.h vendored Normal file

File diff suppressed because it is too large Load Diff

179
thirdparty/raknet/Source/GetTime.cpp vendored Normal file
View File

@@ -0,0 +1,179 @@
/// \file
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#include "GetTime.h"
#ifdef _XBOX360
#include "Console1Includes.h" // Developers of a certain platform will know what to do here.
#elif defined(_WIN32)
#include <windows.h>
DWORD mProcMask;
DWORD mSysMask;
HANDLE mThread;
static LARGE_INTEGER yo;
#elif defined(_PS3)
#include "Console2Includes.h"
#include <sys/sys_time.h> // GetTime.cpp
#include <stdint.h> // GetTime.cpp
#include <sys/time_util.h> // GetTime.cpp
uint64_t ticksPerSecond;
uint64_t initialTime;
#else
#include <sys/time.h>
#include <unistd.h>
static timeval tp;
RakNetTimeNS initialTime;
#endif
static bool initialized=false;
int queryCount=0;
RakNetTime RakNet::GetTime( void )
{
return (RakNetTime)(GetTimeNS()/1000);
}
RakNetTimeNS RakNet::GetTimeNS( void )
{
#if defined(_PS3)
uint64_t curTime;
if ( initialized == false)
{
ticksPerSecond = _PS3_GetTicksPerSecond();
// Use the function to get elapsed ticks, this is a macro.
_PS3_GetElapsedTicks(curTime);
uint64_t quotient, remainder;
quotient=(curTime / ticksPerSecond);
remainder=(curTime % ticksPerSecond);
initialTime = (RakNetTimeNS) quotient*(RakNetTimeNS)1000000 + (remainder*(RakNetTimeNS)1000000 / ticksPerSecond);
initialized = true;
}
#elif defined(_WIN32)
// Win32
if ( initialized == false)
{
initialized = true;
#if !defined(_WIN32_WCE)
// Save the current process
HANDLE mProc = GetCurrentProcess();
// Get the current Affinity
#if _MSC_VER >= 1400 && defined (_M_X64)
GetProcessAffinityMask(mProc, (PDWORD_PTR)&mProcMask, (PDWORD_PTR)&mSysMask);
#else
GetProcessAffinityMask(mProc, &mProcMask, &mSysMask);
#endif
mThread = GetCurrentThread();
#endif // !defined(_WIN32_WCE)
QueryPerformanceFrequency( &yo );
}
// 01/12/08 - According to the docs "The frequency cannot change while the system is running." so this shouldn't be necessary
/*
if (++queryCount==200)
{
// Set affinity to the first core
SetThreadAffinityMask(mThread, 1);
QueryPerformanceFrequency( &yo );
// Reset affinity
SetThreadAffinityMask(mThread, mProcMask);
queryCount=0;
}
*/
#elif (defined(__GNUC__) || defined(__GCCXML__))
if ( initialized == false)
{
gettimeofday( &tp, 0 );
initialized=true;
// I do this because otherwise RakNetTime in milliseconds won't work as it will underflow when dividing by 1000 to do the conversion
initialTime = ( tp.tv_sec ) * (RakNetTimeNS) 1000000 + ( tp.tv_usec );
}
#endif
#if defined(_PS3)
// Use the function to get elapsed ticks, this is a macro.
_PS3_GetElapsedTicks(curTime);
uint64_t quotient, remainder;
quotient=(curTime / ticksPerSecond);
remainder=(curTime % ticksPerSecond);
curTime = (RakNetTimeNS) quotient*(RakNetTimeNS)1000000 + (remainder*(RakNetTimeNS)1000000 / ticksPerSecond);
// Subtract from initialTime so the millisecond conversion does not underflow
return curTime - initialTime;
#elif defined(_WIN32)
RakNetTimeNS curTime;
static RakNetTimeNS lastQueryVal=(RakNetTimeNS)0;
static unsigned long lastTickCountVal = GetTickCount();
LARGE_INTEGER PerfVal;
#if !defined(_WIN32_WCE)
// Set affinity to the first core
SetThreadAffinityMask(mThread, 1);
#endif // !defined(_WIN32_WCE)
// Docs: On a multiprocessor computer, it should not matter which processor is called.
// However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL). To specify processor affinity for a thread, use the SetThreadAffinityMask function.
// Query the timer
QueryPerformanceCounter( &PerfVal );
#if !defined(_WIN32_WCE)
// Reset affinity
SetThreadAffinityMask(mThread, mProcMask);
#endif // !defined(_WIN32_WCE)
__int64 quotient, remainder;
quotient=((PerfVal.QuadPart) / yo.QuadPart);
remainder=((PerfVal.QuadPart) % yo.QuadPart);
curTime = (RakNetTimeNS) quotient*(RakNetTimeNS)1000000 + (remainder*(RakNetTimeNS)1000000 / yo.QuadPart);
#if !defined(_WIN32_WCE)
if (lastQueryVal==0)
{
// First call
lastQueryVal=curTime;
return curTime;
}
// To workaround http://support.microsoft.com/kb/274323 where the timer can sometimes jump forward by hours or days
unsigned long curTickCount = GetTickCount();
unsigned elapsedTickCount = curTickCount - lastTickCountVal;
RakNetTimeNS elapsedQueryVal = curTime - lastQueryVal;
if (elapsedQueryVal/1000 > elapsedTickCount+100)
{
curTime=lastQueryVal+elapsedTickCount*1000;
}
lastTickCountVal=curTickCount;
lastQueryVal=curTime;
#endif
return curTime;
#elif (defined(__GNUC__) || defined(__GCCXML__))
// GCC
RakNetTimeNS curTime;
gettimeofday( &tp, 0 );
curTime = ( tp.tv_sec ) * (RakNetTimeNS) 1000000 + ( tp.tv_usec );
// Subtract from initialTime so the millisecond conversion does not underflow
return curTime - initialTime;
#endif
}

33
thirdparty/raknet/Source/GetTime.h vendored Normal file
View File

@@ -0,0 +1,33 @@
/// \file
/// \brief Returns the value from QueryPerformanceCounter. This is the function RakNet uses to represent time.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __GET_TIME_H
#define __GET_TIME_H
#include "Export.h"
#include "RakNetTypes.h" // For RakNetTime
/// The namespace RakNet is not consistently used. It's only purpose is to avoid compiler errors for classes whose names are very common.
/// For the most part I've tried to avoid this simply by using names very likely to be unique for my classes.
namespace RakNet
{
/// Returns the value from QueryPerformanceCounter. This is the function RakNet uses to represent time.
RakNetTime RAK_DLL_EXPORT GetTime( void );
RakNetTimeNS RAK_DLL_EXPORT GetTimeNS( void );
}
#endif

View File

@@ -0,0 +1,191 @@
#include "RakAssert.h"
#include "GridSectorizer.h"
//#include <stdlib.h>
#include <math.h>
GridSectorizer::GridSectorizer()
{
grid=0;
}
GridSectorizer::~GridSectorizer()
{
if (grid)
delete [] grid;
}
void GridSectorizer::Init(const float _maxCellWidth, const float _maxCellHeight, const float minX, const float minY, const float maxX, const float maxY)
{
RakAssert(_maxCellWidth > 0.0f && _maxCellHeight > 0.0f);
if (grid)
delete [] grid;
cellOriginX=minX;
cellOriginY=minY;
gridWidth=maxX-minX;
gridHeight=maxY-minY;
gridCellWidthCount=(int) ceil(gridWidth/_maxCellWidth);
gridCellHeightCount=(int) ceil(gridHeight/_maxCellHeight);
// Make the cells slightly smaller, so we allocate an extra unneeded cell if on the edge. This way we don't go outside the array on rounding errors.
cellWidth=gridWidth/gridCellWidthCount;
cellHeight=gridHeight/gridCellHeightCount;
invCellWidth = 1.0f / cellWidth;
invCellHeight = 1.0f / cellHeight;
#ifdef _USE_ORDERED_LIST
grid = new DataStructures::OrderedList<void*, void*>[gridCellWidthCount*gridCellHeightCount];
DataStructures::OrderedList<void*,void*>::IMPLEMENT_DEFAULT_COMPARISON();
#else
grid = new DataStructures::List<void*>[gridCellWidthCount*gridCellHeightCount];
#endif
}
void GridSectorizer::AddEntry(void *entry, const float minX, const float minY, const float maxX, const float maxY)
{
RakAssert(cellWidth>0.0f);
RakAssert(minX < maxX && minY < maxY);
int xStart, yStart, xEnd, yEnd, xCur, yCur;
xStart=WorldToCellXOffsetAndClamped(minX);
yStart=WorldToCellYOffsetAndClamped(minY);
xEnd=WorldToCellXOffsetAndClamped(maxX);
yEnd=WorldToCellYOffsetAndClamped(maxY);
for (xCur=xStart; xCur <= xEnd; ++xCur)
{
for (yCur=yStart; yCur <= yEnd; ++yCur)
{
#ifdef _USE_ORDERED_LIST
grid[yCur*gridCellWidthCount+xCur].Insert(entry,entry, true);
#else
grid[yCur*gridCellWidthCount+xCur].Insert(entry);
#endif
}
}
}
#ifdef _USE_ORDERED_LIST
void GridSectorizer::RemoveEntry(void *entry, const float minX, const float minY, const float maxX, const float maxY)
{
RakAssert(cellWidth>0.0f);
RakAssert(minX <= maxX && minY <= maxY);
int xStart, yStart, xEnd, yEnd, xCur, yCur;
xStart=WorldToCellXOffsetAndClamped(minX);
yStart=WorldToCellYOffsetAndClamped(minY);
xEnd=WorldToCellXOffsetAndClamped(maxX);
yEnd=WorldToCellYOffsetAndClamped(maxY);
for (xCur=xStart; xCur <= xEnd; ++xCur)
{
for (yCur=yStart; yCur <= yEnd; ++yCur)
{
grid[yCur*gridCellWidthCount+xCur].RemoveIfExists(entry);
}
}
}
void GridSectorizer::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)
{
RakAssert(cellWidth>0.0f);
RakAssert(sourceMinX < sourceMaxX && sourceMinY < sourceMaxY);
RakAssert(destMinX < destMaxX && destMinY < destMaxY);
if (PositionCrossesCells(sourceMinX, sourceMinY, destMinX, destMinY)==false &&
PositionCrossesCells(destMinX, destMinY, destMinX, destMinY)==false)
return;
int xStartSource, yStartSource, xEndSource, yEndSource;
int xStartDest, yStartDest, xEndDest, yEndDest;
int xCur, yCur;
xStartSource=WorldToCellXOffsetAndClamped(sourceMinX);
yStartSource=WorldToCellYOffsetAndClamped(sourceMinY);
xEndSource=WorldToCellXOffsetAndClamped(sourceMaxX);
yEndSource=WorldToCellYOffsetAndClamped(sourceMaxY);
xStartDest=WorldToCellXOffsetAndClamped(destMinX);
yStartDest=WorldToCellYOffsetAndClamped(destMinY);
xEndDest=WorldToCellXOffsetAndClamped(destMaxX);
yEndDest=WorldToCellYOffsetAndClamped(destMaxY);
// Remove source that is not in dest
for (xCur=xStartSource; xCur <= xEndSource; ++xCur)
{
for (yCur=yStartSource; yCur <= yEndSource; ++yCur)
{
if (xCur < xStartDest || xCur > xEndDest ||
yCur < yStartDest || yCur > yEndDest)
{
grid[yCur*gridCellWidthCount+xCur].RemoveIfExists(entry);
}
}
}
// Add dest that is not in source
for (xCur=xStartDest; xCur <= xEndDest; ++xCur)
{
for (yCur=yStartDest; yCur <= yEndDest; ++yCur)
{
if (xCur < xStartSource || xCur > xEndSource ||
yCur < yStartSource || yCur > yEndSource)
{
grid[yCur*gridCellWidthCount+xCur].Insert(entry,entry, true);
}
}
}
}
#endif
void GridSectorizer::GetEntries(DataStructures::List<void*>& intersectionList, const float minX, const float minY, const float maxX, const float maxY)
{
#ifdef _USE_ORDERED_LIST
DataStructures::OrderedList<void*, void*>* cell;
#else
DataStructures::List<void*>* cell;
#endif
int xStart, yStart, xEnd, yEnd, xCur, yCur;
unsigned index;
xStart=WorldToCellXOffsetAndClamped(minX);
yStart=WorldToCellYOffsetAndClamped(minY);
xEnd=WorldToCellXOffsetAndClamped(maxX);
yEnd=WorldToCellYOffsetAndClamped(maxY);
intersectionList.Clear(true);
for (xCur=xStart; xCur <= xEnd; ++xCur)
{
for (yCur=yStart; yCur <= yEnd; ++yCur)
{
cell = grid+yCur*gridCellWidthCount+xCur;
for (index=0; index < cell->Size(); ++index)
intersectionList.Insert(cell->operator [](index));
}
}
}
bool GridSectorizer::PositionCrossesCells(const float originX, const float originY, const float destinationX, const float destinationY) const
{
return originX/cellWidth!=destinationX/cellWidth || originY/cellHeight!=destinationY/cellHeight;
}
int GridSectorizer::WorldToCellX(const float input) const
{
return (int)((input-cellOriginX)*invCellWidth);
}
int GridSectorizer::WorldToCellY(const float input) const
{
return (int)((input-cellOriginY)*invCellHeight);
}
int GridSectorizer::WorldToCellXOffsetAndClamped(const float input) const
{
int cell=WorldToCellX(input);
cell = cell > 0 ? cell : 0; // __max(cell,0);
cell = gridCellWidthCount-1 < cell ? gridCellWidthCount-1 : cell; // __min(gridCellWidthCount-1, cell);
return cell;
}
int GridSectorizer::WorldToCellYOffsetAndClamped(const float input) const
{
int cell=WorldToCellY(input);
cell = cell > 0 ? cell : 0; // __max(cell,0);
cell = gridCellHeightCount-1 < cell ? gridCellHeightCount-1 : cell; // __min(gridCellHeightCount-1, cell);
return cell;
}
void GridSectorizer::Clear(void)
{
int cur;
int count = gridCellWidthCount*gridCellHeightCount;
for (cur=0; cur<count;cur++)
grid[cur].Clear(true);
}

View File

@@ -0,0 +1,68 @@
#ifndef _GRID_SECTORIZER_H
#define _GRID_SECTORIZER_H
//#define _USE_ORDERED_LIST
#include "RakMemoryOverride.h"
#ifdef _USE_ORDERED_LIST
#include "DS_OrderedList.h"
#else
#include "DS_List.h"
#endif
class GridSectorizer : public RakNet::RakMemoryOverride
{
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

View File

@@ -0,0 +1,189 @@
/// \file
/// \brief Contains HTTPConnection, used to communicate with web servers
///
/// This file is part of RakNet Copyright 2008 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#include "TCPInterface.h"
#include "HTTPConnection.h"
#include "RakSleep.h"
#include "RakString.h"
#include "RakAssert.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
using namespace RakNet;
HTTPConnection::HTTPConnection(TCPInterface& _tcp, const char *_host, unsigned short _port)
: tcp(_tcp), host(_host), port(_port), state(RAK_HTTP_INITIAL) {}
void HTTPConnection::Post(const char *remote_path, const char *data, const char *_contentType)
{
if(state == RAK_HTTP_IDLE)
state = RAK_HTTP_ESTABLISHED;
else if(state == RAK_HTTP_INITIAL)
state = RAK_HTTP_STARTING;
else
return;
outgoing = data;
path = remote_path;
contentType=_contentType;
incoming.Clear();
}
bool HTTPConnection::HasBadResponse(int *code, RakNet::RakString *data)
{
if(badResponses.IsEmpty())
return false;
if (code)
*code = badResponses.Peek().code;
if (data)
*data = badResponses.Pop().data;
return true;
}
bool HTTPConnection::InList(StatusCheckFunction func)
{
SystemAddress address = (tcp.*func)();
if(address == UNASSIGNED_SYSTEM_ADDRESS)
return false;
server = address;
return true;
}
void HTTPConnection::Update(void)
{
if(InList(&TCPInterface::HasCompletedConnectionAttempt))
state = RAK_HTTP_ESTABLISHED;
if(InList(&TCPInterface::HasFailedConnectionAttempt))
state = RAK_HTTP_STARTING; // retry
// normally, HTTP servers close the stream after sending data
if(InList(&TCPInterface::HasLostConnection))
state = RAK_HTTP_INITIAL;
if(state == RAK_HTTP_STARTING)
{
server = tcp.Connect(host, port, false);
state = RAK_HTTP_CONNECTING;
}
if(state == RAK_HTTP_ESTABLISHED)
{
RakString request("POST %s HTTP/1.0\r\n"
"Host: %s\r\n"
"Content-Type: %s\r\n"
"Content-Length: %u\r\n"
"\r\n"
"%s",
path.C_String(),
host.C_String(),
contentType.C_String(),
(unsigned) outgoing.GetLength(),
outgoing.C_String());
tcp.Send(request, (unsigned int) strlen(request), server);
state = RAK_HTTP_REQUEST_SENT;
}
}
RakString HTTPConnection::Read(void)
{
const char *start_of_body = strstr(incoming, "\r\n\r\n");
if(! start_of_body)
{
badResponses.Push(BadResponse(incoming, HTTPConnection::NoBody));
return RakString();
}
return RakString(start_of_body + 4);
}
SystemAddress HTTPConnection::GetServerAddress(void) const
{
return server;
}
bool HTTPConnection::ProcessFinalTCPPacket(Packet *packet)
{
RakAssert(packet);
// read all the packets possible
if(packet->systemAddress == server)
{
if(incoming.GetLength() == 0)
{
int response_code = atoi((char *)packet->data + strlen("HTTP/1.0 "));
if(response_code > 299)
badResponses.Push(BadResponse(packet->data, response_code));
}
incoming += (char *)packet->data; // safe because TCPInterface Null-terminates
assert(strlen((char *)packet->data) == packet->length); // otherwise it contains Null bytes
const char *start_of_body = strstr(incoming, "\r\n\r\n");
// besides having the server close the connection, they may
// provide a length header and supply that many bytes
if(start_of_body && state == RAK_HTTP_REQUEST_SENT)
{
if (strstr((const char*) packet->data, "\r\nConnection: close\r\n"))
{
state = RAK_HTTP_IDLE;
}
else
{
long length_of_headers = (long)(start_of_body + 4 - incoming.C_String());
const char *length_header = strstr(incoming, "\r\nLength: ");
if(length_header)
{
long length = atol(length_header + 10) + length_of_headers;
if((long) incoming.GetLength() >= length)
state = RAK_HTTP_IDLE;
}
}
}
}
return IsBusy()==false;
}
bool HTTPConnection::IsBusy(void) const
{
return state != RAK_HTTP_IDLE && state != RAK_HTTP_INITIAL;
}
int HTTPConnection::GetState(void) const
{
return state;
}
HTTPConnection::~HTTPConnection(void)
{
tcp.CloseConnection(server);
}

View File

@@ -0,0 +1,127 @@
/// \file
/// \brief Contains HTTPConnection, used to communicate with web servers
///
/// This file is part of RakNet Copyright 2008 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __HTTP_CONNECTION
#define __HTTP_CONNECTION
#include "Export.h"
#include "RakString.h"
#include "RakMemoryOverride.h"
#include "RakNetTypes.h"
#include "DS_Queue.h"
class TCPInterface;
struct SystemAddress;
/// \brief Use HTTPConnection to communicate with a web server.
/// Start an instance of TCPInterface via the Start() command.
/// Instantiate a new instance of HTTPConnection, and associate TCPInterface with the class in the constructor.
/// Use Post() to send commands to the web server, and ProcessDataPacket() to update the connection with packets returned from TCPInterface that have the system address of the web server
/// This class will handle connecting and reconnecting as necessary.
///
/// Note that only one Post() can be handled at a time.
class RAK_DLL_EXPORT HTTPConnection : public RakNet::RakMemoryOverride
{
public:
/// Returns a HTTP object associated with this tcp connection
/// \pre tcp should already be started
HTTPConnection(TCPInterface& tcp, const char *host, unsigned short port=80);
virtual ~HTTPConnection();
/// Submit data to the HTTP server
/// HTTP only allows one request at a time per connection
///
/// \pre IsBusy()==false
/// \param path the path on the remote server you want to POST to. For example "mywebpage/index.html"
/// \param data A NULL terminated string to submit to the server
/// \param contentType "Content-Type:" passed to post.
void Post(const char *path, const char *data, const char *_contentType="application/x-www-form-urlencoded");
/// Get data returned by the HTTP server
/// If IsFinished()==false then this may be empty or a partial
/// response.
RakNet::RakString Read(void);
/// Call periodically to do time-based updates
void Update(void);
/// Returns the address of the server we are connected to
SystemAddress GetServerAddress(void) const;
/// Process an HTTP data packet returned from TCPInterface
/// Returns true when we have gotten all the data from the HTTP server.
/// If this returns true then it's safe to Post() another request
/// Deallocate the packet as usual via TCPInterface
/// \param packet NULL or a packet associated with our host and port
/// \return true when all data from one Post() has been read.
bool ProcessFinalTCPPacket(Packet *packet);
/// Results of HTTP requests. Standard response codes are < 999
/// ( define HTTP codes and our internal codes as needed )
enum ResponseCodes { NoBody=1001, OK=200, Deleted=1002 };
HTTPConnection& operator=(const HTTPConnection& rhs){(void) rhs; return *this;}
/// Encapsulates a raw HTTP response and response code
struct BadResponse
{
public:
BadResponse() {code=0;}
BadResponse(const unsigned char *_data, int _code)
: data((const char *)_data), code(_code) {}
BadResponse(const char *_data, int _code)
: data(_data), code(_code) {}
operator int () const { return code; }
RakNet::RakString data;
int code; // ResponseCodes
};
/// Queued events of failed exchanges with the HTTP server
bool HasBadResponse(int *code, RakNet::RakString *data);
/// Returns false if the connection is not doing anything else
bool IsBusy(void) const;
/// \internal
int GetState(void) const;
private:
SystemAddress server;
TCPInterface& tcp;
RakNet::RakString host;
unsigned short port;
enum { RAK_HTTP_INITIAL,
RAK_HTTP_STARTING,
RAK_HTTP_CONNECTING,
RAK_HTTP_ESTABLISHED,
RAK_HTTP_REQUEST_SENT,
RAK_HTTP_IDLE } state;
RakNet::RakString outgoing, incoming, path, contentType;
DataStructures::Queue<BadResponse> badResponses;
void Process(Packet *packet); // the workhorse
// this helps check the various status lists in TCPInterface
typedef SystemAddress (TCPInterface::*StatusCheckFunction)(void);
bool InList(StatusCheckFunction func);
};
#endif

View File

@@ -0,0 +1,49 @@
#include "InlineFunctor.h"
void InlineFunctor::HandleResult(bool wasCancelled, void *context)
{
ifp->Pop(callDepth);
}
InlineFunctorProcessor::InlineFunctorProcessor()
{
}
InlineFunctorProcessor::~InlineFunctorProcessor()
{
StopThreads(false);
}
void InlineFunctorProcessor::StartThreads(int numThreads)
{
functionThread.StartThreads(numThreads);
}
void InlineFunctorProcessor::StopThreads(bool blockOnCurrentProcessing)
{
functionThread.StopThreads(blockOnCurrentProcessing);
}
void InlineFunctorProcessor::YieldOnFunctor(InlineFunctor *inlineFunctor)
{
inlineFunctor->callDepth=GetCallDepth();
inlineFunctor->ifp=this;
functionThread.Push(inlineFunctor);
completedThreads.Push(false);
}
bool InlineFunctorProcessor::UpdateIFP(void)
{
functionThread.CallResultHandlers();
if (completedThreads.Size() && completedThreads[completedThreads.Size()-1]==true)
{
completedThreads.Pop();
return true;
}
return false;
}
void InlineFunctorProcessor::Pop(int threadCallDepth)
{
completedThreads[threadCallDepth]=true;
}
unsigned InlineFunctorProcessor::GetCallDepth(void) const
{
return completedThreads.Size();
}

View File

@@ -0,0 +1,61 @@
#include "FunctionThread.h"
#include "DS_List.h"
class InlineFunctorProcessor;
/// A base class to derive functors from for the InlineFunctorProcessor system
class InlineFunctor : public RakNet::Functor
{
protected:
/// \internal - Calls InlineFunctorProcessor to signal that the functor is done
virtual void HandleResult(bool wasCancelled, void *context);
/// Tracks the call depth when this functor was pushed. It allows the system to return from functions in the correct order
int callDepth;
/// Pointer to the calling instance of InlineFunctorProcessor
InlineFunctorProcessor *ifp;
friend class InlineFunctorProcessor;
};
/// A base class that will allow you to call YieldOnFunctor() from within a function, and continue with that function when the asynchronous processing has completed
class InlineFunctorProcessor
{
public:
InlineFunctorProcessor();
~InlineFunctorProcessor();
/// Start the threads. Should call this first
/// \param[in] numThreads How many worker threads to start
/// \note If only one thread is started, then the calls to YieldOnFunctor will process in that order
void StartThreads(int numThreads);
/// Stop the threads
/// \param[in] blockOnCurrentProcessing Wait for the current processing to finish?
void StopThreads(bool blockOnCurrentProcessing);
/// Yield processing in the current function, continuing with the function implemented by CallYieldFunction
/// When the functor completes, this function will return and the caller will continue processing
/// \param[in] inlineFunctor A class that implements Functor::Process() to perform processing that can work asynchronously, such as loading a file or doing a database call
void YieldOnFunctor(InlineFunctor *inlineFunctor);
/// \internal
/// If the functor is done, continue processing the caller
/// \return True if the topmost functor has completed, false otherwise
bool UpdateIFP(void);
/// \internal
/// Notify the caller that the functor is done
void Pop(int threadCallDepth);
protected:
/// Returns the number of functors that were passed to the system
unsigned GetCallDepth(void) const;
/// Used to create a thread that processes functors
RakNet::FunctionThread functionThread;
/// Tracks which threads have been completed
DataStructures::List<bool> completedThreads;
};

View File

@@ -0,0 +1,91 @@
/// \file
/// \brief \b [Internal] A class which stores a user message, and all information associated with sending and receiving that message.
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
///
/// Usage of RakNet is subject to the appropriate license agreement.
/// Creative Commons Licensees are subject to the
/// license found at
/// http://creativecommons.org/licenses/by-nc/2.5/
/// Single application licensees are subject to the license found at
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
/// Custom license users are subject to the terms therein.
/// GPL license users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.
#ifndef __INTERNAL_PACKET_H
#define __INTERNAL_PACKET_H
#include "PacketPriority.h"
#include "RakNetTypes.h"
#include "RakMemoryOverride.h"
typedef unsigned short SplitPacketIdType;
typedef unsigned int SplitPacketIndexType;
/// This is the counter used for holding packet numbers, so we can detect duplicate packets. It should be large enough that if the variables
/// were to wrap, the newly wrapped values would no longer be in use. Warning: Too large of a value wastes bandwidth!
/// Use the smallest possible value, such that you send no more than rangeof(MessageNumberType) / GetTimeoutTime() packets per second
/// For the default value of 10 seconds, this is
/// unsigned char - 25.5 packets per second
/// unsigned short - 6553.5 packets per second
/// unsigned int - You'll run out of memory first.
typedef unsigned int MessageNumberType;
/// This is the counter used for holding ordered packet numbers, so we can detect out-of-order packets. It should be large enough that if the variables
/// were to wrap, the newly wrapped values would no longer be in use. Warning: Too large of a value wastes bandwidth!
typedef MessageNumberType OrderingIndexType;
typedef RakNetTime RemoteSystemTimeType;
/// Holds a user message, and related information
/// Don't use a constructor or destructor, due to the memory pool I am using
struct InternalPacket : public RakNet::RakMemoryOverride//<InternalPacket>
{
///True if this is an acknowledgment packet
//bool isAcknowledgement;
/// A unique numerical identifier given to this user message. Used to identify messages on the network
MessageNumberType messageNumber;
/// Identifies the order in which this number was sent. Used locally
MessageNumberType messageInternalOrder;
/// Has this message number been assigned yet? We don't assign until the message is actually sent.
/// This fixes a bug where pre-determining message numbers and then sending a message on a different channel creates a huge gap.
/// This causes performance problems and causes those messages to timeout.
bool messageNumberAssigned;
/// Used only for tracking packetloss and windowing internally, this is the aggreggate packet number that a message was last sent in
unsigned packetNumber;
/// Was this packet number used this update to track windowing drops or increases? Each packet number is only used once per update.
// bool allowWindowUpdate;
///The priority level of this packet
PacketPriority priority;
///What type of reliability algorithm to use with this packet
PacketReliability reliability;
///What ordering channel this packet is on, if the reliability type uses ordering channels
unsigned char orderingChannel;
///The ID used as identification for ordering channels
OrderingIndexType orderingIndex;
///The ID of the split packet, if we have split packets. This is the maximum number of split messages we can send simultaneously per connection.
SplitPacketIdType splitPacketId;
///If this is a split packet, the index into the array of subsplit packets
SplitPacketIndexType splitPacketIndex;
///The size of the array of subsplit packets
SplitPacketIndexType splitPacketCount;
///When this packet was created
RakNetTimeNS creationTime;
///The next time to take action on this packet
RakNetTimeNS nextActionTime;
// If this was a reliable packet, it included the ping time, to be sent back in an ack
//RakNetTimeNS remoteSystemTime;
//RemoteSystemTimeType remoteSystemTime;
///How many bits the data is
BitSize_t dataBitLength;
///Buffer is a pointer to the actual data, assuming this packet has data at all
unsigned char *data;
};
#endif

45
thirdparty/raknet/Source/Itoa.cpp vendored Normal file
View File

@@ -0,0 +1,45 @@
// Fast itoa from http://www.jb.man.ac.uk/~slowe/cpp/itoa.html for Linux since it seems like Linux doesn't support this function.
// I modified it to remove the std dependencies.
char* Itoa( int value, char* result, int base )
{
// check that the base if valid
if (base < 2 || base > 16) { *result = 0; return result; }
char* out = result;
int quotient = value;
int absQModB;
do {
// KevinJ - get rid of this dependency
//*out = "0123456789abcdef"[ std::abs( quotient % base ) ];
absQModB=quotient % base;
if (absQModB < 0)
absQModB=-absQModB;
*out = "0123456789abcdef"[ absQModB ];
++out;
quotient /= base;
} while ( quotient );
// Only apply negative sign for base 10
if ( value < 0 && base == 10) *out++ = '-';
// KevinJ - get rid of this dependency
// std::reverse( result, out );
*out = 0;
// KevinJ - My own reverse code
char *start = result;
char temp;
out--;
while (start < out)
{
temp=*start;
*start=*out;
*out=temp;
start++;
out--;
}
return result;
}

8
thirdparty/raknet/Source/Itoa.h vendored Normal file
View File

@@ -0,0 +1,8 @@
#ifndef __RAK_ITOA_H
#define __RAK_ITOA_H
#include "Export.h"
RAK_DLL_EXPORT char* Itoa( int value, char* result, int base );
#endif

84
thirdparty/raknet/Source/Kbhit.h vendored Normal file
View File

@@ -0,0 +1,84 @@
/*****************************************************************************
kbhit() and getch() for Linux/UNIX
Chris Giese <geezer@execpc.com> http://my.execpc.com/~geezer
Release date: ?
This code is public domain (no copyright).
You can do whatever you want with it.
*****************************************************************************/
#if !defined(linux)
#include <conio.h> /* kbhit(), getch() */
#else
#include <sys/time.h> /* struct timeval, select() */
/* ICANON, ECHO, TCSANOW, struct termios */
#include <termios.h> /* tcgetattr(), tcsetattr() */
#include <stdlib.h> /* atexit(), exit() */
#include <unistd.h> /* read() */
#include <stdio.h> /* printf() */
#include <string.h> /* memcpy */
static struct termios g_old_kbd_mode;
/*****************************************************************************
*****************************************************************************/
static void cooked(void)
{
tcsetattr(0, TCSANOW, &g_old_kbd_mode);
}
/*****************************************************************************
*****************************************************************************/
static void raw(void)
{
static char init;
/**/
struct termios new_kbd_mode;
if(init)
return;
/* put keyboard (stdin, actually) in raw, unbuffered mode */
tcgetattr(0, &g_old_kbd_mode);
memcpy(&new_kbd_mode, &g_old_kbd_mode, sizeof(struct termios));
new_kbd_mode.c_lflag &= ~(ICANON | ECHO);
new_kbd_mode.c_cc[VTIME] = 0;
new_kbd_mode.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &new_kbd_mode);
/* when we exit, go back to normal, "cooked" mode */
atexit(cooked);
init = 1;
}
/*****************************************************************************
*****************************************************************************/
static int kbhit(void)
{
struct timeval timeout;
fd_set read_handles;
int status;
raw();
/* check stdin (fd 0) for activity */
FD_ZERO(&read_handles);
FD_SET(0, &read_handles);
timeout.tv_sec = timeout.tv_usec = 0;
status = select(0 + 1, &read_handles, NULL, NULL, &timeout);
if(status < 0)
{
printf("select() failed in kbhit()\n");
exit(1);
}
return status;
}
/*****************************************************************************
*****************************************************************************/
static int getch(void)
{
unsigned char temp;
raw();
/* stdin = fd 0 */
if(read(0, &temp, 1) != 1)
return 0;
return temp;
}
#endif

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