Skip to content

Networking

LuisAntonRebollo edited this page Dec 4, 2013 · 1 revision
<SCRIPT SRC="../../../include/tutorial.js" LANGUAGE="JavaScript"></SCRIPT> <SCRIPT SRC="../../../include/prototype.js" LANGUAGE="JavaScript"></SCRIPT> <SCRIPT SRC="../../../include/scriptaculous.js" LANGUAGE="JavaScript"></SCRIPT> <SCRIPT SRC="../../../include/glossaryLookUp.js" LANGUAGE="JavaScript"></SCRIPT> <SCRIPT SRC="../../../include/referenceLookUp.js" LANGUAGE="JavaScript"></SCRIPT> <SCRIPT SRC="../../../include/component.js" LANGUAGE="JavaScript"></SCRIPT> <SCRIPT SRC="../../../include/componentContainer.js" LANGUAGE="JavaScript"></SCRIPT> <SCRIPT>DocImagePath = "../../../";</SCRIPT> <script> // this script chunk is to update the ToC to the current doc and expand it pageID = 52; parent.leftFrame.expandToItem('tree2', 'doc52'); var element = parent.leftFrame.document.getElementById('doc52'); if((element) && (element.className==parent.leftFrame.nodeClosedClass)) { element.className = parent.leftFrame.nodeOpenClass } ; </script> <title>Torque 3D - Networking</title>
    <table border="0" cellpadding="0" cellspacing="0" width="700">
      <tbody>
        <tr>
          <td width="700"><table id="toc" summary="Contents">
              <tbody>
                <tr>
                  <td><div id="toctitle">
                      <h2>Contents</h2>
                      </div>
                    <ul>
                      <li class="toclevel-1"><a href="#Introduction"><span class="tocnumber">1</span> <span class="toctext">Introduction</span></a></li>
                      <li class="toclevel-1"><a href="#The_Client.2FServer_Concept"><span class="tocnumber">2</span> <span class="toctext">The Client/Server Concept</span></a>
                        <ul>
                          <li class="toclevel-2"><a href="#The_Server"><span class="tocnumber">2.1</span> <span class="toctext">The Server</span></a></li>
                          <li class="toclevel-2"><a href="#The_Client"><span class="tocnumber">2.2</span> <span class="toctext">The Client</span></a></li>
                        </ul>
                      </li>
                      <li class="toclevel-1"><a href="#Datablocks_in_Networking"><span class="tocnumber">3</span> <span class="toctext">Datablocks in Networking</span></a></li>
                      <li class="toclevel-1"><a href="#Network_Connection_Classes_.E2.80.93_Linking_Client_and_Server"><span class="tocnumber">4</span> <span class="toctext">Network Connection Classes – Linking Client and Server</span></a>
                        <ul>
                          <li class="toclevel-2"><a href="#NetConnection"><span class="tocnumber">4.1</span> <span class="toctext">NetConnection</span></a></li>
                          <li class="toclevel-2"><a href="#GameConnection"><span class="tocnumber">4.2</span> <span class="toctext">GameConnection</span></a></li>
                          <li class="toclevel-2"><a href="#ServerConnection"><span class="tocnumber">4.3</span> <span class="toctext">ServerConnection</span></a></li>
                          <li class="toclevel-2"><a href="#LocalClientConnection"><span class="tocnumber">4.4</span> <span class="toctext">LocalClientConnection</span></a></li>
                          <li class="toclevel-2"><a href="#Setting_Up_The_Server"><span class="tocnumber">4.5</span> <span class="toctext">Setting Up The Server</span></a></li>
                          <li class="toclevel-2"><a href="#Setting_Up_the_Client"><span class="tocnumber">4.6</span> <span class="toctext">Setting Up the Client</span></a></li>
                          <li class="toclevel-2"><a href="#Using_the_GameCore_Package"><span class="tocnumber">4.7</span> <span class="toctext">Using the GameCore Package</span></a></li>
                        </ul>
                      </li>
                      <li class="toclevel-1"><a href="#Sending_Commands_in_Torque.27s_Client.2FServer_Model"><span class="tocnumber">5</span> <span class="toctext">Sending Commands in Torque's Client/Server Model</span></a>
                        <ul>
                          <li class="toclevel-2"><a href="#Client_to_Server_Commands"><span class="tocnumber">5.1</span> <span class="toctext">Client to Server Commands</span></a></li>
                          <li class="toclevel-2"><a href="#Server_to_Client_Commands"><span class="tocnumber">5.2</span> <span class="toctext">Server to Client Commands</span></a></li>
                        </ul>
                      </li>
                      <li class="toclevel-1"><a href="#Making_Your_Own_Commands"><span class="tocnumber">6</span> <span class="toctext">Making Your Own Commands</span></a>
                        <ul>
                          <li class="toclevel-2"><a href="#Client_Setup"><span class="tocnumber">6.1</span> <span class="toctext">Client Setup</span></a></li>
                          <li class="toclevel-2"><a href="#Server_Setup"><span class="tocnumber">6.2</span> <span class="toctext">Server Setup</span></a></li>
                          <li class="toclevel-2"><a href="#Execution_Setup"><span class="tocnumber">6.3</span> <span class="toctext">Execution Setup</span></a></li>
                          <li class="toclevel-2"><a href="#Mission_Setup"><span class="tocnumber">6.4</span> <span class="toctext">Mission Setup</span></a></li>
                        </ul>
                      </li>
                      <li class="toclevel-1"><a href="#Further_Reading"><span class="tocnumber">7</span> <span class="toctext">Further Reading</span></a></li>
                    </ul></td>
                </tr>
              </tbody>
            </table>
            <a name="Introduction" id="Introduction"></a>
            <h2> <span class="mw-headline"> Introduction </span></h2>
            <p>Torque 3D was designed around networked games. This tutorial will 
              give an overview of the high level Client-Server Networking concepts 
              utilized by Torque and will show you how to make a network teleport 
              command sequence you can use as a springboard for your own networked 
              game play ideas. </p>
            <p><br />
              <b>Suggested reading before you start this tutorial:</b> </p>
            <ul>
              <li> <a href="../Torque 3D - Script Manual.chm" class="downloads" title="TorqueScript Reference" rel="nofollow">TorqueScript Reference</a> </li>
            </ul>
            <ul>
              <li> <a href="../../Introduction/ToolBox.html" title="Torque 3D Toolbox" rel="nofollow">Toolbox Reference</a> </li>
            </ul>
            <p><br />
              This guide uses the Full Template from the Torque Toolbox as a base. If 
              you haven't already, go ahead and make a new project with the template. </p>
            <p><br />
              <b>What is covered in this tutorial:</b> </p>
            <ul>
              <li> <i>The Client/Server Concept</i> </li>
            </ul>
            <ul>
              <li> <i>Datablocks in Networking</i> </li>
            </ul>
            <ul>
              <li> <i>Network Connection Classes – Linking Client and Server</i> </li>
            </ul>
            <ul>
              <li> <i>Sending Commands in the Torque Client/Server Model</i> </li>
            </ul>
            <ul>
              <li> <i>Making Your Own Commands</i> </li>
            </ul>
            <a name="The_Client.2FServer_Concept" id="The_Client.2FServer_Concept"></a>
            <br><h2> <span class="mw-headline"> The Client/Server Concept </span></h2>
            <p>This is a high level overview of the <b>Client/Server Networking Model</b> that Torque 3D uses for its networking model.  A networked Torque game normally uses only a single <b>Server</b> instance, but multiple <b>Client</b> instances can connect to the Server at once. When a client joins a 
              server and the mission begins downloading, there is a 3 phase process: </p>
            <ol>
              <li> Datablocks are sent to the client, such as vehicle and weapon data. Datablocks will be covered in more detail in the <b>Datablocks in Networking</b> section of this tutorial. </li>
              <li> In-Mission Objects are <b>ghosted</b> to the client, such as other players. Ghosting will be discussed in The Server section of this tutorial. </li>
              <li> Finally, the scene is lit on the client, and then game play can begin. </li>
            </ol>
            <p><br />
              There are 3 types of networking setups an instance of Torque can be in: </p>
            <ul>
              <li> <b>Dedicated Server</b> – The server has no local client; it only connects to external clients. Games like MMOs generally use dedicated servers. </li>
            </ul>
            <ul>
              <li> <b>Hosted Server</b> – The server has a local client that 
                connects directly to the server instance instead of over the network. 
                This is used in both a Single-Player instance of Torque, and when the 
                instance hosting the game also has a player. Many FPS games and LAN 
                party games use this setup, where one player's game is the host and 
                other clients connect to the host. </li>
            </ul>
            <ul>
              <li> <b>Client Only</b> – The game runs in client mode only and 
                joins a game play session by connecting to a server either on a local 
                network or over the internet. </li>
            </ul>
            <a name="The_Server" id="The_Server"></a>
            <br><h3> <span class="mw-headline"> The Server </span></h3>
            <p>The <b>Server</b> has multiple responsibilities, and is the central 
              "care-taker" of a networked game. Even when running in a single-player 
              instance, or when the server is not a dedicated server, Torque uses the 
              Client-Server Networking model. In this case, the server connects to a 
              "client" in the same game instance, and sends "short-circuited" commands
              to the local client. </p>
            <p><br />
              The Server has the following responsibilities, and may have more, depending on how a specific game is structured: </p>
            <ul>
              <li><b>Authoritative</b> – Information transmitted from the Server 
                overrides the local Client information in the case of a bad prediction
                on the part of the Client. This ensures that the local data of the Client does not 
                "drift" from the data the other Clients have. </li>
            </ul>
            <ul>
              <li><b>Ghosting</b> – The server keeps track of all the "true" 
                objects in play, and "Ghosts" or copies data for each of them to the 
                Clients by using <b>Scoping</b>.  What this means the server has a 
                master list of objects, and sends updated information for them to a 
                local copy of the object on the client. </li>
            </ul>
            <ul>
              <li><b>Scoping</b> - Scoping helps sort out what each client is aware of so 
                Torque does not have to send updates for objects that don't need to be 
                updated. In order to save bandwidth and minimize network delay, objects 
                are initially ghosted to the client in the second phase of mission 
                startup. </li>
            </ul>
            <ul>
              <li><b>Datablocks</b> – Datablocks are sent in the first phase of 
                mission start-up. The Server has all of the datablocks for clients to 
                download when they begin a mission. This means that the server only has 
                to send datablocks as they are needed, and can send new datablocks for 
                different missions. Datablocks are discussed further in the <b>Datablocks in Networking</b> section below. </li>
            </ul>
            <ul>
              <li><b>Collision &amp; Physics</b> – The Server performs collision checks and important physics calculations like rigid-body dynamics that affect game objects. </li>
            </ul>
            <ul>
              <li><b>Security</b> – The Server can kick bad players and cheaters 
                out of the game, and can be setup to detect hacks being performed by a 
                bad client. </li>
            </ul>
            <ul>
              <li><b>Message Routing</b> – The server can route messages, such as in-game chats, between clients. </li>
            </ul>
            <a name="The_Client" id="The_Client"></a>
            <br><h3> <span class="mw-headline"> The Client </span></h3>
            <p>The Client also has several important responsibilities, so that it 
              can work well with the server and provide a quality game play 
              experience: </p>
            <ul>
              <li><b>Rendering</b> – the Client is responsible for rendering the 
                game for the player, and may be responsible for non-important physical 
                simulations, such as cloth simulations and particle effect physics. </li>
            </ul>
            <ul>
              <li><b>Sound</b> – The Client instance plays back sound effects and 
                music tracks on the local machine and doesn't involve the server with 
                sound playback. </li>
            </ul>
            <ul>
              <li><b>Input</b> – The Client accepts player input and sends that information to the server. </li>
            </ul>
            <ul>
              <li><b>User Preferences</b> – Many games store user preferences on the local machine  where the client instance runs. </li>
            </ul>
            <ul>
              <li><b>Prediction</b> – The Client can predict what will happen to 
                game objects in the short term while it waits for the server to 
                synchronize, in order to maintain correct-looking game behavior. </li>
            </ul>
            <ul>
              <li><b>Interpolation</b> – As part of the prediction process, the 
                Client can determine where it needs to be between where it thought it 
                needed to be and where the server tells it to go. </li>
            </ul>
            <a name="Datablocks_in_Networking" id="Datablocks_in_Networking"></a>
            <br><h2> <span class="mw-headline"> Datablocks in Networking </span></h2>
            <p>Datablocks are a useful way to have game objects share common data, 
              such as which model to use, physics properties, ammo type, whatever is 
              relevant to the class the datablock is associated with. This saves 
              Memory and makes it easier to create new types of objects by deriving 
              new datablocks from old datablocks and overriding only the data that is 
              different. Datablocks are declared on the server when a mission is 
              started, and wired over to clients when they begin downloading the 
              mission data. Once downloaded, they cannot be changed. </p>
            <pre>// An Example Datablock

