using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using MUDEngine.Objects.Environment; using MUDEngine.Objects; using MUDEngine; using MUDEngine.FileSystem; using MUDEngine.Attributes; namespace RoomDesigner { public partial class frmMain : Form { //Current _CurrentRoom Room _CurrentRoom; //Doorway currently loaded. Door _CurrentDoor; ManagedScripting.ScriptingEngine _ScriptEngine; List _Plugins; public frmMain() { InitializeComponent(); //Initialize the Room & Doorway _CurrentRoom = new Room(); _CurrentDoor = new Door(AvailableTravelDirections.None); //Show the user(s) the rooms properties propertyRoom.SelectedObject = _CurrentRoom; //This instances a copy of AvailableTravelDirections which is a list of //currently available directions users can travel within rooms. //Instead of updating the editor each time a new travel direction is implemented, //we simply build an array that contains each travel direction currently available //within the engine by getting each element from the AvailableTravelDirections enum AvailableTravelDirections direction = new AvailableTravelDirections(); //Build an array of travel directions currently implemented Array Values = System.Enum.GetValues(direction.GetType()); //Loop through each travel direction within the array and add it //to the lstDirections listbox. foreach (int Value in Values) { string Display = Enum.GetName(direction.GetType(), Value); //The array contains a 'None' direction. As the editor will allow for //installing and uninstalling doorways, we don't need to show a 'None' direction //in the listbox. if (!Display.Equals("None")) this.lstDirections.Items.Add(Display); } //Load all of our plugin .dll files. This is the only directory not generated by //the engine, developers will need to manually create the folder if they want to //create plugins LoadPlugins(); //Before we loop through the plugins list to build our combo box return values //we need to add the MUDEngine.dll to the list, so that it's objects can be //used as return values with the engines scripts. //We can use Assembly.Load("MUDEngine.dll") but that would load a 2nd copy //of the engine in memory, as RoomDesigner.exe already has it loaded in memory. //To prevent duplicate copies in memory, we will search every assembly currently //loaded by the application instead until we find our engine. //Build an array of assemblies currently loaded in memory by RoomDesigner.exe System.Reflection.Assembly[] tempList = System.AppDomain.CurrentDomain.GetAssemblies(); //Loop through each assembly in the array and find the mud engine foreach (System.Reflection.Assembly a in tempList) { //Check the assemblies manifest name to see if it matches our mud engine name if (a.ManifestModule.Name.ToLower() == "mudengine.dll") { //Found the engine, add it to the plugins list so that we can //add it's BaseObject inherited classes to the Script tab's //Return Type combo box. _Plugins.Add(a); break; } } //Loop through each plugin, and add it's objects to the return type //combo box, so scripts can inherit from them. foreach (System.Reflection.Assembly assembly in _Plugins) { //Loop through each time within this specific plugin assembly foreach (Type type in assembly.GetTypes()) { //Check if the current Type inherits from BaseObject if (type.BaseType.Name == "BaseObject") { //Now that we know it inherits from BaseObject //we need to make sure that it is a useable class //or it's for internal use only. This can be set by //the developer using the UnusableAttribute attribute //on the class bool isUseable = true; foreach (object attribute in type.GetCustomAttributes(false)) { //Check if the Type contains the UnsableAttribute attribute if (attribute is UnusableAttribute) { //It does, exit the loop and declare it unuseable isUseable = false; break; } } //If the class does not contain the UnusableAttribute attribute //we can use it as a return value for our scripts. if (isUseable) { comReturnTypes.Items.Add(type.Name); } } }//foreach Type loop }//foreach Assembly loop //Instance the scripting engine and set it up. _ScriptEngine = new ManagedScripting.ScriptingEngine(); _ScriptEngine.Compiler = ManagedScripting.ScriptingEngine.CompilerSelections.SourceCompiler; _ScriptEngine.CompileStyle = ManagedScripting.Compilers.BaseCompiler.ScriptCompileStyle.CompileToMemory; _ScriptEngine.KeepTempFiles = false; } private void LoadPlugins() { string pluginPath = System.IO.Path.Combine(Application.StartupPath, "Plugins"); _Plugins = new List(); //Check if the plugin path exists. if (!System.IO.Directory.Exists(pluginPath)) return; //Now loop through every .dll file in the plugins directory and load it into memory //A copy is stored within a collection for use later if needed. foreach (string assembly in System.IO.Directory.GetFiles(pluginPath, "*.dll")) { _Plugins.Add(System.Reflection.Assembly.LoadFile(assembly)); } //TODO: Look for ways to allow Types to inherit from a Windows Control, and add each //control to a new tab or menu item, allowing for editor plugins as well. } /// /// Closes the editor. /// TODO: Serialize the Room out to file. /// /// /// private void btnCloseEditor_Click(object sender, EventArgs e) { Application.Exit(); } /// /// Change the currently selected direction, allowing users to uninstall or install /// a doorway, and display the selected doorways properties for editing. /// /// /// private void lstDirections_SelectedIndexChanged(object sender, EventArgs e) { //Used to indicate that the direction the user selected exists, //and was found for editing bool IsFound = false; //Loop through each doorway installed within the _CurrentRoom and see if the user has //selected a direction that belongs to a _CurrentDoor already created. If a _CurrentDoor with //the selected direction is found, we display it's properties for editing instead //of creating a new _CurrentDoor and overwriting the previously created doorway. foreach (Door newDoor in _CurrentRoom.InstalledDoors) { //Check if the current _CurrentDoor in the loop matches the currently selected //travel direction the user has selected in the listbox. if (newDoor.TravelDirection.ToString() == lstDirections.SelectedItem.ToString()) { //The travel directions match, let's set the current _CurrentDoor in the loop as our //new selected doorway so that the user can edit it. _CurrentDoor = newDoor; //Indicates that we found a matching doorway and have set it up for //editing within the propertygrid IsFound = true; //Exit the loop break; } } //There isn't a _CurrentDoor installed into the _CurrentRoom yet with a travel direction //matching that of the users currently selected travel direction within the listbox. //so we instance a new _CurrentDoor if (!IsFound) { AvailableTravelDirections direction = GetDirection(lstDirections.SelectedItem.ToString()); _CurrentDoor = new Door(direction); } //Display the properties for users to edit. This could be a pre-existing doorway //found within our loop, or a new doorway. propertyDoor.SelectedObject = _CurrentDoor; } /// /// Modified values within the doorway get stored within the currentDoor Field. /// /// /// private void propertyDoor_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) { //Check if we are installing the door into the room or //uninstalling it from the current room. switch (_CurrentDoor.DoorState) { case Door.AvailableDoorStates.Installed: InstallDoor(); break; case Door.AvailableDoorStates.Uninstalled: UninstallDoor(); break; } } /// /// Converts a string into an AvailableTravelDirections enum equivilant if it /// exists within the enum list. /// /// /// private AvailableTravelDirections GetDirection(string Direction) { foreach (AvailableTravelDirections value in Enum.GetValues(typeof(AvailableTravelDirections))) { string name = value.ToString(); if (name == Direction) return value; } return AvailableTravelDirections.None; } /// /// Installs the _CurrentDoor into the _CurrentRoom's collection of doorways /// private void InstallDoor() { //Indicates if we found a door already installed within the room //matching the selected travel direction. bool IsInstalled = false; //Incase there are no existing doors, the foreach loop gets skipped. if (_CurrentRoom.InstalledDoors.Count == 0) { //Add the new door to the room _CurrentRoom.InstalledDoors.Add(_CurrentDoor); return; } //Loop through all of the installed doors within this room and //check to see if we have a doorway with the same travel direction //that the user has selected within the list box. If so then we //need to prompt the user to ensure it's ok to overwrite the previous //door with a new door. //TODO: Look at this closer, do i need this messagebox? foreach (Door newDoor in _CurrentRoom.InstalledDoors) { if (newDoor.TravelDirection == _CurrentDoor.TravelDirection) { /*DialogResult result = MessageBox.Show("Door already exists! Overwrite it?", "Room Designer", MessageBoxButtons.YesNo); if (result == DialogResult.No) return; */ _CurrentRoom.InstalledDoors.Remove(newDoor); _CurrentRoom.InstalledDoors.Add(_CurrentDoor); IsInstalled = true; break; } } if (!IsInstalled) _CurrentRoom.InstalledDoors.Add(_CurrentDoor); } /// /// Uninstalls the doorway from the room. /// private void UninstallDoor() { foreach (Door door in _CurrentRoom.InstalledDoors) { if (door.TravelDirection == _CurrentDoor.TravelDirection) { _CurrentRoom.InstalledDoors.Remove(door); break; } } } /// /// Resets the room. /// /// /// private void btnNewRoom_Click(object sender, EventArgs e) { DialogResult result = MessageBox.Show("Are you sure you want to create a new room?", "Room Designer", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.No) return; _CurrentRoom = new Room(); _CurrentDoor = new Door(AvailableTravelDirections.None); propertyDoor.SelectedObject = null; propertyRoom.SelectedObject = _CurrentRoom; } } }