To make it even more secure you can whitelist all functions allowed to be called via callback with a simple modification:
KK_fnc_CB_WHITELIST = {
_this in [
"fnc_lolfunc",
"function2",
"function3"
]
};
KK_fnc_CB_ERROR = {
diag_log (format [
"CB_ERROR! Call to non-existent function '%1' (Passed params: %2)",
_this select 0,
_this
])
};
KK_fnc_CB = {
private ["_fnc","_code"];
_fnc = _this select 0;
if (_fnc call KK_fnc_CB_WHITELIST) then {
_code = missionNamespace getVariable [
format ["%1", _fnc],
KK_fnc_CB_ERROR
];
if ((_this select 2) == "call") then {
_this call _code;
} else {
null = _this spawn _code;
}
}
};
Few notes about compileFinal. You have to assign final code to a variable. It is the variable containing the code that then becomes final and therefore the code becomes final. You can include a file containing a bunch public functions like this:
//a bad example
call compileFinal preprocessFileLineNumbers "myfile.sqf";
Or even this:
//another bad example
functions = compileFinal preprocessFileLineNumbers "myfile.sqf";
call functions;
None of the public functions inside will get finalised by association. You have to do it explicitly, you have to do them all individually or by placing them in a separate file each, then compileFinal preprocessFileLineNumbers each file.
//a good example
function1 = compileFinal preprocessFileLineNumbers "myfunction1.sqf"
function2 = compileFinal preprocessFileLineNumbers "myfunction2.sqf"
Alternatively, as was mentioned before, convert your functions to strings and then compileFinal.
Enjoy,
KK