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 ForsakenRadial v0.3.1
plugins/ForsakenRadial.dll
Decompiled 5 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; using Valheim.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("ForsakenRadial")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.1.0")] [assembly: AssemblyInformationalVersion("0.3.1")] [assembly: AssemblyProduct("ForsakenRadial")] [assembly: AssemblyTitle("ForsakenRadial")] [assembly: AssemblyVersion("0.3.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ForsakenRadial { [HarmonyPatch(typeof(ValheimRadialConfig), "InitRadialConfig")] internal static class ForsakenPowerRadial { private sealed class PowerDefinition { internal readonly string Power; internal readonly string DefeatedKey; internal PowerDefinition(string power, string defeatedKey) { Power = power; DefeatedKey = defeatedKey; } } private sealed class ForsakenPowerChoice : IRadialConfig { internal readonly string Power; private readonly string _name; internal readonly string Description; internal GroupElement? Element; public string LocalizedName { get { if (Localization.instance != null) { return Localization.instance.Localize(_name); } return _name; } } public Sprite Sprite { get; } internal ForsakenPowerChoice(string power, string name, Sprite sprite, string description) { Power = power; _name = name; Sprite = sprite; Description = description; } public void InitRadialConfig(RadialBase radial) { } } private sealed class ForsakenRadialConfig : IRadialConfig { private Player? _player; private List<ForsakenPowerChoice> _choices = new List<ForsakenPowerChoice>(); private RadialBase? _radial; private DescriptionPanel? _descriptionPanel; private ForsakenPowerChoice? _describedChoice; private bool _descriptionUnavailable; internal RadialBase? Radial => _radial; public string LocalizedName { get { if (Localization.instance != null) { return Localization.instance.Localize("Forsaken Powers"); } return "Forsaken Powers"; } } public Sprite? Sprite { get { string activePower = (((Object)(object)_player == (Object)null) ? string.Empty : _player.GetGuardianPowerName()); return _choices.Find((ForsakenPowerChoice choice) => choice.Power == activePower)?.Sprite ?? _choices[0].Sprite; } } internal void Initialize(Player? player, List<ForsakenPowerChoice> choices) { _player = player; _choices = choices; } public void InitRadialConfig(RadialBase radial) { _radial = radial; List<RadialMenuElement> list = new List<RadialMenuElement>(_choices.Count); foreach (ForsakenPowerChoice choice in _choices) { GroupElement val = Object.Instantiate<GroupElement>(RadialData.SO.GroupElement); val.Init((IRadialConfig)(object)choice, (IRadialConfig)null, radial); choice.Element = val; ((RadialMenuElement)val).Interact = delegate { if ((Object)(object)_player == (Object)null || (Object)(object)_player != (Object)(object)Player.m_localPlayer) { return false; } try { _player.SetGuardianPower(choice.Power); ForsakenRadialPlugin.Log.LogInfo((object)("Selected Forsaken power '" + choice.Power + "'.")); return true; } catch (Exception arg) { ForsakenRadialPlugin.Log.LogError((object)$"Could not select Forsaken power '{choice.Power}': {arg}"); return false; } }; ((RadialMenuElement)val).CloseOnInteract = () => true; list.Add((RadialMenuElement)(object)val); } radial.ConstructRadial(list); } internal void UpdateDescription(RadialBase radial) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (_descriptionUnavailable) { return; } ForsakenPowerChoice forsakenPowerChoice = _choices.Find((ForsakenPowerChoice choice) => (Object)(object)choice.Element == (Object)(object)radial.Selected); if (forsakenPowerChoice == null) { _describedChoice = null; _descriptionPanel?.Hide(); return; } try { if (forsakenPowerChoice != _describedChoice) { _describedChoice = forsakenPowerChoice; if (_descriptionPanel == null) { _descriptionPanel = new DescriptionPanel(Hud.instance, radial); } _descriptionPanel.Show(forsakenPowerChoice.Description); } _descriptionPanel?.Position(((RadialMenuElement)forsakenPowerChoice.Element).ElementTransform, radial.InfoPosition); } catch (Exception arg) { _descriptionUnavailable = true; _descriptionPanel?.Dispose(); _descriptionPanel = null; ForsakenRadialPlugin.Log.LogWarning((object)$"Could not display the focused Forsaken power description: {arg}"); } } internal void DisposeDescription() { _descriptionPanel?.Dispose(); _descriptionPanel = null; _describedChoice = null; } } [HarmonyPatch(typeof(RadialBase), "Update")] private static class RadialUpdatePatch { private static void Postfix(RadialBase __instance) { UpdateDescription(__instance); } } [HarmonyPatch(typeof(RadialBase), "Open")] private static class RadialOpenPatch { private static void Prefix(RadialBase __instance) { HideDescription(__instance); } } [HarmonyPatch(typeof(RadialBase), "Close")] private static class RadialClosePatch { private static void Prefix(RadialBase __instance) { HideDescription(__instance); } } private sealed class DescriptionPanel : IDisposable { private readonly GameObject _root; private readonly RectTransform _layoutRoot; private readonly RectTransform _panel; private readonly TMP_Text _text; private readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4]; private readonly Vector3 _baseScale; internal DescriptionPanel(Hud? hud, RadialBase radial) { //IL_00a3: 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) UITooltip val = (((Object)(object)hud?.m_pieceIconPrefab != (Object)null) ? hud.m_pieceIconPrefab.GetComponent<UITooltip>() : null); if ((Object)(object)val?.m_tooltipPrefab == (Object)null) { throw new InvalidOperationException("The HUD tooltip template is unavailable."); } _root = Object.Instantiate<GameObject>(val.m_tooltipPrefab, ((Component)radial).transform); try { ((Object)_root).name = "ForsakenRadial_Description"; _root.SetActive(false); _root.transform.SetAsLastSibling(); _baseScale = _root.transform.localScale; ref RectTransform layoutRoot = ref _layoutRoot; Transform transform = _root.transform; layoutRoot = (RectTransform)(object)(((transform is RectTransform) ? transform : null) ?? throw new InvalidOperationException("The HUD tooltip layout is unavailable.")); ref RectTransform panel = ref _panel; Transform child = _root.transform.GetChild(0); panel = (RectTransform)(object)(((child is RectTransform) ? child : null) ?? throw new InvalidOperationException("The HUD tooltip panel is unavailable.")); Transform val2 = FindChild(_root.transform, "Topic"); if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.SetActive(false); } Transform? obj = FindChild(_root.transform, "Text"); _text = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null) ?? _root.GetComponentInChildren<TMP_Text>(true) ?? throw new InvalidOperationException("The HUD tooltip text is unavailable."); if ((Object)(object)val2 == (Object)null) { _panel = _layoutRoot; HorizontalOrVerticalLayoutGroup component = _root.GetComponent<HorizontalOrVerticalLayoutGroup>(); if ((Object)(object)component != (Object)null) { component.childControlHeight = true; } ContentSizeFitter component2 = _root.GetComponent<ContentSizeFitter>(); if ((Object)(object)component2 != (Object)null) { component2.verticalFit = (FitMode)2; } } Graphic[] componentsInChildren = _root.GetComponentsInChildren<Graphic>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].raycastTarget = false; } } catch { Object.Destroy((Object)(object)_root); throw; } } internal void Show(string text) { if (string.IsNullOrWhiteSpace(text)) { Hide(); return; } _text.text = text; _root.SetActive(true); LayoutRebuilder.ForceRebuildLayoutImmediate(_layoutRoot); } internal void Position(RectTransform icon, Vector2 center) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0142: 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) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: 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_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) if (_root.activeSelf) { icon.GetWorldCorners(_corners); Rect val = Rect.MinMaxRect(_corners[0].x, _corners[0].y, _corners[2].x, _corners[2].y); _root.transform.localScale = _baseScale; _panel.GetWorldCorners(_corners); Vector2 val2 = Vector2.op_Implicit(_corners[2] - _corners[0]); float num = Mathf.Min(1f, Mathf.Min(((float)Screen.width - 16f) / Mathf.Max(1f, val2.x), ((float)Screen.height - 16f) / Mathf.Max(1f, val2.y))); _root.transform.localScale = _baseScale * Mathf.Max(0.01f, num); _panel.GetWorldCorners(_corners); val2 = Vector2.op_Implicit(_corners[2] - _corners[0]); bool flag = ((Rect)(ref val)).center.x >= center.x; float num2 = (flag ? (((Rect)(ref val)).xMax + 8f) : (((Rect)(ref val)).xMin - 8f - val2.x)); if (flag && num2 + val2.x > (float)Screen.width - 8f) { num2 = ((Rect)(ref val)).xMin - 8f - val2.x; } else if (!flag && num2 < 8f) { num2 = ((Rect)(ref val)).xMax + 8f; } Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(Mathf.Clamp(num2, 8f, Mathf.Max(8f, (float)Screen.width - 8f - val2.x)), Mathf.Clamp(((Rect)(ref val)).center.y - val2.y * 0.5f, 8f, Mathf.Max(8f, (float)Screen.height - 8f - val2.y))); Transform transform = _root.transform; transform.position += Vector2.op_Implicit(val3 - Vector2.op_Implicit(_corners[0])); } } internal void Hide() { if ((Object)(object)_root != (Object)null) { _root.SetActive(false); } } public void Dispose() { if (!((Object)(object)_root == (Object)null)) { _root.SetActive(false); Object.Destroy((Object)(object)_root); } } private static Transform? FindChild(Transform root, string name) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown foreach (Transform item in root) { Transform val = item; if (((Object)val).name == name) { return val; } Transform val2 = FindChild(val, name); if ((Object)(object)val2 != (Object)null) { return val2; } } return null; } } private static readonly PowerDefinition[] Powers = new PowerDefinition[7] { new PowerDefinition("GP_Eikthyr", "defeated_eikthyr"), new PowerDefinition("GP_TheElder", "defeated_gdking"), new PowerDefinition("GP_Bonemass", "defeated_bonemass"), new PowerDefinition("GP_Moder", "defeated_dragon"), new PowerDefinition("GP_Yagluth", "defeated_goblinking"), new PowerDefinition("GP_Queen", "defeated_queen"), new PowerDefinition("GP_Fader", "defeated_fader") }; private static readonly MethodInfo ConstructRadialMethod = AccessTools.Method(typeof(RadialBase), "ConstructRadial", new Type[1] { typeof(List<RadialMenuElement>) }, (Type[])null); private static readonly MethodInfo AppendTileAndConstructMethod = AccessTools.Method(typeof(ForsakenPowerRadial), "AppendTileAndConstruct", (Type[])null, (Type[])null); private static ForsakenRadialConfig? _tooltipConfig; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { bool patched = false; foreach (CodeInstruction instruction in instructions) { if (!patched && CodeInstructionExtensions.Calls(instruction, ConstructRadialMethod)) { yield return new CodeInstruction(OpCodes.Call, (object)AppendTileAndConstructMethod); patched = true; } else { yield return instruction; } } if (!patched) { throw new InvalidOperationException("Could not find the vanilla radial construction call to add the Forsaken Powers tile."); } } private static void AppendTileAndConstruct(RadialBase radial, List<RadialMenuElement> elements) { ZoneSystem instance = ZoneSystem.instance; ObjectDB instance2 = ObjectDB.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || radial.CurrentConfig == null || (Object)(object)RadialData.SO == (Object)null || (Object)(object)RadialData.SO.GroupElement == (Object)null) { radial.ConstructRadial(elements); return; } List<ForsakenPowerChoice> list = new List<ForsakenPowerChoice>(); PowerDefinition[] powers = Powers; foreach (PowerDefinition powerDefinition in powers) { if (instance.GetGlobalKey(powerDefinition.DefeatedKey)) { StatusEffect statusEffect = instance2.GetStatusEffect(StringExtensionMethods.GetStableHashCode(powerDefinition.Power)); if ((Object)(object)statusEffect == (Object)null || (Object)(object)statusEffect.m_icon == (Object)null) { ForsakenRadialPlugin.Log.LogWarning((object)("The status effect or icon for '" + powerDefinition.Power + "' is missing; its radial entry was skipped.")); } else { list.Add(new ForsakenPowerChoice(powerDefinition.Power, statusEffect.m_name, statusEffect.m_icon, GetEffectDescription(statusEffect))); } } } if (list.Count > 0) { ForsakenRadialConfig forsakenRadialConfig = new ForsakenRadialConfig(); forsakenRadialConfig.Initialize(Player.m_localPlayer, list); GroupElement val = Object.Instantiate<GroupElement>(RadialData.SO.GroupElement); val.Init((IRadialConfig)(object)forsakenRadialConfig, radial.CurrentConfig, radial); elements.Add((RadialMenuElement)(object)val); } radial.ConstructRadial(elements); } private static string GetEffectDescription(StatusEffect effect) { string text = effect.GetTooltipString() ?? effect.m_tooltip ?? string.Empty; if (Localization.instance != null) { text = Localization.instance.Localize(text); } text = text.Replace("\r\n", "\n").Replace('\r', '\n'); int num = text.IndexOf("\n\n", StringComparison.Ordinal); text = ((num < 0) ? string.Empty : text.Substring(num + 2).Trim()); AddAttribute((StatusAttribute)4, "Tailwind while sailing"); AddAttribute((StatusAttribute)8, "Faster taming of nearby creatures"); AddAttribute((StatusAttribute)2, "Incoming collision damage: <color=orange>×2</color>"); return text; void AddAttribute(StatusAttribute attribute, string description) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (effect.HaveAttribute(attribute)) { string text2 = ((Localization.instance == null) ? description : Localization.instance.Localize(description)); text = ((text.Length == 0) ? text2 : (text + "\n" + text2)); } } } internal static void UpdateDescription(RadialBase radial) { if (radial.CurrentConfig is ForsakenRadialConfig forsakenRadialConfig) { _tooltipConfig = forsakenRadialConfig; forsakenRadialConfig.UpdateDescription(radial); } else { HideDescription(radial); } } internal static void HideDescription(RadialBase radial) { if (_tooltipConfig != null && _tooltipConfig.Radial == radial) { _tooltipConfig.DisposeDescription(); _tooltipConfig = null; } } internal static void Shutdown() { if ((Object)(object)_tooltipConfig?.Radial != (Object)null) { HideDescription(_tooltipConfig.Radial); } } } [BepInPlugin("com.thedefside.forsakenradial", "ForsakenRadial", "0.3.1")] public sealed class ForsakenRadialPlugin : BaseUnityPlugin { public const string PluginGuid = "com.thedefside.forsakenradial"; public const string PluginName = "ForsakenRadial"; public const string PluginVersion = "0.3.1"; internal static ManualLogSource Log; private Harmony? _harmony; private bool _patchesApplied; private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("com.thedefside.forsakenradial"); try { _harmony.PatchAll(typeof(ForsakenRadialPlugin).Assembly); _patchesApplied = true; } catch (Exception arg) { Log.LogError((object)$"Could not install radial integration patches: {arg}"); try { _harmony.UnpatchSelf(); } catch (Exception arg2) { Log.LogError((object)$"Could not clean up failed radial integration patches: {arg2}"); } _harmony = null; return; } Log.LogInfo((object)"ForsakenRadial loaded. Forsaken Powers is added to the vanilla radial."); } private void OnDestroy() { ForsakenPowerRadial.Shutdown(); if (_patchesApplied) { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } }