Init
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 015e5afa17239334c8f085479673d346
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
#if NET_4_6 && !NET_STANDARD_2_0
|
||||
#define QC_SUPPORTED
|
||||
#endif
|
||||
|
||||
using Mono.CSharp;
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.IO;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
|
||||
#if QC_SUPPORTED
|
||||
namespace CSharpCompiler
|
||||
{
|
||||
public class CodeCompiler : ICodeCompiler
|
||||
{
|
||||
static long assemblyCounter = 0;
|
||||
|
||||
public CompilerResults CompileAssemblyFromDom(CompilerParameters options, CodeCompileUnit compilationUnit)
|
||||
{
|
||||
return CompileAssemblyFromDomBatch(options, new[] { compilationUnit });
|
||||
}
|
||||
|
||||
public CompilerResults CompileAssemblyFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException("options");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return CompileFromDomBatch(options, ea);
|
||||
}
|
||||
finally
|
||||
{
|
||||
options.TempFiles.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private CompilerResults CompileFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
|
||||
{
|
||||
throw new NotImplementedException("sorry ICodeGenerator is not implemented, feel free to fix it and request merge");
|
||||
}
|
||||
|
||||
public CompilerResults CompileAssemblyFromFile(CompilerParameters options, string fileName)
|
||||
{
|
||||
return CompileAssemblyFromFileBatch(options, new[] { fileName });
|
||||
}
|
||||
|
||||
public CompilerResults CompileAssemblyFromFileBatch(CompilerParameters options, string[] fileNames)
|
||||
{
|
||||
var settings = ParamsToSettings(options);
|
||||
|
||||
foreach (var fileName in fileNames)
|
||||
{
|
||||
string path = Path.GetFullPath(fileName);
|
||||
var unit = new SourceFile(fileName, path, settings.SourceFiles.Count + 1);
|
||||
settings.SourceFiles.Add(unit);
|
||||
}
|
||||
|
||||
return CompileFromCompilerSettings(settings, options.GenerateInMemory);
|
||||
}
|
||||
|
||||
public CompilerResults CompileAssemblyFromSource(CompilerParameters options, string source)
|
||||
{
|
||||
return CompileAssemblyFromSourceBatch(options, new[] { source });
|
||||
}
|
||||
|
||||
public CompilerResults CompileAssemblyFromSourceBatch(CompilerParameters options, string[] sources)
|
||||
{
|
||||
var settings = ParamsToSettings(options);
|
||||
|
||||
int i = 0;
|
||||
foreach (var _source in sources)
|
||||
{
|
||||
var source = _source;
|
||||
Func<Stream> getStream = () => { return new MemoryStream(Encoding.UTF8.GetBytes(source ?? "")); };
|
||||
var fileName = i.ToString();
|
||||
var unit = new SourceFile(fileName, fileName, settings.SourceFiles.Count + 1, getStream);
|
||||
settings.SourceFiles.Add(unit);
|
||||
i++;
|
||||
}
|
||||
|
||||
return CompileFromCompilerSettings(settings, options.GenerateInMemory);
|
||||
}
|
||||
|
||||
|
||||
CompilerResults CompileFromCompilerSettings(CompilerSettings settings, bool generateInMemory)
|
||||
{
|
||||
var compilerResults = new CompilerResults(new TempFileCollection(Path.GetTempPath()));
|
||||
var driver = new CustomDynamicDriver(new CompilerContext(settings, new CustomReportPrinter(compilerResults)));
|
||||
|
||||
AssemblyBuilder outAssembly = null;
|
||||
try
|
||||
{
|
||||
driver.Compile(out outAssembly, AppDomain.CurrentDomain, generateInMemory);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
compilerResults.Errors.Add(new CompilerError()
|
||||
{
|
||||
IsWarning = false,
|
||||
ErrorText = e.Message,
|
||||
});
|
||||
}
|
||||
compilerResults.CompiledAssembly = outAssembly;
|
||||
|
||||
return compilerResults;
|
||||
}
|
||||
|
||||
|
||||
CompilerSettings ParamsToSettings(CompilerParameters parameters)
|
||||
{
|
||||
var settings = new CompilerSettings();
|
||||
|
||||
|
||||
foreach (var assembly in parameters.ReferencedAssemblies) settings.AssemblyReferences.Add(assembly);
|
||||
|
||||
settings.Encoding = System.Text.Encoding.UTF8;
|
||||
settings.GenerateDebugInfo = parameters.IncludeDebugInformation;
|
||||
settings.MainClass = parameters.MainClass;
|
||||
settings.Platform = Platform.AnyCPU;
|
||||
settings.StdLibRuntimeVersion = RuntimeVersion.v4;
|
||||
if (parameters.GenerateExecutable)
|
||||
{
|
||||
settings.Target = Target.Exe;
|
||||
settings.TargetExt = ".exe";
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.Target = Target.Library;
|
||||
settings.TargetExt = ".dll";
|
||||
}
|
||||
if (parameters.GenerateInMemory) settings.Target = Target.Library;
|
||||
|
||||
if (string.IsNullOrEmpty(parameters.OutputAssembly))
|
||||
{
|
||||
parameters.OutputAssembly = settings.OutputFile = "DynamicAssembly_" + assemblyCounter + settings.TargetExt;
|
||||
assemblyCounter++;
|
||||
}
|
||||
settings.OutputFile = parameters.OutputAssembly; // if it is not being outputted, we use this to set name of the dynamic assembly
|
||||
|
||||
settings.Version = LanguageVersion.Default;
|
||||
settings.WarningLevel = parameters.WarningLevel;
|
||||
settings.WarningsAreErrors = parameters.TreatWarningsAsErrors;
|
||||
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3f2a9227250eeb43a8e3c138ce1a6a1
|
||||
timeCreated: 1438909233
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
// modified version of Mono.CSharp.Driver
|
||||
|
||||
// driver.cs: The compiler command line driver.
|
||||
//
|
||||
// Authors:
|
||||
// Miguel de Icaza (miguel@gnu.org)
|
||||
// Marek Safar (marek.safar@gmail.com)
|
||||
//
|
||||
// Dual licensed under the terms of the MIT X11 or GNU GPL
|
||||
//
|
||||
// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
|
||||
// Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
|
||||
// Copyright 2011 Xamarin Inc
|
||||
//
|
||||
|
||||
#if NET_4_6 && !NET_STANDARD_2_0
|
||||
#define QC_SUPPORTED
|
||||
#endif
|
||||
|
||||
#if QC_SUPPORTED
|
||||
using Mono.CSharp;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace CSharpCompiler
|
||||
{
|
||||
/// <summary>
|
||||
/// The compiler driver.
|
||||
/// </summary>
|
||||
public class CustomDynamicDriver
|
||||
{
|
||||
readonly CompilerContext ctx;
|
||||
|
||||
public CustomDynamicDriver(CompilerContext ctx)
|
||||
{
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
public Report Report
|
||||
{
|
||||
get
|
||||
{
|
||||
return ctx.Report;
|
||||
}
|
||||
}
|
||||
|
||||
void tokenize_file(SourceFile sourceFile, ModuleContainer module, ParserSession session)
|
||||
{
|
||||
Stream input;
|
||||
|
||||
try
|
||||
{
|
||||
input = sourceFile.GetDataStream();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Report.Error(2001, "Source file `" + sourceFile.Name + "' could not be found");
|
||||
return;
|
||||
}
|
||||
|
||||
using (input)
|
||||
{
|
||||
SeekableStreamReader reader = new SeekableStreamReader(input, ctx.Settings.Encoding);
|
||||
var file = new CompilationSourceFile(module, sourceFile);
|
||||
|
||||
Tokenizer lexer = new Tokenizer(reader, file, session, ctx.Report);
|
||||
int token, tokens = 0, errors = 0;
|
||||
|
||||
while ((token = lexer.token()) != Token.EOF)
|
||||
{
|
||||
tokens++;
|
||||
if (token == Token.ERROR)
|
||||
errors++;
|
||||
}
|
||||
Console.WriteLine("Tokenized: " + tokens + " found " + errors + " errors");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public void Parse(ModuleContainer module)
|
||||
{
|
||||
bool tokenize_only = module.Compiler.Settings.TokenizeOnly;
|
||||
var sources = module.Compiler.SourceFiles;
|
||||
|
||||
Location.Initialize(sources);
|
||||
|
||||
var session = new ParserSession
|
||||
{
|
||||
UseJayGlobalArrays = true,
|
||||
LocatedTokens = new LocatedToken[15000]
|
||||
};
|
||||
|
||||
for (int i = 0; i < sources.Count; ++i)
|
||||
{
|
||||
if (tokenize_only)
|
||||
{
|
||||
tokenize_file(sources[i], module, session);
|
||||
}
|
||||
else
|
||||
{
|
||||
Parse(sources[i], module, session, Report);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Parse(SourceFile file, ModuleContainer module, ParserSession session, Report report)
|
||||
{
|
||||
Stream input;
|
||||
|
||||
try
|
||||
{
|
||||
input = file.GetDataStream();
|
||||
}
|
||||
catch
|
||||
{
|
||||
report.Error(2001, "Source file `{0}' could not be found", file.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check 'MZ' header
|
||||
if (input.ReadByte() == 77 && input.ReadByte() == 90)
|
||||
{
|
||||
|
||||
report.Error(2015, "Source file `{0}' is a binary file and not a text file", file.Name);
|
||||
input.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
input.Position = 0;
|
||||
SeekableStreamReader reader = new SeekableStreamReader(input, ctx.Settings.Encoding, session.StreamReaderBuffer);
|
||||
|
||||
Parse(reader, file, module, session, report);
|
||||
|
||||
if (ctx.Settings.GenerateDebugInfo && report.Errors == 0 && !file.HasChecksum)
|
||||
{
|
||||
input.Position = 0;
|
||||
var checksum = session.GetChecksumAlgorithm();
|
||||
file.SetChecksum(checksum.ComputeHash(input));
|
||||
}
|
||||
|
||||
reader.Dispose();
|
||||
input.Close();
|
||||
}
|
||||
|
||||
public static void Parse(SeekableStreamReader reader, SourceFile sourceFile, ModuleContainer module, ParserSession session, Report report)
|
||||
{
|
||||
var file = new CompilationSourceFile(module, sourceFile);
|
||||
module.AddTypeContainer(file);
|
||||
|
||||
CSharpParser parser = new CSharpParser(reader, file, report, session);
|
||||
parser.parse();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Main compilation method
|
||||
//
|
||||
public bool Compile(out AssemblyBuilder outAssembly, AppDomain domain, bool generateInMemory)
|
||||
{
|
||||
var settings = ctx.Settings;
|
||||
|
||||
outAssembly = null;
|
||||
//
|
||||
// If we are an exe, require a source file for the entry point or
|
||||
// if there is nothing to put in the assembly, and we are not a library
|
||||
//
|
||||
if (settings.FirstSourceFile == null &&
|
||||
((settings.Target == Target.Exe || settings.Target == Target.WinExe || settings.Target == Target.Module) ||
|
||||
settings.Resources == null))
|
||||
{
|
||||
Report.Error(2008, "No files to compile were specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings.Platform == Platform.AnyCPU32Preferred && (settings.Target == Target.Library || settings.Target == Target.Module))
|
||||
{
|
||||
Report.Error(4023, "Platform option `anycpu32bitpreferred' is valid only for executables");
|
||||
return false;
|
||||
}
|
||||
|
||||
TimeReporter tr = new TimeReporter(settings.Timestamps);
|
||||
ctx.TimeReporter = tr;
|
||||
tr.StartTotal();
|
||||
|
||||
var module = new ModuleContainer(ctx);
|
||||
RootContext.ToplevelTypes = module;
|
||||
|
||||
tr.Start(TimeReporter.TimerType.ParseTotal);
|
||||
Parse(module);
|
||||
tr.Stop(TimeReporter.TimerType.ParseTotal);
|
||||
|
||||
if (Report.Errors > 0)
|
||||
return false;
|
||||
|
||||
if (settings.TokenizeOnly || settings.ParseOnly)
|
||||
{
|
||||
tr.StopTotal();
|
||||
tr.ShowStats();
|
||||
return true;
|
||||
}
|
||||
|
||||
var output_file = settings.OutputFile;
|
||||
string output_file_name;
|
||||
/* if (output_file == null)
|
||||
{
|
||||
var source_file = settings.FirstSourceFile;
|
||||
|
||||
if (source_file == null)
|
||||
{
|
||||
Report.Error(1562, "If no source files are specified you must specify the output file with -out:");
|
||||
return false;
|
||||
}
|
||||
|
||||
output_file_name = source_file.Name;
|
||||
int pos = output_file_name.LastIndexOf('.');
|
||||
|
||||
if (pos > 0)
|
||||
output_file_name = output_file_name.Substring(0, pos);
|
||||
|
||||
output_file_name += settings.TargetExt;
|
||||
output_file = output_file_name;
|
||||
}
|
||||
else
|
||||
{*/
|
||||
output_file_name = Path.GetFileName(output_file);
|
||||
|
||||
/* if (string.IsNullOrEmpty(Path.GetFileNameWithoutExtension(output_file_name)) ||
|
||||
output_file_name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
|
||||
{
|
||||
Report.Error(2021, "Output file name is not valid");
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
var assembly = new AssemblyDefinitionDynamic(module, output_file_name, output_file);
|
||||
module.SetDeclaringAssembly(assembly);
|
||||
|
||||
var importer = new ReflectionImporter(module, ctx.BuiltinTypes);
|
||||
assembly.Importer = importer;
|
||||
|
||||
var loader = new DynamicLoader(importer, ctx);
|
||||
loader.LoadReferences(module);
|
||||
|
||||
if (!ctx.BuiltinTypes.CheckDefinitions(module))
|
||||
return false;
|
||||
|
||||
if (!assembly.Create(domain, AssemblyBuilderAccess.RunAndSave))
|
||||
return false;
|
||||
|
||||
module.CreateContainer();
|
||||
|
||||
loader.LoadModules(assembly, module.GlobalRootNamespace);
|
||||
|
||||
module.InitializePredefinedTypes();
|
||||
|
||||
if (settings.GetResourceStrings != null)
|
||||
module.LoadGetResourceStrings(settings.GetResourceStrings);
|
||||
|
||||
tr.Start(TimeReporter.TimerType.ModuleDefinitionTotal);
|
||||
module.Define();
|
||||
tr.Stop(TimeReporter.TimerType.ModuleDefinitionTotal);
|
||||
|
||||
if (Report.Errors > 0)
|
||||
return false;
|
||||
|
||||
if (settings.DocumentationFile != null)
|
||||
{
|
||||
var doc = new DocumentationBuilder(module);
|
||||
doc.OutputDocComment(output_file, settings.DocumentationFile);
|
||||
}
|
||||
|
||||
assembly.Resolve();
|
||||
|
||||
if (Report.Errors > 0)
|
||||
return false;
|
||||
|
||||
|
||||
tr.Start(TimeReporter.TimerType.EmitTotal);
|
||||
assembly.Emit();
|
||||
tr.Stop(TimeReporter.TimerType.EmitTotal);
|
||||
|
||||
if (Report.Errors > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
tr.Start(TimeReporter.TimerType.CloseTypes);
|
||||
module.CloseContainer();
|
||||
tr.Stop(TimeReporter.TimerType.CloseTypes);
|
||||
|
||||
tr.Start(TimeReporter.TimerType.Resouces);
|
||||
if (!settings.WriteMetadataOnly)
|
||||
assembly.EmbedResources();
|
||||
tr.Stop(TimeReporter.TimerType.Resouces);
|
||||
|
||||
if (Report.Errors > 0)
|
||||
return false;
|
||||
|
||||
|
||||
if (!generateInMemory) assembly.Save();
|
||||
outAssembly = assembly.Builder;
|
||||
|
||||
|
||||
tr.StopTotal();
|
||||
tr.ShowStats();
|
||||
|
||||
return Report.Errors == 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e389d8a5b0e25ae44a841060cecca276
|
||||
timeCreated: 1435446720
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
#if NET_4_6 && !NET_STANDARD_2_0
|
||||
#define QC_SUPPORTED
|
||||
#endif
|
||||
|
||||
using Mono.CSharp;
|
||||
using System.CodeDom.Compiler;
|
||||
|
||||
#if QC_SUPPORTED
|
||||
namespace CSharpCompiler
|
||||
{
|
||||
|
||||
public class CustomReportPrinter : ReportPrinter
|
||||
{
|
||||
|
||||
readonly CompilerResults compilerResults;
|
||||
#region Properties
|
||||
|
||||
public new int ErrorsCount { get; protected set; }
|
||||
|
||||
public new int WarningsCount { get; private set; }
|
||||
|
||||
#endregion
|
||||
public CustomReportPrinter(CompilerResults compilerResults)
|
||||
{
|
||||
this.compilerResults = compilerResults;
|
||||
}
|
||||
|
||||
public override void Print(AbstractMessage msg, bool showFullPath)
|
||||
{
|
||||
if (msg.IsWarning)
|
||||
{
|
||||
++WarningsCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++ErrorsCount;
|
||||
}
|
||||
compilerResults.Errors.Add(new CompilerError()
|
||||
{
|
||||
IsWarning = msg.IsWarning,
|
||||
Column = msg.Location.Column,
|
||||
Line = msg.Location.Row,
|
||||
ErrorNumber = msg.Code.ToString(),
|
||||
ErrorText = msg.Text,
|
||||
FileName = showFullPath ? msg.Location.SourceFile.FullPathName : msg.Location.SourceFile.Name,
|
||||
// msg.RelatedSymbols // extra info
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39ec208e78505e342a2829289445b934
|
||||
timeCreated: 1438909233
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Implementation of ISynchronizeInvoke for Unity3D game engine.
|
||||
Can be used to invoke anything on main Unity thread.
|
||||
ISynchronizeInvoke is used extensively in .NET forms it's is elegant and quite useful in Unity as well.
|
||||
I implemented it so i can use it with System.IO.FileSystemWatcher.SynchronizingObject.
|
||||
|
||||
help from: http://www.codeproject.com/Articles/12082/A-DelegateQueue-Class
|
||||
example usage: https://gist.github.com/aeroson/90bf21be3fdc4829e631
|
||||
|
||||
license: WTFPL (http://www.wtfpl.net/)
|
||||
contact: aeroson (theaeroson @gmail.com)
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
public class DeferredSynchronizeInvoke : ISynchronizeInvoke
|
||||
{
|
||||
Queue<UnityAsyncResult> fifoToExecute = new Queue<UnityAsyncResult>();
|
||||
Thread mainThread;
|
||||
public bool InvokeRequired { get { return mainThread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId; } }
|
||||
|
||||
public DeferredSynchronizeInvoke()
|
||||
{
|
||||
mainThread = Thread.CurrentThread;
|
||||
}
|
||||
public IAsyncResult BeginInvoke(Delegate method, object[] args)
|
||||
{
|
||||
var asyncResult = new UnityAsyncResult()
|
||||
{
|
||||
method = method,
|
||||
args = args,
|
||||
IsCompleted = false,
|
||||
AsyncWaitHandle = new ManualResetEvent(false),
|
||||
};
|
||||
lock (fifoToExecute)
|
||||
{
|
||||
fifoToExecute.Enqueue(asyncResult);
|
||||
}
|
||||
return asyncResult;
|
||||
}
|
||||
public object EndInvoke(IAsyncResult result)
|
||||
{
|
||||
if (!result.IsCompleted)
|
||||
{
|
||||
result.AsyncWaitHandle.WaitOne();
|
||||
}
|
||||
return result.AsyncState;
|
||||
}
|
||||
public object Invoke(Delegate method, object[] args)
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
var asyncResult = BeginInvoke(method, args);
|
||||
return EndInvoke(asyncResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
return method.DynamicInvoke(args);
|
||||
}
|
||||
}
|
||||
public void ProcessQueue()
|
||||
{
|
||||
if (Thread.CurrentThread != mainThread)
|
||||
{
|
||||
throw new TargetException(
|
||||
this.GetType() + "." + MethodBase.GetCurrentMethod().Name + "() " +
|
||||
"must be called from the same thread it was created on " +
|
||||
"(created on thread id: " + mainThread.ManagedThreadId + ", called from thread id: " + Thread.CurrentThread.ManagedThreadId
|
||||
);
|
||||
}
|
||||
bool loop = true;
|
||||
UnityAsyncResult data = null;
|
||||
while (loop)
|
||||
{
|
||||
lock (fifoToExecute)
|
||||
{
|
||||
loop = fifoToExecute.Count > 0;
|
||||
if (!loop) break;
|
||||
data = fifoToExecute.Dequeue();
|
||||
}
|
||||
|
||||
data.AsyncState = Invoke(data.method, data.args);
|
||||
data.IsCompleted = true;
|
||||
}
|
||||
}
|
||||
class UnityAsyncResult : IAsyncResult
|
||||
{
|
||||
public Delegate method;
|
||||
public object[] args;
|
||||
public bool IsCompleted { get; set; }
|
||||
public WaitHandle AsyncWaitHandle { get; internal set; }
|
||||
public object AsyncState { get; set; }
|
||||
public bool CompletedSynchronously { get { return IsCompleted; } }
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6228134abfaad746965d9639b73908a
|
||||
timeCreated: 1435576341
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
Copyright (c) 2001, 2002, 2003 Ximian, Inc and the individuals listed
|
||||
on the ChangeLog entries.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09298e73731a3b64fbedf483cf7d4e42
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ce9bfedd125d1c49adb5c65c9e8ce53
|
||||
folderAsset: yes
|
||||
timeCreated: 1435432572
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
+30
@@ -0,0 +1,30 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0447405aaa6f3bd4c96d4c64631542fd
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
#if NET_4_6 && !NET_STANDARD_2_0
|
||||
#define QC_SUPPORTED
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
#if QC_SUPPORTED
|
||||
namespace CSharpCompiler
|
||||
{
|
||||
public class ScriptBundleLoader
|
||||
{
|
||||
public Func<Type, object> createInstance = (Type type) => { return Activator.CreateInstance(type); };
|
||||
public Action<object> destroyInstance = delegate { };
|
||||
|
||||
public TextWriter logWriter = Console.Out;
|
||||
|
||||
ISynchronizeInvoke synchronizedInvoke;
|
||||
List<ScriptBundle> allFilesBundle = new List<ScriptBundle>();
|
||||
|
||||
public ScriptBundleLoader(ISynchronizeInvoke synchronizedInvoke)
|
||||
{
|
||||
this.synchronizedInvoke = synchronizedInvoke;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="fileSources"></param>
|
||||
/// <returns>true on success, false on failure</returns>
|
||||
public ScriptBundle LoadAndWatchScriptsBundle(IEnumerable<string> fileSources)
|
||||
{
|
||||
var bundle = new ScriptBundle(this, fileSources);
|
||||
allFilesBundle.Add(bundle);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages a bundle of files which form one assembly, if one file changes entire assembly is recompiled.
|
||||
/// </summary>
|
||||
public class ScriptBundle
|
||||
{
|
||||
Assembly assembly;
|
||||
IEnumerable<string> filePaths;
|
||||
List<FileSystemWatcher> fileSystemWatchers = new List<FileSystemWatcher>();
|
||||
List<object> instances = new List<object>();
|
||||
ScriptBundleLoader manager;
|
||||
|
||||
string[] assemblyReferences;
|
||||
public ScriptBundle(ScriptBundleLoader manager, IEnumerable<string> filePaths)
|
||||
{
|
||||
this.filePaths = filePaths.Select(x => Path.GetFullPath(x));
|
||||
this.manager = manager;
|
||||
|
||||
var domain = System.AppDomain.CurrentDomain;
|
||||
this.assemblyReferences = domain
|
||||
.GetAssemblies()
|
||||
.Where(a => !(a is System.Reflection.Emit.AssemblyBuilder) && !string.IsNullOrEmpty(a.Location))
|
||||
.Select(a => a.Location)
|
||||
.ToArray();
|
||||
|
||||
manager.logWriter.WriteLine("loading " + string.Join(", ", filePaths.ToArray()));
|
||||
CompileFiles();
|
||||
CreateFileWatchers();
|
||||
CreateNewInstances();
|
||||
}
|
||||
|
||||
void CompileFiles()
|
||||
{
|
||||
filePaths = filePaths.Where(x => File.Exists(x)).ToArray();
|
||||
|
||||
var options = new CompilerParameters();
|
||||
options.GenerateExecutable = false;
|
||||
options.GenerateInMemory = true;
|
||||
options.ReferencedAssemblies.AddRange(assemblyReferences);
|
||||
|
||||
var compiler = new CodeCompiler();
|
||||
var result = compiler.CompileAssemblyFromFileBatch(options, filePaths.ToArray());
|
||||
|
||||
foreach (var err in result.Errors)
|
||||
{
|
||||
manager.logWriter.WriteLine(err);
|
||||
}
|
||||
|
||||
this.assembly = result.CompiledAssembly;
|
||||
}
|
||||
void CreateFileWatchers()
|
||||
{
|
||||
foreach (var filePath in filePaths)
|
||||
{
|
||||
FileSystemWatcher watcher = new FileSystemWatcher();
|
||||
fileSystemWatchers.Add(watcher);
|
||||
watcher.Path = Path.GetDirectoryName(filePath);
|
||||
/* Watch for changes in LastAccess and LastWrite times, and
|
||||
the renaming of files or directories. */
|
||||
watcher.NotifyFilter = NotifyFilters.LastWrite
|
||||
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
|
||||
watcher.Filter = Path.GetFileName(filePath);
|
||||
|
||||
// Add event handlers.
|
||||
watcher.Changed += new FileSystemEventHandler((object o, FileSystemEventArgs a) => { Reload(recreateWatchers: false); });
|
||||
//watcher.Created += new FileSystemEventHandler((object o, FileSystemEventArgs a) => { });
|
||||
watcher.Deleted += new FileSystemEventHandler((object o, FileSystemEventArgs a) => { Reload(recreateWatchers: false); });
|
||||
watcher.Renamed += new RenamedEventHandler((object o, RenamedEventArgs a) =>
|
||||
{
|
||||
filePaths = filePaths.Select(x =>
|
||||
{
|
||||
if (x == a.OldFullPath) return a.FullPath;
|
||||
else return x;
|
||||
});
|
||||
Reload(recreateWatchers: true);
|
||||
});
|
||||
watcher.SynchronizingObject = manager.synchronizedInvoke;
|
||||
// Begin watching.
|
||||
watcher.EnableRaisingEvents = true;
|
||||
}
|
||||
}
|
||||
void StopFileWatchers()
|
||||
{
|
||||
foreach (var w in fileSystemWatchers)
|
||||
{
|
||||
w.EnableRaisingEvents = false;
|
||||
w.Dispose();
|
||||
}
|
||||
fileSystemWatchers.Clear();
|
||||
}
|
||||
void Reload(bool recreateWatchers = false)
|
||||
{
|
||||
manager.logWriter.WriteLine("reloading " + string.Join(", ", filePaths.ToArray()));
|
||||
StopInstances();
|
||||
CompileFiles();
|
||||
CreateNewInstances();
|
||||
if (recreateWatchers)
|
||||
{
|
||||
StopFileWatchers();
|
||||
CreateFileWatchers();
|
||||
}
|
||||
}
|
||||
void CreateNewInstances()
|
||||
{
|
||||
if (assembly == null) return;
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
manager.synchronizedInvoke.Invoke((System.Action)(() =>
|
||||
{
|
||||
instances.Add(manager.createInstance(type));
|
||||
}), null);
|
||||
}
|
||||
}
|
||||
void StopInstances()
|
||||
{
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
manager.synchronizedInvoke.Invoke((System.Action)(() =>
|
||||
{
|
||||
manager.destroyInstance(instance);
|
||||
}), null);
|
||||
}
|
||||
instances.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3dfc88ca39a87dc46bc7fd337be863bb
|
||||
timeCreated: 1440503653
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,110 @@
|
||||
#if NET_4_6 && !NET_STANDARD_2_0
|
||||
#define QC_SUPPORTED
|
||||
#endif
|
||||
|
||||
#if QC_SUPPORTED && !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace QFSW.QC
|
||||
{
|
||||
public static class DynamicCodeCommands
|
||||
{
|
||||
private const Platform execAvailability = Platform.AllPlatforms ^ (Platform.WebGLPlayer | Platform.IPhonePlayer | Platform.XboxOne | Platform.PS4 | Platform.Switch);
|
||||
|
||||
[CommandDescription("Loads the code at the specified file and compiles it to C# which will then be executed. Use with caution as no safety checks will be performed. Not supported in AOT (IL2CPP) builds." +
|
||||
"\n\nBy default, boiler plate code will NOT be inserted around the code you provide. Please see 'exec' for more information about boilerplate insertion")]
|
||||
[Command("exec-extern", execAvailability)]
|
||||
private static async Task ExecuteExternalArbitaryCodeAsync(string filePath, bool insertBoilerplate = false)
|
||||
{
|
||||
if (!File.Exists(filePath)) { throw new ArgumentException($"file at the specified path '{filePath}' did not exist."); }
|
||||
string code = File.ReadAllText(filePath);
|
||||
await ExecuteArbitaryCodeAsync(code.Replace("”", "\"").Replace("“", "\""), insertBoilerplate);
|
||||
}
|
||||
|
||||
[CommandDescription("Compiles the given code to C# which will then be executed. Use with caution as no safety checks will be performed. Not supported in AOT (IL2CPP) builds." +
|
||||
"\n\nBy default, boiler plate code will be inserted around the code you provide. This means various namespaces will be included, and the main class and main function entry point will " +
|
||||
"provided. In this case, the code you provide should be code that would exist within the body of the main function, and thus cannot contain things such as class definition. If you " +
|
||||
"disable boiler plate insertion, you can write whatever code you want, however you must provide a static entry point called Main in a static class called Program")]
|
||||
[Command("exec", execAvailability)]
|
||||
private static async Task ExecuteArbitaryCodeAsync(string code, bool insertBoilerplate = true)
|
||||
{
|
||||
#if !UNITY_EDITOR && ENABLE_IL2CPP
|
||||
await Task.FromException(new Exception("exec is not supported on AOT platforms such as IL2CPP and requires JIT (Mono)."));
|
||||
#else
|
||||
MethodInfo entryPoint = await Task.Run(() =>
|
||||
{
|
||||
string fullCode = string.Empty;
|
||||
if (insertBoilerplate)
|
||||
{
|
||||
string[] includedNamespaces = new string[] { "System", "System.Collections", "System.Collections.Generic",
|
||||
"System.Reflection", "System.Linq", "System.Text", "System.Globalization",
|
||||
"UnityEngine", "UnityEngine.Events", "UnityEngine.EventSystems", "UnityEngine.UI" };
|
||||
|
||||
for (int i = 0; i < includedNamespaces.Length; i++) { fullCode += $"using {includedNamespaces[i]};\n"; }
|
||||
fullCode += @"
|
||||
public class Program
|
||||
{
|
||||
public static void Main()
|
||||
{"
|
||||
+ code +
|
||||
@"}
|
||||
}";
|
||||
}
|
||||
else { fullCode = code; }
|
||||
|
||||
Assembly assembly = CompileCode(fullCode);
|
||||
BindingFlags searchFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
|
||||
Type program = assembly.GetType("Program");
|
||||
if (program == null) { throw new ArgumentException("Code Execution Failure - required static class Program could not be found"); }
|
||||
entryPoint = program.GetMethod("Main", searchFlags);
|
||||
if (entryPoint == null) { throw new ArgumentException("Code Execution Failure - required static entry point Main could not be found"); }
|
||||
return entryPoint;
|
||||
});
|
||||
|
||||
entryPoint.Invoke(null, null);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static Assembly CompileCode(string code)
|
||||
{
|
||||
#if !UNITY_EDITOR && ENABLE_IL2CPP
|
||||
throw new Exception("Code compilation is not supported on AOT platforms such as IL2CPP and requires JIT (Mono).");
|
||||
#else
|
||||
CSharpCompiler.CodeCompiler compiler = new CSharpCompiler.CodeCompiler();
|
||||
CompilerParameters compilerParams = new CompilerParameters();
|
||||
Assembly[] allLoadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
compilerParams.GenerateExecutable = false;
|
||||
compilerParams.GenerateInMemory = true;
|
||||
for (int i = 0; i < allLoadedAssemblies.Length; i++)
|
||||
{
|
||||
if (!allLoadedAssemblies[i].IsDynamic)
|
||||
{
|
||||
string dllName = allLoadedAssemblies[i].Location;
|
||||
compilerParams.ReferencedAssemblies.Add(dllName);
|
||||
}
|
||||
}
|
||||
|
||||
CompilerResults compiledCode = compiler.CompileAssemblyFromSource(compilerParams, code);
|
||||
|
||||
if (compiledCode.Errors.HasErrors)
|
||||
{
|
||||
string errorMessage = "Code Compilation Failure";
|
||||
for (int i = 0; i < compiledCode.Errors.Count; i++)
|
||||
{
|
||||
errorMessage += $"\n{compiledCode.Errors[i].ErrorNumber} - {compiledCode.Errors[i].ErrorText}";
|
||||
}
|
||||
|
||||
throw new ArgumentException(errorMessage);
|
||||
}
|
||||
|
||||
return compiledCode.CompiledAssembly;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e32a67fb03a2f6548b653203ff9fedf3
|
||||
timeCreated: 1553955853
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user