Game Development Community

dev|Pro Game Development Curriculum

Environment Package Save/Load System

by Michael Perry · 01/22/2008 (7:25 am) · 4 comments

GENERAL INFO AND INTRODUCTION
This resource introduces a package save/load system to Torque's WorldEditor. Using the new Save Package GUI, with only a few mouse clicks you can export any combination of environment objects(Sun, Sky, foliage, precipitation, BG Forest, etc) to a package file. Instead of manually recreating these objects, or copying and pasting them in script, you can use the Load Package GUI to add the saved environment to your other missions.

This resource came about at the request of Steve "Asian Steve" Ngu, lead level developer for Zombie Shortbus. Steve wanted a module the mission creation team could use to rapidly reproduce environments for levels which share geographic zones. For instance, we will have two missions with dissimilar game play objectives, entities, and terrain. However, the missions are located near each other geographically, and share a similar time frame.

What if one mission is a wetland, with lush foliage and forestry, overcast by heavy rain and wind? Through that description, you will probably modify the Sun and Sky, add Precipitation, foliage replicators, shape replicators, Ben Garney's Forest Pack, and more.

The second mission takes place 4 hours later, 9 miles away. Your options are to copy and paste files/scripts, manually recreate the objects, or use this resource.

SETUP
This resource was developed in following environment:

Engine Version - TGE/AFX 1.5.2
Compiler - MS Visual Studio 2005
Script IDE - Torsion

You will be modifying 1 engine file, editing 2 script files, and adding 2 GUIs. On to the good stuff. . .

Step 1: Download the files: (PackageSystemResource.zip)

Step 2: Back up original files:
  • engineconsolesimbase.cc[li]examplecommonclientcanvas.cs[li]examplecreatoreditorEditorGui.cs
Step 3: Copy new files:
  • Copy SavePackageDlg.gui and LoadPackageDlg.gui into the examplecommonui directory
Step 4: Building:
  • Open engineconsolesimbase.cc and add the following:
  • ///////////////////////////////////////
    // Stole from engineguiguiDebugger.cc
    static const char* itoa(S32 i)
    {
       static char buf[32];
       dSprintf(buf, sizeof(buf), "%d", i);
       return buf;
    }
    ConsoleMethod(SimSet, getObjects, const char*, 3, 3, "set.getObjects("className")")
    {
    	argc; argv;
    
    	U32 iBufferSize = 0;				// Will determine size of return string
    	Vector<S32> myVec;					// Will store IDs of the objects we find
    	const char* searchType = argv[2];	// Find out what we are looking for
    	
    	// Iterate through the simset (missiongroup)
    	object->lock();
    	SimSet::iterator itr;
    	for(itr = object->begin(); itr != object->end(); itr++)
    	{
    		SimObject *obj = *itr;
    		
    		// Get the className of the current object in interation
    		const char *className = obj->getClassName();
    
    		// Is the current object in interation the same as what we are looking for?
    		if(!dStrcmp(className, searchType))
    			myVec.push_back(obj->getId());		// Yes, so add it to our vector
    	}
    	object->unlock();
    	
    	// Allocate memory for the return buffer
    	iBufferSize = myVec.size()*5*sizeof(SimObjectId);
    
    	// Create a return buffer (string format)
    	char* retBuffer = Con::getReturnBuffer(iBufferSize);
    	
    	// Clear out the buffer(paranoia check)
    	dStrcpy(retBuffer, "");
    
    	// Iterate our vector and fill up our returnBuffer
    	for(int j = 0; j < myVec.size(); j++)
    	{
    		// Add the ID in string format
    		dStrcat(retBuffer, itoa(myVec[j]));
    
    		// Add a space between IDs
    		dStrcat(retBuffer," ");
    	}
    	// Return
    	return retBuffer;
    }
  • I added this just before the listObjects Console Method[li]Recompile the Debug and Release executables
