Futher progress on presets UI

This commit is contained in:
ang-xd committed 2025-04-12 23:29:09 -04:00
1 parent 8f590b94a8
commit 32a44d646d
5 files changed
+230 -52

No files matched your search

@@ -6,6 +6,7 @@ using HarmonyLib;
using MiraAPI.Hud;
using MiraAPI.PluginLoading;
using MiraAPI.Presets;
using MiraAPI.Utilities.Assets;
using Reactor.Utilities;
using Reactor.Utilities.Extensions;
using TMPro;
@@ -21,7 +22,7 @@ internal static class GamePresetsTabPatches
private static GameObject _saveButton = null!;
private static GameObject _refreshButton = null!;
private static GameObject _folderButton = null!;
private static GameObject _newDivider = null!;
private static GameObject _presetHolder = null!;
private static GridArrange _arrange = null!;
@@ -39,11 +40,19 @@ internal static class GamePresetsTabPatches
return;
}
__instance.PresetDescriptionText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
var oldDiv = __instance.transform.FindChild("DividerImage");
_newDivider = Object.Instantiate(oldDiv.gameObject, oldDiv.transform.parent);
_newDivider.transform.localPosition = new Vector3(1.85f, 0.13f, 0f);
_newDivider.transform.localScale = new Vector3(1.13f, 1, 1);
_newDivider.transform.localRotation = Quaternion.Euler(new Vector3(0, 0, 90));
// create the save button
var saveButton = Object.Instantiate(prefab, __instance.transform);
_saveButton = saveButton.gameObject;
_saveButton.gameObject.name = "SaveButton";
_saveButton.transform.localPosition = new Vector3(3.4f, 1.7f, -2);
_saveButton.transform.localPosition = new Vector3(3.2f, 1.7f, -2);
// set the button text and alignment
var saveText = saveButton.buttonText;
@@ -55,36 +64,34 @@ internal static class GamePresetsTabPatches
saveText.transform.parent.localPosition.y,
saveText.transform.parent.localPosition.z);
// adjust the button size and colliders
foreach (var collider in saveButton.Colliders)
{
if (collider.TryCast<BoxCollider2D>() is { } col)
{
col.size = new Vector2(col.size.x / 2, col.size.y);
}
}
foreach (var rend in saveButton.GetComponentsInChildren<SpriteRenderer>(true))
{
rend.size = new Vector2(rend.size.x / 2, rend.size.y);
}
DivideSize(saveButton.gameObject, 2f);
// Create refresh button
var refreshButton = Object.Instantiate(saveButton, __instance.transform);
_refreshButton = refreshButton.gameObject;
_refreshButton.name = "RefreshButton";
_refreshButton.transform.localPosition = new Vector3(3.4f, 1.1f, -2);
_refreshButton.transform.localPosition = new Vector3(2.85f, 1.1f, -2);
var refreshText = refreshButton.buttonText;
refreshText.text = "Refresh";
var icon = new GameObject("Sprite");
icon.transform.SetParent(refreshButton.transform);
icon.transform.localPosition = new Vector3(-0.47f, -0.08f, -5f);
icon.transform.localScale = new Vector3(0.5f, 0.5f, 1);
icon.layer = refreshButton.gameObject.layer;
var openFolderButton = Object.Instantiate(saveButton, __instance.transform);
var iconSpriteRend = icon.AddComponent<SpriteRenderer>();
iconSpriteRend.sprite = MiraAssets.RefreshIcon.LoadAsset();
DivideSize(refreshButton.gameObject, 2f);
refreshButton.buttonText.gameObject.Destroy();
var openFolderButton = Object.Instantiate(refreshButton, __instance.transform);
_folderButton = openFolderButton.gameObject;
_folderButton.name = "OpenFolderButton";
_folderButton.transform.localPosition = new Vector3(3.4f, 0.5f, -2);
_folderButton.transform.localPosition = new Vector3(3.55f, 1.1f, -2);
var openFolderText = openFolderButton.buttonText;
openFolderText.text = "Presets Folder";
openFolderText.fontSizeMax = 4;
var folderRend = openFolderButton.transform.FindChild("Sprite").gameObject.GetComponent<SpriteRenderer>();
folderRend.sprite = MiraAssets.FolderIcon.LoadAsset();
folderRend.transform.localScale = new Vector3(0.4f, 0.4f, 1);
openFolderButton.OnClick = new Button.ButtonClickedEvent();
openFolderButton.OnClick.AddListener(
@@ -103,7 +110,6 @@ internal static class GamePresetsTabPatches
// add the click event to save the preset
saveButton.OnClick = new Button.ButtonClickedEvent();
var input = saveButton.gameObject.AddComponent<InputBox>();
saveButton.OnClick.AddListener(
(UnityAction)(() =>
{
@@ -112,31 +118,33 @@ internal static class GamePresetsTabPatches
return;
}
input.CreateDialog(
"Preset Name",
"Enter preset name...",
"Save Preset",
name =>
SavePresetPopup.CreatePopup(name =>
{
if (GameSettingMenuPatches.SelectedMod == null)
{
if (GameSettingMenuPatches.SelectedMod == null)
{
return;
}
return;
}
var presetFile = new ConfigFile(
Path.Join(
PresetManager.PresetDirectory,
GameSettingMenuPatches.SelectedMod.PluginId,
$"{name}.cfg"),
true);
foreach (var option in GameSettingMenuPatches.SelectedMod.InternalOptions.Where(
x => x.IncludeInPreset))
{
option.SaveToPreset(presetFile, true);
}
if (name == string.Empty)
{
return;
}
presetFile.Save();
});
var presetFile = new ConfigFile(
Path.Join(
PresetManager.PresetDirectory,
GameSettingMenuPatches.SelectedMod.PluginId,
$"{name}.cfg"),
true);
foreach (var option in GameSettingMenuPatches.SelectedMod.InternalOptions.Where(
x => x.IncludeInPreset))
{
option.SaveToPreset(presetFile, true);
}
presetFile.Save();
Refresh();
});
}));
// add the click event to refresh the presets
@@ -146,13 +154,15 @@ internal static class GamePresetsTabPatches
_saveButton.SetActive(false);
_refreshButton.SetActive(false);
_folderButton.SetActive(false);
_newDivider.SetActive(false);
_presetHolder = new GameObject("PresetHolder");
_presetHolder.transform.SetParent(__instance.transform, false);
_presetHolder.transform.localPosition = new Vector3(-1.7f, 1.7f, 0);
_presetHolder.transform.localScale = new Vector3(0.9f, 0.9f, 1);
_presetHolder.transform.localPosition = new Vector3(-1.9f, 1.7f, 0);
_arrange = _presetHolder.AddComponent<GridArrange>();
_arrange.Alignment = GridArrange.StartAlign.Right;
_arrange.CellSize = new Vector2(2.5f, -.55f);
_arrange.CellSize = new Vector2(2.15f, -.55f);
_arrange.MaxColumns = 2;
var watcher = new FileSystemWatcher
@@ -177,6 +187,22 @@ internal static class GamePresetsTabPatches
GameSettingMenu.Instance.ChangeTab(0, false); // refresh the tab
}
}
public static void DivideSize(GameObject obj, float amount)
{
foreach (var collider in obj.GetComponentsInChildren<Collider2D>(true))
{
if (collider.TryCast<BoxCollider2D>() is { } col)
{
col.size = new Vector2(col.size.x / amount, col.size.y);
}
}
foreach (var rend in obj.GetComponentsInChildren<SpriteRenderer>(true))
{
rend.size = new Vector2(rend.size.x / amount, rend.size.y);
}
}
[HarmonyPatch(typeof(GamePresetsTab), nameof(GamePresetsTab.OnEnable))]
public static class GamePresetsOnEnablePatch
@@ -188,6 +214,15 @@ internal static class GamePresetsTabPatches
__instance.StandardPresetButton.gameObject.SetActive(GameSettingMenuPatches.SelectedModIdx == 0);
__instance.SecondPresetButton.gameObject.SetActive(GameSettingMenuPatches.SelectedModIdx == 0);
if (GameSettingMenuPatches.SelectedModIdx != 0)
{
__instance.PresetDescriptionText.text = "Select or create an options preset for this mod";
}
else
{
__instance.SetSelectedText();
}
// Show the save and refresh buttons
if (_saveButton)
{
@@ -202,6 +237,11 @@ internal static class GamePresetsTabPatches
_folderButton.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
}
if (_newDivider)
{
_newDivider.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
}
var prefab = GameSettingMenu.Instance.GameSettingsButton;
foreach (var preset in MiraPluginManager.Instance.RegisteredPlugins.SelectMany(x => x.Presets))
@@ -213,6 +253,8 @@ internal static class GamePresetsTabPatches
tmp.DestroyImmediate();
}
button.buttonText.alignment = TextAlignmentOptions.Center;
button.OnClick = new Button.ButtonClickedEvent();
button.OnClick.AddListener(
(UnityAction)(() =>
+91
View File
@@ -0,0 +1,91 @@
using System;
using Il2CppInterop.Runtime.InteropTypes.Fields;
using MiraAPI.Modifiers.ModifierDisplay;
using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
using Reactor.Utilities.Attributes;
using Reactor.Utilities.Extensions;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[RegisterInIl2Cpp]
public class SavePresetPopup(nint ptr) : Minigame(ptr)
{
private PassiveButton saveButton;
private PassiveButton closeButton;
private TextMeshPro textBoxText;
private TextBoxTMP textBox;
private Action<string> onSave;
// Cleanup holder object
public void OnDestroy()
{
transform.parent.gameObject.Destroy();
}
public override void Close()
{
}
private void Awake()
{
var textboxHolder = transform.GetChild(1).GetChild(1);
saveButton = transform.FindChild("SaveButton").GetComponent<PassiveButton>();
closeButton = transform.FindChild("CloseButton").GetComponent<PassiveButton>();
textBox = textboxHolder.GetChild(0).GetComponent<TextBoxTMP>();
textBoxText = textBox.transform.GetChild(0).GetComponent<TextMeshPro>();
saveButton.OnClick = new Button.ButtonClickedEvent();
saveButton.OnClick.AddListener((UnityAction)(() =>
{
onSave.Invoke(textBoxText.text);
this.BaseClose();
}));
closeButton.OnClick = new Button.ButtonClickedEvent();
closeButton.OnClick.AddListener((UnityAction)(() =>
{
this.BaseClose();
}));
textBox.OnChange = new Button.ButtonClickedEvent();
textBox.OnChange.AddListener((UnityAction)(() =>
{
textBoxText.text = textBoxText.text.Replace(" ", string.Empty);
}));
textBox.GetComponent<PassiveButton>().OnClick.AddListener((UnityAction)(() =>
{
textBox.GiveFocus();
}));
foreach (var tmp in gameObject.GetComponentsInChildren<TextMeshPro>())
{
if (tmp.gameObject.transform.parent.name == "Textbox") continue;
var text = tmp.text;
tmp.text = $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF RadialMenu Material\">{text}</font>";
}
}
public static void CreatePopup(Action<string> saveAction)
{
// Because innerscuff doesnt account for Z value in Close animation
var holder = new GameObject("PopupHolder")
{
transform =
{
parent = Camera.main!.transform,
},
};
holder.transform.localPosition = new Vector3(0, -1f, -500);
var gameObject = Instantiate(MiraAssets.PresetSavePopup.LoadAsset(), holder.transform);
var popup = gameObject.GetComponent<SavePresetPopup>();
popup.onSave = saveAction;
popup.Begin(null);
}
}
Binary file not shown.
+6 -4
View File
@@ -21,14 +21,16 @@ public static class MiraAssets
0U,
SpriteMeshType.Tight,
new Vector4(20, 20, 20, 20));
public static readonly AssetBundle MiraAssetBundle = AssetBundleManager.Load("mirabundle");
public static readonly LoadableAsset<GameObject> ModifierDisplay = new LoadableBundleAsset<GameObject>("Modifiers", MiraAssetBundle);
public static readonly LoadableResourceAsset Empty = new("MiraAPI.Resources.Empty.png");
RoundedBox = new LoadableAssetWrapper<Sprite>(boxSprite);
}
internal static readonly AssetBundle MiraAssetBundle = AssetBundleManager.Load("mirabundle");
internal static readonly LoadableAsset<GameObject> ModifierDisplay = new LoadableBundleAsset<GameObject>("Modifiers", MiraAssetBundle);
internal static readonly LoadableAsset<GameObject> PresetSavePopup = new LoadableBundleAsset<GameObject>("PresetSavePopup", MiraAssetBundle);
internal static readonly LoadableAsset<Sprite> RefreshIcon = new LoadableBundleAsset<Sprite>("refresh", MiraAssetBundle);
internal static readonly LoadableAsset<Sprite> FolderIcon = new LoadableBundleAsset<Sprite>("freePlay_folderTaskRoom", MiraAssetBundle);
/// <summary>
/// Gets the accepted teal color used for various selections in the UI.
/// </summary>
+43
View File
@@ -41,6 +41,49 @@ public static class Extensions
BitConverter.GetBytes(count.Value).AddRangeToArray(BitConverter.GetBytes(chance.Value)));
}
/// <summary>
/// Used if you override Minigame.Close.
/// </summary>
/// <param name="self">The minigame.</param>
public static void BaseClose(this Minigame self)
{
bool isComplete;
if (self.amClosing == Minigame.CloseState.Closing)
{
UnityEngine.Object.Destroy(self.gameObject);
return;
}
if (self.CloseSound && Constants.ShouldPlaySfx())
{
SoundManager.Instance.PlaySound(self.CloseSound, false, 1f, null);
}
if (PlayerControl.LocalPlayer.Data.Role.TeamType == RoleTeamTypes.Crewmate)
{
GameManager.Instance.LogicMinigame.OnMinigameClose();
}
if (PlayerControl.LocalPlayer)
{
PlayerControl.HideCursorTemporarily();
}
self.amClosing = Minigame.CloseState.Closing;
self.logger.Info(string.Concat("Closing minigame ", self.GetType().Name));
IAnalyticsReporter analytics = DestroyableSingleton<DebugAnalytics>.Instance.Analytics;
NetworkedPlayerInfo data = PlayerControl.LocalPlayer.Data;
TaskTypes taskType = self.TaskType;
float realtimeSinceStartup = Time.realtimeSinceStartup - self.timeOpened;
PlayerTask myTask = self.MyTask;
if (myTask != null)
{
isComplete = myTask.IsComplete;
}
else
{
isComplete = false;
}
analytics.MinigameClosed(data, taskType, realtimeSinceStartup, isComplete);
self.StartCoroutine(self.CoDestroySelf());
}
/// <summary>
/// Gets a PlayerControl from their PlayerVoteArea in a meeting.
/// </summary>