Jump to content

Recommended Posts

Hello. Im learning currently JIP and have some problems. Respawn type in Description.ext is 3 (BASE)

 

1. I have a task (tsk1) created in InitPlayerLocal.sqf

tsk1 = player createSimpleTask [localize "STR_tsk1"];
tsk1 setSimpleTaskDescription [localize "STR_tsk1_1", localize "STR_tsk1", localize "STR_tsk1"];

 

2. I have a trigger with condition: !alive typ1 (Execution only on server). By activation: ["task1Completed","stat.sqf"] remoteExec ["execVM",0]

3. The problem is that the tasks are not completed if player joins in progress (I execute triggers only on server, so they doesn't run by JIP players)

 

How I can synchronize the tasks by that way? So the tasks, which are completed by currently playing players will be marked as completed by JIP players too..? :icon7: Any suggestions?

Share this post


Link to post
Share on other sites

Try adding the JIP parameter, then it should also run for JIPs.

["task1Completed","stat.sqf"] remoteExec ["execVM",0, true];

 

Share this post


Link to post
Share on other sites
10 hours ago, Muzzleflash said:

Try adding the JIP parameter, then it should also run for JIPs.


["task1Completed","stat.sqf"] remoteExec ["execVM",0, true];

 

 

But here is also again this problem, that this trigger will execute by every JIP player. Well, not the trigger (technically), but that remoteExec command

 

2 hours ago, mrcurry said:

I recommend using the "new" task framework instead. It does JIP and MP updates automagically. 

 

Arma 3 task framework

 

Im not sure why, but BIS_fnc_taskSetState doesn't do anything

Share this post


Link to post
Share on other sites
13 minutes ago, mrcurry said:

Did you create the task using BIS_fnc_taskCreate?

 

Hm. No. with taskCreate it worked now. Need to test the synchronization in MP. (But im not sure that this will work)

Share this post


Link to post
Share on other sites

As long as you only use the Task Framework functions you should be set.

Share this post


Link to post
Share on other sites
2 hours ago, jts_2009 said:

 

But here is also again this problem, that this trigger will execute by every JIP player. Well, not the trigger (technically), but that remoteExec command

 

Im not sure why, but BIS_fnc_taskSetState doesn't do anything

Well the trigger itself only activates/has any effect on the server right? The execution of remoteExec command is only done on the server, and it ensures that  "task1completed" execVM "stat.sqf" runs for all current clients. If you add the JIP flag, then it will also run for all future JIPs - isn't that what you want? For all future JIPs to see the task status as complete? Edit: looking at Task Framework implementation you could use that, and at appearance it does look like BI actually made a library that is JIP compatible. It makes all the data about tasks available using publicVariables, and also uses a  [...] remoteExecCall ["TaskId", 0, true]  to ensure JIPs also get the tasks.

Share this post


Link to post
Share on other sites
54 minutes ago, Muzzleflash said:

Well the trigger itself only activates/has any effect on the server right? The execution of remoteExec command is only done on the server, and it ensures that  "task1completed" execVM "stat.sqf" runs for all current clients. If you add the JIP flag, then it will also run for all future JIPs - isn't that what you want? For all future JIPs to see the task status as complete? Edit: looking at Task Framework implementation you could use that, and at appearance it does look like BI actually made a library that is JIP compatible. It makes all the data about tasks available using publicVariables, and also uses a  [...] remoteExecCall ["TaskId", 0, true]  to ensure JIPs also get the tasks.

 

Well in that script is not only the command for task completion. The server will run that script on every JIP player, what I wanted to avoid.

 

stat.sqf:

switch (_this) do
{
	case ("t1"):
	{
		["tsk1", "SUCCEEDED",true] spawn BIS_fnc_taskSetState;

		_line1 = [name (leader testgrp), "Gopnik is dead. How copy, over?"]; 
		_line2 = [name (units testgrp select 1), "Understood. Let's check JIP and objective status"];
		_line3 = [name (leader testgrp), "You forgot to say, that there is new respawn point. We should test this too..."]; 
		[[_line1,_line2,_line3],"group",0.15,false] execVM "Conv.sqf";
		[missionNamespace,"test2","Forest"] call BIS_fnc_addRespawnPosition;
		"nb1" setMarkerColorLocal "ColorGreen";
	};
};

So I thought I need then do it like this:

 

switch (_this) do
{
	case ("t1"):
	{
		if (isServer) then {[BIS_fnc_taskSetState, ["tsk1", "SUCCEEDED",true]] remoteExec ["spawn",0,true]};

		_line1 = [name (leader testgrp), "Gopnik is dead. How copy, over?"]; 
		_line2 = [name (units testgrp select 1), "Understood. Let's check JIP and objective status"];
		_line3 = [name (leader testgrp), "You forgot to say, that there is new respawn point. We should test this too..."]; 
		[[_line1,_line2,_line3],"group",0.15,false] execVM "Conv.sqf";
		[missionNamespace,"test2","Forest"] call BIS_fnc_addRespawnPosition;
		"nb1" setMarkerColorLocal "ColorGreen";
	};
};

 

But I think there is maybe other right solution of this. In ARMA 2 these things were done too somehow, without these A3 features...

Share this post


Link to post
Share on other sites

For the task itself, your second code should be fine, assuming your trigger is something like: ["t1","stat.sqf"] remoteExec ["execVM",0], since the task framework should automatically work both for current and JIPs so nothing to do there. Instead of both your calls to taskSetState, I would do:

if (isServer) then {["tsk1", "SUCCEEDED",true] spawn BIS_fnc_taskSetState;};

since the a single call should automatically sync with current players and JIPs. Assuming BIS_fnc_addRespawnPosition is JIP-compatible - since it is global you might want to wrap that in isServer also - you should be done.

Share this post


Link to post
Share on other sites

You asked how to do everything manually. Here is one explanation.


The typical approach used (at least for me) is to consider two kinds of clients. The ones currently in the game. For those you give updates regularly and they are then always up to date - this is Part 1. The second kind just joined (JIP) and are not up to date. The goal here is to make them up to date like the rest - Part 2 - and then give them the same updates regularly.

 

Here is how to do it without completely vanilla. For Part 1, (could be in init.sqf):

// Section 1 - This is essentially your "stat.sqf" except rewritten as a function. You can still do it with a script though.
OnTaskStatusChange = {
    params ["_taskId", "_newStatus"];
    if (_taskId == 1) then {
        // Create task if not existing
        // ...

        // Other tasks based on new status for example:
        if (_newStatus == "SUCCEEDED") then {
            // Play conversation
            // Move respawn
        };
        if (_newStatus == "FAILED") then {
            // Play other conversation
        };
    };
};

// Section 2
if (hasInterface) then {
    "Task_1_Status" addPublicVariableEventHandler {[1, _this select 1] spawn OnTaskStatusChange;};
};
// Section 3
if (isServer) then {
    // Initialize to say, "PENDING"
    Task_1_Status = "PENDING"; publicVariable "Task_1_Status";
};

In your trigger you would then have something like this in your on act:

if (isServer) then {Task_1_Status = "SUCCEEDED"; publicVariable "Task_1_Status"; if (hasInterface) then {[1, Task_1_Status] spawn OnTaskStatusChange; };};

The first two pieces update the variable, and gives it to all clients. Their handler then runs, and thus runs OnTaskStatusChange on all their machines. The last expression is needed because if you do publicVariable, the handlers only run on all other machines except the one you public variable on, so you need to do that manually.


This takes care of all current clients. But if someone JIPs that won't get the task until the next update. So we modify the previous section 2 to this:

// New section 2:
if (hasInterface) then {
    //Either we already got the data, or we have not received any yet.
    //If we already have it we need to run manually
    if (!isNil "Task_1_Status") then {
        [1, Task_1_Status] spawn OnTaskStatusChange;
    };
    //If we did not have the data yet, we can expect it shortly.
    //Regardless, on any future updates run the function again.
    "Task_1_Status" addPublicVariableEventHandler {[1, _this select 1] spawn OnTaskStatusChange;};
};

To be honest all this public variable becomes annoying, so I use something like CBA_addEventHandler and CBA_GlobalEvent . Then the on act of the trigger simply becomes:

["Task_Status", [1, "SUCCEEDED"]] call CBA_fnc_globalEvent;

And instead of addPublicVariableEventHandler I just do:

["Task_Status", OnTaskStatusChange] call CBA_fnc_addEventHandler;

 

  • Like 2

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

×