Step 5: Script Changes:
  • In examplecommonclientcanvas.cs, modify the initCanvas function to look like this:
  • //-----------------------------------------------------------------------------
    // Function to construct and initialize the default canvas window
    // used by the games
    
    function initCanvas(%windowName, %effectCanvas)
    {
       ...
    
       // Common GUI's
       
       [b]// Package guis
       exec("~/ui/SavePackageDlg.gui");
       exec("~/ui/LoadPackageDlg.gui");
       [/b]   
       
       // Commonly used helper scripts
    
       ...
    }

  • In examplecreatoreditorEditorGui.cs, modify EditorGui::init(%this):

  • Swap
    EditorMenuBar.clearMenus();
       EditorMenuBar.addMenu("File", 0);
       EditorMenuBar.addMenuItem("File", "New Mission...", 1);
       EditorMenuBar.addMenuItem("File", "Open Mission...", 2, "Ctrl O");
       EditorMenuBar.addMenuItem("File", "Save Mission...", 3, "Ctrl S");
       EditorMenuBar.addMenuItem("File", "Save Mission As...", 4);
       EditorMenuBar.addMenuItem("File", "-", 0);
       EditorMenuBar.addMenuItem("File", "Import Terraform Data...", 6);
       EditorMenuBar.addMenuItem("File", "Import Texture Data...", 5);
       EditorMenuBar.addMenuItem("File", "-", 0);
       EditorMenuBar.addMenuItem("File", "Export Terraform Bitmap...", 5);
       EditorMenuBar.addMenuItem("File", "-", 0);
       EditorMenuBar.addMenuItem("File", "Toggle Map Editor...", 7, "F11");
       EditorMenuBar.addMenuItem("File", "Quit", 8);

    With
    EditorMenuBar.clearMenus();
       EditorMenuBar.addMenu("File", 0);
       EditorMenuBar.addMenuItem("File", "New Mission...", 1);
       EditorMenuBar.addMenuItem("File", "Open Mission...", 2, "Ctrl O");
       EditorMenuBar.addMenuItem("File", "Save Mission...", 3, "Ctrl S");
       EditorMenuBar.addMenuItem("File", "Save Mission As...", 4);
       EditorMenuBar.addMenuItem("File", "-", 0);
       EditorMenuBar.addMenuItem("File", "Import Terraform Data...", 6);
       EditorMenuBar.addMenuItem("File", "Import Texture Data...", 5);
       EditorMenuBar.addMenuItem("File", "-", 0);
       EditorMenuBar.addMenuItem("File", "Export Terraform Bitmap...", 5);
       EditorMenuBar.addMenuItem("File", "-", 0);
       [b]EditorMenuBar.addMenuItem("File", "Load Package...", 7);
       EditorMenuBar.addMenuItem("File", "Save Package...", 8);
       EditorMenuBar.addMenuItem("File", "-", 0);   [/b]
       EditorMenuBar.addMenuItem("File", "Toggle Map Editor...", 9, "F11");
       EditorMenuBar.addMenuItem("File", "Quit", 10);

  • In examplecreatoreditorEditorGui.cs, add two new case statements to EditorMenuBar::onFileMenuItemSelect:
  • . . .
    case "Load Package...":
             EditorLoadPackage();
          case "Save Package...":
             EditorSavePackageAs();
    . . .

Step 6: RTFM!
  • Open and read PackageReadme.doc for instructions on using the module
If you followed the steps properly (and if I didn't make any errors), you should have two new options under the WorldEditor File Menu. The usage is pretty straight forward, but you have a doc to follow just in case.

Bugs & Suggestions
If you look through the script code, you will come across comments like this:
//////////////////////////////
// NOTE # 1
//////////////////////////////

These are points of interest. Some notes merely draw your attention to code blocks important to this resource, while others point out code that is bugged or can be improved. For instance, the code under Note # 3 is volatile and could definitely benefit from an alternative method. My suggestion there is to use Orion Elenzil's findWord/findField/findRecord resource.

Also, you'll notice I am using the file extension ".pak." I chose this on a whim to separate the exported files from the rest of the scripts. However, .pak files are nothing more than .cs files with a different name. You can still open them with notepad, but Torsion seems to get stuck on them. You can change the file extension in the .gui files.

The big bug right now is found under Note # 4. You must manually relight your mission to get the proper shadowing of your objects. The big annoyance is that your foliage and shape replicators do not create and render their objects unless you click on each replicator in the World Inspector list. What happens here is that the message to create the foliage does not get fired off correctly when the replicators are executed from a client script. You will notice my first attempt to force the replication did not succeed, but I left the commented code in so you can attempt to resolve the issue if I can't.

More to come...

Conclusion and Updates
Post your thoughts and suggestions here in the resource so that together, we can improve the code.

Step_Two.jpg

#1
01/22/2008 (7:07 pm)
Great stuff Michael! Glad to see you're still keepin' busy. Shoot me an email when you can :-).
#2
01/25/2008 (8:40 am)
great idea! that's very cool
#3
10/13/2008 (9:08 am)
Ehy Michael, do you think would it be difficult to implement it in TGEA?

JoZ :-)
#4
06/13/2009 (9:46 am)
404 not found.