private void ResolveReferences(CompilablePlugin plugin) { foreach (string reference in plugin.References) { Match match = Regex.Match(reference, @"^(Oxide\.(?:Ext|Game)\.(.+))$", RegexOptions.IgnoreCase); if (!match.Success) { continue; } string fullName = match.Groups[1].Value; string name = match.Groups[2].Value; if (extensionNames.Contains(name)) { continue; } if (Directory.Exists(includePath)) { string includeFilePath = Path.Combine(includePath, $"Ext.{name}.cs"); if (File.Exists(includeFilePath)) { plugin.IncludePaths.Add(includeFilePath); continue; } } string message = $"{fullName} is referenced by {plugin.Name} plugin but is not loaded! An appropriate include file needs to be saved to plugins\\include\\Ext.{name}.cs if this extension is not required."; Interface.Oxide.LogError(message); plugin.CompilerErrors = message; RemovePlugin(plugin); } }
internal void Compile(CompilablePlugin[] plugins, Action<Compilation> callback) { var id = lastId++; var compilation = new Compilation(id, callback, plugins); compilations[id] = compilation; compilation.Prepare(() => EnqueueCompilation(compilation)); }
private void ResolveReferences(CompilablePlugin plugin) { foreach (string reference in plugin.References) { Match match = Regex.Match(reference, "^(Oxide\\.(?:Ext|Game)\\.(.+))$", RegexOptions.IgnoreCase); if (!match.Success) { continue; } string value = match.Groups[1].Value; string str = match.Groups[2].Value; if (this.extensionNames.Contains <string>(str)) { continue; } if (Directory.Exists(this.includePath)) { string str1 = Path.Combine(this.includePath, string.Concat("Ext.", str, ".cs")); if (File.Exists(str1)) { plugin.IncludePaths.Add(str1); continue; } } string str2 = string.Concat(new string[] { value, " is referenced by ", plugin.Name, " plugin but is not loaded! An appropriate include file needs to be saved to plugins\\include\\Ext.", str, ".cs if this extension is not required." }); Interface.Oxide.LogError(str2, Array.Empty <object>()); plugin.CompilerErrors = str2; this.RemovePlugin(plugin); } }
public override void Reload(string directory, string name) { if (!Regex.Match(directory, "\\\\include\\b", RegexOptions.IgnoreCase).Success) { CompilablePlugin compilablePlugin = CSharpPluginLoader.GetCompilablePlugin(directory, name); if (!compilablePlugin.IsLoading) { this.Load(compilablePlugin); return; } Interface.Oxide.LogDebug(string.Concat("Reload requested for plugin which is already loading: ", compilablePlugin.Name), Array.Empty <object>()); return; } name = string.Concat("Oxide.", name); foreach (CompilablePlugin value in CSharpPluginLoader.plugins.Values) { if (!value.References.Contains(name)) { continue; } Interface.Oxide.LogInfo(string.Concat("Reloading ", value.Name, " because it references updated include file: ", name), Array.Empty <object>()); value.LastModifiedAt = DateTime.Now; this.Load(value); } }
/// <summary> /// Attempt to asynchronously compile plugin and only reload if successful /// </summary> /// <param name="directory"></param> /// <param name="name"></param> public override void Reload(string directory, string name) { if (Regex.Match(directory, @"\\include\b", RegexOptions.IgnoreCase).Success) { name = $"Oxide.{name}"; foreach (CompilablePlugin plugin in plugins.Values) { if (!plugin.References.Contains(name)) { continue; } Interface.Oxide.LogInfo($"Reloading {plugin.Name} because it references updated include file: {name}"); plugin.LastModifiedAt = DateTime.Now; Load(plugin); } return; } CompilablePlugin compilablePlugin = GetCompilablePlugin(directory, name); if (compilablePlugin.IsLoading) { Interface.Oxide.LogDebug($"Reload requested for plugin which is already loading: {compilablePlugin.Name}"); return; } // Attempt to compile the plugin before unloading the old version Load(compilablePlugin); }
public CompiledAssembly(string name, CompilablePlugin[] plugins, byte[] raw_assembly) { Name = name; CompilablePlugins = plugins; RawAssembly = raw_assembly; PluginNames = CompilablePlugins.Select(pl => pl.Name).ToArray(); }
public CompiledAssembly(string name, CompilablePlugin[] plugins, byte[] rawAssembly, float duration) { Name = name; CompilablePlugins = plugins; RawAssembly = rawAssembly; Duration = duration; PluginNames = CompilablePlugins.Select(pl => pl.Name).ToArray(); }
private void AddReference(CompilablePlugin plugin, AssemblyName reference) { string compilerFile = string.Concat(reference.Name, ".dll"); if (!this.references.ContainsKey(compilerFile)) { this.references[compilerFile] = new CompilerFile(Interface.Oxide.ExtensionDirectory, compilerFile); } plugin.References.Add(reference.Name); }
private void AddReference(CompilablePlugin plugin, AssemblyName reference) { var filename = reference.Name + ".dll"; if (!references.ContainsKey(filename)) { references[filename] = new CompilerFile(Interface.Oxide.ExtensionDirectory, filename); } plugin.References.Add(reference.Name); }
/// <summary> /// Called when a CompilablePlugin wants to be compiled /// </summary> /// <param name="plugin"></param> public void CompilationRequested(CompilablePlugin plugin) { compilationQueue.Add(plugin); if (compilationQueue.Count > 1) return; Interface.Oxide.NextTick(() => { CompileAssembly(compilationQueue.ToArray()); compilationQueue.Clear(); }); }
public static CompilablePlugin GetCompilablePlugin(string directory, string name) { string className = Regex.Replace(name, "_", ""); if (!plugins.TryGetValue(className, out CompilablePlugin plugin)) { plugin = new CompilablePlugin(extension, Instance, directory, name); plugins[className] = plugin; } return(plugin); }
public static CompilablePlugin GetCompilablePlugin(string directory, string name) { var class_name = Regex.Replace(Regex.Replace(name, @"(?:^|_)([a-z])", m => m.Groups[1].Value.ToUpper()), "_", ""); CompilablePlugin plugin; if (!plugins.TryGetValue(class_name, out plugin)) { plugin = new CompilablePlugin(extension, Instance, directory, name); plugins[class_name] = plugin; } return plugin; }
internal bool IncludesRequiredPlugin(string name) { if (referencedPlugins.Contains(name)) { return(true); } CompilablePlugin compilablePlugin = plugins.SingleOrDefault(pl => pl.Name == name); return(compilablePlugin != null && compilablePlugin.CompilerErrors == null); }
public override Plugin Load(string directory, string name) { CompilablePlugin compilablePlugin = CSharpPluginLoader.GetCompilablePlugin(directory, name); if (!compilablePlugin.IsLoading) { this.Load(compilablePlugin); return(null); } Interface.Oxide.LogDebug(string.Concat("Load requested for plugin which is already loading: ", compilablePlugin.Name), Array.Empty <object>()); return(null); }
private void AddReference(CompilablePlugin plugin, string assemblyName) { string path = Path.Combine(Interface.Oxide.ExtensionDirectory, assemblyName + ".dll"); if (!File.Exists(path)) { if (assemblyName.StartsWith("Oxide.")) { plugin.References.Add(assemblyName); return; } Interface.Oxide.LogError($"Assembly referenced by {plugin.Name} plugin does not exist: {assemblyName}.dll"); plugin.CompilerErrors = $"Referenced assembly does not exist: {assemblyName}"; RemovePlugin(plugin); return; } Assembly assembly; try { assembly = Assembly.Load(assemblyName); } catch (FileNotFoundException) { Interface.Oxide.LogError($"Assembly referenced by {plugin.Name} plugin is invalid: {assemblyName}.dll"); plugin.CompilerErrors = $"Referenced assembly is invalid: {assemblyName}"; RemovePlugin(plugin); return; } AddReference(plugin, assembly.GetName()); // Include references made by the referenced assembly foreach (AssemblyName reference in assembly.GetReferencedAssemblies()) { // TODO: Fix Oxide.References to avoid these and other dependency conflicts if (reference.Name.StartsWith("Newtonsoft.Json") || reference.Name.StartsWith("Rust.Workshop")) { continue; } string referencePath = Path.Combine(Interface.Oxide.ExtensionDirectory, reference.Name + ".dll"); if (!File.Exists(referencePath)) { Interface.Oxide.LogWarning($"Reference {reference.Name}.dll from {assembly.GetName().Name}.dll not found"); continue; } AddReference(plugin, reference); } }
protected override object InvokeMethod(HookMethod method, object[] args) { // TODO: Ignore base_ methods for now if (!hookDispatchFallback && !method.IsBaseHook) { if (args != null && args.Length > 0) { ParameterInfo[] parameters = method.Parameters; for (int i = 0; i < args.Length; i++) { object value = args[i]; if (value == null) { continue; } Type parameter_type = parameters[i].ParameterType; if (!parameter_type.IsValueType) { continue; } Type argument_type = value.GetType(); if (parameter_type != typeof(object) && argument_type != parameter_type) { args[i] = Convert.ChangeType(value, parameter_type); } } } try { if (DirectCallHook(method.Name, out object ret, args)) { return(ret); } PrintWarning("Unable to call hook directly: " + method.Name); } catch (InvalidProgramException ex) { Interface.Oxide.LogError("Hook dispatch failure detected, falling back to reflection based dispatch. " + ex); CompilablePlugin compilablePlugin = CSharpPluginLoader.GetCompilablePlugin(Interface.Oxide.PluginDirectory, Name); if (compilablePlugin?.CompiledAssembly != null) { File.WriteAllBytes(Interface.Oxide.PluginDirectory + "\\" + Name + ".dump", compilablePlugin.CompiledAssembly.PatchedAssembly); Interface.Oxide.LogWarning($"The invalid raw assembly has been dumped to Plugins/{Name}.dump"); } hookDispatchFallback = true; } } return(method.Method.Invoke(this, args)); }
public static CompilablePlugin GetCompilablePlugin(string directory, string name) { var className = Regex.Replace(Regex.Replace(name, @"(?:^|_)([a-z])", m => m.Groups[1].Value.ToUpper()), "_", ""); CompilablePlugin plugin; if (!plugins.TryGetValue(className, out plugin)) { plugin = new CompilablePlugin(extension, Instance, directory, name); plugins[className] = plugin; } return(plugin); }
public static CompilablePlugin GetCompilablePlugin(string directory, string name) { CompilablePlugin compilablePlugin; string str = Regex.Replace(name, "_", ""); if (!CSharpPluginLoader.plugins.TryGetValue(str, out compilablePlugin)) { compilablePlugin = new CompilablePlugin(CSharpPluginLoader.extension, CSharpPluginLoader.Instance, directory, name); CSharpPluginLoader.plugins[str] = compilablePlugin; } return(compilablePlugin); }
private bool CacheScriptLines(CompilablePlugin plugin) { var waitingForAccess = false; while (true) { try { if (!File.Exists(plugin.ScriptPath)) { Interface.Oxide.LogWarning("Script no longer exists: {0}", plugin.Name); plugin.CompilerErrors = "Plugin file was deleted"; RemovePlugin(plugin); return(false); } plugin.CheckLastModificationTime(); if (plugin.LastCachedScriptAt != plugin.LastModifiedAt) { using (var reader = File.OpenText(plugin.ScriptPath)) { var lines = new List <string>(); while (!reader.EndOfStream) { lines.Add(reader.ReadLine()); } if (!string.IsNullOrEmpty(gameExtensionName)) { lines.Insert(0, $"#define {gameExtensionName}"); } plugin.ScriptLines = lines.ToArray(); plugin.ScriptEncoding = reader.CurrentEncoding; } plugin.LastCachedScriptAt = plugin.LastModifiedAt; if (plugins.Remove(plugin)) { queuedPlugins.Add(plugin); } } return(true); } catch (IOException) { if (!waitingForAccess) { waitingForAccess = true; Interface.Oxide.LogWarning("Waiting for another application to stop using script: {0}", plugin.Name); } Thread.Sleep(50); } } }
internal void Add(CompilablePlugin plugin) { if (!queuedPlugins.Add(plugin)) return; plugin.Loader.PluginLoadingStarted(plugin); plugin.CompilerErrors = null; plugin.OnCompilationStarted(); foreach (var pl in Interface.Oxide.RootPluginManager.GetPlugins().Where(pl => pl is CSharpPlugin)) { var loadedPlugin = CSharpPluginLoader.GetCompilablePlugin(plugin.Directory, pl.Name); if (!loadedPlugin.Requires.Contains(plugin.Name)) continue; AddDependency(loadedPlugin); } }
private void PluginLoadingCompleted(CompilablePlugin plugin) { LoadingPlugins.Remove(plugin.Name); plugin.IsLoading = false; foreach (var loadingName in LoadingPlugins.ToArray()) { var loadingPlugin = GetCompilablePlugin(plugin.Directory, loadingName); if (loadingPlugin.IsLoading && loadingPlugin.Requires.Contains(plugin.Name)) { Load(loadingPlugin); } } }
private void AddReference(CompilablePlugin plugin, AssemblyName reference) { string filename = reference.Name + ".dll"; if (!references.ContainsKey(filename)) { references[filename] = new CompilerFile(Interface.Oxide.ExtensionDirectory, filename); } #if DEBUG Interface.Oxide.LogWarning($"{reference.Name} has been added as a reference"); #endif plugin.References.Add(reference.Name); }
internal bool IncludesRequiredPlugin(string name) { if (this.referencedPlugins.Contains(name)) { return(true); } CompilablePlugin compilablePlugin = this.plugins.SingleOrDefault <CompilablePlugin>((CompilablePlugin pl) => pl.Name == name); if (compilablePlugin == null) { return(false); } return(compilablePlugin.CompilerErrors == null); }
private void PluginLoadingCompleted(CompilablePlugin plugin) { base.LoadingPlugins.Remove(plugin.Name); plugin.IsLoading = false; string[] array = base.LoadingPlugins.ToArray(); for (int i = 0; i < (int)array.Length; i++) { string str = array[i]; CompilablePlugin compilablePlugin = CSharpPluginLoader.GetCompilablePlugin(plugin.Directory, str); if (compilablePlugin.IsLoading && compilablePlugin.Requires.Contains(plugin.Name)) { this.Load(compilablePlugin); } } }
/// <summary> /// Attempt to asynchronously compile and load plugin /// </summary> /// <param name="directory"></param> /// <param name="name"></param> /// <returns></returns> public override Plugin Load(string directory, string name) { CompilablePlugin compilablePlugin = GetCompilablePlugin(directory, name); if (compilablePlugin.IsLoading) { Interface.Oxide.LogDebug($"Load requested for plugin which is already loading: {compilablePlugin.Name}"); return(null); } // Attempt to compile the plugin before unloading the old version Load(compilablePlugin); return(null); }
public void CompilationRequested(CompilablePlugin plugin) { if (Compilation.Current != null) { Compilation.Current.Add(plugin); return; } if (this.compilationQueue.Count < 1) { Interface.Oxide.NextTick(() => { this.CompileAssembly(this.compilationQueue.ToArray()); this.compilationQueue.Clear(); }); } this.compilationQueue.Add(plugin); }
private void AddReference(CompilablePlugin plugin, string assemblyName) { var path = Path.Combine(Interface.Oxide.ExtensionDirectory, assemblyName + ".dll"); if (!File.Exists(path)) { if (assemblyName.StartsWith("Oxide.")) { plugin.References.Add(assemblyName); return; } Interface.Oxide.LogError($"Assembly referenced by {plugin.Name} plugin does not exist: {assemblyName}.dll"); plugin.CompilerErrors = "Referenced assembly does not exist: " + assemblyName; RemovePlugin(plugin); return; } Assembly assembly; try { assembly = Assembly.Load(assemblyName); } catch (FileNotFoundException) { Interface.Oxide.LogError($"Assembly referenced by {plugin.Name} plugin is invalid: {assemblyName}.dll"); plugin.CompilerErrors = "Referenced assembly is invalid: " + assemblyName; RemovePlugin(plugin); return; } AddReference(plugin, assembly.GetName()); // Include references made by the referenced assembly foreach (var reference in assembly.GetReferencedAssemblies()) { var referencePath = Path.Combine(Interface.Oxide.ExtensionDirectory, reference.Name + ".dll"); if (!File.Exists(referencePath)) { Interface.Oxide.LogWarning($"Reference {reference.Name}.dll from {assembly.GetName().Name}.dll not found"); continue; } AddReference(plugin, reference); } }
public void Load(CompilablePlugin plugin) { plugin.Compile(compiled => { if (!compiled) { PluginLoadingCompleted(plugin); return; } IEnumerable <string> loadedLoadingRequirements = plugin.Requires.Where(r => LoadedPlugins.ContainsKey(r) && LoadingPlugins.Contains(r)); foreach (string loadedPlugin in loadedLoadingRequirements) { Interface.Oxide.UnloadPlugin(loadedPlugin); } IEnumerable <string> missingRequirements = plugin.Requires.Where(r => !LoadedPlugins.ContainsKey(r)); if (missingRequirements.Any()) { IEnumerable <string> loadingRequirements = plugin.Requires.Where(r => LoadingPlugins.Contains(r)); if (loadingRequirements.Any()) { Interface.Oxide.LogDebug($"{plugin.Name} plugin is waiting for requirements to be loaded: {loadingRequirements.ToSentence()}"); } else { Interface.Oxide.LogError($"{plugin.Name} plugin requires missing dependencies: {missingRequirements.ToSentence()}"); PluginErrors[plugin.Name] = $"Missing dependencies: {missingRequirements.ToSentence()}"; PluginLoadingCompleted(plugin); } } else { Interface.Oxide.UnloadPlugin(plugin.Name); plugin.LoadPlugin(pl => { if (pl != null) { LoadedPlugins[pl.Name] = pl; } PluginLoadingCompleted(plugin); }); } }); }
private void AddReference(CompilablePlugin plugin, string assemblyName) { Assembly assembly; if (!File.Exists(Path.Combine(Interface.Oxide.ExtensionDirectory, string.Concat(assemblyName, ".dll")))) { if (assemblyName.StartsWith("Oxide.")) { plugin.References.Add(assemblyName); return; } Interface.Oxide.LogError(string.Concat(new string[] { "Assembly referenced by ", plugin.Name, " plugin does not exist: ", assemblyName, ".dll" }), Array.Empty <object>()); plugin.CompilerErrors = string.Concat("Referenced assembly does not exist: ", assemblyName); this.RemovePlugin(plugin); return; } try { assembly = Assembly.Load(assemblyName); } catch (FileNotFoundException fileNotFoundException) { Interface.Oxide.LogError(string.Concat(new string[] { "Assembly referenced by ", plugin.Name, " plugin is invalid: ", assemblyName, ".dll" }), Array.Empty <object>()); plugin.CompilerErrors = string.Concat("Referenced assembly is invalid: ", assemblyName); this.RemovePlugin(plugin); return; } this.AddReference(plugin, assembly.GetName()); AssemblyName[] referencedAssemblies = assembly.GetReferencedAssemblies(); for (int i = 0; i < (int)referencedAssemblies.Length; i++) { AssemblyName assemblyName1 = referencedAssemblies[i]; if (!assemblyName1.Name.StartsWith("Newtonsoft.Json") && !assemblyName1.Name.StartsWith("Rust.Workshop")) { if (File.Exists(Path.Combine(Interface.Oxide.ExtensionDirectory, string.Concat(assemblyName1.Name, ".dll")))) { this.AddReference(plugin, assemblyName1); } else { Interface.Oxide.LogWarning(string.Concat(new string[] { "Reference ", assemblyName1.Name, ".dll from ", assembly.GetName().Name, ".dll not found" }), Array.Empty <object>()); } } } }
internal override void OnCompilationStarted() { base.OnCompilationStarted(); foreach (Plugin plugin in Interface.Oxide.RootPluginManager.GetPlugins()) { if (!(plugin is CSharpPlugin)) { continue; } CompilablePlugin compilablePlugin = CSharpPluginLoader.GetCompilablePlugin(this.Directory, plugin.Name); if (!compilablePlugin.Requires.Contains(this.Name)) { continue; } compilablePlugin.CompiledAssembly = null; this.Loader.Load(compilablePlugin); } }
private void RemovePlugin(CompilablePlugin plugin) { if (plugin.LastCompiledAt == default(DateTime)) { return; } queuedPlugins.Remove(plugin); plugins.Remove(plugin); plugin.OnCompilationFailed(); // Remove plugins which are required by this plugin if they are only being compiled for this requirement foreach (var requiredPlugin in plugins.Where(pl => !pl.IsCompilationNeeded && plugin.Requires.Contains(pl.Name)).ToArray()) { if (!plugins.Any(pl => pl.Requires.Contains(requiredPlugin.Name))) { RemovePlugin(requiredPlugin); } } }
/// <summary> /// Called when a CompilablePlugin wants to be compiled /// </summary> /// <param name="plugin"></param> public void CompilationRequested(CompilablePlugin plugin) { if (Compilation.Current != null) { //Interface.Oxide.LogDebug("Adding plugin to outstanding compilation: {0}", plugin.Name); Compilation.Current.Add(plugin); return; } if (compilationQueue.Count < 1) { Interface.Oxide.NextTick(() => { CompileAssembly(compilationQueue.ToArray()); compilationQueue.Clear(); }); } compilationQueue.Add(plugin); }
/// <summary> /// Called when a CompilablePlugin wants to be compiled /// </summary> /// <param name="plugin"></param> public void CompilationRequested(CompilablePlugin plugin) { if (Compilation.Current != null) { Interface.Oxide.LogDebug("Adding plugin to outstanding compilation: " + plugin.Name); Compilation.Current.Add(plugin); return; } if (compilationQueue.Count < 1) { Interface.Oxide.NextTick(() => { CompileAssembly(compilationQueue.ToArray()); compilationQueue.Clear(); }); } compilationQueue.Add(plugin); }
internal Compilation(int id, Action<Compilation> callback, CompilablePlugin[] plugins) { this.id = id; this.callback = callback; this.queuedPlugins = new ConcurrentHashSet<CompilablePlugin>(plugins); if (Current == null) Current = this; foreach (var plugin in plugins) { plugin.CompilerErrors = null; plugin.OnCompilationStarted(); } includePath = Path.Combine(Interface.Oxide.PluginDirectory, "Include"); extensionNames = Interface.Oxide.GetAllExtensions().Select(ext => ext.Name).ToArray(); gameExtensionNamespace = Interface.Oxide.GetAllExtensions().SingleOrDefault(ext => ext.IsGameExtension)?.GetType().Namespace; newGameExtensionNamespace = gameExtensionNamespace != null && gameExtensionNamespace.Contains(".Game."); }
/// <summary> /// Called when a CompilablePlugin wants to be compiled /// </summary> /// <param name="plugin"></param> public void CompilationRequested(CompilablePlugin plugin) { if (compilationQueue.Count < 1) { Interface.Oxide.NextTick(() => { CompileAssembly(compilationQueue.ToArray()); compilationQueue.Clear(); }); } compilationQueue.Add(plugin); // Enqueue compilation of any plugins which depend on this plugin foreach (var compilable_plugin in plugins.Values.Where(pl => pl.Requires.Contains(plugin.Name))) { if (compilationQueue.Contains(compilable_plugin)) continue; compilable_plugin.CompiledAssembly = null; Reload(Interface.Oxide.PluginDirectory, compilable_plugin.Name); } }
internal void Add(CompilablePlugin plugin) { if (!queuedPlugins.Add(plugin)) { return; } plugin.Loader.PluginLoadingStarted(plugin); plugin.CompilerErrors = null; plugin.OnCompilationStarted(); foreach (var pl in Interface.Oxide.RootPluginManager.GetPlugins().Where(pl => pl is CSharpPlugin)) { var loadedPlugin = CSharpPluginLoader.GetCompilablePlugin(plugin.Directory, pl.Name); if (!loadedPlugin.Requires.Contains(plugin.Name)) { continue; } AddDependency(loadedPlugin); } }
private void AddDependency(CompilablePlugin plugin) { if (plugin.IsLoading || this.plugins.Contains(plugin) || this.queuedPlugins.Contains(plugin)) { return; } CompiledAssembly compiledAssembly = plugin.CompiledAssembly; if (compiledAssembly == null || compiledAssembly.IsOutdated()) { this.Add(plugin); } else { this.referencedPlugins.Add(plugin.Name); if (!this.references.ContainsKey(compiledAssembly.Name)) { this.references[compiledAssembly.Name] = new CompilerFile(compiledAssembly.Name, compiledAssembly.RawAssembly); return; } } }
internal override void OnCompilationStarted() { base.OnCompilationStarted(); // Enqueue compilation of any plugins which depend on this plugin foreach (Core.Plugins.Plugin plugin in Interface.Oxide.RootPluginManager.GetPlugins()) { if (!(plugin is CSharpPlugin)) { continue; } CompilablePlugin compilablePlugin = CSharpPluginLoader.GetCompilablePlugin(Directory, plugin.Name); if (!compilablePlugin.Requires.Contains(Name)) { continue; } compilablePlugin.CompiledAssembly = null; Loader.Load(compilablePlugin); } }
internal void Add(CompilablePlugin plugin) { if (!this.queuedPlugins.Add(plugin)) { return; } plugin.Loader.PluginLoadingStarted(plugin); plugin.CompilerErrors = null; plugin.OnCompilationStarted(); foreach (Plugin plugin1 in from pl in Interface.Oxide.RootPluginManager.GetPlugins() where pl is CSharpPlugin select pl) { CompilablePlugin compilablePlugin = CSharpPluginLoader.GetCompilablePlugin(plugin.Directory, plugin1.Name); if (!compilablePlugin.Requires.Contains(plugin.Name)) { continue; } this.AddDependency(compilablePlugin); } }
private void CompileAssembly(CompilablePlugin[] plugs) { foreach (var pl in plugs) pl.OnCompilationStarted(compiler); var plugins = new List<CompilablePlugin>(plugs); compiler.Compile(plugins, (assembly_name, raw_assembly, duration) => { if (plugins.Count > 1 && raw_assembly == null) { var plugin_names = plugins.Select(pl => pl.Name); var standalone_plugins = plugins.Where(pl => !pl.Requires.Any(r => plugin_names.Contains(r))).ToArray(); foreach (var plugin in standalone_plugins) plugins.Remove(plugin); foreach (var plugin in plugins) { plugin.OnCompilationFailed(); PluginErrors[plugin.Name] = "Batch containing dependencies failed to compile"; } if (standalone_plugins.Length < 1) { Interface.Oxide.LogError($"A batch of {plugins.Count} plugins failed to compile"); return; } Interface.Oxide.LogError($"A batch of {plugins.Count} plugins failed to compile, attempting to compile separately"); foreach (var plugin in standalone_plugins) CompileAssembly(new[] { plugin }); return; } if (raw_assembly == null) { var plugin = plugins[0]; plugin.OnCompilationFailed(); PluginErrors[plugin.Name] = "Failed to compile: " + plugin.CompilerErrors; Interface.Oxide.LogError("{0} plugin failed to compile!", plugin.ScriptName); Interface.Oxide.LogError(plugin.CompilerErrors); RemoteLogger.Warning($"{plugin.ScriptName} plugin failed to compile!\n{plugin.CompilerErrors}"); } else { var compiled_plugins = plugins.Where(pl => pl.CompilerErrors == null).ToList(); var compiled_names = compiled_plugins.Select(pl => pl.Name).ToArray(); CompiledAssembly compiled_assembly = null; if (compiled_plugins.Count > 0) { var verb = compiled_plugins.Count > 1 ? "were" : "was"; Interface.Oxide.LogInfo($"{compiled_names.ToSentence()} {verb} compiled successfully in {Math.Round(duration * 1000f)}ms"); compiled_assembly = new CompiledAssembly(assembly_name, compiled_plugins.ToArray(), raw_assembly); } foreach (var plugin in plugins) { if (plugin.CompilerErrors == null) { plugin.OnCompilationSucceeded(compiled_assembly); } else { plugin.OnCompilationFailed(); PluginErrors[plugin.Name] = "Failed to compile: " + plugin.CompilerErrors; Interface.Oxide.LogError($"Error while compiling {plugin.CompilerErrors}"); } } } }); }
internal void Compile(CompilablePlugin[] plugins, Action<Compilation> callback) { if (!CheckCompiler()) { OnCompilerFailed("Compiler couldn't be started."); return; } var id = lastId++; var compilation = new Compilation(id, callback, plugins); compilations[id] = compilation; compilation.Prepare(() => EnqueueCompilation(compilation)); }
public void PluginLoadingStarted(CompilablePlugin plugin) { // Let the Oxide core know that this plugin will be loading asynchronously LoadingPlugins.Add(plugin.Name); plugin.IsLoading = true; }
/// <summary> /// Called by a CompilablePlugin that wants to be compiled /// </summary> /// <param name="plugin"></param> public void CompilationRequested(CompilablePlugin plugin) { loader.CompilationRequested(plugin); }
private void CompileAssembly(CompilablePlugin[] plugins) { compiler.Compile(plugins, compilation => { if (compilation.compiledAssembly == null) { foreach (var plugin in compilation.plugins) { plugin.OnCompilationFailed(); PluginErrors[plugin.Name] = "Failed to compile: " + plugin.CompilerErrors; Interface.Oxide.LogError("{0} plugin failed to compile!", plugin.ScriptName); Interface.Oxide.LogError(plugin.CompilerErrors); RemoteLogger.Warning($"{plugin.ScriptName} plugin failed to compile!\n{plugin.CompilerErrors}"); } } else { if (compilation.plugins.Count > 0) { var compiled_names = compilation.plugins.Select(pl => pl.Name).ToArray(); var verb = compilation.plugins.Count > 1 ? "were" : "was"; Interface.Oxide.LogInfo($"{compiled_names.ToSentence()} {verb} compiled successfully in {Math.Round(compilation.duration * 1000f)}ms"); } foreach (var plugin in compilation.plugins) { if (plugin.CompilerErrors == null) { Interface.Oxide.UnloadPlugin(plugin.Name); } } foreach (var plugin in compilation.plugins) { if (plugin.CompilerErrors == null) { plugin.OnCompilationSucceeded(compilation.compiledAssembly); } else { plugin.OnCompilationFailed(); PluginErrors[plugin.Name] = "Failed to compile: " + plugin.CompilerErrors; Interface.Oxide.LogError($"Error while compiling {plugin.CompilerErrors}"); } } } }); }
private void PluginLoadingCompleted(CompilablePlugin plugin) { LoadingPlugins.Remove(plugin.Name); plugin.IsLoading = false; foreach (var loading_name in LoadingPlugins.ToArray()) { var loading_plugin = GetCompilablePlugin(plugin.Directory, loading_name); if (loading_plugin.IsLoading && loading_plugin.Requires.Contains(plugin.Name)) Load(loading_plugin); } }
private void AddDependency(CompilablePlugin plugin) { if (plugin.IsLoading || plugins.Contains(plugin) || queuedPlugins.Contains(plugin)) return; var compiledDependency = plugin.CompiledAssembly; if (compiledDependency != null && !compiledDependency.IsOutdated()) { // The dependency already has a compiled assembly which is up to date referencedPlugins.Add(plugin.Name); if (!references.ContainsKey(compiledDependency.Name)) references[compiledDependency.Name] = new CompilerFile(compiledDependency.Name, compiledDependency.RawAssembly); } else { // The dependency needs to be compiled Add(plugin); } }
private void AddReference(int currentId, CompilablePlugin plugin, string assembly_name) { var compilation = pluginComp[currentId]; var path = Path.Combine(Interface.Oxide.ExtensionDirectory, string.Format("{0}.dll", assembly_name)); if (!File.Exists(path)) { if (assembly_name.StartsWith("Oxide.Ext.")) { plugin.References.Add(assembly_name); return; } Interface.Oxide.LogError("Assembly referenced by {0} plugin does not exist: {1}.dll", plugin.Name, assembly_name); plugin.CompilerErrors = "Referenced assembly does not exist: " + assembly_name; RemovePlugin(compilation.plugins, plugin); return; } Assembly assembly; try { assembly = Assembly.Load(assembly_name); } catch (FileNotFoundException) { Interface.Oxide.LogError("Assembly referenced by {0} plugin is invalid: {1}.dll", plugin.Name, assembly_name); plugin.CompilerErrors = "Referenced assembly is invalid: " + assembly_name; RemovePlugin(compilation.plugins, plugin); return; } compilation.references.Add(new CompilerFile(Interface.Oxide.ExtensionDirectory, assembly_name + ".dll")); plugin.References.Add(assembly_name); // Include references made by the referenced assembly foreach (var reference in assembly.GetReferencedAssemblies()) { var reference_path = Path.Combine(Interface.Oxide.ExtensionDirectory, string.Format("{0}.dll", reference.Name)); if (!File.Exists(reference_path)) { Interface.Oxide.LogWarning("Reference {0}.dll from {1}.dll not found.", reference.Name, assembly.GetName().Name); continue; } compilation.references.Add(new CompilerFile(Interface.Oxide.ExtensionDirectory, reference.Name + ".dll")); plugin.References.Add(reference.Name); } }
private void RemovePlugin(List<CompilablePlugin> plugins, CompilablePlugin plugin) { if (!plugins.Remove(plugin)) return; plugin.OnCompilationFailed(); // Remove plugins which are required by this plugin if they are only being compiled for this requirement foreach (var required_plugin in plugins.Where(pl => !pl.IsCompilationNeeded && plugin.Requires.Contains(pl.Name)).ToArray()) { if (!plugins.Any(pl => pl.Requires.Contains(required_plugin.Name))) RemovePlugin(plugins, required_plugin); } }
private void PreparseScript(CompilablePlugin plugin) { plugin.References.Clear(); plugin.IncludePaths.Clear(); plugin.Requires.Clear(); var parsingNamespace = false; for (var i = 0; i < plugin.ScriptLines.Length; i++) { var line = plugin.ScriptLines[i].Trim(); if (line.Length < 1) continue; Match match; if (parsingNamespace) { // Skip blank lines and opening brace at the top of the namespace block match = Regex.Match(line, @"^\s*\{?\s*$", RegexOptions.IgnoreCase); if (match.Success) continue; // Skip class custom attributes match = Regex.Match(line, @"^\s*\[", RegexOptions.IgnoreCase); if (match.Success) continue; // Detect main plugin class name match = Regex.Match(line, @"^\s*(?:public|private|protected|internal)?\s*class\s+(\S+)\s+\:\s+\S+Plugin\s*$", RegexOptions.IgnoreCase); if (!match.Success) break; var className = match.Groups[1].Value; if (className != plugin.Name) { Interface.Oxide.LogError($"Plugin filename is incorrect: {plugin.ScriptName}.cs (should be {className}.cs)"); plugin.CompilerErrors = $"Filename is incorrect: {plugin.ScriptName}.cs (should be {className}.cs)"; RemovePlugin(plugin); } break; } // Include explicit plugin dependencies defined by magic comments in script match = Regex.Match(line, @"^//\s*Requires:\s*(\S+?)(\.cs)?\s*$", RegexOptions.IgnoreCase); if (match.Success) { var dependencyName = match.Groups[1].Value; plugin.Requires.Add(dependencyName); if (!File.Exists(Path.Combine(plugin.Directory, dependencyName + ".cs"))) { Interface.Oxide.LogError($"{plugin.Name} plugin requires missing dependency: {dependencyName}"); plugin.CompilerErrors = $"Missing dependency: {dependencyName}"; RemovePlugin(plugin); return; } //Interface.Oxide.LogDebug(plugin.Name + " plugin requires dependency: " + dependency_name); var dependencyPlugin = CSharpPluginLoader.GetCompilablePlugin(plugin.Directory, dependencyName); AddDependency(dependencyPlugin); continue; } // Include explicit references defined by magic comments in script match = Regex.Match(line, @"^//\s*Reference:\s*(\S+)\s*$", RegexOptions.IgnoreCase); if (match.Success) { var result = match.Groups[1].Value; if (!newGameExtensionNamespace || !result.StartsWith(gameExtensionNamespace.Replace(".Game.", ".Ext."))) AddReference(plugin, match.Groups[1].Value); else Interface.Oxide.LogWarning("Ignored obsolete game extension reference '{0}' in plugin '{1}'", result, plugin.Name); continue; } // Include implicit references detected from using statements in script match = Regex.Match(line, @"^\s*using\s+(Oxide\.(?:Ext|Game)\.(?:[^\.]+))[^;]*;\s*$", RegexOptions.IgnoreCase); if (match.Success) { AddReference(plugin, match.Groups[1].Value); continue; } // Start parsing the Oxide.Plugins namespace contents match = Regex.Match(line, @"^\s*namespace Oxide\.Plugins\s*(\{\s*)?$", RegexOptions.IgnoreCase); if (match.Success) parsingNamespace = true; } }
private void RemovePlugin(CompilablePlugin plugin) { if (plugin.LastCompiledAt == default(DateTime)) return; queuedPlugins.Remove(plugin); plugins.Remove(plugin); plugin.OnCompilationFailed(); // Remove plugins which are required by this plugin if they are only being compiled for this requirement foreach (var requiredPlugin in plugins.Where(pl => !pl.IsCompilationNeeded && plugin.Requires.Contains(pl.Name)).ToArray()) { if (!plugins.Any(pl => pl.Requires.Contains(requiredPlugin.Name))) RemovePlugin(requiredPlugin); } }
private bool CacheScriptLines(CompilablePlugin plugin) { var waitingForAccess = false; while (true) { try { if (!File.Exists(plugin.ScriptPath)) { Interface.Oxide.LogWarning("Script no longer exists: {0}", plugin.Name); plugin.CompilerErrors = "Plugin file was deleted"; RemovePlugin(plugin); return false; } plugin.CheckLastModificationTime(); if (plugin.LastCachedScriptAt != plugin.LastModifiedAt) { using (var reader = File.OpenText(plugin.ScriptPath)) { var lines = new List<string>(); while (!reader.EndOfStream) lines.Add(reader.ReadLine()); if (!string.IsNullOrEmpty(gameExtensionName)) lines.Insert(0, $"#define {gameExtensionName}"); plugin.ScriptLines = lines.ToArray(); plugin.ScriptEncoding = reader.CurrentEncoding; } plugin.LastCachedScriptAt = plugin.LastModifiedAt; if (plugins.Remove(plugin)) queuedPlugins.Add(plugin); } return true; } catch (IOException) { if (!waitingForAccess) { waitingForAccess = true; Interface.Oxide.LogWarning("Waiting for another application to stop using script: {0}", plugin.Name); } Thread.Sleep(50); } } }
private void AddReference(CompilablePlugin plugin, AssemblyName reference) { var filename = reference.Name + ".dll"; if (!references.ContainsKey(filename)) references[filename] = new CompilerFile(Interface.Oxide.ExtensionDirectory, filename); plugin.References.Add(reference.Name); }
private void AddReference(CompilablePlugin plugin, string assembly_name) { var path = Path.Combine(Interface.Oxide.ExtensionDirectory, assembly_name + ".dll"); if (!File.Exists(path)) { if (assembly_name.StartsWith("Oxide.Ext.")) { plugin.References.Add(assembly_name); return; } Interface.Oxide.LogError($"Assembly referenced by {plugin.Name} plugin does not exist: {assembly_name}.dll"); plugin.CompilerErrors = "Referenced assembly does not exist: " + assembly_name; RemovePlugin(plugin); return; } Assembly assembly; try { assembly = Assembly.Load(assembly_name); } catch (FileNotFoundException) { Interface.Oxide.LogError($"Assembly referenced by {plugin.Name} plugin is invalid: {assembly_name}.dll"); plugin.CompilerErrors = "Referenced assembly is invalid: " + assembly_name; RemovePlugin(plugin); return; } AddReference(plugin, assembly.GetName()); // Include references made by the referenced assembly foreach (var reference in assembly.GetReferencedAssemblies()) { var referencePath = Path.Combine(Interface.Oxide.ExtensionDirectory, reference.Name + ".dll"); if (!File.Exists(referencePath)) { Interface.Oxide.LogWarning($"Reference {reference.Name}.dll from {assembly.GetName().Name}.dll not found"); continue; } AddReference(plugin, reference); } }
private bool CacheScriptLines(CompilablePlugin plugin) { var waiting_for_access = false; while (true) { try { if (!File.Exists(plugin.ScriptPath)) { Interface.Oxide.LogWarning("Script no longer exists: {0}", plugin.Name); plugin.CompilerErrors = "Plugin file was deleted"; return false; } using (var reader = File.OpenText(plugin.ScriptPath)) { var list = new List<string>(); while (!reader.EndOfStream) list.Add(reader.ReadLine()); plugin.ScriptLines = list.ToArray(); plugin.ScriptEncoding = reader.CurrentEncoding; } //plugin.ScriptLines = File.ReadAllLines(plugin.ScriptPath); return true; } catch (IOException) { if (!waiting_for_access) { waiting_for_access = true; Interface.Oxide.LogWarning("Waiting for another application to stop using script: {0}", plugin.Name); } Thread.Sleep(50); } } }
public void Load(CompilablePlugin plugin) { plugin.Compile(compiled => { if (!compiled) { PluginLoadingCompleted(plugin); return; } var missing_requirements = plugin.Requires.Where(r => !LoadedPlugins.ContainsKey(r)); if (missing_requirements.Any()) { var loading_requirements = plugin.Requires.Where(r => LoadingPlugins.Contains(r)); if (loading_requirements.Any()) { Interface.Oxide.LogDebug(plugin.Name + " plugin is waiting for requirements to be loaded: " + loading_requirements.ToSentence()); } else { Interface.Oxide.LogError($"{plugin.Name} plugin requires missing dependencies: {missing_requirements.ToSentence()}"); PluginErrors[plugin.Name] = $"Missing dependencies: {missing_requirements.ToSentence()}"; PluginLoadingCompleted(plugin); } } else { Interface.Oxide.UnloadPlugin(plugin.Name); plugin.LoadPlugin(pl => { if (pl != null) LoadedPlugins[pl.Name] = pl; PluginLoadingCompleted(plugin); }); } }); }
private void RemovePlugin(List<CompilablePlugin> plugins, CompilablePlugin plugin) { plugins.Remove(plugin); plugin.OnCompilationFailed(); }
private void ResolveReferences(CompilablePlugin plugin) { foreach (var reference in plugin.References) { var match = Regex.Match(reference, @"^(Oxide\.(?:Ext|Game)\.(.+))$", RegexOptions.IgnoreCase); if (!match.Success) continue; var fullName = match.Groups[1].Value; var name = match.Groups[2].Value; if (extensionNames.Contains(name)) continue; if (Directory.Exists(includePath)) { var includeFilePath = Path.Combine(includePath, $"Ext.{name}.cs"); if (File.Exists(includeFilePath)) { plugin.IncludePaths.Add(includeFilePath); continue; } } var message = $"{fullName} is referenced by {plugin.Name} plugin but is not loaded! An appropriate include file needs to be saved to Plugins\\Include\\Ext.{name}.cs if this extension is not required."; Interface.Oxide.LogError(message); plugin.CompilerErrors = message; RemovePlugin(plugin); } }