protected override object InvokeMethod(MethodInfo method, object[] args) { //TODO ignore base_ methods for now if (!hookDispatchFallback && !method.Name.StartsWith("base_")) { try { object ret; if (DirectCallHook(method.Name, out 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.ToString()); var compilable_plugin = CSharpPluginLoader.GetCompilablePlugin(Interface.Oxide.PluginDirectory, Name); if (compilable_plugin != null && compilable_plugin.CompiledAssembly != null) { System.IO.File.WriteAllBytes(Interface.Oxide.PluginDirectory + "\\" + Name + ".dump", compilable_plugin.CompiledAssembly.PatchedAssembly); Interface.Oxide.LogWarning($"The invalid raw assembly has been dumped to Plugins/{Name}.dump"); } hookDispatchFallback = true; } } return(method.Invoke(this, args)); }
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); } }
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 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 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); } } }
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); } }
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); } }
internal override void OnCompilationStarted() { base.OnCompilationStarted(); // Enqueue compilation of any plugins which depend on this plugin foreach (var plugin in Interface.Oxide.RootPluginManager.GetPlugins()) { if (!(plugin is CSharpPlugin)) { continue; } var 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 PreparseScript(CompilablePlugin plugin) { plugin.References.Clear(); plugin.IncludePaths.Clear(); plugin.Requires.Clear(); bool parsingNamespace = false; for (int i = 0; i < plugin.ScriptLines.Length; i++) { string 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; } string className = match.Groups[1].Value; if (className != plugin.Name) { Interface.Oxide.LogError($"Plugin filename {plugin.ScriptName}.cs must match the main class {className} (should be {className}.cs)"); plugin.CompilerErrors = $"Plugin filename {plugin.ScriptName}.cs must match the main class {className} (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) { string 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); CompilablePlugin 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) { string result = match.Groups[1].Value; if (!result.StartsWith("Oxide.") && !result.Contains("Harmony") && !result.Contains("Newtonsoft.Json") && !result.Contains("protobuf-net") && !result.StartsWith("Rust.")) { AddReference(plugin, result); Interface.Oxide.LogInfo("Added '// Reference: {0}' in plugin '{1}'", result, plugin.Name); } else { Interface.Oxide.LogWarning("Ignored unnecessary '// 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\.(?:Core|Ext|Game)\.(?:[^\.]+))[^;]*;.*$", RegexOptions.IgnoreCase); if (match.Success) { string result = match.Groups[1].Value; string newResult = Regex.Replace(result, @"Oxide\.[\w]+\.([\w]+)", "Oxide.$1"); if (!string.IsNullOrEmpty(newResult) && File.Exists(Path.Combine(Interface.Oxide.ExtensionDirectory, newResult + ".dll"))) { AddReference(plugin, newResult); } else { AddReference(plugin, result); } 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 PreparseScript(CompilablePlugin plugin) { plugin.References.Clear(); plugin.IncludePaths.Clear(); plugin.Requires.Clear(); if (plugin.ScriptLines.Any <string>((string line) => { if (line.Contains("uMod")) { return(true); } return(line.Contains("Universal")); })) { plugin.ScriptLines = ( from s in plugin.ScriptLines select s.Replace("uMod", "Oxide.Core").Replace("using Oxide.Core;", "using Oxide.Core; using Oxide.Core.Plugins;").Replace("namespace Oxide.Core.Plugins", "namespace Oxide.Plugins").Replace("Libraries.Universal", "Libraries.Covalence").Replace("UniversalPlugin", "CovalencePlugin").Replace("Oxide.Core.Version", "OxideMod.Version")).ToArray <string>(); } bool flag = false; for (int i = 0; i < (int)plugin.ScriptLines.Length; i++) { string str = plugin.ScriptLines[i].Trim(); if (str.Length >= 1) { if (!flag) { Match match = Regex.Match(str, "^//\\s*Requires:\\s*(\\S+?)(\\.cs)?\\s*$", RegexOptions.IgnoreCase); if (!match.Success) { match = Regex.Match(str, "^//\\s*Reference:\\s*(\\S+)\\s*$", RegexOptions.IgnoreCase); if (!match.Success) { match = Regex.Match(str, "^\\s*using\\s+(Oxide\\.(?:Core|Ext|Game)\\.(?:[^\\.]+))[^;]*;.*$", RegexOptions.IgnoreCase); if (!match.Success) { match = Regex.Match(str, "^\\s*namespace Oxide\\.Plugins\\s*(\\{\\s*)?$", RegexOptions.IgnoreCase); if (match.Success) { flag = true; } } else { string value = match.Groups[1].Value; string str1 = Regex.Replace(value, "Oxide\\.[\\w]+\\.([\\w]+)", "Oxide.$1"); if (string.IsNullOrEmpty(str1) || !File.Exists(Path.Combine(Interface.get_Oxide().get_ExtensionDirectory(), string.Concat(str1, ".dll")))) { this.AddReference(plugin, value); } else { this.AddReference(plugin, str1); } } } else { string value1 = match.Groups[1].Value; if (value1.StartsWith("Oxide.") || value1.StartsWith("Newtonsoft.Json") || value1.StartsWith("protobuf-net") || value1.StartsWith("Rust.")) { Interface.get_Oxide().LogWarning("Ignored unnecessary '// Reference: {0}' in plugin '{1}'", new object[] { value1, plugin.Name }); } else { this.AddReference(plugin, value1); Interface.get_Oxide().LogInfo("Added '// Reference: {0}' in plugin '{1}'", new object[] { value1, plugin.Name }); } } } else { string value2 = match.Groups[1].Value; plugin.Requires.Add(value2); if (!File.Exists(Path.Combine(plugin.Directory, string.Concat(value2, ".cs")))) { Interface.get_Oxide().LogError(string.Concat(plugin.Name, " plugin requires missing dependency: ", value2), Array.Empty <object>()); plugin.CompilerErrors = string.Concat("Missing dependency: ", value2); this.RemovePlugin(plugin); return; } this.AddDependency(CSharpPluginLoader.GetCompilablePlugin(plugin.Directory, value2)); } } else { Match match1 = Regex.Match(str, "^\\s*\\{?\\s*$", RegexOptions.IgnoreCase); if (!match1.Success) { match1 = Regex.Match(str, "^\\s*\\[", RegexOptions.IgnoreCase); if (!match1.Success) { match1 = Regex.Match(str, "^\\s*(?:public|private|protected|internal)?\\s*class\\s+(\\S+)\\s+\\:\\s+\\S+Plugin\\s*$", RegexOptions.IgnoreCase); if (!match1.Success) { break; } string str2 = match1.Groups[1].Value; if (str2 == plugin.Name) { break; } Interface.get_Oxide().LogError(string.Concat(new string[] { "Plugin filename ", plugin.ScriptName, ".cs must match the main class ", str2, " (should be ", str2, ".cs)" }), Array.Empty <object>()); plugin.CompilerErrors = string.Concat(new string[] { "Plugin filename ", plugin.ScriptName, ".cs must match the main class ", str2, " (should be ", str2, ".cs)" }); this.RemovePlugin(plugin); return; } } } } } }
protected override object InvokeMethod(HookMethod method, object[] args) { object obj; object obj1; bool compiledAssembly; if (!this.hookDispatchFallback && !method.IsBaseHook) { if (args != null && args.Length != 0) { ParameterInfo[] parameters = method.Parameters; for (int i = 0; i < (int)args.Length; i++) { object obj2 = args[i]; if (obj2 != null) { Type parameterType = parameters[i].ParameterType; if (parameterType.IsValueType) { Type type = obj2.GetType(); if (parameterType != typeof(object) && type != parameterType) { args[i] = Convert.ChangeType(obj2, parameterType); } } } } } try { if (!this.DirectCallHook(method.Name, out obj, args)) { this.PrintWarning(string.Concat("Unable to call hook directly: ", method.Name), Array.Empty <object>()); return(method.Method.Invoke(this, args)); } else { obj1 = obj; } } catch (InvalidProgramException invalidProgramException1) { InvalidProgramException invalidProgramException = invalidProgramException1; Interface.Oxide.LogError(string.Concat("Hook dispatch failure detected, falling back to reflection based dispatch. ", invalidProgramException), Array.Empty <object>()); CompilablePlugin compilablePlugin = CSharpPluginLoader.GetCompilablePlugin(Interface.Oxide.PluginDirectory, base.Name); if (compilablePlugin != null) { compiledAssembly = compilablePlugin.CompiledAssembly; } else { compiledAssembly = false; } if (compiledAssembly) { File.WriteAllBytes(string.Concat(Interface.Oxide.PluginDirectory, "\\", base.Name, ".dump"), compilablePlugin.CompiledAssembly.PatchedAssembly); Interface.Oxide.LogWarning(string.Concat("The invalid raw assembly has been dumped to Plugins/", base.Name, ".dump"), Array.Empty <object>()); } this.hookDispatchFallback = true; return(method.Method.Invoke(this, args)); } return(obj1); } return(method.Method.Invoke(this, args)); }
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; } } }