Skip to content
This repository has been archived by the owner on Oct 16, 2024. It is now read-only.

Commit

Permalink
Integrate subversion, entrypoint support for subversions
Browse files Browse the repository at this point in the history
  • Loading branch information
misandrie committed Dec 26, 2023
1 parent 824ab0e commit 2b5c8b8
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 137 deletions.
12 changes: 4 additions & 8 deletions Marsey/MarseyPatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public static void CreateInstance(Assembly? robClientAssembly)

_instance = new MarseyPatcher(robClientAssembly);
}


/// <exception cref="Exception">Excepts if Robust.Client assembly is null</exception>
private MarseyPatcher(Assembly? robClientAssembly)
{
if (robClientAssembly == null) throw new Exception("Robust.Client was null.");
Expand All @@ -62,18 +63,13 @@ private MarseyPatcher(Assembly? robClientAssembly)
///
/// Executed by the loader.
/// </summary>
/// <exception cref="Exception">Excepts if Robust.Client assembly is null</exception>
public void Boot()
{
// Preload marseypatches, if available
Marsyfier.Preload();

// Initialize subverter if enabled and present
if (MarseyVars.Subverter && Subverse.InitSubverter())
{
// Side-load custom code
Subverse.PatchSubverter();
}
// Side-load custom code
Subverse.PatchSubverter();

// Manage game assemblies
GameAssemblyManager.GetGameAssemblies(out Assembly? clientAss, out Assembly? robustSharedAss, out Assembly? clientSharedAss);
Expand Down
5 changes: 1 addition & 4 deletions Marsey/Misc/FileHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,7 @@ public static void LoadExactAssembly(string file)
}
catch (FileNotFoundException)
{
if (!file.EndsWith(Subverse.SubverterFile))
{
MarseyLogger.Log(MarseyLogger.LogType.DEBG, $"{file} could not be found");
}
MarseyLogger.Log(MarseyLogger.LogType.DEBG, $"{file} could not be found");
}
catch (PatchAssemblyException ex)
{
Expand Down
2 changes: 1 addition & 1 deletion Marsey/PatchAssembly/AssemblyFieldHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ private static void SetupLogger(Assembly patch)
/// <summary>
/// Get methodhandle for the entrypoint function in patch
/// </summary>
private static MethodInfo? GetEntry(Assembly patch, Type entryType)
public static MethodInfo? GetEntry(Assembly patch, Type entryType)
{
MethodInfo? entry = entryType.GetMethod("Entry", BindingFlags.Public | BindingFlags.Static);
return entry;
Expand Down
4 changes: 0 additions & 4 deletions Marsey/PatchAssembly/AssemblyInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@ private static void ProcessDataType(Assembly assembly, Type dataType)

break;
}
case "SubverterPatch" when Subverse.CheckSubverterPresent() && Subverse.CheckSubverterDuplicate(assembly):
MarseyLogger.Log(MarseyLogger.LogType.FATL,
$"{Path.GetFileName(assembly.Location)}: Tried to create a SubverterPatch with the same assembly as Subverter!");
return;
}

AssemblyFieldHandler.GetFields(dataType, out string name, out string description);
Expand Down
134 changes: 49 additions & 85 deletions Marsey/Subversion/Subverse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
using System.IO;
using System.Linq;
using System.Reflection;
using HarmonyLib;
using Marsey.Config;
using Marsey.GameAssembly;
using Marsey.Handbrake;
using Marsey.Stealthsey;
using Marsey.Misc;
using Marsey.PatchAssembly;
using Marsey.Serializer;
using Marsey.Stealthsey.Reflection;

namespace Marsey.Subversion;
Expand All @@ -17,63 +21,6 @@ namespace Marsey.Subversion;
/// </summary>
public static class Subverse
{
public static string SubverterFile = "Subverter.dll";
private static SubverterPatch? _subverter = null;

/// <summary>
/// Initializes the subverter library.
/// </summary>
/// <returns>True if the library was initialized successfully.</returns>
public static bool InitSubverter()
{
string path = Path.Combine(Directory.GetCurrentDirectory(), SubverterFile);
FileHandler.LoadExactAssembly(path);

List<SubverterPatch> patches = Subverter.GetSubverterPatches();
SubverterPatch? subverterPatch = patches.FirstOrDefault(p => p.Name == "Subverter");

if (subverterPatch == null) return false;

AssignSubverter(subverterPatch);
SetHidesey();
patches.Clear();

return true;
}

private static void SetHidesey()
{
if (_subverter == null) return;

Type? subverterPatchType = _subverter.Asm.GetType("SubverterPatch");
MethodInfo? hideMethod = typeof(Subverter).GetMethod("Hide", BindingFlags.NonPublic | BindingFlags.Static);
FieldInfo? hideDelegateField = subverterPatchType?.GetField("hideDelegate", BindingFlags.Public | BindingFlags.Static);

if (subverterPatchType == null || hideMethod == null || hideDelegateField == null)
{
List<string> missingComps = new List<string>();
if (subverterPatchType == null) missingComps.Add("subverterPatchType");
if (hideMethod == null) missingComps.Add("hideMethod");
if (hideDelegateField == null) missingComps.Add("hideDelegateField");

string missingCompStr = string.Join(", ", missingComps);

MarseyLogger.Log(MarseyLogger.LogType.FATL, $"Failed to connect patch to subverter. Missing components: {missingCompStr}.");
return;
}

try
{
Delegate logDelegate = Delegate.CreateDelegate(hideDelegateField.FieldType, hideMethod);
hideDelegateField.SetValue(null, logDelegate);
}
catch (Exception e)
{
MarseyLogger.Log(MarseyLogger.LogType.FATL, $"Failed to to assign hide delegate: {e.Message}");
}
}


/// <summary>
/// Enables subverter if any of the of the subverter patches are enabled
/// Used by the launcher to determine if it should load subversions
Expand All @@ -91,44 +38,61 @@ public static void CheckEnabled()

MarseyVars.Subverter = false;
}

/// <summary>
/// Check if a patch is loaded from the same place subverter is
/// Patches subverter ahead of everything else
/// This is done as we attach to the assembly loading function
/// </summary>
/// <returns></returns>
public static bool CheckSubverterDuplicate(SubverterPatch subverter)
{
if (CheckSubverterPresent())
return CheckSubverterDuplicate(subverter.Asm);

return false;
}

public static bool CheckSubverterDuplicate(Assembly assembly)
public static void PatchSubverter()
{
return assembly == _subverter?.Asm;
MethodInfo Target = AccessTools.Method(AccessTools.TypeByName("Robust.Shared.ContentPack.ModLoader"), "TryLoadModules");
MethodInfo Prefix = typeof(Subverse).GetMethod("Prefix", BindingFlags.NonPublic | BindingFlags.Static)!;

MarseyLogger.Log(MarseyLogger.LogType.DEBG, "Subversion", $"Hooking {Target.Name} with {Prefix.Name}");

Manual.Patch(Target, Prefix, HarmonyPatchType.Prefix);
}

/// <summary>
/// Check if subverter is already defined.
/// Used by the launcher in the plugins/patches tab.
/// </summary>
public static bool CheckSubverterPresent()
private static bool Prefix(object __instance)
{
return _subverter != null;
MarseyLogger.Log(MarseyLogger.LogType.DEBG, "Subversion", "Detour");
MethodInfo? loadGameAssemblyMethod = AccessTools.Method(AccessTools.TypeByName("Robust.Shared.ContentPack.BaseModLoader"), "InitMod");

foreach (string path in GetSubverters())
{
Assembly subverterAssembly = Assembly.LoadFrom(path);
MarseyLogger.Log(MarseyLogger.LogType.DEBG, "Subversion", $"Sideloading {path}");
loadGameAssemblyMethod.Invoke(__instance, new object[] { subverterAssembly });

MethodInfo? Entry = CheckEntry(subverterAssembly);
if (Entry != null)
Doorbreak.Enter(Entry);

Hidesey.HidePatch(subverterAssembly);
}

return true;
}

/// <summary>
/// Patches subverter ahead of everything else
/// This is done as we attach to the assembly loading function
/// </summary>
public static void PatchSubverter()
private static IEnumerable<string> GetSubverters()
{
if (_subverter != null) GamePatcher.Patch(new List<SubverterPatch>() { _subverter });
string directoryPath = Path.Combine(Directory.GetCurrentDirectory(), "Marsey");
MarseyLogger.Log(MarseyLogger.LogType.DEBG, "Subversion", $"Loading from {directoryPath}");

List<string> patches = Marserializer.Deserialize(new string[] { directoryPath }, Subverter.MarserializerFile) ?? new List<string>();

foreach (string filePath in patches)
{
yield return filePath;
}
}
private static void AssignSubverter(SubverterPatch subverter)

private static MethodInfo? CheckEntry(Assembly assembly)
{
_subverter = subverter;
Type? entryType = assembly.GetType("MarseyEntry");
if (entryType == null) return null;

MethodInfo? entryMethod = AssemblyFieldHandler.GetEntry(assembly, entryType);
return entryMethod != null ? entryMethod : null;
}
}
6 changes: 0 additions & 6 deletions Marsey/Subversion/Subverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,5 @@ public SubverterPatch(string asmpath, Assembly asm, string name, string desc)
Name = name;
Desc = desc;
Asm = asm;

