Init
BIN
Help/RakNet/documentation/0SleepTimer.jpg
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
Help/RakNet/documentation/0SleepTimerSmall.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
Help/RakNet/documentation/30SleepTimer.jpg
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
Help/RakNet/documentation/30SleepTimerSmall.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
73
Help/RakNet/documentation/AutopatcherVideo.htm
Normal file
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!-- saved from url=(0014)about:internet -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<!-- saved from url=(0025)http://www.techsmith.com/ -->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="DC.creator" content="Kevin Jenkins" />
|
||||
<meta name="Author Homepage" content="http://www.jenkinssoftware.com" />
|
||||
<meta name="DC.date" content="Sunday, July 27, 2008" />
|
||||
<meta name="DC.language" content="ENU" />
|
||||
<meta name="DC.title" content="RPC3" />
|
||||
|
||||
<title>RPC3 Video</title>
|
||||
<script type="text/javascript" src="swfobject.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body
|
||||
{
|
||||
background-color: #1a1a1a;
|
||||
font: .8em/1.3em verdana,arial,helvetica,sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
#media
|
||||
{
|
||||
margin-top: 40px;
|
||||
}
|
||||
#noUpdate
|
||||
{
|
||||
margin: 0 auto;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: x-small;
|
||||
color: #cccccc;
|
||||
text-align: left;
|
||||
width: 210px;
|
||||
height: 200px;
|
||||
padding: 40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="media">
|
||||
<div id="noUpdate">
|
||||
<p>The Camtasia Studio video content presented here requires JavaScript to be enabled and the latest version of the Macromedia Flash Player. If you are you using a browser with JavaScript disabled please enable it now. Otherwise, please update your version of the free Flash Player by <a href="http://www.macromedia.com/go/getflashplayer">downloading here</a>. </p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// <![CDATA[
|
||||
var so = new SWFObject( "AutopatcherDemo.swf", "csSWF", "800", "618", "9.0.28", "#1a1a1a");
|
||||
so.addParam( "quality", "best" );
|
||||
so.addParam( "allowFullScreen", "true" );
|
||||
so.addParam( "scale", "showall" );
|
||||
so.addParam( "allowScriptAccess", "always" );
|
||||
so.addVariable( "autostart", "false" );
|
||||
so.write("media");
|
||||
// ]]>
|
||||
</script>
|
||||
<!-- Users looking for simple object / embed tags can copy and paste the needed tags below.
|
||||
<div id="media">
|
||||
<object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="800" height="618" codebase="http://active.macromedia.com/flash7/cabs/ swflash.cab#version=9,0,28,0">
|
||||
<param name="src" value="AutopatcherDemo.swf"/>
|
||||
<param name="bgcolor" value="#1a1a1a"/>
|
||||
<param name="quality" value="best"/>
|
||||
<param name="allowScriptAccess" value="always"/>
|
||||
<param name="allowFullScreen" value="true"/>
|
||||
<param name="scale" value="showall"/>
|
||||
<param name="flashVars" value="autostart=false"/>
|
||||
<embed name="csSWF" src="AutopatcherDemo.swf" width="800" height="618" bgcolor="#1a1a1a" quality="best" allowScriptAccess="always" allowFullScreen="true" scale="showall" flashVars="autostart=false" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
|
||||
</object>
|
||||
</div>
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
Help/RakNet/documentation/CSharpBuildConfiguration.jpg
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
Help/RakNet/documentation/DirectoryServerListing.jpg
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
Help/RakNet/documentation/IrrlichtRakNetDemo.jpg
Normal file
|
After Width: | Height: | Size: 198 KiB |
BIN
Help/RakNet/documentation/PathVariableShot.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
73
Help/RakNet/documentation/RPC3Video.htm
Normal file
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!-- saved from url=(0014)about:internet -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<!-- saved from url=(0025)http://www.techsmith.com/ -->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="DC.creator" content="Kevin Jenkins" />
|
||||
<meta name="Author Homepage" content="http://www.jenkinssoftware.com" />
|
||||
<meta name="DC.date" content="Sunday, July 27, 2008" />
|
||||
<meta name="DC.language" content="ENU" />
|
||||
<meta name="DC.title" content="RPC3" />
|
||||
|
||||
<title>RPC3 Video</title>
|
||||
<script type="text/javascript" src="swfobject.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body
|
||||
{
|
||||
background-color: #1a1a1a;
|
||||
font: .8em/1.3em verdana,arial,helvetica,sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
#media
|
||||
{
|
||||
margin-top: 40px;
|
||||
}
|
||||
#noUpdate
|
||||
{
|
||||
margin: 0 auto;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: x-small;
|
||||
color: #cccccc;
|
||||
text-align: left;
|
||||
width: 210px;
|
||||
height: 200px;
|
||||
padding: 40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="media">
|
||||
<div id="noUpdate">
|
||||
<p>The Camtasia Studio video content presented here requires JavaScript to be enabled and the latest version of the Macromedia Flash Player. If you are you using a browser with JavaScript disabled please enable it now. Otherwise, please update your version of the free Flash Player by <a href="http://www.macromedia.com/go/getflashplayer">downloading here</a>. </p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// <![CDATA[
|
||||
var so = new SWFObject( "RPC3.swf", "csSWF", "800", "618", "9.0.28", "#1a1a1a");
|
||||
so.addParam( "quality", "best" );
|
||||
so.addParam( "allowFullScreen", "true" );
|
||||
so.addParam( "scale", "showall" );
|
||||
so.addParam( "allowScriptAccess", "always" );
|
||||
so.addVariable( "autostart", "false" );
|
||||
so.write("media");
|
||||
// ]]>
|
||||
</script>
|
||||
<!-- Users looking for simple object / embed tags can copy and paste the needed tags below.
|
||||
<div id="media">
|
||||
<object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="800" height="618" codebase="http://active.macromedia.com/flash7/cabs/ swflash.cab#version=9,0,28,0">
|
||||
<param name="src" value="RPC3.swf"/>
|
||||
<param name="bgcolor" value="#1a1a1a"/>
|
||||
<param name="quality" value="best"/>
|
||||
<param name="allowScriptAccess" value="always"/>
|
||||
<param name="allowFullScreen" value="true"/>
|
||||
<param name="scale" value="showall"/>
|
||||
<param name="flashVars" value="autostart=false"/>
|
||||
<embed name="csSWF" src="RPC3.swf" width="800" height="618" bgcolor="#1a1a1a" quality="best" allowScriptAccess="always" allowFullScreen="true" scale="showall" flashVars="autostart=false" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
|
||||
</object>
|
||||
</div>
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
Help/RakNet/documentation/RakNetLogo.jpg
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
74
Help/RakNet/documentation/RakNetMajorFeatures.htm
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!-- saved from url=(0014)about:internet -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<!-- saved from url=(0025)http://www.techsmith.com/ -->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="DC.date" content="Thursday, May 28, 2009" />
|
||||
<meta name="DC.language" content="ENU" />
|
||||
<meta name="DC.title" content="RakNetMajorFeatures" />
|
||||
<meta name="Author Homepage" content="http://www.jenkinssoftware.com" />
|
||||
<meta name="DC.creator" content="Kevin Jenkins" />
|
||||
<meta name="DC.publisher" content="Oculus VR, Inc." />
|
||||
|
||||
<title>Created with Camtasia Studio 5</title>
|
||||
<script type="text/javascript" src="swfobject.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body
|
||||
{
|
||||
background-color: #1a1a1a;
|
||||
font: .8em/1.3em verdana,arial,helvetica,sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
#media
|
||||
{
|
||||
margin-top: 40px;
|
||||
}
|
||||
#noUpdate
|
||||
{
|
||||
margin: 0 auto;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: x-small;
|
||||
color: #cccccc;
|
||||
text-align: left;
|
||||
width: 210px;
|
||||
height: 200px;
|
||||
padding: 40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="media">
|
||||
<div id="noUpdate">
|
||||
<p>The Camtasia Studio video content presented here requires JavaScript to be enabled and the latest version of the Macromedia Flash Player. If you are you using a browser with JavaScript disabled please enable it now. Otherwise, please update your version of the free Flash Player by <a href="http://www.macromedia.com/go/getflashplayer">downloading here</a>. </p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// <![CDATA[
|
||||
var so = new SWFObject( "RakNetMajorFeatures.swf", "csSWF", "1024", "786", "9.0.28", "#1a1a1a");
|
||||
so.addParam( "quality", "best" );
|
||||
so.addParam( "allowFullScreen", "true" );
|
||||
so.addParam( "scale", "showall" );
|
||||
so.addParam( "allowScriptAccess", "always" );
|
||||
so.addVariable( "autostart", "false" );
|
||||
so.write("media");
|
||||
// ]]>
|
||||
</script>
|
||||
<!-- Users looking for simple object / embed tags can copy and paste the needed tags below.
|
||||
<div id="media">
|
||||
<object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="1024" height="786" codebase="http://active.macromedia.com/flash7/cabs/ swflash.cab#version=9,0,28,0">
|
||||
<param name="src" value="RakNetMajorFeatures.swf"/>
|
||||
<param name="bgcolor" value="#1a1a1a"/>
|
||||
<param name="quality" value="best"/>
|
||||
<param name="allowScriptAccess" value="always"/>
|
||||
<param name="allowFullScreen" value="true"/>
|
||||
<param name="scale" value="showall"/>
|
||||
<param name="flashVars" value="autostart=false"/>
|
||||
<embed name="csSWF" src="RakNetMajorFeatures.swf" width="1024" height="786" bgcolor="#1a1a1a" quality="best" allowScriptAccess="always" allowFullScreen="true" scale="showall" flashVars="autostart=false" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
|
||||
</object>
|
||||
</div>
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
73
Help/RakNet/documentation/RakNetMajorFeatures.html
Normal file
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!-- saved from url=(0014)about:internet -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<!-- saved from url=(0025)http://www.techsmith.com/ -->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="DC.date" content="Monday, January 21, 2008" />
|
||||
<meta name="DC.language" content="ENU" />
|
||||
<meta name="DC.title" content="RakNetMajorFeatures" />
|
||||
<meta name="Author Homepage" content="http://www.jenkinssoftware.com" />
|
||||
<meta name="DC.creator" content="Kevin Jenkins" />
|
||||
|
||||
<title>RakNet Major Features Video</title>
|
||||
<script type="text/javascript" src="swfobject.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body
|
||||
{
|
||||
background-color: #1a1a1a;
|
||||
font: .8em/1.3em verdana,arial,helvetica,sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
#media
|
||||
{
|
||||
margin-top: 40px;
|
||||
}
|
||||
#noUpdate
|
||||
{
|
||||
margin: 0 auto;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: x-small;
|
||||
color: #cccccc;
|
||||
text-align: left;
|
||||
width: 210px;
|
||||
height: 200px;
|
||||
padding: 40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="media">
|
||||
<div id="noUpdate">
|
||||
<p>The Camtasia Studio video content presented here requires JavaScript to be enabled and the latest version of the Macromedia Flash Player. If you are you using a browser with JavaScript disabled please enable it now. Otherwise, please update your version of the free Flash Player by <a href="http://www.macromedia.com/go/getflashplayer">downloading here</a>. </p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// <![CDATA[
|
||||
var so = new SWFObject( "RakNetMajorFeatures.swf", "csSWF", "800", "618", "9.0.28", "#1a1a1a");
|
||||
so.addParam( "quality", "best" );
|
||||
so.addParam( "allowFullScreen", "true" );
|
||||
so.addParam( "scale", "showall" );
|
||||
so.addParam( "allowScriptAccess", "always" );
|
||||
so.addVariable( "autostart", "false" );
|
||||
so.write("media");
|
||||
// ]]>
|
||||
</script>
|
||||
<!-- Users looking for simple object / embed tags can copy and paste the needed tags below.
|
||||
<div id="media">
|
||||
<object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="800" height="618" codebase="http://active.macromedia.com/flash7/cabs/ swflash.cab#version=9,0,28,0">
|
||||
<param name="src" value="RakNetMajorFeatures.swf"/>
|
||||
<param name="bgcolor" value="#1a1a1a"/>
|
||||
<param name="quality" value="best"/>
|
||||
<param name="allowScriptAccess" value="always"/>
|
||||
<param name="allowFullScreen" value="true"/>
|
||||
<param name="scale" value="showall"/>
|
||||
<param name="flashVars" value="autostart=false"/>
|
||||
<embed name="csSWF" src="RakNetMajorFeatures.swf" width="800" height="618" bgcolor="#1a1a1a" quality="best" allowScriptAccess="always" allowFullScreen="true" scale="showall" flashVars="autostart=false" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
|
||||
</object>
|
||||
</div>
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
Help/RakNet/documentation/RakNetUML.jpg
Normal file
|
After Width: | Height: | Size: 221 KiB |
BIN
Help/RakNet/documentation/RakNet_Icon_Final-copy.jpg
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
Help/RakNet/documentation/RakNet_Server_Setup.docx
Normal file
50
Help/RakNet/documentation/RaknetManual.css
Normal file
@ -0,0 +1,50 @@
|
||||
.RakNetManualTextBody {
|
||||
font-family: Geneva, Arial, Helvetica, sans-serif;
|
||||
font-size: small;
|
||||
font-style: normal;
|
||||
line-height: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
color: 666666;
|
||||
height: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.RakNetBlueHeader {
|
||||
font-family: Geneva, Verdana, Arial, Helvetica, sans-serif;
|
||||
font-size: small;
|
||||
font-style: normal;
|
||||
line-height: normal;
|
||||
font-weight: bold;
|
||||
font-variant: normal;
|
||||
color: 3366CC;
|
||||
height: auto;
|
||||
width: auto;
|
||||
}
|
||||
.RakNetCode {
|
||||
font-family: Geneva, Arial, Helvetica, sans-serif;
|
||||
font-size: x-small;
|
||||
color: 333333;
|
||||
}
|
||||
|
||||
a:link {
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||
color: 003399;
|
||||
font-size: small;
|
||||
}
|
||||
a:visited {
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||
font-size: small;
|
||||
color: 003399;
|
||||
}
|
||||
body {
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||
font-size: small;
|
||||
color: 666666;
|
||||
}
|
||||
.RakNetWhiteHeader {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: large;
|
||||
color: FFFFFF;
|
||||
font-weight: bold;
|
||||
}
|
||||
74
Help/RakNet/documentation/ReplicaManager3Video.htm
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!-- saved from url=(0014)about:internet -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<!-- saved from url=(0025)http://www.techsmith.com/ -->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="Author Homepage" content="http://www.jenkinssoftware.com" />
|
||||
<meta name="DC.creator" content="Kevin Jenkins" />
|
||||
<meta name="DC.publisher" content="Oculus VR, Inc." />
|
||||
<meta name="DC.date" content="Wednesday, June 03, 2009" />
|
||||
<meta name="DC.language" content="ENU" />
|
||||
<meta name="DC.title" content="ReplicaManager3Video" />
|
||||
|
||||
<title>Created with Camtasia Studio 5</title>
|
||||
<script type="text/javascript" src="swfobject.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body
|
||||
{
|
||||
background-color: #1a1a1a;
|
||||
font: .8em/1.3em verdana,arial,helvetica,sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
#media
|
||||
{
|
||||
margin-top: 40px;
|
||||
}
|
||||
#noUpdate
|
||||
{
|
||||
margin: 0 auto;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: x-small;
|
||||
color: #cccccc;
|
||||
text-align: left;
|
||||
width: 210px;
|
||||
height: 200px;
|
||||
padding: 40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="media">
|
||||
<div id="noUpdate">
|
||||
<p>The Camtasia Studio video content presented here requires JavaScript to be enabled and the latest version of the Macromedia Flash Player. If you are you using a browser with JavaScript disabled please enable it now. Otherwise, please update your version of the free Flash Player by <a href="http://www.macromedia.com/go/getflashplayer">downloading here</a>. </p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// <![CDATA[
|
||||
var so = new SWFObject( "ReplicaManager3Video.swf", "csSWF", "1024", "786", "9.0.28", "#1a1a1a");
|
||||
so.addParam( "quality", "best" );
|
||||
so.addParam( "allowFullScreen", "true" );
|
||||
so.addParam( "scale", "showall" );
|
||||
so.addParam( "allowScriptAccess", "always" );
|
||||
so.addVariable( "autostart", "false" );
|
||||
so.write("media");
|
||||
// ]]>
|
||||
</script>
|
||||
<!-- Users looking for simple object / embed tags can copy and paste the needed tags below.
|
||||
<div id="media">
|
||||
<object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="1024" height="786" codebase="http://active.macromedia.com/flash7/cabs/ swflash.cab#version=9,0,28,0">
|
||||
<param name="src" value="ReplicaManager3Video.swf"/>
|
||||
<param name="bgcolor" value="#1a1a1a"/>
|
||||
<param name="quality" value="best"/>
|
||||
<param name="allowScriptAccess" value="always"/>
|
||||
<param name="allowFullScreen" value="true"/>
|
||||
<param name="scale" value="showall"/>
|
||||
<param name="flashVars" value="autostart=false"/>
|
||||
<embed name="csSWF" src="ReplicaManager3Video.swf" width="1024" height="786" bgcolor="#1a1a1a" quality="best" allowScriptAccess="always" allowFullScreen="true" scale="showall" flashVars="autostart=false" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
|
||||
</object>
|
||||
</div>
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
74
Help/RakNet/documentation/SQLite3LoggerPluginVideo.html
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!-- saved from url=(0014)about:internet -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<!-- saved from url=(0025)http://www.techsmith.com/ -->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="Author Homepage" content="http://www.jenkinssoftware.com" />
|
||||
<meta name="DC.creator" content="Kevin Jenkins" />
|
||||
<meta name="DC.publisher" content="Oculus VR, Inc." />
|
||||
<meta name="DC.date" content="Monday, November 02, 2009" />
|
||||
<meta name="DC.language" content="ENU" />
|
||||
<meta name="DC.title" content="SQLite3LoggerPlugin1" />
|
||||
|
||||
<title>SQLite3LoggerPlugin Video</title>
|
||||
<script type="text/javascript" src="swfobject.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body
|
||||
{
|
||||
background-color: #1a1a1a;
|
||||
font: .8em/1.3em verdana,arial,helvetica,sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
#media
|
||||
{
|
||||
margin-top: 40px;
|
||||
}
|
||||
#noUpdate
|
||||
{
|
||||
margin: 0 auto;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: x-small;
|
||||
color: #cccccc;
|
||||
text-align: left;
|
||||
width: 210px;
|
||||
height: 200px;
|
||||
padding: 40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="media">
|
||||
<div id="noUpdate">
|
||||
<p>The Camtasia Studio video content presented here requires JavaScript to be enabled and the latest version of the Macromedia Flash Player. If you are you using a browser with JavaScript disabled please enable it now. Otherwise, please update your version of the free Flash Player by <a href="http://www.macromedia.com/go/getflashplayer">downloading here</a>. </p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// <![CDATA[
|
||||
var so = new SWFObject( "SQLite3LoggerPlugin1.swf", "csSWF", "800", "618", "9.0.28", "#1a1a1a");
|
||||
so.addParam( "quality", "best" );
|
||||
so.addParam( "allowFullScreen", "true" );
|
||||
so.addParam( "scale", "showall" );
|
||||
so.addParam( "allowScriptAccess", "always" );
|
||||
so.addVariable( "autostart", "false" );
|
||||
so.write("media");
|
||||
// ]]>
|
||||
</script>
|
||||
<!-- Users looking for simple object / embed tags can copy and paste the needed tags below.
|
||||
<div id="media">
|
||||
<object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="800" height="618" codebase="http://active.macromedia.com/flash7/cabs/ swflash.cab#version=9,0,28,0">
|
||||
<param name="src" value="SQLite3LoggerPlugin1.swf"/>
|
||||
<param name="bgcolor" value="#1a1a1a"/>
|
||||
<param name="quality" value="best"/>
|
||||
<param name="allowScriptAccess" value="always"/>
|
||||
<param name="allowFullScreen" value="true"/>
|
||||
<param name="scale" value="showall"/>
|
||||
<param name="flashVars" value="autostart=false"/>
|
||||
<embed name="csSWF" src="SQLite3LoggerPlugin1.swf" width="800" height="618" bgcolor="#1a1a1a" quality="best" allowScriptAccess="always" allowFullScreen="true" scale="showall" flashVars="autostart=false" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
|
||||
</object>
|
||||
</div>
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
Help/RakNet/documentation/addchatserverfile.jpg
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
Help/RakNet/documentation/addchatserverfilesmall.jpg
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
147
Help/RakNet/documentation/autopatcher.html
Normal file
@ -0,0 +1,147 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Autopatcher</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Autopatcher</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<P><span class="RakNetBlueHeader">The autopatcher system</span><BR>
|
||||
<BR>
|
||||
|
||||
The autopatcher is a class that manages the copying of missing or changed files between two or more systems. It handles transferring files, compressing transferred files, security, and file operations. It does not handle basic connectivity or provide a user interface. For basic connectivity, make sure you connect RakPeerInterface or PacketizedTCP before using it. For a UI, that is entirely up to you. Autopatchers are used in all online only games and most AAA commercial games.<BR><BR>
|
||||
On the client, you need an instance of AutopatcherClient. The server needs an instance of AutopatcherServer. The code for those classes is not part of RakNet core. They are located at .\DependentExtensions\ , and you need to add them to your project.<br>
|
||||
<br>
|
||||
<strong>On the client side</strong> <br>
|
||||
<br>
|
||||
On the client side, most work is done with just a couple of methods of AutopatcherClient.<br>
|
||||
<br>
|
||||
|
||||
<span class="RakNetCode">void SetFileListTransferPlugin(FileListTransfer *flt);</span><BR>
|
||||
<br>
|
||||
This plugin has a dependency on the FileListTransfer plugin, which it uses to actually send the files.
|
||||
So you need an instance of that plugin registered with RakPeerInterface, and a pointer to that interface should be passed in this function.<br>
|
||||
<br>
|
||||
|
||||
|
||||
|
||||
|
||||
<span class="RakNetCode">bool PatchApplication(const char *_applicationName, const char *_applicationDirectory, const char *lastUpdateDate, SystemAddress host, FileListTransferCBInterface *onFileCallback, const char *restartOutputFilename, const char *pathToRestartExe); </span><BR>
|
||||
<br>
|
||||
|
||||
Patches a certain directory associated with a named application to match the same named application on the patch server<br>
|
||||
<em>_applicationName</em> - The name of the application<br>
|
||||
<em>_applicationDirectory</em> - The directory to write the output to.<br>
|
||||
<em>lastUpdateDate</em> - A string representing the last time you updated from the patch server, so you only check newer files. Should be 0 the first time, or if you want to do a full scan. Returned in GetServerDate() after you call PatchApplication successfully.<br>
|
||||
<em>host</em> - The address of the remote system to send the message to.<br>
|
||||
<em>onFileCallback</em> - Callback to call per-file (optional). When fileIndex+1==setCount in the callback then the download is done.<br>
|
||||
<em>_restartOutputFilename</em> - If it is necessary to restart this application, where to write the restart data to. You can include a path in this filename.<br>
|
||||
<em>pathToRestartExe</em> - What exe to launch from the AutopatcherClientRestarter . argv[0] will work to relaunch this application.<br>
|
||||
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
There are other functions and classes involved in the client side, but you should study the sample at <em>\Samples\AutopatcherClient</em>.
|
||||
<P><strong>On the server side</strong> <br>
|
||||
<br>
|
||||
On the client side, you use an instance of AutopatcherServer.<br>
|
||||
<br>
|
||||
<span class="RakNetCode"> void SetFileListTransferPlugin(FileListTransfer *flt);</span><BR>
|
||||
Like AutopatcherClient, this plugin also has a dependency on the FileListTransfer plugin, which it uses to actually send the files.
|
||||
So you need an instance of that plugin registered with RakPeerInterface, and a pointer to that interface should be passed here.
|
||||
<br><br>
|
||||
|
||||
<span class="RakNetCode">void SetAutopatcherRepositoryInterface(AutopatcherRepositoryInterface *ari);</span><BR>
|
||||
With the function, you tell AutopatchServer how to take care of the network transfer of the patchs.
|
||||
This class only does the network transfers for the autopatcher. All the data is stored in a repository.
|
||||
Pass the interface to your repository with this function. RakNet comes with AutopatcherPostgreRepository if you wish to use that.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<BR>
|
||||
<br>
|
||||
Check the sample at <em>\Samples\AutoPatcherServer</em>. It uses an implementation of AutopatcherRepositoryInterface for PostgreSQL (AutopatcherPostgreRepository), to store all the files of an application in a PostgreSQL database.<br>
|
||||
<br>
|
||||
<strong>Directory structure</strong><br>
|
||||
<br>
|
||||
It's possible to use directory structures.
|
||||
For example, suppose you have the following directory structure for your application: <br>
|
||||
<br>
|
||||
|
||||
Readme.txt<BR>
|
||||
Music/Song1.wav<BR>
|
||||
Music/Song2.wav<BR>
|
||||
<br>
|
||||
|
||||
The Autopatcher will keep directories structures intact. So if the sending system has that directory structure, the downloading system will mirror this directory structure.
|
||||
<P><strong>Server required files (using <a href="http://www.postgresql.org/">PostgreSQL</a>):</strong>
|
||||
<ul>
|
||||
<li>All source files in DependentExtensions\bzip2-1.0.3</li>
|
||||
<li>DependentExtensions\CreatePatch.h and .cpp</li>
|
||||
<li>DependentExtensions\MemoryCompressor.h and .cpp</li>
|
||||
<li>DependentExtensions\AutopatcherServer.h and .cpp</li>
|
||||
<li>All source files in DependentExtensions\AutopatcherPostgreRepository</li>
|
||||
<li>All source files in DependentExtensions\PostgreSQLInterface</li>
|
||||
<li>All source files in Samples\AutopatcherServer, should you want to use the default console application to run the server.</li>
|
||||
</ul>
|
||||
<p><strong>Server Dependencies (using <a href="http://www.postgresql.org/">PostgreSQL</a>):</strong></p>
|
||||
<p>PostgreSQL 8.2 or newer, installed at C:\Program Files\PostgreSQL\8.2. Change the project property paths should your installation directory be different. Do not forget to check development tools in the PostgreSQL installer or the headers and libs will not be installed.</p>
|
||||
<p><strong>Client required files</strong></p>
|
||||
<ul>
|
||||
<li>All source files in DependentExtensions\bzip2-1.0.3</li>
|
||||
<li>DependentExtensions\MemoryCompressor.h and .cpp</li>
|
||||
<li>DependentExtensions\ApplyPatch.h and .cpp</li>
|
||||
<li>DependentExtensions\AutopatcherClient.h and .cpp</li>
|
||||
<li>All source files in Samples\AutopatcherClient, should you want to use the default console application as a design template.</li>
|
||||
<li>All source files in Samples\AutopatcherClientRestarter, should you want to use the default console application to restart the autopatcher after it patches itself. </li>
|
||||
</ul>
|
||||
<p><strong>Using TCP instead of UDP (recommended)</strong></p>
|
||||
<p>RakPeerInterfaces uses UDP, which is a problem if RakNet's protocol changes - the autopatcher wouldn't be able to connect to the new protocol. It is recommended you use TCP instead of UDP. In the sample AutopatcherClientTest.cpp and AutopatcherServerTest_MySQL.cpp or AutopatcherServerTest.cpp you can enable this with the define USE_TCP found at the top of those files.</p>
|
||||
<p>Changes:</p>
|
||||
<ol>
|
||||
<li>Use the PacketizedTCP class instead of RakPeerInterface</li>
|
||||
<li>PacketizedTCP returns connection state changes with HasCompletedConnectionAttempt(), HasNewIncomingConnection(), and HasLostConnection(), rather than byte identifiers.</li>
|
||||
<li>Attach the plugin to your instance of PacketizedTCP instead of RakPeerInterface</li>
|
||||
</ol>
|
||||
<p><strong>Optimizing for large games:</strong></p>
|
||||
<p>AutopatcherClient::PatchApplication has a parameter lastUpdateDate. If 0 is passed for this parameter, the server does not know what version the client is using. This generates a full-scan, where the server has to access the database for the hash of every file for the application, and is very slow, so should be avoided whenever possible.</p>
|
||||
<p>When distributing your application, you should get the timestamp on the patching server using the time() function and store this with the distribution. You can then pass that value to AutopatcherClient::PatchApplication. As long as this value is greater than or equal to the time when AutopatcherRepositoryInterface::UpdateApplicationFiles was called, the server can use it to do an optimized lookup for which files changed from the version the client is using.</p>
|
||||
<p>AutopatcherServer has an additional optimization through the function CacheMostRecentPatch(). This will store the most recent patch in memory if using AutopatcherPostgreRepository. If the time passed to PatchApplication() is greater than the most recent patch, the patch is skipped entirely. If it is less than the most recent patch, but still greater than the patch prior to that, the patch is served from memory instead of disk. For this to work, every time you get ID_AUTOPATCHER_FINISHED call AutopatcherClient::GetServerDate(), save it to disk, and use that date for the next call to PatchApplication().</p>
|
||||
<p>Summary of performance tips:</p>
|
||||
<OL>
|
||||
<LI>The autopatcher was not designed to serve the entire application, only to patch.
|
||||
Your users should download from FTP or a webserver as much as possible before patching.
|
||||
<LI>Use AutopatcherServer::CacheMostRecentPatch() if using AutopatcherPostgreRepository
|
||||
<LI>AutopatcherPostgreRepository is about 10x faster than AutopatcherMySQLRepository even without CacheMostRecentPatch()
|
||||
<LI>If 0 is passed to lastUpdateDate for AutopatcherClient::PatchApplication, this generates a full-scan of every file accessing the database for each file. Do not do it except on user request to repair corrupted installations.<br>
|
||||
<LI>To distribute your application, call time() on the server immediately after UpdateApplicationFiles(). Store that value with the client distribution, and use as the default to lastUpdateParameter for the first call to
|
||||
AutopatcherClient::PatchApplication.<br>
|
||||
<LI>Whenever you get ID_AUTOPATCHER_FINISHED, save the value returned by AutopatcherClient::GetServerDate() to use for the lastUpdateDate parameter of next call to AutopatcherClient::PatchApplication<br>
|
||||
<LI>With CacheMostRecentPatch(), only the most recent patch is stored in memory, so do not call UpdateApplicationFiles pointlessly.
|
||||
</OL>
|
||||
<p><strong>Notes on memory usage:</strong></p>
|
||||
<p>Patches are created with code from Colin Percival <a href="http://www.daemonology.net/bsdiff/">http://www.daemonology.net/bsdiff/</a> . The patching algorithm uses <a href="http://www.cs.lth.se/Research/Algorithms/Papers/jesper5.ps"> Larsson and Sadakane's qsufsort</a> and is quite memory intensive, and not recommended for files over several hundred megabytes. If you use CacheMostRecentPatch() your most recent patch is also kept in memory. Additionally, file transfer takes about 8 megabytes of memory per user.</p></TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="cloudhosting.html">Cloud Hosting</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
179
Help/RakNet/documentation/bitstreams.html
Normal file
@ -0,0 +1,179 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Bitstreams</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Bitstream Overview</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<span class="RakNetBlueHeader">Description</span><BR>
|
||||
<BR>
|
||||
|
||||
The bitstream class is a helper class under the namespace RakNet that is used to wrap a dynamic array for the purpose of packing and unpacking bits. Its main four benefits are:
|
||||
<OL>
|
||||
<LI>Creating packets dynamically
|
||||
<LI>Compression
|
||||
<LI>Writing Bits
|
||||
<LI>Endian swapping
|
||||
</OL>
|
||||
<p>With structs you have to predefine your structures and cast them to a (char*). With a bitstream, you can choose to write blocks at runtime, depending on the context. Bitstreams can compress the native types using the SerializeBitsFromIntegerRange and SerializeFloat16().<BR>
|
||||
<BR>
|
||||
You can also write bits. Most of the time you will not care about this. However, when writing booleans it will automatically only write one bit. This can also be very useful for encryption since your data will no longer be byte aligned.<BR>
|
||||
<BR>
|
||||
<B>Writing Data</B></p>
|
||||
<p>Bitstream is templated to take any type of data. If this is a built-in type, such as NetworkIDObject, it uses partial template specialization to write the type more efficiently. If it's a native type, or a structure, it writes the individual bits, similar to memcpy. You can pass structs containing multiple data members to bitstreams. However, you may wish to serialize each individual element to do correct <A HREF="http://en.wikipedia.org/wiki/Endianness">endian</A> swapping (needed for communication between PCs and Macs, for example).<BR>
|
||||
<BR>
|
||||
<span class="RakNetCode">
|
||||
struct MyVector<BR>
|
||||
{<BR>
|
||||
float x,y,z;<BR>
|
||||
} myVector;<BR>
|
||||
<BR>
|
||||
// No endian swapping<BR>
|
||||
bitStream.Write(myVector);<BR>
|
||||
<BR>
|
||||
// With endian swapping<BR>
|
||||
#undef __BITSTREAM_NATIVE_END<BR>
|
||||
bitStream.Write(myVector.x);<BR>
|
||||
bitStream.Write(myVector.y);<BR>
|
||||
bitStream.Write(myVector.z);<BR>
|
||||
<BR>
|
||||
// You can also override operator left shift and right shift</span><br>
|
||||
<span class="RakNetCode">// Shift operators have to be in the namespace RakNet or they might use the default one in BitStream.h instead. Error occurs with std::string<br>
|
||||
namespace RakNet<br>
|
||||
{</span></p>
|
||||
<p><span class="RakNetCode"> RakNet::BitStream& operator << (RakNet::BitStream& out, MyVector& in)<BR>
|
||||
{<BR>
|
||||
out.WriteNormVector(in.x,in.y,in.z);<BR>
|
||||
return out;<BR>
|
||||
}<BR>
|
||||
RakNet::BitStream& operator >> (RakNet::BitStream& in, MyVector& out)<BR>
|
||||
{<BR>
|
||||
bool success = in.ReadNormVector(out.x,out.y,out.z);<BR>
|
||||
assert(success);<BR>
|
||||
return in;<BR>
|
||||
}</span></p>
|
||||
<p><span class="RakNetCode">} // namespace RakNet<BR>
|
||||
<BR>
|
||||
// Read from bitstream<BR>
|
||||
myVector << bitStream;<BR>
|
||||
// Write to bitstream<BR>
|
||||
myVector >> bitStream;<BR>
|
||||
</span>
|
||||
<BR>
|
||||
Optional - One of the constructor versions takes a length in bytes as a parameter. If you have an idea of the size of your data you can pass this number when creating the bitstream to avoid internal reallocations.<BR>
|
||||
<BR>
|
||||
See <A HREF="creatingpackets.html">Creating Packets</A> for more details.<BR>
|
||||
<BR>
|
||||
<B>Reading Data</B>
|
||||
<BR>
|
||||
<BR>
|
||||
Reading data is equally simple. Create a bitstream, and in the constructor assign it your data.<BR>
|
||||
<BR>
|
||||
<span class="RakNetCode">
|
||||
|
||||
// Assuming we have a Packet *<BR>
|
||||
BitStream myBitStream(packet->data, packet->length, false);<BR>
|
||||
|
||||
struct MyVector<BR>
|
||||
{<BR>
|
||||
float x,y,z;<BR>
|
||||
} myVector;<BR>
|
||||
<BR>
|
||||
// No endian swapping<BR>
|
||||
bitStream.Read(myVector);<BR>
|
||||
<BR>
|
||||
// With endian swapping (__BITSTREAM_NATIVE_END should just be commented in RakNetDefines.h)<BR>
|
||||
#undef __BITSTREAM_NATIVE_END<BR>
|
||||
#include "BitStream.h"
|
||||
bitStream.Read(myVector.x);<BR>
|
||||
bitStream.Read(myVector.y);<BR>
|
||||
bitStream.Read(myVector.z);<BR>
|
||||
<BR>
|
||||
</span>
|
||||
See <A HREF="receivingpackets.html">Receiving Packets</A> for a more complete example.<BR>
|
||||
<BR>
|
||||
|
||||
<B>Serializing Data</B>
|
||||
<BR>
|
||||
<BR>
|
||||
You can have the same function read and write, by using BitStream::Serialize() instead of Read() or Write().<BR>
|
||||
<BR>
|
||||
<span class="RakNetCode">
|
||||
|
||||
struct MyVector<BR>
|
||||
{<BR>
|
||||
float x,y,z;<BR>
|
||||
// writeToBitstream==true means write, writeToBitstream==false means read<BR>
|
||||
void Serialize(bool writeToBitstream, BitStream *bs)<BR>
|
||||
{<BR>
|
||||
bs->Serialize(writeToBitstream, x);<BR>
|
||||
bs->Serialize(writeToBitstream, y);<BR>
|
||||
bs->Serialize(writeToBitstream, z);<BR>
|
||||
}<BR>
|
||||
} myVector;<BR>
|
||||
</span>
|
||||
|
||||
<BR>
|
||||
See <A HREF="receivingpackets.html">Receiving Packets</A> for a more complete example.<BR>
|
||||
<BR>
|
||||
</p></TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Useful functions</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<p><span class="RakNetBlueHeader">See BitStream.h for a full list of functions.</span><BR>
|
||||
<br>
|
||||
<strong>Reset</strong><br>
|
||||
Restart the bitstream, clearing all data.
|
||||
</p>
|
||||
<p><B>Write functions</B><BR>
|
||||
The write functions write data to the bitstream at the end of the bitstream. You should use the analogous Read to get the data back out.<BR>
|
||||
<BR>
|
||||
<B>Read functions</B><BR>
|
||||
The read functions read data already in the bitstream, in order from beginning to end. The read function returns false if there is no more data in the bitstream.</p>
|
||||
<p><strong>WriteBitsFromIntegerRange, ReadBitsFromIntegerRange, SerializeBitsFromIntegerRange<br>
|
||||
</strong>If a number only uses a specific range of values (such as 10-20) this function will determine automatically the number of bits needed to write that range of values.</p>
|
||||
<p><strong>WriteCasted, ReadCasted</strong><br>
|
||||
Write a variable of one type as if it were casted to another type. For example, WriteCasted<char>(5); is equivalent to char c=5; Write(c);</p>
|
||||
<p><strong>WriteNormVector, ReadNormVector</strong><br>
|
||||
Writes a normalized vector where each component ranges from -1 to +1. Each component is written with 16 bites. </p>
|
||||
<p><strong>WriteFloat16, ReadFloat16<br>
|
||||
</strong>Given a min and max value for a floating point number, divide the range by 65535 and write the result in 16 bytes (lossy)..</p>
|
||||
<p><strong>WriteNormQuat, ReadNormQuat</strong><br>
|
||||
Write a quaternion in 16*3+4 bits (lossy).</p>
|
||||
<p><strong>WriteOrthMatrix, ReadOrthMatrix</strong><br>
|
||||
Convert an orthonormal matrix to a quaternion, then call WriteNormQuat/ReadNormQuat.</p>
|
||||
<p><B>GetNumberOfBitsUsed</B><BR>
|
||||
<B>GetNumberOfBytesUsed</B><BR>
|
||||
Gives you the number of bytes or bits written.<BR>
|
||||
<BR>
|
||||
<B>GetData</B><BR>
|
||||
Gives you a pointer to the internal data of the bitstream. This is a (char*) allocated with malloc and is presented in case you need direct assess to the data. </p>
|
||||
<p> <br>
|
||||
</p></TD>
|
||||
</TR></TABLE>
|
||||
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="creatingpackets.html">Creating Packets</A><BR>
|
||||
<A HREF="receivingpackets.html">Receiving Packets</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
162
Help/RakNet/documentation/bluetooth.html
Normal file
@ -0,0 +1,162 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head><title>RakNet bluetooth integration</title>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</head>
|
||||
<body leftmargin="0" topmargin="0" style="background-color: rgb(255, 255, 255);" alink="#003399" link="#003399" marginheight="0" marginwidth="0" vlink="#003399">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><br>
|
||||
<br>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" height="1" width="8">Windows bluetooth integration</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Can be supported in C using sockets and native libraries</span><br>
|
||||
<br>
|
||||
Bluetooth support is relatively easy to add.
|
||||
<OL>
|
||||
<LI>Include "Ws2bth.h"
|
||||
<LI>Modify socket calls in SocketLayer.cpp, refer to <A HREF="http://msdn.microsoft.com/en-us/library/aa362928%28v=vs.85%29.aspx">http://msdn.microsoft.com/en-us/library/aa362928%28v=vs.85%29.aspx</A>
|
||||
<LI><A HREF="http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedotherprotocol4j.html">Source example</A>
|
||||
<LI>There is also an <A HREF="http://www.broadcom.com/support/bluetooth/sdk.php">API from Broadcom</A> for Windows although I'm not sure what the difference is between that and the native Windows system calls.
|
||||
</OL>
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" height="1" width="8">Linux bluetooth integration</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Can be supported in C using the BlueZ library</span><br>
|
||||
<br>
|
||||
|
||||
Linux uses the <A HREF="http://www.bluez.org">BlueZ</A> library to interface with Bluetooth devices. There is a great resource on BlueZ here: <A HREF="http://people.csail.mit.edu/albert/bluez-intro/">http://people.csail.mit.edu/albert/bluez-intro/</A>.
|
||||
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" height="1" width="8">Mac bluetooth integration</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Indirectly send through IOBluetoothL2CAPChannelRef?</span><br>
|
||||
<br>
|
||||
|
||||
<A HREF="http://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/Bluetooth/Bluetooth.pdf">Mac Bluetooth support</A> is supported through the IOBluetooth library, written in Objective-C. C equivalents are available by suffixing Ref to the name, for example IOBluetoothObjectRef contains the interface in C. You are expected to create instances of <A HREF="http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Reference/IOBluetooth/IOBluetoothL2CAPChannel_h/Classes/IOBluetoothL2CAPChannel/">IOBluetoothL2CAPChannel</A> which represent a communication channel. L2CAP is an unreliable communications channel. The equivalent reliable communications channel uses <A HREF="http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Reference/IOBluetooth/IOBluetoothRFCOMMChannel_h/Classes/IOBluetoothRFCOMMChannel/index.html">RFCOMM</A>
|
||||
|
||||
<A HREF="http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Reference/IOBluetooth/">The full framework of methods</A>
|
||||
|
||||
It doesn't appear to be possible to get direct socket access to Bluetooth on the Mac. However, it may be possible to use RakNet and IOBluetoothL2CAPChannel together by using RakNet's SocketLayer::SetSocketLayerOverride(), and thereby changing RakNet's sendto and recvfrom calls to use IOBluetoothL2CAPChannel instead.
|
||||
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" height="1" width="8">iPhone bluetooth integration</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Bluetooth exposed through Gamekit</span><br>
|
||||
<br>
|
||||
The only interface for Bluetooth communications is through the higher level framework <A HREF="http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/GameKit_Guide/Introduction/Introduction.html">GameKit</A>. Gamekit uses Objective-C.</p> Similar to the Mac, it may be possible to indirectly send through RakNet using SocketLayer::SetSocketLayerOverride() through the <A HREF="http://developer.apple.com/library/ios/#documentation/GameKit/Reference/GKSession_Class/Reference/Reference.html#//apple_ref/occ/instm/GKSession/sendData:toPeers:withDataMode:error:">sendData:toPeers</A> method exposed by GKSession, and sending that data unreliabily.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" height="1" width="8">Android bluetooth integration</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">BlueZ used for underlying support, however not accessible to implementation</span><br>
|
||||
<UL>
|
||||
<LI>Android uses BlueZ (w/ l2cap, etc.) as the underlying Bluetooth API (at the Linux OS level, underneath the Android Dalvik VM). All of the Android SDK (Java) Bluetooth classes end up using this API.
|
||||
The Android NDK cross-compiler provides access to many of the Android system's underlying libraries. However, Bluetooth does NOT appear to be exposed by the NDK. I.e.: The NDK's headers do not include Bluetooth-specific headers, tokens, etc. (I performed a find-in-files on the NDK headers and other files for various Bluetooth related/specific tokens like: BTPROTO_RFCOMM, l2cap, etc.)
|
||||
<LI>For a list of supported native libraries, see: <A HREF="http://developer.android.com/sdk/ndk/overview.html">http://developer.android.com/sdk/ndk/overview.html</A>
|
||||
<LI>There is indication in the forums and stackoverflow that Bluetooth cannot be accessed directly via the NDK (see: <A HREF="http://groups.google.com/group/android-ndk/browse_thread/thread/bd0834426b4264b9">http://groups.google.com/group/android-ndk/browse_thread/thread/bd0834426b4264b9</A> and <A HREF="http://groups.google.com/group/android-ndk/browse_thread/thread/a2e3b5133f4a7a4b">http://groups.google.com/group/android-ndk/browse_thread/thread/a2e3b5133f4a7a4b</A> and <A HREF="http://groups.google.com/group/android-ndk/msg/fe9b846a7ee37ba5">http://groups.google.com/group/android-ndk/msg/fe9b846a7ee37ba5</A> and accepted answer at <A HREF="http://stackoverflow.com/questions/4205468/create-an-android-rfcomm-socket-without-any-input-from-the-user-how">http://stackoverflow.com/questions/4205468/create-an-android-rfcomm-socket-without-any-input-from-the-user-how</A>)
|
||||
<LI>It looks like Bluetooth support via the NDK was possible at one point via a hack involving the HTC released BlueZ sources: <A HREF="http://blog.blackwhale.at/2009/08/android-bluetooth-on-steroids-with-the-ndk-and-bluez/">http://blog.blackwhale.at/2009/08/android-bluetooth-on-steroids-with-the-ndk-and-bluez/</A>
|
||||
<LI>A possible work around is to use the Android SDK's Java Bluetooth libraries for discovery, establishing connections, etc. and delegating the actual communications streams to RakNet by passing the in/out streams to RakNet via a JNI bridge.
|
||||
</UL>
|
||||
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><strong> See Also</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><font class="G10" color="#111122" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="1"><a href="index.html">Index</a><br>
|
||||
<a href="autopatcher.html">Autopatcher</a><br>
|
||||
<a href="cloudcomputing.html">CloudComputing</a><br>
|
||||
<a href="connectiongraph.html">ConnectionGraph2</a><br>
|
||||
<a href="crashreporter.html">CrashReporter</a><br>
|
||||
<a href="replicamanager3.html">ReplicaManager3</a><br>
|
||||
<a href="fullyconnectedmesh2.html">FullyConnectedMesh2</a> <br>
|
||||
<a href="natpunchthrough.html">NATPunchthrough</a> <br>
|
||||
<a href="packetlogger.html">PacketLogger</a> <br>
|
||||
<a href="readyevent.html">ReadyEvent</a> <br>
|
||||
<a href="RPC3Video.htm">RPC3</a> <br>
|
||||
<a href="teambalancer.html">TeamBalancer</a><br>
|
||||
<a href="sqlite3loggerplugin.html">SQLite3LoggerPlugin</a></p>
|
||||
<p><a href="packetlogger.html"></a><br>
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body></html>
|
||||
BIN
Help/RakNet/documentation/clientserver.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
96
Help/RakNet/documentation/cloudcomputing.html
Normal file
@ -0,0 +1,96 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Cloud Computing manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Cloud Computing Overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Client memory / events accessible through a server cloud</span> </p>
|
||||
<p>Sometimes you want a large number of clients that are not connected and do not necessarily know about each other to share memory or to get notifications of events. For example:</p>
|
||||
<UL>
|
||||
<LI>A high performance server browser
|
||||
<LI>In-game statistics
|
||||
for millions of players<LI>Cloud computing
|
||||
</UL>
|
||||
<p>The "Cloud" in CloudServer means that the system supports distributed servers. Any client can Post() to or Get() from any server. Post() operations can be subscribed to or Get() by other clients, regardless of what server that client is subscribed to. Servers can be added or removed at runtime, and the system will continue to work as expected. This allows the system to be scaled according to your player load, using your own servers or virtual servers such as <a href="cloudhosting.html">Rackspace</a>.</p>
|
||||
<p>The design of the system assumes that all servers are connected in a fully connected mesh. You should authenticate other servers before adding them with CloudServer::AddServer(). The <a href="twowayauthentication.html">TwoWayAuthentication</a> and <a href="connectiongraph.html">ConnectionGraph2</a> plugins can help with this. Or just run/modify the CloudServer sample, which does this already.</p>
|
||||
<p>The servers should be accessible by the internet through a static IP address, either without a router, or with the ports opened.</p>
|
||||
<p>Note: The design of the system is that client data only persists while that client is connected to the server. The server itself can perform local operations or persist data with a local client.</p>
|
||||
<p><strong>Code Usage:</strong></p>
|
||||
<p>On the server, you can optionally restrict uploads and downloads to reduce memory and bandwidth usage.</p>
|
||||
<p><span class="RakNetCode">CloudServer cloudServer;<br>
|
||||
rakPeer->AttachPlugin(&cloudServer);<br>
|
||||
// Restrict how many bytes a client can upload to this server.
|
||||
<br>
|
||||
cloudServer.SetMaxUploadBytesPerClient(MAX_UPLOAD_BYTES);
|
||||
<br>
|
||||
cloudServer.SetMaxBytesPerDownload(MAX_DOWNLOAD_BYTE</span>S);</p>
|
||||
<p>On the client:</p>
|
||||
<p><span class="RakNetCode">CloudClient cloudClient;<br>
|
||||
rakPeer->AttachPlugin(&cloudClient);<br>
|
||||
// Optional: Provide an overridden allocator to
|
||||
store or deallocate the downloaded rows in your own application<br>
|
||||
Cloud_Allocator cloudAllocator;<br>
|
||||
// Optional: You'll want to actually provide an overridden instance to handle downloads <br>
|
||||
Cloud_ClientCallback clientCallback;<br>
|
||||
// Set the allocation callbacks<br>
|
||||
cloudClient.SetCallbacks(&cloudAllocator, &clientCallback);<br>
|
||||
// Every uploaded is associated with a pair of keys
|
||||
<br>
|
||||
Cloud_DataKey dataKey;<br>
|
||||
dataKey.primaryKey="ApplicationName";<br>
|
||||
dataKey.secondaryKey=ID_PLAYER_COUNT; // Enumeration<br>
|
||||
unsigned char playerCount=16;<br>
|
||||
// Upload data to the cloud, to a server we are already connected to
|
||||
<br>
|
||||
cloudClient.Post(&dataKey, &playerCount,
|
||||
sizeof(playercount), serverAddressOrGuid);<br>
|
||||
// Download the data we just uploaded. clientCallback will have the OnDownload member called when the query completes.<br>
|
||||
Cloud_KeyQuery query;<br>
|
||||
query.keys.Push(dataKey, __FILE__, __LINE__);</span><span class="RakNetCode"><br>
|
||||
cloudClient.Get(&query, serverAddressOrGuid);</span><br>
|
||||
</p>
|
||||
<p><strong>Use cases:</strong></p>
|
||||
<p><em>Server directory</em><br>
|
||||
Assign a secret unique name for the application, and use that as the the Cloud_DataKey primaryKey. Have each game server maintain a common list of enumerations representing fields to query, such as PLAYER_COUNT, PLAYER_LIST, and LEVEL_NAME. The IP address and RakNetGUID properties of the other game servers are maintained automatically. When a game server becomes available to be listed, use the CloudClient::Post() operation once per field to be uploaded. To query for other servers, use the CloudClient::Get() operation for any system, passing the list of CloudMemory_DataKey keys you care about to Cloud_KeyQuery. If you did not query all keys in the prior call, you can get more detail on a particular server again using the CloudClient::Get() operation, with a larger list of keys, and by using the overloaded version of CloudClient::Get() that has the specificSystems parameter. You can subscribe to updates for a particular system in the CloudClient::Get() call if desired, but this is usually not necessary. The game server is delisted if it disconnects from the CloudServer (for example crashing) and games can be manually delisted with the CloudClient::Release() call.</p>
|
||||
<p><em>In-game statistics</em><br>
|
||||
Support you want to track number of kills across all running games ever. Furthermore, the game has millions of players, so it is not viable to have each client individually hit a single database server. You also want to hide the database server from the public. The cloud system can help here, mirroring common statistics in memory. To do so, each game client will Post() kills to the cloud. Each server in the cloud has a local client used to update the database. The local client uses the Get() function to query or subscribe to kill posts by the game clients. The local client will also periodically write to the database server (or it could be every kill if you wanted real-time statistics). Similarly, the local client will read from the central database to get an updated kill count, and Post() this data to the cloud. Lastly, the game clients use the Get() function with the specificSystems parameter set to their own server to subscribe to the updated kill count.
|
||||
<p><em>Cloud computing<br>
|
||||
</em>Sometimes you want to split a problem across many clients. For example, rendering lighting in your game levels. The cloud system can help by acting as a distributed event coordinator. Each client that wants to process part of the problem will call CloudClient::Post(), potentially with no data, to signal that it is ready to perform processing. CloudMemory_DataKey::primaryKey may be "LevelRenderer" while CloudMemory_DataKey::secondaryKey may be ID_SIGNAL_READY. The client will also call Get() to subscribe to new tasks, such as ID_TASK_SUBSCRIPTION. And to Post() results, such as ID_TASK_COMPLETION. The server will have a local client on 127.0.0.1 that contains the actual problem to solve. This local client will subscribe to ID_SIGNAL_READY. When the notification arrives, part of the problem is split off and Post() is used with ID_TASK_SUBSCRIPTION. The data field can specify the GUID of which client should process this task. If the local client on the server gets the Cloud_ClientCallback::OnDeletion() call, then one of the processing clients lost the connection or crashed. The data being processed can be reassigned to another client.
|
||||
<p><strong>Distributed CloudServer Implementation</strong>
|
||||
<p>See Samples/CloudServer for a distributed authenticated implementation of CloudServer with DNS based host migration. See Samples/CloudServer/readme.txt for specific details on how it is implemented, how to implement load balancing among clients, and for a list of supported plugins.
|
||||
<p><strong>Server Directory Implementation</strong>
|
||||
<p>See Samples/CloudClient for an implementation of a high-performance server directory using the CloudServer sample as the backend. The distributed topology is allows for new servers can be added at runtime with no restarts, configuration, or code changes.
|
||||
<p> See CloudServer.h and CloudClient.h for a complete list of all documented functions and parameters.</TR>
|
||||
</TABLE>
|
||||
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR><TD>
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="http://www.youtube.com/watch?v=QpwcLQt1E0o">Cloud Computing Video</A><BR>
|
||||
<A HREF="cloudhosting.html">Cloud Hosting</A><BR>
|
||||
<A HREF="connectiongraph.html">ConnectionGraph2 plugin</A><BR>
|
||||
<A HREF="twowayauthentication.html">TwoWayAuthentication plugin</A><BR>
|
||||
</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
60
Help/RakNet/documentation/cloudhosting.html
Normal file
@ -0,0 +1,60 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>How to setup cloud hosting with RakNet</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">How to setup cloud hosting with RakNet</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<P><span class="RakNetBlueHeader">Cloud hosting through Rackspace</span><BR>
|
||||
<br>
|
||||
Services such as the <a href="autopatcher.html">autopatcher</a> require a server running RakNet. Technically, <a href="natpunchthrough.html">NATPunchthroughServer</a> does as well, although we do <a href="http://www.jenkinssoftware.com/forum/index.php?topic=5006.0">provide a free server</a>. While it is possible to run your server using a traditional host, such as <a href="http://www.hypernia.com/">Hypernia</a> these services will cost you about $150 USD a month. Scaling up the services also requires time-consuming installation of the codebase and it is not possible to do so programmatically.
|
||||
<P>RakNet was tested with two cloud hosting providers: <a href="http://aws.amazon.com/">Amazon AWS</a> and <a href="http://www.rackspace.com/cloud/">Rackspace Cloud</a>. I could not get Amazon AWS to work with incoming UDP connections. Furthermore, peformance on loopback using the BigPacketTest project was very bad. Rackspace did not have these problems and the cost for their lowest-end Linux servers is low. I also provide a <a href="rackspaceinterface.html">C++ interface to Rackspace</a> allowing you to programatically control your servers, so it's a good starting point.<P><strong>Signing up</strong>
|
||||
<P><img src="cloudhosting1.jpg">
|
||||
<P><br>
|
||||
<strong>Creating the server</strong>
|
||||
<P>The first step is to create a server, using Hosting / Cloud Servers / Add Server. This will bring up a menu asking if you want Linux or Windows, and how much RAM. The low-end Linux servers are cheaper than the Windows servers. RakNet should work with either. Cloud server and NAT punchthrough server both take minimal RAM. The Autopatcher takes a lot of RAM however, I recommend four gigabytes to serve 256 concurrent users or eight gigabytes to serve 512.
|
||||
<P><img src="cloudhosting2.jpg">
|
||||
<P>Once your server has been created, you will get an email telling you the password and login IP.
|
||||
<P><img src="cloudhosting3.jpg">
|
||||
<P> For Windows 7, enter the username, password, and login IP using Remote Desktop, found under Start / Accessories.
|
||||
<P><img src="cloudhosting4.jpg">
|
||||
<P>
|
||||
<P><strong>Setting up the server</strong>
|
||||
<P>Once logged in, server setup is the same as any computer.
|
||||
<ol>
|
||||
<li> The default installation contains Internet Explorer, which you can use to download <a href="http://www.mozilla.com/en-US/firefox/">Firefox</a> or <a href="http://www.google.com/chrome">Chrome</a>.</li>
|
||||
<li> Use that webbrowser to <a href="http://www.jenkinssoftware.com/download.html">download RakNet</a>. </li>
|
||||
<li>On Windows, you can download Visual C++ 2010 Express for free. Installation will require a reboot.</li>
|
||||
</ol>
|
||||
<p><img src="cloudhosting5.jpg"></p>
|
||||
<p>Once your server is setup, open the RakNet solution and compile normally. You now have a working server, using the IP address you connected to using Remote Desktop.</p>
|
||||
<p><strong>Backing up and scaling the server</strong></p>
|
||||
<P>Once you have the server setup the way you want it, you can create an image of the server, which is essentially a harddrive backup. This is important for scalability, because you can create a new instance of the server with the same configuration as your image.
|
||||
<P><img src="cloudhosting6.jpg">
|
||||
<P>When you are not running your server, be sure to delete the instance and leave the much cheaper image. Unlike Amazon AWS which only charges for usage, Rackspace charges as long as your server exists at all. To start your server again, or to start multiple instances of the same server, use the Cloud Servers menu under My Server Images.
|
||||
<P><img src="cloudhosting7.jpg">
|
||||
</TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<a href="autopatcher.html">Autopatcher</a><BR>
|
||||
<a href="cloudcomputing.html">Cloud Computing</a><BR>
|
||||
<a href="natpunchthrough.html">NAT punchthrough</a><BR>
|
||||
<a href="rackspaceinterface.html">Rackspace interface</A>
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/cloudhosting1.jpg
Normal file
|
After Width: | Height: | Size: 153 KiB |
BIN
Help/RakNet/documentation/cloudhosting2.jpg
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
Help/RakNet/documentation/cloudhosting3.jpg
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
Help/RakNet/documentation/cloudhosting4.jpg
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
Help/RakNet/documentation/cloudhosting5.jpg
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
Help/RakNet/documentation/cloudhosting6.jpg
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
Help/RakNet/documentation/cloudhosting7.jpg
Normal file
|
After Width: | Height: | Size: 124 KiB |
139
Help/RakNet/documentation/compilersetup.html
Normal file
@ -0,0 +1,139 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Compiler Setup</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Before you begin</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD>
|
||||
Use the source, static lib ,or a DLL?
|
||||
<BR>
|
||||
<BR>
|
||||
|
||||
RakNet includes the source, along with the projects to make the DLL and static lib, and samples. It no longer includes pre-built DLLs or libraries - this is due to incompatibilities across compilers. We recommend using the source directly, however you can also use the DLL or static lib projects to build your own.
|
||||
|
||||
<P><font color="#666666" size="2" face="Geneva, Verdana, Arial, Helvetica, sans-serif" class="G10">Projects to build the DLL/Static Lib, and the samples, are provided for Microsoft Visual Studio .Net 2003 and 2005.
|
||||
|
||||
Users of other compilers will have to make their own projects.<BR>
|
||||
|
||||
|
||||
|
||||
</TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">DLL Users</td>
|
||||
</tr></table>
|
||||
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<p class="RakNetBlueHeader">Creating a DLL</p>
|
||||
<ol>
|
||||
<li>Create a DLL project. I'll assume you know how to do this. In MSVC 7 you would create an empty project, then under Application Settings you check DLL and empty project.</li>
|
||||
<li>Add the source files under the /Source directory to the project.</li>
|
||||
<li>Add to "Additional Include Directories" your directory with the source files.<font color="#666666" size="2" face="Geneva, Verdana, Arial, Helvetica, sans-serif" class="G10"></li>
|
||||
<li>Import ws2_32.lib, or wsock32.lib if you don't have Winsock 2 installed. In MSVC 7 you can right click on the project, select configuration properties / linker / input / additional dependencies and type "ws2_32.lib" in there.</li>
|
||||
<li>Set your project to use multi-threaded runtime libraries. In MSVC 7 you can right click on the project, select configuration properties / C/C++ / Code Generation / Runtime Library and change it to Multi-threaded (/MT).</li>
|
||||
<li>Add _RAKNET_DLL to the Preprocessor Definitions. In VS Project Properties -> Configuration Properties -> C/C++ -> PreProcessor -> Preprocessor Definitions</li>
|
||||
<li>Set the character set to "not set".In VS Project Properties -> Configuration Properties -> General-> Character Set </li>
|
||||
<li>Optionally set your <A HREF="preprocessordirectives.html">preprocessor directives.</A></li>
|
||||
<li>Then hit F7 or the equivalent to build your DLL and Lib.</li>
|
||||
</ol>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="makedll.jpg"><IMG SRC="makedllsmall.jpg"></A><BR>
|
||||
</TD>
|
||||
<TR ALIGN="CENTER"><TD>
|
||||
<B>Creating an empty DLL project in .net 2003</B></TD></TR></TABLE>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="multithreadeddebug.jpg"><IMG SRC="multithreadeddebugsmall.jpg"></A><BR>
|
||||
</TD>
|
||||
<TR ALIGN="CENTER"><TD>
|
||||
<B>Setting Multithreaded debug in .net 2003</B></TD></TR></TABLE>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="ws2_32include.jpg"><IMG SRC="ws2_32includesmall.jpg"></A><BR>
|
||||
<TR ALIGN="CENTER"><TD>
|
||||
<B>Including ws2_32.lib in .net 2003</B>
|
||||
</TD></TR></TABLE>
|
||||
|
||||
|
||||
<p class="RakNetBlueHeader">Game Setup </p>
|
||||
<OL>
|
||||
<LI>Copy the DLL you just created to your game in the same directory as the exe. The lib can be in any directory you want.
|
||||
<LI>Add the .lib to your project
|
||||
<LI>Add all header files from /Source to your project</OL>
|
||||
<BR>
|
||||
|
||||
If you want to jump right in, refer to the <A HREF="tutorial.html">Basic code tutorial</A><BR>
|
||||
For more detail, refer to <A HREF="detailedimplementation.html">Detailed Implementation</A>
|
||||
|
||||
</TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Source users</td>
|
||||
</tr></table>
|
||||
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<span class="RakNetBlueHeader">Game Setup</span><BR>
|
||||
<BR>
|
||||
|
||||
<OL>
|
||||
<LI>Add the files under the /Source directory to the project. While not all of these are strictly necessary, the ones you don't use won't hurt you.
|
||||
<LI>Import ws2_32.lib, or wsock32.lib if you don't have Winsock 2 installed. In MSVC 7 you can right click on the project, select configuration properties / linker / input / additional dependencies and type "ws2_32.lib" in there.
|
||||
<LI>Set your project to use multi-threaded runtime libraries. In MSVC 7 you can right click on the project, select configuration properties / C/C++ / Code Generation / Runtime Library and change it to Multi-threaded (/MT).
|
||||
<LI>Set an additional include path to include the RakNet source (if you copied the source files to a different directory).
|
||||
<LI>Optionally set your <A HREF="preprocessordirectives.html">preprocessor directives.</A>
|
||||
</OL>
|
||||
|
||||
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="multithreadeddebug.jpg"><IMG SRC="multithreadeddebugsmall.jpg"></A><BR>
|
||||
</TD>
|
||||
<TR ALIGN="CENTER"><TD>
|
||||
<B>Setting Multithreaded debug in .net 2003</B></TD></TR></TABLE>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="ws2_32include.jpg"><IMG SRC="ws2_32includesmall.jpg"></A><BR>
|
||||
<TR ALIGN="CENTER"><TD>
|
||||
<B>Including ws2_32.lib in .net 2003</B>
|
||||
</TD></TR></TABLE>
|
||||
<BR>
|
||||
|
||||
</TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">3rd party dependencies</td>
|
||||
</tr></table>
|
||||
<BR>
|
||||
<span class="RakNetBlueHeader">Projects that won't compile by default</span><BR>
|
||||
<BR>
|
||||
Not all projects will build without installing 3rd party dependencies. These are not required to use the majority of RakNet, however you will be missing specific features or demos without them.<BR>
|
||||
<BR>
|
||||
<A HREF="dependencies.html">3rd party dependencies page</A><BR>
|
||||
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<BR>
|
||||
</TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><A HREF="index.html">Index</A><BR>
|
||||
<A HREF="dependencies.html">3rd party dependencies</A><BR>
|
||||
<A HREF="introduction.html">Introduction</A><BR>
|
||||
<A HREF="systemoverview.html">System Overview</A><BR>
|
||||
<A HREF="detailedimplementation.html">Detailed Implementation</A><BR>
|
||||
<A HREF="tutorial.html">Tutorial</A><BR>
|
||||
<A HREF="preprocessordirectives.html">Preprocessor directives</A><BR>
|
||||
</p></TD></TR></TABLE>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
172
Help/RakNet/documentation/compilersetup_xcode.html
Normal file
@ -0,0 +1,172 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Compiler Setup (Xcode)</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Xcode notes</td>
|
||||
</tr></table>
|
||||
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD>
|
||||
|
||||
Although Raknet is cross-platform, not all of the samples provided will compile/run on Mac OS X or iOS.
|
||||
Here I'll show you how to compile Raknet for Mac OS X and iOS, along with one of the samples for testing
|
||||
<br><br>
|
||||
</TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Compiling as a static library for Mac OS X</td>
|
||||
</tr></table>
|
||||
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<p class="RakNetBlueHeader">Create an empty workspace</p>
|
||||
<ol>
|
||||
<li>Create a folder named <i>RakNetTests</i>, and then create a new empty Workspace. Name it <i>RakNetTests</i>, and save it inside the new folder<BR><BR>
|
||||
<IMG SRC="xcode_newworkspace.jpg"><BR><BR>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p class="RakNetBlueHeader">Create the RakNet static library project</p>
|
||||
<ol>
|
||||
<li>
|
||||
Using <i>File->New->New Project</i>, create a new Mac OS X C/C++ library project<BR><BR>
|
||||
<A HREF="xcode_library.jpg"><IMG SRC="xcode_librarysmall.jpg"></A><BR><BR>
|
||||
Name it <i>RakNet</i> and use the following options:<BR>
|
||||
<IMG SRC="xcode_libraryname.jpg"><BR>
|
||||
Save it inside the same folder as the workspace<BR><BR>
|
||||
</li>
|
||||
|
||||
<li>Using Finder, copy RakNet's source code (<i>Source</i> folder) to where RakNet project file was created<BR><BR>
|
||||
<IMG SRC="xcode_sourcefolder.jpg">
|
||||
<BR><BR>
|
||||
</li>
|
||||
<li>
|
||||
Right-click the <i>RakNet</i> project, and select <i>Add Files to "RakNet"...</i> ,
|
||||
and select the new <i>Source</i> folder you should have in the same folder as the <i>RakNet</i>
|
||||
Project file. Use the following options:<BR><BR>
|
||||
<IMG SRC="xcode_addfiles.jpg"><BR><BR>
|
||||
This should create a <i>Source</i> group, like this:<BR>
|
||||
<IMG SRC="xcode_addfiles_newgroup.jpg"><BR><BR>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <font color="red">files inside the <i>cat</i> folder aren't supposed to be compiled</font>, so remove the <i>Source/cat</i> group from the project files.<br>
|
||||
When prompted for the deletion method, pick <strong><i>Remove References Only</i></strong>.<BR>
|
||||
<IMG SRC="xcode_remove_cat.jpg"><BR><BR>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Build Raknet using <i>Product->Build</i><BR>
|
||||
You should get a successful compilation.
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
</TD></TR>
|
||||
</TABLE>
|
||||
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Testing the static library</td>
|
||||
</tr></table>
|
||||
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<p class="RakNetBlueHeader">A simple sample...</p>
|
||||
For testing, we're going to use the sample <i>"Chat Example"</i> provided with the Raknet. You can find it the <i>"Samples/Chat Example"</i> folder.
|
||||
This sample has 2 source files, named <i>"Chat Example Server.cpp"</i> and <i>"Chat Example Client.cpp"</i>.
|
||||
We are going to create two projects from those files (one project for the Server, and another for the Client).
|
||||
|
||||
<BR><BR>
|
||||
Inside the folder where you have your workspace, create another folder named <i>Samples</i>,
|
||||
and copy <i>"Chat Example Server.cpp"</i> and <i>"Chat Example Client.cpp"</i> into that folder.<BR><BR>
|
||||
|
||||
<p class="RakNetBlueHeader">The server</p>
|
||||
<ol>
|
||||
<li>Create a <i>Command Line Tool</i> project for the Server:<BR>
|
||||
<IMG SRC="xcode_newcommandlinetool.jpg"><BR>
|
||||
In the next window where it asks for the options for your new project, name it <i>ChatExampleServer</i>,
|
||||
leave <i>Type</i> as <i>C++</i>, and <i>"Use Automatic Reference Counting"</i> unchecked.<BR>
|
||||
Save the project inside your <i>Samples</i> folder.<BR><BR>
|
||||
<li>
|
||||
Inside the newly created ChatExampleServer, you should have a group named <i>ChatExampleServer</i>.
|
||||
Delete the <i>main.cpp</i> you'll find inside that group, and add the <i>"Chat Example Server.cpp"</i> file<BR><BR>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Specify where to look for the RakNet header files, by changing the Build Settings of the ChatExampleServer project.
|
||||
This can be done in the <strong><i>Header Search Paths</i></strong> option, under the <strong><i>Search Paths</i></strong> section:<BR>
|
||||
<IMG SRC="xcode_headersearchpaths.jpg"><BR>
|
||||
If your folder structure is exactly the same as the one used for this tutorial, then the search path
|
||||
should be what you see in the above image. If not then you need to adjust it accordingly.<BR>
|
||||
<strong>NOTE:</strong> The search path is relative to the project file's location.<BR><BR>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Link <i>ChatExampleServer</i> project with our RakNet static library, by going to <strong><i>Build Phases</i></strong>, section
|
||||
<strong><i>Link Binary With Libraries</i></strong>, clicking the <strong>'+'</strong> button and picking our RakNet library as shown:<BR>
|
||||
<IMG SRC="xcode_linkwithlibrary.jpg"><BR><BR>
|
||||
</li>
|
||||
<li>
|
||||
You should be able to successfully build and run the Server now.<BR>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p class="RakNetBlueHeader">The Client</p>
|
||||
The steps to create the client project are the same as the ones for the Server:
|
||||
<ol>
|
||||
<li>Create a <i>"Command Line Tool"</i> project, and name it <i>ChatExampleClient</i></li>
|
||||
<li>Delete the file <i>main.cpp</i> and add the file <i>"Chat Example Client.cpp"</i></li>
|
||||
<li>Change the C/C++ compiler to <strong><i>LLVM GCC</i></strong></li>
|
||||
<li>Set the header search paths</li>
|
||||
<li>Add <i>RakNet</i> library to the list of libraries to link with.</li>
|
||||
</ol>
|
||||
|
||||
<p class="RakNetBlueHeader">Running the sample</p>
|
||||
You should now have 2 products ready to run (ChatExampleClient and ChatExampleServer). You can run
|
||||
one of them from inside Xcode, and run the other externally by right-clicking on it and selecting
|
||||
<strong>"Open With External Editor"</strong>.
|
||||
|
||||
</TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Compiling as a static library for iOS</td>
|
||||
</tr></table>
|
||||
<br>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
Compiling Raknet as a static library for iOS is essentially the same as for Mac OS X.<br>
|
||||
You can create a new project for the iOS library, or you can just create another Target for your Mac OS X
|
||||
static library project, and change what SDK to use:<br><br>
|
||||
<img src="xcode_changesdk.jpg">
|
||||
<br>
|
||||
<br>
|
||||
You can find some iOS samples in the <strong>Samples/iOS</strong> folder.<br><br>
|
||||
<br>
|
||||
</TD></TR>
|
||||
</TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><A HREF="index.html">Index</A><BR>
|
||||
<A HREF="dependencies.html">3rd party dependencies</A><BR>
|
||||
<A HREF="introduction.html">Introduction</A><BR>
|
||||
<A HREF="systemoverview.html">System Overview</A><BR>
|
||||
<A HREF="detailedimplementation.html">Detailed Implementation</A><BR>
|
||||
<A HREF="tutorial.html">Tutorial</A><BR>
|
||||
<A HREF="preprocessordirectives.html">Preprocessor directives</A><BR>
|
||||
</p></TD></TR></TABLE>
|
||||
|
||||
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/completeproject.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
227
Help/RakNet/documentation/congestioncontrol.html
Normal file
@ -0,0 +1,227 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Detailed Implementation</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">UDT based congestion control</td>
|
||||
</tr></table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<HTML>
|
||||
<!-- @page { margin: 0.79in } H1 { margin-top: 0.03in; margin-bottom: 0in; text-align: left } H1.western { font-family: "Times New Roman", serif; font-size: 12pt } H1.cjk { font-family: "Lucida Sans Unicode"; font-size: 12pt } H1.ctl { font-family: "Tahoma"; font-size: 12pt; font-weight: normal } H2 { margin-top: 0.03in; margin-bottom: 0in; text-align: left } H2.western { font-family: "Times New Roman", serif; font-size: 12pt } H2.cjk { font-family: "Lucida Sans Unicode"; font-size: 12pt } H2.ctl { font-family: "Tahoma"; font-size: 12pt; font-weight: normal } P { margin-bottom: 0.08in } -->
|
||||
<BODY DIR="LTR">
|
||||
<H1>The UDT Congestion Control Algorithm</H1>
|
||||
|
||||
<p ALIGN="CENTER">Yunhong Gu</p>
|
||||
<p ALIGN="CENTER">Aug. 2009</p>
|
||||
|
||||
<H1>OVERVIEW</H1>
|
||||
<p>UDT uses an AIMD (additive increase multiplicative decrease) style congestion control algorithm. The algorithm controls the sending rate by tuning the packet sending period (i.e. how often to send out one packet). This period is presented by the symbol <strong>SND </strong>in the rest of this document. The sending rate is increased every 10 milliseconds according to Section 3 if and only if at least one acknowledgement (ACK) has been received since the last rate increase. The rate will be decreased according to Section 4 upon receiving a packet loss report (negative acknowledgement, or NAK). The rate may or may not be decreased on a timeout event, see Section 5.</p>
|
||||
|
||||
<p>Note that the packet sending period is different from the inter-packet time. The former includes the time that is required to send out a packet, which can be significant in high speed networks. The latter does not include the packet sending time.</p>
|
||||
|
||||
<p>UDT also uses a supportive window-based control by tuning the maximum number of on-flight packets (unacknowledged packets) (<strong>CWND</strong>). An upper threshold of CWND should be used and set as large enough to not limit throughput. A lower threshold should be set as well to avoid deadlock (CWND cannot be 0). In UDT, the lower threshold is 2. The CWND value is updated when an ACK is received.</p>
|
||||
|
||||
<p>The congestion control includes two phases: it starts with a slow start phase and then enters then regular phase as described above. The slow start phase runs exactly once at the beginning of a connection and stops when a packet loss occurs or CWND reaches its maximum value.</p>
|
||||
|
||||
<p><strong>Implementation Note 1.1</strong>: Initially, SND is set at 0 and CWND is set at 2.</p>
|
||||
|
||||
<p><strong>Implementation Note 1.2</strong>: When necessary, the packet sending interval does not need to be strictly enforced. The sender can sends out a group of packets and then sleeps an aggregate amount of inter-packet time. For example, if SND = 10ms, the sender can sends out 10 packets continuously and sleep 100ms minus the time used to send out those 10 packets. This is especially important as most operating systems have a minimum sleep time (e.g., 10ms).</p>
|
||||
|
||||
<p><strong>Implementation Note 1.3</strong>: The window control is independent of flow control. However, they can be enforced at the same place in the sender. The sender should stop sending once the number of the on-flight packets reaches either the congestion window size or the flow window size, until a new ACK comes.</p>
|
||||
|
||||
<H1>PRELIMINARY</H1>
|
||||
<H2>ASSUMPTIONS</H2>
|
||||
<p>UDT assumes most of packets have the same size. If this assumption does not hold, the unit “packets per second” in the rest of the paper should be converted to bits per second.</p>
|
||||
|
||||
<p>UDT increases its sending rate every 10 milliseconds, this constant time is defined as <strong>SYN</strong>. At least one ACK should be sent back every SYN, provided that there are data packets received.</p>
|
||||
|
||||
<H2>Packet Pair Technique</H2>
|
||||
<p>UDT requires an estimated value of the link capacity. This is done by using a packet pair technique. In this technique, the sender sends two back-to-back packets of the same size. Once these two packets arrive at the receiver side, there will be an interval between the two packets. The link capacity can then be determined by</p>
|
||||
|
||||
<p> B = packet size / interval</p>
|
||||
|
||||
<p>UDT sends out a packet pair every 16 packets. However, when it happens that there is no 17th packet to be sent out, UDT will still send out the 16th packet, rather than waiting for the next one. In this case, there will be a bigger interval (hence underestimation) at the receiver side. The receiver should use a median filter to detect and discard such values.</p>
|
||||
|
||||
<p>In addition, other patterns of packet pairs can be used, as long as the receiver has a way to identify the packet pairs.</p>
|
||||
|
||||
<p><strong>Implementation Note 2.1</strong>: All packets in the packet pairs should have the same size. The ideal packet size used in packet pair should be the path MTU size (including all packet headers). If this is not possible, the size should be as close to the MTU size as possible. However, the size must not be bigger than MTU.</p>
|
||||
|
||||
<p>Because UDT was designed for transferring big data, there should be always enough MTU-sized packets to use. In certain situations where most packets are small ones, those packets can still be used for packet pair estimation, although overestimation may be caused, depending on how small the packets are. In addition, if the packets are sent out very frequently, they can be combined into bigger ones. If the packets are sent less frequently, then they are not likely to cause any congestion (hence the congestion control may not be necessarily strictly enforced).</p>
|
||||
|
||||
<p>If the sizes of the packets are too small or the two packets have different sizes, this packet pair should be ignored. The receiver keeps a window of the last <em>N</em> packet pairs. The value <em>N</em> can be any proper number as long as it can reach a reasonable estimation, and it should not be too large to consume too much memory and CPU time. In UDT, <em>N</em> = 64.</p>
|
||||
|
||||
<p>Here the data structure “window” is a circular linked list with a fixed size of <em>N</em>. However, it does not matter how it is implemented, as long as it can store a list of historical values and uses the most recent value to replace the oldest value each time.</p>
|
||||
|
||||
<p>The receiver should use a median filter to filter out noises. UDT computes a median value of the intervals kept in the window. All values greater than 8x of the median or less than 1/8 of the median should be ignored. UDT then computes the average of the rest intervals. The link capacity will then be calculated using the average interval.</p>
|
||||
|
||||
<p> B = packet size / average_interval</p>
|
||||
|
||||
<p>Note that this formula is based on the assumption that most packets have the same size. If this assumption does not hold, B should be computed from each pair independently and then the average B is calculated.</p>
|
||||
|
||||
<p>The window should be filled with very large intervals (i.e., low bandwidth, for safety purpose) initially. UDT uses 1 second.</p>
|
||||
|
||||
<p>The estimation is done at the receiver side. The receiver should send this value back to the sender. This can be carried by any proper control packets. UDT carries the estimation value in every ACK.</p>
|
||||
|
||||
<p>The sender, upon receiving a new value, should use a smooth average to update its own value:</p>
|
||||
|
||||
<p> B = B * 0.875 + b * 0.125</p>
|
||||
|
||||
<p>where B is the link capacity value that the sender maintains and b is the value that is just sent back by the receiver.</p>
|
||||
|
||||
<p><strong>Note 2.1:</strong> Accuracy of the packet pair technique may depend on the network equipments and network congestion. Both overestimation and underestimation can happen. However, the rate increase formula in Section 3 can tolerate misestimation to a scale up to 10x or 1/10 of the real link capacity.</p>
|
||||
|
||||
<p><strong>Implementation Note 2.2</strong>: The link capacity value B can be sent only with selected ACKs (e.g., every 10 ACKs or every 10ms). It depends on how often an ACK is generated. Calculating B is time consuming, so some ACKs can be skipped if ACKs are sent very often. This principle applies to the packet arrival rate (AS) as well, see Section 2.4.</p>
|
||||
|
||||
<H2>RTT and RTO</H2>
|
||||
<p>UDT needs to update RTT (Round Trip Time) and RTO (Retransmission Time Out). UDT sends one ACK2 (acknowledgement of acknowledgement) for selective ACK. The receiver records the time when an ACK is sent out. The ACK carries a unique sequence number (independent of the data packet sequence number). The corresponding ACK2 also carries the same sequence number. This technique is called ACK sub-sequencing.</p>
|
||||
|
||||
<p>Upon receiving the ACK2, UDT calculates the RTT by comparing the difference between the ACK2 arrival time and the ACK departure time. In the following formula, “RTT” is the current value that the receiver maintains and “rtt” is the recent value that was just calculated from ACK/ACK2.</p>
|
||||
|
||||
<p><em>RTT = RTT * 0.875 + rtt * 0.125</em></p>
|
||||
<p><em>RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125</em></p>
|
||||
|
||||
<p>The RTT value should be sent back to the sender, e.g., in ACK. UDT does not transmit RTTVar to the peer side. The peer side will update its own RTT and RTTVar values using the same formulae as above, in which case “rtt” is the most recent value it receives, e.g., carried by an incoming ACK.</p>
|
||||
|
||||
<p>Both RTT and RTTVar are changing variables. RTT is not a fixed value. It can be changed by congestion or even route change. RTTVar records the variance of the RTT value and is required to compute RTO:</p>
|
||||
|
||||
<p><em>RTO = RTT + 4 * RTTVar</em></p>
|
||||
|
||||
<p><strong>Note 2.2: </strong>A UDT socket can both send and receive. RTT, RTTVar, and RTO are not just sender specific variables. They are shared by both the sender and the receiver (of the same socket). When a UDT socket receives data, it updates its local RTT and RTTVar, which can be used for its own sender as well.</p>
|
||||
|
||||
<p><strong>Implementation Note 2.3</strong>: There is no need to calculate RTT and RTTVar in the same way as UDT does. If a protocol acknowledges immediately after receiving a data packet, RTT can be calculated by the difference between the ACK arrival time and the departure time of the corresponding data packet. In this case, there is no need to send ACK2.</p>
|
||||
|
||||
<p>RTO is the time that an acknowledgement is expected after a data packet is sent out. If there is no acknowledgement after this amount of time elapsed, a timeout event should be triggered.</p>
|
||||
<p>Since UDT only acknowledges every SYN time, in UDT</p>
|
||||
|
||||
<p><em>RTO = RTT + 4 * RTTVar + SYN</em></p>
|
||||
|
||||
<p><strong>Implementation Note 2.4:</strong> It is important to have a lower threshold for RTO. If RTO is too small, retransmission can be easily triggered by a busy CPU, etc. UDT uses 100ms as the lower threshold.</p>
|
||||
|
||||
<p><strong>Implementation Note 2.5: </strong>Continuous timeout should increase the RTO value. In UDT, a counter (ExpCount) is used to track the number of continuous timeout.</p>
|
||||
|
||||
<p><em> RTO = ExpCount * (RTT + 4 * RTTVar) + SYN</em></p>
|
||||
|
||||
<H2>Packet Arrival Rate</H2>
|
||||
<p>The receiver records the intervals between any two adjacent data packet arrivals. The number of interval values can be limited by a window size. The packet arrival rate can be calculated by </p>
|
||||
|
||||
<p>AS = 1 / average_interval</p>
|
||||
|
||||
<p>The average packet arrival interval also requires a media filter, similar to that in Section 2.2. The thresholds are the same as those used for B (link capacity): 8x for upper threshold and 1/8 for lower threshold. </p>
|
||||
|
||||
<p><strong>Implementation Note 2.6: </strong>Similar to the estimated bandwidth, if most of the data packets are less than MTU, the arrival rate can be computed as bits per second, rather than number of packets per second.</p>
|
||||
|
||||
<H1>WHEN AN ACK COMES</H1>
|
||||
<p><strong>This event and only this event can trigger the increase of a packet sending rate (or reduce packet sending period SND) and the updated of the size of the congestion window (CWND).</strong></p>
|
||||
|
||||
<p>The congestion control is in the slow start phase initially. Within the slow start phase, the packet sending period (SND) is 0. The window size starts at 2 and is set to the number of total sent packets so far every time an ACK comes.</p>
|
||||
|
||||
<p>Slow start phase stops upon receiving an NAK or the maximum size of the window has been reached. CWND has an upper threshold (“maximum size of the window”). This upper threshold is used for safety purpose (even if there is no packet loss, the slow start phase has to stop at a certain point). The threshold can be set to the maximum of the receiver buffer size.</p>
|
||||
|
||||
<p>At the end of the slow start phase, the packet interval should be set to the reverse of the packet arrival rate:</p>
|
||||
|
||||
<p> SND = 1/ AS</p>
|
||||
|
||||
<p>There is nothing else to do during the slow start phase. The slow start phase will only run exact once at the beginning of a connection.</p>
|
||||
|
||||
<p>In the regular phase (post slow start), the rate increase can be defined according to the following formulae:</p>
|
||||
|
||||
<p>First, the number of sent packets to be increased in the next SYN period (inc) is calculated as:</p>
|
||||
<p> </p>
|
||||
<p> <em> if (B <= C)</em></p>
|
||||
<p> <em>inc = 1/MSS;</em></p>
|
||||
<p><em>else</em></p>
|
||||
<p> <em>inc = max(10^(ceil(log10((B-C)*MSS*8))) * Beta/MSS, 1/MSS);</em></p>
|
||||
|
||||
<p>where B is the estimated link capacity sent back by the receiver (Section 2.2) and C is the current sending speed (C = 1/SND) . Both are counted as packets per second. MSS is the fixed/maximum size of UDT packet counted in bytes, usually MSS = MTU – UDP/UDT packet header size. Beta is a constant value of 0.0000015.</p>
|
||||
|
||||
<p><strong>Note 3.1</strong>: If B and C use bits per second as the unit, “MSS” should be removed from the (B-C)*MSS part. This can be helpful if most of the packets are less than MTU size.</p>
|
||||
|
||||
<p>The SND value is the updated as:</p>
|
||||
|
||||
<p><em>SND = (SND * SYN) / (SND * inc + SYN).</em></p>
|
||||
|
||||
<p>Meanwhile, the congestion window size should be updated by:</p>
|
||||
|
||||
<p><em>CWND = AS * (RTT + SYN) + 16</em></p>
|
||||
|
||||
<p>where AS is the packet arrival rate sent back by the receiver (Section 2.4).</p>
|
||||
|
||||
<p><strong>During the regular phase, sending rate cannot be increased more than once during any SYN time. </strong>Meanwhile, although CWND can be updated for all ACKs, it is usually updated together with SND.</p>
|
||||
|
||||
<H1>WHEN AN NAK COMES</H1>
|
||||
<H2>Congestion Period</H2>
|
||||
<p>Every time an NAK is received, UDT updates the largest sequence number has been sent so far (LastDecSeq). We define a congestion period as the time between two NAKs in which the biggest lost packet sequence number carried in the NAK is greater than the LastDecSeq.</p>
|
||||
|
||||
<p>For example, if the sender has sent out packets 1 – 100 and an NAK comes informing the sender that packet 60 is missing, the LastDecSeq value should be updated as 100. If after a while, another NAKs comes indicating that packet 140 is lost, this NAK starts a new congestion period, which lasts until the next period starts.</p>
|
||||
|
||||
<p>Note that one congestion period can cause multiple packet loss events. For example, if the sender sends out packet 1 – 100, packets 60 and 80 are lost. When the sender receives NAK(60), a new congestion period is started, and the sender updates LastDecSeq as 100. When the sender receives NAK(80), which is less than LastDecSeq(100), so the sender knows that it already decreased the sending rate before (at NAK-60) and it may decrease less for this packet loss (UDT uses a random process to decide how much to decrease).</p>
|
||||
|
||||
<p>After the sender decreases the sending rate at NAK(60) or possibly NAK(80), it continues to send out new packets 101, 102, etc. For example, when it receives an NAK(140), which is greater than LastDecSeq(100), this means that the current sending rate is still too high: packets sent after a rate decrease still got dropped.</p>
|
||||
|
||||
<H2>Decreasing Sending Rate</H2>
|
||||
<p>These four parameters are used in rate decrease, and their initial values are in the parentheses: AvgNAKNum (1), NAKCount (1), DecCount(0), LastDecSeq (initial sequence number - 1).</p>
|
||||
|
||||
<p>AvgNAKNum is the average number of NAKs during a congestion period. NAKCount is the number of NAKs received so far in the current congestion period. DecCount means the number of times that the sending rate has been decreased during the congestion period.</p>
|
||||
|
||||
<p><em>If it is in the slow start phase, set SND to 1/AS. Slow start ends. Stop.</em></p>
|
||||
|
||||
<p><em>If this NAK starts a new congestion period</em></p>
|
||||
<p><em>{</em></p>
|
||||
<p> <em>increase SND = SND * 1.125;</em></p>
|
||||
<p> <em>Update AvgNAKNum;</em></p>
|
||||
<p> <em>Reset NAKCount to 1;</em></p>
|
||||
<p><em>Compute DecRandom to a random (uniform distribution) number between 1 and AvgNAKNum;</em></p>
|
||||
<p> <em>Reset DecCount to 1;</em></p>
|
||||
<p> <em>Reset Update LastDecSeq;</em></p>
|
||||
<p> <em>Stop.</em></p>
|
||||
<p><em>}</em></p>
|
||||
|
||||
<p><em>If (DecCount <= 5) and (NAKCount == DecCount * DecRandom)</em></p>
|
||||
<p><em>{</em></p>
|
||||
<p> <em>Update SND period: SND = SND * 1.125;</em></p>
|
||||
<p> <em>Increase DecCount by 1;</em></p>
|
||||
<p><em>}</em></p>
|
||||
|
||||
<p><em>Update LastDecSeq and NAKCount.</em></p>
|
||||
|
||||
<p>UDT decreases the sending rate for each congestion period by a random factor between 1/8 to 1/2. For the first NAK in the congestion period, UDT decreases its sending rate by 1/8 (SND = SND * 1.125). For the following NAKs, UDT uses a random number (DecRandom) to decide if the rate should be decreased or not. DecRandom is a random number between 1 and the average number of NAKs per congestion period (AvgNAKNum).</p>
|
||||
|
||||
<p>For example, if DecRandom = 2, then UDT will decrease its sending rate on the 1st, 2nd, 4th, 6th, … NAKs. However, the sending rate should not be decreased by more than 1/2 in each congestion period, so UDT will stop decreasing after the 6th decrease (DecCount <= 5), as 1.125^6 = 2.</p>
|
||||
|
||||
<H1>RETRANSMISSION</H1>
|
||||
<p>The expiration of the RTO timer can trigger the transmission of packets sending and may decrease of the sending rate as well. Note that RTO is NOT set per packet/message; it is a system timer and it is reset by every ACK and NAK.</p>
|
||||
|
||||
<p>In UDT 4.4, the sending rate is unchanged. In UDT 4.5, the sending rate is halved (SND = SND * 2). The latter is recommended now because it is safer for low bandwidth networks.</p>
|
||||
|
||||
<p>Because RTO is actually greater than RTT (Section 2.3), there should not be more than one timeout per RTT.</p>
|
||||
|
||||
<p>Finally, after the aggregate continuous timeouts exceeds a threshold, the connection should be deemed to be broken.</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td><p><A HREF="index.html">Index</A><BR>
|
||||
</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD><p><BR>
|
||||
</p>
|
||||
</TD></TR></TABLE>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
261
Help/RakNet/documentation/connecting.html
Normal file
@ -0,0 +1,261 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head><title>Connecting</title>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API"></head>
|
||||
|
||||
<body leftmargin="0" topmargin="0" style="background-color: rgb(255, 255, 255);" alink="#003399" link="#003399" marginheight="0" marginwidth="0" vlink="#003399">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><br>
|
||||
<br>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><span class="RakNetWhiteHeader"><img src="spacer.gif" height="1" width="8">Connecting
|
||||
to other systems</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><span class="RakNetBlueHeader">Find
|
||||
who to connect to<br>
|
||||
</span><br>
|
||||
There are 5 ways to find other systems to connect to:<br>
|
||||
<ol>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Direct IP entry (you already know it)</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">LAN Broadcast</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Using the CloudServer/CloudClient plugins</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Using the Lobby server or RoomsPlugin</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Using MasterServer2</li>
|
||||
</ol>
|
||||
<span class="RakNetBlueHeader">Option 1: Direct IP Entry</span><br>
|
||||
<br>
|
||||
The simplest and easiest way from a coding perspective is to either
|
||||
hardcode an IP address or domain name, or present a GUI to the user
|
||||
asking them to enter the IP address of the other system they would like
|
||||
to connect to. Most of the samples use this method. Back when networked
|
||||
games first came out, this was the only option available.<br>
|
||||
<br>
|
||||
<span style="font-style: italic;">Advantages:<br>
|
||||
</span>
|
||||
|
||||
<ul>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Little to no GUI work required of programmers and
|
||||
artists</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">If the IP address or domain name is fixed, such as if
|
||||
you are running a dedicated server, this is the correct solution</li>
|
||||
</ul>
|
||||
<span style="font-style: italic;"><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Disadvantages:<br>
|
||||
</span>
|
||||
<ul>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Inflexible</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Users will only be able to play with people they
|
||||
already know.</li>
|
||||
</ul>
|
||||
<p><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Note: Use
|
||||
127.0.0.1, or localhost, to connect to another instance of RakPeer on
|
||||
the same computer, or the same application.</p>
|
||||
<span class="RakNetBlueHeader">Option 2: Lan Broadcast</span>
|
||||
<p> RakNet supports the ability to broadcast a packet to find other systems
|
||||
on a local LAN, with optional data to send and retrieve identifying the
|
||||
application. The sample <span style="font-weight: bold;">LANServerDiscovery</span>
|
||||
demonstrates this technique.<br>
|
||||
<br>
|
||||
In RakPeerInterface.h, the Ping function will can do this, as follows<br>
|
||||
<br>
|
||||
<span style="font-style: italic;"></span><small>rakPeer->Ping("255.255.255.255",
|
||||
REMOTE_GAME_PORT, onlyReplyOnAcceptingConnections);</small><br>
|
||||
<span style="font-weight: bold;"></span><br>
|
||||
REMOTE_GAME_PORT should be whatever port the other system is running
|
||||
the application you care about on. onlyReplyOnAcceptingConnections is a
|
||||
boolean indicating if the other system should reply, even if they have
|
||||
no connections available for you to connect to.<br>
|
||||
<br>
|
||||
Open systems will reply with ID_UNCONNECTED_PONG. From the sample:<br>
|
||||
<br>
|
||||
<span class="RakNetCode">if (p->data[0]==ID_UNCONNECTED_PONG)<br>
|
||||
{<br>
|
||||
RakNet::TimeMS time;<br>
|
||||
RakNet::BitStream bsIn(packet->data,packet->length,false);<br>
|
||||
bsIn.IgnoreBytes(1);<br>
|
||||
bsIn.Read(time);<br>
|
||||
printf("Got pong from %s with time
|
||||
%i\n", p->systemAddress.ToString(), RakNet::GetTime() - time);</span><br>
|
||||
}<br>
|
||||
<span style="font-weight: bold;"></span><br>
|
||||
In order to send custom user data, call
|
||||
RakPeer::SetOfflinePingResponse(customUserData, lengthInBytes); RakNet
|
||||
will copy the data passed to it and return this data appended to
|
||||
ID_UNCONNECTED_PONG.<br>
|
||||
<span style="font-style: italic;"><br>
|
||||
<font size="-1">Note: there is a hardcoded define
|
||||
MAX_OFFLINE_DATA_LENGTH in RakPeer.cpp limiting the length of your
|
||||
custom user data. Change this value and recompile if your data is
|
||||
larger than this define.<br>
|
||||
</span><br>
|
||||
<span style="font-style: italic;">Advantages:</span></p>
|
||||
<ul>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">You can join games automatically on program startup,
|
||||
no GUI or user interaction required</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Best way to find games on the LAN</li>
|
||||
</ul>
|
||||
<span style="font-style: italic;"><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Disadvantages:</span><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2"><br>
|
||||
<ul>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Won't work for the general internet</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Not as flexible as the <a href="lightweightdatabase.html">lightweight database plugin</a></li>
|
||||
</ul>
|
||||
<p><span class="RakNetBlueHeader">Option 3: Using the CloudServer/CloudClient plugins</span><br>
|
||||
<br>
|
||||
The <a href="cloudcomputing.html">CloudServer/CloudClient</a> plugin can act as a directory server without modification.</p>
|
||||
<p><span style="font-style: italic;">Advantages:</span></p>
|
||||
<ul>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Customizable</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">You can subscribe to update notifications when memory has been updated from another system</li>
|
||||
</ul>
|
||||
<span style="font-style: italic;"><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Disadvantages:</span><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2"><br>
|
||||
<ul>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Only scales to a few hundred users</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">You have to host your own server</li>
|
||||
</ul>
|
||||
<p><span class="RakNetBlueHeader">Option 4: Using the Lobby server or RoomsPlugin</span><br>
|
||||
<br>
|
||||
If you are not using a service that already provides a lobby, on the PC we provide database code that has similar functionality. The lobby server provides a database driven service for players to
|
||||
interact and start games. It provides features such as friends,
|
||||
matchmaking, emails, ranking, instant messenging, quick match, rooms,
|
||||
and room moderation.<br>
|
||||
<br>
|
||||
See the samples <span style="font-weight: bold;">Lobby2Server_PGSQL</span>
|
||||
and <span style="font-weight: bold;">Lobby2Client</span>
|
||||
for a demonstration of how to use this feature.<br>
|
||||
<br>
|
||||
<span style="font-style: italic;">Advantages: </span>
|
||||
</p>
|
||||
<ul>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">The most flexible solution for players to join games</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Allows users to interact before starting games</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Builds community</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Supports multiple titles</li>
|
||||
</ul>
|
||||
<span style="font-style: italic;"><span style="font-style: italic;">Disadvantages:<br>
|
||||
</span></span>
|
||||
<ul>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Requires a separate, dedicated server to host the
|
||||
plugin, and the server must have database support</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Feature is relatively large and complex compared to a
|
||||
simple game listing, requiring a good investment in time and programming</li>
|
||||
</ul>
|
||||
<p><span class="RakNetBlueHeader">Option 5: MasterServer2</span><br>
|
||||
<br>
|
||||
We host a master server for our customers. See <A HREF="http://masterserver2.raknet.com/">this page</A> for more details.
|
||||
<br>
|
||||
<br>
|
||||
<span style="font-style: italic;">Advantages:
|
||||
</span>
|
||||
<ul>
|
||||
<li>Fast</li>
|
||||
<li>Easy to use</li>
|
||||
<li>You do not have to host a server</li>
|
||||
</ul>
|
||||
<span style="font-style: italic;">Disadvantages:<br>
|
||||
</span>
|
||||
<ul>
|
||||
<li>Special licensing if you need the server sources</li>
|
||||
</ul>
|
||||
<span class="RakNetBlueHeader">Initiate
|
||||
connection attempt<span style="font-weight: normal;"><br>
|
||||
<br>
|
||||
</span></span>Once you know the IP
|
||||
address of the remote system(s) to connect to, use
|
||||
RakPeerInterface::Connect() to initiate an <span style="font-style: italic;">asynchronous</span>
|
||||
connection attempt. The parameters to connect are:<br>
|
||||
<br>
|
||||
<span class="RakNetCode">ConnectionAttemptResult Connect( const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, PublicKey *publicKey=0, unsigned connectionSocketIndex=0, unsigned sendConnectionAttemptCount=6, unsigned timeBetweenSendConnectionAttemptsMS=1000, RakNet::TimeMS timeoutTime=0 )</span><br>
|
||||
<ul>
|
||||
<li>host is an IP address, or domain name.</li>
|
||||
<li>remotePort is the port that the remote system is
|
||||
listening on, which you passed to the Startup() function</li>
|
||||
<li>passwordData is optional binary data to send with the
|
||||
connection request. If this data does not match what was passed to
|
||||
RakPeerInterface::SetPassword(), the remote system will reply with
|
||||
ID_INVALID_PASSWORD.</li>
|
||||
<li>passwordDataLength is the length, in bytes, of
|
||||
passwordData</li>
|
||||
<li>publicKey is the public key parameter that was passed to InitializeSecurity() on the remote system. If you don't use security, pass 0.</li>
|
||||
<li>connectionSocketIndex is the index into the array of socket descriptors passed to socketDescriptors in RakPeer::Startup() to determine the one to send on.</li>
|
||||
<li>sendConnectionAttemptCount is how many datagrams to send before giving up as unable to connect. This is also used for MTU detection, with 3 different MTU sizes. So the default of 12 means send each MTU size 4 times, which should be sufficient to tolerate any reasonable packetloss. Lower values mean that ID_CONNECTION_ATTEMPT_FAILED would be returned to you faster.</li>
|
||||
<li>timeBetweenSendConnectionAttemptsMS is how many milliseconds to wait before sending another connection attempt. A good value is 4 times the expected ping.</li>
|
||||
<li>timeoutTime is how many milliseconds to wait, for this particular connection, before dropping the remote system if a message cannot be delivered. The default value of 0 means use the global value from SetTimeoutTime().</li>
|
||||
</ul>
|
||||
<p>Connect() will return CONNECTION_ATTEMPT_STARTED for a successful attempt, something else on failure.<br>
|
||||
<br>
|
||||
<span style="font-style: italic;">Note: Connect()
|
||||
returning true does NOT mean you are connected. If successful the message ID_CONNECTION_REQUEST_ACCEPTED should be received. If not you will recieve one of the error messages.</span></p>
|
||||
<p class="RakNetBlueHeader">Connectivity messages returned as the first byte of the Packet::data structure</p>
|
||||
<p><strong>Connection closed</strong>: ID_DISCONNECTION_NOTIFICATION, ID_CONNECTION_LOST<br>
|
||||
<strong>New connection</strong>:
|
||||
ID_NEW_INCOMING_CONNECTION, ID_CONNECTION_REQUEST_ACCEPTED<br>
|
||||
<strong>Connection attempt failed</strong>:
|
||||
ID_CONNECTION_ATTEMPT_FAILED, ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY, ID_OUR_SYSTEM_REQUIRES_SECURITY, ID_PUBLIC_KEY_MISMATCH, ID_ALREADY_CONNECTED, ID_NO_FREE_INCOMING_CONNECTIONS, ID_CONNECTION_BANNED, ID_INVALID_PASSWORD, ID_INCOMPATIBLE_PROTOCOL_VERSION, ID_IP_RECENTLY_CONNECTED</p>
|
||||
<p class="RakNetBlueHeader">Troubleshooting ID_CONNECTION_ATTEMPT_FAILED</p>
|
||||
<p> ID_CONNECTION_ATTEMPT_FAILED is
|
||||
the generic message meaning no communication was established with the remote system. Possible
|
||||
reasons include:</p>
|
||||
<ul>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">The IP address is wrong</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">That system is not running RakNet, or
|
||||
RakPeerInterface::Startup() was not called on that system</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">The remote system has started RakNet, but
|
||||
RakPeerInterface::SetMaximumIncomingConnections() was not called</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">A firewall on either system is blocking UDP packets
|
||||
on the port you have chosen</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">A router on the remote system is blocking incoming
|
||||
UDP packets on the port you have chosen. See the <a href="natpunchthrough.html">NAT Punchthrough</a>
|
||||
plugin to resolve this.</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">On Windows Vista, the network driver
|
||||
security service pack sometimes breaks UDP, not just for RakNet, but in
|
||||
general, even for DirectPlay. This service pack should be rolled back,
|
||||
and not installed.</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2"><a href="secureconnections.html">Secure
|
||||
connections</a> are enabled, and your system failed the security
|
||||
check.</li>
|
||||
<li><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2">Your IP address was banned with
|
||||
RakPeerInterface::AddToBanList(). Note that some plugins, such as the <a href="connectionFilter.html">connection filter</a>,
|
||||
have the option to ban IP addresses automatically.</li>
|
||||
</ul>
|
||||
<p> Assuming you are able to connect, it
|
||||
is time to go onto the section:
|
||||
<a href="creatingpackets.html">Creating
|
||||
Packets</a><br>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><strong>See
|
||||
Also</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><font class="G10" color="#111122" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="1">
|
||||
<a href="index.html">Index</a><br>
|
||||
<a href="connectionFilter.html">Connection Filter</a><br>
|
||||
<a href="creatingpackets.html">Creating Packets</a><br>
|
||||
<a href="lightweightdatabase.html">Lightweight
|
||||
Database plugin</a><br>
|
||||
<a href="natpunchthrough.html"><span style="text-decoration: underline;">NAT Punchthrough plugin</span></a><br>
|
||||
<a href="secureconnections.html">Secure connections</a><br>
|
||||
<a href="faq.html">FAQ</a><br>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body></html>
|
||||
0
Help/RakNet/documentation/connectionFilter.html
Normal file
56
Help/RakNet/documentation/connectiongraph.html
Normal file
@ -0,0 +1,56 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Connection Graph</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92">
|
||||
<span class="RakNetWhiteHeader">Connection Graph<img src="spacer.gif" width="8" height="1">Plugin Interface Implementation</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD>
|
||||
<span class="RakNetBlueHeader">Connection Graph Implementation Overview</span><BR>
|
||||
<BR>
|
||||
|
||||
|
||||
The Connection Graph plugin maintains a graph of connections for the entire network, so every peer knows about every other peer. The graph of connections is updated as new systems connect or disconnect from the network.<br />
|
||||
You can optionally specify a password which you can use to allow certain systems to take part on the graph. <br />
|
||||
<br />
|
||||
Connection Graph doesn't connect to the other involved systems. It just keeps an aupdated graph of the entire network. If you want all systems
|
||||
connected to each other, see <A HREF="fullyconnectedmesh2.html">Fully Connected Mesh</A>.<BR>
|
||||
<BR>
|
||||
|
||||
|
||||
|
||||
|
||||
Returns the connection graph, stored as map of adjacency lists.
|
||||
<BR>
|
||||
|
||||
DataStructures::WeightedGraph<ConnectionGraph::SystemAddressAndGroupId, unsigned short, false> *GetGraph(void);<BR>
|
||||
<BR>
|
||||
|
||||
|
||||
See the sample at <I>Samples\ConnectioGraph</I><BR></TD>
|
||||
</TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="plugininterface.html">PluginInterface</A><br />
|
||||
<A HREF="fullyconnectedmesh.html">Full Connected Mesh</A> <BR>
|
||||
<A HREF="replicamanager.html">Replica Manager</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/consoleapplication.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
124
Help/RakNet/documentation/consoleserver.html
Normal file
@ -0,0 +1,124 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Console Server Manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Command Console Server Overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Use the console to remotely control a game server</span> <BR>
|
||||
</p>
|
||||
<p>Sometimes it is useful to control a server when you are not in front of that particular computer. This can arise due to server hosting, where the host is located offsite. Or perhaps you have many servers, and you want to control them via a script. The ConsoleServer, CommandParserInterface, and TransportInterface are three classes that work together to meet these needs.</p>
|
||||
<p><strong>ConsoleServer</strong></p>
|
||||
<p>The ConsoleServer class, located at ConsoleServer.h, contains a list of CommandParserInterface classes, added with ConsoleServer::AddCommandParser(). By calling ConsoleServer::Update() once per game tick, all CommandParserInterface classes are processed for incoming input</p>
|
||||
<p><strong>CommandParserInterface</strong></p>
|
||||
<p>A command parser is a class which operates on a named set of registered commands. CommandParserInterface is a base class from which you should derive functionality for each command parser. For example, RakNetCommandParser.h exposes most functions that are available to call in RakPeerInterface. RakNetTransportCommandParser exposes functions that deal with the RakNetTransport class, used to actually send data used by the ConsoleServer.</p>
|
||||
<p><strong>TransportInterface</strong></p>
|
||||
<p>The TransportInterface class provides functionality to the ConsoleServer to send strings. There are currently two implementations of TransportInterface: TelnetTransport, and RakNetTransport. TelnetTransport uses <a href="tcpinterface.html">TCPInterface.h</a> to reply to a remote telnet terminal. RakNetTransport sends strings through an instance of RakPeer, with <a href="secureconnections.html">secure connections</a> enabled.</p>
|
||||
<p><strong>Putting it all together</strong></p>
|
||||
<p>Excerpts from the sample CommandConsoleServer</p>
|
||||
<p class="RakNetCode">ConsoleServer consoleServer;<br>
|
||||
TelnetTransport tt;<br>
|
||||
RakNetCommandParser rcp;<br>
|
||||
LogCommandParser lcp;</p>
|
||||
<p class="RakNetCode">consoleServer.AddCommandParser(&rcp);<br>
|
||||
consoleServer.AddCommandParser(&lcp);<br>
|
||||
consoleServer.SetTransportProvider(ti, port);<br>
|
||||
lcp.AddChannel("TestChannel");<br>
|
||||
</p>
|
||||
<p class="RakNetCode">while (1)<br>
|
||||
{<br>
|
||||
lcp.WriteLog("TestChannel", "Test of logger");<br>
|
||||
consoleServer.Update();<br>
|
||||
// Game loop here<br>
|
||||
}</p>
|
||||
<p>It's quite simple in practice. You have one instance of a console server, one instance of a transport interface (EIther TelnetTransport or RakNetTransport), and your command parsers. Call ConsoleServer::AddCommandParser for each parser, ConsoleServer::SetTransportProvider() for telnet or RakNet, and ConsoleServer::Update() once per tick. Here I also add an output channel to the LogCommandParser, and output to the log once per tick.</p>
|
||||
<p>Assuming the server is already started, you can connect as follows:</p>
|
||||
<p><strong>Start telnet from the start menu</strong><br>
|
||||
<img src="telnet1.jpg" alt="Start Telnet" width="348" height="176"></p>
|
||||
<p><strong>Connect to your server with telnet</strong><br>
|
||||
<img src="telnet2.jpg" alt="Connect to localhost" width="641" height="302"></p>
|
||||
<p><strong>The system should handle everything else</strong><br>
|
||||
<img src="telnet3.jpg" alt="Help" width="640" height="301"></p>
|
||||
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> RakNetTransport</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD>
|
||||
<p class="RakNetBlueHeader">Secure console connections</p>
|
||||
<p>Telnet is easy to use but not secure. If you want to send passwords or other sensitive data, you should use RakNetTransport on the server instead. This comes with an additional command parser, RakNetTransportCommandParser, which adds the functionality to change the password on the instance of RakPeer that is internal to RakNetTransport. It was designed this way so remote users connect to the command parser without connecting to the game itself, and the game and the command parser can have different passwords.</p>
|
||||
<p>For the client-side, the sample CommandConsoleClient is an implementation of a console application that uses RakNet to connect to RakNetTransport</p>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Creating your own command parser</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD>
|
||||
<p class="RakNetBlueHeader">Predefine commands and/or pass the command strings directly to your scripting system</p>
|
||||
<p>To add a new command parser, first derive a class from CommandParserInterface, as was done in RakNetCommandParser.h. You will want to override OnCommand, GetName, and SendHelp. Additionally, any functionality you need to communicate with your game, such as SetGamePointer() or SetLogger(), you should add on your own.</p>
|
||||
<p>1. In the constructor of your new class, call RegisterCommand for each command you want to add. Here is an example from <strong>RakNetCommandParser.cpp</strong></p>
|
||||
<p><code>RegisterCommand(4, "Startup","( unsigned short maxConnections, int _threadSleepTimer, unsigned short localPort, const char *forceHostAddress );");</code></p>
|
||||
<p>The first parameter, 4, is the number of parameters to pass to the function. The second parameter, "Startup" is the name of the command, and will show up in the abbreviated command list. The third parameter, "unsigned short maxConnections ...", defines the helpString, displayed when help is called on a particular named command.</p>
|
||||
<p>Given this syntax, ConsoleServer will verify that the correct number of parameters was passed, and return an error to the user should this not be the case when calling a particular command.</p>
|
||||
<p>2. In OnCommand(), compare the command string to your registered commands, and take the desired action</p>
|
||||
<p><code>if (strcmp(command, "Startup")==0)<br>
|
||||
{<br>
|
||||
SocketDescriptor socketDescriptor((unsigned short)atoi(parameterList[1]), parameterList[3]);<br>
|
||||
ReturnResult(peer->Startup((unsigned short)atoi(parameterList[0]), atoi(parameterList[2]), &socketDescriptor, 1), command, transport, systemAddress);<br>
|
||||
}</code></p>
|
||||
<p>The return value of OnCommand is currently not used, so just return true.</p>
|
||||
<p>ReturnResult is a function you can optionally call that will return back a string to the requesting system.</p>
|
||||
<p>3. Implement GetName(), returning the name of your command parser. This will show up in the command parser listing.</p>
|
||||
<p>4. Implement SendHelp(), which will return extended help when queried for your particular parser. If your parser is not runnable due to failed preconditions, it is a good idea to return a notification message about that here.</p>
|
||||
<p><strong>Unknown or variable number of parameters:</strong></p>
|
||||
<p>Pass CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS as the first parameter to RegisterCommand. CommandServer will not check for a valid number of parameters in this case. It is up to you in OnCommand() to deal with error conditions that may come up in this case.</p>
|
||||
<p><strong>Direct string parsing</strong></p>
|
||||
<p>If you don't want ConsoleServer to parse the incoming string for you, use the parameter originalString passed to OnCommand. For example, if you are controlling your scripting system, you would probably want to pass this string directly along.</p>
|
||||
<p><strong>Changing delineators</strong></p>
|
||||
<p>If you want to separate your commands by something other than space, or separate your strings by something other than quotation marks, the defines are found in CommandServer.cpp</p>
|
||||
<p class="RakNetCode">#define COMMAND_DELINATOR ' '<br>
|
||||
#define COMMAND_DELINATOR_TOGGLE '"'</p>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <p><A HREF="index.html">Index</A><br>
|
||||
<a href="http://en.wikipedia.org/wiki/TELNET">Telnet (Wikipedia)</a><br>
|
||||
<a href="tcpinterface.html">TCP Interface</a><br>
|
||||
<a href="secureconnections.html">Secure connections</a><BR>
|
||||
</p>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
65
Help/RakNet/documentation/crashreporter.html
Normal file
@ -0,0 +1,65 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Crash Reporter Manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Crash Reporter Overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Minidumps made easy</span><BR>
|
||||
</p>
|
||||
<p>The CrashReporter, found at RakNet/Samples/CrashReporter, is a Windows-only class designed to make it easier to debug unmonitored servers and/or game clients. When a crash occurs, the CrashReporter implementation catches the exception, writes a minidump, and then writes to disk or sends an email. The email operation can be interactive, opening the user's email client, or non-interactive, conecting to the mail server with the <a href="emailsender.html">EmailSender</a> class and sending a report automatically.</p>
|
||||
<p><strong>Copied from CrashReporter.h</strong></p>
|
||||
<p>The minidump can be opened in visual studio and will show you where the crash occurred and give you the local variable values.<br>
|
||||
<br>
|
||||
<em>How to use the minidump:</em><br>
|
||||
<br>
|
||||
Put the minidump on your harddrive and double click it. It will open Visual Studio. It will look for the exe that caused the crash in the directory
|
||||
that the program that crashed was running at. If it can't find this exe, or if it is different, it will look in the current
|
||||
directory for that exe. If it still can't find it, or if it is different, it will load Visual Studio and indicate that it can't find
|
||||
the executable module. No source code will be shown at that point. However, you can specify modpath=<pathToExeDirectory> in the
|
||||
project properties window for "Command Arguments".
|
||||
The best solution is copy the .dmp to a directory containing a copy of the exe that crashed.<br>
|
||||
<br>
|
||||
On load, Visual Studio will look for the .pdb, which it uses to find the source code files and other information. This is fine as long as the source
|
||||
code files on your harddrive match those that were used to create the exe. If they don't, you will see source code but it will be the wrong code.
|
||||
There are three ways to deal with this.<br>
|
||||
<br>
|
||||
The first way is to change the path to your source code so it won't find the wrong code automatically.
|
||||
This will cause the debugger to not find the source code pointed to in the .pdb . You will be prompted for the location of the correct source code.<br>
|
||||
<br>
|
||||
The second way is to build the exe on a different path than what you normally program with. For example, when you program you use c:/Working/Mygame
|
||||
When you release builds, you do at c:/Version2.2/Mygame . After a build, you keep the source files, the exe, and the pdb
|
||||
on a harddrive at that location. When you get a crash .dmp, copy it to the same directory as the exe, ( c:/Version2.2/Mygame/bin )
|
||||
This way the .pdb will point to the correct sources to begin wtih.<br>
|
||||
<br>
|
||||
The third way is save build labels or branches in source control and get that version (you only need source code + .exe + .pdb) before debugging.
|
||||
After debugging, restore your previous work.<br>
|
||||
</p>
|
||||
<p> To use:<br>
|
||||
#include "DbgHelp.h"<br>
|
||||
Link with Dbghelp.lib ws2_32.lib</p>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <A HREF="index.html">Index</A><BR> </TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
363
Help/RakNet/documentation/creatingpackets.html
Normal file
@ -0,0 +1,363 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head><title>Creating Packets</title>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</head>
|
||||
<body leftmargin="0" topmargin="0" style="background-color: rgb(255, 255, 255);" alink="#003399" link="#003399" marginheight="0" marginwidth="0" vlink="#003399">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><br>
|
||||
<br>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" height="1" width="8">Creating
|
||||
Packets</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><span class="RakNetBlueHeader">How
|
||||
to encode your game data into packets</span><br>
|
||||
<br>
|
||||
Systems
|
||||
that run RakNet, and in fact all systems on the internet, communicate
|
||||
through what is commonly known as packets. Or more accurately in the
|
||||
case of UDP, datagrams. Each datagram is created by RakNet and contains
|
||||
one or more messages. Messages could be created by you, such as
|
||||
position or health, or sometimes are created by RakNet internally, such
|
||||
as pings. By convention, the first byte of messages contain a numerical
|
||||
identifier from 0 to 255 which is used to indicate what type of message
|
||||
it is. RakNet already has a large set of messages it uses internally,
|
||||
or for plugins. These can be viewed in the file MessageIdentifiers.h.<br>
|
||||
<br>
|
||||
For this example, lets set the position of a timed mine in the gameworld.
|
||||
We'll need the following data:<br>
|
||||
<ul>
|
||||
<li>The position of the mine, which is 3 floats. float x,
|
||||
float y,
|
||||
float z. You may have your own vector type which you can use intead. </li>
|
||||
<li>Some way to refer to the mine that all systems agree
|
||||
on. The <a href="networkidobject.html">NetworkIDObject</a>
|
||||
class is perfect for that. Lets assume class Mine inherits from
|
||||
NetworkIDObject. Then all we have to store is get the NetworkID of the
|
||||
mine (for more information see <a href="receivingpackets.html">Receiving
|
||||
Packets</a>, <a href="sendingpackets.html">Sending
|
||||
Packets</a>. </li>
|
||||
<li>Who owns the mine. That way if someone steps on it we
|
||||
know who
|
||||
to give credit to. The built in reference to players, SystemAddress, is
|
||||
perfect.. You can use GetExternalID() to get the SystemAddress. </li>
|
||||
<li>When the mine was placed. Lets say after 10 seconds
|
||||
the mine
|
||||
is automatically disintegrated, so it's important that we get the time
|
||||
correct so the mine doesn't disintegrate at different times on
|
||||
different computers. Fortunately the RakNet has the built-in ability to
|
||||
handle this using <a href="timestamping.html">Timestamping</a>.</li>
|
||||
</ul>
|
||||
<span class="RakNetBlueHeader">Use
|
||||
a structure or a bitstream?</span><br>
|
||||
<br>
|
||||
Ultimately, anytime you send data you will send a stream of characters.
|
||||
There are two easy ways to encode your data into this. One is to create
|
||||
a structure and cast it to a (char*) the other is to use the built-in <a href="bitstreams.html">BitStream</a> class.<br>
|
||||
<br>
|
||||
The advantage of creating a structure and casting is that it is very
|
||||
easy to change the structure and to see what data you are actually
|
||||
sending. Since both the sender and the recipient can share the same
|
||||
source file defining the structure, you avoid casting mistakes. There
|
||||
is also no risk of getting the data out of order, or using the wrong
|
||||
types. The disadvantage of creating a structure is that you often have
|
||||
to change and recompile many files to do so. You lose the
|
||||
compression you can automatically perform with the bitstream class. And RakNet cannot automatically endian-swap the structure members.<br>
|
||||
<br>
|
||||
The advantage of using a bitstream is that you don't have to change any
|
||||
external files to use it. Simply create the bitstream, write the data
|
||||
you want in whatever order you want, and send it. You can use the
|
||||
'compressed' version of the read and write methods to write using fewer
|
||||
bits and it will write bools using only one bit. You can write
|
||||
data out dynamically, writing certain values if certain conditions are
|
||||
true or false. BitStream will automatically endian-swap members written with Serialize(), Write(), or Read(). The disadvantage of a bitstream is you are now
|
||||
susceptible to make mistakes. You can read data in a way that does not
|
||||
complement how you wrote it - the wrong order, a wrong data type, or
|
||||
other mistakes.<br>
|
||||
<br>
|
||||
We will cover both ways of creating packets here.<br></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" height="1" width="8">Creating
|
||||
Packets with structs</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<p><br>
|
||||
As I’ve probably mentioned earlier, RakNet uses a convention on how
|
||||
packets (Packet) types are identified.
|
||||
The first byte of the data field is a single byte enumeration that
|
||||
specifies type, followed by the transmitted data.
|
||||
In packets that include a time stamp, the first byte contains
|
||||
ID_TIMESTAMP, the following 4 bytes the actual time stamp value, then
|
||||
the byte that identifies the packet, and only then the actual data
|
||||
transmitted. <br>
|
||||
<br>
|
||||
<span class="RakNetBlueHeader">Without
|
||||
Timestamping</span>
|
||||
<span class="RakNetCode"><br>
|
||||
</span></p>
|
||||
<p class="RakNetCode">#pragma pack(push, 1)<br>
|
||||
struct structName<br>
|
||||
{<br>
|
||||
unsigned char typeId; // Your type here<br>
|
||||
// Your data here<br>
|
||||
};<br>
|
||||
#pragma pack(pop)</p>
|
||||
<p>Noticed
|
||||
the #pragma pack(push,1) and #pragma pack(pop) ? These force your
|
||||
compiler (in this case VC++), to pack the structure as byte-aligned.
|
||||
Check your compiler documentation to learn more.</p>
|
||||
<p class="RakNetBlueHeader">With Timestamping</p>
|
||||
<p class="RakNetCode"> #pragma pack(push, 1)<br>
|
||||
struct structName<br>
|
||||
{<br>
|
||||
unsigned char useTimeStamp; // Assign ID_TIMESTAMP to this<br>
|
||||
RakNet::Time timeStamp; // Put the system time in here returned by RakNet::GetTime() or some other method that returns a similar value<br>
|
||||
unsigned char typeId; // Your type here<br>
|
||||
// Your data here<br>
|
||||
};<br>
|
||||
#pragma pack(pop)</p>
|
||||
<p>Note that when sending structures, RakNet assumes the timeStamp is in network order. You would have to use the function BitStream::EndianSwapBytes() on the timeStamp field to make this happen. To then read the timestamp on the receiving system, use if (bitStream->DoEndianSwap()) bitStream->ReverseBytes(timeStamp, sizeof(timeStamp). This step is not necessary if using BitStreams.</p>
|
||||
<p> Fill out your packet. For our timed mine, we want the form that uses
|
||||
timestamping. So the end result should look like the following...</p>
|
||||
<span class="RakNetCode"> #pragma pack(push, 1)<br>
|
||||
struct structName<br>
|
||||
{<br>
|
||||
unsigned char useTimeStamp; // Assign ID_TIMESTAMP to this<br>
|
||||
RakNet::Time timeStamp; // Put the system time in here returned by RakNet::GetTime()<br>
|
||||
unsigned char typeId; // You should put here an enum you defined after the last one defined in MessageIdentifiers.h, lets say ID_SET_TIMED_MINE<br>
|
||||
float x,y,z; // Mine position<br>
|
||||
NetworkID networkId; // NetworkID of the mine, used as a common method to refer to the mine on different computers<br>
|
||||
SystemAddress systemAddress; // The SystenAddress of the player that owns the mine<br>
|
||||
};<br>
|
||||
#pragma pack(pop)</span>
|
||||
<p>
|
||||
As I wrote in the comment above, we have to define enums for our own
|
||||
packets types, so when the data stream arrives in a Receive call we
|
||||
know what we are looking at. You should define your enums as starting
|
||||
at ID_USER_PACKET_ENUM, like this:</p>
|
||||
<p><span class="RakNetCode"><br>
|
||||
// Define our custom packet ID's<br>
|
||||
enum {<br>
|
||||
ID_SET_TIMED_MINE = ID_USER_PACKET_ENUM,<br>
|
||||
// More enums....<br>
|
||||
};<br>
|
||||
</span><br>
|
||||
NOTE THAT YOU CANNOT INCLUDE POINTERS DIRECTLY OR
|
||||
INDIRECTLY IN THE STRUCTS.<br>
|
||||
<br>
|
||||
It seems to be a fairly common mistake that people include a pointer or
|
||||
a class with a pointer in the struct and think that the data pointed to
|
||||
by the pointer will be sent over the network. This is not the case -
|
||||
all it would send is the pointer address<br>
|
||||
<br>
|
||||
Nested Structures<br>
|
||||
<br>
|
||||
There is no problem with nesting structures. Just keep in mind that the
|
||||
first byte is always what determines the packet type.<br>
|
||||
|
||||
<span class="RakNetCode"><br>
|
||||
#pragma pack(push, 1)<br>
|
||||
struct A<br>
|
||||
{<br>
|
||||
unsigned char typeId; // ID_A<br>
|
||||
};<br>
|
||||
struct B<br>
|
||||
{<br>
|
||||
unsigned char typeId; // ID_A<br>
|
||||
};<br>
|
||||
struct C // Struct C is of type ID_A<br>
|
||||
{<br>
|
||||
A a;<br>
|
||||
B b;<br>
|
||||
}<br>
|
||||
struct D // Struct D is of type ID_B<br>
|
||||
{<br>
|
||||
B b;<br>
|
||||
A a;<br>
|
||||
}<br>
|
||||
#pragma pack(pop)</span><font class="G10" color="#111122" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="1"><br>
|
||||
</p>
|
||||
<p></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><strong><span class="RakNetWhiteHeader"> Creating
|
||||
Packets with Bitstreams</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Write
|
||||
less data with bitstreams
|
||||
</span><br>
|
||||
<br>
|
||||
Lets take our mine example above and use a bitstream to write it out
|
||||
instead. We have all the same data as before.<br>
|
||||
<br>
|
||||
<span class="RakNetCode"> MessageID useTimeStamp; // Assign this to ID_TIMESTAMP<br>
|
||||
RakNet::Time timeStamp; // Put the system time in here returned by RakNet::GetTime()<br>
|
||||
MessageID typeId; // This will be assigned to a type I've added after ID_USER_PACKET_ENUM, lets say ID_SET_TIMED_MINE<br>
|
||||
useTimeStamp = ID_TIMESTAMP;<br>
|
||||
timeStamp = RakNet::GetTime();<br>
|
||||
typeId=ID_SET_TIMED_MINE;<br>
|
||||
Bitstream myBitStream;<br>
|
||||
myBitStream.Write(useTimeStamp);<br>
|
||||
myBitStream.Write(timeStamp);<br>
|
||||
myBitStream.Write(typeId);<br>
|
||||
// Assume we have a Mine* mine object<br>
|
||||
myBitStream.Write(mine->GetPosition().x);<br>
|
||||
myBitStream.Write(mine->GetPosition().y);<br>
|
||||
myBitStream.Write(mine->GetPosition().z);<br>
|
||||
myBitStream.Write(mine->GetNetworkID()); // In the struct this is NetworkID networkId<br>
|
||||
myBitStream.Write(mine->GetOwner()); // In the struct this is SystemAddress systemAddress<br>
|
||||
</span><br>
|
||||
If we were to send myBitStream to RakPeerInterface::Send it would be
|
||||
identical internally to a casted struct at this point. Now lets try
|
||||
some improvements. Lets assume that a good deal of the time mines are
|
||||
at 0,0,0 for some reason. We can then do this instead:<br>
|
||||
<span class="RakNetCode"><br>
|
||||
unsigned char useTimeStamp; // Assign this to ID_TIMESTAMP<br>
|
||||
RakNet::Time timeStamp; // Put the system time in here returned by RakNet::GetTime()<br>
|
||||
unsigned char typeId; // This will be assigned to a type I've added after ID_USER_PACKET_ENUM, lets say ID_SET_TIMED_MINE<br>
|
||||
useTimeStamp = ID_TIMESTAMP;<br>
|
||||
timeStamp = RakNet::GetTime();<br>
|
||||
typeId=ID_SET_TIMED_MINE;<br>
|
||||
Bitstream myBitStream;<br>
|
||||
myBitStream.Write(useTimeStamp);<br>
|
||||
myBitStream.Write(timeStamp);<br>
|
||||
myBitStream.Write(typeId);<br>
|
||||
// Assume we have a Mine* mine object<br>
|
||||
// If the mine is at 0,0,0, use 1 bit to represent this<br>
|
||||
if (mine->GetPosition().x==0.0f && mine->GetPosition().y==0.0f && mine->GetPosition().z==0.0f)<br>
|
||||
{<br>
|
||||
myBitStream.Write(true);<br>
|
||||
}<br>
|
||||
else<br>
|
||||
{<br>
|
||||
myBitStream.Write(false);<br>
|
||||
myBitStream.Write(mine->GetPosition().x);<br>
|
||||
myBitStream.Write(mine->GetPosition().y);<br>
|
||||
myBitStream.Write(mine->GetPosition().z);<br>
|
||||
}<br>
|
||||
myBitStream.Write(mine->GetNetworkID()); // In the struct this is NetworkID networkId<br>
|
||||
myBitStream.Write(mine->GetOwner()); // In the struct this is SystemAddress systemAddress<br>
|
||||
</span><br>
|
||||
This can potentially save us sending 3 floats over the network, at the
|
||||
cost of 1 bit.<br>
|
||||
<br>
|
||||
<span class="RakNetBlueHeader">Common
|
||||
mistake!</span><br>
|
||||
<br style="font-weight: bold;">
|
||||
When
|
||||
writing the first byte to a bitstream, be sure to cast it to
|
||||
(MessageID) or (unsigned char). If you just write the enumeration
|
||||
directly you will be writing a full integer (4 bytes).<span style="font-style: italic;"><br>
|
||||
</span><br>
|
||||
Right:<br>
|
||||
<span class="RakNetCode">bitStream->Write((MessageID)ID_SET_TIMED_MINE); </span></p>
|
||||
<p> Wrong: <br>
|
||||
<span class="RakNetCode">bitStream->Write(ID_SET_TIMED_MINE);</span></p>
|
||||
<p> In the second case, RakNet will see the first byte is 0, which is
|
||||
reserved internally to ID_INTERNAL_PING, and you will never get it.</p>
|
||||
<p><font class="G10" color="#666666" size="2"><br>
|
||||
<strong class="RakNetBlueHeader">Writing
|
||||
strings</strong>
|
||||
<br>
|
||||
<br>
|
||||
It is possible to write strings using the array overload of the
|
||||
BitStream. One way to do it would be to write the length, then the data
|
||||
such as:</p>
|
||||
<p><span class="RakNetCode">void WriteStringToBitStream(char *myString, BitStream *output)<br>
|
||||
{<br>
|
||||
output->Write((unsigned short) strlen(myString));<br>
|
||||
output->Write(myString, strlen(myString);<br>
|
||||
}</span></p>
|
||||
<p>Decoding
|
||||
is similar. However, that is not very efficient. RakNet comes with a
|
||||
built in StringCompressor called... stringCompressor. It is a global
|
||||
instance. With it, WriteStringToBitStream becomes:</p>
|
||||
<p><span class="RakNetCode">void WriteStringToBitStream(char *myString, BitStream *output)<br>
|
||||
{<br>
|
||||
stringCompressor->EncodeString(myString, 256, output);<br>
|
||||
}</span></p>
|
||||
<p>Not
|
||||
only does it encode the string, so the string can not easily be read by
|
||||
packet sniffers, but it compresses it as well. To decode the string you
|
||||
would use:</p>
|
||||
<p><span class="RakNetCode">void WriteBitStreamToString(char *myString, BitStream *input)<br>
|
||||
{<br>
|
||||
stringCompressor->DecodeString(myString, 256, input);<br>
|
||||
}</span></p>
|
||||
<p>The
|
||||
256 in this case is the maximum number of bytes to write and read. In
|
||||
EncodeString, if your string is less than 256 it will write the entire
|
||||
string. If it is greater than 256 characters it will truncate it such
|
||||
that it would decode to an array with 256 characters, including the
|
||||
null terminator. </p>
|
||||
<p>RakNet also has a string class, RakNet::RakString, found in RakString.h</p>
|
||||
<p class="RakNetCode">RakNet::RakString rakString("The value is %i", myInt);</p>
|
||||
<p><span class="RakNetCode">bitStream->write(rakString);</span><br>
|
||||
<br>
|
||||
RakString is approximately 3X faster than std::string.</p>
|
||||
<p>Use RakWString for Unicode support.</p>
|
||||
<p><i>Programmer's notes:</i><br>
|
||||
<br>
|
||||
1. You can also write structs
|
||||
directly into a Bitstream simply by casting it to a (char*). It will
|
||||
copy your structs using memcpy. As with structs, it will not
|
||||
dereference pointers so you should not write pointers into the
|
||||
bitstream.<br>
|
||||
2.
|
||||
If you use a string very commonly, you can use the StringTable class
|
||||
instead. It works the same way as StringCompressor, but can send two
|
||||
bytes to represent a known string.<font class="G10" color="#666666" size="2"><font class="G10" color="#666666" size="2"><font class="G10" color="#666666" size="2"><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2"><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2"><font class="G10" color="#666666" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="2"><br>
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><strong> See Also</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><font class="G10" color="#111122" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="1"><a href="index.html">Index</a><br>
|
||||
<a href="sendingpackets.html">Sending Packets</a><br>
|
||||
<a href="receivingpackets.html">Receiving Packets</a><br>
|
||||
<a href="timestamping.html">Timestamping</a><br>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body></html>
|
||||
52
Help/RakNet/documentation/csharpunity.html
Normal file
@ -0,0 +1,52 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>C# and Unity Manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> C# and Unity</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">More sophisticated networking when using Unity</span><BR>
|
||||
</p>
|
||||
<p><a href="http://unity3d.com/">Unity</a> uses RakNet version <a href="http://www.raknet.net/raknet/downloads/RakNet-3.731.zip">3.731</a>, which should also be network compatible with <a href="http://www.raknet.net/raknet/downloads/RakNet-3.732.zip">3.732</a>. In order to use RakNet with Unity, you do not have to download RakNet or sign a license agreement, as Unity ships RakNet integrated into the binary code already.</p>
|
||||
<p>If you want more sophisticated networking, such as being able to run your own server, more efficient network communication for an MMO, or to otherwise modify or extend the networking of Unity you can use RakNet version 4.x, which has <a href="swigtutorial.html">C# support</a>. Unity allows you to write game code in C#, therefore you would be able to use write your own network code using RakNet directly and have full access to its feature set.</p>
|
||||
<p>Unity users do not have access RakNet 4.x. So it is necessary to <a href="http://www.raknet.net/contact.html">contact us</a> for a license when planning to make this upgrade.</p>
|
||||
<B>Version 4 improvements over RakNet bundled with Unity</B>
|
||||
<UL>
|
||||
<LI>Support for C# via SWIG
|
||||
<LI>Support for XBOX / PS3 / Windows Phone 8 / Windows Store 8
|
||||
<LI>Faster autopatcher
|
||||
<LI>NAT punchthrough now more likely to work, and we host it for you
|
||||
<LI>Hosted master server http://masterserver2.raknet.com/
|
||||
<LI>IPV6 support
|
||||
<LI>Better congestion control
|
||||
<LI>Better HTTP support
|
||||
<LI>TeamManager class, to automatically manage players across teams
|
||||
<LI>StatisticsHistory class
|
||||
<LI>HTTP Based lobby3 system, supporting leaderboards, achievements, friends, clans, etc.
|
||||
</UL>
|
||||
<p> </p></TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <A HREF="index.html">Index</A><BR>
|
||||
<a href="swigtutorial.html">SWIG Tutorial</a></TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
54
Help/RakNet/documentation/custommemorymanagement.html
Normal file
@ -0,0 +1,54 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Custom Memory Management</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92">
|
||||
<img src="spacer.gif" width="8" height="1"><span class="RakNetWhiteHeader">Custom Memory Management</span></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD>
|
||||
<span class="RakNetBlueHeader">Override new, delete, malloc, free, and realloc
|
||||
</p>
|
||||
</span>
|
||||
<p>Users wishing to provide custom memory management functions can do so via RakMemoryOverride.cpp.</p>
|
||||
<p>There are 3 global pointers defined in this file, with predefined defaults:</p>
|
||||
<p class="RakNetCode">void* (*rakMalloc) (size_t size) = RakMalloc;<br>
|
||||
void* (*rakRealloc) (void *p, size_t size) = RakRealloc;<br>
|
||||
void (*rakFree) (void *p) = RakFree;</p>
|
||||
<p>To override, simply set the values of these variables to something else.</p>
|
||||
<p>For example, to override malloc, you may write:</p>
|
||||
<p class="RakNetCode">#include "RakMemoryOverride.h"</p>
|
||||
<p class="RakNetCode">void *MyMalloc(size_t size)<br>
|
||||
{<br>
|
||||
return malloc(size);<br>
|
||||
}</p>
|
||||
<p class="RakNetCode">int main()<br>
|
||||
{<br>
|
||||
rakMalloc=MyMalloc;<br>
|
||||
// ...<br>
|
||||
}</p>
|
||||
<p>Then edit the file RakNetDefinesOverrides.h and add </p>
|
||||
<p class="RakNetCode">#define _USE_RAK_MEMORY_OVERRIDE 1</p>
|
||||
<p>Alternatively, edit RakNetDefines.h _USE_RAK_MEMORY_OVERRIDE</p></TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92">
|
||||
<img src="spacer.gif" width="8" height="1"><span class="RakNetWhiteHeader">See Also</span></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><A HREF="index.html">Index</A><br>
|
||||
<A HREF="networkidobject.html">NetworkIDObject</A></p>
|
||||
</TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
96
Help/RakNet/documentation/datacompression.html
Normal file
@ -0,0 +1,96 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Data Compression</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Data Compression Overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><span class="RakNetBlueHeader">Description </span><BR>
|
||||
<BR>
|
||||
RakNet can automatically compress all your outgoing data and decompress your incoming data. To do this, it needs a 'sample' frequency table for your average game so it can pre-compute how to encode the data to get maximum savings. Here is the general process of how to go about this:
|
||||
<OL>
|
||||
<LI>Run a sample 'average' game. Get the frequency table for the server and for one of the clients (or average all the clients if you want).
|
||||
<LI>Generate the decompression layer for the server from the client's frequency table
|
||||
<LI>Generate the compression layer for the server from the server's frequency table
|
||||
<LI>Generate the decompression layer for the client from the server's frequency table
|
||||
<LI>Generate the compression layer for the client from the client's frequency table.
|
||||
</OL>
|
||||
After that everything is handled automatically.<BR>
|
||||
<BR>
|
||||
The functions are described below. See Samples\Compression for a full example. </TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Data Compression Functions</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><span class="RakNetCode">SetCompileFrequencyTable( bool doCompile )</span><BR>
|
||||
<BR>
|
||||
|
||||
Enables or disables frequency table tracking. This is required to get a frequency table, which is used in GenerateCompressionLayer()
|
||||
This value persists between connect calls and defaults to false (no frequency tracking)
|
||||
You can call this at any time - however you SHOULD only call it when disconnected. Otherwise you will only trackpart of the values sent over the network.
|
||||
|
||||
<BR><BR>
|
||||
<span class="RakNetCode">GenerateCompressionLayer(unsigned long inputFrequencyTable[256], bool inputLayer)</span><BR>
|
||||
<BR>
|
||||
|
||||
|
||||
This is an optional function to generate the compression layer based on the input frequency table, which you get with GetOutgoingFrequencyTable.You should call this twice - once with inputLayer as true and once as false.
|
||||
The frequency table passed here with inputLayer=true should match the frequency table on the recipient with inputLayer=false.
|
||||
Likewise, the frequency table passed here with inputLayer=false should match the frequency table on the recipient with inputLayer=true.
|
||||
Calling this function when there is an existing layer will overwrite the old layer.
|
||||
<BR>
|
||||
<BR>
|
||||
<span class="RakNetCode">DeleteCompressionLayer(bool inputLayer) <BR>
|
||||
</span><BR>
|
||||
|
||||
Delete the output or input layer as specified. This is not necessary to call and is only valuable for freeing memory.
|
||||
You should only call this when disconnected<BR>
|
||||
|
||||
<BR>
|
||||
<span class="RakNetCode">GetOutgoingFrequencyTable(unsigned long outputFrequencyTable[256]) </span><BR>
|
||||
<BR>
|
||||
|
||||
Returns the frequency of outgoing bytes into output frequency table
|
||||
The purpose is to save to file as either a master frequency table from a sample game session for passing to GenerateCompressionLayer() .
|
||||
You should only call this when disconnected. Requires that you first enable data frequency tracking by calling SetCompileFrequencyTable(true)
|
||||
<BR>
|
||||
|
||||
<BR>
|
||||
<span class="RakNetCode">float GetCompressionRatio </span><BR>
|
||||
<BR>
|
||||
This returns a number n > 0.0f where lower numbers are better. n == 1.0f means your data is no smaller or greater than the original. This shows how effective your compression rates are.<BR>
|
||||
|
||||
<BR>
|
||||
<span class="RakNetCode">float GetDecompressionRatio </span><BR>
|
||||
<BR>
|
||||
This returns a number n > 0.0f where higher numbers are better. n == 1.0f means the incoming data was decompressed to be just as large as it was when it came in. This shows how effective your compression rates are.<BR>
|
||||
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <A HREF="index.html">Index</A><BR> </TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
39
Help/RakNet/documentation/datareplicationvideo.html
Normal file
@ -0,0 +1,39 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Data Replication Video</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNetLogo.jpg" alt="Oculus VR, Inc."><BR><BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#6699CC">
|
||||
Data Replication Video</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
Covers the data replication system.
|
||||
<BR><BR>
|
||||
|
||||
|
||||
<CENTER>
|
||||
<embed type="application/x-mplayer2" pluginspage="http://www.microsoft.com/Windows/MediaPlayer/" name="mediaplayer1" ShowStatusBar="true" EnableContextMenu="false" autostart="false" width="640" height="580" loop="false" src="http://www.jenkinssoftware.com/raknet/downloads/DataReplication.wmv" />
|
||||
</CENTER>
|
||||
|
||||
<P>
|
||||
You can also right click and hit save as to <A HREF="http://www.jenkinssoftware.com/raknet/downloads/DataReplication.wmv">Download this video.</A>. in wmv format.
|
||||
<P>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="helloworldvideo.html">Hello World Video</A><BR>
|
||||
<A HREF="helloworldvideo.html">Hello World Video</A><BR>
|
||||
<A HREF="rpcvideo.html">Remote Procedure Call Video</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
118
Help/RakNet/documentation/debuggingdisconnects.html
Normal file
@ -0,0 +1,118 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Debugging Disconnections</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">Debugging disconnections or missing packets</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">How to trace and debug received datagrams in RakNet</span><BR>
|
||||
</p>
|
||||
<p>If your systems seem to get disconnected, or get no data, and all the usual debugging attempts have failed, here is an overview of how the RakNet handles incoming messages.</p>
|
||||
<p><strong>1. SocketLayer::RecvFromBlocking() in SocketLayer.cpp</strong></p>
|
||||
<p>RecvFromBlocking() is called from a thread RecvFromLoop that is created in RakPeer.cpp. Every datagram that arrives goes through this function - therefore, if you get no data, this is the first place to put a breakpoint. </p>
|
||||
<p class="RakNetCode">*bytesReadOut = recvfrom( s, dataOutModified, dataOutSize, flag, sockAddrPtr, socketlenPtr );</p>
|
||||
<p>That function should return, and bytesReadOut should be greater than 0. If you put a breakpoint after that function, and the breakpoint does not hit, then no datagrams arrived. At the bottom of the function the following code reads the address and port of the sender.</p>
|
||||
<p class="RakNetCode">systemAddressOut->port=ntohs( sa.sin_port );<br>
|
||||
systemAddressOut->binaryAddress=sa.sin_addr.s_addr; </p>
|
||||
<p>The datagram ends up in the rakPeer->bufferedPackets queue. The function SetEvent() is called on the rakPeer->quitAndDataEvents SignaledEvent class, which tells the UpdateNetworkLoop() thread to stop waiting and process the message.</p>
|
||||
<p><em>If you do not even hit this breakpoint, then there is a bug in your network.</em></p>
|
||||
<p><strong>2. RakPeer::RunUpdateCycle()</strong><strong> in RakPeer.cpp</strong></p>
|
||||
<p>RunUpdateCycle() is an update function that the UpdateNetworkLoop calls, many times per second. It's triggered by either time or by the rakPeer->quitAndDataEvents SignaledEvent class. For debugging message flows, you want a breakpoint towards the top of the function here:</p>
|
||||
<p class="RakNetCode">if (socketListIndex!=socketList.Size())<br>
|
||||
ProcessNetworkPacket(recvFromStruct->systemAddress, recvFromStruct->data, recvFromStruct->bytesRead, this, socketList[socketListIndex], recvFromStruct->timeRead);</p>
|
||||
<p>When a datagram is put in the rakPeer->bufferedPackets queue from step 1, it is processed here.</p>
|
||||
<p><em>If you do not hit this breakpoint, then either the thread is not running (unlikely) or there is a bug with the SignaledEvent class, or else the thread has locked up somewhere.</em></p>
|
||||
<p><strong>3. void ProcessNetworkPacket(...) in RakPeer.cpp</strong></p>
|
||||
<p>ProcessNetworkPacket is called for each incoming datagram. At the very top of the function a call is made to ProcessOfflineNetworkPacket(). ProcessOfflineNetworkPacket() checks if the sender is banned and if the message is prefixed with an array of bytes corresponding to OFFLINE_MESSAGE_DATA_ID. If the user is banned, the function returns and no further processing occurs. If the message is prefixed with OFFLINE_MESSAGE_DATA_ID, then this is generally a handshaking message, and the caller ProcessNetworkPacket() does not process further. For systems that are already connected, ProcessOfflineNetworkPacket() should return false. For debugging loss of messages for systems I already know are connected, I would step over the call to ProcessOfflineNetworkPacket, and only trace into it if it returns true.</p>
|
||||
<p>The next operation in ProcessNetworkPacket() is to look up the structure representing the remote system from the systemAddress (the IP address) by calling rakPeer->GetRemoteSystemFromSystemAddress( systemAddress, true, true );. A remoteSystem structure should be returned. If not, then the sender's IP address is unknown, and the message is not tagged as an offline message, so the datagram is ignored.</p>
|
||||
<p>Generally, you should expect ProcessNetworkPacket() to proceed to </p>
|
||||
<p>remoteSystem->reliabilityLayer.HandleSocketReceiveFromConnectedPlayer(<br>
|
||||
data, length, systemAddress, rakPeer->messageHandlerList, remoteSystem->MTUSize,<br>
|
||||
rakNetSocket->s, &rnr, rakNetSocket->remotePortRakNetWasStartedOn_PS3, timeRead);</p>
|
||||
<p><em>If HandleSocketReceiveFromConnectedPlayer() does not get called, then either the sender is not connected, the sender is banned, the sender was recently disconnected, there is a bug with GetRemoteSystemFromSystemAddress(), or the connected datagram encoding happened to match OFFLINE_MESSAGE_DATA_ID which shouldn't happen except due to bugs.</em></p>
|
||||
<p><strong>4. ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer(...)</strong></p>
|
||||
<p>This function handles processing a datagram from a connected player. Each datagram roughly follows the DatagramHeaderFormat structure at the top of the file. A datagram is either an acknowledgement of datagrams this system had previously sent, a negative acknowledgement of datagrams that didn't arrive, or one or more messages that the user had generated from the RakPeer::Send() call.</p>
|
||||
<p>This function is large and complex, but you generally do not need to deal with ACKs or NAKs, and can skip to the part that reads:</p>
|
||||
<p class="RakNetCode">InternalPacket* internalPacket = CreateInternalPacketFromBitStream( &socketData, timeRead );</p>
|
||||
<p>ReliabilityLayer::CreateInternalPacketFromBitStream(...) reads the header for each user message. The header contains data such as how long the message is, if the message had to be fragmented, and if it needs to be ordered. If the format of the message is invalid, the function will return 0. Otherwise, the InternalPacket structure is allocated and return with the user data filled in.</p>
|
||||
<p>If the very first call to the function fails, that is a bug. However, a datagram can contain more than one message, so the function is called in a loop until failure.</p>
|
||||
<p class="RakNetCode">while ( internalPacket )<br>
|
||||
{<br>
|
||||
...<br>
|
||||
// Parse the bitstream to create an internal packet<br>
|
||||
internalPacket = CreateInternalPacketFromBitStream( &socketData, timeRead );<br>
|
||||
}</p>
|
||||
<p>Immediately inside that loop is this block of code:</p>
|
||||
<p class="RakNetCode">for (unsigned int messageHandlerIndex=0; messageHandlerIndex < messageHandlerList.Size(); messageHandlerIndex++)<br>
|
||||
{<br>
|
||||
#if CC_TIME_TYPE_BYTES==4<br>
|
||||
messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, receivePacketCount, systemAddress, timeRead, false);<br>
|
||||
#else<br>
|
||||
messageHandlerList[messageHandlerIndex]->OnInternalPacket(internalPacket, receivePacketCount, systemAddress, (RakNet::TimeMS)(timeRead/(CCTimeType)1000), false);<br>
|
||||
#endif<br>
|
||||
}</p>
|
||||
<p>OnInternalPacket() is used for the PacketLogger plugin. If you think messages are being sent, but they are not listed by the PacketLogger, then it didn't get this far.</p>
|
||||
<p>The next block of code checks if this is a duplicate message. </p>
|
||||
<p class="RakNetCode">holeCount = (DatagramSequenceNumberType)(internalPacket->reliableMessageNumber-receivedPacketsBaseIndex);<br>
|
||||
const DatagramSequenceNumberType typeRange = (DatagramSequenceNumberType)(const uint32_t)-1;</p>
|
||||
<p>That is the start of a major chunk of code. <span class="RakNetCode">receivedPacketsBaseIndex</span> is a number that is incremented by one for each message that arrives from the remote system. As long as messages arrive in order, holeCount would be 0. If a message skipped one index, holeCount would be one. If a message was an immediate duplicate, holeCount would be negative 1 and be ignored. hasReceivedPacketQueue is a queue of booleans that indicates if we got a message for a given index. One potential failure point is this code:</p>
|
||||
<p class="RakNetCode">if (holeCount > (DatagramSequenceNumberType) 1000000)<br>
|
||||
{<br>
|
||||
RakAssert("Hole count too high. See ReliabilityLayer.h" && 0);<br>
|
||||
...<br>
|
||||
}</p>
|
||||
<p>To avoid memory attacks, the queue size is limited to that number. In practice a message should never be out of order by that much, even on a LAN.</p>
|
||||
<p>If the message was split by the sender, ReliabiltyLayer::InsertIntoSplitPacketList(...) is called. When all parts of a message has arrived, then ReliabiltyLayer::BuildPacketFromSplitPacketList() will return the reassembled message.</p>
|
||||
<p>From HandleSocketReceiveFromConnectedPlayer zero or more messages may be returned to the user. They are pushed to the outputQueue queue, for example:</p>
|
||||
<p class="RakNetCode">outputQueue.Push( internalPacket, _FILE_AND_LINE_ );</p>
|
||||
<p><em>The most likely failure point here should you not get data is a bug with the packet format in CreateInternalPacketFromBitStream().</em></p>
|
||||
<p><strong>5. ReliabilityLayer::Receive( unsigned char **data )</strong></p>
|
||||
<p>This function returns messages pushed to the outputQueue queue. It is called from RakPeer::RunUpdateCycle() and should be called on a regular interval, once for each connected system.</p>
|
||||
<p><strong>6. bool RakPeer::RunUpdateCycle( RakNet::TimeUS timeNS, RakNet::Time timeMS )</strong></p>
|
||||
<p class="RakNetCode">// Does the reliability layer have any packets waiting for us?<br>
|
||||
// To be thread safe, this has to be called in the same thread as HandleSocketReceiveFromConnectedPlayer<br>
|
||||
bitSize = remoteSystem->reliabilityLayer.Receive( &data );</p>
|
||||
<p>As described in step 5, the above code is called on a regular interval, once for each connected system. If bitSize is greater than 0, then we have a message from a connected system. This is probably a user message, although as you can see from the code in RakPeer it also checks for messages the user should not send, such as ID_CONNECTION_REQUEST. This is because part of the handshaking process is done reliably.</p>
|
||||
<p>Assuming that this is indeed a user message, the message is pushed to a queue here:<span class="RakNetCode"></span></p>
|
||||
<p class="RakNetCode">if (data[0]>=(MessageID)ID_TIMESTAMP &&<br>
|
||||
remoteSystem->isActive<br>
|
||||
)<br>
|
||||
{<br>
|
||||
packet=AllocPacket(byteSize, data, _FILE_AND_LINE_);<br>
|
||||
packet->bitSize = bitSize;<br>
|
||||
packet->systemAddress = systemAddress;<br>
|
||||
packet->systemAddress.systemIndex = ( SystemIndex ) remoteSystemIndex;<br>
|
||||
packet->guid = remoteSystem->guid;<br>
|
||||
packet->guid.systemIndex=packet->systemAddress.systemIndex;<br>
|
||||
AddPacketToProducer(packet);<br>
|
||||
}</p>
|
||||
<p>This adds the message to the packetReturnQueue queue found in RakPeer.</p>
|
||||
<p><strong>7. Packet* RakPeer::Receive( void )</strong></p>
|
||||
<p>Receive() is called by the user. The Update() function is called for all plugins. Then the packetReturnQueue is checked to see if a message should be returned to the user.</p>
|
||||
<p> </p>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <A HREF="index.html">Index</A><BR>
|
||||
<a href="RakNetUML.jpg">UML Diagram</a><a href="swigtutorial.html"></a></TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
108
Help/RakNet/documentation/dependencies.html
Normal file
@ -0,0 +1,108 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head><title>3rd party dependencies</title>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API"></head>
|
||||
|
||||
<body leftmargin="0" topmargin="0" style="background-color: rgb(255, 255, 255);" alink="#003399" link="#003399" marginheight="0" marginwidth="0" vlink="#003399">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><br>
|
||||
<br>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">Optional 3rd party dependencies</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p>What follows is a list of projects that will not build without 3rd party dependencies, and where to get these dependencies. These projects are optional: you can use RakNet without them. Unpack to is where the project, library, and/or post build step paths are set to by default for the Visual Studio project, and can be changed manually.</p>
|
||||
<h3><a href="irrlichtfpsdemo.html">IrrlichtDemo</a></h3>
|
||||
<p><img src="IrrlichtRakNetDemo.jpg" width="403" height="312">
|
||||
</p>
|
||||
<p>Peer to peer first person shooter demo showing off PHPDirectoryServer, ReplicaManager3, and NAT punchthrough. </p>
|
||||
<p><em>Download from</em>: <a href="http://irrlicht.sourceforge.net/downloads.html">http://irrlicht.sourceforge.net/downloads.html</a></p>
|
||||
<p><em>Unpack to</em>: C:\irrlicht-1.7.2\include</p>
|
||||
<p> </p>
|
||||
<h3><a href="ogre3dinterpdemo.html">Ogre3DInterpDemo</a></h3>
|
||||
Client/Server ReplicaManager3 and interpolation demo
|
||||
<p><em>Download from</em>: http://www.ogre3d.org/download</p>
|
||||
<p><em>Unpack to</em>: Doesn't matter, Uses enviroment variable $(OGRE_HOME)</p>
|
||||
<p><em>Last checked against</em>: Prebuilt binary 1.7.4. OGRE_HOME set to C:\OgreSDK_vc9_v1-7-4.</p>
|
||||
<p> </p>
|
||||
<h3><a href="autopatcher.html">AutopatcherMySQLRepository</a></h3>
|
||||
One of two supported database backends for the AutopatcherServer project, which is required to use AutopatcherClient. You only need one of the two.
|
||||
<p><em>Download from</em>: http://dev.mysql.com/downloads/</p>
|
||||
<p><em>Unpack to</em>: C:\Program Files (x86)\MySQL\MySQL Server 5.1</p>
|
||||
<p>Note: MySQL is an order of magnitude slower than PostgreSQL with AutopatcherServer.</p>
|
||||
<p> </p>
|
||||
<h3><a href="autopatcher.html">AutopatcherPostgreSQLRepository</a></h3>
|
||||
One of two supported database backends for the AutopatcherServer project, which is required to use AutopatcherClient. You only need one of the two.
|
||||
During installation be sure to check developer tools, or the header files will not be installed.
|
||||
<p><em>Download from</em>: http://www.postgresql.org/download/</p>
|
||||
<p><em>Unpack to</em>: C:\Program Files (x86)\PostgreSQL\9.1</p>
|
||||
<p> </p>
|
||||
<p><strong>SQLite\Logger\D3D9Samples\Matrices</strong></p>
|
||||
<p>This is a demo that assumes the DirectX SDK is installed. Get it from <a href="http://www.microsoft.com">http://www.microsoft.com</a> . You will also need to setup the Visual Studio global library and include paths.</p>
|
||||
<p> </p>
|
||||
<h3><a href="lobby.html">Lobby2Server_PGSQL</a></h3>
|
||||
Database backend for the Lobby2 system, supporting users, clans, friends, and other persistent information.
|
||||
<p><em>Download from</em>: http://www.postgresql.org/download/</p>
|
||||
<p><em>Unpack to</em>: C:\Program Files (x86)\PostgreSQL\8.3</p>
|
||||
<p> </p>
|
||||
<p><strong>RoomsAndLobbyGFx3
|
||||
</strong></p>
|
||||
<p> Visual front-end for the RoomsPlugin and Lobby2 systems, with the ability to login and display a list of rooms. Note: Scaleform requires registration and is not-free. </p>
|
||||
<p><em>Download from</em>: http://www.scaleform.com/</p>
|
||||
<p><em>Unpack to</em>: Doesn't matter, uses enviroment variable $(GFXSDK)</p>
|
||||
<p> </p>
|
||||
<h3><a href="autopatcher.html">AutopatcherClientGFx3</a></h3>
|
||||
Visual front-end for the AutopatcherClient system. Note: Scaleform requires registration and is non-free.
|
||||
<p><em>Download from</em>: http://www.scaleform.com/</p>
|
||||
<p><em>Unpack to</em>: Doesn't matter, uses enviroment variable $(GFXSDK)</p>
|
||||
<p> </p>
|
||||
<h3><a href="rakvoice.html">RakVoiceDSound</a></h3>
|
||||
One of three sound implementations of RakVoice, supporting DirectSound, FMOD, and PortAudio. PortAudio is already included in the RakVoice project. Unless you intend to use DirectSound, you do not need this project.
|
||||
<p><em>Download from</em>: http://msdn.microsoft.com/en-us/directx/aa937788.aspx</p>
|
||||
<p><em>Unpack to</em>: Doesn't matter, uses enviroment variable $(DXSDK_DIR)</p>
|
||||
<p> </p>
|
||||
<h3><a href="rakvoice.html">RakVoiceFMOD</a></h3>
|
||||
One of three sound implementations of RakVoice, supporting DirectSound, FMOD, and PortAudio. PortAudio is already included in the RakVoice project. Unless you intend to use FMOD, you do not need this project.
|
||||
Note: FMOD is not necessarily free.
|
||||
<p><em>Download from</em>: http://www.fmod.org/index.php/download</p>
|
||||
<p><em>Unpack to</em>: C:\Program Files\FMOD SoundSystem</p>
|
||||
<p><em>Last checked against</em>: Fmod 4.38.07</p>
|
||||
<p> </p>
|
||||
<h3><a href="RPC3Video.htm">RPC3</a></h3>
|
||||
Remote procedure calls using C++ and semi-automatic serialization. Includes support for networked <a href="http://en.wikipedia.org/wiki/Signals_and_slots">signals and slots</a>. Note: The majority of boost is not required, only those files actually used by RPC3. If you don't want to use Boost, you can use the RPC4 plugin instead which has similar functionality to the RPC found in RakNet version 3.
|
||||
<p><em>Download from</em>: http://www.boost.org/users/download/</p>
|
||||
<p><em>Unpack to</em>: c:/boost_1_48_0</p>
|
||||
<p>Note: You can use RPC4 if you do not want to install Boost, it however cannot call directly into C++ member functions or automatically serialize method parameters.</p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><strong>See
|
||||
Also</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><font class="G10" color="#111122" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="1"><a href="index.html">Index</a><br>
|
||||
<a href="faq.html">FAQ</a><br>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body></html>
|
||||
276
Help/RakNet/documentation/detailedimplementation.html
Normal file
@ -0,0 +1,276 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Detailed Implementation</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Detailed Implementation</td>
|
||||
</tr></table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td>Implementation <BR>
|
||||
<BR>
|
||||
For basic network communication, all you have to do is get an instance of RakPeer in your program.<BR>
|
||||
<BR>
|
||||
These are the most common headers you'll need:</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Headers</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody">#include "MessageIdentifiers.h"<BR>
|
||||
#include "RakPeerInterface.h"<BR>
|
||||
#include "RakNetTypes.h"<BR>
|
||||
<BR>
|
||||
MessageIdentifiers.h contains a giant enumeration representing the native message identifiers that RakNet uses to send you messages, such as disconnection notifications. Since you will probably want to define your own message identifiers, your enumerations should start at the
|
||||
highest enumeration in MessageIdentifiers.h + 1<font color="#666666" size="2" face="Geneva, Verdana, Arial, Helvetica, sans-serif">RakPeerInterface.h is an interface for the RakPeer
|
||||
class. RakNetTypes.h defines the structures used in RakNet, including <I>SystemAddress</I> - a unique identifier for systems, and <I>Packet</I> which the API returns to you when you get data or when it needs to send you a message.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Instancing</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody"><BR>
|
||||
RakNet::RakPeerInterface* peer = RakNet::RakPeerInterface::GetInstance();<BR>
|
||||
<BR>
|
||||
That code would give you one instance of the peer. Usually you would only want one of these in a particular exe.<BR>
|
||||
<BR>
|
||||
The next step is to connect, either as client or as a server.<BR>
|
||||
<BR>
|
||||
For example:<BR></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Connection as Client </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody">peer->Startup(1, &SocketDescriptor(), 1)<BR>
|
||||
peer->Connect(serverIP, serverPort, 0, 0);<BR>
|
||||
<BR>
|
||||
The call to Startup starts the network threads.<br>
|
||||
The first parameter is the maximum mumber of connections. For a pure client, we use 1.<br>
|
||||
The second parameter (SocketDescriptor()), specifies the ports/addresses to listen on . Since we want a client, we don't need to specify anything.<BR>
|
||||
<br>
|
||||
The call to Connect connects to the server.<br>
|
||||
The first parameter, serverIP, is the IP address or domain of the server. If you want to connect to your own system, such as when running two copies of the same program, use "127.0.0.1" or "localhost" which is accepted notation for your own system. For IPV6, this is "::1".<BR>
|
||||
The next parameter in Connect is the serverPort. This is the port you want to try to connect to on the server. If you specify a port the server is not expecting data on you won't be able to connect just like if you had entered the wrong IP. The IP and the port always work together in this fashion to form the complete address. How do you know what port to connect to? Well as the programmer you decide this ahead of time and then just hardcode it into your program. How do you choose a port? You can choose whatever you want as long as no one else is using it and its within the range of 2^16 (0 to 65535). However, certain ports are reserved for use by established programs, such as your web browser, telnet, and FTP. You can look up these port assignments on the internet, but the quick and dirty answer is most ports under 32000 are reserved and ports over 32000 are open to whoever wants them.<BR>
|
||||
<BR>
|
||||
In practice ports are generally set with #define per program and not changed. For example:<BR>
|
||||
<BR>
|
||||
#define SERVER_PORT 60005<BR>
|
||||
#define CLIENT_PORT 60006<BR>
|
||||
<BR>
|
||||
This way the server will always know what port to respond to and the clients will always know what port to connect to. It also saves end-users the trouble of typing the ports in.<BR>
|
||||
<BR>
|
||||
Note that connection attempts are asynchronous. The function will return CONNECTION_ATTEMPT_STARTED immediately if it succeeded in the attempt to connect, but it does not mean your connection succeeded. You know your connection succeeded when you call RakPeerInterface::Receive() and a Packet is returned with the first byte ID_CONNECTION_ACCEPTED.<br>
|
||||
You get a network message ID_CONNECTION_ATTEMPT_FAILED when the connection fails.<br>
|
||||
RakNet connects quickly so if you don't connect within a few seconds it's not going to connect. ID_CONNECTION_ATTEMPT_FAILED will be returned to inform you of this.<BR>
|
||||
<BR>
|
||||
Starting as a server is similar.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Connection as Server </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody"><p>peer->Startup(maxConnectionsAllowed, &SocketDescriptor(serverPort,0), 1);<br>
|
||||
peer->SetMaximumIncomingConnections(maxPlayersPerServer); </p>
|
||||
<p>The first parameter to Startup is how many simultaneous client connections to allow. The second and third parameter tells what port to listen on.<br>
|
||||
The call to SetMaximumIncomingConnections sets how many incoming connections are allowed.<BR>
|
||||
Keep in mind that the actual number of players you could have playing is one more than the number of clients you support if you program your game to allow the server to act as a player. If your server is a dedicated server or if you program your game to have both a client and a server on the same system then obviously the number of people who could play would change accordingly.<BR>
|
||||
<BR>
|
||||
</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Peer to peer connections </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody">RakNet::SocketDescriptor sd(serverPort,0);<br>
|
||||
peer->Startup(maxConnectionsAllowed, &sd, 1);<BR>
|
||||
peer->SetMaximumIncomingConnections(4);<BR>
|
||||
<BR>
|
||||
Startup sets 10 allowable connections. An allowable connection is either incoming or outgoing. It uses port 60000 to receive data.<br>
|
||||
SetMaximumIncomingConnections is necessary if you want to allow other peers to connect to you, but is not necessary if you only plan to connect to others. In this case, it sets the value to 4. This is a maximum value rather than a reserved value, so it is still possible to say connect to 8 peers - you would then only be able to accept 2 incoming connections until you disconnected from one or more of those peers.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Reading Packets </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody"><p><span class="RakNetCode">RakNet::Packet *packet = peer->Receive();</span><BR>
|
||||
<BR>
|
||||
It's that easy. If packet is 0 then there was nothing to read and you can go on with your game. Otherwise you got some data. You should normally call this in a loop, for example:</p>
|
||||
<p><span class="RakNetCode">RakNet::Packet *packet;<br>
|
||||
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive()) {<br>
|
||||
}
|
||||
</span><BR>
|
||||
<BR>
|
||||
You can get two kinds of data:<BR>
|
||||
Messages from the engine<BR>
|
||||
Messages from other instances of RakNet, on the same computer or from other computers<BR>
|
||||
Both are handled the same way.<BR>
|
||||
<BR>
|
||||
Lets look at the Packet struct:</p>
|
||||
<p class="RakNetCode">nam<span class="RakNetCode">espace RakNet<br>
|
||||
{<BR>
|
||||
</span>struct Packet<br>
|
||||
{<br>
|
||||
/// The system that send this packet.<br>
|
||||
SystemAddress systemAddress;<br>
|
||||
/// A unique identifier for the system that sent this packet, regardless of IP address (internal / external / remote system)<br>
|
||||
/// Only valid once a connection has been established (ID_CONNECTION_REQUEST_ACCEPTED, or ID_NEW_INCOMING_CONNECTION)<br>
|
||||
/// Until that time, will be UNASSIGNED_RAKNET_GUID<br>
|
||||
RakNetGUID guid;<br>
|
||||
/// The length of the data in bytes<br>
|
||||
unsigned int length;<br>
|
||||
/// The length of the data in bits<br>
|
||||
BitSize_t bitSize;<br>
|
||||
/// The data from the sender<br>
|
||||
unsigned char* data;<br>
|
||||
} // Namespace</p>
|
||||
<p> systemAddress specifies the origin of the packet. Every connected system has a unique SystemAddress which is assigned automatically. Note that the system address will be constant over the lifetime of the connection. Certain native network messages use the systemAddress member- for example ID_REMOTE_DISCONNECTION_NOTIFICATION tells you as a client that another client has disconnected. systemAddress in that case specifies which client. UNASSIGNED_SYSTEM_ADDRESS is a reserved value for "Unknown". You should not use systemAddress as a unique identifier for a remote computer. This is because the same computer can have a different systemAddress to every other connection. Use RakNetGUID as a unique identifier for a particular instance of RakPeerInterface.<BR>
|
||||
<BR>
|
||||
bitSize tells you how many bits long the data field of the struct is.<BR>
|
||||
<BR>
|
||||
Now that you got a packet you need to determine what the data means. Usually the first byte of the data is an enum that specifies type (see creating packets for more information). This is not always the case as you'll later learn, because with some packets, you might get a TimeStamp. To make things easy here it is a function to get the identifier when the packet has a TimeStamp:<BR>
|
||||
<BR>
|
||||
<span class="RakNetCode">unsigned char GetPacketIdentifier(Packet *p)<BR>
|
||||
{<BR>
|
||||
if ((unsigned char)p->data[0] == ID_TIMESTAMP)<BR>
|
||||
return (unsigned char) p->data[sizeof(MessageID) + sizeof(RakNet::Time)];<BR>
|
||||
else<BR>
|
||||
return (unsigned char) p->data[0];<BR>
|
||||
}<BR>
|
||||
</span><BR>
|
||||
This will return an unsigned char, which corresponds to an enum specified in MessageIdentifiers.h.<BR>
|
||||
<BR>
|
||||
The network engine will return certain messages only for the client, certain messages only for the server, and certain messages for both. For a full explanation of the messages refer to MessageIdentifiers.h. The important ones to worry about are ID_NEW_INCOMING_CONNECTION and ID_CONNECTION_REQUEST_ACCEPTED. These mean that the server or a peer got a new incoming client, and the client or a peer has successfully connected respectively. At this point you can send your own messages. <BR>
|
||||
<BR>
|
||||
If the packet identifier is NOT one of the pre-defined identifiers then you got user data which was sent by another system. You can then decode the data and handle it in your game as appropriate. See <A HREF="creatingpackets.html">creating packets</A> for information on encoding and decoding data.<BR>
|
||||
<BR>
|
||||
<I>IMPORTANT!</I><BR>
|
||||
When you are done with your data, don't forget to deallocate the packet! Just pass it to DeallocatePacket.<br>
|
||||
<BR>
|
||||
peer->DeallocatePacket(p);</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Sending Data </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody"><p>The best way to illustrate sending data is with an example:<BR>
|
||||
const char* message = "Hello World";<BR>
|
||||
<BR>
|
||||
To all connected systems:<BR>
|
||||
peer->Send((char*)message, strlen(message)+1, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_RAKNET_GUID, true);<BR>
|
||||
<BR>
|
||||
The first parameter is your data and must be a byte stream. Since we're sending a string, and a string is a byte stream, we can send it directly without any casting.<BR>
|
||||
<BR>
|
||||
The second parameter is how many bytes to send. In this example we send the length of the string and one more for the null terminator.<BR>
|
||||
<BR>
|
||||
The third parameter is the priority of the packet. This takes one of three values:<BR>
|
||||
IMMEDIATE_PRIORITY,<br>
|
||||
HIGH_PRIORITY<BR>
|
||||
MEDIUM_PRIORITY<BR>
|
||||
LOW_PRIORITY<BR>
|
||||
<BR>
|
||||
IMMEDIATE_PRIORITY messages signal RakNet's update thread to update immediately. Assuming bandwidth is available, they get sent immediately. HIGH_PRIORITY, MEDIUM_PRIORITY, and LOW_PRIORITY messages are put into a buffer. The next time RakNet's update thread ticks (which is every 10 milliseconds) those messages get sent. Those 3 priorities can be more efficient for bandwidth, because if multiple messages can be aggregated into a single datagram, RakNet will transparently do so</p>
|
||||
<p>Twice as many messages get sent out for each higher priority. So if messages of all priorities were waiting to go out, 8 IMMEDIATE_PRIORITY, 4 HIGH_PRIORITY, 2 MEDIUM_PRIORITY, and 1 LOW_PRIORITY would be sent. Obviously however, if only LOW_PRIORITY messages were waiting at all, then those messages would all go out as fast as possible.<BR>
|
||||
<BR>
|
||||
The fourth parameter takes one of five major values. Lets say you send data 1,2,3,4,5,6. Here's the order and substance of what you might get back:<BR>
|
||||
<BR>
|
||||
UNRELIABLE - 5, 1, 6<BR>
|
||||
UNRELIABLE_SEQUENCED - 5 (6 was lost in transit, 1,2,3,4 arrived later than 5)<BR>
|
||||
RELIABLE - 5, 1, 4, 6, 2, 3<BR>
|
||||
RELIABLE_ORDERED - 1, 2, 3, 4, 5, 6<BR>
|
||||
RELIABLE_SEQUENCED - 5, 6 (1,2,3,4 arrived later than 5)<BR>
|
||||
<BR>
|
||||
For more details on this refer to PacketPriority.h.<BR>
|
||||
<BR>
|
||||
The fifth parameter to Send() (0 in this example) is which ordering stream to use. This is used for relative ordering of packets in relation to other packets on the same stream. It's not important for now, but for more information on this refer to the <A HREF="sendingpackets.html">Sending Packets</A> section.</p>
|
||||
<p>The sixth parameter (UNASSIGNED_RAKNET_GUID), is the remote system to send to. UNASSIGNED_RAKNET_GUID is a reserved value meaning "no-one in particular". This parameter means one of two things : either who you want to send the packet to, or who you don't want to send the packet to, depending on the value of broadcast, which is the last parameter.<br>
|
||||
<BR>
|
||||
The seventh parameter (true in this example) is whether to broadcast to all connected systems or not. This parameter works with the sixth parameter. If broadcast is true, then the sixth parameter specifies who not to send to. If it is false, then it specifies who to send to. If we want to broadcast to everyone, then we just specify UNASSIGNED_RAKNET_GUID. This works out when relaying packets, because the Packet::systemAddress field in the packet you get will specify who the sender is. We can relay the packet to everyone BUT the sender, which makes sense since we usually don't want to send the same information back to the person who just sent it to us.</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Shutting Down </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody"><BR>
|
||||
Shutting down is easy and nearly instantaneous. Just call Shutdown() on your peer object, and then destroy it <BR>
|
||||
<BR>
|
||||
somePeer->Shutdown(300);<br>
|
||||
<BR>
|
||||
Shutdown stops the network threads. If you specify a higher than 0 parameter to Shutdown(), Shutdown() will block for up to this amount of time to notify connected systems (if any) to inform them of the connection dropping. 0 will cause a slient Shutdown(), and remote systems will detect the disconnection within about 10 seconds, returning ID_CONNECTION_LOST.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Cleaning Up </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td>Just pass the instance that the factory gave you to the DestroyRakPeerInterface. You may want to do this mid-program to free memory but it is not required.<BR>
|
||||
<BR>
|
||||
RakNet::RakPeerInterface::DestroyInstance(rakPeer);</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td><p><BR>
|
||||
Next page: <A HREF="tutorial.html">Step by step tutorial</A></p>
|
||||
<p><A HREF="index.html">Index</A><BR>
|
||||
<A HREF="introduction.html">Introduction</A><BR>
|
||||
<A HREF="systemoverview.html">System Overview</A><BR>
|
||||
<A HREF="tutorial.html">Tutorial</A><BR>
|
||||
<A HREF="compilersetup.html">Compiler Setup</A><BR>
|
||||
</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD><p><BR>
|
||||
</p>
|
||||
</TD></TR></TABLE>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
52
Help/RakNet/documentation/directorydeltatransfer.html
Normal file
@ -0,0 +1,52 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Directory Delta Transfer Manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<style type="text/css">
|
||||
<!--
|
||||
.style1 {color: #333333}
|
||||
-->
|
||||
</style>
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">Directory Delta Transfer Overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Send file differences between directories automatically</span><BR>
|
||||
<BR>
|
||||
DirectoryDeltaTransfer.h is useful if you allow user-moddable content. For example, if each server has a /skins directory, you could run this plugin to upload that directory to the clients. Each client that does not already have a particular skin will get it. You will get download progress notifications via a user-supplied callback. DirectoryDeltaTransfer relies on the FileListTransfer plugin to actually transmit hte files.</p>
|
||||
<p>Usage:</p>
|
||||
<ol>
|
||||
<li>Attach the plugin and connect to the remote system</li>
|
||||
<li>Server and client: Call directoryDeltaTransfer.SetFileListTransferPlugin(&fileListTransfer);</li>
|
||||
<li>Server: set the application directory: <span class="style1"><code> directoryDeltaTransfer.SetApplicationDirectory("c:\myGame");</code></span></li>
|
||||
<li>Server: set the download directory: <span class="RakNetCode">directoryDeltaTransfer.AddUploadsFromSubdirectory("skins");</span></li>
|
||||
<li>Client: to download call: <span class="RakNetCode">directoryDeltaTransfer.DownloadFromSubdirectory("skins", "downloaded\skins", true, serverAddress, &transferCallback, HIGH_PRIORITY, 0);</span></li>
|
||||
<li>Client: Wait for the callback member <span class="RakNetCode">OnFileProgress()</span>. When onFileStruct->fileIndex is equal to onFileStruct->setCount this download is done.</li>
|
||||
</ol>
|
||||
<p>For full details on all parameters and other available functions, see the header file DirectoryDeltaTransfer.h and the sample at <em>Samples/DirectoryDeltaTransfer</em></p>
|
||||
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <A HREF="index.html">Index</A><br>
|
||||
<A HREF="filelisttransfer.html">FileListTransfer</A> <BR> </TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
295
Help/RakNet/documentation/distributednetworkobject.html
Normal file
@ -0,0 +1,295 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Distributed Objects</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNetLogo.jpg" alt="Oculus VR, Inc."><BR><BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">Distributed Objects</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
Overview of the distributed network object system
|
||||
<BR><BR>
|
||||
|
||||
The distributed network object system is the highest level layer over RakNet. The concept is simple: objects that are instantiated on one system are instantiated on all systems. Objects that are destroyed on one system are destroyed on all systems. Tagged memory is matched between systems. When a new player connects, these objects are also created on his system.<BR>
|
||||
<BR>
|
||||
This is very useful conceptually because it has a direct analogy to game objects. For example, a one tank in a multiplayer game with twenty players actually has been instantiated twenty times. However, as far as the player is concerned there is only one tank. The player expects that the position, orientation, number of shells left, and amount of armor is the same on all systems.<BR>
|
||||
<BR>
|
||||
Traditionally, to maintain a tank you would have to craft a series of custom packets for the tank. One packet to describe position, another packet for the tank to shoot, and another to have the tank take damage. Using the distributed network object system, you can synchronize the tank, those 3 member variables, and everything matches automatically.<BR>
|
||||
<BR>
|
||||
The distributed object system has both strengths and weaknesses.<BR>
|
||||
<BR>
|
||||
<B>Strengths</B>
|
||||
<UL>
|
||||
<LI>Implementation only takes a minute and once it works it is foolproof.
|
||||
<LI>You don't have to worry about sending game data to new players.
|
||||
<LI>You don't have to worry about game objects getting out of synch.
|
||||
<LI>You don't care about the complexity of interactions between objects because you always get the correct final result.
|
||||
<LI>It is easy to network existing single player games.
|
||||
<LI>Interpolation is built-in.
|
||||
</UL>
|
||||
<BR>
|
||||
<B>Weaknesses</B>
|
||||
<UL>
|
||||
<LI>Timestamping is not supported so you can't extrapolate position.
|
||||
<LI>Tracking the results of actions is less accurate than sending triggers that cause actions.
|
||||
<LI>Wasteful of bandwidth for predictable actions. For example, if a rocket shoots 20 cans this system requires 20 objects to receive data over time as the cans fall. With a packet you could describe only the rocket when it was launched and hence only one do one send. The cans would also fall precisely assuming the physics is repeatable.
|
||||
<LI>Doesn't currently support arrays or pointers, although with arrays you can get around this by synchronizing each element or enclosing it in a structure.
|
||||
</UL>
|
||||
Despite these weaknesses, this is the primary system in use by many games.<BR>
|
||||
<BR>
|
||||
|
||||
How to implement the distributed object system
|
||||
<BR><BR>
|
||||
|
||||
Before you can use the distributed object system, you have to register your instance of RakClient and/or RakServer with the Distributed Network Object Manager.<BR>
|
||||
<BR>
|
||||
DistributedNetworkObjectManager::Instance()->RegisterRakClientInterface(rakClient);<BR>
|
||||
DistributedNetworkObjectManager::Instance()->RegisterRakServerInterface(rakServer);<BR>
|
||||
<BR>
|
||||
The multiplayer class will automatically handle distributed object network messages. If you don't use the multiplayer class, you must handle these packet types yourself:<BR>
|
||||
<BR>
|
||||
|
||||
ID_UPDATE_DISTRIBUTED_NETWORK_OBJECT<BR>
|
||||
ID_DISTRIBUTED_NETWORK_OBJECT_CREATION_ACCEPTED<BR>
|
||||
ID_DISTRIBUTED_NETWORK_OBJECT_CREATION_REJECTED<BR>
|
||||
<BR>
|
||||
You would pass them to the DistributedNetworkObjectManager in exactly the same fashion as is done in Multiplayer.h.<BR>
|
||||
<BR>
|
||||
Once that is done, then you have several steps per class.
|
||||
<OL>
|
||||
<LI>Add <I>#include "DistributedNetworkObjectHeader.h"</I> to the header file for your class.
|
||||
|
||||
<LI>The basemost class should derive from <I>DistributedNetworkObject</I>
|
||||
|
||||
<LI>If you plan to instantiate this class, then add <I>REGISTER_DISTRIBUTED_CLASS(ClassName)</I> in main() or Winmain(), with the name of your class or a unique identifier replacing ClassName.
|
||||
|
||||
<LI>Once per game cycle call <I>objectInstance->UpdateDistributedObject(ClassName)</I> where objectInstance is the instance of your class and ClassName is the name of the class or a unique identifier replacing ClassName that matches the unique identifier passed to REGISTER_DISTRIBUTED_CLASS.
|
||||
</OL>
|
||||
For example, if you want every instance of Tank to match among all systems then you would do the following:<BR>
|
||||
<BR>
|
||||
|
||||
#include "DistributedNetworkObjectHeader.h"<BR>
|
||||
<BR>
|
||||
class Tank : public DistributedNetworkObject<BR>
|
||||
{<BR>
|
||||
// Your data and functions here<BR>
|
||||
// ...<BR>
|
||||
<BR>
|
||||
// The update function for the class is a good place to put UpdateDistributedObject<BR>
|
||||
void Update(void) {UpdateDistributedObject("Tank");}<BR>
|
||||
};<BR>
|
||||
<BR>
|
||||
REGISTER_DISTRIBUTED_CLASS(Tank);<BR>
|
||||
<BR>
|
||||
<BR>
|
||||
How to implement synchronized member variables within the distributed object system
|
||||
<BR><BR>
|
||||
|
||||
That tank is nice but would be a lot more useful if we had the data members synchronized automatically as well. There are two ways to do that:
|
||||
<OL>
|
||||
<LI>REGISTER_X_DISTRIBUTED_OBJECT_MEMBERS preprocessor macro.
|
||||
<LI>SynchronizeMemory function
|
||||
</OL>
|
||||
The advantage of the REGISTER_X_DISTRIBUTED_OBJECT_MEMBERS macro is that you can perform automatic interpolation on data elements and it requires only one line of code in your header file for all members. The disadvantages are that the declaration must match on all systems, variables cannot be added at runtime, and it doesn't support pointers or arrays.<BR>
|
||||
<BR>
|
||||
The advantage of the SynchronizeMemory function is that you can add elements at runtime, members do not have to match, and it can support anything. The disadvantages are that it cannot perform interpolation, is more susceptible to user error, and requires one line of code in your cpp file per variable.<BR>
|
||||
<BR>
|
||||
The REGISTER_X_DISTRIBUTED_OBJECT_MEMBERS macro
|
||||
<BR><BR>
|
||||
To use REGISTER_X_DISTRIBUTED_OBJECT_MEMBERS, in the public section of the class definition add a macro that takes the following form:<BR>
|
||||
<BR>
|
||||
REGISTER_X_DISTRIBUTED_OBJECT_MEMBERS(BaseClass,<BR>
|
||||
SynchronizationMethod, AuthoritativeNetwork, VariableType, VariableName,<BR>
|
||||
...<BR>
|
||||
)<BR>
|
||||
<BR>
|
||||
The first parameter is in <I>REGISTER_X_DISTRIBUTED_OBJECT_MEMBERS</I>. Replace that X with however many member variables you are synchronizing.<BR> For example, if you want to synch 3 member variables then you would instead write <I>REGISTER_3_DISTRIBUTED_OBJECT_MEMBERS</I>.<BR>
|
||||
<BR>
|
||||
The second parameter, <I>BaseClass</I> is the name of the class your class derives from. As we specified earlier, you must derive from DistributedNetworkObject in the basemost class so this always has a value. If you had Apple derive from Fruit derive from DistributedNetworkObject then the first parameter for REGISTER_X_DISTRIBUTED_OBJECT_MEMBERS for Apple would be Fruit, and for Fruit it would be DistributedNetworkObject.<BR>
|
||||
<BR>
|
||||
The third parameter is a set of parameters - SynchronizationMethod, AuthoritativeNetwork, VariableType, and VariableName.<BR><BR>
|
||||
<I>SynchronizationMethod</I> takes one of the following values:
|
||||
<UL>
|
||||
<LI><I>DOM_COPY_UNCOMPRESSED</I><BR>This means send the data without <A HREF="bitstreams.html">bitstream compression</A> and when a new value arrives on a system, just copy over the old value. This is useful for data such as player health, stored in a unsigned char and going from 0 to 200.
|
||||
<LI><I>DOM_COPY_COMPRESSED</I><BR>Same as DOM_COPY_UNCOMPRESSED except use <A HREF="bitstreams.html">bitstream compression</A>. Useful for values that stay near 0, such as sending the score in a soccer game. As per the restrictions with bitstream compression, this can only be used with native types (char, int, short, long, float, bool).
|
||||
<LI><I>DOM_INTERPOLATE_UNCOMPRESSED</I><BR>No compression and when the data arrives on the new system, interpolate from the old value to the new value. Interpolation is linear and and lasts for whatever value was passed to DistributedNetworkObject::SetMaximumUpdateFrequency (default is 50 ms). If you overwrite the value while it is interpolating, the interpolation will stop. Interpolation requires the +, -, *, and = operators to be defined.
|
||||
<LI><I>DOM_INTERPOLATE_COMPRESSED</I><BR>Same as DOM_INTERPOLATE_UNCOMPRESSED except that data is sent using <A HREF="bitstreams.html">bitstream compression</A>. As per the restrictions with bitstream compression, this can only be used with native types (char, int, short, long, float, bool). Interpolation requires the +, -, *, and = operators to be defined.
|
||||
</UL>
|
||||
|
||||
The rules on type bear repeating, because if you make a mistake you will get a seemingly unrelated compile error:<BR>
|
||||
<B>My type is a</B>
|
||||
<UL>
|
||||
<LI><I>Mathematical native data type - bool, float, double, char, int, long, short.</I>
|
||||
You can use DOM_COPY_UNCOMPRESSED, DOM_COPY_COMPRESSED, DOM_INTERPOLATE_UNCOMPRESSED, or DOM_INTERPOLATE_COMPRESSED.
|
||||
<LI><I>Nonnative data type but is mathematical, i.e. has +, -, *, and = overloaded, such as many vector classes.</I>
|
||||
You can use DOM_COPY_UNCOMPRESSED or DOM_INTERPOLATE_UNCOMPRESSED.
|
||||
<LI><I>Any regular data block (i.e. struct) as long as the data block does not contain pointers.</I>
|
||||
You can use DOM_COPY_UNCOMPRESSED.
|
||||
<LI><I>Array.</I>
|
||||
You can either synchronize each element normally or can enclose the array in a struct and send the struct. We'll try to find a better solution for this in a later release.
|
||||
<LI><I>Pointer.</I>
|
||||
Unsupported.
|
||||
</UL>
|
||||
|
||||
<I>AuthoritativeNetwork</I> takes one of the following values:
|
||||
<UL>
|
||||
<LI><I>DOM_SERVER_AUTHORITATIVE</I><BR>The server is in charge of the variable. While a client can change it, any changes will be overwritten the next time the server changes it. This is what you would normally use for data such as health.
|
||||
<LI><I>DOM_CLIENT_AUTHORITATIVE</I><BR>The client(s) are in charge of the variable. While the server can change it, any changes will be overwritten the next time an authorized client changes it. By default, the client that created the object is the only system authorized to change the client authoritative members of that object. You can change the owner to another client, or remove the owner by calling SetClientOwnerID. You will also want to call that function when the server creates an object with client authoritative members and you want to assign an owner to your new object. When there is no owner, multiple clients can fight over the same data if you wish - although it doesn't make much sense to do so.
|
||||
</UL>
|
||||
|
||||
<I>VariableType</I> is the type of the variable being synchronized. This must match the type of the variable declaration and cannot be an array or a
|
||||
pointer.<BR>
|
||||
<BR>
|
||||
<I>VariableName</I> must match the name of the variable being synchronized.<BR>
|
||||
<BR>
|
||||
These four parameters that compose the third set of parameters can be repeated as many times as you wish, up to the number of types the define pattern was cut and paste in DistributedObjectNetworkHeader.h<BR>
|
||||
<BR>
|
||||
Here is our tank with two member variables synchronized:<BR><BR>
|
||||
|
||||
#include "DistributedNetworkObjectHeader.h"<BR>
|
||||
<BR>
|
||||
class Tank : public DistributedNetworkObject<BR>
|
||||
{<BR>
|
||||
// Your data and functions here<BR>
|
||||
// ...<BR>
|
||||
<BR>
|
||||
// The update function for the class is a good place to put UpdateDistributedObject<BR>
|
||||
void Update(void) {UpdateDistributedObject("Tank");}<BR>
|
||||
public:<BR>
|
||||
float turrentAngle;<BR>
|
||||
Vector position;<BR>
|
||||
<BR>
|
||||
REGISTER_2_DISTRIBUTED_OBJECT_MEMBERS(DistributedNetworkObject,<BR>
|
||||
DOM_INTERPOLATE_COMPRESSED, DOM_CLIENT_AUTHORITATIVE, float, turrentAngle,<BR>
|
||||
DOM_COPY_UNCOMPRESSED, DOM_SERVER_AUTHORITATIVE, Vector, position)<BR>
|
||||
};<BR>
|
||||
<BR>
|
||||
REGISTER_DISTRIBUTED_CLASS(Tank);<BR>
|
||||
<BR>
|
||||
|
||||
<B>Additional notes</B><BR>
|
||||
|
||||
<OL>
|
||||
<LI>This is all done by the preprocessor so if you make a mistake you will get a compile error rather than a run-time error.
|
||||
<LI>REGISTER_X_DISTRIBUTED_OBJECT_MEMBERS may not be written out as many times as you have data members. If you have more members than I wrote out, you can add elements yourself. It follows a very obvious pattern. Refer to the bottom of DistributedNetworkObjectHeader.h. If anyone knows of a way to automate this please let me know.
|
||||
<LI>If a data member is client authoritative, then you will get a different value on creation depending on whether the client created the object or the server did. If the client created the object, then the value propigated over the network will be whatever the client set before the first call to UpdateDistributedObject. If the server created the object, then the value propigated over the network will be whatever the server set before the first call to UpdateDistributedObject. In this way, the server can force the client to start with particular values, or the client can specify which values to start with.
|
||||
</OL>
|
||||
The SynchronizeMemory function
|
||||
<BR><BR>
|
||||
Synchronizing memory at runtime is possible with the SynchronizeMemory and related functions. The outcome is the same as with REGISTER_X_DISTRIBUTED_OBJECT_MEMBERS. Here is how to use it with our tank example:<BR>
|
||||
<BR>
|
||||
|
||||
#include "DistributedNetworkObjectHeader.h"<BR>
|
||||
<BR>
|
||||
class Tank : public DistributedNetworkObject<BR>
|
||||
{<BR>
|
||||
Tank() {SynchronizeMemory(0, &turrentAngle, sizeof(turrentAngle), false); SynchronizeMemory(1, &position, sizeof(position), true); }<BR>
|
||||
<BR>
|
||||
// Your data and functions here<BR>
|
||||
// ...<BR>
|
||||
<BR>
|
||||
// The update function for the class is a good place to put UpdateDistributedObject<BR>
|
||||
void Update(void) {UpdateDistributedObject("Tank");}<BR>
|
||||
public:<BR>
|
||||
float turrentAngle;<BR>
|
||||
Vector position;<BR>
|
||||
<BR>
|
||||
};<BR>
|
||||
<BR>
|
||||
REGISTER_DISTRIBUTED_CLASS(Tank);<BR>
|
||||
<BR>
|
||||
|
||||
This does the same as the code above. The first parameter is a unique unsigned char to identify the variable. The system will then expect all objects with synchronized memory that use that same value to match in size and type. The second parameter is the memory address of the variable. The third parameter is the size of the block to synchronize. The last parameter is true if you want the server to be the authority on the object, false for the client to be the authority.<BR>
|
||||
<BR>
|
||||
<B>Refer to Samples\CodeSamples\DistributedNetworkObject\DistributedNetworkObjectSample.cpp for an implementation example.</B><BR>
|
||||
<BR>
|
||||
|
||||
User functions of the DistributedNetworkObject
|
||||
<BR><BR>
|
||||
|
||||
|
||||
Call this every update cycle for every distributed object that you want updated over the network and to interpolate.<BR>
|
||||
classID should be a unique identifier for the class that matches the parameter to REGISTER_DISTRIBUTED_CLASS. The obvious choice is the name of the class - however you can use something shorter if you wish to save a bit of bandwidth<BR>
|
||||
<B>
|
||||
virtual void UpdateDistributedObject(char *classID, bool isClassIDEncoded=false);<BR>
|
||||
</B>
|
||||
<BR>
|
||||
Sets the maximum frequency with which memory synchronization packets can be sent.<BR>
|
||||
Lower values increase granularity but require more bandwidth<BR>
|
||||
<B>virtual void SetMaximumUpdateFrequency(unsigned long frequency);</B><BR>
|
||||
<BR>
|
||||
Broadcasts a request to destroy an object on the network. OnDistrubtedObjectDestruction will be called.<BR>
|
||||
If you wish to block deletion, override OnDistributedObjectDestruction to not delete itself<BR>
|
||||
<B>virtual void DestroyObjectOnNetwork(void);</B><BR>
|
||||
<BR>
|
||||
Server only function -<BR>
|
||||
By default, when a client creates an object only it can update the client authoritative members of the class it creates. You can also set this manually with SetClientOwnerID<BR>
|
||||
This function is called when a client that does not own an object tries to change any fields in that object<BR>
|
||||
Return true to allow the update.<BR>
|
||||
Return false (default) to not allow the update.<BR>
|
||||
<B>virtual bool AllowSpectatorUpdate(PlayerID sender);</B>
|
||||
<BR>
|
||||
<BR>
|
||||
Tags memory to be synchronized. You can set the server or the client as the authority for this block.<BR>
|
||||
Only the authority will write this memory to the network when it is changed.<BR>
|
||||
<B>void SynchronizeMemory(unsigned char memoryBlockIndex, void* memoryBlock, int memoryBlockSize, bool serverAuthority);</B><BR>
|
||||
<BR>
|
||||
Untags memory that was formerly synchronized.<BR>
|
||||
<B>void DesynchronizeMemory(unsigned char memoryBlockIndex);</B><BR>
|
||||
<BR>
|
||||
Changes the authority for memory. You probably will never need this.<BR>
|
||||
<B>void SetAuthority(unsigned char memoryBlockIndex, bool serverAuthority);</B><BR>
|
||||
<BR>
|
||||
Tells you if a block of memory was formerly used. You probably will never need this.<BR>
|
||||
<B>bool IsMemoryBlockIndexUsed(unsigned char memoryBlockIndex);</B><BR>
|
||||
<BR>
|
||||
Use this to set a maximum update frequency higher than what was specified to SetMaximumUpdateFrequency<BR>
|
||||
Lower values have no effect.<BR>
|
||||
<B>void SetMaxMemoryBlockUpdateFrequency(unsigned char memoryBlockIndex, int max);</B><BR>
|
||||
<BR>
|
||||
When object creation data is needed, WriteCreationData is called.<BR>
|
||||
This function is for you to write any data that is needed to create or initialize the object on remote systems<BR>
|
||||
<B>virtual void WriteCreationData(BitStream *initialData);</B><BR>
|
||||
<BR>
|
||||
When an object is created, ReadCreationData is called immediately after a successful call to OnDistributedObjectCreation<BR>
|
||||
This function is for you to read any data written from WriteCreationData on remote systems. If the object is created by the client, this function is also called by the creator of the object when sent back from the server in case the server overrode any settings<BR>
|
||||
<B>virtual void ReadCreationData(BitStream *initialData);</B><BR>
|
||||
<BR>
|
||||
When distributed data changes for an object, this function gets called. Default behavior is to do nothing. Override it if you want to perform updates when data is changed.<BR>
|
||||
On the server it is also important to override this to make sure the data the client just sent you is reasonable.<BR>
|
||||
<B>virtual void OnNetworkUpdate(PlayerID sender);</B><BR>
|
||||
<BR>
|
||||
This is called when the object is created by the network. Return true to accept the new object, false to reject it.<BR>
|
||||
The return value is primarily useful for the server to reject objects created by the client. On the client you would normally return true<BR>
|
||||
senderID is the playerID of the player that created the object (or the server, which you can get from RakClientInterface::GetServerID)<BR>
|
||||
<I>You must call the base class version of this function when overriding!</I>.<BR>
|
||||
<B>virtual bool OnDistributedObjectCreation(PlayerID senderID);</B><BR>
|
||||
<BR>
|
||||
This is called when the object is destroyed by the network.<BR>
|
||||
Default behavior is to delete itself. You can override this if you want to delete it elsewhere, or at a later time.<BR>
|
||||
If you don't delete the object, you should call DestroyObjectOnNetwork manually to remove it from the network.<BR>
|
||||
Note it is important to override this on the server for objects you don't want clients to delete.<BR>
|
||||
senderID is the playerID of the player that created the object (or the server, which you can get from RakClientInterface::GetServerID)<BR>
|
||||
<B>virtual void OnDistributedObjectDestruction(PlayerID senderID);</B><BR>
|
||||
<BR>
|
||||
This is called when the server rejects an object the client created. Default behavior is to destroy the object.<BR>
|
||||
You can override this to destroy the object yourself.<BR>
|
||||
<B>virtual void OnDistributedObjectRejection(void);</B><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="bitstreams.html">Bitstreams</A><BR>
|
||||
<A HREF="timestamping.html">Timestamping</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
40
Help/RakNet/documentation/emailsender.html
Normal file
@ -0,0 +1,40 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>EmailSender manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Email Sender Overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Simple class to send emails via C++</span><BR>
|
||||
<BR>
|
||||
|
||||
The EmailSender class, found at EmailSender.h, is a simple class with only one function, Send(...), to send an email using a provided mail server. It is used internally by the <a href="crashreporter.html">CrashReporter</a> class to send emails for unmonitored servers. See EmailSender.h for a full description of each parameter.</p>
|
||||
<p>See the project Samples/SendEmail for a sample of this</p>
|
||||
<p>The class has also been tested to work with Gmail POP servers, so if you have a Gmail account you can send emails without using your own mail server. The sample has the settings you need by default. You will also need to uncomment OPEN_SSL_CLIENT_SUPPORT in RakNetDefines.h, as Gmail requires the TCP connection to be made with SSL.</p></TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <p><A HREF="index.html">Index</A><br>
|
||||
<a href="crashreporter.html">Crash Repoter</a><BR>
|
||||
</p>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
212
Help/RakNet/documentation/faq.html
Normal file
@ -0,0 +1,212 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>FAQ</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">FAQ</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<p><B>I'm having problems sending strings.</B><BR>
|
||||
Use the StringCompressor or RakString class to send strings through Bitstreams.</p>
|
||||
<p><B>How do I simulate lag?</B><BR>
|
||||
In a hurry, use RakPeer::ApplyNetworkSimulator. But I recommend
|
||||
<a href="http://www.netlimiter.com/" target="_blank">http://www.netlimiter.com/</a> instead.<BR>
|
||||
There is also Network Emulator Toolkit (NEWT) from <A HREF="http://blog.mrpol.nl/2010/01/14/network-emulator-toolkit/">http://blog.mrpol.nl/2010/01/14/network-emulator-toolkit/</A> or <A HREF="http://blogs.msdn.com/b/lkruger/archive/2009/06/08/introducing-true-network-emulation-in-visual-studio-2010.aspx">http://blogs.msdn.com/b/lkruger/archive/2009/06/08/introducing-true-network-emulation-in-visual-studio-2010.aspx</A> </p>
|
||||
<p><strong>How do I detect if I have exceeded the available bandwidth of the connection?</strong><br>
|
||||
// Returns true if RakNet's output queue is increasing over time<br>
|
||||
bool PushingPastCapacity(RakNet::RakPeerInterface *rakPeer, RakNet::Time currentTime, SystemAddress remoteSystem) {<br>
|
||||
static double bufferedBytesLastTick=0.0;<br>
|
||||
static RakNet::Time whenStartedPushingPastCapacity=currentTime;<br>
|
||||
RakNetStatistics rns;<br>
|
||||
rakPeer->GetStatistics(remoteSystem, &rns);<br>
|
||||
double bufferedBytesThisTick=rns.bytesInSendBuffer[IMMEDIATE_PRIORITY]+rns.bytesInSendBuffer[HIGH_PRIORITY]+rns.bytesInSendBuffer[MEDIUM_PRIORITY]+rns.bytesInSendBuffer[LOW_PRIORITY];<br>
|
||||
if ( bufferedBytesThisTick > bufferedBytesLastTick) {<br>
|
||||
if ( currentTime-whenStartedPushingPastCapacity>500 ) {<br>
|
||||
bufferedBytesLastTick=bufferedBytesThisTick; return true;<br>
|
||||
}<br>
|
||||
}<br>
|
||||
else {<br>
|
||||
whenStartedPushingPastCapacity=currentTime;<br>
|
||||
}<br>
|
||||
bufferedBytesLastTick=bufferedBytesThisTick;<br>
|
||||
return false; <br>
|
||||
}<br>
|
||||
</p>
|
||||
<p><B>My data that I write using bitstreams is messed up on the other side.</B><BR>
|
||||
Make sure if you write one of the ID_* enumerations you cast it to an (unsigned char). Do not use types that may be different on 64 and 32 bit systems, such as int or long (See NativeTypes.h). Other than that, make sure your read and write calls match.<BR>
|
||||
<BR>
|
||||
<B>My data pointed to by a pointer isn't arriving.</B><BR>
|
||||
This is the same problem as when trying to use a default copy constructor with allocated memory. You can just send pointers if you want, but it will send the pointer variable rather than the data pointed to. You will need to serialize the contents of pointers yourself.<BR>
|
||||
<BR>
|
||||
<B>How should I deal with firewalls?</B><BR>
|
||||
Be sure to specify that your end-users need to open the appropriate ports, or use a port that is probably already open (such as the http port). One way to reduce tech support calls in this regard is to have your application try connecting a local client to a local server. If you can't connect after a couple of tries then the user probably has a firewall blocking this. You can message the user in-game that they probably have a firewall that needs to be turned off on whichever port your game uses.<BR>
|
||||
<BR>
|
||||
<B>I get errors from winsock.h such as follows</B><BR>
|
||||
C:\Program Files\Microsoft SDKs\Windows\v6.0A\\include\ws2def.h(91) : warning C4005: 'AF_IPX' : macro redefinition<BR>
|
||||
C:\Program Files\Microsoft SDKs\Windows\v6.0A\\include\winsock.h(460) : see previous definition of 'AF_IPX'<BR>
|
||||
C:\Program Files\Microsoft SDKs\Windows\v6.0A\\include\ws2def.h(127) : warning C4005: 'AF_MAX' : macro redefinition<BR>
|
||||
C:\Program Files\Microsoft SDKs\Windows\v6.0A\\include\winsock.h(479) : see previous definition of 'AF_MAX'<BR>
|
||||
C:\Program Files\Microsoft SDKs\Windows\v6.0A\\include\ws2def.h(163) : warning C4005: 'SO_DONTLINGER' : macro redefinition<BR>
|
||||
C:\Program Files\Microsoft SDKs\Windows\v6.0A\\include\winsock.h(402) : see previous definition of 'SO_DONTLINGER'<BR>
|
||||
C:\Program Files\Microsoft SDKs\Windows\v6.0A\\include\ws2def.h(206) : error C2011: 'sockaddr' : 'struct' type redefinition<BR>
|
||||
C:\Program Files\Microsoft SDKs\Windows\v6.0A\\include\winsock.h(485) : see declaration of 'sockaddr'<BR>
|
||||
This is a bug in winsock.h. You have to include winsock2.h before including winsock.h. You can fix this by including "WindowsIncludes.h" before including winsock.h.
|
||||
<BR>
|
||||
<BR>
|
||||
<B>I get conflicting lib errors such as follows</B><BR>
|
||||
LIBCMT.lib(dosmap.obj) : error LNK2005: __dosmaperr already defined in LIBCD.lib(dosmap.obj)<BR>
|
||||
LIBCMT.lib(mbctype.obj) : error LNK2005: __getmbcp already defined in LIBCD.lib(mbctype.obj)<BR>
|
||||
LIBCMT.lib(mbctype.obj) : error LNK2005: __setmbcp already defined in LIBCD.lib(mbctype.obj)<BR>
|
||||
LIBCMT.lib(mbctype.obj) : error LNK2005: ___initmbctable already defined in LIBCD.lib(mbctype.obj)<BR>
|
||||
LIBCMT.lib(tolower.obj) : error LNK2005: __tolower already defined in LIBCD.lib(tolower.obj)<BR>
|
||||
LIBCMT.lib(tolower.obj) : error LNK2005: _tolower already defined in LIBCD.lib(tolower.obj)<BR>
|
||||
LIBCMT.lib(isctype.obj) : error LNK2005: __isctype already defined in LIBCD.lib(isctype.obj)<BR>
|
||||
LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library<BR>
|
||||
<BR>
|
||||
You need to select Multithreaded Debug and Multithreaded libraries in the project options.<BR>
|
||||
<BR>
|
||||
<B>I get linker errors such as follows</B><BR>
|
||||
LIBCMTD.lib(invarg.obj) : error LNK2005: __invoke_watson already defined in MSVCRTD.lib(MSVCR80D.dll)<BR>
|
||||
LIBCMTD.lib(setlocal.obj) : error LNK2005: __configthreadlocale already defined in MSVCRTD.lib(MSVCR80D.dll)<BR>
|
||||
LIBCMTD.lib(tidtable.obj) : error LNK2005: __encode_pointer already defined in MSVCRTD.lib(MSVCR80D.dll)<BR>
|
||||
LIBCMTD.lib(tidtable.obj) : error LNK2005: __decode_pointer already defined in MSVCRTD.lib(MSVCR80D.dll)<BR>
|
||||
LIBCMTD.lib(dbgheap.obj) : error LNK2005: _malloc already defined in MSVCRTD.lib(MSVCR80D.dll)<BR>
|
||||
LIBCMTD.lib(dbgheap.obj) : error LNK2005: _realloc already defined in MSVCRTD.lib(MSVCR80D.dll)<BR>
|
||||
LIBCMTD.lib(dbgheap.obj) : error LNK2005: _free already defined in MSVCRTD.lib(MSVCR80D.dll)<BR>
|
||||
LINK : warning LNK4098: defaultlib 'MSVCRTD' conflicts with use of other libs; use /NODEFAULTLIB:library<BR>
|
||||
LINK : warning LNK4098: defaultlib 'LIBCMTD' conflicts with use of other libs; use /NODEFAULTLIB:library<BR>
|
||||
<BR>
|
||||
Right click on the project name, click properties, go to Configuration Properties / C/C++ / Code Generation and change from Multithreaded Debug DLL to Multithreaded Debug (same for release).<BR>
|
||||
<BR>
|
||||
<B>Dropped connections are not detected and/or I can't reconnect after losing the connection.</B><BR>
|
||||
By default, the timeout in debug build is set to 30 seconds, and in release to 10 senconds. A detect lost connections message is sent every 5 seconds. So you may have to wait 35 seconds before you can reconnect. You can change the timeout using RakPeerInterface::SetTimeoutTime.<BR>
|
||||
<BR>
|
||||
<B>I want event callbacks on packet arrival.</B><BR>
|
||||
There are no event callbacks on packet arrival. If you want an event, poll Receive and make your own event if non-zero is returned.<BR>
|
||||
<BR>
|
||||
<B>I can't connect to the other system or other systems can't connect to me. What are some possible reasons?</B> </p>
|
||||
|
||||
<UL>
|
||||
<LI>The other system isn't running RakNet.
|
||||
<LI>The other system didn't start the connection, or tried to start it and it failed (the startup function returned false).
|
||||
<LI>The server has a firewall blocking incoming connections.
|
||||
<LI>The server has a firewall blocking UDP data on the specified server port or the server port + 1 (for winsock 2.0+).
|
||||
<LI>The client has a firewall blocking UDP data on the specified client port or the server port + 1 (for winsock 2.0+).
|
||||
<LI>The server already has the maximum number of connected clients.
|
||||
<LI>The server has a lot of network traffic and is too busy to respond to your connection request.
|
||||
<LI>You used a different value for connectionValidationInteger than the other system.
|
||||
<LI>You are connecting to the wrong port on the server.
|
||||
<LI>You entered the wrong IP address of the server. This could be by mistyping or confusing the LAN address with the internet address.
|
||||
<LI>One or both systems are not using high priority threads and are at the same time using a lot of CPU power for other threads. This could cause the network threads to not respond to the handshaking sequence fast enough.
|
||||
<LI>The handshaking packets were lost due to normal packetloss
|
||||
<LI>You did connect, but never handled the network messaging packets that indicated you you did either because you aren't handling any messages or because you didn't handle those in particular.
|
||||
<LI>The recipient is behind a NAT and didn't use NAT punch-through.
|
||||
</UL>
|
||||
<p><B>I get linker errors about winsock function redefinitions<BR>
|
||||
i.e. - error C2011: 'WSAData' : 'struct' type redefinition<BR>
|
||||
i.e. - warning C4005: 'SO_DONTLINGER' : macro redefinition</B>
|
||||
<BR>
|
||||
<BR>
|
||||
Add this to your preprocessor definitions<BR>
|
||||
_WINSOCKAPI_<BR>
|
||||
In .Net this would be project / configuration properties / C/C++ / Preprocessor / Preprocessor defintions.<BR>
|
||||
You will get this or a similar warning:<BR>
|
||||
warning C4005: '_WINSOCKAPI_' : macro redefinition unknown(0) : see previous definition of '_WINSOCKAPI_'<BR>
|
||||
You can ignore it.<BR>
|
||||
<BR>
|
||||
<B>I can connect but don't get any data from the other system. What are some possible reasons?</B><BR>
|
||||
<BR>
|
||||
You aren't calling Receive.<BR>
|
||||
The other system didn't send any data, or didn't send any to you.<BR>
|
||||
The other system immediately kicked you after you connected, such as due to you being banned or using a wrong password.<BR>
|
||||
The network disconnected you because of cheating or because it couldn't deliver a reliable packet.<BR>
|
||||
<BR>
|
||||
<B>Some kind of networked action happens twice, such as when I press the trigger to fire a bullet two bullets come out.</B><BR>
|
||||
<BR>
|
||||
The server is broadcasting to everyone, including the client that just initiated the action. To fix this, pass the systemAddress parameter of the packet to the systemAddress field of RakPeerInterface::Send when broadcasting. This will relay the message to all players BUT the sender.<BR>
|
||||
<BR>
|
||||
<B>When I send some particular kind of packet, I immediately get flooded with hundreds of copies the same packet.</B><BR>
|
||||
This is a feedback loop, caused by the following sort of coding:<BR>
|
||||
<BR>
|
||||
|
||||
// Client<BR>
|
||||
void DoMyFunctionA(void)<BR>
|
||||
{<BR>
|
||||
SendPacketToDoFunctionA();<BR>
|
||||
}<BR>
|
||||
<BR>
|
||||
// Server<BR>
|
||||
void HandlePacketToDoFunctionA(void)<BR>
|
||||
{<BR>
|
||||
// Broadcast to all connected players<BR>
|
||||
SendToAllPacketToDoFunctionA();<BR>
|
||||
}<BR>
|
||||
<BR>
|
||||
// Client<BR>
|
||||
void ReceivePacketToDoFunctionA(void)<BR>
|
||||
{<BR>
|
||||
DoMyFunctionA();<BR>
|
||||
}<BR>
|
||||
<BR>
|
||||
|
||||
To fix this, either don't have the function that does the action also send the packet, or use a parameter specifying whether to send a packet or not and set that parameter to false if the function is called from the network code. See Programming Tips for help on how to handle this.<BR>
|
||||
<BR>
|
||||
<B>How do I create a master game browser?</B><BR>
|
||||
We offer this at http://masterserver2.raknet.com/. You could also use CloudServer, PHPDirectoryServer2, RoomsPlugin, SteamLobby, or SQLite3Plugin<BR>
|
||||
<BR>
|
||||
<B>Which version of the multithreaded library does RakNet use?</B><BR>
|
||||
Multithreaded (/MT)<BR>
|
||||
<BR>
|
||||
<B>Since RakNet uses threads does my program need to use the multithreaded library?</B><BR>
|
||||
If you use the DLL then no. The threads are confined to the dll. If you use the static lib or source then yes.<BR>
|
||||
<BR>
|
||||
<B>Can I run more than one instance of the client or server on the same system?<BR>
|
||||
</B>
|
||||
Yes, but each instance will have its own thread and require its own memory. You'll need to remember to give different port assigments to each instance as well. There isn't really any reason to do this since you can use RakPeer to handle multiple outgoing connections.<BR>
|
||||
<BR>
|
||||
<B>How do I send files?</B><BR>
|
||||
Just send it as a data stream using RELIABLE.<BR>
|
||||
<BR>
|
||||
<B>If I purchase one license, can I use it in more than one game?</B><BR>
|
||||
A site license will allow you to do this. A normal license requires one copy of the license per game. Refer to the License Agreement for full details.<BR>
|
||||
<BR>
|
||||
<B>Can I use RakNet in non-games?</B><BR>
|
||||
Yes<BR><BR>
|
||||
<B>My game is too laggy. How can I decrease lag?</B><BR>
|
||||
- Use bandwidth more efficiently (see the optimization section in Programming Tips )<BR>
|
||||
- Design your game so it doesn't require as much bandwidth (see the optimization section in Programming Tips )<BR>
|
||||
- Use high priority threads<BR>
|
||||
- Get a faster computer. This will make threads more responsive.<BR>
|
||||
- Get a better internet connection.<BR>
|
||||
- Decrease the number of clients allowed.<BR>
|
||||
<BR>
|
||||
<B>Does RakNet use TCP at all?</B><BR>
|
||||
RakPeer does not. However, some plugins support it - EmailSender, Autopatcher, FileListTransfer, DeltaDirectoryTransfer.
|
||||
<BR>
|
||||
<BR>
|
||||
<B>Will RakNet work with my game written in C?</B><BR>
|
||||
No. </p>
|
||||
<p><strong>On Windows 7 why can I not open more than one outgoing connection at a time, unless I run as administrator?</strong><br>
|
||||
This was a design flaw in Windows 7 when it shipped. However, once you run the updater, this design flaw was fixed. See <A HREF="http://www.jenkinssoftware.com/forum/index.php?topic=3721.0">http://www.jenkinssoftware.com/forum/index.php?topic=3721.0</A></p>
|
||||
<p><strong>Does RakNet support cloud hosting services?<br>
|
||||
</strong><A HREF="cloudhosting.html">Yes</A>, RakNet works with <A HREF="http://www.rackspace.com/cloud/">Rackspace Cloud</A>.</p>
|
||||
<p><strong><br>
|
||||
</strong></p></TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
80
Help/RakNet/documentation/filelisttransfer.html
Normal file
@ -0,0 +1,80 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>FileListTransfer manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">FileListTransfer Overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Send and receive file(s) more easily</span><BR>
|
||||
</p>
|
||||
<p>The FileListTransfer plugin is designed to send a list of files that have been read into the <strong>FileList</strong> class. It is similar to the <a href="directorydeltatransfer.html">DirectoryDeltaTransfer</a> plugin, except that it doesn't send deltas based on pre-existing files or actually write the files to disk. It solely handles the networking part of sending files.</p>
|
||||
<p>Usage:</p>
|
||||
<ol>
|
||||
<li>Server: Call SetupReceive(...) with the address of a system to allow a file send, and a <strong>FileListTransferCBInterface</strong> derived callback handler to be called as the data arrives.</li>
|
||||
<li>Client: Encode the files you want to send into the <strong>FileList</strong> class.</li>
|
||||
<li>Client: Call Send(...) with your <strong>FileList</strong> class instance, a user-defined ID to identify this set of files, parameters to pass to RakPeerInterface::Send() or TCPInterface::Send(), and a boolean indicating if the files should be compressed or not. Compression is not very fast, so it's best to leave that off unless bandwidth is at a premium. </li>
|
||||
</ol>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">FileList Overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p>The FileList class stores a list of files and data, and also contains utility functions for dealing with the harddrive in general. It was originally written for the <a href="autopatcher.html">Autopatcher</a>, but can be used for your own purposes as well.</p>
|
||||
<p>See FileList.h for a complete description of all functions and parameters.</p>
|
||||
<p class="RakNetCode">/// Add all the files at a given directory.<br>
|
||||
void AddFilesFromDirectory(const char *applicationDirectory, const char *subDirectory, bool writeHash, bool writeData, bool recursive, unsigned char context);</p>
|
||||
<p class="RakNetCode"> /// Deallocate all memory<br>
|
||||
void Clear(void);</p>
|
||||
<p class="RakNetCode"> /// Write all encoded data into a bitstream<br>
|
||||
void Serialize(RakNet::BitStream *outBitStream);</p>
|
||||
<p class="RakNetCode"> /// Read all encoded data from a bitstream. Clear() is called before deserializing.<br>
|
||||
bool Deserialize(RakNet::BitStream *inBitStream);</p>
|
||||
<p class="RakNetCode"> /// Given the existing set of files, search applicationDirectory for the same files.<br>
|
||||
/// For each file that is missing or different, add that file to missingOrChangedFiles. Note: the file contents are not written, and only the hash if written if alwaysWriteHash is true<br>
|
||||
void ListMissingOrChangedFiles(const char *applicationDirectory, FileList *missingOrChangedFiles, bool alwaysWriteHash, bool neverWriteHash);</p>
|
||||
<p class="RakNetCode"> /// Return the files that need to be written to make \a input match this current FileList.<br>
|
||||
void GetDeltaToCurrent(FileList *input, FileList *output, const char *dirSubset, const char *remoteSubdir);</p>
|
||||
<p class="RakNetCode"> /// Assuming FileList contains a list of filenames presumably without data, read the data for these filenames<br>
|
||||
void PopulateDataFromDisk(const char *applicationDirectory, bool writeFileData, bool writeFileHash, bool removeUnknownFiles);</p>
|
||||
<p class="RakNetCode"> /// Write all files to disk, prefixing the paths with applicationDirectory<br>
|
||||
void WriteDataToDisk(const char *applicationDirectory);</p>
|
||||
<p class="RakNetCode"> /// Add a file, given data already in memory<br>
|
||||
void AddFile(const char *filename, const char *data, const unsigned dataLength, const unsigned fileLength, unsigned char context);</p>
|
||||
<p class="RakNetCode"> /// Add a file, reading it from disk<br>
|
||||
void AddFile(const char *filepath, const char *filename, unsigned char context);</p>
|
||||
<p class="RakNetCode"> /// Delete all files stored in the file list<br>
|
||||
void DeleteFiles(const char *applicationDirectory);
|
||||
</p>
|
||||
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <p><A HREF="index.html">Index</A><br>
|
||||
<a href="directorydeltatransfer.html">Delta Directory Transfer</a><BR>
|
||||
</p>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
44
Help/RakNet/documentation/fullyconnectedmesh.html
Normal file
@ -0,0 +1,44 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Fully Connected Mesh</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Fully Connected Mesh Plugin Interface Implementation</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Automatically connect all peers in a peer to peer game</span><BR>
|
||||
<BR>
|
||||
|
||||
|
||||
The fully connected mesh implementation reads connection messages from RakNet and tries to connect to all systems on the network. On a new connection, it will tell the remote system of all systems it knows about. When that packet arrives, that system will then try to connect to all those systems in turn. You can optionally specify a password which you can use to allow certain systems to join the mesh and other systems to not do so.</p>
|
||||
<p> NOTE : The implementation requires that a ConnectionGraph plugin is also attached to the RakPeer.<BR></p>
|
||||
<p class="RakNetCode">/// Set the password to use to connect to the other systems<br>
|
||||
void Startup(const char *password, int _passwordLength);</p>
|
||||
<p class="RakNetCode"> /// Use the NAT punchthrough system to connect rather than calling directly<br>
|
||||
void ConnectWithNatPunchthrough(NatPunchthrough *np, SystemAddress _facilitator); </p>
|
||||
<p>See <em>Samples/FullyConnectedMesh</em> for a demonstration of this plugin</p></TD>
|
||||
</TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><A HREF="index.html">Index</A><BR>
|
||||
<A HREF="plugininterface.html">PluginInterface</A><br>
|
||||
<a href="natpunchthrough.html">NAT-Punchthrough</a><br>
|
||||
<a href="readyevent.html">Ready Event</a><BR>
|
||||
</p>
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
88
Help/RakNet/documentation/fullyconnectedmesh2.html
Normal file
@ -0,0 +1,88 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Fully Connected Mesh 2</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Fully Connected 2 Mesh Plugin</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Consistently join a fully connected mesh. Automatically determine who is host.</span></p>
|
||||
<p>FullyConnectedMesh2 solves two problems with peer to peer games. First, how to connect to a list of systems maintained by the session host, with correct behavior on a failed connection. Secondly, to determine and automatically migrate a session host. A session host is needed for authoritative behavior, for example the host may send out game end notifications or may control the AI.</p>
|
||||
<p><strong>Properly joining a fully connected mesh:</strong>
|
||||
<ol>
|
||||
<li>All systems: Call SetConnectOnNewRemoteConnection(false, "");
|
||||
<li>All systems: Call SetAutoparticipateConnections(false);
|
||||
<li>Host: When a new system connects and is allowed to join, call StartVerifiedJoin() to send ID_FCM2_VERIFIED_JOIN_START to that system.
|
||||
<li>Client: On ID_FCM2_VERIFIED_JOIN_START, call fullyConnectedMesh2->GetVerifiedJoinRequiredProcessingList() to get a list of systems to connect to.
|
||||
<li>Client: Attempt to connect to each of the system returned from GetVerifiedJoinRequiredProcessingList(). Use NATPunchthroughClient and/or UPNP as necessary. Once all connections have failed or succeeded, the host is informed automatically.
|
||||
<li>Client: On ID_FCM2_VERIFIED_JOIN_FAILED, either you lost connection to the host, or the host required you to connect to a participant you were not able to. Inform the player via the UI.
|
||||
<li>Host: On ID_FCM2_VERIFIED_JOIN_CAPABLE, call RespondOnVerifiedJoinCapable() to accept or reject the join based on game logic.
|
||||
<li>Client: On ID_FCM2_VERIFIED_JOIN_REJECTED, the host rejected the join for gameplay reasons. Disconnect from the host if the connection is no longer needed. Use GetVerifiedJoinRejectedAdditionalData() to determine why the join was rejected, and inform the player via the UI.
|
||||
<li>Client: On ID_FCM2_VERIFIED_JOIN_ACCEPTED, the host accepted the join. AddParticipant() has automatically been called on all systems, and you have joined the mesh. Call GetVerifiedJoinAcceptedAdditionalData() if desired.
|
||||
</ol>
|
||||
|
||||
StartVerifiedJoin() is of significant benefit when using NatPunchthroughClient because if a connection fails, previously successful connections are closed automatically. Also, because NatPunchthroughClient takes a significant amount of time, a valid game session may no longer valid by the time it completes. However, even when not using NatPunchthroughClient this system is useful because you may still not fully connect due to firewalls or because sessions are full. Ignoring this means you may only connect partially to the mesh, resulting in some players not able to see other players.
|
||||
|
||||
<p><strong>Determining who is host of the fully connected mesh</strong></p>
|
||||
<ol>
|
||||
<li>If NOT using StartVerifiedJoin(), call AddParticipant() on every system, for every new connection. Note: this is done automatically by default, and is controlled by SetAutoparticipateConnections(true).
|
||||
<li>Use GetHostSystem() and IsHostSystem() to query who is the host
|
||||
<li>Do not start gameplay until the host has been calculated. This is known once you get ID_FCM2_NEW_HOST at least once.
|
||||
<li>Do host migration if necessary when you get ID_FCM2_NEW_HOST during gameplay
|
||||
</ol>
|
||||
|
||||
<p>Host calculation starts automatically once one or more remote connections have been added with AddParticipant(). Until host calculation has completed, GetHostSystem() will return your own guid and GetConnectedHost() will return UNASSIGNED_RAKNET_GUID. You will get ID_FCM2_NEW_HOST as soon as the host is known. The host will generally be whichever system has been running the longest of all systems added with AddParticipant().</p>
|
||||
<p>GetParticipantList() and GetHostOrder() can be used to find out which systems were added with AddParticipant().</p>
|
||||
<p>If the game does not immediately start networked, you should call ResetHostCalculation() to reinitialize the host timer when network play is now relevant. Otherwise, a user could play a game in single player, connect to a network session, and then be considered the host because his system was running the longest, although he was the last to join the network session. A good time to call ResetHostCalculation() is just before attempting to join a network room or lobby.</p>
|
||||
<p><strong>Reading ID_FCM2_NEW_HOST:</strong></p>
|
||||
<p>ID_FCM2_NEW_HOST has the RakNetGUID of the old host encoded in the network stream. The new host is written to the systemAddress and guid members of the Packet.
|
||||
<PRE>
|
||||
case ID_FCM2_NEW_HOST:
|
||||
{
|
||||
if (packet->guid==rakPeer->GetMyGUID())
|
||||
printf("Got new host (ourselves)");
|
||||
else
|
||||
printf("Got new host %s, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString());
|
||||
RakNet::BitStream bs(packet->data,packet->length,false);
|
||||
bs.IgnoreBytes(1);
|
||||
RakNetGUID oldHost;
|
||||
bs.Read(oldHost);
|
||||
if (oldHost==UNASSIGNED_RAKNET_GUID)
|
||||
{
|
||||
DataStructures::List<RakNetGUID> participantList;
|
||||
fullyConnectedMesh2->GetParticipantList(participantList);
|
||||
// First time ID_FCM2_NEW_HOST was returned. Host is now known - can start gameplay, and add all systems that were previously added with AddParticipant() as players
|
||||
// ...
|
||||
}
|
||||
break;
|
||||
</PRE>
|
||||
See <em>Samples/FCMHost</em> for a demonstration of this plugin</p></TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> </TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><A HREF="index.html">Index</A><BR>
|
||||
<A HREF="plugininterface.html">PluginInterface</A><br>
|
||||
<a href="natpunchthrough.html">NAT-Punchthrough</a><br>
|
||||
<a href="readyevent.html">Ready Event</a><BR>
|
||||
</p>
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
73
Help/RakNet/documentation/helloworldvideo.html
Normal file
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!-- saved from url=(0014)about:internet -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<!-- saved from url=(0025)http://www.techsmith.com/ -->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="DC.date" content="Thursday, February 07, 2008" />
|
||||
<meta name="DC.language" content="ENU" />
|
||||
<meta name="DC.title" content="RakNetIntroVideo" />
|
||||
<meta name="Author Homepage" content="http://www.jenkinssoftware.com" />
|
||||
<meta name="DC.creator" content="Kevin Jenkins" />
|
||||
|
||||
<title>Created with Camtasia Studio 5</title>
|
||||
<script type="text/javascript" src="swfobject.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body
|
||||
{
|
||||
background-color: #1a1a1a;
|
||||
font: .8em/1.3em verdana,arial,helvetica,sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
#media
|
||||
{
|
||||
margin-top: 40px;
|
||||
}
|
||||
#noUpdate
|
||||
{
|
||||
margin: 0 auto;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: x-small;
|
||||
color: #cccccc;
|
||||
text-align: left;
|
||||
width: 210px;
|
||||
height: 200px;
|
||||
padding: 40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="media">
|
||||
<div id="noUpdate">
|
||||
<p>The Camtasia Studio video content presented here requires JavaScript to be enabled and the latest version of the Macromedia Flash Player. If you are you using a browser with JavaScript disabled please enable it now. Otherwise, please update your version of the free Flash Player by <a href="http://www.macromedia.com/go/getflashplayer">downloading here</a>. </p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// <![CDATA[
|
||||
var so = new SWFObject( "RakNetIntroVideo.swf", "csSWF", "800", "618", "9.0.28", "#1a1a1a");
|
||||
so.addParam( "quality", "best" );
|
||||
so.addParam( "allowFullScreen", "true" );
|
||||
so.addParam( "scale", "showall" );
|
||||
so.addParam( "allowScriptAccess", "always" );
|
||||
so.addVariable( "autostart", "false" );
|
||||
so.write("media");
|
||||
// ]]>
|
||||
</script>
|
||||
<!-- Users looking for simple object / embed tags can copy and paste the needed tags below.
|
||||
<div id="media">
|
||||
<object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="800" height="618" codebase="http://active.macromedia.com/flash7/cabs/ swflash.cab#version=9,0,28,0">
|
||||
<param name="src" value="RakNetIntroVideo.swf"/>
|
||||
<param name="bgcolor" value="#1a1a1a"/>
|
||||
<param name="quality" value="best"/>
|
||||
<param name="allowScriptAccess" value="always"/>
|
||||
<param name="allowFullScreen" value="true"/>
|
||||
<param name="scale" value="showall"/>
|
||||
<param name="flashVars" value="autostart=false"/>
|
||||
<embed name="csSWF" src="RakNetIntroVideo.swf" width="800" height="618" bgcolor="#1a1a1a" quality="best" allowScriptAccess="always" allowFullScreen="true" scale="showall" flashVars="autostart=false" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
|
||||
</object>
|
||||
</div>
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
253
Help/RakNet/documentation/index.html
Normal file
@ -0,0 +1,253 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Oculus VR, Inc.</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="2c5d92"><font color="#FFFFFF" size="3" face="Arial, Helvetica, sans-serif" class="RakNetWhiteHeader"><span class="RakNetWhiteHeader"> Introduction</span></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD> <p><span class="RakNetBlueHeader">Manual Last Updated
|
||||
11/19/2012. See readme.txt for the current version number.</span></p>
|
||||
<p>RakNet is a high-performance network API designed for games or other high-performance network applications. RakNet is intended to provide most to all features modern games need, such as a master server, autopatcher, voice chat, and cross-platform capabilities. RakNet currently supports Windows, PlayStation 3, XBOX 360, PlayStation Vita, Linux, Mac, the iPhone, Android, and Windows Phone 8.</p></TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="2c5d92"> <span class="RakNetWhiteHeader">Quick Start</span></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD><p><A HREF="multiplayergamecomponents.html">Components of a multiplayer game</A><BR>
|
||||
<A HREF="systemoverview.html">System Overview</A><BR>
|
||||
<A HREF="detailedimplementation.html">Detailed Implementation</A><BR>
|
||||
<A HREF="tutorial.html">Tutorial</A><BR>
|
||||
<A HREF="compilersetup.html">Compiler Setup (Visual Studio)</A><BR>
|
||||
<A HREF="compilersetup_xcode.html">Compiler Setup (XCode)</A><BR>
|
||||
<A HREF="dependencies.html">Optional 3rd party dependencies</A><br>
|
||||
<a href="http://www.jenkinssoftware.com/forum/index.php?topic=584.0">HowTo</a><BR>
|
||||
</p></TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="2c5d92" class="RakNetWhiteHeader"> Training Videos</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD><p><A HREF="http://www.youtube.com/watch?v=sez3o00uCqU">Introduction:Major Features</A><br>
|
||||
<A HREF="http://www.jenkinssoftware.com/raknet/manual/RPC3Video.htm">Tutorial 1: RPC3</A><BR>
|
||||
<A HREF="http://www.jenkinssoftware.com/raknet/manual/ReplicaManager3Video.htm">Tutorial 2: ReplicaManager3</A><BR>
|
||||
<A HREF="http://www.jenkinssoftware.com/raknet/manual/AutopatcherVideo.htm">Tutorial 3: Autopatcher</A><BR>
|
||||
<A HREF="http://www.youtube.com/watch?v=w4OUGeLKcss">Tutorial 4: A complete sample covering object replication, teams, player hosted rooms and lobbies, NAT traversal, and host migration</A><br>
|
||||
</p></TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="2c5d92" class="RakNetWhiteHeader"> Feature Videos</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD><p><A HREF="http://www.jenkinssoftware.com/raknet/manual/SQLite3LoggerPluginVideo.html">Networked logging with SQLiteClientLoggerPlugin</A><br>
|
||||
</p></TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="2c5d92">
|
||||
<img src="spacer.gif" width="8" height="1"><span class="RakNetWhiteHeader">The Basics</span></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<p><a href="startup.html">Startup</a> <BR>
|
||||
- Starting up RakPeerInterface, and the thread sleep timer explained</p>
|
||||
<p><a href="connecting.html">Connecting</a> <BR>
|
||||
- How to find and connect to other systems, and what to do if there are problems </p>
|
||||
<p><A HREF="creatingpackets.html">Creating Packets</A><BR>
|
||||
- How to create custom packets using structures and bitstreams, and how to encode timestamps.<BR>
|
||||
<BR>
|
||||
<A HREF="sendingpackets.html">Sending Packets</A><BR>
|
||||
- How to send packets already prepared, and what parameters to use.<BR>
|
||||
<BR>
|
||||
<A HREF="receivingpackets.html">Receiving Packets</A><BR>
|
||||
- How to converting raw data back to a packet you can read via a structure or bitstream.</p>
|
||||
<p><A HREF="systemaddresses.html">SystemAddress</A><BR>
|
||||
- Describes the purpose and use of the SystemAddress structure used in packets and in some function parameters.</p>
|
||||
<p><A HREF="bitstreams.html">Bitstreams</A><BR>
|
||||
- An overview of RakNet's bitstream class, used throughout the API.</p>
|
||||
<p><A HREF="reliabilitytypes.html">Reliability types</A><BR>
|
||||
- Covers parameters you can use to control how data gets sent.</p>
|
||||
<p><A HREF="networkmessages.html">Network Messages</A><BR>
|
||||
- Gives an overview of the messages the API will send to the user. This is also listed in MessageIdentifiers.h.
|
||||
<p><A HREF="timestamping.html">Timestamping your packets</A><BR>
|
||||
- Covers the purpose of timestamps.<BR>
|
||||
<BR>
|
||||
<A HREF="networkidobject.html">NetworkIDObject</A><BR>
|
||||
- A Utility class to give each class instance a unique identifier that all systems can share.</p>
|
||||
<p><A HREF="statistics.html">Statistics</A><BR>
|
||||
- The statistics that RakNet provides.<BR>
|
||||
<BR>
|
||||
<A HREF="secureconnections.html">Secure connections</A><BR>
|
||||
- How to activate and use secure connections.</p>
|
||||
<p><a href="http://masterserver2.raknet.com/">Master server</a><br>
|
||||
- Our hosted master server service, to find other games on the internet.
|
||||
</p>
|
||||
<p><a href="cloudhosting.html">Cloud hosting</a><br>
|
||||
- Setting up RakNet with cloud-hosted services</p>
|
||||
<p><a href="rackspaceinterface.html">Rackspace interface</a><br>
|
||||
- C++ interface to Rackspace, allowing you to programatically create, delete, reboot, image, and perform other operations on servers.</p>
|
||||
<p><a href="nattraversalarchitecture.html">NAT traversal architecture</a><br>
|
||||
- How to use combine UPNP, NAT type detection, NAT punchthrough, and Router2 so P2P connections complete quickly and efficiently.<BR>
|
||||
<BR>
|
||||
<A HREF="preprocessordirectives.html">Preprocessor Directives</A><BR>
|
||||
- Enables you to rebuild the library with different code settings.</p>
|
||||
<p><A HREF="custommemorymanagement.html">Custom Memory Management</A><BR>
|
||||
- For consoles, memory tracking, etc.</p>
|
||||
<p><a href="ipv6support.html">IPV6 support</a><br>
|
||||
- The next-generation IP address
|
||||
format.</p>
|
||||
<p><a href="marmalade.html">Marmalade integration</a><br>
|
||||
- Integration with the Marmalade SDK for the IOS and Android platforms.</p></TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92"><font color="#FFFFFF" size="3" face="Arial, Helvetica, sans-serif"><strong><span class="RakNetWhiteHeader"> Plugins</span></strong></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="plugininterface.html">Plugin Interface 2</A><BR>
|
||||
- The base class of all plugins<BR>
|
||||
|
||||
<p><A HREF="autopatcher.html">Autopatcher</A><BR>
|
||||
- Overview of the autopatcher included with RakNet.</p>
|
||||
<p><a href="RPC3Video.htm">RPC3</a><br>
|
||||
- Call C and C++ functions with native parameter lists, using Boost for additional functionality.</p>
|
||||
<p><a href="rpc4.html">RPC4</a><br>
|
||||
- Call C functions, no external dependencies.</p>
|
||||
<p><A HREF="connectiongraph.html">Connection Graph</A><BR>
|
||||
- A plugin-in that maintains a graph of the entire network.</p>
|
||||
<p><a href="directorydeltatransfer.html">Directory Delta Transfer</a><br>
|
||||
- Send changed or missing files between directories. In essence, a simple autopatcher that can be used for transmitting levels, skins, etc.<br>
|
||||
<br>
|
||||
<a href="filelisttransfer.html">File List Transfer</a><br>
|
||||
- Plugin to send a list of files, encoded in the FileList structure<br>
|
||||
<br>
|
||||
<A HREF="fullyconnectedmesh2.html">Fully Connected Mesh 2</A><BR>
|
||||
- A plug-in for peer to peer games, for host determination and verified connectivity to the mesh.</p>
|
||||
<p><a href="lobby.html">Lobby2Client - PC</a><br>
|
||||
- PostgreSQL backed database for game data, including users, friends, clans, messages
|
||||
</p>
|
||||
<p><a href="steamlobby.html">Lobby2Client - Steam</a><br>
|
||||
- Steamworks powered backend, using the Lobby2 interface.</p>
|
||||
<p><a href="ps3lobby.html">Lobby2Client - PS3<br>
|
||||
</a>- PS3 NP backend, using the Lobby2 interface.</p>
|
||||
<p><a href="xbox360lobby.html">Lobby2Client - XBOX 360</a><br>
|
||||
- LIVE backend and voice chat support, using the Lobby2 interface with support for RakVoiceXBOX360Plugin and FullyConnectedMesh2</p>
|
||||
<p><a href="gfwllobby.html">Lobby2Client - Games for Windows Live</a><br>
|
||||
- Same as XBOX 360 backend but runs on Windows</p>
|
||||
<p><a href="messagefilter.html">Message Filter</a><br>
|
||||
- Prevent unwanted network messages based on sender for added security.</p>
|
||||
<p><A HREF="nattypedetection.html">NAT type detection</A><BR>
|
||||
- Find out what kind of NAT you are behind to keep users that will probably not be able to connect separate</p>
|
||||
<p><A HREF="natpunchthrough.html">NAT punchthrough</A><BR>
|
||||
- Connect users behind NAT. Required for peer to peer, voice communication, or to allow players to host their own servers.</p>
|
||||
<p><a href="packetlogger.html">Packet Logger</a><br>
|
||||
- Print network traffic to the screen, file, or elsewhere.</p>
|
||||
<p><A HREF="rakvoice.html">RakVoice</A><BR>
|
||||
- Overview of RakVoice. Refer to RakVoice.h for full implementation and function details. </p>
|
||||
<p><a href="readyevent.html">Ready Event</a><br>
|
||||
- Synchronize when a group of systems are all ready on a common identifier, useful in peer to peer enviroments to start games at the same time, or progress turns in a turn based game.</p>
|
||||
<p><A HREF="replicamanager3.html">Replica Manager 3</A><BR>
|
||||
- A plug-in that provides management for your game objects and players to make serialization, scoping, and object creation and destruction easier.<BR>
|
||||
<BR>
|
||||
<a href="router.html">Router2</a><br>
|
||||
- Send network messages to one or more remote systems we are not directly connected to<br>
|
||||
<br>
|
||||
<a href="sqlite3loggerplugin.html">SQLite3LoggerPlugin</a><br>
|
||||
- Create networked log files using SQLite. Based on <a href="sqlite3plugin.html">SQLite3Plugin</a></p>
|
||||
<p><a href="sqlite3plugin.html">SQLite3Plugin</a><br>
|
||||
- Execute statements over the network with SQLite (replacement for LightweightDatabase)</p>
|
||||
<p><a href="teammanager.html">TeamManager</a><br>
|
||||
- Manages lists of teams and team members. Supports client/server and peer to peer</p>
|
||||
<p><a href="twowayauthentication.html">TwoWayAuthentication</a><br>
|
||||
- Implements <a href="http://en.wikipedia.org/wiki/Mutual_authentication">Two Way Authentication</a>, validating a predesignated password without transmitting the password. </p></TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92"> <strong><span class="RakNetWhiteHeader">C# and SWIG</span></strong></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<p><a href="swigtutorial.html">Swig Tutorial</a><br>
|
||||
- How to run RakNet from C# using SWIG and possibly Mono.</p>
|
||||
<p><a href="csharpunity.html">Unity Integration</a><br>
|
||||
- How RakNet is used with Unity, and how to upgrade to version 4.x</p>
|
||||
</TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92"> <strong><span class="RakNetWhiteHeader">Utilities</span></strong></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><a href="crashreporter.html">Crash Reporter</a><br>
|
||||
- Sends mini-dumps when your application crashes, writing to disk and/or sending an email.</p>
|
||||
<p><a href="consoleserver.html">Console Server</a><br>
|
||||
- Text based backdoor to a server using either secure RakNet or telnet, allowing execution of predesignated commands or arbitrary command strings.</p>
|
||||
<p><a href="emailsender.html">Email Sender</a><br>
|
||||
- Used by the crash reporter to send emails via TCP</p>
|
||||
<p><a href="stringcompressor.html">String Compressor / String Table</a><br>
|
||||
- Used to encode strings with less bandwidth and more security.
|
||||
<p><a href="tcpinterface.html">TCP Interface</a><br>
|
||||
- Wrapper class for TCP connections</p>
|
||||
</TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92"><font color="#FFFFFF" size="3" face="Arial, Helvetica, sans-serif"><strong><span class="RakNetWhiteHeader"> 3D Demos</span></strong></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><a href="ogre3dinterpdemo.html">Ogre 3D Interpolation Demo</a><br>
|
||||
- Use <A HREF="http://www.ogre3d.org/">Ogre 3D</A> to show a demo of popping popcorn over a client/server network, using <a href="replicamanager3.html">ReplicaManager3</a></p>
|
||||
<p><a href="irrlichtfpsdemo.html">Irrlicht FPS Demo</a><br>
|
||||
- Use <A HREF="http://irrlicht.sourceforge.net/">Irrlicht</A> to show a 3D FPS demo using peer to peer with NAT punchthrough. Also uses <a href="replicamanager3.html">ReplicaManager3</a></p>
|
||||
</TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92"><font color="#FFFFFF" size="3" face="Arial, Helvetica, sans-serif"><strong><span class="RakNetWhiteHeader"> Technical Design Documents</span></strong></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD>
|
||||
<a href="RakNetUML.jpg">UML Diagram</a><BR>
|
||||
<a href="bluetooth.html">Potential Bluetooth support</a>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92"><font color="#FFFFFF" size="3" face="Arial, Helvetica, sans-serif"><strong><span class="RakNetWhiteHeader"> Data Structures</span></strong></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p>DS_BinarySearchTree.h - <a href="http://en.wikipedia.org/wiki/Binary_search_tree">Binary search tree</a>, and an <a href="http://en.wikipedia.org/wiki/AVL_tree">AVL balanced</a> binary search tree.<br>
|
||||
DS_BPlusTree.h - <a href="http://en.wikipedia.org/wiki/B%2B_tree">BPlus tree</a> for fast lookup, delete, and insert.<br>
|
||||
DS_BytePool.h - Returns data blocks at certain size thresholds to reduce memory fragmentation.<br>
|
||||
DS_ByteQueue.h - A queue specialized for reading and writing bytes.<br>
|
||||
DS_Heap.h - <a href="http://en.wikipedia.org/wiki/Heap_%28data_structure%29">Heap data structure</a>, includes both minheap and maxheap.<br>
|
||||
DS_HuffmanEncodingTree.h - <a href="http://en.wikipedia.org/wiki/Huffman_coding">Huffman encoding tree</a>, used to find the minimal bitwise representation given a frequency table.<br>
|
||||
DS_HuffmanEncodingTreeFactory.h - Creates instances of the Huffman encoding tree.<br>
|
||||
DS_HuffmanEncodingTreeNode.h - Node in the Huffman encoding tree.<br>
|
||||
DS_LinkedList.h - Standard <a href="http://en.wikipedia.org/wiki/Linked_list">linked list</a>.<br>
|
||||
DS_List.h - Dynamic <a href="http://en.wikipedia.org/wiki/Array">array</a> (sometimes improperly called a vector). Also doubles as a <a href="http://en.wikipedia.org/wiki/Stack_%28data_structure%29">stack</a>.<br>
|
||||
DS_Map.h - (<a href="http://en.wikipedia.org/wiki/Associative_array">Associative array</a>) Ordered list with an per-element sort key.<br>
|
||||
DS_MemoryPool.h - Allocate and free reused instances of a fixed size structure, used to reduce memory fragmentation.<BR>
|
||||
DS_Multilist_h - (Added 4/8/2009) Combines a list, stack, queue, and ordered list into one class with a common interface.<BR>
|
||||
DS_OrderedChannelHeap.h - Maxheap which returns a node based on the relative weight of the node's associated channel. Used for task scheduling with priorities.<br>
|
||||
DS_OrderedList.h - List ordered by an arbitrary key via <a href="http://en.wikipedia.org/wiki/Quicksort">quicksort</a>.<br>
|
||||
DS_Queue.h - Standard <a href="http://en.wikipedia.org/wiki/Queue_%28data_structure%29">queue</a> implemented with an array<br>
|
||||
DS_QueueLinkedList.h - Standard queue implemented with a <a href="http://en.wikipedia.org/wiki/Linked_list">linked list</a><br>
|
||||
DS_RangeList.h - Stores a list of numerical values, and when the values are sequential, represents them as a range rather than individual elements. Useful when storing many values that are usually sequential.<br>
|
||||
DS_Table.h - <a href="http://en.wikipedia.org/wiki/Table_%28database%29">Table</a> with columns and rows, and operations on that table.<br>
|
||||
DS_Tree.h - Noncyclic <a href="http://en.wikipedia.org/wiki/Graph_%28data_structure%29">graph</a><br>
|
||||
DS_WeightedGraph.h - Graph with weighted edges, used for routing via <a href="http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">Dijkstra's algorithm</a><br>
|
||||
RakString - String implementation, up to 4.5 times faster than std::string</p></TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader"><font color="#FFFFFF" size="3" face="Arial, Helvetica, sans-serif" class="RakNetWhiteHeader"> Support</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="faq.html">FAQ</A><br>
|
||||
<a href="debuggingdisconnects.html">Debugging Disconnections</a><BR>
|
||||
<A HREF="programmingtips.html">Programming Tips</A><BR>
|
||||
<A HREF="revisionlog.html">Revision Log</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
138
Help/RakNet/documentation/introduction.html
Normal file
@ -0,0 +1,138 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Introduction</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
Introduction</td>
|
||||
</tr></table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody"><span class="RakNetBlueHeader">Installation</span><BR>
|
||||
<BR>
|
||||
Please refer to the <A HREF="compilersetup.html">Compiler Setup</A> page, as all your questions should be answered there. If you have additional problems please refer to the <A HREF="faq.html">FAQ</A>, <A HREF="http://www.jenkinssoftware.com">http://www.jenkinssoftware.com</A>, or <A HREF="mailto:rakkar@jenkinssoftware.com">contact us</A>. Advanced users can jump to the <A HREF="tutorial.html">code tutorial</A>. Beginners or those wishing to learn more about RakNet should keep reading. <BR>
|
||||
<BR>
|
||||
API Description <BR>
|
||||
<BR>
|
||||
RakNet is a game engine solely managing networking and related services. It includes game-level replication, patching, NAT punchthrough, and voice chat. It allows any application to communicate with other applications that also uses it, whether that be on the same computer, over a LAN, or over the internet. Although RakNet can be used for any networked application, it was developed with a focus on online gaming and provides extra functionality to facilitate the programming of online games as well as being programmed to address the most common needs of online games. <BR>
|
||||
<BR>
|
||||
Networking 101 <BR>
|
||||
<BR>
|
||||
Game network connections usually fall under two general categories: peer to peer and client/server. Each of these are implemented in a variety of ways and with a variety of protocols.
|
||||
However, RakNet supports any topology. <BR>
|
||||
<BR>
|
||||
<CENTER>
|
||||
<IMG SRC="clientserver.jpg" width="380" height="456">
|
||||
</CENTER>
|
||||
<BR>
|
||||
Generally speaking, the fastest computer with the best connection should act as the server, with other computers acting as the clients.<BR>
|
||||
<BR>
|
||||
While there are many types of ways to encode packets, they are all transmitted as either UDP
|
||||
or TCP packets. TCP packets are good for sending files, but not so good for
|
||||
games. They are often delayed (resulting in games with a lot of lag) and arrive
|
||||
as streams rather than packets (so you have to implement your own scheme to
|
||||
separate data). UDP packets are good because they are sent right away and are sent in packets so you can easily distinguish data. However, the added flexibility comes with a variety of problems:<BR>
|
||||
<UL>
|
||||
<LI>UDP packets are not guaranteed to arrive. You may get all the packets you sent, none of them, or some fraction of them.
|
||||
<LI>UDP packets are not guaranteed to arrive in any order. This can be a huge problem when programming games. For example you may get the message that a tank was destroyed before you ever got the message that that tank had been created!
|
||||
<LI>UDP packets are guaranteed to arrive with correct data, but have no protection from hackers intercepting and changing the data once it has arrived.
|
||||
<LI>UDP packets do not require a connection to be accepted. This sounds like a good thing until you realize that games without protection from this would be very easy to hack. For example, if you had a message that said "Give such and such invulnerability" a hacker could copy that message and send it to the server everytime they wanted invulnerability.
|
||||
<LI>The UDP transport does not provide flow control or aggregation so it is possible to overrun the recipient and to send data inefficiently.
|
||||
</UL></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> How does RakNet help me with these issues?</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody">At the lowest level, RakNet's peer to peer class, RakPeerInterface provides a layer over UDP packets that handle these problems transparently, allowing the programmer to focus on the game rather than worrying about the engine.<BR>
|
||||
<UL>
|
||||
<LI>RakNet can automatically resend packets that did not arrive.
|
||||
|
||||
<LI>RakNet can automatically order or sequence packets that arrived out of order, and does so efficiently.
|
||||
|
||||
<LI>RakNet protects data that is transmitted, and will inform the programmer if that data was externally changed.
|
||||
|
||||
<LI>RakNet provides a fast, simple, connection layer that blocks unauthorized transmission.
|
||||
|
||||
<LI>RakNet transparently handles network issues such as flow control and aggreggation.
|
||||
|
||||
</UL>
|
||||
Of course, RakNet would be not much use if it handled these issues inefficiently such as by sending a lot of data, locking up with blocking operations, or making it hard to take advantage of these features. Fortunately, that is not the case.<BR>
|
||||
<BR>
|
||||
Unlike some other networking APIs:<BR>
|
||||
<UL>
|
||||
<LI>RakNet adds very few bytes to your data.
|
||||
|
||||
<LI>RakNet does not incur overhead for features you do not use.
|
||||
<LI>RakNet has nearly instantaneous connections and disconnections.
|
||||
|
||||
<LI>RakNet does not assume the internet is reliable. RakNet will gracefully handle connection problems rather than block, lock-up, or crash.
|
||||
|
||||
<LI>RakNet technology has been successfully used in dozens of games. It's been proven to work.
|
||||
|
||||
<LI>RakNet is easy to use.
|
||||
|
||||
<LI>RakNet is well-documented. Every header file has every class and
|
||||
function documented. There is a Doxygen manual as well as the HTML manual
|
||||
you are looking at.
|
||||
</UL></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> What else can RakNet do for me? </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="10">
|
||||
<tr>
|
||||
<td class="RakNetManualTextBody"><p>Working at the level of byte streams and packets is bandwidth efficient and gives you a great deal of control but is time consuming. RakNet
|
||||
provides many features to make networking easier, including remote function
|
||||
calls, the BitStream class, and automatic object synchronization.<BR>
|
||||
<BR>
|
||||
Most games share a common set of functionality, such as setting player limits, password production, and statistics. RakNet
|
||||
includes all these features and more. If your game needs it you should
|
||||
check to make sure RakNet doesn't have it integrated already. </p>
|
||||
<p class="RakNetManualTextBody">Lastly, RakNet includes programs and services that work in conjunction with your game, such as the <A HREF="http://masterserver2.raknet.com/">master server</A> or real time voice <BR>
|
||||
<BR>
|
||||
Here is a partial list of things you can do "out of the box."<BR>
|
||||
</p>
|
||||
<UL class="RakNetManualTextBody">
|
||||
<LI>Implement low-bandwidth voice communications.
|
||||
|
||||
<LI>Use our <A HREF="http://masterserver2.raknet.com/">master server</A> for players to find games on the internet.
|
||||
|
||||
<LI>Utilize remote function calls, allowing you to call functions on other computers with variable parameters.
|
||||
|
||||
<LI>Get statistics such as ping, packetloss, bytes sent, bytes received, packets sent, packets received, and more.
|
||||
|
||||
<LI>Optional per-packet timestamping so you know with a fair degree of accuracy how long ago an action was performed on another system despite ping fluctuations.
|
||||
|
||||
</UL>
|
||||
Next page: <A HREF="systemoverview.html">System Overview</A> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="systemoverview.html">System Overview</A><BR>
|
||||
<A HREF="detailedimplementation.html">Detailed Implementation</A><BR>
|
||||
<A HREF="tutorial.html">Tutorial</A><BR>
|
||||
<A HREF="compilersetup.html">Compiler Setup</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
43
Help/RakNet/documentation/iocompletionports.html
Normal file
@ -0,0 +1,43 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>IO Completion ports</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNetLogo.jpg" alt="Oculus VR, Inc."><BR><BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">IO Completion ports [Currently Disabled - Do not use]</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
IO completion ports overview
|
||||
<BR><BR>
|
||||
|
||||
<B>IO Completion ports require Windows NT 3.5, 2000, or XP!</B><BR>
|
||||
<BR>
|
||||
IO Completion ports is a method Windows uses to notify and awaken a thread when asynchronous IO is complete. This is more efficient than creating one thread per IO operation and having that thread wait for the operation to complete. Instead, a pool of threads is created (in this case two threads per processor). These pool of threads block on the IO completion port and when an IO operation is complete one thread wakes up and performs another operation. This will benefit servers with hundreds to thousands of players. It does not benefit games with only a few players and in fact may be slower due to Windows overhead.<BR>
|
||||
<BR>
|
||||
RakNet pools the IO completion port worker threads. Therefore, multiple instances of servers and clients on one computer will all share the worker threads. This improves efficiency in cases such as running multiple servers on one machine, or a client and a server on the same machine.
|
||||
<P>Enabling IO completion ports
|
||||
<BR><BR>
|
||||
|
||||
To enable IO completion ports, declare the preprocessor define <B>__USE_IO_COMPLETION_PORTS</B> and rebuild all. To not enable IO completion ports, simply do not define this. Note that the included pre-build DLLs do not use IO completion ports to ensure Windows compatibility. You can however easily build your own by loading the sample project found at \Samples\Project Samples\CreateDLLSampleProject , defining __USE_IO_COMPLETION_PORTS, and building.<BR>
|
||||
<BR>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="useiocompletionports.jpg"><IMG SRC="useiocompletionportssmall.jpg"></A><BR>
|
||||
</TD>
|
||||
<TR ALIGN="CENTER"><TD>
|
||||
<B>Defining __USE_IO_COMPLETION_PORTS in .net 2003</B></TD></TR></TABLE>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
61
Help/RakNet/documentation/ipv6support.html
Normal file
@ -0,0 +1,61 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>IPV6 Support</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92">
|
||||
<img src="spacer.gif" width="8" height="1"><span class="RakNetWhiteHeader">IPV6 support</span></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD>
|
||||
<span class="RakNetBlueHeader">IPV6 addresses
|
||||
</p> and the difference between IPV4.
|
||||
</span>
|
||||
<p>IPV6 is the next-generation of IP address. IPV6 was developed because of all available IPV4 addresses have been allocated. Over time the industry will transition to use IPV6 so it is necessary to support this for future-generation appplications.</p>
|
||||
<p>IPV4 represents IP addresses with 4 bytes, in the notation 127.0.0.1. IPV6 uses 16 bytes, with a notation such as fe80::7c:31f7:fec4:27de. When RAKNET_SUPPORT_IPV6 is set to 1 in RakNetDefines.h, which it is by default, support for IPV6 will be built into RakNet.</p>
|
||||
<p>The loopback address with IPV4 is 127.0.0.1. The loopback address with IPV6 is ::1. The broadcast address with IPV4 is 255.255.255.255. IPV6 does not support broadcast. It does support multicast if you configure your router to do so. There is no default multicast address for IPV6, meaning LANServerDiscovery will not work without manual configuration by the end-user.</p>
|
||||
<p>NAT Punchthrough is not necessary when using IPV6 exclusively. Provided that you know the IP address of the system, you can connect to that system directly even if that system is behind a router.</p>
|
||||
<p>IPV4 sockets / IP addresses cannot connect to IPV6 sockets / IP addresses and vice-versa.</p>
|
||||
<p>It is valid to start two sockets on the same port if one socket is used for IPV4 and the other IPV6, as you can see in the code fragment below.</p>
|
||||
<p><strong>Supporting IPV6</strong></p>
|
||||
<p>This code is from the project ChatExampleServer. It starts two sockets if possible, the second of which supports IPV6. Not all operating systems support IPV6 by default or necessarily at all, so the fallback is necessary.</p>
|
||||
<p class="RakNetCode">RakNet::SocketDescriptor socketDescriptors[2];<br>
|
||||
socketDescriptors[0].port=atoi(portstring);<br>
|
||||
socketDescriptors[0].socketFamily=AF_INET; // Test out IPV4<br>
|
||||
socketDescriptors[1].port=atoi(portstring);<br>
|
||||
socketDescriptors[1].socketFamily=AF_INET6; // Test out IPV6<br>
|
||||
bool b = server->Startup(4, socketDescriptors, 2 )==RakNet::RAKNET_STARTED;<br>
|
||||
server->SetMaximumIncomingConnections(4);<br>
|
||||
if (!b)<br>
|
||||
{<br>
|
||||
printf("Failed to start dual IPV4 and IPV6 ports. Trying IPV4 only.\n");<br>
|
||||
// Try again, but leave out IPV6<br>
|
||||
b = server->Startup(4, socketDescriptors, 1 )==RakNet::RAKNET_STARTED;<br>
|
||||
if (!b)<br>
|
||||
{<br>
|
||||
puts("Server failed to start. Terminating.");<br>
|
||||
exit(1);<br>
|
||||
}<br>
|
||||
}</p>
|
||||
<p class="RakNetManualTextBody">As you can see, the process to enable IPV6 is to set the socketFamily member in the SocketDescriptor structure to AF_INET6. The default is AF_INET, which is to say IPV4.</p>
|
||||
<p class="RakNetManualTextBody">RakNet's console platforms do not support IPV6 at the time of this writing.</p></TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92">
|
||||
<img src="spacer.gif" width="8" height="1"><span class="RakNetWhiteHeader">See Also</span></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><A HREF="index.html">Index</A></p>
|
||||
</TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
58
Help/RakNet/documentation/irrlichtfpsdemo.html
Normal file
@ -0,0 +1,58 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Irrlicht FPS Demo Manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Irrlicht FPS Demo</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Demonstrates peer to peer connectivity in a first person shooter</span><BR>
|
||||
<BR>
|
||||
<IMG SRC="IrrlichtRakNetDemo.jpg"><BR>
|
||||
|
||||
</p>
|
||||
<p>The FPS demo uses the game engine Irrlicht to move actors and bullets around.</p>
|
||||
<p>To run it, download <a href="http://irrlicht.sourceforge.net/">Irrlicht</a>, a free game engine. By default, it is assumed to be installed at C:\irrlicht-1.6<br>
|
||||
</p>
|
||||
<p>In the solution, open Samples / 3D Demos / Irrlicht Demo. Right click and build.</p>
|
||||
<p>Most of the network code is found in RakNetStuff.cpp under DependentExtensions\IrrlichtDemo. For a technical description of how the code was implemented, see readme.txt in that same directory. As the sample is peer to peer, it requires the NAT punchthrough server to be running. The jenkinssoftware.com website provides a free server, pointed to by DEFAULT_NAT_PUNCHTHROUGH_FACILITATOR_IP. If you can't connect, it's likely that the server is down for testing. You can also run your own server, as the code that is running is the sample code found in the NAT punchthrough project.</p>
|
||||
<p><em>The code is located at DependentExtensions\IrrlichtDemo</em></p>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Dependencies</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD>Irrlicht must be installed. It assumes it was installed to c:\irrlicht-1.6. It also requires irrKlang for sound, provided by default.
|
||||
|
||||
<BR>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <p><a href="replicamanager3.html">ReplicaManager3</a><br>
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
</p>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
51
Help/RakNet/documentation/lightweightdatabase.html
Normal file
@ -0,0 +1,51 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Lightweight Database</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">Lightweight Database</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD>
|
||||
<p><strong>--- Depreciated, use <a href="sqlite3plugin.html">SQLite3Plugin</a> instead ---</strong><BR>
|
||||
<br>
|
||||
LightweightDatabaseServer/LightweightDatabaseClient provides a simple way to implement a master game server. <br>
|
||||
A master game server is a server that maintains a list of running game servers. It provides the same functionality as similar commercial utilities, at no extra charge.</p>
|
||||
<p><img src="DirectoryServerListing.jpg" alt="Directory Server Listing" width="512" height="128"><BR>
|
||||
<br>
|
||||
There are just two classes you can use. One for the master game server (LightweightDatabaseServer), and one for the client (LightweightDatabaseClient), which your game should use to talk to the master game server. To include this functionality, just make one instantiation of LightweightDatabaseServer or LightweightDatabaseClient as appropriate.<BR>
|
||||
<BR>
|
||||
Your master game server, (which uses LightweightDatabaseServer) will generally be a console application or a simple windowed application, whose only purpose is to wait for game servers to inform they are available , or to reply to players systems who want to know what game servers are available. <br>
|
||||
LightweightDatabaseServer uses in-memory tables to manage the game servers. Just like in a real database, you can define what fields you want in a table.<br>
|
||||
Check the documentation for LightweightDatabaseServer::AddTable and LightweightDatabaseServer::GetTable<br>
|
||||
Those functions return a table to which you can add columns (fields).<br>
|
||||
<br>
|
||||
It's a good idea to host your master game server on a domain name rather than a specific IP so you can change servers without forcing your players to update. For example, if your game's website is mutantkillerfrogs.com you can code the MasterClient to connect to this domain, which will be resolved to an IP.<BR>
|
||||
<BR>
|
||||
LightweightDatabaseClient is a client that game servers should use to inform the master game server they are available for use. That is done by connecting to the master game server, and adding a new row in master game server's table. Use LightweightDatabaseClient::UpdateRow for that.<br>
|
||||
<br>
|
||||
Note you'll also use LightweightDatabaseClient for the player system to connect to the master game server, but just for queries to find available game servers. <br>
|
||||
<br>
|
||||
See <em>\Samples\LightweightDatabase</em> for full details on how to use those classes. <BR>
|
||||
</p></TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><A HREF="index.html">Index</A><BR>
|
||||
<A HREF="natpunchthrough.html">NAT Punch-through</A><BR>
|
||||
<a href="sqlite3plugin.html">SQLite3Plugin</a><BR>
|
||||
</p></TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
108
Help/RakNet/documentation/lobby.html
Normal file
@ -0,0 +1,108 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>LobbyServer and LobbyClient manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Lobby Server</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Datbase support friends, rooms, emails, ranking, and more</span><BR>
|
||||
<BR>
|
||||
|
||||
The lobby server is a plugin that provides <A HREF="http://www.postgresql.org/">PostgreSQL</A> database driven functionality for persistent game data and matchmaking. The lobby server itself does not require significant user interaction - instead, commands are carried out on via the LobbyClient_PC class.</p>
|
||||
<p>The Lobby Server is split into two classes. <strong>LobbyServer</strong> itself solely provides networking functionality, calling interfaces to a generic database via virtual functions.<strong>LobbyServerPostgreSQL</strong>, found at DependentExtensions\Lobby\LobbyServer_PostgreSQL\LobbyServer_PostgreSQL.h is an implementation of <strong>LobbyServer</strong> that uses PostgreSQL to power the database.</p>
|
||||
<p>The basic class has functions to connect to the database, and create and destroy the basic required tables. The sample found at Samples/LobbyServerTest/LobbyServerTest.cpp, in the project LobbyServer, demonstrates this fairly clearly.</p>
|
||||
<p>One additional requirement is the use of the <strong>Functor</strong> class. A functor is a class in RakNet that implements a specific unit of functionality that is run asynchronously in a <strong>FunctionThread</strong>, another utility class that is part of RakNet. For the most part you don't have to care about this - however, there is one functor you do have to care about, which is the one to add new titles (games/applications) to the database.</p>
|
||||
<p>How to do this is illustrated in the sample</p>
|
||||
<p class="RakNetCode">/// This functor asynchronously adds a title to the database. Full sample in LobbyDB_PostgreSQLTest<br>
|
||||
AddTitle_PostgreSQLImpl *functor = AddTitle_PostgreSQLImpl::Alloc();<br>
|
||||
printf("Adds a title to the database\n");<br>
|
||||
printf("Enter title name: ");<br>
|
||||
gets(inputStr);<br>
|
||||
if (inputStr[0]==0) strcpy(inputStr, "Hangman EXTREME!");<br>
|
||||
functor->titleName = inputStr;<br>
|
||||
printf("Enter title password (binary): ");<br>
|
||||
gets(inputStr);<br>
|
||||
if (inputStr[0]==0) strcpy(inputStr, "SECRET_PER_GAME_LOGIN_PW_PREVIOUSLY_SETUP_ON_THE_DB");<br>
|
||||
functor->titlePassword = AddTitle_PostgreSQLImpl::AllocBytes((int) strlen(inputStr));<br>
|
||||
functor->titlePasswordLength = (int) strlen(inputStr);<br>
|
||||
memcpy(functor->titlePassword, inputStr, functor->titlePasswordLength);<br>
|
||||
functor->allowClientAccountCreation=true;<br>
|
||||
functor->lobbyIsGameIndependent=true;<br>
|
||||
functor->defaultAllowUpdateHandle=true;<br>
|
||||
functor->defaultAllowUpdateCCInfo=true;<br>
|
||||
functor->defaultAllowUpdateAccountNumber=true;<br>
|
||||
functor->defaultAllowUpdateAdminLevel=true;<br>
|
||||
functor->defaultAllowUpdateAccountBalance=true;<br>
|
||||
functor->defaultAllowClientsUploadActionHistory=true;<br>
|
||||
/// Puts this functor on the processing queue. It will process sometime later in a thread.<br>
|
||||
/// See projects LobbyDB_PostgreSQLTest, TitleValidationDB_PostgreSQLTest, RankingServerDBTest for a complete demo of these and other functors<br>
|
||||
lobbyServer.PushFunctor(functor);</p>
|
||||
<p>This adds a title to the database with various properties indicating what types of operations are allowed for this title. See the class declaration AddTitle_Data in DependentExtensions\Lobby\TitleValidationDBSpec.h for a complete explanation of each parameter. Many other functors are available to perform various database operations. The directories found at DependentExtensions/*_PostgreRepository contain these implementations, while DependentExtensions\Lobby\*DBSpec.h contain the data members and documentation for this functionality. Test applications and demos for the various functors can be found in the projects TitleValidationDB_PostgreSQLTest, RankingServerDB_PostgreSQLTest, and LobbyDB_PostgreSQLTest</p>
|
||||
<p>See LobbyServerTest for a console application that will run the LobbyServer.</p>
|
||||
<p><strong>Required files (using <a href="http://www.postgresql.org/">PostgreSQL</a>):</strong></p>
|
||||
<ul>
|
||||
<li>All source files in DependentExtensions\Lobby that do not start with LobbyClient</li>
|
||||
<li>All source files in DependentExtensions\Lobby\LobbyDB_PostgreRepository</li>
|
||||
<li>All source files in DependentExtensions\Lobby\LobbyServer_PostgreSQL</li>
|
||||
<li>All source files in DependentExtensions\Lobby\RankingServerDB_PostgreRepository</li>
|
||||
<li>All source files in DependentExtensions\Lobby\TitleValidationDB_PostgreRepository</li>
|
||||
<li>All source files in DependentExtensions\PostgreSQLInterface</li>
|
||||
<li>All source files in Samples\LobbyServerTest, should you want to use the default console application.</li>
|
||||
</ul>
|
||||
<p><strong>Dependencies (using <a href="http://www.postgresql.org/">PostgreSQL</a>):</strong></p>
|
||||
<p>PostgreSQL 8.2 or newer, installed at C:\Program Files\PostgreSQL\8.2. Change the project property paths should your installation directory be different. Do not forget to check development tools in the PostgreSQL installer or the headers and libs will not be installed.</p>
|
||||
<p> </p>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Lobby Client (PC)</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">User interface to the database</span><BR>
|
||||
</p>
|
||||
<p><strong>Quick start:</strong></p>
|
||||
<ol>
|
||||
<li>Attach the plugin to an instance of RakPeerInterface, and connect to the server.</li>
|
||||
<li>Call SetCallbackInterface() with a derived implementation of LobbyClientInterfaceCB. The general design of the system is that all calls are asynchronous, so each call will return its results (success or failure) to your registered callback.</li>
|
||||
<li> If you do not already have an account, call RegisterAccount to create a user account on the lobby. Wait for LobbyClientInterfaceCB::RegisterAccount_Result() to see if the query was successful. One possible failure is that the name is already in use, or disallowed (swear word).</li>
|
||||
<li>Call SetTitleLoginId() with information identifying what title you are playing (can be done later if multiple games are allowed per lobby). This should have been hardcoded into the application, returned when the title was added to the server (as documented above).</li>
|
||||
<li>Call Login() with the account you just created (or previously had stored). Wait for LobbyClientInterfaceCB::Login_Result() to indicate success. If you have friends, they should get LobbyClientInterfaceCB::FriendStatus_Notify() calls that you are online.</li>
|
||||
<li>Use DownloadRooms() to get a list of all rooms, based on search filters, followed by JoinRoom(), SetReadyToPlayStatus(), and StartGame(). Or use QuickMatch() to automatically start a game with a given number of players.</li>
|
||||
<li>Once the game starts, you will get LobbyClientInterfaceCB::StartGame_Notify(). This will give you the IP addresses of all players, participants, who the moderator is, user handles, and other information relevant to playing the game. At this point you can disconnect from the lobby. If you do not, you are automatically sent back to the main lobby (outside of any room).</li>
|
||||
</ol>
|
||||
<p>For a complete list of functions, with documented parameters, see DependentExtensions\Lobby\LobbyClientPC.h. </p>
|
||||
<p><strong>Required files</strong></p>
|
||||
<ul>
|
||||
<li>All source files in DependentExtensions\Lobby, except for LobbyServer.h and LobbyServer.cpp</li>
|
||||
<li>All source files in Samples\LobbyClientTest, should you want to use the default console application as a framework to base your own GUI implementation on.</li>
|
||||
</ul>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <p><A HREF="index.html">Index</A><BR>
|
||||
<a href="steamlobby.html">SteamLobby</a></p>
|
||||
<p> </p></TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/makedll.jpg
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
Help/RakNet/documentation/makedllsmall.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
68
Help/RakNet/documentation/marmalade.html
Normal file
@ -0,0 +1,68 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Marmalade Support</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92">
|
||||
<img src="spacer.gif" width="8" height="1"><span class="RakNetWhiteHeader">Marmalade support</span></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD>
|
||||
<span class="RakNetBlueHeader">How to integrate with the Marmalade SDK
|
||||
</span>
|
||||
<p><a href="http://www.madewithmarmalade.com/">Marmalade</a> is a SDK that enables you to write games for the IOS and Android using Native C++. It is not a game engine, although it includes graphic libraries and other tools. As Marmalade can compile Native C++, it can compile RakNet and therefore enable you to use RakNet on those platforms in a consistent way.</p>
|
||||
<p><strong>Step 1 - Download Marmalde:</strong></p>
|
||||
<p><a href="http://www.madewithmarmalade.com/downloads">Download</a> and install Marmalade Beta 5.1 or later. This requires registration and other steps with Marmalade.</p>
|
||||
<p><strong>Step 2 - Create RakNet solution:</strong></p>
|
||||
<p>Assuming you have RakNet downloaded, go to DependentExtensions\Marmalade and double click RakNet.mkb. If Marmalade is installed correctly, this will create a directory build_raknet_vc9 or similar. If necessary to add or remote RakNet source files, edit in a text editor the .mkb and .mkf files where the RakNet source files are listed and double click the .mkb again.</p>
|
||||
<p><strong>Step 3 - Build RakNet library:</strong></p>
|
||||
<p>Find the .sln solution file in the directory created in step 2. Open it, and build for all platforms you care about. Build / batch build / select all / build will do this as well. Assuming this worked, you will now have object files created in a directory such as DependentExtensions\Marmalade\build_raknet_vc9\Debug_RakNet_vc9_x86</p>
|
||||
<p><strong>Step 4 - Link RakNet to your application:</strong></p>
|
||||
<p>Add these two lines to your application .mkb file</p>
|
||||
<p>option module_path="../../DependentExtensions/Marmalade"<br>
|
||||
subproject RakNet</p>
|
||||
<p>The path under option module_path should modified to point to wherever you installed RakNet. There is an example of this under Samples\Marmalade . After doing so you will need to double click the .mkb file to regenerate your project solution.</p>
|
||||
<p>If, upon building RakNet, you get a build error "unresolved external symbol _strtoull ..." then you need to either update Marmalade to a newer version, or comment out the last strtoull in RakNetGUID::FromString in RakNetTypes.h, then build step 3 again.</p>
|
||||
|
||||
<p><strong>Step 5 - Fix allocator:</strong></p>
|
||||
The Marmalade bucket system is not threadsafe. Be sure you have this code in main()
|
||||
<pre>
|
||||
#include "RakMemoryOverride.h"
|
||||
|
||||
void* MarmaladeMalloc(size_t size)
|
||||
{
|
||||
return s3eMallocBase(size);
|
||||
}
|
||||
void* MarmaladeRealloc(void *p, size_t size)
|
||||
{
|
||||
return s3eReallocBase(p, size);
|
||||
}
|
||||
void MarmaladeFree(void *p)
|
||||
{
|
||||
s3eFreeBase(p);
|
||||
}
|
||||
SetMalloc(MarmaladeMalloc);
|
||||
SetRealloc(MarmaladeRealloc);
|
||||
SetFree(MarmaladeFree);
|
||||
</pre>
|
||||
</TD>
|
||||
</TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92">
|
||||
<img src="spacer.gif" width="8" height="1"><span class="RakNetWhiteHeader">See Also</span></td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<p><A HREF="index.html">Index</A></p>
|
||||
</TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
42
Help/RakNet/documentation/masterserver.html
Normal file
@ -0,0 +1,42 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Master Server</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNetLogo.jpg" alt="Oculus VR, Inc."><BR><BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">Master Server</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
<B>Deprecated, see <A HREF="http://masterserver2.raknet.com/">Master Server 2</A></B>
|
||||
Description of the provided master server
|
||||
<BR><BR>
|
||||
|
||||
A master game server is a server that maintains a list of running game servers. It provides the same functionality as Gamespy minus the limited sorting features they provide but for thousands of $$$ less. It's almost required these days because otherwise your players have no way to find other active games to connect to.<BR>
|
||||
<BR>
|
||||
This is the sample implementation of a master game server using RakNet. There are many features you may wish to add on your own as this is just a shell.<BR>
|
||||
<BR>
|
||||
The code is class-based, one class for the master server and another for the master client, which your game should use to talk to the master server. To include this functionality, just make one instantiation of MasterServer or MasterClient as appropriate.<BR>
|
||||
<BR>
|
||||
MasterServer will generally be a console application or a simple windowed application. To run it, just call Initialize once, then Update once per frame. You can also derive and implement OnModifiedPacket if you want. MasterServerMain contains test code which is an excellent overview of the master server's capabilities. It's a good idea to host this on a domain name rather than a specific IP so you can change servers without forcing your players to update. For example, if your game's website is mutantkillerfrogs.com you can code the MasterClient to connect to this domain, which will be resolved to an IP.<BR>
|
||||
<BR>
|
||||
MasterClient is a client that game servers should include and manage. It would be a good idea to connect to a domain name rather than a specific IP (see above)<BR>
|
||||
<BR>
|
||||
See <B>MasterClient.h</B>, <B>MasterServer.h</B>, and <B>MasterCommon.h</B> for full details on what the master server and master client can do.
|
||||
<BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="natpunchthrough.html">NAT Punch-through</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
112
Help/RakNet/documentation/memorysynchronizer.html
Normal file
@ -0,0 +1,112 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Memory Synchronizer</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNetLogo.jpg" alt="Oculus VR, Inc."><BR><BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">Memory Synchronizer Implementation</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
Memory Synchronizer Overview
|
||||
<BR><BR>
|
||||
|
||||
|
||||
The memory synchronizer is an implementation of the message handler interface that scans memory for changes, serializes the changes, and sends it to specified systems. This is a more advanced implementation than in the DistribtedNetworkObject class.<BR>
|
||||
<UL>
|
||||
<LI>Can work with any topology, not just client/server.
|
||||
<LI>Can specify target systems globally or per-data element, with per-system synchronization
|
||||
<LI>Strings identify common pointers, rather than relying on the user to provide enumerations.
|
||||
<LI>Can use all send parameters to send updates.
|
||||
<LI>Can include timestamps with updates.
|
||||
</UL>
|
||||
<BR>
|
||||
|
||||
|
||||
Adding and removing participants is optional. Passing UNASSIGNED_PLAYER_ID to either means all connected systems. Synchronizations will only be sent to and accepted by systems that are in the participant list. These functions are valid to call at any time.<BR>
|
||||
|
||||
|
||||
|
||||
void AddParticipant(PlayerID playerId);<BR>
|
||||
void RemoveParticipant(PlayerID playerId);<BR>
|
||||
|
||||
<BR>
|
||||
|
||||
|
||||
SynchronizeMemory associates the pointer memory of size memorySize (in bytes) with a string identifier, or a class that implements MemSynchSpec (see below). Pass 0 for either memory or memorySpec, since only one of these parameters is allowed. stringId must be a unique identifier for this memory block. If you have instantiated objects you either have to think of a scheme to provide a unique ID for each instance or else you can derive from NetworkIDGenerator and pass the value to optionalInstanceID, which will concatenate that value to the string for you.<BR>
|
||||
Priority, reliability, and ordering channel are equivalent to the parameters in the RakNet send call and are used in that capacity.<BR>
|
||||
sendUpdates and receiveUpdates specify whether we scan for and send updates to other systems and whether we accept updates from other systems. Generally one system would send updates and all other systems receive updates for a particular memory block.<BR>
|
||||
|
||||
void SynchronizeMemory(const char *stringId, int maxUpdateFrequencyMS, PacketPriority priority, PacketReliability reliability, char orderingChannel, void *memory, int memorySize, MemSynchSpec *memorySpec, bool sendUpdates, bool receiveUpdates, ObjectID optionalInstanceId=UNASSIGNED_OBJECT_ID);<BR>
|
||||
|
||||
<BR>
|
||||
UnsynchronizeMemory stops synchronization of a memory block. Pass a value for either memory or memorySpec, and 0 for the unused parameter.<BR>
|
||||
|
||||
|
||||
void UnsynchronizeMemory(void *memory, MemSynchSpec *memorySpec);<BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">MemSynchSpec class</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
Custom memory synchronization per data element
|
||||
<BR><BR>
|
||||
|
||||
|
||||
The class interface <I>MemSynchSpec</I> is used by the MemorySynchronizer implementation to provide the user with greater control over how and when memory elements are synchronized. To use, pass a pointer to an implementation of MemSynchSpec to the associated parameter in SynchronizeMemory and UnsynchronizeMemory.
|
||||
|
||||
|
||||
<BR>
|
||||
You are supposed to serialize your networked data elements into the provided BitStream using the BitStream Write functions. lastSentValue and lastSendTime are provided in case you want to use them for optimization purposes.<BR>
|
||||
|
||||
virtual void Serialize(RakNet::BitStream *bitstream, MemSynchSpec *lastSentValue, unsigned long lastSendTime)=0;<BR>
|
||||
<BR>
|
||||
You are supposed to deserialize the data you serialized in the Serialize call. You can write the data to your networked memory directly, or elsewhere if you wish to interpolate to new values. timePacketSent will be a valid timestamped value (relative to your system) if IncludeTimestamp returns true.<BR>
|
||||
|
||||
virtual void Deserialize(RakNet::BitStream *bitstream, unsigned int timePacketSent)=0;<BR>
|
||||
<BR>
|
||||
This is called when RakNet needs to make a copy of your networked data. You should allocate a copy of the class, copy your data to that class, and return the pointer.<BR>
|
||||
|
||||
virtual MemSynchSpec * MakeSynchronizedDataCopy(void)=0;<BR>
|
||||
<BR>
|
||||
This is called when RakNet needs to write the last value it sent out. You should overwrite your networked data with the values held by the pointer. The pointer points to the user data that is synchronized, while the class called is the copy.<BR>
|
||||
|
||||
virtual void CopySynchronizedDataFrom(MemSynchSpec *source)=0;<BR>
|
||||
<BR>
|
||||
RakNet no longer needs this copy of data. You can delete the class immediately if you wish via a call to <I>delete this;</I><BR>
|
||||
|
||||
virtual Release(void)=0;<BR>
|
||||
<BR>
|
||||
This is an all-purpose update function telling RakNet if a given copy of data is different, different enough to send, and worth sending to a particular player. You have total control over whether the data gets sent or not - however for RakNet to properly record the last copy that was sent to each system IsUnifiedMemory must return true.<BR>
|
||||
|
||||
virtual bool ShouldSendUpdate(PlayerID destinationSystem, MemSynchSpec *lastSentValue, unsigned long lastSendTime)=0;<BR>
|
||||
<BR>
|
||||
If you return true, the same value will be sent to all remote systems at the same time. This is useful for data that is always serialized to everyone the same way regardless of context, such as the current game score. If true, the same copy of the last sent data is used for all systems which saves memory and speed. You should return false if different destination systems will have different values sent to them or at different times. This should be used for contextual data, such as position updates which may not be sent to everyone, or may be sent more or less frequently. This will store an individual copy of the last sent data per remote system.<BR>
|
||||
|
||||
virtual bool IsUnifiedMemory(void)=0;<BR>
|
||||
<BR>
|
||||
Return true if you want a valid time value sent to Deserialize. Only set to true if you need it as bandwidth will be wasted otherwise.<BR>
|
||||
|
||||
virtual bool IncludeTimestamp(void)=0;<BR>
|
||||
<BR>
|
||||
|
||||
For a usage example, see the sample <I>Samples\Code Samples\MemorySynchronization</I>.
|
||||
|
||||
</TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="distributednetworkobject.html">Distributed Network Object</A><BR>
|
||||
<A HREF="messagehandler.html">Message Handler Interface</A><BR>
|
||||
<A HREF="fullyconnectedmesh.html">Fully Connected Mesh</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
66
Help/RakNet/documentation/messagefilter.html
Normal file
@ -0,0 +1,66 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>MessageFilter manual</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> Message Filter Overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD><p><span class="RakNetBlueHeader">Limit incoming messages by category</span> <BR></p>
|
||||
<p>With client/server topologies, you do not usually want any system to send any message. For example, perhaps only the server can send kill messages. Or perhaps you want to segment players into stages, where players who have logged on but not yet provided their password cannot yet send game messages. The message filter is designed to deal with these situations automatically.</p>
|
||||
<p>The MessageFilter plugin defines categories of users by 'filterSet' which is just a numerical identifier supplied by the user. For example, you may have one filter set for newly connected systems, and another for authenticated systems. For each filter set you can</p>
|
||||
<ol>
|
||||
<li>Automatically add new connections</li>
|
||||
<li>Allow RPC calls</li>
|
||||
<li>Limit what messages, or ranges of messages, can be received, and what actions to take if this condition is violated (kick/ban/notify)</li>
|
||||
<li>Delete them</li>
|
||||
</ol>
|
||||
<p><strong>Example:</strong></p>
|
||||
<p class="RakNetCode">messageFilter.SetAutoAddNewConnectionsToFilter(0);<br>
|
||||
messageFilter.SetAllowMessageID(true, ID_USER_PACKET_ENUM, ID_USER_PACKET_ENUM, 0);<br>
|
||||
messageFilter.SetAllowMessageID(true, ID_USER_PACKET_ENUM+1, ID_USER_PACKET_ENUM+1, 1);</p>
|
||||
<p>This setup would automatically add all new connections to filter set 0, and only allow the message ID_USER_PACKET_ENUM to arrive. It would also create a new filter set, with the filterSet id 1, that only allowed ID_USER_PACKET_ENUM+1 to arrive.</p>
|
||||
<p><strong>Messages that are always allowed (filtering them has no effect):</strong></p>
|
||||
<p class="RakNetCode">ID_CONNECTION_LOST<br>
|
||||
ID_DISCONNECTION_NOTIFICATION<br>
|
||||
ID_NEW_INCOMING_CONNECTION<br>
|
||||
ID_CONNECTION_REQUEST_ACCEPTED<br>
|
||||
ID_CONNECTION_ATTEMPT_FAILED<br>
|
||||
ID_NO_FREE_INCOMING_CONNECTIONS<br>
|
||||
ID_RSA_PUBLIC_KEY_MISMATCH<br>
|
||||
ID_CONNECTION_BANNED<br>
|
||||
ID_INVALID_PASSWORD<br>
|
||||
ID_MODIFIED_PACKET<br>
|
||||
ID_PONG<br>
|
||||
ID_ALREADY_CONNECTED<br>
|
||||
ID_ADVERTISE_SYSTEM<br>
|
||||
ID_REMOTE_DISCONNECTION_NOTIFICATION<br>
|
||||
ID_REMOTE_CONNECTION_LOST<br>
|
||||
ID_REMOTE_NEW_INCOMING_CONNECTION<br>
|
||||
ID_DOWNLOAD_PROGRESS</p>
|
||||
<p>See <em>Samples/MessageFilter</em> for a complete sample. See MessageFilter.h for a complete list of all documented functions and parameters.</p>
|
||||
|
||||
</TR>
|
||||
</TABLE>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <A HREF="index.html">Index</A><BR> </TD>
|
||||
</TR>
|
||||
</TABLE></TD>
|
||||
</TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
72
Help/RakNet/documentation/messagehandler.html
Normal file
@ -0,0 +1,72 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>Message Handler Interface</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<img src="RakNetLogo.jpg" alt="Oculus VR, Inc."><BR><BR>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">Message Handler</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
Message Handler Overview
|
||||
<BR><BR>
|
||||
|
||||
The message handler interface <I>MessageHandlerInterface.h</I> is a class interface that works with RakNet to provide automatic functionality. To use it, derive from the base class and implement the pure virtual functions. Then register your class by calling RakPeer.<BR>
|
||||
<BR>
|
||||
OnUpdate is called everytime Receive is called through RakNet<BR>
|
||||
|
||||
virtual void OnUpdate(RakPeerInterface *peer)=0;<BR>
|
||||
|
||||
<BR>
|
||||
|
||||
OnReceive is called everytime a packet goes through RakNet. You can handle it or not as you want. Return true to absorb the packet, false to allow the packet to propagate to another handler, or to the game. Generally you will return false unless the packet type is specific to your handler.<BR>
|
||||
|
||||
virtual bool OnReceive(RakPeerInterface *peer, Packet *packet)=0;<BR>
|
||||
|
||||
<BR>
|
||||
|
||||
Called when Disconnect is called for RakNet.<BR>
|
||||
|
||||
virtual void OnDisconnect(RakPeerInterface *peer)=0;<BR>
|
||||
|
||||
<BR>
|
||||
|
||||
PropagateToGame tells RakPeer if a particular packet should be sent to the game or not. Return true unless the packet type is custom for your handler.<BR>
|
||||
|
||||
virtual bool PropagateToGame(Packet *packet) const;<BR>
|
||||
|
||||
<BR>
|
||||
|
||||
|
||||
</TD></TR></TABLE>
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">Message Handler Implementations</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
Fully Connected Mesh<BR><BR>
|
||||
|
||||
The <A HREF="fullyconnectedmesh.html">fully connected mesh</A> intercepts connection notifications and automatically connects to other known peers.
|
||||
|
||||
<BR><BR>
|
||||
Memory Synchronizer<BR><BR>
|
||||
|
||||
The <A HREF="memorysynchronizer.html">memory synchronizer</A> updates in OnUpdate, checking against registered memory elements, and transmits changes to those memory elements.
|
||||
|
||||
|
||||
|
||||
</TD></TR></TABLE>
|
||||
<table width="100%" border="0"><tr><td bgcolor="#6699CC">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td></tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD>
|
||||
|
||||
<A HREF="index.html">Index</A><BR>
|
||||
<A HREF="fullyconnectedmesh.html">Fully Connected Mesh</A><BR>
|
||||
<A HREF="memorysynchronizer.html">Memory Synchronizer</A><BR>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
304
Help/RakNet/documentation/multiplayergamecomponents.html
Normal file
@ -0,0 +1,304 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head><title>Components of a multiplayer game</title>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</head>
|
||||
<body leftmargin="0" topmargin="0" style="background-color: rgb(255, 255, 255);" alink="#003399" link="#003399" marginheight="0" marginwidth="0" vlink="#003399">
|
||||
<img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"><br>
|
||||
<br>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" height="1" width="8">Components of a multiplayer game</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Major systems that go into the making of a multiplayer game</span><br>
|
||||
<br>
|
||||
In the early days of gaming all you had was an IP address and a download. These days you have integration into 3rd party systems such as Steam, patching, voice chat, multiple game modes, cross-platform play, and more. I list some major systems by category below, along with the options available for solving these problems and pros and cons of each system. This page applies to any multiplayer game, not just those using RakNet, although RakNet specific solutions are listed at the end of each section.</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">Discovering other systems</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<p class="RakNetBlueHeader">Direct IP entry</p>
|
||||
<p> The oldest and simplest method, this involves typing in the IP address of the user you want to connect to. The remote user can go to a page such as <a href="http://www.whatismyip.com/">http://www.whatismyip.com/</a> to get their IP. They can then communicate this IP to you through other communication channels such as email or instant messenger. If the remote user is behind a router, they will have to open the appropriate ports on the firewall to accept incoming connections. If they are behind a firewall, they will have to configure the firewall as well.</p>
|
||||
<p class="RakNetBlueHeader">DNS entry</p>
|
||||
<p>Applicable to client/server games where you control the servers, you can have a DNS entry point to the server. Connecting clients can then connect to the DNS entry rather than typing in a fixed IP address. This is useful if the IP address of the server may change. This service is available for free through <a href="http://www.dyndns.com/">http://www.dyndns.com/</a>. RakNet provides a class to update DynDNS as well, found in Source/DynDNS.h and Source/DynDNS.cpp. This is usually used for client/server games where you host your own server.</p>
|
||||
<p><span class="RakNetBlueHeader">LAN Broadcast</span></p>
|
||||
<p>If the remote computer is on the same LAN, you can discover this computer by sending a datagram to the IP address 255.255.255.255 provided that the remote computer is listening on the port you send on, and will send a datagram in response. RakNet provides this through the Ping() and AdvertiseSystem() functions.</p>
|
||||
<p class="RakNetBlueHeader">Lobby server</p>
|
||||
<p>Consoles such as the XBOX 360 and the PS3, and services such as Steam on the PC offer a lobby system. The lobby system also typically provides services such as DLC, achievements, friends, and rooms. RakNet provides the SteamLobby plugin, and rough equivalents on the XBOX and PS3 with their respective lobby classes. This is usually used for peer-to-peer games, where players have some significant interaction between each other before the game starts.</p>
|
||||
<p class="RakNetBlueHeader">Master server</p>
|
||||
<p>Similar to the rooms server, a server maintains a list of running games. Typically, when an end-user starts a game, they upload statistics about the game to a master server, which allows queries on uploaded games. We offer this service for free at with our <a href="masterserver2.html">hosted master server</a>.</p>
|
||||
<p></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><strong><span class="RakNetWhiteHeader"> Network topology</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Client/Server where you host the servers
|
||||
</span><br>
|
||||
<br>
|
||||
Usually used for massively multiplayer games, you will host one or more servers that contain the game world(s) provided to the players.This is also the most expensive solution since you have to have dedicated servers with guaranteed uptime and pay for bandwidth yourself. </p>
|
||||
<p><span class="RakNetBlueHeader">Client/Server where users host the servers</span><br>
|
||||
<br>
|
||||
This is used for games where if the server drops, so does the entire game session. It is nonetheless common because it has the following advantages:</p>
|
||||
<ol>
|
||||
<li>Easier to program because a single system can resolve contention between clients</li>
|
||||
<li>Can support a large number of players, because dedicated servers with a high bandwidth capacity can host</li>
|
||||
<li>Better for long-term gameplay sessions because a dedicated server is less likely to drop or cause problems</li>
|
||||
<li>Dedicated servers can be spread throughout the world, resulting in low-ping sessions</li>
|
||||
</ol>
|
||||
It is also possible to program client/server using an end-user as a host, but then you get all of the disadvantages of client/server without none of the advantages except ease of programming.
|
||||
<p><span class="RakNetBlueHeader">Peer to peer</span><br>
|
||||
<br>
|
||||
This is used for more informal game sessions without dedicated servers. It is the most common topology for console games since consoles do not allow dedicated servers. The only advantage is a dedicated host is not necessary. The disadvantages are:</p>
|
||||
<ol>
|
||||
<li>Still need a server of some sort to find running game sessions</li>
|
||||
<li>Have to punch through routers</li>
|
||||
<li>Have to deal with host migration</li>
|
||||
<li>Have to deal with contention. If two peers do the same mutually exclusive operation at the same time, how to resolve?</li>
|
||||
</ol>
|
||||
<p>RakNet provides plugins to make peer to peer programming easier: <a href="natpunchthrough.html">NATPunchthrough</a>, <a href="readyevent.html">ReadyEvent</a>, <a href="connectiongraph.html">ConnectionGraph2</a>, <a href="fullyconnectedmesh2.html">FullyConnectedMesh2</a>, and <a href="teambalancer.html">TeamBalancer</a>. See the project ComprehensivePCGame in the RakNet solution for an example where all these plugins are combined together.<br>
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><strong><span class="RakNetWhiteHeader"> Game and game design changes for networking</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<p><span class="RakNetBlueHeader">Level loading</span><br><BR>
|
||||
Rather than loading all objects in the level as done in single player, objects now need to be categorized according to how they influence networking<BR>
|
||||
<ol>
|
||||
<LI>Objects that still load normally are those that always exist in the level and are not referenced by network code.
|
||||
<LI>Objects may still load normally with the level, but need to be referred to by network code. For example, event triggers. These objects can either be loaded with a NetworkID (64 bit GUID), or the code at load time can gather these types of objects and assign them ids.
|
||||
<LI>Objects may or may not exist on level load need to be dynamically loaded. For example, such as players, spawned weapons, and bullets. Some of these objects should be preloaded during level load, on the assumption that they will eventually be spawned, to avoid runtime harddrive access.
|
||||
</OL>
|
||||
Generally, after level load the game does not start until all players have finished loading. Even on consoles, the disk may be scratched so systems may take a different amount of time to load a level. Before considering level load complete:<BR>
|
||||
<OL>
|
||||
<LI>Transmit selections from other users that affect our load state. For example, what character models the other users picked
|
||||
<LI>Load the level as well as whatever models / textures, etc. are needed based on the other player's choices
|
||||
<LI>Stay on an intermission screen until all other players are also done loading. <a href="readyevent.html">ReadyEvent</a> can be used for this
|
||||
</OL>
|
||||
Midgame joins are the same, except that you skip the intermission screen. However, if the game session ends while you are still loading, you should be able to cancel the load and enter whatever intermission state is shown at game end.
|
||||
<BR>
|
||||
<p><span class="RakNetBlueHeader">Game Objects</span><br>
|
||||
<BR>
|
||||
Objects that are networkable need to implement an interface to support <A HREF="replicamanager3.html">ReplicaManager3</A>:
|
||||
<OL>
|
||||
<LI>Objects must be able to return an identifier for what type of class the object is, for example ENUM_BULLET or "CBullet" for a bullet.
|
||||
<LI>Object must be instantiable given that identifier and initialization data. Sometimes this is done through a class factory.
|
||||
<LI>Objects should implement an interface allowing them to serialize data for construction, destruction, and per-tick serialization
|
||||
<LI>Objects that are deleted when the owning user leaves the game session should support deletion. For example, if a remote user's avatar is deleted, this should not end the game session locally.
|
||||
</OL>
|
||||
Game objects owned by the host or other users may need to support a partial-interactive ghost state where the object is rendered and animated but has typically has physics disabled and does not start triggers. However:<BR>
|
||||
<OL>
|
||||
<LI>Partial-interactive ghost objects may still cause sounds, such as footsteps on glass
|
||||
<LI>Partial-interactive ghost objects may still cause visual effect triggers
|
||||
</OL>
|
||||
Whether an object is in an fully interactive state depends on whether a unique host is needed to resolve conflicts. Objects in the game world need to be categorized correspondingly based on bandwidth and gameplay considerations:<BR>
|
||||
<OL>
|
||||
<LI>Object is only fully interactive on the host, for example triggers that affect gameplay in some way.
|
||||
<LI>Object is fully interactive on all systems, for example a trigger that plays a particle effect
|
||||
<LI>Object is only fully interactive on the system that owns it, for example your own avatar.
|
||||
</OL>
|
||||
<p><span class="RakNetBlueHeader">Host Migration</span><br>
|
||||
<BR>
|
||||
Host migration is needed for peer to peer games, where one system is host. While some platforms offer a system for host migration, we have a cross-platform solution <A HREF="fullyconnectedmesh2.html">FullyConnectedMesh2</A>
|
||||
<p><span class="RakNetBlueHeader">Users</span><br>
|
||||
<BR>
|
||||
In-game, a user class needs to be implemented, containing information such as score, name, user id, achievements, etc. Some games may support multiple users on the same system, for example split-screen play
|
||||
<p><span class="RakNetBlueHeader">Remote Systems</span><br>
|
||||
<BR>
|
||||
A Remote system class may need to be implemented, containing information such as level load state or a trust metric for cheat detection. If the game only supports one user per system, this is sometimes rolled into the User class.
|
||||
<BR>
|
||||
<br>
|
||||
<span class="RakNetBlueHeader">Teams</span><br>
|
||||
<BR>
|
||||
If the game supports teams, this needs to be serialized including players, team score, etc. Team management is supported with the <A HREF="teammanager.html">TeamManager</A> plugin. It supports any network topology, offline teams, and advanced features such as switching requested teams.<BR>
|
||||
<BR>
|
||||
<span class="RakNetBlueHeader">World / Game State</span><br>
|
||||
<BR>
|
||||
Not all game information is necessarily held by game objects, for example the match countdown. It can be represented using Replica3 as usual, or can be updated directly through network messages.
|
||||
<BR>
|
||||
<p><span class="RakNetBlueHeader">Level End</span><br>
|
||||
<BR>
|
||||
When the host determines level end, the game needs to support the ability to pause gameplay, despawn all players, and show some kind of end-game score screen. During this phase score updates should be paused and other game events should halt. If sesssion statistics are transmitted to a server, it can be done at this time.<BR>
|
||||
<p><span class="RakNetBlueHeader">Spectating / Replay</span><br>
|
||||
<BR>
|
||||
Some games allow you to watch gameplay from the point of view of fixed cameras, other players, or a replay cam after death.
|
||||
<BR>
|
||||
<p><span class="RakNetBlueHeader">Post-Game statistics and UI</span><br>
|
||||
<BR>
|
||||
After a game session, sometimes a series of UI screens are shown after the level has unloaded. After that, the game state may either go back to the game browser screen, or stay in a room with the users you just played with.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><strong><span class="RakNetWhiteHeader"> Patching</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Per-file difference based patching
|
||||
</span><br>
|
||||
<br>
|
||||
The most advanced but time consuming way to patch users is to find the difference between a file the user has and the current version of that file. Under those circumstances the smallest delta can be sent and applied to the file. If the patch fails (for example, an unknown version of the file) the entire file will need to be transmitted. A database of patches will need to be maintained for this solution, as generating the patch at runtime is too time consuming.</p>
|
||||
<p>RakNet provides the <a href="autopatcher.html">AutopatcherServer and AutopatcherClient plugins</a> as a diff based patching system.</p>
|
||||
<p><span class="RakNetBlueHeader">Per-file patching</span><br>
|
||||
<br>
|
||||
A simpler way to patch is to find a list of changed or missing files for a client and to send only those files. One advantage of this system is that it can be used by end-user hosted game servers. For example, if a game server has a map or skins that a connecting client does not, those files can be downloaded before the game starts.</p>
|
||||
<p>RakNet provides the <a href="filelisttransfer.html">FileListTransfer</a> plugin to transfer lists of files, and the <a href="directorydeltatransfer.html">DirectoryDeltaTransfer</a> plugin to transfer lists of changed or missing files.</p>
|
||||
<p><br>
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><strong><span class="RakNetWhiteHeader"> Debugging</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Logging</span><br>
|
||||
<br>
|
||||
Multiplayer games are hard to debug because a bug can be spread between two systems. For example, system A performs an action but system B does not see it, or sees it differently. The bug may be caused by latency, showing up only at certain loads. Performance or other issues may come up as the application scales with more users. While logging can help with all these problems, they are hard to correlate because the system times are different.</p>
|
||||
<p>RakNet provides two logging solutions. The first is called <a href="sqlite3loggerplugin.html">SQLite3LoggerPlugin</a>, and is based on SQLite3 on a hosted server. All logs go to the same server, and are automatically correlated. The logs can be viewed in viewer that supports SQLite although RakNet also provides a free and open source custom viewer called <a href="http://www.raknet.net/echochamber">EchoChamber</a>. Individual game and connectivity messages can be logged per system using the <a href="packetlogger.html">PacketLogger</a> plugin.</p>
|
||||
<p><span class="RakNetBlueHeader">Minidump</span><br>
|
||||
<br>
|
||||
Because crashes can be hard to reproduce, Windows applications can produce <a href="http://msdn.microsoft.com/en-us/library/ms680369%28v=vs.85%29.aspx">minidump</a> files. If you know what version of the code produced the crash, you can debug the crash as if you had a debugger connected at the time.</p>
|
||||
<p>RakNet provides the <a href="crashreporter.html">CrashReporter</a> system to make this easier. It provides additional functionality such as sending emails to the developer in the case of unattended servers.</p>
|
||||
<p><br>
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><strong><span class="RakNetWhiteHeader"> Persistent data</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><span class="RakNetBlueHeader">Persistent user data
|
||||
</span><br>
|
||||
<br>
|
||||
Games that persist data beyond a single session require a system to create user accounts. User accounts can store data such as game statistics, name, and logo. Users can also have friends, form clans, and perform other social tasks. In order to write such a system, a database backend is needed with a persistent sever to store this data. The users should not be able to send arbitrary queries to the database, so the server will need code to form queries based on user inputs.
|
||||
</p>
|
||||
<p>RakNet provides a system called <a href="lobby.html">LobbyServer and LobbyClient</a> to provide this kind of functionality for the PC. Steam, the PS3, and the XBOX already store this on their own backend. For those cases, RakNet uses the same <a href="lobby.html">LobbyClient</a> interface so as to provide a unified interface to all systems.</p>
|
||||
<p><br>
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92"><font color="#ffffff" face="Arial, Helvetica, sans-serif" size="3"><strong><span class="RakNetWhiteHeader"> Security</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p><br>
|
||||
Popular competitive games will draw cheaters. Cheaters can attack the application by</p>
|
||||
<ol>
|
||||
<li>Modifying the EXE to send unauthorized data (sending kill messages)</li>
|
||||
<li>Modifying the EXE to view extra data (seeing through walls)</li>
|
||||
<li>Modifying datagrams in transmit to change data sent</li>
|
||||
<li>Replaying datagrams to simulate login or game events (running bots)</li>
|
||||
<li>Introducing latency to get a competitive advantage</li>
|
||||
</ol>
|
||||
<p>The game should verify all inputs for sanity when possible. This will need to be done even if cheating is not a concern, since latency will also cause unusual inputs.</p>
|
||||
<p>RakNet can automatically protect against attacks #3 and #4 with <a href="secureconnections.html">secure connection</a> support. Solutions already exist for protecting the EXE from modification on the PC. Protecting against latency based cheating just takes smart design decisions, such as not trusting client/peer inputs.</p>
|
||||
<p><br>
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><strong> See Also</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><font class="G10" color="#111122" face="Geneva, Verdana, Arial, Helvetica, sans-serif" size="1"><a href="index.html">Index</a><br>
|
||||
<a href="autopatcher.html">Autopatcher</a><br>
|
||||
<a href="crashreporter.html">CrashReporter</a><br>
|
||||
<a href="replicamanager3.html">ReplicaManager3</a><br>
|
||||
<a href="fullyconnectedmesh2.html">FullyConnectedMesh2</a> <br>
|
||||
<a href="http://masterserver2.raknet.com/">Master Server 2</a> <br>
|
||||
<a href="natpunchthrough.html">NATPunchthrough</a> <br>
|
||||
<a href="packetlogger.html">PacketLogger</a> <br>
|
||||
<a href="RPC3Video.htm">RPC3</a> <br>
|
||||
<a href="teammanager.html">TeamManager</a><br>
|
||||
<a href="sqlite3loggerplugin.html">SQLite3LoggerPlugin</a></p>
|
||||
<p><a href="packetlogger.html"></a><br>
|
||||
</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body></html>
|
||||
BIN
Help/RakNet/documentation/multithreadeddebug.jpg
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
Help/RakNet/documentation/multithreadeddebugsmall.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
6
Help/RakNet/documentation/natpunchpanel1.html
Normal file
@ -0,0 +1,6 @@
|
||||
<HTML>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="natpunchpanel2.html"><IMG SRC="natpunchpanel1.jpg"></A></TD></TR>
|
||||
<TR><TD><CENTER><B>Page 1/7</B><BR>Click image for next page</CENTER></TD></TR>
|
||||
</TABLE>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/natpunchpanel1.jpg
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
Help/RakNet/documentation/natpunchpanel1small.jpg
Normal file
|
After Width: | Height: | Size: 29 KiB |
6
Help/RakNet/documentation/natpunchpanel2.html
Normal file
@ -0,0 +1,6 @@
|
||||
<HTML>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="natpunchpanel3.html"><IMG SRC="natpunchpanel2.jpg"></A></TD></TR>
|
||||
<TR><TD><CENTER><B>Page 2/7</B><BR>Click image for next page</CENTER></TD></TR>
|
||||
</TABLE>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/natpunchpanel2.jpg
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
Help/RakNet/documentation/natpunchpanel2small.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
6
Help/RakNet/documentation/natpunchpanel3.html
Normal file
@ -0,0 +1,6 @@
|
||||
<HTML>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="natpunchpanel4.html"><IMG SRC="natpunchpanel3.jpg"></A></TD></TR>
|
||||
<TR><TD><CENTER><B>Page 3/7</B><BR>Click image for next page</CENTER></TD></TR>
|
||||
</TABLE>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/natpunchpanel3.jpg
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
Help/RakNet/documentation/natpunchpanel3small.jpg
Normal file
|
After Width: | Height: | Size: 31 KiB |
6
Help/RakNet/documentation/natpunchpanel4.html
Normal file
@ -0,0 +1,6 @@
|
||||
<HTML>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="natpunchpanel5.html"><IMG SRC="natpunchpanel4.jpg"></A></TD></TR>
|
||||
<TR><TD><CENTER><B>Page 4/7</B><BR>Click image for next page</CENTER></TD></TR>
|
||||
</TABLE>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/natpunchpanel4.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
Help/RakNet/documentation/natpunchpanel4small.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
6
Help/RakNet/documentation/natpunchpanel5.html
Normal file
@ -0,0 +1,6 @@
|
||||
<HTML>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="natpunchpanel6.html"><IMG SRC="natpunchpanel5.jpg"></A></TD></TR>
|
||||
<TR><TD><CENTER><B>Page 5/7</B><BR>Click image for next page</CENTER></TD></TR>
|
||||
</TABLE>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/natpunchpanel5.jpg
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
Help/RakNet/documentation/natpunchpanel5small.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
6
Help/RakNet/documentation/natpunchpanel6.html
Normal file
@ -0,0 +1,6 @@
|
||||
<HTML>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="natpunchpanel7.html"><IMG SRC="natpunchpanel6.jpg"></A></TD></TR>
|
||||
<TR><TD><CENTER><B>Page 6/7</B><BR>Click image for next page</CENTER></TD></TR>
|
||||
</TABLE>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/natpunchpanel6.jpg
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
Help/RakNet/documentation/natpunchpanel6small.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
6
Help/RakNet/documentation/natpunchpanel7.html
Normal file
@ -0,0 +1,6 @@
|
||||
<HTML>
|
||||
<TABLE><TR><TD>
|
||||
<A HREF="natpunchpanel1.html"><IMG SRC="natpunchpanel7.jpg"></A></TD></TR>
|
||||
<TR><TD><CENTER><B>Page 7/7</B><BR>Click image for first page</CENTER></TD></TR>
|
||||
</TABLE>
|
||||
</HTML>
|
||||
BIN
Help/RakNet/documentation/natpunchpanel7.jpg
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
Help/RakNet/documentation/natpunchpanel7small.jpg
Normal file
|
After Width: | Height: | Size: 31 KiB |
193
Help/RakNet/documentation/natpunchthrough.html
Normal file
@ -0,0 +1,193 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>NAT Punch-through</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD><BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">NAT Punchthrough overview</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD>
|
||||
|
||||
<A HREF="http://science.webhostinggeeks.com/raknet-nat-punchthrough">Serbo-Croatian translation</A>
|
||||
|
||||
<p><span class="RakNetBlueHeader">What is NAT?</span> <BR>
|
||||
<BR>
|
||||
NAT is short for network address translation. It is used by routers to map addresses behind the router to a single destination address, using different ports. For example, if you have two computers behind a router, but only one ISP, then both computers will use the same IP address, but with different source ports than what the application actually assigned. The router keeps a lookup table of what mappings it provides, so when a remote computer replies it is routed to the correct local computer behind the NAT.</p>
|
||||
<p>The problem with NAT is that remote computers cannot initiate sends to local computers because no mapping yet exists. Therefore, if two computers both behind NAT try to connect, neither will be able to do so. This is a problem with voice communication, peer to peer games, or games where your users host and the host is behind a NAT. In the old days your users would have to go to their router configuration screen and setup a mapping. However, in modern applications users are not usually required to do this, thanks to NatPunchthrough.</p>
|
||||
<p><span class="RakNetBlueHeader">NAT Punchthrough Overview</span></p>
|
||||
<p> The NatPunchthroughClient.cpp plugin requires a user hosted server, not behind NAT, running NatPunchthroughServer.cpp that both clients can connect to. The server will find the external IP address of each client, and tell both clients to connect to that address at the same time. If that fails, each client will attempt to estimate the ports used by the other. If that fails, the process repeats once again, in case later port estimation opened a prior port. If that also fails, the plugin returns ID_NAT_PUNCHTHROUGH_FAILED. </p>
|
||||
<p>Note 1: If you publish through Steam, we also provide <a href="steamlobby.html">SteamLobby</a>, which uses servers hosted by Valve, in which case NATPunchthrough is not necessary.<br>
|
||||
Note 2: NAT Punchthrough is not necessary if exclusively using <a href="ipv6support.html">IPV6</a>.<br>
|
||||
Note 3: If your game is client/server only, you may simply enforce that servers must support UPNP. See <em>DependentExtensions\miniupnpc-1.6.20120410</em>. Most routers support this these days, and assuming UPNP passes, anyone can connect to you.</p>
|
||||
<p><span class="RakNetBlueHeader">NAT Punchthrough Algorithm</span></p>
|
||||
<ol>
|
||||
<li> Peer P1 wants to connect to peer P2, both of whom are connected to a third Non-NAT system, F</li>
|
||||
<li>Peer P1 calls OpenNAT() with the RakNetGUID (unique identifier) of P2 to F.</li>
|
||||
<li>F returns failure if P2 is not connected, or already attempting punchthrough to P1.</li>
|
||||
<li>F remembers busy state of P1 and P2. If either P1 or P2 is busy, the request is pushed to a queue. Otherwise F requests most recently used external port from P1 and P2. P1 and P2 are flagged as busy.</li>
|
||||
<li>If either P1 or P2 do not respond punchthrough fails with ID_NAT_TARGET_UNRESPONSIVE and the busy flag is unset. Otherwise, F sends timestamped connection message to P1 and P2 simultaneously.</li>
|
||||
<li>P1 and P2 act identically at this point. First, they send multiple UDP datagrams to each other's internal LAN addresses. They then try each other's external IP/port as seen by F. Ports are attempted sequentially, up to MAX_PREDICTIVE_PORT_RANGE.</li>
|
||||
<li>If at any point a datagram arrives from the remote peer, we enter state PUNCHING_FIXED_PORT. Datagrams are only sent to that IP/port combination the remainder of the algorithm. If our reply arrives on the remote system, the NAT is considered bidirectional and ID_NAT_PUNCHTHROUGH_SUCCEEDED is returned to the user.</li>
|
||||
<li>When NAT is open, or if we exhaust all ports, P1 and P2 send to F that they are ready for a new punchthrough attempt.</li>
|
||||
</ol>
|
||||
<p>Algorithm effectivness depends on the NAT types involved. It will work with whichever NAT is the most permissive.</p>
|
||||
<p><strong>Full cone NAT</strong>: Accepts any datagrams to a port that has been previously used. Will accept the first datagram from the remote peer.</p>
|
||||
<p><strong>Address-Restricted cone NAT</strong>: Accepts datagrams to a port as long as the datagram source IP address is a system we have already sent to. Will accept the first datagram if both systems send simultaneously. Otherwise, will accept the first datagram after we have sent one datagram.</p>
|
||||
<p><strong>Port-Restricted cone NAT</strong>: Same as address-restricted cone NAT, but we had to send to both the correct remote IP address and correct remote port. The same source address and port to a different destination uses the same mapping.</p>
|
||||
<p><strong>Symmetric NAT</strong>: A different port is chosen for every remote destination. The same source address and port to a different destination uses a different mapping. Since the port will be different, the first external punchthrough attempt will fail. For this to work it requires port-prediction (MAX_PREDICTIVE_PORT_RANGE>1) and that the router chooses ports sequentially.</p>
|
||||
|
||||
<CENTER><B>Success Graph</B>
|
||||
<TABLE BORDER=1>
|
||||
<TR><TD>Router Type</TD><TD><I>Full cone NAT</I></TD><TD><I>Address-Restricted cone NAT</I></TD><TD><I>Port-Restricted cone NAT</I></TD><TD><I>Symmetric NAT</I></TD></TR>
|
||||
<TR><TD><I>Full cone NAT</I></TD><TD>YES</TD><TD>YES</TD><TD>YES</TD><TD>YES</TD></TR>
|
||||
<TR><TD><I>Address-Restricted cone NAT</I></TD><TD>YES</TD><TD>YES</TD><TD>YES</TD><TD>YES</TD></TR>
|
||||
<TR><TD><I>Port-Restricted cone NAT</I></TD><TD>YES</TD><TD>YES</TD>
|
||||
<TD>YES</TD><TD>NO</TD></TR>
|
||||
<TR><TD><I>Symmetric NAT</I></TD><TD>YES</TD><TD>YES</TD><TD>NO</TD><TD>NO</TD></TR>
|
||||
</TABLE></CENTER>
|
||||
<BR>
|
||||
<FONT SIZE="1">* NO may still connect if port estimation works, but can't be relied upon.</FONT>
|
||||
|
||||
<p><span class="RakNetBlueHeader">Client Implementation</span></p>
|
||||
<ol>
|
||||
<li>Create an instance of the plugin: <span class="RakNetCode">NatPunchthroughClient natPunchthroughClient;</span></li>
|
||||
<li>Attach the plugin to an instance of RakPeerInterface: <span class="RakNetCode">rakPeer->AttachPlugin(&natPunchthroughClient);</span></li>
|
||||
<li>Connect to the server, and wait for ID_CONNECTION_REQUEST_ACCEPTED. Use the following line to use the free server provided by RakNet: <span class="RakNetCode">rakPeer->Connect("natpunch.jenkinssoftware.com", 61111, 0, 0);</span></li>
|
||||
<li>Call OpenNAT with the RakNetGUID (globally unique identifier) of the remote system that you want to connect to. In order to get the RakNetGUID, you would either have to transmit it with your own code on the server, upload it to the <A HREF="phpdirectoryserver.html">PHPDirectoryServer</A>, or use a plugin that stores it, such as <A HREF="lightweightdatabase.html">LightweightDatabase</A>: <span class="RakNetCode">natPunchthroughClient.OpenNAT(remoteGuid, serverSystemAddress);</span>. In order to read your own RakNetGUID, use <span class="RakNetCode">RakPeerInterface::GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS);</span></li>
|
||||
<li>Wait a while. It may take over 10 seconds to try every possible port twice, although it often works within a couple of seconds. If you want to get text messages on what is happening, you can use <span class="RakNetCode">NatPunchthroughClient::SetDebugInterface()</span></li>
|
||||
<li>ID_NAT_PUNCHTHROUGH_SUCCEEDED means the punchthrough succeeded, and you should be able to connect or send other messages to the remote system. Packet::SystemAddress is the address of the system you can now connect to. Any other ID_NAT_* means the punchthrough failed. See MessageIdentifiers.h for the list of codes and comments on each. </li>
|
||||
</ol>
|
||||
<p><span class="RakNetBlueHeader">Server Implementation</span></p>
|
||||
<ol>
|
||||
<li>Host a server somewhere, not using NAT / e.g. behind a firewall. (RakNet provides a free one at 8.17.250.34:60481, however you may wish to host your own for consistent uptime).</li>
|
||||
<li>Create an instance of the plugin: <span class="RakNetCode">NatPunchthroughServer natPunchthroughServer;</span></li>
|
||||
<li>Attach the plugin: <span class="RakNetCode">rakPeer->AttachPlugin(&natPunchthroughServer);</span></li>
|
||||
<li>Don't forget to call <span class="RakNetCode">RakPeerInterface::Startup()</span> and <span class="RakNetCode">RakPeerInterface::SetMaximumIncomingConnections(MAX_CONNECTIONS);</span></li>
|
||||
</ol>
|
||||
<P><span class="RakNetBlueHeader">Using the NatPunchthrough class </span><BR>
|
||||
<BR>
|
||||
|
||||
See the sample <em>\Samples\NATCompleteClient</em>
|
||||
and
|
||||
<em>\Samples\NATCompleteServer</em>
|
||||
<P>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">UDP Proxy</td>
|
||||
</tr>
|
||||
</table>
|
||||
<P>With some poor quality or homemade routers, it is possible that NAT punchthrough will not work. For example, a router that picks a new random port for each outgoing connection, and will only allow incoming connections to this port, will never work. This happens about 5% of the time. To handle this case, RakNet provides the UDPProxy system. Essentially, it uses a server that you run to route messages between the source and destination client transparently. This even works to route datagrams from games not using RakNet (though you need RakNet to setup the forwarding). The combination of NATPunchthrough and UDPProxy should enable any system to connect to any other system with a 100% success rate, provided you are willing to host enough proxy servers to forward all the traffic.
|
||||
<P>The UDP Proxy system uses 3 main classes:
|
||||
<ul>
|
||||
<li><strong>UDPProxyClient</strong>: Makes requests of UDPProxyCoordinator to setup forwarding. This is the class the client runs.</li>
|
||||
<li><strong>UDPProxyCoordinator</strong>: Runs on the server that will get all requests from UDPProxyClient. Also, gets all logins from UDPProxyServer</li>
|
||||
<li><strong>UDPProxyServer</strong>: Actually does the UDP datagram forwarding, via a composite instance of UDPForwarder.cpp<br>
|
||||
</li>
|
||||
</ul>
|
||||
<p><span class="RakNetBlueHeader">Client Implementation</span>:</p>
|
||||
<ol>
|
||||
<li>Create an instance of the plugin: <span class="RakNetCode">UDPProxyClient udpProxyClient;</span></li>
|
||||
<li>Derive a class from <span class="RakNetCode">RakNet::UDPProxyClientResultHandler</span> to get event notifications for the system.</li>
|
||||
<li>Attach the plugin to an instance of RakPeerInterface: <span class="RakNetCode">rakPeer->AttachPlugin(&udpProxyClient);</span></li>
|
||||
<li>Call UDPProxyClient::SetResultHandler() on the class created in step 2.</li>
|
||||
<li>Try NATPunchthrough first. If you get ID_NAT_PUNCHTHROUGH_FAILED for the system that initiated NATPunchthrough, go to step 6. Both systems will return ID_NAT_PUNCHTHROUGH_FAILED, however, only one system needs to start the proxy system.</li>
|
||||
<li>Call UDPProxyClient::RequestForwarding with the address of the coordinator, the address you want to forward from (UNASSIGNED_SYSTEM_ADDRESS for your own), the address you want to forward to, and how long to keep the forwarding active on no data. For example:<BR>
|
||||
<span class="RakNetCode">SystemAddress coordinatorAddress;<BR>
|
||||
coordinatorAddress.SetBinaryAddress("8.17.250.34");<BR>
|
||||
coordinatorAddress.port=60481;<BR>
|
||||
udpProxyClient.RequestForwarding(coordinatorAddress, UNASSIGNED_SYSTEM_ADDRESS, p->systemAddress, 7000);</span></li>
|
||||
<li>Assuming you are connected to the coordinator, and the coordinator is running the plugin, your event handler class created in step 2 should get a callback within a second or two. <span class="RakNetCode">UDPProxyClientResultHandler::OnForwardingSuccess</span> will be returned if a UDPProxyServer has been assigned to forward datagrams from the source system specified in step 6, to the target system specified in step 6. For example, to connect to the remote system use: <span class="RakNetCode">rakPeer->Connect(proxyIPAddress, proxyPort, 0, 0);</span></li>
|
||||
</ol>
|
||||
<p>If more than one server is available, and both source and target relay systems are running RakNet, then source and target will automatically ping all available servers. The servers will be attempted in order of lowest ping sum to highest. This is based on the assumption that the lowest ping sum gives you the server that has the shortest path between the two systems, and therefore the least lag.</p>
|
||||
<p><span class="RakNetBlueHeader">Coordinator Implementation</span>:</p>
|
||||
<ol>
|
||||
<li>Create an instance of the plugin: <span class="RakNetCode">UDPProxyCoordinator udpProxyCoordinator;</span></li>
|
||||
<li>Attach the plugin to an instance of RakPeerInterface: <span class="RakNetCode">rakPeer->AttachPlugin(&udpProxyCoordinator);</span></li>
|
||||
<li>Set the password on the coordinator for the servers to use <span class="RakNetCode">udpProxyCoordinator.SetRemoteLoginPassword(COORDINATOR_PASSWORD);</span></li>
|
||||
<li>Don't forget to call <span class="RakNetCode">RakPeerInterface::Startup()</span> and <span class="RakNetCode">RakPeerInterface::SetMaximumIncomingConnections(MAX_CONNECTIONS);</span></li>
|
||||
</ol>
|
||||
<p><span class="RakNetBlueHeader">Server Implementation</span>:</p>
|
||||
<ol>
|
||||
<li>Create an instance of the plugin: <span class="RakNetCode">UDPProxyServer udpProxyServer;</span></li>
|
||||
<li>Attach the plugin to an instance of RakPeerInterface: <span class="RakNetCode">rakPeer->AttachPlugin(&udpProxyServer);</span></li>
|
||||
<li>Connect to the coordinator</li>
|
||||
<li>Login to the coordinator. This can be done at runtime, so you can dynamically add more forwarding servers as your game is more popular.<BR>
|
||||
<span class="RakNetCode">udpProxyServer.LoginToCoordinator(COORDINATOR_PASSWORD, coordinatorSystemAddress);</span><BR>
|
||||
If the coordinator plugin is on the same system as the server plugin, use:<BR>
|
||||
<span class="RakNetCode">udpProxyServer.LoginToCoordinator(COORDINATOR_PASSWORD, rakPeer->GetInternalID(UNASSIGNED_SYSTEM_ADDRESS));</span></li>
|
||||
<li>If you want to get callbacks as events occur (especially login failure) derive from <span class="RakNetCode">RakNet::UDPProxyServerResultHandler</span> and register your derived class with <span class="RakNetCode">UDPProxyServer::SetResultHandler()</span></li>
|
||||
</ol>
|
||||
<p><strong>State diagram with UDP Proxy</strong></p>
|
||||
|
||||
<TABLE>
|
||||
<TR>
|
||||
<TD><A HREF="natpunchpanel1.jpg"><IMG SRC="natpunchpanel1small.jpg"></A></TD>
|
||||
<TD><A HREF="natpunchpanel2.jpg"><IMG SRC="natpunchpanel2small.jpg"></A></TD>
|
||||
<TD><A HREF="natpunchpanel3.jpg"><IMG SRC="natpunchpanel3small.jpg"></A></TD>
|
||||
<TD><A HREF="natpunchpanel4.jpg"><IMG SRC="natpunchpanel4small.jpg"></A></TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD><A HREF="natpunchpanel5.jpg"><IMG SRC="natpunchpanel5small.jpg"></A></TD>
|
||||
<TD><A HREF="natpunchpanel6.jpg"><IMG SRC="natpunchpanel6small.jpg"></A></TD>
|
||||
<TD><A HREF="natpunchpanel7.jpg"><IMG SRC="natpunchpanel7small.jpg"></A></TD>
|
||||
<TD></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<BR>
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">Server hosting</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p><span class="RakNetBlueHeader">Server requirements</span>
|
||||
|
||||
<OL>
|
||||
<LI>No network address translation.</LI>
|
||||
<LI>No firewall, or firewall opened on the appropriate ports.</LI>
|
||||
<LI>Static IP address. <A HREF="http://www.dyndns.com/">Dynamic DNS</A> is one way to get around this requirement.</LI>
|
||||
<LI>Compile with __GET_TIME_64BIT if you want to run the server longer than a month without rebooting</LI>
|
||||
<LI>Enough bandwidth to handle all connections</LI>
|
||||
</OL>
|
||||
|
||||
<p><span class="RakNetBlueHeader">Commercial hosting solutions</span>
|
||||
<OL>
|
||||
<LI><A HREF="http://www.hypernia.com/">Hypernia</A><BR>
|
||||
Worldwide locations. Servers are individual machines. Starting at $150 a month</LI>
|
||||
</OL>
|
||||
|
||||
If you find more hosting solutions, <A HREF="mailto:rakkar@jenkinssoftware.com">contact us</A> and it'll be added to this list.
|
||||
<BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0">
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"><img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr>
|
||||
</table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%">
|
||||
<TR>
|
||||
<TD> <p><A HREF="index.html">Index</A><br>
|
||||
<A HREF="cloudhosting.html">Cloud Hosting</A><BR>
|
||||
<a href="ipv6support.html">IPV6 support </a><BR>
|
||||
<a href="nattraversalarchitecture.html">NAT Traversal architecture</a><BR>
|
||||
<A HREF="nattypedetection.html">NAT type detection</A><br>
|
||||
<a href="steamlobby.html">SteamLobby</a><br>
|
||||
<BR>
|
||||
</p></TD>
|
||||
</TR>
|
||||
</TABLE> </TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
226
Help/RakNet/documentation/nattraversalarchitecture.html
Normal file
@ -0,0 +1,226 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
|
||||
<TITLE>NAT Traversal Architecture</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
<link href="RaknetManual.css" rel="stylesheet" type="text/css">
|
||||
<meta name="title" content="RakNet - Advanced multiplayer game networking API">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#003399" vlink="#003399" alink="#003399" LEFTMARGIN="0" TOPMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0"">
|
||||
<span style="background-color: rgb(255, 255, 255);"><img src="RakNet_Icon_Final-copy.jpg" alt="Oculus VR, Inc." width="150" height="150"></span><BR>
|
||||
<BR>
|
||||
|
||||
<table width="100%" border="0"><tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">NAT Traversal Architecture</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR>
|
||||
<TD>
|
||||
<p><span class="RakNetBlueHeader">How to use combine MasterServer2, UPNP, NAT type detection, FullyConnectedMesh2, and NAT punchthrough for P2P games</span></p>
|
||||
<p>Systems involved for peer to peer game listing and connectivity on the PC, Mac, Linux, or mobiles.</p>
|
||||
<p><a href="http://masterserver2.raknet.com/">MasterServer2</a>: A free server we host that can hold lists of games, and data describing those games<br>
|
||||
<a href="http://miniupnp.free.fr/">UPNP</a>: Tells the router to create a port mapping, in order to allow incoming connections. This a programmatic way of the user manually editing the router configuration<br>
|
||||
<a href="nattypedetection.html">NAT type detection</a>: (Optional) Find out if we have a router, and how restrictive that router is<br>
|
||||
<a href="fullyconnectedmesh2.html">FullyConnectedMesh2</a>: Manages the complexity of joining a group of systems at the same time<br>
|
||||
<a href="natpunchthrough.html">NAT punchthrough</a>: Attempt to connect systems for cases where UPNP fails<br>
|
||||
<a href="router.html">Router2</a> (Optional) - Use other player's bandwidth for routers that cannot connect<br>
|
||||
<a href="natpunchthrough.html">UDPProxyClient</a> (Optional) - Route failed connections through your own servers </p>
|
||||
<p><strong>Step 1: Attempt to connect to the free NAT punchthrough server</strong></p>
|
||||
<p>rakPeer->Connect("natpunch.jenkinssoftware.com", 61111, 0, 0);</p>
|
||||
<p>Upon ID_CONNECTION_REQUEST_ACCEPTED, you have connected.<br>
|
||||
Upon
|
||||
ID_NO_FREE_INCOMING_CONNECTIONS, ID_CONNECTION_ATTEMPT_FAILED, ID_INCOMPATIBLE_PROTOCOL_VERSION you have failed to connect. You may wish to abort online play at this stage, although this is not technically an absolute failure case.</p>
|
||||
<p><strong>Step 3 (Optional): Detect NAT type</strong></p>
|
||||
<p>Provided you connected to the NAT punchthrouhg server, you may wish to detect what type of router you have, or if you have any at all. This can improve the experience for your players by speeding up later steps.<br>
|
||||
<span class="RakNetCode">natTypeDetectionClient->DetectNATType(natPunchServerAddress);</span><br>
|
||||
<br>
|
||||
Upon
|
||||
ID_NAT_TYPE_DETECTION_RESULT, your NAT type is held in packet->data[1]<br>
|
||||
<span class="RakNetCode">printf("NAT Type is %s (%s)\n", NATTypeDetectionResultToString(packet->data[1]), NATTypeDetectionResultToStringFriendly(packet->data[1]));</span></p>
|
||||
<p>The list of results can be see in NATTypeDetectionResult in NatTypeDetectionCommon.cpp</p>
|
||||
<p>The NAT type will not generally change during play, so this step only needs to be done once per executable session.</p>
|
||||
<p><strong>Step 3: Execute UPNP if necessary</strong></p>
|
||||
<p>UPNP is the best way to resolve NAT issues, because it means many other steps are unnecessary, or will always succeed. If NAT type detection returned NAT_TYPE_NONE, you can skip this step.</p>
|
||||
<p class="RakNetCode">DataStructures::List<RakNetSocket2* > sockets;<br>
|
||||
rakPeer->GetSockets(sockets);<br>
|
||||
UPNPOpenAsynch(sockets[0]->GetBoundAddress().GetPort(), 2000, UPNPProgressCallback, UPNPResultCallback, 0);</p>
|
||||
<p>Asynch example code:<br>
|
||||
<em>See Samples\ComprehensivePCGame\ComprehensivePCGame.cpp</em><br>
|
||||
RAK_THREAD_DECLARATION(UPNPOpenWorker) and related code</p>
|
||||
<p>Library located at:<br>
|
||||
<em>DependentExtensions\miniupnpc-1.6.20120410</em></p>
|
||||
<p>If UPNP succeeds, the forwarding entry will stay open for a large period of time (perhaps indefinitely), so this step only needs to be done once per executable session.</p>
|
||||
<p><strong>Step 4 (Optional): FullyConnectedMesh2::ResetHostCalculation()</strong></p>
|
||||
<p>FullyConnectedMesh2 will attempt to determine the host of the peer to peer session based on who has been running the longest. ResetHostCalculation() updates the timer of how long the multiplayer session has been active. If you do not call this, then time spent in single player, menus, loading screens, etc. will be counted which is should normally not be. If you do care if the host is kept in order of players joining the session, you can skip this step.</p>
|
||||
<p><strong>Step 5A: Joining - Download from Master Server 2</strong></p>
|
||||
<p>To join a game in progress, you can download from the <a href="masterserver2.raknet.com">Master Server 2</a> what game sessions have been posted</p>
|
||||
<p class="RakNetCode">#define MASTER_SERVER_ADDRESS "masterserver2.raknet.com"<br>
|
||||
#define MASTER_SERVER_PORT 80 </p>
|
||||
<p class="RakNetCode">tcp = TCPInterface::GetInstance();<br>
|
||||
tcp->AttachPlugin(httpConnection2);<br>
|
||||
tcp->Start(0,0,1);<br>
|
||||
RakString rsRequest = RakString::FormatForGET(<br>
|
||||
MASTER_SERVER_ADDRESS "/testServer?__gameId=myGameId");<br>
|
||||
httpConnection2->TransmitRequest(rsRequest, MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT);</p>
|
||||
<p class="RakNetCode">SystemAddress sa;<br>
|
||||
sa = tcp->HasCompletedConnectionAttempt();<br>
|
||||
for (packet = tcp->Receive(); packet; tcp->DeallocatePacket(packet), packet = tcp->Receive())<br>
|
||||
;<br>
|
||||
sa = tcp->HasFailedConnectionAttempt();<br>
|
||||
sa = tcp->HasLostConnection();<br>
|
||||
RakString stringTransmitted;<br>
|
||||
RakString hostTransmitted;<br>
|
||||
RakString responseReceived;<br>
|
||||
SystemAddress hostReceived;<br>
|
||||
int contentOffset;<br>
|
||||
if (httpConnection2->GetResponse(stringTransmitted, hostTransmitted, responseReceived, hostReceived, contentOffset))<br>
|
||||
{<br>
|
||||
// Parse JSON results here<br>
|
||||
}</p>
|
||||
<p>Example code:<br>
|
||||
See Samples\ComprehensivePCGame\ComprehensivePCGame.cpp</p>
|
||||
<p>In ComprehensivePCGame.cpp, I use jansson included at DependentExtensions\jansson-2.4 to parse the json returned from the master server.</p>
|
||||
<p>If tcp->HasFailedConnectionAttempt() returns something other than UNASSIGNED_SYSTEM_ADDRESS, then masterserver2.raknet.com is offline.</p>
|
||||
<p><strong>Step 5B: Joining - Connect to the session host</strong></p>
|
||||
<p>The results from the master server will include a field __addr (the ip address that uploaded the row) and if you follow what I do in step 6, the RakNetGuid of that system in __rowId. It may also include a field 'routerIsOpen' if you did that in step 6.</p>
|
||||
<p>If 'routerIsOpen' is there and the value is non-zero, then you can just use rakPeer->Connect(...) to connect the host directly because either UPNP succeeded, they already have a forwarding entry for your game, or they do not have a router.</p>
|
||||
<p>If 'routerIsOpen' is zero, then it is required that you previously connected to the NAT punchthrough server in step 1, and you use <a href="natpunchthrough.html">NATPunchthroughClient</a> to connect.</p>
|
||||
<p>In ComprehensivePCGame.cpp this code starts NAT punchthrough to the host:<br>
|
||||
<span class="RakNetCode">if (clientGUID!=rakPeer->GetMyGUID())<br>
|
||||
natPunchthroughClient->OpenNAT(clientGUID, game->natPunchServerAddress);</span></p>
|
||||
<p>NAT punchthrough, if it succeeds, will return ID_NAT_PUNCHTHROUGH_SUCCEEDED. In this case, call rakPeer->Connect(...) to actually connect to the host, and wait for ID_CONNECTION_REQUEST_ACCEPTED, or a failure message (ID_NO_FREE_INCOMING_CONNECTION, ID_CONNECTION_ATTEMPT_FAILED).</p>
|
||||
<p> NAT punchthrough, if it fails, wll return ID_NAT_TARGET_NOT_CONNECTED, ID_NAT_TARGET_UNRESPONSIVE, ID_NAT_CONNECTION_TO_TARGET_LOST, ID_NAT_ALREADY_IN_PROGRESS, or ID_NAT_PUNCHTHROUGH_FAILED. Upon failure, remove this server from the list of servers returned to the user and display an appropriate error message.</p>
|
||||
<p><strong>Step 5C: Joining - Connect as a fully connected mesh</strong></p>
|
||||
<p>Provided that your game uses a fully connected mesh topology, then upon ID_CONNECTION_REQUEST_ACCEPTED, you should try to connect to the peers in the session. FullyConnectedMesh2 has a feature 'verified joins' to faciliate this. First, ask the host to join the game session using your own game logic. In ComprehensivePCGame I send ID_USER_PACKET_ENUM to do so. If the game is joinable at the time the HOST should execute StartVerifiedJoin()</p>
|
||||
<p class="RakNetCode">case ID_USER_PACKET_ENUM:<br>
|
||||
if (game->phase > Game::SEARCH_FOR_GAMES)<br>
|
||||
{<br>
|
||||
printf("Got request from client to join session.\nExecuting StartVerifiedJoin()\n");<br>
|
||||
fullyConnectedMesh2->StartVerifiedJoin(packet->guid);<br>
|
||||
}<br>
|
||||
else<br>
|
||||
{<br>
|
||||
BitStream bsOut;<br>
|
||||
bsOut.Write((MessageID)(ID_USER_PACKET_ENUM+1));<br>
|
||||
rakPeer->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet->guid,false);<br>
|
||||
}<br>
|
||||
break;</p>
|
||||
<p>StartVerifiedJoin() sends ID_FCM2_VERIFIED_JOIN_START to the client along with the list of participants using FullyConnectedMesh2. The CLIENT, upon getting this list, should perform NAT punchthrough and subsequently connect to each of these systems.</p>
|
||||
<p class="RakNetCode">case ID_FCM2_VERIFIED_JOIN_START:<br>
|
||||
{<br>
|
||||
DataStructures::List<SystemAddress> addresses;<br>
|
||||
DataStructures::List<RakNetGUID> guids;<br>
|
||||
fullyConnectedMesh2->GetVerifiedJoinRequiredProcessingList(packet->guid, addresses, guids);<br>
|
||||
for (unsigned int i=0; i < guids.Size(); i++)<br>
|
||||
natPunchthroughClient->OpenNAT(guids[i], game->natPunchServerAddress);<br>
|
||||
}<br>
|
||||
break;<br>
|
||||
case ID_NAT_PUNCHTHROUGH_SUCCEEDED:<br>
|
||||
{<br>
|
||||
rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(), 0, 0);<br>
|
||||
}<br>
|
||||
break;
|
||||
</p>
|
||||
<p>FullyConnectedMesh2 will automatically handle details such as NAT punchthrough failing to some peers, new peers joining while NAT punchthrough is in progress, peers disconnecting, etc. If the client has connected to all the peers existing in the session, the host will get ID_FCM2_VERIFIED_JOIN_CAPABLE. According to your game logic, you may at this point accept or reject the potential new player:</p>
|
||||
<p class="RakNetCode">if (game->lockGame)<br>
|
||||
{<br>
|
||||
RakNet::BitStream bsOut;<br>
|
||||
bsOut.Write("Game is locked");<br>
|
||||
fullyConnectedMesh2->RespondOnVerifiedJoinCapable(packet, false, &bsOut);<br>
|
||||
}<br>
|
||||
else<br>
|
||||
{<br>
|
||||
fullyConnectedMesh2->RespondOnVerifiedJoinCapable(packet, true, 0);<br>
|
||||
}</p>
|
||||
<p>The CLIENT will get ID_FCM2_VERIFIED_JOIN_ACCEPTED or ID_FCM2_VERIFIED_JOIN_REJECTED based on the 2nd parameter to RespondOnVerifiedJoinCapable() that the HOST executed. If you get ID_FCM2_VERIFIED_JOIN_ACCEPTED, you can consider yourself in the game session - already connected to all other peers in the session.</p>
|
||||
<p>The CLIENT may also get ID_FCM2_VERIFIED_JOIN_FAILED. This means that either NAT punchthrough or the connection attempt failed to one of the systems in the group. In this case, you cannot join this session as a fully connected mesh.</p>
|
||||
<p>If you do not need a fully-connected mesh, but can play with a partial mesh, you may wish to derive from FullyConnectedMesh2::OnVerifiedJoinFailed() to not call CloseConnection() if it was called due to ID_FCM2_VERIFIED_JOIN_FAILED, and still treat ID_FCM2_VERIFIED_JOIN_FAILED as join success in your game logic.</p>
|
||||
<p><strong>Step 6: Creating - Post to Master Server 2</strong></p>
|
||||
<p>New game sessions should be posted to <a href="masterserver2.raknet.com">Master Server 2</a>. In the following code I post the name of the game, how long until the row times out, my RakPeer GUID, and whether or not my router is open to incoming connections (optional).</p>
|
||||
<p class="RakNetCode">#define MASTER_SERVER_ADDRESS "masterserver2.raknet.com"<br>
|
||||
#define MASTER_SERVER_PORT 80</p>
|
||||
<p class="RakNetCode">int routerIsOpen = natType == NAT_TYPE_NONE || upnpSucceeded;</p>
|
||||
<p class="RakNetCode">tcp = TCPInterface::GetInstance();<br>
|
||||
tcp->AttachPlugin(httpConnection2);<br>
|
||||
tcp->Start(0,0,1);<br>
|
||||
RakString rsRequest = RakString::FormatForPOST(<br>
|
||||
(const char*) MASTER_SERVER_ADDRESS "/testServer",<br>
|
||||
"text/plain; charset=UTF-8",<br>
|
||||
RakString("{'__gameId': myGameId, '__clientReqId': '0', '__timeoutSec': '30', '__rowId': %I64u, 'routerIsOpen': %i }", rakPeer->GetMyGUID().g, routerIsOpen );</p>
|
||||
<p class="RakNetCode"> // POST the room again slightly less than every 30 seconds<br>
|
||||
game->whenToNextUpdateMasterServer = RakNet::GetTime() + 30000 - 1000;</p>
|
||||
<p><span class="RakNetCode"> httpConnection2->TransmitRequest(rsRequest, MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT);</span></p>
|
||||
<p><strong>Step 7: Update Master Server 2 while the session is joinable</strong></p>
|
||||
<p>One of the systems in the game session must be responsible for updating Master Server 2. Otherwise, the session will be delisted since master server 2 will assume that system crashed with no further updates. If you use FullyConnectedMesh2, then the current host can do this every n seconds, based on __timeoutSec.</p>
|
||||
<p class="RakNetCode">// This system has become host<br>
|
||||
case ID_FCM2_NEW_HOST:<br>
|
||||
{<br>
|
||||
RakNet::BitStream bs(packet->data,packet->length,false);<br>
|
||||
bs.IgnoreBytes(1);<br>
|
||||
RakNetGUID oldHost;<br>
|
||||
bs.Read(oldHost);<br>
|
||||
if (packet->guid==rakPeer->GetMyGUID() && oldHost!=UNASSIGNED_RAKNET_GUID)<br>
|
||||
PostRoomToMaster();<br>
|
||||
}</p>
|
||||
<p class="RakNetCode">// Time has elasped while the game is joinable<br>
|
||||
RakNet::Time t = RakNet::GetTime();<br>
|
||||
if (((fullyConnectedMesh2->IsConnectedHost() || game->users.Size()==1) &&<br>
|
||||
t > game->whenToNextUpdateMasterServer) &&<br>
|
||||
game->phase == Game::IN_LOBBY_WITH_HOST ||<br>
|
||||
game->phase == Game::IN_GAME<br>
|
||||
)<br>
|
||||
{<br>
|
||||
PostRoomToMaster();<br>
|
||||
}</p>
|
||||
<p>Updating a room is identical to posting a new room (step 6).</p>
|
||||
<p><strong>Step 8: Delist the game if and when the session is no longer joinable</strong></p>
|
||||
<p>If at some point in your game new players are not accepted, you can delist the game from Master Server 2. This will also happen automaticaly if you just stop updating.</p>
|
||||
<p>RakString rsRequest = RakString::FormatForDELETE(<br>
|
||||
RakString(MASTER_SERVER_ADDRESS "/testServer?__gameId=myGameId&__rowId=%I64u", rakPeer->GetMyGUID().g));<br>
|
||||
httpConnection2->TransmitRequest(rsRequest, MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT);</p>
|
||||
<p>You may also disconnect from the NAT PunchthroughServer at this time, provided you reconnect when you need it again. It will save bandwidth if you do this.</p>
|
||||
<p><strong>Step 9 (Optional): Router2 or UDPProxyClient as a backup</strong></p>
|
||||
<p>For players that failed NATPunchthrough, you can route their connections through players that did not fail, using the <a href="router.html">Router2</a> plugin. You can also use the <a href="natpunchthrough.html">UDPProxyClient</a> while you are running your own UDPProxyServer to forward those connections through a server.</p>
|
||||
<p>Router2 will return ID_ROUTER_2_FORWARDING_NO_PATH if forwarding is not possible and ID_ROUTER_2_FORWARDING_ESTABLISHED on success.</p>
|
||||
<p>UDPPRoxyClient will return ID_UDP_PROXY_GENERAL. Byte 1 indicates the return value. Success is returned on ID_UDP_PROXY_FORWARDING_SUCCEEDED. The remote system will get ID_UDP_PROXY_FORWARDING_NOTIFICATION on success. Anything else means failure.</p>
|
||||
<p>If these solutions fail, or you do not use them, then it is not possible to complete a peer to peer gaming session. Leave the game session on the server. You should show a dialog box to the user that they need to manually open ports on their router before they can play. Or you can just try a different session.</p>
|
||||
<p>See the sample <em>\Samples\NATCompleteClient</em> for Router2 and UDPProxyClient<em></em></p></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td bgcolor="#2c5d92" class="RakNetWhiteHeader"> The simpler way</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<p><span class="RakNetBlueHeader">Just UPNP and NatPunchthroughClient</span></p>
|
||||
<p>UPNP enabled routers are common these days. Therefore, this simpler solution will work in nearly all cases, and is recommended unless you are writing a back-end service with multiple fallbacks.</p>
|
||||
<ol>
|
||||
<li>Connect to a hosting server running NATPunchthroughServer. For example, <a href="http://www.jenkinssoftware.com/forum/index.php?topic=5006.0">our free server</a>.</li>
|
||||
<li>Call the OpenUPNP() function in step 3 above. It doesn't matter if the function succeeds or not, because you do the next steps regardless.</li>
|
||||
<li>When you find which game server you want to connect to, call <span class="RakNetCode">natPunchthroughClient->OpenNAT(gameServerGuid, masterServerAddress);</span></li>
|
||||
<li>If you get ID_NAT_PUNCHTHROUGH_SUCCEEDED, connect to that server. For a client/server game, you are done.</li>
|
||||
<li>For a peer to peer game, you will also need to connect to the other peers after connecting to the server. Using the plugin FullyConnectedMesh2, call fullyConnectedMesh2->StartVerifiedJoin(gameServerGuid);</li>
|
||||
<li>As described in the documentation for FullyConnectedMesh2::StartVerifiedJoin,() you will get ID_FCM2_VERIFIED_JOIN_START which contains a list of all peers in the session. Call NatPunchthroughClient::OpenNAT() on each of those peers, and connect on success, similar to step 3. FullyConnectedMesh2 internally tracks which systems failed or passed, and you will get ID_FCM2_VERIFIED_JOIN_ACCEPTED once negotation has completed.</li>
|
||||
</ol>
|
||||
<p>See the sample <em>\Samples\ComprehensivePCGame</em></p></TD>
|
||||
</TR></TABLE>
|
||||
|
||||
|
||||
<table width="100%" border="0"><tr><td bgcolor="#2c5d92" class="RakNetWhiteHeader">
|
||||
<img src="spacer.gif" width="8" height="1">See Also</td>
|
||||
</tr></table>
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%"><TR><TD><p><A HREF="index.html">Index</A><BR>
|
||||
<A HREF="http://miniupnp.free.fr/">MiniUPnP</A><BR>
|
||||
<A HREF="natpunchthrough.html">NAT punchthrough</A><BR>
|
||||
<A HREF="nattypedetection.html">NAT type detection</A><br>
|
||||
<A HREF="router.html">Router2</A><br>
|
||||
</p></TD></TR></TABLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||