// From art/datablocks/weapons/rocketLauncher.cs for the rocket launcher ammo:

datablock ItemData(RocketLauncherAmmo) { // Mission editor category category = "Ammo";

// Add the Ammo namespace as a parent. The ammo namespace provides // common ammo related functions and hooks into the inventory system. className = "Ammo";

// Basic Item properties shapeFile = "art/shapes/weapons/SwarmGun/rocket.dts"; mass = 2; elasticity = 0.2; friction = 0.6;

// Dynamic properties defined by the scripts pickUpName = "Rockets"; maxInventory = 20; };

Just like the benefit datablocks provide to memory, they also save bandwith as the common data they contain is only sent once. Datablocks also make it easier for a client to get mods from the server without updating scripts, as the modded behavior is acquired when the mod datablocks are downloaded.


When the server begins a mission with the client it sends relevant datablocks to the client as part of a multiphase loading process. Datablocks are sent in the first phase of the process, as all in-game objects will need the datablocks to be initialized with the correct settings. Once all datablocks have been downloaded, the server moves on to Phase 2 of the mission downloading process.


For more information on datablocks, you can read: Datablock Editor


Network Connection Classes – Linking Client and Server

Torque uses several connection object classes to provide multiplayer networking facilities. The basic functionality is defined in the NetConnection and expanded upon with the other connection classes.


NetConnection

The Base multiplayer networking object class is the NetConnection class, which provides the functionality to create connections between two instances of torque (or the same instance if the client is also the server).

//an example of NetConnection in the wild…
%connect = new NetConnection(MyNetConnection);
RootGroup.add( MyNetConnection );

%connect.connect(%someAddress); //connect MyNetConnection to %someAddress

//if successful, you are now networked on a basic level


The important console method commands to note in the class are:

  • NetConnection.connect( %address ) – attempts to connect this object to another NetConnection object in an instance of Torque running at the network %address.
  • NetConnection.connectLocal() - attempts to connect this NetConnection object to the local server when running the client and server in the same instance of Torque. Returns an empty string "" when successful and an error message otherwise.

GameConnection

The primary subclass of NetConnection used by a Torque multiplayer game, utilizes everything that NetConnection does but adds game-specific networking functionality on top of that.

//making the GameConnection…
%gameCon = new GameConnection(MyGameConnection);
RootGroup.add(MyGameConnection);

MyGameConnection.connect(%someAddress); //connect MyNetConnection to %someAddress


The GameConnection class enables what is known as the Control Object, which can be anything derived from the ShapeBase engine class. The client instance of the game tracks control from this object, such as the Player or the Camera used in in editing, and sends it to the server. GameConnection has both client and server-side console methods:

//setting a control object, we do this on the server side
MyGameConnection.setControlObject(PlayerOne);

//change the view to third-person, on the server side MyGameConnection.setFirstPerson(false);

//other fun stuff…


The GameConnection object applies changes to the client control object based on Player input to the game via the Move engine structure, which contains positional and rotational changes as well as trigger state changes. The Moves are collected based on time, applied to the client object, and then sent over to the server for processing.


ServerConnection

This is the named instance of a GameConnection object that represents the Client Connection to the Server. It is created on the scripting level:

//from core/scripts/server/server.cs
%conn = new GameConnection( ServerConnection );
RootGroup.add( ServerConnection );

%conn.setConnectArgs( $pref::Player::Name ); %conn.setJoinPassword( $Client::Password );


LocalClientConnection

This is the named instance of a NetConnection/GameConnection (depending on which class you use) object that is created when it is connectLocal() method is performed successfully.

//furthering the ServerConnection example from before
%conn = new GameConnection( ServerConnection );
RootGroup.add( ServerConnection );

%conn.setConnectArgs( $pref::Player::Name ); %conn.setJoinPassword( $Client::Password );

// LocalClientConnection is made right here, on the engine level %result = %conn.connectLocal();

if( %result !$= "" ) { %conn.delete(); destroyServer();

return false; }


Setting Up The Server

  • First, we need to set up the Port that Torque will be using for communication on the computer. A port is a communication channel a computer uses to filter network traffic. The Stock Example uses port# 28000 by default, set in core/prefs.cs. You can use the script helper function portInit(%port), which will try to find an open port with the console function setNetPort(%port). (Single-Player games can skip this step)
//an example of setting the port
%myPort = 12345;
//…
if( setNetPort(%myPort) )
{
//success!
echo("successfully connected to port:" SPC %myPort);
}
else
{
//failure
error("error connecting to port:" SPC %myPort);

//fallback behavior, maybe try a new port… }

  • Next, we need to enable the Torque instance to allow network Connections, we do this by the console function allowConnections(%enable). (Single-Player games can skip this step)
//activate connections on our selected port
allowConnections(true);
  • Afterwards, we setup our ServerGroup, load up our datablocks, and begin loading the selected mission.
//an updated example from core/scripts/server/server.cs…

// Load the level $ServerGroup = new SimGroup(ServerGroup);

// Load up any core datablocks exec("core/art/datablocks/datablockExec.cs");

// Let the game initialize some things now that the // the server has been created onServerCreated();

loadMission(%level, true); //only true if loading first mission

  • All of the above is can be performed with the createServer(%serverType, %level) script helper function:
//do all of the above in one call
if( createServer(%type, %myMission )
{
//server for mission created properly
echo(%type SPC "server created successfully for mission:" SPC %myMission);
}
else
{
//fallback behavior
error("error in" SPC %type SPC "server creation process!" SPC %myMission);
}
  • At this point, if we're running a client on the same instance as the server, we can create our ServerConnection object, and connect it to the local server instance:
// from server.cs again… with a few extra comments

//create our server connection object %conn = new GameConnection( ServerConnection );

// RootGroup is the master SimGroup for the entire instance RootGroup.add( ServerConnection );

%conn.setConnectArgs( $pref::Player::Name ); %conn.setJoinPassword( $Client::Password );

//if you've modified or subclassed GameConnection, // your additional connection settings might //go here

%result = %conn.connectLocal(); //create the LocalServerConnection if( %result !$= "" ) { //uh-oh, get rid of the bad connection %conn.delete(); destroyServer();

return false; }

  • We can create the server AND connect locally with the createAndConnectToLocalServer( %serverType, %level) script helper function, which also calls the createServer() script helper function to make the server.
//do all of the above
if( createAndConnectToLocalServer(%type, %myMission) )
{
//local server & local client connection for mission created properly
echo(%type SPC "server & client created successfully for mission:" SPC %myMission);
}
else
{
//fallback behavior
error("error in" SPC %type SPC "server & client creation process!" SPC %myMission);
}

Setting Up the Client

It is pretty straightforward, you can look at how the script helper function connect(%server) works to see this in action:

// Example from the connect(%server) script helper function in :
// core/scripts/client/missionDownload.cs…

function connect(%server) {

//First, Create ServerConnection object.

%conn = new GameConnection(ServerConnection); RootGroup.add(ServerConnection);

// Next, Setup our connection settings, // such as player name, password, // and any other game-specific extensions. %conn.setConnectArgs($pref::Player::Name); %conn.setJoinPassword($Client::Password);

// Call the GameConnection.connect(%server) method to initiate the connection.

%conn.connect(%server); }


Using the GameCore Package

A Package is a set of modified scripts that can be loaded "over" preexisting functions, and unloaded to remove the alternate functionality. The GameCore package in a stock Torque project sets up the FPS Single and Multiplayer games. You can find the GameCore package functions in game/scripts/server/gameCore.cs.


The GameCore Package overrides the "blank" functionality associated with many GameConnection console callbacks with game-specific behavior, like informing the client it has joined a game with a welcome message, putting in a message when another player enters/leaves the game, how the player is spawned in the world, setting the active inventory, and so on and so forth.

//game core example, onConnect override, short verson…
function GameConnection::onConnect(%client, %name)
{
// Send down the connection error info, the client is responsible for
// displaying this message if a connection error occurs.
messageClient(%client, 'MsgConnectionError',"",$Pref::Server::ConnectionError);

// Send mission information to the client sendLoadInfoToClient(%client);

//other stuff…

// Save client preferences on the connection object for later use. %client.gender = "Male"; %client.armor = "Light"; %client.race = "Human"; %client.skin = addTaggedString("base"); %client.setPlayerName(%name); %client.score = 0; %client.kills = 0; %client.deaths = 0;

// Inform the client of all the other clients %count = ClientGroup.getCount(); for (%cl = 0; %cl < %count; %cl++) { //… }

// Inform the client about joining //…

// Inform all the other clients of the new guy //…

// If the mission is running, go ahead download it to the client if ($missionRunning) { %client.loadMission(); } else if ($Server::LoadFailMsg !$= "") { messageClient(%client, 'MsgLoadFailed', $Server::LoadFailMsg); } $Server::PlayerCount++; }


To make your own game-specific functionality you could re-write the GameCore package or make a new package that overrides the functions that the GameCore Package defines.


Sending Commands in Torque Client/Server Model

Torque has a very simple setup for sending script commands between the client and server, allowing for a great deal of flexibility in setting up your own commands.


Client to Server Commands

The way to send a command from the client to the server is with the commandToServer(%cmdname, %arglist…) console function. The %arglist… is any number of optional arguments that the function needs to pass to the server command.

//commandToServer example, tell the server to start some giant laser mayhem
commandToServer('GiantLaserAttack', %laserPosition, 12, "1.0 0.0 0.75 0.9");

For the server to process the command, use the prefix serverCmd, followed by the command name. The first argument is the game object id of the client that send the command, followed by the optional arguments given it.
//serverCmd example, notice the args match up with our commandToServer() call
function serverCmdGiantLaserAttack(%client, %position, %powerLevel, %laserColor)
{
   if( $GiantLaserActive == false)
   {
      echo("Received GLA from Client:" SPC %client);
      //perform some giant laser mayhem
      beginGiantLaserAttack(%position, %powerLevel, %laserColor);
   }
   //there can only be one giant laser attack at any given time!
}
            <a name="Server_to_Client_Commands" id="Server_to_Client_Commands"></a>
            <br><h3> <span class="mw-headline"> Server to Client Commands </span></h3>
            <p>Sending commands from the server to the client is *almost* the mirror
              version of sending them from the client to the server. To send a 
              command to the client, use the 
              commandToClient(%client, %cmdName, arglist.. ) console function. You
              have to specify a client to send the command to. Unlike with 
              commandToServer(), there could be multiple clients. </p>
            <pre>//commandToClient example, update our world damage state

commandToClient(%thatClient,'UpdateGiantLaserWorldDamage', %laserPosition, %radius);

//sending a command to all the clients %count = ClientGroup.getCount(); for (%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); commandToClient( %cl, 'UpdateGiantLaserWorldDamage' , %laserPosition, %radius); }


And similar to the serverCmd prefix, we have the clientCmd prefix + commandName:

//clientCmd example, updating our GiantLaser world damage
function clientCmdUpdateGiantLaserWorldDamage( %position, %radius)
{
destroyPlayersInArea(%position, %radius);
destroyVehiclesInArea(%position, %radius);
destroyPropsInArea(%position, %radius);
applyWorldDamageDecal(%postion, %radius, "GiantLaser");
breakAllWindowsInArea(%position, %radius);
}

Making Your Own Commands

As you learned with the previous section, making client/server commands in Torque is really easy. With this example, you'll learn how to make your own client/server commands.

You'll use a timed command on the client to send a command to the server saying "ready to teleport". The server will teleport the player and send a command to the client to echo a message to the console;
Armed with that, you can modify the example and play with making your own commands to make the server and client do whatever you want them to!

You'll be modifying the Stock Torque Full Template for this example, so if you have that ready to go then you're all set.


Client Setup

First, add a file on the client for our client side commands. Call this file myClientCommands.cs and make it in the game/scripts/client directory,. Once you've done that, add a few functions to that file.

//this will send the command that you're ready to start the teleport procedure
function sendTeleportSignal()
{
%time = 5000; //a five second delay should be fine

// call the serverCmdTeleportReady, with a time argument of 5 seconds commandToServer('TeleportReady', %time); }

//this clientCmd will report the distance the server teleported the player function clientCmdAcknowledgeTeleport(%distance) { // tell the user how far up they were teleported echo("VOIP! You were teleported! Distance:" SPC %distance); }


Server Setup

Next, add our server command functions. Make a file in the game/scripts/server directory called myServerScripts.cs, and fill it in with the following code:

//this will set us up to teleport the clients in a few seconds
function serverCmdTeleportReady(%client, %time)
{
schedule(%time, 0, "beginTeleport"); //schedule our teleport
}

//this function will send all the clients the teleport command function beginTeleport() { %count = ClientGroup.getCount(); //get the count for all of our clients for (%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); //get each client %dist = 5 + (getRandom() * 5); //generate a random distance between 5 and 10 %controlObject = %cl.getControlObject(); //nab our control object for this client teleportUp(%controlObject,%dist); //teleport our object commandToClient( %cl, 'AcknowledgeTeleport', %dist); //send the command to the client } }

//teleport our control object up! function teleportUp(%controlObject, %distance) { %pos = %controlObject.position; //nab position

%height = getWord(%pos,2); //get the current height

%height += %distance; //add the distance

%pos = setWord(%pos, 2, %height); //set the position

%controlObject.position = %pos; //set the control the position of the object }


Execution Setup

Now, go to game/scripts/main.cs, and add the following under where the normal init.cs scripts are executed, so we can execute our new scripts:

// Load the scripts that start it all...
exec("./client/init.cs");
exec("./server/init.cs");

//add our own command scripts exec("./client/myClientCommands.cs"); //exec our client commands exec("./server/myServerCommands.cs"); //exec our server commands


Mission Setup

Finally, go to game/core/scripts/client/mission.cs, and add the following line at the end of the clientStartMission() script function, after $Client::missionRunning = true;, this is so a client can trigger the teleport sequence whenever they enter the game:

//…

// Done.

$Client::missionRunning = true;

sendTeleportSignal(); //start our teleportation sequence


(click to enlarge)



And that is all there is to it! Every time a new client Joins the party, everyone gets teleported a random distance. Now that you know how to make your own client and server scripts, you can start working on your own networking ideas.


Further Reading

For further reading and a deeper understanding of Torque's Netcode, check out:

<script type="text/javascript"> var links = document.getElementsByTagName('a'); for (var i = 0; i < links.length; i++) if (links[i].className == 'livethumbnail') { var img = links[i].getElementsByTagName('img')[0]; img.state = 'small'; img.smallSrc = img.getAttribute('src'); img.smallWidth = parseInt(img.getAttribute('width')); img.smallHeight = parseInt(img.getAttribute('height')); img.largeSrc = links[i].getAttribute('href'); img.largeWidth = parseInt(img.getAttribute('largewidth')); img.largeHeight = parseInt(img.getAttribute('largeheight')); img.ratio = img.smallHeight / img.smallWidth; links[i].onclick = scale; } function scale() { var img = this.getElementsByTagName('img')[0]; img.src = img.smallSrc; if (! img.preloaded) { img.preloaded = new Image(); img.preloaded.src = img.largeSrc; } var interval = window.setInterval(scaleStep, 10); return false; function scaleStep() { var step = 45; var width = parseInt(img.getAttribute('width')); var height = parseInt(img.getAttribute('height')); if (img.state == 'small') { width += step; height += Math.floor(step * img.ratio); img.setAttribute('width', width); img.setAttribute('height', height); if (width > img.largeWidth - step) { img.setAttribute('width', img.largeWidth); img.setAttribute('height', img.largeHeight); img.setAttribute('src', img.largeSrc); window.clearInterval(interval); img.state = 'large'; } } else { width -= step; height -= Math.floor(step * img.ratio); img.setAttribute('width', width); img.setAttribute('height', height); if (width < img.smallWidth + step) { img.setAttribute('width', img.smallWidth); img.setAttribute('height', img.smallHeight); img.src = img.smallSrc; window.clearInterval(interval); img.state = 'small'; } } } } </script>
Clone this wiki locally