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

View File

@ -0,0 +1,14 @@
#
# This file was taken from RakNet 4.082 without any modifications.
# Please see licenses/RakNet license.txt for the underlying license and related copyright.
#
cmake_minimum_required(VERSION 2.6)
GETCURRENTFOLDER()
STANDARDSUBPROJECT(${current_folder})

View File

@ -0,0 +1,307 @@
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*/
#include "MasterClient.h"
#include "RakPeerInterface.h"
#include "PacketEnumerations.h"
#include "RakNetworkFactory.h"
#include "StringCompressor.h"
#include "GetTime.h"
#include <cstring>
// Uncomment this define for debugging printfs
#define _SHOW_MASTER_SERVER_PRINTF
#ifdef _SHOW_MASTER_SERVER_PRINTF
#include <cstdio>
#endif
MasterClient::MasterClient()
{
}
MasterClient::~MasterClient()
{
ClearServerList();
}
bool MasterClient::Connect(char* host, int masterServerPort)
{
localServer.Clear();
listServer=serverListed=localServerModified=false;
localServer.connectionIdentifier.port=rakPeer->GetInternalID().port;
ruleIdentifierList.Reset();
return rakPeer->Connect(host, masterServerPort, 0, 0);
}
void MasterClient::Disconnect(void)
{
if (IsConnected())
DelistServer();
rakPeer->Disconnect(100);
}
bool MasterClient::IsConnected(void)
{
unsigned short numberOfSystems;
rakPeer->GetConnectionList(0, &numberOfSystems);
return numberOfSystems==1;
}
void MasterClient::AddQueryRule(char *ruleIdentifier)
{
if (ruleIdentifier && IsReservedRuleIdentifier(ruleIdentifier)==false)
stringCompressor->EncodeString(ruleIdentifier, 256, &ruleIdentifierList);
}
void MasterClient::ClearQueryRules(void)
{
ruleIdentifierList.Reset();
}
void MasterClient::QueryMasterServer(void)
{
BitStream outgoingBitStream;
// Request to the master server for the list of servers that contain at least one of the specified keys
outgoingBitStream.Write((unsigned char)ID_QUERY_MASTER_SERVER);
if (ruleIdentifierList.GetNumberOfBitsUsed()>0)
outgoingBitStream.WriteBits(ruleIdentifierList.GetData(), ruleIdentifierList.GetNumberOfBitsUsed(), false);
rakPeer->Send(&outgoingBitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_PLAYER_ID, true);
}
void MasterClient::PingServers(void)
{
unsigned serverIndex;
for (serverIndex=0; serverIndex < gameServerList.serverList.Size(); serverIndex++)
{
rakPeer->Ping((char*)rakPeer->PlayerIDToDottedIP(gameServerList.serverList[serverIndex]->connectionIdentifier),
gameServerList.serverList[serverIndex]->connectionIdentifier.port, false);
}
}
void MasterClient::Update(RakPeerInterface *peer)
{
BitStream outgoingBitStream;
if (listServer && ((serverListed && localServerModified) || (serverListed==false)))
{
outgoingBitStream.Write((unsigned char)ID_MASTER_SERVER_SET_SERVER);
SerializeServer(&localServer, &outgoingBitStream);
rakPeer->Send(&outgoingBitStream, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_PLAYER_ID, true);
serverListed=true;
localServerModified=false;
}
}
bool MasterClient::OnReceive(RakPeerInterface *peer, Packet *packet)
{
switch(packet->data[0])
{
case ID_NO_FREE_INCOMING_CONNECTIONS:
OnMasterServerFull();
return false; // Do not absorb packet
case ID_DISCONNECTION_NOTIFICATION:
OnLostConnection();
return false; // Do not absorb packet
case ID_CONNECTION_LOST:
OnLostConnection();
return false; // Do not absorb packet
case ID_MODIFIED_PACKET:
OnModifiedPacket();
return false;
case ID_CONNECTION_ATTEMPT_FAILED:
OnConnectionAttemptFailed();
return false; // Do not absorb packet
case ID_MASTER_SERVER_UPDATE_SERVER:
HandleServerListResponse(packet, false);
return true; // Absorb packet
case ID_MASTER_SERVER_SET_SERVER:
HandleServerListResponse(packet, true);
return true; // Absorb packet
case ID_PONG:
HandlePong(packet);
return false; // Absorb packet
case ID_RELAYED_CONNECTION_NOTIFICATION:
HandleRelayedConnectionNotification(packet);
return true; // Absorb packet
}
return 0;
}
void MasterClient::ConnectionAttemptNotification(char *serverIP, unsigned short serverPort)
{
if (serverIP==0)
return;
BitStream bitStream(23);
bitStream.Write((unsigned char)ID_RELAYED_CONNECTION_NOTIFICATION);
bitStream.Write(localServer.connectionIdentifier.port); // Your own game client port
bitStream.Write(serverPort); // The game server you are connecting to port
stringCompressor->EncodeString(serverIP, 22, &bitStream); // The game server IP you are connecting to
rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_PLAYER_ID, true);
}
void MasterClient::ListServer(void)
{
listServer=true;
}
void MasterClient::DelistServer(void)
{
BitStream bitStream;
listServer=false;
if (serverListed)
{
bitStream.Write((unsigned char)ID_MASTER_SERVER_DELIST_SERVER);
bitStream.Write(localServer.connectionIdentifier.port);
rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_PLAYER_ID, true);
serverListed=false;
}
}
void MasterClient::HandleServerListResponse(Packet *packet, bool overwriteExisting)
{
int serverIndex;
bool newServerAdded;
unsigned short numberOfServers;
GameServer *gameServer;
RakNetTime currentTime;
BitStream inputBitStream(packet->data, packet->length, false);
inputBitStream.IgnoreBits(8*sizeof(unsigned char));
if (inputBitStream.ReadCompressed(numberOfServers)==false)
return;
currentTime=RakNet::GetTime();
for (serverIndex=0; serverIndex < numberOfServers; serverIndex++)
{
gameServer = DeserializeServer(&inputBitStream);
// Find the existing game server that matches this port/address.
// If not found, then add it to the list.
// else update it
// If (overwriteExisting)
// - Delete any fields that exist in the old and not in the new
// Add any fields that exist in the new and do not exist in the old
// Update any fields that exist in both
// Unset the deletion mark
gameServer=UpdateServerList(gameServer,overwriteExisting, &newServerAdded);
if (newServerAdded)
{
// Ping the new server
rakPeer->Ping((char*)rakPeer->PlayerIDToDottedIP(gameServer->connectionIdentifier),
gameServer->connectionIdentifier.port, false);
// Returns true if new server updated
OnGameServerListAddition(gameServer);
}
else
{
// returns false if an existing server is modified
OnGameServerListRuleUpdate(gameServer);
}
}
// Any servers that were not updated on the last call to UpdateServerList
// will have lastUpdateTime time as less than the current time
// Delete those
serverIndex=0;
while (serverIndex < (int) gameServerList.serverList.Size())
{
if (gameServerList.serverList[serverIndex]->lastUpdateTime < currentTime)
{
delete gameServerList.serverList[serverIndex];
gameServerList.serverList.RemoveAtIndex(serverIndex);
}
else
serverIndex++;
}
OnGameServerListQueryComplete();
}
void MasterClient::HandleRelayedConnectionNotification(Packet *packet)
{
PlayerID clientSystem;
BitStream incomingBitStream(packet->data, packet->length, false);
incomingBitStream.IgnoreBits(8*sizeof(unsigned char));
incomingBitStream.Read(clientSystem.binaryAddress);
incomingBitStream.Read(clientSystem.port);
OnConnectionRequest(rakPeer->PlayerIDToDottedIP(clientSystem), clientSystem.port);
}
void MasterClient::PostRule(char *ruleIdentifier, char *stringData, int intData)
{
if (ruleIdentifier)
{
if (IsReservedRuleIdentifier(ruleIdentifier))
return;
localServerModified |= UpdateServerRule(&localServer, ruleIdentifier, stringData, intData);
}
}
void MasterClient::RemoveRule(char *ruleIdentifier)
{
if (ruleIdentifier)
localServerModified |= RemoveServerRule(&localServer, ruleIdentifier);
}
void MasterClient::OnLostConnection(void)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Connection lost.\n");
#endif
}
void MasterClient::OnConnectionAttemptFailed(void)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Connection attempt failed.\n");
#endif
}
void MasterClient::OnMasterServerFull(void)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Server full.\n");
#endif
}
void MasterClient::OnModifiedPacket(void)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Modified packet.\n");
#endif
}
void MasterClient::OnGameServerListAddition(GameServer *newServer)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Server added.\n");
#endif
}
void MasterClient::OnGameServerListRuleUpdate(GameServer *updatedServer)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Rules updated for a server.\n");
#endif
}
void MasterClient::OnGameServerListQueryComplete(void)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Query complete.\n");
#endif
}
// Event when a game client wants to connect to our server
// You should call AdvertiseSystem to the passed IP and port from your game instance
void MasterClient::OnConnectionRequest(const char *clientIP, unsigned short clientPort)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Master client indicates a connection request from %s:%i.\n", clientIP, clientPort);
#endif
rakPeer->AdvertiseSystem((char*)clientIP, clientPort,0,0);
}

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*/
// TOPOLOGY
// Connect to master server
// Stay connected
// When an information query comes in, parse it and write out to a bitstream.
// When all bitstreams are written, send that back to the master server.
#ifndef __MASTER_CLIENT_H
#define __MASTER_CLIENT_H
#include "MasterCommon.h"
#include "BitStream.h"
/// \ingroup MasterServer
/// \brief implements the master client
class MasterClient : public MasterCommon
{
public:
MasterClient();
~MasterClient();
// ---------------------------------------------------
// NETWORKING FUNCTIONS
// ---------------------------------------------------
// We must be connected to call any of the following functions.
// Host is the master server IP
// masterServerPort is the master server port
// masterClientPort is the port the master client should use (must be different than gamePort)
// gamePort is the port your game server or game client is using.
bool Connect(char* host, int masterServerPort);
// Disconnect and terminate. Game servers should stay connected to use NAT punch-through. Game clients,
// or game servers that do not need NAT punch-through can disconnect.
void Disconnect(void);
// Returns true if connected
bool IsConnected(void);
// This will tell the master server that we are trying to connect to the indicated game server.
// The indicated server will then also try to connect to us, bypassing most NATs
// and increasing the chance of a successful connection. You should try connecting to the game server
// at the same time you call this function.
void ConnectionAttemptNotification(char *serverIP, unsigned short serverPort);
// ---------------------------------------------------
// SERVER LISTING FUNCTIONS
// ---------------------------------------------------
// List the server.
void ListServer(void);
// Remove our server listing from the master server
void DelistServer(void);
// Add a rule about our server. Can be done before or after listing
void PostRule(char *ruleIdentifier, char *stringData, int intData);
// Remove a rule about our server
void RemoveRule(char *ruleIdentifier);
// ---------------------------------------------------
// SERVER QUERY FUNCTIONS
// ---------------------------------------------------
// Adds a rule to look for when we query. This will update existing servers that contain these rules.
// Do not query for "Ping", "IP", or "Port" as these are automatically returned.
void AddQueryRule(char *ruleIdentifier);
// Clears all rules from our query list. This will return all servers.
void ClearQueryRules(void);
// Query the master server with our rule set. To get all servers, call ClearQueryRules() after
// any prior calls to add AddQueryRule to clear the rule set.
void QueryMasterServer(void);
// Pings all servers on our list.
void PingServers(void);
// ---------------------------------------------------
// SEE MasterCommon.h FOR BROWSER FUNCTIONS
// ---------------------------------------------------
// ---------------------------------------------------
// OVERRIDABLE EVENTS
// ---------------------------------------------------
// Event if we lose the connection to the master server
void OnLostConnection(void);
// Couldn't connect
void OnConnectionAttemptFailed(void);
// Event if the master server is full when we try to connect
void OnMasterServerFull(void);
// Event if a packet was tampered with mid-steram
void OnModifiedPacket(void);
// Event if a server was added to the list
void OnGameServerListAddition(GameServer *newServer);
// Event if a server has its rules updated (only happens if querying with a rule set)
void OnGameServerListRuleUpdate(GameServer *updatedServer);
// Event when we complete a query
void OnGameServerListQueryComplete(void);
// Event when a game client wants to connect to our server
// You should call AdvertiseSystem to the passed IP and port from your game instance
void OnConnectionRequest(const char *clientIP, unsigned short clientPort);
protected:
void Update(RakPeerInterface *peer);
bool OnReceive(RakPeerInterface *peer, Packet *packet);
void HandleServerListResponse(Packet *packet, bool overwriteExisting);
void HandleRelayedConnectionNotification(Packet *packet);
bool listServer, serverListed, localServerModified;
GameServer localServer;
BitStream ruleIdentifierList;
};
#endif

