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<AggregateKey, AggregateEntry> _aggregates = new Dictionary<AggregateKey, AggregateEntry>();
private readonly List<AggregateKey> _flushBuffer = new List<AggregateKey>();
private readonly List<ScreenEntry> _screenEntries = new List<ScreenEntry>();
private readonly Dictionary<PerHitSpreadKey, int> _perHitSpreadCounters = new Dictionary<PerHitSpreadKey, int>();
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<DamageNumberManager>();
}
}
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<AggregateKey, AggregateEntry> 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>();
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<PerHitSpreadKey>
{
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<AggregateKey>
{
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<TextMeshPro>();
((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<bool> Enabled;
internal static ConfigEntry<DisplayMode> Mode;
internal static ConfigEntry<RenderMode> Renderer;
internal static ConfigEntry<MergedColorMode> AggregateColorMode;
internal static ConfigEntry<bool> UseWeakspotColors;
internal static ConfigEntry<bool> TreatOneMultiplierAsNormal;
internal static ConfigEntry<bool> RequireNpcTarget;
internal static ConfigEntry<bool> RequireSourceUnitPlayer;
internal static ConfigEntry<bool> ShowPlayerOwnedSecondaryEffects;
internal static ConfigEntry<float> MinDamageToShow;
internal static ConfigEntry<bool> ShowDecimals;
internal static ConfigEntry<float> Lifetime;
internal static ConfigEntry<float> FloatSpeed;
internal static ConfigEntry<float> WorldScale;
internal static ConfigEntry<float> RandomJitter;
internal static ConfigEntry<float> FontSize;
internal static ConfigEntry<int> ScreenFontSize;
internal static ConfigEntry<float> ScreenFloatSpeed;
internal static ConfigEntry<float> ScreenJitter;
internal static ConfigEntry<float> PerHitStackScreenSpread;
internal static ConfigEntry<float> PerHitStackWorldSpread;
internal static ConfigEntry<int> MaxActiveNumbers;
internal static ConfigEntry<bool> DebugLog;
internal static ConfigEntry<bool> 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<bool>("General", "Enabled", true, "Enable damage number display.");
Mode = ((BaseUnityPlugin)this).Config.Bind<DisplayMode>("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<RenderMode>("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<bool>("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<bool>("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<MergedColorMode>("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<bool>("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<bool>("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<bool>("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<float>("Filter", "MinDamageToShow", 0.01f, "Final damage below this value will not be shown.");
ShowDecimals = ((BaseUnityPlugin)this).Config.Bind<bool>("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<float>("Visual", "Lifetime", 0.85f, "Damage number lifetime in seconds.");
FloatSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "FloatSpeed", 1.25f, "World-space upward speed for WorldTextMeshPro renderer.");
WorldScale = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "WorldScale", 0.045f, "World-space scale of each TextMeshPro damage number.");
RandomJitter = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "RandomJitter", 0.18f, "Random horizontal world-space offset. Useful for PerHit shotgun pellets.");
FontSize = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "FontSize", 6f, "TextMeshPro font size for WorldTextMeshPro renderer.");
ScreenFontSize = ((BaseUnityPlugin)this).Config.Bind<int>("Visual", "ScreenFontSize", 28, "Screen-space GUI font size.");
ScreenFloatSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "ScreenFloatSpeed", 70f, "Screen-space upward speed in pixels per second.");
ScreenJitter = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "ScreenJitter", 26f, "Random screen-space offset in pixels. Useful for PerHit shotgun pellets.");
PerHitStackScreenSpread = ((BaseUnityPlugin)this).Config.Bind<float>("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<float>("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<int>("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<bool>("Debug", "DebugLog", false, "Print accepted/rejected damage events to LogOutput.log.");
DebugSpawnTestOnF8 = ((BaseUnityPlugin)this).Config.Bind<bool>("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
}