Code Monkey home page Code Monkey logo

mhr-ingame-modmenu-api's Introduction

ModOptionsMenu

Example

Look at the ModUI_ExampleTest.lua file for a more detailed example to get your feet wet.

local modUI = require("ModOptionsMenu.ModMenuApi");

local someSettingValue = false;
local optionIdx = 1;

local options = {"Option1", "Option2"};

local name = "Example Mod";
local description = "It's just a test mod.";
local modObj = modUI.OnMenu(name, description, function()
	
	local changed;
	
	modUI.Header("Header");
	
	changed, someSettingValue = modUI.CheckBox("CheckBox", someSettingValue, "Some optional toolip style message here.");
	
	changed, optionIdx = modUI.Options("Options", optionIdx, options);

	--and so much more
	
end)

API

local ModUI = require("ModOptionsMenu.ModMenuApi")

Do something like this to import the api into your script. It can be called anything you'd like.


ModUI.OnMenu(name, description, uiCallback)

Register your mod to the options menu.

Params:

  • name name of your mod that will be displayed in the menu
  • description will be displayed in the system message box to describe your mod in the mod list
  • uiCallback called every frame while your mod's menu is open. put your mod ui code in here

Returns: an object containing the mod's data

Notes:

Technically you can register multiple mods through this but I would advise against it.
Make sure to only call this once for the menu you want to add and NOT inside of some kind of update function.

ModUI.Header(text)

Displays a non-interactable header message to divide your ui sections.

Notes:

Displaying two headers right next to each other allows one to be selectable with a gamepad.

ModUI.FloatSlider(label, curValue, min, max, toolTip, isImmediateUpdate)

Draws a float slider.

Params:

  • label displayed name of this setting
  • curValue the current/starting value that will be modified by the slider
  • min minimum value the slider can go to
  • max maximum value the slider can go to
  • (optional) toolTip message displayed in the system message box while hovering this element
  • (optional) isImmediateUpdateif true, the value will update immediately rather than waiting for the user to accept the change

Returns: (tuple of) wasChanged, newValue

Notes:

Keep in mind this value only has precision to the nearest hundreth due to the game's limitations.

ModUI.Slider(label, curValue, min, max, toolTip, isImmediateUpdate)

Draws an integer slider.

Params:

  • label displayed name of this setting
  • curValue the current/starting value that will be modified by the slider
  • min minimum value the slider can go to
  • max maximum value the slider can go to
  • (optional) toolTip message displayed in the system message box while hovering this element
  • (optional) isImmediateUpdate if true, the value will update immediately rather than waiting for the user to accept the change

Returns: (tuple of) wasChanged, newValue


ModUI.Options(label, curValue, optionNames, optionMessages, toolTip, isImmediateUpdate)

Draws a cycle-able set of options for the user to choose between.

Params:

  • label displayed name of this setting
  • curValue the current/starting index
  • optionNames a lua table of the displayed names for each selectable option e.g. {"Option1", "Option2"}
  • (optional) optionMessages a lua table of tooltips to go along with each option
  • (optional) toolTip message displayed in the system message box while hovering this element
  • (optional) isImmediateUpdate if true, the value will update immediately rather than waiting for the user to accept the change

Returns: (tuple of) wasChanged, newIndex

Notes:

lua is NOT zero indexed, and neither is the input/output index of this function.
The tables you give should be declared as variables OUTSIDE the scope of your UI callback.
This is to avoid creating a new table every frame causing the UI to redraw every frame which breaks things.

ModUI.CheckBox(label, curValue, toolTip)

An easily clickable checkbox useful for on/off values where the user doesn't have to manually select on or off

Params:

  • label displayed name of this setting
  • curValue the current/starting value
  • (optional) toolTip message displayed in the system message box while hovering this element

Returns: (tuple of) wasChanged, onOffValue


ModUI.Toggle(label, curValue, toolTip, (optional)togNames[2], (optional)togMsgs[2], isImmediateUpdate)

Basically a wrapper around ModUI.Options that only takes two options and returns the result as a boolean instead of an index

Params:

  • label displayed name of this setting
  • curValue the current/starting index
  • (optional) toolTip message displayed in the system message box while hovering this element
  • (optional) togNames[2] a lua table of the displayed names for each selectable option e.g. {"Option1", "Option2"}
  • (optional) togMsgs[2] a lua table of tooltips to go along with each option
  • (optional) isImmediateUpdate if true, the value will update immediately rather than waiting for the user to accept the change

Returns: (tuple of) wasChanged, onOffValue

Notes:

The tables you give should be declared as variables OUTSIDE the scope of your UI callback.
This is to avoid creating a new table every frame causing the UI to redraw every frame which breaks things.

ModUI.Button(label, prompt, isHighlight, toolTip)

Draws clickable element in the GUI

