Selected Common Code Client Modules


Next, we will take a close look at some of the common code client modules. The modules selected are the ones that will best help illuminate how Torque operates.

Keep in mind that all of these modules are designed to affect things that concern the local client, even though they might require contacting the server from time to time.

This point is important: When you add features or capabilities, you must always keep in mind whether you want the feature to affect only the local client (such as some user preference change) or you want the feature to affect all clients. In the latter case it would be best to use modules that are server-resident when they run.

The Canvas Module

The Canvas module is another one of those simple, small, but critical modules. One of the key features of this module is that the primary function contained in here, InitCanvas, loads a number of general graphical user interface support modules. This module is loaded from the InitCommon function, rather than from the InitBaseClient function, which is where the rest of the key common modules get loaded. Here are the contents of the common/client/canvas.cs module.

 //----------------------------------------------------------------------------- // Torque Game Engine // // Copyright (c) 2001 GarageGames.com //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Function to construct and initialize the default canvas window // used by the games function InitCanvas(%windowName) {    VideoSetGammaCorrection($pref::OpenGL::gammaCorrection);    if (!CreateCanvas(%windowName)) {       Quit();       return;    }    SetOpenGLTextureCompressionHint( $pref::OpenGL::compressionHint );    SetOpenGLAnisotropy( $pref::OpenGL::anisotropy );    SetOpenGLMipReduction( $pref::OpenGL::mipReduction );    SetOpenGLInteriorMipReduction( $pref::OpenGL::interiorMipReduction );    SetOpenGLSkyMipReduction( $pref::OpenGL::skyMipReduction );    // Declare default GUI Profiles.    Exec("~/ui/defaultProfiles.cs");    // Common GUI's    Exec("~/ui/GuiEditorGui.gui");    Exec("~/ui/ConsoleDlg.gui");    Exec("~/ui/InspectDlg.gui");    Exec("~/ui/LoadFileDlg.gui");    Exec("~/ui/SaveFileDlg.gui");    Exec("~/ui/MessageBoxOkDlg.gui");    Exec("~/ui/MessageBoxYesNoDlg.gui");    Exec("~/ui/MessageBoxOKCancelDlg.gui");    Exec("~/ui/MessagePopupDlg.gui");    Exec("~/ui/HelpDlg.gui");    Exec("~/ui/RecordingsDlg.gui");    // Commonly used helper scripts    Exec("./metrics.cs");    Exec("./messageBox.cs");    Exec("./screenshot.cs");    Exec("./cursor.cs");    Exec("./help.cs"); } function ResetCanvas() {    if (IsObject(Canvas))    {       Canvas.Repaint();    } } 

InitCanvas is obviously the main function in this module. When it is called, it first calls VideoSetGammaCorrection using a global preferences variable. If the value passed is 0 or undefined, then there is no change in the gamma correction (see Table 7.1).

Table 7.1: OpenGL Settings

Module

Function

GammaCorrection

Gamma correction modifies the overall brightness of an image. Images that are not corrected can look either overbleached or too dark.

TextureCompressionHint

The choice of how much texture compression (to reduce memory and graphics transfer bandwidth) to employ is left up to the drivers and hardware, but we can hint at how we would like the compression to work, if feasible. Valid hints are:

    GL_DONT_CARE    GL_FASTEST    GL_NICEST 

Anisotropy

Anisotropic filtering is used to address a specific kind of texture artifact that occurs when a 3D surface is sloped relative to the view camera. The higher the value set for this (between 0 and 1, exclusive), the more filtering is performed by the hardware. Too high a setting might cause too much fuzziness in an image.

MipReduction

See Chapter 3 for a discussion of mipmapping. This value can be from 0 to 5. The higher the number, the more mipmapping levels supported. Image textures must be created to support these levels in order to achieve the best effect.

InteriorMipReduction

The same as MipReduction, but for use in interiors (.dif file format models).

SkyMipReduction

The same as MipReduction, but for use in skybox images.

Then we attempt to create the canvas, which is an abstracted call to the Windows API to create a window. The %windowName variable is passed in as a string that sets the window's title. If we can't create the window, we quit because there is no point continuing without any means to display our game.

Following that, there is a series of OpenGL settings, again using global preference variables. See Table 7.1 for an explanation of these settings.

Next, the function loads a bunch of support files that establish user interface mechanisms, dialogs, and profiles for describing them.

Then there is a series of calls to load modules that provide access to some common utility functions that can be used for measuring performance, taking screen shots, displaying Help information, and so on.

The ResetCanvas function checks to see if a canvas object exists, and if so, ResetCanvas then forces it to be repainted (re-rendered).

The Mission Module

The Mission module doesn't really do much. Its existence is no doubt because some fore-thought had been given to future expansion directions for the common code scripts. Here are the contents of the common/client/mission.cs module.

 //----------------------------------------------------------------------------- // Torque Game Engine // // Copyright (c) 2001 GarageGames.com //----------------------------------------------------------------------------- //---------------------------------------------------------------------------- // Mission start / end events sent from the server //---------------------------------------------------------------------------- function ClientCmdMissionStart(%seq) {    // The client receives a mission start right before    // being dropped into the game. } function ClientCmdMissionEnd(%seq) {    // Disable mission lighting if it's going; this is here    // in case the mission ends while we are in the process    // of loading it.    $lightingMission = false;    $sceneLighting::terminateLighting = true; } 

