Jump to content
Sign in to follow this  
Nielsen

Problem with JIP: PublicVariables and MP Framework not working.

Recommended Posts

Hi all.

For longer than I care to rememeber, I have tried to make my missions JIP compatible - but to no avail. I've read all I could find about this and it is starting to drive me crazy.

I have done a 2 trigger solution:

-1trigger:

Con: this

Act: objdone = true; PublicVariable "objdone";

-2trigger

Con: Objdone

Act: tskObj1 settaskstate "SUCCEEDED";

This failed to update when I had a player connect and multiple tasks where both created and completed with PV on JIP. I figured that Variable/trigger that completed the task might "fire" before the Variable creating it. I then removed the PublicVariables in the triggers, and set a -

Init.sqf:

onPlayerConnected "nul=[] execVM 'testJIP.sqf'";

testJIP.sqf:

obj1created = true;
sleep 1;
PubliVariable "obj1created";
sleep 1;
obj1done = true;
sleep 1;
"PublicVariable "obj1done";
sleep 1;
obj2created = true;
sleep 1;
PublicVariable "obj2created";
sleep 1;
//And so on.

I inluded the sleep, as I read on a forum, that it might cause problems when a client recieves more than 1 publicvariable at a time (pr. frame).

This solution seems to be much more consistent, but it still fails to update all (8) tasks to completed. 1 or 2 are allways only created when a player connects. In addition this does'nt solve the problem when another JIP happens, and the variables are allready public trough onplayerconnected. Then nothing really works.

Then I read about the Multiplayer Framework in the functions module and thought :yay:

I have tried it, but can not get it to work either.

I add a functions module to my mission.

In init.sqf I add:

waituntil {!isnil "bis_fnc_init"};
waituntil {!isnil "BIS_MPF_InitDone"};

as I have seen suggested on the forums.

The I use the code

[nil,TskObj1,"per",rSettaskState,"Succeeded"] call RE;

to update the tasks, but it does not work.

I get and Error. I says that BIS_missionScope is nil.

I have tried to include a:

waituntil {!isnil "BIS_missionScope"};

In the init.sqf, but that does not work.

I read on the forum that the MP Framework had to be initialized, and that could be done with:

 if (isnil "RE") then {[] execVM "\ca\Modules\MP\data\scripts\MPframework.sqf"};  

That does not seem to work either..

I have also tried the TaskMaster script by 'Shk', but that wont work for me either. When I open the demomissions and have a buddy JIP the tasks wont update correctly.

Would someone be so kind to explain to me how I get the Multiplayer Framework to work, or how to make my tasks update properly for JIP.

I would be forever gratefull. Thanks in advance.

Kind regards,

R. Nielsen

Edited by Nielsen

Share this post


Link to post
Share on other sites

Something I made during lunch break, give it a go. Tasks needs to be named task1, task2, task3 etc. The spawn is basically your briefing.sqf (apart from the for-loop that just adds dummy tasks for testing).

init.sqf

if isserver then {
 task_states_for_jips = [];
};
fnCompleteTask = {
 if isserver then {
   task_states_for_jips set [count task_states_for_jips,_this];
   publicvariable "task_states_for_jips";
 };
 call compile format ["task%1 settaskstate ""succeeded""",_this];
};

if !isdedicated then {
 [] spawn {
   waitUntil {!isnull player};
   for [{_i=15},{_i>0},{_i=_i-1}] do {
     call compile format ["
       task%1 = player createSimpleTask [""task%1""];
       task%1 setSimpleTaskDescription [""desc%1"",""title%1"",""""];"
     ,_i];
   };
   waituntil {!isnil "task_states_for_jips"};
   {
     call compile format ["task%1 settaskstate ""succeeded""",_x];
   } foreach task_states_for_jips;
 };
};

To update task in a trigger:

1 call fnCompleteTask

1 being number of the task obviously.

example mission

Edited by Shuko

Share this post


Link to post
Share on other sites

Hmm. Cant figure out how to delete this post.

Edited by Nielsen

Share this post


Link to post
Share on other sites

@shk

It is really kind of you to make this. I really like the update method. Even a novice like me can make that work :) I'm not sure how it all works though.

