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

Debug watching for statements that run on a remote machine #658

Merged
merged 14 commits into from
May 7, 2017
23 changes: 23 additions & 0 deletions addons/diagnostic/Cfg3DEN.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

class Cfg3DEN {
class Mission {
class Scenario {
class AttributeCategories {
class States {
class Attributes {
class EnableTargetDebug {
property = "EnableTargetDebug";
value = 0;
control = "CheckboxNumber";
displayName = CSTRING(EnableTargetDebug);
tooltip = CSTRING(EnableTargetDebug_tooltip);
defaultValue = "0";
expression = "true";
wikiType = "[[Bool]]";
};
};
};
};
};
};
};
2 changes: 2 additions & 0 deletions addons/diagnostic/CfgEventHandlers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ class Extended_DisplayLoad_EventHandlers {
};
class RscDisplayInterrupt {
GVAR(extendedDebug) = QUOTE(_this call (uiNamespace getVariable 'FUNC(initExtendedDebugConsole)'));
GVAR(targetDebug) = QUOTE(_this call (uiNamespace getVariable 'FUNC(initTargetDebugConsole)'));
};
class RscDisplayMPInterrupt {
GVAR(extendedDebug) = QUOTE(_this call (uiNamespace getVariable 'FUNC(initExtendedDebugConsole)'));
GVAR(targetDebug) = QUOTE(_this call (uiNamespace getVariable 'FUNC(initTargetDebugConsole)'));
};
};
50 changes: 50 additions & 0 deletions addons/diagnostic/XEH_preInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,53 @@ GVAR(projectileStartedDrawing) = false;
GVAR(projectileTrackedUnits) = [];

ADDON = true;

if (getMissionConfigValue ["EnableTargetDebug", 0] isEqualTo 1) then {
INFO("EnableTargetDebug is enabled");

[QGVAR(watchVariable), {
params ["_clientID", "_varIndex", "_statementText"];
TRACE_3("targetWatchVariable",_clientID,_varIndex,_statementText);

private _timeStart = diag_tickTime;
private _returnString = _statementText call{
private ["_clientID", "_statementText", "_varName", "_timeStart", "_x"];
_this = ([nil] apply compile _this) select 0;
if (isNil "_this") exitWith {"#NIL"};
str _this
};
_returnString = _returnString select [0, 1000]; // limit string length
private _duration = diag_tickTime - _timeStart;

private _varName = format ["CBA_targetWatchVar_%1_%2", _clientID, _varIndex];
(missionNamespace getVariable [_varName, []]) params [["_responseStatement", "", [""]], ["_responseReturn", "", [""]], ["_lastDuration", 0, [0]]];
if (_responseStatement isEqualTo _statementText) then {_duration = 0.1 * _duration + 0.9 * _lastDuration;}; // if statement is the same, get an average

missionNamespace setVariable [_varName, [_statementText, _returnString, _duration]];
if (_clientID != CBA_clientID) then {
publicVariable _varName; // send back over network
};
}] call CBA_fnc_addEventHandler;


if (isNil QGVAR(clientIDs)) then {
GVAR(clientIDs) = [[2, profileName]];
};

if (isServer) then {
addMissionEventHandler ["PlayerConnected", {
params ["", "", "_name", "", "_owner"];

if (_owner == 2) exitWith {};
GVAR(clientIDs) pushBackUnique [_owner, _name];
publicVariable QGVAR(clientIDs);
}];

addMissionEventHandler ["PlayerDisconnected", {
params ["", "", "_name", "", "_owner"];

GVAR(clientIDs) deleteAt (GVAR(clientIDs) find [_owner, _name]);
publicVariable QGVAR(clientIDs);
}];
};
};
1 change: 1 addition & 0 deletions addons/diagnostic/XEH_preStart.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
#include "XEH_PREP.sqf"

