private void AddNewSymbols(CsModPermission permission, string[] values) { SymbolPermissions.AddOrUpdate(permission, values, (p, v) => v.Concat(values).Distinct().OrderBy(N => N).ToArray()); }
internal Func <object, string> GetExec <T>(CsModPermission csScriptsAllowed, T rootObjectCompileTime, string script) where T : IScriptRootData { var messages = new List <string>(); bool success = true; MethodInfo mainMethod = null; Script <object> csScript = null; CsModPermission permissionNeeded; var rootCompileTime = rootObjectCompileTime as IScriptRootData; using (var loader = new InteractiveAssemblyLoader()) { var options = ScriptOptions.Default .WithAllowUnsafe(false) .WithEmitDebugInformation(false) .WithCheckOverflow(true) .WithOptimizationLevel(OptimizationLevel.Release) .WithImports(DefaultConfiguration.Current.Usings) .AddImports(Configuration.Current.Usings) .WithReferences(DefaultConfiguration.Current.AssemblyReferences) .AddReferences(Configuration.Current.AssemblyReferences) .AddReferences(typeof(EmpyrionScripting).Assembly.Location, typeof(IScriptRootData).Assembly.Location) .AddReferences(CustomAssemblies.Values.Select(A => A.LoadedAssembly)); csScript = CSharpScript.Create <object>(script, options, typeof(IScriptModData), loader); var compilation = csScript.GetCompilation(); var WhitelistDiagnosticAnalyzer = new WhitelistDiagnosticAnalyzer(DefaultConfiguration, Configuration); var analyzerCompilation = compilation .WithAnalyzers(ImmutableArray.Create <DiagnosticAnalyzer>(WhitelistDiagnosticAnalyzer)) .GetAnalysisResultAsync(CancellationToken.None) .GetAwaiter().GetResult().CompilationDiagnostics; analyzerCompilation.ForEach(A => AnalyzeDiagnostics(A.Value, messages, ref success)); if (WhitelistDiagnosticAnalyzer.ConfigurationIsChanged) { Configuration.Current.PrepareForSave(); Configuration.Save(); DefaultConfiguration.Current.PrepareForSave(); DefaultConfiguration.Save(); } permissionNeeded = WhitelistDiagnosticAnalyzer.PermissionNeeded; Assembly assembly = null; if (compilation.Assembly.TypeNames.Contains("ModMain")) { using (var assemblyStream = new MemoryStream()) { try { var result = compilation.Emit(assemblyStream); var resultSuccess = result.Success; if (resultSuccess) { assembly = Assembly.ReflectionOnlyLoad(assemblyStream.ToArray()); var callMainType = assembly.GetTypes().SingleOrDefault(MT => MT.Name == "ModMain"); mainMethod = callMainType.GetMethod("Main"); if (mainMethod != null) { assemblyStream.Seek(0, SeekOrigin.Begin); assembly = Assembly.Load(assemblyStream.ToArray()); callMainType = assembly.GetTypes().SingleOrDefault(MT => MT.Name == "ModMain"); mainMethod = callMainType.GetMethod("Main"); } } } catch (Exception loadError) { messages.Add($"Assembly:{loadError}"); } } } } if (messages.Count > 0) { Log?.Invoke($"C# Compile [{rootCompileTime.ScriptId}]:{string.Join("\n", messages)}", LogLevel.Error); if (EmpyrionScripting.Configuration.Current.ScriptTrackingError) { File.AppendAllText(rootObjectCompileTime is ScriptSaveGameRootData root ? EmpyrionScripting.GetTrackingFileName(root) : EmpyrionScripting.GetTrackingFileName(rootObjectCompileTime.E.GetCurrent(), rootObjectCompileTime.Script.GetHashCode().ToString()) + ".error", string.Join("\n", messages)); } } return(rootObject => { if (!success) { return string.Join("\n", messages); } var root = rootObject as IScriptRootData; if (csScriptsAllowed == CsModPermission.SaveGame && !(root is ScriptSaveGameRootData)) { return "C# scripts are only allowed in SaveGameScripts"; } if (csScriptsAllowed == CsModPermission.Admin && root.E.GetCurrent().Faction.Group != FactionGroup.Admin) { return "C# scripts are only allowed on admin structures"; } if (permissionNeeded == CsModPermission.SaveGame && !(root is ScriptSaveGameRootData)) { return "This script is only allowed in SaveGameScripts"; } if (permissionNeeded == CsModPermission.Admin && root.E.GetCurrent().Faction.Group != FactionGroup.Admin) { return "This script is only allowed on admin structures"; } string exceptionMessage = null; using (var output = new StringWriter()) { root.ScriptOutput = output; try { object result = null; if (mainMethod != null) { if (root.CsRoot is CsScriptFunctions csRoot) { csRoot.ScriptRoot = root; } result = mainMethod.Invoke(null, new[] { root as IScriptModData }); } else { result = csScript .RunAsync(root, ex => { exceptionMessage = $"Exception: {(root.IsElevatedScript ? ex.ToString() : ex.Message)}"; return true; }) .ConfigureAwait(true) .GetAwaiter() .GetResult() .ReturnValue; } if (result is Action action) { action(); } else if (result is Action <IScriptModData> simpleaction) { simpleaction(root); } else if (result is Func <IScriptModData, object> func) { output.Write(func(root)?.ToString()); } else if (result is Task task) { task.RunSynchronously(); } else { output.Write(result?.ToString()); } return exceptionMessage == null?output.ToString() : $"{exceptionMessage}\n\nScript output up to exception:\n{output}"; } catch (Exception error) { exceptionMessage = error.ToString(); return root.IsElevatedScript ? error.ToString() : error.Message; } finally { if (!string.IsNullOrEmpty(exceptionMessage)) { Log?.Invoke($"C# Run [{root.ScriptId}]:{exceptionMessage}\n{output}", LogLevel.Error); if (EmpyrionScripting.Configuration.Current.ScriptTrackingError) { File.AppendAllText(root is ScriptSaveGameRootData saveGameRoot ? EmpyrionScripting.GetTrackingFileName(saveGameRoot) : EmpyrionScripting.GetTrackingFileName(root.E.GetCurrent(), root.Script.GetHashCode().ToString()) + ".error", $"{exceptionMessage}\n\nScript output up to exception:\n{output}"); } } } } }); }