Params:

  • label displayed name of this setting
  • (optional) prompt additional text to the right of the button
  • (optional) isHighlight if true, the label will be highlighted in yellow to make it more apparent it's a button
  • (optional) toolTip message displayed in the system message box while hovering this element

Returns: (boolean) wasClicked


ModUI.Label(label, displayValue, toolTip)

Just draws some text

Params:

  • label displayed name of this setting
  • (optional) displayValue additional text to the right of the label, useful to display values and such
  • (optional) toolTip message displayed in the system message box while hovering this element

ModUI.PromptYN(promptMessage, callback(result))

Displays a system message prompt with an option to select yes or no.

Params:

  • promptMessage text displayed within the prompt
  • callback(result) function called when the user has selected their choice

Notes:

The result in the callback will be true if the user selected `Yes`, and false if `No`.

ModUI.PromptMsg(promptMessage, callback)

Displays a system message prompt.

Params:

  • promptMessage text displayed within the prompt
  • callback function called when the user has closed the prompt

Notes:

The normal UI is not updated while the prompt is open.


Rich Text:

The game has its own sort of 'rich text' functionality, currently I only really know how to use colors.
I think there's a system for displaying button icons through text but you'd have to figure that out yourself.

Built-in Colors:

  • YEL
  • RED
  • GRAY
  • More colors can be added (see AddTextColor below)

ModUI.AddTextColor(colName, colHexStr)

Params:

  • colName name of the color you wish to add, should be distinct
  • colHexStr a string representing the color's hex code WITHOUT '#' symbol e.g. "9F2B68"

Notes:

Call this BEFORE your UI code, otherwise will add the color every frame which would be BAD.
Keep in mind these are shared across mods so use descriptive names.
Use the name like the built in color codes e.g. if you added a color called 'purple' use `<COL purple>text</COL>`


Layout Functions:

  • ModUI.IncreaseIndent()
  • ModUI.DecreaseIndent()
  • ModUI.SetIndent(indentLevel)

Notes:

You can have fairly dynamic UI layouts, but keep in mind every time something changes the entire UI needs to be rebuilt. Also the practical limits of how many elements you can have in one menu is untested currently.


Rare Functions:

  • ModUI.Repaint()

      Forces game to re-show the data and show changes.
      You probably don't need to use this anymore as almost any change should be automatically detected.
    
  • ModUI.ForceDeselect()

      Forces game to deselect current option.
    
  • modObj.regenOptions

      Can be set to true to force the API to regenerate the UI layout, but you probably dont need this.
    

mhr-ingame-modmenu-api's People

Contributors

bolt-scripts avatar raff-run avatar hookedbehemoth avatar

Stargazers

◢ 徇 ◤ avatar optimal prime avatar  avatar  avatar Jhosevic Castañeda avatar Jet_DC avatar Fahrayheit avatar GreenComfyTea avatar ExE Boss avatar Rémi Lavergne avatar dtlnor avatar  avatar  avatar

Watchers

 avatar  avatar

mhr-ingame-modmenu-api's Issues

reliance on plugin?

I'm trying to figure out why this requires a native plugin before installing it. I'd like to avoid running precompiled dll's if it's not strictly necessary.
Could "PtrToGuidTest" not be expressed in lua? It seems you're able to set the value from lua. Is it too slow to do it like that?

[Feature Suggestion] Fit text in tooltips

Hey! When I was implementing my mod options with your API, I noticed that the text will resize and become unreadable if too lengthy.
This means that it needs carefully applied newlines, and also that the newlines need to be at different places if you're also using the usual REF UI since they have different default window sizes.

So I made a lua util function that automatically finds the best way to fit a text in a tooltip and caches the result, and wanted to share it with you if you in case want to incorporate it into the mod's API:

local minLineLength = 40
local lineBreakPattern = "(" .. ('.'):rep(minLineLength) .. ('.?'):rep(16) .. ") "  -- in regex: /(.{40,56}) /
local conversionCache = {} -- the UI will slow down without a cache

local function wrapText(text)
    text = text:gsub("\n", " "):gsub("  ", " ") -- this is here just so authors can feed their REF ui label strings straight into the api instead of having a version for each
    text = text:gsub(lineBreakPattern, "%1\n")
    return text
end

local function fitInBox(text)
    local newText = conversionCache[text]
    if newText ~= nil then return newText end

    newText = wrapText(text)
    conversionCache[text] = newText

    return newText
end

local function fitOptionsInBox(textTable)
    local newTextTable = conversionCache[textTable]
    if newTextTable ~= nil then return newTextTable end
    newTextTable = {}

    for _, text in ipairs(textTable) do
        table.insert(newTextTable, wrapText(text)) 
    end

    conversionCache[textTable] = newTextTable

    return newTextTable
end

Here are some example outputs:
image
image
image
image

Of course, if the string is long enough, it will overflow downwards, but I think that's better than seeing this and then having to place line breaks yourself:
image

Occasional exception when clicking a button also changes its prompt.

