Jump to content
Sign in to follow this  
zwobot

publicVariable in a "killed" eventHandler in MP

Recommended Posts

Hi community

in short: using publicVariable in my killed eventHandler script does not broadcast the respective variable when the human players are in different groups in Multiplayer. Please, can you help me figure out why it does not work?

Long version: I want to count friendly and enemy casualties in a coop mission, reward points for kills and substract points for losses.

Everything worked fine on a dedicated server when the players are inside the same group.

However if the players were in different groups the casualty counter variable was not updated correctly despite using the publicVariable command, e. g. in my test there were 2 players on the server in different groups; both killed 1 enemy unit but for both players the Opfor casualty count showed only 1 kill.

Find below some background information on how I call the scripts and the scripts themselves:

init.sqf where the casualty counting variables are setup and the eventHandlers are added:

// Casualty counting
menPointLoss = 1;
specialMenPointLoss = 2; // currently not used
specialMen = [];  // currently not used
vehiclePointLoss = 6; // currently not used

// timelimit
timeLimit = 60;

sleep 1;

westCasualties = 0;
countWestUnits = count west_units; // west_units is filled with all west units in a editor placed trigger "Blufor present" trigger (west_units = thislist)
menPointLossWest = 0;
vehiclePointLossWest = 0;
eastCasualties = 0;
countEastUnits = count east_units; // east_units is filled with all east units in a editor placed "Opfor present" trigger (east_units = thislist)
menPointLossEast = 0;

{_x addEventHandler ["killed", {0 = _this execVM "killed.sqf";}]} forEach west_units;
{_x addEventHandler ["killed", {0 = _this execVM "killed.sqf";}]} forEach east_units;

killed.sqf called from the added killed eventHandlers

private ["_unit"];

_unit = _this select 0;

if(time < (timeLimit * 2)) then {
if(_unit in west_units) then {
	westCasualties = westCasualties + 1;
	publicVariable "westCasualties";
	menPointLossWest = menPointLossWest + menPointLoss;
	publicVariable "menPointLossWest";
};

if(_unit in east_units) then {
	eastCasualties = eastCasualties + 1;
	publicVariable "eastCasualties";
	menPointLossEast = menPointLossEast + menPointLoss;
	publicVariable "menPointLossEast";
};
};

Share this post


Link to post
Share on other sites

Make server do everything, just have a PVEH on clients to catch score updates sent from server.

Share this post


Link to post
Share on other sites

I don't fully understand your answer Shuko. Do you mean I should add the eventHandlers only on the server? The comref says that "killed" eventHandlers are executed where the killed unit is local.

Would you please elaborate you answer? What do you mean by PVEH?

Share this post


Link to post
Share on other sites

Hi zwobot,

Have you noticed that you are overriding all those global variables at mission start for every player?

Meaning that, when a player joins, his machine will override the last PublicVariable'd value.

So my guess is that those IF statements are not returning true in MP for the clients.

Your init.sqf should look like this instead:

if (isServer) then
{
  //assign and public variable the global variables here
};

_neo_

Share this post


Link to post
Share on other sites

neokika, thanks for your answer. I don't think JIP is the immediate problem since everything worked as intended when both players were in the very same group.

Nevertheless I tested your suggestion with 2 Arma2 instances on a LAN server and now the global variables seem to be nonexistant on the client instance (returning "any" and "scalar" in debug hints)...

Share this post


Link to post
Share on other sites
neokika, thanks for your answer. I don't think JIP is the immediate problem since everything worked as intended when both players were in the very same group.

Nevertheless I tested your suggestion with 2 Arma2 instances on a LAN server and now the global variables seem to be nonexistant on the client instance (returning "any" and "scalar" in debug hints)...

Can you post what you have tried?

_neo_

Share this post


Link to post
Share on other sites

Sure, I updated the init.sqf like this:

execVM "briefing.sqf";

if(isServer) then {

// Casualty counting
menPointLoss = 1;
specialMenPointLoss = 2;
specialMen = [];
vehiclePointLoss = 6;

// timelimit
timeLimit = 60;

sleep 1;

westCasualties = 0;
countWestUnits = count west_units;
menPointLossWest = 0;
vehiclePointLossWest = 0;
eastCasualties = 0;
countEastUnits = count east_units;
menPointLossEast = 0;

// objective points
objectivePointsWest = 0;
objectivePointsEast = 0;
};

