├── .editorconfig ├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── CsCompiler ├── CsCompiler.csproj ├── CsCompiler │ ├── AnalysisExtensions.cs │ ├── CsCompiler.cs │ ├── CsCompilerConfiguration.cs │ ├── LoadedAssemblyInfo.cs │ └── WhitelistDiagnosticAnalyzer.cs ├── CsModPermission.cs ├── ICsScriptRootFunctions.cs ├── IScriptRootModData.cs ├── Properties │ └── AssemblyInfo.cs ├── app.config └── packages.config ├── EcfParser.UnitTests ├── Data │ └── blocksmap.dat ├── EcfParser.UnitTests.csproj ├── MergeTests.cs ├── ParseTests.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── EcfParser ├── DictionaryExtensions.cs ├── EcfAttribute.cs ├── EcfBlock.cs ├── EcfFile.cs ├── EcfParser.csproj ├── Merge.cs ├── Parse.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── EmpyrionScripting.Examples ├── CargoTeleporter.cs ├── EmpyrionScripting.Examples.csproj ├── Examples.cs ├── Properties │ └── AssemblyInfo.cs ├── app.config └── packages.config ├── EmpyrionScripting.Interface ├── DialogResult.cs ├── EmpyrionScripting.Interface.csproj ├── EmpyrionScripting.Interface.nuspec ├── EnumerableExtensions.cs ├── ExtensionsToolbox.cs ├── IBlockData.cs ├── IConfigEcfAccess.cs ├── IConsoleMock.cs ├── IContainerSource.cs ├── ICsScriptFunctions.cs ├── IDisplayOutputConfiguration.cs ├── IEntityCultureInfo.cs ├── IEntityData.cs ├── IEventStore.cs ├── IHarvestInfo.cs ├── IItemBase.cs ├── IItemMoveInfo.cs ├── IItemsData.cs ├── IItemsSource.cs ├── ILimitedPlayerData.cs ├── IPlayerData.cs ├── IPlayfieldData.cs ├── IPlayfieldDetails.cs ├── IScriptInfo.cs ├── IScriptModData.cs ├── IScriptSaveGameRootData.cs ├── ISignalData.cs ├── ISignalEventBase.cs ├── IStructureData.cs ├── IStructureTankWrapper.cs ├── ITeleporterData.cs ├── Properties │ └── AssemblyInfo.cs ├── ScriptLanguage.cs └── packages.config ├── EmpyrionScripting.UnitTests ├── EmpyrionScripting.UnitTests.csproj ├── IdListsTests.cs ├── MockDeviceLock.cs ├── Properties │ └── AssemblyInfo.cs ├── UnitTestConfig.cs ├── UnitTestHandlebar.cs ├── UnitTestcs.cs ├── app.config └── packages.config ├── EmpyrionScripting.sln ├── EmpyrionScripting ├── ConfigEcfAccess.cs ├── Configuration.cs ├── CsHelper │ ├── BlockHelpers.cs │ ├── ConsoleMock.cs │ ├── ConveyorHelpers.cs │ ├── CsScriptFunctions.cs │ ├── DialogHelpers.cs │ ├── EffectHelpers.cs │ ├── EntityAccessHelpers.cs │ ├── FormatHelpers.cs │ └── ItemAccessHelpers.cs ├── CustomHelpers │ ├── BlockHelpers.cs │ ├── ConveyorHelpers.cs │ ├── DBAccessHelpers.cs │ ├── DialogHelpers.cs │ ├── EffectHelpers.cs │ ├── EntityAccessHelpers.cs │ ├── ExternalDataHelpers.cs │ ├── FormatHelpers.cs │ ├── HelpersTools.cs │ ├── ItemAccessHelpers.cs │ ├── LcdHelpers.cs │ ├── LightsHelpers.cs │ ├── LogicHelpers.cs │ ├── LoopHelpers.cs │ ├── MathHelpers.cs │ ├── SaveGameScriptHelpers.cs │ ├── SignalHelpers.cs │ └── TeleporterHelpers.cs ├── DataWrapper │ ├── BlockData.cs │ ├── ContainerData.cs │ ├── ContainerSource.cs │ ├── EntityData.cs │ ├── EventStore.cs │ ├── HarvestInfo.cs │ ├── ItemTokenAccess.cs │ ├── ItemsData.cs │ ├── PlayerData.cs │ ├── PlayfieldData.cs │ ├── ScriptRootData.cs │ ├── ScriptSaveGameRootData.cs │ ├── SignalData.cs │ ├── SignalEvent.cs │ ├── SignalEventBase.cs │ ├── SignalEventElevated.cs │ ├── StructureData.cs │ ├── StructureTank.cs │ └── TeleporterData.cs ├── DefaultCsCompilerConfiguration.json ├── DeviceLock.cs ├── DisplayOutputConfiguration.cs ├── EmpyrionScripting.cs ├── EmpyrionScripting.csproj ├── EmpyrionScripting_Info.yaml ├── EntityCultureInfo.cs ├── GlobalSuppressions.cs ├── HandlebarsHelpers.cs ├── IdLists.cs ├── Internal.Interface │ ├── IDeviceLock.cs │ ├── IPlayfieldScriptData.cs │ └── IScriptRootData.cs ├── ItemInfos.cs ├── Localization.cs ├── PlayfieldScriptData.cs ├── Properties │ └── AssemblyInfo.cs ├── SaveGamesScripts.cs ├── ScriptExecQueue.cs ├── ScriptInfo.cs ├── SerializeHelper.cs ├── SqlDbAccess.cs ├── UnityEngine.CoreModule.dll ├── WeakDeviceLock.cs ├── app.config └── packages.config ├── LICENSE ├── README.md ├── RoslynCsCompiler ├── CompilerAccess.cs ├── ILMerge.props ├── ILMergeOrder.txt ├── Properties │ └── AssemblyInfo.cs ├── RoslynCsCompiler.csproj ├── RoslynCsCompiler.sln ├── app.config └── packages.config ├── Screenshots ├── AddOnAssembly.png ├── Conveyor.png ├── DemoShipScreen.png ├── LCD1.png └── RedAlert.png ├── WpfExtractCustomIcons ├── App.config ├── App.xaml ├── App.xaml.cs ├── FilePathes.txt ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── WpfExtractCustomIcons.csproj └── packages.config └── dependencies ├── Handlebars.dll ├── Mif.dll ├── ModApi.dll └── UnityEngine.CoreModule.dll /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{cs,vb}] 2 | 3 | # IDE0060: Remove unused parameter 4 | dotnet_code_quality_unused_parameters = all:suggestion 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /CsCompiler/CsCompiler/AnalysisExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using System.Linq; 3 | using System.Text; 4 | 5 | namespace EmpyrionScripting.CsCompiler 6 | { 7 | public static class AnalysisExtensions 8 | { 9 | public static string GetFullMetadataName(this ISymbol s) 10 | { 11 | if (s == null || s.IsRootNamespace()) return string.Empty; 12 | 13 | var sb = new StringBuilder(s.MetadataName); 14 | var last = s; 15 | 16 | s = s.ContainingSymbol; 17 | 18 | while (!IsRootNamespace(s)) 19 | { 20 | if (s is ITypeSymbol && last is ITypeSymbol) sb.Insert(0, '+'); 21 | else sb.Insert(0, '.'); 22 | 23 | sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); 24 | s = s.ContainingSymbol; 25 | } 26 | 27 | return sb.ToString(); 28 | } 29 | 30 | private static bool IsRootNamespace(this ISymbol symbol) 31 | { 32 | return (symbol is INamespaceSymbol s) && s.IsGlobalNamespace; 33 | } 34 | 35 | public static bool IsInSource(this ISymbol symbol) => symbol.Locations.All(L => L.IsInSource); 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /CsCompiler/CsCompiler/CsCompilerConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Linq; 5 | 6 | namespace EmpyrionScripting.CsCompiler 7 | { 8 | public class SymbolList : ConcurrentDictionary { } 9 | 10 | public class CsSymbolsConfiguration 11 | { 12 | public CsSymbolsConfiguration() 13 | { 14 | Symbols = new Lazy(() => 15 | SymbolPermissions.Keys 16 | .SelectMany(permission => SymbolPermissions[permission].Select(item => (permission, item))) 17 | .Aggregate(new SymbolList(), 18 | (list, data) => { list.AddOrUpdate(data.item, data.permission, (i, p) => data.permission); return list; }) 19 | ); 20 | } 21 | 22 | public ConcurrentDictionary SymbolPermissions { get; set; } = new ConcurrentDictionary(); 23 | 24 | [JsonIgnore] 25 | public Lazy Symbols; 26 | 27 | public void AddNewSymbols() 28 | { 29 | AddNewSymbols(CsModPermission.SaveGame, Symbols.Value.Where(P => P.Value == CsModPermission.SaveGame).Select(P => P.Key).ToArray()); 30 | AddNewSymbols(CsModPermission.Admin, Symbols.Value.Where(P => P.Value == CsModPermission.Admin ).Select(P => P.Key).ToArray()); 31 | AddNewSymbols(CsModPermission.Player, Symbols.Value.Where(P => P.Value == CsModPermission.Player ).Select(P => P.Key).ToArray()); 32 | } 33 | 34 | private void AddNewSymbols(CsModPermission permission, string[] values) 35 | { 36 | SymbolPermissions.AddOrUpdate(permission, values, (p, v) => v.Concat(values).Distinct().OrderBy(N => N).ToArray()); 37 | } 38 | } 39 | 40 | public class CsCompilerConfiguration : CsSymbolsConfiguration 41 | { 42 | public bool WithinLearnMode { get; set; } 43 | public bool DebugMode { get; set; } 44 | public string[] CustomAssemblies { get; set; } = new string[] { }; 45 | public string[] Usings { get; set; } = new string[] { }; 46 | public string[] AssemblyReferences { get; set; } = new string[] { }; 47 | 48 | public void PrepareForSave() 49 | { 50 | AddNewSymbols(); 51 | Usings = Usings.OrderBy(N => N).ToArray(); 52 | AssemblyReferences = AssemblyReferences.OrderBy(N => N).ToArray(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /CsCompiler/CsCompiler/LoadedAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace EmpyrionScripting.CsCompiler 4 | { 5 | public interface ILoadedAssemblyInfo 6 | { 7 | string FullAssemblyDllName { get; set; } 8 | Assembly LoadedAssembly { get; set; } 9 | } 10 | 11 | public class LoadedAssemblyInfo : ILoadedAssemblyInfo 12 | { 13 | public string FullAssemblyDllName { get; set; } 14 | public Assembly LoadedAssembly { get; set; } 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /CsCompiler/CsCompiler/WhitelistDiagnosticAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionNetAPITools; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using System.Collections.Immutable; 6 | 7 | namespace EmpyrionScripting.CsCompiler 8 | { 9 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 10 | public class WhitelistDiagnosticAnalyzer : DiagnosticAnalyzer 11 | { 12 | #pragma warning disable RS2008 // Enable analyzer release tracking 13 | internal static readonly DiagnosticDescriptor PROHIBITED_OBJECT_RULE 14 | = new DiagnosticDescriptor("ProhibitedLanguageElement", "Prohibited Language Element", "The language element '{0}' is prohibited", "Whitelist", DiagnosticSeverity.Error, true); 15 | #pragma warning restore RS2008 // Enable analyzer release tracking 16 | 17 | public WhitelistDiagnosticAnalyzer( 18 | ConfigurationManager defaultConfiguration, 19 | ConfigurationManager configuration) 20 | { 21 | DefaultConfiguration = defaultConfiguration; 22 | Configuration = configuration; 23 | } 24 | 25 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(PROHIBITED_OBJECT_RULE); 26 | 27 | public CsModPermission PermissionNeeded { get; set; } 28 | public ConfigurationManager DefaultConfiguration { get; } 29 | public ConfigurationManager Configuration { get; } 30 | public bool ConfigurationIsChanged { get; set; } 31 | 32 | public override void Initialize(AnalysisContext context) 33 | { 34 | context.EnableConcurrentExecution(); 35 | context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); 36 | context.RegisterSyntaxNodeAction(Analyze, 37 | SyntaxKind.AliasQualifiedName, 38 | SyntaxKind.QualifiedName, 39 | SyntaxKind.GenericName, 40 | SyntaxKind.IdentifierName); 41 | } 42 | 43 | void Analyze(SyntaxNodeAnalysisContext context) 44 | { 45 | var node = context.Node; 46 | 47 | if (IsQualifiedName(node.Parent)) return; 48 | 49 | var info = context.SemanticModel.GetSymbolInfo(node); 50 | if (info.Symbol == null || info.Symbol.IsInSource()) return; 51 | 52 | var fullName = info.Symbol.GetFullMetadataName(); 53 | var genericTypePos = fullName.IndexOf('`'); 54 | if (genericTypePos >= 0) fullName = fullName.Substring(0, genericTypePos); 55 | 56 | if (FoundPermission(fullName)) return; 57 | if (FoundPermissionWithWildcard(fullName)) return; 58 | 59 | if (Configuration.Current.WithinLearnMode) 60 | { 61 | Configuration.Current.Symbols.Value.TryAdd(fullName, CsModPermission.SaveGame); 62 | ConfigurationIsChanged = true; 63 | } 64 | 65 | PermissionNeeded = CsModPermission.SaveGame; // Im SaveGame ist alles erlaubt 66 | } 67 | 68 | private bool FoundPermissionWithWildcard(string name) 69 | { 70 | var testName = name; 71 | while(true) 72 | { 73 | if (DefaultConfiguration.Current.Symbols.Value.TryGetValue(testName + ".*", out var defaultPermission)) 74 | { 75 | if (PermissionNeeded < defaultPermission) PermissionNeeded = defaultPermission; 76 | return true; 77 | } 78 | 79 | if (Configuration.Current.Symbols.Value.TryGetValue(testName + ".*", out var permission)) 80 | { 81 | if (PermissionNeeded < permission) PermissionNeeded = permission; 82 | return true; 83 | } 84 | 85 | var lastDotPos = testName.LastIndexOf('.'); 86 | if (lastDotPos > 0) testName = testName.Substring(0, lastDotPos); 87 | else return false; 88 | }; 89 | } 90 | 91 | private bool FoundPermission(string name) 92 | { 93 | if (DefaultConfiguration.Current.Symbols.Value.TryGetValue(name, out var defaultPermission)) 94 | { 95 | if (PermissionNeeded < defaultPermission) PermissionNeeded = defaultPermission; 96 | return true; 97 | } 98 | 99 | if (Configuration.Current.Symbols.Value.TryGetValue(name, out var permission)) 100 | { 101 | if (PermissionNeeded < permission) PermissionNeeded = permission; 102 | return true; 103 | } 104 | 105 | return false; 106 | } 107 | 108 | bool IsQualifiedName(SyntaxNode arg) 109 | { 110 | switch (arg.Kind()) 111 | { 112 | default: return false; 113 | case SyntaxKind.QualifiedName: 114 | case SyntaxKind.AliasQualifiedName: return true; 115 | } 116 | } 117 | 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /CsCompiler/CsModPermission.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting 2 | { 3 | public enum CsModPermission 4 | { 5 | Player, 6 | Admin, 7 | SaveGame, 8 | None 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /CsCompiler/ICsScriptRootFunctions.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Internal.Interface; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface ICsScriptRootFunctions 6 | { 7 | IScriptRootModData ScriptRoot { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /CsCompiler/IScriptRootModData.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using EmpyrionScripting.Interface; 3 | 4 | namespace EmpyrionScripting.Internal.Interface 5 | { 6 | public interface IScriptRootModData : IScriptModData 7 | { 8 | ScriptLanguage ScriptLanguage { get; set; } 9 | string Script { get; set; } 10 | TextWriter ScriptOutput { get; set; } 11 | bool ColorChanged { get; set; } 12 | bool BackgroundColorChanged { get; set; } 13 | bool FontSizeChanged { get; set; } 14 | int ScriptPriority { get; set; } 15 | IScriptInfo ScriptDiagnosticInfo { get; set; } 16 | bool Running { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /CsCompiler/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("CsCompiler")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("CsCompiler")] 12 | [assembly: AssemblyCopyright("Copyright © 2022")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("84cecefa-6313-4cc7-8785-acbdd0c64cca")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /CsCompiler/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /CsCompiler/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /EcfParser.UnitTests/Data/blocksmap.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHub-TC/EmpyrionScripting/ce87e85b4a220574b76dd1b8ef019b9e362ff22d/EcfParser.UnitTests/Data/blocksmap.dat -------------------------------------------------------------------------------- /EcfParser.UnitTests/EcfParser.UnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {634C1CC3-EDFA-4ADD-9544-4738A4BAEF1E} 9 | Library 10 | Properties 11 | EcfParser.UnitTests 12 | EcfParser.UnitTests 13 | v4.8 14 | 512 15 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | 15.0 17 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 18 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 19 | False 20 | UnitTest 21 | 22 | 23 | 24 | 25 | 26 | true 27 | full 28 | false 29 | bin\Debug\ 30 | DEBUG;TRACE 31 | prompt 32 | 4 33 | 34 | 35 | pdbonly 36 | true 37 | bin\Release\ 38 | TRACE 39 | prompt 40 | 4 41 | 42 | 43 | 44 | ..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll 45 | 46 | 47 | ..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {6eb355c6-6a17-41d8-8821-70754904f57a} 60 | EcfParser 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /EcfParser.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("EcfParser.UnitTests")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: AssemblyCompany("")] 8 | [assembly: AssemblyProduct("EcfParser.UnitTests")] 9 | [assembly: AssemblyCopyright("Copyright © 2020")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | 13 | [assembly: ComVisible(false)] 14 | 15 | [assembly: Guid("634c1cc3-edfa-4add-9544-4738a4baef1e")] 16 | 17 | // [assembly: AssemblyVersion("1.0.*")] 18 | [assembly: AssemblyVersion("1.0.0.0")] 19 | [assembly: AssemblyFileVersion("1.0.0.0")] 20 | -------------------------------------------------------------------------------- /EcfParser.UnitTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /EcfParser/DictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EcfParser 4 | { 5 | public static class DictionaryExtensions 6 | { 7 | /// Gets the value of specified key. Simply returns the default value if dic or key are null or specified key does not exists. 8 | public static TValue GetValueOrDefault(this IDictionary dic, TKey key, TValue defaultValue = default) 9 | => (dic != null && key != null && dic.TryGetValue(key, out TValue value)) ? value : defaultValue; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EcfParser/EcfAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EcfParser 4 | { 5 | public class EcfAttribute 6 | { 7 | public string Name { get; set; } 8 | public object Value { get; set; } 9 | public IDictionary AddOns { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EcfParser/EcfBlock.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EcfParser 4 | { 5 | public class EcfBlock 6 | { 7 | public string Name { get; set; } 8 | public List Attr { get; set; } 9 | public IDictionary Childs { get; set; } 10 | 11 | /// 12 | /// Flache Liste der gefunden Attribute und deren primären Werte 13 | /// 14 | public IDictionary Values { get; set; } 15 | /// 16 | /// Flache Liste der gefunden Attribute 17 | /// 18 | public IDictionary EcfValues { get; set; } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /EcfParser/EcfFile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EcfParser 4 | { 5 | public class EcfFile 6 | { 7 | public List Blocks { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /EcfParser/EcfParser.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6EB355C6-6A17-41D8-8821-70754904F57A} 8 | Library 9 | Properties 10 | EcfParser 11 | EcfParser 12 | v4.8 13 | 512 14 | true 15 | 8.0 16 | 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /EcfParser/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("EcfParser")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("EcfParser")] 12 | [assembly: AssemblyCopyright("Copyright © 2021")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("6eb355c6-6a17-41d8-8821-70754904f57a")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.1.0")] 35 | [assembly: AssemblyFileVersion("1.0.1.0")] 36 | -------------------------------------------------------------------------------- /EcfParser/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /EmpyrionScripting.Examples/EmpyrionScripting.Examples.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {28D9AD16-EDED-420D-BDCD-9F823327177D} 8 | Library 9 | Properties 10 | EmpyrionScripting.Examples 11 | EmpyrionScripting.Examples 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\dependencies\Mif.dll 37 | 38 | 39 | ..\dependencies\ModApi.dll 40 | 41 | 42 | ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | ..\dependencies\UnityEngine.CoreModule.dll 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | {dd121666-d54d-47e7-ab4d-b7f79bf1278d} 64 | EmpyrionScripting.Interface 65 | 66 | 67 | {DC79FD9D-5E85-4588-A4BD-46F7ED62150F} 68 | EmpyrionScripting 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /EmpyrionScripting.Examples/Examples.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace EmpyrionScripting.Examples 7 | { 8 | public class Examples 9 | { 10 | public string Example1(IScriptModData g) 11 | { 12 | var E = g.E; 13 | return 14 | $"Name: {E.Name}" + 15 | $"Id: {E.Id}" + 16 | $"DeviceNames: " + 17 | string.Join(",", E.DeviceNames) + 18 | $"EntityType: {E.EntityType}" + 19 | $"Faction: Id:{E.Faction.Id} Group:{E.Faction.Group}" 20 | ; 21 | } 22 | public string Example2(IScriptModData g) 23 | { 24 | var E = g.E; 25 | 26 | return 27 | $"GetCurrentPlayfield: {E.GetCurrentPlayfield().Name}\n" + 28 | $"GetCurrent: {E.GetCurrent()}\n" 29 | ; 30 | 31 | } 32 | 33 | public string Example3(IScriptModData g) 34 | { 35 | var S = g.E.S; 36 | 37 | return 38 | "Player StructureData\n" + 39 | $"GetCurrentPlayfield: {S.DockedE}\n" + 40 | $"AllCustomDeviceNames: {S.AllCustomDeviceNames}\n" + 41 | $"ControlPanelSignals: {S.ControlPanelSignals}\n" + 42 | $"BlockSignals: {S.BlockSignals}\n" + 43 | $"ContainerSource: {S.ContainerSource}\n" + 44 | $"DamageLevel: {S.DamageLevel}\n" + 45 | $"GetDeviceTypeNames: {S.GetDeviceTypeNames}\n" + 46 | $"IsOfflineProtectable: {S.IsOfflineProtectable}\n" + 47 | $"IsPowerd: {S.IsPowerd}\n" + 48 | $"IsReady: {S.IsReady}\n" + 49 | $"E: {S.E}\n" + 50 | $"Items: {S.Items}\n" + 51 | $"OxygenTank: {S.OxygenTank}\n" + 52 | $"FuelTank: {S.FuelTank}\n" + 53 | $"PentaxidTank: {S.PentaxidTank}\n" + 54 | $"Passengers: {S.Passengers}\n" + 55 | $"Pilot: {S.Pilot}\n" 56 | ; 57 | } 58 | 59 | public string Example4(IScriptModData g) 60 | { 61 | var I = g.E.S.Items.FirstOrDefault(); 62 | var s = I?.Source?.FirstOrDefault(); 63 | 64 | return 65 | "Player ItemsData\n" + 66 | $"Id: {I?.Id}\n" + 67 | $"Key: {I?.Key}\n" + 68 | $"Name: {I?.Name}\n" + 69 | $"Count: {I?.Count}\n" + 70 | $"Source: {I?.Source?.FirstOrDefault()}\n" + 71 | $"CustomName: {s?.CustomName}\n" + 72 | $"Id: {s?.Id}\n" + 73 | $"Count: {s?.Count}\n" + 74 | $"E: {s?.E}\n" + 75 | $"Position: {s?.Position}\n" + 76 | "" 77 | ; 78 | } 79 | 80 | public string Example5(IScriptModData g) 81 | { 82 | var p = g.E.S.Pilot; 83 | 84 | return 85 | "Player PlayerData\n" + 86 | $"Id: {p.Id}\n" + 87 | $"Name: {p.Name}\n" + 88 | $"SteamId: {p.SteamId}\n" + 89 | $"Ping: {p.Ping}\n" + 90 | "\n" + 91 | $"BodyTemp: {p.BodyTemp}\n" + 92 | $"BodyTempMax: {p.BodyTempMax}\n" + 93 | $"Food: {p.Food}\n" + 94 | $"FoodMax: {p.FoodMax}\n" + 95 | $"Health: {p.Health}\n" + 96 | $"HealthMax: {p.HealthMax}\n" + 97 | $"Radiation: {p.Radiation}\n" + 98 | $"RadiationMax: {p.RadiationMax}\n" + 99 | $"Stamina: {p.Stamina}\n" + 100 | $"StaminaMax: {p.StaminaMax}\n" + 101 | $"Oxygen: {p.Oxygen}\n" + 102 | $"OxygenMax: {p.OxygenMax}\n" + 103 | "\n" + 104 | $"Bag: {p.Bag?.Count()}\n" + 105 | $"Toolbar: {p.Toolbar?.Count()}\n" + 106 | "\n" + 107 | $"Credits: {p.Credits}\n" + 108 | $"Died: {p.Died}\n" + 109 | $"ExperiencePoints: {p.ExperiencePoints}\n" + 110 | $"UpgradePoints: {p.UpgradePoints}\n" + 111 | $"FactionData: {p.FactionData}\n" + 112 | $"FactionRole: {p.FactionRole}\n" + 113 | $"Kills: {p.Kills}\n" + 114 | $"Origin: {p.Origin}\n" + 115 | $"StartPlayfield: {p.StartPlayfield}\n" + 116 | "" 117 | ; 118 | } 119 | 120 | 121 | public string Example6(IScriptModData g) 122 | { 123 | var f = g.E.S.FuelTank; 124 | 125 | return 126 | "Player StructureTank\n" + 127 | $"Capacity: {f.Capacity}\n" + 128 | $"Content: {f.Content}\n" + 129 | $"AllowedItem: {f.AllowedItem(2266)}\n" + 130 | $"ItemsNeededForFill: {f.ItemsNeededForFill(2266, 100)}\n" + 131 | "" 132 | ; 133 | } 134 | 135 | public string Example7(IScriptModData g) 136 | { 137 | var E = g.E; 138 | 139 | Console.WriteLine( 140 | $"BlockSignals: {E.S.BlockSignals.Count()}\n" + 141 | GetNames(E.S.BlockSignals) + 142 | ""); 143 | 144 | Console.WriteLine( 145 | $"ControlPanelSignals: " + 146 | $"{E.S.ControlPanelSignals.Count()}\n" + 147 | GetNames(E.S.ControlPanelSignals) + 148 | ""); 149 | 150 | string GetNames(IEnumerable s) 151 | { 152 | return string.Join(";", s.Select(i => i.Name)); 153 | } 154 | 155 | return null; 156 | } 157 | 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /EmpyrionScripting.Examples/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("EmpyrionScripting.Examples")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("EmpyrionScripting.Examples")] 12 | [assembly: AssemblyCopyright("Copyright © 2020")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("28d9ad16-eded-420d-bdcd-9f823327177d")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /EmpyrionScripting.Examples/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /EmpyrionScripting.Examples/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/DialogResult.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public class DialogResult 4 | { 5 | public int ButtonIdx { get; set; } 6 | public string Link { get; set; } 7 | public string PlayerInput { get; set; } 8 | public IPlayerData Player { get; set; } 9 | public int DialogData { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/EmpyrionScripting.Interface.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | EmpyrionScripting.Interface 5 | 1.0.0.0 6 | EmpyrionScripting.Interface 7 | ASTIC/TC 8 | ASTIC/TC 9 | MIT 10 | https://github.com/GitHub-TC/EmpyrionScripting 11 | false 12 | A interface to the EmpyrionScriptingMod C# 13 | Copyright 2020 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace EmpyrionScripting.Interface 5 | { 6 | public static class EnumerableExtensions 7 | { 8 | public static IEnumerable ForEach(this T[] aArray, Action aAction) 9 | { 10 | if (aArray == null) return null; 11 | 12 | foreach (var item in aArray) aAction(item); 13 | return aArray; 14 | } 15 | 16 | public static IEnumerable ForEach(this IEnumerable aArray, Action aAction) 17 | { 18 | if (aArray == null) return null; 19 | 20 | foreach (var item in aArray) aAction(item); 21 | return aArray; 22 | } 23 | public static Dictionary SafeToDictionary( 24 | this IEnumerable source, 25 | Func keySelector, 26 | Func elementSelector, 27 | IEqualityComparer comparer = null) 28 | { 29 | var dictionary = new Dictionary(comparer); 30 | 31 | if (source == null) 32 | { 33 | return dictionary; 34 | } 35 | 36 | foreach (TSource element in source) 37 | { 38 | dictionary[keySelector(element)] = elementSelector(element); 39 | } 40 | 41 | return dictionary; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/ExtensionsToolbox.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | 7 | namespace EmpyrionScripting.Interface 8 | { 9 | public static class ExtensionsToolbox 10 | { 11 | public static string NormalizePath(this string path) 12 | { 13 | return Path.GetFullPath(new Uri(path).LocalPath) 14 | .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) 15 | .ToUpperInvariant(); 16 | } 17 | 18 | public static IEnumerable Values(this IDevicePosList list) 19 | { 20 | for (int i = 0; i < list.Count; i++) yield return list.GetAt(i); 21 | } 22 | 23 | public static object Get(this object[] args, int index) 24 | { 25 | return args.Length > index ? args[index] : null; 26 | } 27 | 28 | public static T Get(this object[] args, int index) where T : class 29 | { 30 | return args.Length > index ? args[index] as T : default; 31 | } 32 | 33 | public static IEnumerable ForEach(this IEnumerable data, Action action, Func terminate) 34 | { 35 | if (data == null || terminate()) return Enumerable.Empty(); 36 | 37 | foreach (var item in data) 38 | { 39 | action(item); 40 | if (terminate()) return Enumerable.Empty(); 41 | } 42 | 43 | return data; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IBlockData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface IBlockData 6 | { 7 | bool Active { get; set; } 8 | string CustomName { get; } 9 | int Damage { get; } 10 | object Device { get; } 11 | int East { get; set; } 12 | int HitPoints { get; } 13 | int Id { get; } 14 | int BlockType { get; set; } 15 | int? LockCode { get; } 16 | VectorInt3 Position { get; } 17 | int Rotation { get; set; } 18 | int Shape { get; set; } 19 | bool SwitchState { get; set; } 20 | 21 | int Top { get; set; } 22 | int Bottom { get; set; } 23 | int West { get; set; } 24 | int South { get; set; } 25 | int North { get; set; } 26 | 27 | int TopColor { get; set; } 28 | int BottomColor { get; set; } 29 | int NorthColor { get; set; } 30 | int SouthColor { get; set; } 31 | int WestColor { get; set; } 32 | int EastColor { get; set; } 33 | bool IsDamaged { get; } 34 | string SendSignalName { get; } 35 | bool SignalState { get; } 36 | int MaxSlots { get; } 37 | 38 | void ChangeBlockType(int newType); 39 | void SetColorForWholeBlock(int texIdx); 40 | void SetColors(int? top, int? bottom, int? north, int? south, int? west, int? east); 41 | void SetTextureForWholeBlock(int texIdx); 42 | void SetTextures(int? top, int? bottom, int? north, int? south, int? west, int? east); 43 | } 44 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IConfigEcfAccess.cs: -------------------------------------------------------------------------------- 1 | using EcfParser; 2 | using System.Collections.Generic; 3 | 4 | namespace EmpyrionScripting.Interface 5 | { 6 | public interface IConfigEcfAccess 7 | { 8 | IReadOnlyDictionary BlockIdMapping { get; } 9 | IReadOnlyDictionary IdBlockMapping { get; } 10 | 11 | IReadOnlyDictionary ConfigBlockById { get; } 12 | IReadOnlyDictionary ConfigBlockByName { get; } 13 | EcfFile Configuration_Ecf { get; } 14 | IReadOnlyDictionary FlatConfigBlockById { get; } 15 | IReadOnlyDictionary FlatConfigBlockByName { get; } 16 | IReadOnlyDictionary> ResourcesForBlockById { get; } 17 | Dictionary HarvestBlockData { get; } 18 | } 19 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IConsoleMock.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public interface IConsoleMock 4 | { 5 | void Write(string value); 6 | void Write(object value); 7 | void Write(ulong value); 8 | void Write(long value); 9 | void Write(int value); 10 | void Write(uint value); 11 | void Write(bool value); 12 | void Write(char value); 13 | void Write(decimal value); 14 | void Write(float value); 15 | void Write(double value); 16 | void Write(string format, params object[] arg); 17 | void Write(char[] buffer); 18 | void Write(char[] buffer, int index, int count); 19 | 20 | void WriteLine(); 21 | void WriteLine(float value); 22 | void WriteLine(int value); 23 | void WriteLine(uint value); 24 | void WriteLine(long value); 25 | void WriteLine(ulong value); 26 | void WriteLine(object value); 27 | void WriteLine(string value); 28 | void WriteLine(decimal value); 29 | void WriteLine(char value); 30 | void WriteLine(bool value); 31 | void WriteLine(double value); 32 | void WriteLine(string format, params object[] arg); 33 | void WriteLine(char[] buffer); 34 | } 35 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IContainerSource.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface IContainerSource 6 | { 7 | IContainer Container { get; set; } 8 | string CustomName { get; set; } 9 | IEntityData E { get; set; } 10 | VectorInt3 Position { get; set; } 11 | float VolumeCapacity { get; } 12 | float DecayFactor { get; } 13 | int MaxSlots { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/ICsScriptFunctions.cs: -------------------------------------------------------------------------------- 1 | using EcfParser; 2 | using Eleon.Modding; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace EmpyrionScripting.Interface 7 | { 8 | public interface ICsScriptFunctions 9 | { 10 | string I18nDefaultLanguage { get; set; } 11 | IScriptModData Root { get; } 12 | 13 | IList Scroll(string content, int lines, int delay, int step = 1); 14 | string Bar(double data, double min, double max, int length, string barChar = null, string barBgChar = null); 15 | IBlockData Block(IStructureData structure, int x, int y, int z); 16 | IBlockData[] Devices(IStructureData structure, string names); 17 | IBlockData[] DevicesOfType(IStructureData structure, DeviceTypeName deviceType); 18 | IEnumerable EntitiesById(params int[] ids); 19 | IEnumerable EntitiesById(string ids); 20 | IEnumerable EntitiesByName(params string[] names); 21 | IEnumerable EntitiesByName(string names); 22 | string Format(object data, string format); 23 | string I18n(int id); 24 | string I18n(int id, string language); 25 | IItemsData[] Items(IStructureData structure, string names); 26 | IList Fill(IItemsData item, IStructureData structure, StructureTankType type, int? maxLimit = null); 27 | IList Move(IItemsData item, IStructureData structure, string names, int? maxLimit = null); 28 | void WithLockedDevice(IStructureData structure, IBlockData block, Action action, Action lockFailed = null); 29 | bool IsLocked(IStructureData structure, IBlockData block); 30 | object ConfigFindAttribute(int id, string name); 31 | EcfBlock ConfigById(int id); 32 | EcfBlock ConfigByName(string name); 33 | bool FunctionNeedsMainThread(Exception error); 34 | T[] GetDevices(params IBlockData[] block) where T : class, IDevice; 35 | T[] GetDevices(IStructureData structure, string names) where T : class, IDevice; 36 | (IBlockData B, T D)[] GetBlockDevices(IStructureData structure, string names) where T : class, IDevice; 37 | (IBlockData B, T D)[] GetBlockDevices(params IBlockData[] block) where T : class, IDevice; 38 | Dictionary ResourcesForBlockById(int id); 39 | bool ShowDialog(int playerId, DialogConfig dialogConfig, DialogActionHandler actionHandler, int customValue); 40 | bool ShowDialog(string signalNames, DialogConfig dialogConfig, DialogActionHandler actionHandler, int customValue); 41 | string ToId(string names); 42 | string ToName(string ids); 43 | } 44 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IDisplayOutputConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public interface IDisplayOutputConfiguration 4 | { 5 | bool AppendAtEnd { get; set; } 6 | int Lines { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IEntityCultureInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface IEntityCultureInfo 6 | { 7 | CultureInfo CultureInfo { get; set; } 8 | /// 9 | /// Language tag from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c 10 | /// 11 | string LanguageTag { get; set; } 12 | string i18nDefault { get; set; } 13 | int UTCplusTimezone { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IEntityData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using UnityEngine; 3 | 4 | namespace EmpyrionScripting.Interface 5 | { 6 | public interface IEntityData 7 | { 8 | string[] DeviceNames { get; } 9 | EntityType EntityType { get; } 10 | FactionData Faction { get; } 11 | int Id { get; } 12 | string Name { get; } 13 | Vector3 Pos { get; } 14 | IStructureData S { get; } 15 | bool IsLocal { get; } 16 | bool IsPoi { get; } 17 | bool IsProxy { get; } 18 | Vector3 Forward { get; } 19 | int BelongsTo { get; } 20 | int DockedTo { get; } 21 | 22 | void MoveForward(float speed); 23 | void MoveTo(Vector3 direction); 24 | void MoveStop(); 25 | 26 | IEntity GetCurrent(); 27 | IPlayfield GetCurrentPlayfield(); 28 | 29 | IScriptInfo[] ScriptInfos { get; } 30 | bool IsElevated { get; } 31 | } 32 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IEventStore.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Collections.Generic; 3 | 4 | namespace EmpyrionScripting.Interface 5 | { 6 | public interface IEventStore 7 | { 8 | ConcurrentDictionary> GetEvents(); 9 | } 10 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IHarvestInfo.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public interface IHarvestInfo 4 | { 5 | int Id { get; } 6 | string Name { get; } 7 | int ChildOnHarvestId { get; } 8 | int DropOnHarvestCount { get; } 9 | int DropOnHarvestId { get; } 10 | string DropOnHarvestItem { get; } 11 | string ChildOnHarvestItem { get; } 12 | int PickupTargetId { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IItemBase.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public interface IItemBase 4 | { 5 | int Id { get; } 6 | int ItemId { get; } 7 | int TokenId { get; } 8 | bool IsToken { get; } 9 | } 10 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IItemMoveInfo.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | 4 | public interface IItemMoveInfo : IItemBase 5 | { 6 | int Count { get; } 7 | int Ammo { get; } 8 | int Decay { get; } 9 | string Destination { get; } 10 | IEntityData DestinationE { get; } 11 | string Error { get; } 12 | string Source { get; } 13 | IEntityData SourceE { get; } 14 | } 15 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IItemsData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface IItemsData : IItemBase 6 | { 7 | int Count { get; set; } 8 | int Ammo { get; set; } 9 | int Decay { get; set; } 10 | string Key { get; set; } 11 | string Name { get; set; } 12 | List Source { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IItemsSource.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface IItemsSource : IItemBase 6 | { 7 | IContainer Container { get; set; } 8 | int Count { get; set; } 9 | int Ammo { get; set; } 10 | int Decay { get; set; } 11 | string CustomName { get; set; } 12 | IEntityData E { get; set; } 13 | VectorInt3 Position { get; set; } 14 | int MaxSlots { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/ILimitedPlayerData.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public interface ILimitedPlayerData 4 | { 5 | int Id { get; } 6 | string Name { get; } 7 | } 8 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IPlayerData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace EmpyrionScripting.Interface 6 | { 7 | public interface IPlayerData : ILimitedPlayerData 8 | { 9 | List Bag { get; } 10 | float BodyTemp { get; } 11 | float BodyTempMax { get; } 12 | double Credits { get; } 13 | int Died { get; } 14 | int ExperiencePoints { get; } 15 | FactionData FactionData { get; } 16 | FactionRole FactionRole { get; } 17 | int Food { get; } 18 | float FoodMax { get; } 19 | float Health { get; } 20 | float HealthMax { get; } 21 | int Kills { get; } 22 | byte Origin { get; } 23 | float Oxygen { get; } 24 | float OxygenMax { get; } 25 | int Ping { get; } 26 | float Radiation { get; } 27 | float RadiationMax { get; } 28 | float Stamina { get; } 29 | float StaminaMax { get; } 30 | string StartPlayfield { get; } 31 | bool IsPilot { get; } 32 | IEntityData DrivingEntity { get; } 33 | IEntityData CurrentStructure { get; } 34 | string SteamId { get; } 35 | string SteamOwnerId { get; } 36 | int HomeBaseId { get; } 37 | List Toolbar { get; } 38 | int UpgradePoints { get; } 39 | 40 | bool Teleport(Vector3 pos); 41 | bool Teleport(string playfieldName, Vector3 pos, Vector3 rot); 42 | } 43 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IPlayfieldData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface IPlayfieldData 6 | { 7 | bool IsPvP { get; } 8 | string Name { get; } 9 | string PlanetClass { get; } 10 | string PlanetType { get; } 11 | string PlayfieldType { get; } 12 | ILimitedPlayerData[] Players { get; } 13 | VectorInt3 SolarSystemCoordinates { get; } 14 | string SolarSystemName { get; } 15 | IPlayfieldDetails Details { get; } 16 | 17 | float GetTerrainHeightAt(float x, float z); 18 | } 19 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IPlayfieldDetails.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public interface IPlayfieldDetails 4 | { 5 | bool AtmosphereBreathable { get; } 6 | double AtmosphereDensity { get; } 7 | double AtmosphereO2 { get; } 8 | string Description { get; } 9 | double Gravity { get; } 10 | double PlanetAxis { get; } 11 | int PlanetSize { get; } 12 | string PlanetType { get; } 13 | string PlayfieldType { get; } 14 | double Radiation { get; } 15 | int[] TemperatureMinMax { get; } 16 | int TemperatureDay { get; } 17 | int TemperatureMin { get; } 18 | int TemperatureMax { get; } 19 | } 20 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IScriptInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface IScriptInfo 6 | { 7 | int Count { get; } 8 | int EntityId { get; } 9 | TimeSpan ExecTime { get; } 10 | DateTime LastStart { get; } 11 | int ScriptPriority { get; } 12 | int RunningInstances { get; } 13 | string ScriptId { get; set; } 14 | int TimeLimitReached { get; } 15 | bool NeedsMainThread { get; } 16 | bool IsElevatedScript { get; } 17 | ScriptLanguage ScriptLanguage { get; } 18 | bool NeedsDeviceLock { get; } 19 | int TimeCriticalScriptExecutions { get; } 20 | } 21 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IScriptModData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using UnityEngine; 6 | 7 | namespace EmpyrionScripting.Interface 8 | { 9 | public interface IScriptModData 10 | { 11 | ICsScriptFunctions CsRoot { get; } 12 | IConsoleMock Console { get; } 13 | IEventStore SignalEventStore { get; } 14 | Color BackgroundColor { get; set; } 15 | Color Color { get; set; } 16 | ConcurrentDictionary Data { get; set; } 17 | bool DeviceLockAllowed { get; } 18 | IDisplayOutputConfiguration DisplayType { get; set; } 19 | IEntityData E { get; } 20 | string Error { get; set; } 21 | int FontSize { get; set; } 22 | Dictionary Ids { get; } 23 | Dictionary PlainIds { get; } 24 | Dictionary NamedIds { get; } 25 | List LcdTargets { get; set; } 26 | IPlayfieldData P { get; set; } 27 | int GetMaxSlots(int blockType); 28 | string ScriptId { get; set; } 29 | ulong GameTicks { get; } 30 | int CycleCounter { get; } 31 | bool IsElevatedScript { get; } 32 | string Version { get; } 33 | IConfigEcfAccess ConfigEcfAccess { get; } 34 | IDictionary GameOptionsYamlSettings { get; } 35 | bool TimeCriticalScript { get; set; } 36 | bool ScriptWithinMainThread { get; set; } 37 | bool ScriptNeedsMainThread { get; set; } 38 | bool ScriptNeedsDeviceLock { get; set; } 39 | ConcurrentDictionary CacheData { get; } 40 | string ScriptingModInfoData { get; } 41 | ConcurrentDictionary ScriptingModScriptsInfoData { get; } 42 | DateTime DateTimeNow { get; } 43 | 44 | IEnumerable GetAllEntities(); 45 | IPlayfield GetCurrentPlayfield(); 46 | IEnumerable GetEntities(); 47 | ConcurrentDictionary GetPersistendData(); 48 | bool TimeLimitReached { get; } 49 | IEntityCultureInfo CultureInfo { get; } 50 | } 51 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IScriptSaveGameRootData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface IScriptSaveGameRootData : IScriptModData 6 | { 7 | string MainScriptPath { get; set; } 8 | IModApi ModApi { get; set; } 9 | string ScriptPath { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/ISignalData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface ISignalData 6 | { 7 | VectorInt3? BlockPos { get; } 8 | int Index { get; } 9 | string Name { get; } 10 | bool State { get; } 11 | } 12 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/ISignalEventBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EmpyrionScripting.Interface 4 | { 5 | public interface ISignalEventBase 6 | { 7 | string Name { get; set; } 8 | bool State { get; set; } 9 | DateTime TimeStamp { get; set; } 10 | int TriggeredByEntityId { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IStructureData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using Eleon.Modding; 3 | using UnityEngine; 4 | 5 | namespace EmpyrionScripting.Interface 6 | { 7 | public interface IStructureData 8 | { 9 | string[] AllCustomDeviceNames { get; } 10 | ISignalData[] ControlPanelSignals { get; } 11 | ISignalData[] BlockSignals { get; } 12 | ConcurrentDictionary ContainerSource { get; } 13 | float DamageLevel { get; } 14 | IEntityData[] DockedE { get; } 15 | IEntityData E { get; } 16 | string[] GetDeviceTypeNames { get; } 17 | bool IsOfflineProtectable { get; } 18 | bool IsPowerd { get; } 19 | bool IsReady { get; } 20 | IItemsData[] Items { get; } 21 | IStructureTankWrapper OxygenTank { get; } 22 | IStructureTankWrapper FuelTank { get; } 23 | IStructureTankWrapper PentaxidTank { get; } 24 | IPlayerData[] Passengers { get; } 25 | IPlayerData Pilot { get; } 26 | VectorInt3 MinPos { get; } 27 | VectorInt3 MaxPos { get; } 28 | int BlockCount { get; } 29 | int TriangleCount { get; } 30 | int LightCount { get; } 31 | float Fuel { get; } 32 | int PowerConsumption { get; } 33 | int PowerOutCapacity { get; } 34 | int SizeClass { get; } 35 | bool IsShieldActive { get; } 36 | int ShieldLevel { get; } 37 | float TotalMass { get; } 38 | bool HasLandClaimDevice { get; } 39 | ulong LastVisitedTicks { get; } 40 | string PlayerCreatedSteamId { get; } 41 | IPlayerData[] Players { get; } 42 | 43 | VectorInt3 GlobalToStructPos(Vector3 globalPos); 44 | Vector3 StructToGlobalPos(VectorInt3 structPos); 45 | 46 | IStructure GetCurrent(); 47 | } 48 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/IStructureTankWrapper.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public enum StructureTankType 4 | { 5 | Oxygen, 6 | Fuel, 7 | Pentaxid 8 | } 9 | 10 | public interface IStructureTankWrapper 11 | { 12 | float Capacity { get; } 13 | float Content { get; } 14 | bool AllowedItem(int itemId); 15 | int AddItems(int itemId, int count); 16 | int ItemsNeededForFill(int itemId, int maxLimit); 17 | } 18 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/ITeleporterData.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public interface ITeleporterData 4 | { 5 | string Destination { get; set; } 6 | string DeviceName { get; set; } 7 | byte Origin { get; set; } 8 | string Playfield { get; set; } 9 | string SolarSystemName { get; set; } 10 | string Target { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("EmpyrionScripting.Interface")] 8 | [assembly: AssemblyDescription("A interface to the EmpyrionScriptingMod C#")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("ASTIC/TC")] 11 | [assembly: AssemblyProduct("EmpyrionScripting.Interface")] 12 | [assembly: AssemblyCopyright("Copyright © 2020")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("dd121666-d54d-47e7-ab4d-b7f79bf1278d")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/ScriptLanguage.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Interface 2 | { 3 | public enum ScriptLanguage 4 | { 5 | Handlebar, 6 | Cs, 7 | CompiledDll 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /EmpyrionScripting.Interface/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /EmpyrionScripting.UnitTests/MockDeviceLock.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Internal.Interface; 2 | 3 | namespace EmpyrionScripting.UnitTests 4 | { 5 | public class MockDeviceLock : IDeviceLock 6 | { 7 | public bool Success => true; 8 | 9 | public bool Exit => false; 10 | 11 | public void Dispose() 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /EmpyrionScripting.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("EmpyrionScripting.UnitTests")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: AssemblyCompany("")] 8 | [assembly: AssemblyProduct("EmpyrionScripting.UnitTests")] 9 | [assembly: AssemblyCopyright("Copyright © 2019")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | 13 | [assembly: ComVisible(false)] 14 | 15 | [assembly: Guid("6b6a2588-d72c-497d-bd81-187f2e359306")] 16 | 17 | // [assembly: AssemblyVersion("1.0.*")] 18 | [assembly: AssemblyVersion("1.0.0.0")] 19 | [assembly: AssemblyFileVersion("1.0.0.0")] 20 | -------------------------------------------------------------------------------- /EmpyrionScripting.UnitTests/UnitTestConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using EcfParser; 5 | using EmpyrionScripting; 6 | using EmpyrionScripting.DataWrapper; 7 | using EmpyrionScripting.Interface; 8 | using Microsoft.VisualStudio.TestTools.UnitTesting; 9 | 10 | namespace EmpyrionLCDInfo.UnitTests 11 | { 12 | [TestClass] 13 | public class UnitTestEcfTemplates 14 | { 15 | [TestMethod] 16 | public void TestMethodConfigTemplates() 17 | { 18 | EmpyrionScripting.EmpyrionScripting.SaveGameModPath = string.Empty; 19 | var config = new ConfigEcfAccess(); 20 | //config.ReadConfigEcf(@"C:\steamcmd\empyrion\Content", null, null, null); 21 | config.ReadConfigEcf(@"C:\steamcmd\empyrion\Content", "Reforged Eden", @"C:\steamcmd\empyrion.server\Saves\Games\Default\blocksmap.dat", null); 22 | var templates = new Dictionary>(); 23 | 24 | config.FlatConfigBlockById 25 | .ForEach(B => { 26 | var idCfg = B.Value.Attr.FirstOrDefault(A => A.Name == "Id"); 27 | if (!int.TryParse(idCfg?.Value?.ToString(), out var id)) return; 28 | 29 | var ressList = new Dictionary(); 30 | var templateRoot = B.Value.Attr.FirstOrDefault(A => A.Name == "TemplateRoot")?.Value?.ToString() ?? 31 | idCfg.AddOns?.FirstOrDefault(A => A.Key == "Name").Value?.ToString(); 32 | if (string.IsNullOrEmpty(templateRoot)) return; 33 | if (!config.FlatConfigTemplatesByName.TryGetValue(templateRoot, out var templateRootBlock)) return; 34 | 35 | ScanTemplates(config, templateRootBlock, ressList); 36 | 37 | if (ressList.Count > 0) templates.Add(id, ressList); 38 | }); 39 | 40 | Console.WriteLine(templates.Count); 41 | } 42 | 43 | private void ScanTemplates(ConfigEcfAccess config, EcfBlock templateRootBlock, Dictionary ressList) 44 | { 45 | var templateName = templateRootBlock.Attr.FirstOrDefault(A => A.Name == "Name")?.Value.ToString(); 46 | bool.TryParse(templateRootBlock.Attr.FirstOrDefault(A => A.Name == "BaseItem")?.Value.ToString(), out var isBaseItem); 47 | 48 | templateRootBlock.Childs? 49 | .FirstOrDefault(C => C.Key == "Child Inputs").Value?.Attr? 50 | .ForEach(C => { 51 | 52 | if (C.Name.ToString() == templateName) return; 53 | 54 | if (!isBaseItem && config.FlatConfigTemplatesByName.TryGetValue(C.Name.ToString(), out var recipe)) 55 | { 56 | bool.TryParse(recipe.Attr.FirstOrDefault(A => A.Name == "BaseItem")?.Value.ToString(), out var isSubBaseItem); 57 | if (!isSubBaseItem) 58 | { 59 | ScanTemplates(config, recipe, ressList); 60 | return; 61 | } 62 | } 63 | 64 | if (!config.FlatConfigBlockByName.TryGetValue(C.Name.ToString(), out var ressource)) return; 65 | if (!int.TryParse(ressource.Attr.FirstOrDefault(A => A.Name == "Id")?.Value.ToString(), out var ressId)) return; 66 | 67 | if (ressList.TryGetValue(ressId, out var count)) ressList[ressId] = count + (int)C.Value; 68 | else ressList.Add(ressId, (int)C.Value); 69 | }); 70 | } 71 | 72 | [TestMethod] 73 | public void ReadHarvestData() 74 | { 75 | EmpyrionScripting.EmpyrionScripting.SaveGameModPath = string.Empty; 76 | var config = new ConfigEcfAccess(); 77 | //config.ReadConfigEcf(@"C:\steamcmd\empyrion\Content", null, null, null); 78 | config.ReadConfigEcf(@"C:\steamcmd\empyrion\Content", "Reforged Eden Atlantis", @"C:\steamcmd\empyrion.server\Saves\Games\Reforged Eden Atlantis\Mods\EmpyrionScripting\NameIdMapping.json", null); 79 | 80 | config.FlatConfigBlockByName.TryGetValue("HeavyWindowSConnect", out var block); 81 | 82 | int i = config.HarvestBlockData.Count; 83 | } 84 | 85 | [TestMethod] 86 | public void ReadGameOptionsYaml() 87 | { 88 | EmpyrionScripting.EmpyrionScripting.SaveGameModPath = @"C:\steamcmd\empyrion.server\Saves\Games\Reforged Eden Atlantis\Mods\EmpyrionScripting"; 89 | EmpyrionScripting.EmpyrionScripting.ReadGameOptionsYaml(); 90 | } 91 | 92 | [TestMethod] 93 | public void ReadPlayfieldYaml() 94 | { 95 | EmpyrionScripting.EmpyrionScripting.SaveGameModPath = @"C:\steamcmd\empyrion.server\Saves\Games\Reforged Eden Atlantis\Mods\EmpyrionScripting"; 96 | var pf = PlayfieldData.ReadPlayfieldInfo("Haven"); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /EmpyrionScripting.UnitTests/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /EmpyrionScripting.UnitTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /EmpyrionScripting.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32112.339 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmpyrionScripting", "EmpyrionScripting\EmpyrionScripting.csproj", "{DC79FD9D-5E85-4588-A4BD-46F7ED62150F}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmpyrionScripting.UnitTests", "EmpyrionScripting.UnitTests\EmpyrionScripting.UnitTests.csproj", "{6B6A2588-D72C-497D-BD81-187F2E359306}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ACDE2554-23D4-45F7-9EB3-7D727E8C651C}" 11 | ProjectSection(SolutionItems) = preProject 12 | .editorconfig = .editorconfig 13 | README.md = README.md 14 | EndProjectSection 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmpyrionScripting.Interface", "EmpyrionScripting.Interface\EmpyrionScripting.Interface.csproj", "{DD121666-D54D-47E7-AB4D-B7F79BF1278D}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmpyrionScripting.Examples", "EmpyrionScripting.Examples\EmpyrionScripting.Examples.csproj", "{28D9AD16-EDED-420D-BDCD-9F823327177D}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EcfParser", "EcfParser\EcfParser.csproj", "{6EB355C6-6A17-41D8-8821-70754904F57A}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EcfParser.UnitTests", "EcfParser.UnitTests\EcfParser.UnitTests.csproj", "{634C1CC3-EDFA-4ADD-9544-4738A4BAEF1E}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsCompiler", "CsCompiler\CsCompiler.csproj", "{84CECEFA-6313-4CC7-8785-ACBDD0C64CCA}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoslynCsCompiler", "RoslynCsCompiler\RoslynCsCompiler.csproj", "{09FBBFBB-1257-483A-BEB3-99939F249C27}" 27 | EndProject 28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfExtractCustomIcons", "WpfExtractCustomIcons\WpfExtractCustomIcons.csproj", "{3E707A29-8AB4-42B7-8BF5-FC93A9C95CFA}" 29 | EndProject 30 | Global 31 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 32 | Debug|Any CPU = Debug|Any CPU 33 | Release|Any CPU = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 36 | {DC79FD9D-5E85-4588-A4BD-46F7ED62150F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {DC79FD9D-5E85-4588-A4BD-46F7ED62150F}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {DC79FD9D-5E85-4588-A4BD-46F7ED62150F}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {DC79FD9D-5E85-4588-A4BD-46F7ED62150F}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {6B6A2588-D72C-497D-BD81-187F2E359306}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {6B6A2588-D72C-497D-BD81-187F2E359306}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {6B6A2588-D72C-497D-BD81-187F2E359306}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {6B6A2588-D72C-497D-BD81-187F2E359306}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {DD121666-D54D-47E7-AB4D-B7F79BF1278D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {DD121666-D54D-47E7-AB4D-B7F79BF1278D}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {DD121666-D54D-47E7-AB4D-B7F79BF1278D}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {DD121666-D54D-47E7-AB4D-B7F79BF1278D}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {28D9AD16-EDED-420D-BDCD-9F823327177D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {28D9AD16-EDED-420D-BDCD-9F823327177D}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {28D9AD16-EDED-420D-BDCD-9F823327177D}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {28D9AD16-EDED-420D-BDCD-9F823327177D}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {6EB355C6-6A17-41D8-8821-70754904F57A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {6EB355C6-6A17-41D8-8821-70754904F57A}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {6EB355C6-6A17-41D8-8821-70754904F57A}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {6EB355C6-6A17-41D8-8821-70754904F57A}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {634C1CC3-EDFA-4ADD-9544-4738A4BAEF1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {634C1CC3-EDFA-4ADD-9544-4738A4BAEF1E}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {634C1CC3-EDFA-4ADD-9544-4738A4BAEF1E}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {634C1CC3-EDFA-4ADD-9544-4738A4BAEF1E}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {84CECEFA-6313-4CC7-8785-ACBDD0C64CCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {84CECEFA-6313-4CC7-8785-ACBDD0C64CCA}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {84CECEFA-6313-4CC7-8785-ACBDD0C64CCA}.Release|Any CPU.ActiveCfg = Release|Any CPU 63 | {84CECEFA-6313-4CC7-8785-ACBDD0C64CCA}.Release|Any CPU.Build.0 = Release|Any CPU 64 | {09FBBFBB-1257-483A-BEB3-99939F249C27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 65 | {09FBBFBB-1257-483A-BEB3-99939F249C27}.Release|Any CPU.ActiveCfg = Release|Any CPU 66 | {3E707A29-8AB4-42B7-8BF5-FC93A9C95CFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 67 | {3E707A29-8AB4-42B7-8BF5-FC93A9C95CFA}.Debug|Any CPU.Build.0 = Debug|Any CPU 68 | {3E707A29-8AB4-42B7-8BF5-FC93A9C95CFA}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {3E707A29-8AB4-42B7-8BF5-FC93A9C95CFA}.Release|Any CPU.Build.0 = Release|Any CPU 70 | EndGlobalSection 71 | GlobalSection(SolutionProperties) = preSolution 72 | HideSolutionNode = FALSE 73 | EndGlobalSection 74 | GlobalSection(ExtensibilityGlobals) = postSolution 75 | SolutionGuid = {A1B504BD-A21A-4EE4-A378-6AF1D6CF319F} 76 | EndGlobalSection 77 | EndGlobal 78 | -------------------------------------------------------------------------------- /EmpyrionScripting/CsHelper/BlockHelpers.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.CustomHelpers; 3 | using EmpyrionScripting.DataWrapper; 4 | using EmpyrionScripting.Interface; 5 | using System.Linq; 6 | 7 | namespace EmpyrionScripting.CsHelper 8 | { 9 | public partial class CsScriptFunctions 10 | { 11 | public IBlockData[] Devices(IStructureData structure, string names) => BlockHelpers.Devices(structure, names); 12 | public IBlockData[] DevicesOfType(IStructureData structure, DeviceTypeName deviceType) => BlockHelpers.DevicesOfType(structure, deviceType); 13 | public IBlockData Block(IStructureData structure, int x, int y, int z) => new BlockData(structure.E, new Eleon.Modding.VectorInt3(x, y, z)); 14 | public T[] GetDevices(IStructureData structure, string names) where T : class, IDevice 15 | => BlockHelpers.Devices(structure, names) 16 | .OfType() 17 | .Select(B => B?.GetStructure()?.GetDevice(B.Position)) 18 | .Where(B => B != null) 19 | .ToArray(); 20 | public T[] GetDevices(params IBlockData[] block) where T : class, IDevice 21 | => block.OfType() 22 | .Select(B => B?.GetStructure()?.GetDevice(B.Position)) 23 | .Where(B => B != null) 24 | .ToArray(); 25 | 26 | public (IBlockData B, T D)[] GetBlockDevices(IStructureData structure, string names) where T : class, IDevice 27 | => BlockHelpers.Devices(structure, names) 28 | .OfType() 29 | .Select(B => (B: (IBlockData)B, D: B?.GetStructure()?.GetDevice(B.Position))) 30 | .Where(B => B.D != null) 31 | .ToArray(); 32 | public (IBlockData B, T D)[] GetBlockDevices(params IBlockData[] block) where T : class, IDevice 33 | => block.OfType() 34 | .Select(B => (B: (IBlockData)B, D: B?.GetStructure()?.GetDevice(B.Position))) 35 | .Where(B => B.D != null) 36 | .ToArray(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /EmpyrionScripting/CsHelper/ConsoleMock.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | using EmpyrionScripting.Internal.Interface; 3 | 4 | namespace EmpyrionScripting.CsHelper 5 | { 6 | public class ConsoleMock : IConsoleMock 7 | { 8 | IScriptRootData Root { get; } 9 | 10 | public ConsoleMock(IScriptRootData root){ Root = root; } 11 | 12 | public void Write(string value) => Root.ScriptOutput?.Write(value); 13 | public void Write(object value) => Root.ScriptOutput?.Write(value); 14 | public void Write(ulong value) => Root.ScriptOutput?.Write(value); 15 | public void Write(long value) => Root.ScriptOutput?.Write(value); 16 | public void Write(int value) => Root.ScriptOutput?.Write(value); 17 | public void Write(uint value) => Root.ScriptOutput?.Write(value); 18 | public void Write(bool value) => Root.ScriptOutput?.Write(value); 19 | public void Write(char value) => Root.ScriptOutput?.Write(value); 20 | public void Write(decimal value) => Root.ScriptOutput?.Write(value); 21 | public void Write(float value) => Root.ScriptOutput?.Write(value); 22 | public void Write(double value) => Root.ScriptOutput?.Write(value); 23 | public void Write(string format, params object[] arg) => Root.ScriptOutput?.WriteLine(format, arg); 24 | public void Write(char[] buffer) => Root.ScriptOutput?.WriteLine(buffer); 25 | public void Write(char[] buffer, int index, int count) => Root.ScriptOutput?.WriteLine(buffer, index, count); 26 | 27 | public void WriteLine() => Root.ScriptOutput?.WriteLine(); 28 | public void WriteLine(float value) => Root.ScriptOutput?.WriteLine(value); 29 | public void WriteLine(int value) => Root.ScriptOutput?.WriteLine(value); 30 | public void WriteLine(uint value) => Root.ScriptOutput?.WriteLine(value); 31 | public void WriteLine(long value) => Root.ScriptOutput?.WriteLine(value); 32 | public void WriteLine(ulong value) => Root.ScriptOutput?.WriteLine(value); 33 | public void WriteLine(object value) => Root.ScriptOutput?.WriteLine(value); 34 | public void WriteLine(string value) => Root.ScriptOutput?.WriteLine(value); 35 | public void WriteLine(decimal value) => Root.ScriptOutput?.WriteLine(value); 36 | public void WriteLine(char value) => Root.ScriptOutput?.WriteLine(value); 37 | public void WriteLine(bool value) => Root.ScriptOutput?.WriteLine(value); 38 | public void WriteLine(double value) => Root.ScriptOutput?.WriteLine(value); 39 | public void WriteLine(string format, params object[] arg) => Root.ScriptOutput?.WriteLine(format, arg); 40 | public void WriteLine(char[] buffer, int index, int count) => Root.ScriptOutput?.WriteLine(buffer, index, count); 41 | public void WriteLine(char[] buffer) => Root.ScriptOutput?.WriteLine(buffer); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /EmpyrionScripting/CsHelper/ConveyorHelpers.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.CustomHelpers; 2 | using EmpyrionScripting.Interface; 3 | using EmpyrionScripting.Internal.Interface; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace EmpyrionScripting.CsHelper 8 | { 9 | public partial class CsScriptFunctions : ICsScriptFunctions 10 | { 11 | public IList Move(IItemsData item, IStructureData structure, string names, int? maxLimit = null) => ConveyorHelpers.Move(ScriptRoot as IScriptRootData, item, structure, names, maxLimit); 12 | public IList Fill(IItemsData item, IStructureData structure, StructureTankType type, int? maxLimit = null) => ConveyorHelpers.Fill(ScriptRoot as IScriptRootData, item, structure, type, maxLimit ?? 100); 13 | public bool IsLocked(IStructureData structure, IBlockData block) => ScriptRoot.GetCurrentPlayfield().IsStructureDeviceLocked(structure.GetCurrent().Id, block.Position); 14 | public void WithLockedDevice(IStructureData structure, IBlockData block, Action action, Action lockFailed = null) 15 | { 16 | using (var locked = ConveyorHelpers.CreateWeakDeviceLock(ScriptRoot as IScriptRootData, ScriptRoot.GetCurrentPlayfield(), structure.GetCurrent(), block.Position)) 17 | { 18 | if (locked.Success) action(); 19 | else lockFailed?.Invoke(); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /EmpyrionScripting/CsHelper/CsScriptFunctions.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | using EmpyrionScripting.Internal.Interface; 3 | using System; 4 | 5 | namespace EmpyrionScripting.CsHelper 6 | { 7 | public partial class CsScriptFunctions : ICsScriptRootFunctions 8 | { 9 | public IScriptRootModData ScriptRoot { get; set; } 10 | 11 | public IScriptModData Root => ScriptRoot; 12 | 13 | public CsScriptFunctions(IScriptRootData root){ ScriptRoot = root; } 14 | 15 | public bool FunctionNeedsMainThread(Exception error) => FunctionNeedsMainThread(error, ScriptRoot); 16 | 17 | public static bool FunctionNeedsMainThread(Exception error, object rootObject) 18 | { 19 | if (string.IsNullOrEmpty(error?.Message) || error.Message.IndexOf("can only be called from the main thread", StringComparison.InvariantCultureIgnoreCase) == -1) return false; 20 | if (rootObject is IScriptModData root) 21 | { 22 | if (root.ScriptWithinMainThread) return false; 23 | root.ScriptNeedsMainThread = true; 24 | return true; 25 | } 26 | else return false; 27 | } 28 | 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /EmpyrionScripting/CsHelper/DialogHelpers.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.CustomHelpers; 3 | using EmpyrionScripting.Interface; 4 | using System; 5 | using System.Linq; 6 | 7 | namespace EmpyrionScripting.CsHelper 8 | { 9 | public partial class CsScriptFunctions : ICsScriptFunctions 10 | { 11 | public bool ShowDialog(int playerId, DialogConfig dialogConfig, DialogActionHandler actionHandler, int customValue) 12 | { 13 | try 14 | { 15 | var playerData = Root.IsElevatedScript 16 | ? (Root.GetCurrentPlayfield().Players.TryGetValue(playerId, out var plainPlayer) ? new DataWrapper.PlayerData(Root.GetCurrentPlayfield(), plainPlayer) : null) 17 | : Root.E.S.Players.FirstOrDefault(P => P.Id == playerId); 18 | 19 | if (playerData == null) return false; 20 | 21 | return EmpyrionScripting.ModApi.Application.ShowDialogBox(playerId, dialogConfig, actionHandler, customValue); 22 | } 23 | catch (Exception error) 24 | { 25 | if (!FunctionNeedsMainThread(error, Root)) Console.WriteLine("{{ShowDialog}} error " + EmpyrionScripting.ErrorFilter(error)); 26 | return false; 27 | } 28 | } 29 | 30 | public bool ShowDialog(string signalNames, DialogConfig dialogConfig, DialogActionHandler actionHandler, int customValue) 31 | { 32 | try 33 | { 34 | var playerId = 0; 35 | 36 | var uniqueNames = Root.SignalEventStore.GetEvents().Keys.GetUniqueNames(signalNames).ToDictionary(N => N); 37 | var signals = Root.SignalEventStore.GetEvents() 38 | .Where(S => uniqueNames.ContainsKey(S.Key)) 39 | .Select(S => S.Value.LastOrDefault()) 40 | .Where(S => S != null) 41 | .ToArray(); 42 | 43 | if (signals.All(S => !S.State)) 44 | { 45 | Root.GetPersistendData().TryRemove($"DialogTo{Root.ScriptId}", out var _); 46 | return false; 47 | } 48 | else playerId = signals.FirstOrDefault(S => S.State)?.TriggeredByEntityId ?? 0; 49 | 50 | var playerData = Root.IsElevatedScript 51 | ? (Root.GetCurrentPlayfield().Players.TryGetValue(playerId, out var plainPlayer) ? new DataWrapper.PlayerData(Root.GetCurrentPlayfield(), plainPlayer) : null) 52 | : Root.E.S.Players.FirstOrDefault(P => P.Id == playerId); 53 | 54 | if (playerData == null) return false; 55 | 56 | var running = (bool)Root.GetPersistendData().GetOrAdd($"DialogTo{Root.ScriptId}", false); 57 | if (running) return false; 58 | 59 | var success = EmpyrionScripting.ModApi.Application.ShowDialogBox(playerId, dialogConfig, actionHandler, customValue); 60 | 61 | if (success) Root.GetPersistendData().AddOrUpdate($"DialogTo{Root.ScriptId}", true, (key, value) => true); 62 | 63 | return success; 64 | } 65 | catch (Exception error) 66 | { 67 | if (!FunctionNeedsMainThread(error, Root)) Console.WriteLine("{{ShowDialog}} error " + EmpyrionScripting.ErrorFilter(error)); 68 | return false; 69 | } 70 | } 71 | 72 | public bool ShowDialog(string signalNames, Func dialogConfig, DialogActionHandler actionHandler, int customValue) 73 | { 74 | try 75 | { 76 | var playerId = 0; 77 | 78 | var uniqueNames = Root.SignalEventStore.GetEvents().Keys.GetUniqueNames(signalNames).ToDictionary(N => N); 79 | var signals = Root.SignalEventStore.GetEvents() 80 | .Where(S => uniqueNames.ContainsKey(S.Key)) 81 | .Select(S => S.Value.LastOrDefault()) 82 | .Where(S => S != null) 83 | .ToArray(); 84 | 85 | if (signals.All(S => !S.State)) 86 | { 87 | Root.GetPersistendData().TryRemove($"DialogTo{Root.ScriptId}", out var _); 88 | return false; 89 | } 90 | else playerId = signals.FirstOrDefault(S => S.State)?.TriggeredByEntityId ?? 0; 91 | 92 | var playerData = Root.IsElevatedScript 93 | ? (Root.GetCurrentPlayfield().Players.TryGetValue(playerId, out var plainPlayer) ? new DataWrapper.PlayerData(Root.GetCurrentPlayfield(), plainPlayer) : null) 94 | : Root.E.S.Players.FirstOrDefault(P => P.Id == playerId); 95 | 96 | if (playerData == null) return false; 97 | 98 | var running = (bool)Root.GetPersistendData().GetOrAdd($"DialogTo{Root.ScriptId}", false); 99 | if (running) return false; 100 | 101 | var success = EmpyrionScripting.ModApi.Application.ShowDialogBox(playerId, dialogConfig(playerData), actionHandler, customValue); 102 | 103 | if (success) Root.GetPersistendData().AddOrUpdate($"DialogTo{Root.ScriptId}", true, (key, value) => true); 104 | 105 | return success; 106 | } 107 | catch (Exception error) 108 | { 109 | if (!FunctionNeedsMainThread(error, Root)) Console.WriteLine("{{ShowDialog}} error " + EmpyrionScripting.ErrorFilter(error)); 110 | return false; 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /EmpyrionScripting/CsHelper/EffectHelpers.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.CustomHelpers; 2 | using EmpyrionScripting.Internal.Interface; 3 | using System.Collections.Generic; 4 | 5 | namespace EmpyrionScripting.CsHelper 6 | { 7 | public partial class CsScriptFunctions 8 | { 9 | public IList Scroll(string content, int lines, int delay, int step = 1) => EffectHelpers.Scroll(ScriptRoot as IScriptRootData, content, lines, delay, step); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /EmpyrionScripting/CsHelper/EntityAccessHelpers.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.CustomHelpers; 2 | using EmpyrionScripting.DataWrapper; 3 | using EmpyrionScripting.Interface; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace EmpyrionScripting.CsHelper 8 | { 9 | public partial class CsScriptFunctions 10 | { 11 | public IEnumerable EntitiesByName(params string[] names) => EntitiesByName(string.Join(";", names)); 12 | public IEnumerable EntitiesByName(string names) => ScriptRoot.GetEntities().Where(E => new[] { E.Name }.GetUniqueNames(names).Any()).Select(E => new EntityData(ScriptRoot.GetCurrentPlayfield(), E)); 13 | public IEnumerable EntitiesById(params int[] ids) => EntitiesByName(string.Join(";", ids.ToString())); 14 | public IEnumerable EntitiesById(string ids) => ScriptRoot.GetEntities().Where(E => new[] { E.Id.ToString() }.GetUniqueNames(ids).Any()).Select(E => new EntityData(ScriptRoot.GetCurrentPlayfield(), E)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /EmpyrionScripting/CsHelper/FormatHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace EmpyrionScripting.CsHelper 5 | { 6 | public partial class CsScriptFunctions 7 | { 8 | public string I18nDefaultLanguage { get; set; } = "English"; 9 | 10 | public string I18n(int id) => I18n(id, I18nDefaultLanguage); 11 | public string I18n(int id, string language) => EmpyrionScripting.ItemInfos.ItemInfo.TryGetValue(id, out ItemInfo data) 12 | ? EmpyrionScripting.Localization.GetName(data.Key, language) 13 | : EmpyrionScripting.Localization.GetName(id.ToString(), language); 14 | 15 | public string Format(object data, string format) => string.Format(ScriptRoot.CultureInfo.CultureInfo, format, data).Replace(" ", EmpyrionScripting.Configuration.Current.NumberSpaceReplace); 16 | 17 | public string Bar(double data, double min, double max, int length, string barChar = null, string barBgChar = null) 18 | { 19 | var len = (int)(length / (max - min) * data); 20 | 21 | return string.Concat(Enumerable.Repeat(barChar ?? EmpyrionScripting.Configuration.Current.BarStandardValueSign, Math.Max(0, Math.Min(length, len)))) + 22 | string.Concat(Enumerable.Repeat(barBgChar ?? EmpyrionScripting.Configuration.Current.BarStandardSpaceSign, Math.Max(0, Math.Min(length, length - len)))); 23 | } 24 | 25 | public string ToId(string names) 26 | { 27 | var idList = names.Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries) 28 | .Select(I => EmpyrionScripting.ConfigEcfAccess.BlockIdMapping.TryGetValue(I.Trim(), out var id) ? id : 0) 29 | .Where(I => I != 0) 30 | .ToArray(); 31 | 32 | return idList.Aggregate((string)null, (n, i) => n == null ? i.ToString() : $"{n};{i}"); 33 | } 34 | 35 | public string ToName(string ids) 36 | { 37 | var idList = ids.Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries) 38 | .Select(I => int.TryParse(I, out var id) ? EmpyrionScripting.ConfigEcfAccess.IdBlockMapping.TryGetValue(id, out var name) ? name : null : null) 39 | .Where(I => !string.IsNullOrEmpty(I)) 40 | .ToArray(); 41 | 42 | return idList.Aggregate((string)null, (n, i) => n == null ? i.ToString() : $"{n};{i}"); 43 | } 44 | 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /EmpyrionScripting/CsHelper/ItemAccessHelpers.cs: -------------------------------------------------------------------------------- 1 | using EcfParser; 2 | using EmpyrionScripting.CustomHelpers; 3 | using EmpyrionScripting.Interface; 4 | using EmpyrionScripting.Internal.Interface; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace EmpyrionScripting.CsHelper 9 | { 10 | public partial class CsScriptFunctions 11 | { 12 | public IItemsData[] Items(IStructureData structure, string names) => ItemAccessHelpers.Items(ScriptRoot as IScriptRootData, structure, names); 13 | 14 | public object ConfigFindAttribute(int id, string name) => EmpyrionScripting.ConfigEcfAccess.FindAttribute(id, name); 15 | public int ConfigId(string name) => EmpyrionScripting.ConfigEcfAccess.FlatConfigBlockByName.TryGetValue(name, out var config) ? (int)config.Attr?.FirstOrDefault(A => A.Name == "Id")?.Value : 0; 16 | public EcfBlock ConfigById(int id) => EmpyrionScripting.ConfigEcfAccess.FlatConfigBlockById.TryGetValue(id, out var block) ? block : null; 17 | public EcfBlock ConfigByName(string name) => EmpyrionScripting.ConfigEcfAccess.FlatConfigBlockByName.TryGetValue(name, out var block) ? block : null; 18 | public Dictionary ResourcesForBlockById(int id) => EmpyrionScripting.ConfigEcfAccess.ResourcesForBlockById.TryGetValue(id, out var recipe) ? recipe : null; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /EmpyrionScripting/CustomHelpers/DBAccessHelpers.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.CsHelper; 2 | using EmpyrionScripting.Interface; 3 | using HandlebarsDotNet; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | 8 | namespace EmpyrionScripting.CustomHelpers 9 | { 10 | [HandlebarHelpers] 11 | public class DBAccessHelpers 12 | { 13 | 14 | [HandlebarTag("db")] 15 | public static void DBAccessBlockHelper(TextWriter output, object rootObject, HelperOptions options, dynamic context, object[] arguments) 16 | { 17 | if (arguments.Length == 0) throw new HandlebarsException("{{db queryname [top] [orderBy] [additionalWhereAnd] [parameters]}} helper must have least one argument: (queryname)"); 18 | 19 | var root = rootObject as IScriptModData; 20 | var queryName = arguments.Get(0)?.ToString(); 21 | if (!int.TryParse(arguments.Get(1)?.ToString(), out var top)) top = 100; 22 | var orderBy = arguments.Get(2)?.ToString(); 23 | var additionalWhereAnd = arguments.Get(3)?.ToString(); 24 | 25 | try 26 | { 27 | var parameter = new Dictionary() 28 | { 29 | { "@PlayerId", root.E.S.Pilot.Id }, 30 | { "@FactionId", root.E.Faction.Id }, 31 | { "@FactionGroup", (int) root.E.Faction.Group }, 32 | { "@EntityId", root.E.Id }, 33 | }; 34 | 35 | for (int i = 4; i < arguments.Length; i++) parameter.Add($"@{i-3}", arguments[i]); 36 | 37 | var result = EmpyrionScripting.SqlDbAccess.ReadData(queryName, root.IsElevatedScript, top, orderBy, additionalWhereAnd, parameter); 38 | 39 | if (result.Count > 0) options.Template(output, result); 40 | else options.Inverse (output, context as object); 41 | } 42 | catch (Exception error) 43 | { 44 | if (!CsScriptFunctions.FunctionNeedsMainThread(error, root)) output.Write("{{db}} error " + EmpyrionScripting.ErrorFilter(error)); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /EmpyrionScripting/CustomHelpers/HelpersTools.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | 8 | namespace EmpyrionScripting.CustomHelpers 9 | { 10 | public static class HelpersTools 11 | { 12 | public static IEnumerable GetUniqueNames(this IEnumerable sourceNames, string namesSearch) 13 | { 14 | return sourceNames.GetUniqueNames(namesSearch, new[] { ';', ',' }); 15 | } 16 | 17 | public static IEnumerable GetUniqueNames(this IEnumerable sourceNames, string namesSearch, char[] delimitter) 18 | { 19 | var names = new List(); 20 | 21 | namesSearch 22 | .Split(delimitter, StringSplitOptions.RemoveEmptyEntries) 23 | .Select(N => N.Trim()) 24 | .ForEach(N => 25 | { 26 | if (N == "*") names.AddRange(sourceNames); 27 | else if (N.EndsWith("*") && N.StartsWith("*")) 28 | { 29 | var contains = N.Substring(1, N.Length - 2).ToLower(); 30 | names.AddRange(sourceNames.Where(SN => SN.ToLower().Contains(contains))); 31 | names.AddRange(sourceNames.Where(SN => SN.ToLower().Equals(contains, StringComparison.InvariantCultureIgnoreCase))); 32 | } 33 | else if (N.EndsWith("*")) 34 | { 35 | var startsWith = N.Substring(0, N.Length - 1).ToLower(); 36 | names.AddRange(sourceNames.Where(SN => SN.ToLower().StartsWith(startsWith, StringComparison.InvariantCultureIgnoreCase))); 37 | names.AddRange(sourceNames.Where(SN => SN.ToLower().Equals(startsWith, StringComparison.InvariantCultureIgnoreCase))); 38 | } 39 | else if (N.StartsWith("*")) 40 | { 41 | var endsWith = N.Substring(1).ToLower(); 42 | names.AddRange(sourceNames.Where(SN => SN.ToLower().EndsWith(endsWith, StringComparison.InvariantCultureIgnoreCase))); 43 | names.AddRange(sourceNames.Where(SN => SN.ToLower().Equals(endsWith, StringComparison.InvariantCultureIgnoreCase))); 44 | } 45 | else 46 | { 47 | var equal = N.ToLower(); 48 | names.AddRange(sourceNames.Where(SN => SN.ToLower().Equals(equal, StringComparison.InvariantCultureIgnoreCase))); 49 | } 50 | }); 51 | 52 | return names 53 | .OrderBy(N => N) 54 | .Distinct() 55 | .ToArray(); 56 | } 57 | 58 | public static IEnumerable TakeLast(this IEnumerable source, int N) 59 | { 60 | return source.Skip(Math.Max(0, source.Count() - N)); 61 | } 62 | 63 | public class FileContent { 64 | public string[] Lines { get; set; } 65 | public string Text { get; set; } 66 | public FileSystemWatcher Watcher { get; set; } 67 | } 68 | 69 | static readonly ConcurrentDictionary FileContentCache = new ConcurrentDictionary(); 70 | 71 | public static FileContent GetFileContent(string filename) 72 | { 73 | try 74 | { 75 | if (FileContentCache.TryGetValue(filename, out var filecontent)) return filecontent; 76 | if (!File.Exists(filename)) return null; 77 | 78 | filecontent = new FileContent() 79 | { 80 | Lines = File.ReadAllLines(filename), 81 | Text = File.ReadAllText(filename), 82 | Watcher = new FileSystemWatcher(Path.GetDirectoryName(filename), Path.GetFileName(filename)) 83 | }; 84 | filecontent.Watcher.Renamed += (S, A) => { filecontent.Watcher.EnableRaisingEvents = false; FileContentCache.TryRemove(filename, out var _); }; 85 | filecontent.Watcher.Changed += (S, A) => { filecontent.Watcher.EnableRaisingEvents = false; FileContentCache.TryRemove(filename, out var _); }; 86 | filecontent.Watcher.Deleted += (S, A) => { filecontent.Watcher.EnableRaisingEvents = false; FileContentCache.TryRemove(filename, out var _); }; 87 | filecontent.Watcher.Created += (S, A) => { filecontent.Watcher.EnableRaisingEvents = false; FileContentCache.TryRemove(filename, out var _); }; 88 | filecontent.Watcher.EnableRaisingEvents = true; 89 | 90 | FileContentCache.AddOrUpdate(filename, filecontent, (S, O) => filecontent); 91 | return filecontent; 92 | } 93 | catch (Exception error) 94 | { 95 | EmpyrionScripting.Log($"Filename: {filename} => {error}", EmpyrionNetAPIDefinitions.LogLevel.Message); 96 | return null; 97 | } 98 | } 99 | 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/ContainerData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | 3 | namespace EmpyrionScripting.DataWrapper 4 | { 5 | public class ContainerData 6 | { 7 | private IContainer _container; 8 | 9 | public ContainerData(IContainer container) 10 | { 11 | _container = container; 12 | } 13 | 14 | public IContainer GetContainer() => _container; 15 | 16 | public float VolumeCapacity => _container.VolumeCapacity; 17 | public float DecayFactor => _container.DecayFactor; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/ContainerSource.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.Interface; 3 | 4 | namespace EmpyrionScripting.DataWrapper 5 | { 6 | public class ContainerSource : IContainerSource 7 | { 8 | public IEntityData E { get; set; } 9 | public IContainer Container { get; set; } 10 | public string CustomName { get; set; } 11 | public VectorInt3 Position { get; set; } 12 | public float VolumeCapacity => Container.VolumeCapacity; 13 | public float DecayFactor => Container.DecayFactor; 14 | public int MaxSlots { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/EventStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using Eleon.Modding; 5 | using EmpyrionScripting.Interface; 6 | 7 | namespace EmpyrionScripting.DataWrapper 8 | { 9 | public sealed class EventStore : IDisposable, IEventStore 10 | { 11 | readonly IEntity _Entity; 12 | readonly ConcurrentDictionary> _Events = new ConcurrentDictionary>(); 13 | 14 | public EventStore(IEntity entity) 15 | { 16 | _Entity = entity; 17 | if (_Entity?.Structure != null) _Entity.Structure.SignalChanged += Structure_SignalChanged; 18 | } 19 | 20 | public ConcurrentDictionary> GetEvents() => _Events; 21 | 22 | private void Structure_SignalChanged(string name, bool newState, int triggeringEntityId) 23 | { 24 | ISignalEventBase e = new SignalEventBase() 25 | { 26 | Name = name, 27 | TimeStamp = DateTime.UtcNow, 28 | State = newState, 29 | TriggeredByEntityId = triggeringEntityId, 30 | }; 31 | 32 | GetEvents().AddOrUpdate(name, N => new List() { e }, (N, L) => 33 | { 34 | L.Add(e); 35 | if (L.Count > EmpyrionScripting.Configuration?.Current?.MaxStoredEventsPerSignal) L.RemoveAt(0); 36 | return L; 37 | }); 38 | } 39 | 40 | public void Dispose() 41 | { 42 | if (_Entity?.Structure != null) _Entity.Structure.SignalChanged -= Structure_SignalChanged; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/HarvestInfo.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | 3 | namespace EmpyrionScripting 4 | { 5 | public class HarvestInfo : IHarvestInfo 6 | { 7 | public int Id { get; set; } 8 | public string Name { get; set; } 9 | public int DropOnHarvestId { get; set; } 10 | public string DropOnHarvestItem { get; set; } 11 | public int DropOnHarvestCount { get; set; } 12 | public int ChildOnHarvestId { get; set; } 13 | public string ChildOnHarvestItem { get; set; } 14 | public int PickupTargetId { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/ItemTokenAccess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Eleon.Modding; 5 | 6 | namespace EmpyrionScripting 7 | { 8 | public static class ItemTokenAccess 9 | { 10 | public static Lazy> TokenItemIds { get; } = new Lazy>(() => 11 | EmpyrionScripting.ConfigEcfAccess?.FlatConfigBlockById 12 | .Where(B => B.Value.Values?.TryGetValue("Class", out var classType) == true && classType.ToString() == "Token") 13 | .Select(B => B.Key) 14 | .ToHashSet() 15 | ); 16 | 17 | public static int TokenIdSeperator = 100000; 18 | 19 | public static int ItemId(this int itemId) => itemId % TokenIdSeperator; 20 | public static int TokenId(this int itemId) => itemId / TokenIdSeperator; 21 | public static bool IsToken(this int itemId) => itemId >= TokenIdSeperator; 22 | 23 | public static int CreateId(this ItemStack item) 24 | => TokenItemIds.Value.Contains(item.id) 25 | ? item.id + item.ammo * TokenIdSeperator 26 | : item.id; 27 | } 28 | } -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/ItemsData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Eleon.Modding; 4 | using EmpyrionScripting.Interface; 5 | 6 | namespace EmpyrionScripting.DataWrapper 7 | { 8 | public class ItemBase : IItemBase 9 | { 10 | public int Id { get; set; } 11 | public int ItemId => Id % ItemTokenAccess.TokenIdSeperator; 12 | public int TokenId => Id / ItemTokenAccess.TokenIdSeperator; 13 | public bool IsToken => Id > ItemTokenAccess.TokenIdSeperator; 14 | } 15 | 16 | public class ItemsSource : ItemBase, IItemsSource 17 | { 18 | public IEntityData E { get; set; } 19 | public IContainer Container { get; set; } 20 | public VectorInt3 Position { get; set; } 21 | public string CustomName { get; set; } 22 | public int Count { get; set; } 23 | public int Ammo { get; set; } 24 | public int Decay { get; set; } 25 | public int MaxSlots { get; set; } 26 | } 27 | 28 | public class ItemsData : ItemBase, IItemsData 29 | { 30 | public int Count { get; set; } 31 | public string Name { get; set; } 32 | public string Key { get; set; } 33 | public List Source { get; set; } 34 | public int Ammo { get; set; } 35 | public int Decay { get; set; } 36 | 37 | public ItemsData AddCount(int count, IItemsSource source) 38 | { 39 | if (Source == null) Source = new List(); 40 | if (source == null) return this; 41 | 42 | lock (Source) 43 | { 44 | Source.Add(source); 45 | Count += count; 46 | } 47 | return this; 48 | } 49 | } 50 | 51 | public static class ItemStackExtensions{ 52 | public static List UniqueSlots(this IEnumerable items) 53 | { 54 | byte index = 0; 55 | return items.Select(i => new ItemStack(i.id, i.count) { slotIdx = index++, decay = i.decay, ammo = i.ammo }).ToList(); 56 | } 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/PlayfieldData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Linq; 4 | using Eleon.Modding; 5 | using EmpyrionScripting.Interface; 6 | using YamlDotNet.Serialization; 7 | using System.IO; 8 | using EmpyrionScripting.CustomHelpers; 9 | 10 | namespace EmpyrionScripting.DataWrapper 11 | { 12 | public class PlayfieldDetails : IPlayfieldDetails 13 | { 14 | public string PlayfieldType { get; set; } 15 | public string PlanetType { get; set; } 16 | public int PlanetSize { get; set; } 17 | public double PlanetAxis { get; set; } 18 | public string Description 19 | { 20 | get => _Description; 21 | set => _Description = value?.FormatToHtml(); 22 | } 23 | string _Description; 24 | 25 | public double Gravity { get; set; } 26 | public int[] TemperatureMinMax { get; set; } 27 | public int TemperatureDay { get; set; } 28 | public int TemperatureMin => TemperatureMinMax == null || TemperatureMinMax.Length == 0 ? TemperatureDay : TemperatureMinMax.FirstOrDefault(); 29 | public int TemperatureMax => TemperatureMinMax == null || TemperatureMinMax.Length == 0 ? TemperatureDay : TemperatureMinMax.LastOrDefault(); 30 | public bool AtmosphereBreathable { get; set; } 31 | public double AtmosphereO2 { get; set; } 32 | public double AtmosphereDensity { get; set; } 33 | public double Radiation { get; set; } 34 | 35 | } 36 | 37 | 38 | public class PlayfieldData : IPlayfieldData 39 | { 40 | static ConcurrentDictionary playfieldInfos = new ConcurrentDictionary(); 41 | static IDeserializer yamlDeserializer { get; } = new DeserializerBuilder() 42 | .IgnoreUnmatchedProperties() 43 | .Build(); 44 | 45 | private IPlayfield playfield; 46 | 47 | public PlayfieldData() 48 | { 49 | } 50 | public PlayfieldData(IPlayfield playfield) 51 | { 52 | this.playfield = playfield; 53 | } 54 | 55 | public IPlayfield GetCurrent() => playfield; 56 | 57 | public string Name => playfield.Name; 58 | public string PlayfieldType => playfield.PlayfieldType; 59 | public string PlanetType => playfield.PlanetType; 60 | public string PlanetClass => playfield.PlanetClass; 61 | public bool IsPvP => playfield.IsPvP; 62 | 63 | public IPlayfieldDetails Details => playfieldInfos.GetOrAdd(Name, ReadPlayfieldInfo); 64 | 65 | public static PlayfieldDetails ReadPlayfieldInfo(string playfieldName) 66 | { 67 | try 68 | { 69 | return yamlDeserializer.Deserialize(File.ReadAllText(Path.Combine(EmpyrionScripting.SaveGameModPath, "..", "..", "Templates", playfieldName, "playfield.yaml"))); 70 | } 71 | catch (Exception error) 72 | { 73 | EmpyrionScripting.Log($"ReadPlayfieldInfo:{playfieldName} -> {error}", EmpyrionNetAPIDefinitions.LogLevel.Message); 74 | return null; 75 | } 76 | } 77 | 78 | public VectorInt3 SolarSystemCoordinates => playfield.SolarSystemCoordinates; 79 | public string SolarSystemName => playfield.SolarSystemName; 80 | 81 | public float GetTerrainHeightAt(float x, float z) => playfield.GetTerrainHeightAt(x, z); 82 | 83 | public ILimitedPlayerData[] Players => _p == null ? _p = playfield.Players.Values.Select(P => new LimitedPlayerData(P)).ToArray() : _p; 84 | 85 | ILimitedPlayerData[] _p; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/ScriptSaveGameRootData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.Interface; 3 | using System.Collections.Concurrent; 4 | using System.Reflection; 5 | 6 | namespace EmpyrionScripting.DataWrapper 7 | { 8 | public class ScriptSaveGameRootData : ScriptRootData, IScriptSaveGameRootData 9 | { 10 | public ScriptSaveGameRootData() : base() 11 | { 12 | } 13 | public ScriptSaveGameRootData(ScriptSaveGameRootData data) : base(data) 14 | { 15 | MainMethod = data.MainMethod; 16 | ModApi = data.ModApi; 17 | ScriptPath = data.ScriptPath; 18 | MainScriptPath = data.MainScriptPath; 19 | } 20 | public ScriptSaveGameRootData( 21 | PlayfieldScriptData playfieldScriptData, 22 | IEntity[] allEntities, 23 | IEntity[] currentEntities, 24 | IPlayfield playfield, 25 | IEntity entity, 26 | ConcurrentDictionary persistendData, 27 | EventStore eventStore) : base(playfieldScriptData, allEntities, currentEntities, playfield, entity, persistendData, eventStore) 28 | { 29 | } 30 | 31 | public MethodInfo MainMethod { get; set; } 32 | public string ScriptPath { get; set; } 33 | public string MainScriptPath { get; set; } 34 | public IModApi ModApi { get; set; } 35 | 36 | public override bool DeviceLockAllowed => true; 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/SignalData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.Interface; 3 | 4 | namespace EmpyrionScripting.DataWrapper 5 | { 6 | public class SignalData : ISignalData 7 | { 8 | private readonly SenderSignal _Signal; 9 | private readonly IStructureData _Structure; 10 | bool? currentState; 11 | 12 | public SignalData(IStructureData structure, SenderSignal signal) 13 | { 14 | _Signal = signal; 15 | _Structure = structure; 16 | } 17 | 18 | public SenderSignal GetCurrent() => _Signal; 19 | 20 | public string Name => _Signal.Name; 21 | public int Index => _Signal.Index; 22 | public VectorInt3? BlockPos => _Signal.BlockPos; 23 | public bool State => currentState.HasValue ? currentState.Value : (currentState = _Structure.GetCurrent().GetSignalState(_Signal.Name)).Value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/SignalEvent.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.Interface; 3 | 4 | namespace EmpyrionScripting.DataWrapper 5 | { 6 | public class SignalEvent : SignalEventBase 7 | { 8 | private readonly IPlayfield _CurrentPlayfield; 9 | public SignalEvent(IPlayfield playfield, SignalEventBase signalBase) : base(signalBase) { 10 | _CurrentPlayfield = playfield; 11 | } 12 | 13 | public IEntityData TriggeredByShip => _CurrentPlayfield.Entities.TryGetValue(TriggeredByEntityId, out var entity) ? (entity.Type != EntityType.Player ? new EntityData(_CurrentPlayfield, entity, true) : null) : null; 14 | public LimitedPlayerData TriggeredByPlayer => _CurrentPlayfield.Players.TryGetValue(TriggeredByEntityId, out var player) ? new LimitedPlayerData(player) : null; 15 | } 16 | } -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/SignalEventBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EmpyrionScripting.Interface; 3 | 4 | namespace EmpyrionScripting.DataWrapper 5 | { 6 | public class SignalEventBase : ISignalEventBase 7 | { 8 | 9 | public SignalEventBase() { } 10 | 11 | public SignalEventBase(SignalEventBase signalBase) 12 | { 13 | Name = signalBase.Name; 14 | TimeStamp = signalBase.TimeStamp; 15 | State = signalBase.State; 16 | TriggeredByEntityId = signalBase.TriggeredByEntityId; 17 | } 18 | 19 | public string Name { get; set; } 20 | public DateTime TimeStamp { get; set; } 21 | public bool State { get; set; } 22 | public int TriggeredByEntityId { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/SignalEventElevated.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.Interface; 3 | 4 | namespace EmpyrionScripting.DataWrapper 5 | { 6 | public class SignalEventElevated : SignalEventBase 7 | { 8 | private readonly IPlayfield _CurrentPlayfield; 9 | 10 | public SignalEventElevated(IPlayfield playfield, SignalEventBase signalBase) : base(signalBase) { 11 | _CurrentPlayfield = playfield; 12 | } 13 | public IEntityData TriggeredByShip => _CurrentPlayfield.Entities.TryGetValue(TriggeredByEntityId, out var entity) ? new EntityData(_CurrentPlayfield, entity, false) : null; 14 | public PlayerData TriggeredByPlayer => _CurrentPlayfield.Players.TryGetValue(TriggeredByEntityId, out var player) ? new PlayerData(_CurrentPlayfield, player) : null; 15 | 16 | } 17 | } -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/StructureTank.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.Interface; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace EmpyrionScripting.DataWrapper 8 | { 9 | public class StructureTank : IStructureTankWrapper 10 | { 11 | private readonly IStructureTank tank; 12 | private readonly StructureTankType type; 13 | 14 | public Dictionary AllowedItems { get; } 15 | 16 | public StructureTank(IStructureTank tank, StructureTankType type) 17 | { 18 | this.tank = tank; 19 | this.type = type; 20 | AllowedItems = EmpyrionScripting.Configuration.Current.StructureTank[type].ToDictionary(I => I.ItemId, I => I.Amount); 21 | } 22 | 23 | public float Capacity => tank == null ? 0 : tank.Capacity; 24 | public float Content => tank == null ? 0 : tank.Content; 25 | 26 | public IStructureTank GetCurrent() => tank; 27 | 28 | public int AddItems(int itemId, int count) 29 | { 30 | if(AllowedItem(itemId)) tank?.AddContent(count * AllowedItems[itemId]); 31 | return 0; 32 | } 33 | 34 | public bool AllowedItem(int itemId) => AllowedItems.ContainsKey(itemId); 35 | 36 | public int ItemsNeededForFill(int itemId, int maxLimit) 37 | { 38 | return tank == null || !AllowedItem(itemId) ? 0 : Math.Max(0, (int)Math.Floor((Capacity * (maxLimit / 100f)) - Content) / AllowedItems[itemId]); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /EmpyrionScripting/DataWrapper/TeleporterData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.Interface; 3 | 4 | namespace EmpyrionScripting.DataWrapper 5 | { 6 | public class TeleporterData : BlockData, ITeleporterData 7 | { 8 | private ITeleporter _teleporter; 9 | private Eleon.Modding.TeleporterData _targetData; 10 | 11 | public TeleporterData(IEntityData entity, VectorInt3 pos) : base(entity, pos) 12 | { 13 | _teleporter = GetDevice() as ITeleporter; 14 | if(_teleporter != null) _targetData = _teleporter.TargetData; 15 | } 16 | 17 | public ITeleporter GetTeleporter() => _teleporter; 18 | 19 | public string DeviceName { get => Get(_targetData.TargetEntityNameOrGroup, 0); set { _targetData.TargetEntityNameOrGroup = $"{value}@{Get(_targetData.TargetEntityNameOrGroup, 1)}"; _teleporter.TargetData = _targetData; } } 20 | public string Target { get => Get(_targetData.TargetEntityNameOrGroup, 1); set { _targetData.TargetEntityNameOrGroup = $"{Get(_targetData.TargetEntityNameOrGroup, 0)}@{value}"; _teleporter.TargetData = _targetData; } } 21 | public string Playfield { get => _targetData.TargetPlayfield; set { _targetData.TargetPlayfield = value; _teleporter.TargetData = _targetData; } } 22 | public string SolarSystemName { get => _targetData.TargetSolarSystemName; set { _targetData.TargetSolarSystemName = value; _teleporter.TargetData = _targetData; } } 23 | public byte Origin { get => _targetData.Origin; set { _targetData.Origin = value; _teleporter.TargetData = _targetData; } } 24 | public string Destination { 25 | get => $"{DeviceName}@{Target}:{Playfield}" + (string.IsNullOrEmpty(SolarSystemName) ? "" : $"@{SolarSystemName}") + (Origin == 255 ? "" : $"#{Origin}"); 26 | set { 27 | var data = value?.Split('@', ':', '#'); 28 | _teleporter.TargetData = new Eleon.Modding.TeleporterData($"{data[0]}@{data[1]}", data.Length >= 4 ? data[3] : null, data[2], data.Length == 5 && byte.TryParse(data[4], out var origin) ? origin : (byte)255); 29 | } 30 | } 31 | 32 | private string Get(string target, int pos) 33 | { 34 | var data = target?.Split('@'); 35 | return data == null || data.Length < pos ? string.Empty : data[pos]; 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /EmpyrionScripting/DeviceLock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Eleon.Modding; 4 | using EmpyrionNetAPIDefinitions; 5 | using EmpyrionScripting.Internal.Interface; 6 | 7 | namespace EmpyrionScripting 8 | { 9 | public sealed class DeviceLock : IDeviceLock 10 | { 11 | readonly Action unlockAction; 12 | 13 | public DeviceLock(IScriptRootData root, IPlayfield playfield, IStructure structure, VectorInt3 position) 14 | { 15 | var witherror = false; 16 | try 17 | { 18 | if (!root.ScriptWithinMainThread) 19 | { 20 | root.ScriptNeedsMainThread = true; 21 | Exit = true; 22 | return; 23 | } 24 | 25 | if (!root.DeviceLockAllowed || root.TimeLimitReached) 26 | { 27 | Exit = true; 28 | return; 29 | } 30 | 31 | if (playfield.IsStructureDeviceLocked(structure.Id, position)) return; 32 | 33 | var lockkey = $"{structure.Id}#{position.x}#{position.y}#{position.z}"; 34 | 35 | var e = new AutoResetEvent(false); 36 | playfield.LockStructureDevice(structure.Id, position, true, (id, pos, success) => 37 | { 38 | if (id != structure.Id || pos != position) return; 39 | 40 | if (witherror) 41 | { 42 | Log($"Lock:Callback:Error {playfield.Name} {structure.Id} {position}", LogLevel.Debug); 43 | if (!playfield.IsStructureDeviceLocked(structure.Id, position)) return; 44 | 45 | playfield.LockStructureDevice(structure.Id, position, false, null); 46 | } 47 | else 48 | { 49 | Success = success; 50 | e.Set(); 51 | } 52 | }); 53 | witherror = !e.WaitOne(10000); 54 | if (witherror) Log($"Lock:WaitOne:Error {playfield.Name} {structure.Id} {position}", LogLevel.Debug); 55 | 56 | if (Success) unlockAction = () => 57 | { 58 | if (!playfield.IsStructureDeviceLocked(structure.Id, position)) return; 59 | 60 | e.Reset(); 61 | playfield.LockStructureDevice(structure.Id, position, false, (id, pos, s) => { 62 | if (id != structure.Id || pos != position) return; 63 | e.Set(); 64 | }); 65 | if (!e.WaitOne(10000)) Log($"Unlock:Timeout {playfield.Name} {structure.Id} {position}", LogLevel.Debug); 66 | }; 67 | } 68 | catch (Exception error) 69 | { 70 | witherror = true; 71 | throw new Exception($"DeviceLock:failed on Playfield:{playfield?.Name} at Id:{structure.Id} on {position} with: {error}"); 72 | } 73 | } 74 | 75 | public static Action Log { get; set; } 76 | public bool Exit { get; } 77 | public bool Success { get; private set; } 78 | 79 | public void Dispose() 80 | { 81 | unlockAction?.Invoke(); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /EmpyrionScripting/DisplayOutputConfiguration.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | 3 | namespace EmpyrionScripting 4 | { 5 | public class DisplayOutputConfiguration : IDisplayOutputConfiguration 6 | { 7 | public int Lines { get; set; } 8 | public bool AppendAtEnd { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /EmpyrionScripting/EmpyrionScripting_Info.yaml: -------------------------------------------------------------------------------- 1 | Name: EmpyrionScripting 2 | Description: Displays dynamic/real LCD stuff and allows scripted automatisation 3 | Author: ASTIC/TC 4 | Version: 11.4.1 5 | Website: https://github.com/GitHub-TC/EmpyrionScripting 6 | 7 | ModTargets: PfServer,Dedi,Client 8 | -------------------------------------------------------------------------------- /EmpyrionScripting/EntityCultureInfo.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | using Newtonsoft.Json; 3 | using System.Globalization; 4 | 5 | namespace EmpyrionScripting 6 | { 7 | public class EntityCultureInfo : IEntityCultureInfo 8 | { 9 | [JsonIgnore] 10 | public CultureInfo CultureInfo { 11 | get{ 12 | if(_CultureInfo == null) 13 | { 14 | try { _CultureInfo = CreateFormatCulture(CultureInfo.CreateSpecificCulture(LanguageTag)); } 15 | catch{ _CultureInfo = FormatCulture; } 16 | } 17 | return _CultureInfo; 18 | } 19 | set => _CultureInfo = value; 20 | } 21 | private CultureInfo _CultureInfo; 22 | 23 | public string LanguageTag { get; set; } = FormatCulture.Name; 24 | public string i18nDefault { get; set; } = "English"; 25 | public int UTCplusTimezone { get; set; } = 0; 26 | 27 | public static CultureInfo FormatCulture { get; } = CreateFormatCulture(CultureInfo.CurrentUICulture); 28 | 29 | public static CultureInfo CreateFormatCulture(CultureInfo currentUICulture) 30 | { 31 | var c = (CultureInfo)currentUICulture.Clone(); 32 | 33 | c.NumberFormat.PercentSymbol = "%"; // z.B. fr-FR benutzt ein von EGS nicht darstellbares Zeichen 34 | c.NumberFormat.PercentNegativePattern = 1; 35 | c.NumberFormat.PercentPositivePattern = 1; 36 | 37 | return c; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /EmpyrionScripting/GlobalSuppressions.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHub-TC/EmpyrionScripting/ce87e85b4a220574b76dd1b8ef019b9e362ff22d/EmpyrionScripting/GlobalSuppressions.cs -------------------------------------------------------------------------------- /EmpyrionScripting/HandlebarsHelpers.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | using HandlebarsDotNet; 3 | using System; 4 | using System.Linq; 5 | using System.Reflection; 6 | 7 | namespace EmpyrionScripting 8 | { 9 | public class HandlebarHelpersAttribute : Attribute { } 10 | 11 | public class HandlebarTagAttribute : Attribute 12 | { 13 | public HandlebarTagAttribute(string tag) 14 | { 15 | Tag = tag; 16 | } 17 | 18 | public string Tag { get; } 19 | } 20 | 21 | public static class HandlebarsHelpers 22 | { 23 | public static void ScanHandlebarHelpers() 24 | { 25 | try 26 | { 27 | var helperTypes = typeof(EmpyrionScripting).Assembly.GetTypes() 28 | .Where(T => T.GetCustomAttributes(typeof(HandlebarHelpersAttribute), true).Length > 0); 29 | 30 | helperTypes.ForEach(T => 31 | T.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public) 32 | .ForEach(M => 33 | { 34 | try 35 | { 36 | if (Attribute.GetCustomAttribute(M, typeof(HandlebarTagAttribute)) is HandlebarTagAttribute A) 37 | Handlebars.RegisterHelper(A.Tag, (HandlebarsHelper)Delegate.CreateDelegate(typeof(HandlebarsHelper), M)); 38 | } 39 | catch { } 40 | 41 | try 42 | { 43 | if (Attribute.GetCustomAttribute(M, typeof(HandlebarTagAttribute)) is HandlebarTagAttribute A) 44 | Handlebars.RegisterHelper(A.Tag, (HandlebarsBlockHelper)Delegate.CreateDelegate(typeof(HandlebarsBlockHelper), M)); 45 | } 46 | catch { } 47 | }) 48 | ); 49 | } 50 | catch (ReflectionTypeLoadException error) 51 | { 52 | Console.WriteLine(error.Message + error.LoaderExceptions.Aggregate("\n", (e, s) => $"{s}{e}\n")); 53 | } 54 | } 55 | 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /EmpyrionScripting/IdLists.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace EmpyrionScripting 8 | { 9 | public class IdLists 10 | { 11 | public IReadOnlyDictionary BlockIdMapping { get; set; } = new Dictionary(); 12 | public IReadOnlyDictionary IdBlockMapping { get; set; } = new Dictionary(); 13 | public Dictionary MappedIds { get; set; } = new Dictionary(); 14 | public Dictionary NamedIds { get; set; } = new Dictionary(); 15 | 16 | public void ProcessLists(IDictionary ids) 17 | { 18 | MappedIds.Clear(); 19 | NamedIds .Clear(); 20 | 21 | ids.ForEach(idList => 22 | { 23 | var values = idList.Value 24 | .Split(',', ';') 25 | .Select(T => T.Trim()) 26 | .ToArray(); 27 | 28 | var idValues = new List(); 29 | var unknownNames = new List(); 30 | 31 | values.ForEach(T => 32 | { 33 | var delimiter = T.IndexOf('-', T.StartsWith("-") ? 1 : 0); 34 | if (delimiter > 0) 35 | { 36 | int? fromId = BlockIdMapping.TryGetValue(T.Substring(0, delimiter ).Trim(), out var idLeft ) ? idLeft : (int?)null; 37 | int? toId = BlockIdMapping.TryGetValue(T.Substring(delimiter + 1).Trim(), out var idRight) ? idRight : (int?)null; 38 | 39 | if (fromId.HasValue && toId.HasValue) idValues.AddRange(Enumerable.Range(fromId.Value, toId.Value - fromId.Value + 1)); 40 | } 41 | else if (BlockIdMapping.TryGetValue(T, out var id)) idValues.Add(id); 42 | else if (int.TryParse(T, out var directId)) idValues.Add(directId); 43 | else if (!string.IsNullOrWhiteSpace(T)) unknownNames.Add(T); 44 | }); 45 | 46 | idValues.Sort(); 47 | idValues = idValues.Distinct().ToList(); 48 | unknownNames = unknownNames.Distinct().ToList(); 49 | 50 | var compressedIdList = new StringBuilder(); 51 | int? lastId = null; 52 | bool withinRange = false; 53 | foreach (var currentId in idValues) 54 | { 55 | if (lastId.HasValue) 56 | { 57 | if (Math.Abs(lastId.Value - currentId) == 1) { lastId = currentId; withinRange = true; } 58 | else if (withinRange) { withinRange = false; compressedIdList.Append($"-{lastId},{(lastId = currentId).Value}"); } 59 | else compressedIdList.Append($",{(lastId = currentId).Value}"); 60 | } 61 | else compressedIdList.Append($",{(lastId = currentId).Value}"); 62 | } 63 | compressedIdList.Append(withinRange ? $"-{lastId}," : ","); 64 | 65 | MappedIds.Add(idList.Key, compressedIdList.ToString()); 66 | 67 | NamedIds.Add(idList.Key, "," + string.Join(",", idValues.Select(id => IdBlockMapping.TryGetValue(id, out var name) ? name : id.ToString()).OrderBy(name => name).Concat(unknownNames)) + ","); 68 | }); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /EmpyrionScripting/Internal.Interface/IDeviceLock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EmpyrionScripting.Internal.Interface 4 | { 5 | public interface IDeviceLock : IDisposable 6 | { 7 | bool Success { get; } 8 | bool Exit { get; } 9 | } 10 | } -------------------------------------------------------------------------------- /EmpyrionScripting/Internal.Interface/IPlayfieldScriptData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionScripting.Interface; 3 | using System.Collections.Concurrent; 4 | 5 | namespace EmpyrionScripting.Internal.Interface 6 | { 7 | public interface IExclusiveAccess 8 | { 9 | string CommandId { get; } 10 | string EntityName { get; } 11 | int EntityId { get; } 12 | } 13 | 14 | public interface IPlayfieldScriptData 15 | { 16 | IEntity[] AllEntities { get; } 17 | IEntity[] CurrentEntities { get; } 18 | ConcurrentDictionary EventStore { get; } 19 | ConcurrentDictionary PersistendData { get; } 20 | ConcurrentDictionary EntityExclusiveAccess { get; } 21 | IPlayfield Playfield { get; } 22 | string PlayfieldName { get; } 23 | ConcurrentQueue MoveLostItems { get; } 24 | } 25 | } -------------------------------------------------------------------------------- /EmpyrionScripting/Internal.Interface/IScriptRootData.cs: -------------------------------------------------------------------------------- 1 | namespace EmpyrionScripting.Internal.Interface 2 | { 3 | 4 | public interface IScriptRootData : IScriptRootModData 5 | { 6 | IPlayfieldScriptData GetPlayfieldScriptData(); 7 | } 8 | } -------------------------------------------------------------------------------- /EmpyrionScripting/ItemInfos.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.DataWrapper; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace EmpyrionScripting 7 | { 8 | public class ItemInfo : ItemBase 9 | { 10 | public string Name { get; set; } 11 | public string Key { get; set; } 12 | } 13 | 14 | public class ItemInfos 15 | { 16 | public Localization Localization { get; set; } 17 | public Dictionary ItemInfo { get; set; } = new Dictionary(); 18 | 19 | public ItemInfos(ConfigEcfAccess configAccess, Localization localization) 20 | { 21 | try 22 | { 23 | Localization = localization; 24 | ItemInfo = GetAllItems(configAccess).ToDictionary(I => I.Id, I => I); 25 | } 26 | catch (Exception error) 27 | { 28 | EmpyrionScripting.Log($"ReadAllItemData:{error}", EmpyrionNetAPIDefinitions.LogLevel.Error); 29 | } 30 | } 31 | 32 | public IEnumerable GetAllItems(ConfigEcfAccess configAccess) => 33 | configAccess.ConfigBlockById 34 | .Select(I => 35 | new ItemInfo() 36 | { 37 | Id = I.Key, 38 | Key = I.Value.Attr.FirstOrDefault(A => A.Name == "Id")?.AddOns?.FirstOrDefault(A => A.Key == "Name").Value?.ToString(), 39 | } 40 | ) 41 | .Select(I => 42 | { 43 | I.Name = Localization.GetName(I.Key, "English"); 44 | return I; 45 | }) 46 | .ToArray(); 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /EmpyrionScripting/Localization.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionNetAPIDefinitions; 2 | using EmpyrionScripting.Interface; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | 8 | namespace EmpyrionScripting 9 | { 10 | public class Localization 11 | { 12 | public static Action Log { get; set; } = (s, l) => Console.WriteLine(s); 13 | 14 | public Dictionary> LocalisationData { get; } 15 | public Localization(string contentPath, string activeScenario) 16 | { 17 | var scenarioPath = string.IsNullOrEmpty(activeScenario) ? null : Path.Combine(contentPath, "Scenarios", activeScenario); 18 | 19 | LocalisationData = ReadLocalisation(contentPath).ToDictionary(item => item.Key, item => RemoveFormats(item.Value)); 20 | 21 | if (!string.IsNullOrEmpty(scenarioPath)) 22 | { 23 | ReadLocalisation(scenarioPath).ForEach(item => 24 | { 25 | if (LocalisationData.ContainsKey(item.Key)) LocalisationData[item.Key] = RemoveFormats(item.Value); 26 | else LocalisationData.Add(item.Key, RemoveFormats(item.Value)); 27 | }); 28 | } 29 | } 30 | 31 | private List RemoveFormats(List values) 32 | => values.Select(v => RemoveFormats(v)).ToList(); 33 | 34 | public static string RemoveFormats(string value) 35 | { 36 | if (string.IsNullOrEmpty(value)) return value; 37 | 38 | var startPos = value.IndexOf('['); 39 | while(startPos >= 0) 40 | { 41 | var endPos = value.IndexOf(']', startPos); 42 | if (endPos >= 0) value = value.Substring(0, startPos) + value.Substring(endPos + 1); 43 | else startPos++; 44 | 45 | if (startPos >= value.Length) return value; 46 | 47 | startPos = value.IndexOf('[', startPos); 48 | } 49 | return value; 50 | } 51 | 52 | private Dictionary> ReadLocalisation(string contentPath) 53 | => ReadLocalisationFile(contentPath) 54 | .Where(L => !string.IsNullOrEmpty(L) && char.IsLetter(L[0])) 55 | .Select(L => 56 | { 57 | var line = L.Split(','); 58 | return new { ID = line.First(), Names = line.Skip(1) }; 59 | }) 60 | .SafeToDictionary(L => L.ID, L => L.Names.ToList(), StringComparer.CurrentCultureIgnoreCase); 61 | 62 | private static string[] ReadLocalisationFile(string contentPath) 63 | { 64 | var filename = Path.Combine(contentPath, @"Extras\Localization.csv"); 65 | Log($"LocalisationData from '{filename}'", LogLevel.Message); 66 | return File.Exists(filename) ? File.ReadAllLines(filename) : new string[] { }; 67 | } 68 | 69 | public string GetName(string name, string language) 70 | { 71 | if (string.IsNullOrEmpty(name)) return string.Empty; 72 | if (!LocalisationData.TryGetValue(name, out List i18nData)) return RemoveFormats(name); 73 | 74 | var languagePos = LocalisationData["KEY"].IndexOf(language); 75 | return languagePos == -1 || languagePos >= i18nData.Count 76 | ? i18nData.Count >= 1 77 | ? i18nData[0] // Fallback Engisch 78 | : RemoveFormats(name) 79 | : string.IsNullOrEmpty(i18nData[languagePos]) ? i18nData[0] : i18nData[languagePos]; 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /EmpyrionScripting/PlayfieldScriptData.cs: -------------------------------------------------------------------------------- 1 | using Eleon.Modding; 2 | using EmpyrionNetAPIDefinitions; 3 | using EmpyrionScripting.DataWrapper; 4 | using EmpyrionScripting.Interface; 5 | using EmpyrionScripting.Internal.Interface; 6 | using System; 7 | using System.Collections.Concurrent; 8 | 9 | namespace EmpyrionScripting 10 | { 11 | public class ExclusiveAccess : IExclusiveAccess 12 | { 13 | public string CommandId { get; set; } 14 | public int EntityId { get; set; } 15 | public string EntityName { get; set; } 16 | } 17 | 18 | public class PlayfieldScriptData : IPlayfieldScriptData 19 | { 20 | public string PlayfieldName { get; set; } 21 | public IPlayfield Playfield { get; set; } 22 | public IEntity[] CurrentEntities { get; set; } 23 | public IEntity[] AllEntities { get; set; } 24 | public bool PauseScripts { get; set; } = true; 25 | public ConcurrentDictionary EntityCultureInfo { get; set; } = new ConcurrentDictionary(); 26 | public ConcurrentDictionary EventStore { get; set; } = new ConcurrentDictionary(); 27 | public ConcurrentDictionary> LcdCompileCache = new ConcurrentDictionary>(); 28 | public ConcurrentQueue MoveLostItems { get; } = new ConcurrentQueue(); 29 | 30 | public ConcurrentDictionary PersistendData { get; set; } = new ConcurrentDictionary(); 31 | public ConcurrentDictionary EntityExclusiveAccess { get; set; } = new ConcurrentDictionary(); 32 | public ScriptExecQueue ScriptExecQueue { get; set; } 33 | 34 | private ConcurrentDictionary CycleCounterStore { get; set; } = new ConcurrentDictionary(); 35 | public int CycleCounter(string scriptId) => CycleCounterStore.GetOrAdd(scriptId, I => 0); 36 | public void IncrementCycleCounter(string scriptId) { CycleCounterStore.AddOrUpdate(scriptId, 0, (I, C) => C + 1); } 37 | public bool DeviceLockAllowed(string scriptId) => (CycleCounter(scriptId) % EmpyrionScripting.Configuration.Current.DeviceLockOnlyAllowedEveryXCycles) == 0; 38 | 39 | public EntityDelegate Playfield_OnEntityLoaded { get; } 40 | public EntityDelegate Playfield_OnEntityUnloaded { get; } 41 | public ConcurrentDictionary LastPOIVisited { get; } = new ConcurrentDictionary(); 42 | 43 | public PlayfieldScriptData(EmpyrionScripting parent) 44 | { 45 | Playfield_OnEntityLoaded = (IEntity entity) => AddEntity(entity); 46 | Playfield_OnEntityUnloaded = (IEntity entity) => RemoveEntity(entity); 47 | 48 | ScriptExecQueue = new ScriptExecQueue(D => parent.ProcessScript(this, D)); 49 | } 50 | 51 | public void RemoveEntity(IEntity entity) 52 | { 53 | if (EventStore.TryRemove(entity.Id, out var store)) ((EventStore)store).Dispose(); 54 | 55 | EmpyrionScripting.Log($"RemoveEntity: {PlayfieldName}:[{entity.Id}] {entity.Name}", LogLevel.Debug); 56 | } 57 | 58 | public IEventStore AddEntity(IEntity entity) 59 | { 60 | if(entity == null) return null; 61 | 62 | EmpyrionScripting.Log($"AddEntity: {PlayfieldName}:[{entity.Id}] {entity.Name}", LogLevel.Debug); 63 | 64 | return EventStore.AddOrUpdate(entity.Id, id => new EventStore(entity), (id, store) => store); 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /EmpyrionScripting/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("EmpyrionScripting")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("ASTIC/TC")] 11 | [assembly: AssemblyProduct("EmpyrionScripting")] 12 | [assembly: AssemblyCopyright("Copyright ©2025")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("dc79fd9d-5e85-4588-a4bd-46f7ed62150f")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("13.4.2.0")] 35 | [assembly: AssemblyFileVersion("13.4.2.0")] 36 | -------------------------------------------------------------------------------- /EmpyrionScripting/ScriptInfo.cs: -------------------------------------------------------------------------------- 1 | using EmpyrionScripting.Interface; 2 | using System; 3 | 4 | namespace EmpyrionScripting 5 | { 6 | 7 | public class ScriptInfo : IScriptInfo 8 | { 9 | public int Count { get; set; } 10 | public DateTime LastStart { get; set; } 11 | public TimeSpan ExecTime { get; set; } 12 | public string ScriptId { get; set; } 13 | public int EntityId { get; set; } 14 | public int ScriptPriority { get; set; } 15 | public bool NeedsMainThread { get; set; } 16 | public bool NeedsDeviceLock { get; set; } 17 | public bool IsElevatedScript { get; set; } 18 | public int TimeCriticalScriptExecutions { get; set; } 19 | 20 | public int RunningInstances => _RunningInstances; 21 | public int _RunningInstances; 22 | 23 | public int TimeLimitReached => _TimeLimitReached; 24 | public int _TimeLimitReached; 25 | public ScriptLanguage ScriptLanguage { get; set; } 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /EmpyrionScripting/SerializeHelper.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Runtime.Serialization.Formatters.Binary; 3 | 4 | namespace EmpyrionScripting 5 | { 6 | public static class SerializeHelper 7 | { 8 | static BinaryFormatter bf = new BinaryFormatter(); 9 | 10 | public static byte[] ObjectToByteArray(object obj) 11 | { 12 | if (obj == null) return null; 13 | 14 | using MemoryStream ms = new MemoryStream(); 15 | bf.Serialize(ms, obj); 16 | 17 | return ms.ToArray(); 18 | } 19 | 20 | // Convert a byte array to an Object 21 | public static T ByteArrayToObject(byte[] arrBytes) where T:class 22 | { 23 | if (arrBytes == null) return default; 24 | 25 | using MemoryStream memStream = new MemoryStream(); 26 | memStream.Write(arrBytes, 0, arrBytes.Length); 27 | memStream.Seek(0, SeekOrigin.Begin); 28 | return bf.Deserialize(memStream) as T; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /EmpyrionScripting/UnityEngine.CoreModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHub-TC/EmpyrionScripting/ce87e85b4a220574b76dd1b8ef019b9e362ff22d/EmpyrionScripting/UnityEngine.CoreModule.dll -------------------------------------------------------------------------------- /EmpyrionScripting/WeakDeviceLock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Eleon.Modding; 3 | using EmpyrionScripting.Internal.Interface; 4 | 5 | namespace EmpyrionScripting 6 | { 7 | public sealed class WeakDeviceLock : IDeviceLock 8 | { 9 | public WeakDeviceLock(IScriptRootData root, IPlayfield playfield, IStructure structure, VectorInt3 position) 10 | { 11 | try 12 | { 13 | root.ScriptNeedsDeviceLock = true; 14 | 15 | if (!root.ScriptWithinMainThread) 16 | { 17 | root.ScriptNeedsMainThread = true; 18 | Exit = true; 19 | return; 20 | } 21 | 22 | if (!root.DeviceLockAllowed || root.TimeLimitReached) 23 | { 24 | Exit = true; 25 | return; 26 | } 27 | 28 | Success = !playfield.IsStructureDeviceLocked(structure.Id, position); 29 | } 30 | catch (Exception error) 31 | { 32 | throw new Exception($"WeakDeviceLock:failed on Playfield:{playfield?.Name} at Id:{structure.Id} on {position} with: {error}"); 33 | } 34 | } 35 | public bool Exit { get; } 36 | 37 | public bool Success { get; } 38 | 39 | public void Dispose(){} 40 | } 41 | } -------------------------------------------------------------------------------- /EmpyrionScripting/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /EmpyrionScripting/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /RoslynCsCompiler/CompilerAccess.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.CSharp.Scripting; 2 | using Microsoft.CodeAnalysis.Scripting; 3 | using Microsoft.CodeAnalysis; 4 | using System; 5 | using System.Threading.Tasks; 6 | using Microsoft.CodeAnalysis.Scripting.Hosting; 7 | using Microsoft.CodeAnalysis.Diagnostics; 8 | using System.Collections.Immutable; 9 | using System.Threading; 10 | using System.Linq; 11 | using System.Reflection; 12 | 13 | namespace RoslynCsCompiler 14 | { 15 | public class CompilerAccess 16 | { 17 | public static Action Log { get; set; } 18 | public static Exception LastError { get; set; } 19 | 20 | public class CompileResult 21 | { 22 | public Script Script { get; set; } 23 | public Compilation Compilation { get; set; } 24 | public AnalysisResult AnalysisResult { get; set; } 25 | } 26 | 27 | public static async Task> CompileAsync (string scriptString, ScriptOptions optionsDefault, Type rootType, InteractiveAssemblyLoader loader, DiagnosticAnalyzer diagnosticAnalyzer) 28 | { 29 | try 30 | { 31 | var defAssembly = typeof(ScriptMetadataResolver).Assembly; 32 | 33 | var reType = defAssembly.GetType("Microsoft.CodeAnalysis.Scripting.Hosting.RuntimeMetadataReferenceResolver"); 34 | var reConstrutor = reType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(); 35 | 36 | var imString = reConstrutor.GetParameters().First().ParameterType; 37 | var searchPaths = Activator.CreateInstance(imString); 38 | var platformAssemblyPaths = Activator.CreateInstance(imString); 39 | 40 | var re = reConstrutor.Invoke(new object[] { searchPaths, null, null, null, platformAssemblyPaths, null }); 41 | 42 | var meType = defAssembly.GetType("Microsoft.CodeAnalysis.Scripting.ScriptMetadataResolver"); 43 | var meConstrutor = meType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(); 44 | var me = meConstrutor.Invoke(new[] { re }) as ScriptMetadataResolver; 45 | 46 | var options = optionsDefault 47 | .WithMetadataResolver(me); 48 | 49 | var script = CSharpScript.Create(scriptString, options, rootType, loader); 50 | var compilation = script 51 | .GetCompilation() 52 | .WithAssemblyName($"EmpyrionScriptingCustomAssembly{DateTime.Now.Ticks}for{scriptString.GetHashCode()}"); 53 | 54 | compilation.WithOptions(compilation.Options 55 | .WithModuleName("ScriptModule") 56 | .WithMainTypeName("ScriptMainType") 57 | .WithScriptClassName("ScriptMainClass") 58 | ); 59 | 60 | return new CompileResult 61 | { 62 | Script = script, 63 | Compilation = compilation, 64 | AnalysisResult = await compilation 65 | .WithAnalyzers(ImmutableArray.Create(diagnosticAnalyzer)) 66 | .GetAnalysisResultAsync(CancellationToken.None) 67 | }; 68 | } 69 | catch (Exception error) 70 | { 71 | LastError = error; 72 | Log($"CompileAsync: {error}"); 73 | return null; 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /RoslynCsCompiler/ILMerge.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | true 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /RoslynCsCompiler/ILMergeOrder.txt: -------------------------------------------------------------------------------- 1 | # this file contains the partial list of the merged assemblies in the merge order 2 | # you can fill it from the obj\CONFIG\PROJECT.ilmerge generated on every build 3 | # and finetune merge order to your satisfaction 4 | 5 | -------------------------------------------------------------------------------- /RoslynCsCompiler/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("RoslynCsCompiler")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("RoslynCsCompiler")] 12 | [assembly: AssemblyCopyright("Copyright © 2022")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("09fbbfbb-1257-483a-beb3-99939f249c27")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /RoslynCsCompiler/RoslynCsCompiler.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32112.339 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoslynCsCompiler", "RoslynCsCompiler.csproj", "{09FBBFBB-1257-483A-BEB3-99939F249C27}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {09FBBFBB-1257-483A-BEB3-99939F249C27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {09FBBFBB-1257-483A-BEB3-99939F249C27}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {09FBBFBB-1257-483A-BEB3-99939F249C27}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {09FBBFBB-1257-483A-BEB3-99939F249C27}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {0DC138A5-90E6-416A-B0D2-0DFD68738383} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /RoslynCsCompiler/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /RoslynCsCompiler/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Screenshots/AddOnAssembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHub-TC/EmpyrionScripting/ce87e85b4a220574b76dd1b8ef019b9e362ff22d/Screenshots/AddOnAssembly.png -------------------------------------------------------------------------------- /Screenshots/Conveyor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHub-TC/EmpyrionScripting/ce87e85b4a220574b76dd1b8ef019b9e362ff22d/Screenshots/Conveyor.png -------------------------------------------------------------------------------- /Screenshots/DemoShipScreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHub-TC/EmpyrionScripting/ce87e85b4a220574b76dd1b8ef019b9e362ff22d/Screenshots/DemoShipScreen.png -------------------------------------------------------------------------------- /Screenshots/LCD1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHub-TC/EmpyrionScripting/ce87e85b4a220574b76dd1b8ef019b9e362ff22d/Screenshots/LCD1.png -------------------------------------------------------------------------------- /Screenshots/RedAlert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHub-TC/EmpyrionScripting/ce87e85b4a220574b76dd1b8ef019b9e362ff22d/Screenshots/RedAlert.png -------------------------------------------------------------------------------- /WpfExtractCustomIcons/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /WpfExtractCustomIcons/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WpfExtractCustomIcons/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace WpfExtractCustomIcons 4 | { 5 | /// 6 | /// Interaction logic for App.xaml 7 | /// 8 | public partial class App : Application 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /WpfExtractCustomIcons/FilePathes.txt: -------------------------------------------------------------------------------- 1 | C:\steamcmd\empyrion\Content\Scenarios\Giga RE2022 V1+\SharedData\Content\Bundles\ItemIcons 2 | C:\steamcmd\empyrion\Content\Scenarios\Giga RE2022 V1+\Content\Configuration 3 | C:\steamcmd\empyrion\Saves\Games\GigaGamingNeue Era V1+\Mods\EmpyrionScripting\NameIdMapping.json 4 | 5 | C:\steamcmd\empyrion\DedicatedServer\EmpyrionAdminHelper\Items 6 | C:\steamcmd\empyrion\Content\Configuration -------------------------------------------------------------------------------- /WpfExtractCustomIcons/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 |