using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using PerfectRandom.Sulfur.Core.Stats; using PerfectRandom.Sulfur.Core.Units; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SulfurDamageNumbersMod")] [assembly: AssemblyDescription("SULFUR damage numbers mod for BepInEx 5")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("ryuka_labs")] [assembly: AssemblyProduct("SulfurDamageNumbersMod")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c9ebec31-296a-4d97-9959-9804ea595a74")] [assembly: AssemblyFileVersion("1.0.6.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.6.0")] namespace SulfurDamageNumbersMod; internal static class DamageLogPatch { private static bool _applied; public static void Apply(Harmony harmony) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown if (!_applied) { MethodBase methodBase = TargetMethod(); if (methodBase == null) { Plugin.Log.LogError((object)"SULFUR Damage Numbers failed: Unit.CreateDamageLog(float, float, DamageTypes, Data, DamageSourceData) was not found."); return; } harmony.Patch(methodBase, (HarmonyMethod)null, new HarmonyMethod(typeof(DamageLogPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _applied = true; Plugin.Log.LogInfo((object)("SULFUR Damage Numbers patched " + methodBase.DeclaringType.FullName + "." + methodBase.Name + ".")); } } private static MethodBase TargetMethod() { return AccessTools.GetDeclaredMethods(typeof(Unit)).FirstOrDefault(delegate(MethodInfo m) { if (m.Name != "CreateDamageLog") { return false; } ParameterInfo[] parameters = m.GetParameters(); return parameters.Length == 5 && parameters[0].ParameterType == typeof(float) && parameters[1].ParameterType == typeof(float) && parameters[2].ParameterType == typeof(DamageTypes) && parameters[4].ParameterType == typeof(DamageSourceData); }); } private static void Postfix(Unit __instance, float __0, float __1, DamageTypes __2, object __3, DamageSourceData __4) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || !Plugin.Enabled.Value) { return; } try { float num = __0; if (num < Plugin.MinDamageToShow.Value) { if (Plugin.DebugLog.Value) { Plugin.Log.LogInfo((object)("[DamageNumbers] reject low damage amount=" + num + " target=" + SafeName((Object)(object)__instance))); } return; } if (!IsAllowedTarget(__instance, out var reason)) { if (Plugin.DebugLog.Value) { Plugin.Log.LogInfo((object)("[DamageNumbers] reject target: " + reason + " target=" + SafeName((Object)(object)__instance))); } return; } if (!IsPlayerExecutedAttack(__4, out reason)) { if (Plugin.DebugLog.Value) { Plugin.Log.LogInfo((object)("[DamageNumbers] reject source: " + reason + " target=" + SafeName((Object)(object)__instance) + " source=" + DescribeSource(__4))); } return; } float hitMultiplier = DamageNumberColor.ResolveHitMultiplier(__3); if (Plugin.DebugLog.Value) { Plugin.Log.LogInfo((object)("[DamageNumbers] accept amount=" + num + " multiplier=" + hitMultiplier + " target=" + SafeName((Object)(object)__instance) + " source=" + DescribeSource(__4))); } DamageNumberManager.RegisterDamage(__instance, __4, num, hitMultiplier); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[DamageNumbers] CreateDamageLog postfix failed: " + ex)); } } private static bool IsAllowedTarget(Unit target, out string reason) { if (target.isPlayer) { reason = "target is player"; return false; } if (Plugin.RequireNpcTarget.Value && !(target is Npc)) { reason = "target is not Npc"; return false; } reason = null; return true; } private static bool IsPlayerExecutedAttack(DamageSourceData sourceData, out string reason) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if (!sourceData.isPlayer) { reason = "sourceData.isPlayer is false"; return false; } if (Plugin.RequireSourceUnitPlayer.Value) { if ((Object)(object)sourceData.sourceUnit == (Object)null) { reason = "sourceUnit is null"; return false; } if (!sourceData.sourceUnit.isPlayer) { reason = "sourceUnit is not player"; return false; } } if ((Object)(object)sourceData.sourceWeapon != (Object)null) { reason = null; return true; } if (sourceData.melee) { reason = null; return true; } if (Plugin.ShowPlayerOwnedSecondaryEffects.Value && !sourceData.states.notCreatedByPlayer) { reason = null; return true; } reason = "no weapon/melee/player-owned secondary marker"; return false; } private static string DescribeSource(DamageSourceData sourceData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) string text = (((Object)(object)sourceData.sourceUnit == (Object)null) ? "null" : SafeName((Object)(object)sourceData.sourceUnit)); string text2 = (((Object)(object)sourceData.sourceWeapon == (Object)null) ? "null" : ((Object)sourceData.sourceWeapon).name); return "isPlayer=" + sourceData.isPlayer + ", melee=" + sourceData.melee + ", weapon=" + text2 + ", unit=" + text + ", instanceId=" + sourceData.instanceId + ", name=" + sourceData.name; } private static string SafeName(Object obj) { return (obj == (Object)null) ? "null" : obj.name; } } internal sealed class DamageNumberManager : MonoBehaviour { private struct AggregateEntry { public float Amount; public Vector3 Position; public int Frame; public float HighestMultiplier; public float LastMultiplier; public float WeightedMultiplierSum; } private struct PerHitSpreadOffset { public static readonly PerHitSpreadOffset Zero = new PerHitSpreadOffset { WorldOffset = Vector3.zero, ScreenOffset = Vector2.zero }; public Vector3 WorldOffset; public Vector2 ScreenOffset; } private sealed class ScreenEntry { public string Text; public Vector3 WorldPosition; public Vector2 ScreenPosition; public Vector2 ScreenJitter; public float StartTime; public float Lifetime; public bool FixedScreen; public Color Color; } private static DamageNumberManager _instance; private readonly Dictionary _aggregates = new Dictionary(); private readonly List _flushBuffer = new List(); private readonly List _screenEntries = new List(); private readonly Dictionary _perHitSpreadCounters = new Dictionary(); private int _perHitSpreadFrame = -1; private GUIStyle _screenStyle; private GUIStyle _outlineStyle; public static void EnsureExists() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("SULFUR Damage Number Manager"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent(); } } public static void RegisterDamage(Unit target, DamageSourceData sourceData, float amount, float hitMultiplier) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) EnsureExists(); _instance.RegisterDamageInternal(target, sourceData, amount, hitMultiplier); } public static void SpawnScreenTestNumber() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) EnsureExists(); _instance.SpawnScreenFixed("999", new Vector2((float)Screen.width * 0.5f, (float)Screen.height * 0.45f), DamageNumberColor.ForMultiplier(0f)); } private void Update() { if (Plugin.DebugSpawnTestOnF8.Value && InputCompat.GetKeyDown((KeyCode)289)) { SpawnScreenTestNumber(); if (Plugin.DebugLog.Value) { Plugin.Log.LogInfo((object)"[DamageNumbers] F8 test number spawned."); } } } private void RegisterDamageInternal(Unit target, DamageSourceData sourceData, float amount, float hitMultiplier) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) Vector3 damagePosition = GetDamagePosition(target); if (Plugin.Mode.Value == DisplayMode.PerHit) { PerHitSpreadOffset nextPerHitSpread = GetNextPerHitSpread(target, sourceData); SpawnNumber(damagePosition, amount, hitMultiplier, useJitter: true, nextPerHitSpread.WorldOffset, nextPerHitSpread.ScreenOffset); return; } AggregateKey key = AggregateKey.Create(target, sourceData); if (!_aggregates.TryGetValue(key, out var value)) { AggregateEntry aggregateEntry = default(AggregateEntry); aggregateEntry.Amount = 0f; aggregateEntry.Position = damagePosition; aggregateEntry.Frame = Time.frameCount; aggregateEntry.HighestMultiplier = 0f; aggregateEntry.LastMultiplier = 0f; aggregateEntry.WeightedMultiplierSum = 0f; value = aggregateEntry; } value.Amount += amount; value.Position = damagePosition; value.Frame = Time.frameCount; value.LastMultiplier = hitMultiplier; value.WeightedMultiplierSum += Mathf.Max(0f, hitMultiplier) * Mathf.Max(0f, amount); if (hitMultiplier > value.HighestMultiplier) { value.HighestMultiplier = hitMultiplier; } _aggregates[key] = value; } private void LateUpdate() { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if (_aggregates.Count == 0) { return; } _flushBuffer.Clear(); foreach (KeyValuePair aggregate in _aggregates) { if (aggregate.Value.Frame <= Time.frameCount) { _flushBuffer.Add(aggregate.Key); } } for (int i = 0; i < _flushBuffer.Count; i++) { AggregateKey key = _flushBuffer[i]; if (_aggregates.TryGetValue(key, out var value)) { SpawnNumber(value.Position, value.Amount, ResolveAggregateMultiplier(value), useJitter: false, Vector3.zero, Vector2.zero); _aggregates.Remove(key); } } } private void OnGUI() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: 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_0101: Unknown result type (might be due to invalid IL or missing references) if (_screenEntries.Count == 0) { return; } EnsureGuiStyles(); Camera main = Camera.main; float time = Time.time; Vector2 val = default(Vector2); Color textColor = default(Color); Rect r = default(Rect); for (int num = _screenEntries.Count - 1; num >= 0; num--) { ScreenEntry screenEntry = _screenEntries[num]; float num2 = time - screenEntry.StartTime; if (num2 >= screenEntry.Lifetime) { _screenEntries.RemoveAt(num); continue; } if (screenEntry.FixedScreen) { val = screenEntry.ScreenPosition; } else { if ((Object)(object)main == (Object)null) { continue; } Vector3 val2 = screenEntry.WorldPosition + Vector3.up * (num2 * 0.25f); Vector3 val3 = main.WorldToScreenPoint(val2); if (val3.z <= 0f) { continue; } ((Vector2)(ref val))..ctor(val3.x, (float)Screen.height - val3.y); } val += screenEntry.ScreenJitter; val.y -= num2 * Plugin.ScreenFloatSpeed.Value; float num3 = Mathf.Clamp01(1f - num2 / screenEntry.Lifetime); Color color = screenEntry.Color; color.a = num3; ((Color)(ref textColor))..ctor(0f, 0f, 0f, num3); ((Rect)(ref r))..ctor(val.x - 100f, val.y - 32f, 200f, 64f); _outlineStyle.normal.textColor = textColor; _screenStyle.normal.textColor = color; DrawOutlinedLabel(r, screenEntry.Text); } } private void DrawOutlinedLabel(Rect r, string text) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) Rect val = r; ((Rect)(ref val)).x = ((Rect)(ref val)).x - 2f; GUI.Label(val, text, _outlineStyle); val = r; ((Rect)(ref val)).x = ((Rect)(ref val)).x + 2f; GUI.Label(val, text, _outlineStyle); val = r; ((Rect)(ref val)).y = ((Rect)(ref val)).y - 2f; GUI.Label(val, text, _outlineStyle); val = r; ((Rect)(ref val)).y = ((Rect)(ref val)).y + 2f; GUI.Label(val, text, _outlineStyle); GUI.Label(r, text, _screenStyle); } private void EnsureGuiStyles() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown int num = Mathf.Max(8, Plugin.ScreenFontSize.Value); if (_screenStyle == null || _screenStyle.fontSize != num) { _screenStyle = new GUIStyle(GUI.skin.label); _screenStyle.alignment = (TextAnchor)4; _screenStyle.fontStyle = (FontStyle)1; _screenStyle.fontSize = num; _screenStyle.clipping = (TextClipping)0; _outlineStyle = new GUIStyle(_screenStyle); } } private static Vector3 GetDamagePosition(Unit target) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) Npc val = (Npc)(object)((target is Npc) ? target : null); if ((Object)(object)val != (Object)null && (Object)(object)val.overhead != (Object)null) { return val.overhead.position; } return ((Component)target).transform.position + Vector3.up * 2f; } private PerHitSpreadOffset GetNextPerHitSpread(Unit target, DamageSourceData sourceData) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) if (_perHitSpreadFrame != Time.frameCount) { _perHitSpreadFrame = Time.frameCount; _perHitSpreadCounters.Clear(); } PerHitSpreadKey key = PerHitSpreadKey.Create(target, sourceData); if (!_perHitSpreadCounters.TryGetValue(key, out var value)) { value = 0; } _perHitSpreadCounters[key] = value + 1; if (value <= 0) { return PerHitSpreadOffset.Zero; } float num = (float)value * 2.3999631f; float num2 = Mathf.Sqrt((float)value); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(Mathf.Cos(num), Mathf.Sin(num)); float num3 = Mathf.Min(42f, Mathf.Max(0f, Plugin.PerHitStackScreenSpread.Value) * num2); float num4 = Mathf.Min(0.36f, Mathf.Max(0f, Plugin.PerHitStackWorldSpread.Value) * num2); PerHitSpreadOffset result = default(PerHitSpreadOffset); result.ScreenOffset = val * num3; result.WorldOffset = new Vector3(val.x * num4, 0f, val.y * num4); return result; } private static void SpawnNumber(Vector3 position, float amount, float hitMultiplier, bool useJitter, Vector3 extraWorldJitter, Vector2 extraScreenJitter) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) string text = FormatDamage(amount); Color color = DamageNumberColor.ForMultiplier(hitMultiplier); Vector3 val = extraWorldJitter; Vector2 val2 = extraScreenJitter; if (useJitter) { if (Plugin.RandomJitter.Value > 0f) { Vector2 val3 = Random.insideUnitCircle * Plugin.RandomJitter.Value; val += new Vector3(val3.x, 0f, val3.y); } if (Plugin.ScreenJitter.Value > 0f) { val2 += Random.insideUnitCircle * Plugin.ScreenJitter.Value; } } if (Plugin.Renderer.Value == RenderMode.ScreenSpace || Plugin.Renderer.Value == RenderMode.Both) { _instance.SpawnScreenWorld(text, position, val2, color); } if (Plugin.Renderer.Value == RenderMode.WorldTextMeshPro || Plugin.Renderer.Value == RenderMode.Both) { GameObject val4 = new GameObject("SULFUR Damage Number"); DamageNumberView damageNumberView = val4.AddComponent(); damageNumberView.Init(text, position, val, Plugin.Lifetime.Value, Plugin.FloatSpeed.Value, Plugin.WorldScale.Value, Plugin.FontSize.Value, color); } } private void SpawnScreenWorld(string text, Vector3 worldPosition, Vector2 jitter, Color color) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) TrimOldScreenEntriesIfNeeded(); _screenEntries.Add(new ScreenEntry { Text = text, WorldPosition = worldPosition, ScreenJitter = jitter, StartTime = Time.time, Lifetime = Mathf.Max(0.05f, Plugin.Lifetime.Value), FixedScreen = false, Color = color }); } private void SpawnScreenFixed(string text, Vector2 screenPosition, Color color) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) TrimOldScreenEntriesIfNeeded(); _screenEntries.Add(new ScreenEntry { Text = text, ScreenPosition = screenPosition, ScreenJitter = Vector2.zero, StartTime = Time.time, Lifetime = Mathf.Max(0.05f, Plugin.Lifetime.Value), FixedScreen = true, Color = color }); } private void TrimOldScreenEntriesIfNeeded() { int num = Mathf.Max(1, Plugin.MaxActiveNumbers.Value); while (_screenEntries.Count >= num) { _screenEntries.RemoveAt(0); } } private static string FormatDamage(float amount) { if (Plugin.ShowDecimals.Value) { float num = Mathf.Round(amount * 10f) / 10f; float num2 = Mathf.Round(num); if (Mathf.Abs(num - num2) <= 0.0001f) { int num3 = Mathf.RoundToInt(num2); if (num3 <= 0 && amount > 0f) { num3 = 1; } return num3.ToString(CultureInfo.InvariantCulture); } return num.ToString("0.0", CultureInfo.InvariantCulture); } int num4 = Mathf.RoundToInt(amount); if (num4 <= 0) { num4 = 1; } return num4.ToString(CultureInfo.InvariantCulture); } private static float ResolveAggregateMultiplier(AggregateEntry entry) { switch (Plugin.AggregateColorMode.Value) { case MergedColorMode.LastHit: return entry.LastMultiplier; case MergedColorMode.DamageWeightedAverage: if (entry.Amount > 0.0001f) { return entry.WeightedMultiplierSum / entry.Amount; } return entry.HighestMultiplier; default: return entry.HighestMultiplier; } } } internal struct PerHitSpreadKey : IEquatable { private int _targetId; private int _frame; private int _sourceId; public static PerHitSpreadKey Create(Unit target, DamageSourceData sourceData) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) int sourceId = 0; if ((Object)(object)sourceData.sourceWeapon != (Object)null) { sourceId = ((Object)sourceData.sourceWeapon).GetInstanceID(); } else if (sourceData.instanceId != 0) { sourceId = sourceData.instanceId; } else if ((Object)(object)sourceData.sourceUnit != (Object)null) { sourceId = ((Object)sourceData.sourceUnit).GetInstanceID(); } PerHitSpreadKey result = default(PerHitSpreadKey); result._targetId = ((Object)target).GetInstanceID(); result._frame = Time.frameCount; result._sourceId = sourceId; return result; } public bool Equals(PerHitSpreadKey other) { return _targetId == other._targetId && _frame == other._frame && _sourceId == other._sourceId; } public override bool Equals(object obj) { return obj is PerHitSpreadKey && Equals((PerHitSpreadKey)obj); } public override int GetHashCode() { int targetId = _targetId; targetId = (targetId * 397) ^ _frame; return (targetId * 397) ^ _sourceId; } } internal struct AggregateKey : IEquatable { private int _targetId; private int _frame; private int _sourceId; private int _damageType; private bool _melee; public static AggregateKey Create(Unit target, DamageSourceData sourceData) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) int sourceId = 0; if ((Object)(object)sourceData.sourceWeapon != (Object)null) { sourceId = ((Object)sourceData.sourceWeapon).GetInstanceID(); } else if (sourceData.instanceId != 0) { sourceId = sourceData.instanceId; } else if ((Object)(object)sourceData.sourceUnit != (Object)null) { sourceId = ((Object)sourceData.sourceUnit).GetInstanceID(); } AggregateKey result = default(AggregateKey); result._targetId = ((Object)target).GetInstanceID(); result._frame = Time.frameCount; result._sourceId = sourceId; result._damageType = Convert.ToInt32(sourceData.damageType); result._melee = sourceData.melee; return result; } public bool Equals(AggregateKey other) { return _targetId == other._targetId && _frame == other._frame && _sourceId == other._sourceId && _damageType == other._damageType && _melee == other._melee; } public override bool Equals(object obj) { return obj is AggregateKey && Equals((AggregateKey)obj); } public override int GetHashCode() { int targetId = _targetId; targetId = (targetId * 397) ^ _frame; targetId = (targetId * 397) ^ _sourceId; targetId = (targetId * 397) ^ _damageType; return (targetId * 397) ^ (_melee ? 1 : 0); } } internal static class DamageNumberColor { private static readonly Color NormalDamageColor = Color.white; private static readonly Color OrangeDamageColor = new Color(1f, 0.5f, 0f, 1f); private static MethodInfo _getShapeMultiplierMethod; private static Type _cachedHitDataType; public static float ResolveHitMultiplier(object hitData) { if (hitData == null) { return 0f; } try { Type type = hitData.GetType(); MethodInfo shapeMultiplierMethod = GetShapeMultiplierMethod(type); if (shapeMultiplierMethod == null) { return 0f; } object obj = shapeMultiplierMethod.Invoke(hitData, null); if (obj is float) { return Mathf.Max(0f, (float)obj); } if (obj is double) { return Mathf.Max(0f, (float)(double)obj); } } catch { return 0f; } return 0f; } public static Color ForMultiplier(float multiplier) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.UseWeakspotColors.Value) { return NormalDamageColor; } if (multiplier <= 0f) { return NormalDamageColor; } if (Plugin.TreatOneMultiplierAsNormal.Value && Mathf.Abs(multiplier - 1f) <= 0.0001f) { return NormalDamageColor; } if (multiplier >= 1.5f) { return Color.red; } if (multiplier >= 1f) { return OrangeDamageColor; } if (multiplier >= 0.75f) { return Color.yellow; } return NormalDamageColor; } private static MethodInfo GetShapeMultiplierMethod(Type type) { if (type == null) { return null; } if (_cachedHitDataType == type) { return _getShapeMultiplierMethod; } _cachedHitDataType = type; _getShapeMultiplierMethod = type.GetMethod("GetShapeMultiplier", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); return _getShapeMultiplierMethod; } } internal static class InputCompat { private static readonly MethodInfo GetKeyDownMethod = FindGetKeyDownMethod(); public static bool GetKeyDown(KeyCode key) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (GetKeyDownMethod == null) { return false; } try { object obj = GetKeyDownMethod.Invoke(null, new object[1] { key }); return obj is bool && (bool)obj; } catch { return false; } } private static MethodInfo FindGetKeyDownMethod() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("UnityEngine.Input", throwOnError: false); if (!(type == null)) { MethodInfo method = type.GetMethod("GetKeyDown", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(KeyCode) }, null); if (method != null) { return method; } } } return null; } } internal sealed class DamageNumberView : MonoBehaviour { private TextMeshPro _text; private Vector3 _basePosition; private Vector3 _jitter; private float _startTime; private float _lifetime; private float _floatSpeed; private Color _baseColor; public void Init(string value, Vector3 position, Vector3 jitter, float lifetime, float floatSpeed, float worldScale, float fontSize, Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) _basePosition = position; _jitter = jitter; _startTime = Time.time; _lifetime = Mathf.Max(0.05f, lifetime); _floatSpeed = floatSpeed; _baseColor = color; ((Component)this).transform.position = position + jitter; ((Component)this).transform.localScale = Vector3.one * worldScale; _text = ((Component)this).gameObject.AddComponent(); ((TMP_Text)_text).text = value; ((TMP_Text)_text).fontSize = fontSize; ((TMP_Text)_text).alignment = (TextAlignmentOptions)514; ((TMP_Text)_text).textWrappingMode = (TextWrappingModes)0; ((Graphic)_text).color = _baseColor; } private void LateUpdate() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) float num = Time.time - _startTime; if (num >= _lifetime) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } ((Component)this).transform.position = _basePosition + _jitter + Vector3.up * (num * _floatSpeed); Camera main = Camera.main; if ((Object)(object)main != (Object)null) { Vector3 val = ((Component)this).transform.position - ((Component)main).transform.position; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f) { ((Component)this).transform.rotation = Quaternion.LookRotation(val, ((Component)main).transform.up); } } float a = Mathf.Clamp01(1f - num / _lifetime); Color baseColor = _baseColor; baseColor.a = a; ((Graphic)_text).color = baseColor; } } internal static class DamageReceivePatch { public static void Apply(Harmony harmony) { DamageLogPatch.Apply(harmony); } } [BepInPlugin("ryuka.sulfur.damagenumbers", "SULFUR Damage Numbers", "1.0.7")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "ryuka.sulfur.damagenumbers"; public const string PluginName = "SULFUR Damage Numbers"; public const string PluginVersion = "1.0.7"; internal static ConfigEntry Enabled; internal static ConfigEntry Mode; internal static ConfigEntry Renderer; internal static ConfigEntry AggregateColorMode; internal static ConfigEntry UseWeakspotColors; internal static ConfigEntry TreatOneMultiplierAsNormal; internal static ConfigEntry RequireNpcTarget; internal static ConfigEntry RequireSourceUnitPlayer; internal static ConfigEntry ShowPlayerOwnedSecondaryEffects; internal static ConfigEntry MinDamageToShow; internal static ConfigEntry ShowDecimals; internal static ConfigEntry Lifetime; internal static ConfigEntry FloatSpeed; internal static ConfigEntry WorldScale; internal static ConfigEntry RandomJitter; internal static ConfigEntry FontSize; internal static ConfigEntry ScreenFontSize; internal static ConfigEntry ScreenFloatSpeed; internal static ConfigEntry ScreenJitter; internal static ConfigEntry PerHitStackScreenSpread; internal static ConfigEntry PerHitStackWorldSpread; internal static ConfigEntry MaxActiveNumbers; internal static ConfigEntry DebugLog; internal static ConfigEntry DebugSpawnTestOnF8; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable damage number display."); Mode = ((BaseUnityPlugin)this).Config.Bind("General", "DamageDisplayMode", DisplayMode.PerTargetTotal, "PerTargetTotal = same frame, same player attack source, same target damage is merged. PerHit = every real damage log call creates one number."); Renderer = ((BaseUnityPlugin)this).Config.Bind("Visual", "Renderer", RenderMode.ScreenSpace, "ScreenSpace is the most reliable renderer. WorldTextMeshPro uses 3D TextMeshPro objects. Both renders both at the same time for debugging."); UseWeakspotColors = ((BaseUnityPlugin)this).Config.Bind("Visual", "UseWeakspotColors", true, "Use weakspot/body-part multiplier colors. The color thresholds match the PositiveShapes debug overlay style: red >= 1.5, orange >= 1.0, yellow >= 0.75, white when no multiplier is available."); TreatOneMultiplierAsNormal = ((BaseUnityPlugin)this).Config.Bind("Visual", "TreatOneMultiplierAsNormal", false, "If true, multiplier 1.0 is shown as white instead of orange. Enable this if the game reports ordinary body hits as multiplier 1.0 and you want only special weakpoints colored."); AggregateColorMode = ((BaseUnityPlugin)this).Config.Bind("Visual", "AggregateColorMode", MergedColorMode.HighestMultiplier, "Color rule for PerTargetTotal. HighestMultiplier = use the strongest pellet/hit color. DamageWeightedAverage = average multipliers by damage. LastHit = use the last hit color."); RequireNpcTarget = ((BaseUnityPlugin)this).Config.Bind("Filter", "RequireNpcTarget", true, "Only show damage numbers on Npc targets. Keep true to avoid barrels/objects if they also use Unit damage code."); RequireSourceUnitPlayer = ((BaseUnityPlugin)this).Config.Bind("Filter", "RequireSourceUnitPlayer", false, "If true, sourceData.sourceUnit must exist and be the player. Default false because some projectiles/explosions keep only the game's isPlayer flag."); ShowPlayerOwnedSecondaryEffects = ((BaseUnityPlugin)this).Config.Bind("Filter", "ShowPlayerOwnedSecondaryEffects", true, "Show player-owned secondary damage such as projectile explosions if the game reports them as created by the player. Turn off if poison/fire DoT becomes noisy."); MinDamageToShow = ((BaseUnityPlugin)this).Config.Bind("Filter", "MinDamageToShow", 0.01f, "Final damage below this value will not be shown."); ShowDecimals = ((BaseUnityPlugin)this).Config.Bind("Visual", "ShowDecimals", false, "Show one decimal place for non-integer damage. Integer values such as 5.0 are still shown as 5."); Lifetime = ((BaseUnityPlugin)this).Config.Bind("Visual", "Lifetime", 0.85f, "Damage number lifetime in seconds."); FloatSpeed = ((BaseUnityPlugin)this).Config.Bind("Visual", "FloatSpeed", 1.25f, "World-space upward speed for WorldTextMeshPro renderer."); WorldScale = ((BaseUnityPlugin)this).Config.Bind("Visual", "WorldScale", 0.045f, "World-space scale of each TextMeshPro damage number."); RandomJitter = ((BaseUnityPlugin)this).Config.Bind("Visual", "RandomJitter", 0.18f, "Random horizontal world-space offset. Useful for PerHit shotgun pellets."); FontSize = ((BaseUnityPlugin)this).Config.Bind("Visual", "FontSize", 6f, "TextMeshPro font size for WorldTextMeshPro renderer."); ScreenFontSize = ((BaseUnityPlugin)this).Config.Bind("Visual", "ScreenFontSize", 28, "Screen-space GUI font size."); ScreenFloatSpeed = ((BaseUnityPlugin)this).Config.Bind("Visual", "ScreenFloatSpeed", 70f, "Screen-space upward speed in pixels per second."); ScreenJitter = ((BaseUnityPlugin)this).Config.Bind("Visual", "ScreenJitter", 26f, "Random screen-space offset in pixels. Useful for PerHit shotgun pellets."); PerHitStackScreenSpread = ((BaseUnityPlugin)this).Config.Bind("Visual", "PerHitStackScreenSpread", 12.8f, "Extra deterministic screen-space spread in pixels for multiple PerHit numbers created on the same target in the same frame. This makes shotgun pellets easier to read without delaying or merging damage."); PerHitStackWorldSpread = ((BaseUnityPlugin)this).Config.Bind("Visual", "PerHitStackWorldSpread", 0.06f, "Extra deterministic world-space spread for multiple PerHit numbers created on the same target in the same frame. Used by WorldTextMeshPro and Both renderers."); MaxActiveNumbers = ((BaseUnityPlugin)this).Config.Bind("Performance", "MaxActiveNumbers", 160, "Maximum active screen-space damage numbers. When exceeded, the oldest entries are discarded first to prevent UI spam during extreme PerHit cases."); DebugLog = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugLog", false, "Print accepted/rejected damage events to LogOutput.log."); DebugSpawnTestOnF8 = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugSpawnTestOnF8", true, "Press F8 in-game to spawn a test number at the screen center. This verifies the renderer even without hitting enemies."); DamageNumberManager.EnsureExists(); _harmony = new Harmony("ryuka.sulfur.damagenumbers"); DamageLogPatch.Apply(_harmony); ((BaseUnityPlugin)this).Logger.LogInfo((object)("SULFUR Damage Numbers 1.0.7 loaded. Renderer=" + Renderer.Value.ToString() + ", Mode=" + Mode.Value.ToString() + ".")); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); _harmony = null; } } } public enum DisplayMode { PerTargetTotal = 1, PerHit } public enum RenderMode { ScreenSpace = 1, WorldTextMeshPro, Both } public enum MergedColorMode { HighestMultiplier = 1, DamageWeightedAverage, LastHit }