Skip to content

Commit

Permalink
UIX: add new API for dynamic settings entry visibility, fix for build…
Browse files Browse the repository at this point in the history
… 1160
  • Loading branch information
knah committed Dec 10, 2021
1 parent 2970ebb commit 69e496c
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 12 deletions.
2 changes: 2 additions & 0 deletions ReleaseChangelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ Read the [Malicious Mods and you](https://github.com/knah/VRCMods/blob/master/Ma

Changes:
* Advanced Safety: added protection for uncommon skid crashes (contributed by Requi and Ben)
* UI Expansion Kit: added APIs to dynamically show or hide mod settings entries
* UI Expansion Kit: fixed compatibility with build 1160


**USE IT AT YOUR OWN RISK.** Modding the client is against VRChat ToS. I am not responsible for any bans or other punishments you may get by using these mods!
35 changes: 30 additions & 5 deletions UIExpansionKit/API/ExpansionKitApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,29 @@ namespace UIExpansionKit.API
{
public static class ExpansionKitApi
{
internal static readonly Dictionary<ExpandedMenu, CustomLayoutedPageImpl> ExpandedMenus = new Dictionary<ExpandedMenu, CustomLayoutedPageImpl>();
internal static readonly Dictionary<string, GameObject> CustomCategoryUIs = new Dictionary<string, GameObject>();
internal static readonly Dictionary<string, CustomLayoutedPageImpl> SettingPageExtensions = new Dictionary<string, CustomLayoutedPageImpl>();
internal static readonly List<IEnumerator> ExtraWaitCoroutines = new List<IEnumerator>();
internal static readonly Dictionary<ExpandedMenu, CustomLayoutedPageImpl> ExpandedMenus = new();
internal static readonly Dictionary<string, GameObject> CustomCategoryUIs = new();
internal static readonly Dictionary<string, CustomLayoutedPageImpl> SettingPageExtensions = new();
internal static readonly List<IEnumerator> ExtraWaitCoroutines = new();
internal static bool CanAddWaitCoroutines = true;

internal static readonly Dictionary<(string, string), IList<(string SettingsValue, string DisplayName)>> EnumSettings = new Dictionary<(string, string), IList<(string SettingsValue, string DisplayName)>>();
internal static readonly Dictionary<(string, string), IList<(string SettingsValue, string DisplayName)>> EnumSettings = new();
internal static readonly Dictionary<(string, string), SettingVisibilityRegistrationValue> SettingsVisibilities = new();

internal static List<Action> onUiManagerInitDelegateList = new();

internal class SettingVisibilityRegistrationValue
{
internal readonly Func<bool> IsVisible;
internal event Action OnUpdateVisibility;

public SettingVisibilityRegistrationValue(Func<bool> isVisible)
{
IsVisible = isVisible;
}

internal void FireUpdateVisibility() => OnUpdateVisibility?.Invoke();
}

/// <summary>
/// Actions added to this even will be called during UI Expansion Kit init, after VrcUiManager has been created
Expand Down Expand Up @@ -203,5 +217,16 @@ public static PreloadedBundleContents GetUiExpansionKitBundleContents()
{
return UiExpansionKitMod.Instance.StuffBundle;
}

/// <summary>
/// Registers a visibility callback for a given settings entry.
/// </summary>
/// <returns>A delegate that can be called to update visibility of settings entry</returns>
public static Action RegisterSettingsVisibilityCallback(string category, string setting, Func<bool> isVisible)
{
var value = new SettingVisibilityRegistrationValue(isVisible);
SettingsVisibilities[(category, setting)] = value;
return value.FireUpdateVisibility;
}
}
}
21 changes: 20 additions & 1 deletion UIExpansionKit/ModSettingsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ void CreateNumericSetting<T>(MelonPreferences_Entry<T> entry, Func<T, string> to

textField.text = toString(newValue);
};
AttachVisibilityHandlerToEntry(textSetting, entry);
}


Expand Down Expand Up @@ -253,6 +254,8 @@ void RefreshOptions()
dropdown.value = newIndex;
};

AttachVisibilityHandlerToEntry(comboSetting, pref);

AttachPinToggle(comboSetting.transform, categoryId, prefId, pinnedSettings);
}
else
Expand Down Expand Up @@ -282,6 +285,8 @@ void RefreshOptions()
UiExpansionKitMod.AreSettingsDirty = true;
textField.text = newValue;
};

AttachVisibilityHandlerToEntry(textSetting, pref);
}

break;
Expand All @@ -304,6 +309,7 @@ void RefreshOptions()

mainToggle.isOn = newValue;
};
AttachVisibilityHandlerToEntry(boolSetting, pref);
break;
case MelonPreferences_Entry<float> floatEntry:
CreateNumericSetting(floatEntry, f => f.ToString(CultureInfo.InvariantCulture),
Expand Down Expand Up @@ -349,7 +355,7 @@ void RefreshOptions()
customEntries?.PopulateButtons(categoryUiContent, false, false);
}