if (Subverse.CheckSubverterDuplicate(this))
{
throw new PatchAssemblyException(
"Tried to create a SubverterPatch that is the same as Subverter! Remove Subverter.dll from the patches folder!");
}
}
}
26 changes: 0 additions & 26 deletions SS14.Launcher/ViewModels/MainWindowTabs/PatchesTabViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ namespace SS14.Launcher.ViewModels.MainWindowTabs
public class PatchesTabViewModel : MainWindowTabViewModel
{
public override string Name => "Plugins";
public bool SubverterPresent { get; set; }
public ObservableCollection<MarseyPatch> MarseyPatches { get; } = new ObservableCollection<MarseyPatch>();
public ObservableCollection<SubverterPatch> SubverterPatches { get; } = new ObservableCollection<SubverterPatch>();

public ICommand OpenPatchDirectoryCommand { get; }

public PatchesTabViewModel()
{
SubverterPresent = Subverse.CheckSubverterPresent();
OpenPatchDirectoryCommand = new RelayCommand(() => OpenPatchDirectory(MarseyVars.MarseyPatchFolder));
LoadPatches();
}
Expand All @@ -38,8 +36,6 @@ private void LoadPatches()
List<MarseyPatch> marseys = Marsyfier.GetMarseyPatches();
LoadPatchList(marseys, MarseyPatches, "marseypatches");

if (!SubverterPresent) return;

List<SubverterPatch> subverters = Subverter.GetSubverterPatches();
LoadPatchList(subverters, SubverterPatches, "subverterpatches");
}
Expand Down Expand Up @@ -79,28 +75,6 @@ public class PathToFileNameConverter : IValueConverter
}
}

