using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Auuueser.EnemyHealthBars.Configuration; using Auuueser.EnemyHealthBars.Core.Configuration; using Auuueser.EnemyHealthBars.Core.Domain; using Auuueser.EnemyHealthBars.Core.GameData; using Auuueser.EnemyHealthBars.Core.Presentation; using Auuueser.EnemyHealthBars.Game; using Auuueser.EnemyHealthBars.Networking; using Auuueser.EnemyHealthBars.Presentation; using Auuueser.EnemyHealthBars.Runtime; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using Microsoft.CodeAnalysis; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; 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("EnemyHealthBar")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+b7c1f2b1f786c084509ca3acd75934243d39aa1d")] [assembly: AssemblyProduct("EnemyHealthBar")] [assembly: AssemblyTitle("EnemyHealthBar")] [assembly: AssemblyVersion("1.0.0.0")] 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; } } } namespace Auuueser.EnemyHealthBars { [BepInPlugin("auuueser.lethalcompany.enemyhealthbar", "Enemy Health Bar", "0.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("Lethal Company.exe")] public sealed class Plugin : BaseUnityPlugin { private HealthBarRuntime? runtime; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; ConfigLanguage language = ChineseProjectLanguageDetector.Detect(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); ModConfig config = ModConfig.Bind(((BaseUnityPlugin)this).Config, language); if (LethalConfigIntegration.IsAvailable()) { LethalConfigIntegration.Register(config, ((BaseUnityPlugin)this).Logger); } runtime = HealthBarRuntime.Start(config, ((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Enemy Health Bar 0.0.2 loaded."); } private void OnDestroy() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin component destroyed; runtime remains active."); } } internal static class PluginInfo { public const string PluginGuid = "auuueser.lethalcompany.enemyhealthbar"; public const string PluginName = "Enemy Health Bar"; public const string PluginVersion = "0.0.2"; } } namespace Auuueser.EnemyHealthBars.Runtime { internal sealed class EnemyHealthBarController : MonoBehaviour { private struct DiagnosticScanCounts { public static readonly DiagnosticScanCounts Empty; public int Spawned; public int Readable; public int Shown; public int Active; public int RejectedMissingEnemy; public int RejectedMissingEnemyType; public int RejectedCannotDie; public int UsedHostSync; public int HiddenWaitingForHostSync; public int HiddenDead; public int HiddenSettling; public int HiddenSpawnSettling; public int HiddenZeroHealth; public int HiddenFull; public int HiddenDistance; public int RetainedEnemyStates; public int RetainedNetworkStates; } private const int MaxSampleDiagnosticsPerScan = 8; private const int MissingStateRetentionScans = 3; private readonly EnemyHealthTracker tracker = new EnemyHealthTracker(); private readonly EnemyHealthReader healthReader = new EnemyHealthReader(); private readonly EnemyMaxHealthResolver maxHealthResolver = new EnemyMaxHealthResolver(); private readonly EnemyHealthSyncNetwork networkSync = new EnemyHealthSyncNetwork(); private readonly HashSet activeEnemyIds = new HashSet(); private readonly HashSet activeNetworkObjectIds = new HashSet(); private readonly TransientIdRetentionSet retainedEnemyStateIds = new TransientIdRetentionSet(3); private readonly TransientIdRetentionSet retainedNetworkStateIds = new TransientIdRetentionSet(3); private ModConfig? config; private ManualLogSource? logger; private RoundManagerEnemySource? enemySource; private LocalPlayerCameraProvider? cameraProvider; private EnemyHealthBarPresenter? presenter; private float nextScanTime; private float nextDiagnosticLogTime; private float nextDebugHeartbeatLogTime; private int observedSettingsVersion; public void Initialize(ModConfig config, ManualLogSource logger, RoundManagerEnemySource enemySource, LocalPlayerCameraProvider cameraProvider, EnemyHealthBarPresenter presenter) { this.config = config; this.logger = logger; this.enemySource = enemySource; this.cameraProvider = cameraProvider; this.presenter = presenter; observedSettingsVersion = config.SettingsVersion; } public void SetEnabled(bool enabled) { ((Behaviour)this).enabled = enabled; ((Component)this).gameObject.SetActive(enabled); } private void Update() { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) if (config == null || enemySource == null || cameraProvider == null || presenter == null) { return; } config.ReloadIfChangedOnDisk(Time.unscaledTime); if (observedSettingsVersion != config.SettingsVersion) { observedSettingsVersion = config.SettingsVersion; presenter.RefreshStyle(); } networkSync.Tick(config.Enabled && config.HostAuthoritySync, Time.unscaledTime); if (!config.Enabled) { presenter.Clear(); LogDiagnosticsIfDue(DiagnosticScanCounts.Empty, null, "Disabled"); LogDebugHeartbeatIfDue(null); return; } Camera activeCamera = cameraProvider.GetActiveCamera(); if ((Object)(object)activeCamera == (Object)null) { presenter.Clear(); LogDiagnosticsIfDue(DiagnosticScanCounts.Empty, null, "No active camera"); LogDebugHeartbeatIfDue(null); return; } Quaternion billboardRotation = HealthBarBillboard.CalculateRotation(activeCamera); UpdateDebugTestBar(activeCamera, billboardRotation); LogDebugHeartbeatIfDue(activeCamera); bool flag = false; if (Time.unscaledTime >= nextScanTime) { nextScanTime = Time.unscaledTime + config.ScanInterval; RefreshEnemies(activeCamera, billboardRotation); flag = true; } if (!flag) { presenter.UpdateActive(activeCamera, billboardRotation); } } private void OnDestroy() { networkSync.Dispose(); presenter?.Clear(); } private void RefreshEnemies(Camera camera, Quaternion billboardRotation) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) if (config == null || enemySource == null || presenter == null) { return; } activeEnemyIds.Clear(); activeNetworkObjectIds.Clear(); HealthBarVisibilityRules val = config.CreateVisibilityRules(); Vector3 position = ((Component)camera).transform.position; List spawnedEnemies = enemySource.GetSpawnedEnemies(); if (spawnedEnemies == null) { ISet set = retainedEnemyStateIds.Update((ISet)activeEnemyIds); ISet set2 = retainedNetworkStateIds.Update((ISet)activeNetworkObjectIds); tracker.KeepOnly(set); EnemyHealthOverrideStore.KeepOnly(set, set2); networkSync.KeepOnlyClientSnapshots(set2); networkSync.KeepOnlyHostSnapshots(set2); networkSync.FlushHostSnapshots(); presenter.HideMissing(activeEnemyIds); LogDiagnosticsIfDue(DiagnosticScanCounts.Empty, camera, "SpawnedEnemies unavailable"); return; } DiagnosticScanCounts counts = new DiagnosticScanCounts { Spawned = spawnedEnemies.Count }; List sampleDiagnostics = (ShouldCollectSampleDiagnostics() ? new List(8) : null); for (int i = 0; i < spawnedEnemies.Count; i++) { EnemyAI val2 = spawnedEnemies[i]; if ((Object)(object)val2 == (Object)null) { counts.RejectedMissingEnemy++; AddMissingEnemyDiagnostic(sampleDiagnostics, i); continue; } if (!healthReader.TryRead(val2, config.ShowInvulnerableEnemies, maxHealthResolver, out var sample, out var failure)) { AddReadFailure(ref counts, failure); AddReadFailureDiagnostic(sampleDiagnostics, val2, failure); continue; } counts.Readable++; activeEnemyIds.Add(((EnemyHealthSample)(ref sample)).EnemyId); if (((EnemyHealthSample)(ref sample)).NetworkObjectId != 0L) { activeNetworkObjectIds.Add(((EnemyHealthSample)(ref sample)).NetworkObjectId); } EnemyHealthSnapshot val3 = tracker.Track(sample, config.MaxHealthMode); if (networkSync.TryGetHostSnapshot(sample, out var snapshot)) { val3 = snapshot; ApplyHostSyncedHealth(val2, sample, val3); counts.UsedHostSync++; } else if (networkSync.ShouldSuppressLocalSnapshot(sample, Time.unscaledTime)) { counts.HiddenWaitingForHostSync++; AddSampleDiagnostic(sampleDiagnostics, val2, sample, val3, "hiddenWaitingForHostSync"); presenter.Hide(((EnemyHealthSample)(ref sample)).EnemyId); continue; } networkSync.QueueHostSnapshot(sample, val3); if (((EnemyHealthSnapshot)(ref val3)).IsDead) { counts.HiddenDead++; AddSampleDiagnostic(sampleDiagnostics, val2, sample, val3, "hiddenDead"); presenter.Hide(((EnemyHealthSample)(ref sample)).EnemyId); continue; } if (((EnemyHealthSnapshot)(ref val3)).IsMaxHealthSettling) { counts.HiddenSettling++; AddSampleDiagnostic(sampleDiagnostics, val2, sample, val3, "hiddenSettling"); presenter.Hide(((EnemyHealthSample)(ref sample)).EnemyId); continue; } if (((EnemyHealthSnapshot)(ref val3)).IsSpawnHealthSettling) { counts.HiddenSpawnSettling++; AddSampleDiagnostic(sampleDiagnostics, val2, sample, val3, "hiddenSpawnSettling"); presenter.Hide(((EnemyHealthSample)(ref sample)).EnemyId); continue; } if (((EnemyHealthSnapshot)(ref val3)).CurrentHealth <= 0 || ((EnemyHealthSnapshot)(ref val3)).MaxHealth <= 0) { counts.HiddenZeroHealth++; AddSampleDiagnostic(sampleDiagnostics, val2, sample, val3, "hiddenZeroHealth"); presenter.Hide(((EnemyHealthSample)(ref sample)).EnemyId); continue; } if (!config.ShowFullHealthEnemies && ((EnemyHealthSnapshot)(ref val3)).IsFullHealth) { counts.HiddenFull++; AddSampleDiagnostic(sampleDiagnostics, val2, sample, val3, "hiddenFullHealth"); presenter.Hide(((EnemyHealthSample)(ref sample)).EnemyId); continue; } Vector3 worldPosition = presenter.GetWorldPosition(val2); Vector3 val4 = position - worldPosition; float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude; if (!((HealthBarVisibilityRules)(ref val)).ShouldShowBySquaredDistance(val3, sqrMagnitude)) { counts.HiddenDistance++; AddSampleDiagnostic(sampleDiagnostics, val2, sample, val3, "hiddenDistance"); presenter.Hide(((EnemyHealthSample)(ref sample)).EnemyId); } else { counts.Shown++; AddSampleDiagnostic(sampleDiagnostics, val2, sample, val3, "shown"); presenter.ShowOrUpdate(val2, val3, worldPosition, camera, billboardRotation); } } ISet set3 = retainedEnemyStateIds.Update((ISet)activeEnemyIds); ISet set4 = retainedNetworkStateIds.Update((ISet)activeNetworkObjectIds); tracker.KeepOnly(set3); EnemyHealthOverrideStore.KeepOnly(set3, set4); networkSync.KeepOnlyClientSnapshots(set4); networkSync.KeepOnlyHostSnapshots(set4); networkSync.FlushHostSnapshots(); presenter.HideMissing(activeEnemyIds); counts.Active = presenter.ActiveCount; counts.RetainedEnemyStates = set3.Count - activeEnemyIds.Count; counts.RetainedNetworkStates = set4.Count - activeNetworkObjectIds.Count; LogDiagnosticsIfDue(counts, camera, "scan", sampleDiagnostics); } private void LogDiagnosticsIfDue(DiagnosticScanCounts counts, Camera? camera, string source, List? sampleDiagnostics = null) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (config != null && logger != null && config.DiagnosticsEnabled && !(Time.unscaledTime < nextDiagnosticLogTime)) { nextDiagnosticLogTime = Time.unscaledTime + config.DiagnosticsLogInterval; string text = (((Object)(object)camera != (Object)null) ? $"{((Object)camera).name}@{FormatVector(((Component)camera).transform.position)} mask={camera.cullingMask}" : "none"); string text2 = maxHealthResolver.FormatUnresolvedNamesForDiagnostics(5); string text3 = ((sampleDiagnostics != null && sampleDiagnostics.Count > 0) ? (", samples=[" + string.Join("; ", sampleDiagnostics) + "]") : string.Empty); logger.LogInfo((object)($"Diagnostics {source}: camera={text}, spawned={counts.Spawned}, readable={counts.Readable}, shown={counts.Shown}, active={counts.Active}, " + $"rejectedNull={counts.RejectedMissingEnemy}, rejectedNoType={counts.RejectedMissingEnemyType}, rejectedCannotDie={counts.RejectedCannotDie}, " + $"hostSync={networkSync.HasHostSync}, usedHostSync={counts.UsedHostSync}, hiddenWaitingHostSync={counts.HiddenWaitingForHostSync}, " + $"hiddenDead={counts.HiddenDead}, hiddenSettling={counts.HiddenSettling}, hiddenSpawnSettling={counts.HiddenSpawnSettling}, hiddenZeroHp={counts.HiddenZeroHealth}, hiddenFull={counts.HiddenFull}, hiddenDistance={counts.HiddenDistance}, " + $"retainedEnemyStates={counts.RetainedEnemyStates}, retainedNetworkStates={counts.RetainedNetworkStates}, unresolvedMaxHealth={maxHealthResolver.UnresolvedCount}, unresolvedNames={text2}{text3}")); } } private void ApplyHostSyncedHealth(EnemyAI enemy, EnemyHealthSample sample, EnemyHealthSnapshot snapshot) { //IL_003e: 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) if (!((EnemyHealthSnapshot)(ref snapshot)).IsDead && ((EnemyHealthSnapshot)(ref snapshot)).CurrentHealth > 0 && !enemy.isEnemyDead) { if (enemy.enemyHP != ((EnemyHealthSnapshot)(ref snapshot)).CurrentHealth) { enemy.enemyHP = ((EnemyHealthSnapshot)(ref snapshot)).CurrentHealth; } networkSync.ConfirmHostSnapshotApplied(sample, snapshot); } } private void UpdateDebugTestBar(Camera camera, Quaternion billboardRotation) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (config != null && presenter != null) { if (config.DebugShowTestBar) { presenter.ShowDebugTestBar(camera, billboardRotation); } else { presenter.HideDebugTestBar(); } } } private void LogDebugHeartbeatIfDue(Camera? camera) { if (config != null && logger != null && presenter != null && config.DiagnosticsEnabled && !(Time.unscaledTime < nextDebugHeartbeatLogTime)) { nextDebugHeartbeatLogTime = Time.unscaledTime + config.DiagnosticsLogInterval; string text = (((Object)(object)camera != (Object)null) ? ((Object)camera).name : "none"); logger.LogInfo((object)$"Debug heartbeat: enabled={config.Enabled}, camera='{text}', active={presenter.ActiveCount}, testBar={presenter.DebugTestBarVisible}"); } } private static void AddReadFailure(ref DiagnosticScanCounts counts, EnemyHealthReadFailure failure) { switch (failure) { case EnemyHealthReadFailure.MissingEnemy: counts.RejectedMissingEnemy++; break; case EnemyHealthReadFailure.MissingEnemyType: counts.RejectedMissingEnemyType++; break; case EnemyHealthReadFailure.CannotDie: counts.RejectedCannotDie++; break; } } private bool ShouldCollectSampleDiagnostics() { if (config != null && config.DiagnosticsLogEnemyHealthSamples) { return Time.unscaledTime >= nextDiagnosticLogTime; } return false; } private static void AddMissingEnemyDiagnostic(List? sampleDiagnostics, int index) { if (CanAddSampleDiagnostic(sampleDiagnostics)) { sampleDiagnostics.Add($"readFailure:index={index}, reason=MissingEnemy"); } } private static void AddReadFailureDiagnostic(List? sampleDiagnostics, EnemyAI enemy, EnemyHealthReadFailure failure) { if (CanAddSampleDiagnostic(sampleDiagnostics)) { string text = (((Object)(object)enemy.enemyType != (Object)null && !string.IsNullOrWhiteSpace(enemy.enemyType.enemyName)) ? enemy.enemyType.enemyName : ((Object)enemy).name); string arg = (((Object)(object)enemy.enemyType != (Object)null) ? enemy.enemyType.canDie.ToString() : "unknown"); string text2 = (((Object)(object)((NetworkBehaviour)enemy).NetworkObject != (Object)null) ? ((NetworkBehaviour)enemy).NetworkObject.NetworkObjectId.ToString() : "none"); sampleDiagnostics.Add($"readFailure:name='{text}', id={((Object)enemy).GetInstanceID()}, netId={text2}, hp={enemy.enemyHP}, " + $"dead={enemy.isEnemyDead}, canDie={arg}, reason={failure}"); } } private static void AddSampleDiagnostic(List? sampleDiagnostics, EnemyAI enemy, EnemyHealthSample sample, EnemyHealthSnapshot snapshot, string result) { if (CanAddSampleDiagnostic(sampleDiagnostics)) { string text = (((Object)(object)enemy.enemyType != (Object)null) ? enemy.enemyType.canDie.ToString() : "unknown"); string text2 = ((((EnemyHealthSample)(ref sample)).NetworkObjectId != 0L) ? ((EnemyHealthSample)(ref sample)).NetworkObjectId.ToString() : "none"); sampleDiagnostics.Add($"sample:name='{((EnemyHealthSample)(ref sample)).DisplayName}', id={((EnemyHealthSample)(ref sample)).EnemyId}, netId={text2}, current={((EnemyHealthSample)(ref sample)).CurrentHealth}, " + $"resolvedMax={((EnemyHealthSample)(ref sample)).MaxHealth}, trackedMax={((EnemyHealthSnapshot)(ref snapshot)).MaxHealth}, fraction={((EnemyHealthSnapshot)(ref snapshot)).HealthFraction:0.###}, " + $"full={((EnemyHealthSnapshot)(ref snapshot)).IsFullHealth}, settling={((EnemyHealthSnapshot)(ref snapshot)).IsMaxHealthSettling}, spawnSettling={((EnemyHealthSnapshot)(ref snapshot)).IsSpawnHealthSettling}, " + $"clientDesync={((EnemyHealthSnapshot)(ref snapshot)).IsClientHealthDesynced}, dead={((EnemyHealthSnapshot)(ref snapshot)).IsDead}, canDie={text}, result={result}"); } } private static bool CanAddSampleDiagnostic(List? sampleDiagnostics) { if (sampleDiagnostics != null) { return sampleDiagnostics.Count < 8; } return false; } private static string FormatVector(Vector3 value) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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) return $"({value.x:0.0},{value.y:0.0},{value.z:0.0})"; } } internal sealed class HealthBarRuntime : IDisposable { private static GameObject? runtimeObject; private static EnemyHealthBarController? runtimeController; private readonly GameObject host; private HealthBarRuntime(GameObject host) { this.host = host; } public static HealthBarRuntime Start(ModConfig config, ManualLogSource logger) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)runtimeObject == (Object)null) { runtimeObject = new GameObject("EnemyHealthBars.Runtime"); ((Object)runtimeObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)runtimeObject); } else if (!runtimeObject.activeSelf) { runtimeObject.SetActive(true); } GameObject val = runtimeObject; runtimeController = val.GetComponent(); if ((Object)(object)runtimeController == (Object)null) { EnemyHealthBarPresenter presenter = new EnemyHealthBarPresenter(config, val.transform); runtimeController = val.AddComponent(); runtimeController.Initialize(config, logger, new RoundManagerEnemySource(), new LocalPlayerCameraProvider(), presenter); logger.LogInfo((object)"Runtime controller active."); } else { runtimeController.SetEnabled(enabled: true); logger.LogInfo((object)"Runtime controller active."); } return new HealthBarRuntime(val); } public void Dispose() { if ((Object)(object)host != (Object)null) { Object.Destroy((Object)(object)host); } } } } namespace Auuueser.EnemyHealthBars.Presentation { internal sealed class EnemyHealthBarPresenter { private sealed class ActiveHealthBar { private Transform? cachedTransform; private Vector3 cachedLocalPosition; private Vector3 cachedWorldPosition; private HealthBarDisplayMode cachedDisplayMode = (HealthBarDisplayMode)(-1); private float cachedVerticalOffset; private float nextTargetRefreshTime; private bool hasCachedPosition; public EnemyAI Enemy { get; set; } public EnemyHealthSnapshot Snapshot { get; set; } public HealthBarView View { get; } public ActiveHealthBar(EnemyAI enemy, HealthBarView view) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Enemy = enemy; View = view; } public void RefreshPosition(Vector3 worldPosition, float verticalOffset, HealthBarDisplayMode displayMode, float currentTime) { //IL_0014: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) Transform val = (cachedTransform = ResolveFollowTransform(Enemy)); cachedWorldPosition = worldPosition; cachedLocalPosition = (((Object)(object)val != (Object)null) ? val.InverseTransformPoint(worldPosition) : worldPosition); cachedVerticalOffset = verticalOffset; cachedDisplayMode = displayMode; nextTargetRefreshTime = currentTime + 0.1f; hasCachedPosition = true; } public Vector3 GetWorldPosition(HealthBarTargetResolver targetResolver, float verticalOffset, HealthBarDisplayMode displayMode, float currentTime) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_0077: 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_0082: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_0068: Unknown result type (might be due to invalid IL or missing references) if (!hasCachedPosition || cachedDisplayMode != displayMode || cachedVerticalOffset != verticalOffset || currentTime >= nextTargetRefreshTime) { Vector3 worldPosition = targetResolver.GetWorldPosition(Enemy, verticalOffset, displayMode); RefreshPosition(worldPosition, verticalOffset, displayMode, currentTime); return worldPosition; } if ((Object)(object)cachedTransform == (Object)null) { Vector3 worldPosition2 = targetResolver.GetWorldPosition(Enemy, verticalOffset, displayMode); RefreshPosition(worldPosition2, verticalOffset, displayMode, currentTime); return worldPosition2; } cachedWorldPosition = cachedTransform.TransformPoint(cachedLocalPosition); return cachedWorldPosition; } private static Transform? ResolveFollowTransform(EnemyAI enemy) { if ((Object)(object)enemy == (Object)null) { return null; } if (enemy is MaskedPlayerEnemy) { Transform radarHeadTransform = enemy.GetRadarHeadTransform(); if ((Object)(object)radarHeadTransform != (Object)null) { return radarHeadTransform; } } return ((Component)enemy).transform; } } private const float TargetPositionRefreshInterval = 0.1f; private const int PrewarmedViewCount = 4; private readonly ModConfig config; private readonly HealthBarPool pool; private readonly HealthBarTargetResolver targetResolver = new HealthBarTargetResolver(); private readonly Dictionary activeBars = new Dictionary(); private readonly List removeBuffer = new List(); private HealthBarView? debugTestBar; public int ActiveCount => activeBars.Count; public bool DebugTestBarVisible => debugTestBar != null; public EnemyHealthBarPresenter(ModConfig config, Transform parent) { this.config = config; pool = new HealthBarPool(config, parent); pool.Prewarm(4); } public void ShowOrUpdate(EnemyAI enemy, EnemyHealthSnapshot snapshot, Vector3 worldPosition, Camera camera, Quaternion billboardRotation) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (!activeBars.TryGetValue(((EnemyHealthSnapshot)(ref snapshot)).EnemyId, out ActiveHealthBar value)) { value = new ActiveHealthBar(enemy, pool.Get()); activeBars.Add(((EnemyHealthSnapshot)(ref snapshot)).EnemyId, value); } value.Enemy = enemy; value.Snapshot = snapshot; value.RefreshPosition(worldPosition, config.VerticalOffset, config.DisplayMode, Time.unscaledTime); value.View.SetHealth(snapshot); value.View.SetWorldPosition(worldPosition, camera, billboardRotation); value.View.SetVisible(visible: true); } public void Hide(int enemyId) { if (activeBars.TryGetValue(enemyId, out ActiveHealthBar value)) { activeBars.Remove(enemyId); pool.Release(value.View); } } public void HideMissing(ISet activeEnemyIds) { removeBuffer.Clear(); foreach (KeyValuePair activeBar in activeBars) { if (!activeEnemyIds.Contains(activeBar.Key)) { removeBuffer.Add(activeBar.Key); } } foreach (int item in removeBuffer) { Hide(item); } } public void RefreshStyle() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) HealthBarStyle style = HealthBarStyle.FromConfig(config); pool.RefreshStyle(style); debugTestBar?.ApplyStyle(style); foreach (KeyValuePair activeBar in activeBars) { activeBar.Value.View.ApplyStyle(style); activeBar.Value.View.SetHealth(activeBar.Value.Snapshot); } } public void ShowDebugTestBar(Camera camera, Quaternion billboardRotation) { //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_0045: 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_005a: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (debugTestBar == null) { debugTestBar = pool.Get(); debugTestBar.SetVisible(visible: true); } Vector3 worldPosition = ((Component)camera).transform.position + ((Component)camera).transform.forward * 2.25f - ((Component)camera).transform.up * 0.35f; debugTestBar.SetVisible(visible: true); debugTestBar.SetHealth(new EnemyHealthSnapshot(-1, "Test enemy", 13, 20, false, false, false, false)); debugTestBar.SetWorldPosition(worldPosition, camera, billboardRotation); } public void HideDebugTestBar() { if (debugTestBar != null) { pool.Release(debugTestBar); debugTestBar = null; } } public void UpdateActive(Camera camera, Quaternion billboardRotation) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) removeBuffer.Clear(); foreach (KeyValuePair activeBar in activeBars) { ActiveHealthBar value = activeBar.Value; if ((Object)(object)value.Enemy == (Object)null) { removeBuffer.Add(activeBar.Key); continue; } Vector3 worldPosition = value.GetWorldPosition(targetResolver, config.VerticalOffset, config.DisplayMode, Time.unscaledTime); value.View.SetWorldPosition(worldPosition, camera, billboardRotation); } foreach (int item in removeBuffer) { Hide(item); } } public void Clear() { HideDebugTestBar(); removeBuffer.Clear(); foreach (int key in activeBars.Keys) { removeBuffer.Add(key); } foreach (int item in removeBuffer) { Hide(item); } } public Vector3 GetWorldPosition(EnemyAI enemy) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) return targetResolver.GetWorldPosition(enemy, config.VerticalOffset, config.DisplayMode); } } internal sealed class HealthBarBillboard : MonoBehaviour { public void SetCamera(Camera? camera) { } public void ApplyRotation(Quaternion rotation) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((Component)this).transform.rotation = rotation; } public static Quaternion CalculateRotation(Camera camera) { //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) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_002d: 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_0021: 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_0034: 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) Transform transform = ((Component)camera).transform; Vector3 forward = transform.forward; Vector3 up = transform.up; if (forward == Vector3.zero || up == Vector3.zero) { return Quaternion.identity; } return Quaternion.LookRotation(forward, up); } } internal sealed class HealthBarPool { private readonly ModConfig config; private readonly Transform parent; private readonly Stack pooledViews = new Stack(); private HealthBarStyle currentStyle; public HealthBarPool(ModConfig config, Transform parent) { this.config = config; this.parent = parent; currentStyle = HealthBarStyle.FromConfig(config); } public HealthBarView Get() { if (pooledViews.Count > 0) { HealthBarView healthBarView = pooledViews.Pop(); healthBarView.ApplyStyle(currentStyle); return healthBarView; } return HealthBarView.Create(parent, currentStyle); } public void Prewarm(int count) { for (int i = pooledViews.Count; i < count; i++) { pooledViews.Push(HealthBarView.Create(parent, currentStyle)); } } public void Release(HealthBarView view) { view.SetVisible(visible: false); pooledViews.Push(view); } public void RefreshStyle(HealthBarStyle style) { currentStyle = style; foreach (HealthBarView pooledView in pooledViews) { pooledView.ApplyStyle(style); } } } internal sealed class HealthBarStyle { private const float PixelUnitScale = 140f; private const float WorldScaleMultiplier = 0.012f; public float Width { get; } public float Height { get; } public float WorldScale { get; } public HealthBarDisplayMode DisplayMode { get; } public bool ShowHealthNumbers { get; } public HealthTextFormat HealthTextFormat { get; } public bool ShowEnemyName { get; } public float SideBarWidth { get; } public float SideBarHeight { get; } public float SideBarHorizontalOffset { get; } public Color BackgroundColor { get; } = new Color(0.02f, 0.02f, 0.02f, 0.78f); public Color FillColor { get; } = new Color(0.78f, 0.08f, 0.07f, 0.92f); public Color BorderColor { get; } = new Color(0f, 0f, 0f, 0.95f); public Color TextColor { get; } = new Color(0.96f, 0.96f, 0.96f, 1f); private HealthBarStyle(float width, float height, float worldScale, HealthBarDisplayMode displayMode, bool showHealthNumbers, HealthTextFormat healthTextFormat, bool showEnemyName, float sideBarWidth, float sideBarHeight, float sideBarHorizontalOffset) { //IL_0015: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_0058: 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_0077: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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) Width = width; Height = height; WorldScale = worldScale; DisplayMode = displayMode; ShowHealthNumbers = showHealthNumbers; HealthTextFormat = healthTextFormat; ShowEnemyName = showEnemyName; SideBarWidth = sideBarWidth; SideBarHeight = sideBarHeight; SideBarHorizontalOffset = sideBarHorizontalOffset; } public static HealthBarStyle FromConfig(ModConfig config) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) return new HealthBarStyle(config.BarWidth * 140f, config.BarHeight * 140f, config.WorldScale * 0.012f, config.DisplayMode, config.ShowHealthNumbers, config.HealthTextFormat, config.ShowEnemyName, config.SideBarWidth * 140f, config.SideBarHeight * 140f, config.SideBarHorizontalOffset * 140f); } } internal sealed class HealthBarTargetResolver { public Vector3 GetWorldPosition(EnemyAI enemy, float verticalOffset, HealthBarDisplayMode displayMode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_00d7: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if ((int)displayMode == 1) { return GetVerticalSideWorldPosition(enemy, verticalOffset); } if (TryGetMaskedStableAnchor(enemy, out var anchor)) { return anchor + Vector3.up * verticalOffset; } if (TryGetRendererBounds(enemy, out var bounds)) { float num = (((Object)(object)enemy.eye != (Object)null) ? Mathf.Max(enemy.eye.position.y, ((Bounds)(ref bounds)).max.y) : ((Bounds)(ref bounds)).max.y); return new Vector3(((Bounds)(ref bounds)).center.x, num + verticalOffset, ((Bounds)(ref bounds)).center.z); } if ((Object)(object)enemy.eye != (Object)null) { return enemy.eye.position + Vector3.up * verticalOffset; } return ((Component)enemy).transform.position + Vector3.up * (1.5f + verticalOffset); } private static Vector3 GetVerticalSideWorldPosition(EnemyAI enemy, float verticalOffset) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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) float num = verticalOffset * 0.25f; if (TryGetMaskedStableAnchor(enemy, out var anchor)) { return anchor + Vector3.up * (num - 0.35f); } if (TryGetRendererBounds(enemy, out var bounds)) { return new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.y + num, ((Bounds)(ref bounds)).center.z); } if ((Object)(object)enemy.eye != (Object)null) { return enemy.eye.position + Vector3.up * (num - 0.35f); } return ((Component)enemy).transform.position + Vector3.up * (1f + num); } private static bool TryGetMaskedStableAnchor(EnemyAI enemy, out Vector3 anchor) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) anchor = default(Vector3); if (!(enemy is MaskedPlayerEnemy)) { return false; } Transform radarHeadTransform = enemy.GetRadarHeadTransform(); if ((Object)(object)radarHeadTransform == (Object)null) { return false; } anchor = radarHeadTransform.position; return true; } private static bool TryGetRendererBounds(EnemyAI enemy, out Bounds bounds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) bounds = default(Bounds); bool flag = false; if (enemy.skinnedMeshRenderers != null) { SkinnedMeshRenderer[] skinnedMeshRenderers = enemy.skinnedMeshRenderers; for (int i = 0; i < skinnedMeshRenderers.Length; i++) { flag = EncapsulateRendererBounds((Renderer?)(object)skinnedMeshRenderers[i], ref bounds, flag); } } if (enemy.meshRenderers != null) { MeshRenderer[] meshRenderers = enemy.meshRenderers; for (int i = 0; i < meshRenderers.Length; i++) { flag = EncapsulateRendererBounds((Renderer?)(object)meshRenderers[i], ref bounds, flag); } } return flag; } private static bool EncapsulateRendererBounds(Renderer? renderer, ref Bounds bounds, bool hasBounds) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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) if ((Object)(object)renderer == (Object)null) { return hasBounds; } if (!hasBounds) { bounds = renderer.bounds; return true; } ((Bounds)(ref bounds)).Encapsulate(renderer.bounds); return true; } } internal sealed class HealthBarView { private const float FillPadding = 1f; private const float SideTextPadding = 6f; private const float TextFontSize = 18f; private static TMP_FontAsset? resolvedTextFont; private static bool textFontResolved; private readonly GameObject gameObject; private readonly RectTransform root; private readonly Image backgroundImage; private readonly Image fillImage; private readonly Outline border; private readonly RectTransform backgroundRect; private readonly RectTransform fillRect; private readonly TextMeshProUGUI healthText; private readonly RectTransform textRect; private readonly Canvas worldCanvas; private readonly HealthBarBillboard billboard; private Camera? lastAppliedCanvasCamera; private HealthBarStyle currentStyle; private int lastTextCurrentHealth = int.MinValue; private int lastTextMaxHealth = int.MinValue; private HealthTextFormat lastTextFormat = (HealthTextFormat)(-1); private HealthBarDisplayMode lastDisplayMode = (HealthBarDisplayMode)(-1); private HealthBarDisplayMode lastFillDisplayMode = (HealthBarDisplayMode)(-1); private float lastFillFraction = -1f; private bool lastShowEnemyName; private string? lastDisplayName; private HealthBarView(GameObject gameObject, RectTransform root, Image backgroundImage, Image fillImage, Outline border, RectTransform backgroundRect, RectTransform fillRect, TextMeshProUGUI healthText, RectTransform textRect, Canvas worldCanvas, HealthBarBillboard billboard, HealthBarStyle style) { //IL_0018: 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_0026: Unknown result type (might be due to invalid IL or missing references) this.gameObject = gameObject; this.root = root; this.backgroundImage = backgroundImage; this.fillImage = fillImage; this.border = border; this.backgroundRect = backgroundRect; this.fillRect = fillRect; this.healthText = healthText; this.textRect = textRect; this.worldCanvas = worldCanvas; this.billboard = billboard; currentStyle = style; } public static HealthBarView Create(Transform parent, HealthBarStyle style) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00d2: Expected O, but got Unknown GameObject val = new GameObject("EnemyHealthBar"); val.transform.SetParent(parent, false); HealthBarBillboard healthBarBillboard = val.AddComponent(); RectTransform parent2 = val.AddComponent(); Canvas val2 = val.AddComponent(); val2.renderMode = (RenderMode)2; val2.overrideSorting = true; val2.sortingOrder = 500; val.AddComponent(); Image val3 = CreateImage("Background", (Transform)(object)parent2, style.BackgroundColor); RectTransform component = ((Component)val3).GetComponent(); Outline val4 = ((Component)val3).gameObject.AddComponent(); Image val5 = CreateImage("Fill", ((Component)val3).transform, style.FillColor); RectTransform component2 = ((Component)val5).GetComponent(); TextMeshProUGUI val6 = CreateHealthText((Transform)(object)parent2, style.TextColor); RectTransform component3 = ((Component)val6).GetComponent(); SetLayerRecursively(val, ((Component)parent).gameObject.layer); HealthBarView healthBarView = new HealthBarView(val, parent2, val3, val5, val4, component, component2, val6, component3, val2, healthBarBillboard, style); healthBarView.ApplyStyle(style); healthBarView.SetVisible(visible: false); return healthBarView; } public void ApplyStyle(HealthBarStyle style) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00af: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Invalid comparison between Unknown and I4 currentStyle = style; ((Transform)root).localScale = Vector3.one * style.WorldScale; ((Graphic)backgroundImage).color = style.BackgroundColor; ((Shadow)border).effectColor = style.BorderColor; ((Shadow)border).effectDistance = new Vector2(1f, -1f); ((Graphic)fillImage).color = style.FillColor; ((Graphic)healthText).color = style.TextColor; ((TMP_Text)healthText).fontSize = 18f; ((Component)healthText).gameObject.SetActive(ShouldShowText(style)); HealthBarDisplayMode displayMode = style.DisplayMode; if ((int)displayMode != 1) { if ((int)displayMode == 2) { ApplyNumbersOnlyLayout(style); } else { ApplyHorizontalLayout(style); } } else { ApplyVerticalSideLayout(style); } ResetTextCache(); } public void SetFill(float fraction) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_002a: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Invalid comparison between Unknown and I4 //IL_006a: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: 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_00d9: Unknown result type (might be due to invalid IL or missing references) if (fraction < 0f) { fraction = 0f; } else if (fraction > 1f) { fraction = 1f; } if (lastFillFraction == fraction && lastFillDisplayMode == currentStyle.DisplayMode) { return; } if ((int)currentStyle.DisplayMode == 2) { SetActiveIfChanged(((Component)backgroundImage).gameObject, active: false); lastFillFraction = fraction; lastFillDisplayMode = currentStyle.DisplayMode; return; } SetActiveIfChanged(((Component)backgroundImage).gameObject, active: true); if ((int)currentStyle.DisplayMode == 1) { fillRect.SetSizeWithCurrentAnchors((Axis)1, Mathf.Lerp(0f, Mathf.Max(0f, currentStyle.SideBarHeight - 2f), fraction)); lastFillFraction = fraction; lastFillDisplayMode = currentStyle.DisplayMode; } else { fillRect.SetSizeWithCurrentAnchors((Axis)0, Mathf.Lerp(0f, Mathf.Max(0f, currentStyle.Width - 2f), fraction)); lastFillFraction = fraction; lastFillDisplayMode = currentStyle.DisplayMode; } } public void SetHealth(EnemyHealthSnapshot snapshot) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) SetFill(((EnemyHealthSnapshot)(ref snapshot)).HealthFraction); if (!ShouldShowText(currentStyle)) { if (((TMP_Text)healthText).text.Length > 0) { ((TMP_Text)healthText).text = string.Empty; } return; } string text = ((EnemyHealthSnapshot)(ref snapshot)).DisplayName ?? string.Empty; if (lastTextCurrentHealth != ((EnemyHealthSnapshot)(ref snapshot)).CurrentHealth || lastTextMaxHealth != ((EnemyHealthSnapshot)(ref snapshot)).MaxHealth || lastTextFormat != currentStyle.HealthTextFormat || lastDisplayMode != currentStyle.DisplayMode || lastShowEnemyName != currentStyle.ShowEnemyName || !(lastDisplayName == text)) { string text2 = HealthTextFormatter.Format(((EnemyHealthSnapshot)(ref snapshot)).CurrentHealth, ((EnemyHealthSnapshot)(ref snapshot)).MaxHealth, currentStyle.HealthTextFormat); if (currentStyle.ShowEnemyName && text.Length > 0) { text2 = text + " " + text2; } ((TMP_Text)healthText).text = text2; lastTextCurrentHealth = ((EnemyHealthSnapshot)(ref snapshot)).CurrentHealth; lastTextMaxHealth = ((EnemyHealthSnapshot)(ref snapshot)).MaxHealth; lastTextFormat = currentStyle.HealthTextFormat; lastDisplayMode = currentStyle.DisplayMode; lastShowEnemyName = currentStyle.ShowEnemyName; lastDisplayName = text; } } public void SetWorldPosition(Vector3 worldPosition, Camera camera, Quaternion billboardRotation) { //IL_0006: 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) ((Transform)root).position = worldPosition; ApplyCanvasCamera(camera); billboard.ApplyRotation(billboardRotation); } public void SetVisible(bool visible) { SetActiveIfChanged(gameObject, visible); } private void ApplyHorizontalLayout(HealthBarStyle style) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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) root.sizeDelta = new Vector2(style.Width, style.Height); SetActiveIfChanged(((Component)backgroundImage).gameObject, active: true); SetRect(backgroundRect, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(style.Width, style.Height)); SetRect(fillRect, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(1f, 0f), new Vector2(0f, Mathf.Max(0f, style.Height - 2f))); fillRect.pivot = new Vector2(0f, 0.5f); fillRect.SetSizeWithCurrentAnchors((Axis)0, 0f); SetFullTextRect(); } private void ApplyVerticalSideLayout(HealthBarStyle style) { //IL_005f: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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) float verticalSideTextWidth = GetVerticalSideTextWidth(style); float num = Mathf.Abs(style.SideBarHorizontalOffset) + style.SideBarWidth * 0.5f + 6f + verticalSideTextWidth; float num2 = Mathf.Max(style.Width, num * 2f); float num3 = Mathf.Max(style.SideBarHeight, Mathf.Max(style.Height, 24f)); root.sizeDelta = new Vector2(num2, num3); SetActiveIfChanged(((Component)backgroundImage).gameObject, active: true); SetRect(backgroundRect, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(style.SideBarHorizontalOffset, 0f), new Vector2(style.SideBarWidth, style.SideBarHeight)); SetRect(fillRect, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 1f), new Vector2(Mathf.Max(0f, style.SideBarWidth - 2f), 0f)); fillRect.pivot = new Vector2(0.5f, 0f); fillRect.SetSizeWithCurrentAnchors((Axis)1, 0f); SetVerticalSideTextRect(style); } private void ApplyNumbersOnlyLayout(HealthBarStyle style) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) root.sizeDelta = new Vector2(style.Width, Mathf.Max(style.Height, 24f)); SetActiveIfChanged(((Component)backgroundImage).gameObject, active: false); SetFullTextRect(); } private static Image CreateImage(string name, Transform parent, Color color) { //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_0013: 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_0027: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent, false); val.AddComponent(); val.AddComponent(); Image obj = val.AddComponent(); ((Graphic)obj).color = color; ((Graphic)obj).raycastTarget = false; return obj; } private static TextMeshProUGUI CreateHealthText(Transform parent, Color color) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0086: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HealthText"); val.transform.SetParent(parent, false); val.AddComponent(); val.AddComponent(); TextMeshProUGUI val2 = val.AddComponent(); ((TMP_Text)val2).text = string.Empty; ((Graphic)val2).raycastTarget = false; ((TMP_Text)val2).alignment = (TextAlignmentOptions)514; ((TMP_Text)val2).enableWordWrapping = false; ((TMP_Text)val2).enableAutoSizing = true; ((TMP_Text)val2).fontSizeMin = 10f; ((TMP_Text)val2).fontSizeMax = 18f; ((TMP_Text)val2).overflowMode = (TextOverflowModes)1; ((TMP_Text)val2).fontStyle = (FontStyles)1; ((TMP_Text)val2).fontSize = 18f; ((Graphic)val2).color = color; TMP_FontAsset val3 = ResolveTextFont(); if ((Object)(object)val3 != (Object)null) { ((TMP_Text)val2).font = val3; } return val2; } private static TMP_FontAsset? ResolveTextFont() { if (textFontResolved) { return resolvedTextFont; } textFontResolved = true; resolvedTextFont = TMP_Settings.defaultFontAsset; if ((Object)(object)resolvedTextFont != (Object)null) { return resolvedTextFont; } Font builtinResource = Resources.GetBuiltinResource("Arial.ttf"); if ((Object)(object)builtinResource != (Object)null) { resolvedTextFont = TMP_FontAsset.CreateFontAsset(builtinResource); } return resolvedTextFont; } private void SetFullTextRect() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0040: 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) textRect.anchorMin = Vector2.zero; textRect.anchorMax = Vector2.one; textRect.pivot = new Vector2(0.5f, 0.5f); textRect.offsetMin = Vector2.zero; textRect.offsetMax = Vector2.zero; ((TMP_Text)healthText).alignment = (TextAlignmentOptions)514; } private void SetVerticalSideTextRect(HealthBarStyle style) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0089: Unknown result type (might be due to invalid IL or missing references) float num = ((style.SideBarHorizontalOffset >= 0f) ? 1f : (-1f)); float verticalSideTextWidth = GetVerticalSideTextWidth(style); float num2 = Mathf.Max(style.SideBarHeight, 24f); float num3 = style.SideBarHorizontalOffset + num * style.SideBarWidth * 0.5f + num * (6f + verticalSideTextWidth * 0.5f); SetRect(textRect, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(num3, 0f), new Vector2(verticalSideTextWidth, num2)); ((TMP_Text)healthText).alignment = (TextAlignmentOptions)((num > 0f) ? 513 : 516); } private static float GetVerticalSideTextWidth(HealthBarStyle style) { return Mathf.Max(style.Width, 72f); } private static void SetRect(RectTransform rect, Vector2 anchorMin, Vector2 anchorMax, Vector2 anchoredPosition, Vector2 sizeDelta) { //IL_0001: 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = anchorMin; rect.anchorMax = anchorMax; rect.pivot = new Vector2(0.5f, 0.5f); rect.anchoredPosition = anchoredPosition; rect.sizeDelta = sizeDelta; } private static bool ShouldShowText(HealthBarStyle style) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 if (!style.ShowHealthNumbers) { return (int)style.DisplayMode == 2; } return true; } private void ResetTextCache() { //IL_0018: 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_0026: Unknown result type (might be due to invalid IL or missing references) lastTextCurrentHealth = int.MinValue; lastTextMaxHealth = int.MinValue; lastTextFormat = (HealthTextFormat)(-1); lastDisplayMode = (HealthBarDisplayMode)(-1); lastFillDisplayMode = (HealthBarDisplayMode)(-1); lastFillFraction = -1f; lastShowEnemyName = false; lastDisplayName = null; } private void ApplyCanvasCamera(Camera camera) { billboard.SetCamera(camera); if (!((Object)(object)lastAppliedCanvasCamera == (Object)(object)camera) || !((Object)(object)worldCanvas.worldCamera == (Object)(object)camera)) { worldCanvas.worldCamera = camera; lastAppliedCanvasCamera = camera; } } private static void SetLayerRecursively(GameObject target, int layer) { target.layer = layer; Transform transform = target.transform; for (int i = 0; i < transform.childCount; i++) { SetLayerRecursively(((Component)transform.GetChild(i)).gameObject, layer); } } private static void SetActiveIfChanged(GameObject target, bool active) { if (target.activeSelf != active) { target.SetActive(active); } } } } namespace Auuueser.EnemyHealthBars.Networking { internal sealed class EnemyHealthSyncNetwork { private const byte ProtocolVersion = 2; private const byte DeadFlag = 1; private const byte MaxHealthSettlingFlag = 2; private const byte SpawnHealthSettlingFlag = 4; private const int MaxPayloadBytes = 1200; private const int MaxSnapshotsPerMessage = 64; private const float ClientHelloInterval = 1f; private const float ClientFallbackDelay = 3f; private const string HelloMessage = "auuueser.enemyhealthbar.hello.v1"; private const string HealthMessage = "auuueser.enemyhealthbar.health.v1"; private readonly EnemyHealthSyncStore clientSnapshots = new EnemyHealthSyncStore(); private readonly Dictionary lastSentSnapshots = new Dictionary(); private readonly Dictionary lastSentEnemyIds = new Dictionary(); private readonly HashSet syncClientIds = new HashSet(); private readonly List sendTargetClientIds = new List(); private readonly List removedClientIds = new List(); private readonly List pendingSnapshots = new List(); private FastBufferWriter writer; private NetworkManager? registeredNetworkManager; private bool handlersRegistered; private bool hostSyncActive; private bool forceFullRefresh; private bool runtimeStateCleared = true; private uint sequence; private float nextHelloTime; private float clientSyncStartTime = -1f; public bool HasHostSync => hostSyncActive; public void Tick(bool enabled, float currentTime) { NetworkManager singleton = NetworkManager.Singleton; if (!enabled || !IsNetworkUsable(singleton)) { ResetRuntimeStateIfNeeded(); return; } runtimeStateCleared = false; EnsureHandlers(singleton); SendClientHelloIfNeeded(singleton, currentTime); } public bool TryGetHostSnapshot(EnemyHealthSample sample, out EnemyHealthSnapshot snapshot) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0038: Unknown result type (might be due to invalid IL or missing references) snapshot = default(EnemyHealthSnapshot); EnemyHealthSyncSnapshot val = default(EnemyHealthSyncSnapshot); if (((EnemyHealthSample)(ref sample)).NetworkObjectId == 0L || !clientSnapshots.TryGetProjected(sample, ref val)) { return false; } snapshot = ((EnemyHealthSyncSnapshot)(ref val)).ToEnemyHealthSnapshot(((EnemyHealthSample)(ref sample)).EnemyId, ((EnemyHealthSample)(ref sample)).DisplayName); return true; } public void ConfirmHostSnapshotApplied(EnemyHealthSample sample, EnemyHealthSnapshot snapshot) { if (((EnemyHealthSample)(ref sample)).NetworkObjectId != 0L && !((EnemyHealthSnapshot)(ref snapshot)).IsDead && ((EnemyHealthSnapshot)(ref snapshot)).CurrentHealth > 0) { clientSnapshots.ConfirmProjectedHealthApplied(((EnemyHealthSample)(ref sample)).NetworkObjectId, ((EnemyHealthSnapshot)(ref snapshot)).CurrentHealth); } } public bool ShouldSuppressLocalSnapshot(EnemyHealthSample sample, float currentTime) { if (((EnemyHealthSample)(ref sample)).NetworkObjectId == 0L) { return false; } if (!IsClientOnly(NetworkManager.Singleton)) { return false; } if (hostSyncActive) { return true; } if (clientSyncStartTime >= 0f) { return currentTime - clientSyncStartTime < 3f; } return false; } public void KeepOnlyClientSnapshots(ISet activeNetworkObjectIds) { clientSnapshots.KeepOnly(activeNetworkObjectIds); } public void KeepOnlyHostSnapshots(ISet activeNetworkObjectIds) { removedClientIds.Clear(); foreach (ulong key in lastSentSnapshots.Keys) { if (!activeNetworkObjectIds.Contains(key)) { removedClientIds.Add(key); } } foreach (ulong removedClientId in removedClientIds) { lastSentSnapshots.Remove(removedClientId); lastSentEnemyIds.Remove(removedClientId); } } public void QueueHostSnapshot(EnemyHealthSample sample, EnemyHealthSnapshot snapshot) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) if (IsHostPublisherReady(NetworkManager.Singleton) && ((EnemyHealthSample)(ref sample)).NetworkObjectId != 0L && syncClientIds.Count != 0) { EnemyHealthSyncSnapshot item = default(EnemyHealthSyncSnapshot); ((EnemyHealthSyncSnapshot)(ref item))..ctor(((EnemyHealthSample)(ref sample)).NetworkObjectId, ((EnemyHealthSnapshot)(ref snapshot)).CurrentHealth, ((EnemyHealthSnapshot)(ref snapshot)).MaxHealth, ((EnemyHealthSnapshot)(ref snapshot)).IsDead, 0u, ((EnemyHealthSnapshot)(ref snapshot)).IsMaxHealthSettling, ((EnemyHealthSnapshot)(ref snapshot)).IsSpawnHealthSettling, ((EnemyHealthSample)(ref sample)).EnemyId); if (forceFullRefresh || !lastSentSnapshots.TryGetValue(((EnemyHealthSample)(ref sample)).NetworkObjectId, out var value) || !lastSentEnemyIds.TryGetValue(((EnemyHealthSample)(ref sample)).NetworkObjectId, out var value2) || value2 != ((EnemyHealthSample)(ref sample)).EnemyId || ((EnemyHealthSyncSnapshot)(ref value)).CurrentHealth != ((EnemyHealthSyncSnapshot)(ref item)).CurrentHealth || ((EnemyHealthSyncSnapshot)(ref value)).MaxHealth != ((EnemyHealthSyncSnapshot)(ref item)).MaxHealth || ((EnemyHealthSyncSnapshot)(ref value)).IsDead != ((EnemyHealthSyncSnapshot)(ref item)).IsDead || ((EnemyHealthSyncSnapshot)(ref value)).IsMaxHealthSettling != ((EnemyHealthSyncSnapshot)(ref item)).IsMaxHealthSettling || ((EnemyHealthSyncSnapshot)(ref value)).IsSpawnHealthSettling != ((EnemyHealthSyncSnapshot)(ref item)).IsSpawnHealthSettling) { pendingSnapshots.Add(item); } } } public void FlushHostSnapshots() { NetworkManager singleton = NetworkManager.Singleton; if (!IsHostPublisherReady(singleton) || pendingSnapshots.Count == 0) { pendingSnapshots.Clear(); return; } BuildSendTargets(singleton); if (sendTargetClientIds.Count == 0) { pendingSnapshots.Clear(); return; } for (int num = 0; num < pendingSnapshots.Count; num = SendSnapshotChunk(singleton, num)) { } pendingSnapshots.Clear(); forceFullRefresh = false; } public void Dispose() { UnregisterHandlers(); if (((FastBufferWriter)(ref writer)).IsInitialized) { ((FastBufferWriter)(ref writer)).Dispose(); } } private void ResetRuntimeState() { UnregisterHandlers(); clientSnapshots.Clear(); syncClientIds.Clear(); sendTargetClientIds.Clear(); removedClientIds.Clear(); pendingSnapshots.Clear(); lastSentSnapshots.Clear(); lastSentEnemyIds.Clear(); hostSyncActive = false; forceFullRefresh = false; clientSyncStartTime = -1f; runtimeStateCleared = true; } private void ResetRuntimeStateIfNeeded() { if (!runtimeStateCleared) { ResetRuntimeState(); } } private void EnsureHandlers(NetworkManager networkManager) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown if (!handlersRegistered || !((Object)(object)registeredNetworkManager == (Object)(object)networkManager)) { UnregisterHandlers(); networkManager.CustomMessagingManager.RegisterNamedMessageHandler("auuueser.enemyhealthbar.hello.v1", new HandleNamedMessageDelegate(HandleHelloMessage)); networkManager.CustomMessagingManager.RegisterNamedMessageHandler("auuueser.enemyhealthbar.health.v1", new HandleNamedMessageDelegate(HandleHealthMessage)); registeredNetworkManager = networkManager; handlersRegistered = true; } } private void UnregisterHandlers() { if (!handlersRegistered || (Object)(object)registeredNetworkManager == (Object)null || registeredNetworkManager.CustomMessagingManager == null) { handlersRegistered = false; registeredNetworkManager = null; return; } registeredNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("auuueser.enemyhealthbar.hello.v1"); registeredNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("auuueser.enemyhealthbar.health.v1"); handlersRegistered = false; registeredNetworkManager = null; } private void SendClientHelloIfNeeded(NetworkManager networkManager, float currentTime) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) if (!IsClientOnly(networkManager)) { clientSyncStartTime = -1f; return; } if (clientSyncStartTime < 0f) { clientSyncStartTime = currentTime; } if (!hostSyncActive && !(currentTime < nextHelloTime)) { nextHelloTime = currentTime + 1f; EnsureWriter(); ((FastBufferWriter)(ref writer)).Seek(0); ((FastBufferWriter)(ref writer)).Truncate(0); ((FastBufferWriter)(ref writer)).WriteByteSafe((byte)2); networkManager.CustomMessagingManager.SendNamedMessage("auuueser.enemyhealthbar.hello.v1", 0uL, writer, (NetworkDelivery)3); } } private void HandleHelloMessage(ulong senderClientId, FastBufferReader payload) { NetworkManager singleton = NetworkManager.Singleton; if (IsHostPublisherReady(singleton) && senderClientId != singleton.LocalClientId) { byte b = default(byte); ((FastBufferReader)(ref payload)).ReadByteSafe(ref b); if (b == 2 && syncClientIds.Add(senderClientId)) { forceFullRefresh = true; } } } private void HandleHealthMessage(ulong senderClientId, FastBufferReader payload) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if (!IsClientOnly(NetworkManager.Singleton) || senderClientId != 0L) { return; } byte b = default(byte); ((FastBufferReader)(ref payload)).ReadByteSafe(ref b); if (b == 2) { uint num = default(uint); ((FastBufferReader)(ref payload)).ReadValueSafe(ref num, default(ForPrimitives)); ushort num2 = default(ushort); ((FastBufferReader)(ref payload)).ReadValueSafe(ref num2, default(ForPrimitives)); hostSyncActive = true; ulong num3 = default(ulong); int num4 = default(int); int num5 = default(int); byte b2 = default(byte); for (int i = 0; i < num2; i++) { ((FastBufferReader)(ref payload)).ReadValueSafe(ref num3, default(ForPrimitives)); ((FastBufferReader)(ref payload)).ReadValueSafe(ref num4, default(ForPrimitives)); ((FastBufferReader)(ref payload)).ReadValueSafe(ref num5, default(ForPrimitives)); ((FastBufferReader)(ref payload)).ReadByteSafe(ref b2); clientSnapshots.ApplyHostSnapshot(new EnemyHealthSyncSnapshot(num3, num4, num5, (b2 & 1) != 0, num, (b2 & 2) != 0, (b2 & 4) != 0, 0)); } } } private int SendSnapshotChunk(NetworkManager networkManager, int startIndex) { //IL_006b: 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) //IL_0084: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) EnsureWriter(); ((FastBufferWriter)(ref writer)).Seek(0); ((FastBufferWriter)(ref writer)).Truncate(0); sequence++; if (sequence == 0) { sequence = 1u; } int num = pendingSnapshots.Count - startIndex; if (num > 64) { num = 64; } ((FastBufferWriter)(ref writer)).WriteByteSafe((byte)2); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref sequence, default(ForPrimitives)); ref FastBufferWriter reference = ref writer; ushort num2 = (ushort)num; ((FastBufferWriter)(ref reference)).WriteValueSafe(ref num2, default(ForPrimitives)); int num3 = startIndex + num; for (int i = startIndex; i < num3; i++) { EnemyHealthSyncSnapshot val = pendingSnapshots[i]; ((EnemyHealthSyncSnapshot)(ref val)).set_Sequence(sequence); EnemyHealthSyncSnapshot val2 = val; byte b = ComposeFlags(val2); ref FastBufferWriter reference2 = ref writer; ulong networkObjectId = ((EnemyHealthSyncSnapshot)(ref val2)).NetworkObjectId; ((FastBufferWriter)(ref reference2)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ref FastBufferWriter reference3 = ref writer; int currentHealth = ((EnemyHealthSyncSnapshot)(ref val2)).CurrentHealth; ((FastBufferWriter)(ref reference3)).WriteValueSafe(ref currentHealth, default(ForPrimitives)); ref FastBufferWriter reference4 = ref writer; currentHealth = ((EnemyHealthSyncSnapshot)(ref val2)).MaxHealth; ((FastBufferWriter)(ref reference4)).WriteValueSafe(ref currentHealth, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteByteSafe(b); lastSentSnapshots[((EnemyHealthSyncSnapshot)(ref val2)).NetworkObjectId] = val2; lastSentEnemyIds[((EnemyHealthSyncSnapshot)(ref val2)).NetworkObjectId] = ((EnemyHealthSyncSnapshot)(ref val2)).EnemyId; } networkManager.CustomMessagingManager.SendNamedMessage("auuueser.enemyhealthbar.health.v1", (IReadOnlyList)sendTargetClientIds, writer, (NetworkDelivery)3); return num3; } private static byte ComposeFlags(EnemyHealthSyncSnapshot snapshot) { byte b = (((EnemyHealthSyncSnapshot)(ref snapshot)).IsDead ? ((byte)1) : ((byte)0)); if (((EnemyHealthSyncSnapshot)(ref snapshot)).IsMaxHealthSettling) { b |= 2; } if (((EnemyHealthSyncSnapshot)(ref snapshot)).IsSpawnHealthSettling) { b |= 4; } return b; } private void BuildSendTargets(NetworkManager networkManager) { sendTargetClientIds.Clear(); removedClientIds.Clear(); foreach (ulong syncClientId in syncClientIds) { if (syncClientId == networkManager.LocalClientId || !IsConnectedClient(networkManager, syncClientId)) { removedClientIds.Add(syncClientId); } else { sendTargetClientIds.Add(syncClientId); } } foreach (ulong removedClientId in removedClientIds) { syncClientIds.Remove(removedClientId); } } private void EnsureWriter() { //IL_0019: 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) if (!((FastBufferWriter)(ref writer)).IsInitialized) { writer = new FastBufferWriter(1200, (Allocator)4, 1200); } } private static bool IsConnectedClient(NetworkManager networkManager, ulong clientId) { foreach (ulong connectedClientsId in networkManager.ConnectedClientsIds) { if (connectedClientsId == clientId) { return true; } } return false; } private static bool IsHostPublisherReady(NetworkManager? networkManager) { if (IsNetworkUsable(networkManager)) { return networkManager.IsServer; } return false; } private static bool IsClientOnly(NetworkManager? networkManager) { if (IsNetworkUsable(networkManager) && networkManager.IsClient) { return !networkManager.IsServer; } return false; } private static bool IsNetworkUsable(NetworkManager? networkManager) { if ((Object)(object)networkManager != (Object)null && networkManager.IsListening) { return networkManager.CustomMessagingManager != null; } return false; } } } namespace Auuueser.EnemyHealthBars.Game { internal enum EnemyHealthReadFailure { None, MissingEnemy, MissingEnemyType, CannotDie } internal sealed class EnemyHealthReader { public bool TryRead(EnemyAI? enemy, bool includeInvulnerableEnemies, EnemyMaxHealthResolver maxHealthResolver, out EnemyHealthSample sample, out EnemyHealthReadFailure failure) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) sample = default(EnemyHealthSample); failure = EnemyHealthReadFailure.None; if ((Object)(object)enemy == (Object)null) { failure = EnemyHealthReadFailure.MissingEnemy; return false; } if ((Object)(object)enemy.enemyType == (Object)null) { failure = EnemyHealthReadFailure.MissingEnemyType; return false; } if (!includeInvulnerableEnemies && !enemy.enemyType.canDie) { failure = EnemyHealthReadFailure.CannotDie; return false; } int instanceID = ((Object)enemy).GetInstanceID(); string text = ResolveDisplayName(enemy); int num = maxHealthResolver.Resolve(enemy, text); ulong num2 = (((Object)(object)((NetworkBehaviour)enemy).NetworkObject != (Object)null) ? ((NetworkBehaviour)enemy).NetworkObject.NetworkObjectId : 0); bool flag = false; int num3 = default(int); if (EnemyHealthOverrideStore.TryGetMaxHealth(instanceID, num2, ref num3)) { num = num3; flag = true; } sample = new EnemyHealthSample(instanceID, text, enemy.enemyHP, num, enemy.isEnemyDead, num2, flag); return true; } private static string ResolveDisplayName(EnemyAI enemy) { EnemyType enemyType = enemy.enemyType; if ((Object)(object)enemyType != (Object)null && !string.IsNullOrWhiteSpace(enemyType.enemyName)) { return enemyType.enemyName; } if (!string.IsNullOrWhiteSpace(((Object)enemy).name)) { return ((Object)enemy).name; } return "Enemy"; } } internal sealed class EnemyMaxHealthResolver { private readonly EnemyMaxHealthLookup maxHealthLookup = new EnemyMaxHealthLookup(EnemyHealthDefaults.Items); public int UnresolvedCount => maxHealthLookup.UnresolvedCount; public int Resolve(EnemyAI enemy, string displayName) { string cacheKey = ResolveCacheKey(enemy, displayName); int baseMaxHealth = ResolveBaseMaxHealth(enemy, cacheKey); return ResolveSpecialMaxHealth(enemy, baseMaxHealth); } public string FormatUnresolvedNamesForDiagnostics(int maxNames) { return maxHealthLookup.FormatUnresolvedNamesForDiagnostics(maxNames); } private int ResolveBaseMaxHealth(EnemyAI enemy, string cacheKey) { int result = default(int); if (maxHealthLookup.TryGetStrictMaxHealth(cacheKey, ref result)) { return result; } if (maxHealthLookup.IsUnresolved(cacheKey)) { return 0; } return maxHealthLookup.StoreResolvedStrictMaxHealth(cacheKey, ResolveFromPrefab(enemy)); } private static int ResolveSpecialMaxHealth(EnemyAI enemy, int baseMaxHealth) { if (enemy is ButlerEnemyAI) { int num = ((!((Object)(object)StartOfRound.Instance != (Object)null)) ? 1 : StartOfRound.Instance.connectedPlayersAmount); return EnemySpecialMaxHealthRules.ResolveButlerMaxHealth(baseMaxHealth, num); } if (enemy is CaveDwellerAI) { return EnemySpecialMaxHealthRules.ResolveManeaterMaxHealth(baseMaxHealth, enemy.currentBehaviourStateIndex); } return baseMaxHealth; } private static string ResolveCacheKey(EnemyAI enemy, string displayName) { EnemyType enemyType = enemy.enemyType; if ((Object)(object)enemyType != (Object)null && !string.IsNullOrWhiteSpace(enemyType.enemyName)) { return enemyType.enemyName; } if (!string.IsNullOrWhiteSpace(displayName)) { return displayName; } if (!string.IsNullOrWhiteSpace(((Object)enemy).name)) { return ((Object)enemy).name; } return string.Empty; } private static int ResolveFromPrefab(EnemyAI enemy) { EnemyType enemyType = enemy.enemyType; if ((Object)(object)enemyType == (Object)null || (Object)(object)enemyType.enemyPrefab == (Object)null) { return 0; } EnemyAI val = default(EnemyAI); if (!enemyType.enemyPrefab.TryGetComponent(ref val)) { return 0; } if (val.enemyHP <= 0) { return 0; } return val.enemyHP; } } internal sealed class LocalPlayerCameraProvider { public Camera? GetActiveCamera() { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null) { if ((Object)(object)instance.localPlayerController != (Object)null && IsUsable(instance.localPlayerController.gameplayCamera)) { return instance.localPlayerController.gameplayCamera; } if (IsUsable(instance.activeCamera)) { return instance.activeCamera; } if (IsUsable(instance.spectateCamera)) { return instance.spectateCamera; } } HUDManager instance2 = HUDManager.Instance; if ((Object)(object)instance2 != (Object)null && (Object)(object)instance2.localPlayer != (Object)null && IsUsable(instance2.localPlayer.gameplayCamera)) { return instance2.localPlayer.gameplayCamera; } if (!((Object)(object)Camera.main != (Object)null)) { return Camera.current; } return Camera.main; } private static bool IsUsable(Camera? camera) { if ((Object)(object)camera != (Object)null) { return ((Behaviour)camera).isActiveAndEnabled; } return false; } } internal sealed class RoundManagerEnemySource { public List? GetSpawnedEnemies() { RoundManager instance = RoundManager.Instance; if (!((Object)(object)instance != (Object)null)) { return null; } return instance.SpawnedEnemies; } } } namespace Auuueser.EnemyHealthBars.Configuration { internal static class ChineseProjectLanguageDetector { public static ConfigLanguage Detect(ConfigFile config, ManualLogSource logger) { if (!DetectLoadedPlugin(logger) && !DetectExistingConfig(config, logger) && !DetectManifestNearConfig(config, logger)) { return (ConfigLanguage)0; } return (ConfigLanguage)1; } private static bool DetectLoadedPlugin(ManualLogSource logger) { foreach (KeyValuePair pluginInfo in Chainloader.PluginInfos) { PluginInfo value = pluginInfo.Value; if (value != null && value.Metadata != null && ChineseProjectDetection.IsChineseProjectPlugin(value.Metadata.GUID, value.Metadata.Name, value.Location)) { logger.LogInfo((object)("LC Chinese Project detected from plugin '" + value.Metadata.GUID + "'. Using Chinese config text.")); return true; } } return false; } private static bool DetectExistingConfig(ConfigFile config, ManualLogSource logger) { if (!File.Exists(config.ConfigFilePath)) { return false; } try { if (!ChineseProjectDetection.ContainsChineseConfigSections(File.ReadAllText(config.ConfigFilePath))) { return false; } logger.LogInfo((object)"Existing Chinese config sections detected. Using Chinese config text."); return true; } catch (Exception ex) { logger.LogWarning((object)("Could not inspect existing config language: " + ex.Message)); return false; } } private static bool DetectManifestNearConfig(ConfigFile config, ManualLogSource logger) { string directoryName = Path.GetDirectoryName(config.ConfigFilePath); if (string.IsNullOrEmpty(directoryName)) { return false; } DirectoryInfo parent = Directory.GetParent(directoryName); if (parent == null) { return false; } string path = Path.Combine(parent.FullName, "plugins"); if (!Directory.Exists(path)) { return false; } try { string[] files = Directory.GetFiles(path, "manifest.json", SearchOption.AllDirectories); for (int i = 0; i < files.Length; i++) { if (ChineseProjectDetection.ContainsChineseProjectManifestText(File.ReadAllText(files[i]))) { logger.LogInfo((object)("LC Chinese Project manifest detected at '" + files[i] + "'. Using Chinese config text.")); return true; } } } catch (Exception ex) { logger.LogWarning((object)("Could not inspect plugin manifests for config language: " + ex.Message)); } return false; } } internal static class LethalConfigIntegration { private const string PluginGuid = "ainavt.lc.lethalconfig"; public static bool IsAvailable() { return Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"); } public static void Register(ModConfig config, ManualLogSource logger) { try { ConfigTexts texts = config.Texts; LethalConfigManager.SetModDescription(texts.ModDescription); AddBool(config.EnabledEntry, texts.EnabledName, texts.GeneralSection, texts.EnabledDescription); AddBool(config.ShowInvulnerableEnemiesEntry, texts.ShowInvulnerableEnemiesName, texts.VisibilitySection, texts.ShowInvulnerableEnemiesDescription); AddEnum(config.MaxHealthModeEntry, texts.MaxHealthModeName, texts.VisibilitySection, texts.MaxHealthModeDescription); AddFloat(config.MaxDistanceEntry, texts.MaxDistanceName, texts.VisibilitySection, texts.MaxDistanceDescription); AddFloat(config.ScanIntervalEntry, texts.ScanIntervalName, texts.PerformanceSection, texts.ScanIntervalDescription); AddBool(config.HostAuthoritySyncEntry, texts.HostAuthoritySyncName, texts.PerformanceSection, texts.HostAuthoritySyncDescription); AddFloat(config.VerticalOffsetEntry, texts.VerticalOffsetName, texts.LayoutSection, texts.VerticalOffsetDescription); AddFloat(config.BarWidthEntry, texts.BarWidthName, texts.LayoutSection, texts.BarWidthDescription); AddFloat(config.BarHeightEntry, texts.BarHeightName, texts.LayoutSection, texts.BarHeightDescription); AddFloat(config.WorldScaleEntry, texts.WorldScaleName, texts.LayoutSection, texts.WorldScaleDescription); AddEnum(config.DisplayModeEntry, texts.DisplayModeName, texts.LayoutSection, texts.DisplayModeDescription); AddBool(config.ShowHealthNumbersEntry, texts.ShowHealthNumbersName, texts.LayoutSection, texts.ShowHealthNumbersDescription); AddEnum(config.HealthTextFormatEntry, texts.HealthTextFormatName, texts.LayoutSection, texts.HealthTextFormatDescription); AddBool(config.ShowEnemyNameEntry, texts.ShowEnemyNameName, texts.LayoutSection, texts.ShowEnemyNameDescription); AddFloat(config.SideBarWidthEntry, texts.SideBarWidthName, texts.LayoutSection, texts.SideBarWidthDescription); AddFloat(config.SideBarHeightEntry, texts.SideBarHeightName, texts.LayoutSection, texts.SideBarHeightDescription); AddFloat(config.SideBarHorizontalOffsetEntry, texts.SideBarHorizontalOffsetName, texts.LayoutSection, texts.SideBarHorizontalOffsetDescription); AddBool(config.DebugEnabledEntry, texts.DebugEnabledName, texts.DebugSection, texts.DebugEnabledDescription); AddBool(config.DebugShowFullHealthEnemiesEntry, texts.DebugShowFullHealthEnemiesName, texts.DebugSection, texts.DebugShowFullHealthEnemiesDescription); AddBool(config.DebugDiagnosticsEnabledEntry, texts.DebugDiagnosticsEnabledName, texts.DebugSection, texts.DebugDiagnosticsEnabledDescription); AddFloat(config.DebugDiagnosticsLogIntervalEntry, texts.DebugDiagnosticsLogIntervalName, texts.DebugSection, texts.DebugDiagnosticsLogIntervalDescription); AddBool(config.DebugLogEnemyHealthSamplesEntry, texts.DebugLogEnemyHealthSamplesName, texts.DebugSection, texts.DebugLogEnemyHealthSamplesDescription); AddBool(config.DebugShowTestBarEntry, texts.DebugShowTestBarName, texts.DebugSection, texts.DebugShowTestBarDescription); logger.LogInfo((object)"Registered localized LethalConfig entries."); } catch (Exception ex) { logger.LogWarning((object)("Could not register LethalConfig entries: " + ex.Message)); } } private static void AddBool(ConfigEntry entry, string name, string section, string description) { //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) //IL_0013: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown LethalConfigManager.SkipAutoGenFor((ConfigEntryBase)(object)entry); LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(entry, new BoolCheckBoxOptions { Name = name, Section = section, Description = description, RequiresRestart = false })); } private static void AddFloat(ConfigEntry entry, string name, string section, string description) { //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) //IL_0013: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown LethalConfigManager.SkipAutoGenFor((ConfigEntryBase)(object)entry); LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatInputFieldConfigItem(entry, new FloatInputFieldOptions { Name = name, Section = section, Description = description, RequiresRestart = false })); } private static void AddEnum(ConfigEntry entry, string name, string section, string description) where T : Enum { //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) //IL_0013: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown LethalConfigManager.SkipAutoGenFor((ConfigEntryBase)(object)entry); LethalConfigManager.AddConfigItem((BaseConfigItem)(object)new EnumDropDownConfigItem(entry, new EnumDropDownOptions { Name = name, Section = section, Description = description, RequiresRestart = false })); } } internal sealed class ModConfig { private const float ConfigFilePollInterval = 0.5f; private readonly ConfigFile configFile; private readonly string configFilePath; private readonly ConfigEntry enabled; private readonly ConfigEntry showInvulnerableEnemies; private readonly ConfigEntry maxHealthMode; private readonly ConfigEntry maxDistance; private readonly ConfigEntry scanInterval; private readonly ConfigEntry hostAuthoritySync; private readonly ConfigEntry verticalOffset; private readonly ConfigEntry barWidth; private readonly ConfigEntry barHeight; private readonly ConfigEntry worldScale; private readonly ConfigEntry displayMode; private readonly ConfigEntry showHealthNumbers; private readonly ConfigEntry healthTextFormat; private readonly ConfigEntry showEnemyName; private readonly ConfigEntry sideBarWidth; private readonly ConfigEntry sideBarHeight; private readonly ConfigEntry sideBarHorizontalOffset; private readonly ConfigEntry debugEnabled; private readonly ConfigEntry debugShowFullHealthEnemies; private readonly ConfigEntry debugDiagnosticsEnabled; private readonly ConfigEntry debugDiagnosticsLogInterval; private readonly ConfigEntry debugLogEnemyHealthSamples; private readonly ConfigEntry debugShowTestBar; private DateTime lastConfigWriteTimeUtc; private float nextConfigFilePollTime; public ConfigLanguage Language { get; } public ConfigTexts Texts { get; } public int SettingsVersion { get; private set; } public bool Enabled => enabled.Value; public bool ShowInvulnerableEnemies => showInvulnerableEnemies.Value; public MaxHealthMode MaxHealthMode => maxHealthMode.Value; public bool HostAuthoritySync => hostAuthoritySync.Value; public bool DebugEnabled => debugEnabled.Value; public bool DiagnosticsEnabled { get { if (DebugEnabled) { return debugDiagnosticsEnabled.Value; } return false; } } public bool ShowFullHealthEnemies { get { if (DebugEnabled) { return debugShowFullHealthEnemies.Value; } return false; } } public bool DebugShowTestBar { get { if (DebugEnabled) { return debugShowTestBar.Value; } return false; } } public float DiagnosticsLogInterval { get { if (!(debugDiagnosticsLogInterval.Value < 1f)) { return debugDiagnosticsLogInterval.Value; } return 1f; } } public bool DiagnosticsLogEnemyHealthSamples { get { if (DiagnosticsEnabled) { return debugLogEnemyHealthSamples.Value; } return false; } } public float ScanInterval { get { if (!(scanInterval.Value < 0.02f)) { return scanInterval.Value; } return 0.02f; } } public float VerticalOffset => verticalOffset.Value; public float BarWidth { get { if (!(barWidth.Value < 0.1f)) { return barWidth.Value; } return 0.1f; } } public float BarHeight { get { if (!(barHeight.Value < 0.03f)) { return barHeight.Value; } return 0.03f; } } public float WorldScale { get { if (!(worldScale.Value < 0.01f)) { return worldScale.Value; } return 0.01f; } } public HealthBarDisplayMode DisplayMode => displayMode.Value; public bool ShowHealthNumbers => showHealthNumbers.Value; public HealthTextFormat HealthTextFormat => healthTextFormat.Value; public bool ShowEnemyName => showEnemyName.Value; public float SideBarWidth { get { if (!(sideBarWidth.Value < 0.03f)) { return sideBarWidth.Value; } return 0.03f; } } public float SideBarHeight { get { if (!(sideBarHeight.Value < 0.1f)) { return sideBarHeight.Value; } return 0.1f; } } public float SideBarHorizontalOffset => sideBarHorizontalOffset.Value; internal ConfigEntry EnabledEntry => enabled; internal ConfigEntry ShowInvulnerableEnemiesEntry => showInvulnerableEnemies; internal ConfigEntry MaxHealthModeEntry => maxHealthMode; internal ConfigEntry MaxDistanceEntry => maxDistance; internal ConfigEntry ScanIntervalEntry => scanInterval; internal ConfigEntry HostAuthoritySyncEntry => hostAuthoritySync; internal ConfigEntry VerticalOffsetEntry => verticalOffset; internal ConfigEntry BarWidthEntry => barWidth; internal ConfigEntry BarHeightEntry => barHeight; internal ConfigEntry WorldScaleEntry => worldScale; internal ConfigEntry DisplayModeEntry => displayMode; internal ConfigEntry ShowHealthNumbersEntry => showHealthNumbers; internal ConfigEntry HealthTextFormatEntry => healthTextFormat; internal ConfigEntry ShowEnemyNameEntry => showEnemyName; internal ConfigEntry SideBarWidthEntry => sideBarWidth; internal ConfigEntry SideBarHeightEntry => sideBarHeight; internal ConfigEntry SideBarHorizontalOffsetEntry => sideBarHorizontalOffset; internal ConfigEntry DebugEnabledEntry => debugEnabled; internal ConfigEntry DebugShowFullHealthEnemiesEntry => debugShowFullHealthEnemies; internal ConfigEntry DebugDiagnosticsEnabledEntry => debugDiagnosticsEnabled; internal ConfigEntry DebugDiagnosticsLogIntervalEntry => debugDiagnosticsLogInterval; internal ConfigEntry DebugLogEnemyHealthSamplesEntry => debugLogEnemyHealthSamples; internal ConfigEntry DebugShowTestBarEntry => debugShowTestBar; private ModConfig(ConfigFile config, ConfigLanguage language) { //IL_001a: 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_0021: Unknown result type (might be due to invalid IL or missing references) configFile = config; configFilePath = config.ConfigFilePath; Language = language; Texts = ConfigTextCatalog.Get(language); enabled = config.Bind(Texts.GeneralSection, "Enabled", true, Texts.EnabledDescription); showInvulnerableEnemies = config.Bind(Texts.VisibilitySection, "ShowInvulnerableEnemies", false, Texts.ShowInvulnerableEnemiesDescription); maxHealthMode = config.Bind(Texts.VisibilitySection, "MaxHealthMode", (MaxHealthMode)2, Texts.MaxHealthModeDescription); maxDistance = config.Bind(Texts.VisibilitySection, "MaxDistance", 35f, Texts.MaxDistanceDescription); scanInterval = config.Bind(Texts.PerformanceSection, "ScanInterval", 0.2f, Texts.ScanIntervalDescription); hostAuthoritySync = config.Bind(Texts.PerformanceSection, "HostAuthoritySync", true, Texts.HostAuthoritySyncDescription); verticalOffset = config.Bind(Texts.LayoutSection, "VerticalOffset", 0.45f, Texts.VerticalOffsetDescription); barWidth = config.Bind(Texts.LayoutSection, "BarWidth", 1.25f, Texts.BarWidthDescription); barHeight = config.Bind(Texts.LayoutSection, "BarHeight", 0.14f, Texts.BarHeightDescription); worldScale = config.Bind(Texts.LayoutSection, "WorldScale", 0.7f, Texts.WorldScaleDescription); displayMode = config.Bind(Texts.LayoutSection, "DisplayMode", (HealthBarDisplayMode)0, Texts.DisplayModeDescription); showHealthNumbers = config.Bind(Texts.LayoutSection, "ShowHealthNumbers", true, Texts.ShowHealthNumbersDescription); healthTextFormat = config.Bind(Texts.LayoutSection, "HealthTextFormat", (HealthTextFormat)0, Texts.HealthTextFormatDescription); showEnemyName = config.Bind(Texts.LayoutSection, "ShowEnemyName", false, Texts.ShowEnemyNameDescription); sideBarWidth = config.Bind(Texts.LayoutSection, "SideBarWidth", 0.14f, Texts.SideBarWidthDescription); sideBarHeight = config.Bind(Texts.LayoutSection, "SideBarHeight", 0.55f, Texts.SideBarHeightDescription); sideBarHorizontalOffset = config.Bind(Texts.LayoutSection, "SideBarHorizontalOffset", 0.55f, Texts.SideBarHorizontalOffsetDescription); debugEnabled = config.Bind(Texts.DebugSection, "Enabled", false, Texts.DebugEnabledDescription); debugShowFullHealthEnemies = config.Bind(Texts.DebugSection, "ShowFullHealthEnemies", false, Texts.DebugShowFullHealthEnemiesDescription); debugDiagnosticsEnabled = config.Bind(Texts.DebugSection, "DiagnosticsEnabled", false, Texts.DebugDiagnosticsEnabledDescription); debugDiagnosticsLogInterval = config.Bind(Texts.DebugSection, "DiagnosticsLogInterval", 3f, Texts.DebugDiagnosticsLogIntervalDescription); debugLogEnemyHealthSamples = config.Bind(Texts.DebugSection, "LogEnemyHealthSamples", false, Texts.DebugLogEnemyHealthSamplesDescription); debugShowTestBar = config.Bind(Texts.DebugSection, "ShowTestBar", false, Texts.DebugShowTestBarDescription); config.SettingChanged += OnConfigChanged; config.ConfigReloaded += OnConfigReloaded; config.Save(); RefreshLastWriteTime(); } public static ModConfig Bind(ConfigFile config, ConfigLanguage language) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new ModConfig(config, language); } public HealthBarVisibilityRules CreateVisibilityRules() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) return new HealthBarVisibilityRules(ShowFullHealthEnemies, maxDistance.Value); } public void ReloadIfChangedOnDisk(float currentTime) { if (!(currentTime < nextConfigFilePollTime) && File.Exists(configFilePath)) { nextConfigFilePollTime = currentTime + 0.5f; if (!(File.GetLastWriteTimeUtc(configFilePath) <= lastConfigWriteTimeUtc)) { configFile.Reload(); RefreshLastWriteTime(); } } } private void OnConfigChanged(object sender, SettingChangedEventArgs args) { SettingsVersion++; RefreshLastWriteTime(); } private void OnConfigReloaded(object sender, EventArgs args) { SettingsVersion++; RefreshLastWriteTime(); } private void RefreshLastWriteTime() { if (File.Exists(configFilePath)) { lastConfigWriteTimeUtc = File.GetLastWriteTimeUtc(configFilePath); } } } }