Do I just create the specifik tasks in the spawn like this:

if !isdedicated then {
 [] spawn {
   waitUntil {!isnull player};
   for [{_i=15},{_i>0},{_i=_i-1}] do {
     call compile format ["
       task%1 = player createSimpleTask [""task%1""];
       task%1 setSimpleTaskDescription [""desc%1"",""title%1"",""""];"
       [color="Red"]task%2 = player createSimpleTask [""Go blow up stuff%2""];
       task%2 setSimpleTaskDescription [""Blow up stuff fast%2"",""Blow up%2"",""""];"[/color]
     ,_i];
   };
   waituntil {!isnil "task_states_for_jips"};
   {
     call compile format ["task%1 settaskstate ""succeeded""",_x];
   } foreach task_states_for_jips;
 };
};

and then change the {_i=15} to the number of tasks I have?

Also. I really want to create the tasks by trigger detection. Not all tasks should be there from the start. Is this possible with this script, or with slight changes?

Unfortunately my buddy is unavailable for JIP testing at the moment. It really looks promising though. I cant wait to test it out. If I could create tasks on the fly and update them like this - and the JIP updates works for all; well, then I would just be the merriest mission maker on this forum :)

Thanks again!

Share this post


Link to post
Share on other sites

I did mention that for loop being just something that creates test tasks. ;)

if !isdedicated then {
 [] spawn {
   waitUntil {!isnull player};
   /* Create your tasks, their variable must be named task1, task2, task3 and so on. */
   task1 = player createSimpleTask ["task1"];
   task1 setSimpleTaskDescription ["Kill some bad guy","Bad guy",""];
   task2 = player createSimpleTask ["task2"];
   task2 setSimpleTaskDescription ["Run away like a little girl","Extraction",""];
   /* End of task creation */
   waituntil {!isnil "task_states_for_jips"};
   {
     call compile format ["task%1 settaskstate ""succeeded""",_x];
   } foreach task_states_for_jips;
 };
};

Also, it shouldn't matter where or when you add tasks, but I didn't test it.

Me and my slow brain after just woking up, it doesn't matter where/when you create them, but you have to pubvar them also, so the JIPs will create the tasks as well.

Edited by Shuko

Share this post


Link to post
Share on other sites

shk, You rock. Thanks for helping me once again. This worked perfect for me.

Share this post


Link to post
Share on other sites

Indeed you did. Sorry, I get it now :)

And it WORKS! :yay: x10

You are awesome!

On the other hand - I suck!

I can not get it to work in my test mission :butbut:

I cant see why. It seems so simple, that I cant believe I'm screwing it up.

init.sqf:

if isserver then {
 task_states_for_jips = [];
};
fnCompleteTask = {
 if isserver then {
   task_states_for_jips set [count task_states_for_jips,_this];
   publicvariable "task_states_for_jips";
 };
 call compile format ["task%1 settaskstate ""succeeded""",_this];
};

if !isdedicated then {
 [] spawn {
   waitUntil {!isnull player};
   /* Create your tasks, their variable must be named task1, task2, task3 and so on. */
   task1 = player createSimpleTask ["task1"];
   task1 setSimpleTaskDescription ["Kill some bad guy","Bad guy",""];
   task2 = player createSimpleTask ["task2"];
   task2 setSimpleTaskDescription ["Run away like a little girl","Extraction",""];
   /* End of task creation */
   waituntil {!isnil "task_states_for_jips"};
   {
     call compile format ["task%1 settaskstate ""succeeded""",_x];
   } foreach task_states_for_jips;
 };
};

Then I create additional tasks via script.

Trigger1:

Con: Radio Juliet

Act: nul = [] execVM "setup_tasks.sqf";

setup_tasks.sqf:

task3 = player createSimpleTask ["task3"]; 
task3 setSimpleTaskDescription ["Kill some bad guy","Bad guy",""]; 
task3 setSimpleTaskDestination getPos testunit;  
task3 setTaskState "Assigned"; 

task4 = player createSimpleTask ["task4"]; 
task4 setSimpleTaskDescription ["Kill some bad guy","Bad guy",""]; 
task4 setSimpleTaskDestination getPos testunit;  
task4 setTaskState "Assigned"; 

