Jump to content
Sign in to follow this  
carlostex

Markers and JIP persistancy...with CBA_fnc_setMarkerPersistant

Recommended Posts

Allright seems like when i try to do something on my own i seldom fail.

I need to set some markers i create while mission is progressing to be JIP persistant. I'm trying to achieve that with CBA_fnc_setMarkerPersistant but failing.

I better show how i'm calling stuff and whatnot so...

The script that creates the markers is called by an addaction attached to an object. Called with MP framework:

[player,_chair,rADDACTION,"Download Serial Numbers", "scripts\serials_hint.sqf",[_chair, player, 1, [_serialgen1,_serialgen2,_serialgen3,_serialgen4]],1,true,true,"","(_target distance _this) < 4"] call RE; 

serials_hint.sqf:

//Script and code by CarlosTex
//Made for FORCEFIELDS
waitUntil{!(isNil "BIS_MPF_InitDone")};

_actionobj = _this select 0;
_actionid = _this select 2;
_serialvars = _this select 3;

_mkrgen1 = createMarker ["markerGEN1",[getpos enemygen1 select 0,getpos enemygen1 select 1]];
_mkrgen1 setMarkerShape "ICON";
"markerGEN1" setMarkerType "mil_warning";
"markerGEN1" setMarkerSize [0.5, 0.5];
"markerGEN1" setMarkerColor "ColorRed";

_mkrgen2 = createMarker ["markerGEN2",[getpos enemygen2 select 0,getpos enemygen2 select 1]];
_mkrgen2 setMarkerShape "ICON";
"markerGEN2" setMarkerType "mil_warning";
"markerGEN2" setMarkerSize [0.5, 0.5];
"markerGEN2" setMarkerColor "ColorRed";

_mkrgen3 = createMarker ["markerGEN3",[getpos civiliangen1 select 0,getpos civiliangen1 select 1]];
_mkrgen3 setMarkerShape "ICON";
"markerGEN3" setMarkerType "mil_warning";
"markerGEN3" setMarkerSize [0.5, 0.5];
"markerGEN3" setMarkerColor "ColorRed";

_mkrgen4 = createMarker ["markerGEN4",[getpos civiliangen2 select 0,getpos civiliangen2 select 1]];
_mkrgen4 setMarkerShape "ICON";
"markerGEN4" setMarkerType "mil_warning";
"markerGEN4" setMarkerSize [0.5, 0.5];
"markerGEN4" setMarkerColor "ColorRed";

	_text = parseText format[
       "<t color='#FFCC33'>Generators Serials</t><br/><t color='#D80000'>%1</t><br/><t color='#D80000'>%2</t><br/><t color='#FFFFFF'>%3</t><br/><t color='#FFFFFF'>%4</t><br/>", (_serialvars select 3) select 0, (_serialvars select 3) select 1, (_serialvars select 3) select 2, (_serialvars select 3) select 3];
       [nil,nil,rHINT,_text] call RE;

[player,_actionobj,rREMOVEACTION,_actionid] call RE; 

[_mkrgen1, true] call CBA_fnc_setMarkerPersistent;
[_mkrgen2, true] call CBA_fnc_setMarkerPersistent;
[_mkrgen3, true] call CBA_fnc_setMarkerPersistent;
[_mkrgen4, true] call CBA_fnc_setMarkerPersistent;

OK markers are created fine, in fact everything is fine, except if i leave the dedicated server and rejoin again the markers won't be there anymore. I think i'm using the correct syntax. CBA wiki says about this function:

Sets or unsets JIP persistency on a global marker.

Will broadcast event to server, if function is called on a client

No go, markers disappear when i JIP.... :confused:

EDIT: No RPT errors BTW....

Share this post


Link to post
Share on other sites

The syntax seems fine. I do believe we tested the function mostly with server-created markers, but I dont think it should matter.

Did you verify if the function calls are executed? E.g put a diag_log before and after the setMarkerPersistent lines and confirm in rpt, or use a hint etc.

Could you verify it in an empty test mission, with just one or two units, mission init.sqf with if (isServer) then { createMarker ...; ... setMarker...; .. call CBA_fnc_setMarkerPersistent };