ClientCmdMissionStart is a stub routine—not much to say here other than this routine gets called immediately before the client-player finds himself in the game. This is a handy place for last-minute client-side code—the mission is known and loaded, and all objects are ghosted, including any remote clients. This might be a good place to build and display a map or to possibly fire up an Internet Relay Chat session, if you have written one for yourself in Torque Script (it is possible—a member of the GarageGames community has done just that).

ClientCmdMissionEnd resets some lighting variables. This would be the place to undo anything you started in the ClientCmdMissionStart function.

The thing that makes this module, and therefore its functions, key is its existence. You should consider utilizing these functions in your game and expanding their functionality.

The MissionDownload Module

Just as the server side has a module called MissionDownload, so has the client code. It certainly can be confusing, so you have to stay on your toes when dealing with these modules, always being aware of whether you are dealing with the client or the server version. The choice of names is understandable though, when you realize that they are functionally complementary—the mission download activity required synchronized and coordinated actions from both the client and the server. Two peas in a pod.

Here are the contents of the common/client/missiondownload.cs module.

 //----------------------------------------------------------------------------- // Torque Game Engine // // Copyright (c) 2001 GarageGames.com //----------------------------------------------------------------------------- //---------------------------------------------------------------------------- // Phase 1 //---------------------------------------------------------------------------- function ClientCmdMissionStartPhase1(%seq, %missionName, %musicTrack) {    // These need to come after the cls.    Echo ("*** New Mission: " @ %missionName);    Echo ("*** Phase 1: Download Datablocks & Targets");    OnMissionDownloadPhase1(%missionName, %musicTrack);    CommandToServer('MissionStartPhase1Ack', %seq); } function OnDataBlockObjectReceived(%index, %total) {    OnPhase1Progress(%index / %total); } //---------------------------------------------------------------------------- // Phase 2 //---------------------------------------------------------------------------- function ClientCmdMissionStartPhase2(%seq,%missionName) {    onPhase1Complete();    Echo ("*** Phase 2: Download Ghost Objects");    purgeResources();    onMissionDownloadPhase2(%missionName);    commandToServer('MissionStartPhase2Ack', %seq); } function OnGhostAlwaysStarted(%ghostCount) {    $ghostCount = %ghostCount;    $ghostsRecvd = 0; } function OnGhostAlwaysObjectReceived() {    $ghostsRecvd++;    OnPhase2Progress($ghostsRecvd / $ghostCount); } //---------------------------------------------------------------------------- // Phase 3 //---------------------------------------------------------------------------- function ClientCmdMissionStartPhase3(%seq,%missionName) {    OnPhase2Complete();    StartClientReplication();    StartFoliageReplication();    Echo ("*** Phase 3: Mission Lighting");    $MSeq = %seq;    $Client::MissionFile = %missionName;    // Need to light the mission before we are ready.    // The sceneLightingComplete function will complete the handshake    // once the scene lighting is done.    if (LightScene("SceneLightingComplete", ""))    {       Error("Lighting mission....");       schedule(1, 0, "UpdateLightingProgress");       OnMissionDownloadPhase3(%missionName);       $lightingMission = true;    } } function UpdateLightingProgress() {    OnPhase3Progress($SceneLighting::lightingProgress);    if ($lightingMission)       $lightingProgressThread = schedule(1, 0, "UpdateLightingProgress"); } function SceneLightingComplete() {    Echo("Mission lighting done");    OnPhase3Complete();    // The is also the end of the mission load cycle.    OnMissionDownloadComplete();    CommandToServer('MissionStartPhase3Ack', $MSeq); } 

When reviewing this module, you should refer back to the server-side MissionDownload module descriptions and Figures 7.1 and 7.2.

The first function for phase one, ClientCmdMissionStartPhase1, calls the function OnMissionDownloadPhase1, which is something you want to define in your control code. Its basic purpose is to set up for a progress display as the datablocks are loaded. As soon as this call returns, an acknowledgment is sent back to the server using CommandToServer to send the MissionStartPhase1Ack message back. At this time it also reflects the sequence number (%seq) back to the server, to ensure that the client and server remain synchronized.

The next function, OnDataBlockObjectReceived, is an important one. This message handler gets called every time the Torque Engine client-side code detects that it has finished receiving a datablock. When invoked, it then calls onPhase1Progress, which needs to be defined in our control client code.

The next function, ClientCmdMissionStartPhase2, is part of the phase two activities. Its duties are much the same as for ClientCmdMissionStartPhase1, but this time using OnMissionDownloadPhase2 and MissionStartPhase2Ack.

The next function, OnGhostAlwaysStarted, is called by the engine after it processes the MissionStartPhase2Ack message. It is used to track ghosted object counts.

When an object has been successfully ghosted, onGhostAlwaysObjectReceived is called from the engine. We use this to call onPhase2Progress in order to update our progress display.