task5 = player createSimpleTask ["task5"]; 
task5 setSimpleTaskDescription ["Kill some bad guy","Bad guy",""]; 
task5 setSimpleTaskDestination getPos testunit;  
task5 setTaskState "Assigned"; 

task6 = player createSimpleTask ["task6"]; 
task6 setSimpleTaskDescription ["Kill some bad guy","Bad guy",""]; 
task6 setSimpleTaskDestination getPos testunit;  
task6 setTaskState "Assigned"; 

task7 = player createSimpleTask ["task7"]; 
task7 setSimpleTaskDescription ["Kill some bad guy","Bad guy",""]; 
task7 setSimpleTaskDestination getPos testunit;  
task7 setTaskState "Assigned"; 

task8 = player createSimpleTask ["task8"]; 
task8 setSimpleTaskDescription ["Kill some bad guy","Bad guy",""]; 
task8 setSimpleTaskDestination getPos testunit;  
task8 setTaskState "Assigned"; 

If (isserver) then {
PublicVariable "task3";
PublicVariable "task4";
PublicVariable "task5";
PublicVariable "task6";
PublicVariable "task7";
PublicVariable "task8";
};

( I tried having it all be in the (isserver), but then the tasks would not be created on my buddys client).

Then to update the tasks I've got a couple of triggers:

Trigger2:

Con: Radio Alpha

Act: 1 call fnCompleteTask;

Trigger2:

Con: Radio Bravo

Act: 2 call fnCompleteTask;

Trigger3:

Con: Radio Charlie

Act: 3 call fnCompleteTask; 4 call fnCompleteTask; 5 call fnCompleteTask;

Trigger4:

Con: Radio Delta

Act: 6 call fnCompleteTask; 7 call fnCompleteTask; 8 call fnCompleteTask;

When I do this, my buddies tasks do not update on Trigger3 and Trigger4, only the two first.

I tried having a trigger with:

Con: Radio Charlie

Act: for "_i" from 3 to 8 do {_i call fnCompleteTask};

Like in your samplemission, but when I did that only the bottom three of his tasks would update to completed.

Bare in mind that this is all before he tries to reconnect. This problem is while I'm trying to complete the tasks with him ingame.

I can not understand this. Your example mission works flawlessly. Everything gets updated, and stays updated on JIP - just as I wanted.

What am I doing wrong here?

Share this post


Link to post
Share on other sites
I did mention that for loop being just something that creates test tasks. ;)

if !isdedicated then {
 [] spawn {
   waitUntil {!isnull player};
   /* Create your tasks, their variable must be named task1, task2, task3 and so on. */
   task1 = player createSimpleTask ["task1"];
   task1 setSimpleTaskDescription ["Kill some bad guy","Bad guy",""];
   task2 = player createSimpleTask ["task2"];
   task2 setSimpleTaskDescription ["Run away like a little girl","Extraction",""];
   /* End of task creation */
   waituntil {!isnil "task_states_for_jips"};
   {
     call compile format ["task%1 settaskstate ""succeeded""",_x];
   } foreach task_states_for_jips;
 };
};

Also, it shouldn't matter where or when you add tasks, but I didn't test it.

Me and my slow brain after just woking up, it doesn't matter where/when you create them, but you have to pubvar them also, so the JIPs will create the tasks as well.

What about failed tasks ?

I mean, if a task should fail if a unit is dead or something...

Would it look like:

   /* End of task creation */
   waituntil {!isnil "task_states_for_jips"};
   {
     call compile format ["task%1 settaskstate ""succeeded""",_x];
     [b]call compile format ["task%1 settaskstate ""failed""",_x];[/b]
   } foreach task_states_for_jips;
 };
};

And in a trigger that fires if that specific unit is dead:

1 call fn[b]Fail[/b]Task

EDIT:

And _i is the number of task's ?

What if i will later create another task ?

Share this post


Link to post
Share on other sites

Reworked this.

Now it's possible to add tasks and you can set task state to anything you want (succeeded/failed/canceled/assigned/created). I had to change it almost completed, meaning tasks are now defined with names instead of numbers and changed variable and function names to a bit more stardard like.