And see how that goes?

If still issues, if you could please create a ticket and attach such test mission https://dev-heaven.net/projects/cca/issues, then I'll get right on it, see if we have a bug or what's going on :)

Edited by Sickboy

Share this post


Link to post
Share on other sites

Hum, never used diag_log before so what's the syntax?

Should i just write diag_log before and after calling the functions or does it need diag_log plus anything? I'm using no handlers when calling the functions.

Also do you want me to test empty test mission on single player?

Share this post


Link to post
Share on other sites

Right i'll do that. I thought maybe you just wanted to see if it was doing it's thing on the server, since isServer in SP returns true.

---------- Post added at 03:01 PM ---------- Previous post was at 02:46 PM ----------

OK still have to do the empty mission test but i set up the diag_log like this:

diag_log format ["%1, %2, %3, %4, %5, %6, %7, %8", _d1, _d2, _d3, _d4, _mkrgen1, _mkrgen2, _mkrgen3, _mkrgen4]; 
_d1 = [_mkrgen1, true] call CBA_fnc_setMarkerPersistent;
_d2 = [_mkrgen2, true] call CBA_fnc_setMarkerPersistent;
_d3 = [_mkrgen3, true] call CBA_fnc_setMarkerPersistent;
_d4 = [_mkrgen4, true] call CBA_fnc_setMarkerPersistent;
diag_log format ["%1, %2, %3, %4, %5, %6, %7, %8", _d1, _d2, _d3, _d4, _mkrgen1, _mkrgen2, _mkrgen3, _mkrgen4]; 

Server RPT returned nothing on this. Arma2OA RPT returned:

"any, any, any, any, markerGEN1, markerGEN2, markerGEN3, markerGEN4"
"true, true, true, true, markerGEN1, markerGEN2, markerGEN3, markerGEN4"

So apparently markers are created fine, handler variables are undefined before the calls, and return true after the calls.

I JIP'ped and markers gone. :mad:

Share this post


Link to post
Share on other sites

Thanks a bunch, if can repro with the empty mission and put in ticket I'll try to look and resolve tonight or tomorrow.

Share this post


Link to post
Share on other sites

Good news for Sickboy, bad news for me.

When tested in empty mission, the marker kept persistant when i JIPped. Then i tried running the test mission again without calling CBA_fnc_setMarkerPersistant. I JIPped and marker was not there.

So i need to understand what i'm doing wrong. Apparently marker must be created on the server, otherwise no go. So i have to change my code. Any thoughts? Is it the way i'm calling?

Share this post


Link to post
Share on other sites

Thanks for testing it out :)

All looks good, it could be related to how markers are handled on the client. It is possible that if the client disconnects, the markers are completely removed,

I seem to remember something similar with markers someone places on the Map in the Map screen?

If it's the case, we should either document this limitation in the function, or we should update the function to deal with this situation, but on first sight it would not be very pretty.

As workaround, you could order the server to create the markers: Init.sqf

if (isServer) then {
  // Setup eventHandler
  ["carlos_markers", { _marker = _this select 0; _pos = _this select 1; ....; createMarker [_marker, _pos]; .... }] call CBA_fnc_addEventHandler; // Probably add markerType/Color/Shape etc

  // Helper function
  carlos_fnc_createMarker = { ["carlos_markers", _this] call CBA_fnc_localEvent }; // no need to broadcast, we're already on the server
} else {
  // Helper function
  carlos_fnc_createMarker = { ["carlos_markers", _this] call CBA_fnc_globalEvent }; // broadcast to execute on server
};

// To create a marker:
["markerName", [x,y,z]] call carlos_fnc_createMarker;

Edited by Sickboy

Share this post


Link to post
Share on other sites

Thanks Sickboy. Yesterday i achived it changing the script:

//Script and code by CarlosTex
//Made for FORCEFIELDS
waitUntil{!(isNil "BIS_MPF_InitDone")};

_actionobj = _this select 0;
_actionid = _this select 2;
_serialvars = _this select 3;