image

When a user clicks/hits the "Gamepad Trigger" button, the prompt will become "Press trigger" and the mod would try to get the next button the user presses and write it into the prompt field. However, occasionally this would throw the exception in the image and stop the prompt from updating. The other parts (getting the next button and setting up the trigger button) still works.

Code: https://github.com/greydust/mhrise-falbg/blob/f8bcf3d717d422258a31879f10d9925e665a5132/src/reframework/autorun/falbg/native_ui.lua#L19

[Feature Suggestion] Custom Colors

As you know there are 3 colors available: YEL, RED and GRAY for <COL> tag. The singleton that handles is snow.gui.MessageManager.
There are fields are might be interested in:

  1. snow.gui.MessageManager -> ColTagUserData -> DataList contains colors and their color hex codes (as strings). You can probably populate it with your own colors.
  2. snow.gui.MessageManager -> AdditionalMessageTagList contains tags and each tag has a function that does the magic associated with it. So theoretically you can make your own tags, thou I imagine it being pretty hard to do.
    • COL
    • COLS
    • ITEM
    • PL
    • EM
    • PLSKILL
    • LSNR
    • OPT
    • BSL
    • MR
  3. snow.gui.MessageManager -> AdditionalMessageTagListSTM
    • STM
Screenshot

image

[Bug] v1.4 - Button turns into other elements

Problem:
When there is a button that shows/hides other elements, it sometimes turns into something else, like Options.

  • Going back to Mod List and then opening the mod menu with that button adds yellow Open Menu to it.
  • Sometimes when toggling options that where shown by pressing the button, all toggles get hidden again.

Video

PS. The problem with incorrect 'changed' value is fixed btw.

[Bug] <COL> tag in a description affects autowrapping and vice versa

Describe the bug
Currently autowrapping does not take into account <COL> tag. The tag affects string length, making WrapText(text) function to insert \n in different place in comparison to when there is no tag.

The problem goes further, and there is a chance that the position at which the new line symbol is inserted will be inside the color name or the tag, which makes the color to behave incorrectly.

Expected behavior
<COL> should be filtered out and autowrapping on text with <COL> should behave the same as on text without <COL>.

Screenshots

"Adjust Width Multiplier for Orange Damage Numbers."

image

"Adjust Width Multiplier for <COL ORANGE_GCT>Orange</COL> Damage Numbers."

image

"Adjust Width Multiplier for <\nCOL ORANGE_GCT>Orange</COL> Damage Numbers."

image

"Adjust Width Multiplier for <CO\nL ORANGE_GCT>Orange</COL> Damage Numbers."

image

"Adjust Width Multiplier for <COL\n ORANGE_GCT>Orange</COL> Damage Numbers."

image

"Adjust Width Multiplier for <COL \nORANGE_GCT>Orange</COL> Damage Numbers."

image

"Adjust Width Multiplier for <COL ORANGE_\nGCT>Orange</COL> Damage Numbers."

image

"Adjust Width Multiplier for <COL ORANGE_GCT\n>Orange</COL> Damage Numbers."

image

"Adjust Width Multiplier for <COL ORANGE_GCT>Orange<\n/COL> Damage Numbers."

image

"Adjust Width Multiplier for <COL ORANGE_GCT>Orange</\nCOL> Damage Numbers."

image

"Adjust Width Multiplier for <COL ORANGE_GCT>Orange</C\nOL> Damage Numbers."

image

"Adjust Width Multiplier for <COL ORANGE_GCT>Orange</COL\n> Damage Numbers."

image

Getting error

Cannot set (new_index) into this object, no defined stack traceback. C: in metamethod "newindex"

[Optimization] Cache methods and singletons

  1. In ModOptionsMenu/ModMenuApi.lua you are calling a couple of methods of GuiManager by passing method name as a string inside PromptMsg and PromptYN functions:
gui_mgr:call("setOpenInfo(System.String, snow.gui.GuiCommonInfoBase.Type, snow.gui.SnowGuiCommonUtility.Segment, System.Boolean, System.Boolean)", promptMessage, 0x1, 0x32, false, false)

In this case it performs a hashmap lookup. You can cache the method.

local setOpenInfoMethod = sdk.find_type_definition("snow.gui.GuiManager"):get_method("setOpenInfo(System.String, snow.gui.GuiCommonInfoBase.Type, snow.gui.SnowGuiCommonUtility.Segment, System.Boolean, System.Boolean)")
...
setOpenInfoMethod:call(gui_mgr, promptMessage, 0x1, 0x32, false, false))
  1. In the same functions you call methods with custom indexers, but I don't know if it does a hashmap lookup or not. Probably not.
gui_mgr:updateInfoWindow()
  1. In the same places for getting GuiManager you call sdk.get_managed_singleton. Since this is a singleton you can cache it the first time you need it, or even maybe during initialization, and the just use it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.