Reduce code duplication of Scripting.cs and MCForgeScripter.cs

This commit is contained in:
UnknownShadow200 2016-07-27 09:18:21 +10:00
parent 5948804f11
commit b551b63c65
2 changed files with 75 additions and 110 deletions

View File

@ -19,6 +19,7 @@
*/
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
@ -47,6 +48,11 @@ namespace MCGalaxy {
public Scripting() {
compiler = CodeDomProvider.CreateProvider(ProviderName);
if (compiler == null) {
Server.s.Log("WARNING: Provider " + ProviderName +
" is missing, you will be unable to compile " + Ext + " commands.");
// TODO: Should we log "You must have .net developer tools. (You need a visual studio)" ?
}
}
public void CreateNew(string cmdName) {
@ -86,12 +92,12 @@ namespace MCGalaxy {
if (!Directory.Exists(DllDir))
Directory.CreateDirectory(DllDir);
CompilerParameters args = new CompilerParameters();
args.GenerateExecutable = false;
args.MainClass = cmdName;
args.OutputAssembly = DllDir + "Cmd" + cmdName + ".dll";
args.ReferencedAssemblies.Add("MCGalaxy_.dll");
string code = File.ReadAllText(path);
results = compiler.CompileAssemblyFromSource(args, code.Replace("MCLawl", "MCGalaxy"));
string source = File.ReadAllText(path);
results = CompileSource(source, args);
switch (results.Errors.Count) {
case 0:
@ -132,6 +138,15 @@ namespace MCGalaxy {
sb.AppendLine();
}
public CompilerResults CompileSource(string source, CompilerParameters args) {
args.ReferencedAssemblies.Add("MCGalaxy_.dll");
args.ReferencedAssemblies.Add("MCGalaxy.exe");
source = source.Replace("MCLawl", "MCGalaxy");
source = source.Replace("MCForge", "MCGalaxy");
return compiler.CompileAssemblyFromSource(args, source);
}
/// <summary> Automatically loads all .dll commands specified in the autoload file. </summary>
public static void Autoload() {
if (!File.Exists(AutoloadFile)) { File.Create(AutoloadFile); return; }
@ -142,7 +157,6 @@ namespace MCGalaxy {
string error = Scripting.Load("Cmd" + cmd.ToLower());
if (error != null) { Server.s.Log(error); continue; }
Server.s.Log("AUTOLOAD: Loaded " + cmd.ToLower() + ".dll");
}
}
@ -153,20 +167,13 @@ namespace MCGalaxy {
if (command.Length < 3 || command.Substring(0, 3).ToLower() != "cmd")
return "Invalid command name specified.";
try {
//Allows unloading and deleting dlls without server restart
byte[] data = File.ReadAllBytes(DllDir + command + ".dll");
Assembly lib = Assembly.Load(data);
Assembly lib = Assembly.Load(data); // TODO: Assembly.LoadFile instead?
List<Command> commands = LoadFrom(lib);
foreach (Type t in lib.GetTypes()) {
if (t.BaseType != typeof(Command)) continue;
object instance = Activator.CreateInstance(t);
if (instance == null) {
Server.s.Log("The command " + command + " couldn't be loaded!");
throw new BadImageFormatException();
}
Command.all.Add((Command)instance);
}
if (commands.Count == 0) return null;
foreach (Command cmd in commands)
Command.all.Add(cmd);
} catch (FileNotFoundException e) {
Server.ErrorLog(e);
return command + ".dll does not exist in the DLL folder, or is missing a dependency. Details in the error log.";
@ -188,5 +195,22 @@ namespace MCGalaxy {
}
return null;
}
public static List<Command> LoadFrom(Assembly lib) {
//Allows unloading and deleting dlls without server restart
List<Command> commands = new List<Command>();
foreach (Type t in lib.GetTypes()) {
if (t.IsAbstract || !t.IsSubclassOf(typeof(Command)) )continue;
object instance = Activator.CreateInstance(t);
if (instance == null) {
Server.s.Log("Command \"" + t.Name + "\" could not be loaded.");
throw new BadImageFormatException();
}
commands.Add((Command)instance);
}
return commands;
}
}
}

View File

@ -22,84 +22,38 @@ using System.Linq;
using System.Reflection;
namespace MCGalaxy.Util {
public sealed class MCGalaxyScripter {
private static readonly CompilerParameters _settings = new CompilerParameters(new [] {"mscorlib.dll", "MCGalaxy_.dll", "MCGalaxy.exe"}) {
GenerateInMemory = true
};
/// <summary>
/// Compiles the specified source code.
/// </summary>
/// <summary> Compiles the specified source code. </summary>
/// <param name="text">The text.</param>
/// <param name="language">The language.</param>
/// <returns>A result from the compilation</returns>
public static CompileResult Compile ( string text, ScriptLanguage language ) {
CodeDomProvider provider = null;
switch ( language ) {
case ScriptLanguage.CSharp:
provider = CodeDomProvider.CreateProvider( "CSharp" );
break;
case ScriptLanguage.VB:
provider = CodeDomProvider.CreateProvider( "VisualBasic" );
break;
case ScriptLanguage.JavaScript:
throw new NotImplementedException( "This language interface has not been implemented yet." );
public static CompileResult Compile(string text, ScriptLanguage language) {
Scripting scripting = language == ScriptLanguage.VB ? Scripting.VB : Scripting.CS;
CompilerParameters args = new CompilerParameters();
args.GenerateInMemory = true;
CompilerResults results = scripting.CompileSource(text, args);
if (results.Errors.HasErrors)
return new CompileResult(null, results.Errors);
List<Command> list = Scripting.LoadFrom(results.CompiledAssembly);
return new CompileResult(list.ToArray(), null);
}
if ( provider == null ) {
throw new NotImplementedException( "You must have .net developer tools. (You need a visual studio)" );
public static Command[] FromAssemblyFile(string file) {
Assembly lib = Assembly.LoadFile(file);
return Scripting.LoadFrom(lib).ToArray();
}
var compile = provider.CompileAssemblyFromSource( _settings, text );
if ( compile.Errors.Count > 0 ) {
return new CompileResult( null, compile.Errors );
}
var assembly = compile.CompiledAssembly;
var list = new List<Command>();
foreach ( Command command in from type in assembly.GetTypes()
where type.BaseType == typeof( Command )
select Activator.CreateInstance( type ) as Command ) {
list.Add( command );
}
return new CompileResult( list.ToArray(), null );
}
public static Command[] FromAssemblyFile ( string file ) {
Assembly lib = Assembly.LoadFile ( file );
var list = new List<Command>();
foreach ( var instance in lib.GetTypes().Where( t => t.BaseType == typeof( Command ) ).Select( Activator.CreateInstance ) ) {
list.Add( (Command) instance );
}
return list.ToArray ();
}
}
public sealed class CompileResult {
/// <summary>
/// Array of errors, if any.
/// </summary>
/// <summary> Array of errors, if any. </summary>
public CompilerErrorCollection CompilerErrors { get; internal set; }
/// <summary>
/// Gets the command object.
/// </summary>
/// <summary> Gets the command object. </summary>
public Command[] Commands { get; internal set; }
/// <summary>
/// Initializes a new instance of the <see cref="CompileResult"/> class.
/// </summary>
/// <summary> Initializes a new instance of the <see cref="CompileResult"/> class. </summary>
/// <param name="commands">The command object.</param>
/// <param name="errors">The errors.</param>
public CompileResult ( Command[] commands, CompilerErrorCollection errors ) {
@ -107,29 +61,16 @@ namespace MCGalaxy.Util {
CompilerErrors = errors;
}
/// <summary>
/// Initializes a new instance of the <see cref="CompileResult"/> class.
/// </summary>
/// <summary> Initializes a new instance of the <see cref="CompileResult"/> class. </summary>
public CompileResult () { }
}
public enum ScriptLanguage {
/// <summary>
/// C#.net Scripting Interface Language
/// </summary>
/// <summary> C#.net Scripting Interface Language </summary>
CSharp,
/// <summary>
/// VB.net Scripting Interface Language
/// </summary>
/// <summary> VB.net Scripting Interface Language </summary>
VB,
/// <summary>
/// JavaScript Scripting Interface Language.
/// NOTE: Not yet implemented
/// </summary>
/// <summary> JavaScript Scripting Interface Language. NOTE: Not yet implemented </summary>
JavaScript
}
}