From 986ac43a688c1b2c029df903371c9552b70941d9 Mon Sep 17 00:00:00 2001 From: jonpas Date: Thu, 18 Aug 2016 19:07:05 +0200 Subject: [PATCH] Cache config UI (#4234) * Cache config UI * Use configClasses to prevent reading entries in base class * Fix header not containing return value * One more count * More lazy eval --- addons/ui/ACE_UI.hpp | 4 -- addons/ui/XEH_PREP.hpp | 2 +- addons/ui/XEH_clientInit.sqf | 20 +++++--- addons/ui/XEH_preInit.sqf | 1 - addons/ui/functions/fnc_compileConfigUI.sqf | 45 ++++++++++++++++++ addons/ui/functions/fnc_findSetElement.sqf | 25 ---------- .../ui/functions/fnc_setAdvancedElement.sqf | 34 +++++++------- .../ui/functions/fnc_setElementVisibility.sqf | 47 +++++++++---------- addons/ui/script_component.hpp | 5 ++ 9 files changed, 104 insertions(+), 79 deletions(-) create mode 100644 addons/ui/functions/fnc_compileConfigUI.sqf delete mode 100644 addons/ui/functions/fnc_findSetElement.sqf diff --git a/addons/ui/ACE_UI.hpp b/addons/ui/ACE_UI.hpp index e59dd50385..7bf395da57 100644 --- a/addons/ui/ACE_UI.hpp +++ b/addons/ui/ACE_UI.hpp @@ -1,7 +1,3 @@ -#define ANYWHERE 0 -#define GROUND_ONLY 1 -#define VEHICLE_ONLY 2 - class ACE_UI { class weaponName { idd = 300; diff --git a/addons/ui/XEH_PREP.hpp b/addons/ui/XEH_PREP.hpp index 5c01ea1c3e..a927a8ad2d 100644 --- a/addons/ui/XEH_PREP.hpp +++ b/addons/ui/XEH_PREP.hpp @@ -1,4 +1,4 @@ -PREP(findSetElement); +PREP(compileConfigUI); PREP(moduleInit); PREP(setAdvancedElement); PREP(setElements); diff --git a/addons/ui/XEH_clientInit.sqf b/addons/ui/XEH_clientInit.sqf index 450ea0904f..5cfa322b0d 100644 --- a/addons/ui/XEH_clientInit.sqf +++ b/addons/ui/XEH_clientInit.sqf @@ -3,6 +3,14 @@ // Exit on Headless if (!hasInterface) exitWith {}; +// Compile and cache config UI +GVAR(configCache) = call CBA_fnc_createNamespace; +call FUNC(compileConfigUI); + +// Scripted API namespace +GVAR(elementsSet) = call CBA_fnc_createNamespace; + +// Attach all event handlers where UI has to be updated ["ace_settingsInitialized", { // Initial settings [false] call FUNC(setElements); @@ -13,9 +21,8 @@ if (!hasInterface) exitWith {}; // Defaults must be set in this EH to make sure controls are activated and advanced settings can be modified private _force = [true, false] select (GVAR(allowSelectiveUI)); { - private _name = configName _x; - [_name, missionNamespace getVariable (format [QGVAR(%1), _name]), false, _force] call FUNC(setAdvancedElement); - } forEach ("true" configClasses (configFile >> "ACE_UI")); + [_x, missionNamespace getVariable (format [QGVAR(%1), _x]), false, _force] call FUNC(setAdvancedElement); + } forEach (allVariables GVAR(configCache)); // Execute local event for when it's safe to modify UI through this API // infoDisplayChanged can execute multiple times, make sure it only happens once @@ -32,10 +39,11 @@ if (!hasInterface) exitWith {}; if (_name in ELEMENTS_BASIC) then { [true] call FUNC(setElements); } else { - if (isClass (configFile >> "ACE_UI" >> _name select [7])) then { - [_name select [7], missionNamespace getVariable _name, true] call FUNC(setAdvancedElement); + private _nameNoPrefix = toLower (_name select [7]); + private _cachedElement = GVAR(configCache) getVariable _nameNoPrefix; + if (!isNil "_cachedElement") then { + [_nameNoPrefix, missionNamespace getVariable _name, true] call FUNC(setAdvancedElement); }; }; }] call CBA_fnc_addEventHandler; - }] call CBA_fnc_addEventHandler; diff --git a/addons/ui/XEH_preInit.sqf b/addons/ui/XEH_preInit.sqf index 8646227653..3dee364f02 100644 --- a/addons/ui/XEH_preInit.sqf +++ b/addons/ui/XEH_preInit.sqf @@ -4,7 +4,6 @@ ADDON = false; #include "XEH_PREP.hpp" -GVAR(elementsSet) = []; GVAR(interfaceInitialized) = false; ADDON = true; diff --git a/addons/ui/functions/fnc_compileConfigUI.sqf b/addons/ui/functions/fnc_compileConfigUI.sqf new file mode 100644 index 0000000000..8bda2c3ce4 --- /dev/null +++ b/addons/ui/functions/fnc_compileConfigUI.sqf @@ -0,0 +1,45 @@ +/* + * Author: Jonpas + * Compiles and caches UI from ACE_UI config. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_ui_fnc_compileConfigUI + * + * Public: No + */ +#include "script_component.hpp" + +{ + private _failure = false; + private _class = toLower (configName _x); + + private _idd = getNumber (_x >> "idd"); + + private _elements = getArray (_x >> "elements"); + if (_elements isEqualTo []) then { + ACE_LOGERROR_1("Failed compiling ACE_UI for Element: %1 - missing elements",_class); + _failure = true; + }; + + private _location = getNumber (_x >> "location"); + if !(_location in [ANYWHERE, GROUND_ONLY, VEHICLE_ONLY]) then { + ACE_LOGERROR_2("Failed compiling ACE_UI for Element: %1 - missing or invalid location %2",_class,_location); + _failure = true; + }; + + if (!_failure) then { + private _conditions = []; + { + _conditions pushBack [compile (getText _x), configName _x]; + TRACE_1("Caching Condition",_x); + } forEach (configProperties [_x >> "conditions"]); + + GVAR(configCache) setVariable [_class, [_idd, _elements, _location, _conditions]]; + }; +} forEach ("true" configClasses (configFile >> "ACE_UI")); diff --git a/addons/ui/functions/fnc_findSetElement.sqf b/addons/ui/functions/fnc_findSetElement.sqf deleted file mode 100644 index 939d371c04..0000000000 --- a/addons/ui/functions/fnc_findSetElement.sqf +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Author: Jonpas - * Finds set element by element name and returns index, source of the set element and state. - * - * Arguments: - * 0: Element Name - * - * Return Value: - * None - * - * Example: - * ["ace_ui_ammoCount"] call ace_ui_fnc_findSetElement - * - * Public: No - */ -#include "script_component.hpp" - -params ["_element"]; - -{ - if (_element in _x) exitWith { - [_forEachIndex, _x select 0, _x select 2] - }; - [-1, "", false] -} forEach GVAR(elementsSet); diff --git a/addons/ui/functions/fnc_setAdvancedElement.sqf b/addons/ui/functions/fnc_setAdvancedElement.sqf index f068c48ed0..0e46badd09 100644 --- a/addons/ui/functions/fnc_setAdvancedElement.sqf +++ b/addons/ui/functions/fnc_setAdvancedElement.sqf @@ -12,7 +12,7 @@ * Successfully Set * * Example: - * ["ace_ui_ammoCount", true, false] call ace_ui_fnc_setAdvancedElement + * _successfullySet = ["ammoCount", true, false] call ace_ui_fnc_setAdvancedElement * * Public: No */ @@ -20,43 +20,40 @@ params ["_element", "_show", ["_showHint", false, [true]], ["_force", false, [true]] ]; +private _cachedElement = GVAR(configCache) getVariable _element; +if (isNil "_cachedElement") exitWith {}; + if (!_force && {!GVAR(allowSelectiveUI)}) exitWith { [LSTRING(Disallowed), 2] call EFUNC(common,displayTextStructured); false }; -private _config = configFile >> "ACE_UI" >> _element; +_cachedElement params ["_idd", "_elements", "_location", "_conditions"]; // Exit if main vehicle type condition not fitting -private _location = getNumber (_config >> "location"); // (0-both, 1-ground, 2-vehicle) private _canUseWeapon = ACE_player call CBA_fnc_canUseWeapon; -if ((_canUseWeapon && _location == 2) || (!_canUseWeapon && _location == 1)) exitWith {false}; - -private _idd = getNumber (_config >> "idd"); -private _elements = getArray (_config >> "elements"); +if ((_canUseWeapon && {_location == 2}) || {!_canUseWeapon && {_location == 1}}) exitWith {false}; // Get setting from config API { - private _condition = call compile (getText _x); - if !(_condition) exitWith { + if (!call (_x select 0)) exitWith { // Display and print info which component forced the element except for default vehicle check if (_showHint) then { [LSTRING(Disabled), 2] call EFUNC(common,displayTextStructured); - ACE_LOGINFO_2("Attempted modification of a forced User Interface element '%1' by '%2'",_element,configName _x); + ACE_LOGINFO_2("Attempted modification of a forced User Interface element '%1' by '%2'.",_element,_x select 1); }; _show = false; }; -} forEach (configProperties [_config >> "conditions"]); +} count _conditions; // Get setting from scripted API if (!_force) then { - private _setElement = [_element] call FUNC(findSetElement); - _setElement params ["_indexSet", "_sourceSet", "_showSet"]; - - if (_indexSet != -1) then { + private _setElement = GVAR(elementsSet) getVariable _element; + if (!isNil "_setElement") then { + _setElement params ["_sourceSet", "_showSet"]; if (_showHint) then { [LSTRING(Disabled), 2] call EFUNC(common,displayTextStructured); - ACE_LOGINFO_2("Attempted modification of a forced User Interface element '%1' by '%2'",_element,_sourceSet); + ACE_LOGINFO_2("Attempted modification of a forced User Interface element '%1' by '%2'.",_element,_sourceSet); }; _show = _showSet; }; @@ -79,7 +76,8 @@ private _success = false; _success = true; }; - } forEach (uiNamespace getVariable "IGUI_displays"); -} forEach _elements; + } count (uiNamespace getVariable "IGUI_displays"); + nil +} count _elements; _success diff --git a/addons/ui/functions/fnc_setElementVisibility.sqf b/addons/ui/functions/fnc_setElementVisibility.sqf index f8ed74c4ad..efc73a681e 100644 --- a/addons/ui/functions/fnc_setElementVisibility.sqf +++ b/addons/ui/functions/fnc_setElementVisibility.sqf @@ -9,10 +9,10 @@ * 3: Show/Hide Element (default: false) * * Return Value: - * None + * Successfully Modified * * Example: - * ["ace_reload", true, "ace_ui_ammoCount", false] call ace_ui_fnc_setElementVisibility + * _successfullyModified = ["ace_reload", true, "ammoCount", false] call ace_ui_fnc_setElementVisibility * * Public: Yes */ @@ -25,45 +25,44 @@ params [ ["_show", false, [true]] ]; -// Verify element is bound -if (!isClass (configFile >> "ACE_UI" >> _element)) exitWith { - ACE_LOGWARNING_1("Element '%1' does not exist",_element); -}; - if (_source == "" || {_element == ""}) exitWith { ACE_LOGWARNING("Source or Element may not be empty strings!"); }; +_element = toLower _element; + +// Verify element is bound +private _cachedElement = GVAR(configCache) getVariable _element; +if (isNil "_cachedElement") exitWith { + ACE_LOGWARNING_2("Element '%1' does not exist - modification by '%2' failed.",_element,_source); +}; + +private _setElement = GVAR(elementsSet) getVariable _element; private _return = false; -private _setElement = [_element] call FUNC(findSetElement); -_setElement params ["_indexSet", "_sourceSet"]; - -if (_set) then { - // Exit if element has been set from another component, print warning if after interface initialization - if (_indexSet != -1) exitWith { - if (GVAR(interfaceInitialized)) then { - ACE_LOGWARNING_2("Element '%1' already set by %2",_element,_sourceSet); - }; - }; - - TRACE_4("Setting element",_source,_element,_show,GVAR(elementsSet)); +if (isNil "_setElement") then { + TRACE_3("Setting element",_source,_element,_show); private _success = [_element, _show, false, true] call FUNC(setAdvancedElement); if (_success) then { - GVAR(elementsSet) pushBack [_source, _element, _show]; + GVAR(elementsSet) setVariable [_element, [_source, _show]]; _return = true; }; } else { - if (_indexSet != -1) then { - TRACE_4("Unsetting element",_sourceSet,_element,_show,GVAR(elementsSet)); + _setElement params ["_sourceSet"]; - GVAR(elementsSet) deleteAt _indexSet; + if (_set) then { + if (GVAR(interfaceInitialized)) then { + ACE_LOGWARNING_3("Element '%1' already set by '%2' - modification by '%3' failed.",_element,_sourceSet,_source); + }; + } else { + TRACE_3("Unsetting element",_sourceSet,_element,_show); + GVAR(elementsSet) setVariable [_element, nil]; [_element, _show, false, true] call FUNC(setAdvancedElement); _return = true; }; }; -TRACE_2("Visibility set",_return,GVAR(elementsSet)); +TRACE_2("Visibility set",_element,_return); _return diff --git a/addons/ui/script_component.hpp b/addons/ui/script_component.hpp index 44ca977563..3666ad36c3 100644 --- a/addons/ui/script_component.hpp +++ b/addons/ui/script_component.hpp @@ -21,6 +21,11 @@ // Basic Elements #define ELEMENTS_BASIC [QGVAR(soldierVehicleWeaponInfo), QGVAR(vehicleRadar), QGVAR(vehicleCompass), QGVAR(commandMenu), QGVAR(groupBar)] +// Locations +#define ANYWHERE 0 +#define GROUND_ONLY 1 +#define VEHICLE_ONLY 2 + /* RscUnitInfo = 300 --------------------