View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>MasterClient</ProjectName>
<ProjectGuid>{4C05DCE2-2DD9-41E9-83BC-3AC4682D1312}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>./../../Source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>./../../Lib/RakNet_LibStatic_Debug_Win32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)MasterClient.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)MasterClient.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>./../../Source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>./../../Lib/RakNet_LibStatic_Release_Win32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)MasterClient.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="MasterClient.cpp" />
<ClCompile Include="MasterClientMain.cpp" />
<ClCompile Include="MasterCommon.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="MasterClient.h" />
<ClInclude Include="MasterCommon.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="MasterClient.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MasterClientMain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MasterCommon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="MasterClient.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MasterCommon.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*/
// This is my own internal test program for the master client but serves as a good example.
// Right now it is hardcoded to connect to 127.0.0.1. You would run the master server first, then run this.
#include "MasterCommon.h"
#include "MasterClient.h"
#include "StringCompressor.h"
#include "BitStream.h"
#include "RakPeerInterface.h"
#include "RakNetworkFactory.h"
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#ifdef WIN32
#include <conio.h>
#else
#include "../Unix/kbhit.h"
#endif
#ifdef _WIN32
#include <conio.h>
#include <windows.h> // Sleep
#else
#include "../Unix/kbhit.h"
#include <unistd.h> // usleep
#endif
#define READCHAR(arg) gets(arg); ch=arg[0];
// remove this
#include "PacketEnumerations.h"
int main(void)
{
printf("DEPRECIATED - Use LightweightDatabase instead\n");
BitStream bitStream;
char str[256];
char ch;
MasterClient masterClient;
RakPeerInterface *testGameServerOrClient;
unsigned int serverListSize, index;
bool identiferFound;
const char *outputString;
int outputInt;
Packet *p;
// Create a fake game
testGameServerOrClient = RakNetworkFactory::GetRakPeerInterface();
testGameServerOrClient->Initialize(8, 60003, 0);
testGameServerOrClient->SetMaximumIncomingConnections(8);
testGameServerOrClient->AttachPlugin(&masterClient);
printf("This project shows how to use the master client.\n");
printf("The master client is used by game servers to advertise themselves.\n");
printf("On the master server and by game clients to download a list of game servers\n");
printf("Difficulty: Intermediate\n\n");
if (masterClient.Connect("127.0.0.1", 60000))
printf("Master client connecting...\n");
else
printf("Master client failed to start or connect.\n");
printf("(Q)uit\n(q)uery master server\n(l)ist server\n(d)elist server\n(D)isconnect from the master server.\n(a)dd rule\n(r)emove rule\n(p)ing server list\n(C)onnect to the master server.\n(c)onnect to another game, using NAT punch-through with master server, bypassing most NATs\n(SPACE) print server list\n");
char buff[256];
while (1)
{
if (kbhit())
{
READCHAR(buff);
if (ch=='Q')
break;
if (ch=='q')
{
masterClient.ClearQueryRules();
printf("Enter query key 1/2 or enter for none: ");
gets(str);
masterClient.AddQueryRule(str);
printf("Enter query key 2/2 or enter for none: ");
gets(str);
masterClient.AddQueryRule(str);
masterClient.QueryMasterServer();
printf("Server queried. Press space to see server list.\n");
}
else if (ch=='l')
{
printf("Uploading game server. Query to see it.\n");
masterClient.ListServer();
}
else if (ch=='d')
{
printf("Server delisted. Query to update our own list.\n");
masterClient.DelistServer();
}
else if (ch=='D')
{
printf("Disconnected.\n");
PlayerID playerId;
testGameServerOrClient->IPToPlayerID("127.0.0.1", 60000, &playerId);
testGameServerOrClient->CloseConnection(playerId, true, 0);
}
else if (ch=='C')
{
if (masterClient.Connect("127.0.0.1", 60000))
printf("Master client connecting...\n");
else
printf("Master client failed to start or connect.\n");
}
else if (ch=='a')
{
printf("Adding sample rules. Query to update our own list.\n");
masterClient.PostRule("Game name", "My big game o' death.", 0);
masterClient.PostRule("Game type", "Death match", 0);
masterClient.PostRule("Score",0, 100);
}
else if (ch=='r')
{
printf("Removing rules. Query to update our own list.\n");
masterClient.RemoveRule("Game type");
masterClient.RemoveRule("Game name");
masterClient.RemoveRule("Score");
}
else if (ch=='p')
{
printf("Pinging any servers in our list\n");
masterClient.PingServers();
}
else if (ch=='c')
{
char ip[22];
printf("Sending connection attempt notification to master server\n");
printf("Enter IP of server from game list: ");
gets(ip);
printf("Enter port: ");
gets(str);
if (ip[0]!=0 && str[0]!=0)
{
masterClient.ConnectionAttemptNotification(ip, atoi(str));
printf("Sent connection attempt notification to the server the master server\n");
}
else
{
printf("Aborting...");
}
}
else if (ch==' ')
{
serverListSize=masterClient.GetServerListSize();
if (serverListSize==0)
{
printf("No servers in list\n");
}
else
{
for (index=0; index < serverListSize; index++)
{
printf("%i. ", index);
outputString=masterClient.GetServerListRuleAsString(index, "IP", &identiferFound);
if (identiferFound)
printf("%s:", outputString);
else
printf("NO_IP:");
outputInt=masterClient.GetServerListRuleAsInt(index, "Port", &identiferFound);
if (identiferFound)
printf("%i ", outputInt);
else
printf("NO_PORT ");
outputInt=masterClient.GetServerListRuleAsInt(index, "Ping", &identiferFound);
if (identiferFound)
printf("%i ", outputInt);
else
printf("NO_PING ");
outputString=masterClient.GetServerListRuleAsString(index, "Game type", &identiferFound);
if (identiferFound)
printf("%s ", outputString);
else
printf("NO_GT ");
outputString=masterClient.GetServerListRuleAsString(index, "Game name", &identiferFound);
if (identiferFound)
printf("%s ", outputString);
else
printf("NO_GN ");
outputInt=masterClient.GetServerListRuleAsInt(index, "Score", &identiferFound);
if (identiferFound)
printf("%i\n", outputInt);
else
printf("NO_SCORE\n");
}
}
}
ch=0;
}
p = testGameServerOrClient->Receive();
while (p)
{
// Ignore any game packets. The master server plugin handles everything.
testGameServerOrClient->DeallocatePacket(p);
// Call Receive every update to keep the plugin going
p = testGameServerOrClient->Receive();
}
#ifdef _WIN32
Sleep(30);
#else
usleep(30 * 1000);
#endif
}
masterClient.Disconnect();
RakNetworkFactory::DestroyRakPeerInterface(testGameServerOrClient);
return 0;
}

