Decompiled source of GoosCombatOverhaul v2.3.0

BepInEx/patchers/GooCombatOverhaul/GooCombatOverhaul.SdwCompatibilityPatcher.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Collections.Generic;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GooCombatOverhaul.SdwCompatibilityPatcher")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.3.0.0")]
[assembly: AssemblyInformationalVersion("2.3.0")]
[assembly: AssemblyProduct("GooCombatOverhaul.SdwCompatibilityPatcher")]
[assembly: AssemblyTitle("GooCombatOverhaul.SdwCompatibilityPatcher")]
[assembly: AssemblyVersion("2.3.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace GooCombatOverhaul.SdwCompatibilityPatcher
{
	internal enum BroadcastFieldRepair
	{
		Unsupported,
		AlreadyCompatible,
		Restored
	}
	internal static class BroadcastFieldCompatibility
	{
		internal static BroadcastFieldRepair Restore(AssemblyDefinition assembly)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Invalid comparison between Unknown and I4
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			if (((AssemblyNameReference)assembly.Name).Name != "assembly_valheim")
			{
				return BroadcastFieldRepair.Unsupported;
			}
			TypeDefinition type = assembly.MainModule.GetType("ZRoutedRpc");
			if (type == null || ((MemberReference)type).FullName != "ZRoutedRpc")
			{
				return BroadcastFieldRepair.Unsupported;
			}
			FieldDefinition val = null;
			Enumerator<FieldDefinition> enumerator = type.Fields.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					FieldDefinition current = enumerator.Current;
					if (!(((MemberReference)current).Name != "Everybody"))
					{
						if (val != null)
						{
							return BroadcastFieldRepair.Unsupported;
						}
						val = current;
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			if (val == null || !val.IsPublic || !val.IsStatic || (int)((FieldReference)val).FieldType.MetadataType != 10)
			{
				return BroadcastFieldRepair.Unsupported;
			}
			if (!val.IsLiteral)
			{
				return BroadcastFieldRepair.AlreadyCompatible;
			}
			if (!val.HasConstant || !(val.Constant is long num) || num != 0L)
			{
				return BroadcastFieldRepair.Unsupported;
			}
			val.Attributes = (FieldAttributes)((val.Attributes & 0x7FBF) | 0x10 | 0x20);
			val.HasConstant = false;
			return BroadcastFieldRepair.Restored;
		}
	}
	public static class Patcher
	{
		private static string[]? _targetDlls;

		public static IEnumerable<string> TargetDLLs => _targetDlls ?? (_targetDlls = ((!SdwPluginPresence.IsInstalled(Paths.PluginPath)) ? Array.Empty<string>() : new string[1] { "assembly_valheim.dll" }));

		public static void Patch(AssemblyDefinition assembly)
		{
			try
			{
				PatchAndReport(assembly);
			}
			catch (Exception)
			{
			}
		}

		private static void PatchAndReport(AssemblyDefinition assembly)
		{
			ManualLogSource val = Logger.CreateLogSource("GCO SDW API Compatibility");
			try
			{
				BroadcastFieldRepair broadcastFieldRepair;
				try
				{
					broadcastFieldRepair = BroadcastFieldCompatibility.Restore(assembly);
				}
				catch (Exception ex)
				{
					val.LogWarning((object)("Could not inspect ZRoutedRpc.Everybody; no field was changed and SDW ServerSync compatibility was not prepared. " + ex.Message));
					return;
				}
				switch (broadcastFieldRepair)
				{
				case BroadcastFieldRepair.Restored:
					val.LogInfo((object)"Prepared the in-memory ZRoutedRpc.Everybody compatibility field for SDW. Broadcast target remains 0; GCO will verify the loaded field at startup.");
					break;
				case BroadcastFieldRepair.AlreadyCompatible:
					val.LogInfo((object)"ZRoutedRpc.Everybody already supports legacy static-field reads; no compatibility change required.");
					break;
				default:
					val.LogWarning((object)"Unsupported ZRoutedRpc.Everybody declaration. No field was changed; SDW ServerSync compatibility could not be prepared for this game build.");
					break;
				}
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}
	}
	internal static class SdwPluginPresence
	{
		private const string SdwGuid = "org.bepinex.plugins.dualwield";

		private const int MaxNamedFiles = 10;

		internal static bool IsInstalled(string? pluginDirectory)
		{
			List<string> list = new List<string>();
			bool flag = false;
			try
			{
				flag = !string.IsNullOrEmpty(pluginDirectory) && Directory.Exists(pluginDirectory) && ScanDirectory(pluginDirectory, list);
			}
			catch (Exception)
			{
			}
			if (!flag && list.Count > 0)
			{
				WarnUnreadable(list);
			}
			return flag;
		}

		private static bool ScanDirectory(string directory, List<string> unreadable)
		{
			string fileName = Path.GetFileName(directory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
			bool flag = true;
			string[] array;
			try
			{
				array = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly);
			}
			catch (Exception)
			{
				array = new string[0];
				flag = false;
				unreadable.Add(fileName + " (folder)");
			}
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				if (DeclaresSdw(array2[i], unreadable))
				{
					return true;
				}
			}
			string[] directories;
			try
			{
				directories = Directory.GetDirectories(directory);
			}
			catch (Exception)
			{
				if (flag)
				{
					unreadable.Add(fileName + " (subfolders)");
				}
				return false;
			}
			array2 = directories;
			for (int i = 0; i < array2.Length; i++)
			{
				if (ScanDirectory(array2[i], unreadable))
				{
					return true;
				}
			}
			return false;
		}

		private static bool DeclaresSdw(string path, List<string> unreadable)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				AssemblyDefinition val = AssemblyDefinition.ReadAssembly(path, new ReaderParameters
				{
					ReadingMode = (ReadingMode)2,
					ReadSymbols = false
				});
				try
				{
					Enumerator<TypeDefinition> enumerator = val.MainModule.Types.GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							Enumerator<CustomAttribute> enumerator2 = enumerator.Current.CustomAttributes.GetEnumerator();
							try
							{
								while (enumerator2.MoveNext())
								{
									CustomAttribute current = enumerator2.Current;
									TypeReference attributeType = current.AttributeType;
									if (((attributeType != null) ? ((MemberReference)attributeType).FullName : null) == "BepInEx.BepInPlugin" && current.ConstructorArguments.Count == 3)
									{
										CustomAttributeArgument val2 = current.ConstructorArguments[0];
										if (((CustomAttributeArgument)(ref val2)).Value is string a && string.Equals(a, "org.bepinex.plugins.dualwield", StringComparison.Ordinal))
										{
											return true;
										}
									}
								}
							}
							finally
							{
								((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
							}
						}
					}
					finally
					{
						((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
					}
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			catch (BadImageFormatException)
			{
				if (HasCliHeader(path))
				{
					unreadable.Add(Path.GetFileName(path));
				}
			}
			catch (Exception)
			{
				unreadable.Add(Path.GetFileName(path));
			}
			return false;
		}

		private static bool HasCliHeader(string path)
		{
			try
			{
				byte[] array = new byte[4096];
				int num;
				using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
				{
					num = fileStream.Read(array, 0, array.Length);
				}
				if (num < 64 || array[0] != 77 || array[1] != 90)
				{
					return false;
				}
				int num2 = BitConverter.ToInt32(array, 60);
				if (num2 < 0 || num2 + 24 > num || array[num2] != 80 || array[num2 + 1] != 69 || array[num2 + 2] != 0 || array[num2 + 3] != 0)
				{
					return false;
				}
				int num3 = num2 + 24;
				if (num3 + 2 > num)
				{
					return false;
				}
				int num4 = BitConverter.ToUInt16(array, num3) switch
				{
					523 => num3 + 112, 
					267 => num3 + 96, 
					_ => -1, 
				};
				int num5 = num4 + 112;
				if (num4 < 0 || num5 + 8 > num || BitConverter.ToUInt32(array, num4 - 4) < 15)
				{
					return false;
				}
				return BitConverter.ToUInt32(array, num5) != 0 && BitConverter.ToUInt32(array, num5 + 4) != 0;
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static void WarnUnreadable(List<string> unreadable)
		{
			try
			{
				string text = string.Join(", ", unreadable.GetRange(0, Math.Min(unreadable.Count, 10)).ToArray());
				if (unreadable.Count > 10)
				{
					text += $" and {unreadable.Count - 10} more";
				}
				ManualLogSource val = Logger.CreateLogSource("GCO SDW API Compatibility");
				try
				{
					val.LogWarning((object)("These plugin files could not be read: " + text + ". If Smoothbrain Dual Wield is one of them, its sync fix was not prepared."));
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			catch (Exception)
			{
			}
		}
	}
}