PREP(initExtendedDebugConsole);
PREP(initTargetDebugConsole);
1 change: 1 addition & 0 deletions addons/diagnostic/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ class CfgPatches {
#include "CfgFunctions.hpp"
#include "CfgEventHandlers.hpp"

#include "Cfg3DEN.hpp"
#include "CfgDisplay3DEN.hpp"
#include "gui.hpp"
6 changes: 3 additions & 3 deletions addons/diagnostic/fnc_initExtendedDebugConsole.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ private _prevButton = _display ctrlCreate ["RscButtonMenu", IDC_DEBUGCONSOLE_PRE
_prevButton ctrlSetPosition [
0 * GUI_GRID_W,
9.25 * GUI_GRID_H + safezoneH - 26.25 * GUI_GRID_H,
11.25 * GUI_GRID_W,
10.875 * GUI_GRID_W,
1 * GUI_GRID_H
];
_prevButton ctrlCommit 0;
Expand All @@ -78,9 +78,9 @@ _prevButton ctrlAddEventHandler ["MouseButtonUp", {_this call FUNC(prevStatement
private _nextButton = _display ctrlCreate ["RscButtonMenu", IDC_DEBUGCONSOLE_NEXT, _debugConsole];

_nextButton ctrlSetPosition [
11.5 * GUI_GRID_W,
11.125 * GUI_GRID_W,
9.25 * GUI_GRID_H + safezoneH - 26.25 * GUI_GRID_H,
11.25 * GUI_GRID_W,
10.875 * GUI_GRID_W,
1 * GUI_GRID_H
];
_nextButton ctrlCommit 0;
Expand Down
183 changes: 183 additions & 0 deletions addons/diagnostic/fnc_initTargetDebugConsole.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/* ----------------------------------------------------------------------------
Function: CBA_diagnostic_fnc_initTargetDebugConsole

Description:
Adds addition watch statements that are run on a remote target and have their values returned to the client.
Requires `EnableTargetDebug = 1; `in description.ext

Author:
(based on BIS's RscDebugConsole.sqf)
PabstMirror
commy2
---------------------------------------------------------------------------- */

//#define DEBUG_MODE_FULL
#include "\a3\ui_f\hpp\defineResinclDesign.inc"
#include "script_component.hpp"

#define COUNT_WATCH_BOXES 8

if (!((getMissionConfigValue ["EnableTargetDebug", 0]) isEqualTo 1)) exitWith {};

params ["_display"];
TRACE_1("adding server watch debug",_display);

// adjust position of the main controls group to make it wider (may be slightly cut off with "Very-Large" text size)
private _debugConsole = _display displayCtrl IDC_RSCDEBUGCONSOLE_RSCDEBUGCONSOLE;
private _debugConsolePos = ctrlPosition _debugConsole;
_debugConsolePos set [2, (_debugConsolePos select 2) + 22.5 * GUI_GRID_W];
_debugConsole ctrlSetPosition _debugConsolePos;
_debugConsole ctrlCommit 0;

private _basePosition = ctrlPosition (_display displayCtrl IDC_RSCDEBUGCONSOLE_WATCHINPUT1);
_basePosition set [0, (_basePosition select 0) + 22.5 * GUI_GRID_W];
_basePosition set [1, (_basePosition select 1) - (1.5 + 2 * (COUNT_WATCH_BOXES - 4)) * GUI_GRID_H];


// Add background and "Target Watch" text:
private _targetWatchBackground = _display ctrlCreate ["RscText", -1, _debugConsole];
_targetWatchBackground ctrlSetBackgroundColor [0,0,0,0.7];
private _ctrlPos = ctrlPosition (_display displayCtrl IDC_RSCDEBUGCONSOLE_WATCHBACKGROUND);
_ctrlPos set [0, (_ctrlPos select 0) + 22.5 * GUI_GRID_W];
_ctrlPos set [1, (_ctrlPos select 1) - (1.5 + 2 * (COUNT_WATCH_BOXES - 4)) * GUI_GRID_H];
_ctrlPos set [3, (_ctrlPos select 3) + (1.5 + 2 * (COUNT_WATCH_BOXES - 4)) * GUI_GRID_H];
_targetWatchBackground ctrlSetPosition _ctrlPos;
_targetWatchBackground ctrlCommit 0;
private _targetWatchText = _display ctrlCreate ["RscText", -1, _debugConsole];
_targetWatchText ctrlSetText format ["%1 %2", localize "str_watch_target", localize "STR_A3_RscDebugConsole_WatchText"];
_targetWatchText ctrlSetFontHeight (0.7 * GUI_GRID_H);
_ctrlPos set [0, (_ctrlPos select 0) + 0.2 * GUI_GRID_W];
_ctrlPos set [3, 0.5 * GUI_GRID_W];
_targetWatchText ctrlSetPosition _ctrlPos;
_targetWatchText ctrlCommit 0;



// Add target selector list
private _clientList = _display ctrlCreate ["RscCombo", -1, _debugConsole];
_clientList ctrlSetPosition _basePosition;
_clientList ctrlCommit 0;
_basePosition set [1, (_basePosition select 1) + 1.5 * GUI_GRID_H];

// - add available targets to list
private _lastSelected = 0;
{
_x params ["_clientID", "_profileName"];
_clientList lbSetValue [_clientList lbAdd format ["%1 - %2", _clientID, _profileName], _clientID];
if (_clientID == GVAR(selectedClientID)) then {_lastSelected = _forEachIndex};
} forEach GVAR(clientIDs);

_clientList lbSetCurSel _lastSelected;
GVAR(selectedClientID) = _clientList lbValue lbCurSel _clientList;

_clientList ctrlAddEventHandler ["LBSelChanged", {
params ["_clientList", "_index"];

GVAR(selectedClientID) = _clientList lbValue _index;
}];

// Add TARGET EXEC button
private _serverExec = _display displayCtrl IDC_RSCDEBUGCONSOLE_BUTTONEXECUTESERVER;
_serverExec ctrlShow false;
_serverExec ctrlEnable false;

private _targetExec = _display ctrlCreate ["RscButtonMenu", -1, _debugConsole];
_targetExec ctrlSetPosition ctrlPosition _serverExec;
_targetExec ctrlCommit 0;
_targetExec ctrlSetText toUpper localize LSTRING(TargetExec);

_targetExec ctrlAddEventHandler ["ButtonClick", {
params ["_targetExec"];
private _statement = ctrlText (ctrlParentControlsGroup _targetExec controlsGroupCtrl IDC_RSCDEBUGCONSOLE_EXPRESSION);
compile _statement remoteExec ["call", GVAR(selectedClientID)];
}];

_targetExec ctrlAddEventHandler ["MouseButtonUp", {
_this call FUNC(logStatement);
false
}];

private _watchVars = [];
for "_varIndex" from 0 to (COUNT_WATCH_BOXES - 1) do {
// Create the controls for each row and fill input with last saved value from profile
private _profileVarName = format ["CBA_targetWatch_%1", _varIndex];
private _savedStatement = profileNamespace getVariable [_profileVarName, ""];
if (!(_savedStatement isEqualType "")) then {_savedStatement = ""};

private _inputEditbox = _display ctrlCreate [QGVAR(watchInput), -1, _debugConsole];
private _outputBackground = _display ctrlCreate ["RscText", -1, _debugConsole];
private _outputEditBox = _display ctrlCreate [QGVAR(watchOutput), -1, _debugConsole];

_outputBackground ctrlSetBackgroundColor [0,0,0,0.75];
_inputEditbox ctrlSetText _savedStatement;

_inputEditbox ctrlSetPosition _basePosition;
_inputEditbox ctrlCommit 0;
_basePosition set [1, (_basePosition select 1) + 1 * GUI_GRID_H];

_outputBackground ctrlSetPosition _basePosition;
_outputBackground ctrlCommit 0;
_outputEditBox ctrlSetPosition _basePosition;
_outputEditBox ctrlCommit 0;
_basePosition set [1, (_basePosition select 1) + 1 * GUI_GRID_H];

_watchVars pushBack [_inputEditbox, _outputBackground, _outputEditBox, -1];
};
_display setVariable [QGVAR(watchVars), _watchVars];


// Runs constantly, sends statement to target and parses the result back in the output window
private _fnc_updateWatchInfo = {
params ["_display"];

private _watchVars = _display getVariable [QGVAR(watchVars), []];
{
private _varIndex = _forEachIndex;
private _varName = format ["CBA_targetWatchVar_%1_%2", CBA_clientID, _varIndex];
_x params ["_inputEditbox", "_outputBackground", "_outputEditBox", "_lastSent"];
private _editText = ctrlText _inputEditbox;
(missionNamespace getVariable [_varName, []]) params [["_responseStatement", "", [""]], ["_responseReturn", "", [""]], ["_duration", 0, [0]]];

if (_editText == "") then {
missionNamespace setVariable [_varName, nil];
} else {
if ((_editText isEqualTo _responseStatement) && {_duration > 0.1}) exitWith {}; // don't re-run if statement that took a long time
if ((diag_tickTime - _lastSent) > random [0.1, 0.2, 0.3]) then {
_x set [3, diag_tickTime]; // set last run to now
[QGVAR(watchVariable), [CBA_clientID, _varIndex, _editText], GVAR(selectedClientID)] call CBA_fnc_ownerEvent; // send statement to target
};
};

private _bgColor = switch (true) do {
case (_duration < 0.0015): {[linearConversion [0.0001, 0.0015, _duration, 0, 0.4, true], linearConversion [0.0005, 0.0015, _duration, 0, 0.4, true], 0, 0.4]};
case (_duration < 0.003): {[linearConversion [0.0015, 0.003, _duration, 0.4, 0.8, true], linearConversion [0.0015, 0.003, _duration, 0.4, 0.5, true], 0, 0.5]};
case (_duration < 0.1): {[linearConversion [0.003, 0.05, _duration, 0.8, 1, true], linearConversion [0.003, 0.05, _duration, 0.5, 0.1, true], 0, 0.8]};
default {[1,0,0,1]};
};
_outputEditBox ctrlSetText _responseReturn;
_outputBackground ctrlSetBackgroundColor _bgColor;
} forEach _watchVars;
};
_display displayAddEventHandler ["MouseMoving", _fnc_updateWatchInfo];
_display displayAddEventHandler ["MouseHolding", _fnc_updateWatchInfo];


// On unload, save the statements to profile (only if they didn't stall badly)
private _fnc_onUnload = {
params ["_display"];

private _watchVars = _display getVariable [QGVAR(watchVars), []];
{
_x params ["_inputEditbox", "_outputBackground", "_outputEditBox", "_lastSent"];
private _varIndex = _forEachIndex;
private _varName = format ["CBA_targetWatchVar_%1_%2", CBA_clientID, _varIndex];
private _editText = ctrlText _inputEditbox;
(missionNamespace getVariable [_varName, []]) params [["_responseStatement", "", [""]], ["_responseReturn", "", [""]], ["_duration", 0, [0]]];

if ((_editText isEqualTo _responseStatement) && {_duration < 0.1}) then {
private _profileVarName = format ["CBA_targetWatch_%1", _varIndex];
profileNamespace setVariable [_profileVarName, _responseStatement];
};
} forEach _watchVars;
};
_display displayAddEventHandler ["Unload", _fnc_onUnload];
25 changes: 25 additions & 0 deletions addons/diagnostic/gui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,28 @@ class RscDisplayMain: RscStandardDisplay {
};
};
};

class RscEdit;
class GVAR(watchInput): RscEdit {
autocomplete = "scripting";
shadow = 0;
font = "EtelkaMonospacePro";
x = 0.5 * GUI_GRID_W;
y = 11 * GUI_GRID_H;
w = 21 * GUI_GRID_W;
h = 1 * GUI_GRID_H;
sizeEx = 0.7 * GUI_GRID_H;
};

class GVAR(watchOutput): RscEdit {
lineSpacing = 1;
style = ST_NO_RECT;
shadow = 0;
font = "EtelkaMonospacePro";
x = 0.5 * GUI_GRID_W;
y = 12 * GUI_GRID_H;
w = 21 * GUI_GRID_W;
h = 1 * GUI_GRID_H;
colorBackground[] = {0,0,0,0.75};
sizeEx = 0.7 * GUI_GRID_H;
};
10 changes: 10 additions & 0 deletions addons/diagnostic/stringtable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,15 @@
<English>Next Statement</English>
<German>Nächster Ausdruck</German>
</Key>
<Key ID="STR_CBA_Diagnostic_TargetExec">
<English>Target Exec</English>
</Key>

<Key ID="STR_CBA_Diagnostic_EnableTargetDebug">
<English>Enable Target Debuging</English>
</Key>
<Key ID="STR_CBA_Diagnostic_EnableTargetDebug_tooltip">
<English>[CBA] Allows remote target debugging. Requires Debug Console.</English>
</Key>
</Package>
</Project>