using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using RegionVo;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.mosadie.mocore")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.2.0")]
[assembly: AssemblyInformationalVersion("2.0.2-alpha.0.2+314e20e4147fb7d8362afa510f7f4810735ad2e0")]
[assembly: AssemblyProduct("MoCore")]
[assembly: AssemblyTitle("com.mosadie.mocore")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace MoCore
{
internal class HTTPServerThread
{
private HttpListener httpListener;
private Thread thread;
internal HTTPServerThread(int port)
{
httpListener = new HttpListener();
httpListener.Prefixes.Add($"http://+:{port}/");
}
internal void StartListening()
{
try
{
if (thread != null)
{
MoCore.Log.LogError((object)"HTTP server thread is already running.");
return;
}
thread = new Thread((ThreadStart)delegate
{
StartThread(httpListener);
});
thread.Start();
}
catch (Exception ex)
{
MoCore.Log.LogError((object)("Failed to start HTTP server thread: " + ex.Message));
}
}
internal void StopListening()
{
try
{
if (httpListener == null || thread == null)
{
MoCore.Log.LogError((object)"HTTP server thread is not running.");
}
else
{
httpListener.Stop();
}
}
catch (Exception ex)
{
MoCore.Log.LogError((object)("Failed to stop HTTP server thread: " + ex.Message));
}
}
private void StartThread(HttpListener httpListener)
{
try
{
httpListener.Start();
MoCore.Log.LogInfo((object)"HTTP server started.");
while (httpListener.IsListening)
{
HttpListenerContext context = httpListener.GetContext();
HttpListenerRequest request = context.Request;
HttpListenerResponse httpListenerResponse = context.Response;
string text = request.Url.AbsolutePath.Trim('/');
string text2 = text.Split('/')[0];
MoCore.Log.LogInfo((object)("HTTP request received: Prefix:" + text2 + " " + text));
Dictionary<string, IMoHttpHandler> httpHandlers = MoCore.GetHttpHandlers();
if (httpHandlers.ContainsKey(text2))
{
IMoHttpHandler moHttpHandler = httpHandlers[text2];
MoCore.Log.LogInfo((object)("HTTP request handled by " + moHttpHandler.GetPrefix()));
httpListenerResponse = moHttpHandler.HandleRequest(request, httpListenerResponse);
}
else
{
MoCore.Log.LogDebug((object)"HTTP request not handled");
httpListenerResponse.StatusCode = 404;
byte[] bytes = Encoding.UTF8.GetBytes("Not Found");
httpListenerResponse.ContentLength64 = bytes.Length;
httpListenerResponse.OutputStream.Write(bytes, 0, bytes.Length);
}
httpListenerResponse?.Close();
}
}
catch (Exception ex)
{
MoCore.Log.LogError((object)("HTTP server error: " + ex.Message));
}
}
}
public interface IMoHttpHandler
{
string GetPrefix();
HttpListenerResponse HandleRequest(HttpListenerRequest request, HttpListenerResponse response);
}
public interface IMoPlugin
{
string GetCompatibleGameVersion();
string GetVersionCheckUrl();
IMoHttpHandler GetHttpHandler();
BaseUnityPlugin GetPluginObject();
}
[BepInPlugin("com.mosadie.mocore", "MoCore", "2.0.2")]
[BepInProcess("Slipstream_Win.exe")]
public class MoCore : BaseUnityPlugin, IMoPlugin
{
private static ConfigEntry<bool> overrideVersionCheck;
private static ConfigEntry<int> httpServerPort;
private static HttpClient httpClient = new HttpClient();
private static List<IMoPlugin> plugins = new List<IMoPlugin>();
private static Dictionary<string, IMoHttpHandler> httpHandlers = new Dictionary<string, IMoHttpHandler>();
private static HTTPServerThread httpServerThread = null;
internal static ManualLogSource Log;
public static readonly string COMPATIBLE_GAME_VERSION = "4.1595";
public static readonly string GAME_VERSION_URL = "https://raw.githubusercontent.com/MoSadie/MoCore/refs/heads/main/versions.json";
private MoCoreHttpHandler moCoreHttpHandler;
public static bool IsSafe { get; private set; } = false;
private void Awake()
{
try
{
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)("Game version: " + Application.version));
overrideVersionCheck = ((BaseUnityPlugin)this).Config.Bind<bool>("BE CAREFUL", "Override Version Check", false, "This will allow my plugins to run on any version of Slipstream, skipping the version checker. Use at your own risk.");
httpServerPort = ((BaseUnityPlugin)this).Config.Bind<int>("HTTP", "HTTP Server Port", 8001, "The port to use for the HTTP server. This is used for any web requests plugins wish to accept.");
httpClient.Timeout = TimeSpan.FromSeconds(5.0);
httpServerThread = new HTTPServerThread(httpServerPort.Value);
httpServerThread.StartListening();
moCoreHttpHandler = new MoCoreHttpHandler(this);
Application.quitting += ApplicationQuitting;
IsSafe = RegisterPlugin(this);
Log.LogInfo((object)"Plugin com.mosadie.mocore is loaded!");
}
catch (Exception ex)
{
Log.LogError((object)("An error occurred during plugin startup: " + ex.Message));
}
}
private void ApplicationQuitting()
{
if (httpServerThread != null)
{
Log.LogInfo((object)"Application is quitting. Stopping HTTP server thread.");
httpServerThread.StopListening();
httpServerThread = null;
}
}
public static bool RegisterPlugin(IMoPlugin plugin)
{
if (plugin == null)
{
Log.LogError((object)"Attempted to register a null plugin!!!");
Log.LogError((object)("Stacktrace: " + Environment.StackTrace));
return false;
}
if (IsRegisteredPlugin(plugin))
{
Log.LogError((object)("Plugin " + PluginName(plugin) + " (" + PluginId(plugin) + ") is already registered. Skipping."));
return false;
}
Log.LogInfo((object)("Registering plugin " + PluginName(plugin) + " (" + PluginId(plugin) + ")"));
Log.LogInfo((object)("Version: " + PluginVersion(plugin)));
if (overrideVersionCheck.Value)
{
Log.LogWarning((object)"Version check override is enabled. Skipping version check.");
plugins.Add(plugin);
return RegisterHttpHandler(plugin);
}
if (plugin.GetVersionCheckUrl() != null)
{
if (!VersionCheck(plugin, Application.version))
{
return false;
}
Log.LogInfo((object)("Plugin " + PluginName(plugin) + " (" + PluginId(plugin) + ") is compatible with this version of the game (" + Application.version + ")."));
}
else if (plugin.GetCompatibleGameVersion() != null)
{
if (!plugin.GetCompatibleGameVersion().Equals(Application.version))
{
Log.LogError((object)("Plugin " + PluginName(plugin) + " (" + PluginId(plugin) + ") is not compatible with this (" + Application.version + " version of the game. (Expected version: " + plugin.GetCompatibleGameVersion() + ")"));
return false;
}
}
else
{
Log.LogInfo((object)("Plugin " + PluginName(plugin) + " (" + PluginId(plugin) + ") did not provide a version check URL or compatible game version. Skipping version check."));
}
plugins.Add(plugin);
return RegisterHttpHandler(plugin);
}
private static bool RegisterHttpHandler(IMoPlugin plugin)
{
if (plugin == null)
{
Log.LogError((object)"Attempted to RegisterHttpHandler with a null plugin!!!");
return false;
}
IMoHttpHandler httpHandler = plugin.GetHttpHandler();
if (httpHandler == null)
{
Log.LogDebug((object)("HttpHandler is null for plugin " + PluginName(plugin) + " (" + PluginId(plugin) + "). Skipping (this is normal, null means does not need feature)"));
return true;
}
Log.LogInfo((object)("Attempting to register http handler " + httpHandler.GetPrefix() + " for plugin " + PluginName(plugin) + " (" + PluginId(plugin) + ")"));
if (httpHandler.GetPrefix() == null)
{
Log.LogError((object)"HttpHandler prefix is null. Skipping");
return false;
}
if (httpHandler.GetPrefix().Length == 0)
{
Log.LogError((object)"HttpHandler prefix is empty. Skipping");
return false;
}
if (httpHandler.GetPrefix().Contains(" "))
{
Log.LogError((object)"HttpHandler prefix contains spaces. Skipping");
return false;
}
if (httpHandler.GetPrefix().Contains("/"))
{
Log.LogError((object)"HttpHandler prefix contains slashes. Skipping");
return false;
}
if (httpHandlers.ContainsKey(httpHandler.GetPrefix()))
{
Log.LogError((object)("HttpHandler prefix " + httpHandler.GetPrefix() + " is already registered. Skipping"));
return false;
}
Log.LogInfo((object)("Registering http handler " + httpHandler.GetPrefix() + " for plugin " + PluginName(plugin) + " (" + PluginId(plugin) + ")"));
httpHandlers.Add(httpHandler.GetPrefix(), httpHandler);
return true;
}
public static bool IsRegisteredPlugin(IMoPlugin plugin)
{
return plugins.Contains(plugin);
}
public static List<IMoPlugin> GetPlugins()
{
return new List<IMoPlugin>(plugins);
}
internal static Dictionary<string, IMoHttpHandler> GetHttpHandlers()
{
return httpHandlers;
}
private static bool VersionCheck(IMoPlugin plugin, string gameVersion)
{
try
{
Dictionary<string, HashSet<string>> dictionary = JsonConvert.DeserializeObject<Dictionary<string, HashSet<string>>>(httpClient.GetStringAsync(plugin.GetVersionCheckUrl()).GetAwaiter().GetResult());
if (dictionary.ContainsKey(PluginVersion(plugin)) && dictionary[PluginVersion(plugin)].Contains(Application.version))
{
return true;
}
if (dictionary.ContainsKey(PluginVersion(plugin)))
{
Log.LogError((object)("Version " + PluginVersion(plugin) + " of " + PluginName(plugin) + " (" + PluginId(plugin) + ") is not compatible with this version of the game (" + Application.version + "). Please check for updates."));
return false;
}
Log.LogError((object)("Version " + PluginVersion(plugin) + " of " + PluginName(plugin) + " (" + PluginId(plugin) + ") is not listed in the version check file. Please contact the plugin's creator."));
return false;
}
catch (TaskCanceledException)
{
Log.LogError((object)"Version check timed out. Falling back to hardcoded version check.");
return plugin.GetCompatibleGameVersion().Equals(gameVersion);
}
catch (Exception ex2)
{
Log.LogError((object)("An error occurred during remote version check, falling back to hardcoded version check: " + ex2.Message));
return plugin.GetCompatibleGameVersion().Equals(gameVersion);
}
}
private static string PluginName(IMoPlugin plugin)
{
return plugin.GetPluginObject().Info.Metadata.Name;
}
private static string PluginId(IMoPlugin plugin)
{
return plugin.GetPluginObject().Info.Metadata.GUID;
}
private static string PluginVersion(IMoPlugin plugin)
{
return plugin.GetPluginObject().Info.Metadata.Version.ToString();
}
public string GetCompatibleGameVersion()
{
return COMPATIBLE_GAME_VERSION;
}
public string GetVersionCheckUrl()
{
return GAME_VERSION_URL;
}
public BaseUnityPlugin GetPluginObject()
{
return (BaseUnityPlugin)(object)this;
}
public IMoHttpHandler GetHttpHandler()
{
return moCoreHttpHandler;
}
}
internal class MoCoreHttpHandler : IMoHttpHandler
{
private class JsonPluginInfo
{
public string Name { get; set; }
public string Version { get; set; }
public string GUID { get; set; }
public string VersionCheckUrl { get; set; }
public string FallbackGameVersion { get; set; }
internal JsonPluginInfo(IMoPlugin plugin)
{
Name = plugin.GetPluginObject().Info.Metadata.Name;
Version = plugin.GetPluginObject().Info.Metadata.Version.ToString();
GUID = plugin.GetPluginObject().Info.Metadata.GUID;
VersionCheckUrl = plugin.GetVersionCheckUrl();
FallbackGameVersion = plugin.GetCompatibleGameVersion();
}
}
private readonly MoCore moCore;
public MoCoreHttpHandler(MoCore moCore)
{
this.moCore = moCore;
}
public string GetPrefix()
{
return "mocore";
}
public HttpListenerResponse HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
{
string[] array = request.Url.AbsolutePath.Trim('/').Split('/');
if (array.Length < 2 || array[0] != "mocore")
{
response.StatusCode = 404;
return response;
}
if (array[1] == "version")
{
response.StatusCode = 200;
response.Headers.Add("Access-Control-Allow-Origin", "*");
byte[] bytes = Encoding.UTF8.GetBytes(moCore.GetPluginObject().Info.Metadata.Version.ToString());
response.ContentLength64 = bytes.Length;
response.OutputStream.Write(bytes, 0, bytes.Length);
response.Close();
return response;
}
if (array[1] == "plugins")
{
List<JsonPluginInfo> list = new List<JsonPluginInfo>();
foreach (IMoPlugin plugin in MoCore.GetPlugins())
{
list.Add(new JsonPluginInfo(plugin));
}
string s = JsonConvert.SerializeObject((object)list, (Formatting)1);
response.StatusCode = 200;
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.ContentType = "application/json";
byte[] bytes2 = Encoding.UTF8.GetBytes(s);
response.ContentLength64 = bytes2.Length;
response.OutputStream.Write(bytes2, 0, bytes2.Length);
return response;
}
if (array[1] == "plugin" && array.Length > 2)
{
IMoPlugin moPlugin = null;
foreach (IMoPlugin plugin2 in MoCore.GetPlugins())
{
if (plugin2.GetPluginObject().Info.Metadata.GUID == array[2])
{
moPlugin = plugin2;
break;
}
}
if (moPlugin != null)
{
string s2 = JsonConvert.SerializeObject((object)new JsonPluginInfo(moPlugin), (Formatting)1);
response.StatusCode = 200;
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.ContentType = "application/json";
byte[] bytes3 = Encoding.UTF8.GetBytes(s2);
response.ContentLength64 = bytes3.Length;
response.OutputStream.Write(bytes3, 0, bytes3.Length);
}
else
{
response.StatusCode = 404;
}
}
else if (array[1] == "variable" && array.Length > 2 && array[2] == "parse")
{
if (!MoCore.IsSafe)
{
response.StatusCode = 503;
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
string text = request.QueryString["string"];
if (text != null)
{
string text2 = VariableHandler.ParseVariables(text);
if (text2 == null)
{
response.StatusCode = 500;
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
response.StatusCode = 200;
response.Headers.Add("Access-Control-Allow-Origin", "*");
byte[] bytes4 = Encoding.UTF8.GetBytes(text2);
response.ContentLength64 = bytes4.Length;
response.OutputStream.Write(bytes4, 0, bytes4.Length);
}
else
{
response.StatusCode = 400;
}
}
else
{
response.StatusCode = 404;
}
return response;
}
}
public class VariableHandler
{
private static Dictionary<string, string> crewMap = new Dictionary<string, string>();
public static string ParseVariables(string message)
{
if (!MoCore.IsSafe)
{
return null;
}
string[] array = message.Split(' ');
string text = "";
string[] array2 = array;
foreach (string text2 in array2)
{
if (text2.StartsWith("$"))
{
string variableValue = GetVariableValue(text2.Substring(1));
text = ((variableValue != null) ? (text + variableValue + " ") : (text + text2 + " "));
}
else
{
text = text + text2 + " ";
}
}
return text.Trim();
}
internal static string GetVariableValue(string variable)
{
//IL_052f: Unknown result type (might be due to invalid IL or missing references)
//IL_0534: Unknown result type (might be due to invalid IL or missing references)
//IL_0560: Unknown result type (might be due to invalid IL or missing references)
//IL_0565: Unknown result type (might be due to invalid IL or missing references)
if (!MoCore.IsSafe)
{
return null;
}
string text = "";
while (variable.Length > 0 && !char.IsLetterOrDigit(variable[variable.Length - 1]))
{
text = variable[variable.Length - 1] + text;
variable = variable.Substring(0, variable.Length - 1);
}
string text2 = "";
if (variable.StartsWith("randomCrew"))
{
text2 = GetRandomCrewMember(variable.Substring(10, variable.Length - 11));
}
else if (variable.StartsWith("crew"))
{
text2 = GetCrewMember(variable.Substring(5, variable.Length - 6));
}
else
{
switch (variable)
{
case "version":
text2 = "2.0.2";
break;
case "captain":
text2 = ((Svc.Get<MpSvc>().Captains != null && Svc.Get<MpSvc>().Captains.CaptainClient != null && Svc.Get<MpSvc>().Captains.CaptainClient.Player != null && Svc.Get<MpSvc>().Captains.CaptainClient.Player.DisplayName != null) ? Svc.Get<MpSvc>().Captains.CaptainClient.Player.DisplayName : "");
break;
case "enemyName":
{
MpScenarioController scenarios5 = Svc.Get<MpSvc>().Scenarios;
text2 = ((scenarios5 != null && scenarios5.CurrentScenario != null && scenarios5.CurrentScenario.Battle != null && scenarios5.CurrentScenario.Battle.Metadata.EnemyName != null) ? scenarios5.CurrentScenario.Battle.Metadata.EnemyName : "");
break;
}
case "enemyIntel":
{
MpScenarioController scenarios2 = Svc.Get<MpSvc>().Scenarios;
text2 = ((scenarios2 != null && scenarios2.CurrentScenario != null && scenarios2.CurrentScenario.Battle != null && scenarios2.CurrentScenario.Battle.Metadata.IntelDescription != null) ? scenarios2.CurrentScenario.Battle.Metadata.IntelDescription : "");
break;
}
case "enemyInvader":
case "enemyInvaders":
{
MpScenarioController scenarios6 = Svc.Get<MpSvc>().Scenarios;
text2 = ((scenarios6 != null && scenarios6.CurrentScenario != null && scenarios6.CurrentScenario.Battle != null && scenarios6.CurrentScenario.Battle.Metadata.InvaderDescription != null) ? scenarios6.CurrentScenario.Battle.Metadata.InvaderDescription : "");
break;
}
case "enemyThreat":
{
MpScenarioController scenarios3 = Svc.Get<MpSvc>().Scenarios;
text2 = ((scenarios3 != null && scenarios3.CurrentScenario != null && scenarios3.CurrentScenario.Battle != null) ? scenarios3.CurrentScenario.Battle.Metadata.ThreatLevel.ToString() : "");
break;
}
case "enemySpeed":
{
MpScenarioController scenarios = Svc.Get<MpSvc>().Scenarios;
text2 = ((scenarios != null && scenarios.CurrentScenario != null && scenarios.CurrentScenario.Battle != null) ? scenarios.CurrentScenario.Battle.Metadata.SpeedLevel.ToString() : "");
break;
}
case "enemyCargo":
{
MpScenarioController scenarios4 = Svc.Get<MpSvc>().Scenarios;
text2 = ((scenarios4 != null && scenarios4.CurrentScenario != null && scenarios4.CurrentScenario.Battle != null) ? scenarios4.CurrentScenario.Battle.Metadata.CargoLevel.ToString() : "");
break;
}
case "campaignName":
{
MpCampaignController campaigns2 = Svc.Get<MpSvc>().Campaigns;
if (campaigns2 != null && campaigns2.CurrentCampaign != null && campaigns2.CurrentCampaign.CaptainCampaign != null && campaigns2.CurrentCampaign.CaptainCampaign.CampaignVo != null)
{
RegionMetadataVo metadata = ((Root)(ref campaigns2.CurrentCampaign.CaptainCampaign.CampaignVo.RegionVo)).Metadata;
if (((RegionMetadataVo)(ref metadata)).Name != null)
{
metadata = ((Root)(ref campaigns2.CurrentCampaign.CaptainCampaign.CampaignVo.RegionVo)).Metadata;
text2 = ((RegionMetadataVo)(ref metadata)).Name;
break;
}
}
text2 = "";
break;
}
case "sectorName":
{
MpCampaignController campaigns = Svc.Get<MpSvc>().Campaigns;
text2 = ((campaigns != null && campaigns.CurrentCampaign != null && campaigns.CurrentCampaign.CaptainCampaign != null && campaigns.CurrentCampaign.CaptainCampaign.CampaignVo != null && campaigns.CurrentCampaign.CaptainCampaign.CampaignVo.CurrentSectorVo != null && ((SectorDefVo)(ref campaigns.CurrentCampaign.CaptainCampaign.CampaignVo.CurrentSectorVo.Definition)).Name != null) ? ((SectorDefVo)(ref campaigns.CurrentCampaign.CaptainCampaign.CampaignVo.CurrentSectorVo.Definition)).Name : "");
break;
}
default:
text2 = "";
break;
}
}
return text2 + text;
}
internal static string GetRandomCrewMember(string id)
{
if (crewMap.ContainsKey(id))
{
return crewMap[id];
}
Dictionary<int, Crewmate> dictionary = Svc.Get<MpSvc>().Crew.CrewMap;
if (dictionary == null || dictionary.Count == 0)
{
return "";
}
int num = new Random().Next(0, dictionary.Count);
int num2 = 0;
Crewmate val = null;
foreach (KeyValuePair<int, Crewmate> item in dictionary)
{
val = item.Value;
if (num2 == num)
{
break;
}
num2++;
}
string displayName = val.Client.Player.DisplayName;
crewMap.Add(id, displayName);
return displayName;
}
internal static string GetCrewMember(string id)
{
Dictionary<int, Crewmate> dictionary = Svc.Get<MpSvc>().Crew.CrewMap;
if (dictionary.Count == 0)
{
return "";
}
int result = 0;
if (!int.TryParse(id, out result))
{
return "";
}
if (!dictionary.ContainsKey(result))
{
return "";
}
return dictionary[result].Client.Player.DisplayName;
}
internal static void Reset()
{
crewMap.Clear();
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "com.mosadie.mocore";
public const string PLUGIN_NAME = "MoCore";
public const string PLUGIN_VERSION = "2.0.2";
}
}