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));
}
}
}