Closed mqueb closed 3 months ago
Also, please avoid force-pushing changes, as it can make it harder to review incremental updates and track the history of your work.
Also, please avoid force-pushing changes, as it can make it harder to review incremental updates and track the history of your work.
i i think u dont start review, i doing it. will avoid now
- The schema for
VisibleIf
should be an object rather than a string relying on matching. I'll be pushing a schema update soon for reference, don't worry about changing anything for now.
always doing like that for string matching. curious abous how u doing
- The schema for VisibleIf should be an object rather than a string relying on matching. I'll be pushing a schema update soon for reference, don't worry about changing anything for now.
there is now a modGUID lvl
- Currently, this implementation only works on initialization and does not update visibility while the user changes settings' values.
no, it's work on update: https://github.com/mqueb/BG3-MCM/blob/conditionnalRendering/Mod%20Configuration%20Menu/Mods/BG3MCM/ScriptExtender/Lua/Client/IMGUILayer.lua#L37 job done here
In the end, the ideal approach would likely require a refactor of UI updates, unfortunately, as it's the most problematic part of the code, but it would behave like this:
- When processing user input (e.g. starting on
IMGUILayer:SetClientStateValue
), iterateBlueprintSetting
instances;- Check
VisibleIf
array for each;- Toggle the corresponding widget's
Visibility
property according to whether conditions are met or not.
When processing user input (e.g. starting on IMGUILayer:SetClientStateValue
), > what i do
- iterate
BlueprintSetting
instances;- Check
VisibleIf
array for each;- Toggle the corresponding widget's
Visibility
property according to whether conditions are met or not.
I dont do that to avait parse all each time. so i build a reverse listing that is simple to use to trigger update visibility
all work since last push, you can test in on your own. my MCM_blueprints for test was.
i havent test on checkbox ... but it should work
{
"SchemaVersion": 1,
"ModName": "Mod Configuration Menu",
"Tabs": [
{
"TabId": "settings",
"TabName": "Settings",
"Handles": {
"NameHandle": "h91b72aadb42a441881a1a7c5de2f82e27agga"
},
"Sections": [
{
"SectionId": "general_settings",
"SectionName": "General settings",
"Settings": [
{
"Id": "toggle_mcm_keybinding",
"Name": "Toggle MCM window",
"Type": "keybinding",
"Default": {
"ScanCode": "INSERT",
"Modifier": ""
},
"Description": "Set the keybinding for toggling MCM's window.",
"Handles": {
"NameHandle": "hb2789893dcaf46fca8c40add9358e1f2ca93",
"DescriptionHandle": "h7728653cb8de46388719316b95f3a4110e7c"
}
},
{
"Id": "host-only_mode",
"Name": "Host-only mode",
"Type": "checkbox",
"Default": false,
"Description": "Only the host can change MCM settings in multiplayer games.",
"Handles": {
"DescriptionHandle": "h48d5ce6ebd8144649e72da14b64214a9b57f",
"NameHandle": "h119ee473f3f6444b887ed4e2a2fdb97b9fea"
}
},
{
"Id": "open_on_start",
"Name": "Open MCM window on start",
"Type": "checkbox",
"Default": true,
"Description": "Open the MCM menu when the game starts.",
"Handles": {
"NameHandle": "h76a89ee330464e30b1b9a01de85cbd0042a6",
"DescriptionHandle": "h0d8762f0ceb645608a64b684e581f7a72d67"
}
},
{
"Id": "auto_resize_window",
"Name": "Automatically resize window",
"Type": "checkbox",
"Default": true,
"Description": "Dynamically resize the MCM window to fit settings.",
"Handles": {
"NameHandle": "hc4abe0365af046e6abac1b4432abc3f7g4g3",
"DescriptionHandle": "h2c525b9161344f509bb4dcad8e49010bb9ce"
}
},
{
"Id": "dynamic_opacity",
"Name": "Dynamic opacity",
"Type": "checkbox",
"Default": true,
"Description": "Make the MCM window more transparent when interacting with game elements.",
"Handles": {
"NameHandle": "h9abda7ddcd564ba69433278a82884c535566",
"DescriptionHandle": "h204a4196566b44eb8070bc8b5d36edde1c1d"
}
}
],
"Handles": {
"NameHandle": "h6db631a023d0425ca0a62566ab1bec41797f"
}
},
{
"SectionId": "debug_settings",
"SectionName": "Debug settings",
"Settings": [
{
"Id": "debug_level",
"Name": "Debug level",
"Type": "slider_int",
"Default": 0,
"Description": "Used mainly to determine which messages to print.\nUseful for developers or general troubleshooting.",
"Options": {
"Min": 0,
"Max": 3
},
"Handles": {
"NameHandle": "hffc964abc9a74a928cb047607a7aeb124594",
"DescriptionHandle": "h1143226dbdd44d4aab3ce3010ffc589a073a"
}
},
{
"Id": "debug_levelfffdfd",
"Name": " test",
"Type": "slider_int",
"VisibleIf": "debug_level=3",
"Default": 0,
"Description": "Used mainly to determine which messages to print.\nUseful for developers or general troubleshooting.",
"Options": {
"Min": 0,
"Max": 3
},
"Handles": {
"NameHandle": "hffc964abc9a74a928cb047607a7aeb124594",
"DescriptionHandle": "h1143226dbdd44d4aab3ce3010ffc589a073a"
}
}
],
"Handles": {
"NameHandle": "h67357ed078184370901b1d572062b7ba26a5"
}
},
{
"SectionId": "debug_settingsg",
"SectionName": "teffst",
"VisibleIf": "debug_level=2",
"Settings": [
{
"Id": "debug_levfel3",
"Name": "Debug level",
"Type": "slider_int",
"Default": 0,
"Description": "Used mainly to determine which messages to print.\nUseful for developers or general troubleshooting.",
"Options": {
"Min": 0,
"Max": 3
},
"Handles": {
"NameHandle": "hffc964abc9a74a928cb047607a7aeb124594",
"DescriptionHandle": "h1143226dbdd44d4aab3ce3010ffc589a073a"
}
}
],
"Handles": {
"NameHandle": "h67357ed078184370901b1d572062b7ba26a5"
}
}
]
}
]
}
I missed that change on SetClientStateValue
in the diff, sorry. Busy day here. I'll only be able to push the new schema in a few hours.
It would use something like this:
// ... definitions ...
"VisibilityCondition": {
"type": "object",
"properties": {
"Expression": {
"type": "object",
"properties": {
"LogicalOperator": {
"type": "string",
"enum": ["and", "or"],
"description": "The logical operator to use between the conditions."
},
"Conditions": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"SettingId": {
"type": "string",
"description": "The ID of the setting that determines the visibility of this element."
},
"Operator": {
"type": "string",
"enum": ["==", "!=", ">", "<", ">=", "<="],
"description": "The operator to use for the comparison."
},
"ExpectedValue": {
"type": "string",
"description": "The expected value of the setting specified by SettingId for this element to be visible."
}
},
"required": [
"SettingId",
"Operator",
"ExpectedValue"
]
}
}
},
"required": [
"LogicalOperator",
"Conditions"
]
}
},
"required": [
"Expression"
],
"description": "A boolean expression that determines the visibility of this element."
}
This wouldn't require string matching and would also allow more complex conditions. Sections would have something like:
"VisibleIf": {
"$ref": "#/definitions/VisibilityCondition",
"description": "Conditions that determine the visibility of this section."
}
it will requie to have a level for operation . May be in a next step. equal cover lot of usage i guess
i'm not sure such a lv lis required for MCM, and with your model it's still lack (c1 OP1 C2 ) OP2 (c3 OP1 c4)
but i think MCM to have a single condition is enought.
the fun fact is that i wrote a rule motor at my job. that condition usage of param inside a json schema.
make necessary to have == != <= >= < > working No mangament for multiple condition
json schema you may want is that:
"definitions": {
"Conditions": {
"type": "object",
"description": "A single tab in the MCM menu.",
"properties": {
"Or": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/definitions/Conditions"
}
},
"And": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/definitions/Conditions"
}
},
"SettingId": {
"type": "string",
"description": "The ID of the setting that determines the visibility of this element."
},
"Operator": {
"type": "string",
"enum": ["==", "!=", ">", "<", ">=", "<="],
"description": "The operator to use for the comparison."
},
"ExpectedValue": {
"type": "string",
"description": "The expected value of the setting specified by SettingId for this element to be visible."
}
},
"additionalProperties": false,
"allOf": [
{
"if": {
"not": {
"properties": {
"And": {
"const": "undefined"
}
}
}
},
"then": {
"propertyNames": {
"pattern": "And"
}
}
},{
"if": {
"not": {
"properties": {
"Or": {
"const": "undefined"
}
}
}
},
"then": {
"propertyNames": {
"pattern": "Or"
}
}
},{
"if": {
"allOf": [
{
"properties": {
"Or": {
"const": "undefined"
}
}
},
{
"properties": {
"Or": {
"const": "undefined"
}
}
}
]
},
"then": {
"required": ["SettingId", "Operator", "ExpectedValue"]
}
}
]
},
"VisibleIf": {
"$ref": "#/definitions/Conditions"
},
so you can write:
"VisibleIf": {
"Or": [
{
"And": [
{
"ExpectedValue": "v1",
"Operator": "!=",
"SettingId": "set1"
},
{
"ExpectedValue": "3",
"Operator": ">",
"SettingId": "set2"
}
]
},
{
"And": [
{
"ExpectedValue": "ff",
"Operator": "!=",
"SettingId": "ff"
},
{
"ExpectedValue": "ff",
"Operator": "!=",
"SettingId": "ff"
}
]
},
{
"ExpectedValue": "ff",
"Operator": "!=",
"SettingId": "ff"
}
]
}
But is it required for MCM ...
i think, a simple way is to manage both over time, the simple string is already done and easy to use for simple condition the "complex" object. could be done later if required. schema can manage both case and code also detect string or object and process as needed
Thinking about it. Will do it soon. Its vert few modification I'm busy today but will bé done next day i think
If u really want 3 param over simple string, i Can Do it. But i think its boilderplate. Thé only usefull thing is ans/or
Let me know before i start
Please don't do anything yet, let me at least push the schema. The schema I proposed leaves out complex conditions by design, especially since authors can create complex patterns already by simply depending on elements that already have conditions. Wanting to have more than simple conditions is probably bad design, so we don't need to include that, but having most operators is something that can be useful.
I'll refactor some stuff and merge later on
What i dont like in your schéma IS that a simple expression require A boilderplate condition level.
I Can understand 3 param vs a string. Ecen if i prefer a single string as end user usage. its simple to build object as that are parsed
Sry for all error in text. Writing from my french phone...
I see your point, but I think this provides the right amount of flexibility. This is just one extra level than what a minimal solution with objects would be. Writing an entry for this in the blueprint JSON with the schema is still very easy as it will point out the structure for you (in VSCode for example) I can read French just fine, you can use it if you want.
any ETA of merge ?
I had some problems with subsequent changes but I plan to get it sorted out today or tomorrow
Thank you for your contribution again. There are a few areas that need a more refined approach:
VisibleIf
should be an object rather than a string relying on matching. I'll be pushing a schema update soon for reference, don't worry about changing anything for now.visibility_trigger
should be granular down to the mod level. Different mods should be able to use identical IDs for their settings without conflict.In the end, the ideal approach would likely require a refactor of UI updates, unfortunately, as it's the most problematic part of the code, but it would behave like this:
IMGUILayer:SetClientStateValue
), iterateBlueprintSetting
instances;VisibleIf
array for each;Visibility
property according to whether conditions are met or not.