UiExpansionKitMod.SetLayerRecursively(settingsContentRoot.gameObject, 12);
UiExpansionKitMod.SetLayerRecursively(settingsContentRoot.gameObject, 19);
}

private static Transform CreateEnumSetting<T>(MelonPreferences_Entry<T> entry, GameObject comboBoxPrefab, Transform categoryUiContent) where T : Enum
Expand Down Expand Up @@ -400,8 +406,21 @@ private static Transform CreateEnumSetting<T>(MelonPreferences_Entry<T> entry, G
if (newIndex != -1)
dropdown.value = newIndex;
};

AttachVisibilityHandlerToEntry(comboSetting, entry);

return comboSetting.transform;
}

private static void AttachVisibilityHandlerToEntry(GameObject entry, MelonPreferences_Entry prefsEntry)
{
var category = prefsEntry.Category.Identifier;
var setting = prefsEntry.Identifier;

if (!ExpansionKitApi.SettingsVisibilities.TryGetValue((category, setting), out var value)) return;

entry.active = value.IsVisible();
value.OnUpdateVisibility += () => { entry.active = value.IsVisible(); };
}
}
}
1 change: 1 addition & 0 deletions UIExpansionKit/PinnedPrefUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ void UpdateText()
Action<string, string> handler = (_, _) => { UpdateText(); };
stringEntry.OnValueChanged += handler;
button.GetOrAddComponent<DestroyListener>().OnDestroyed += () => stringEntry.OnValueChanged -= handler;
button.GetOrAddComponent<EnableDisableListener>().OnEnabled += UpdateText;
}

private static void CreatePinnedPrefButtonForEnum<T>(MelonPreferences_Entry<T> enumEntry, Transform expandoRoot, GameObject buttonPrefab) where T: Enum
Expand Down
16 changes: 12 additions & 4 deletions UIExpansionKit/ScanningReflectionCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Linq;
using System.Reflection;
using Il2CppSystem.Collections.Generic;
using UnhollowerBaseLib.Attributes;
using UnhollowerRuntimeLib.XrefScans;
using UnityEngine;
using UnityEngine.UI;
Expand All @@ -24,9 +23,18 @@ internal static ShowUiInputPopupAction ShowUiInputPopup
{
if (ourShowUiInputPopupAction != null) return ourShowUiInputPopupAction;

var targetMethod = typeof(VRCUiPopupManager).GetMethod(
nameof(VRCUiPopupManager
.Method_Public_Void_String_String_InputType_Boolean_String_Action_3_String_List_1_KeyCode_Text_Action_String_Boolean_Action_1_VRCUiPopup_Boolean_Int32_0),
var candidates = typeof(VRCUiPopupManager)
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly).Where(it =>
it.Name.StartsWith("Method_Public_Void_String_String_InputType_Boolean_String_Action_3_String_List_1_KeyCode_Text_Action_String_Boolean_Action_1_VRCUiPopup_Boolean_Int32_")
&& !it.Name.EndsWith("_PDM"))
.ToList();

var targetMethod = candidates.SingleOrDefault(it => XrefScanner.XrefScan(it).Any(jt =>
jt.Type == XrefType.Global &&
jt.ReadAsObject()?.ToString() == "UserInterface/MenuContent/Popups/InputPopup"));

if (targetMethod == null)
targetMethod = typeof(VRCUiPopupManager).GetMethod(nameof(VRCUiPopupManager.Method_Public_Void_String_String_InputType_Boolean_String_Action_3_String_List_1_KeyCode_Text_Action_String_Boolean_Action_1_VRCUiPopup_Boolean_Int32_0),
BindingFlags.Instance | BindingFlags.Public);

ourShowUiInputPopupAction = (ShowUiInputPopupAction) Delegate.CreateDelegate(typeof(ShowUiInputPopupAction), VRCUiPopupManager.field_Private_Static_VRCUiPopupManager_0, targetMethod);
Expand Down
2 changes: 1 addition & 1 deletion UIExpansionKit/UIExpansionKit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFramework>net472</TargetFramework>
<VrcReferences>true</VrcReferences>
<LangVersion>latest</LangVersion>
<AssemblyVersion>0.4.0.0</AssemblyVersion>
<AssemblyVersion>0.4.1.0</AssemblyVersion>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="modui.assetbundle" />
Expand Down
2 changes: 1 addition & 1 deletion UIExpansionKit/UiExpansionKitMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
using Object = UnityEngine.Object;
using QuickMenuNew = VRC.UI.Elements.QuickMenu;

[assembly:MelonInfo(typeof(UiExpansionKitMod), "UI Expansion Kit", "0.4.0", "knah", "https://github.com/knah/VRCMods")]
[assembly:MelonInfo(typeof(UiExpansionKitMod), "UI Expansion Kit", "0.4.1", "knah", "https://github.com/knah/VRCMods")]
[assembly:MelonGame("VRChat", "VRChat")]

namespace UIExpansionKit
Expand Down

0 comments on commit 69e496c

Please sign in to comment.