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

@ -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
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.CodeDom.Compiler;
@ -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." );
}
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 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);
}
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 static Command[] FromAssemblyFile(string file) {
Assembly lib = Assembly.LoadFile(file);
return Scripting.LoadFrom(lib).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
}
}