[-0, {
_mkrgen1 = createMarker ["markerGEN1",[getpos enemygen1 select 0,getpos enemygen1 select 1]];
_mkrgen1 setMarkerShape "ICON";
"markerGEN1" setMarkerType "mil_warning";
"markerGEN1" setMarkerSize [0.5, 0.5];
"markerGEN1" setMarkerColor "ColorRed";

_mkrgen2 = createMarker ["markerGEN2",[getpos enemygen2 select 0,getpos enemygen2 select 1]];
_mkrgen2 setMarkerShape "ICON";
"markerGEN2" setMarkerType "mil_warning";
"markerGEN2" setMarkerSize [0.5, 0.5];
"markerGEN2" setMarkerColor "ColorRed";

_mkrgen3 = createMarker ["markerGEN3",[getpos civiliangen1 select 0,getpos civiliangen1 select 1]];
_mkrgen3 setMarkerShape "ICON";
"markerGEN3" setMarkerType "mil_warning";
"markerGEN3" setMarkerSize [0.5, 0.5];
"markerGEN3" setMarkerColor "ColorRed";

_mkrgen4 = createMarker ["markerGEN4",[getpos civiliangen2 select 0,getpos civiliangen2 select 1]];
_mkrgen4 setMarkerShape "ICON";
"markerGEN4" setMarkerType "mil_warning";
"markerGEN4" setMarkerSize [0.5, 0.5];
"markerGEN4" setMarkerColor "ColorRed";

[_mkrgen1, true] call CBA_fnc_setMarkerPersistent;
[_mkrgen2, true] call CBA_fnc_setMarkerPersistent;
[_mkrgen3, true] call CBA_fnc_setMarkerPersistent;
[_mkrgen4, true] call CBA_fnc_setMarkerPersistent;

}] call CBA_fnc_globalExecute;


	_text = parseText format[
       "<t color='#FFCC33'>Generators Serials</t><br/><t color='#D80000'>%1</t><br/><t color='#D80000'>%2</t><br/><t color='#FFFFFF'>%3</t><br/><t color='#FFFFFF'>%4</t><br/>", (_serialvars select 3) select 0, (_serialvars select 3) select 1, (_serialvars select 3) select 2, (_serialvars select 3) select 3];
       [nil,nil,rHINT,_text] call RE;

[player,_actionobj,rREMOVEACTION,_actionid] call RE; 

Basically calling the marker creation and setpersistancy ONLY on the server.

And i do agree that maybe you guys do need to change or improve your documentation on this function.

The function you wrote there for me looks interesting enough. I'll probably move all my functions to separate scripts and compile them, than writing the same code all the time or have it in the init.sqf.

Thanks Sickboy!

Share this post


Link to post
Share on other sites

Sure mate np, glad you got it sorted. I've updated the function documentation, will be in a future update.

Share this post


Link to post
Share on other sites

Just for info:

I couldn't not make your function to work. I set it up on init.sqf like this:

if (isServer) then {
  // Setup eventHandler
  ["TEX_markers", 
{ 
_marker = _this select 0; //String
_pos = _this select 1; //Array
_shape = _this select 2; //String
_type = _this select 3; //String
_size = _this select 4; //Array 
_color = _this select 5; //String
_mkr = createMarker [_marker, _pos];
_marker setMarkerShape _shape;
_marker setMarkerSize _size;
_marker setMarkerColor _color;
}] call CBA_fnc_addEventHandler; //EventHandler	

  // Helper function
  TEX_fnc_createMarker = { ["TEX_markers", _this] call CBA_fnc_localEvent }; // no need to broadcast, we're already on the server
} else {
  // Helper function
  TEX_fnc_createMarker = { ["TEX_markers", _this] call CBA_fnc_globalEvent }; // broadcast to execute on server
};


// To create a marker:
["MarkerOne", (getmarkerpos "mkrpos"), "icon", "mil_warning", [0.5,0.5], "ColorGreen"] call TEX_fnc_createMarker;

No errors, no nothing, diag_log shows nothing wrong in RPT but marker is never created. It would be nice to have this function working but i won't cry for it.

Share this post


Link to post
Share on other sites

Does the "mkrpos" marker exist, and diag_log

(getmarkerpos "mkrpos") shows correct value?

