diff --git a/MudEngine/WinPC_Engine/Core/Interfaces/ISavable.cs b/MudEngine/WinPC_Engine/Core/Interfaces/ISavable.cs index fce1efd..d518d20 100644 --- a/MudEngine/WinPC_Engine/Core/Interfaces/ISavable.cs +++ b/MudEngine/WinPC_Engine/Core/Interfaces/ISavable.cs @@ -19,7 +19,9 @@ namespace MudEngine.Core.Interfaces /// Save method for dumping the object to physical file. /// /// - void Save(String path); + Boolean Save(String filename); + + Boolean Save(String filename, Boolean ignoreignoreFileWrite); /// /// Load method for retrieving saved data from file. diff --git a/MudEngine/WinPC_Engine/Core/ObjectCollection.cs b/MudEngine/WinPC_Engine/Core/ObjectCollection.cs new file mode 100644 index 0000000..51c0b36 --- /dev/null +++ b/MudEngine/WinPC_Engine/Core/ObjectCollection.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using MudEngine.Game; +using MudEngine.GameScripts; +using MudEngine.Scripting; + +namespace MudEngine.Core +{ + internal class ObjectCollection : ICollection + { + #region Public Properties + public Boolean IsReadOnly + { + get { return this.isReadOnly; } + } + #endregion + + #region public Methods + + #endregion + + #region public Interface Methods + /// + /// Adds a new Scripted Object to the games Object Manager. + /// + /// + public void Add(BaseScript item) + { + //Checks if the Object Manager is currently in Read-Only mode. + if (this.isReadOnly) + { + Logger.WriteLine("Warning: Attempted to add a scripted object while the Object Manager is Read Only."); + return; + } + + //TODO: Allow the same Scripts to be used provided different ID's are assigned. + if (!this.Contains(item)) + this.scriptCollection.Add(item); + else + Logger.WriteLine("Warning: Scripted object (" + item.ID.ToString() + ")" + item.Name + " was not added to the Object Manager due to being a duplicate."); + } + + /// + /// Clears the Object Manager of all Scripted Objects + /// + public void Clear() + { + this.scriptCollection.Clear(); + } + + /// + /// Checks if the Object Manager currently has a Scripted Object matching the supplied Object. + /// + /// + /// + public Boolean Contains(BaseScript item) + { + bool isFound = false; + + foreach (BaseScript script in this.scriptCollection) + { + if (script.Equals(item)) + { + isFound = true; + break; + } + } + + return isFound; + } + + public void CopyTo(BaseScript[] array, int arrayIndex) + { + this.scriptCollection.CopyTo(array, arrayIndex); + } + + public Int32 Count + { + get { return this.scriptCollection.Count; } + } + + public bool Remove(BaseScript item) + { + if (this.Contains(item)) + { + this.scriptCollection.Remove(item); + return true; + } + + return false; + } + + public Int32 Length { get { return this.scriptCollection.Count; } } + + public IEnumerator GetEnumerator() + { + return new ScriptEnumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new ScriptEnumerator(this); + } + #endregion + + #region Constructors + public ObjectCollection(StandardGame game) + { + this.scriptCollection = new List(); + this.isReadOnly = false; + + this._Game = game; + } + + /// + /// Get or Set a index value for this collection + /// + /// + /// + public BaseScript this[Int32 index] + { + //TODO: Perform some exception handling here. + //TODO: Don't allow setting if isReadOnly=true + get { return (BaseScript)this.scriptCollection[index]; } + set { this.scriptCollection[index] = value; } + } + #endregion + + #region Private Fields + private List scriptCollection; + private Boolean isReadOnly; + private StandardGame _Game; + #endregion + } +} diff --git a/MudEngine/WinPC_Engine/DAL/XMLData.cs b/MudEngine/WinPC_Engine/DAL/XMLData.cs new file mode 100644 index 0000000..b255c94 --- /dev/null +++ b/MudEngine/WinPC_Engine/DAL/XMLData.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using System.Reflection; + +using MudEngine.GameScripts; + +namespace MudEngine.DAL +{ + public class XMLData + { + public XElement SaveData { get; private set; } + + /// + /// Instances the ObjectSaver and all of its Properties and Fields + /// + public XMLData(String objectType) + { + SaveData = new XElement(objectType); + } + + public void AddSaveData(String property, String value) + { + this.SaveData.Add(new XElement(property, value)); + } + + public Boolean Save(String filename) + { + this.SaveData.Save(filename); + return true; + } + } +} diff --git a/MudEngine/WinPC_Engine/DAL/XmlParser.cs b/MudEngine/WinPC_Engine/DAL/XmlParser.cs deleted file mode 100644 index 4e18fb0..0000000 --- a/MudEngine/WinPC_Engine/DAL/XmlParser.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace MudEngine.DAL -{ - public class XmlParser - { - - } -} diff --git a/MudEngine/WinPC_Engine/Game/Characters/MyCharacter.cs b/MudEngine/WinPC_Engine/Game/Characters/MyCharacter.cs new file mode 100644 index 0000000..695c3f9 --- /dev/null +++ b/MudEngine/WinPC_Engine/Game/Characters/MyCharacter.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using MudEngine.Game; + +namespace MudEngine.Game.Characters +{ + class MyCharacter : StandardCharacter + { + public int Age { get; set; } + + public MyCharacter(StandardGame game, String name, String desc) + : base(game, name, desc) + { + } + + public override bool Save(string filename) + { + base.Save(filename, true); + + this.SaveData.AddSaveData("Age", Age.ToString()); + return this.SaveData.Save(filename); + } + } +} diff --git a/MudEngine/WinPC_Engine/Game/Characters/StandardCharacter.cs b/MudEngine/WinPC_Engine/Game/Characters/StandardCharacter.cs index 1ddf003..b2dc6e3 100644 --- a/MudEngine/WinPC_Engine/Game/Characters/StandardCharacter.cs +++ b/MudEngine/WinPC_Engine/Game/Characters/StandardCharacter.cs @@ -6,6 +6,7 @@ using System.Text; using System.Net; using System.Net.Sockets; using System.Threading; +using System.Xml.Linq; using MudEngine.GameScripts; using MudEngine.Core.Interfaces; @@ -47,18 +48,18 @@ namespace MudEngine.Game.Characters protected CommandSystem Commands { get; private set; } - public StandardCharacter(String name, String description, StandardGame game) : base(name, description) + public StandardCharacter(StandardGame game, String name, String description) : base(game, name, description) { this.Game = game; //Instance this Characters personal Command System with a copy of the command //collection already loaded and prepared by the Active Game. this.Commands = new CommandSystem(CommandSystem.Commands); - + this.OnConnectEvent += new OnConnectHandler(OnConnect); } - public StandardCharacter(String name, String description, StandardGame game, Socket connection) : this(name, description, game) + public StandardCharacter(StandardGame game, String name, String description, Socket connection) : this(game, name, description) { this._Connection = connection; @@ -69,6 +70,18 @@ namespace MudEngine.Game.Characters this._InitialMessage = true; //Strips Telnet client garbage text from initial message sent from client. } + public override bool Save(String filename) + { + base.Save(filename, true); + + SaveData.AddSaveData("Immovable", Immovable.ToString()); + SaveData.AddSaveData("Password", Password); + + this.SaveData.Save(filename); + + return true; + } + internal void ExecuteCommand(string command) { //Process commands here. @@ -176,11 +189,6 @@ namespace MudEngine.Game.Characters } } - public void Save(string path) - { - throw new NotImplementedException(); - } - public void Load(string filename) { throw new NotImplementedException(); diff --git a/MudEngine/WinPC_Engine/GameScripts/BaseScript.cs b/MudEngine/WinPC_Engine/GameScripts/BaseScript.cs index 3f59904..90cb0e1 100644 --- a/MudEngine/WinPC_Engine/GameScripts/BaseScript.cs +++ b/MudEngine/WinPC_Engine/GameScripts/BaseScript.cs @@ -3,20 +3,76 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; +using System.Xml.Linq; +using System.IO; + +using MudEngine.Game; +using MudEngine.DAL; namespace MudEngine.GameScripts { public class BaseScript { + [DefaultValue("Scripted Object")] public String Name { get; set; } public String ID { get; set; } public String Description { get; set; } - public BaseScript(String name, String description) + public XMLData SaveData { get; protected set; } + + public BaseScript(StandardGame game, String name, String description) { + this.Name = name; + this.Description = description; + this.ID = Guid.NewGuid().ToString(); + + this.SaveData = new XMLData(this.GetType().Name); + } + + public virtual Boolean Save(String filename) + { + return this.Save(filename, false); + } + + public virtual Boolean Save(String filename, Boolean ignoreFileWrite) + { + if (File.Exists(filename)) + File.Delete(filename); + + try + { + this.SaveData.AddSaveData("Name", Name); + this.SaveData.AddSaveData("ID", ID); + this.SaveData.AddSaveData("Description", Description); + + if (!ignoreFileWrite) + this.SaveData.Save(filename); + } + catch + { + return false; + } + + return true; + } + + public virtual Boolean Load(String filename) + { + try + { + if (!File.Exists(filename)) + return false; + + XElement data = XElement.Load(filename); + } + catch + { + return false; + } + return true; } public override string ToString() diff --git a/MudEngine/WinPC_Engine/Networking/ConnectionManager.cs b/MudEngine/WinPC_Engine/Networking/ConnectionManager.cs index a923c23..71f76ae 100644 --- a/MudEngine/WinPC_Engine/Networking/ConnectionManager.cs +++ b/MudEngine/WinPC_Engine/Networking/ConnectionManager.cs @@ -29,7 +29,7 @@ namespace MudEngine.Networking Connections = new List(); //Instance a new character and provide it with the Socket. - StandardCharacter character = new StandardCharacter("New Player", "New networked client.", game, connection); + StandardCharacter character = new StandardCharacter(game, "New Player", "New networked client.", connection); //Add it to the Connections collection Connections.Add(character); diff --git a/MudEngine/WinPC_Engine/Scripting/CSharp.cs b/MudEngine/WinPC_Engine/Scripting/CSharp.cs new file mode 100644 index 0000000..9cf0f00 --- /dev/null +++ b/MudEngine/WinPC_Engine/Scripting/CSharp.cs @@ -0,0 +1,126 @@ +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +#if WINDOWS_PC +using Microsoft.CSharp; +#endif + +namespace MudEngine.Scripting +{ + /// + /// Standard C# source code compiler. + /// + internal class CSharp : ICompiler + { +#if WINDOWS_PC + /// + /// The file extension used for the script files. + /// + public String ScriptExtension { get; set; } + + /// + /// Provides a collection of Assemblies that the compiler will add to its reference list. + /// + public List AssemblyReferences { get; set; } + + /// + /// The results of the compilation + /// + public CompilerResults Results { get; set; } + + /// + /// Provides compiling options to various compilers, if they support this feature. + /// + public Dictionary CompilerOptions { get; set; } + + /// + /// Compiles the source files found within the scriptRepository directory matching the ICompiler.ScriptExtension + /// The Compiler defaults to the C# 4.0 compiler if none other is supplied via the ICompiler.CompilerOptions argument. + /// + /// Compiler Parameters that can be supplied to customize the compilation of the source. + /// Returns true if the compilation was completed without error. + public Boolean Compile(CompilerParameters param, String scriptRepository) + { + //Make sure we have a compiler version supplied. + if (!CompilerOptions.ContainsKey("CompilerVersion")) + CompilerOptions.Add("CompilerVersion", "v4.0"); + + //Instance a reference to the C# code provider, this is what will perform the compiling. + CSharpCodeProvider provider = new CSharpCodeProvider(CompilerOptions); + //Create an array of script files found within the ScriptRepository matching the ScriptExtension properties. + String[] scripts = Directory.GetFiles(scriptRepository, "*" + this.ScriptExtension, SearchOption.AllDirectories); + + //Compile the scripts and provide the Results property with a reference to the compilation results. + Results = provider.CompileAssemblyFromFile(param, scripts); + + //if the compiler has errors, return false. + if (Results.Errors.HasErrors) + return false; + else + return true; + } + + /// + /// Compiles the source files found within the scriptFile argument. + /// The Compiler defaults to the C# 4.0 compiler if none other is supplied via the ICompiler.CompilerOptions argument. + /// + /// + /// + public Boolean Compile(CompilerParameters param, FileInfo scriptFile) + { + //Make sure we have a compiler version supplied. + if (!CompilerOptions.ContainsKey("CompilerVersion")) + CompilerOptions.Add("CompilerVersion", "v4.0"); + + CSharpCodeProvider provider = new CSharpCodeProvider(CompilerOptions); + + //Make sure the file exists prior to attempting to compile it. + if (scriptFile.Exists) + { + //Compile the script and provide the Results property with a referece to the compilation results. + Results = provider.CompileAssemblyFromFile(param, scriptFile.FullName); + } + else + { + Results.Errors.Add(new CompilerError(scriptFile.FullName, 0, 0, "rS01", "The supplied filename does not exist.")); + return false; + } + + if (Results.Errors.HasErrors) + return false; + else + return true; + } + + /// + /// Compiles the source code found within the scriptSourceCode argument + /// The Compiler defaults to the C# 4.0 compiler if none other is supplied via the ICompiler.CompilerOptions argument. + /// + /// + /// + public Boolean Compile(CompilerParameters param, String[] scriptSourceCode) + { + if (!CompilerOptions.ContainsKey("CompilerVersion")) + CompilerOptions.Add("CompilerVersion", "v4.0"); + + CSharpCodeProvider provider = new CSharpCodeProvider(CompilerOptions); + + if (scriptSourceCode.Length == 0) + { + Results.Errors.Add(new CompilerError("None", 0, 0, "rS02", "No Source provided.")); + return false; + } + else + { + Results = provider.CompileAssemblyFromSource(param, scriptSourceCode); + } + + if (Results.Errors.HasErrors) + return false; + else + return true; + } +#endif + } +} \ No newline at end of file diff --git a/MudEngine/WinPC_Engine/Scripting/CompileEngine.cs b/MudEngine/WinPC_Engine/Scripting/CompileEngine.cs new file mode 100644 index 0000000..4169357 --- /dev/null +++ b/MudEngine/WinPC_Engine/Scripting/CompileEngine.cs @@ -0,0 +1,415 @@ +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +#if WINDOWS_PC +using Microsoft.CSharp; +#endif +namespace MudEngine.Scripting +{ + /// + /// Provides Properties & Methods needed to compile script source code into .NET assemblies. + /// + public class CompileEngine + { + /// + /// The file extension used for the script files. + /// + public String ScriptExtension + { + get + { + return _ScriptExtension; + } + set + { + if (value.StartsWith(".")) + _ScriptExtension = value; + else + _ScriptExtension = "." + value; + } + } + private String _ScriptExtension; + + /// + /// Provides a collection of Assemblies that the compiler will add to its reference list. + /// + public List AssemblyReferences { get; private set; } + + /// + /// Provides a reference to the assembly generated during script compilation. + /// + public Assembly CompiledAssembly { get; set; } + + /// + /// The compiler that will be used when the contents of ScriptRepository are compiled. + /// + public String Compiler { get; set; } + + /// + /// Used to supply compiling options to various compilers if they support this feature. + /// + public Dictionary CompilerOptions { get; set; } + + /// + /// Used to check if the compilation contained any errors. + /// + public Boolean HasErrors { get; internal set; } + + /// + /// String of errors that occurred during compilation, if any. + /// + public String Errors + { + get + { + if (_CompileMessages.Length == 0) + return "No Errors."; + else + { + StringBuilder builder = new StringBuilder(); + foreach (String error in _CompileMessages) + { + builder.AppendLine(error); + } + + return builder.ToString(); + } + } + } + + //Messages stored from the compilers CompilerResults property. + private String[] _CompileMessages; + + //Returns all of the assemblies currently loaded in the current domain. + private Assembly[] _Assemblies + { + get + { + return AppDomain.CurrentDomain.GetAssemblies(); + } + } + + public CompileEngine() : this(".cs") + { + //Passes defaults off to the parameterized constructor. + } + + public CompileEngine(String scriptExtensions) + { + _CompileMessages = new String[] { "No compiler messages available." }; + + CompilerOptions = new Dictionary(); + Compiler = "C#"; + + AssemblyReferences = new List(); + AssemblyReferences.Add("mscorlib.dll"); + AssemblyReferences.Add("System.dll"); + AssemblyReferences.Add("System.Core.dll"); + + ScriptExtension = scriptExtensions; + } + + /// + /// Adds a reference to the supplied Assembly name to the compilers reference collection. + /// + /// + public void AddAssemblyReference(String assembly) + { + if (!AssemblyReferences.Contains(assembly)) + AssemblyReferences.Add(assembly); + } + + /// + /// Adds a reference to the supplied Assembly to the compilers reference collection. + /// + /// + public void AddAssemblyReference(Assembly assembly) + { + if (!AssemblyReferences.Contains(assembly.GetName().Name)) + AssemblyReferences.Add(assembly.GetName().Name); + } + + /// + /// Removes the supplied assembly from the compilers reference collection. + /// + /// + public void RemoveAssemblyReference(String assembly) + { + if (AssemblyReferences.Contains(assembly)) + AssemblyReferences.Remove(assembly); + } + + /// + /// Clears the compilers reference collection, leaving it empty. + /// + public void ClearAssemblyReference() + { + AssemblyReferences.Clear(); + } + + /// + /// Compiles the scripts found within the CompileEngine.ScriptRepository directory that match the CompileEngine.ScriptExtension file extension. + /// The compiler will compile the scripts using the compiler specified with the CompileEngine.Compiler Property. + /// + /// Returns true if compilation was completed without any errors. + public Boolean Compile(String scriptRepository) + { +#if WINDOWS_PC + //Get the compiler that the developer has selected. + //If the developer chooses a compiler that is not part of the engine, the GetCompiler() method + //will check all the currently loaded assemblies in memory for a custom compiler implementing + //the ICompiler interface. + Type compiler = GetCompiler(); + + //Incase a non-default compiler was specified and we could not find it in memory, fail. + if (compiler.Name == "ICompiler") + { + this._CompileMessages = new string[] { "Compilation Failed.", "Unable to locate the specified compiler of Type '" + Compiler + "'." }; + return false; + } + + //Get the compiler parameters. + CompilerParameters param = GetParameters(); + + //Create a Instance of the compiler, either custom or internal. + ICompiler com = (ICompiler)Activator.CreateInstance(compiler); + + //Setup it's properties to match that of our CompileEngine. + com.AssemblyReferences = AssemblyReferences; + com.ScriptExtension = ScriptExtension; + com.CompilerOptions = this.CompilerOptions; + + //Compile the scripts. + Boolean isSuccess = com.Compile(param, scriptRepository); + HasErrors = !isSuccess; + + //If the compilation failed, store all of the compiler errors + //into our _CompileMessages string. + if (!isSuccess) + { + List compilerMessages = new List(); + foreach (String message in com.Results.Output) + { + compilerMessages.Add(message); + } + + _CompileMessages = compilerMessages.ToArray(); + return false; + } + else + { + //Compiling completed without error, so we need to save + //a reference to the compiled assembly. + CompiledAssembly = com.Results.CompiledAssembly; + return true; + } +#else + return false; +#endif + } + + /// + /// Compiles the script supplied. + /// The compiler will compile the script using the compiler specified with the CompileEngine.Compiler Property. + /// + /// Returns true if compilation was completed without any errors. + public Boolean Compile(FileInfo sourceFile) + { +#if WINDOWS_PC + if (!sourceFile.Exists) + { + this._CompileMessages = new String[] { "Error: File " + sourceFile.FullName + " does not exists." }; + return false; + } + + //Get the compiler that the developer has selected. + //If the developer chooses a compiler that is not part of the engine, the GetCompiler() method + //will check all the currently loaded assemblies in memory for a custom compiler implementing + //the ICompiler interface. + Type compiler = GetCompiler(); + + //Incase a non-default compiler was specified and we could not find it in memory, fail. + if (compiler.Name == "ICompiler") + { + this._CompileMessages = new string[] { "Compilation Failed.", "Unable to locate the specified compiler of Type '" + Compiler + "'." }; + return false; + } + + //Get the compiler parameters. + CompilerParameters param = GetParameters(); + + //Create a Instance of the compiler, either custom or internal. + ICompiler com = (ICompiler)Activator.CreateInstance(compiler); + + //Setup it's properties to match that of our CompileEngine. + com.AssemblyReferences = AssemblyReferences; + com.ScriptExtension = ScriptExtension; + com.CompilerOptions = this.CompilerOptions; + + //Compile the script. + Boolean isSuccess = com.Compile(param, sourceFile); + HasErrors = !isSuccess; + + //If the compilation failed, store all of the compiler errors + //into our _CompileMessages string. + if (!isSuccess) + { + List compilerMessages = new List(); + foreach (String message in com.Results.Output) + { + compilerMessages.Add(message); + } + + _CompileMessages = compilerMessages.ToArray(); + return false; + } + else + { + //Compiling completed without error, so we need to save + //a reference to the compiled assembly. + CompiledAssembly = com.Results.CompiledAssembly; + return true; + } +#else + return false; +#endif + } + + /// + /// Compiles the source code provided. + /// The compiler will compile the scripts using the compiler specified with the CompileEngine.Compiler Property. + /// + /// Returns true if compilation was completed without any errors. + public Boolean Compile(String[] sourceCode) + { +#if WINDOWS_PC + //Get the compiler that the developer has selected. + //If the developer chooses a compiler that is not part of the engine, the GetCompiler() method + //will check all the currently loaded assemblies in memory for a custom compiler implementing + //the ICompiler interface. + Type compiler = GetCompiler(); + + //Incase a non-default compiler was specified and we could not find it in memory, fail. + if (compiler.Name == "ICompiler") + { + this._CompileMessages = new string[] { "Compilation Failed.", "Unable to locate the specified compiler of Type '" + Compiler + "'." }; + return false; + } + + //Get the compiler parameters. + CompilerParameters param = GetParameters(); + + //Create a Instance of the compiler, either custom or internal. + ICompiler com = (ICompiler)Activator.CreateInstance(compiler); + + //Setup it's properties to match that of our CompileEngine. + com.AssemblyReferences = AssemblyReferences; + com.ScriptExtension = ScriptExtension; + com.CompilerOptions = this.CompilerOptions; + + //Compile the scripts. + Boolean isSuccess = com.Compile(param, sourceCode); + HasErrors = !isSuccess; + + //If the compilation failed, store all of the compiler errors + //into our _CompileMessages string. + if (!isSuccess) + { + List compilerMessages = new List(); + foreach (String message in com.Results.Output) + { + compilerMessages.Add(message); + } + + _CompileMessages = compilerMessages.ToArray(); + return false; + } + else + { + //Compiling completed without error, so we need to save + //a reference to the compiled assembly. + CompiledAssembly = com.Results.CompiledAssembly; + return true; + } +#else + return false; +#endif + } +#if WINDOWS_PC + /// + /// Gets compiler parameters that the compiler will be supplied with. + /// + /// + private CompilerParameters GetParameters() + { + //Setup some default parameters that will be used by the compilers. + CompilerParameters param = new CompilerParameters(this.AssemblyReferences.ToArray()); + param.GenerateExecutable = false; + param.GenerateInMemory = true; + + //Left out, Add as CompileEngine properties in the future. + //param.TreatWarningsAsErrors = true; + //param.WarningLevel = 0; + //param.IncludeDebugInformation = true; + return param; + } + + /// + /// Gets the compiler that will be used during the compilation of the scripts. + /// If a custom compiler is used, then the method will check every assembly in memory + /// and find the custom one requested. If none are found, then it will return a new + /// Object of type ICompiler. + /// + /// + private Type GetCompiler() + { + Type compiler = typeof(ICompiler); + + //Internal CSharpRaw compiler Type specified, so we'll use that. + if ((this.Compiler.ToLower() == "c#") || (this.Compiler.ToLower() == "csharp")) + { + compiler = typeof(CSharp); + return compiler; + } + + //Build a collection of available compilers by scanning all the assemblies loaded in memory. + //If any of the assemblies contain a Type that uses the ICompiler interface, we will assume that the + //assembly is a add-on assembly for rScript, adding a new compiler to the CompileEngine. + //Only used if a non-internal compiler is specified + else + { //Non-internal compiler supplied, so loop through every assembly loaded in memory + foreach (Assembly a in _Assemblies) + { + Boolean isCompiler = false; + + //Create an array of all Types within this assembly + Type[] types = a.GetTypes(); + + //Itterate through each Type; See if any implement the ICompiler interface. + foreach (Type t in a.GetTypes()) + { + //If this Type implements ICompiler, then our compiler field needs to reference the Type. + if ((t.GetInterface("ICompiler") != null) && (t.Name.ToLower() == Compiler.ToLower())) + { + //compiler needs to reference this custom compiler Type. + compiler = t; + isCompiler = true; + break; + } + } + + //If we found a matching compiler, then exit this loop. + if (isCompiler) + break; + } + } + + + return compiler; + } +#endif + } +} \ No newline at end of file diff --git a/MudEngine/WinPC_Engine/Scripting/ICompiler.cs b/MudEngine/WinPC_Engine/Scripting/ICompiler.cs new file mode 100644 index 0000000..509ee7f --- /dev/null +++ b/MudEngine/WinPC_Engine/Scripting/ICompiler.cs @@ -0,0 +1,43 @@ +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; + +namespace MudEngine.Scripting +{ + /// + /// Used to implement a wrapper for an existing compiler. + /// + public interface ICompiler + { +#if WINDOWS_PC + CompilerResults Results { get; set; } + /// + /// The file extension used for the script files. + /// + String ScriptExtension { get; set; } + + /// + /// Provides a collection of Assemblies that the compiler will add to its reference list. + /// + List AssemblyReferences { get; set; } + + /// + /// Provides compiling options to various compilers, if they support this feature. + /// + Dictionary CompilerOptions { get; set; } + + /// + /// Compiles the source files found within the scriptRepository directory matching the ICompiler.ScriptExtension + /// The Compiler defaults to the C# 4.0 compiler if none other is supplied via the ICompiler.CompilerOptions argument. + /// + /// Compiler Parameters that can be supplied to customize the compilation of the source. + /// Returns true if the compilation was completed without error. + Boolean Compile(CompilerParameters param, String scriptRepository); + + Boolean Compile(CompilerParameters param, System.IO.FileInfo scriptFile); + + Boolean Compile(CompilerParameters param, String[] scriptSource); + +#endif + } +} \ No newline at end of file diff --git a/MudEngine/WinPC_Engine/Scripting/ScriptEnumerator.cs b/MudEngine/WinPC_Engine/Scripting/ScriptEnumerator.cs new file mode 100644 index 0000000..94b4814 --- /dev/null +++ b/MudEngine/WinPC_Engine/Scripting/ScriptEnumerator.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using MudEngine.GameScripts; +using MudEngine.Core; + +namespace MudEngine.Scripting +{ + internal class ScriptEnumerator : IEnumerator + { + public ScriptEnumerator(ObjectCollection objectManager) + { + this._ObjectCollection = objectManager; + } + + public void Reset() + { + this._currentIndex = -1; + } + + public BaseScript Current + { + get + { + if (this._currentIndex < 0) + return null; + else if (this._currentIndex > this._ObjectCollection.Length) + return null; + else + return this._ObjectCollection[this._currentIndex]; + } + } + + public void Dispose() + { + throw new NotImplementedException(); + } + + object System.Collections.IEnumerator.Current + { + get { throw new NotImplementedException(); } + } + + public bool MoveNext() + { + throw new NotImplementedException(); + } + + private Int32 _currentIndex = -1; + private ObjectCollection _ObjectCollection; + } +} diff --git a/MudEngine/WinPC_Engine/Scripting/ScriptFactory.cs b/MudEngine/WinPC_Engine/Scripting/ScriptFactory.cs new file mode 100644 index 0000000..a1a553f --- /dev/null +++ b/MudEngine/WinPC_Engine/Scripting/ScriptFactory.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +using MudEngine.Core; +using MudEngine.Game; +using MudEngine.GameScripts; + +namespace MudEngine.Scripting +{ + public class ScriptFactory + { + //The assembly loaded that will be used. + private List _AssemblyCollection; + +#if WINDOWS_PC + /// + /// Constructor for a Windows PC Script Factory + /// + /// + public ScriptFactory(String assembly) + { + Assembly a; + _AssemblyCollection = new List(); + + //See if a file exists first with this assembly name. + if (File.Exists(assembly)) + { + a = Assembly.Load(new AssemblyName(assembly)); + } + //If not, then try and load it differently + else + { + a = Assembly.Load(assembly); + } + + if (a == null) + return; + + //Add the assembly to our assembly collection. + _AssemblyCollection.Add(a); + } + + /// + /// Alternate Constructor for a Windows PC ScriptFactory + /// + /// + public ScriptFactory(Assembly assembly) + { + _AssemblyCollection = new List(); + //Add the supplied assembly to our AssemblyCollection + _AssemblyCollection.Add(assembly); + } +#endif + /// + /// Adds another assembly to the factories assembly collection. + /// + /// provides the name of the assembly, or file name that needs to be loaded. + public void AddAssembly(String assembly) + { + Assembly a; + + //See if a file exists first with this assembly name. + if (File.Exists(assembly)) + { + a = Assembly.Load(new AssemblyName(assembly)); + } + //If not, then try and load it differently + else + { + a = Assembly.Load(assembly); + } + + //Add the assembly to our assembly collection. + _AssemblyCollection.Add(a); + } + + /// + /// Adds another assembly to the factories assembly collection. + /// + /// Provides a reference to the assembly that will be added to the collection. + public void AddAssembly (Assembly assembly) + { + //Add the supplied assembly to our AssemblyCollection + _AssemblyCollection.Add(assembly); + } + + public BaseScript GetScript(String scriptName, StandardGame game) + { + Type script = typeof(Object); + Boolean foundScript = false; + + if (_AssemblyCollection.Count == 0) + return new BaseScript(game, "New Object", String.Empty); + + try + { +#if WINDOWS_PC + foreach (Assembly a in _AssemblyCollection) + { + //The assembly can be null if accessing after a failed compilation. + if (a == null) + continue; + + foreach (Type t in a.GetTypes()) + { + if (t.Name == scriptName) + { + script = t; + foundScript = true; + break; + } + } + + if (foundScript) + break; + } +#elif WINDOWS_PHONE + foreach (Type t in Assembly.GetExecutingAssembly().GetTypes()) + { + if (t.Name == scriptName) + { + script = t; + foundScript = true; + break; + } + } +#endif + } + catch + { + throw new Exception("Error encounted during factory instancing of script " + scriptName + "."); + } + + try + { + BaseScript obj = (BaseScript)Activator.CreateInstance(script, game, "New Object", String.Empty); + return obj; + } + catch + { + Logger.WriteLine("ERROR: Failed to locate and instance script (" + scriptName + ")"); + return new BaseScript(game, "New Object", String.Empty); + } + } + } +} diff --git a/MudEngine/WinPC_Engine/Scripting/ScriptObject.cs b/MudEngine/WinPC_Engine/Scripting/ScriptObject.cs new file mode 100644 index 0000000..0141f53 --- /dev/null +++ b/MudEngine/WinPC_Engine/Scripting/ScriptObject.cs @@ -0,0 +1,92 @@ +using System; +using System.Reflection; +using System.Text; + +namespace sEngine.Scripting +{ + public class ScriptObject + { + public Object Instance { get; set; } + + public ScriptObject(Object instance) + { + if (instance == null) + Instance = new Object(); + else + Instance = instance; + } + + ~ScriptObject() + { + //TODO: Add ability to call a Shutdown() method within this Instance. + Instance = null; + } + + public void SetProperty(String propertyName, object propertyValue) + { + PropertyInfo propertyInfo = Instance.GetType().GetProperty(propertyName); + + if (propertyValue is String) + { + if (propertyInfo.PropertyType.Name is String) + { + propertyInfo.SetValue(Instance, propertyValue, null); + } + } + } + + public object GetProperty(String propertyName) + { + String[] tokens = propertyName.Split('.'); + PropertyInfo previousProperty = Instance.GetType().GetProperty(tokens[0]); + + return previousProperty.GetValue(Instance, null); + } + +#if WINDOWS_PC + public dynamic GetProperty() + { + return Instance; + } +#endif + + public object GetField(String propertyName) + { + String[] tokens = propertyName.Split('.'); + FieldInfo previousField = Instance.GetType().GetField(tokens[0]); + + return previousField.GetValue(Instance); + } + +#if WINDOWS_PC + public dynamic GetField() + { + return Instance; + } +#endif + + public Object InvokeMethod(String methodName) + { + return InvokeMethod(methodName, null); + } + + public Object InvokeMethod(String methodName, params Object[] parameters) + { + MethodInfo method = Instance.GetType().GetMethod(methodName); + + try + { + if (parameters == null || parameters.Length == 0) + return method.Invoke(Instance, null); + else + return method.Invoke(Instance, parameters); + } + catch + { + StringBuilder sb = new StringBuilder(); + sb.Append("Error invoking method. Does the method exist?"); + return sb.ToString(); + } + } + } +} diff --git a/MudEngine/WinPC_Engine/WinPC_Engine.csproj b/MudEngine/WinPC_Engine/WinPC_Engine.csproj index a389644..241b771 100644 --- a/MudEngine/WinPC_Engine/WinPC_Engine.csproj +++ b/MudEngine/WinPC_Engine/WinPC_Engine.csproj @@ -51,11 +51,13 @@ + - + + @@ -63,10 +65,15 @@ + + + + + + -