mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Common - Improve PBO checking (#9266)
* Update PBO checking * Added kicking of clients without ACE loaded * Update fnc_errorMessage.sqf * Update fnc_checkVersionNumber.sqf * More compatibility for #9568 * Cleanup * Minor cleanup + added server source * update outdated/not present error message * check version number fixes * Update fnc_errorMessage.sqf * Changed error names Server is always right, client has either older or newer versions, or missing or additional addons * Improved ACE detection method * Tweaks and fixes * Try another approach * Update events-framework.md * Update XEH_postInit.sqf * Update fnc_checkVersionNumber.sqf * Removed check for non-ACE clients * Update XEH_postInit.sqf * Cleanup * Remove rogue change * Improved message display in systemChat * Update fnc_checkPBOs.sqf * Removed loop variable initialisers * Fixed header * Updated headers --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: LinkIsGrim <salluci.lovi@gmail.com>
This commit is contained in:
parent
db6c4a72a6
commit
7ea2aab2c9
@ -30,6 +30,7 @@ PREP(changeProjectileDirection);
|
||||
PREP(checkFiles);
|
||||
PREP(checkFiles_diagnoseACE);
|
||||
PREP(checkPBOs);
|
||||
PREP(checkVersionNumber);
|
||||
PREP(claim);
|
||||
PREP(claimSafeServer);
|
||||
PREP(codeToString);
|
||||
|
@ -15,15 +15,20 @@
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
// Don't execute in scheduled environment
|
||||
if (canSuspend) exitWith {
|
||||
[FUNC(checkFiles), nil] call CBA_fnc_directCall;
|
||||
};
|
||||
|
||||
///////////////
|
||||
// check addons
|
||||
// Check addons
|
||||
///////////////
|
||||
private _mainCfg = configFile >> "CfgPatches" >> "ace_main";
|
||||
private _mainVersion = getText (_mainCfg >> "versionStr");
|
||||
private _mainSource = configSourceMod _mainCfg;
|
||||
private _cfgPatches = configFile >> "CfgPatches";
|
||||
private _mainVersion = getText (_cfgPatches >> "ace_main" >> "versionStr");
|
||||
private _mainSource = configSourceMod (_cfgPatches >> "ace_main");
|
||||
|
||||
// CBA Versioning check - close main display if using incompatible version
|
||||
private _cbaVersionAr = getArray (configFile >> "CfgPatches" >> "cba_main" >> "versionAr");
|
||||
private _cbaVersionAr = getArray (_cfgPatches >> "cba_main" >> "versionAr");
|
||||
private _cbaRequiredAr = getArray (configFile >> "CfgSettings" >> "CBA" >> "Versioning" >> "ACE" >> "dependencies" >> "CBA") select 1;
|
||||
|
||||
private _cbaVersionStr = _cbaVersionAr joinString ".";
|
||||
@ -31,53 +36,62 @@ private _cbaRequiredStr = _cbaRequiredAr joinString ".";
|
||||
|
||||
INFO_3("ACE is version %1 - CBA is version %2 (min required %3)",_mainVersion,_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] 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 {toLowerANSI _x};
|
||||
//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 _oldAddons = [];
|
||||
private _oldSources = [];
|
||||
private _oldCompats = [];
|
||||
|
||||
{
|
||||
private _addonCfg = configFile >> "CfgPatches" >> _x;
|
||||
private _addonVersion = getText (_addonCfg >> "versionStr");
|
||||
|
||||
if (_addonVersion != _mainVersion) then {
|
||||
private _addonSource = configSourceMod _addonCfg;
|
||||
|
||||
_oldSources pushBackUnique _addonSource;
|
||||
|
||||
// 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 {
|
||||
if (hasInterface) 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;
|
||||
|
||||
if (_oldAddons isNotEqualTo []) then {
|
||||
_oldAddons = _oldAddons apply {format ["%1.pbo", _x]};
|
||||
private _errorMsg = "";
|
||||
if (count _oldAddons > 3) then {
|
||||
_errorMsg = format ["The following files are outdated: %1, and %2 more.<br/>ACE Main version is %3 from %4.<br/>Loaded mods with outdated ACE files: %5", (_oldAddons select [0, 3]) joinString ", ", (count _oldAddons) -3, _mainVersion, _mainSource, (_oldSources joinString ", ")];
|
||||
|
||||
private _errorMsg = if (count _oldAddons > 3) then {
|
||||
format ["The following files are outdated: %1, and %2 more.<br/>ACE Main version is %3 from %4.<br/>Loaded mods with outdated ACE files: %5", (_oldAddons select [0, 3]) joinString ", ", (count _oldAddons) - 3, _mainVersion, _mainSource, _oldSources joinString ", "];
|
||||
} else {
|
||||
_errorMsg = format ["The following files are outdated: %1.<br/>ACE Main version is %2 from %3.<br/>Loaded mods with outdated ACE files: %4", (_oldAddons) joinString ", ", _mainVersion, _mainSource, (_oldSources) joinString ", "];
|
||||
format ["The following files are outdated: %1.<br/>ACE Main version is %2 from %3.<br/>Loaded mods with outdated ACE files: %4", _oldAddons joinString ", ", _mainVersion, _mainSource, _oldSources joinString ", "];
|
||||
};
|
||||
|
||||
if (hasInterface) then {
|
||||
["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
|
||||
["[ACE] ERROR", _errorMsg] call FUNC(errorMessage);
|
||||
};
|
||||
|
||||
ERROR(_errorMsg);
|
||||
};
|
||||
|
||||
if (_oldCompats isNotEqualTo []) then {
|
||||
_oldCompats = _oldCompats apply {format ["%1 (%2)", _x select 0, _x select 1]};
|
||||
|
||||
[{
|
||||
// Lasts for ~10 seconds
|
||||
ERROR_WITH_TITLE_3("The following ACE compatiblity PBOs are outdated","%1. ACE Main version is %2 from %3.",_this select 0,_this select 1,_this select 2);
|
||||
@ -85,9 +99,10 @@ if (_oldCompats isNotEqualTo []) then {
|
||||
};
|
||||
|
||||
///////////////
|
||||
// check extensions
|
||||
// Check extensions
|
||||
///////////////
|
||||
private _platform = toLowerANSI (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");
|
||||
@ -101,8 +116,10 @@ if (!isServer && {_platform in ["linux", "osx"]}) then {
|
||||
|
||||
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];
|
||||
};
|
||||
@ -114,7 +131,7 @@ if (!isServer && {_platform in ["linux", "osx"]}) then {
|
||||
ERROR(_errorMsg);
|
||||
|
||||
if (hasInterface) then {
|
||||
["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
|
||||
["[ACE] ERROR", _errorMsg] call FUNC(errorMessage);
|
||||
};
|
||||
} else {
|
||||
// Print the current extension version
|
||||
@ -123,54 +140,66 @@ 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
|
||||
GVAR(ServerVersion) = _mainVersion;
|
||||
GVAR(ServerAddons) = _addons;
|
||||
publicVariable QGVAR(ServerVersion);
|
||||
publicVariable QGVAR(ServerAddons);
|
||||
// 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 {
|
||||
// clients have to wait for the variables
|
||||
[{
|
||||
if (isNil QGVAR(ServerVersion) || isNil QGVAR(ServerAddons)) exitWith {};
|
||||
GVAR(clientVersion) = _version;
|
||||
GVAR(clientAddons) = _addons;
|
||||
|
||||
(_this select 0) params ["_mainVersion", "_addons"];
|
||||
|
||||
if (_mainVersion != GVAR(ServerVersion)) then {
|
||||
private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2.", GVAR(ServerVersion), _mainVersion];
|
||||
private _fnc_check = {
|
||||
if (GVAR(clientVersion) != GVAR(serverVersion)) then {
|
||||
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);
|
||||
|
||||
ERROR(_errorMsg);
|
||||
|
||||
if (hasInterface) then {
|
||||
["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
|
||||
["[ACE] ERROR", _errorMsg] call FUNC(errorMessage);
|
||||
};
|
||||
};
|
||||
|
||||
_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];
|
||||
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);
|
||||
|
||||
ERROR(_errorMsg);
|
||||
|
||||
if (hasInterface) then {
|
||||
["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
|
||||
["[ACE] ERROR", _errorMsg] call FUNC(errorMessage);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
[_this select 1] call CBA_fnc_removePerFrameHandler;
|
||||
}, 1, [_mainVersion,_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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -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 <HASHMAP>
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_common_fnc_checkFiles_diagnoseACE
|
||||
@ -16,23 +16,35 @@
|
||||
*/
|
||||
|
||||
// Only run once
|
||||
if (missionNameSpace getVariable [QGVAR(checkFiles_diagnoseACE), false]) exitWith {};
|
||||
if (missionNameSpace getVariable [QGVAR(checkFiles_diagnoseACE), false]) exitWith {
|
||||
createHashMap // return
|
||||
};
|
||||
|
||||
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];
|
||||
systemChat _errorMsg;
|
||||
@ -40,13 +52,17 @@ private _allMods = createHashMap;
|
||||
};
|
||||
} 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];
|
||||
@ -55,4 +71,4 @@ private _allMods = createHashMap;
|
||||
};
|
||||
} forEach _allMods;
|
||||
|
||||
_allMods
|
||||
_allMods // return
|
||||
|
@ -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.
|
||||
*
|
||||
@ -9,8 +9,8 @@
|
||||
* 0 = Warn once
|
||||
* 1 = Warn permanently
|
||||
* 2 = Kick
|
||||
* 1: Check all PBOs? (default: false) <BOOL>
|
||||
* 2: Whitelist (default: "") <STRING>
|
||||
* 1: Check all PBOs? <BOOL> (default: false)
|
||||
* 2: Whitelist <STRING> (default: "")
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
@ -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 = toLowerANSI _whitelist;
|
||||
_whitelist = _whitelist splitString "[,""']";
|
||||
TRACE_1("Array",_whitelist);
|
||||
@ -32,75 +32,67 @@ 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 ["_missingAddonClient", "_additionalAddonClient", "_olderVersionClient", "_newerVersionClient"];
|
||||
_thisArgs params ["_mode"];
|
||||
|
||||
(_this select 0) params ["_mode", "_checkAll", "_whitelist"];
|
||||
// Display error message(s)
|
||||
if (_missingAddonClient || {_additionalAddonClient} || {_olderVersionClient} || {_newerVersionClient}) then {
|
||||
private _errorMsg = "[ACE] Version mismatch:<br/><br/>";
|
||||
private _error = [];
|
||||
|
||||
// Display error message.
|
||||
if (_missingAddon || {_missingAddonServer} || {_oldVersionClient} || {_oldVersionServer}) then {
|
||||
private _text = "[ACE] Version mismatch:<br/><br/>";
|
||||
private _error = format ["ACE version mismatch: %1: ", profileName];
|
||||
|
||||
if (_missingAddon) then {
|
||||
_text = _text + "Detected missing addon on client<br/>";
|
||||
_error = _error + "Missing file(s); ";
|
||||
};
|
||||
if (_missingAddonServer) then {
|
||||
_text = _text + "Detected missing addon on server<br/>";
|
||||
_error = _error + "Additional file(s); ";
|
||||
};
|
||||
if (_oldVersionClient) then {
|
||||
_text = _text + "Detected old client version<br/>";
|
||||
_error = _error + "Older version; ";
|
||||
};
|
||||
if (_oldVersionServer) then {
|
||||
_text = _text + "Detected old server version<br/>";
|
||||
_error = _error + "Newer version; ";
|
||||
if (_missingAddonClient) then {
|
||||
_errorMsg = _errorMsg + "Detected missing addon on client<br/>";
|
||||
_error pushBack "Missing file(s)";
|
||||
};
|
||||
|
||||
//[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent;
|
||||
if (_additionalAddonClient) then {
|
||||
_errorMsg = _errorMsg + "Detected additional addon on client<br/>";
|
||||
_error pushBack "Additional file(s)";
|
||||
};
|
||||
|
||||
ERROR(_error);
|
||||
if (_olderVersionClient) then {
|
||||
_errorMsg = _errorMsg + "Detected older client version<br/>";
|
||||
_error pushBack "Older version";
|
||||
};
|
||||
|
||||
if (_newerVersionClient) then {
|
||||
_errorMsg = _errorMsg + "Detected newer client version<br/>";
|
||||
_error pushBack "Newer version";
|
||||
};
|
||||
|
||||
ERROR_2("[ACE] Version mismatch: %1: %2",profileName,_error joinString ", ");
|
||||
|
||||
_errorMsg = parseText format ["<t align='center'>%1</t>", _errorMsg];
|
||||
|
||||
// Warn
|
||||
if (_mode < 2) then {
|
||||
_text = composeText [lineBreak, parseText format ["<t align='center'>%1</t>", _text]];
|
||||
|
||||
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;
|
||||
(uiNamespace getVariable "ACE_ctrlErrorHint") ctrlSetStructuredText composeText [lineBreak, _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;
|
||||
};
|
||||
} else {
|
||||
// Kick
|
||||
["[ACE] ERROR", composeText [_errorMsg]] call FUNC(errorMessage);
|
||||
};
|
||||
};
|
||||
}, [_mode]] call CBA_fnc_addEventHandlerArgs;
|
||||
};
|
||||
|
||||
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 ["<t align='center'>%1</t>", _text]];
|
||||
["[ACE] ERROR", _text, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
|
||||
}, [_text]] call CBA_fnc_waitUntilAndExecute;
|
||||
};
|
||||
};
|
||||
|
||||
[_this select 1] call CBA_fnc_removePerFrameHandler;
|
||||
}, 1, [_mode, _checkAll, _whitelist]] call CBA_fnc_addPerFrameHandler;
|
||||
};
|
||||
|
||||
if (_checkAll) then {
|
||||
0 spawn COMPILE_FILE(scripts\checkVersionNumber); // @todo
|
||||
};
|
||||
// Check file version numbers
|
||||
[_whitelist] call FUNC(checkVersionNumber);
|
||||
|
161
addons/common/functions/fnc_checkVersionNumber.sqf
Normal file
161
addons/common/functions/fnc_checkVersionNumber.sqf
Normal file
@ -0,0 +1,161 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: commy2, johnb43
|
||||
* Compares version numbers from loaded addons.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Lowercase addon whitelist <ARRAY> (default: missionNamespace getVariable ["ACE_Version_Whitelist", []])
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_common_fnc_checkVersionNumber
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
// 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_") &&
|
||||
{_x select [0, 4] != "ace_"} &&
|
||||
{!((toLowerANSI _x) in _whitelist)}
|
||||
};
|
||||
|
||||
private _cfgPatches = configFile >> "CfgPatches";
|
||||
private _versions = [];
|
||||
|
||||
{
|
||||
(getText (_cfgPatches >> _x >> "version") splitString ".") params [["_major", "0"], ["_minor", "0"]];
|
||||
private _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 _missingAddonsClient = [];
|
||||
private _olderVersionsClient = [];
|
||||
private _newerVersionsClient = [];
|
||||
|
||||
{
|
||||
private _serverVersion = _serverVersions select _forEachIndex;
|
||||
|
||||
private _index = _files find _x;
|
||||
|
||||
if (_index == -1) then {
|
||||
if (_x != "ace_server") then {
|
||||
_missingAddonsClient pushBack _x;
|
||||
};
|
||||
} else {
|
||||
private _clientVersion = _versions select _index;
|
||||
|
||||
if (_clientVersion < _serverVersion) then {
|
||||
_olderVersionsClient pushBack [_x, _clientVersion, _serverVersion];
|
||||
};
|
||||
|
||||
if (_clientVersion > _serverVersion) then {
|
||||
_newerVersionsClient pushBack [_x, _clientVersion, _serverVersion];
|
||||
};
|
||||
};
|
||||
} forEach _serverFiles;
|
||||
|
||||
// Find client files which the server doesn't have
|
||||
private _additionalAddonsClient = _files select {!(_x in _serverFiles)};
|
||||
|
||||
// Check for client missing addons, server missing addons, client outdated addons and server outdated addons
|
||||
private _clientErrors = [];
|
||||
|
||||
#define DISPLAY_NUMBER_ADDONS (10 + 1) // +1 to account for header
|
||||
|
||||
{
|
||||
_x params ["_items", "_string"];
|
||||
|
||||
// Check if something is either missing or outdated
|
||||
private _isMissingItems = _items isNotEqualTo [];
|
||||
|
||||
if (_isMissingItems) then {
|
||||
// Generate error message
|
||||
private _errorLog = +_items;
|
||||
private _header = format ["[ACE] %1: ERROR %2 addon(s): ", _client, _string];
|
||||
|
||||
// Don't display all missing items, as they are logged
|
||||
private _errorMsg = _header + ((_errorLog select [0, DISPLAY_NUMBER_ADDONS]) joinString ", ");
|
||||
_errorLog = _header + (_errorLog joinString ", ");
|
||||
|
||||
private _count = count _items;
|
||||
|
||||
if (_count > DISPLAY_NUMBER_ADDONS) then {
|
||||
_errorMsg = _errorMsg + format [", and %1 more.", _count - DISPLAY_NUMBER_ADDONS];
|
||||
};
|
||||
|
||||
// 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;
|
||||
} forEach [
|
||||
[_missingAddonsClient, "client missing"],
|
||||
[_additionalAddonsClient, "client additional"],
|
||||
[_olderVersionsClient, "older client"],
|
||||
[_newerVersionsClient, "newer client"]
|
||||
];
|
||||
|
||||
TRACE_4("",_missingAddonsClient,_additionalAddonsClient,_olderVersionsClient,_newerVersionsClient);
|
||||
|
||||
ACE_Version_ClientErrors = _clientErrors;
|
||||
|
||||
// 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;
|
||||
};
|
@ -1,46 +1,53 @@
|
||||
#include "..\script_component.hpp"
|
||||
#include "\a3\ui_f\hpp\defineResincl.inc"
|
||||
#include "\a3\ui_f\hpp\defineDIKCodes.inc"
|
||||
/*
|
||||
* Author: commy2, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI)
|
||||
* Stops simulation and opens a textbox with error message.
|
||||
* 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.
|
||||
*
|
||||
* Arguments:
|
||||
* ?
|
||||
* 0: Header <STRING>
|
||||
* 1: Text <STRING|TEXT>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_common_fnc_errorMessage
|
||||
* ["[ACE] ERROR", "Test"] call ace_common_fnc_errorMessage
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
disableSerialization;
|
||||
// Force stop any loading screens
|
||||
endLoadingScreen;
|
||||
|
||||
// no message without player possible
|
||||
// No message without interface possible
|
||||
if (!hasInterface) exitWith {};
|
||||
|
||||
// wait for display
|
||||
if (isNull (call BIS_fnc_displayMission)) exitWith {
|
||||
[{
|
||||
if (isNull (call BIS_fnc_displayMission)) exitWith {};
|
||||
!isNull (call BIS_fnc_displayMission)
|
||||
}, {
|
||||
params ["_textHeader", "_textMessage"];
|
||||
|
||||
(_this select 0) call FUNC(errorMessage);
|
||||
[_this select 1] call CBA_fnc_removePerFrameHandler;
|
||||
disableSerialization;
|
||||
|
||||
}, 1, _this] call CBA_fnc_addPerFrameHandler;
|
||||
// Use curator display if present
|
||||
private _curatorDisplay = findDisplay 312;
|
||||
|
||||
private _mainDisplay = if (!isNull _curatorDisplay) then {
|
||||
_curatorDisplay
|
||||
} else {
|
||||
call BIS_fnc_displayMission
|
||||
};
|
||||
|
||||
params ["_textHeader", "_textMessage", ["_onOK", {}], ["_onCancel", {}]];
|
||||
|
||||
if (_textMessage isEqualType "") then {
|
||||
_textMessage = parseText _textMessage;
|
||||
};
|
||||
|
||||
ARR_SELECT(_this,4,call BIS_fnc_displayMission) 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;
|
||||
@ -109,39 +116,26 @@ _ctrlRscMessageBox ctrlSetPosition [
|
||||
_ctrlRscMessageBox ctrlEnable true;
|
||||
_ctrlRscMessageBox ctrlCommit 0;
|
||||
|
||||
if (_onOK isEqualTo {}) then {
|
||||
_ctrlButtonOK ctrlEnable false;
|
||||
_ctrlButtonOK ctrlSetFade 0;
|
||||
_ctrlButtonOK ctrlSetText "";
|
||||
_ctrlButtonOK ctrlCommit 0;
|
||||
} else {
|
||||
// Enable ok button
|
||||
_ctrlButtonOK ctrlEnable true;
|
||||
_ctrlButtonOK ctrlSetFade 0;
|
||||
_ctrlButtonOK ctrlSetText localize "STR_DISP_OK";
|
||||
_ctrlButtonOK ctrlCommit 0;
|
||||
|
||||
ctrlSetFocus _ctrlButtonOK;
|
||||
};
|
||||
|
||||
if (_onCancel isEqualTo {}) then {
|
||||
// Disable cancel button
|
||||
_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;
|
||||
};
|
||||
_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}];
|
||||
|
||||
_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}];
|
||||
_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}];
|
||||
// Intercept all keystrokes except the enter keys
|
||||
_display displayAddEventHandler ["KeyDown", {!((_this select 1) in [DIK_RETURN, DIK_NUMPADENTER])}];
|
||||
|
||||
GVAR(errorOnOK) = _onOK;
|
||||
GVAR(errorOnCancel) = _onCancel;
|
||||
|
||||
_display displayAddEventHandler ["Unload", {call ([{}, GVAR(errorOnOK), GVAR(errorOnCancel)] select (_this select 1))}];
|
||||
_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}];
|
||||
// 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;
|
||||
|
@ -1,160 +0,0 @@
|
||||
// by commy2
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
private _aceWhitelist = missionNamespace getVariable ["ACE_Version_Whitelist", []];
|
||||
private _files = CBA_common_addons select {
|
||||
(_x select [0,3] != "a3_") &&
|
||||
{_x select [0,4] != "ace_"} &&
|
||||
{!((toLowerANSI _x) in _aceWhitelist)}
|
||||
};
|
||||
|
||||
private _versions = [];
|
||||
{
|
||||
getText (configFile >> "CfgPatches" >> _x >> "version") splitString "." params [["_major", "0"], ["_minor", "0"]];
|
||||
private _version = parseNumber _major + parseNumber _minor/100;
|
||||
_versions set [_forEachIndex, _version];
|
||||
} forEach _files;
|
||||
|
||||
if (isServer) then {
|
||||
ACE_Version_ServerVersions = [_files, _versions];
|
||||
publicVariable "ACE_Version_ServerVersions";
|
||||
} else {
|
||||
ACE_Version_ClientVersions = [_files, _versions];
|
||||
};
|
||||
|
||||
// Begin client version check
|
||||
if (!isServer) then {
|
||||
// Wait for server to send the servers files and version numbers
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
!isNil "ACE_Version_ClientVersions" && {!isNil "ACE_Version_ServerVersions"}
|
||||
};
|
||||
|
||||
private _client = profileName;
|
||||
|
||||
_files = ACE_Version_ClientVersions select 0;
|
||||
_versions = ACE_Version_ClientVersions select 1;
|
||||
|
||||
private _serverFiles = ACE_Version_ServerVersions select 0;
|
||||
private _serverVersions = ACE_Version_ServerVersions select 1;
|
||||
|
||||
// Compare client and server files and versions
|
||||
private _missingAddons = [];
|
||||
private _oldVersionsClient = [];
|
||||
private _oldVersionsServer = [];
|
||||
{
|
||||
private _serverVersion = _serverVersions select _forEachIndex;
|
||||
|
||||
private _index = _files find _x;
|
||||
if (_index == -1) then {
|
||||
if (_x != "ace_server") then {_missingAddons pushBack _x;};
|
||||
} else {
|
||||
|
||||
private _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 = [];
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
private _missingAddon = false;
|
||||
if (count _missingAddons > 0) then {
|
||||
_missingAddon = true;
|
||||
|
||||
private _error = format ["[ACE] %1: ERROR client missing addon(s): ", _client];
|
||||
{
|
||||
_error = _error + format ["%1, ", _x];
|
||||
|
||||
if (_forEachIndex > 9) exitWith {};
|
||||
} forEach _missingAddons;
|
||||
|
||||
_error = _error call _fnc_cutComma;
|
||||
|
||||
diag_log text _error;
|
||||
[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent;
|
||||
[QGVAR(serverLog), _error] call CBA_fnc_serverEvent;
|
||||
};
|
||||
|
||||
private _missingAddonServer = false;
|
||||
if (count _missingAddonsServer > 0) then {
|
||||
_missingAddonServer = true;
|
||||
|
||||
private _error = format ["[ACE] %1: ERROR server missing addon(s): ", _client];
|
||||
{
|
||||
_error = _error + format ["%1, ", _x];
|
||||
|
||||
if (_forEachIndex > 9) exitWith {};
|
||||
} forEach _missingAddonsServer;
|
||||
|
||||
_error = _error call _fnc_cutComma;
|
||||
|
||||
diag_log text _error;
|
||||
[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent;
|
||||
[QGVAR(serverLog), _error] call CBA_fnc_serverEvent;
|
||||
};
|
||||
|
||||
private _oldVersionClient = false;
|
||||
if (count _oldVersionsClient > 0) then {
|
||||
_oldVersionClient = true;
|
||||
|
||||
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 (_forEachIndex > 9) exitWith {};
|
||||
} forEach _oldVersionsClient;
|
||||
|
||||
_error = _error call _fnc_cutComma;
|
||||
|
||||
diag_log text _error;
|
||||
[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent;
|
||||
[QGVAR(serverLog), _error] call CBA_fnc_serverEvent;
|
||||
};
|
||||
|
||||
private _oldVersionServer = false;
|
||||
if (count _oldVersionsServer > 0) then {
|
||||
_oldVersionServer = 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 > 9) exitWith {};
|
||||
} forEach _oldVersionsServer;
|
||||
|
||||
_error = _error call _fnc_cutComma;
|
||||
|
||||
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];
|
||||
};
|
@ -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`)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user