Share this post


Link to post
Share on other sites

Yes it is editor place. And diag_log (getmarkerpos "mkrpos") returns as well.

Share this post


Link to post
Share on other sites

I suppose the main problem is that you do not use

_marker setMarkerType _type;

Share this post


Link to post
Share on other sites

Haha, love the smiley :) No worries, happens to us all :P

Share this post


Link to post
Share on other sites

BTW, how beneficial do you consider if i decide to precompile it, since i'm probably gonna call it quite a few times during the mission?

Share this post


Link to post
Share on other sites
BTW, how beneficial do you consider if i decide to precompile it, since i'm probably gonna call it quite a few times during the mission?
It already is precompiled.

---------- Post added at 12:21 ---------- Previous post was at 12:15 ----------

The diff is in:

A) Not precompiled

Init: Nothing

Call:

[someParam, someParam2] call compile preProcessFileLineNumbers "functionName.sqf";

vs

B) Precompiled

Init:

TEX_functionName = { .... function content ... };

Which could also have been (no real difference other than directory structure):

TEX_functionName = compile preProcessFileLineNumbers "functionName.sqf"

Call:

[someParam, someParam2] call TEX_functionName;

Edited by Sickboy

Share this post


Link to post
Share on other sites

OK, i wrote the function in a separate script called "fn_createMarkers.sqf".

So in the init.sqf i have:

call compile preProcessFileLineNumbers "functions\fn_createMarkers.sqf".

So this would be getting the same result because it is already precompiled?:

execVM "functions\fn_createMarkers.sqf"

I thought that preCompiling meant something like when you write a program in C# language and then compile it with GCC, ICC or Open64 compilers makes it faster because you're not running raw data (and obviously compiler also translates it into machine language). (Probably now you'll get that i understand 0 about programming). :confused:

So basically doing:

global or local variable = {code here};

already precompiles it?

EDIT: BTW when i tested my mission precompiling the function in the init.sqf and creating the markers using the function everything is working fine. But with your explanation i understand now that i also could have execVM "functions\fn_CreateMarkers.sqf" and it would be the same.

So what's the point of having the command if you can preCompile in the scripts instead?

Edited by CarlosTex

Share this post


Link to post
Share on other sites

Nope you misunderstood me.

As said you already precompiled the function from the beginning by specifying it as TEX_name = { ... }, there is nothing more you need to do.

TEX_name = { ... }; comes down to the same as putting the code in a sqf and then using TEX_name = compile preProcessFileLineNumbers "file.sqf";

Especially don't use execVM if you are going to use it over and over, besides that it is to run scripts, and not to call functions that return anything.

Share this post


Link to post
Share on other sites

I did understand it and i think perhaps you also misunderstood me. I still have to run that function once, because i'm not writing the function in the init.sqf. I did put the entire code in a separate sqf called fn_CreateMarkers. The global variable that contains the function must be initialised in order for me to use it later on the mission right? So if i execVM fn_CreateMarkers.sqf once let's say from the init, the eventhandler and the calling functions will be created and initialised once and i can use them later.

So execVM will do the same because inside the file the function is already set with the TEX_fnc_createMarker = {}, that i understand now, i just didn't know that using a global variable and {} would not need for compile anymore. I understand now that compile and preProcessFile commands will remotely create a function out of a sqf that was not done with global variable and {};

My confusion was that i understood compile and preProcessFileLineNumbers as what GNU compiler or ICC do. I thought that compile and preProcessFileLineNumbers would make a script more efficient, use less memory and CPU cycles. I do understand my mistake now.

Share this post


Link to post
Share on other sites