SHK_createTask = { // "name" call SHK_createTask
 if isserver then {
   SHK_Jiptasks set [count SHK_Jiptasks,_this];
   publicvariable "SHK_Jiptasks";
 };
 if !isdedicated then {
   /* -- add extra tasks below -- */
   switch _this do {
     case "blowup": {
       taskBlowup = player createSimpleTask ["blowup"]; 
       taskBlowup setSimpleTaskDescription ["blow up stuff","blow up stuff",""]; 
       taskBlowup setSimpleTaskDestination getPos testunit;  
       taskBlowup setTaskState "Assigned"; 
     };
     case "radar": {
       taskRadar = player createSimpleTask ["radar"]; 
       taskRadar setSimpleTaskDescription ["knock down a radar","radar",""]; 
       taskRadar setSimpleTaskDestination getPos testunit;  
       taskRadar setTaskState "Assigned"; 
     };
   };
 };
};
SHK_updateTask = { // ["name","state"] call SHK_updateTask
 if isserver then {
   SHK_Jiptasks set [count SHK_Jiptasks,_this];
   publicvariable "SHK_Jiptasks";
 };
 if !isdedicated then {
   call compile format ["task%1 settaskstate ""%2""",(_this select 0),(_this select 1)];
 };
};
if isserver then { SHK_Jiptasks = [] };
if !isdedicated then {
 [] spawn {
   waitUntil {!isnull player};

   /* -- add briefing tasks below -- */
   taskExtraction = player createSimpleTask ["extract"];
   taskExtraction setSimpleTaskDescription ["Run away like a little girl","Extraction",""];
   taskKill = player createSimpleTask ["kill"];
   taskKill setSimpleTaskDescription ["Kill some bad guy","Bad guy",""];
   taskKill setTaskState "Assigned";
   player setcurrenttask taskKill;
   /* -- add briefing tasks above -- */

   waituntil {!isnil "SHK_Jiptasks"};
   {
     switch (typename _x) do {
       case (typename ""): { _x call SHK_createTask };
       case (typename []): { call compile format ["task%1 settaskstate ""%2""",(_x select 0),(_x select 1)] };
     };
   } foreach SHK_Jiptasks;
 };
};

Updated example as well: jiptasks.rar

Edited by Shuko

Share this post


Link to post
Share on other sites

SHK_createTask = { // "name" call SHK_createTask
 if isserver then {
   SHK_Jiptasks set [count SHK_Jiptasks,_this];
   publicvariable "SHK_Jiptasks";
 };
 if !isdedicated then {
   [color="Red"]/* -- add extra tasks below -- */
   switch _this do {
     case "blowup": {
       taskBlowup = player createSimpleTask ["blowup"]; 
       taskBlowup setSimpleTaskDescription ["blow up stuff","blow up stuff",""]; 
       taskBlowup setSimpleTaskDestination getPos testunit;  
       taskBlowup setTaskState "Assigned"; 
     };
     case "radar": {
       taskRadar = player createSimpleTask ["radar"]; 
       taskRadar setSimpleTaskDescription ["knock down a radar","radar",""]; 
       taskRadar setSimpleTaskDestination getPos testunit;  
       taskRadar setTaskState "Assigned"; 
     };[/color]
   };
 };
};
SHK_updateTask = { // ["name","state"] call SHK_updateTask
 if isserver then {
   SHK_Jiptasks set [count SHK_Jiptasks,_this];
   publicvariable "SHK_Jiptasks";
 };
 if !isdedicated then {
   call compile format ["task%1 settaskstate ""%2""",(_this select 0),(_this select 1)];
 };
};
if isserver then { SHK_Jiptasks = [] };
if !isdedicated then {
 [] spawn {
   waitUntil {!isnull player};

   [color="YellowGreen"]/* -- add briefing tasks below -- */
   taskExtraction = player createSimpleTask ["extract"];
   taskExtraction setSimpleTaskDescription ["Run away like a little girl","Extraction",""];
   taskKill = player createSimpleTask ["kill"];
   taskKill setSimpleTaskDescription ["Kill some bad guy","Bad guy",""];
   taskKill setTaskState "Assigned";
   player setcurrenttask taskKill;
   /* -- add briefing tasks above -- */[/color]

   waituntil {!isnil "SHK_Jiptasks"};
   {
     switch (typename _x) do {
       case (typename ""): { _x call SHK_createTask };
       case (typename []): { call compile format ["task%1 settaskstate ""%2""",(_x select 0),(_x select 1)] };
     };
   } foreach SHK_Jiptasks;
 };
};

