Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of GlowNames v1.1.0
GlowNames.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("GlowNames")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0+33956dea114c4d68693291e47a8b8666dfba1d34")] [assembly: AssemblyProduct("GlowNames")] [assembly: AssemblyTitle("GlowNames")] [assembly: AssemblyVersion("1.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace GlowNames { internal sealed class GameReflection { private static readonly string[] DeadFieldNames = new string[8] { "deadSet", "isDead", "dead", "isDeath", "death", "isKilled", "isDowned", "downed" }; private readonly GlowNamesPlugin _plugin; private readonly Dictionary<object, object> _nameplatePlayerCache = new Dictionary<object, object>(); private readonly Dictionary<string, FieldInfo> _deadFieldCache = new Dictionary<string, FieldInfo>(); private Type _gameDirectorType; private Type _playerAvatarType; private Type _nameplateType; private Type _deathHeadType; private FieldInfo _gameDirectorInstanceField; private PropertyInfo _gameDirectorInstanceProperty; private FieldInfo _playerListField; private PropertyInfo _playerListProperty; private FieldInfo _playerIsLocalField; private FieldInfo _playerIsDisabledField; private FieldInfo _playerNameplateField; private FieldInfo _playerVisualsField; private FieldInfo _playerDeathHeadField; private FieldInfo _nameplatePlayerField; private FieldInfo _nameplateTextField; private FieldInfo _nameplateShowTimerField; private FieldInfo _nameplateWorldPositionField; private FieldInfo _deathHeadTriggeredField; private FieldInfo _deathHeadPhysGrabObjectField; private FieldInfo _physGrabObjectCenterPointField; private MethodInfo _nameplateShowMethod; internal Type PlayerAvatarType => _playerAvatarType; internal Type NameplateType => _nameplateType; internal GameReflection(GlowNamesPlugin plugin) { _plugin = plugin; } internal void CacheMembers() { _gameDirectorType = AccessTools.TypeByName("GameDirector"); _playerAvatarType = AccessTools.TypeByName("PlayerAvatar"); _nameplateType = AccessTools.TypeByName("WorldSpaceUIPlayerName"); _deathHeadType = AccessTools.TypeByName("PlayerDeathHead"); Type type = AccessTools.TypeByName("PhysGrabObject"); if (_gameDirectorType != null) { _gameDirectorInstanceField = AccessTools.Field(_gameDirectorType, "instance"); _gameDirectorInstanceProperty = AccessTools.Property(_gameDirectorType, "instance"); _playerListField = AccessTools.Field(_gameDirectorType, "PlayerList"); _playerListProperty = AccessTools.Property(_gameDirectorType, "PlayerList"); } if (_playerAvatarType != null) { _playerIsLocalField = AccessTools.Field(_playerAvatarType, "isLocal"); _playerIsDisabledField = AccessTools.Field(_playerAvatarType, "isDisabled"); _playerNameplateField = AccessTools.Field(_playerAvatarType, "worldSpaceUIPlayerName"); _playerVisualsField = AccessTools.Field(_playerAvatarType, "playerAvatarVisuals"); _playerDeathHeadField = AccessTools.Field(_playerAvatarType, "playerDeathHead"); } if (_nameplateType != null) { _nameplatePlayerField = AccessTools.Field(_nameplateType, "playerAvatar"); _nameplateTextField = AccessTools.Field(_nameplateType, "text"); _nameplateShowTimerField = AccessTools.Field(_nameplateType, "showTimer"); _nameplateWorldPositionField = AccessTools.Field(_nameplateType, "worldPosition") ?? AccessTools.Field(_nameplateType.BaseType, "worldPosition"); _nameplateShowMethod = AccessTools.Method(_nameplateType, "Show", (Type[])null, (Type[])null); } if (_deathHeadType != null) { _deathHeadTriggeredField = AccessTools.Field(_deathHeadType, "triggered"); _deathHeadPhysGrabObjectField = AccessTools.Field(_deathHeadType, "physGrabObject"); } if (type != null) { _physGrabObjectCenterPointField = AccessTools.Field(type, "centerPoint"); } WarnMissing(_gameDirectorType, "GameDirector type"); WarnMissing(_playerAvatarType, "PlayerAvatar type"); WarnMissing(_nameplateType, "WorldSpaceUIPlayerName type"); WarnMissing(_playerIsLocalField, "PlayerAvatar.isLocal"); WarnMissing(_playerIsDisabledField, "PlayerAvatar.isDisabled"); WarnMissing(_playerNameplateField, "PlayerAvatar.worldSpaceUIPlayerName"); WarnMissing(_playerVisualsField, "PlayerAvatar.playerAvatarVisuals"); WarnMissing(_playerDeathHeadField, "PlayerAvatar.playerDeathHead"); WarnMissing(_nameplatePlayerField, "WorldSpaceUIPlayerName.playerAvatar"); WarnMissing(_nameplateTextField, "WorldSpaceUIPlayerName.text"); WarnMissing(_nameplateShowTimerField, "WorldSpaceUIPlayerName.showTimer"); WarnMissing(_nameplateWorldPositionField, "WorldSpaceUIChild.worldPosition"); WarnMissing(_nameplateShowMethod, "WorldSpaceUIPlayerName.Show"); WarnMissing(_deathHeadType, "PlayerDeathHead type"); WarnMissing(_deathHeadTriggeredField, "PlayerDeathHead.triggered"); WarnMissing(_deathHeadPhysGrabObjectField, "PlayerDeathHead.physGrabObject"); WarnMissing(_physGrabObjectCenterPointField, "PhysGrabObject.centerPoint"); } internal IList GetPlayerList() { try { object obj = ((_gameDirectorInstanceField != null) ? _gameDirectorInstanceField.GetValue(null) : _gameDirectorInstanceProperty?.GetValue(null, null)); if (obj == null) { return null; } return ((_playerListField != null) ? _playerListField.GetValue(obj) : _playerListProperty?.GetValue(obj, null)) as IList; } catch (Exception ex) { _plugin.LogThrottled("player-list", "Failed to read GameDirector.instance.PlayerList: " + ex.Message, 10f, (LogLevel)4); return null; } } internal object FindLocalPlayer(IList players) { int num = 0; while (players != null && num < players.Count) { object obj = players[num]; if (!IsNullOrDestroyed(obj) && IsLocalPlayer(obj)) { return obj; } num++; } return null; } internal bool IsLocalPlayer(object player) { return GetBoolField(player, _playerIsLocalField, fallback: false); } internal bool IsDisabledPlayer(object player) { return GetBoolField(player, _playerIsDisabledField, fallback: false); } internal object GetNameplate(object player) { if (IsNullOrDestroyed(player) || _playerNameplateField == null) { return null; } try { object value = _playerNameplateField.GetValue(player); return IsNullOrDestroyed(value) ? null : value; } catch (Exception ex) { _plugin.LogThrottled("get-nameplate", "Failed to read PlayerAvatar.worldSpaceUIPlayerName: " + ex.Message, 10f, (LogLevel)4); return null; } } internal object GetPlayerForNameplate(object nameplate) { if (IsNullOrDestroyed(nameplate)) { return null; } if (_nameplatePlayerCache.TryGetValue(nameplate, out var value) && !IsNullOrDestroyed(value)) { return value; } if (_nameplatePlayerField != null) { try { object value2 = _nameplatePlayerField.GetValue(nameplate); if (!IsNullOrDestroyed(value2)) { _nameplatePlayerCache[nameplate] = value2; return value2; } } catch (Exception ex) { _plugin.LogThrottled("get-nameplate-player", "Failed to read WorldSpaceUIPlayerName.playerAvatar: " + ex.Message, 10f, (LogLevel)4); } } IList playerList = GetPlayerList(); int num = 0; while (playerList != null && num < playerList.Count) { object obj = playerList[num]; if (!IsNullOrDestroyed(obj) && GetNameplate(obj) == nameplate) { _nameplatePlayerCache[nameplate] = obj; return obj; } num++; } return null; } internal TextMeshProUGUI GetText(object nameplate) { if (IsNullOrDestroyed(nameplate) || _nameplateTextField == null) { return null; } try { object? value = _nameplateTextField.GetValue(nameplate); return (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null); } catch (Exception ex) { _plugin.LogThrottled("read-text", "Failed to read WorldSpaceUIPlayerName.text: " + ex.Message, 10f, (LogLevel)4); return null; } } internal void ShowNameplate(object nameplate) { if (!IsNullOrDestroyed(nameplate)) { _nameplateShowMethod?.Invoke(nameplate, null); } } internal void SetShowTimer(object nameplate, float value) { if (IsNullOrDestroyed(nameplate) || _nameplateShowTimerField == null) { return; } try { _nameplateShowTimerField.SetValue(nameplate, Mathf.Max(0f, value)); } catch (Exception ex) { _plugin.LogThrottled("set-show-timer", "Failed to set WorldSpaceUIPlayerName.showTimer: " + ex.Message, 10f, (LogLevel)4); } } internal Vector3 GetPosition(object obj) { //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_001d: 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_0054: 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) try { Component val = (Component)((obj is Component) ? obj : null); return ((Object)(object)val != (Object)null) ? val.transform.position : Vector3.zero; } catch (Exception ex) { _plugin.LogThrottled("get-position", "Failed to read object position: " + ex.Message, 10f, (LogLevel)4); return Vector3.zero; } } internal Vector3 GetFallbackOrigin() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if (!((Object)(object)main != (Object)null)) { return Vector3.zero; } return ((Component)main).transform.position; } internal Vector3 GetLabelWorldPosition(object player, object nameplate) { //IL_000b: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_003f: 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_008c: Unknown result type (might be due to invalid IL or missing references) if (TryGetDeathHeadLabelPosition(player, out var position)) { return position; } if (!IsNullOrDestroyed(nameplate) && _nameplateWorldPositionField != null) { try { object value = _nameplateWorldPositionField.GetValue(nameplate); if (value is Vector3) { return (Vector3)value; } } catch (Exception ex) { _plugin.LogThrottled("get-label-position", "Failed to read nameplate worldPosition: " + ex.Message, 10f, (LogLevel)4); } } return GetPosition(player) + Vector3.up * 1.8f; } internal Vector3 GetTrackingPosition(object player) { //IL_0013: 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) if (!TryGetDeathHeadLabelPosition(player, out var position)) { return GetPosition(player); } return position; } internal bool HasValidDeathHead(object player) { Vector3 position; return TryGetDeathHeadLabelPosition(player, out position); } internal void UpdateNameplateWorldPosition(object player, object nameplate) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (IsNullOrDestroyed(nameplate) || _nameplateWorldPositionField == null || !TryGetDeathHeadLabelPosition(player, out var position)) { return; } try { _nameplateWorldPositionField.SetValue(nameplate, position); } catch (Exception ex) { _plugin.LogThrottled("set-label-position", "Failed to set nameplate worldPosition: " + ex.Message, 10f, (LogLevel)4); } } internal bool IsDeadPlayer(object player) { if (IsNullOrDestroyed(player)) { return false; } Type type = player.GetType(); string key = type.FullName ?? type.Name; if (!_deadFieldCache.TryGetValue(key, out var value)) { value = null; for (int i = 0; i < DeadFieldNames.Length; i++) { value = AccessTools.Field(type, DeadFieldNames[i]); if (value != null && value.FieldType == typeof(bool)) { break; } value = null; } _deadFieldCache[key] = value; } if (value != null) { return GetBoolField(player, value, fallback: false); } return false; } internal bool IsPlayerCollider(Collider collider, object player) { if ((Object)(object)collider == (Object)null || IsNullOrDestroyed(player)) { return false; } Component val = (Component)((player is Component) ? player : null); if ((Object)(object)val != (Object)null && ((Component)collider).transform.IsChildOf(val.transform)) { return true; } Transform playerVisualsTransform = GetPlayerVisualsTransform(player); if ((Object)(object)playerVisualsTransform != (Object)null && ((Component)collider).transform.IsChildOf(playerVisualsTransform)) { return true; } Transform playerDeathHeadTransform = GetPlayerDeathHeadTransform(player); if ((Object)(object)playerDeathHeadTransform != (Object)null && ((Component)collider).transform.IsChildOf(playerDeathHeadTransform)) { return true; } if (_playerAvatarType != null) { Component componentInParent = ((Component)collider).GetComponentInParent(_playerAvatarType); if ((Object)(object)componentInParent != (Object)null && componentInParent == player) { return true; } } return false; } private bool TryGetDeathHeadLabelPosition(object player, out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); if (!IsDisabledPlayer(player) || !IsDeadPlayer(player)) { return false; } object playerDeathHead = GetPlayerDeathHead(player); if (IsNullOrDestroyed(playerDeathHead) || !GetBoolField(playerDeathHead, _deathHeadTriggeredField, fallback: false)) { return false; } object obj = null; if (_deathHeadPhysGrabObjectField != null) { try { obj = _deathHeadPhysGrabObjectField.GetValue(playerDeathHead); } catch (Exception ex) { _plugin.LogThrottled("get-deathhead-physgrab", "Failed to read PlayerDeathHead.physGrabObject: " + ex.Message, 10f, (LogLevel)4); } } if (!IsNullOrDestroyed(obj) && _physGrabObjectCenterPointField != null) { try { if (_physGrabObjectCenterPointField.GetValue(obj) is Vector3 val) { position = val + Vector3.up * 0.45f; return true; } } catch (Exception ex2) { _plugin.LogThrottled("get-deathhead-center", "Failed to read PhysGrabObject.centerPoint: " + ex2.Message, 10f, (LogLevel)4); } } Component val2 = (Component)((playerDeathHead is Component) ? playerDeathHead : null); if ((Object)(object)val2 != (Object)null) { position = val2.transform.position + Vector3.up * 0.5f; return true; } return false; } private object GetPlayerDeathHead(object player) { if (IsNullOrDestroyed(player) || _playerDeathHeadField == null) { return null; } try { object value = _playerDeathHeadField.GetValue(player); return IsNullOrDestroyed(value) ? null : value; } catch (Exception ex) { _plugin.LogThrottled("get-deathhead", "Failed to read PlayerAvatar.playerDeathHead: " + ex.Message, 10f, (LogLevel)4); return null; } } private Transform GetPlayerDeathHeadTransform(object player) { object playerDeathHead = GetPlayerDeathHead(player); Component val = (Component)((playerDeathHead is Component) ? playerDeathHead : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.transform; } private Transform GetPlayerVisualsTransform(object player) { if (IsNullOrDestroyed(player) || _playerVisualsField == null) { return null; } try { object? value = _playerVisualsField.GetValue(player); Component val = (Component)((value is Component) ? value : null); return ((Object)(object)val != (Object)null) ? val.transform : null; } catch (Exception ex) { _plugin.LogThrottled("get-player-visuals", "Failed to read PlayerAvatar.playerAvatarVisuals: " + ex.Message, 10f, (LogLevel)4); return null; } } internal static bool IsNullOrDestroyed(object obj) { if (obj == null) { return true; } Object val = (Object)((obj is Object) ? obj : null); if (val != null) { return val == (Object)null; } return false; } private bool GetBoolField(object instance, FieldInfo field, bool fallback) { if (IsNullOrDestroyed(instance) || field == null) { return fallback; } try { return (field.GetValue(instance) is bool flag) ? flag : fallback; } catch (Exception ex) { _plugin.LogThrottled("bool-field-" + field.Name, "Failed to read " + field.DeclaringType?.Name + "." + field.Name + ": " + ex.Message, 10f, (LogLevel)4); return fallback; } } private void WarnMissing(object value, string name) { if (value == null) { _plugin.LogWarning("Could not find " + name + "; GlowNames will use fallbacks where possible."); } } } internal sealed class GlowNamesConfig { private static readonly string[] ColorOptions = new string[10] { "White", "Black", "Yellow", "Cyan", "Red", "Green", "Blue", "Orange", "Purple", "Pink" }; internal ConfigEntry<float> Range { get; } internal ConfigEntry<float> Alpha { get; } internal ConfigEntry<float> BaseFontSize { get; } internal ConfigEntry<bool> IncludeDeadPlayers { get; } internal ConfigEntry<string> TextColor { get; } internal ConfigEntry<bool> OutlineEnabled { get; } internal ConfigEntry<string> OutlineColor { get; } internal ConfigEntry<float> OutlineWidth { get; } internal ConfigEntry<bool> OcclusionEnabled { get; } internal ConfigEntry<float> OcclusionCheckInterval { get; } internal GlowNamesConfig(ConfigFile config) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Expected O, but got Unknown Range = config.Bind<float>("Display", "Range", 20f, new ConfigDescription("Maximum distance from the local player to reveal names.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 500f), Array.Empty<object>())); Alpha = config.Bind<float>("Display", "Alpha", 1f, new ConfigDescription("Text alpha for revealed names.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); BaseFontSize = config.Bind<float>("Display", "BaseFontSize", 20f, new ConfigDescription("Base value for the distance size formula: fontSize = BaseFontSize - camera distance. Applies to living-player and death-head names.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); IncludeDeadPlayers = config.Bind<bool>("Filters", "IncludeDeadPlayers", true, "If true, include players that expose a dead/downed flag such as deadSet."); TextColor = config.Bind<string>("Text", "Color", "White", new ConfigDescription("Text color while GlowNames is active.", (AcceptableValueBase)(object)new AcceptableValueList<string>(ColorOptions), Array.Empty<object>())); OutlineEnabled = config.Bind<bool>("Outline", "Enabled", false, "If true, apply TMP outline while GlowNames is active. Disabled by default for plain white text."); OutlineColor = config.Bind<string>("Outline", "Color", "White", new ConfigDescription("TMP outline color while GlowNames is active. Ignored when Outline.Enabled is false.", (AcceptableValueBase)(object)new AcceptableValueList<string>(ColorOptions), Array.Empty<object>())); OutlineWidth = config.Bind<float>("Outline", "Width", 0f, new ConfigDescription("TMP outline width while GlowNames is active. Ignored when Outline.Enabled is false.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); OcclusionEnabled = config.Bind<bool>("Occlusion", "Enabled", true, "If true, names hidden behind walls or large physics objects will not be revealed."); OcclusionCheckInterval = config.Bind<float>("Occlusion", "CheckInterval", 0.1f, new ConfigDescription("Seconds between line-of-sight checks per nameplate. Lower values react faster but do more raycasts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 1f), Array.Empty<object>())); } internal Color GetOutlineColor() { //IL_000b: 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) return GetNamedColor(OutlineColor.Value, Color.white); } internal Color GetTextColor() { //IL_000b: 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) return GetNamedColor(TextColor.Value, Color.white); } private static Color GetNamedColor(string value, Color fallback) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0208: 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_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(value)) { return fallback; } value = value.Trim(); switch (value.ToLowerInvariant()) { case "white": return Color.white; case "black": return Color.black; case "yellow": return Color.yellow; case "cyan": return Color.cyan; case "red": return Color.red; case "green": return Color.green; case "blue": return Color.blue; case "orange": return new Color(1f, 0.5f, 0f, 1f); case "purple": return new Color(0.65f, 0.35f, 1f, 1f); case "pink": return new Color(1f, 0.35f, 0.75f, 1f); default: { if (!value.StartsWith("#", StringComparison.Ordinal)) { value = "#" + value; } Color result = default(Color); if (!ColorUtility.TryParseHtmlString(value, ref result)) { return fallback; } return result; } } } } internal static class HarmonyPatches { internal static void PatchNameplateUpdate(Harmony harmony, Type nameplateType, ManualLogSource logger) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown try { MethodInfo methodInfo = ((nameplateType != null) ? AccessTools.Method(nameplateType, "Update", (Type[])null, (Type[])null) : null); MethodInfo methodInfo2 = AccessTools.Method(typeof(HarmonyPatches), "WorldSpaceUIPlayerNameUpdatePostfix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { logger.LogWarning((object)"Could not patch WorldSpaceUIPlayerName.Update; active refresh will still call Show(), but styling may be overwritten by the game."); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex) { logger.LogWarning((object)("Could not patch WorldSpaceUIPlayerName.Update: " + ex.Message + ". Active refresh will still call Show(), but styling may be overwritten by the game.")); } } private static void WorldSpaceUIPlayerNameUpdatePostfix(object __instance) { GlowNamesPlugin.Instance?.OnNameplateUpdated(__instance); } } internal sealed class LogThrottle { private readonly ManualLogSource _log; private readonly Dictionary<string, float> _nextLogTimeByKey = new Dictionary<string, float>(); internal LogThrottle(ManualLogSource log) { _log = log; } internal void Log(string key, string message, float intervalSeconds, LogLevel level) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) float realtimeSinceStartup = Time.realtimeSinceStartup; if (!_nextLogTimeByKey.TryGetValue(key, out var value) || !(realtimeSinceStartup < value)) { _nextLogTimeByKey[key] = realtimeSinceStartup + Mathf.Max(0.1f, intervalSeconds); ManualLogSource log = _log; if (log != null) { log.Log(level, (object)message); } } } } internal sealed class NameplateHighlighter { private struct TextState { public Color Color; public float FontSize; public Color OutlineColor; public float OutlineWidth; } private readonly GlowNamesPlugin _plugin; private readonly Dictionary<TextMeshProUGUI, TextState> _originalStateByText = new Dictionary<TextMeshProUGUI, TextState>(); internal NameplateHighlighter(GlowNamesPlugin plugin) { _plugin = plugin; } internal void Apply(TextMeshProUGUI text, GlowNamesConfig settings, float? fontSizeOverride) { //IL_0012: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)text == (Object)null)) { CacheOriginalState(text); Color textColor = settings.GetTextColor(); textColor.a = Mathf.Clamp01(settings.Alpha.Value); ((Graphic)text).color = textColor; if (fontSizeOverride.HasValue) { ((TMP_Text)text).fontSize = fontSizeOverride.Value; } if (settings.OutlineEnabled.Value) { ((TMP_Text)text).outlineColor = Color32.op_Implicit(settings.GetOutlineColor()); ((TMP_Text)text).outlineWidth = Mathf.Clamp01(settings.OutlineWidth.Value); } else { RestoreOutline(text); } } } internal void Hide(TextMeshProUGUI text) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)text == (Object)null)) { CacheOriginalState(text); Color color = ((Graphic)text).color; color.a = 0f; ((Graphic)text).color = color; } } internal void RestoreOutline(TextMeshProUGUI text) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)text == (Object)null || !_originalStateByText.TryGetValue(text, out var value)) { return; } try { ((TMP_Text)text).outlineColor = Color32.op_Implicit(value.OutlineColor); ((TMP_Text)text).outlineWidth = value.OutlineWidth; } catch (Exception ex) { _plugin.LogThrottled("restore-outline", "Failed to restore TMP outline: " + ex.Message, 10f, (LogLevel)4); } } internal void RestoreAll() { if (_originalStateByText.Count != 0) { List<TextMeshProUGUI> list = new List<TextMeshProUGUI>(_originalStateByText.Keys); for (int i = 0; i < list.Count; i++) { Restore(list[i]); } _originalStateByText.Clear(); } } internal void Restore(TextMeshProUGUI text) { //IL_001e: 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_003b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)text == (Object)null || !_originalStateByText.TryGetValue(text, out var value)) { return; } try { ((Graphic)text).color = value.Color; ((TMP_Text)text).fontSize = value.FontSize; ((TMP_Text)text).outlineColor = Color32.op_Implicit(value.OutlineColor); ((TMP_Text)text).outlineWidth = value.OutlineWidth; } catch (Exception ex) { _plugin.LogThrottled("restore-text-state", "Failed to restore TMP text state: " + ex.Message, 10f, (LogLevel)4); } finally { _originalStateByText.Remove(text); } } private void CacheOriginalState(TextMeshProUGUI text) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)text == (Object)null) && !_originalStateByText.ContainsKey(text)) { _originalStateByText[text] = new TextState { Color = ((Graphic)text).color, FontSize = ((TMP_Text)text).fontSize, OutlineColor = Color32.op_Implicit(((TMP_Text)text).outlineColor), OutlineWidth = ((TMP_Text)text).outlineWidth }; } } } internal sealed class NameplateOcclusion { private struct OcclusionState { public bool IsOccluded; public float NextCheckTime; } private static readonly string[] OcclusionLayerNames = new string[5] { "Default", "StaticGrabObject", "PhysGrabObject", "PhysGrabObjectCart", "PhysGrabObjectHinge" }; private readonly GlowNamesPlugin _plugin; private readonly Dictionary<object, OcclusionState> _stateByNameplate = new Dictionary<object, OcclusionState>(); private readonly int _occlusionMask; internal NameplateOcclusion(GlowNamesPlugin plugin) { _plugin = plugin; _occlusionMask = BuildOcclusionMask(); } internal bool IsVisible(object player, object nameplate) { if (!_plugin.Settings.OcclusionEnabled.Value || _occlusionMask == 0) { return true; } object obj = nameplate ?? player; if (obj == null) { return true; } if (!_stateByNameplate.TryGetValue(obj, out var value) || Time.time >= value.NextCheckTime) { value.IsOccluded = IsOccluded(player, nameplate); value.NextCheckTime = Time.time + Mathf.Max(0.02f, _plugin.Settings.OcclusionCheckInterval.Value); _stateByNameplate[obj] = value; } return !value.IsOccluded; } internal void ClearCache() { _stateByNameplate.Clear(); } private bool IsOccluded(object player, object nameplate) { //IL_001e: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return false; } Vector3 labelWorldPosition = _plugin.Game.GetLabelWorldPosition(player, nameplate); Vector3 position = ((Component)main).transform.position; Vector3 val = labelWorldPosition - position; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= Mathf.Epsilon) { return false; } RaycastHit[] array = Physics.RaycastAll(position, ((Vector3)(ref val)).normalized, magnitude, _occlusionMask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { Collider collider = ((RaycastHit)(ref array[i])).collider; if (!((Object)(object)collider == (Object)null) && !_plugin.Game.IsPlayerCollider(collider, player)) { return true; } } return false; } private static int BuildOcclusionMask() { int num = 0; for (int i = 0; i < OcclusionLayerNames.Length; i++) { int num2 = LayerMask.NameToLayer(OcclusionLayerNames[i]); if (num2 >= 0) { num |= 1 << num2; } } return num; } } [BepInPlugin("com.zhuanban.glownames", "GlowNames", "1.1.0")] public sealed class GlowNamesPlugin : BaseUnityPlugin { public const string PluginGuid = "com.zhuanban.glownames"; public const string PluginName = "GlowNames"; public const string PluginVersion = "1.1.0"; private NameplateHighlighter _highlighter; private NameplateOcclusion _occlusion; private LogThrottle _logThrottle; private Harmony _harmony; private const float ForcedShowTimer = 0.5f; internal static GlowNamesPlugin Instance { get; private set; } internal GlowNamesConfig Settings { get; private set; } internal GameReflection Game { get; private set; } private void Awake() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown Instance = this; _logThrottle = new LogThrottle(((BaseUnityPlugin)this).Logger); Settings = new GlowNamesConfig(((BaseUnityPlugin)this).Config); Game = new GameReflection(this); _highlighter = new NameplateHighlighter(this); _occlusion = new NameplateOcclusion(this); Game.CacheMembers(); _harmony = new Harmony("com.zhuanban.glownames"); HarmonyPatches.PatchNameplateUpdate(_harmony, Game.NameplateType, ((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Logger.LogInfo((object)"GlowNames 1.1.0 loaded. Player names are always shown while visible and in range."); } private void OnDestroy() { _highlighter?.RestoreAll(); try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to unpatch Harmony cleanly: " + ex.Message)); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { try { RefreshVisibleNameplates(); } catch (Exception arg) { LogThrottled("update", $"GlowNames Update failed: {arg}", 5f, (LogLevel)4); } } private void RefreshVisibleNameplates() { //IL_003c: 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_0056: 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) IList playerList = Game.GetPlayerList(); if (playerList == null || playerList.Count == 0) { return; } object obj = Game.FindLocalPlayer(playerList); Vector3 origin = ((obj != null) ? Game.GetPosition(obj) : Game.GetFallbackOrigin()); for (int i = 0; i < playerList.Count; i++) { object player = playerList[i]; if (!IsEligiblePlayer(player, obj, origin)) { continue; } object nameplate = Game.GetNameplate(player); if (nameplate == null) { continue; } Game.UpdateNameplateWorldPosition(player, nameplate); if (!_occlusion.IsVisible(player, nameplate)) { HideNameplate(nameplate); continue; } try { Game.ShowNameplate(nameplate); Game.SetShowTimer(nameplate, 0.5f); ApplyHighlight(player, nameplate); } catch (Exception ex) { LogThrottled("show-nameplate", "Failed to show a player nameplate: " + ex.Message, 5f, (LogLevel)4); } } } internal void OnNameplateUpdated(object nameplate) { //IL_0061: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) try { if (nameplate == null) { RestoreOutline(nameplate); return; } object playerForNameplate = Game.GetPlayerForNameplate(nameplate); if (playerForNameplate == null) { RestoreOutline(nameplate); return; } IList playerList = Game.GetPlayerList(); object obj = ((playerList != null) ? Game.FindLocalPlayer(playerList) : null); Vector3 origin = ((obj != null) ? Game.GetPosition(obj) : Game.GetFallbackOrigin()); if (!IsEligiblePlayer(playerForNameplate, obj, origin)) { RestoreOutline(nameplate); return; } Game.UpdateNameplateWorldPosition(playerForNameplate, nameplate); if (!_occlusion.IsVisible(playerForNameplate, nameplate)) { HideNameplate(nameplate); return; } Game.SetShowTimer(nameplate, 0.5f); ApplyHighlight(playerForNameplate, nameplate); } catch (Exception ex) { LogThrottled("postfix", "WorldSpaceUIPlayerName.Update postfix failed: " + ex.Message, 5f, (LogLevel)4); } } private bool IsEligiblePlayer(object player, object localPlayer, Vector3 origin) { //IL_00a6: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) if (player == null) { return false; } if (player == localPlayer || Game.IsLocalPlayer(player)) { return false; } bool flag = Game.IsDeadPlayer(player); bool flag2 = Game.IsDisabledPlayer(player); if (flag2 && (!Settings.IncludeDeadPlayers.Value || !flag || !Game.HasValidDeathHead(player))) { return false; } if (!flag2 && !Settings.IncludeDeadPlayers.Value && flag) { return false; } float num = Mathf.Max(0f, Settings.Range.Value); if (num <= 0f) { return false; } Vector3 val = Game.GetTrackingPosition(player) - origin; return ((Vector3)(ref val)).sqrMagnitude <= num * num; } private void ApplyHighlight(object player, object nameplate) { TextMeshProUGUI text = Game.GetText(nameplate); if ((Object)(object)text != (Object)null) { _highlighter.Apply(text, Settings, GetFontSizeOverride(player, nameplate)); } } private float? GetFontSizeOverride(object player, object nameplate) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return null; } float num = Vector3.Distance(Game.GetLabelWorldPosition(player, nameplate), ((Component)main).transform.position); return Settings.BaseFontSize.Value - num; } private void HideNameplate(object nameplate) { Game.SetShowTimer(nameplate, 0f); TextMeshProUGUI text = Game.GetText(nameplate); if ((Object)(object)text != (Object)null) { _highlighter.Hide(text); _highlighter.RestoreOutline(text); } } private void RestoreOutline(object nameplate) { TextMeshProUGUI text = Game.GetText(nameplate); if ((Object)(object)text != (Object)null) { _highlighter.Restore(text); } } internal void LogThrottled(string key, string message, float intervalSeconds, LogLevel level) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _logThrottle.Log(key, message, intervalSeconds, level); } internal void LogWarning(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); } } }