preProcessFile preProcesses a file to a preprocessed string (all preprocessor directives like #define, #ifdef, #ifndef, etc have been processed).

compile converts a string ("") into code ({}), and afaik does a syntax check.

If you have a file called fn_createMarker.sqf you shouldn't put TEX_fn_createMarker = { in that file, but just the code itself. See for example; https://dev-heaven.net/projects/cca/repository/revisions/develop/entry/addons/common/fnc_addWeapon.sqf or any of the BIS functions etc.

Instead you should then use TEX_fn_createMarker = compile preProcessFileLineNumbers "fn_createMarker.sqf";

Directly in your init.sqf, or e.g in an init_functions.sqf.

In latter case yes you could use execVM "init_functions.sqf" from init.sqf, but please do note that execVM's might be scheduled to run rather late depending on scheduler load, so i'd advise not to use it.

In that case it would be better to use from init.sqf: call compile preProcessFileLineNumbers "init_functions.sqf";

There's spawn and call. Call will run the code synchronously and allows you to return a value, Spawn will execute asynchronously and cannot return a value, instead it returns the scriptHandle.

You could say that "execVM 'file.sqf'" is basically the same as "spawn compile preProcessFileLineNumbers 'file.sqf'"

---------- Post added at 14:40 ---------- Previous post was at 14:34 ----------

If your mission is relying on CBA, I would even go as far as dropping the init.sqf usage for function compilation, and throw this in the description.ext instead:

class Extended_PreInit_EventHandlers {
  class TEX_Mission {
     init = "call compile preProcessFileLineNumbers 'init_functions.sqf'"; // Initializes on any type of machine
     // clientInit = ""; // Initializes only on machines with a client (Dedicated Client, or ClientServer/SP)
     // serverInit = ""; // Initializes only on machines that are server (Dedicated Server, or ClientServer/SP)
  };
};

Then your functions are even usable from within Editor Init Fields :) In case of mission init.sqf - they will not be.

Examples here: http://browser.six-projects.net/configclasses/Extended_PreInit_EventHandlers/config

Some more EH options:

InitOnce, PostInit: http://browser.six-projects.net/configclasses/Extended_PostInit_EventHandlers/config

Init on Objects: http://browser.six-projects.net/configclasses/Extended_Init_EventHandlers/config

---------- Post added at 14:47 ---------- Previous post was at 14:40 ----------

Oh and alternatively you could even use the BI function module to compile the functions, in description.ext:

Examples here; http://browser.six-projects.net/configclasses/CfgFunctions/config

Edited by Sickboy

Share this post


Link to post
Share on other sites

fn_CreateMarkers.sqf:

//Create Global Markers function
//By CarlosTex and Sickboy

if (isServer) then {
  // Setup eventHandler
  ["TEX_markers", 
{ 
_marker = _this select 0; //String
_pos = _this select 1; //Array
_shape = _this select 2; //String
_type = _this select 3; //String
_size = _this select 4; //Array 
_color = _this select 5; //String
_mkr = createMarker [_marker, _pos];
_marker setMarkerShape _shape;
_marker setMarkerType _type;
_marker setMarkerSize _size;
_marker setMarkerColor _color;
}] call CBA_fnc_addEventHandler; //EventHandler	

  // Helper function
  TEX_fnc_createMarker = { ["TEX_markers", _this] call CBA_fnc_localEvent }; // no need to broadcast, we're already on the server
} else {
  // Helper function
  TEX_fnc_createMarker = { ["TEX_markers", _this] call CBA_fnc_globalEvent }; // broadcast to execute on server
};

on the init.sqf i'm, doing this:

call compile preProcessFileLineNumbers "functions\fn_CreateMarkers.sqf";

I create markers on other scripts using TEX_fnc_createMarker. Isn't this correct?

Other example:

fn_customLoadouts.sqf:

_getgroup = _this select 0;

_grpunits = units _getgroup;

_officer = _grpunits select 0;
_number2 = _grpunits select 1;
_number3 = _grpunits select 2;
_number4 = _grpunits select 3;
_number5 = _grpunits select 4;
_number6 = _grpunits select 5;
_number7 = _grpunits select 6;
_number8 = _grpunits select 7;
_number9 = _grpunits select 8;

{removeallweapons _x} foreach units _getgroup;
{removeallitems _x} foreach units _getgroup;

{_x addweapon "ACE_AK74M_TWS_FL"} foreach [_officer, _number9];

{_x addweapon "ACE_AK74M_GL_TWS"} foreach [_number3, _number4, _number6, _number7];

{_x addweapon "ACE_RPK74M_1P29"} foreach [_number2, _number5];

