GAMECHANGE

Full Version: How to add elements to the UI
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
This is a brief tutorial on how to add elements like a button to the UI. For ease of testing, it adds a button to the main menu, but this technique could be used elsewhere. 

It is assumed that you already know how to make a DLL mod for the game.

1. Create a DLL mod new project.
2. Add the following Harmony patch to your project. It will simply add a button with a popup to the main screen.
Code:
using System;
using System.Linq;
using HarmonyLib;
using Amplitude.Mercury.UI;
using Amplitude.UI.Interactables;
using Amplitude.UI.Renderers;
using UnityEngine;
using Amplitude.UI;
using Amplitude.Graphics.Text;



[HarmonyPatch(typeof(MainMenuScreen))]
    public class MainMenuScreen_Patch
    {

        [HarmonyPatch(nameof(Refresh))]
        [HarmonyPostfix]
        public static void Refresh(MainMenuScreen __instance)
        {
            //Grab an existing button reference that you want to clone - In this example, the quickstart button.
            var quickStartButton = AccessTools.FieldRefAccess<MainMenuScreen, UIButton>(
                __instance, "quickStartButton");
            //Get a reference to the parent container.
            var buttonContainer = quickStartButton.transform.parent.gameObject;
            //Check if your button was already added in a previous refresh.
            var myButton_go = buttonContainer.transform.Find(myButtonName)?.gameObject;
            if (myButton_go == null)
            {
                //Clone the base button (note, other buttons and controls will need different properties cloned).
                myButton_go = CloneButton(myButtonName, quickStartButton.gameObject);
                //Add a click handler to your button.
                myButton_go.GetComponent<UIButton>().LeftClick += Button_LeftClick;
                //Attach your button to the button container.
                myButton_go.transform.parent = buttonContainer.transform;
            }

        }

        //Example button name
        const string myButtonName = "My Button";

        //Example click handler that simply displays a popup.
        private static void Button_LeftClick(IUIButton obj)
        {
            var message = new MessageModalWindow.Message
            {
                Title = "Test",
                Description = "My new button works!",
                Buttons = new[]
                {
                    new MessageBoxButton.Data(MessageBox.Choice.Ok, null, isDismiss: true)
                }
            };
            MessageModalWindow.ShowMessage(message);
        }

        //Example UI element cloning method. It copies some known components and their properties over to the new button.
        private static GameObject CloneButton(string newName, GameObject originalButton_gameObject)
        {

            var myButton_go = new GameObject(newName) { };

            //Add a new button handler
            myButton_go.AddComponent<UIButton>();

            //Add other components and style them like the original button

            //Setup blur
            var originalBlur = originalButton_gameObject.GetComponent<BlurBackgroundWidget>();
            var blur = myButton_go.AddComponent<BlurBackgroundWidget>();
            blur.BottomLeftCornerRadius = originalBlur.BottomLeftCornerRadius;
            blur.BottomRightCornerRadius = originalBlur.BottomRightCornerRadius;
            blur.TopLeftCornerRadius = originalBlur.TopLeftCornerRadius;
            blur.TopRightCornerRadius = originalBlur.TopRightCornerRadius;
            blur.Color = originalBlur.Color;
            blur.Gradient = originalBlur.Gradient;
            blur.BlurGradient = originalBlur.Gradient;

            //Setup visuals
            var originalSquircle = originalButton_gameObject.GetComponent<SquircleBackgroundWidget>();
            var squircle = myButton_go.AddComponent<SquircleBackgroundWidget>();
            squircle.BackgroundColor = originalSquircle.BackgroundColor;
            squircle.OuterBorderColor = originalSquircle.OuterBorderColor;
            squircle.BorderColor = originalSquircle.BorderColor;
            squircle.BorderGradient = originalSquircle.BorderGradient;
            squircle.CornerRadius = originalSquircle.CornerRadius;

            squircle.BackgroundGradient = originalSquircle.BackgroundGradient;
            squircle.HighlightColor = originalSquircle.HighlightColor;
            squircle.HighlightGradient = originalSquircle.HighlightGradient;

            //Setup text
            var originalLabel = originalButton_gameObject.GetComponent<UILabel>();
            var label = myButton_go.AddComponent<UILabel>();
            label.Text = newName;
            label.Alignment = originalLabel.Alignment;
            label.FontFamily = originalLabel.FontFamily;
            label.Color = originalLabel.Color;
            label.FontSize = originalLabel.FontSize;
            label.ForceCaps = originalLabel.ForceCaps;
            label.Margins = originalLabel.Margins;
            label.InterLetterAdditionalSpacing = originalLabel.InterLetterAdditionalSpacing;
            label.InterLineAdditionalSpacing = originalLabel.InterLineAdditionalSpacing;
            label.InterParagraphAdditionalSpacing = originalLabel.InterParagraphAdditionalSpacing;
            label.UseAscent = originalLabel.UseAscent;
            label.WordWrap = originalLabel.WordWrap;

            //Setup tooltip
            var originalTooltip = originalButton_gameObject.GetComponent<UITooltip>();
            var tooltip = myButton_go.AddComponent<UITooltip>();
            tooltip.Message = "Tooltip works!";
            tooltip.AnchorMode = originalTooltip.AnchorMode;

            //Added automatically when other amplitude ui components went in. Adjust dimensions to match original.
            var originalTransform = originalButton_gameObject.GetComponent<UITransform>();
            var uitransform = myButton_go.GetComponent<UITransform>();
            uitransform.Width = originalTransform.Width;
            uitransform.Height = originalTransform.Height;

            return myButton_go;
        }

    }
3. This is just an example. You will most likely want to add your UI element to a different screen and make it do something different, but this is meant to be a starting point.

4. One way to see the structure of the existing UI in order to better prepare your code to modify it is to use UnityExplorer (generic mod for all Unity games with a BepInEx and alternative installation methods). It can be a little hard to navigate at first and will probably click parts of the game underneath it while trying to use it, but it can be very helpful to find the structure of the UI. Maybe there is a better way, but this way works.

https://github.com/sinai-dev/UnityExplorer


[Image: y4mHULzcUr2F4Vgt9HmFn4091QE0bF7YX-4tXIx9...pmode=none]

[Image: y4m5Ou3xKfoQl34Qu4IyK6oT_x_KR5g-EqC2TN3U...pmode=none]

UnityExplorer:
[Image: y4m3kJZowCYng06tjG9bl-kghoaBDWuFDVgeA0wz...pmode=none]