Init
This commit is contained in:
14
Samples/MasterServer/CMakeLists.txt
Normal file
14
Samples/MasterServer/CMakeLists.txt
Normal 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})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
307
Samples/MasterServer/MasterClient.cpp
Normal file
307
Samples/MasterServer/MasterClient.cpp
Normal 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);
|
||||
}
|
||||
118
Samples/MasterServer/MasterClient.h
Normal file
118
Samples/MasterServer/MasterClient.h
Normal 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
|
||||
106
Samples/MasterServer/MasterClient.vcxproj
Normal file
106
Samples/MasterServer/MasterClient.vcxproj
Normal 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>
|
||||
32
Samples/MasterServer/MasterClient.vcxproj.filters
Normal file
32
Samples/MasterServer/MasterClient.vcxproj.filters
Normal 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>
|
||||
225
Samples/MasterServer/MasterClientMain.cpp
Normal file
225
Samples/MasterServer/MasterClientMain.cpp
Normal 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;
|
||||
}
|
||||
160
Samples/MasterServer/MasterCommon.h
Normal file
160
Samples/MasterServer/MasterCommon.h
Normal 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
|
||||
353
Samples/MasterServer/MasterServer.cpp
Normal file
353
Samples/MasterServer/MasterServer.cpp
Normal 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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
40
Samples/MasterServer/MasterServer.h
Normal file
40
Samples/MasterServer/MasterServer.h
Normal 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
|
||||
106
Samples/MasterServer/MasterServer.vcxproj
Normal file
106
Samples/MasterServer/MasterServer.vcxproj
Normal 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>
|
||||
32
Samples/MasterServer/MasterServer.vcxproj.filters
Normal file
32
Samples/MasterServer/MasterServer.vcxproj.filters
Normal 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>
|
||||
129
Samples/MasterServer/MasterServerMain.cpp
Normal file
129
Samples/MasterServer/MasterServerMain.cpp
Normal 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;
|
||||
}
|
||||
623
Samples/MasterServer/mastercommon.cpp
Normal file
623
Samples/MasterServer/mastercommon.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user