From 0b34a13960f6866e35f12ae9c538c5214c69a549 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 15 Jul 2023 11:34:56 +0200 Subject: [PATCH 01/26] Update PBO checking --- addons/common/functions/fnc_checkFiles.sqf | 75 +++--- addons/common/functions/fnc_checkPBOs.sqf | 72 +++-- addons/common/functions/fnc_errorMessage.sqf | 33 ++- addons/common/scripts/checkVersionNumber.sqf | 268 +++++++++++-------- 4 files changed, 261 insertions(+), 187 deletions(-) diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index 463ee20f0b8..601c4635306 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -16,12 +16,13 @@ */ /////////////// -// check addons +// Check addons /////////////// -private _version = getText (configFile >> "CfgPatches" >> "ace_main" >> "versionStr"); +private _cfgPatches = configFile >> "CfgPatches"; +private _version = getText (_cfgPatches >> "ace_main" >> "versionStr"); -//CBA Versioning check - close main display if using incompatible version -private _cbaVersionAr = getArray (configFile >> "CfgPatches" >> "cba_main" >> "versionAr"); +// CBA Versioning check - close main display if using incompatible version +private _cbaVersionAr = getArray (_cfgPatches >> "cba_main" >> "versionAr"); private _cbaRequiredAr = getArray (configFile >> "CfgSettings" >> "CBA" >> "Versioning" >> "ACE" >> "dependencies" >> "CBA") select 1; private _cbaVersionStr = _cbaVersionAr joinString "."; @@ -29,34 +30,37 @@ private _cbaRequiredStr = _cbaRequiredAr joinString "."; INFO_3("ACE is version %1 - CBA is version %2 (min required %3)",_version,_cbaVersionStr,_cbaRequiredStr); -if ([_cbaRequiredAr, _cbaVersionAr] call cba_versioning_fnc_version_compare) then { +if ([_cbaRequiredAr, _cbaVersionAr] call CBA_versioning_fnc_version_compare) then { private _errorMsg = format ["CBA version %1 is outdated (required %2)", _cbaVersionStr, _cbaRequiredStr]; ERROR(_errorMsg); + if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); }; }; -//private _addons = activatedAddons; // broken with High-Command module, see #2134 -private _addons = (cba_common_addons select {(_x select [0,4]) == "ace_"}) apply {toLower _x}; +//private _addons = activatedAddons; // Broken with High-Command module, see #2134 +private _addons = (CBA_common_addons select {(_x select [0, 4]) == "ace_"}) apply {toLower _x}; +private _errorMsg = ""; private _oldCompats = []; + { - if (getText (configFile >> "CfgPatches" >> _x >> "versionStr") != _version) then { - private _errorMsg = format ["File %1.pbo is outdated.", _x]; + if (getText (_cfgPatches >> _x >> "versionStr") != _version) then { + _errorMsg = format ["File %1.pbo is outdated.", _x]; ERROR(_errorMsg); if ((_x select [0, 10]) != "ace_compat") then { if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); }; } else { _oldCompats pushBack _x; // Don't block game if it's just an old compat pbo }; }; - false -} count _addons; +} forEach _addons; + if (_oldCompats isNotEqualTo []) then { [{ // Lasts for ~10 seconds @@ -65,24 +69,33 @@ if (_oldCompats isNotEqualTo []) then { }; /////////////// -// check extensions +// Check extensions /////////////// private _platform = toLower (productVersion select 6); + if (!isServer && {_platform in ["linux", "osx"]}) then { // Linux and OSX client ports do not support extensions at all INFO("Operating system does not support extensions"); } else { + private _extension = ""; + private _isWindows = false; + private _isLinux = false; + private _isClient = false; + private _isServer = false; + { - private _extension = configName _x; - private _isWindows = _platform == "windows" && {getNumber (_x >> "windows") == 1}; - private _isLinux = _platform == "linux" && {getNumber (_x >> "linux") == 1}; - private _isClient = hasInterface && {getNumber (_x >> "client") == 1}; - private _isServer = !hasInterface && {getNumber (_x >> "server") == 1}; + _extension = configName _x; + _isWindows = _platform == "windows" && {getNumber (_x >> "windows") == 1}; + _isLinux = _platform == "linux" && {getNumber (_x >> "linux") == 1}; + _isClient = hasInterface && {getNumber (_x >> "client") == 1}; + _isServer = !hasInterface && {getNumber (_x >> "server") == 1}; if ((_isWindows || _isLinux) && {_isClient || _isServer}) then { private _versionEx = _extension callExtension "version"; + if (_versionEx == "") then { private _extensionFile = _extension; + if (productVersion select 7 == "x64") then { _extensionFile = format ["%1_x64", _extensionFile]; }; @@ -90,11 +103,11 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { private _platformExt = [".dll", ".so"] select (_platform == "linux"); _extensionFile = format ["%1%2", _extensionFile, _platformExt]; - private _errorMsg = format ["Extension %1 not found.", _extensionFile]; + _errorMsg = format ["Extension %1 not found.", _extensionFile]; ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); }; } else { // Print the current extension version @@ -103,25 +116,26 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { }; } forEach ("true" configClasses (configFile >> "ACE_Extensions")); }; + if (isArray (configFile >> "ACE_Extensions" >> "extensions")) then { WARNING("extensions[] array no longer supported"); }; /////////////// -// check server version/addons +// Check server version/addons /////////////// if (isMultiplayer) then { - // don't check optional addons - _addons = _addons select {getNumber (configFile >> "CfgPatches" >> _x >> "ACE_isOptional") != 1}; + // Don't check optional addons + _addons = _addons select {getNumber (_cfgPatches >> _x >> "ACE_isOptional") != 1}; if (isServer) then { - // send servers version of ACE to all clients + // Send server's version of ACE to all clients GVAR(ServerVersion) = _version; GVAR(ServerAddons) = _addons; publicVariable QGVAR(ServerVersion); publicVariable QGVAR(ServerAddons); } else { - // clients have to wait for the variables + // Clients have to wait for the variables [{ if (isNil QGVAR(ServerVersion) || isNil QGVAR(ServerAddons)) exitWith {}; @@ -133,22 +147,23 @@ if (isMultiplayer) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); }; }; _addons = _addons - GVAR(ServerAddons); + if (_addons isNotEqualTo []) then { - private _errorMsg = format ["Client/Server Addon Mismatch. Client has extra addons: %1.",_addons]; + private _errorMsg = format ["Client/Server Addon Mismatch. Client has extra addons: %1.", _addons]; ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); }; }; [_this select 1] call CBA_fnc_removePerFrameHandler; - }, 1, [_version,_addons]] call CBA_fnc_addPerFrameHandler; + }, 0.5, [_version,_addons]] call CBA_fnc_addPerFrameHandler; }; }; diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index b45fae45d6e..d7a560d2115 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -1,6 +1,6 @@ #include "script_component.hpp" /* - * Author: commy2 + * Author: commy2, johnb43 * Used to execute the checkPBOs module without placing the module. Don't use this together with the module. * Checks PBO versions and compares to the one running on server. * @@ -24,7 +24,7 @@ params ["_mode", ["_checkAll", false], ["_whitelist", "", [""]]]; TRACE_3("params",_mode,_checkAll,_whitelist); -//lowercase and convert whiteList String into array of strings: +// Lowercase and convert whiteList string into array of strings: _whitelist = toLower _whitelist; _whitelist = _whitelist splitString "[,""']"; TRACE_1("Array",_whitelist); @@ -32,75 +32,73 @@ TRACE_1("Array",_whitelist); ACE_Version_CheckAll = _checkAll; ACE_Version_Whitelist = _whitelist; -if (!_checkAll) exitWith {}; //ACE is checked by FUNC(checkFiles) +// ACE is checked by FUNC(checkFiles) +if (!_checkAll) exitWith {}; if (!isServer) then { - [{ - if (isNil "ACE_Version_ClientErrors") exitWith {}; + ["ace_versioning_clientCheckDone", { + // Don't let this event get triggered again + [_thisType, _thisId] call CBA_fnc_removeEventHandler; - ACE_Version_ClientErrors params ["_missingAddon", "_missingAddonServer", "_oldVersionClient", "_oldVersionServer"]; + params ["_clientErrors"]; + _clientErrors params ["_missingAddon", "_missingAddonServer", "_oldVersionClient", "_oldVersionServer"]; + _thisArgs params ["_mode"]; - (_this select 0) params ["_mode", "_checkAll", "_whitelist"]; - - // Display error message. + // Display error message(s) if (_missingAddon || {_missingAddonServer} || {_oldVersionClient} || {_oldVersionServer}) then { - private _text = "[ACE] Version mismatch:

"; + private _errorMsg = "[ACE] Version mismatch:

"; private _error = format ["ACE version mismatch: %1: ", profileName]; if (_missingAddon) then { - _text = _text + "Detected missing addon on client
"; + _errorMsg = _errorMsg + "Detected missing addon on client
"; _error = _error + "Missing file(s); "; }; + if (_missingAddonServer) then { - _text = _text + "Detected missing addon on server
"; + _errorMsg = _errorMsg + "Detected missing addon on server
"; _error = _error + "Additional file(s); "; }; + if (_oldVersionClient) then { - _text = _text + "Detected old client version
"; + _errorMsg = _errorMsg + "Detected old client version
"; _error = _error + "Older version; "; }; + if (_oldVersionServer) then { - _text = _text + "Detected old server version
"; + _errorMsg = _errorMsg + "Detected old server version
"; _error = _error + "Newer version; "; }; - //[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - ERROR(_error); + // Warn if (_mode < 2) then { - _text = composeText [lineBreak, parseText format ["%1", _text]]; + _errorMsg = composeText [lineBreak, parseText format ["%1", _errorMsg]]; private _rscLayer = "ACE_RscErrorHint" call BIS_fnc_rscLayer; _rscLayer cutRsc ["ACE_RscErrorHint", "PLAIN", 0, true]; disableSerialization; + private _ctrlHint = uiNamespace getVariable "ACE_ctrlErrorHint"; - _ctrlHint ctrlSetStructuredText _text; + _ctrlHint ctrlSetStructuredText _errorMsg; if (_mode == 0) then { [{ - params ["_rscLayer"]; - TRACE_2("Hiding Error message after 10 seconds",time,_rscLayer); - _rscLayer cutFadeOut 0.2; - }, [_rscLayer], 10] call CBA_fnc_waitAndExecute; + TRACE_2("Hiding Error message after 10 seconds",time,_this); + _this cutFadeOut 0.2; + }, _rscLayer, 10] call CBA_fnc_waitAndExecute; }; - }; - - if (_mode == 2) then { - [{alive player}, { // To be able to show list if using checkAll - params ["_text"]; - TRACE_2("Player is alive, showing msg and exiting",time,_text); - _text = composeText [parseText format ["%1", _text]]; - ["[ACE] ERROR", _text, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); - }, [_text]] call CBA_fnc_waitUntilAndExecute; + } else { + // Kick + [{alive player}, { + TRACE_2("Player is alive, showing msg and exiting",time,_this); + private _errorMsg = composeText [parseText format ["%1", _this]]; + ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); + }, _errorMsg] call CBA_fnc_waitUntilAndExecute; }; }; - - [_this select 1] call CBA_fnc_removePerFrameHandler; - }, 1, [_mode, _checkAll, _whitelist]] call CBA_fnc_addPerFrameHandler; + }, [_mode]] call CBA_fnc_addEventHandlerArgs; }; -if (_checkAll) then { - 0 spawn COMPILE_FILE(scripts\checkVersionNumber); // @todo -}; +[_whitelist] spawn COMPILE_FILE(scripts\checkVersionNumber); // @todo diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index c062c8836cf..6582397993e 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -1,27 +1,36 @@ #include "script_component.hpp" /* - * Author: commy2, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) + * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) * Stops simulation and opens a textbox with error message. * * Arguments: - * ? + * 0: Header + * 1: Text + * 2: Code that is executed when 'Ok' is pressed (default: {}) + * 3: Code that is executed when 'Cancel' is pressed (default: {}) + * 4: Display (default: call BIS_fnc_displayMission) + * 5: Show buttons + * 5.0: Show ok button if ok has code (default: true) + * 5.1: Show cancel button if cancel has code (default: true) * * Return Value: * None * * Example: - * call ace_common_fnc_errorMessage + * ["[ACE] ERROR", text "Test", {findDisplay 46 closeDisplay 0}] call ace_common_fnc_errorMessage * * Public: No */ disableSerialization; + +// Force stop any loading screens endLoadingScreen; -// no message without player possible +// No message without player possible if (!hasInterface) exitWith {}; -// wait for display +// Wait for display if (isNull (call BIS_fnc_displayMission)) exitWith { [{ if (isNull (call BIS_fnc_displayMission)) exitWith {}; @@ -32,13 +41,14 @@ if (isNull (call BIS_fnc_displayMission)) exitWith { }, 1, _this] call CBA_fnc_addPerFrameHandler; }; -params ["_textHeader", "_textMessage", ["_onOK", {}], ["_onCancel", {}]]; +params ["_textHeader", "_textMessage", ["_onOK", {}, [{}]], ["_onCancel", {}, [{}]], ["_mainDisplay", call BIS_fnc_displayMission, [displayNull]], ["_showButtons", [true, true]]]; +_showButtons params [["_showOkButton", true, [false]], ["_showCancelButton", true, [false]]]; if (_textMessage isEqualType "") then { _textMessage = parseText _textMessage; }; -ARR_SELECT(_this,4,call BIS_fnc_displayMission) createDisplay "RscDisplayCommonMessagePause"; +_mainDisplay createDisplay "RscDisplayCommonMessagePause"; private _display = uiNamespace getVariable "RscDisplayCommonMessage_display"; private _ctrlRscMessageBox = _display displayCtrl 2351; @@ -109,7 +119,7 @@ _ctrlRscMessageBox ctrlSetPosition [ _ctrlRscMessageBox ctrlEnable true; _ctrlRscMessageBox ctrlCommit 0; -if (_onOK isEqualTo {}) then { +if (!_showOkButton || {_onOK isEqualTo {}}) then { _ctrlButtonOK ctrlEnable false; _ctrlButtonOK ctrlSetFade 0; _ctrlButtonOK ctrlSetText ""; @@ -123,7 +133,7 @@ if (_onOK isEqualTo {}) then { ctrlSetFocus _ctrlButtonOK; }; -if (_onCancel isEqualTo {}) then { +if (!_showCancelButton || {_onCancel isEqualTo {}}) then { _ctrlButtonCancel ctrlEnable false; _ctrlButtonCancel ctrlSetFade 0; _ctrlButtonCancel ctrlSetText ""; @@ -140,8 +150,5 @@ if (_onCancel isEqualTo {}) then { _ctrlButtonOK ctrlAddEventHandler ["buttonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}]; _ctrlButtonCancel ctrlAddEventHandler ["buttonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}]; -GVAR(errorOnOK) = _onOK; -GVAR(errorOnCancel) = _onCancel; - -_display displayAddEventHandler ["unload", {call ([{}, GVAR(errorOnOK), GVAR(errorOnCancel)] select (_this select 1))}]; +[_display, "unload", {call (_thisArgs select (_this select 1))}, [{}, _onOK, _onCancel]] call CBA_fnc_addBISEventHandler; _display displayAddEventHandler ["keyDown", {_this select 1 == 1}]; diff --git a/addons/common/scripts/checkVersionNumber.sqf b/addons/common/scripts/checkVersionNumber.sqf index 15832ed2bd7..56fb21e8dd9 100644 --- a/addons/common/scripts/checkVersionNumber.sqf +++ b/addons/common/scripts/checkVersionNumber.sqf @@ -1,160 +1,214 @@ -// by commy2 #include "script_component.hpp" +/* + * Author: commy2, johnb43 + * Compares version numbers addons loaded. + * + * Arguments: + * 0: Whitelist (default: []) + * + * Return Value: + * None + * + * Public: No + */ + +params [["_whitelist", []]]; -private _aceWhitelist = missionNamespace getVariable ["ACE_Version_Whitelist", []]; private _files = CBA_common_addons select { - (_x select [0,3] != "a3_") && - {_x select [0,4] != "ace_"} && - {!((toLower _x) in _aceWhitelist)} + (_x select [0, 3] != "a3_") && + {_x select [0, 4] != "ace_"} && + {!((toLower _x) in _whitelist)} }; +private _cfgPatches = configFile >> "CfgPatches"; +private _version = -1; private _versions = []; + { - getText (configFile >> "CfgPatches" >> _x >> "version") splitString "." params [["_major", "0"], ["_minor", "0"]]; - private _version = parseNumber _major + parseNumber _minor/100; - _versions set [_forEachIndex, _version]; + (getText (_cfgPatches >> _x >> "version") splitString ".") params [["_major", "0"], ["_minor", "0"]]; + _version = parseNumber _major + parseNumber _minor / 100; + _versions pushBack _version; } forEach _files; -if (isServer) then { +if (isServer) exitWith { ACE_Version_ServerVersions = [_files, _versions]; publicVariable "ACE_Version_ServerVersions"; -} else { - ACE_Version_ClientVersions = [_files, _versions]; + + // Raise event when done + ["ace_versioning_serverCheckDone", [+ACE_Version_ServerVersions]] call CBA_fnc_localEvent; }; // Begin client version check -if (!isServer) then { - // Wait for server to send the servers files and version numbers +ACE_Version_ClientVersions = [_files, _versions]; + +// Wait for server to send the servers files and version numbers +if (isNil "ACE_Version_ServerVersions") then { waitUntil { - sleep 1; - !isNil "ACE_Version_ClientVersions" && {!isNil "ACE_Version_ServerVersions"} + sleep 0.5; + !isNil "ACE_Version_ServerVersions" }; +}; - private _client = profileName; +ACE_Version_ServerVersions params [["_serverFiles", []], ["_serverVersions", []]]; - _files = ACE_Version_ClientVersions select 0; - _versions = ACE_Version_ClientVersions select 1; +// Compare client and server files and versions +private _client = profileName; +private _missingAddons = []; +private _oldVersionsClient = []; +private _oldVersionsServer = []; - private _serverFiles = ACE_Version_ServerVersions select 0; - private _serverVersions = ACE_Version_ServerVersions select 1; +private _clientVersion = -1; +private _serverVersion = -1; +private _index = -1; - // Compare client and server files and versions - private _missingAddons = []; - private _oldVersionsClient = []; - private _oldVersionsServer = []; - { - private _serverVersion = _serverVersions select _forEachIndex; +{ + _serverVersion = _serverVersions select _forEachIndex; - private _index = _files find _x; - if (_index == -1) then { - if (_x != "ace_server") then {_missingAddons pushBack _x;}; - } else { + _index = _files find _x; - private _clientVersion = _versions select _index; + if (_index == -1) then { + if (_x != "ace_server") then { + _missingAddons pushBack _x; + }; + } else { + _clientVersion = _versions select _index; - if (_clientVersion < _serverVersion) then { - _oldVersionsClient pushBack [_x, _clientVersion, _serverVersion]; - }; + if (_clientVersion < _serverVersion) then { + _oldVersionsClient pushBack [_x, _clientVersion, _serverVersion]; + }; - if (_clientVersion > _serverVersion) then { - _oldVersionsServer pushBack [_x, _clientVersion, _serverVersion]; - }; + if (_clientVersion > _serverVersion) then { + _oldVersionsServer pushBack [_x, _clientVersion, _serverVersion]; }; - } forEach _serverFiles; + }; +} forEach _serverFiles; - // find client files which the server doesn't have - private _missingAddonsServer = []; - { - private _index = _serverFiles find _x; - if (_index == -1) then { - _missingAddonsServer pushBack _x; - } - } forEach _files; - - // display and log error messages - private _fnc_cutComma = { - private _string = _this; - _string = toArray _string; - - private _count = count _string; - _string set [_count - 2, toArray "." select 0]; - _string set [_count - 1, -1]; - _string = _string - [-1]; - - toString _string; +// Find client files which the server doesn't have +private _missingAddonsServer = []; + +{ + if ((_serverFiles find _x) == -1) then { + _missingAddonsServer pushBack _x; }; +} forEach _files; - private _missingAddon = false; - if (count _missingAddons > 0) then { - _missingAddon = true; +// Client missing addon +private _missingAddon = _missingAddons isNotEqualTo []; - private _error = format ["[ACE] %1: ERROR client missing addon(s): ", _client]; - { - _error = _error + format ["%1, ", _x]; +if (_missingAddon) then { + private _error = [format ["[ACE] %1: ERROR client missing addon(s): ", _client]]; + private _cutComma = true; - if (_forEachIndex > 9) exitWith {}; - } forEach _missingAddons; + { + if (_forEachIndex >= 11) exitWith { + _error pushBack format ["and %1 more.", (count _missingAddons) - 11]; + _cutComma = false; + }; - _error = _error call _fnc_cutComma; + _error pushBack format ["%1, ", _x]; + } forEach _missingAddons; - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; + _error = _error joinString ""; + + // Remove last comma and whitespace + if (_cutComma) then { + _error = _error select [0, count _error - 2]; }; - private _missingAddonServer = false; - if (count _missingAddonsServer > 0) then { - _missingAddonServer = true; + // Display and log error messages + diag_log text _error; + [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; +}; - private _error = format ["[ACE] %1: ERROR server missing addon(s): ", _client]; - { - _error = _error + format ["%1, ", _x]; +// Server missing addon +private _missingAddonServer = _missingAddonsServer isNotEqualTo []; - if (_forEachIndex > 9) exitWith {}; - } forEach _missingAddonsServer; +if (_missingAddonServer) then { + private _error = [format ["[ACE] %1: ERROR server missing addon(s): ", _client]]; + private _cutComma = true; - _error = _error call _fnc_cutComma; + { + if (_forEachIndex >= 11) exitWith { + _error pushBack format ["and %1 more.", (count _missingAddonsServer) - 11]; + _cutComma = false; + }; + + _error pushBack format ["%1, ", _x]; + } forEach _missingAddonsServer; + + _error = _error joinString ""; - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; + // Remove last comma and whitespace + if (_cutComma) then { + _error = _error select [0, count _error - 2]; }; - private _oldVersionClient = false; - if (count _oldVersionsClient > 0) then { - _oldVersionClient = true; + // Display and log error messages + diag_log text _error; + [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; +}; + +// Client outdated addon +private _oldVersionClient = _oldVersionsClient isNotEqualTo []; - private _error = format ["[ACE] %1: ERROR outdated client addon(s): ", _client]; - { - _error = _error + format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; +if (_oldVersionClient) then { + private _error = [format ["[ACE] %1: ERROR outdated client addon(s): ", _client]]; + private _cutComma = true; + + { + if (_forEachIndex >= 11) exitWith { + _error pushBack format ["and %1 more.", (count _oldVersionsClient) - 11]; + _cutComma = false; + }; - if (_forEachIndex > 9) exitWith {}; - } forEach _oldVersionsClient; + _error pushBack format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; + } forEach _oldVersionsClient; - _error = _error call _fnc_cutComma; + _error = _error joinString ""; - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; + // Remove last comma and whitespace + if (_cutComma) then { + _error = _error select [0, count _error - 2]; }; - private _oldVersionServer = false; - if (count _oldVersionsServer > 0) then { - _oldVersionServer = true; + // Display and log error messages + diag_log text _error; + [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; +}; + +// Server outdated addon +private _oldVersionServer = _oldVersionsServer isNotEqualTo []; + +if (_oldVersionServer) then { + private _error = [format ["[ACE] %1: ERROR outdated server addon(s): ", _client]]; + private _cutComma = true; - private _error = format ["[ACE] %1: ERROR outdated server addon(s): ", _client]; - { - _error = _error + format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; + { + if (_forEachIndex >= 11) exitWith { + _error pushBack format ["and %1 more.", (count _oldVersionsServer) - 11]; + _cutComma = false; + }; - if (_forEachIndex > 9) exitWith {}; - } forEach _oldVersionsServer; + _error pushBack format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; + } forEach _oldVersionsServer; - _error = _error call _fnc_cutComma; + _error = _error joinString ""; - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; + // Remove last comma and whitespace + if (_cutComma) then { + _error = _error select [0, count _error - 2]; }; - ACE_Version_ClientErrors = [_missingAddon, _missingAddonServer, _oldVersionClient, _oldVersionServer]; + // Display and log error messages + diag_log text _error; + [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; }; + +ACE_Version_ClientErrors = [_missingAddon, _missingAddonServer, _oldVersionClient, _oldVersionServer]; + +// Raise event when done +["ace_versioning_clientCheckDone", [+ACE_Version_ClientErrors]] call CBA_fnc_localEvent; From 8386a3cf66207b58c21eb5a853793a2988e1ce1d Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 1 Aug 2023 09:34:19 +0200 Subject: [PATCH 02/26] Added kicking of clients without ACE loaded --- addons/common/XEH_PREP.hpp | 1 + addons/common/XEH_postInit.sqf | 29 +++ addons/common/functions/fnc_checkFiles.sqf | 23 +- addons/common/functions/fnc_checkPBOs.sqf | 3 +- .../functions/fnc_checkVersionNumber.sqf | 216 ++++++++++++++++++ addons/common/functions/fnc_errorMessage.sqf | 10 +- addons/common/scripts/checkVersionNumber.sqf | 214 ----------------- addons/common/scripts/script_component.hpp | 1 - 8 files changed, 270 insertions(+), 227 deletions(-) create mode 100644 addons/common/functions/fnc_checkVersionNumber.sqf delete mode 100644 addons/common/scripts/checkVersionNumber.sqf delete mode 100644 addons/common/scripts/script_component.hpp diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index 323f2c1d0d4..962e94f1784 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -26,6 +26,7 @@ PREP(canInteractWith); PREP(changeProjectileDirection); PREP(checkFiles); PREP(checkPBOs); +PREP(checkVersionNumber); PREP(claim); PREP(claimSafeServer); PREP(codeToString); diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 00d1a4406b6..6e6b3e52727 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -244,6 +244,35 @@ if (_currentVersion != _previousVersion) then { call FUNC(checkFiles); +// Let the server know that we have ACE loaded +missionNamespace setVariable [QGVAR(aceLoaded_) + getPlayerUID player, true, 2]; + +// This handles clients joining that do not have ACE loaded +if (isServer) then { + addMissionEventHandler ["PlayerConnected", { + [{ + params ["", "_uid", "", "", "_owner"]; + + // If ACE is not loaded, kick unit + if !(missionNamespace getVariable [QGVAR(aceLoaded_) + _uid, false]) then { + // Send function to client + _owner publicVariableClient QFUNC(errorMessage); + + // Wait for function to broadcast, then kick client + [{ + ["[ACE] ERROR", "ACE is not present", {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] remoteExecCall [QFUNC(errorMessage), _this]; + }, _owner, 0.5] call CBA_fnc_waitAndExecute; + }; + }, _this, 3] call CBA_fnc_waitAndExecute; + }]; + + addMissionEventHandler ["PlayerDisconnected", { + params ["", "_uid"]; + + // Reset variable + missionNamespace setVariable [QGVAR(aceLoaded_) + _uid, nil]; + }]; +}; ////////////////////////////////////////////////// // Set up ace_settingsInitialized eventhandler diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index 601c4635306..27bbcaaf31a 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -135,14 +135,12 @@ if (isMultiplayer) then { publicVariable QGVAR(ServerVersion); publicVariable QGVAR(ServerAddons); } else { - // Clients have to wait for the variables - [{ - if (isNil QGVAR(ServerVersion) || isNil QGVAR(ServerAddons)) exitWith {}; - - (_this select 0) params ["_version", "_addons"]; + GVAR(ClientVersion) = _version; + GVAR(ClientAddons) = _addons; - if (_version != GVAR(ServerVersion)) then { - private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2.", GVAR(ServerVersion), _version]; + private _fnc_check = { + if (GVAR(ClientVersion) != GVAR(ServerVersion)) then { + private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2.", GVAR(ServerVersion), GVAR(ClientVersion)]; ERROR(_errorMsg); @@ -151,7 +149,7 @@ if (isMultiplayer) then { }; }; - _addons = _addons - GVAR(ServerAddons); + private _addons = GVAR(ClientAddons) - GVAR(ServerAddons); if (_addons isNotEqualTo []) then { private _errorMsg = format ["Client/Server Addon Mismatch. Client has extra addons: %1.", _addons]; @@ -162,8 +160,13 @@ if (isMultiplayer) then { ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); }; }; + }; - [_this select 1] call CBA_fnc_removePerFrameHandler; - }, 0.5, [_version,_addons]] call CBA_fnc_addPerFrameHandler; + // Clients have to wait for the variables + if (isNil QGVAR(ServerVersion) || isNil QGVAR(ServerAddons)) then { + GVAR(ServerVersion) addPublicVariableEventHandler _fnc_check; + } else { + call _fnc_check; + }; }; }; diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index d7a560d2115..47d64b9a80f 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -101,4 +101,5 @@ if (!isServer) then { }, [_mode]] call CBA_fnc_addEventHandlerArgs; }; -[_whitelist] spawn COMPILE_FILE(scripts\checkVersionNumber); // @todo +// Check file version numbers +[_whitelist] call FUNC(checkVersionNumber); diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf new file mode 100644 index 00000000000..496a0494c33 --- /dev/null +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -0,0 +1,216 @@ +#include "script_component.hpp" +/* + * Author: commy2, johnb43 + * Compares version numbers from loaded addons. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Public: No + */ + +private _whitelist = missionNamespace getVariable ["ACE_Version_Whitelist", []]; + +private _files = CBA_common_addons select { + (_x select [0, 3] != "a3_") && + {_x select [0, 4] != "ace_"} && + {!((toLower _x) in _whitelist)} +}; + +private _cfgPatches = configFile >> "CfgPatches"; +private _version = -1; +private _versions = []; + +{ + (getText (_cfgPatches >> _x >> "version") splitString ".") params [["_major", "0"], ["_minor", "0"]]; + _version = parseNumber _major + parseNumber _minor / 100; + _versions pushBack _version; +} forEach _files; + +if (isServer) exitWith { + ACE_Version_ServerVersions = [_files, _versions]; + publicVariable "ACE_Version_ServerVersions"; + + // Raise event when done + ["ace_versioning_serverCheckDone", [+ACE_Version_ServerVersions]] call CBA_fnc_localEvent; +}; + +// Begin client version check +ACE_Version_ClientVersions = [_files, _versions]; + +private _fnc_check = { + ACE_Version_ClientVersions params [["_files", []], ["_versions", []]]; + ACE_Version_ServerVersions params [["_serverFiles", []], ["_serverVersions", []]]; + + // Compare client and server files and versions + private _client = profileName; + private _missingAddons = []; + private _oldVersionsClient = []; + private _oldVersionsServer = []; + + private _clientVersion = -1; + private _serverVersion = -1; + private _index = -1; + + { + _serverVersion = _serverVersions select _forEachIndex; + + _index = _files find _x; + + if (_index == -1) then { + if (_x != "ace_server") then { + _missingAddons pushBack _x; + }; + } else { + _clientVersion = _versions select _index; + + if (_clientVersion < _serverVersion) then { + _oldVersionsClient pushBack [_x, _clientVersion, _serverVersion]; + }; + + if (_clientVersion > _serverVersion) then { + _oldVersionsServer pushBack [_x, _clientVersion, _serverVersion]; + }; + }; + } forEach _serverFiles; + + // Find client files which the server doesn't have + private _missingAddonsServer = []; + + { + if ((_serverFiles find _x) == -1) then { + _missingAddonsServer pushBack _x; + }; + } forEach _files; + + // Client missing addon + private _missingAddon = _missingAddons isNotEqualTo []; + + if (_missingAddon) then { + private _error = [format ["[ACE] %1: ERROR client missing addon(s): ", _client]]; + private _cutComma = true; + + { + if (_forEachIndex >= 11) exitWith { + _error pushBack format ["and %1 more.", (count _missingAddons) - 11]; + _cutComma = false; + }; + + _error pushBack format ["%1, ", _x]; + } forEach _missingAddons; + + _error = _error joinString ""; + + // Remove last comma and whitespace + if (_cutComma) then { + _error = _error select [0, count _error - 2]; + }; + + // Display and log error messages + diag_log text _error; + [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; + }; + + // Server missing addon + private _missingAddonServer = _missingAddonsServer isNotEqualTo []; + + if (_missingAddonServer) then { + private _error = [format ["[ACE] %1: ERROR server missing addon(s): ", _client]]; + private _cutComma = true; + + { + if (_forEachIndex >= 11) exitWith { + _error pushBack format ["and %1 more.", (count _missingAddonsServer) - 11]; + _cutComma = false; + }; + + _error pushBack format ["%1, ", _x]; + } forEach _missingAddonsServer; + + _error = _error joinString ""; + + // Remove last comma and whitespace + if (_cutComma) then { + _error = _error select [0, count _error - 2]; + }; + + // Display and log error messages + diag_log text _error; + [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; + }; + + // Client outdated addon + private _oldVersionClient = _oldVersionsClient isNotEqualTo []; + + if (_oldVersionClient) then { + private _error = [format ["[ACE] %1: ERROR outdated client addon(s): ", _client]]; + private _cutComma = true; + + { + if (_forEachIndex >= 11) exitWith { + _error pushBack format ["and %1 more.", (count _oldVersionsClient) - 11]; + _cutComma = false; + }; + + _error pushBack format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; + } forEach _oldVersionsClient; + + _error = _error joinString ""; + + // Remove last comma and whitespace + if (_cutComma) then { + _error = _error select [0, count _error - 2]; + }; + + // Display and log error messages + diag_log text _error; + [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; + }; + + // Server outdated addon + private _oldVersionServer = _oldVersionsServer isNotEqualTo []; + + if (_oldVersionServer) then { + private _error = [format ["[ACE] %1: ERROR outdated server addon(s): ", _client]]; + private _cutComma = true; + + { + if (_forEachIndex >= 11) exitWith { + _error pushBack format ["and %1 more.", (count _oldVersionsServer) - 11]; + _cutComma = false; + }; + + _error pushBack format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; + } forEach _oldVersionsServer; + + _error = _error joinString ""; + + // Remove last comma and whitespace + if (_cutComma) then { + _error = _error select [0, count _error - 2]; + }; + + // Display and log error messages + diag_log text _error; + [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; + }; + + ACE_Version_ClientErrors = [_missingAddon, _missingAddonServer, _oldVersionClient, _oldVersionServer]; + + // Raise event when done + ["ace_versioning_clientCheckDone", [+ACE_Version_ClientErrors]] call CBA_fnc_localEvent; +}; + +// Wait for server to send the servers files and version numbers +if (isNil "ACE_Version_ServerVersions") then { + ACE_Version_ServerVersions addPublicVariableEventHandler _fnc_check; +} else { + call _fnc_check; +}; diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index 6582397993e..5b5c5f187b7 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -150,5 +150,13 @@ if (!_showCancelButton || {_onCancel isEqualTo {}}) then { _ctrlButtonOK ctrlAddEventHandler ["buttonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}]; _ctrlButtonCancel ctrlAddEventHandler ["buttonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}]; -[_display, "unload", {call (_thisArgs select (_this select 1))}, [{}, _onOK, _onCancel]] call CBA_fnc_addBISEventHandler; +// CBA isn't guaranteed to be loaded +private _ehID = _display displayAddEventHandler ["unload", { + params ["_display", "_exitCode"]; + + call ((_display getVariable [QGVAR(errorMessageCode_) + str _thisEventHandler, [{}, {}, {}]]) select _exitCode) +}]; + +_display setVariable [QGVAR(errorMessageCode_) + str _ehID, [{}, _onOK, _onCancel]]; + _display displayAddEventHandler ["keyDown", {_this select 1 == 1}]; diff --git a/addons/common/scripts/checkVersionNumber.sqf b/addons/common/scripts/checkVersionNumber.sqf deleted file mode 100644 index 56fb21e8dd9..00000000000 --- a/addons/common/scripts/checkVersionNumber.sqf +++ /dev/null @@ -1,214 +0,0 @@ -#include "script_component.hpp" -/* - * Author: commy2, johnb43 - * Compares version numbers addons loaded. - * - * Arguments: - * 0: Whitelist (default: []) - * - * Return Value: - * None - * - * Public: No - */ - -params [["_whitelist", []]]; - -private _files = CBA_common_addons select { - (_x select [0, 3] != "a3_") && - {_x select [0, 4] != "ace_"} && - {!((toLower _x) in _whitelist)} -}; - -private _cfgPatches = configFile >> "CfgPatches"; -private _version = -1; -private _versions = []; - -{ - (getText (_cfgPatches >> _x >> "version") splitString ".") params [["_major", "0"], ["_minor", "0"]]; - _version = parseNumber _major + parseNumber _minor / 100; - _versions pushBack _version; -} forEach _files; - -if (isServer) exitWith { - ACE_Version_ServerVersions = [_files, _versions]; - publicVariable "ACE_Version_ServerVersions"; - - // Raise event when done - ["ace_versioning_serverCheckDone", [+ACE_Version_ServerVersions]] call CBA_fnc_localEvent; -}; - -// Begin client version check -ACE_Version_ClientVersions = [_files, _versions]; - -// Wait for server to send the servers files and version numbers -if (isNil "ACE_Version_ServerVersions") then { - waitUntil { - sleep 0.5; - !isNil "ACE_Version_ServerVersions" - }; -}; - -ACE_Version_ServerVersions params [["_serverFiles", []], ["_serverVersions", []]]; - -// Compare client and server files and versions -private _client = profileName; -private _missingAddons = []; -private _oldVersionsClient = []; -private _oldVersionsServer = []; - -private _clientVersion = -1; -private _serverVersion = -1; -private _index = -1; - -{ - _serverVersion = _serverVersions select _forEachIndex; - - _index = _files find _x; - - if (_index == -1) then { - if (_x != "ace_server") then { - _missingAddons pushBack _x; - }; - } else { - _clientVersion = _versions select _index; - - if (_clientVersion < _serverVersion) then { - _oldVersionsClient pushBack [_x, _clientVersion, _serverVersion]; - }; - - if (_clientVersion > _serverVersion) then { - _oldVersionsServer pushBack [_x, _clientVersion, _serverVersion]; - }; - }; -} forEach _serverFiles; - -// Find client files which the server doesn't have -private _missingAddonsServer = []; - -{ - if ((_serverFiles find _x) == -1) then { - _missingAddonsServer pushBack _x; - }; -} forEach _files; - -// Client missing addon -private _missingAddon = _missingAddons isNotEqualTo []; - -if (_missingAddon) then { - private _error = [format ["[ACE] %1: ERROR client missing addon(s): ", _client]]; - private _cutComma = true; - - { - if (_forEachIndex >= 11) exitWith { - _error pushBack format ["and %1 more.", (count _missingAddons) - 11]; - _cutComma = false; - }; - - _error pushBack format ["%1, ", _x]; - } forEach _missingAddons; - - _error = _error joinString ""; - - // Remove last comma and whitespace - if (_cutComma) then { - _error = _error select [0, count _error - 2]; - }; - - // Display and log error messages - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; -}; - -// Server missing addon -private _missingAddonServer = _missingAddonsServer isNotEqualTo []; - -if (_missingAddonServer) then { - private _error = [format ["[ACE] %1: ERROR server missing addon(s): ", _client]]; - private _cutComma = true; - - { - if (_forEachIndex >= 11) exitWith { - _error pushBack format ["and %1 more.", (count _missingAddonsServer) - 11]; - _cutComma = false; - }; - - _error pushBack format ["%1, ", _x]; - } forEach _missingAddonsServer; - - _error = _error joinString ""; - - // Remove last comma and whitespace - if (_cutComma) then { - _error = _error select [0, count _error - 2]; - }; - - // Display and log error messages - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; -}; - -// Client outdated addon -private _oldVersionClient = _oldVersionsClient isNotEqualTo []; - -if (_oldVersionClient) then { - private _error = [format ["[ACE] %1: ERROR outdated client addon(s): ", _client]]; - private _cutComma = true; - - { - if (_forEachIndex >= 11) exitWith { - _error pushBack format ["and %1 more.", (count _oldVersionsClient) - 11]; - _cutComma = false; - }; - - _error pushBack format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; - } forEach _oldVersionsClient; - - _error = _error joinString ""; - - // Remove last comma and whitespace - if (_cutComma) then { - _error = _error select [0, count _error - 2]; - }; - - // Display and log error messages - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; -}; - -// Server outdated addon -private _oldVersionServer = _oldVersionsServer isNotEqualTo []; - -if (_oldVersionServer) then { - private _error = [format ["[ACE] %1: ERROR outdated server addon(s): ", _client]]; - private _cutComma = true; - - { - if (_forEachIndex >= 11) exitWith { - _error pushBack format ["and %1 more.", (count _oldVersionsServer) - 11]; - _cutComma = false; - }; - - _error pushBack format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; - } forEach _oldVersionsServer; - - _error = _error joinString ""; - - // Remove last comma and whitespace - if (_cutComma) then { - _error = _error select [0, count _error - 2]; - }; - - // Display and log error messages - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; -}; - -ACE_Version_ClientErrors = [_missingAddon, _missingAddonServer, _oldVersionClient, _oldVersionServer]; - -// Raise event when done -["ace_versioning_clientCheckDone", [+ACE_Version_ClientErrors]] call CBA_fnc_localEvent; diff --git a/addons/common/scripts/script_component.hpp b/addons/common/scripts/script_component.hpp deleted file mode 100644 index 6a1bf9154d5..00000000000 --- a/addons/common/scripts/script_component.hpp +++ /dev/null @@ -1 +0,0 @@ -#include "\z\ace\addons\common\script_component.hpp" From fcc8e1db1cdfa617c14ab20039feb6987bf90ebd Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 14 Sep 2023 08:38:25 +0200 Subject: [PATCH 03/26] Update fnc_errorMessage.sqf --- addons/common/functions/fnc_errorMessage.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index 5b5c5f187b7..e5eb224d09b 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -10,8 +10,8 @@ * 3: Code that is executed when 'Cancel' is pressed (default: {}) * 4: Display (default: call BIS_fnc_displayMission) * 5: Show buttons - * 5.0: Show ok button if ok has code (default: true) - * 5.1: Show cancel button if cancel has code (default: true) + * - 0: Show ok button if ok has code (default: true) + * - 1: Show cancel button if cancel has code (default: true) * * Return Value: * None From f5c0fd4bd8a72f48c1e11e59c0950252402aa09f Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 14 Sep 2023 08:46:09 +0200 Subject: [PATCH 04/26] Update fnc_checkVersionNumber.sqf --- addons/common/functions/fnc_checkVersionNumber.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index 496a0494c33..d831c5c3d70 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -1,4 +1,4 @@ -#include "script_component.hpp" +#include "..\script_component.hpp" /* * Author: commy2, johnb43 * Compares version numbers from loaded addons. From 152995e3737d5a1d1f7d0c1a3c99ac1d9a666ae7 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 23 Oct 2023 23:34:08 +0200 Subject: [PATCH 05/26] More compatibility for #9568 --- addons/common/functions/fnc_checkFiles.sqf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index 48905010d7c..d0ce92adf26 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -74,9 +74,9 @@ if (_oldAddons isNotEqualTo []) then { _oldAddons = _oldAddons apply {"%1.pbo", _x}; private _errorMsg = if (count _oldAddons > 3) then { - format ["The following files are outdated: %1, and %2 more.
ACE Main version is %3.
Loaded mods with outdated ACE files: %4", (_oldAddons select [0, 3]) joinString ", ", (count _oldAddons) - 3, _mainVersion, _oldSources joinString ", "]; + format ["The following files are outdated: %1, and %2 more.
ACE Main version is %3 from %4.
Loaded mods with outdated ACE files: %5", (_oldAddons select [0, 3]) joinString ", ", (count _oldAddons) - 3, _mainVersion, _mainSource, _oldSources joinString ", "]; } else { - format ["The following files are outdated: %1.
ACE Main version is %2.
Loaded mods with outdated ACE files: %3", _oldAddons joinString ", ", _mainVersion, _oldSources joinString ", "]; + format ["The following files are outdated: %1.
ACE Main version is %2 from %3.
Loaded mods with outdated ACE files: %4", _oldAddons joinString ", ", _mainVersion, _mainSource, _oldSources joinString ", "]; }; if (hasInterface) then { @@ -87,7 +87,7 @@ if (_oldAddons isNotEqualTo []) then { }; if (_oldCompats isNotEqualTo []) then { - _oldCompats = _oldCompats apply {format ["%1 (%2, source: %3)", _x select 0, _x select 1]}; + _oldCompats = _oldCompats apply {format ["%1 (%2)", _x select 0, _x select 1]}; [{ // Lasts for ~10 seconds From b5af26727b6f000fdc0f9201814ea5b5df8af121 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 25 Oct 2023 19:16:56 +0200 Subject: [PATCH 06/26] Cleanup --- addons/common/functions/fnc_checkFiles.sqf | 29 ++-- addons/common/functions/fnc_checkPBOs.sqf | 8 +- .../functions/fnc_checkVersionNumber.sqf | 145 +++++------------- 3 files changed, 64 insertions(+), 118 deletions(-) diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index 9ca77868084..ad52894a512 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -15,6 +15,11 @@ * Public: No */ + // Don't execute in scheduled environment + if (canSuspend) exitWith { + [FUNC(checkFiles), nil] call CBA_fnc_directCall; + }; + /////////////// // Check addons /////////////// @@ -158,20 +163,21 @@ if (isMultiplayer) then { if (isServer) then { // Send server's version of ACE to all clients - GVAR(ServerVersion) = _mainVersion; - GVAR(ServerAddons) = _addons; - publicVariable QGVAR(ServerVersion); - publicVariable QGVAR(ServerAddons); + GVAR(serverVersion) = _mainVersion; + GVAR(serverAddons) = _addons; + publicVariable QGVAR(serverVersion); + publicVariable QGVAR(serverAddons); } else { - GVAR(ClientVersion) = _version; - GVAR(ClientAddons) = _addons; + GVAR(clientVersion) = _version; + GVAR(clientAddons) = _addons; private _fnc_check = { - if (GVAR(ClientVersion) != GVAR(ServerVersion)) then { - private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2.", GVAR(ServerVersion), GVAR(ClientVersion)]; + if (GVAR(clientVersion) != GVAR(serverVersion)) then { + private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2.", GVAR(serverVersion), GVAR(clientVersion)]; // Check ACE install call FUNC(checkFiles_diagnoseACE); + ERROR(_errorMsg); if (hasInterface) then { @@ -179,13 +185,14 @@ if (isMultiplayer) then { }; }; - private _addons = GVAR(ClientAddons) - GVAR(ServerAddons); + private _addons = GVAR(clientAddons) - GVAR(serverAddons); if (_addons isNotEqualTo []) then { private _errorMsg = format ["Client/Server Addon Mismatch. Client has extra addons: %1.", _addons]; // Check ACE install call FUNC(checkFiles_diagnoseACE); + ERROR(_errorMsg); if (hasInterface) then { @@ -195,8 +202,8 @@ if (isMultiplayer) then { }; // Clients have to wait for the variables - if (isNil QGVAR(ServerVersion) || isNil QGVAR(ServerAddons)) then { - GVAR(ServerVersion) addPublicVariableEventHandler _fnc_check; + if (isNil QGVAR(serverVersion) || isNil QGVAR(serverAddons)) then { + GVAR(serverVersion) addPublicVariableEventHandler _fnc_check; } else { call _fnc_check; }; diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index 0bb8f63750f..37f8355b300 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -24,7 +24,7 @@ params ["_mode", ["_checkAll", false], ["_whitelist", "", [""]]]; TRACE_3("params",_mode,_checkAll,_whitelist); -// Lowercase and convert whiteList string into array of strings: +// Lowercase and convert whiteList string into array of strings _whitelist = toLower _whitelist; _whitelist = _whitelist splitString "[,""']"; TRACE_1("Array",_whitelist); @@ -41,15 +41,15 @@ if (!isServer) then { [_thisType, _thisId] call CBA_fnc_removeEventHandler; params ["_clientErrors"]; - _clientErrors params ["_missingAddon", "_missingAddonServer", "_oldVersionClient", "_oldVersionServer"]; + _clientErrors params ["_missingAddonClient", "_missingAddonServer", "_oldVersionClient", "_oldVersionServer"]; _thisArgs params ["_mode"]; // Display error message(s) - if (_missingAddon || {_missingAddonServer} || {_oldVersionClient} || {_oldVersionServer}) then { + if (_missingAddonClient || {_missingAddonServer} || {_oldVersionClient} || {_oldVersionServer}) then { private _errorMsg = "[ACE] Version mismatch:

"; private _error = format ["ACE version mismatch: %1: ", profileName]; - if (_missingAddon) then { + if (_missingAddonClient) then { _errorMsg = _errorMsg + "Detected missing addon on client
"; _error = _error + "Missing file(s); "; }; diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index d831c5c3d70..f76789a16d9 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -9,10 +9,18 @@ * Return Value: * None * + * Example: + * call ace_common_fnc_checkVersionNumber + * * Public: No */ -private _whitelist = missionNamespace getVariable ["ACE_Version_Whitelist", []]; +// Don't execute in scheduled environment +if (canSuspend) exitWith { + [FUNC(checkVersionNumber), _this] call CBA_fnc_directCall; +}; + +params [["_whitelist", missionNamespace getVariable ["ACE_Version_Whitelist", []]]]; private _files = CBA_common_addons select { (_x select [0, 3] != "a3_") && @@ -86,123 +94,54 @@ private _fnc_check = { }; } forEach _files; - // Client missing addon - private _missingAddon = _missingAddons isNotEqualTo []; - - if (_missingAddon) then { - private _error = [format ["[ACE] %1: ERROR client missing addon(s): ", _client]]; - private _cutComma = true; - - { - if (_forEachIndex >= 11) exitWith { - _error pushBack format ["and %1 more.", (count _missingAddons) - 11]; - _cutComma = false; - }; - - _error pushBack format ["%1, ", _x]; - } forEach _missingAddons; - _error = _error joinString ""; + // Check for client missing addons, server missing addons, client outdated addons and server outdated addons + private _clientErrors = []; + private _errorLog = []; + private _errorMsg = ""; + private _count = 0; - // Remove last comma and whitespace - if (_cutComma) then { - _error = _error select [0, count _error - 2]; - }; - - // Display and log error messages - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; - }; - - // Server missing addon - private _missingAddonServer = _missingAddonsServer isNotEqualTo []; - - if (_missingAddonServer) then { - private _error = [format ["[ACE] %1: ERROR server missing addon(s): ", _client]]; - private _cutComma = true; - - { - if (_forEachIndex >= 11) exitWith { - _error pushBack format ["and %1 more.", (count _missingAddonsServer) - 11]; - _cutComma = false; - }; + #define DISPLAY_NUMBER_ADDONS (10 + 1) // +1 to account for header - _error pushBack format ["%1, ", _x]; - } forEach _missingAddonsServer; + { + params ["_items", "_string"]; - _error = _error joinString ""; + // Check if something is either missing or outdated + _missing = _items isNotEqualTo []; - // Remove last comma and whitespace - if (_cutComma) then { - _error = _error select [0, count _error - 2]; - }; + if (_missing) then { + // Generate error message + _errorLog = [format ["[ACE] %1: ERROR %2 addon(s): ", _client, _string]]; - // Display and log error messages - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; - }; + _errorLog append _items; - // Client outdated addon - private _oldVersionClient = _oldVersionsClient isNotEqualTo []; + // Don't display all missing items, as they are logged + _errorMsg = (_errorLog select [0, DISPLAY_NUMBER_ADDONS]) joinString ", "; + _errorLog = _errorLog joinString ", "; - if (_oldVersionClient) then { - private _error = [format ["[ACE] %1: ERROR outdated client addon(s): ", _client]]; - private _cutComma = true; + _count = count _items; - { - if (_forEachIndex >= 11) exitWith { - _error pushBack format ["and %1 more.", (count _oldVersionsClient) - 11]; - _cutComma = false; + if (_count > DISPLAY_NUMBER_ADDONS) then { + _errorMsg = _errorMsg + format ["and %1 more.", _count - DISPLAY_NUMBER_ADDONS]; }; - _error pushBack format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; - } forEach _oldVersionsClient; - - _error = _error joinString ""; - - // Remove last comma and whitespace - if (_cutComma) then { - _error = _error select [0, count _error - 2]; + // Log and display error messages + diag_log text _errorLog; + [QGVAR(serverLog), _errorLog] call CBA_fnc_serverEvent; + [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; }; - // Display and log error messages - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; - }; - - // Server outdated addon - private _oldVersionServer = _oldVersionsServer isNotEqualTo []; - - if (_oldVersionServer) then { - private _error = [format ["[ACE] %1: ERROR outdated server addon(s): ", _client]]; - private _cutComma = true; - - { - if (_forEachIndex >= 11) exitWith { - _error pushBack format ["and %1 more.", (count _oldVersionsServer) - 11]; - _cutComma = false; - }; - - _error pushBack format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; - } forEach _oldVersionsServer; - - _error = _error joinString ""; - - // Remove last comma and whitespace - if (_cutComma) then { - _error = _error select [0, count _error - 2]; - }; + _clientErrors pushBack _missing; + } forEach [ + [_missingAddonsClient, "client missing"], + [_missingAddonsServer, "server missing"], + [_oldVersionsClient, "outdated client"], + [_oldVersionsServer, "outdated server"] + ]; - // Display and log error messages - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; - }; + TRACE_4("",_missingAddonsClient,_missingAddonsServer,_oldVersionsClient,_oldVersionsServer); - ACE_Version_ClientErrors = [_missingAddon, _missingAddonServer, _oldVersionClient, _oldVersionServer]; + ACE_Version_ClientErrors = _clientErrors; // Raise event when done ["ace_versioning_clientCheckDone", [+ACE_Version_ClientErrors]] call CBA_fnc_localEvent; From 4b560d29b0e73e9df5b1d0ddf7db4ed99bd99d5d Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 29 Oct 2023 17:28:43 +0100 Subject: [PATCH 07/26] Minor cleanup + added server source --- addons/common/functions/fnc_checkFiles.sqf | 10 ++-- .../functions/fnc_checkFiles_diagnoseACE.sqf | 46 +++++++++++++------ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index ad52894a512..0005fcf4cb6 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -68,10 +68,11 @@ private _oldCompats = []; // Check ACE install call FUNC(checkFiles_diagnoseACE); + // Don't block game if it's just an old compat pbo if ((_x select [0, 10]) != "ace_compat") then { _oldAddons pushBack _x; } else { - _oldCompats pushBack [_x, _addonVersion]; // Don't block game if it's just an old compat pbo + _oldCompats pushBack [_x, _addonVersion]; }; }; } forEach _addons; @@ -165,15 +166,18 @@ if (isMultiplayer) then { // Send server's version of ACE to all clients GVAR(serverVersion) = _mainVersion; GVAR(serverAddons) = _addons; + GVAR(serverSource) = _mainSource; + publicVariable QGVAR(serverVersion); publicVariable QGVAR(serverAddons); + publicVariable QGVAR(serverSource); } else { GVAR(clientVersion) = _version; GVAR(clientAddons) = _addons; private _fnc_check = { if (GVAR(clientVersion) != GVAR(serverVersion)) then { - private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2.", GVAR(serverVersion), GVAR(clientVersion)]; + private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2. Server modDir: %3", GVAR(serverVersion), GVAR(clientVersion), GVAR(serverSource)]; // Check ACE install call FUNC(checkFiles_diagnoseACE); @@ -188,7 +192,7 @@ if (isMultiplayer) then { private _addons = GVAR(clientAddons) - GVAR(serverAddons); if (_addons isNotEqualTo []) then { - private _errorMsg = format ["Client/Server Addon Mismatch. Client has extra addons: %1.", _addons]; + private _errorMsg = format ["Client/Server Addon Mismatch. Client has extra addons: %1. Server modDir: %2", _addons, GVAR(serverSource)]; // Check ACE install call FUNC(checkFiles_diagnoseACE); diff --git a/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf b/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf index 5b7f80198b5..9ec12154fd1 100644 --- a/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf +++ b/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf @@ -1,13 +1,13 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Diagnose ACE install problems, this will only be called if there is a known problem + * Diagnoses ACE install problems, this will only be called if there is a known problem. * * Arguments: * None * * Return Value: - * None + * ACE addons' WS IDs * * Example: * [] call ace_common_fnc_checkFiles_diagnoseACE @@ -16,40 +16,56 @@ */ // Only run once -if (missionNameSpace getVariable [QGVAR(checkFiles_diagnoseACE), false]) exitWith {}; +if (missionNameSpace getVariable [QGVAR(checkFiles_diagnoseACE), false]) exitWith { + createHashMap +}; + GVAR(checkFiles_diagnoseACE) = true; -private _addons = cba_common_addons select {(_x select [0,4]) == "ace_"}; +private _addons = CBA_common_addons select {(_x select [0, 4]) == "ace_"}; private _cfgPatches = configFile >> "CfgPatches"; private _allMods = createHashMap; +private _getLoadedModsInfo = getLoadedModsInfo; -// Check ACE_ADDONs are in expected mod DIR +// Check if ACE_ADDONs are in expected mod DIR { - private _cfg = (_cfgPatches >> _x); + private _cfg = _cfgPatches >> _x; private _actualModDir = configSourceMod _cfg; private _expectedModDir = getText (_cfg >> "ACE_expectedModDir"); - if (_expectedModDir == "") then { _expectedModDir = "@ace" }; + + if (_expectedModDir == "") then { + _expectedModDir = "@ace"; + }; + private _expectedSteamID = getText (_cfg >> "ACE_expectedSteamID"); - if (_expectedSteamID == "") then { _expectedSteamID = "463939057" }; + + if (_expectedSteamID == "") then { + _expectedSteamID = "463939057" + }; (_allMods getOrDefault [_actualModDir, [], true]) pushBackUnique _expectedSteamID; + if (_actualModDir != _expectedModDir) then { - private _errorMsg = format ["%1 loading from unexpected modDir [%2]",_x,_actualModDir]; + private _errorMsg = format ["%1 loading from unexpected modDir [%2]", _x, _actualModDir]; systemChat _errorMsg; WARNING_1("%1",_errorMsg); }; } forEach _addons; -// Check all ACE ModDirs have expected steam WS ID +// Check if all ACE ModDirs have expected steam WS ID { private _modDir = _x; - if ((count _y) != 1) then { ERROR_2("Unexpected multiple steamIDs %1 - %2",_modDir,_y) }; - private _expectedSteamID = _y # 0; - private _index = getLoadedModsInfo findIf {_x#1 == _modDir}; - (getLoadedModsInfo param [_index, []]) params [["_modName", "$Error$"], "", "", "", "", "", "", ["_actualID", ""]]; + + if (count _y != 1) then { + ERROR_2("Unexpected multiple steamIDs %1 - %2",_modDir,_y); + }; + + private _expectedSteamID = _y select 0; + private _index = _getLoadedModsInfo findIf {_x select 1 == _modDir}; + (_getLoadedModsInfo param [_index, []]) params [["_modName", "$Error$"], "", "", "", "", "", "", ["_actualID", ""]]; if (_actualID != _expectedSteamID) then { - private _errorMsg = format ["%1 [%2] unexpected workshopID [%3]",_modDir,_modName,_actualID]; + private _errorMsg = format ["%1 [%2] unexpected workshopID [%3]", _modDir, _modName, _actualID]; systemChat _errorMsg; WARNING_1("%1",_errorMsg); }; From 0de1b26c9d001769a116899f013aa3f7c0c20879 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Mon, 8 Jan 2024 04:24:31 -0300 Subject: [PATCH 08/26] update outdated/not present error message --- addons/common/XEH_postInit.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index a3749403b21..95df21fe6e0 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -279,7 +279,7 @@ if (isServer) then { // Wait for function to broadcast, then kick client [{ - ["[ACE] ERROR", "ACE is not present", {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] remoteExecCall [QFUNC(errorMessage), _this]; + ["[ACE] ERROR", "ACE is not present or outdated past version 3.X.X", {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] remoteExecCall [QFUNC(errorMessage), _this]; }, _owner, 0.5] call CBA_fnc_waitAndExecute; }; }, _this, 3] call CBA_fnc_waitAndExecute; From cf50c786fd157b91d211b5d934013d45fd32ea5b Mon Sep 17 00:00:00 2001 From: LinkIsGrim Date: Mon, 8 Jan 2024 06:09:41 -0300 Subject: [PATCH 09/26] check version number fixes --- .../common/functions/fnc_checkVersionNumber.sqf | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index f76789a16d9..b86202bd495 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -55,7 +55,7 @@ private _fnc_check = { // Compare client and server files and versions private _client = profileName; - private _missingAddons = []; + private _missingAddonsClient = []; private _oldVersionsClient = []; private _oldVersionsServer = []; @@ -70,7 +70,7 @@ private _fnc_check = { if (_index == -1) then { if (_x != "ace_server") then { - _missingAddons pushBack _x; + _missingAddonsClient pushBack _x; }; } else { _clientVersion = _versions select _index; @@ -102,14 +102,13 @@ private _fnc_check = { private _count = 0; #define DISPLAY_NUMBER_ADDONS (10 + 1) // +1 to account for header - { - params ["_items", "_string"]; + _x params ["_items", "_string"]; // Check if something is either missing or outdated - _missing = _items isNotEqualTo []; + private _isMissingItems = _items isNotEqualTo []; - if (_missing) then { + if (_isMissingItems) then { // Generate error message _errorLog = [format ["[ACE] %1: ERROR %2 addon(s): ", _client, _string]]; @@ -122,16 +121,16 @@ private _fnc_check = { _count = count _items; if (_count > DISPLAY_NUMBER_ADDONS) then { - _errorMsg = _errorMsg + format ["and %1 more.", _count - DISPLAY_NUMBER_ADDONS]; + _errorMsg = _errorMsg + format [", and %1 more.", _count - DISPLAY_NUMBER_ADDONS]; }; // Log and display error messages diag_log text _errorLog; [QGVAR(serverLog), _errorLog] call CBA_fnc_serverEvent; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + [QGVAR(systemChatGlobal), _errorMsg] call CBA_fnc_globalEvent; }; - _clientErrors pushBack _missing; + _clientErrors pushBack _isMissingItems; } forEach [ [_missingAddonsClient, "client missing"], [_missingAddonsServer, "server missing"], From 9168207f541b2e2f6c63344649993d9d1c4b8a0b Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 8 Jan 2024 20:15:35 +0100 Subject: [PATCH 10/26] Update fnc_errorMessage.sqf --- addons/common/functions/fnc_errorMessage.sqf | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index cc47fde8b4d..50791d9aee2 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) - * Stops simulation and opens a textbox with error message. + * Opens a textbox with an error message. * * Arguments: * 0: Header @@ -17,7 +17,7 @@ * None * * Example: - * ["[ACE] ERROR", text "Test", {findDisplay 46 closeDisplay 0}] call ace_common_fnc_errorMessage + * ["[ACE] ERROR", "Test", {findDisplay 46 closeDisplay 0}] call ace_common_fnc_errorMessage * * Public: No */ @@ -38,7 +38,7 @@ if (isNull (call BIS_fnc_displayMission)) exitWith { (_this select 0) call FUNC(errorMessage); [_this select 1] call CBA_fnc_removePerFrameHandler; - }, 1, _this] call CBA_fnc_addPerFrameHandler; + }, 0.25, _this] call CBA_fnc_addPerFrameHandler; }; params ["_textHeader", "_textMessage", ["_onOK", {}, [{}]], ["_onCancel", {}, [{}]], ["_mainDisplay", call BIS_fnc_displayMission, [displayNull]], ["_showButtons", [true, true]]]; @@ -147,16 +147,18 @@ if (!_showCancelButton || {_onCancel isEqualTo {}}) then { ctrlSetFocus _ctrlButtonCancel; }; -_ctrlButtonOK ctrlAddEventHandler ["buttonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}]; -_ctrlButtonCancel ctrlAddEventHandler ["buttonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}]; +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}]; +_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}]; // CBA isn't guaranteed to be loaded -private _ehID = _display displayAddEventHandler ["unload", { +private _ehID = _display displayAddEventHandler ["Unload", { params ["_display", "_exitCode"]; - call ((_display getVariable [QGVAR(errorMessageCode_) + str _thisEventHandler, [{}, {}, {}]]) select _exitCode) + call ((_display getVariable [format [QGVAR(errorMessageCode_%1), _thisEventHandler], createHashMap]) getOrDefault [_exitCode, {}]); }]; -_display setVariable [QGVAR(errorMessageCode_) + str _ehID, [{}, _onOK, _onCancel]]; +// Prevent data from being overwritten +_display setVariable [format [QGVAR(errorMessageCode_%1), _ehID], compileFinal createHashMapFromArray [[1, compileFinal _onOK], [2, compileFinal _onCancel]]]; -_display displayAddEventHandler ["keyDown", {_this select 1 == 1}]; +// Intercept all keystrokes except the esacpe key +_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}]; From 1d08693b3642c1a73c87e3510dcdf9c80c7435f6 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:14:51 +0100 Subject: [PATCH 11/26] Changed error names Server is always right, client has either older or newer versions, or missing or additional addons --- addons/common/functions/fnc_checkPBOs.sqf | 18 ++++++++--------- .../functions/fnc_checkVersionNumber.sqf | 20 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index 37f8355b300..55229edbef9 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -41,31 +41,31 @@ if (!isServer) then { [_thisType, _thisId] call CBA_fnc_removeEventHandler; params ["_clientErrors"]; - _clientErrors params ["_missingAddonClient", "_missingAddonServer", "_oldVersionClient", "_oldVersionServer"]; + _clientErrors params ["_missingAddonClient", "_additionalAddonClient", "_olderVersionClient", "_newerVersionClient"]; _thisArgs params ["_mode"]; // Display error message(s) - if (_missingAddonClient || {_missingAddonServer} || {_oldVersionClient} || {_oldVersionServer}) then { + if (_missingAddonClient || {_additionalAddonClient} || {_olderVersionClient} || {_newerVersionClient}) then { private _errorMsg = "[ACE] Version mismatch:

"; - private _error = format ["ACE version mismatch: %1: ", profileName]; + private _error = format ["[ACE] Version mismatch: %1: ", profileName]; if (_missingAddonClient) then { _errorMsg = _errorMsg + "Detected missing addon on client
"; _error = _error + "Missing file(s); "; }; - if (_missingAddonServer) then { - _errorMsg = _errorMsg + "Detected missing addon on server
"; + if (_additionalAddonClient) then { + _errorMsg = _errorMsg + "Detected additional addon on client
"; _error = _error + "Additional file(s); "; }; - if (_oldVersionClient) then { - _errorMsg = _errorMsg + "Detected old client version
"; + if (_olderVersionClient) then { + _errorMsg = _errorMsg + "Detected older client version
"; _error = _error + "Older version; "; }; - if (_oldVersionServer) then { - _errorMsg = _errorMsg + "Detected old server version
"; + if (_newerVersionClient) then { + _errorMsg = _errorMsg + "Detected newer client version
"; _error = _error + "Newer version; "; }; diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index b86202bd495..5939f12dc12 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -56,8 +56,8 @@ private _fnc_check = { // Compare client and server files and versions private _client = profileName; private _missingAddonsClient = []; - private _oldVersionsClient = []; - private _oldVersionsServer = []; + private _olderVersionsClient = []; + private _newerVersionsClient = []; private _clientVersion = -1; private _serverVersion = -1; @@ -76,21 +76,21 @@ private _fnc_check = { _clientVersion = _versions select _index; if (_clientVersion < _serverVersion) then { - _oldVersionsClient pushBack [_x, _clientVersion, _serverVersion]; + _olderVersionsClient pushBack [_x, _clientVersion, _serverVersion]; }; if (_clientVersion > _serverVersion) then { - _oldVersionsServer pushBack [_x, _clientVersion, _serverVersion]; + _newerVersionsClient pushBack [_x, _clientVersion, _serverVersion]; }; }; } forEach _serverFiles; // Find client files which the server doesn't have - private _missingAddonsServer = []; + private _additionalAddonsClient = []; { if ((_serverFiles find _x) == -1) then { - _missingAddonsServer pushBack _x; + _additionalAddonsClient pushBack _x; }; } forEach _files; @@ -133,12 +133,12 @@ private _fnc_check = { _clientErrors pushBack _isMissingItems; } forEach [ [_missingAddonsClient, "client missing"], - [_missingAddonsServer, "server missing"], - [_oldVersionsClient, "outdated client"], - [_oldVersionsServer, "outdated server"] + [_additionalAddonsClient, "client additional"], + [_olderVersionsClient, "older client"], + [_newerVersionsClient, "newer client"] ]; - TRACE_4("",_missingAddonsClient,_missingAddonsServer,_oldVersionsClient,_oldVersionsServer); + TRACE_4("",_missingAddonsClient,_additionalAddonsClient,_olderVersionsClient,_newerVersionsClient); ACE_Version_ClientErrors = _clientErrors; From c84a7fbc6e5082cb79bd21bbb8d66a60c26018cf Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 10 Jan 2024 09:21:59 +0100 Subject: [PATCH 12/26] Improved ACE detection method --- addons/common/XEH_PREP.hpp | 2 + addons/common/XEH_postInit.sqf | 45 +++-- addons/common/config.cpp | 2 +- .../common/functions/fnc_checkAcePresence.sqf | 36 ++++ .../functions/fnc_checkErrorMessage.sqf | 173 ++++++++++++++++++ addons/common/functions/fnc_checkFiles.sqf | 20 +- addons/common/functions/fnc_checkPBOs.sqf | 2 +- addons/common/functions/fnc_errorMessage.sqf | 17 +- 8 files changed, 257 insertions(+), 40 deletions(-) create mode 100644 addons/common/functions/fnc_checkAcePresence.sqf create mode 100644 addons/common/functions/fnc_checkErrorMessage.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index de5b4d5e3f8..9ccbb505740 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -26,6 +26,8 @@ PREP(canDig); PREP(canGetInPosition); PREP(canInteractWith); PREP(changeProjectileDirection); +PREP(checkAcePresence); +PREP(checkErrorMessage); PREP(checkFiles); PREP(checkFiles_diagnoseACE); PREP(checkPBOs); diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 95df21fe6e0..79ff75159f6 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -263,33 +263,38 @@ if (_currentVersion != _previousVersion) then { call FUNC(checkFiles); -// Let the server know that we have ACE loaded -missionNamespace setVariable [QGVAR(aceLoaded_) + getPlayerUID player, true, 2]; - // This handles clients joining that do not have ACE loaded if (isServer) then { addMissionEventHandler ["PlayerConnected", { - [{ - params ["", "_uid", "", "", "_owner"]; + params ["", "", "", "", "_owner"]; - // If ACE is not loaded, kick unit - if !(missionNamespace getVariable [QGVAR(aceLoaded_) + _uid, false]) then { - // Send function to client - _owner publicVariableClient QFUNC(errorMessage); + private _random = []; - // Wait for function to broadcast, then kick client - [{ - ["[ACE] ERROR", "ACE is not present or outdated past version 3.X.X", {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] remoteExecCall [QFUNC(errorMessage), _this]; - }, _owner, 0.5] call CBA_fnc_waitAndExecute; - }; - }, _this, 3] call CBA_fnc_waitAndExecute; - }]; + // Make a random string of length 64 + for "_i" from 0 to 31 do { + _random pushBack selectRandom GVAR(hexArray); // used GVAR(hexArray) because it was easy to use + }; + + _random = _random joinString ""; + + // Add the random suffix, so that it's much harder for the client to predict the function name and put preventive mesures in place + private _fncNameCheckAcePresence = format [QFUNC(checkAcePresence_%1), _random]; + private _fncNameCheckErrorMessage = format [QFUNC(checkErrorMessage_%1), _random]; + + // Send functions to the connecting client + missionNamespace setVariable [_fncNameCheckAcePresence, /*compile toString */FUNC(checkAcePresence), _owner]; // compile toString removes isFinal status + missionNamespace setVariable [_fncNameCheckErrorMessage, /*compile toString */FUNC(checkErrorMessage), _owner]; + + // Wait for function to broadcast, then run function on client + [{ + params ["_owner", "_fncNameCheckAcePresence", "_fncNameCheckErrorMessage"]; - addMissionEventHandler ["PlayerDisconnected", { - params ["", "_uid"]; + _fncNameCheckErrorMessage remoteExecCall [_fncNameCheckAcePresence, _owner]; - // Reset variable - missionNamespace setVariable [QGVAR(aceLoaded_) + _uid, nil]; + // Delete the functions on the server + //missionNamespace setVariable [_fncNameCheckAcePresence, nil]; + //missionNamespace setVariable [_fncNameCheckErrorMessage, nil]; + }, [_owner, _fncNameCheckAcePresence, _fncNameCheckErrorMessage], 1] call CBA_fnc_waitAndExecute; }]; }; diff --git a/addons/common/config.cpp b/addons/common/config.cpp index 144e7d96c61..88e5a5ca9c3 100644 --- a/addons/common/config.cpp +++ b/addons/common/config.cpp @@ -6,7 +6,7 @@ class CfgPatches { units[] = {"ACE_Box_Misc", "ACE_bananaItem", "ACE_Flag_Black", "ACE_Flag_White"}; weapons[] = {"ACE_ItemCore", "ACE_FakePrimaryWeapon", "ACE_Banana"}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"ace_main","ace_modules"}; + requiredAddons[] = {"ace_main", "ace_modules"}; author = CSTRING(ACETeam); authors[] = {"KoffeinFlummi"}; url = ECSTRING(main,URL); diff --git a/addons/common/functions/fnc_checkAcePresence.sqf b/addons/common/functions/fnc_checkAcePresence.sqf new file mode 100644 index 00000000000..e394c1ed5ff --- /dev/null +++ b/addons/common/functions/fnc_checkAcePresence.sqf @@ -0,0 +1,36 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Used to check if ACE is loaded. If ACE is not present, an error message is shown. + * This function is sent by the server to the client, client runs the function. + * + * Arguments: + * 0: Unique name of the error message function sent by the server + * + * Return Value: + * None + * + * Example: + * "ace_common_fnc_checkErrorMessage" call ace_common_fnc_checkAcePresence + * + * Public: No + */ + +params ["_fncNameCheckErrorMessage"]; + +INFO("Checking for ACE presence"); + +private _cfgPatches = configFile >> "CfgPatches"; + +if ( + getText (_cfgPatches >> "ace_main" >> "versionStr") == "" || + {getText (_cfgPatches >> QUOTE(ADDON) >> "versionStr") == ""} || + {getArray (_cfgPatches >> "cba_main" >> "versionAr") isEqualTo []} || + {getArray (configFile >> "CfgSettings" >> "CBA" >> "Versioning" >> "ACE" >> "dependencies" >> "CBA") isEqualTo []} +) exitWith { + INFO("ACE was not detected"); + + ["[ACE] ERROR", "ACE is not present or outdated past version 3.X.X", _fncNameCheckErrorMessage] call (missionNamespace getVariable [_fncNameCheckErrorMessage, ""]); +}; + +INFO("ACE was detected"); diff --git a/addons/common/functions/fnc_checkErrorMessage.sqf b/addons/common/functions/fnc_checkErrorMessage.sqf new file mode 100644 index 00000000000..4a4a17e5a13 --- /dev/null +++ b/addons/common/functions/fnc_checkErrorMessage.sqf @@ -0,0 +1,173 @@ +#include "..\script_component.hpp" +#include "\a3\ui_f\hpp\defineResincl.inc" +/* + * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) + * Opens a textbox with an error message, used for PBO checking. + * CBA isn't guaranteed to be loaded, so use vanilla functionality only! + * + * Arguments: + * 0: Header + * 1: Text + * 2: Unique name of the error message function sent by the server + * + * Return Value: + * None + * + * Example: + * ["[ACE] ERROR", "Test"] call ace_common_fnc_checkErrorMessage + * + * Public: No + */ + +disableSerialization; + +// Force stop any loading screens +endLoadingScreen; + +// No message without player possible +if (!hasInterface) exitWith {}; + +private _mainDisplay = call BIS_fnc_displayMission; + +// Wait for display +if (isNull _mainDisplay) exitWith { + _this spawn { + params ["", "", "_fncNameCheckErrorMessage"]; + + waitUntil { + uiSleep 0.25; + + !isNull (call BIS_fnc_displayMission) + }; + + _this call (missionNamespace getVariable [_fncNameCheckErrorMessage, ""]); + }; +}; + +params ["_textHeader", "_textMessage"]; + +// Use curator display if present +private _curatorDisplay = findDisplay 312; + +if (!isNull _curatorDisplay) then { + _mainDisplay = _curatorDisplay; +}; + +if (_textMessage isEqualType "") then { + _textMessage = parseText _textMessage; +}; + +private _display = _mainDisplay createDisplay "RscDisplayCommonMessagePause"; + +if (isNull _display) exitWith {}; + +private _ctrlRscMessageBox = _display displayCtrl 2351; +private _ctrlBcgCommonTop = _display displayCtrl 235100; +private _ctrlBcgCommon = _display displayCtrl 235101; +private _ctrlText = _display displayCtrl 235102; +private _ctrlBackgroundButtonOK = _display displayCtrl 235103; +private _ctrlBackgroundButtonMiddle = _display displayCtrl 235104; +private _ctrlBackgroundButtonCancel = _display displayCtrl 235105; +private _ctrlButtonOK = _display displayCtrl 235106; +private _ctrlButtonCancel = _display displayCtrl 235107; + +_ctrlBcgCommonTop ctrlSetText _textHeader; + +private _ctrlButtonOKPos = ctrlPosition _ctrlButtonOK; +private _ctrlBcgCommonPos = ctrlPosition _ctrlBcgCommon; +private _bottomSpaceY = (_ctrlButtonOKPos select 1) - ((_ctrlBcgCommonPos select 1) + (_ctrlBcgCommonPos select 3)); + +private _ctrlTextPos = ctrlPosition _ctrlText; +private _marginX = (_ctrlTextPos select 0) - (_ctrlBcgCommonPos select 0); +private _marginY = (_ctrlTextPos select 1) - (_ctrlBcgCommonPos select 1); + +_ctrlText ctrlSetStructuredText _textMessage; +private _ctrlTextPosH = ctrlTextHeight _ctrlText; + +_ctrlBcgCommon ctrlSetPosition [ + _ctrlBcgCommonPos select 0, + _ctrlBcgCommonPos select 1, + _ctrlBcgCommonPos select 2, + _ctrlTextPosH + _marginY * 2 +]; +_ctrlBcgCommon ctrlCommit 0; + +_ctrlText ctrlSetPosition [ + (_ctrlBcgCommonPos select 0) + _marginX, + (_ctrlBcgCommonPos select 1) + _marginY, + (_ctrlBcgCommonPos select 2) - _marginX * 2, + _ctrlTextPosH +]; +_ctrlText ctrlCommit 0; + +private _bottomPosY = (_ctrlBcgCommonPos select 1) + _ctrlTextPosH + (_marginY * 2) + _bottomSpaceY; + +{ + private _xPos = ctrlPosition _x; + + _xPos set [1, _bottomPosY]; + _x ctrlSetPosition _xPos; + _x ctrlCommit 0; +} forEach [ + _ctrlBackgroundButtonOK, + _ctrlBackgroundButtonMiddle, + _ctrlBackgroundButtonCancel, + _ctrlButtonOK, + _ctrlButtonCancel +]; + +private _ctrlRscMessageBoxPos = ctrlPosition _ctrlRscMessageBox; +private _ctrlRscMessageBoxPosH = _bottomPosY + (_ctrlButtonOKPos select 3); + +_ctrlRscMessageBox ctrlSetPosition [ + 0.5 - (_ctrlBcgCommonPos select 2) / 2, + 0.5 - _ctrlRscMessageBoxPosH / 2, + (_ctrlBcgCommonPos select 2) + 0.5, + _ctrlRscMessageBoxPosH +]; + +_ctrlRscMessageBox ctrlEnable true; +_ctrlRscMessageBox ctrlCommit 0; + +// Enable ok button +_ctrlButtonOK ctrlEnable true; +_ctrlButtonOK ctrlSetFade 0; +_ctrlButtonOK ctrlSetText localize "STR_DISP_OK"; +_ctrlButtonOK ctrlCommit 0; + +ctrlSetFocus _ctrlButtonOK; + +// Disable cancel button +_ctrlButtonCancel ctrlEnable false; +_ctrlButtonCancel ctrlSetFade 0; +_ctrlButtonCancel ctrlSetText ""; +_ctrlButtonCancel ctrlCommit 0; + +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; +_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_CANCEL; true}]; + +// Intercept all keystrokes except the esacpe key +_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}]; + +// If BIS_fnc_guiMessage is called while the display is opened, the "Unload" display EH will be lost and won't fire +[_display] spawn { + disableSerialization; + + params ["_display"]; + + // Wait until the display has been closed + waitUntil { + uiSleep 0.25; + + !isNull _display; + }; + + // Just to be safe + endLoadingScreen; + + // Close curator and mission displays + findDisplay 312 closeDisplay 0; + findDisplay 46 closeDisplay 0; +}; + +nil diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index cce022722e6..12c8ddaaac5 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -15,10 +15,10 @@ * Public: No */ - // Don't execute in scheduled environment - if (canSuspend) exitWith { - [FUNC(checkFiles), nil] call CBA_fnc_directCall; - }; +// Don't execute in scheduled environment +if (canSuspend) exitWith { + [FUNC(checkFiles), nil] call CBA_fnc_directCall; +}; /////////////// // Check addons @@ -41,7 +41,7 @@ if ([_cbaRequiredAr, _cbaVersionAr] call CBA_versioning_fnc_version_compare) the ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); }; }; @@ -87,7 +87,7 @@ if (_oldAddons isNotEqualTo []) then { }; if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); }; ERROR(_errorMsg); @@ -141,7 +141,7 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); }; } else { // Print the current extension version @@ -185,14 +185,14 @@ if (isMultiplayer) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); }; }; private _addons = GVAR(clientAddons) - GVAR(serverAddons); if (_addons isNotEqualTo []) then { - private _errorMsg = format ["Client/Server Addon Mismatch. Client has extra addons: %1. Server modDir: %2", _addons, GVAR(serverSource)]; + private _errorMsg = format ["Client/Server Addon Mismatch. Client has additional addons: %1. Server modDir: %2", _addons, GVAR(serverSource)]; // Check ACE install call FUNC(checkFiles_diagnoseACE); @@ -200,7 +200,7 @@ if (isMultiplayer) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); }; }; }; diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index 55229edbef9..63b6fabc36d 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -94,7 +94,7 @@ if (!isServer) then { [{alive player}, { TRACE_2("Player is alive, showing msg and exiting",time,_this); private _errorMsg = composeText [parseText format ["%1", _this]]; - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}, {findDisplay 46 closeDisplay 0}, nil, [true, false]] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); }, _errorMsg] call CBA_fnc_waitUntilAndExecute; }; }; diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index 50791d9aee2..104a9cfb388 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -1,4 +1,5 @@ #include "..\script_component.hpp" +#include "\a3\ui_f\hpp\defineResincl.inc" /* * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) * Opens a textbox with an error message. @@ -48,9 +49,10 @@ if (_textMessage isEqualType "") then { _textMessage = parseText _textMessage; }; -_mainDisplay createDisplay "RscDisplayCommonMessagePause"; +private _display = _mainDisplay createDisplay "RscDisplayCommonMessagePause"; + +if (isNull _display) exitWith {}; -private _display = uiNamespace getVariable "RscDisplayCommonMessage_display"; private _ctrlRscMessageBox = _display displayCtrl 2351; private _ctrlBcgCommonTop = _display displayCtrl 235100; private _ctrlBcgCommon = _display displayCtrl 235101; @@ -147,10 +149,12 @@ if (!_showCancelButton || {_onCancel isEqualTo {}}) then { ctrlSetFocus _ctrlButtonCancel; }; -_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}]; -_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}]; +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; +_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_CANCEL; true}]; + +// Intercept all keystrokes except the esacpe key +_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}]; -// CBA isn't guaranteed to be loaded private _ehID = _display displayAddEventHandler ["Unload", { params ["_display", "_exitCode"]; @@ -159,6 +163,3 @@ private _ehID = _display displayAddEventHandler ["Unload", { // Prevent data from being overwritten _display setVariable [format [QGVAR(errorMessageCode_%1), _ehID], compileFinal createHashMapFromArray [[1, compileFinal _onOK], [2, compileFinal _onCancel]]]; - -// Intercept all keystrokes except the esacpe key -_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}]; From dd84f2fa359deca936385cfb0cb50a39aebf9184 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 10 Jan 2024 10:50:06 +0100 Subject: [PATCH 13/26] Tweaks and fixes --- addons/common/XEH_postInit.sqf | 3 ++ .../functions/fnc_checkErrorMessage.sqf | 32 +++++++++++-------- addons/common/functions/fnc_errorMessage.sqf | 5 +-- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 79ff75159f6..bd3795eb3c7 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -268,6 +268,9 @@ if (isServer) then { addMissionEventHandler ["PlayerConnected", { params ["", "", "", "", "_owner"]; + // Don't run on server + if (_owner == 2) exitWith {}; + private _random = []; // Make a random string of length 64 diff --git a/addons/common/functions/fnc_checkErrorMessage.sqf b/addons/common/functions/fnc_checkErrorMessage.sqf index 4a4a17e5a13..9825a6b4909 100644 --- a/addons/common/functions/fnc_checkErrorMessage.sqf +++ b/addons/common/functions/fnc_checkErrorMessage.sqf @@ -1,5 +1,6 @@ #include "..\script_component.hpp" #include "\a3\ui_f\hpp\defineResincl.inc" +#include "\a3\ui_f\hpp\defineDIKCodes.inc" /* * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) * Opens a textbox with an error message, used for PBO checking. @@ -144,30 +145,35 @@ _ctrlButtonCancel ctrlSetText ""; _ctrlButtonCancel ctrlCommit 0; _ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; -_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_CANCEL; true}]; -// Intercept all keystrokes except the esacpe key -_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}]; +// Intercept all keystrokes except the enter keys +_display displayAddEventHandler ["KeyDown", {!((_this select 1) in [DIK_RETURN, DIK_NUMPADENTER])}]; + +// Close curator and mission displays (because of the message display, it doesn't quit the mission yet) +findDisplay 312 closeDisplay 0; +findDisplay 46 closeDisplay 0; -// If BIS_fnc_guiMessage is called while the display is opened, the "Unload" display EH will be lost and won't fire [_display] spawn { + // Limitation: This can't close error message boxes (e.g. "No entry") disableSerialization; params ["_display"]; - // Wait until the display has been closed - waitUntil { - uiSleep 0.25; + // This sleep will work when game is paused + uiSleep 17.5; - !isNull _display; + // Close display automatically + if (!isNull _display) then { + _display closeDisplay IDC_OK; }; - // Just to be safe - endLoadingScreen; + uiSleep 2.5; - // Close curator and mission displays - findDisplay 312 closeDisplay 0; - findDisplay 46 closeDisplay 0; + // Close any other BIS_fnc_guiMessage messages that could be open + if (!isNull findDisplay 46) then { + uiNamespace setVariable ["BIS_fnc_guiMessage_status", true]; + findDisplay 46 closeDisplay 0; + }; }; nil diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index 104a9cfb388..326c2da6697 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -1,5 +1,6 @@ #include "..\script_component.hpp" #include "\a3\ui_f\hpp\defineResincl.inc" +#include "\a3\ui_f\hpp\defineDIKCodes.inc" /* * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) * Opens a textbox with an error message. @@ -152,8 +153,8 @@ if (!_showCancelButton || {_onCancel isEqualTo {}}) then { _ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; _ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_CANCEL; true}]; -// Intercept all keystrokes except the esacpe key -_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}]; +// Intercept the escape key +_display displayAddEventHandler ["KeyDown", {_this select 1 == DIK_ESCAPE}]; private _ehID = _display displayAddEventHandler ["Unload", { params ["_display", "_exitCode"]; From 551437329fcdce3bfb62aaa74785f757079ff9c7 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 11 Jan 2024 00:24:02 +0100 Subject: [PATCH 14/26] Try another approach --- addons/common/XEH_PREP.hpp | 2 - addons/common/XEH_postInit.sqf | 56 ++++-- addons/common/XEH_preInit.sqf | 5 + .../common/functions/fnc_checkAcePresence.sqf | 36 ---- .../functions/fnc_checkErrorMessage.sqf | 179 ------------------ addons/common/functions/fnc_checkFiles.sqf | 10 +- addons/common/functions/fnc_checkPBOs.sqf | 2 +- addons/common/functions/fnc_errorMessage.sqf | 94 ++++----- 8 files changed, 85 insertions(+), 299 deletions(-) delete mode 100644 addons/common/functions/fnc_checkAcePresence.sqf delete mode 100644 addons/common/functions/fnc_checkErrorMessage.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index 9ccbb505740..de5b4d5e3f8 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -26,8 +26,6 @@ PREP(canDig); PREP(canGetInPosition); PREP(canInteractWith); PREP(changeProjectileDirection); -PREP(checkAcePresence); -PREP(checkErrorMessage); PREP(checkFiles); PREP(checkFiles_diagnoseACE); PREP(checkPBOs); diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index bd3795eb3c7..1d7ff321c53 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -266,38 +266,52 @@ call FUNC(checkFiles); // This handles clients joining that do not have ACE loaded if (isServer) then { addMissionEventHandler ["PlayerConnected", { - params ["", "", "", "", "_owner"]; + params ["", "_uid", "_name", "", "_owner"]; // Don't run on server if (_owner == 2) exitWith {}; - private _random = []; + INFO_3("Client %1 connected. UID is %2, Client ID is %3",_name,_uid,_owner); - // Make a random string of length 64 - for "_i" from 0 to 31 do { - _random pushBack selectRandom GVAR(hexArray); // used GVAR(hexArray) because it was easy to use - }; + [{ + params ["", "_uid", "_name", "", "_owner"]; - _random = _random joinString ""; + // If the player has left, ignore the rest + if (allUsers findIf {_userInfo = getUserInfo _x; (_userInfo select 1) == _owner && {(_userInfo select 2) == _uid}} == -1) exitWith {}; - // Add the random suffix, so that it's much harder for the client to predict the function name and put preventive mesures in place - private _fncNameCheckAcePresence = format [QFUNC(checkAcePresence_%1), _random]; - private _fncNameCheckErrorMessage = format [QFUNC(checkErrorMessage_%1), _random]; + // If ACE is not loaded, kick unit + if !(missionNamespace getVariable [format [QGVAR(aceLoaded_%1), _owner], false]) then { + WARNING_3("Client %1 connected without ACE. UID is %2, Client ID is %3",_name,_uid,_owner); - // Send functions to the connecting client - missionNamespace setVariable [_fncNameCheckAcePresence, /*compile toString */FUNC(checkAcePresence), _owner]; // compile toString removes isFinal status - missionNamespace setVariable [_fncNameCheckErrorMessage, /*compile toString */FUNC(checkErrorMessage), _owner]; + private _random = []; - // Wait for function to broadcast, then run function on client - [{ - params ["_owner", "_fncNameCheckAcePresence", "_fncNameCheckErrorMessage"]; + // Make a random string of length 32 + for "_i" from 0 to 15 do { + _random pushBack selectRandom GVAR(hexArray); // used GVAR(hexArray) because it was easy to use + }; + + // Add the random string as a suffix, so that it's much harder for the client to predict the function name and put preventive measures in place + private _fncName = format [QFUNC(errorMessage_%1), _random joinString ""]; - _fncNameCheckErrorMessage remoteExecCall [_fncNameCheckAcePresence, _owner]; + // This avoids 'Attempt to delete final function' error spammed in RPT, which happens if a final function is sent directly to the client + missionNamespace setVariable [_fncName, FUNC(errorMessage)]; + + // Send function to the connecting client + _owner publicVariableClient _fncName; + + // Wait for function to broadcast, then run function on client + [{ + ["[ACE] ERROR", "ACE is not present or outdated past version 3.X.X"] remoteExec _this; + }, [_fncName, _owner], 0.5] call CBA_fnc_waitAndExecute; + }; + }, _this, 15] call CBA_fnc_waitAndExecute; + }]; + + addMissionEventHandler ["PlayerDisconnected", { + params ["", "", "", "", "_owner"]; - // Delete the functions on the server - //missionNamespace setVariable [_fncNameCheckAcePresence, nil]; - //missionNamespace setVariable [_fncNameCheckErrorMessage, nil]; - }, [_owner, _fncNameCheckAcePresence, _fncNameCheckErrorMessage], 1] call CBA_fnc_waitAndExecute; + // Reset variable + missionNamespace setVariable [format [QGVAR(aceLoaded_%1), _owner], nil]; }]; }; diff --git a/addons/common/XEH_preInit.sqf b/addons/common/XEH_preInit.sqf index 78c08d5e428..a910f255c99 100644 --- a/addons/common/XEH_preInit.sqf +++ b/addons/common/XEH_preInit.sqf @@ -7,6 +7,11 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +// Let the server know that we have ACE loaded +if (!isServer) then { + missionNamespace setVariable [format [QGVAR(aceLoaded_%1), clientOwner], true, 2]; +}; + GVAR(syncedEvents) = createHashMap; GVAR(showHudHash) = createHashMap; GVAR(vehicleIconCache) = createHashMap; // for getVehicleIcon diff --git a/addons/common/functions/fnc_checkAcePresence.sqf b/addons/common/functions/fnc_checkAcePresence.sqf deleted file mode 100644 index e394c1ed5ff..00000000000 --- a/addons/common/functions/fnc_checkAcePresence.sqf +++ /dev/null @@ -1,36 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: johnb43 - * Used to check if ACE is loaded. If ACE is not present, an error message is shown. - * This function is sent by the server to the client, client runs the function. - * - * Arguments: - * 0: Unique name of the error message function sent by the server - * - * Return Value: - * None - * - * Example: - * "ace_common_fnc_checkErrorMessage" call ace_common_fnc_checkAcePresence - * - * Public: No - */ - -params ["_fncNameCheckErrorMessage"]; - -INFO("Checking for ACE presence"); - -private _cfgPatches = configFile >> "CfgPatches"; - -if ( - getText (_cfgPatches >> "ace_main" >> "versionStr") == "" || - {getText (_cfgPatches >> QUOTE(ADDON) >> "versionStr") == ""} || - {getArray (_cfgPatches >> "cba_main" >> "versionAr") isEqualTo []} || - {getArray (configFile >> "CfgSettings" >> "CBA" >> "Versioning" >> "ACE" >> "dependencies" >> "CBA") isEqualTo []} -) exitWith { - INFO("ACE was not detected"); - - ["[ACE] ERROR", "ACE is not present or outdated past version 3.X.X", _fncNameCheckErrorMessage] call (missionNamespace getVariable [_fncNameCheckErrorMessage, ""]); -}; - -INFO("ACE was detected"); diff --git a/addons/common/functions/fnc_checkErrorMessage.sqf b/addons/common/functions/fnc_checkErrorMessage.sqf deleted file mode 100644 index 9825a6b4909..00000000000 --- a/addons/common/functions/fnc_checkErrorMessage.sqf +++ /dev/null @@ -1,179 +0,0 @@ -#include "..\script_component.hpp" -#include "\a3\ui_f\hpp\defineResincl.inc" -#include "\a3\ui_f\hpp\defineDIKCodes.inc" -/* - * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) - * Opens a textbox with an error message, used for PBO checking. - * CBA isn't guaranteed to be loaded, so use vanilla functionality only! - * - * Arguments: - * 0: Header - * 1: Text - * 2: Unique name of the error message function sent by the server - * - * Return Value: - * None - * - * Example: - * ["[ACE] ERROR", "Test"] call ace_common_fnc_checkErrorMessage - * - * Public: No - */ - -disableSerialization; - -// Force stop any loading screens -endLoadingScreen; - -// No message without player possible -if (!hasInterface) exitWith {}; - -private _mainDisplay = call BIS_fnc_displayMission; - -// Wait for display -if (isNull _mainDisplay) exitWith { - _this spawn { - params ["", "", "_fncNameCheckErrorMessage"]; - - waitUntil { - uiSleep 0.25; - - !isNull (call BIS_fnc_displayMission) - }; - - _this call (missionNamespace getVariable [_fncNameCheckErrorMessage, ""]); - }; -}; - -params ["_textHeader", "_textMessage"]; - -// Use curator display if present -private _curatorDisplay = findDisplay 312; - -if (!isNull _curatorDisplay) then { - _mainDisplay = _curatorDisplay; -}; - -if (_textMessage isEqualType "") then { - _textMessage = parseText _textMessage; -}; - -private _display = _mainDisplay createDisplay "RscDisplayCommonMessagePause"; - -if (isNull _display) exitWith {}; - -private _ctrlRscMessageBox = _display displayCtrl 2351; -private _ctrlBcgCommonTop = _display displayCtrl 235100; -private _ctrlBcgCommon = _display displayCtrl 235101; -private _ctrlText = _display displayCtrl 235102; -private _ctrlBackgroundButtonOK = _display displayCtrl 235103; -private _ctrlBackgroundButtonMiddle = _display displayCtrl 235104; -private _ctrlBackgroundButtonCancel = _display displayCtrl 235105; -private _ctrlButtonOK = _display displayCtrl 235106; -private _ctrlButtonCancel = _display displayCtrl 235107; - -_ctrlBcgCommonTop ctrlSetText _textHeader; - -private _ctrlButtonOKPos = ctrlPosition _ctrlButtonOK; -private _ctrlBcgCommonPos = ctrlPosition _ctrlBcgCommon; -private _bottomSpaceY = (_ctrlButtonOKPos select 1) - ((_ctrlBcgCommonPos select 1) + (_ctrlBcgCommonPos select 3)); - -private _ctrlTextPos = ctrlPosition _ctrlText; -private _marginX = (_ctrlTextPos select 0) - (_ctrlBcgCommonPos select 0); -private _marginY = (_ctrlTextPos select 1) - (_ctrlBcgCommonPos select 1); - -_ctrlText ctrlSetStructuredText _textMessage; -private _ctrlTextPosH = ctrlTextHeight _ctrlText; - -_ctrlBcgCommon ctrlSetPosition [ - _ctrlBcgCommonPos select 0, - _ctrlBcgCommonPos select 1, - _ctrlBcgCommonPos select 2, - _ctrlTextPosH + _marginY * 2 -]; -_ctrlBcgCommon ctrlCommit 0; - -_ctrlText ctrlSetPosition [ - (_ctrlBcgCommonPos select 0) + _marginX, - (_ctrlBcgCommonPos select 1) + _marginY, - (_ctrlBcgCommonPos select 2) - _marginX * 2, - _ctrlTextPosH -]; -_ctrlText ctrlCommit 0; - -private _bottomPosY = (_ctrlBcgCommonPos select 1) + _ctrlTextPosH + (_marginY * 2) + _bottomSpaceY; - -{ - private _xPos = ctrlPosition _x; - - _xPos set [1, _bottomPosY]; - _x ctrlSetPosition _xPos; - _x ctrlCommit 0; -} forEach [ - _ctrlBackgroundButtonOK, - _ctrlBackgroundButtonMiddle, - _ctrlBackgroundButtonCancel, - _ctrlButtonOK, - _ctrlButtonCancel -]; - -private _ctrlRscMessageBoxPos = ctrlPosition _ctrlRscMessageBox; -private _ctrlRscMessageBoxPosH = _bottomPosY + (_ctrlButtonOKPos select 3); - -_ctrlRscMessageBox ctrlSetPosition [ - 0.5 - (_ctrlBcgCommonPos select 2) / 2, - 0.5 - _ctrlRscMessageBoxPosH / 2, - (_ctrlBcgCommonPos select 2) + 0.5, - _ctrlRscMessageBoxPosH -]; - -_ctrlRscMessageBox ctrlEnable true; -_ctrlRscMessageBox ctrlCommit 0; - -// Enable ok button -_ctrlButtonOK ctrlEnable true; -_ctrlButtonOK ctrlSetFade 0; -_ctrlButtonOK ctrlSetText localize "STR_DISP_OK"; -_ctrlButtonOK ctrlCommit 0; - -ctrlSetFocus _ctrlButtonOK; - -// Disable cancel button -_ctrlButtonCancel ctrlEnable false; -_ctrlButtonCancel ctrlSetFade 0; -_ctrlButtonCancel ctrlSetText ""; -_ctrlButtonCancel ctrlCommit 0; - -_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; - -// Intercept all keystrokes except the enter keys -_display displayAddEventHandler ["KeyDown", {!((_this select 1) in [DIK_RETURN, DIK_NUMPADENTER])}]; - -// Close curator and mission displays (because of the message display, it doesn't quit the mission yet) -findDisplay 312 closeDisplay 0; -findDisplay 46 closeDisplay 0; - -[_display] spawn { - // Limitation: This can't close error message boxes (e.g. "No entry") - disableSerialization; - - params ["_display"]; - - // This sleep will work when game is paused - uiSleep 17.5; - - // Close display automatically - if (!isNull _display) then { - _display closeDisplay IDC_OK; - }; - - uiSleep 2.5; - - // Close any other BIS_fnc_guiMessage messages that could be open - if (!isNull findDisplay 46) then { - uiNamespace setVariable ["BIS_fnc_guiMessage_status", true]; - findDisplay 46 closeDisplay 0; - }; -}; - -nil diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index 12c8ddaaac5..bc7145518d5 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -41,7 +41,7 @@ if ([_cbaRequiredAr, _cbaVersionAr] call CBA_versioning_fnc_version_compare) the ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); + ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); }; }; @@ -87,7 +87,7 @@ if (_oldAddons isNotEqualTo []) then { }; if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); + ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); }; ERROR(_errorMsg); @@ -141,7 +141,7 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); + ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); }; } else { // Print the current extension version @@ -185,7 +185,7 @@ if (isMultiplayer) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); + ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); }; }; @@ -200,7 +200,7 @@ if (isMultiplayer) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); + ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); }; }; }; diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index 63b6fabc36d..e3a8e6aae87 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -94,7 +94,7 @@ if (!isServer) then { [{alive player}, { TRACE_2("Player is alive, showing msg and exiting",time,_this); private _errorMsg = composeText [parseText format ["%1", _this]]; - ["[ACE] ERROR", _errorMsg] call FUNC(checkErrorMessage); + ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); }, _errorMsg] call CBA_fnc_waitUntilAndExecute; }; }; diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index 326c2da6697..7746d3e0756 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -3,48 +3,52 @@ #include "\a3\ui_f\hpp\defineDIKCodes.inc" /* * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) - * Opens a textbox with an error message. + * Opens a textbox with an error message, used for PBO checking. + * This function is sent by the server to the client, client runs the function. + * CBA isn't guaranteed to be loaded, so use vanilla functionality only! * * Arguments: * 0: Header * 1: Text - * 2: Code that is executed when 'Ok' is pressed (default: {}) - * 3: Code that is executed when 'Cancel' is pressed (default: {}) - * 4: Display (default: call BIS_fnc_displayMission) - * 5: Show buttons - * - 0: Show ok button if ok has code (default: true) - * - 1: Show cancel button if cancel has code (default: true) * * Return Value: * None * * Example: - * ["[ACE] ERROR", "Test", {findDisplay 46 closeDisplay 0}] call ace_common_fnc_errorMessage + * ["[ACE] ERROR", "Test"] spawn ace_common_fnc_errorMessage * * Public: No */ -disableSerialization; - // Force stop any loading screens endLoadingScreen; // No message without player possible if (!hasInterface) exitWith {}; +params ["_textHeader", "_textMessage"]; + +disableSerialization; + +private _mainDisplay = call BIS_fnc_displayMission; + // Wait for display -if (isNull (call BIS_fnc_displayMission)) exitWith { - [{ - if (isNull (call BIS_fnc_displayMission)) exitWith {}; +if (isNull _mainDisplay) then { + waitUntil { + uiSleep 0.25; - (_this select 0) call FUNC(errorMessage); - [_this select 1] call CBA_fnc_removePerFrameHandler; + _mainDisplay = call BIS_fnc_displayMission; - }, 0.25, _this] call CBA_fnc_addPerFrameHandler; + !isNull _mainDisplay + }; }; -params ["_textHeader", "_textMessage", ["_onOK", {}, [{}]], ["_onCancel", {}, [{}]], ["_mainDisplay", call BIS_fnc_displayMission, [displayNull]], ["_showButtons", [true, true]]]; -_showButtons params [["_showOkButton", true, [false]], ["_showCancelButton", true, [false]]]; +// Use curator display if present +private _curatorDisplay = findDisplay 312; + +if (!isNull _curatorDisplay) then { + _mainDisplay = _curatorDisplay; +}; if (_textMessage isEqualType "") then { _textMessage = parseText _textMessage; @@ -122,45 +126,25 @@ _ctrlRscMessageBox ctrlSetPosition [ _ctrlRscMessageBox ctrlEnable true; _ctrlRscMessageBox ctrlCommit 0; -if (!_showOkButton || {_onOK isEqualTo {}}) then { - _ctrlButtonOK ctrlEnable false; - _ctrlButtonOK ctrlSetFade 0; - _ctrlButtonOK ctrlSetText ""; - _ctrlButtonOK ctrlCommit 0; -} else { - _ctrlButtonOK ctrlEnable true; - _ctrlButtonOK ctrlSetFade 0; - _ctrlButtonOK ctrlSetText localize "STR_DISP_OK"; - _ctrlButtonOK ctrlCommit 0; - - ctrlSetFocus _ctrlButtonOK; -}; - -if (!_showCancelButton || {_onCancel isEqualTo {}}) then { - _ctrlButtonCancel ctrlEnable false; - _ctrlButtonCancel ctrlSetFade 0; - _ctrlButtonCancel ctrlSetText ""; - _ctrlButtonCancel ctrlCommit 0; -} else { - _ctrlButtonCancel ctrlEnable true; - _ctrlButtonCancel ctrlSetFade 0; - _ctrlButtonCancel ctrlSetText localize "STR_DISP_CANCEL"; - _ctrlButtonCancel ctrlCommit 0; - - ctrlSetFocus _ctrlButtonCancel; -}; +// Enable ok button +_ctrlButtonOK ctrlEnable true; +_ctrlButtonOK ctrlSetFade 0; +_ctrlButtonOK ctrlSetText localize "STR_DISP_OK"; +_ctrlButtonOK ctrlCommit 0; -_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; -_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_CANCEL; true}]; +ctrlSetFocus _ctrlButtonOK; -// Intercept the escape key -_display displayAddEventHandler ["KeyDown", {_this select 1 == DIK_ESCAPE}]; +// Disable cancel button +_ctrlButtonCancel ctrlEnable false; +_ctrlButtonCancel ctrlSetFade 0; +_ctrlButtonCancel ctrlSetText ""; +_ctrlButtonCancel ctrlCommit 0; -private _ehID = _display displayAddEventHandler ["Unload", { - params ["_display", "_exitCode"]; +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; - call ((_display getVariable [format [QGVAR(errorMessageCode_%1), _thisEventHandler], createHashMap]) getOrDefault [_exitCode, {}]); -}]; +// Intercept all keystrokes except the enter keys +_display displayAddEventHandler ["KeyDown", {!((_this select 1) in [DIK_RETURN, DIK_NUMPADENTER])}]; -// Prevent data from being overwritten -_display setVariable [format [QGVAR(errorMessageCode_%1), _ehID], compileFinal createHashMapFromArray [[1, compileFinal _onOK], [2, compileFinal _onCancel]]]; +// Close curator and mission displays (because of the message display, it doesn't quit the mission yet) +findDisplay 312 closeDisplay 0; +findDisplay 46 closeDisplay 0; From a9fa625f17bd6627e25b4f3242f89af78b0e5691 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 11 Jan 2024 00:41:50 +0100 Subject: [PATCH 15/26] Update events-framework.md --- docs/wiki/framework/events-framework.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/wiki/framework/events-framework.md b/docs/wiki/framework/events-framework.md index c29f271719c..12a2ba7ea34 100644 --- a/docs/wiki/framework/events-framework.md +++ b/docs/wiki/framework/events-framework.md @@ -30,6 +30,8 @@ The vehicle events will also have the following local variables available `_gunn |`ace_firedPlayerVehicle` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | ACE_player turret fires |`ace_firedPlayerVehicleNonLocal` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | Any other player turret fires |`ace_firedNonPlayerVehicle` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | AI turret fires +|`ace_versioning_clientCheckDone` | [[_missingAddonsClient, _additionalAddonsClient, _olderVersionsClient, _newerVersionsClient]] | Local | Listen | When PBO checking has finished on a client +|`ace_versioning_serverCheckDone` | [[_serverFiles, _serverVersions]] | Local | Listen | When PBO checking has finished on the server ### 2.2 Medical (`ace_medical`) From c45344a342739804e2ecf98c0eeb6fc78643ab43 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:55:39 +0100 Subject: [PATCH 16/26] Update XEH_postInit.sqf --- addons/common/XEH_postInit.sqf | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index f7c30b6be26..a5af12a405d 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -283,15 +283,8 @@ if (isServer) then { if !(missionNamespace getVariable [format [QGVAR(aceLoaded_%1), _owner], false]) then { WARNING_3("Client %1 connected without ACE. UID is %2, Client ID is %3",_name,_uid,_owner); - private _random = []; - - // Make a random string of length 32 - for "_i" from 0 to 15 do { - _random pushBack selectRandom GVAR(hexArray); // used GVAR(hexArray) because it was easy to use - }; - - // Add the random string as a suffix, so that it's much harder for the client to predict the function name and put preventive measures in place - private _fncName = format [QFUNC(errorMessage_%1), _random joinString ""]; + // Add a UUID as a suffix, so that it's much harder for the client to predict the function name and put preventive measures in place + private _fncName = format [QFUNC(errorMessage_%1), call CBA_fnc_createUUID]; // This avoids 'Attempt to delete final function' error spammed in RPT, which happens if a final function is sent directly to the client missionNamespace setVariable [_fncName, FUNC(errorMessage)]; From 6b2e036ce54c6dece39e9ff10708f68532492d3a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 24 Mar 2024 11:47:25 +0100 Subject: [PATCH 17/26] Update fnc_checkVersionNumber.sqf --- addons/common/functions/fnc_checkVersionNumber.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index 5939f12dc12..7eb9572f4b9 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -25,7 +25,7 @@ params [["_whitelist", missionNamespace getVariable ["ACE_Version_Whitelist", [] private _files = CBA_common_addons select { (_x select [0, 3] != "a3_") && {_x select [0, 4] != "ace_"} && - {!((toLower _x) in _whitelist)} + {!((toLowerANSI _x) in _whitelist)} }; private _cfgPatches = configFile >> "CfgPatches"; From c21c5cae939f296a426d2a6725cf6433cf1ccb98 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 24 Mar 2024 23:02:55 +0100 Subject: [PATCH 18/26] Removed check for non-ACE clients --- addons/common/XEH_postInit.sqf | 45 ---------------------------------- addons/common/XEH_preInit.sqf | 5 ---- 2 files changed, 50 deletions(-) diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index c3cb0116a05..56f6f5b3ac0 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -263,51 +263,6 @@ if (_currentVersion != _previousVersion) then { call FUNC(checkFiles); -// This handles clients joining that do not have ACE loaded -if (isServer) then { - addMissionEventHandler ["PlayerConnected", { - params ["", "_uid", "_name", "", "_owner"]; - - // Don't run on server - if (_owner == 2) exitWith {}; - - INFO_3("Client %1 connected. UID is %2, Client ID is %3",_name,_uid,_owner); - - [{ - params ["", "_uid", "_name", "", "_owner"]; - - // If the player has left, ignore the rest - if (allUsers findIf {_userInfo = getUserInfo _x; (_userInfo select 1) == _owner && {(_userInfo select 2) == _uid}} == -1) exitWith {}; - - // If ACE is not loaded, kick unit - if !(missionNamespace getVariable [format [QGVAR(aceLoaded_%1), _owner], false]) then { - WARNING_3("Client %1 connected without ACE. UID is %2, Client ID is %3",_name,_uid,_owner); - - // Add a UUID as a suffix, so that it's much harder for the client to predict the function name and put preventive measures in place - private _fncName = format [QFUNC(errorMessage_%1), call CBA_fnc_createUUID]; - - // This avoids 'Attempt to delete final function' error spammed in RPT, which happens if a final function is sent directly to the client - missionNamespace setVariable [_fncName, FUNC(errorMessage)]; - - // Send function to the connecting client - _owner publicVariableClient _fncName; - - // Wait for function to broadcast, then run function on client - [{ - ["[ACE] ERROR", "ACE is not present or outdated past version 3.X.X"] remoteExec _this; - }, [_fncName, _owner], 0.5] call CBA_fnc_waitAndExecute; - }; - }, _this, 15] call CBA_fnc_waitAndExecute; - }]; - - addMissionEventHandler ["PlayerDisconnected", { - params ["", "", "", "", "_owner"]; - - // Reset variable - missionNamespace setVariable [format [QGVAR(aceLoaded_%1), _owner], nil]; - }]; -}; - ////////////////////////////////////////////////// // Set up ace_settingsInitialized eventhandler ////////////////////////////////////////////////// diff --git a/addons/common/XEH_preInit.sqf b/addons/common/XEH_preInit.sqf index e4ab6421d62..9b5d27d12ca 100644 --- a/addons/common/XEH_preInit.sqf +++ b/addons/common/XEH_preInit.sqf @@ -7,11 +7,6 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; -// Let the server know that we have ACE loaded -if (!isServer) then { - missionNamespace setVariable [format [QGVAR(aceLoaded_%1), clientOwner], true, 2]; -}; - GVAR(syncedEvents) = createHashMap; GVAR(showHudHash) = createHashMap; GVAR(vehicleIconCache) = createHashMap; // for getVehicleIcon From a45c37a9fada127f5e45ff858f44e9dd2ecd0513 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 24 Mar 2024 23:04:23 +0100 Subject: [PATCH 19/26] Update XEH_postInit.sqf --- addons/common/XEH_postInit.sqf | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 56f6f5b3ac0..cf1f4b6fe0e 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -263,6 +263,7 @@ if (_currentVersion != _previousVersion) then { call FUNC(checkFiles); + ////////////////////////////////////////////////// // Set up ace_settingsInitialized eventhandler ////////////////////////////////////////////////// From 59f189b27b324d6db179144dab3fba0aab5bd2b8 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 1 Apr 2024 20:18:33 +0200 Subject: [PATCH 20/26] Cleanup --- addons/common/functions/fnc_checkFiles.sqf | 10 +- .../functions/fnc_checkFiles_diagnoseACE.sqf | 4 +- addons/common/functions/fnc_checkPBOs.sqf | 7 +- .../functions/fnc_checkVersionNumber.sqf | 10 +- addons/common/functions/fnc_errorMessage.sqf | 231 +++++++++--------- 5 files changed, 122 insertions(+), 140 deletions(-) diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index a112efe7818..31fc2e7e460 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -41,7 +41,7 @@ if ([_cbaRequiredAr, _cbaVersionAr] call CBA_versioning_fnc_version_compare) the ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; }; @@ -87,7 +87,7 @@ if (_oldAddons isNotEqualTo []) then { }; if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; ERROR(_errorMsg); @@ -141,7 +141,7 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; } else { // Print the current extension version @@ -185,7 +185,7 @@ if (isMultiplayer) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; }; @@ -200,7 +200,7 @@ if (isMultiplayer) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; }; }; diff --git a/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf b/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf index 9ec12154fd1..f9271ca2137 100644 --- a/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf +++ b/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf @@ -17,7 +17,7 @@ // Only run once if (missionNameSpace getVariable [QGVAR(checkFiles_diagnoseACE), false]) exitWith { - createHashMap + createHashMap // return }; GVAR(checkFiles_diagnoseACE) = true; @@ -71,4 +71,4 @@ private _getLoadedModsInfo = getLoadedModsInfo; }; } forEach _allMods; -_allMods +_allMods // return diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index 3fb4ee9da4f..8af3fda001d 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -78,10 +78,7 @@ if (!isServer) then { private _rscLayer = "ACE_RscErrorHint" call BIS_fnc_rscLayer; _rscLayer cutRsc ["ACE_RscErrorHint", "PLAIN", 0, true]; - disableSerialization; - - private _ctrlHint = uiNamespace getVariable "ACE_ctrlErrorHint"; - _ctrlHint ctrlSetStructuredText _errorMsg; + (uiNamespace getVariable "ACE_ctrlErrorHint") ctrlSetStructuredText _errorMsg; if (_mode == 0) then { [{ @@ -94,7 +91,7 @@ if (!isServer) then { [{alive player}, { TRACE_2("Player is alive, showing msg and exiting",time,_this); private _errorMsg = composeText [parseText format ["%1", _this]]; - ["[ACE] ERROR", _errorMsg] spawn FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }, _errorMsg] call CBA_fnc_waitUntilAndExecute; }; }; diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index 7eb9572f4b9..3612fcbcda2 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -86,14 +86,7 @@ private _fnc_check = { } forEach _serverFiles; // Find client files which the server doesn't have - private _additionalAddonsClient = []; - - { - if ((_serverFiles find _x) == -1) then { - _additionalAddonsClient pushBack _x; - }; - } forEach _files; - + private _additionalAddonsClient = _files select {!(_x in _serverFiles)}; // Check for client missing addons, server missing addons, client outdated addons and server outdated addons private _clientErrors = []; @@ -102,6 +95,7 @@ private _fnc_check = { private _count = 0; #define DISPLAY_NUMBER_ADDONS (10 + 1) // +1 to account for header + { _x params ["_items", "_string"]; diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index 7746d3e0756..8085f3dbd74 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -4,8 +4,6 @@ /* * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) * Opens a textbox with an error message, used for PBO checking. - * This function is sent by the server to the client, client runs the function. - * CBA isn't guaranteed to be loaded, so use vanilla functionality only! * * Arguments: * 0: Header @@ -23,128 +21,121 @@ // Force stop any loading screens endLoadingScreen; -// No message without player possible +// No message without interface possible if (!hasInterface) exitWith {}; -params ["_textHeader", "_textMessage"]; +[{ + !isNull (call BIS_fnc_displayMission) +}, { + params ["_textHeader", "_textMessage"]; -disableSerialization; + disableSerialization; -private _mainDisplay = call BIS_fnc_displayMission; + // Use curator display if present + private _curatorDisplay = findDisplay 312; -// Wait for display -if (isNull _mainDisplay) then { - waitUntil { - uiSleep 0.25; - - _mainDisplay = call BIS_fnc_displayMission; + private _mainDisplay = if (!isNull _curatorDisplay) then { + _curatorDisplay + } else { + call BIS_fnc_displayMission + }; - !isNull _mainDisplay + if (_textMessage isEqualType "") then { + _textMessage = parseText _textMessage; }; -}; - -// Use curator display if present -private _curatorDisplay = findDisplay 312; - -if (!isNull _curatorDisplay) then { - _mainDisplay = _curatorDisplay; -}; - -if (_textMessage isEqualType "") then { - _textMessage = parseText _textMessage; -}; - -private _display = _mainDisplay createDisplay "RscDisplayCommonMessagePause"; - -if (isNull _display) exitWith {}; - -private _ctrlRscMessageBox = _display displayCtrl 2351; -private _ctrlBcgCommonTop = _display displayCtrl 235100; -private _ctrlBcgCommon = _display displayCtrl 235101; -private _ctrlText = _display displayCtrl 235102; -private _ctrlBackgroundButtonOK = _display displayCtrl 235103; -private _ctrlBackgroundButtonMiddle = _display displayCtrl 235104; -private _ctrlBackgroundButtonCancel = _display displayCtrl 235105; -private _ctrlButtonOK = _display displayCtrl 235106; -private _ctrlButtonCancel = _display displayCtrl 235107; - -_ctrlBcgCommonTop ctrlSetText _textHeader; - -private _ctrlButtonOKPos = ctrlPosition _ctrlButtonOK; -private _ctrlBcgCommonPos = ctrlPosition _ctrlBcgCommon; -private _bottomSpaceY = (_ctrlButtonOKPos select 1) - ((_ctrlBcgCommonPos select 1) + (_ctrlBcgCommonPos select 3)); - -private _ctrlTextPos = ctrlPosition _ctrlText; -private _marginX = (_ctrlTextPos select 0) - (_ctrlBcgCommonPos select 0); -private _marginY = (_ctrlTextPos select 1) - (_ctrlBcgCommonPos select 1); - -_ctrlText ctrlSetStructuredText _textMessage; -private _ctrlTextPosH = ctrlTextHeight _ctrlText; - -_ctrlBcgCommon ctrlSetPosition [ - _ctrlBcgCommonPos select 0, - _ctrlBcgCommonPos select 1, - _ctrlBcgCommonPos select 2, - _ctrlTextPosH + _marginY * 2 -]; -_ctrlBcgCommon ctrlCommit 0; - -_ctrlText ctrlSetPosition [ - (_ctrlBcgCommonPos select 0) + _marginX, - (_ctrlBcgCommonPos select 1) + _marginY, - (_ctrlBcgCommonPos select 2) - _marginX * 2, - _ctrlTextPosH -]; -_ctrlText ctrlCommit 0; - -private _bottomPosY = (_ctrlBcgCommonPos select 1) + _ctrlTextPosH + (_marginY * 2) + _bottomSpaceY; - -{ - private _xPos = ctrlPosition _x; - - _xPos set [1, _bottomPosY]; - _x ctrlSetPosition _xPos; - _x ctrlCommit 0; -} forEach [ - _ctrlBackgroundButtonOK, - _ctrlBackgroundButtonMiddle, - _ctrlBackgroundButtonCancel, - _ctrlButtonOK, - _ctrlButtonCancel -]; - -private _ctrlRscMessageBoxPos = ctrlPosition _ctrlRscMessageBox; -private _ctrlRscMessageBoxPosH = _bottomPosY + (_ctrlButtonOKPos select 3); - -_ctrlRscMessageBox ctrlSetPosition [ - 0.5 - (_ctrlBcgCommonPos select 2) / 2, - 0.5 - _ctrlRscMessageBoxPosH / 2, - (_ctrlBcgCommonPos select 2) + 0.5, - _ctrlRscMessageBoxPosH -]; - -_ctrlRscMessageBox ctrlEnable true; -_ctrlRscMessageBox ctrlCommit 0; - -// Enable ok button -_ctrlButtonOK ctrlEnable true; -_ctrlButtonOK ctrlSetFade 0; -_ctrlButtonOK ctrlSetText localize "STR_DISP_OK"; -_ctrlButtonOK ctrlCommit 0; - -ctrlSetFocus _ctrlButtonOK; - -// Disable cancel button -_ctrlButtonCancel ctrlEnable false; -_ctrlButtonCancel ctrlSetFade 0; -_ctrlButtonCancel ctrlSetText ""; -_ctrlButtonCancel ctrlCommit 0; - -_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; - -// Intercept all keystrokes except the enter keys -_display displayAddEventHandler ["KeyDown", {!((_this select 1) in [DIK_RETURN, DIK_NUMPADENTER])}]; - -// Close curator and mission displays (because of the message display, it doesn't quit the mission yet) -findDisplay 312 closeDisplay 0; -findDisplay 46 closeDisplay 0; + + private _display = _mainDisplay createDisplay "RscDisplayCommonMessagePause"; + + if (isNull _display) exitWith {}; + + private _ctrlRscMessageBox = _display displayCtrl 2351; + private _ctrlBcgCommonTop = _display displayCtrl 235100; + private _ctrlBcgCommon = _display displayCtrl 235101; + private _ctrlText = _display displayCtrl 235102; + private _ctrlBackgroundButtonOK = _display displayCtrl 235103; + private _ctrlBackgroundButtonMiddle = _display displayCtrl 235104; + private _ctrlBackgroundButtonCancel = _display displayCtrl 235105; + private _ctrlButtonOK = _display displayCtrl 235106; + private _ctrlButtonCancel = _display displayCtrl 235107; + + _ctrlBcgCommonTop ctrlSetText _textHeader; + + private _ctrlButtonOKPos = ctrlPosition _ctrlButtonOK; + private _ctrlBcgCommonPos = ctrlPosition _ctrlBcgCommon; + private _bottomSpaceY = (_ctrlButtonOKPos select 1) - ((_ctrlBcgCommonPos select 1) + (_ctrlBcgCommonPos select 3)); + + private _ctrlTextPos = ctrlPosition _ctrlText; + private _marginX = (_ctrlTextPos select 0) - (_ctrlBcgCommonPos select 0); + private _marginY = (_ctrlTextPos select 1) - (_ctrlBcgCommonPos select 1); + + _ctrlText ctrlSetStructuredText _textMessage; + private _ctrlTextPosH = ctrlTextHeight _ctrlText; + + _ctrlBcgCommon ctrlSetPosition [ + _ctrlBcgCommonPos select 0, + _ctrlBcgCommonPos select 1, + _ctrlBcgCommonPos select 2, + _ctrlTextPosH + _marginY * 2 + ]; + _ctrlBcgCommon ctrlCommit 0; + + _ctrlText ctrlSetPosition [ + (_ctrlBcgCommonPos select 0) + _marginX, + (_ctrlBcgCommonPos select 1) + _marginY, + (_ctrlBcgCommonPos select 2) - _marginX * 2, + _ctrlTextPosH + ]; + _ctrlText ctrlCommit 0; + + private _bottomPosY = (_ctrlBcgCommonPos select 1) + _ctrlTextPosH + (_marginY * 2) + _bottomSpaceY; + + { + private _xPos = ctrlPosition _x; + + _xPos set [1, _bottomPosY]; + _x ctrlSetPosition _xPos; + _x ctrlCommit 0; + } forEach [ + _ctrlBackgroundButtonOK, + _ctrlBackgroundButtonMiddle, + _ctrlBackgroundButtonCancel, + _ctrlButtonOK, + _ctrlButtonCancel + ]; + + private _ctrlRscMessageBoxPos = ctrlPosition _ctrlRscMessageBox; + private _ctrlRscMessageBoxPosH = _bottomPosY + (_ctrlButtonOKPos select 3); + + _ctrlRscMessageBox ctrlSetPosition [ + 0.5 - (_ctrlBcgCommonPos select 2) / 2, + 0.5 - _ctrlRscMessageBoxPosH / 2, + (_ctrlBcgCommonPos select 2) + 0.5, + _ctrlRscMessageBoxPosH + ]; + + _ctrlRscMessageBox ctrlEnable true; + _ctrlRscMessageBox ctrlCommit 0; + + // Enable ok button + _ctrlButtonOK ctrlEnable true; + _ctrlButtonOK ctrlSetFade 0; + _ctrlButtonOK ctrlSetText localize "STR_DISP_OK"; + _ctrlButtonOK ctrlCommit 0; + + ctrlSetFocus _ctrlButtonOK; + + // Disable cancel button + _ctrlButtonCancel ctrlEnable false; + _ctrlButtonCancel ctrlSetFade 0; + _ctrlButtonCancel ctrlSetText ""; + _ctrlButtonCancel ctrlCommit 0; + + _ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; + + // Intercept all keystrokes except the enter keys + _display displayAddEventHandler ["KeyDown", {!((_this select 1) in [DIK_RETURN, DIK_NUMPADENTER])}]; + + // Close curator and mission displays (because of the message display, it doesn't quit the mission yet) + findDisplay 312 closeDisplay 0; + findDisplay 46 closeDisplay 0; +}, _this] call CBA_fnc_waitUntilAndExecute; From 87eac7739558e390cc251403f76a93145148df3b Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 4 Apr 2024 16:52:00 +0200 Subject: [PATCH 21/26] Remove rogue change --- addons/common/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/common/config.cpp b/addons/common/config.cpp index 88e5a5ca9c3..144e7d96c61 100644 --- a/addons/common/config.cpp +++ b/addons/common/config.cpp @@ -6,7 +6,7 @@ class CfgPatches { units[] = {"ACE_Box_Misc", "ACE_bananaItem", "ACE_Flag_Black", "ACE_Flag_White"}; weapons[] = {"ACE_ItemCore", "ACE_FakePrimaryWeapon", "ACE_Banana"}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"ace_main", "ace_modules"}; + requiredAddons[] = {"ace_main","ace_modules"}; author = CSTRING(ACETeam); authors[] = {"KoffeinFlummi"}; url = ECSTRING(main,URL); From effcfd1aaadf4151796b0301c06c81349f3e6a23 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 4 Apr 2024 18:53:05 +0200 Subject: [PATCH 22/26] Improved message display in systemChat --- addons/common/functions/fnc_checkPBOs.sqf | 12 ++--- .../functions/fnc_checkVersionNumber.sqf | 45 ++++++++++++++----- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index 8af3fda001d..ea72b7eceb2 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -71,14 +71,14 @@ if (!isServer) then { ERROR(_error); + _errorMsg = parseText format ["%1", _errorMsg]; + // Warn if (_mode < 2) then { - _errorMsg = composeText [lineBreak, parseText format ["%1", _errorMsg]]; - private _rscLayer = "ACE_RscErrorHint" call BIS_fnc_rscLayer; _rscLayer cutRsc ["ACE_RscErrorHint", "PLAIN", 0, true]; - (uiNamespace getVariable "ACE_ctrlErrorHint") ctrlSetStructuredText _errorMsg; + (uiNamespace getVariable "ACE_ctrlErrorHint") ctrlSetStructuredText composeText [lineBreak, _errorMsg]; if (_mode == 0) then { [{ @@ -88,11 +88,7 @@ if (!isServer) then { }; } else { // Kick - [{alive player}, { - TRACE_2("Player is alive, showing msg and exiting",time,_this); - private _errorMsg = composeText [parseText format ["%1", _this]]; - ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); - }, _errorMsg] call CBA_fnc_waitUntilAndExecute; + ["[ACE] ERROR", composeText [_errorMsg]] call FUNC(errorMessage); }; }; }, [_mode]] call CBA_fnc_addEventHandlerArgs; diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index 3612fcbcda2..d3bb3a70f6d 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -90,9 +90,11 @@ private _fnc_check = { // Check for client missing addons, server missing addons, client outdated addons and server outdated addons private _clientErrors = []; + private _isMissingItems = false; private _errorLog = []; + private _header = ""; private _errorMsg = ""; - private _count = 0; + private _count = -1; #define DISPLAY_NUMBER_ADDONS (10 + 1) // +1 to account for header @@ -100,17 +102,16 @@ private _fnc_check = { _x params ["_items", "_string"]; // Check if something is either missing or outdated - private _isMissingItems = _items isNotEqualTo []; + _isMissingItems = _items isNotEqualTo []; if (_isMissingItems) then { // Generate error message - _errorLog = [format ["[ACE] %1: ERROR %2 addon(s): ", _client, _string]]; - - _errorLog append _items; + _errorLog = +_items; + _header = format ["[ACE] %1: ERROR %2 addon(s): ", _client, _string]; // Don't display all missing items, as they are logged - _errorMsg = (_errorLog select [0, DISPLAY_NUMBER_ADDONS]) joinString ", "; - _errorLog = _errorLog joinString ", "; + _errorMsg = _header + ((_errorLog select [0, DISPLAY_NUMBER_ADDONS]) joinString ", "); + _errorLog = _header + (_errorLog joinString ", "); _count = count _items; @@ -118,10 +119,32 @@ private _fnc_check = { _errorMsg = _errorMsg + format [", and %1 more.", _count - DISPLAY_NUMBER_ADDONS]; }; - // Log and display error messages - diag_log text _errorLog; - [QGVAR(serverLog), _errorLog] call CBA_fnc_serverEvent; - [QGVAR(systemChatGlobal), _errorMsg] call CBA_fnc_globalEvent; + // Wait until in briefing screen + [{ + getClientStateNumber >= 9 // "BRIEFING SHOWN" + }, { + params ["_errorLog", "_errorMsg"]; + + // Log and display error messages + diag_log text _errorLog; + [QGVAR(serverLog), _errorLog] call CBA_fnc_serverEvent; + [QGVAR(systemChatGlobal), _errorMsg] call CBA_fnc_globalEvent; + + // Wait until after map screen + [{ + !isNull (call BIS_fnc_displayMission) + }, { + params ["_errorMsg", "_timeOut"]; + + // If the briefing screen was shown for less than 5 seconds, display the error message again, but locally + if (_timeOut < CBA_missionTime) exitWith {}; + + // Make sure systemChat is ready by waiting a bit + [{ + systemChat _this; + }, _errorMsg, 1] call CBA_fnc_waitAndExecute; + }, [_errorMsg, CBA_missionTime + 5]] call CBA_fnc_waitUntilAndExecute; + }, [_errorLog, _errorMsg]] call CBA_fnc_waitUntilAndExecute; }; _clientErrors pushBack _isMissingItems; From 7d84ea96069e3e4286d91f8eb11977ddc5c4bcda Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 10 Apr 2024 09:53:46 +0200 Subject: [PATCH 23/26] Update fnc_checkPBOs.sqf --- addons/common/functions/fnc_checkPBOs.sqf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index ea72b7eceb2..f8391dd2a24 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -47,29 +47,29 @@ if (!isServer) then { // Display error message(s) if (_missingAddonClient || {_additionalAddonClient} || {_olderVersionClient} || {_newerVersionClient}) then { private _errorMsg = "[ACE] Version mismatch:

"; - private _error = format ["[ACE] Version mismatch: %1: ", profileName]; + private _error = []; if (_missingAddonClient) then { _errorMsg = _errorMsg + "Detected missing addon on client
"; - _error = _error + "Missing file(s); "; + _error pushBack "Missing file(s)"; }; if (_additionalAddonClient) then { _errorMsg = _errorMsg + "Detected additional addon on client
"; - _error = _error + "Additional file(s); "; + _error pushBack "Additional file(s)"; }; if (_olderVersionClient) then { _errorMsg = _errorMsg + "Detected older client version
"; - _error = _error + "Older version; "; + _error pushBack "Older version"; }; if (_newerVersionClient) then { _errorMsg = _errorMsg + "Detected newer client version
"; - _error = _error + "Newer version; "; + _error pushBack "Newer version"; }; - ERROR(_error); + ERROR_2("[ACE] Version mismatch: %1: %2",profileName,_error joinString ", "); _errorMsg = parseText format ["%1", _errorMsg]; From 6ddcfb183bfa937edc8988155d7a5f68fca1f96a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 6 Jun 2024 09:46:35 +0200 Subject: [PATCH 24/26] Removed loop variable initialisers --- addons/common/functions/fnc_checkFiles.sqf | 26 ++++++----------- .../functions/fnc_checkVersionNumber.sqf | 28 ++++++------------- 2 files changed, 17 insertions(+), 37 deletions(-) diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index 31fc2e7e460..7b90a1b0a85 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -48,20 +48,16 @@ if ([_cbaRequiredAr, _cbaVersionAr] call CBA_versioning_fnc_version_compare) the //private _addons = activatedAddons; // Broken with High-Command module, see #2134 private _addons = (CBA_common_addons select {(_x select [0, 4]) == "ace_"}) apply {toLowerANSI _x}; -private _addonCfg = configNull; -private _addonVersion = ""; -private _addonSource = ""; - private _oldAddons = []; private _oldSources = []; private _oldCompats = []; { - _addonCfg = configFile >> "CfgPatches" >> _x; - _addonVersion = getText (_addonCfg >> "versionStr"); + private _addonCfg = configFile >> "CfgPatches" >> _x; + private _addonVersion = getText (_addonCfg >> "versionStr"); if (_addonVersion != _mainVersion) then { - _addonSource = configSourceMod _addonCfg; + private _addonSource = configSourceMod _addonCfg; _oldSources pushBackUnique _addonSource; @@ -111,18 +107,12 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { // Linux and OSX client ports do not support extensions at all INFO("Operating system does not support extensions"); } else { - private _extension = ""; - private _isWindows = false; - private _isLinux = false; - private _isClient = false; - private _isServer = false; - { - _extension = configName _x; - _isWindows = _platform == "windows" && {getNumber (_x >> "windows") == 1}; - _isLinux = _platform == "linux" && {getNumber (_x >> "linux") == 1}; - _isClient = hasInterface && {getNumber (_x >> "client") == 1}; - _isServer = !hasInterface && {getNumber (_x >> "server") == 1}; + private _extension = configName _x; + private _isWindows = _platform == "windows" && {getNumber (_x >> "windows") == 1}; + private _isLinux = _platform == "linux" && {getNumber (_x >> "linux") == 1}; + private _isClient = hasInterface && {getNumber (_x >> "client") == 1}; + private _isServer = !hasInterface && {getNumber (_x >> "server") == 1}; if ((_isWindows || _isLinux) && {_isClient || _isServer}) then { private _versionEx = _extension callExtension "version"; diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index d3bb3a70f6d..0343e745aae 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -29,12 +29,11 @@ private _files = CBA_common_addons select { }; private _cfgPatches = configFile >> "CfgPatches"; -private _version = -1; private _versions = []; { (getText (_cfgPatches >> _x >> "version") splitString ".") params [["_major", "0"], ["_minor", "0"]]; - _version = parseNumber _major + parseNumber _minor / 100; + private _version = parseNumber _major + parseNumber _minor / 100; _versions pushBack _version; } forEach _files; @@ -59,21 +58,17 @@ private _fnc_check = { private _olderVersionsClient = []; private _newerVersionsClient = []; - private _clientVersion = -1; - private _serverVersion = -1; - private _index = -1; - { - _serverVersion = _serverVersions select _forEachIndex; + private _serverVersion = _serverVersions select _forEachIndex; - _index = _files find _x; + private _index = _files find _x; if (_index == -1) then { if (_x != "ace_server") then { _missingAddonsClient pushBack _x; }; } else { - _clientVersion = _versions select _index; + private _clientVersion = _versions select _index; if (_clientVersion < _serverVersion) then { _olderVersionsClient pushBack [_x, _clientVersion, _serverVersion]; @@ -90,11 +85,6 @@ private _fnc_check = { // Check for client missing addons, server missing addons, client outdated addons and server outdated addons private _clientErrors = []; - private _isMissingItems = false; - private _errorLog = []; - private _header = ""; - private _errorMsg = ""; - private _count = -1; #define DISPLAY_NUMBER_ADDONS (10 + 1) // +1 to account for header @@ -102,18 +92,18 @@ private _fnc_check = { _x params ["_items", "_string"]; // Check if something is either missing or outdated - _isMissingItems = _items isNotEqualTo []; + private _isMissingItems = _items isNotEqualTo []; if (_isMissingItems) then { // Generate error message - _errorLog = +_items; - _header = format ["[ACE] %1: ERROR %2 addon(s): ", _client, _string]; + private _errorLog = +_items; + private _header = format ["[ACE] %1: ERROR %2 addon(s): ", _client, _string]; // Don't display all missing items, as they are logged - _errorMsg = _header + ((_errorLog select [0, DISPLAY_NUMBER_ADDONS]) joinString ", "); + private _errorMsg = _header + ((_errorLog select [0, DISPLAY_NUMBER_ADDONS]) joinString ", "); _errorLog = _header + (_errorLog joinString ", "); - _count = count _items; + private _count = count _items; if (_count > DISPLAY_NUMBER_ADDONS) then { _errorMsg = _errorMsg + format [", and %1 more.", _count - DISPLAY_NUMBER_ADDONS]; From fbea26cfa389b649d52deb0896ddcbd1ba5cbf3a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 14 Jun 2024 20:43:12 +0200 Subject: [PATCH 25/26] Fixed header --- addons/common/functions/fnc_errorMessage.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index 8085f3dbd74..e98a5baf8f9 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -7,13 +7,13 @@ * * Arguments: * 0: Header - * 1: Text + * 1: Text * * Return Value: * None * * Example: - * ["[ACE] ERROR", "Test"] spawn ace_common_fnc_errorMessage + * ["[ACE] ERROR", "Test"] call ace_common_fnc_errorMessage * * Public: No */ From 27b3fbab52ace47bff176669f3abc5c801c76c36 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 22 Jun 2024 15:48:12 +0200 Subject: [PATCH 26/26] Updated headers --- addons/common/functions/fnc_checkPBOs.sqf | 4 ++-- addons/common/functions/fnc_checkVersionNumber.sqf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index f8391dd2a24..4f2e3f4fa6b 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -9,8 +9,8 @@ * 0 = Warn once * 1 = Warn permanently * 2 = Kick - * 1: Check all PBOs? (default: false) - * 2: Whitelist (default: "") + * 1: Check all PBOs? (default: false) + * 2: Whitelist (default: "") * * Return Value: * None diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index 0343e745aae..a2861299174 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -4,7 +4,7 @@ * Compares version numbers from loaded addons. * * Arguments: - * None + * 0: Lowercase addon whitelist (default: missionNamespace getVariable ["ACE_Version_Whitelist", []]) * * Return Value: * None