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;
using System.CodeDom.Compiler; using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
@ -47,6 +48,11 @@ namespace MCGalaxy {
public Scripting() { public Scripting() {
compiler = CodeDomProvider.CreateProvider(ProviderName); 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) { public void CreateNew(string cmdName) {
@ -86,12 +92,12 @@ namespace MCGalaxy {
if (!Directory.Exists(DllDir)) if (!Directory.Exists(DllDir))
Directory.CreateDirectory(DllDir); Directory.CreateDirectory(DllDir);
CompilerParameters args = new CompilerParameters();
args.GenerateExecutable = false; args.GenerateExecutable = false;
args.MainClass = cmdName; args.MainClass = cmdName;
args.OutputAssembly = DllDir + "Cmd" + cmdName + ".dll"; args.OutputAssembly = DllDir + "Cmd" + cmdName + ".dll";
args.ReferencedAssemblies.Add("MCGalaxy_.dll"); string source = File.ReadAllText(path);
string code = File.ReadAllText(path); results = CompileSource(source, args);
results = compiler.CompileAssemblyFromSource(args, code.Replace("MCLawl", "MCGalaxy"));
switch (results.Errors.Count) { switch (results.Errors.Count) {
case 0: case 0:
@ -132,6 +138,15 @@ namespace MCGalaxy {
sb.AppendLine(); 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> /// <summary> Automatically loads all .dll commands specified in the autoload file. </summary>
public static void Autoload() { public static void Autoload() {
if (!File.Exists(AutoloadFile)) { File.Create(AutoloadFile); return; } if (!File.Exists(AutoloadFile)) { File.Create(AutoloadFile); return; }
@ -142,7 +157,6 @@ namespace MCGalaxy {
string error = Scripting.Load("Cmd" + cmd.ToLower()); string error = Scripting.Load("Cmd" + cmd.ToLower());
if (error != null) { Server.s.Log(error); continue; } if (error != null) { Server.s.Log(error); continue; }
Server.s.Log("AUTOLOAD: Loaded " + cmd.ToLower() + ".dll"); Server.s.Log("AUTOLOAD: Loaded " + cmd.ToLower() + ".dll");
} }
} }
@ -153,20 +167,13 @@ namespace MCGalaxy {
if (command.Length < 3 || command.Substring(0, 3).ToLower() != "cmd") if (command.Length < 3 || command.Substring(0, 3).ToLower() != "cmd")
return "Invalid command name specified."; return "Invalid command name specified.";
try { try {
//Allows unloading and deleting dlls without server restart
byte[] data = File.ReadAllBytes(DllDir + command + ".dll"); 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 (commands.Count == 0) return null;
if (t.BaseType != typeof(Command)) continue; foreach (Command cmd in commands)
object instance = Activator.CreateInstance(t); Command.all.Add(cmd);
if (instance == null) {
Server.s.Log("The command " + command + " couldn't be loaded!");
throw new BadImageFormatException();
}
Command.all.Add((Command)instance);
}
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Server.ErrorLog(e); Server.ErrorLog(e);
return command + ".dll does not exist in the DLL folder, or is missing a dependency. Details in the error log."; 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; 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

@ -1,19 +1,19 @@
/* /*
Copyright 2013 - Headdetect, And his almightyness Copyright 2013 - Headdetect, And his almightyness
Dual-licensed under the Educational Community License, Version 2.0 and Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing, Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS" software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses. permissions and limitations under the Licenses.
*/ */
using System; using System;
using System.CodeDom.Compiler; using System.CodeDom.Compiler;
@ -22,84 +22,38 @@ using System.Linq;
using System.Reflection; using System.Reflection;
namespace MCGalaxy.Util { namespace MCGalaxy.Util {
public sealed class MCGalaxyScripter { public sealed class MCGalaxyScripter {
private static readonly CompilerParameters _settings = new CompilerParameters(new [] {"mscorlib.dll", "MCGalaxy_.dll", "MCGalaxy.exe"}) { /// <summary> Compiles the specified source code. </summary>
GenerateInMemory = true
};
/// <summary>
/// Compiles the specified source code.
/// </summary>
/// <param name="text">The text.</param> /// <param name="text">The text.</param>
/// <param name="language">The language.</param> /// <param name="language">The language.</param>
/// <returns>A result from the compilation</returns> /// <returns>A result from the compilation</returns>
public static CompileResult Compile ( string text, ScriptLanguage language ) { public static CompileResult Compile(string text, ScriptLanguage language) {
CodeDomProvider provider = null; Scripting scripting = language == ScriptLanguage.VB ? Scripting.VB : Scripting.CS;
CompilerParameters args = new CompilerParameters();
switch ( language ) { args.GenerateInMemory = true;
case ScriptLanguage.CSharp:
provider = CodeDomProvider.CreateProvider( "CSharp" ); CompilerResults results = scripting.CompileSource(text, args);
break; if (results.Errors.HasErrors)
case ScriptLanguage.VB: return new CompileResult(null, results.Errors);
provider = CodeDomProvider.CreateProvider( "VisualBasic" ); List<Command> list = Scripting.LoadFrom(results.CompiledAssembly);
break; return new CompileResult(list.ToArray(), null);
case ScriptLanguage.JavaScript:
throw new NotImplementedException( "This language interface has not been implemented yet." );
}
if ( provider == null ) {
throw new NotImplementedException( "You must have .net developer tools. (You need a visual studio)" );
}
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 ) { public static Command[] FromAssemblyFile(string file) {
Assembly lib = Assembly.LoadFile ( file ); Assembly lib = Assembly.LoadFile(file);
var list = new List<Command>(); return Scripting.LoadFrom(lib).ToArray();
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 { public sealed class CompileResult {
/// <summary> Array of errors, if any. </summary>
/// <summary>
/// Array of errors, if any.
/// </summary>
public CompilerErrorCollection CompilerErrors { get; internal set; } public CompilerErrorCollection CompilerErrors { get; internal set; }
/// <summary> /// <summary> Gets the command object. </summary>
/// Gets the command object.
/// </summary>
public Command[] Commands { get; internal set; } public Command[] Commands { get; internal set; }
/// <summary> /// <summary> Initializes a new instance of the <see cref="CompileResult"/> class. </summary>
/// Initializes a new instance of the <see cref="CompileResult"/> class.
/// </summary>
/// <param name="commands">The command object.</param> /// <param name="commands">The command object.</param>
/// <param name="errors">The errors.</param> /// <param name="errors">The errors.</param>
public CompileResult ( Command[] commands, CompilerErrorCollection errors ) { public CompileResult ( Command[] commands, CompilerErrorCollection errors ) {
@ -107,29 +61,16 @@ namespace MCGalaxy.Util {
CompilerErrors = errors; CompilerErrors = errors;
} }
/// <summary> /// <summary> Initializes a new instance of the <see cref="CompileResult"/> class. </summary>
/// Initializes a new instance of the <see cref="CompileResult"/> class.
/// </summary>
public CompileResult () { } public CompileResult () { }
} }
public enum ScriptLanguage { public enum ScriptLanguage {
/// <summary> C#.net Scripting Interface Language </summary>
/// <summary>
/// C#.net Scripting Interface Language
/// </summary>
CSharp, CSharp,
/// <summary> VB.net Scripting Interface Language </summary>
/// <summary>
/// VB.net Scripting Interface Language
/// </summary>
VB, VB,
/// <summary> JavaScript Scripting Interface Language. NOTE: Not yet implemented </summary>
/// <summary>
/// JavaScript Scripting Interface Language.
/// NOTE: Not yet implemented
/// </summary>
JavaScript JavaScript
} }
} }