muddesigner/MudEngine/Scripting/ScriptEngine.cs
Scionwest_cp 793c3cf1e9 MudEngine:
- FileManager.GetDataPath now returns the actual Root directory when Root is requested rather than Root/Projects. That was considered Root for the older Designer.
 - CommandEngine.GetCommands is now a method rather than a property.
 - CommandEngine.LoadAllCommands replaced with CommandEngine.LoadBaseCommands for loading Engine specific Game commands. This is called from within Game.Start. A possible property for disabling default commands could be looked at in the future.
 - CommandEngine.LoadCommandLibrary method added for loading custom user commands. This is fully implemented.
 - CommandEngine.ClearCommands method added for clearing all currently loaded commands.
 - Game.IsDebug static property added.
 - Added additional logging for testing purposes throughout the project. Changing Game.IsDebug to false will remove the majority of the logged messages.
 - Game.IsMultiplayer property added for enabling or disabling the server for Online/Offline support. Fully implemented.
 - Game no longer loads user script libraries as this was being handled already by ScriptEngine.Initialize()
 - Log now caches messages so consoles can print only content that was logged since the last loop. Using Log.FlushMessages() will clear the cached messages allowing each loop to show only the new logged messages.
 - BaseCharacter IsAdmin argument in the constructor has been removed. No longer needed for testing.
 - ScriptEngine can now compile more than 1 script without error.
 - ScriptEngine.Assembly property added for accessing the currently loaded script library. This should be a List<Assembly> in the future for multiple libraries.
 - Removed the last of my BlitScript engine code from ScriptEngine.cs as it was XNA specific. Need to look at StartupObject.cs as I believe that is XNA specific as well and not needed.

MudGame:
 - Renamed MudGame to MudOfflineExample as it will be used for testing the game with Game.IsMultiplayer disabled. Makes testing easier then needing to stop/restart the server and connect via telnet constantly.

MudServer:
 - Added MudServer project. This is a dedicated server that runs with Game.IsMultiplayer enabled. Developers can connect to it via telnet clients. All engine game commands are implemented.
 - MudServer includes bin/Debug/Scripts.dll, which is a compiled library of scripts generated via MudCompiler. MudEngine.Game handles loading the library and there is no additional code required by the developers to implement their libraries into their games provided the name is 'Scripts.dll'
2010-07-27 16:31:50 -07:00

228 lines
8.1 KiB
C#

