XMLData class added. This will manage the saving and loading of all scripted objects during runtime. The saved files will be XML formatted.

Added rScript files to the engine.  These have not been implemented and currently don't work with the engine.
BaseScript has been modified to support the new XMLData class for saving data.
This commit is contained in:
Scionwest_cp 2012-02-29 20:06:14 -08:00
parent fc27d9fc22
commit 38bdf75bf1
16 changed files with 1174 additions and 25 deletions

View file

@ -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
{
/// <summary>
/// Standard C# source code compiler.
/// </summary>
internal class CSharp : ICompiler
{
#if WINDOWS_PC
/// <summary>
/// The file extension used for the script files.
/// </summary>
public String ScriptExtension { get; set; }
/// <summary>
/// Provides a collection of Assemblies that the compiler will add to its reference list.
/// </summary>
public List<String> AssemblyReferences { get; set; }
/// <summary>
/// The results of the compilation
/// </summary>
public CompilerResults Results { get; set; }
/// <summary>
/// Provides compiling options to various compilers, if they support this feature.
/// </summary>
public Dictionary<String, String> CompilerOptions { get; set; }
/// <summary>
/// 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.
/// </summary>
/// <param name="param">Compiler Parameters that can be supplied to customize the compilation of the source.</param>
/// <returns>Returns true if the compilation was completed without error.</returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
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
}
}

View file

@ -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
{
/// <summary>
/// Provides Properties & Methods needed to compile script source code into .NET assemblies.
/// </summary>
public class CompileEngine
{
/// <summary>
/// The file extension used for the script files.
/// </summary>
public String ScriptExtension
{
get
{
return _ScriptExtension;
}
set
{
if (value.StartsWith("."))
_ScriptExtension = value;
else
_ScriptExtension = "." + value;
}
}
private String _ScriptExtension;
/// <summary>
/// Provides a collection of Assemblies that the compiler will add to its reference list.
/// </summary>
public List<String> AssemblyReferences { get; private set; }
/// <summary>
/// Provides a reference to the assembly generated during script compilation.
/// </summary>
public Assembly CompiledAssembly { get; set; }
/// <summary>
/// The compiler that will be used when the contents of ScriptRepository are compiled.
/// </summary>
public String Compiler { get; set; }
/// <summary>
/// Used to supply compiling options to various compilers if they support this feature.
/// </summary>
public Dictionary<String, String> CompilerOptions { get; set; }
/// <summary>
/// Used to check if the compilation contained any errors.
/// </summary>
public Boolean HasErrors { get; internal set; }
/// <summary>
/// String of errors that occurred during compilation, if any.
/// </summary>
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<string, string>();
Compiler = "C#";
AssemblyReferences = new List<string>();
AssemblyReferences.Add("mscorlib.dll");
AssemblyReferences.Add("System.dll");
AssemblyReferences.Add("System.Core.dll");
ScriptExtension = scriptExtensions;
}
/// <summary>
/// Adds a reference to the supplied Assembly name to the compilers reference collection.
/// </summary>
/// <param name="assembly"></param>
public void AddAssemblyReference(String assembly)
{
if (!AssemblyReferences.Contains(assembly))
AssemblyReferences.Add(assembly);
}
/// <summary>
/// Adds a reference to the supplied Assembly to the compilers reference collection.
/// </summary>
/// <param name="assembly"></param>
public void AddAssemblyReference(Assembly assembly)
{
if (!AssemblyReferences.Contains(assembly.GetName().Name))
AssemblyReferences.Add(assembly.GetName().Name);
}
/// <summary>
/// Removes the supplied assembly from the compilers reference collection.
/// </summary>
/// <param name="assembly"></param>
public void RemoveAssemblyReference(String assembly)
{
if (AssemblyReferences.Contains(assembly))
AssemblyReferences.Remove(assembly);
}
/// <summary>
/// Clears the compilers reference collection, leaving it empty.
/// </summary>
public void ClearAssemblyReference()
{
AssemblyReferences.Clear();
}
/// <summary>
/// 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.
/// </summary>
/// <returns>Returns true if compilation was completed without any errors.</returns>
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<String> compilerMessages = new List<string>();
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
}
/// <summary>
/// Compiles the script supplied.
/// The compiler will compile the script using the compiler specified with the CompileEngine.Compiler Property.
/// </summary>
/// <returns>Returns true if compilation was completed without any errors.</returns>
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<String> compilerMessages = new List<string>();
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
}
/// <summary>
/// Compiles the source code provided.
/// The compiler will compile the scripts using the compiler specified with the CompileEngine.Compiler Property.
/// </summary>
/// <returns>Returns true if compilation was completed without any errors.</returns>
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<String> compilerMessages = new List<string>();
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
/// <summary>
/// Gets compiler parameters that the compiler will be supplied with.
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <returns></returns>
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
}
}

View file

@ -0,0 +1,43 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
namespace MudEngine.Scripting
{
/// <summary>
/// Used to implement a wrapper for an existing compiler.
/// </summary>
public interface ICompiler
{
#if WINDOWS_PC
CompilerResults Results { get; set; }
/// <summary>
/// The file extension used for the script files.
/// </summary>
String ScriptExtension { get; set; }
/// <summary>
/// Provides a collection of Assemblies that the compiler will add to its reference list.
/// </summary>
List<String> AssemblyReferences { get; set; }
/// <summary>
/// Provides compiling options to various compilers, if they support this feature.
/// </summary>
Dictionary<String, String> CompilerOptions { get; set; }
/// <summary>
/// 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.
/// </summary>
/// <param name="param">Compiler Parameters that can be supplied to customize the compilation of the source.</param>
/// <returns>Returns true if the compilation was completed without error.</returns>
Boolean Compile(CompilerParameters param, String scriptRepository);
Boolean Compile(CompilerParameters param, System.IO.FileInfo scriptFile);
Boolean Compile(CompilerParameters param, String[] scriptSource);
#endif
}
}

View file

@ -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<BaseScript>
{
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;
}
}

View file

@ -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<Assembly> _AssemblyCollection;
#if WINDOWS_PC
/// <summary>
/// Constructor for a Windows PC Script Factory
/// </summary>
/// <param name="assembly"></param>
public ScriptFactory(String assembly)
{
Assembly a;
_AssemblyCollection = new List<Assembly>();
//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);
}
/// <summary>
/// Alternate Constructor for a Windows PC ScriptFactory
/// </summary>
/// <param name="assembly"></param>
public ScriptFactory(Assembly assembly)
{
_AssemblyCollection = new List<Assembly>();
//Add the supplied assembly to our AssemblyCollection
_AssemblyCollection.Add(assembly);
}
#endif
/// <summary>
/// Adds another assembly to the factories assembly collection.
/// </summary>
/// <param name="assembly">provides the name of the assembly, or file name that needs to be loaded.</param>
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);
}
/// <summary>
/// Adds another assembly to the factories assembly collection.
/// </summary>
/// <param name="assembly">Provides a reference to the assembly that will be added to the collection.</param>
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);
}
}
}
}

View file

@ -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();
}
}
}
}