{_x addMPEventHandler ["MPKilled", {0 = _this execVM "killed.sqf";}]} forEach west_units;
{_x addMPEventHandler ["MPKilled", {0 = _this execVM "killed.sqf";}]} forEach east_units;

Would it be easier to setVariable and getVariable the counter variables on an editor placed game logic instead of declaring them in the init.sqf or would this open another can of worms?

Edited by zwobot

Share this post


Link to post
Share on other sites

I havent scripted in many months, but what I was thinking was something like this. I didn't test it.

if isserver then {
 // init functions
 ZWO_EH_Killed = {
   private ["_killed","_side"];
   _killed = _this select 0;
   _side   = _killed getvariable "ZWO_Side";

   if (time < (ZWO_TimeLimit * 2)) then { //what are you trying to do with this, because it doesnt really make sense?
     switch (_side) do {
       case EAST: {
         ZWO_Score set [0,((ZWO_Score select 0) + 1)];
         ZWO_Score set [1,((ZWO_Score select 1) + ZWO_PointLoss_Man)];
       };
       case WEST: {
         ZWO_Score set [2,((ZWO_Score select 2) + 1)];
         ZWO_Score set [3,((ZWO_Score select 3) + ZWO_PointLoss_Man)];
       };
     };
   };

   // sync updated score to clients
   publicvariable "ZWO_Score";

   // make sure the host of non dedicated MP game sees the score display as well
   if (!isdedicated) then {call ZWO_EH_DisplayScore};
 };

 // init variables
 ZWO_PointLoss_Man = 1;
 ZWO_TimeLimit = 60;

 private ["_side"];
 {
   _side = side _x;
   if (_side in [EAST,WEST]) then {
     // save unit's side for later use, because side changes to civilian on death
     _x setvariable ["ZWO_Side",_side];

     // add killed eventhandler for all east and west units
     _x addeventhandler ["killed",ZWO_EH_Killed];
   };
 } foreach allunits;

 /* init score array
   0: casualties east
   1: point loss east
   2: casualties west
   3: point loss west
 */
 ZWO_Score = [0,0,0,0];
};

// clients
if (!isdedicated) then {
 // init var in case it hasnt been sent from server yet
 if (isnil "ZWO_Score") then {ZWO_Score = [0,0,0,0]};

 // eventhandler to catch and display score updates sent from server
 ZWO_EH_DisplayScore = {
   hintsilent format ["EAST\nCasualties: %1\nPoint Loss: %2\n\nWEST\nCasualties: %3\nPoint Loss: %4",
   (ZWO_Score select 0),(ZWO_Score select 1),(ZWO_Score select 2),(ZWO_Score select 3)];
 };
 "ZWO_Score" addpublicvariableeventhandler ZWO_EH_DisplayScore;
};

Edited by Shuko

Share this post


Link to post
Share on other sites

Thanks for your help guys. I just couldn't get it to work properly with eventHandlers.

Instead of using eventHandlers and updating the counter variables after every kill, I decided to count the units at mission start and compare it with the number of units at mission end and calculate the points based on that. This is done only on the server and the results are broadcasted via the Multiplayer framework to the clients.

Share this post


Link to post
Share on other sites

easiest way would be to use setVariable , this will work with SP, MP and JIP

have a logic or object on the map called server

add to a server only file

server setVariable ["westunits", 0, true];
server setVariable ["eastunits", 0, true];

{_x addEventHandler ["killed", {_score = server getVariable "westunits"; _score = _score + 1;server setVariable ["westunits", _score, true] ;}]} forEach west_units; 
{_x addEventHandler ["killed", {_score = server getVariable "eastunits"; _score = _score + 1;server setVariable ["eastunits", _score, true];}]} forEach east_units; 

on the client

_side = side player;
_score = 0;
while {alive player} do
{

if (_side == west) then{
waituntil {((server getVariable "westunits") != _score)};
}else{
waituntil {((server getVariable "eastunits") != _score)};
};

_score = if (_side == west) then {(server getVariable "westunits")}else{server getVariable "eastunits")};
hint str(_score);  // or what ever you want to do with that score
sleep 1;

};

you will have to restart the client file after respawn , the score will still be correct tho

Edited by Zonekiller

Share this post


Link to post
Share on other sites

Thanks Zonekiller for your late answer.

I'm quite fed up with eventHandlers now and haven't got anymore motivation whatsoever to try to get it to work that way.

The alternative solution I found is enough for my current requirements.

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  

×