View File

@ -0,0 +1,160 @@
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*/
/// \file
#ifndef __MASTER_COMMON_H
#define __MASTER_COMMON_H
#include "DS_List.h"
#include "NetworkTypes.h"
#include "BitStream.h"
#include "PluginInterface.h"
using namespace RakNet;
class RakPeerInterface;
struct Packet;
// IP, Port, Ping - case sensitive!
#define NUMBER_OF_DEFAULT_MASTER_SERVER_KEYS 3
// If we ping NUMBER_OF_MISSED_PINGS_TO_DROP without ever a response, that server is dropped from the list.
// This includes the last ping, so actually NUMBER_OF_MISSED_PINGS_TO_DROP-1 would be truly missed
#define NUMBER_OF_MISSED_PINGS_TO_DROP 4
// KEEP_ALIVE_PING_FREQUENCY is how often to ping servers to make sure they are active
#define KEEP_ALIVE_PING_FREQUENCY 20000
// How many ms must pass per connection before we check average bytes for a flood attack
#define FLOOD_ATTACK_CHECK_DELAY 5000
// How many bytes per ms someone has to send on average before they are banned.
#define FLOOD_ATTACK_BYTES_PER_MS 2.0f
struct GameServerRule;
struct GameServer;
/// \defgroup MASTER_SERVER_GROUP MasterServer
/// \ingroup PLUGINS_GROUP
/// \ingroup MASTER_SERVER_GROUP
/// \brief Just a utility class.
struct GameServerList
{
public:
GameServerList();
~GameServerList();
void Clear(void);
void SortOnKey(char *key, bool ascending);
void QuickSort(int low, int high, bool ascending);
int Partition(int low, int high, bool ascending);
int GetIndexByPlayerID(PlayerID playerID);
DataStructures::List<GameServer*> serverList;
};
/// \ingroup MASTER_SERVER_GROUP
class MasterCommon : public PluginInterface
{
public:
MasterCommon();
// ---------------------------------------------------
// BROWSER FUNCTIONS
// ---------------------------------------------------
// Sorting function
// ruleIdentifier is a string used by you previously when adding rules via PostRule
// It can also be "IP" "Port" or "Ping"
// Set ascending to true to sort from low to high. Otherwise sorts from high to low.
void SortServerListOnKey(char *ruleIdentifier, bool ascending);
// serverIndex should be from 0 to GetServerListSize()-1
// ruleIdentifier is a string used by you previously when adding rules via PostRule
// It can also be "IP" "Port" or "Ping".
// identifier found will return true if the specified rule is found AND you are reading the
// correct type.
// GetServerListRuleAsInt should be used for int values.
// GetServerListRuleAsString should be used for string values
unsigned int GetServerListSize(void);
int GetServerListRuleAsInt(int serverIndex, char *ruleIdentifier, bool *identifierFound);
const char* GetServerListRuleAsString(int serverIndex, char *ruleIdentifier, bool *identifierFound);
protected:
void OnAttach(RakPeerInterface *peer);
// Delete all elements from the server list
void ClearServerList(void);
// Returns true if a rule is reserved
bool IsReservedRuleIdentifier(char *ruleIdentifier);
void HandlePong(Packet *packet);
// Adds or updates the specified rule to the specified server.
// Returns true if the server has been changed. False if we are adding a rule that is already the same
bool UpdateServerRule(GameServer *gameServer, char *ruleIdentifier, char *stringData, int intData);
// Remove the specified rule from the server.
// Returns true if the rule was removed.
bool RemoveServerRule(GameServer *gameServer, char *ruleIdentifier);
// Encode a playerID to a bitstream
void SerializePlayerID(PlayerID *playerID, BitStream *outputBitStream);
// Encode a rule to a bitstream
void SerializeRule(GameServerRule *gameServerRule, BitStream *outputBitStream);
// Decode a playerID from a bitstream
void DeserializePlayerID(PlayerID *playerID, BitStream *inputBitStream);
// Decode a rule from a bitstream
GameServerRule *DeserializeRule(BitStream *inputBitStream);
// Encode a server to a bitstream
void SerializeServer(GameServer *gameServer, BitStream *outputBitStream);
// Create a server from a bitstream
GameServer *DeserializeServer(BitStream *inputBitStream);
// Add the default rules to a server (ip, port, ping)
void AddDefaultRulesToServer(GameServer *gameServer, PlayerID playerID);
// Update one server based on the information in another
void UpdateServer(GameServer *destination, GameServer *source, bool deleteSingleRules);
// Add the specified server to the list of servers - or if the server already exists
// Update the existing server and delete the server passed
// deleteSingleRules means if a match is found and a rule exists in the old
// server but not the new, then delete that rule.
// Returns the new or updated server
GameServer * UpdateServerList(GameServer *gameServer, bool deleteSingleRules, bool *newServerAdded);
RakPeerInterface *rakPeer;
GameServerList gameServerList;
};
/// \ingroup MASTER_SERVER_GROUP
struct GameServerRule
{
GameServerRule();
~GameServerRule();
char *key;
// stringValue and intValue are mutually exclusive
char *stringValue;
int intValue;
};
/// \ingroup MASTER_SERVER_GROUP
struct GameServer
{
GameServer();
~GameServer();
void Clear(void);
bool FindKey(char *key);
int keyIndex;
int numberOfKeysFound;
RakNetTime lastUpdateTime;
PlayerID connectionIdentifier; // The game server
PlayerID originationId; // Only used by the server - the master client PlayerID
int failedPingResponses;
RakNetTime nextPingTime;
// When inserting rules, don't forget that IP and ping should always be added.
// These are required for any game server
DataStructures::List<GameServerRule*> serverRules;
};
#endif

