//.NET using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.IO; using System.Text; using System.Windows.Forms; //Mud Designer using MudDesigner.MudEngine.FileSystem; using MudDesigner.MudEngine.GameManagement; using MudDesigner.MudEngine.GameObjects; using MudDesigner.MudEngine.GameObjects.Environment; using MudDesigner.MudEngine.GameObjects.Items; using MudDesigner.UIWidgets; namespace MudDesigner { public partial class Designer : Form { //The available object types that we can scan through //while loading objects enum ObjectType { Nothing, Project, Currency, Realm, ZoneRoot, ZoneWithinRealm, RoomRoot, RoomWithinZone, Zone, Room, } //Currently loaded project ProjectInformation _Project; //Used for temporarily holding an object during load. BaseObject _GameObject; //Check for if the loaded object is saved yet or not. bool IsSaved; /// /// Initializes the Designers Temporary objects, Project Information and varifies project paths. /// public Designer() { InitializeComponent(); //instance a baseObject so that we can store inherited classes //for use during our runtime _GameObject = new BaseObject(); _Project = new ProjectInformation(); IsSaved = true; //Get out saved project file string projectPath = FileManager.GetDataPath(SaveDataTypes.Root); if (File.Exists(Path.Combine(projectPath, _Project.Filename))) _Project = (ProjectInformation)_Project.Load(projectPath); //ensure the path exists ValidatePath(projectPath); //Display the Project directory structure in the Project Explorer RefreshProjectExplorer(); } /// /// Checks the provided treenode to see what Type of object it is. /// The result is returned for use. This method is only useful for /// Files that have been selected in the designer. /// /// /// private ObjectType GetNodeType(TreeNode node) { try { //The provided nodes parent node is aquired so we can //find if we can get it's current type. TreeNode parentNode = node.Parent; //Root searching. switch (node.Text) { case "Currencies": return ObjectType.Currency; case "Realms": return ObjectType.Realm; case "Zones": if (parentNode.Text == "Realms") return ObjectType.ZoneWithinRealm; else return ObjectType.ZoneRoot; } //switch is only for ProjectInfo, Currency, un-owned Zones & Rooms switch (parentNode.Text) { case "Project": if (node.Text == _Project.Filename) return ObjectType.Project; break; case "Currencies": return ObjectType.Currency; case "Realms": return ObjectType.Realm; case "Zones": if ((parentNode.Parent.Parent != null) && (parentNode.Parent.Parent.Text == "Realms")) return ObjectType.ZoneWithinRealm; else return ObjectType.ZoneRoot; } //Basic Root items where not found, do a deeper search now. //Find Realms, owned Zones & owned Rooms TreeNode grandparentNode = new TreeNode(); if (parentNode.Parent != null) grandparentNode = parentNode.Parent; switch (grandparentNode.Text) { case "Realms": return ObjectType.Realm; //Root Zones case "Zones": if (grandparentNode.Parent.Text == "Project") return ObjectType.ZoneRoot; else return ObjectType.ZoneWithinRealm; } } //Something happened, handle it with a message box. catch (Exception ex) { MessageBox.Show("Internal Error: " + ex.Message); } return ObjectType.Nothing; } public void SaveObject() { //We can use to get a copy of the currently selected object //if it is a BaseObject (Aquire it's BaseObject.Filename) var obj = (BaseObject)propertyObject.SelectedObject; //Filepaths string objectPath = ""; string filename = ""; //Scan through the available Types that can be saved switch (obj.GetType().Name) { //ProjectInformation case "ProjectInformation": filename = Path.Combine(FileManager.GetDataPath(SaveDataTypes.Root), "Game.xml"); _Project.Save(filename); break; //Currency case "Currency": filename = Path.Combine(FileManager.GetDataPath(SaveDataTypes.Currencies), obj.Filename); obj.Save(filename); break; //Realm case "Realm": objectPath= Path.Combine(FileManager.GetDataPath(SaveDataTypes.Realms), obj.Name); filename = Path.Combine(objectPath, obj.Filename); obj.Save(filename); break; //Zone case "Zone": //Get the current Zone being edited. We need to check if it has a Realm Zone z = new Zone(); z = (Zone)obj; //No realm assigned to it, so it's in the Root Zones directory. //Base our save path off of that if (z.Realm == "No Realm Associated.") { objectPath = Path.Combine(FileManager.GetDataPath(SaveDataTypes.Zones), z.Name); filename = Path.Combine(objectPath, z.Filename); } //Realm assigned to it, so save the zone within that Realm else { objectPath = FileManager.GetDataPath(z.Realm, z.Name); filename = Path.Combine(objectPath, z.Filename); } //Save the Zone obj.Save(filename); //Check if the Rooms Directory exists. string roomsPath = Path.Combine(objectPath, "Rooms"); if (!Directory.Exists(roomsPath)) Directory.CreateDirectory(roomsPath); break; case "Room": break; } RefreshProjectExplorer(); } /// /// Searchs to find what Type the selected TreeNode is, and loads /// that objects into the propertygrid. /// /// private void LoadObject(TreeNode selectedNode) { ///Method Fields we will need to use string projectPath = FileManager.GetDataPath(SaveDataTypes.Root); string objectFilename = ""; string objectPath = ""; string objectName = ""; string parentName = ""; ObjectType objType = GetNodeType(selectedNode); //for root objects switch (objType) { //A non-editable object was found case ObjectType.Nothing: return; //Project Information file case ObjectType.Project: _Project = (ProjectInformation)_Project.Load(FileManager.GetDataPath(SaveDataTypes.Root)); propertyObject.SelectedObject = _Project; break; //Currency File case ObjectType.Currency: Currency currency = new Currency(); objectFilename = Path.Combine(FileManager.GetDataPath(SaveDataTypes.Currencies), selectedNode.Text); propertyObject.SelectedObject = (Currency)currency.Load(objectFilename); break; //Realm File selected case ObjectType.Realm: objectName = Path.GetFileNameWithoutExtension(selectedNode.Parent.Text); objectPath = Path.Combine(FileManager.GetDataPath(SaveDataTypes.Realms), objectName); objectFilename = Path.Combine(objectPath, selectedNode.Text); _GameObject = new Realm(); propertyObject.SelectedObject = _GameObject.Load(objectFilename); break; //Zone File located under Project/Zones case ObjectType.ZoneRoot: objectName = Path.GetFileNameWithoutExtension(selectedNode.Parent.Text); objectPath = Path.Combine(FileManager.GetDataPath(SaveDataTypes.Zones), objectName); objectFilename = Path.Combine(objectPath, selectedNode.Text); _GameObject = new Zone(); propertyObject.SelectedObject = _GameObject.Load(objectFilename); break; //Zone File located under Project/Realms/Zones case ObjectType.ZoneWithinRealm: TreeNode grandparent = selectedNode.Parent.Parent; objectName = Path.GetFileNameWithoutExtension(selectedNode.Parent.Text); parentName = grandparent.Parent.Text; objectFilename = Path.Combine(FileManager.GetDataPath(parentName, objectName), selectedNode.Text); _GameObject = new Zone(); propertyObject.SelectedObject = _GameObject.Load(objectFilename); break; } } /// /// Checks the supplied path and creates it if the path does not exist. /// /// public static void ValidatePath(string path) { if (!Directory.Exists(path)) Directory.CreateDirectory(path); } /// /// Checks to see if the curent object in the Properties Pane has been saved or not. /// /// private bool CheckSavedState() { //No need to continue if the save flag is already set if (IsSaved) return true; //Inform the user DialogResult result = MessageBox.Show(lblObjectProperties.Text + " has not been saved! Do you wish to save it?", "Mud Designer", MessageBoxButtons.YesNoCancel); //Don't save it. Return true so that it can be overwrote if (result == DialogResult.No) return true; //User hit cancel, it's not saved so return false. else if (result == DialogResult.Cancel) return false; //User hit Yes, so save the object else SaveObject(); return true; } /// /// Searches the Project Explorer for a TreeNode matching the supplied string /// /// /// /// private TreeNode FindNode(string nodeText, TreeNode startNode) { foreach (TreeNode node in startNode.Nodes) { if (node.Text == nodeText) { return node; } if (node.Nodes.Count != 0) { TreeNode n = FindNode(nodeText, node); if (n == null) continue; else return n; } } return null; } /// /// Populates the Project Explorer with a directory hierarchy /// /// /// private void PopulateTree(string dir, TreeNode node) { // get the information of the directory DirectoryInfo directory = new DirectoryInfo(dir); // loop through each subdirectory foreach (DirectoryInfo d in directory.GetDirectories()) { // create a new node TreeNode t = new TreeNode(d.Name); // populate the new node recursively PopulateTree(d.FullName, t); node.Nodes.Add(t); // add the node to the "master" node } // lastly, loop through each file in the directory, and add these as nodes foreach (FileInfo f in directory.GetFiles()) { // create a new node TreeNode t = new TreeNode(f.Name); // add it to the "master" t.ForeColor = System.Drawing.Color.Blue; if (node.Text == "Rooms") t.ForeColor = System.Drawing.Color.Red; node.Nodes.Add(t); } treeExplorer.SelectedNode = node; } public void RefreshProjectExplorer() { treeExplorer.Nodes.Clear(); TreeNode node = new TreeNode("Project"); treeExplorer.Nodes.Add(node); PopulateTree(FileManager.GetDataPath(SaveDataTypes.Root), node); } public void FindObject(string obj) { if (txtSearch.Text == "") return; TreeNode node = FindNode(txtSearch.Text, treeExplorer.Nodes[0]); if (node == null) MessageBox.Show("No results found!", "Mud Designer"); else { treeExplorer.SelectedNode = node; //TODO: Fix objects not loading during search. LoadObject(node); } } /// /// Refreshes the Project Explorer incase the directory structure /// has changed, but was not reflected in the Explorer /// /// /// private void btnRefreshObjects_Click(object sender, EventArgs e) { RefreshProjectExplorer(); } /// /// Right-Click context menu for the Project Explorer. /// Loads the currently selected object into the Property Pane /// /// /// private void mnuEditObject_Click(object sender, EventArgs e) { if (CheckSavedState()) LoadObject(treeExplorer.SelectedNode); } /// /// Loads the Project Information for editing into the Properties Pane /// /// /// private void mnuProjectInformation_Click(object sender, EventArgs e) { if (CheckSavedState()) propertyObject.SelectedObject = _Project; } /// /// Creates a new Realm for editing within the Properties Pane /// /// /// private void mnuNewRealm_Click(object sender, EventArgs e) { if (CheckSavedState()) propertyObject.SelectedObject = new Realm(); } /// /// Creates a new Currency for editing within the Properties Pane /// /// /// private void mnuNewCurrency_Click(object sender, EventArgs e) { if (CheckSavedState()) propertyObject.SelectedObject = new Currency(); } /// /// Creates a new Zone for editing within the Properties Pane /// /// /// private void mnuNewZone_Click(object sender, EventArgs e) { if (CheckSavedState()) propertyObject.SelectedObject = new Zone(); } private void mnuDeleteSelectedObject_Click(object sender, EventArgs e) { //Check if we are trying to delete the root node if (treeExplorer.SelectedNode.Text == "Project") { MessageBox.Show("You cannot delete the root item 'Project'", "Mud Designer"); return; } DialogResult result; TreeNode selectedNode = treeExplorer.SelectedNode; bool IsFile = true; result = MessageBox.Show("Are you sure you want to delete this object?\n\nAll objects contained within it will be deleted too!", "Mud Designer", MessageBoxButtons.YesNo); //User hit no, cancel if (result == DialogResult.No) return; //Check if the object is a Zone owned by a Realm. //If so, remove the zone from the realms zone collection if (GetNodeType(selectedNode) == ObjectType.ZoneWithinRealm) { Realm r = new Realm(); string filename = ""; //If the user selected the file, then we need to get the realm //filename differently if (IsFile) { string realmName = selectedNode.Parent.Parent.Parent.Text; filename = Path.Combine(realmName, realmName + ".realm"); filename = Path.Combine(FileManager.GetDataPath(SaveDataTypes.Realms), filename); } else { string realmName = selectedNode.Parent.Parent.Text; filename = Path.Combine(realmName, realmName + ".realm"); filename = Path.Combine(FileManager.GetDataPath(SaveDataTypes.Realms), filename); } //Finalize the filename of the realm filename = Path.Combine(Application.StartupPath, filename); //Load the realm that this Zone belongs to r = (Realm)r.Load(filename); //Zone collection does not contain filenames, so we need //to check so we can use the directory name for removal if (IsFile) r.Zones.Remove(selectedNode.Parent.Text); else r.Zones.Remove(selectedNode.Text); } //Delete the object. //Check if it's a file, if so then delete the parent directory so that //we dont have a left over empty folder if (IsFile) Directory.Delete(selectedNode.Parent.FullPath, true); else Directory.Delete(selectedNode.FullPath, true); //Just incase we have the zone or the realm selected that the zone belonged too. //users can re-save the current realm and if it contained the zone we just deleted //the zone will be still be saved as part of the realm. propertyObject.SelectedObject = null; RefreshProjectExplorer(); } private void propertyObject_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) { IsSaved = false; if (propertyObject.SelectedObject is BaseObject) { BaseObject obj = (BaseObject)propertyObject.SelectedObject; //Don't auto-save if we haven't assigned a valid name if (obj.Name == "New " + obj.GetType().Name) return; } SaveObject(); IsSaved = true; RefreshProjectExplorer(); } private void mnuAbout_Click(object sender, EventArgs e) { MessageBox.Show("Mud Designer.\n\nDownload at http://MudDesigner.Codeplex.com\n" + "Join the community at http://MudDesigner.DailyForum.net", "Mud Designer"); } private void mnuExit_Click(object sender, EventArgs e) { Application.Exit(); } private void treeExplorer_DoubleClick(object sender, EventArgs e) { if (treeExplorer.SelectedNode.Text == "Project") return; if (Path.GetExtension(treeExplorer.SelectedNode.Text) == "") return; if (CheckSavedState()) LoadObject(treeExplorer.SelectedNode); } private void mnuNewRoom_Click(object sender, EventArgs e) { if (propertyObject.SelectedObject is Zone) { MudDesigner.MudEngine.UITypeEditors.UIRoomControl control = new MudDesigner.MudEngine.UITypeEditors.UIRoomControl((Zone)propertyObject.SelectedObject); control.ShowDialog(); } else { MessageBox.Show("You must have a zone loaded prior to attempting to create a Room!\n\n" + "You can use a loaded Zones 'Rooms' property via the Object Properties pane to create and manage Rooms as well.", "Mud Designer"); return; } } private void txtSearch_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) FindObject(txtSearch.Text); } } }