Decompiled source of BetterBulletTrails v1.0.0

BepInEx/plugins/BetterBulletTrails/BetterBulletTrails.dll

Decompiled 18 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ComputerysModdingUtilities;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BetterBulletTrails")]
[assembly: AssemblyDescription("STRAFTAT: thinner, more transparent bullet trails for your own shots (client-side).")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: StraftatMod(true)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BetterBulletTrails;

[BepInPlugin("dorsth.straftat.betterbullettrails", "BetterBulletTrails", "1.0.0")]
public sealed class BetterBulletTrailsPlugin : BaseUnityPlugin
{
	public const string Guid = "dorsth.straftat.betterbullettrails";

	public const string Name = "BetterBulletTrails";

	public const string Version = "1.0.0";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> Width;

	internal static ConfigEntry<float> Opacity;

	private void Awake()
	{
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Expected O, but got Unknown
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Expected O, but got Unknown
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Log.LogMessage((object)"Dorsth was here");
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Change the look of your own bullet trails. Only affects your own screen.");
		Width = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Width", 0.5f, new ConfigDescription("Width of your own bullet trails compared to normal (0.5 = half as wide).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
		Opacity = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Opacity", 0.5f, new ConfigDescription("Opacity of your own bullet trails compared to normal (0.5 = half as opaque).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		TrailPatcher.Install(new Harmony("dorsth.straftat.betterbullettrails"));
	}
}
internal static class TrailPatcher
{
	private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private const BindingFlags AnyStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

	private const string TrailRpcPrefix = "RpcLogic___SpawnBulletTrail_";

	private static FieldInfo _trailField;

	private static PropertyInfo _isOwner;

	private static readonly Dictionary<int, LineRenderer> Templates = new Dictionary<int, LineRenderer>();

	private static readonly HashSet<int> TemplateIds = new HashSet<int>();

	private static GameObject _templateHolder;

	private static bool _errorLogged;

	private static bool _materialLogged;

	private static ManualLogSource Log => BetterBulletTrailsPlugin.Log;

	internal static void Install(Harmony harmony)
	{
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Expected O, but got Unknown
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Expected O, but got Unknown
		try
		{
			Type type = FindGameType("Weapon");
			if (type == null)
			{
				Log.LogError((object)"Couldn't find the game's Weapon class, so the mod is inactive. (Did the game update?)");
				return;
			}
			_trailField = FindField(type, "bulletTrailLocal", typeof(LineRenderer));
			_isOwner = type.GetProperty("IsOwner", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (_trailField == null || _isOwner == null || _isOwner.PropertyType != typeof(bool))
			{
				Log.LogError((object)"Couldn't find Weapon.bulletTrailLocal / IsOwner, so the mod is inactive. (Did the game update?)");
				return;
			}
			List<string> list = new List<string>();
			HarmonyMethod val = new HarmonyMethod(typeof(TrailPatcher).GetMethod("SwapPrefix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
			HarmonyMethod val2 = new HarmonyMethod(typeof(TrailPatcher).GetMethod("RestorePostfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
			foreach (Type item in LoadableTypes(type.Assembly))
			{
				if (!type.IsAssignableFrom(item))
				{
					continue;
				}
				MethodInfo methodInfo = null;
				MethodInfo methodInfo2 = null;
				MethodInfo[] methods = item.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo3 in methods)
				{
					if (methodInfo3.Name.StartsWith("RpcLogic___SpawnBulletTrail_", StringComparison.Ordinal))
					{
						methodInfo2 = methodInfo3;
					}
					else if (methodInfo3.Name == "SpawnBulletTrail")
					{
						methodInfo = methodInfo3;
					}
				}
				MethodInfo methodInfo4 = methodInfo2 ?? methodInfo;
				if (!(methodInfo4 == null) && !methodInfo4.IsAbstract)
				{
					try
					{
						harmony.Patch((MethodBase)methodInfo4, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						list.Add(item.Name);
					}
					catch (Exception ex)
					{
						Log.LogError((object)("Failed to hook " + item.Name + "." + methodInfo4.Name + ": " + ex.Message));
					}
				}
			}
			if (list.Count == 0)
			{
				Log.LogError((object)"Couldn't find any bullet trail code, so the mod is inactive. (Did the game update?)");
				return;
			}
			list.Sort(StringComparer.Ordinal);
			Log.LogInfo((object)("Ready. Hooked bullet trails for: " + string.Join(", ", list.ToArray()) + "."));
			BetterBulletTrailsPlugin.Width.SettingChanged += delegate
			{
				ClearTemplates();
			};
			BetterBulletTrailsPlugin.Opacity.SettingChanged += delegate
			{
				ClearTemplates();
			};
		}
		catch (Exception ex2)
		{
			Log.LogError((object)("Failed to set up the bullet trail hooks: " + ex2));
		}
	}

	private static void SwapPrefix(object __instance, out LineRenderer __state)
	{
		__state = null;
		try
		{
			if (!BetterBulletTrailsPlugin.Enabled.Value || __instance == null || !(bool)_isOwner.GetValue(__instance, null))
			{
				return;
			}
			object? value = _trailField.GetValue(__instance);
			LineRenderer val = (LineRenderer)((value is LineRenderer) ? value : null);
			if (!((Object)(object)val == (Object)null) && !TemplateIds.Contains(((Object)val).GetInstanceID()))
			{
				LineRenderer slimTemplate = GetSlimTemplate(val);
				if (!((Object)(object)slimTemplate == (Object)null))
				{
					_trailField.SetValue(__instance, slimTemplate);
					__state = val;
				}
			}
		}
		catch (Exception e)
		{
			LogErrorOnce(e);
		}
	}

	private static void RestorePostfix(object __instance, LineRenderer __state)
	{
		if ((Object)(object)__state == (Object)null)
		{
			return;
		}
		try
		{
			object? value = _trailField.GetValue(__instance);
			LineRenderer val = (LineRenderer)((value is LineRenderer) ? value : null);
			if ((Object)(object)val != (Object)null && TemplateIds.Contains(((Object)val).GetInstanceID()))
			{
				_trailField.SetValue(__instance, __state);
			}
		}
		catch (Exception e)
		{
			LogErrorOnce(e);
		}
	}

	private static LineRenderer GetSlimTemplate(LineRenderer original)
	{
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Expected O, but got Unknown
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Expected O, but got Unknown
		if (Templates.TryGetValue(((Object)original).GetInstanceID(), out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		if ((Object)(object)_templateHolder == (Object)null)
		{
			_templateHolder = new GameObject("BetterBulletTrails_Templates");
			_templateHolder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_templateHolder);
			((Object)_templateHolder).hideFlags = (HideFlags)61;
		}
		GameObject val = (GameObject)Object.Instantiate((Object)(object)((Component)original).gameObject, _templateHolder.transform);
		((Object)val).name = ((Object)((Component)original).gameObject).name;
		float value2 = BetterBulletTrailsPlugin.Width.Value;
		float value3 = BetterBulletTrailsPlugin.Opacity.Value;
		LineRenderer[] componentsInChildren = val.GetComponentsInChildren<LineRenderer>(true);
		foreach (LineRenderer obj in componentsInChildren)
		{
			obj.widthMultiplier *= value2;
			obj.colorGradient = ScaleAlpha(obj.colorGradient, value3);
		}
		MonoBehaviour[] componentsInChildren2 = val.GetComponentsInChildren<MonoBehaviour>(true);
		for (int i = 0; i < componentsInChildren2.Length; i++)
		{
			ScaleColorFields(componentsInChildren2[i], value3);
		}
		value = val.GetComponent<LineRenderer>();
		Templates[((Object)original).GetInstanceID()] = value;
		TemplateIds.Add(((Object)value).GetInstanceID());
		if (!_materialLogged)
		{
			_materialLogged = true;
			Material sharedMaterial = ((Renderer)original).sharedMaterial;
			Log.LogInfo((object)("Slimmed down trail '" + ((Object)((Component)original).gameObject).name + "' (material: " + (((Object)(object)sharedMaterial != (Object)null) ? ((Object)sharedMaterial).name : "none") + ")."));
		}
		return value;
	}

	private static Gradient ScaleAlpha(Gradient gradient, float factor)
	{
		GradientAlphaKey[] alphaKeys = gradient.alphaKeys;
		for (int i = 0; i < alphaKeys.Length; i++)
		{
			alphaKeys[i].alpha *= factor;
		}
		gradient.alphaKeys = alphaKeys;
		return gradient;
	}

	private static void ScaleColorFields(MonoBehaviour script, float factor)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		Type type = ((object)script).GetType();
		while (type != null && type != typeof(MonoBehaviour))
		{
			FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!(fieldInfo.FieldType != typeof(Color)) && !fieldInfo.IsInitOnly && !fieldInfo.IsLiteral)
				{
					Color val = (Color)fieldInfo.GetValue(script);
					val.a *= factor;
					fieldInfo.SetValue(script, val);
				}
			}
			type = type.BaseType;
		}
	}

	private static void ClearTemplates()
	{
		foreach (LineRenderer value in Templates.Values)
		{
			if ((Object)(object)value != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)value).gameObject);
			}
		}
		Templates.Clear();
		TemplateIds.Clear();
	}

	private static IEnumerable<Type> LoadableTypes(Assembly asm)
	{
		try
		{
			return asm.GetTypes();
		}
		catch (ReflectionTypeLoadException ex)
		{
			List<Type> list = new List<Type>();
			Type[] types = ex.Types;
			foreach (Type type in types)
			{
				if (type != null)
				{
					list.Add(type);
				}
			}
			return list;
		}
	}

	private static Type FindGameType(string name)
	{
		Type type = Type.GetType(name + ", Assembly-CSharp", throwOnError: false);
		if (type != null)
		{
			return type;
		}
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			try
			{
				type = assembly.GetType(name, throwOnError: false);
			}
			catch
			{
				type = null;
			}
			if (type != null)
			{
				return type;
			}
		}
		return null;
	}

	private static FieldInfo FindField(Type type, string name, Type expectedType)
	{
		Type type2 = type;
		while (type2 != null)
		{
			FieldInfo field = type2.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				if (!(expectedType == null) && !(field.FieldType == expectedType))
				{
					return null;
				}
				return field;
			}
			type2 = type2.BaseType;
		}
		return null;
	}

	private static void LogErrorOnce(Exception e)
	{
		if (!_errorLogged)
		{
			_errorLogged = true;
			Log.LogError((object)("Bullet trail hook failed (further errors are suppressed): " + e));
		}
	}
}