//Microsoft .NET Framework
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Reflection;
using MudEngine.GameObjects;
using MudEngine.GameObjects.Characters;
using MudEngine.GameManagement;
namespace MudEngine.Scripting
{
public class ScriptEngine
{
public enum ScriptTypes
{
Assembly,
SourceFiles
}
/// <summary>
/// Path to the the script files directory
/// </summary>
public string ScriptPath { get; set; }
public string InstallPath { get; private set; }
public GameObjectCollection ObjectCollection { get; private set; }
public Assembly Assembly { get { return _ScriptAssembly; } private set { _ScriptAssembly = value; } }
/// <summary>
/// File Extension for the scripts
/// </summary>
public string ScriptExtension { get; set; }
/// <summary>
/// Error Messages logged during script compilation
/// </summary>
public string ErrorMessage
{
get
{
string errorMessages = "Script Compilation Failed!\n";
//Construct our error message.
foreach (string error in _ErrorMessages)
errorMessages += error + "\n";
return errorMessages;
}
private set
{
_ErrorMessages = new string[] { value };
}
}
private ScriptTypes _ScriptTypes;
private Assembly _ScriptAssembly;
private string[] _ErrorMessages;
public ScriptEngine() : this(ScriptTypes.Assembly)
{
//Empty constructor. Only here for end-user ease of use. ScriptEngine(Game, ScriptTypes) is called from here.
}
/// <summary>
/// Instances a new copy of the script engine
/// </summary>
/// <param name="scriptTypes">Tells the engine what kind of scripts will be loaded. Source File or assembly based.</param>
public ScriptEngine(ScriptTypes scriptTypes)
{
//Initialize our engine fields
_ScriptTypes = scriptTypes;
ScriptExtension = ".cs";
//Get our current install path
ScriptPath = Environment.CurrentDirectory;
InstallPath = Environment.CurrentDirectory;
}
/// <summary>
/// Compiles a collection of scripts stored in ScriptEngine.ScriptPath. Not supported on XBox360.
/// </summary>
/// <returns></returns>
public bool CompileScripts()
{
//Ensure the script path exists.
if (!System.IO.Directory.Exists(ScriptPath))
{
ErrorMessage = "Invalid Script path supplied.";
return false;
}
//Build an array of scripts
string[] scripts = System.IO.Directory.GetFiles(ScriptPath, "*" + ScriptExtension, System.IO.SearchOption.AllDirectories);
//Prepare the scripts. MUD Scripts are wrote without defining a namespace
if (Directory.Exists("temp"))
Directory.Delete("temp", true);
Directory.CreateDirectory("temp");
//Setup the additional sourcecode that's needed in the script.
string[] usingStatements = new string[] { "using System;", "using MudEngine.GameObjects;", "using MudEngine.GameObjects.Characters;", "using MudEngine.GameManagement;", "using MudEngine.FileSystem;" };
foreach (string script in scripts)
{
string tempPath = "temp";
string source = "\nnamespace MudScripts{\n}";
FileStream fr = new FileStream(script, FileMode.Open, FileAccess.Read, FileShare.None);
FileStream fw = new FileStream(Path.Combine(tempPath, Path.GetFileName(script)), FileMode.Create, FileAccess.Write);
StreamWriter sw = new StreamWriter(fw, System.Text.Encoding.Default);
StreamReader sr = new StreamReader(fr, System.Text.Encoding.Default);
string content = sr.ReadToEnd();
foreach (string statement in usingStatements)
source = source.Insert(0, statement);
source = source.Insert(source.Length - 1, content);
sw.Write(source);
sr.Close();
sw.Flush();
sw.Close();
}
string oldPath = ScriptPath;
ScriptPath = "temp";
//Prepare the compiler.
Dictionary<string, string> providerOptions = new Dictionary<string,string>();
providerOptions.Add("CompilerVersion", "v3.5");
CompilerParameters param = new CompilerParameters(new string[] {"mscorlib.dll", "System.dll", "MudEngine.dll"});
param.GenerateExecutable = false;
param.GenerateInMemory = true;
param.OutputAssembly = "Scripts.dll";
param.IncludeDebugInformation = false;
param.TreatWarningsAsErrors = true;
//Compile the scripts with the C# CodeProvider
CSharpCodeProvider codeProvider = new CSharpCodeProvider(providerOptions);
CompilerResults results = new CompilerResults(new TempFileCollection());
scripts = Directory.GetFiles(ScriptPath, "*.Mud", SearchOption.AllDirectories);
results = codeProvider.CompileAssemblyFromFile(param, scripts);
//Delete the temp folder
//Directory.Delete("temp", true);
ScriptPath = oldPath;
//if we encountered errors we need to log them to our ErrorMessages property
if (results.Errors.Count >= 1)
{
List<string> errorCollection = new List<string>();
foreach (CompilerError error in results.Errors)
{
string prefix = "Error: ";
if (error.IsWarning)
prefix = "Warning: ";
errorCollection.Add(prefix + error.FileName + "(" + error.Line + ") - " + error.ErrorText);
_ErrorMessages = errorCollection.ToArray();
}
return false;
}
else
return true;
}
/// <summary>
/// Initializes the script engine, loading the compiled scripts into memory
/// </summary>
/// <param name="scriptAssembly"></param>
public void Initialize()
{
if (_ScriptTypes == ScriptTypes.Assembly)
{
InitializeAssembly();
}
else
{
InitializeSourceFiles();
}
}
private void InitializeAssembly()
{
if (!System.IO.File.Exists("Scripts.dll"))
{
ErrorMessage = "Failed to load Script Assembly!";
Log.Write(ErrorMessage);
return;
}
_ScriptAssembly = Assembly.LoadFile(Path.Combine(InstallPath, "Scripts.dll"));
foreach (Type type in _ScriptAssembly.GetTypes())
{
if (type.BaseType == typeof(BaseCharacter))
{
}
}
}
private void InitializeSourceFiles()
{
}
public GameObject GetObject(string objectName)
{
IEnumerable<GameObject> objectQuery =
from gameObject in ObjectCollection._GameObjects
where gameObject.Name == objectName
select gameObject;
foreach (GameObject gameObject in objectQuery)
{
if (gameObject.Name == objectName)
return gameObject;
}
return null;
}
}
}