public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is bool booleanValue)
{
return booleanValue;
}
throw new InvalidOperationException("Invalid boolean value");
}

public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value == null) throw new ArgumentNullException(nameof(value));
if (value is bool visibilityValue)
{
return visibilityValue;
}
throw new InvalidOperationException("Invalid visibility value");
}
}

public class BooleanToPreloadConverter : IValueConverter
{
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
Expand Down
1 change: 0 additions & 1 deletion SS14.Launcher/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public MainWindowViewModel()

HarmonyManager.Init(new Harmony(MarseyVars.Identifier));
Hidesey.Initialize();
Subverse.InitSubverter();

ServersTab = new ServerListTabViewModel(this);
NewsTab = new NewsTabViewModel();
Expand Down
3 changes: 1 addition & 2 deletions SS14.Launcher/Views/MainWindowTabs/PatchesTabView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
x:Class="SS14.Launcher.Views.MainWindowTabs.PatchesTabView"
Name="PatchesTab">
<UserControl.Resources>
<global:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<global:PathToFileNameConverter x:Key="PathToFileNameConverter"/>
<global:BooleanToPreloadConverter x:Key="BooleanToPreloadConverter"/>
</UserControl.Resources>
Expand Down Expand Up @@ -46,7 +45,7 @@
</ScrollViewer>
</TabItem>

<TabItem Header="Subverter" IsVisible="{Binding SubverterPresent, Converter={StaticResource BooleanToVisibilityConverter}}">
<TabItem Header="Subverter">
<ScrollViewer HorizontalScrollBarVisibility="Disabled">
<StackPanel>
<TextBlock Margin="4, 0" Text="Sideloading" Classes="NanoHeadingMedium" />
Expand Down

0 comments on commit 2b5c8b8

Please sign in to comment.