Files

144 lines
5.0 KiB
C#
Raw Permalink Normal View History

2025-06-27 21:31:38 +03:00
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using Nebula.Shared;
using Nebula.Shared.Models;
using Nebula.Shared.Services;
using Nebula.Shared.Services.Logging;
using Nebula.Shared.Utils;
2024-12-27 19:15:33 +03:00
using Robust.LoaderApi;
2025-06-27 21:31:38 +03:00
namespace Nebula.Runner.Services;
2024-12-27 19:15:33 +03:00
[ServiceRegister]
2025-01-05 17:05:23 +03:00
public sealed class RunnerService(
ContentService contentService,
DebugService debugService,
ConfigurationService varService,
EngineService engineService,
2025-06-27 21:31:38 +03:00
AssemblyService assemblyService,
ReflectionService reflectionService,
HarmonyService harmonyService)
2024-12-27 19:15:33 +03:00
{
private ILogger _logger = debugService.GetLogger("RunnerService");
2025-06-27 21:31:38 +03:00
private bool MetricEnabled = false; //TODO: ADD METRIC THINKS LATER
2024-12-27 19:15:33 +03:00
2025-01-14 22:10:16 +03:00
public async Task Run(string[] runArgs, RobustBuildInfo buildInfo, IRedialApi redialApi,
ILoadingHandlerFactory loadingHandler,
2024-12-27 19:15:33 +03:00
CancellationToken cancellationToken)
{
_logger.Log("Start Content!");
var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion, loadingHandler, cancellationToken);
2024-12-27 19:15:33 +03:00
if (engine is null)
2025-03-13 14:58:47 +03:00
throw new Exception("Engine version not found: " + buildInfo.BuildInfo.Build.EngineVersion);
2024-12-27 19:15:33 +03:00
2026-01-16 21:02:34 +03:00
var fileApi = await contentService.EnsureItems(buildInfo, loadingHandler, cancellationToken);
2024-12-27 19:15:33 +03:00
var extraMounts = new List<ApiMount>
{
2026-01-16 21:02:34 +03:00
new(fileApi, "/")
2024-12-27 19:15:33 +03:00
};
2026-01-16 21:02:34 +03:00
if (fileApi.TryOpen("manifest.yml", out var stream))
{
var modules = ContentManifestParser.ExtractModules(stream);
2024-12-27 19:15:33 +03:00
foreach (var moduleStr in modules)
{
var module =
await engineService.EnsureEngineModules(moduleStr, loadingHandler, buildInfo.BuildInfo.Build.EngineVersion);
if (module is not null)
extraMounts.Add(new ApiMount(module, "/"));
}
await stream.DisposeAsync();
}
2024-12-27 19:15:33 +03:00
var args = new MainArgs(runArgs, engine, redialApi, extraMounts);
2025-01-14 22:10:16 +03:00
if (!assemblyService.TryOpenAssembly(varService.GetConfigValue(CurrentConVar.RobustAssemblyName)!, engine,
out var clientAssembly))
2024-12-27 19:15:33 +03:00
throw new Exception("Unable to locate Robust.Client.dll in engine build!");
2025-06-27 21:31:38 +03:00
2025-01-05 17:05:23 +03:00
if (!assemblyService.TryGetLoader(clientAssembly, out var loader))
2024-12-27 19:15:33 +03:00
return;
2025-06-27 21:31:38 +03:00
if(!assemblyService.TryOpenAssembly("Prometheus.NetStandard", engine, out var prometheusAssembly))
return;
reflectionService.RegisterRobustAssemblies(engine);
harmonyService.CreateInstance();
IDisposable? metricServer = null;
2024-12-27 19:15:33 +03:00
2025-06-27 21:31:38 +03:00
if (MetricEnabled)
{
MetricsEnabledPatcher.ApplyPatch(reflectionService, harmonyService);
metricServer = RunHelper.RunMetric(prometheusAssembly);
}
loadingHandler.Dispose();
2024-12-27 19:15:33 +03:00
await Task.Run(() => loader.Main(args), cancellationToken);
2025-06-27 21:31:38 +03:00
metricServer?.Dispose();
}
}
public static class MetricsEnabledPatcher
{
public static void ApplyPatch(ReflectionService reflectionService, HarmonyService harmonyService)
{
var harmony = harmonyService.Instance.Harmony;
2025-06-28 14:05:19 +03:00
2025-06-27 21:31:38 +03:00
var targetType = reflectionService.GetType("Robust.Shared.GameObjects.EntitySystemManager");
2025-09-08 21:26:12 +03:00
var targetMethod = targetType.GetProperty("MetricsEnabled")?.GetGetMethod() ??
throw new Exception("target method is null.. huh.. do we have patch a right think?");
2025-06-28 14:05:19 +03:00
2025-06-27 21:31:38 +03:00
var prefix = typeof(MetricsEnabledPatcher).GetMethod(nameof(MetricsEnabledGetterPrefix),
BindingFlags.Static | BindingFlags.NonPublic);
2025-06-28 14:05:19 +03:00
2025-06-27 21:31:38 +03:00
var prefixMethod = new HarmonyMethod(prefix);
2025-06-28 14:05:19 +03:00
2025-06-27 21:31:38 +03:00
harmony.Patch(targetMethod, prefix: prefixMethod);
}
2025-06-28 14:05:19 +03:00
2025-06-27 21:31:38 +03:00
private static bool MetricsEnabledGetterPrefix(ref bool __result)
{
__result = true;
return false; // Skip original method
}
}
public static class RunHelper
{
public static IDisposable RunMetric(Assembly prometheusAssembly)
{
var metricServerType = prometheusAssembly.GetType("Prometheus.MetricServer");
var collectorRegistryType = prometheusAssembly.GetType("Prometheus.CollectorRegistry");
var ctor = metricServerType!.GetConstructor(new Type[]
{
typeof(string),
typeof(int),
typeof(string),
collectorRegistryType!,
typeof(bool)
});
var hostname = "localhost";
var port = 51235;
var url = "metrics/";
object? registry = null;
var useHttps = false;
var metricServerInstance = ctor!.Invoke(new object[] { hostname, port, url, registry!, useHttps });
metricServerType.GetMethod("Start")!.Invoke(metricServerInstance, BindingFlags.Default, null, null, CultureInfo.CurrentCulture);
return (IDisposable)metricServerInstance;
2024-12-27 19:15:33 +03:00
}
}