/// <summary> /// Rooms treeview after select /// </summary> private void tvRooms_AfterSelect(object sender, TreeViewEventArgs e) { // Get the currently selected node GMNode node = tvRooms.SelectedNode.Tag as GMNode; // If the node is a child node, disable room name (it will inherit the overwritten room's name), else enable it txtName.Text = node.NodeType == GMNodeType.Child ? node.Name : App.Room.Name; txtName.Enabled = node.NodeType == GMNodeType.Child ? false : true; Verify(); }
/// <summary> /// Gets a GMNode from a .net tree node. /// </summary> /// <param name="treeNode">The tree node to convert.</param> /// <returns>A Game Maker node.</returns> public static GMNode GetGMNodeFromTreeNode(TreeNode treeNode) { GMNode tag = new GMNode(); if (treeNode.Nodes != null) { tag = treeNode.Tag as GMNode; tag.Nodes = new GMNode[treeNode.Nodes.Count]; for (int i = 0; i < treeNode.Nodes.Count; i++) { tag.Nodes[i] = GetGMNodeFromTreeNode(treeNode.Nodes[i]); } } return(tag); }
/// <summary> /// Reads a Game Maker project file /// </summary> public void ReadProject(string file) { // If the file does not exist, throw exception if (File.Exists(file) == false) { throw new Exception("The Game Maker project file does not exist."); } // Get file extension string ext = file.Substring(file.LastIndexOf('.')).ToLower(); // If a GMS project file if (ext == ".gmx") { // Read in the project as a Game Maker Studio project and return ReadProjectGMS(file); return; } // Get file size FileInfo info = new FileInfo(file); long length = info.Length; // Create a new GM file reader using (GMFileReader reader = new GMFileReader(new FileStream(file, FileMode.Open, FileAccess.Read))) { // Progress event ProgressChanged("Starting project read...", reader.BaseStream.Position, length); // Read the magic number int id = reader.ReadGMInt(); // If the magic number was incorrect, not a Game Maker project file if (id != 1234321) { throw new Exception("Not a valid Game Maker project file."); } // Get Game Maker project file version int version = reader.ReadGMInt(); // Check version switch (version) { case 500: this.GameMakerVersion = GMVersionType.GameMaker50; break; case 510: this.GameMakerVersion = GMVersionType.GameMaker51; break; case 520: this.GameMakerVersion = GMVersionType.GameMaker52; break; case 530: this.GameMakerVersion = GMVersionType.GameMaker53; break; case 600: this.GameMakerVersion = GMVersionType.GameMaker60; break; case 701: this.GameMakerVersion = GMVersionType.GameMaker70; break; case 800: this.GameMakerVersion = GMVersionType.GameMaker80; break; case 810: this.GameMakerVersion = GMVersionType.GameMaker81; break; } // Skip over reserved bytes if (version < 600) { reader.ReadGMBytes(4); } // Game Maker 7 project file encryption if (version == 701) { // Bill and Fred, psssttt they like each other ;) int bill = reader.ReadGMInt(); int fred = reader.ReadGMInt(); // Skip bytes to treasure. reader.ReadGMBytes(bill * 4); // Get the seed for swap table int seed = reader.ReadGMInt(); // Skip bytes to get out of the junk yard reader.ReadGMBytes(fred * 4); // Read first byte of Game id (Not encrypted) byte b = reader.ReadByte(); // Set the seed reader.SetSeed(seed); // Read game id id = reader.ReadGMInt(b); } else // Read game id normally { id = reader.ReadGMInt(); } // Skip unknown bytes reader.ReadGMBytes(16); // Read settings ProgressChanged("Reading Settings...", reader.BaseStream.Position, length); // Read main project objects this.Settings = GMSettings.ReadSettings(reader); this.Settings.GameIdentifier = id; // If the version is greater than Game Maker 7.0 if (version > 701) { // Read triggers and constants. this.Triggers = GMTrigger.ReadTriggers(reader); this.Settings.Constants = GMConstant.ReadConstants(reader); } // Read sounds ProgressChanged("Reading Sounds...", reader.BaseStream.Position, length); this.Sounds = GMSound.ReadSounds(reader); // Read sprites ProgressChanged("Reading Sprites...", reader.BaseStream.Position, length); this.Sprites = GMSprite.ReadSprites(reader); // Read backgrounds ProgressChanged("Reading Backgrounds...", reader.BaseStream.Position, length); this.Backgrounds = GMBackground.ReadBackgrounds(reader); // Read paths ProgressChanged("Reading Paths...", reader.BaseStream.Position, length); this.Paths = GMPath.ReadPaths(reader); // Read scripts ProgressChanged("Reading Scripts...", reader.BaseStream.Position, length); this.Scripts = GMScript.ReadScripts(reader); // Get version int version2 = reader.ReadGMInt(); // Check version if (version2 != 440 && version2 != 540 && version2 != 800) { throw new Exception("Unsupported Pre-Font/Pre-Data File object version."); } // If version is old, read data files else, read fonts. if (version2 == 440) { // Read data files ProgressChanged("Reading Data Files...", reader.BaseStream.Position, length); this.DataFiles = GMDataFile.ReadDataFiles(reader); } else { // Read fonts ProgressChanged("Reading Fonts...", reader.BaseStream.Position, length); this.Fonts = GMFont.ReadFonts(version2, reader); } // Read timelines ProgressChanged("Reading Timelines...", reader.BaseStream.Position, length); this.Timelines = GMTimeline.ReadTimelines(reader); // Read objects ProgressChanged("Reading Objects...", reader.BaseStream.Position, length); this.Objects = GMObject.ReadObjects(reader); // Read rooms ProgressChanged("Reading Rooms...", reader.BaseStream.Position, length); this.Rooms = GMRoom.ReadRooms(this.Objects, reader); // Read last ids for instances and tiles this.LastInstanceId = reader.ReadGMInt(); this.LastTileId = reader.ReadGMInt(); // If the version is above 6.1, read include files and packages if (version >= 700) { // Read includes ProgressChanged("Reading Includes...", reader.BaseStream.Position, length); this.Settings.Includes = GMInclude.ReadIncludes(reader); // Read packages ProgressChanged("Reading Packages...", reader.BaseStream.Position, length); this.Packages.AddRange(GMPackage.ReadPackages(reader)); } // Read game information ProgressChanged("Reading Game Information...", reader.BaseStream.Position, length); this.GameInformation = GMGameInformation.ReadGameInformation(reader); // Get version version = reader.ReadGMInt(); // Check version if (version != 500) { throw new Exception("Unsupported Post-Game Information object version."); } // Read libraries ProgressChanged("Reading Libraries...", reader.BaseStream.Position, length); this.Libraries = GMLibrary.ReadLibraries(reader); // Read project tree ProgressChanged("Reading Project Tree...", reader.BaseStream.Position, length); this.ProjectTree = GMNode.ReadTree(file.Substring(file.LastIndexOf(@"\") + 1), reader); // Progress event ProgressChanged("Finished Reading Project.", reader.BaseStream.Position, length); } }
/// <summary> /// Reads a Game Maker Studio project file /// </summary> private void ReadProjectGMS(string file) { // Set version GameMakerVersion = GMVersionType.GameMakerStudio; // Path with project file removed string folder = file.Remove(file.LastIndexOf("\\")); // Set up resource directory strings Dictionary <GMResourceType, string> directories = new Dictionary <GMResourceType, string>(); directories.Add(GMResourceType.Assets, file); directories.Add(GMResourceType.DataFiles, file); directories.Add(GMResourceType.Configs, file); directories.Add(GMResourceType.Constants, file); directories.Add(GMResourceType.Hash, file); directories.Add(GMResourceType.Backgrounds, folder + "\\" + "background"); directories.Add(GMResourceType.Objects, folder + "\\" + "objects"); directories.Add(GMResourceType.Rooms, folder + "\\" + "rooms"); directories.Add(GMResourceType.Sprites, folder + "\\" + "sprites"); directories.Add(GMResourceType.Sounds, folder + "\\" + "sound"); directories.Add(GMResourceType.TimeLines, folder + "\\" + "timelines"); directories.Add(GMResourceType.Shaders, folder + "\\" + "shaders"); directories.Add(GMResourceType.Scripts, folder + "\\" + "scripts"); directories.Add(GMResourceType.Paths, folder + "\\" + "paths"); // Resource load index int index = 0; // Iterate through directories foreach (KeyValuePair <GMResourceType, string> item in directories) { // Increment directory index index++; // If the directory does not exist, continue if (Path.GetExtension(item.Value) != ".gmx" && !Directory.Exists(item.Value)) { continue; } // Progress changed ProgressChanged("Reading " + item.Key.ToString() + "...", index, directories.Count); // Load data based on resource type switch (item.Key) { case GMResourceType.Hash: Settings.Hash = ReadHashGMX(item.Value); break; case GMResourceType.Assets: ProjectTree = GMNode.ReadTreeGMX(item.Value); Assets = (List <string>)ProjectTree.Tag; break; case GMResourceType.DataFiles: DataFiles = GMDataFile.ReadDataFilesGMX(item.Value, out LastDataFileId); break; case GMResourceType.Sprites: Sprites = GMSprite.ReadSpritesGMX(item.Value, ref Assets); break; //case GMResourceType.Configs: Settings.Configs = GMSettings.GetConfigsGMX(item.Value); break; //case GMResourceType.Constants: Settings.Constants = GMSettings.ReadConstantsGMX(item.Value); break; case GMResourceType.Backgrounds: Backgrounds = GMBackground.ReadBackgroundsGMX(item.Value, ref Assets); break; case GMResourceType.Objects: Objects = GMObject.ReadObjectsGMX(item.Value, ref Assets); break; case GMResourceType.Rooms: Rooms = GMRoom.ReadRoomsGMX(item.Value, ref Assets, out LastTileId); break; //case GMResourceType.TimeLines: Timelines = GMTimeline.ReadTimelinesGMX(item.Value, Assets); break; //case GMResourceType.Sounds: Sounds = GMSound.ReadSoundsGMX(item.Value, ref Assets); break; //case GMResourceType.Shaders: Shaders = GMShader.ReadShadersGMX(item.Value, ref Assets); break; //case GMResourceType.Scripts: Scripts = GMScript.ReadScriptsGMX(item.Value, ref Assets); break; //case GMResourceType.Paths: Paths = GMPath.ReadPathsGMX(item.Value, ref Assets); break; //case GMResourceType.TimeLines: Timelines = GMTimeline.ReadTimelinesGMX(item.Value, Assets); break; } } // Retrieve tutorial data foreach (GMNode node in ProjectTree.Nodes) { // If the node is the tutorial state node and it has the nodes we're looking for if (node.ResourceType == GMResourceType.TutorialState && node.Nodes != null && node.Nodes.Length == 3) { Settings.IsTutorial = node.Nodes[0].Nodes == null ? Settings.IsTutorial : GMResource.GMXBool(node.Nodes[0].Nodes[0].Name, true); Settings.TutorialName = node.Nodes[1].Nodes == null ? Settings.TutorialName : GMResource.GMXString(node.Nodes[1].Nodes[0].FilePath, ""); Settings.TutorialPage = node.Nodes[2].Nodes == null ? Settings.TutorialPage : GMResource.GMXInt(node.Nodes[2].Nodes[0].Name, 0); } } // Progress event ProgressChanged("Finished Reading Project.", index, directories.Count); }
/// <summary> /// Reads a Game Maker tree node recursively. /// </summary> private void ReadNodeRecursive(GMNode parent) { // Iterate through child nodes. foreach (GMNode node in parent.Nodes) { // Read node data. node.NodeType = (GMNodeType)(ReadInt()); node.ResourceType = (GMResourceType)(ReadInt()); node.Id = ReadInt(); node.Name = ReadString(); node.Children = ReadInt(); // If the node has child nodes. if (node.Children > 0) { // Create a new node array. node.Nodes = new GMNode[node.Children]; // Iterate through children. for (int i = 0; i < node.Children; i++) { // Add new node. node.Nodes[i] = new GMNode(); } // Read in child nodes recursively. ReadNodeRecursive(node); } } }
/// <summary> /// Reads Object Tree from GM file /// </summary> private GMNode ReadTree(string name) { // Get version. int version = ReadInt(); // Check version. if (version != 500 && version != 540 && version != 700) throw new Exception("Unsupported Project Tree object version."); // Room execution Order. ReadBytes(ReadInt() * 4); // Set the number of main resource nodes. int rootNum = (version > 540) ? 12 : 11; // Create a project node; GMNode projectTree = new GMNode(); projectTree.Nodes = new GMNode[rootNum]; projectTree.Name = name; projectTree.NodeType = GMNodeType.Parent; projectTree.Children = projectTree.Nodes.Length; // Iterate through Game Maker project root nodes for (int i = 0; i < rootNum; i++) { // Create new node GMNode node = new GMNode(); // Read node data. node.NodeType = (GMNodeType)(ReadInt()); node.ResourceType = (GMResourceType)(ReadInt()); node.Id = ReadInt(); node.Name = ReadString(); node.Children = ReadInt(); // If there is at least one child node. if (node.Children > 0) { // Create a new node array. node.Nodes = new GMNode[node.Children]; // Iterate through children. for (int j = 0; j < node.Children; j++) { // Add new node. node.Nodes[j] = new GMNode(); } // Read in child nodes recursively. ReadNodeRecursive(node); } // Add new main node. projectTree.Nodes[i] = node; } // Return project tree. return projectTree; }
/// <summary> /// Converts a GMNode to a drop down menu item. Stores original GM node data in tag property. /// </summary> /// <param name="node">The GMNode to convert.</param> /// <returns>A drop down item of the GMNode.</returns> private ToolStripDropDownItem GetMenuFromGMNode(GMNode node) { // Set-up tree node. ToolStripMenuItem menu = new ToolStripMenuItem(); menu.Text = node.Name; menu.Tag = node; // Set dropdown menu item image. if (node.NodeType == GMNodeType.Group) menu.Image = GMare.Properties.Resources.file_close; else { // Get GM object based on id. GMareObject obj = _objects.Find(delegate(GMareObject o) { return o.Resource.Id == node.Id; }); // If an object was found, set image. if (obj != null) menu.Image = obj.Image; } // If no child nodes, return the top item. if (node.Nodes == null) return menu; // Iterate through nodes. for (int i = 0; i < node.Children; i++) { // Add a dropdown menu item. menu.DropDownItems.Add(GetMenuFromGMNode(node.Nodes[i])); } // Return a dropdown menu item. return menu; }
/// <summary> /// Reads a Game Maker tree node recursively. /// </summary> private void WriteNodeRecursive(GMNode parent) { // Write node data. WriteInt((int)parent.NodeType); WriteInt((int)parent.ResourceType); WriteInt(parent.Id); WriteString(parent.Name); WriteInt(parent.Children); if (parent.Nodes != null) { // Iterate through children. for (int i = 0; i < parent.Children; i++) { // Write child nodes recursively. WriteNodeRecursive(parent.Nodes[i]); } } }
/// <summary> /// Writes object tree from Game Maker project. /// </summary> private void WriteTree(GMNode rootNode, GMVersionType version) { // Write version number. if (version < GMVersionType.GameMaker60) WriteInt(500); else if (version == GMVersionType.GameMaker60) WriteInt(540); else if (version >= GMVersionType.GameMaker70) WriteInt(700); // Write room execution Order. WriteInt(0); // Set the number of main resource nodes. int rootNum = (version > GMVersionType.GameMaker60) ? 12 : 11; // Iterate through Game Maker project root nodes for (int i = 0; i < rootNum; i++) { // Write child nodes recursively. WriteNodeRecursive(rootNode.Nodes[i]); } }
/// <summary> /// Gets a .net tree node from a GM node. Stores original GM node data in tag property. /// </summary> /// <param name="node">The GM node to convert to treenode.</param> /// <returns>A tree node version of the GM node.</returns> public static TreeNode GetTreeNodeFromGMNode(GMNode node) { // Set-up tree node. TreeNode treeNode = new TreeNode(); treeNode.Text = node.Name; treeNode.Tag = node; switch (node.NodeType) { // If a child node, get appropriate resource key. case GMNodeType.Child: switch (node.ResourceType) { case GMResourceType.Rooms: treeNode.ImageKey = ImageKeyRoom; treeNode.SelectedImageKey = ImageKeyRoomSelected; break; } break; default: treeNode.ImageKey = ImageKeyGroup; treeNode.SelectedImageKey = ImageKeyGroupSelected; break; } // If no child nodes, return the top node. if (node.Nodes == null) return treeNode; // Iterate through nodes. for (int i = 0; i < node.Children; i++) { // Set the node. treeNode.Nodes.Add(GetTreeNodeFromGMNode(node.Nodes[i])); } // Return a .net tree node. return treeNode; }
/// <summary> /// Gets a GMNode from a .net tree node. /// </summary> /// <param name="treeNode">The tree node to convert.</param> /// <returns>A Game Maker node.</returns> public static GMNode GetGMNodeFromTreeNode(TreeNode treeNode) { GMNode tag = new GMNode(); if (treeNode.Nodes != null) { tag = treeNode.Tag as GMNode; tag.Nodes = new GMNode[treeNode.Nodes.Count]; for (int i = 0; i < treeNode.Nodes.Count; i++) { tag.Nodes[i] = GetGMNodeFromTreeNode(treeNode.Nodes[i]); } } return tag; }
/// <summary> /// Ok button clicked /// </summary> private void butExport_Click(object sender, EventArgs e) { try { // Get the currently selected node GMNode node = tvRooms.SelectedNode.Tag as GMNode; // Create a new room GMRoom room; // If the node is a child node if (node.NodeType == GMNodeType.Child) { // Give warning about an overwrite DialogResult result = MessageBox.Show("Are you sure you want to overwrite room: " + node.Name + "?", "GMare", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2); // If not ok, return if (result != DialogResult.Yes) { return; } } // Create a backup of the original project file string filePath = MakeBackup(); // If the backup failed, return, else write the file if (filePath == "") { return; } // If the node is being overwritten, overwrite, else add the node if (node.NodeType == GMNodeType.Child) { // Find the room to overwrite room = _project.Rooms.Find(r => r.Id == node.Id); // Set room properties if (!SetRoomProperties(room, -1)) { // Notify the user that the export failed MessageBox.Show("An error occurred while exporting the room, export aborted.", "GMare", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; } } else { // Check for any resource doubles foreach (string asset in _project.Assets) { // If the asset already exists, return if (asset == txtName.Text) { MessageBox.Show("The game resource name already exists. Please use a unique name for this room. Export aborted.", "GMare", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); return; } } // Create a new room room = new GMRoom(); // Set room properties if (!SetRoomProperties(room, _project.Rooms.LastId++)) { // Give warning about an overwrite MessageBox.Show("An error occurred while exporting the room, export aborted.", "GMare", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; } // Add the room to the project _project.Rooms.Add(room); // Increase the amount of children for parent node (tvRooms.SelectedNode.Tag as GMNode).Children++; // Create a new tree node TreeNode treeNode = new TreeNode(room.Name); // Create a new Game Maker node GMNode newNode = new GMNode(); newNode.Name = room.Name; newNode.NodeType = GMNodeType.Child; newNode.ResourceType = GMResourceType.Rooms; newNode.ResourceSubType = GMResourceSubType.Room; newNode.Id = room.Id; newNode.FilePath = "rooms\\" + room.Name; // Set the tree node tag to Game Maker node treeNode.Tag = newNode; treeNode.ImageIndex = 2; // Add the new node to the tree tvRooms.SelectedNode.Nodes.Add(treeNode); } // Set room nodes _project.ProjectTree.Nodes[GetResourceIndex(GMResourceType.Rooms)] = GMUtilities.GetGMNodeFromTreeNode(tvRooms.Nodes[0]); // If refactor tiles, refactor if (chkRefactorTiles.Checked == true) { _project.RefactorTileIds(); } // If refactor instances, refactor if (chkRefactorInstances.Checked == true) { _project.RefactorInstanceIds(); } // If a game maker studio project and there is room data, wirte project if (_project.GameMakerVersion == GMVersionType.GameMakerStudio) { // If the room was never created, notify user if (room == null) { MessageBox.Show("There was an error creating the room to export. Export failed.", "GMare", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } else { // NOTE: Normally I would not do things this way. It should be the data that drives // the project file creation. However, we're only changing the room portion of the // project and it's just safer, as of now, to write only the project file and the // room vs. writing the entire project out. Luckily GM:S is modular and allows that // to happen GameMaker.Resource.GMNode.WriteTreeGMX(_projectPath, ref _project); GameMaker.Resource.GMRoom.WriteRoomGMX(room, Path.GetDirectoryName(_projectPath) + "\\" + "rooms"); } } // Legacy Game Maker project write else { _writer.WriteGMProject(_projectPath, _project, _project.GameMakerVersion); } // Display success message if (MessageBox.Show("Export complete. A backup of the original project was made. Do you want to open the directory it was copied to?", "GMare", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button2) == DialogResult.Yes) { Process.Start(filePath); } // Close the form Close(); } catch (Exception) { // Notify the user that the export failed MessageBox.Show("An error occurred while exporting the room, export aborted.", "GMare", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } }
/// <summary> /// Gets a .net tree node from a GM node. Stores original GM node data in tag property. /// </summary> /// <param name="node">The GM node to convert to treenode.</param> /// <returns>A tree node version of the GM node.</returns> public static TreeNode GetTreeNodeFromGMNode(GMProject project, GMNode node, List <Image> images) { // Set-up tree node. TreeNode treeNode = new TreeNode(); treeNode.Text = node.Name; treeNode.Tag = node; // If the list does not have the folder graphics, add them. if (images != null && images.Count < 2) { images.Add((Image)GMare.Properties.Resources.file_close.Clone()); images.Add((Image)GMare.Properties.Resources.file_open.Clone()); images.Add((Image)GMare.Properties.Resources.instance.Clone()); } switch (node.NodeType) { // If a child node, get appropriate resource key. case GMNodeType.Child: // Do action based on object type. switch (node.ResourceType) { // Sprites. case GMResourceType.Sprites: // If no images to load, break. if (images == null) { break; } // Get sprite. GMSprite sprite = project.Sprites.Find(delegate(GMSprite s) { return(s.Id == node.Id); }); // If a sprite was found. if (sprite != null) { // Get image. Bitmap image = GMUtilities.GetBitmap(sprite.SubImages[0]); // Set transparency if needed. if (sprite.Transparent && sprite.SubImages[0].Compressed) { image.MakeTransparent(image.GetPixel(0, image.Height - 1)); } images.Add(image); treeNode.ImageIndex = images.Count - 1; treeNode.SelectedImageIndex = images.Count - 1; } else { treeNode.ImageIndex = 2; treeNode.SelectedImageIndex = 2; } break; // Objects. case GMResourceType.Objects: // If no images to load, break. if (images == null) { break; } // Get the object id, use it to get the sprite id. GMObject obj = project.Objects.Find(delegate(GMObject o) { return(o.Id == node.Id); }); GMSprite spt = project.Sprites.Find(delegate(GMSprite s) { return(s.Id == obj.SpriteId); }); // If a sprite was found. if (spt != null && spt.SubImages != null && spt.SubImages.Length > 0) { // Get image. Bitmap image = GMUtilities.GetBitmap(spt.SubImages[0]); // Set transparency if needed. if (spt.Transparent && spt.SubImages[0].Compressed) { image.MakeTransparent(image.GetPixel(0, image.Height - 1)); } images.Add(image); treeNode.ImageIndex = images.Count - 1; treeNode.SelectedImageIndex = images.Count - 1; } else { treeNode.ImageIndex = 2; treeNode.SelectedImageIndex = 2; } break; // Rooms. case GMResourceType.Rooms: treeNode.ImageKey = ImageKeyRoom; treeNode.SelectedImageKey = ImageKeyRoomSelected; break; } break; // Folders or parents. default: treeNode.ImageIndex = 0; treeNode.SelectedImageIndex = 1; treeNode.ImageKey = ImageKeyGroup; treeNode.SelectedImageKey = ImageKeyGroupSelected; break; } // If no child nodes, return the top node. if (node.Nodes == null) { return(treeNode); } // Iterate through nodes. for (int i = 0; i < node.Children; i++) { // Set the node. treeNode.Nodes.Add(GetTreeNodeFromGMNode(project, node.Nodes[i], images)); } // Return a .net tree node. return(treeNode); }