_number8 addweapon "ksvk";

{_grpunitmags = _x;
{_grpunitmags addMagazine "ACE_75Rnd_545x39_T_RPK"} forEach [1,2,3,4,5,6,7,8,9,10];
} foreach [_officer, _number2, _number3, _number4, _number5, _number6, _number7, _number9];

{_grpunitmags = _x;
{_grpunitmags addMagazine "ACE_5Rnd_127x108_T_KSVK"} forEach [1,2,3,4,5,6,7,8,9,10];
} foreach [_number8];

{_grpunitmags = _x;
{_grpunitmags addMagazine "ACE_M84"} forEach [1,2];
} foreach [_number2, _number3, _number4]; 

{_grpunitmags = _x;
{_grpunitmags addMagazine "ACE_M7A3"} forEach [1,2];
} foreach [_number1, _number5, _number6];

{_grpunitmags = _x;
{_grpunitmags addMagazine "ACE_M34"} forEach [1];
} foreach [_number7, _number8, _number9]; 

{_grpunitmags = _x;
{_grpunitmags addMagazine "ACE_ANM14"} forEach [1];
} foreach units _getgroup; 

{_x addmagazine "ACE_M15"} foreach units _getgroup;  

{_grpunitgrenades = _x;
{_grpunitgrenades addMagazine "ACE_1Rnd_HE_GP25P"} forEach [1,2,3,4,5,6];
} foreach [_number3, _number4, _number6, _number7];  

{_grpunitgrenades = _x;
{_grpunitgrenades addMagazine "ACE_1Rnd_CS_GP25"} forEach [1];
} foreach units _getgroup;

{_grpunitgrenades = _x;
{_grpunitgrenades addMagazine "1Rnd_SmokeRed_GP25"} forEach [1];
} foreach units _getgroup;

//nv goggles for every unit
{_x addweapon "NVGoggles"} foreach units _getgroup;

//gps for everyone
{_x addweapon "ItemGPS"} foreach units _getgroup;

//radio for everyone
{_x addweapon "ItemRadio"} foreach units _grpone;

//Earplugs for everyone
{_x addweapon "ACE_Earplugs"} foreach units _grpone;

{_x addweapon "ACE_RPG22"} foreach [_number4, _number7];

//Rangefinder for everyone
{_x addweapon "ACE_YardAge450"} foreach units _getgroup;

init.sqf:

TEX_fnc_CustomLoadouts = compile preProcessFileLineNumbers "functions\fn_CustomLoadouts.sqf";

I call the function after i spawn a group with BIS_fnc_SpawnGroup.

_grpcustom3 = [[5830.0566,3153.0872,17.918724], EAST, ["TK_Soldier_Officer_EP1", "TK_Soldier_MG_EP1", "TK_Soldier_EP1", "TK_Soldier_HAT_EP1", "TK_Soldier_AR_EP1", "TK_Soldier_GL_EP1", "TK_Soldier_EP1", "TK_Soldier_SniperH_EP1", "TK_Soldier_Medic_EP1"],[],[],[],[],[],180] call BIS_fnc_spawnGroup;
_nul = [_grpcustom3] call TEX_fnc_CustomLoadouts;

It appears to be running fine.

I also understood and actually liked your input about how to compile from the description.ext. Looks actually to be a good idea.

Thanks Sickboy, i think i'm understanding it, but if you feel i am not then please feel free to further educate me. I'm still a lousy scripter.

Edited by CarlosTex

Share this post


Link to post
Share on other sites

Looking good there, especially the TEX_fnc_CustomLoadouts example.

For consistency sake, you should imo rename fn_createMarkers.sqf to init_createMarkers.sqf. IMO a fn_ function file should contain just function code directly like you have in fn_customLoadOut.sqf. The fn_createMarkers.sqf attaches an eventhandler and initializes a function, hence init_createMarkers.sqf or even simply moving the code directly into the init.sqf would therefore seem more logical.

Share this post


Link to post
Share on other sites

OK so if i use init_createMarkers.sqf how do i initialize it? execVM? I could lay the code on init.sqf, but i would prefer the init.sqf to be cleaner...

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×