The ClientCmdMissionStartPhase3 function is the last in the series. When it is called, we update our progress display and then turn on two client-side replication functions. These functions provide special objects (such as grass and trees) that will be computed and rendered only by the client. For example, the server sends a seed for the location of a tuft of grass. The client-side replication code calculates the locations of hundreds or even thousands of copies of this tuft of grass and distributes them appropriately.

Because these objects are deemed not to be critical for game play, we can take the risk of client-side computation without risking someone modifying the code to cheat. Someone could modify the code, but it wouldn't gain him any online advantage.

Next we call the function LightScene to perform the scene's terrain and interior lighting passes. We pass the completion callback function SceneLightingComplete, which will be called when the lighting calculations are finished.

We also schedule a function (UpdateLightingProgress) to be repeatedly called while the lighting is under way, as follows:

 schedule(1, 0, "updateLightingProgress"); 

In this case the function is called after one millisecond.

UpdateLightingProgress is a short function. It makes a call to update the progress display and then schedules itself to be called again in another millisecond if the lighting is not finished. It can tell if the lighting is finished by checking the variable $lightingMission. If it is true, then lighting is still under way.

SceneLightingComplete is the completion callback passed to LightScene. When SceneLighting-Complete is called, lighting has completed, so it sets the variable $lightingMission to false, which will eventually, within a millisecond or so, be detected by UpdateLightingProgress. It then notifies the server that lighting is complete by sending the MissionStartPhase3Ack message. And away we go!

The Message Module

The Message module provides front-end generic message handlers for two defined message types, as well as a tool for installing handlers at run time. You may or may not find this useful, but a look at how these functions work will help when it comes to creating your own sophisticated messaging system. Here are the contents of the common/client/message.cs module.

 //----------------------------------------------------------------------------- // Torque Game Engine // // Copyright (c) 2001 GarageGames.com // Portions Copyright (c) 2001 by Sierra Online, Inc. //----------------------------------------------------------------------------- function ClientCmdChatMessage(%sender, %voice, %pitch, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10) {    OnChatMessage(detag(%msgString), %voice, %pitch); } function ClientCmdServerMessage(%msgType, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10) {    // Get the message type; terminates at any whitespace.    %tag = GetWord(%msgType, 0);    // First see if there is a callback installed that doesn't have a type;    // if so, that callback is always executed when a message arrives.    for (%i = 0; (%func = $MSGCB["", %i]) !$= ""; %i++) {       call(%func, %msgType, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10);    }    // Next look for a callback for this particular type of ServerMessage.    if (%tag !$= "") {       for (%i = 0; (%func = $MSGCB[%tag, %i]) !$= ""; %i++) {          call(%func, %msgType, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10);       }    } } function AddMessageCallback(%msgType, %func) {    for (%i = 0; (%afunc = $MSGCB[%msgType, %i]) !$= ""; %i++) {       // If it already exists as a callback for this type,       // nothing to do.       if (%afunc $= %func) {          return;       }    }    // Set it up.    $MSGCB[%msgType, %i] = %func; } function DefaultMessageCallback(%msgType, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10) {    OnServerMessage(detag(%msgString)); } AddMessageCallback("", DefaultMessageCallback); 

The first function, ClientCmdChatMessage, is for chat messages only and is invoked on the client when the server uses the CommandToClient function with the message type ChatMessage. Refer back to the server-side message module if you need to. The first parameter (%sender) is the GameConnection object handle of the player that sent the chat message. The second parameter (%voice) is an Audio Voice identifier string. Parameter three (%pitch) will also be covered in the audio chapter later. Finally, the fourth parameter (%msgString) contains the actual chat message in a tagged string. The rest of the parameters are not actually acted on so can be safely ignored for now. The parameters are passed on to the pseudo-handler OnChatMessage. It's called a pseudo-handler because the function that calls OnChatMessage is not really calling out from the engine. However, it is useful to treat this operation as if a callback message and handler were involved for conceptual reasons.

The next function, ClientCmdServerMessage, is used to deal with game event descriptions, which may or may not include text messages. These can be sent using the message functions in the server-side Message module. Those functions use CommandToClient with the type ServerMessage, which invokes the function described next.

For ServerMessage messages, the client can install callbacks that will be run according to the type of the message.

Obviously, ClientCmdServerMessage is more involved. After it uses the GetWord function to extract the message type as the first text word from the string %msgType, it iterates through the message callback array ($MSGCB) looking for any untyped callback functions and executes them all. It then goes through the array again, looking for registered callback functions with the same message type as the incoming message, executing any that it finds.

The next function, addMessageCallback, is used to register callback functions in the $MSGCB message callback array. This is not complex; addMessageCallback merely steps through the array looking for the function to be registered. If it isn't there, addMessageCallback stores a handle to the function in the next available slot.

The last function, DefaultMessageCallback, is supplied in order to provide an untyped message to be registered. The registration takes place with the line after the function definition.




3D Game Programming All in One
3D Game Programming All in One (Course Technology PTR Game Development Series)
ISBN: 159200136X
EAN: 2147483647
Year: 2006
Pages: 197

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net