Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile and cache configFile eventhandlers at preStart #1052

Merged
merged 12 commits into from
Feb 17, 2019
56 changes: 11 additions & 45 deletions addons/xeh/CfgFunctions.hpp
Original file line number Diff line number Diff line change
@@ -1,65 +1,31 @@
class CfgFunctions {
class CBA {
class XEH {
class isScheduled {
description = "Check if the current scope is running in scheduled or unscheduled environment.";
file = PATHTOF(fnc_isScheduled.sqf);
};
class isRecompileEnabled {
description = "Check if recompiling is enabled.";
file = PATHTOF(fnc_isRecompileEnabled.sqf);
};
class addClassEventHandler {
description = "Add an eventhandler to a class and all children.";
file = PATHTOF(fnc_addClassEventHandler.sqf);
};
class init {
headerType = -1;
description = "Runs Init and InitPost event handlers on this object.";
file = PATHTOF(fnc_init.sqf);
};
class initEvents {
headerType = -1;
description = "Adds all event handlers to this object.";
file = PATHTOF(fnc_initEvents.sqf);
};
class supportMonitor {
description = "Iterate through all vehicle classes and find those who don't support extended event handlers.";
file = PATHTOF(fnc_supportMonitor.sqf);
};
class compileEventHandlers {
description = "Compiles all Extended EventHandlers in given config.";
file = PATHTOF(fnc_compileEventHandlers.sqf);
};
class compileFunction {
description = "Compiles a function into mission namespace and into ui namespace for caching purposes.";
file = PATHTOF(fnc_compileFunction.sqf);
};
PATHTO_FNC(isScheduled);
PATHTO_FNC(isRecompileEnabled);
PATHTO_FNC(addClassEventHandler);
PATHTO_FNC(init);
PATHTO_FNC(initEvents);
PATHTO_FNC(supportMonitor);
PATHTO_FNC(compileEventHandlers);
PATHTO_FNC(compileFunction);
PATHTO_FNC(startFallbackLoop);

class preStart {
preStart = 1;
description = "Occurs once during game start.";
file = PATHTOF(fnc_preStart.sqf);
};
class preInit {
preInit = 1;
description = "Occurs once per mission before objects are initialized.";
file = PATHTOF(fnc_preInit.sqf);
};
class postInit {
postInit = 1;
description = "Occurs once per mission after objects and functions are initialized.";
file = PATHTOF(fnc_postInit.sqf);
};
class postInit_unscheduled {
description = "Occurs once per mission after objects and functions are initialized.";
file = PATHTOF(fnc_postInit_unscheduled.sqf);
};
class startFallbackLoop {
description = "Starts a loop to iterate through all objects to initialize event handlers on XEH incompatible objects.";
file = PATHTOF(fnc_startFallbackLoop.sqf);
};
};
};

class A3 {
class GUI {
class initDisplay {
Expand Down
143 changes: 81 additions & 62 deletions addons/xeh/fnc_compileEventHandlers.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -27,72 +27,80 @@ params [["_baseConfig", configNull, [configNull]]];
private _result = [];
private _resultNames = [];

private _allowRecompile = _baseConfig isEqualTo configFile;

if (_allowRecompile) then {
if ("compile" call CBA_fnc_isRecompileEnabled || {isFilePatchingEnabled}) then {
XEH_LOG("XEH: init function preProcessing disabled [recompile or filepatching enabled]");
_allowRecompile = false;
};
};

// note: format is never used for config parsing here, because of it's 8192 character limitation.

{
private _eventName = _x;

{
private _eventFunc = "";
private _funcAll = "";
private _funcClient = "";
private _funcServer = "";
private _customName = configName _x;

if (isClass _x) then {
// events on clients and server
private _entry = _x >> "init";

if (isText _entry) then {
_eventFunc = _eventFunc + getText _entry + ";";
_funcAll = getText _entry;
};

// client only events
if (!isDedicated) then {
_entry = _x >> "clientInit";

if (isText _entry) then {
_eventFunc = _eventFunc + getText _entry + ";";
};
_entry = _x >> "clientInit";
if (isText _entry) then {
_funcClient = getText _entry;
};

// server only events
if (isServer) then {
_entry = _x >> "serverInit";

if (isText _entry) then {
_eventFunc = _eventFunc + getText _entry + ";";
};
_entry = _x >> "serverInit";
if (isText _entry) then {
_funcServer = getText _entry;
};
} else {
// global events
if (isText _x) then {
_eventFunc = getText _x + ";";
_funcAll = getText _x;
};
};

if !(_eventFunc isEqualTo "") then {

//Optimize "QUOTE(call COMPILE_FILE(XEH_preInit));" down to just the content of the EH script
if (!(["compile"] call CBA_fnc_isRecompileEnabled) && { //Users might expect their preInit script to be reloaded everytime when debugging
(toLower (_eventFunc select [0,40])) isEqualTo "call compile preprocessfilelinenumbers '" && {
(_eventFunc select [count _eventFunc -2]) isEqualTo "';"
}}) then {
private _funcPath = _eventFunc select [40, count _eventFunc - 42];
//If there is a quote mark in the path, then something went wrong and we got multiple paths, just skip optimization
//Example cause: "call COMPILE_FILE(XEH_preInit);call COMPILE_FILE(XEH_preClientInit)"
if (_funcPath find "'" == -1) then {
_eventFunc = preprocessFileLineNumbers _funcPath;

TRACE_2("eventfunction redirected",_customName,_funcPath);
private _eventFuncs = [_funcAll, _funcClient, _funcServer] apply {
if (_x == "") then {
TRACE_2("does NOT do something",_customName,_eventName);
{} // apply return
} else {
TRACE_2("does something",_customName,_eventName);
private _eventFunc = _x;

//Optimize "QUOTE(call COMPILE_FILE(XEH_preInit));" down to just the content of the EH script
if (_allowRecompile) then {
if (toLower (_eventFunc select [0,40]) isEqualTo "call compile preprocessfilelinenumbers '" && {(_eventFunc select [count _eventFunc - 1]) isEqualTo "'"}) then {
private _funcPath = _eventFunc select [40, count _eventFunc - 41];

//If there is a quote mark in the path, then something went wrong and we got multiple paths, just skip optimization
//Example cause: "call COMPILE_FILE(XEH_preInit);call COMPILE_FILE(XEH_preClientInit)"
if (_funcPath find "'" == -1) then {
_eventFunc = preprocessFileLineNumbers _funcPath;
TRACE_2("eventfunction redirected",_customName,_funcPath);
};
};
// if (_eventFunc isEqualTo _x) then { diag_log text format ["XEH: Could not recompile [%1-%2]: %3", _eventName, _customName, _eventFunc]; };
};
};

_eventFunc = compile _eventFunc;
TRACE_2("does something",_customName,_eventName);
} else {
_eventFunc = {};
TRACE_2("does NOT do something",_customName,_eventName);
compile _eventFunc // apply return
};
};

_result pushBack ["", _eventName, _eventFunc];
_result pushBack ["", _eventName, _eventFuncs];
_resultNames pushBack _customName;
} forEach configProperties [_baseConfig >> XEH_FORMAT_CONFIG_NAME(_eventName)];
} forEach ["preInit", "postInit"];
Expand All @@ -119,10 +127,12 @@ private _resultNames = [];
};

{
private _eventFunc = _eventFuncBase;
private _customName = configName _x;
private _allowInheritance = true;
private _excludedClasses = [];
private _funcAll = "";
private _funcClient = "";
private _funcServer = "";

if (isClass _x) then {
// allow inheritance of this event?
Expand All @@ -132,6 +142,9 @@ private _resultNames = [];
_allowInheritance = getNumber _scope != 0;
};

// init event handlers that should run on respawn again, onRespawn = 1
private _onRespawn = toLower _eventName in ["init", "initpost"] && {getNumber (_x >> "onRespawn") == 1};

// classes excluded from this event
private _exclude = _x >> "exclude";

Expand All @@ -147,35 +160,38 @@ private _resultNames = [];
private _entry = _x >> _entryName;

if (isText _entry) then {
_eventFunc = _eventFunc + getText _entry + ";";
_funcAll = _eventFuncBase + getText _entry + ";";

if (_onRespawn) then {
_funcAll = _funcAll + "(_this select 0) addEventHandler ['Respawn', " + str _funcAll + "];";
};
};

// client only events
if (!isDedicated) then {
_entry = _x >> format ["client%1", _entryName];
_entry = _x >> format ["client%1", _entryName];

if (isText _entry) then {
_funcClient = _eventFuncBase + getText _entry + ";";

if (isText _entry) then {
_eventFunc = _eventFunc + getText _entry + ";";
if (_onRespawn) then {
_funcClient = _funcClient + "(_this select 0) addEventHandler ['Respawn', " + str _funcClient + "];";
};
};

// server only events
if (isServer) then {
_entry = _x >> format ["server%1", _entryName];
_entry = _x >> format ["server%1", _entryName];

if (isText _entry) then {
_eventFunc = _eventFunc + getText _entry + ";";
};
};
if (isText _entry) then {
_funcServer = _eventFuncBase + getText _entry + ";";

// init event handlers that should run on respawn again, onRespawn = 1
if (toLower _eventName in ["init", "initpost"] && {getNumber (_x >> "onRespawn") == 1}) then {
_eventFunc = _eventFunc + "(_this select 0) addEventHandler ['Respawn', " + str _eventFunc + "];";
if (_onRespawn) then {
_funcServer = _funcServer + "(_this select 0) addEventHandler ['Respawn', " + str _funcServer + "];";
};
};
} else {
// global events
if (isText _x) then {
_eventFunc = _eventFunc + getText _x + ";";
_funcAll = _eventFuncBase + getText _x + ";";
};
};

Expand All @@ -197,19 +213,22 @@ private _resultNames = [];
};
} forEach _resultNames;

// only add event on machines where it exists
if !(_eventFunc isEqualTo _eventFuncBase) then {
_eventFunc = compile _eventFunc;
TRACE_3("does something",_customName,_className,_eventName);
} else {
_eventFunc = {};
TRACE_3("does NOT do something",_customName,_className,_eventName);
private _eventFuncs = [_funcAll, _funcClient, _funcServer] apply {
// only add event on machines where it exists
if (_x == "") then {
TRACE_3("does NOT do something",_customName,_className,_eventName);
{}
} else {
TRACE_3("does something",_customName,_className,_eventName);
compile _x
};
};

_result pushBack [_className, _eventName, _eventFunc, _allowInheritance, _excludedClasses];
_result pushBack [_className, _eventName, _eventFuncs, _allowInheritance, _excludedClasses];
_resultNames pushBack _customName;
} forEach configProperties [_x];
} forEach configProperties [_baseConfig >> XEH_FORMAT_CONFIG_NAME(_eventName), "isClass _x"];
} forEach [XEH_EVENTS];

_result select {!((_x select 2) isEqualTo {})}
TRACE_2("compiled",_baseConfig,count _result);

_result select {!((_x select 2) isEqualTo [{},{},{}])}
2 changes: 1 addition & 1 deletion addons/xeh/fnc_initDisplay.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ if !(_event isEqualTo "") then {
private ["_event", "_className"]; // prevent these variables from being overwritten
_args call compile getText _x;
} forEach configProperties [_x >> XEH_FORMAT_CONFIG_NAME(_event) >> _className, "isText _x"];
} forEach XEH_MAIN_CONFIGS;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Macro seemed pointless. Bugged me for a while and now is an opportunity to muck it out.

} forEach [configFile, campaignConfigFile, missionConfigFile];
};
49 changes: 48 additions & 1 deletion addons/xeh/fnc_postInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,51 @@ Author:
commy2
---------------------------------------------------------------------------- */

CBA_fnc_postInit_unscheduled call CBA_fnc_directCall;
isNil {
XEH_LOG("XEH: PostInit started. " + PFORMAT_9("MISSIONINIT",missionName,missionVersion,worldName,isMultiplayer,isServer,isDedicated,CBA_isHeadlessClient,hasInterface,didJIP));

// fix CBA_missionTime being -1 on (non-JIP) clients at mission start.
if (CBA_missionTime == -1) then {
CBA_missionTime = 0;
};

// call PostInit events
{
if (_x select 1 == "postInit") then {
(_x select 2) call {
private "_x";

[] call (_this select 0);

if (!isDedicated) then {
[] call (_this select 1);
};

if (isServer) then {
[] call (_this select 2);
};
};
};
} forEach GVAR(allEventHandlers);

// do InitPost
{
_x params ["_this"];

{
[_this] call _x;
} forEach (_this getVariable QGVAR(initPost));
} forEach GVAR(initPostStack);

GVAR(initPostStack) = nil;

#ifdef DEBUG_MODE_FULL
diag_log text format ["isScheduled = %1", call CBA_fnc_isScheduled];
#endif

SLX_XEH_MACHINE set [8, true]; // PostInit passed

XEH_LOG("XEH: PostInit finished.");
};

nil
Loading