using Nebula.Shared.Models; using Nebula.Shared.Services.Logging; using Robust.LoaderApi; namespace Nebula.Shared.Services; [ServiceRegister] public sealed class RunnerService( ContentService contentService, DebugService debugService, ConfigurationService varService, EngineService engineService, AssemblyService assemblyService) { private ILogger _logger = debugService.GetLogger("RunnerService"); public async Task PrepareRun(RobustBuildInfo buildInfo, ILoadingHandler loadingHandler, CancellationToken cancellationToken) { _logger.Log("Prepare Content!"); var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion); if (engine is null) throw new Exception("Engine version not found: " + buildInfo.BuildInfo.Build.EngineVersion); await contentService.EnsureItems(buildInfo.RobustManifestInfo, loadingHandler, cancellationToken); await engineService.EnsureEngineModules("Robust.Client.WebView", buildInfo.BuildInfo.Build.EngineVersion); } public async Task Run(string[] runArgs, RobustBuildInfo buildInfo, IRedialApi redialApi, ILoadingHandler loadingHandler, CancellationToken cancellationToken) { _logger.Log("Start Content!"); var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion); if (engine is null) throw new Exception("Engine version not found: " + buildInfo.BuildInfo.Build.EngineVersion); var hashApi = await contentService.EnsureItems(buildInfo.RobustManifestInfo, loadingHandler, cancellationToken); var extraMounts = new List { new(hashApi, "/") }; if (hashApi.TryOpen("manifest.yml", out var stream)) { var modules = ContentManifestParser.ExtractModules(stream); foreach (var moduleStr in modules) { var module = await engineService.EnsureEngineModules(moduleStr, buildInfo.BuildInfo.Build.EngineVersion); if (module is not null) extraMounts.Add(new ApiMount(module, "/")); } await stream.DisposeAsync(); } var args = new MainArgs(runArgs, engine, redialApi, extraMounts); if (!assemblyService.TryOpenAssembly(varService.GetConfigValue(CurrentConVar.RobustAssemblyName)!, engine, out var clientAssembly)) throw new Exception("Unable to locate Robust.Client.dll in engine build!"); if (!assemblyService.TryGetLoader(clientAssembly, out var loader)) return; await Task.Run(() => loader.Main(args), cancellationToken); } } public static class ContentManifestParser { public static List ExtractModules(Stream manifestStream) { using var reader = new StreamReader(manifestStream); return ExtractModules(reader.ReadToEnd()); } public static List ExtractModules(string manifestContent) { var modules = new List(); var lines = manifestContent.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); bool inModulesSection = false; foreach (var rawLine in lines) { var line = rawLine.Trim(); if (line.StartsWith("modules:")) { inModulesSection = true; continue; } if (inModulesSection) { if (line.StartsWith("- ")) { modules.Add(line.Substring(2).Trim()); } else if (!line.StartsWith(" ")) { break; } } } return modules; } }