/// <summary> /// Loads the component data for the currently selected mod. /// </summary> public void Load() { // TODO: Replace with a more robust building mechanism (and maybe more partial modding support?) CSharpCodeProvider codeProvider = new CSharpCodeProvider(new Dictionary <string, string> { { "CompilerVersion", "v3.5" } }); CompilerParameters pars = new CompilerParameters(); // Uncomment the following line to enforce code security // pars.Evidence = new Evidence(new object[] { new Zone(SecurityZone.Internet) }, null); pars.GenerateExecutable = false; pars.GenerateInMemory = true; pars.IncludeDebugInformation = true; // NOTE: Maybe the referenced assemblies and usings for inline methods should be defined in a xml? pars.ReferencedAssemblies.Add("System.dll"); pars.ReferencedAssemblies.Add("System.Core.dll"); pars.ReferencedAssemblies.Add("System.Drawing.dll"); pars.ReferencedAssemblies.Add("System.Xml.dll"); pars.ReferencedAssemblies.Add("SdlDotNet.dll"); pars.ReferencedAssemblies.Add("Teraluwide.Blackbird.Core.dll"); pars.ReferencedAssemblies.Add(Assembly.GetEntryAssembly().Location); string inlineCode = "using System; using System.Linq; using System.Drawing; using System.Text; using Teraluwide.Blackbird.Core.Gui; using Teraluwide.Blackbird.Core.Gui.Controls; public partial class Core { " + inlineMethods.ToString() + " }"; if (Game.Debug) { System.IO.File.WriteAllText("inlineSources.cs", inlineCode.ToString()); } Stopwatch sw = Stopwatch.StartNew(); // NOTE: If we expect to have huge scripts, it may be necessary to use an alternate way to compile them; At present time, this implementation is sufficient. CompilerResults res = codeProvider.CompileAssemblyFromSource(pars, VirtualPathProvider.FindFiles(VirtualPathProvider.EnsureModVirtualPath("scripts", Game.ModName), "*.cs").Select(i => VirtualPathProvider.GetFile(i).ReadToEnd()).Concat(new string[] { inlineCode }).ToArray()); sw.Stop(); Console.WriteLine("Scripts compiled in {0:#,###,##0} ms.", sw.ElapsedMilliseconds); // NOTE: Maybe there should be a better way to filter out warnings. if (res.Errors.Count > 0 && res.Errors.OfType <CompilerError>().Any(i => !i.IsWarning)) { System.IO.File.WriteAllLines("error.log", res.Errors.OfType <CompilerError>().Select(i => i.ToString()).ToArray()); // TODO: Handle compiler errors. if (!Debugger.IsAttached) { Debugger.Launch(); } Debugger.Break(); } else { Assembly assembly = res.CompiledAssembly; Type coreType = assembly.GetType("Core"); core = Activator.CreateInstance(coreType, Game); // Notify the late method binders. foreach (var binder in methodBinders) { // TODO: Add some error handling - missing methods, wrong definitions etc. MethodInfo mi = coreType.GetMethod(binder.MethodName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); binder.BindMethod(Delegate.CreateDelegate(binder.DelegateType, core, mi, true)); } } }