Updated example as well: jiptasks.rar

Thanks !

So if the (public ?)variable "radar" or "blowup" goes true the extra task is assigned. The other are visible from beginning.

To update the tasks (let them Fail) i do this with:

taskExtraction setTaskState "SUCCEEDED";

nul = [objNull, objNull, taskExtraction, "SUCCEEDED"] execVM "CA\Modules\MP\data\scriptCommands\taskHint.sqf";

Is this correct ?

Share this post


Link to post
Share on other sites

To create:

"Blowup" call SHK_createTask

To update:

["Extraction","failed"] call SHK_updateTask

Share this post


Link to post
Share on other sites

@Shk

:yay:

Dude, you are so at the top of my list of most-appreciated-Arma2-community-members right about now!

This rewrite is pure gold! The fact that I dont have to sequentially name my tasks, and that I can create/change tasks on the fly, just makes this the biggest gem I've seen on the editing forum for a while.

Thank you SO much for taking the time to make this.

YOU ROCK! :ok:

Regards,

Share this post


Link to post
Share on other sites

The first time I tried the task, they were not being updated. I found out I was naming them wrong. Have to have task in front of the name.

taskAirfield = player createSimpleTask ["Airfield"]; Right way

Airfield = player createSimpleTask ["Airfield"]; wrong way

Might help some others.

Works great though!

Share this post


Link to post
Share on other sites

@Mia389

Thanks for the heads up.

Also, when you create the tasks in mp, you should only do so on the host (i.e. include an 'if (isserver)' check), otherwise the tasks will be created twice on the client.

Example:

if (isServer) then {"Blowup" call SHK_createTask};

And yes, It works like a charm. :bounce3:

Share this post


Link to post
Share on other sites

Shouldn't need that isserver check, so something to fix still. Can you confirm if that only happens when you create a task before updating one?

Share this post


Link to post
Share on other sites

@shk:

My buddy is offline atm, so I cant duplicate it. However, I did create the new tasks before updating any tasks.

This is what I did.

I set up the init like you did, and added

case "test1": {
       taskTest1 = player createSimpleTask ["test1"]; 
       taskTest1 setSimpleTaskDescription ["knock down a radar","radar",""]; 
       taskTest1 setSimpleTaskDestination getPos testunit;  
       taskTest1 setTaskState "Assigned"; 
     };
  case "test2": {
       taskTest2 = player createSimpleTask ["test2"]; 
       taskTest2 setSimpleTaskDescription ["knock down a radar","radar",""]; 
       taskTest2 setSimpleTaskDestination getPos testunit;  
       taskTest2 setTaskState "Assigned"; 
     };
//And so forth.

I then made a Radio Alpha trigger with activation:

nul = [] execVM "setup_tasks.sqf";

setup_tasks.sqf

"test1" call SHK_createTask;
"test2" call SHK_createTask;
"test3" call SHK_createTask;
"test4" call SHK_createTask;
"test5" call SHK_createTask;
"test6" call SHK_createTask;

When I hit Alpha I got the 6 tasks, but he got 12. When I completed the tasks with "["test1","SUCCEEDED"] call SHK_updateTask;" (etc.), the six intended tasks got completed, and stayed as such on JIP. The 6 "ghost tasks" did not update at all.

As soon as I wrapped a "if (isServer) then {};" around the code in the setup_tasks.sqf, everything seemed fine.

Creating before updating might be the problem. I think I'm gonna stick with the isServer check until you get it sorted out. The check shouldnt cause any problems should it?

Edited by Nielsen

Share this post


