muddesigner/RoomDesigner/frmMain.cs
Scionwest_cp 6999457b19 MUD Engine:
* Added Attributes namespace to hold custom attributes.
 * UnusableAttribute.cs - Added to tag classes as unusable by the editors regardless if they inherit from BaseObject or not.
 * BaseObject.cs - Contains OnEnter and OnExit methods
 * InitialLocation.cs - UnusableAttribute tag applied.

Room Designer:
 * frmMain.cs - Additional Script UI design.
 * frmMain.cs - Added plugin support. 

Plugin support is being tested. Room Designer is the testbed. It will ultimately end up inside MUDEngine.Engine. Curently (if ROOT/Plugins exists) loads all .dll files contained within the plugin directory. All classes inheriting from BaseObject and not tagged with the UnusableAttribute attribute automatically get added to the script editor.
2009-11-24 18:36:25 -08:00

330 lines
14 KiB
C#

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<System.Reflection.Assembly> _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()
{
//Check if the plugin path exists.
string pluginPath = System.IO.Path.Combine(Application.StartupPath, "Plugins");
if (!System.IO.Directory.Exists(pluginPath))
return;
_Plugins = new List<System.Reflection.Assembly>();
//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.
}
/// <summary>
/// Closes the editor.
/// TODO: Serialize the Room out to file.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCloseEditor_Click(object sender, EventArgs e)
{
Application.Exit();
}
/// <summary>
/// Change the currently selected direction, allowing users to uninstall or install
/// a doorway, and display the selected doorways properties for editing.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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;
}
/// <summary>
/// Modified values within the doorway get stored within the currentDoor Field.
/// </summary>
/// <param name="s"></param>
/// <param name="e"></param>
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;
}
}
/// <summary>
/// Converts a string into an AvailableTravelDirections enum equivilant if it
/// exists within the enum list.
/// </summary>
/// <param name="Direction"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Installs the _CurrentDoor into the _CurrentRoom's collection of doorways
/// </summary>
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);
}
/// <summary>
/// Uninstalls the doorway from the room.
/// </summary>
private void UninstallDoor()
{
foreach (Door door in _CurrentRoom.InstalledDoors)
{
if (door.TravelDirection == _CurrentDoor.TravelDirection)
{
_CurrentRoom.InstalledDoors.Remove(door);
break;
}
}
}
/// <summary>
/// Resets the room.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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;
}
}
}