View File

@ -0,0 +1,353 @@
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*/
#include "MasterServer.h"
#include "RakPeerInterface.h"
#include "BitStream.h"
#include "RakNetworkFactory.h"
#include "PacketEnumerations.h"
#include "StringCompressor.h"
#include "GetTime.h"
#include "RakNetStatistics.h"
// Uncomment this define for debugging printfs
#define _SHOW_MASTER_SERVER_PRINTF
#ifdef _SHOW_MASTER_SERVER_PRINTF
#include <cstdio>
#endif
MasterServer::MasterServer()
{
}
MasterServer::~MasterServer()
{
ClearServerList();
}
void MasterServer::Update(RakPeerInterface *peer)
{
unsigned serverIndex;
RakNetTime time;
// TODO - should have multiple listing security
time = RakNet::GetTime();
serverIndex=0;
while (serverIndex < gameServerList.serverList.Size())
{
if (time >= gameServerList.serverList[serverIndex]->nextPingTime)
{
if (gameServerList.serverList[serverIndex]->failedPingResponses>=NUMBER_OF_MISSED_PINGS_TO_DROP)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Deleting %s for lack of ping response.\n", (char*)rakPeer->PlayerIDToDottedIP(gameServerList.serverList[serverIndex]->connectionIdentifier));
#endif
gameServerList.serverList[serverIndex]->Clear();
delete gameServerList.serverList[serverIndex];
gameServerList.serverList.RemoveAtIndex(serverIndex);
}
else
{
gameServerList.serverList[serverIndex]->nextPingTime = time + KEEP_ALIVE_PING_FREQUENCY;
if (rakPeer->GetIndexFromPlayerID(gameServerList.serverList[serverIndex]->connectionIdentifier)==-1)
{
rakPeer->Ping((char*)rakPeer->PlayerIDToDottedIP(gameServerList.serverList[serverIndex]->connectionIdentifier),
gameServerList.serverList[serverIndex]->connectionIdentifier.port, false);
gameServerList.serverList[serverIndex]->failedPingResponses++;
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Pinging %s. Waiting on %i repl(ies) so far.\n", (char*)rakPeer->PlayerIDToDottedIP(gameServerList.serverList[serverIndex]->connectionIdentifier),gameServerList.serverList[serverIndex]->failedPingResponses);
#endif
}
else
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Not pinging %s since they are currently connected.\n", (char*)rakPeer->PlayerIDToDottedIP(gameServerList.serverList[serverIndex]->connectionIdentifier));
#endif
}
serverIndex++;
}
}
else
serverIndex++;
}
}
bool MasterServer::OnReceive(RakPeerInterface *peer, Packet *packet)
{
RakNetStatisticsStruct *rss;
RakNetTime connectionTime;
RakNetTime time;
unsigned serverIndex;
time = RakNet::GetTime();
// Quick and dirty flood attack security:
// If a client has been connected for more than 5 seconds,
// and has sent more than 1000 bytes per second on average then ban them
rss=rakPeer->GetStatistics(packet->playerId);
if (rss)
{
connectionTime=time-rss->connectionStartTime;
if (connectionTime > FLOOD_ATTACK_CHECK_DELAY &&
(float)(rss->bitsReceived/8) / (float) connectionTime > FLOOD_ATTACK_BYTES_PER_MS)
{
rakPeer->CloseConnection(packet->playerId, true,0);
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("%s banned for session due to for flood attack\n", (char*)rakPeer->PlayerIDToDottedIP(packet->playerId));
#endif
rakPeer->AddToBanList(rakPeer->PlayerIDToDottedIP(packet->playerId));
// Find all servers with this IP and kill them.
serverIndex=0;
while (serverIndex < gameServerList.serverList.Size())
{
if (gameServerList.serverList[serverIndex]->connectionIdentifier.binaryAddress==packet->playerId.binaryAddress)
{
delete gameServerList.serverList[serverIndex];
gameServerList.serverList.RemoveAtIndex(serverIndex);
}
else
serverIndex++;
}
}
}
switch(packet->data[0])
{
case ID_QUERY_MASTER_SERVER:
HandleQuery(packet);
return true;
case ID_MASTER_SERVER_DELIST_SERVER:
HandleDelistServer(packet);
return true;
case ID_MASTER_SERVER_SET_SERVER:
HandleUpdateServer(packet);
return true;
case ID_PONG:
HandlePong(packet);
return false;
case ID_RELAYED_CONNECTION_NOTIFICATION:
HandleRelayedConnectionNotification(packet);
return true;
}
return false; // Absorb packet
}
bool MasterServer::PropagateToGame(Packet *packet) const
{
unsigned char packetIdentifier = packet->data[ 0 ];
return packetIdentifier!=ID_QUERY_MASTER_SERVER &&
packetIdentifier!=ID_MASTER_SERVER_DELIST_SERVER &&
packetIdentifier!=ID_MASTER_SERVER_SET_SERVER &&
packetIdentifier!=ID_RELAYED_CONNECTION_NOTIFICATION;
}
void MasterServer::HandleDelistServer(Packet *packet)
{
PlayerID serverPlayerID;
int existingServerIndex;
BitStream bitStream(packet->data, packet->length, false);
bitStream.IgnoreBits(sizeof(unsigned char)*8); // Ignore the packet type enum
bitStream.Read(serverPlayerID.port);
serverPlayerID.binaryAddress=packet->playerId.binaryAddress;
existingServerIndex=gameServerList.GetIndexByPlayerID(serverPlayerID);
if (existingServerIndex>=0)
{
gameServerList.serverList[existingServerIndex]->Clear();
delete gameServerList.serverList[existingServerIndex];
gameServerList.serverList.RemoveAtIndex(existingServerIndex);
}
//else
// Server does not already exist
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("%i servers on the list\n", gameServerList.serverList.Size());
#endif
}
void MasterServer::HandleQuery(Packet *packet)
{
DataStructures::List<GameServer*> serversWithKeysList;
char ruleIdentifier[256];
unsigned index, serverIndex;
int key;
bool queryAll;
BitStream outputBitStream;
BitStream compressedString(packet->data, packet->length, false);
compressedString.IgnoreBits(8*sizeof(unsigned char));
queryAll=true;
while (compressedString.GetNumberOfUnreadBits()>0)
{
// Generate a list of the indices of the servers that have one or more of the specified keys.
stringCompressor->DecodeString(ruleIdentifier, 256, &compressedString);
if (ruleIdentifier[0]==0)
// If we fail to read the first string, queryAll remains true.
break;
queryAll=false;
if (IsReservedRuleIdentifier(ruleIdentifier))
continue;
for (index=0; index < gameServerList.serverList.Size(); index++)
{
if (gameServerList.serverList[index]->connectionIdentifier==UNASSIGNED_PLAYER_ID)
continue;
if (gameServerList.serverList[index]->FindKey(ruleIdentifier))
{
serverIndex=serversWithKeysList.GetIndexOf(gameServerList.serverList[index]);
if (serverIndex==MAX_UNSIGNED_LONG)
{
gameServerList.serverList[index]->numberOfKeysFound=1;
serversWithKeysList.Insert(gameServerList.serverList[index]);
}
else
{
serversWithKeysList[serverIndex]->numberOfKeysFound++;
}
}
}
}
// Write the packet id
if (queryAll)
outputBitStream.Write((unsigned char) ID_MASTER_SERVER_SET_SERVER);
else
outputBitStream.Write((unsigned char) ID_MASTER_SERVER_UPDATE_SERVER);
if (queryAll)
{
// Write the number of servers
outputBitStream.WriteCompressed((unsigned short)gameServerList.serverList.Size());
for (index=0; index < gameServerList.serverList.Size(); index++)
{
// Write the whole server
SerializeServer(gameServerList.serverList[index], &outputBitStream);
}
}
else
{
compressedString.ResetReadPointer();
compressedString.IgnoreBits(8*sizeof(unsigned char));
// Write the number of servers with requested keys
outputBitStream.WriteCompressed((unsigned short)serversWithKeysList.Size());
// For each server, write the header which consists of the IP/PORT.
// Then go through the list of requested keys and write those
for (index=0; index < serversWithKeysList.Size(); index++)
{
SerializePlayerID(&(serversWithKeysList[index]->connectionIdentifier), &outputBitStream);
outputBitStream.WriteCompressed((unsigned short)serversWithKeysList[index]->numberOfKeysFound);
while (compressedString.GetNumberOfUnreadBits()>0)
{
// Generate a list of the indices of the servers that have one or more of the specified keys.
stringCompressor->DecodeString(ruleIdentifier, 256, &compressedString);
if (ruleIdentifier[0]==0)
break;
if (IsReservedRuleIdentifier(ruleIdentifier))
continue;
serversWithKeysList[index]->FindKey(ruleIdentifier);
key=serversWithKeysList[index]->keyIndex;
if (key>=0)
SerializeRule(serversWithKeysList[index]->serverRules[key], &outputBitStream);
}
}
}
rakPeer->Send(&outputBitStream, MEDIUM_PRIORITY, RELIABLE, 0, packet->playerId, false);
}
void MasterServer::HandleUpdateServer(Packet *packet)
{
GameServer *gameServer;
bool newServerAdded;
BitStream incomingBitStream(packet->data, packet->length, false);
incomingBitStream.IgnoreBits(8*sizeof(unsigned char));
gameServer = DeserializeServer(&incomingBitStream);
gameServer->connectionIdentifier.binaryAddress=packet->playerId.binaryAddress;
UpdateServerList(gameServer, true, &newServerAdded);
if (newServerAdded)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Server added. %i servers on the list\n", gameServerList.serverList.Size());
#endif
gameServer->originationId=packet->playerId;
}
#ifdef _SHOW_MASTER_SERVER_PRINTF
else
printf("Server updated. %i servers on the list\n", gameServerList.serverList.Size());
#endif
}
void MasterServer::OnModifiedPacket(void)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Modified packet.\n");
#endif
}
void MasterServer::HandleRelayedConnectionNotification(Packet *packet)
{
char str[22];
unsigned short clientGamePort, serverGamePort;
BitStream incomingBitStream(packet->data, packet->length, false);
incomingBitStream.IgnoreBits(8*sizeof(unsigned char));
incomingBitStream.Read(clientGamePort);
incomingBitStream.Read(serverGamePort);
if (!stringCompressor->DecodeString(str, 22, &incomingBitStream))
return;
if (str[0]==0)
return;
BitStream outgoingBitStream;
outgoingBitStream.Write((unsigned char)ID_RELAYED_CONNECTION_NOTIFICATION);
// Assumes the game client is on the same computer as the master client
outgoingBitStream.Write(packet->playerId.binaryAddress); // This is the public IP, which the sender doesn't necessarily know
outgoingBitStream.Write(clientGamePort);
PlayerID targetID;
rakPeer->IPToPlayerID(str, serverGamePort, &targetID);
// Given the IP and port of the game system, give me the index into the game server list
int serverIndex = gameServerList.GetIndexByPlayerID(targetID);
if (serverIndex>=0)
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("ID_RELAYED_CONNECTION_NOTIFICATION sent to %s:%i from %s:%i\n", str, serverGamePort, rakPeer->PlayerIDToDottedIP(packet->playerId), packet->playerId.port);
#endif
rakPeer->Send(&outgoingBitStream, HIGH_PRIORITY, RELIABLE, 0, gameServerList.serverList[serverIndex]->originationId, false);
}
else
{
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("ID_RELAYED_CONNECTION_NOTIFICATION not sent to %s:%i from %s:%i.\nMaster server does not know about target system.\n", str, serverGamePort, rakPeer->PlayerIDToDottedIP(packet->playerId), packet->playerId.port);
#endif
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*/
// TOPOLOGY
// Always running
// Active game servers == active clients
#ifndef __MASTER_SERVER_H
#define __MASTER_SERVER_H
#include "MasterCommon.h"
#include "NetworkTypes.h"
/// \ingroup MASTER_SERVER_GROUP
/// \brief implements the master server
class MasterServer : public MasterCommon
{
public:
MasterServer();
~MasterServer();
protected:
virtual void Update(RakPeerInterface *peer);
virtual bool OnReceive(RakPeerInterface *peer, Packet *packet);
// Event when a packet was tampered with mid-stream. Override.
void OnModifiedPacket(void);
bool PropagateToGame(Packet *packet) const;
void HandleQuery(Packet *packet);
void HandleDelistServer(Packet *packet);
void HandleUpdateServer(Packet *packet);
void HandleRelayedConnectionNotification(Packet *packet);
};
#endif

View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>MasterServer</ProjectName>
<ProjectGuid>{4C05DCE2-2DD9-41E9-83BC-3AC4682D1312}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>./../../Source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>./../../Lib/RakNet_LibStatic_Debug_Win32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)MasterServer.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)MasterServer.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>./../../Source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>./../../Lib/RakNet_LibStatic_Release_Win32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)MasterServer.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="MasterCommon.cpp" />
<ClCompile Include="MasterServer.cpp" />
<ClCompile Include="MasterServerMain.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="MasterCommon.h" />
<ClInclude Include="MasterServer.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="MasterCommon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MasterServer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MasterServerMain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="MasterCommon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MasterServer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*/
// This is my own internal test program for the master server but serves as a good example.
#include "MasterCommon.h"
#include "MasterServer.h"
#include "RakNetworkFactory.h"
#include "RakPeerInterface.h"
#include <cstdio>
#include <cstring>
#ifdef WIN32
#include <conio.h>
#else
#include "../Unix/kbhit.h"
#endif
#ifdef _WIN32
#include <conio.h>
#include <windows.h> // Sleep
#else
#include "../Unix/kbhit.h"
#include <unistd.h> // usleep
#endif
#define READCHAR(arg) gets(arg); ch=arg[0];
int main(void)
{
MasterServer masterServer;
int serverListSize;
const char *outputString;
int outputInt;
bool identiferFound;
int index;
char ch;
Packet *p;
RakPeerInterface *testGameMasterServer;
testGameMasterServer = RakNetworkFactory::GetRakPeerInterface();
testGameMasterServer->Initialize(10, 60000, 0);
testGameMasterServer->SetMaximumIncomingConnections(8);
testGameMasterServer->AttachPlugin(&masterServer);
printf("This project shows how to use the master server.\n");
printf("The master server is a plugin that maintains a list of games uplodated.\n");
printf("by the master client.\n");
printf("Difficulty: Beginner\n\n");
printf("(p)rint\n(q)uit\n");
char buff[256];
while (1)
{
if (kbhit())
{
READCHAR(buff);
if (ch=='q')
break;
else if (ch=='p')
{
serverListSize=masterServer.GetServerListSize();
if (serverListSize==0)
{
printf("No servers in list\n");
}
else
{
for (index=0; index < serverListSize; index++)
{
printf("%i. ", index);
outputString=masterServer.GetServerListRuleAsString(index, "IP", &identiferFound);
if (identiferFound)
printf("%s:", outputString);
else
printf("NO_IP:");
outputInt=masterServer.GetServerListRuleAsInt(index, "Port", &identiferFound);
if (identiferFound)
printf("%i ", outputInt);
else
printf("NO_PORT ");
outputString=masterServer.GetServerListRuleAsString(index, "Game type", &identiferFound);
if (identiferFound)
printf("%s ", outputString);
else
printf("NIL_GT ");
outputString=masterServer.GetServerListRuleAsString(index, "Game name", &identiferFound);
if (identiferFound)
printf("%s ", outputString);
else
printf("NIL_GN ");
outputInt=masterServer.GetServerListRuleAsInt(index, "Score", &identiferFound);
if (identiferFound)
printf("%i\n", outputInt);
else
printf("NO_SCORE\n");
}
}
}
ch=0;
}
p = testGameMasterServer->Receive();
while (p)
{
// Ignore any game packets. The master server plugin handles everything.
testGameMasterServer->DeallocatePacket(p);
// Call Receive every update to keep the plugin going
p = testGameMasterServer->Receive();
}
#ifdef _WIN32
Sleep(30);
#else
usleep(30 * 1000);
#endif
}
return 0;
}

