Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CustomCrosshairV2 v0.2.0
RoR2CustomCrosshair.dll
Decompiled 8 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Acolyte; using EntityStates.Acolyte.Weapon; using EntityStates.Bandit2.Weapon; using EntityStates.Captain.Weapon; using EntityStates.Chef; using EntityStates.Commando.CommandoWeapon; using EntityStates.Croco; using EntityStates.Drifter; using EntityStates.DroneTech.Weapon; using EntityStates.DroneTech.Weapon.Paint; using EntityStates.Enforcer; using EntityStates.Engi.EngiMissilePainter; using EntityStates.Engi.EngiWeapon; using EntityStates.FalseSon; using EntityStates.Huntress; using EntityStates.Huntress.HuntressWeapon; using EntityStates.Huntress.Weapon; using EntityStates.Loader; using EntityStates.Mage.Weapon; using EntityStates.Railgunner.Weapon; using EntityStates.Seeker; using EntityStates.Toolbot; using EntityStates.Treebot; using EntityStates.Treebot.Weapon; using EntityStates.VoidSurvivor.Weapon; using Microsoft.CodeAnalysis; using On.RoR2.UI; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.Skills; using RoR2.UI; using TMPro; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("RoR2CustomCrosshair")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+22e94bea5b59c79ed031d79d0662ef9f1885cb96")] [assembly: AssemblyProduct("RoR2CustomCrosshair")] [assembly: AssemblyTitle("RoR2CustomCrosshair")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace RoR2CustomCrosshair { internal static class AttackSpread { private static readonly Dictionary<Type, EntityState?> ConfiguredStates = new Dictionary<Type, EntityState>(); internal static SpreadSample Bullet(GenericBulletBaseState state, float bloomDegrees, string context) { float num = Mathf.Max(state.spreadYawScale, state.spreadPitchScale); return new SpreadSample((state.maxSpread + bloomDegrees) * num, SpreadKind.Bloom, context); } internal static SpreadSample Projectile(GenericProjectileBaseState state, string context) { return new SpreadSample(state.maxSpread, SpreadKind.Fixed, context); } internal static bool TryFromState(EntityState state, float bloomDegrees, out SpreadSample sample) { GenericBulletBaseState val = (GenericBulletBaseState)(object)((state is GenericBulletBaseState) ? state : null); if (val == null) { GenericProjectileBaseState val2 = (GenericProjectileBaseState)(object)((state is GenericProjectileBaseState) ? state : null); if (val2 != null) { sample = Projectile(val2, ((object)state).GetType().Name); return true; } sample = default(SpreadSample); return false; } sample = Bullet(val, bloomDegrees, ((object)state).GetType().Name); return true; } internal static bool TryFromConfiguredState(Type stateType, float bloomDegrees, out SpreadSample sample) { EntityState val = AttackSpread.Configured<EntityState>(stateType); if (val == null) { sample = default(SpreadSample); return false; } return TryFromState(val, bloomDegrees, out sample); } internal static T? Configured<T>(Type stateType) where T : EntityState { if (!ConfiguredStates.TryGetValue(stateType, out EntityState value)) { try { value = EntityStateCatalog.InstantiateState(stateType); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not read configuration of " + stateType.FullName + ": " + ex.Message)); value = null; } ConfiguredStates[stateType] = value; } return (T)(object)((value is T) ? value : null); } } internal sealed class BodyStateMachine { private readonly string _name; private CharacterBody? _body; private EntityStateMachine? _machine; internal BodyStateMachine(string name) { _name = name; } internal EntityState? StateOf(CharacterBody body) { if ((Object)(object)body != (Object)(object)_body) { _body = body; _machine = EntityStateMachine.FindByCustomName(((Component)body).gameObject, _name); } if (!Object.op_Implicit((Object)(object)_machine)) { return null; } return _machine.state; } } internal sealed class BanditSpreadSource : ISpreadSource { private sealed class Weapon { internal readonly string Name; private readonly GenericBulletBaseState _config; internal readonly float FanDegrees; internal readonly bool HasFan; internal Weapon(string name, GenericBulletBaseState config, bool hasFan, float fanDegrees) { Name = name; _config = config; HasFan = hasFan; FanDegrees = fanDegrees; } internal float EnvelopeDegrees(float bloom) { float num = _config.maxSpread + bloom; return Mathf.Max((HasFan ? (FanDegrees + bloom) : 0f) + num * _config.spreadYawScale, num * _config.spreadPitchScale); } internal string Describe() { return $"{_config.bulletCount} bullet(s), maxSpread {_config.maxSpread:0.###}, yaw x{_config.spreadYawScale:0.###}, " + string.Format("pitch x{0:0.###}, fan {1}", _config.spreadPitchScale, HasFan ? $"+/-{FanDegrees:0.###} deg + bloom" : "none"); } } private const string BanditBodyName = "Bandit2Body"; private readonly BodyStateMachine _weaponMachine = new BodyStateMachine("Weapon"); private BodyIndex _banditBodyIndex = (BodyIndex)(-1); private readonly Dictionary<Type, Weapon?> _weapons = new Dictionary<Type, Weapon>(); private SkillDef? _lastPrimarySkill; private Weapon? _lastWeapon; private CharacterBody? _loggedBody; private Weapon? _loggedWeapon; public bool LogSamples => false; public bool CanHandle(CharacterBody body) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0025: 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_000f: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if ((int)_banditBodyIndex == -1) { _banditBodyIndex = BodyCatalog.FindBodyIndex("Bandit2Body"); if ((int)_banditBodyIndex == -1) { return false; } } return body.bodyIndex == _banditBodyIndex; } public bool TrySample(CharacterBody body, out SpreadSample sample) { sample = default(SpreadSample); EntityState val = _weaponMachine.StateOf(body); BaseFireSidearmRevolverState val2 = (BaseFireSidearmRevolverState)(object)((val is BaseFireSidearmRevolverState) ? val : null); if (val2 == null) { BasePrepSidearmRevolverState val3 = (BasePrepSidearmRevolverState)(object)((val is BasePrepSidearmRevolverState) ? val : null); if (val3 == null) { if (val is Bandit2FireShiv) { sample = SpreadSample.None("Bandit2FireShiv"); return true; } } else { BaseFireSidearmRevolverState val4 = RevolverShotFor(val3); if (val4 != null) { sample = new SpreadSample(val4.maxSpread, SpreadKind.Fixed, ((object)val4).GetType().Name); return true; } } Weapon weapon = CurrentPrimary(body); if (weapon == null) { return false; } LogWeaponOnce(body, weapon); sample = new SpreadSample(weapon.EnvelopeDegrees(body.spreadBloomAngle), SpreadKind.Bloom, weapon.Name); return true; } sample = new SpreadSample(val2.maxSpread, SpreadKind.Fixed, ((object)val2).GetType().Name); return true; } private static BaseFireSidearmRevolverState? RevolverShotFor(BasePrepSidearmRevolverState prep) { Type type = ((prep is PrepSidearmSkullRevolver) ? typeof(FireSidearmSkullRevolver) : ((!(prep is PrepSidearmResetRevolver)) ? null : typeof(FireSidearmResetRevolver))); Type type2 = type; if (!(type2 != null)) { return null; } return AttackSpread.Configured<BaseFireSidearmRevolverState>(type2); } private Weapon? CurrentPrimary(CharacterBody body) { GenericSkill val = (Object.op_Implicit((Object)(object)body.skillLocator) ? body.skillLocator.primary : null); SkillDef val2 = (Object.op_Implicit((Object)(object)val) ? val.skillDef : null); if ((Object)(object)val2 == (Object)null) { return null; } if ((Object)(object)val2 != (Object)(object)_lastPrimarySkill) { _lastPrimarySkill = val2; Type stateType = ((SerializableEntityStateType)(ref val2.activationState)).stateType; _lastWeapon = ((stateType != null) ? WeaponFor(stateType) : null); } return _lastWeapon; } private Weapon? WeaponFor(Type stateType) { if (_weapons.TryGetValue(stateType, out Weapon value)) { return value; } Weapon weapon = null; if (typeof(FireShotgun2).IsAssignableFrom(stateType)) { FireShotgun2 val = AttackSpread.Configured<FireShotgun2>(stateType); if (val != null) { bool hasFan = ((GenericBulletBaseState)val).bulletCount > 1; float fanDegrees = Mathf.Max(val.minFixedSpreadYaw, val.maxFixedSpreadYaw); weapon = new Weapon(stateType.Name, (GenericBulletBaseState)(object)val, hasFan, fanDegrees); } } else if (typeof(Bandit2FireRifle).IsAssignableFrom(stateType)) { Bandit2FireRifle val2 = AttackSpread.Configured<Bandit2FireRifle>(stateType); if (val2 != null) { weapon = new Weapon(stateType.Name, (GenericBulletBaseState)(object)val2, hasFan: false, 0f); } } _weapons[stateType] = weapon; return weapon; } private void LogWeaponOnce(CharacterBody body, Weapon weapon) { if (!((Object)(object)_loggedBody == (Object)(object)body) || _loggedWeapon != weapon) { _loggedBody = body; _loggedWeapon = weapon; AnimationCurve spreadBloomCurve = body.spreadBloomCurve; float num = ((spreadBloomCurve != null) ? spreadBloomCurve.Evaluate(0f) : 0f); float num2 = ((spreadBloomCurve != null) ? spreadBloomCurve.Evaluate(1f) : 0f); Plugin.Log.LogDebug((object)("[Spread] Bandit source active: primary '" + _lastPrimarySkill?.skillName + "' (" + weapon.Name + "), " + weapon.Describe() + "; " + $"bloom {num:0.###}..{num2:0.###} deg, decay {body.spreadBloomDecayTime:0.###} s " + $"(attack speed scales decay: {body.spreadBloomDecayWithAttackSpeed}); " + $"envelope {weapon.EnvelopeDegrees(num):0.###} deg with no bloom, {weapon.EnvelopeDegrees(num2):0.###} deg at full bloom.")); } } } internal static class BaseGameSurvivorSpread { internal static ISpreadSource[] Create() { return new ISpreadSource[8] { Huntress(), Engineer(), Artificer(), Mercenary(), Rex(), Loader(), Acrid(), Captain() }; } private static ISpreadSource Huntress() { return new TableSpreadSource("Huntress", "HuntressBody", new string[2] { "Weapon", "Body" }, AttackRule.None(typeof(FireSeekingArrow), "Strafe/Flurry (homing arrow)"), AttackRule.None(typeof(ThrowGlaive), "Laser Glaive (homing orb)"), AttackRule.None(typeof(ThrowCycloneKickable), "Cyclone (straight projectile)"), AttackRule.None(typeof(ArrowRain), "Arrow Rain (world-targeted)")); } private static ISpreadSource Engineer() { return new TableSpreadSource("Engineer", "EngiBody", new string[1] { "Weapon" }, AttackRule.Bloom(typeof(ChargeGrenades), "Bouncing Grenades (charging)"), AttackRule.Bloom(typeof(FireGrenades), "Bouncing Grenades"), AttackRule.None(typeof(EnterEngiLaserCutter), "Laser Cutter (zero-spread beam)"), AttackRule.None(typeof(EngiLaserCutter), "Laser Cutter (zero-spread beam)"), AttackRule.None(typeof(FireMines), "Mine/Bubble Shield (straight throw)"), AttackRule.None(typeof(Fire), "Thermal Harpoons (homing)")); } private static ISpreadSource Artificer() { return new TableSpreadSource("Artificer", "MageBody", new string[2] { "Weapon", "Body" }, AttackRule.None(typeof(FireFireBolt), "Flame/Plasma Bolt (straight projectile)"), AttackRule.None(typeof(BaseChargeBombState), "Nano-Bomb/Spear charging (charge does not change aim)"), AttackRule.None(typeof(BaseThrowBombState), "Nano-Bomb/Spear (straight projectile)"), AttackRule.None(typeof(Flamethrower), "Flamethrower (zero-spread beam)"), AttackRule.Fixed(typeof(FireEarthShards), "Earth shards (fan + noise)", () => FireEarthShards.maxSpread * 0.5f + FireEarthShards.maxNoise)); } private static ISpreadSource Mercenary() { return new TableSpreadSource("Mercenary", "MercBody", new string[2] { "Weapon", "Body" }); } private static ISpreadSource Rex() { return new TableSpreadSource("REX", "TreebotBody", new string[1] { "Weapon" }, AttackRule.Fixed(typeof(FireSyringe), "DIRECTIVE: Inject (fixed yaw fan)", SyringeFanDegrees), AttackRule.None(typeof(ChargeSonicBoom), "Sonic Boom (area cone)"), AttackRule.None(typeof(FireSonicBoom), "Sonic Boom (area cone)"), AttackRule.None(typeof(AimThrowableBase), "Mortar/throw (world-targeted)"), AttackRule.None(typeof(TreebotFireFruitSeed), "DIRECTIVE: Harvest (straight projectile)"), AttackRule.None(typeof(FireFlower2), "Tangling Growth (world-targeted)")); } private static ISpreadSource Loader() { return new TableSpreadSource("Loader", "LoaderBody", new string[4] { "Weapon", "Hook", "Pylon", "Body" }, AttackRule.None(typeof(FireHook), "Grapple (straight projectile)"), AttackRule.None(typeof(ThrowPylon), "M551 Pylon (straight projectile)"), AttackRule.None(typeof(BaseChargeFist), "Gauntlet charging (charge does not change aim)")); } private static ISpreadSource Acrid() { return new TableSpreadSource("Acrid", "CrocoBody", new string[3] { "Weapon", "Mouth", "Body" }, AttackRule.None(typeof(FireSpit), "Neurotoxin/Epidemic (straight projectile)"), AttackRule.None(typeof(Breath), "Breath (straight projectile)")); } private static ISpreadSource Captain() { return new TableSpreadSource("Captain", "CaptainBody", new string[2] { "Weapon", "Skillswap" }, new AttackRule(typeof(ChargeCaptainShotgun), (EntityState _, CharacterBody body) => CaptainShotgunEnvelope(body)), AttackRule.None(typeof(FireTazer), "Power Tazer (straight projectile)"), AttackRule.None(typeof(AimThrowableBase), "Orbital Probe (world-targeted)"), AttackRule.None(typeof(CallSupplyDropBase), "Supply Beacon (world-targeted)")); } private static SpreadSample CaptainShotgunEnvelope(CharacterBody body) { FireCaptainShotgun val = AttackSpread.Configured<FireCaptainShotgun>(typeof(FireCaptainShotgun)); if (val == null) { return new SpreadSample(body.spreadBloomAngle, SpreadKind.Bloom, "Vulcan Shotgun (charging)"); } return AttackSpread.Bullet((GenericBulletBaseState)(object)val, body.spreadBloomAngle, "Vulcan Shotgun (charging)"); } private static float SyringeFanDegrees() { int projectileCount = FireSyringe.projectileCount; if (projectileCount < 2) { return 0f; } float num = 0f; for (int i = 0; i < projectileCount; i++) { float num2 = (float)Mathf.FloorToInt((float)i - (float)(projectileCount - 1) / 2f) / (float)(projectileCount - 1) * FireSyringe.totalYawSpread; num = Mathf.Max(num, Mathf.Abs(num2)); } return num; } } internal sealed class CommandoSpreadSource : ISpreadSource { private const string CommandoBodyName = "CommandoBody"; private readonly BodyStateMachine _weapon = new BodyStateMachine("Weapon"); private BodyIndex _commandoBodyIndex = (BodyIndex)(-1); private SkillDef? _lastPrimarySkill; private bool _lastPrimaryIsDoubleTap; private CharacterBody? _loggedBody; public bool LogSamples => false; public bool CanHandle(CharacterBody body) { return IsCommando(body); } public bool TrySample(CharacterBody body, out SpreadSample sample) { sample = default(SpreadSample); if (!IsCommando(body) || body.spreadBloomCurve == null) { return false; } LogBodyOnce(body); float spreadBloomAngle = body.spreadBloomAngle; EntityState val = _weapon.StateOf(body); if (!(val is FireBarrage)) { Sabotage val2 = (Sabotage)(object)((val is Sabotage) ? val : null); if (val2 == null) { if (val != null && AttackSpread.TryFromState(val, spreadBloomAngle, out sample)) { return true; } if (!PrimaryIsDoubleTap(body)) { return false; } sample = new SpreadSample(spreadBloomAngle, SpreadKind.Bloom, "Double Tap"); return true; } Sabotage val3 = val2; sample = new SpreadSample(SabotageEnvelope(val3), SpreadKind.Fixed, ((object)val3).GetType().Name); return true; } sample = new SpreadSample(FireBarrage.maxSpread, SpreadKind.Fixed, "Suppressive Fire"); return true; } private static float SabotageEnvelope(Sabotage sabotage) { float num = 0f; for (int i = 0; i < Mathf.Max(1, sabotage.projectileCount); i++) { float num2 = ((float)sabotage.projectileCount / 2f - (float)i) * sabotage.yawSpread - sabotage.yawSpread / 2f; num = Mathf.Max(num, Mathf.Abs(num2)); } return num + sabotage.maxSpread; } private bool IsCommando(CharacterBody body) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0025: 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_000f: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if ((int)_commandoBodyIndex == -1) { _commandoBodyIndex = BodyCatalog.FindBodyIndex("CommandoBody"); if ((int)_commandoBodyIndex == -1) { return false; } } return body.bodyIndex == _commandoBodyIndex; } private bool PrimaryIsDoubleTap(CharacterBody body) { GenericSkill val = (Object.op_Implicit((Object)(object)body.skillLocator) ? body.skillLocator.primary : null); SkillDef val2 = (Object.op_Implicit((Object)(object)val) ? val.skillDef : null); if ((Object)(object)val2 == (Object)null) { return false; } if ((Object)(object)val2 != (Object)(object)_lastPrimarySkill) { _lastPrimarySkill = val2; Type stateType = ((SerializableEntityStateType)(ref val2.activationState)).stateType; _lastPrimaryIsDoubleTap = stateType != null && typeof(FirePistol2).IsAssignableFrom(stateType); } return _lastPrimaryIsDoubleTap; } private void LogBodyOnce(CharacterBody body) { if (!((Object)(object)_loggedBody == (Object)(object)body)) { _loggedBody = body; string arg = "none"; GameObject defaultCrosshairPrefab = body.defaultCrosshairPrefab; CrosshairController val = default(CrosshairController); if (Object.op_Implicit((Object)(object)defaultCrosshairPrefab) && defaultCrosshairPrefab.TryGetComponent<CrosshairController>(ref val)) { arg = $"{((Object)defaultCrosshairPrefab).name} maxSpreadAngle {val.maxSpreadAngle:0.###}"; } AnimationCurve spreadBloomCurve = body.spreadBloomCurve; Plugin.Log.LogDebug((object)($"[Spread] Commando source active: Double Tap spread {spreadBloomCurve.Evaluate(0f):0.###} deg with no bloom, " + $"{spreadBloomCurve.Evaluate(1f):0.###} deg at full bloom, decay {body.spreadBloomDecayTime:0.###} s; " + $"Suppressive Fire fixed {FireBarrage.maxSpread:0.###} deg; vanilla crosshair: {arg}.")); } } } internal static class CrosshairConfig { private const int CurrentConfigVersion = 2; private const float SliderStep = 0.5f; internal static ConfigEntry<bool> Enabled; internal static BarsSettings InnerBars; internal static BarsSettings OuterBars; internal static CircleSettings Circle; internal static DotSettings CenterDot; internal static ProgressBarSettings ProgressBar; internal static CountIndicatorSettings CountIndicator; internal static int Revision { get; private set; } internal static void Bind(ConfigFile config) { //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_00ee: 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) bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; Enabled = config.Bind<bool>("General", "Enabled", true, "Replace the ordinary crosshair of your own survivor with the custom crosshair."); InnerBars = new BarsSettings(config, "Inner Bars", new BarsDefaults { Enabled = true, Length = 8f, Thickness = 2f, Gap = 4f, GapMax = 64f, Fill = new Color32((byte)0, byte.MaxValue, (byte)0, byte.MaxValue) }); OuterBars = new BarsSettings(config, "Outer Bars", new BarsDefaults { Enabled = false, Length = 10f, Thickness = 2f, Gap = 14f, GapMax = 128f, Fill = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue) }); Circle = new CircleSettings(config, "Circle"); CenterDot = new DotSettings(config, "Center Dot"); ProgressBar = new ProgressBarSettings(config, "Progress Bar"); CountIndicator = new CountIndicatorSettings(config, "Count Indicator"); MigrateFromVersion1(config); config.Save(); config.SaveOnConfigSet = saveOnConfigSet; config.SettingChanged += delegate { Revision++; }; } internal static void RegisterRiskOfOptions() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown ModSettingsManager.SetModDescription("Procedural crosshair with Inner Bars, Outer Bars, Circle and Center Dot layers. Sizes are pixels at 1920x1080 and scale with resolution."); Sprite val = ModIcon.Load(); if ((Object)(object)val != (Object)null) { ModSettingsManager.SetModIcon(val, "com.example.ror2customcrosshair", "RoR2 Custom Crosshair"); } ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(Enabled)); InnerBars.Register(); OuterBars.Register(); Circle.Register(); CenterDot.Register(); ProgressBar.Register(); CountIndicator.Register(); } private static void MigrateFromVersion1(ConfigFile config) { ConfigEntry<int> val = config.Bind<int>("Internal", "Config Version", 0, "Settings layout version, used for migration. Do not edit."); if (val.Value < 2) { BarsSettings innerBars = InnerBars; Move<float>(config, "Crosshair", "Length", innerBars.Length); Move<float>(config, "Crosshair", "Thickness", innerBars.Thickness); Move<float>(config, "Crosshair", "Gap", innerBars.Gap); Move<int>(config, "Crosshair Color", "Opacity", innerBars.Fill.Opacity); Move<int>(config, "Crosshair Color", "R", innerBars.Fill.Red); Move<int>(config, "Crosshair Color", "G", innerBars.Fill.Green); Move<int>(config, "Crosshair Color", "B", innerBars.Fill.Blue); Move<bool>(config, "Outline", "Enabled", innerBars.Outline.Enabled); Move<float>(config, "Outline", "Thickness", innerBars.Outline.Thickness); Move<int>(config, "Outline Color", "Opacity", innerBars.Outline.Color.Opacity); Move<int>(config, "Outline Color", "R", innerBars.Outline.Color.Red); Move<int>(config, "Outline Color", "G", innerBars.Outline.Color.Green); Move<int>(config, "Outline Color", "B", innerBars.Outline.Color.Blue); val.Value = 2; Plugin.Log.LogInfo((object)"Migrated crosshair settings to the layered layout (old values now under 'Inner Bars')."); } } private static void Move<T>(ConfigFile config, string oldSection, string oldKey, ConfigEntry<T> target) { ConfigEntry<T> val = config.Bind<T>(oldSection, oldKey, (T)((ConfigEntryBase)target).DefaultValue, (ConfigDescription)null); target.Value = val.Value; config.Remove(((ConfigEntryBase)val).Definition); } internal static ConfigEntry<float> BindFloat(ConfigFile config, string section, string key, float defaultValue, float min, float max, string description) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown return config.Bind<float>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>())); } internal static ConfigEntry<int> BindByte(ConfigFile config, string section, string key, int defaultValue) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown return config.Bind<int>(section, key, defaultValue, new ConfigDescription(key + " value from 0 to 255.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255), Array.Empty<object>())); } internal static void AddFloatOption(ConfigEntry<float> entry, float min, float max) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new StepSliderOption(entry, new StepSliderConfig { min = min, max = max, increment = 0.5f, FormatString = "{0:0.0}" })); } internal static void AddByteOption(ConfigEntry<int> entry) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new IntSliderOption(entry, new IntSliderConfig { min = 0, max = 255 })); } } internal sealed class ColorSettings { internal readonly ConfigEntry<int> Red; internal readonly ConfigEntry<int> Green; internal readonly ConfigEntry<int> Blue; internal readonly ConfigEntry<int> Opacity; internal Color Value => new Color((float)Red.Value / 255f, (float)Green.Value / 255f, (float)Blue.Value / 255f, (float)Opacity.Value / 255f); internal ColorSettings(ConfigFile config, string section, string keyPrefix, Color32 defaults) { //IL_0014: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) Red = CrosshairConfig.BindByte(config, section, keyPrefix + "R", defaults.r); Green = CrosshairConfig.BindByte(config, section, keyPrefix + "G", defaults.g); Blue = CrosshairConfig.BindByte(config, section, keyPrefix + "B", defaults.b); Opacity = CrosshairConfig.BindByte(config, section, keyPrefix + "Opacity", defaults.a); } internal void Register() { CrosshairConfig.AddByteOption(Red); CrosshairConfig.AddByteOption(Green); CrosshairConfig.AddByteOption(Blue); CrosshairConfig.AddByteOption(Opacity); } } internal sealed class OutlineSettings { internal const float MaxThickness = 10f; internal readonly ConfigEntry<bool> Enabled; internal readonly ConfigEntry<float> Thickness; internal readonly ColorSettings Color; internal bool Visible { get { if (Enabled.Value) { return Thickness.Value > 0.001f; } return false; } } internal OutlineSettings(ConfigFile config, string section) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) Enabled = config.Bind<bool>(section, "Outline Enabled", true, "Draw a border around this layer."); Thickness = CrosshairConfig.BindFloat(config, section, "Outline Thickness", 1f, 0f, 10f, "Border width on each side, in pixels at 1920x1080."); Color = new ColorSettings(config, section, "Outline ", new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue)); } internal void Register() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(Enabled)); CrosshairConfig.AddFloatOption(Thickness, 0f, 10f); Color.Register(); } } internal struct BarsDefaults { internal bool Enabled; internal float Length; internal float Thickness; internal float Gap; internal float GapMax; internal Color32 Fill; } internal sealed class BarsSettings { internal const float MaxLength = 64f; internal const float MaxThickness = 20f; private readonly float _gapMax; internal readonly ConfigEntry<bool> Enabled; internal readonly ConfigEntry<CrosshairMode> Mode; internal readonly ConfigEntry<float> Length; internal readonly ConfigEntry<float> Thickness; internal readonly ConfigEntry<float> Gap; internal readonly ColorSettings Fill; internal readonly OutlineSettings Outline; internal BarsSettings(ConfigFile config, string section, BarsDefaults defaults) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) _gapMax = defaults.GapMax; Enabled = config.Bind<bool>(section, "Enabled", defaults.Enabled, "Show the " + section + "."); Mode = config.Bind<CrosshairMode>(section, "Mode", CrosshairMode.Static, "Static: fixed gap. Dynamic: gap will follow actual weapon spread (not implemented yet; currently same as Static)."); Length = CrosshairConfig.BindFloat(config, section, "Length", defaults.Length, 0.5f, 64f, "Length of each arm, in pixels at 1920x1080."); Thickness = CrosshairConfig.BindFloat(config, section, "Thickness", defaults.Thickness, 0.5f, 20f, "Thickness of each arm, in pixels at 1920x1080."); Gap = CrosshairConfig.BindFloat(config, section, "Gap", defaults.Gap, 0f, _gapMax, "Distance from screen center to the inner edge of each arm, in pixels at 1920x1080."); Fill = new ColorSettings(config, section, "", defaults.Fill); Outline = new OutlineSettings(config, section); } internal void Register() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(Enabled)); ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)Mode)); CrosshairConfig.AddFloatOption(Length, 0.5f, 64f); CrosshairConfig.AddFloatOption(Thickness, 0.5f, 20f); CrosshairConfig.AddFloatOption(Gap, 0f, _gapMax); Fill.Register(); Outline.Register(); } } internal sealed class CircleSettings { internal const float MaxRadius = 128f; internal const float MaxThickness = 20f; internal readonly ConfigEntry<bool> Enabled; internal readonly ConfigEntry<CrosshairMode> Mode; internal readonly ConfigEntry<float> Radius; internal readonly ConfigEntry<float> Thickness; internal readonly ColorSettings Fill; internal readonly OutlineSettings Outline; internal CircleSettings(ConfigFile config, string section) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) Enabled = config.Bind<bool>(section, "Enabled", false, "Show the circle."); Mode = config.Bind<CrosshairMode>(section, "Mode", CrosshairMode.Static, "Static: fixed radius. Dynamic: radius will follow actual weapon spread (not implemented yet; currently same as Static)."); Radius = CrosshairConfig.BindFloat(config, section, "Radius", 16f, 0f, 128f, "Distance from screen center to the inner edge of the ring, in pixels at 1920x1080."); Thickness = CrosshairConfig.BindFloat(config, section, "Thickness", 2f, 0.5f, 20f, "Ring thickness, in pixels at 1920x1080."); Fill = new ColorSettings(config, section, "", new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue)); Outline = new OutlineSettings(config, section); } internal void Register() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(Enabled)); ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)Mode)); CrosshairConfig.AddFloatOption(Radius, 0f, 128f); CrosshairConfig.AddFloatOption(Thickness, 0.5f, 20f); Fill.Register(); Outline.Register(); } } internal sealed class DotSettings { internal const float MaxSize = 20f; internal readonly ConfigEntry<bool> Enabled; internal readonly ConfigEntry<float> Size; internal readonly ColorSettings Fill; internal readonly OutlineSettings Outline; internal DotSettings(ConfigFile config, string section) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) Enabled = config.Bind<bool>(section, "Enabled", false, "Show the center dot."); Size = CrosshairConfig.BindFloat(config, section, "Size", 2f, 0.5f, 20f, "Diameter of the dot, in pixels at 1920x1080."); Fill = new ColorSettings(config, section, "", new Color32((byte)0, byte.MaxValue, (byte)0, byte.MaxValue)); Outline = new OutlineSettings(config, section); } internal void Register() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(Enabled)); CrosshairConfig.AddFloatOption(Size, 0.5f, 20f); Fill.Register(); Outline.Register(); } } internal static class CrosshairDisplayPolicy { private const string StandardCrosshairAddress = "RoR2/Base/UI/StandardCrosshair.prefab"; private const string GenericSprintCrosshairPath = "Prefabs/Crosshair/SprintingCrosshair"; private static readonly string[] StockPreservingAddresses = new string[5] { "RoR2/Base/Bandit2/Bandit2Crosshair.prefab", "RoR2/Base/Toolbot/ToolbotGrenadeLauncherCrosshair.prefab", "RoR2/Base/Toolbot/ToolbotDualWieldCrosshair.prefab", "RoR2/Base/Mage/MageCrosshair.prefab", "RoR2/Base/Huntress/HuntressSnipeCrosshair.prefab" }; private static readonly (string Address, bool Always)[] CountSupersededAddresses = new(string, bool)[12] { ("RoR2/Base/Toolbot/ToolbotGrenadeLauncherCrosshair.prefab", true), ("RoR2/Base/Toolbot/ToolbotDualWieldCrosshair.prefab", true), ("RoR2/Base/Bandit2/Bandit2Crosshair.prefab", false), ("RoR2/Base/Mage/MageCrosshair.prefab", false), ("RoR2/Base/Huntress/HuntressSnipeCrosshair.prefab", false), ("RoR2/Base/Engi/EngiPaintCrosshair.prefab", false), ("RoR2/DLC2/Chef/ChefCrosshair.prefab", false), ("RoR2/DLC2/FalseSon/FSCrosshair.prefab", false), ("RoR2/DLC2/FalseSon/FSStakeCrosshair.prefab", false), ("RoR2/DLC3/Drone Tech/DroneTechCrosshair.prefab", false), ("RoR2/DLC3/Drone Tech/DroneTechSprintingCrosshair.prefab", false), ("RoR2/DLC3/Drone Tech/DroneTechPaintCrosshair.prefab", false) }; private static readonly Dictionary<GameObject, bool> SupersededByCount = new Dictionary<GameObject, bool>(); private static readonly Dictionary<GameObject, GameObject?> CountSuperseded = new Dictionary<GameObject, GameObject>(); private static readonly BodyStateMachine WeaponMachine = new BodyStateMachine("Weapon"); private static readonly BodyStateMachine BodyMachine = new BodyStateMachine("Body"); private static readonly (string BodyName, BodyStateMachine Machine, Type StateType)[] ChargeDisplayContexts = new(string, BodyStateMachine, Type)[6] { ("MageBody", WeaponMachine, typeof(BaseChargeBombState)), ("LoaderBody", WeaponMachine, typeof(BaseChargeFist)), ("SeekerBody", WeaponMachine, typeof(BaseChargePalmBlast)), ("FalseSonBody", WeaponMachine, typeof(ClubSwing3)), ("FalseSonBody", WeaponMachine, typeof(LaserFather)), ("ChefBody", BodyMachine, typeof(RolyPoly)) }; private static readonly (string Address, string? BodyName)[] CosmeticSkillCrosshairAddresses = new(string, string)[3] { ("RoR2/Base/Bandit2/Bandit2CrosshairPrepRevolver.prefab", null), ("RoR2/Base/Bandit2/Bandit2CrosshairPrepRevolverFire.prefab", null), ("RoR2/Base/UI/BadCrosshair.prefab", "ToolbotBody") }; private static Transform? _holder; private static GameObject? _standardTemplate; private static readonly Dictionary<GameObject, GameObject?> StockPreserving = new Dictionary<GameObject, GameObject>(); private static readonly Dictionary<GameObject, GameObject?> Classified = new Dictionary<GameObject, GameObject>(); private static readonly Dictionary<GameObject, GameObject?> ChargeDisplays = new Dictionary<GameObject, GameObject>(); private static readonly Dictionary<GameObject, string?> CosmeticSkillCrosshairs = new Dictionary<GameObject, string>(); private static readonly Dictionary<string, BodyIndex> BodyIndices = new Dictionary<string, BodyIndex>(); private static GameObject? _genericSprintCrosshair; private static bool _genericSprintCrosshairLoaded; private static int _pendingLoads; internal static bool IsReady { get { if (_pendingLoads == 0) { return (Object)(object)_standardTemplate != (Object)null; } return false; } } internal static void Initialize(Transform holder) { _holder = holder; _pendingLoads = 1 + StockPreservingAddresses.Length + CountSupersededAddresses.Length + CosmeticSkillCrosshairAddresses.Length; CrosshairPrefabFactory.LoadAsync("RoR2/Base/UI/StandardCrosshair.prefab", delegate(GameObject? standard) { _standardTemplate = Build(standard, (GameObject s) => CrosshairPrefabFactory.BuildStandard(s, holder)); if ((Object)(object)_standardTemplate != (Object)null) { Plugin.Log.LogInfo((object)"Crosshair template ready."); } else { Plugin.Log.LogError((object)"Crosshair template unavailable; vanilla crosshairs will be used."); } _pendingLoads--; }); string[] stockPreservingAddresses = StockPreservingAddresses; for (int num = 0; num < stockPreservingAddresses.Length; num++) { CrosshairPrefabFactory.LoadAsync(stockPreservingAddresses[num], delegate(GameObject? vanilla) { if ((Object)(object)vanilla != (Object)null) { GameObject val = Build(vanilla, (GameObject v) => CrosshairPrefabFactory.BuildStockPreserving(v, holder)); StockPreserving[vanilla] = val; if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)(((Object)vanilla).name + ": ammo displays could not be preserved; its vanilla crosshair will be kept.")); } } _pendingLoads--; }); } (string, bool)[] countSupersededAddresses = CountSupersededAddresses; for (int num = 0; num < countSupersededAddresses.Length; num++) { var (address, always) = countSupersededAddresses[num]; CrosshairPrefabFactory.LoadAsync(address, delegate(GameObject? vanilla) { if ((Object)(object)vanilla != (Object)null) { SupersededByCount[vanilla] = always; } _pendingLoads--; }); } (string, string)[] cosmeticSkillCrosshairAddresses = CosmeticSkillCrosshairAddresses; for (int num = 0; num < cosmeticSkillCrosshairAddresses.Length; num++) { var (address2, bodyName) = cosmeticSkillCrosshairAddresses[num]; CrosshairPrefabFactory.LoadAsync(address2, delegate(GameObject? prefab) { if ((Object)(object)prefab != (Object)null) { CosmeticSkillCrosshairs[prefab] = bodyName; } _pendingLoads--; }); } } internal static void Shutdown() { _standardTemplate = null; StockPreserving.Clear(); SupersededByCount.Clear(); CountSuperseded.Clear(); Classified.Clear(); ChargeDisplays.Clear(); CosmeticSkillCrosshairs.Clear(); BodyIndices.Clear(); _holder = null; } internal static GameObject? ChooseTemplate(CharacterBody body, GameObject picked, IndicatorFrame indicators) { if (!IsReady || !Object.op_Implicit((Object)(object)picked)) { return null; } bool num = !CrosshairPrefabFactory.IndicatorsUnavailable; bool countShown = num && CrosshairConfig.CountIndicator.Enabled.Value && indicators.AnyCount; if ((!num || !CrosshairConfig.ProgressBar.Enabled.Value || !indicators.AnyProgress) && IsChargeDisplayContext(body)) { GameObject val = ChargeDisplayFor(picked); if ((Object)(object)val != (Object)null) { return val; } } if (IsGenericSprintCrosshair(body, picked) || IsCosmeticSkillCrosshair(body, picked)) { return TemplateFor(ActiveWeaponCrosshair(body) ?? body.defaultCrosshairPrefab, countShown); } return TemplateFor(picked, countShown); } private static GameObject? TemplateFor(GameObject? vanilla, bool countShown) { if ((Object)(object)vanilla == (Object)null) { return _standardTemplate; } if (SupersededByCount.TryGetValue(vanilla, out var value) && (countShown || value) && CrosshairConfig.CountIndicator.Enabled.Value && !CrosshairPrefabFactory.IndicatorsUnavailable) { return CountSupersededTemplate(vanilla); } if (StockPreserving.TryGetValue(vanilla, out GameObject value2)) { return value2; } return ClassifiedTemplate(vanilla); } private static GameObject? ClassifiedTemplate(GameObject vanilla) { if (Classified.TryGetValue(vanilla, out GameObject value)) { return value; } GameObject val; if (CrosshairPrefabFactory.IsPureReticle(vanilla, out string extra)) { val = _standardTemplate; } else { val = Build(vanilla, (GameObject v) => CrosshairPrefabFactory.BuildOverlay(v, _holder)); Plugin.Log.LogInfo((object)(((Object)(object)val != (Object)null) ? ("Phase C review: " + ((Object)vanilla).name + " carries " + extra + "; custom reticle overlaid, its spread art removed, everything else kept.") : ("Phase C review: " + ((Object)vanilla).name + " carries " + extra + "; overlay could not be built, vanilla crosshair kept."))); } Classified[vanilla] = val; return val; } private static GameObject? CountSupersededTemplate(GameObject vanilla) { if (!CountSuperseded.TryGetValue(vanilla, out GameObject value)) { value = (StockPreserving.ContainsKey(vanilla) ? (Build(vanilla, (GameObject v) => CrosshairPrefabFactory.BuildStockPreserving(v, _holder, keepSpreadArt: false, keepCounts: false)) ?? _standardTemplate) : Build(vanilla, (GameObject v) => CrosshairPrefabFactory.BuildOverlay(v, _holder, stripCounts: true))); CountSuperseded[vanilla] = value; Plugin.Log.LogDebug((object)(((Object)(object)value != (Object)null) ? (((Object)vanilla).name + ": count pips superseded by the Count Indicator (" + ((Object)value).name + ").") : (((Object)vanilla).name + ": count-superseded template could not be built; vanilla pips kept."))); } if ((Object)(object)value != (Object)null) { return value; } if (!StockPreserving.TryGetValue(vanilla, out GameObject value2)) { return ClassifiedTemplate(vanilla); } return value2; } private static GameObject? ActiveWeaponCrosshair(CharacterBody body) { GenericSkill val = (Object.op_Implicit((Object)(object)body.skillLocator) ? body.skillLocator.primary : null); if (Object.op_Implicit((Object)(object)val)) { SkillDef skillDef = val.skillDef; ToolbotWeaponSkillDef val2 = (ToolbotWeaponSkillDef)(object)((skillDef is ToolbotWeaponSkillDef) ? skillDef : null); if (val2 != null && Object.op_Implicit((Object)(object)val2.crosshairPrefab)) { return val2.crosshairPrefab; } } return null; } private static bool IsCosmeticSkillCrosshair(CharacterBody body, GameObject picked) { if (!CosmeticSkillCrosshairs.TryGetValue(picked, out string value)) { return false; } if (value != null) { return IsBody(body, value); } return true; } private static bool IsChargeDisplayContext(CharacterBody body) { (string, BodyStateMachine, Type)[] chargeDisplayContexts = ChargeDisplayContexts; for (int i = 0; i < chargeDisplayContexts.Length; i++) { var (bodyName, bodyStateMachine, type) = chargeDisplayContexts[i]; if (IsBody(body, bodyName)) { EntityState val = bodyStateMachine.StateOf(body); if (val != null && type.IsInstanceOfType(val)) { return true; } } } return false; } private static GameObject? ChargeDisplayFor(GameObject vanilla) { if (!ChargeDisplays.TryGetValue(vanilla, out GameObject value)) { value = Build(vanilla, (GameObject v) => CrosshairPrefabFactory.BuildStockPreserving(v, _holder, keepSpreadArt: true)); ChargeDisplays[vanilla] = value; } return value; } private static bool IsBody(CharacterBody body, string bodyName) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Invalid comparison between Unknown and I4 //IL_002b: 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) if (!BodyIndices.TryGetValue(bodyName, out var value) || (int)value == -1) { value = BodyCatalog.FindBodyIndex(bodyName); BodyIndices[bodyName] = value; } if ((int)value != -1) { return body.bodyIndex == value; } return false; } private static GameObject? Build(GameObject? source, Func<GameObject, GameObject?> build) { if ((Object)(object)source == (Object)null || (Object)(object)_holder == (Object)null) { return null; } try { return build(source); } catch (Exception arg) { Plugin.Log.LogError((object)$"Could not build crosshair template from {((Object)source).name}: {arg}"); return null; } } private static bool IsGenericSprintCrosshair(CharacterBody body, GameObject picked) { if (!body.isSprinting || !body.useSprintCrosshair || Object.op_Implicit((Object)(object)body.sprintCrosshairPrefabOverride)) { return false; } GameObject genericSprintCrosshair = GetGenericSprintCrosshair(); if ((Object)(object)genericSprintCrosshair != (Object)null) { return (Object)(object)picked == (Object)(object)genericSprintCrosshair; } return false; } private static GameObject? GetGenericSprintCrosshair() { if (!_genericSprintCrosshairLoaded) { _genericSprintCrosshairLoaded = true; _genericSprintCrosshair = LegacyResourcesAPI.Load<GameObject>("Prefabs/Crosshair/SprintingCrosshair"); if ((Object)(object)_genericSprintCrosshair == (Object)null) { Plugin.Log.LogWarning((object)"Could not load 'Prefabs/Crosshair/SprintingCrosshair'; the vanilla sprint crosshair will be shown."); } } return _genericSprintCrosshair; } } internal readonly struct PixelFrame { internal readonly float ResolutionScale; internal readonly float PixelsPerUnit; internal readonly float CenterFraction; internal readonly Vector2 Center; internal readonly Vector2 OriginOffset; internal PixelFrame(float resolutionScale, float pixelsPerUnit, float centerFraction, Vector2 anchorScreen, Vector2 rootScreen) { //IL_0016: 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_0030: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) ResolutionScale = resolutionScale; PixelsPerUnit = pixelsPerUnit; CenterFraction = centerFraction; Center = new Vector2(SnapToGrid(anchorScreen.x, centerFraction), SnapToGrid(anchorScreen.y, centerFraction)); OriginOffset = Center - rootScreen; } internal static float FractionFor(float logicalSize, float resolutionScale) { if (Mathf.Max(1, RoundPx(logicalSize * resolutionScale)) % 2 != 0) { return 0.5f; } return 0f; } internal int Width(float logical) { return Mathf.Max(1, RoundPx(logical * ResolutionScale)); } internal int CenteredSize(float logical) { float num = logical * ResolutionScale; if (CenterFraction == 0f) { return Mathf.Max(2, 2 * RoundPx(num * 0.5f)); } return Mathf.Max(1, 2 * (int)Mathf.Floor(num * 0.5f) + 1); } internal float EdgeDistance(float logical, float extraPixels = 0f) { float num = Mathf.Max(0f, Mathf.Max(0f, logical) * ResolutionScale + extraPixels); return Mathf.Floor(CenterFraction + num + 0.5f) - CenterFraction; } internal int WholePixels(float logical) { return Mathf.Max(0, RoundPx(logical * ResolutionScale)); } internal float SnapEdge(float offset) { return Mathf.Floor(CenterFraction + offset + 0.5f) - CenterFraction; } internal float ToLocal(float pixels) { return pixels / PixelsPerUnit; } internal void Place(RectTransform rect, Vector4 pixelRect) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0073: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor((pixelRect.x + pixelRect.z) * 0.5f, (pixelRect.y + pixelRect.w) * 0.5f); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(pixelRect.z - pixelRect.x, pixelRect.w - pixelRect.y); rect.anchoredPosition = (OriginOffset + val) / PixelsPerUnit; rect.sizeDelta = val2 / PixelsPerUnit; } internal static int RoundPx(float value) { return (int)Mathf.Floor(value + 0.5f); } private static float SnapToGrid(float value, float fraction) { return Mathf.Floor(value - fraction + 0.5f) + fraction; } } internal sealed class BorderedRect { private static readonly string[] SideNames = new string[4] { "Top", "Bottom", "Left", "Right" }; private readonly Image _fill; private readonly Image[] _strips = (Image[])(object)new Image[4]; private BorderedRect(Transform layer, string name) { _fill = Find(layer, "Fill" + name); for (int i = 0; i < 4; i++) { _strips[i] = Find(layer, "Outline" + name + SideNames[i]); } } internal static BorderedRect Bind(Transform layer, string name) { return new BorderedRect(layer, name); } internal static void BuildBorder(Transform layer, string name) { string[] sideNames = SideNames; foreach (string text in sideNames) { CrosshairPrefabFactory.CreateImage("Outline" + name + text, layer); } } internal static void BuildFill(Transform layer, string name) { CrosshairPrefabFactory.CreateImage("Fill" + name, layer); } internal void Apply(in PixelFrame frame, Vector4 r, Color fill, int border, Color borderColor) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_0047: 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_0055: 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) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_008a: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: 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) Show(_fill, in frame, r, fill); if (border <= 0) { Image[] strips = _strips; for (int i = 0; i < strips.Length; i++) { ((Behaviour)strips[i]).enabled = false; } } else { float num = border; Show(_strips[0], in frame, new Vector4(r.x - num, r.w, r.z + num, r.w + num), borderColor); Show(_strips[1], in frame, new Vector4(r.x - num, r.y - num, r.z + num, r.y), borderColor); Show(_strips[2], in frame, new Vector4(r.x - num, r.y, r.x, r.w), borderColor); Show(_strips[3], in frame, new Vector4(r.z, r.y, r.z + num, r.w), borderColor); } } internal void Hide() { ((Behaviour)_fill).enabled = false; Image[] strips = _strips; for (int i = 0; i < strips.Length; i++) { ((Behaviour)strips[i]).enabled = false; } } private static void Show(Image image, in PixelFrame frame, Vector4 r, Color color) { //IL_0007: 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) frame.Place(((Graphic)image).rectTransform, r); ((Graphic)image).color = color; ((Behaviour)image).enabled = true; } private static Image Find(Transform layer, string name) { return ((Component)layer.Find(name)).GetComponent<Image>(); } } internal sealed class BarsLayer { private static readonly string[] ArmNames = new string[4] { "Left", "Right", "Top", "Bottom" }; private readonly BarsSettings _settings; private readonly BorderedRect[] _arms = new BorderedRect[4]; internal bool Enabled => _settings.Enabled.Value; internal float Thickness => _settings.Thickness.Value; internal BarsLayer(Transform root, string layerName, BarsSettings settings) { _settings = settings; Transform layer = root.Find(layerName); for (int i = 0; i < 4; i++) { _arms[i] = BorderedRect.Bind(layer, ArmNames[i]); } } internal static void Build(Transform root, string layerName) { Transform layer = (Transform)(object)CrosshairPrefabFactory.CreateRect(layerName, root); string[] armNames = ArmNames; foreach (string name in armNames) { BorderedRect.BuildBorder(layer, name); } armNames = ArmNames; foreach (string name2 in armNames) { BorderedRect.BuildFill(layer, name2); } } internal void Apply(in PixelFrame frame, float dynamicOffset) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: 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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) if (!Enabled) { BorderedRect[] arms = _arms; for (int i = 0; i < arms.Length; i++) { arms[i].Hide(); } return; } float extraPixels = ((_settings.Mode.Value == CrosshairMode.Dynamic) ? dynamicOffset : 0f); float num = (float)frame.CenteredSize(_settings.Thickness.Value) * 0.5f; float num2 = frame.EdgeDistance(_settings.Gap.Value, extraPixels); float num3 = num2 + (float)frame.Width(_settings.Length.Value); Color value = _settings.Fill.Value; Color value2 = _settings.Outline.Color.Value; int border = (_settings.Outline.Visible ? frame.Width(_settings.Outline.Thickness.Value) : 0); _arms[0].Apply(in frame, new Vector4(0f - num3, 0f - num, 0f - num2, num), value, border, value2); _arms[1].Apply(in frame, new Vector4(num2, 0f - num, num3, num), value, border, value2); _arms[2].Apply(in frame, new Vector4(0f - num, num2, num, num3), value, border, value2); _arms[3].Apply(in frame, new Vector4(0f - num, 0f - num3, num, 0f - num2), value, border, value2); } } internal sealed class RingPart { private const float SegmentPixels = 1.5f; private const int MinSegments = 24; private const int MaxSegments = 512; private readonly RingMesh _mesh; private readonly Image _image; private RingPart(Transform layer, string name) { _mesh = ((Component)layer.Find(name)).GetComponent<RingMesh>(); _image = _mesh.Image; } internal static RingPart Bind(Transform layer, string name) { return new RingPart(layer, name); } internal static void Build(Transform layer, string name) { CrosshairPrefabFactory.CreateImage(name, layer); ((Component)layer.Find(name)).gameObject.AddComponent<RingMesh>(); } internal void Apply(in PixelFrame frame, float inner, float outer, int border, Color fill, Color borderColor, Vector2 centerOffset = default(Vector2)) { //IL_003b: 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_004d: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) float num = outer + (float)border + 1f; int segments = Mathf.Clamp(Mathf.CeilToInt(MathF.PI * 2f * (outer + (float)border) / 1.5f), 24, 512); frame.Place(((Graphic)_image).rectTransform, new Vector4(centerOffset.x - num, centerOffset.y - num, centerOffset.x + num, centerOffset.y + num)); ((Graphic)_image).color = Color.white; _mesh.SetShape(frame.ToLocal(inner), frame.ToLocal(outer), frame.ToLocal(border), frame.ToLocal(1f), fill, borderColor, segments); ((Behaviour)_image).enabled = true; } internal void Hide() { ((Behaviour)_image).enabled = false; } } internal sealed class CenterDotLayer { private const string DotName = "Dot"; private readonly DotSettings _settings; private readonly RingPart _dot; internal bool Enabled => _settings.Enabled.Value; internal float Size => _settings.Size.Value; internal CenterDotLayer(Transform root, string layerName, DotSettings settings) { _settings = settings; _dot = RingPart.Bind(root.Find(layerName), "Dot"); } internal static void Build(Transform root, string layerName) { RingPart.Build((Transform)(object)CrosshairPrefabFactory.CreateRect(layerName, root), "Dot"); } internal void Apply(in PixelFrame frame) { //IL_007c: 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) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) if (!Enabled) { _dot.Hide(); return; } float outer = (float)frame.CenteredSize(_settings.Size.Value) * 0.5f; int border = (_settings.Outline.Visible ? frame.Width(_settings.Outline.Thickness.Value) : 0); _dot.Apply(in frame, 0f, outer, border, _settings.Fill.Value, _settings.Outline.Color.Value); } } internal sealed class CircleLayer { private const string RingName = "Ring"; private readonly CircleSettings _settings; private readonly RingPart _ring; internal CircleLayer(Transform root, string layerName, CircleSettings settings) { _settings = settings; _ring = RingPart.Bind(root.Find(layerName), "Ring"); } internal static void Build(Transform root, string layerName) { RingPart.Build((Transform)(object)CrosshairPrefabFactory.CreateRect(layerName, root), "Ring"); } internal void Apply(in PixelFrame frame, float dynamicOffset) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (!_settings.Enabled.Value) { _ring.Hide(); return; } float extraPixels = ((_settings.Mode.Value == CrosshairMode.Dynamic) ? dynamicOffset : 0f); float num = frame.EdgeDistance(_settings.Radius.Value, extraPixels); float outer = num + (float)frame.Width(_settings.Thickness.Value); int border = (_settings.Outline.Visible ? frame.Width(_settings.Outline.Thickness.Value) : 0); _ring.Apply(in frame, num, outer, border, _settings.Fill.Value, _settings.Outline.Color.Value); } } internal enum CrosshairMode { Static, Dynamic } internal static class CrosshairPrefabFactory { internal const string ProceduralRootName = "ProceduralCrosshair"; internal const string CircleLayerName = "Circle"; internal const string OuterBarsLayerName = "OuterBars"; internal const string InnerBarsLayerName = "InnerBars"; internal const string CenterDotLayerName = "CenterDot"; internal const string IndicatorLayerName = "Indicators"; private static readonly HashSet<Type> PresentationTypes = new HashSet<Type> { typeof(Image), typeof(RawImage), typeof(HudElement), typeof(CrosshairController), typeof(AspectRatioFitter), typeof(LayoutElement), typeof(ContentSizeFitter), typeof(HorizontalLayoutGroup), typeof(VerticalLayoutGroup), typeof(GridLayoutGroup), typeof(Shadow), typeof(Outline) }; private const float LargeArtUnits = 300f; private static readonly HashSet<string> PresentationTypeNames = new HashSet<string> { "ObjectScaleCurve", "RotateAroundAxis" }; internal static bool IndicatorsUnavailable { get; private set; } internal static void LoadAsync(string address, Action<GameObject?> onLoaded) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)address); val.Completed += delegate(AsyncOperationHandle<GameObject> op) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)op.Status != 1 || (Object)(object)op.Result == (Object)null) { Plugin.Log.LogError((object)$"Could not load '{address}': {op.OperationException}"); onLoaded(null); } else { onLoaded(op.Result); } }; } internal static GameObject BuildStandard(GameObject standardCrosshair, Transform holder) { CrosshairController controller; GameObject val = Clone(standardCrosshair, holder, "RoR2CustomCrosshair", out controller); Plugin.Log.LogDebug((object)("StandardCrosshair components: " + string.Join(", ", from c in val.GetComponents<Component>() select ((object)c).GetType().Name))); controller.spriteSpreadPositions = Array.Empty<SpritePosition>(); controller.skillStockSpriteDisplays = Array.Empty<SkillStockSpriteDisplay>(); controller.remapSprites = Array.Empty<RawImage>(); HideVanillaVisuals(val, new HashSet<Transform>()); AddProceduralCrosshair(val); return val; } internal static GameObject? BuildStockPreserving(GameObject vanillaCrosshair, Transform holder, bool keepSpreadArt = false, bool keepCounts = true) { //IL_005d: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_0089: 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_00d2: 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_00e4: Unknown result type (might be due to invalid IL or missing references) string text = (keepSpreadArt ? "_ChargeDisplay" : (keepCounts ? "" : "_CountSuperseded")); CrosshairController controller; GameObject val = Clone(vanillaCrosshair, holder, "RoR2CustomCrosshair_" + ((Object)vanillaCrosshair).name + text, out controller); Transform transform = val.transform; List<SkillStockSpriteDisplay> list = new List<SkillStockSpriteDisplay>(); SkillStockSpriteDisplay[] array = controller.skillStockSpriteDisplays ?? Array.Empty<SkillStockSpriteDisplay>(); foreach (SkillStockSpriteDisplay val2 in array) { if (Object.op_Implicit((Object)(object)val2.target) && !IsAtCenter(transform, val2.target.transform) && (keepCounts || !IsCountDisplay(val2))) { list.Add(val2); } } List<SpritePosition> list2 = new List<SpritePosition>(); if (keepSpreadArt) { SpritePosition[] array2 = controller.spriteSpreadPositions ?? Array.Empty<SpritePosition>(); foreach (SpritePosition val3 in array2) { if (Object.op_Implicit((Object)(object)val3.target)) { list2.Add(val3); } } } if (list.Count == 0 && list2.Count == 0) { Object.Destroy((Object)(object)val); return null; } controller.spriteSpreadPositions = list2.ToArray(); controller.remapSprites = Array.Empty<RawImage>(); controller.skillStockSpriteDisplays = list.ToArray(); HashSet<Transform> hashSet = new HashSet<Transform>(); foreach (Transform item in list.Select((SkillStockSpriteDisplay d) => d.target.transform).Concat(list2.Select((SpritePosition s) => (Transform)(object)s.target))) { Transform val4 = item; while ((Object)(object)val4 != (Object)null && (Object)(object)val4 != (Object)(object)transform) { hashSet.Add(val4); val4 = val4.parent; } } HideVanillaVisuals(val, hashSet); AddProceduralCrosshair(val); Plugin.Log.LogDebug((object)(((Object)vanillaCrosshair).name + text + ": keeping vanilla stock displays [" + string.Join(", ", list.Select((SkillStockSpriteDisplay d) => ((Object)d.target).name)) + "]" + (keepSpreadArt ? (" and charge-display art [" + string.Join(", ", list2.Select((SpritePosition s) => ((Object)s.target).name)) + "]") : "; spread artwork removed") + ".")); return val; } internal static bool IsPureReticle(GameObject vanilla, out string extra) { //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); CrosshairController val = default(CrosshairController); if (vanilla.TryGetComponent<CrosshairController>(ref val)) { SkillStockSpriteDisplay[] skillStockSpriteDisplays = val.skillStockSpriteDisplays; if (skillStockSpriteDisplays != null && skillStockSpriteDisplays.Length > 0) { list.Add($"{skillStockSpriteDisplays.Length} skill-stock display(s)"); } } MonoBehaviour[] componentsInChildren = vanilla.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && !PresentationTypes.Contains(((object)val2).GetType()) && !PresentationTypeNames.Contains(((object)val2).GetType().Name)) { list.Add(((object)val2).GetType().Name + " on '" + ((Object)val2).name + "'"); } } HashSet<Transform> hashSet = new HashSet<Transform>(); if ((Object)(object)val != (Object)null) { SpritePosition[] array = val.spriteSpreadPositions ?? Array.Empty<SpritePosition>(); foreach (SpritePosition val3 in array) { if (Object.op_Implicit((Object)(object)val3.target)) { hashSet.Add((Transform)(object)val3.target); } } } Graphic[] componentsInChildren2 = vanilla.GetComponentsInChildren<Graphic>(true); foreach (Graphic val4 in componentsInChildren2) { RectTransform rectTransform = val4.rectTransform; if (!hashSet.Contains((Transform)(object)rectTransform) && (rectTransform.anchorMin != rectTransform.anchorMax || Mathf.Abs(rectTransform.sizeDelta.x) > 300f || Mathf.Abs(rectTransform.sizeDelta.y) > 300f)) { list.Add("large art '" + ((Object)val4).name + "'"); } } extra = string.Join(", ", list.Distinct()); return list.Count == 0; } internal static GameObject BuildOverlay(GameObject vanillaCrosshair, Transform holder, bool stripCounts = false) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_00cc: 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_007c: 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) string text = (stripCounts ? "_CountSuperseded" : ""); CrosshairController controller; GameObject val = Clone(vanillaCrosshair, holder, "RoR2CustomCrosshair_" + ((Object)vanillaCrosshair).name + text, out controller); if (stripCounts) { List<SkillStockSpriteDisplay> list = new List<SkillStockSpriteDisplay>(); SkillStockSpriteDisplay[] array = controller.skillStockSpriteDisplays ?? Array.Empty<SkillStockSpriteDisplay>(); foreach (SkillStockSpriteDisplay val2 in array) { if (Object.op_Implicit((Object)(object)val2.target)) { if (IsCountDisplay(val2)) { val2.target.SetActive(false); } else { list.Add(val2); } } } controller.skillStockSpriteDisplays = list.ToArray(); } SpritePosition[] array2 = controller.spriteSpreadPositions ?? Array.Empty<SpritePosition>(); foreach (SpritePosition val3 in array2) { if (Object.op_Implicit((Object)(object)val3.target)) { ((Component)val3.target).gameObject.SetActive(false); } } RawImage[] array3 = controller.remapSprites ?? Array.Empty<RawImage>(); foreach (RawImage val4 in array3) { if (Object.op_Implicit((Object)(object)val4)) { ((Behaviour)val4).enabled = false; } } controller.spriteSpreadPositions = Array.Empty<SpritePosition>(); controller.remapSprites = Array.Empty<RawImage>(); Graphic[] components = val.GetComponents<Graphic>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } AddProceduralCrosshair(val); return val; } private static GameObject Clone(GameObject source, Transform holder, string name, out CrosshairController controller) { GameObject val = Object.Instantiate<GameObject>(source, holder, false); ((Object)val).name = name; HudElement val2 = default(HudElement); if (!val.TryGetComponent<CrosshairController>(ref controller) || !val.TryGetComponent<HudElement>(ref val2)) { Object.Destroy((Object)(object)val); throw new InvalidOperationException(((Object)source).name + " no longer has CrosshairController + HudElement."); } return val; } private static bool IsCountDisplay(SkillStockSpriteDisplay display) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return display.minimumStockCountToBeValid >= 1; } private static bool IsAtCenter(Transform root, Transform target) { //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_000c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = root.InverseTransformPoint(target.position); return ((Vector3)(ref val)).sqrMagnitude < 1f; } private static void HideVanillaVisuals(GameObject template, HashSet<Transform> keep) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown foreach (Transform item in template.transform) { Transform val = item; if (!keep.Contains(val)) { ((Component)val).gameObject.SetActive(false); } } Graphic[] components = template.GetComponents<Graphic>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } } private static void AddProceduralCrosshair(GameObject template) { RectTransform val = CreateRect("ProceduralCrosshair", template.transform); try { IndicatorLayer.Build((Transform)(object)val, "Indicators"); } catch (Exception arg) { IndicatorsUnavailable = true; Transform val2 = ((Transform)val).Find("Indicators"); if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)((Component)val2).gameObject); } Plugin.Log.LogError((object)$"Could not build indicator layer; vanilla indicators will be kept: {arg}"); } CircleLayer.Build((Transform)(object)val, "Circle"); BarsLayer.Build((Transform)(object)val, "OuterBars"); BarsLayer.Build((Transform)(object)val, "InnerBars"); CenterDotLayer.Build((Transform)(object)val, "CenterDot"); template.AddComponent<ProceduralCrosshairView>(); } internal static RectTransform CreateRect(string name, Transform parent) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform; ((Transform)val).SetParent(parent, false); val.anchorMin = new Vector2(0.5f, 0.5f); val.anchorMax = new Vector2(0.5f, 0.5f); val.pivot = new Vector2(0.5f, 0.5f); val.anchoredPosition = Vector2.zero; val.sizeDelta = Vector2.zero; return val; } internal static void CreateImage(string name, Transform parent) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = CreateRect(name, parent); ((Component)obj).gameObject.AddComponent<CanvasRenderer>(); Image obj2 = ((Component)obj).gameObject.AddComponent<Image>(); ((Graphic)obj2).raycastTarget = false; ((MaskableGraphic)obj2).maskable = false; ((Graphic)obj2).color = Color.clear; ((Behaviour)obj2).enabled = false; } } internal static class DlcSurvivorSpread { internal static ISpreadSource[] Create() { return new ISpreadSource[9] { Railgunner(), VoidFiend(), Seeker(), FalseSon(), Chef(), Drifter(), DroneTech(), Acolyte(), Enforcer() }; } private static ISpreadSource Railgunner() { return new TableSpreadSource("Railgunner", "RailgunnerBody", new string[2] { "Weapon", "WeaponMine" }, new AttackRule(typeof(FirePistol), (EntityState state, CharacterBody body) => new SpreadSample(((FirePistol)state).baseInaccuracyDegrees + body.spreadBloomAngle, SpreadKind.Bloom, "M99 pistol")), AttackRule.None(typeof(BaseWindupSnipe), "Supercharge/Cryocharge windup (zero-spread shot)"), AttackRule.None(typeof(BaseChargeSnipe), "Supercharge/Cryocharge charging (no shot)"), AttackRule.None(typeof(BaseFireMine), "Mine (straight throw)")); } private static ISpreadSource VoidFiend() { return new TableSpreadSource("Void Fiend", "VoidSurvivorBody", new string[2] { "Weapon", "Body" }, AttackRule.Bloom(typeof(FireHandBeam), "Drown"), new AttackRule(typeof(FireCorruptHandBeam), (EntityState state, CharacterBody _) => new SpreadSample(((FireCorruptHandBeam)state).maxSpread, SpreadKind.Fixed, "Corrupted Drown")), new AttackRule(typeof(ChargeCorruptHandBeam), (EntityState _, CharacterBody _) => CorruptBeamEnvelope()), AttackRule.None(typeof(ChargeMegaBlaster), "Flood charging (zero-spread shot)"), AttackRule.None(typeof(ReadyMegaBlaster), "Flood charged (zero-spread shot)"), AttackRule.None(typeof(FireMegaBlasterBase), "Flood (zero-spread projectile)"), new AttackRule(typeof(FireCorruptDisks), (EntityState state, CharacterBody body) => new SpreadSample(body.spreadBloomAngle + ((FireCorruptDisks)state).spread, SpreadKind.Bloom, "Corrupted Flood"))); } private static SpreadSample CorruptBeamEnvelope() { FireCorruptHandBeam val = AttackSpread.Configured<FireCorruptHandBeam>(typeof(FireCorruptHandBeam)); if (val == null) { return SpreadSample.None("Corrupted Drown (charging, unconfigured)"); } return new SpreadSample(val.maxSpread, SpreadKind.Fixed, "Corrupted Drown (charging)"); } private static ISpreadSource Seeker() { return new TableSpreadSource("Seeker", "SeekerBody", new string[2] { "Weapon", "Body" }, AttackRule.None(typeof(SpiritPunch), "Spirit Punch (straight projectile)"), AttackRule.None(typeof(SoulSearch), "Soul Search (homing)"), AttackRule.None(typeof(UnseenHand), "Unseen Hand (world-targeted)"), AttackRule.None(typeof(BaseChargePalmBlast), "Palm Blast charging (charge does not change aim)"), AttackRule.None(typeof(BaseFirePalmBlast), "Palm Blast (no spread)")); } private static ISpreadSource FalseSon() { return new TableSpreadSource("False Son", "FalseSonBody", new string[2] { "Weapon", "Body" }, AttackRule.None(typeof(LunarSpikes), "Lunar Spikes/Stake (straight projectile)"), AttackRule.None(typeof(LunarSpikesShotgun), "Lunar Spikes shotgun (straight projectile)"), AttackRule.None(typeof(ClubSwing3), "Club charge (melee)"), AttackRule.None(typeof(LaserFather), "Laser of the Father charging (zero-spread beam)"), AttackRule.None(typeof(LaserFatherCharged), "Laser of the Father (zero-spread beam)"), AttackRule.None(typeof(LaserFatherBurstPrep), "Laser Burst windup (zero-spread beam)"), AttackRule.None(typeof(LaserFatherBurst), "Laser Burst (zero-spread beam)"), AttackRule.None(typeof(MeridiansWillAim), "Meridian's Will (world-targeted)")); } private static ISpreadSource Chef() { return new TableSpreadSource("CHEF", "ChefBody", new string[2] { "Weapon", "Body" }, AttackRule.None(typeof(Dice), "Dice (straight projectile)"), AttackRule.Fixed(typeof(Sear), "Sear", () => Sear.maxSpread), AttackRule.None(typeof(IceBox), "Ice Box (straight projectiles)"), new AttackRule(typeof(Glaze), (EntityState _, CharacterBody body) => new SpreadSample(body.spreadBloomAngle + Glaze.xDeviationSpread, SpreadKind.Bloom, "Glaze")), AttackRule.None(typeof(RolyPoly), "Roll charge (no aim)")); } private static ISpreadSource Drifter() { return new TableSpreadSource("Drifter", "DrifterBody", new string[2] { "Weapon", "Body" }, new AttackRule(typeof(AimMagicBag), (EntityState state, CharacterBody _) => new SpreadSample(((AimMagicBag)state).shotgunConeAngle, SpreadKind.Fixed, "Cleanup (pellet cone)")), new AttackRule(typeof(Cleanup), (EntityState state, CharacterBody _) => new SpreadSample(((Cleanup)state).shotgunConeAngle, SpreadKind.Fixed, "Cleanup classic (pellet cone)")), AttackRule.None(typeof(AimThrowableBase), "Throw (world-targeted)"), AttackRule.None(typeof(AimRepossess), "Repossess (targeted)")); } private static ISpreadSource DroneTech() { return new TableSpreadSource("Drone Tech", "DroneTechBody", new string[2] { "Weapon", "Shield" }, AttackRule.None(typeof(Activate), "Command (targeted)"), AttackRule.None(typeof(ThrowDroneBall), "Drone ball (straight projectile)"), AttackRule.None(typeof(ShieldFormation), "Shield formation (straight projectile)"), AttackRule.None(typeof(FireShield), "Shield (straight projectile)"), AttackRule.None(typeof(BaseDroneHeadbuttPaintState), "Headbutt paint (lock-on)")); } private static ISpreadSource Acolyte() { return new TableSpreadSource("Acolyte", "AcolyteBody", new string[2] { "Weapon", "Body" }, AttackRule.None(typeof(BolaWhip), "Bola (straight projectile)"), AttackRule.None(typeof(AimSacrifice), "Sacrifice (lock-on)"), AttackRule.None(typeof(AimThrowableBase), "Soul Jar (world-targeted)")); } private static ISpreadSource Enforcer() { return new TableSpreadSource("Enforcer", "Enforcer2Body", new string[4] { "Reload", "Weapon", "Body", "Shield" }, new AttackRule(typeof(FireRiotShotgunShielded), ShieldedShotgunEnvelope)); } private static SpreadSample ShieldedShotgunEnvelope(EntityState state, CharacterBody body) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown FireRiotShotgunShielded val = (FireRiotShotgunShielded)state; float num = Mathf.Max(((GenericBulletBaseState)val).spreadYawScale, ((GenericBulletBaseState)val).spreadPitchScale); float num2 = body.spreadBloomAngle; AnimationCurve spreadBloomCurve = body.spreadBloomCurve; if ((Object)(object)state.outer == (Object)null && spreadBloomCurve != null && spreadBloomCurve.length > 0) { float num3 = spreadBloomCurve.Evaluate(1f); float num4 = ((num3 > 0f) ? Mathf.Clamp01(num2 / num3) : 0f); num2 = spreadBloomCurve.Evaluate(Mathf.Clamp01(num4 + val.bulletSpreadBloom)); } return new SpreadSample(num2 * ((GenericBulletBaseState)val).maxSpread * num, SpreadKind.Bloom, "Riot shotgun (shielded)"); } } internal enum SpreadKind { Zero, Fixed, Bloom } internal readonly struct SpreadSample { internal readonly float Degrees; internal readonly SpreadKind Kind; internal readonly string Context; internal SpreadSample(float degrees, SpreadKind kind, string context) { Degrees = ((degrees < 0f) ? 0f : degrees); Kind = ((!(Degrees <= 0f)) ? kind : SpreadKind.Zero); Context = context; } internal static SpreadSample None(string context) { return new SpreadSample(0f, SpreadKind.Zero, context); } } internal interface ISpreadSource { bool LogSamples { get; } bool CanHandle(CharacterBody body); bool TrySample(CharacterBody body, out SpreadSample sample); } internal sealed class SpreadSourceResolver { private readonly ISpreadSource[] _sources; private CharacterBody? _body; private ISpreadSource? _source; internal SpreadSourceResolver(params ISpreadSource[] sources) { _sources = sources; } internal bool TrySample(CharacterBody body, out SpreadSample sample, out ISpreadSource? source) { if ((Object)(object)body != (Object)(object)_body) { _body = body; _source = null; ISpreadSource[] sources = _sources; foreach (ISpreadSource spreadSource in sources) { if (spreadSource.CanHandle(body)) { _source = spreadSource; break; } } } source = _source; sample = default(SpreadSample); if (_source != null) { return _source.TrySample(body, out sample); } return false; } } internal static class SpreadProjection { internal static float HalfAngleToPixels(float halfAngleDegrees, Camera camera) { float num = camera.fieldOfView * 0.5f * (MathF.PI / 180f); if (num <= 0f || halfAngleDegrees <= 0f) { return 0f; } return Mathf.Tan(Mathf.Min(halfAngleDegrees, 89f) * (MathF.PI / 180f)) / Mathf.Tan(num) * ((float)camera.pixelHeight * 0.5f); } } internal sealed class HudCrosshairDriver : MonoBehaviour { private static readonly ISpreadSource[] SpreadSources = CreateSpreadSources(); private const float OffsetStepPixels = 0.25f; private const float SpreadLogInterval = 1f; private float _nextSpreadLogTime; private string? _lastLoggedContext; private float _lastLoggedPixels = -1f; private readonly SpreadSourceResolver _spreadResolver = new SpreadSourceResolver(SpreadSources); private readonly IndicatorSourceResolver _indicatorResolver = new IndicatorSourceResolver(SurvivorIndicators.Create()); private readonly IndicatorFrame _indicators = new IndicatorFrame(); private int _indicatorFrameNumber = -1; private CharacterBody? _indicatorBody; private CrosshairManager? _crosshairManager; private bool _replacing; private static ISpreadSource[] CreateSpreadSources() { List<ISpreadSource> list = new List<ISpreadSource>(); list.Add(new CommandoSpreadSource()); list.Add(new BanditSpreadSource()); list.Add(new ToolbotSpreadSource()); list.AddRange(BaseGameSurvivorSpread.Create()); list.AddRange(DlcSurvivorSpread.Create()); return list.ToArray(); } internal static void Attach(HUD hud) { if (!Object.op_Implicit((Object)(object)((Component)hud).GetComponent<HudCrosshairDriver>())) { ((Component)hud).gameObject.AddComponent<HudCrosshairDriver>(); } } private void Awake() { _crosshairManager = ((Component)this).GetComponent<CrosshairManager>(); if (!Object.op_Implicit((Object)(object)_crosshairManager)) { Plugin.Log.LogWarning((object)("HUD '" + ((Object)this).name + "' has no CrosshairManager; custom crosshair unavailable.")); } } private void OnEnable() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)_crosshairManager)) { _crosshairManager.pickCrosshairGlobal += new PickCrosshairDelegate(OnPickCrosshair); } } private void OnDisable() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)_crosshairManager)) { _crosshairManager.pickCrosshairGlobal -= new PickCrosshairDelegate(OnPickCrosshair); } SetReplacing(replacing: false, null); } private void OnPickCrosshair(CrosshairManager manager, ref GameObject crosshairPrefab) { CharacterBody ownLiveBody = GetOwnLiveBody(manager); GameObject val = (((Object)(object)ownLiveBody != (Object)null && CrosshairConfig.Enabled.Value) ? CrosshairDisplayPolicy.ChooseTemplate(ownLiveBody, crosshairPrefab, SampleIndicators(ownLiveBody)) : null); if ((Object)(object)val != (Object)null) { crosshairPrefab = val; } SetReplacing((Object)(object)val != (Object)null, ownLiveBody); } internal DynamicOffsets GetDynamicOffsets() { if (!_replacing || !Object.op_Implicit((Object)(object)_crosshairManager)) { return default(DynamicOffsets); } CameraRigController cameraRigController = _crosshairManager.cameraRigController; CharacterBody ownLiveBody = GetOwnLiveBody(_crosshairManager); Camera val = (Object.op_Implicit((Object)(object)cameraRigController) ? cameraRigController.sceneCam : null); if ((Object)(object)ownLiveBody == (Object)null || (Object)(object)val == (Object)null || !_spreadResolver.TrySample(ownLiveBody, out SpreadSample sample, out ISpreadSource source)) { return default(DynamicOffsets); } float num = Mathf.Round(SpreadProjection.HalfAngleToPixels(sample.Degrees, val) / 0.25f) * 0.25f; if (source.LogSamples) { LogSpreadSample(in sample, val, num); } return new DynamicOffsets(num, num, num); } internal IndicatorFrame GetIndicators() { CharacterBody val = ((_replacing && Object.op_Implicit((Object)(object)_crosshairManager)) ? GetOwnLiveBody(_crosshairManager) : null); if ((Object)(object)val == (Object)null) { _indicators.Clear(); _indicatorBody = null; _indicatorFrameNumber = Time.frameCount; return _indicators; } return SampleIndicators(val); } private IndicatorFrame SampleIndicators(CharacterBody body) { if (Time.frameCount != _indicatorFrameNumber || (Object)(object)body != (Object)(object)_indicatorBody) { _indicatorFrameNumber = Time.frameCount; _indicatorBody = body; _indicatorResolver.Sample(body, _indicators); } return _indicators; } private void LogSpreadSample(in SpreadSample sample, Camera camera, float pixels) { bool num = sample.Context != _lastLoggedContext; bool flag = Mathf.Abs(pixels - _lastLoggedPixels) >= 0.25f; if (num || (flag && !(Time.unscaledTime < _nextSpreadLogTime))) { _lastLoggedContext = sample.Context; _lastLoggedPixels = pixels; _nextSpreadLogTime = Time.unscaledTime + 1f; Plugin.Log.LogDebug((object)($"[Spread] {sample.Context}: {sample.Kind} envelope {sample.Degrees:0.###} deg, " + $"vertical FOV {camera.fieldOfView:0.#}, camera {camera.pixelWidth}x{camera.pixelHeight} -> " + $"projected spread radius {pixels:0.##} px.")); } } private static CharacterBody? GetOwnLiveBody(CrosshairManager manager) { CameraRigController cameraRigController = manager.cameraRigController; if (!Object.op_Implicit((Object)(object)cameraRigController) || cameraRigController.hasOverride) { return null; } LocalUser localUserViewer = cameraRigController.localUserViewer; CharacterBody targetBody = cameraRigController.targetBody; if (localUserViewer == null || !Object.op_Implicit((Object)(object)targetBody) || (Object)(object)localUserViewer.cachedBodyObject != (Object)(object)((Component)targetBody).gameObject) { return null; } if (!Object.op_Implicit((Object)(object)targetBody.healthComponent) || !targetBody.healthComponent.alive) { return null; } return targetBody; } private void SetReplacing(bool replacing, CharacterBody? body) { if (replacing != _replacing) { _replacing = replacing; Plugin.Log.LogDebug((object)(replacing ? ("Custom crosshair active for " + body.GetDisplayName() + " (" + ((Object)body).name + ").") : "Custom crosshair released; vanilla crosshair logic in control.")); } } } internal enum IndicatorPlacement { Above, Below, Left, Right } internal enum ProgressBarMode { Static, Dynamic } internal enum BarOrientation { Horizontal, Vertical } internal enum FillFrom { LeftOrBottom, RightOrTop } internal enum CountDisplayMode { Dots, Number, Bars } internal enum CountLayout { Horizontal, Vertical } internal enum CountNumberFormat { Current, CurrentOfMaximum } internal static class IndicatorDistance { internal const float Default = 8f; internal const float Max = 128f; internal static ConfigEntry<float> Bind(ConfigFile config, string section) { return CrosshairConfig.BindFloat(config, section, "Distance From Crosshair", 8f, 0f, 128f, "Gap between the crosshair's configured outer edge and the first indicator in its slot, in pixels at 1920x1080. Further indicators in the same slot stack outward from it."); } internal static void Register(ConfigEntry<float> distance) { CrosshairConfig.AddFloatOption(distance, 0f, 128f); } } internal sealed class ProgressBarSettings { internal const float MaxLength = 200f; internal const float MaxThickness = 40f; internal readonly ConfigEntry<bool> Enabled; internal readonly ConfigEntry<ProgressBarMode> Mode; internal readonly ConfigEntry<BarOrientation> Orientation; internal readonly ConfigEntry<FillFrom> FillFrom; internal readonly ConfigEntry<IndicatorPlacement> Placement; internal readonly ConfigEntry<float> Distance; internal readonly ConfigEntry<float> Length; internal readonly ConfigEntry<float> Thickness; internal readonly ColorSettings NotReady; internal readonly ColorSettings Ready; internal readonly ConfigEntry<bool> ShowBackground; internal readonly ColorSettings Background; internal readonly OutlineSettings Outline; internal ProgressBarSettings(ConfigFile config, string section) { //IL_00ef: 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) //IL_0148: Unknown result type (might be due to invalid IL or missing references) Enabled = config.Bind<bool>(section, "Enabled", true, "Show progress / charge / readiness bars (e.g. MUL-T Rebar Puncher readiness)."); Mode = config.Bind<ProgressBarMode>(section, "Mode", ProgressBarMode.Dynamic, "Static: the whole bar is Not Ready color until ready, then Ready color. Dynamic: the bar fills with progress, then turns Ready color."); Orientation = config.Bind<BarOrientation>(section, "Orientation", BarOrientation.Vertical, "Horizontal or vertical bar."); FillFrom = config.Bind<FillFrom>(section, "Fill From", RoR2CustomCrosshair.FillFrom.LeftOrBottom, "Dynamic fill start: left (horizontal) / bottom (vertical), or the opposite end."); Placement = config.Bind<IndicatorPlacement>(section, "Placement", IndicatorPlacement.Right, "Mod-defined slot around the crosshair. Several indicators on one side stack automatically."); Distance = IndicatorDistance.Bind(config, section); Length = CrosshairConfig.BindFloat(config, section, "Length", 24f, 4f, 200f, "Bar length along its orientation, in pixels at 1920x1080."); Thickness = CrosshairConfig.BindFloat(config, section, "Thickness", 4f, 1f, 40f, "Bar thickness across its orientation, in pixels at 1920x1080."); NotReady = new ColorSettings(config, section, "Not Ready ", new Color32(byte.MaxValue, (byte)140, (byte)0, byte.MaxValue)); Ready = new ColorSettings(config, section, "Ready ", new Color32((byte)60, (byte)220, (byte)60, byte.MaxValue)); ShowBackground = config.Bind<bool>(section, "Show Empty Background", true, "Dynamic mode: draw the unfilled part of the bar."); Background = new ColorSettings(config, section, "Background ", new Color32((byte)0, (byte)0, (byte)0, (byte)120)); Outline = new OutlineSettings(config, section); } internal void Register() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or m