Decompiled source of LinuxControllerFix v1.0.0

Plugins/LinuxControllerFix.dll

Decompiled 2 months ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using LinuxControllerFix;
using MelonLoader;
using MelonLoader.Utils;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "LinuxControllerFix", "1.0.0", "Supercopia", null)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: MelonColor(255, 100, 200, 100)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("LinuxControllerFix")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+fe3de839b1893d4f3390067b933aa70958589a4e")]
[assembly: AssemblyProduct("LinuxControllerFix")]
[assembly: AssemblyTitle("LinuxControllerFix")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace LinuxControllerFix;

public class Core : MelonPlugin
{
	private const string TargetExtension = "XR_META_touch_controller_plus";

	private const string PatchedExtension = "AR_META_touch_controller_plus";

	private string _assetsPath;

	private long _patchOffset = -1L;

	private bool _patched;

	public override void OnPreInitialization()
	{
		_assetsPath = FindAssetsFile();
		if (_assetsPath == null)
		{
			((MelonBase)this).LoggerInstance.Warning("Could not find globalgamemanagers.assets — skipping patch.");
			return;
		}
		_patchOffset = FindStringOffset(_assetsPath, "XR_META_touch_controller_plus");
		if (_patchOffset >= 0)
		{
			PatchByte(_assetsPath, _patchOffset, 65);
			_patched = true;
			((MelonBase)this).LoggerInstance.Msg($"Patched {"XR_META_touch_controller_plus"} at offset {_patchOffset} (X -> A).");
		}
		else
		{
			long num = FindStringOffset(_assetsPath, "AR_META_touch_controller_plus");
			if (num >= 0)
			{
				_patchOffset = num;
				_patched = true;
				((MelonBase)this).LoggerInstance.Msg("Extension already patched from a previous run — will restore on exit.");
			}
			else
			{
				((MelonBase)this).LoggerInstance.Msg("XR_META_touch_controller_plus not found in assets — nothing to patch.");
			}
		}
	}

	public override void OnApplicationQuit()
	{
		RestorePatch();
	}

	public override void OnDeinitializeMelon()
	{
		RestorePatch();
	}

	private void RestorePatch()
	{
		if (!_patched || _patchOffset < 0)
		{
			return;
		}
		try
		{
			PatchByte(_assetsPath, _patchOffset, 88);
			((MelonBase)this).LoggerInstance.Msg($"Restored {"XR_META_touch_controller_plus"} at offset {_patchOffset} (A -> X).");
			_patched = false;
		}
		catch (Exception ex)
		{
			((MelonBase)this).LoggerInstance.Error("Failed to restore patch: " + ex.Message);
		}
	}

	private static string FindAssetsFile()
	{
		string text = Path.Combine(MelonEnvironment.GameRootDirectory, "RUMBLE_Data", "globalgamemanagers.assets");
		if (File.Exists(text))
		{
			return text;
		}
		text = Path.Combine("RUMBLE_Data", "globalgamemanagers.assets");
		if (File.Exists(text))
		{
			return text;
		}
		return null;
	}

	private static long FindStringOffset(string filePath, string target)
	{
		byte[] bytes = Encoding.ASCII.GetBytes(target);
		byte[] array = new byte[65536];
		int num = bytes.Length;
		using FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
		long length = fileStream.Length;
		int num3;
		int num4;
		for (long num2 = 0L; num2 < length; num2 += num4 - ((num2 > 0) ? num3 : 0))
		{
			num3 = ((num2 > 0) ? (num - 1) : 0);
			if (num3 > 0)
			{
				fileStream.Position = num2 - num3;
			}
			else
			{
				fileStream.Position = num2;
			}
			num4 = fileStream.Read(array, 0, array.Length);
			if (num4 == 0)
			{
				break;
			}
			int num5 = ((num2 > 0) ? num3 : 0);
			for (int i = num5; i <= num4 - num; i++)
			{
				bool flag = true;
				for (int j = 0; j < num; j++)
				{
					if (array[i + j] != bytes[j])
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					return ((num2 > 0) ? (num2 - num3) : 0) + i;
				}
			}
		}
		return -1L;
	}

	private static void PatchByte(string filePath, long offset, byte value)
	{
		using FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Write, FileShare.ReadWrite);
		fileStream.Position = offset;
		fileStream.WriteByte(value);
	}
}