View File

@ -0,0 +1,623 @@
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*/
#include "MasterCommon.h"
#include "RakNetworkFactory.h"
#include "RakPeerInterface.h"
#include <cstring>
#include "GetTime.h"
#include "StringCompressor.h"
#include "BitStream.h"
using namespace RakNet;
// For debugging
#include <cstdio>
GameServerRule::GameServerRule()
{
key=0;
stringValue=0;
intValue=-1;
}
GameServerRule::~GameServerRule()
{
if (key)
delete [] key;
if (stringValue)
delete [] stringValue;
}
GameServer::GameServer()
{
connectionIdentifier=UNASSIGNED_PLAYER_ID;
nextPingTime=0;
failedPingResponses=0;
lastUpdateTime=RakNet::GetTime();
}
GameServer::~GameServer()
{
Clear();
}
void GameServer::Clear()
{
unsigned i;
for (i=0; i < serverRules.Size(); i++)
delete serverRules[i];
serverRules.Clear();
}
bool GameServer::FindKey(char *key)
{
unsigned i;
for (i=0; i < serverRules.Size(); i++)
if (strcmp(serverRules[i]->key, key)==0)
{
keyIndex=i;
return true;
}
keyIndex=-1;
return false;
}
GameServerList::GameServerList()
{
}
GameServerList::~GameServerList()
{
Clear();
}
void GameServerList::Clear(void)
{
unsigned i;
for (i=0; i < serverList.Size(); i++)
delete serverList[i];
serverList.Clear();
}
void GameServerList::SortOnKey(char *key, bool ascending)
{
unsigned i;
// Set keyindex
for (i=0; i < serverList.Size(); i++)
serverList[i]->FindKey(key);
QuickSort(0, serverList.Size()-1,ascending);
}
void GameServerList::QuickSort(int low, int high, bool ascending)
{
int pivot;
if ( high > low )
{
pivot = Partition( low, high, ascending);
QuickSort( low, pivot-1,ascending);
QuickSort( pivot+1, high,ascending);
}
}
int EQ(GameServer *left, GameServer *right)
{
if (left->keyIndex==-1 || right->keyIndex==-1)
return true;
if (left->serverRules[left->keyIndex]->stringValue)
return strcmp(left->serverRules[left->keyIndex]->stringValue,right->serverRules[right->keyIndex]->stringValue)==0;
else
return left->serverRules[left->keyIndex]->intValue == right->serverRules[right->keyIndex]->intValue;
}
int LT(GameServer *left, GameServer *right)
{
if (left->keyIndex==-1)
return true;
if (right->keyIndex==-1)
return false;
if (left->serverRules[left->keyIndex]->stringValue)
return strcmp(left->serverRules[left->keyIndex]->stringValue,right->serverRules[right->keyIndex]->stringValue) < 0;
else
return left->serverRules[left->keyIndex]->intValue < right->serverRules[right->keyIndex]->intValue;
}
int LTEQ(GameServer *left, GameServer *right)
{
return LT(left, right) || EQ(left, right);
}
int GT(GameServer *left, GameServer *right)
{
if (left->keyIndex==-1)
return false;
if (right->keyIndex==-1)
return true;
if (left->serverRules[left->keyIndex]->stringValue)
return strcmp(left->serverRules[left->keyIndex]->stringValue,right->serverRules[right->keyIndex]->stringValue) > 0;
else
return left->serverRules[left->keyIndex]->intValue > right->serverRules[right->keyIndex]->intValue;
}
int GTEQ(GameServer *left, GameServer *right)
{
return GT(left, right) || EQ(left, right);
}
int GameServerList::Partition(int low, int high, bool ascending)
{
int left, right, pivot;
GameServer *pivot_item, *temp;
pivot_item = serverList[low];
pivot = left = low;
right = high;
while ( left < right )
{
if (ascending)
{
/* Move left while item < pivot */
while( LTEQ(serverList[left], pivot_item) && left < high) left++;
/* Move right while item > pivot */
while( GT(serverList[right], pivot_item) && right > 0) right--;
if ( left < right )
{
temp=serverList[left];
serverList[left]=serverList[right];
serverList[right]=temp;
}
}
else
{
while( GTEQ(serverList[left], pivot_item) && left < high) left++;
while( LT(serverList[right], pivot_item) && right > 0) right--;
if ( left < right )
{
temp=serverList[left];
serverList[left]=serverList[right];
serverList[right]=temp;
}
}
}
/* right is final position for the pivot */
serverList[low] = serverList[right];
serverList[right] = pivot_item;
return right;
}
int GameServerList::GetIndexByPlayerID(PlayerID playerID)
{
int i;
for (i=0; i < (int)serverList.Size(); i++)
{
if (serverList[i]->connectionIdentifier==playerID)
return i;
}
return -1;
}
MasterCommon::MasterCommon()
{
// rakPeer = RakNetworkFactory::GetRakPeerInterface();
}
void MasterCommon::ClearServerList(void)
{
gameServerList.Clear();
}
void MasterCommon::SortServerListOnKey(char *ruleIdentifier, bool ascending)
{
gameServerList.SortOnKey(ruleIdentifier, ascending);
}
unsigned int MasterCommon::GetServerListSize(void)
{
return gameServerList.serverList.Size();
}
int MasterCommon::GetServerListRuleAsInt(int serverIndex, char *ruleIdentifier, bool *identifierFound)
{
int keyIndex;
if (serverIndex >= (int)gameServerList.serverList.Size())
{
*identifierFound=false;
return -1;
}
gameServerList.serverList[serverIndex]->FindKey(ruleIdentifier);
keyIndex=gameServerList.serverList[serverIndex]->keyIndex;
if (keyIndex==-1)
{
*identifierFound=false;
return -1;
}
if (gameServerList.serverList[serverIndex]->serverRules[keyIndex]->stringValue)
{
*identifierFound=false;
return -1;
}
*identifierFound=true;
return gameServerList.serverList[serverIndex]->serverRules[keyIndex]->intValue;
}
const char* MasterCommon::GetServerListRuleAsString(int serverIndex, char *ruleIdentifier, bool *identifierFound)
{
int keyIndex;
if (serverIndex >= (int)gameServerList.serverList.Size())
{
*identifierFound=false;
return "serverIndex out of bounds";
}
gameServerList.serverList[serverIndex]->FindKey(ruleIdentifier);
keyIndex=gameServerList.serverList[serverIndex]->keyIndex;
if (keyIndex==-1)
{
*identifierFound=false;
return "Server does not contain specified rule";
}
if (gameServerList.serverList[serverIndex]->serverRules[keyIndex]->stringValue==0)
{
*identifierFound=false;
return "Server rule is not a string. Use GetServerListRuleAsInt";
}
*identifierFound=true;
return gameServerList.serverList[serverIndex]->serverRules[keyIndex]->stringValue;
}
bool MasterCommon::IsReservedRuleIdentifier(char *ruleIdentifier)
{
if (strcmp(ruleIdentifier, "Ping")==0 ||
strcmp(ruleIdentifier, "IP")==0 ||
strcmp(ruleIdentifier, "Port")==0)
return true;
return false;
}
void MasterCommon::AddDefaultRulesToServer(GameServer *gameServer, PlayerID playerID)
{
GameServerRule *gameServerRule;
// Every server has NUMBER_OF_DEFAULT_MASTER_SERVER_KEYS keys by default: IP, port, and ping
gameServerRule = new GameServerRule;
gameServerRule->key=new char[strlen("IP")+1];
strcpy(gameServerRule->key, "IP");
gameServerRule->stringValue=new char[22]; // Should be enough to hold an IP address
strncpy(gameServerRule->stringValue, rakPeer->PlayerIDToDottedIP(playerID), 21);
gameServerRule->stringValue[21]=0;
gameServer->serverRules.Insert(gameServerRule);
gameServerRule = new GameServerRule;
gameServerRule->key=new char[strlen("Port")+1];
strcpy(gameServerRule->key, "Port");
gameServerRule->intValue=playerID.port;
gameServer->serverRules.Insert(gameServerRule);
gameServerRule = new GameServerRule;
gameServerRule->key=new char[strlen("Ping")+1];
strcpy(gameServerRule->key, "Ping");
gameServerRule->intValue=9999;
gameServer->serverRules.Insert(gameServerRule);
}
void MasterCommon::HandlePong(Packet *packet)
{
// Find the server specified by packet
int serverIndex;
unsigned int pingTime;
serverIndex=gameServerList.GetIndexByPlayerID(packet->playerId);
if (serverIndex>=0)
{
gameServerList.serverList[serverIndex]->failedPingResponses=0;
if (gameServerList.serverList[serverIndex]->FindKey("Ping"))
{
RakNet::BitStream ptime( packet->data+1, sizeof(unsigned int), false);
ptime.Read(pingTime);
gameServerList.serverList[serverIndex]->serverRules[gameServerList.serverList[serverIndex]->keyIndex]->intValue=pingTime;
#ifdef _SHOW_MASTER_SERVER_PRINTF
printf("Got pong. Ping=%i\n", pingTime);
#endif
}
#ifdef _DEBUG
else
// No ping key!
assert(0);
#endif
}
}
bool MasterCommon::UpdateServerRule(GameServer *gameServer, char *ruleIdentifier, char *stringData, int intData)
{
GameServerRule *gameServerRule;
gameServer->lastUpdateTime=RakNet::GetTime();
// Add the rule to our local server. If it changes the local server, set a flag so we upload the
// local server on the next update.
if (gameServer->FindKey(ruleIdentifier))
{
// Is the data the same?
if (gameServer->serverRules[gameServer->keyIndex]->stringValue)
{
if (stringData==0)
{
// No string. Delete the string and use int data instead
delete [] gameServer->serverRules[gameServer->keyIndex]->stringValue;
gameServer->serverRules[gameServer->keyIndex]->stringValue=0;
gameServer->serverRules[gameServer->keyIndex]->intValue=intData;
return true;
}
else if (strcmp(gameServer->serverRules[gameServer->keyIndex]->stringValue, stringData)!=0)
{
// Different string
delete [] gameServer->serverRules[gameServer->keyIndex]->stringValue;
gameServer->serverRules[gameServer->keyIndex]->stringValue = new char [strlen(stringData)+1];
strcpy(gameServer->serverRules[gameServer->keyIndex]->stringValue, stringData);
return true;
}
}
else
{
if (stringData)
{
// Has a string where there is currently none
gameServer->serverRules[gameServer->keyIndex]->stringValue = new char [strlen(stringData)+1];
strcpy(gameServer->serverRules[gameServer->keyIndex]->stringValue, stringData);
gameServer->serverRules[gameServer->keyIndex]->intValue=-1;
return true;
}
else if (gameServer->serverRules[gameServer->keyIndex]->intValue!=intData)
{
// Different int value
gameServer->serverRules[gameServer->keyIndex]->intValue=intData;
return true;
}
}
}
else
{
// No such key. Add a new one.
gameServerRule = new GameServerRule;
gameServerRule->key=new char[strlen(ruleIdentifier)+1];
strcpy(gameServerRule->key, ruleIdentifier);
if (stringData)
{
gameServerRule->stringValue=new char[strlen(stringData)+1];
strcpy(gameServerRule->stringValue, stringData);
}
else
{
gameServerRule->intValue=intData;
}
gameServer->serverRules.Insert(gameServerRule);
return true;
}
return false;
}
bool MasterCommon::RemoveServerRule(GameServer *gameServer, char *ruleIdentifier)
{
if (gameServer->FindKey(ruleIdentifier))
{
delete gameServer->serverRules[gameServer->keyIndex];
gameServer->serverRules.RemoveAtIndex(gameServer->keyIndex);
return true;
}
return false;
}
void MasterCommon::SerializePlayerID(PlayerID *playerID, BitStream *outputBitStream)
{
outputBitStream->Write(playerID->binaryAddress);
outputBitStream->Write(playerID->port);
}
void MasterCommon::SerializeRule(GameServerRule *gameServerRule, BitStream *outputBitStream)
{
stringCompressor->EncodeString(gameServerRule->key, 256, outputBitStream);
if (gameServerRule->stringValue)
{
outputBitStream->Write(true);
stringCompressor->EncodeString(gameServerRule->stringValue, 256, outputBitStream);
}
else
{
outputBitStream->Write(false);
outputBitStream->WriteCompressed(gameServerRule->intValue);
}
}
void MasterCommon::DeserializePlayerID(PlayerID *playerID, BitStream *inputBitStream)
{
*playerID=UNASSIGNED_PLAYER_ID;
inputBitStream->Read(playerID->binaryAddress);
inputBitStream->Read(playerID->port);
}
GameServerRule * MasterCommon::DeserializeRule(BitStream *inputBitStream)
{
char output[256];
bool isAString;
GameServerRule *newRule;
newRule = new GameServerRule;
stringCompressor->DecodeString(output, 256, inputBitStream);
if (output[0]==0)
{
#ifdef _DEBUG
assert(0);
#endif
return 0;
}
newRule->key = new char [strlen(output)+1];
strcpy(newRule->key, output);
if (inputBitStream->Read(isAString)==false)
{
#ifdef _DEBUG
assert(0);
#endif
return 0;
}
if (isAString)
{
stringCompressor->DecodeString(output, 256, inputBitStream);
if (output[0]==0)
{
#ifdef _DEBUG
assert(0);
#endif
return 0;
}
newRule->stringValue = new char[strlen(output)+1];
strcpy(newRule->stringValue, output);
}
else
{
if (inputBitStream->ReadCompressed(newRule->intValue)==false)
{
#ifdef _DEBUG
assert(0);
#endif
return 0;
}
}
return newRule;
}
void MasterCommon::SerializeServer(GameServer *gameServer, BitStream *outputBitStream)
{
unsigned serverIndex;
unsigned short numberOfRulesToWrite;
numberOfRulesToWrite=0;
// Find out how many rules to write.
for (serverIndex=0; serverIndex < gameServer->serverRules.Size(); serverIndex++)
{
// We don't write reserved identifiers
if (IsReservedRuleIdentifier(gameServer->serverRules[serverIndex]->key)==false)
numberOfRulesToWrite++;
}
// Write the server identifier
SerializePlayerID(&(gameServer->connectionIdentifier), outputBitStream);
// Write the number of rules
outputBitStream->WriteCompressed(numberOfRulesToWrite);
// Write all the rules
for (serverIndex=0; serverIndex < gameServer->serverRules.Size(); serverIndex++)
{
if (IsReservedRuleIdentifier(gameServer->serverRules[serverIndex]->key))
continue;
SerializeRule(gameServer->serverRules[serverIndex], outputBitStream);
}
}
GameServer * MasterCommon::DeserializeServer(BitStream *inputBitStream)
{
unsigned serverIndex;
unsigned short numberOfRulesToWrite;
GameServer *gameServer;
GameServerRule *gameServerRule;
gameServer= new GameServer;
DeserializePlayerID(&(gameServer->connectionIdentifier), inputBitStream);
// Read the number of rules
if (inputBitStream->ReadCompressed(numberOfRulesToWrite)==false)
{
delete gameServer;
return 0;
}
// Read all the rules
for (serverIndex=0; serverIndex < numberOfRulesToWrite; serverIndex++)
{
gameServerRule = DeserializeRule(inputBitStream);
if (gameServerRule==0)
{
delete gameServer;
return 0;
}
if (IsReservedRuleIdentifier(gameServerRule->key))
delete gameServerRule;
else
gameServer->serverRules.Insert(gameServerRule);
}
return gameServer;
}
void MasterCommon::UpdateServer(GameServer *destination, GameServer *source, bool deleteSingleRules)
{
unsigned sourceRuleIndex,destinationRuleIndex;
destination->lastUpdateTime=RakNet::GetTime();
// If (deleteSingleRules) then delete any rules that exist in the old and not in the new
if (deleteSingleRules)
{
destinationRuleIndex=0;
while (destinationRuleIndex < destination->serverRules.Size())
{
if (IsReservedRuleIdentifier(destination->serverRules[destinationRuleIndex]->key)==false &&
source->FindKey(destination->serverRules[destinationRuleIndex]->key)==false)
{
delete destination->serverRules[destinationRuleIndex];
destination->serverRules.RemoveAtIndex(destinationRuleIndex);
}
else
destinationRuleIndex++;
}
}
// Go through all the rules.
for (sourceRuleIndex=0; sourceRuleIndex < source->serverRules.Size(); sourceRuleIndex++)
{
if (IsReservedRuleIdentifier(source->serverRules[sourceRuleIndex]->key))
continue;
// Add any fields that exist in the new and do not exist in the old
// Update any fields that exist in both
UpdateServerRule(destination, source->serverRules[sourceRuleIndex]->key, source->serverRules[sourceRuleIndex]->stringValue, source->serverRules[sourceRuleIndex]->intValue);
}
}
GameServer* MasterCommon::UpdateServerList(GameServer *gameServer, bool deleteSingleRules, bool *newServerAdded)
{
int searchIndex;
if (gameServer==0)
{
#ifdef _DEBUG
assert(0);
#endif
return 0;
}
// Find the existing game server that matches this port/address.
searchIndex = gameServerList.GetIndexByPlayerID(gameServer->connectionIdentifier);
if (searchIndex<0)
{
// If not found, then add it to the list.
AddDefaultRulesToServer(gameServer, gameServer->connectionIdentifier);
gameServerList.serverList.Insert(gameServer);
*newServerAdded=true;
return gameServer;
}
else
{
// Update the existing server
UpdateServer(gameServerList.serverList[searchIndex], gameServer, deleteSingleRules);
delete gameServer;
*newServerAdded=false;
return gameServerList.serverList[searchIndex];
}
}
void MasterCommon::OnAttach(RakPeerInterface *peer)
{
rakPeer=peer;
}