Link to post
Share on other sites
SHK_createTask = { // "name" call SHK_createTask
 if isserver then {
   SHK_Jiptasks set [count SHK_Jiptasks,_this];
   publicvariable "SHK_Jiptasks";
 };
 if !isdedicated then {
   /* -- add extra tasks below -- */
   switch _this do {
     case "test1": {
       taskTest1 = player createSimpleTask ["test1"]; 
       taskTest1 setSimpleTaskDescription ["test1","test1",""]; 
     };
   };
 };
};
SHK_updateTask = { // ["name","state"] call SHK_updateTask
 if isserver then {
   SHK_Jiptasks set [count SHK_Jiptasks,_this];
   publicvariable "SHK_Jiptasks";
 };
 if !isdedicated then {
   call compile format ["task%1 settaskstate ""%2""",(_this select 0),(_this select 1)];
 };
};
private "_jip";
_jip = false;
if isserver then {
 SHK_Jiptasks = []
} else {
 if (isnull player) then { _jip = true };
};
if !isdedicated then {
 _jip spawn {
   waitUntil {!isnull player};

   /* -- add briefing tasks below -- */
   /* -- add briefing tasks above -- */

   if _this then {
     waituntil {!isnil "SHK_Jiptasks"};
     {
       switch (typename _x) do {
         case (typename ""): { _x call SHK_createTask };
         case (typename []): { call compile format ["task%1 settaskstate ""%2""",(_x select 0),(_x select 1)] };
       };
     } foreach SHK_Jiptasks;
   };
 };
};

Share this post


Link to post
Share on other sites

Thanks for doing the tweaks. Works perfect!

Share this post


Link to post
Share on other sites
To create:

"Blowup" call SHK_createTask

To update:

["Extraction","failed"] call SHK_updateTask

@ shk

This does not work, at least not with OA and your newest script...

And what is "Blowup" or "Extraction" ?

Is it this ?

taskTest1 = player createSimpleTask ["Blowup"];

Share this post


Link to post
Share on other sites

I'm using this in OA, no problems so far.

Blowup and Extraction are just example tasks.

Share this post


Link to post
Share on other sites

I use this script:

SHK_createTask = { // "name" call SHK_createTask
 if isserver then {
   SHK_Jiptasks set [count SHK_Jiptasks,_this];
   publicvariable "SHK_Jiptasks";
 };
 if !isdedicated then {
   /* -- add extra tasks below -- */
   switch _this do {
     case "test1": {
       taskTest1 = player createSimpleTask ["test1"]; 
       taskTest1 setSimpleTaskDescription ["test1","test1",""]; 
     };
   };
 };
};
SHK_updateTask = { // ["name","state"] call SHK_updateTask
 if isserver then {
   SHK_Jiptasks set [count SHK_Jiptasks,_this];
   publicvariable "SHK_Jiptasks";
 };
 if !isdedicated then {
   call compile format ["task%1 settaskstate ""%2""",(_this select 0),(_this select 1)];
 };
};
private "_jip";
_jip = false;
if isserver then {
 SHK_Jiptasks = []
} else {
 if (isnull player) then { _jip = true };
};
if !isdedicated then {
 _jip spawn {
   waitUntil {!isnull player};

[color="Red"]    /* -- add briefing tasks below -- */
task1 = player createsimpletask["Secure LZ"];
task1 setSimpleTaskDescription["Secure the LZ, our UAV's currently report that the area around the LZ is clean. However you should still be careful !", "Secure LZ", "Secure LZ"];
player setCurrentTask task1;	
   /* -- add briefing tasks above -- */[/color]

   if _this then {
     waituntil {!isnil "SHK_Jiptasks"};
     {
       switch (typename _x) do {
         case (typename ""): { _x call SHK_createTask };
         case (typename []): { call compile format ["task%1 settaskstate ""%2""",(_x select 0),(_x select 1)] };
       };
     } foreach SHK_Jiptasks;
   };
 };
};

Trigger:

Condition = free

On Act = ["Secure LZ","failed"] call SHK_updateTask;

And if free goes true (checked with hint)...nothing happens.

Edited by Wiggum

Share this post


Link to post
Share on other sites

-showscripterrors startup switch is a faster typo checker. Missing " shouldn't require a forum post.

Share this post


Link to post
Share on other sites
-showscripterrors startup switch is a faster typo checker. Missing " shouldn't require a forum post.

Ups, but i only forgott these " in my post here...ingame i used it.

There shoulded be any script errors, its your script only with one task added.

Can someone help ?

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  

×