Jump to content
Sign in to follow this  
CptBBQ

Making a script multiplayer compatible

Recommended Posts

Hi there!

I´m new to scripting and I tried to do something what I thought would be really easy: Have a team of AI´s spawn with me, delete it whenever I die and respawn them at my location. Also my gear is spawned by this script. All this works just fine in single player.

But now when I want to host my map on a dedi, the problems start. Most of the time to many units are spawned, some of them don´t belong to my team (cannot give any orders to them) but they follow me like a shadow...

I´ve read a few times that some scripts should only be executed by the server and some by clients only. In fact, throwing in a "if (isServer)..." helped, but still, the script is acting weird in multiplayer.

It looks as if the timing is completely fubar. Delays are ignored and things just don´t happen in the correct order. And at least when respawning there are still to many AI´s created.

Maybe some of you experienced modders can have a look at it. So here´s what I´ve got:

// respawn1.sqf

sleep 3;

waitUntil {alive myplayer};

_unit = myplayer;

removeAllWeapons _unit;

_unit addWeapon "M107";
_unit addMagazine "ACE_10Rnd_127x99_T_m107";
_unit addMagazine "ACE_10Rnd_127x99_T_m107";
_unit addMagazine "ACE_10Rnd_127x99_T_m107";
_unit addMagazine "ACE_10Rnd_127x99_T_m107";
_unit addMagazine "ACE_10Rnd_127x99_T_m107";
_unit addMagazine "ACE_10Rnd_127x99_T_m107";
_unit addMagazine "ACE_10Rnd_127x99_T_m107";
_unit addMagazine "ACE_10Rnd_127x99_T_m107";
_unit addMagazine "ACE_10Rnd_127x99_T_m107";
_unit addWeapon "ACE_Glock18";
_unit addMagazine "ACE_33Rnd_9x19_G18";
_unit addMagazine "ACE_33Rnd_9x19_G18";
_unit addMagazine "ACE_33Rnd_9x19_G18";
_unit addMagazine "ACE_33Rnd_9x19_G18";
_unit addMagazine "HandGrenade_West";
_unit addMagazine "HandGrenade_West";
_unit addMagazine "HandGrenade_West";
_unit addWeapon "Binocular";
_unit addWeapon "NVGoggles";


//Team1 incl. gear is spawned at player position

"spawn1" setMarkerPos getpos myplayer;

deleteVehicle ai2; 
deleteVehicle ai3; 
deleteVehicle ai4; 
deleteVehicle ai5; 
deleteVehicle ai6; 
deleteVehicle ai7; 
deleteVehicle ai8; 
deleteVehicle ai9; 
deleteVehicle ai10;


if (isServer) then {

sleep 3; 

ai2 = alpha createUnit ["USMC_Soldier_HAT", getMarkerPos "spawn1", [], 10, "FORM"];
ai3 = alpha createUnit ["USMC_Soldier_HAT", getMarkerPos "spawn1", [], 10, "FORM"]; 
ai4 = alpha createUnit ["USMC_Soldier_HAT", getMarkerPos "spawn1", [], 10, "FORM"]; 
ai5 = alpha createUnit ["USMC_Soldier_Medic", getMarkerPos "spawn1", [], 10, "FORM"]; 
ai6 = alpha createUnit ["USMC_SoldierS_SniperH", getMarkerPos "spawn1", [], 10, "FORM"];
ai7 = alpha createUnit ["USMC_Soldier_MG", getMarkerPos "spawn1", [], 10, "FORM"];
ai8 = alpha createUnit ["USMC_SoldierM_Marksman", getMarkerPos "spawn1", [], 10, "FORM"]; 
ai9 = alpha createUnit ["USMC_Soldier_AR", getMarkerPos "spawn1", [], 10, "FORM"]; 
ai10 = alpha createUnit ["USMC_Soldier_AR", getMarkerPos "spawn1", [], 10, "FORM"];

// arm javelingunner1
_unit2 = ai2;

removeAllWeapons _unit2;

_unit2 addWeapon "M16A4";
_unit2 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit2 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit2 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit2 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit2 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit2 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit2 addWeapon "Javelin";
_unit2 addMagazine "Javelin";
_unit2 addWeapon "ACE_Glock18";
_unit2 addMagazine "ACE_33Rnd_9x19_G18";
_unit2 addMagazine "ACE_33Rnd_9x19_G18";
_unit2 addMagazine "ACE_33Rnd_9x19_G18";
_unit2 addMagazine "ACE_33Rnd_9x19_G18";
_unit2 addMagazine "HandGrenade_West";
_unit2 addMagazine "HandGrenade_West";
_unit2 addMagazine "HandGrenade_West";
_unit2 addMagazine "HandGrenade_West";
_unit2 addWeapon "Binocular";
_unit2 addWeapon "NVGoggles";


// arm javelingunner2
_unit3 = ai3;

removeAllWeapons _unit3;

_unit3 addWeapon "M16A4";
_unit3 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit3 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit3 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit3 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit3 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit3 addMagazine "ACE_30Rnd_556x45_T_Stanag";
_unit3 addWeapon "Javelin";
_unit3 addMagazine "Javelin";
_unit3 addWeapon "ACE_Glock18";
_unit3 addMagazine "ACE_33Rnd_9x19_G18";
_unit3 addMagazine "ACE_33Rnd_9x19_G18";
_unit3 addMagazine "ACE_33Rnd_9x19_G18";
_unit3 addMagazine "ACE_33Rnd_9x19_G18";
_unit3 addMagazine "HandGrenade_West";
_unit3 addMagazine "HandGrenade_West";
_unit3 addMagazine "HandGrenade_West";
_unit3 addMagazine "HandGrenade_West";
_unit3 addWeapon "Binocular";
_unit3 addWeapon "NVGoggles";

// same with ai4 to ai10

};
exit;

// init.sqs: 

execVM "respawn1.sqf"; //for initial gear and ai
alpha = group myplayer;

And a trigger:

Condition: (!alive myplayer) 
On act.: myplayer exec "respawn1.sqf";

Also, there is a second player using an identical script called respawn2.sqf, only with different unit names and gear.

Any advice would be appreciated.

Thanks in advance!

Cheers,

Bbq.

Share this post


Link to post
Share on other sites

Call it from a 'killed' event handler, rather than a trigger:

if ( isNil{player getVariable "mk_killedEHadded"} ) then 
{
player addEventHandler ["killed", 
{ 
	[] spawn {
		waitUntil { alive player }; 
		execVM "script.sqf";

	};	
}];
player setVariable ["mk_killedEHadded", true];
};

Share this post


Link to post
Share on other sites

CptBBQ, for me, actually, arma's "local/global" scripts is the biggest pain when making a mission. If not that, I would have done all the scripts, I am making now, long ago. If Reimann didn't help me some time ago with this "onPlayerRespawn" scipt and many other people that I ask in the forum with other scripts, I wouldn't do any progress in my mission :) I wish, arma was simplier... and in BIS wiki there's only a piece of all information and only few examples... btw, I started learning arma's scripting a few days ago, so I am unexperienced like you =) so, let's hope we will know everything about arma's scripting soon :)

Edited by McArcher

Share this post


Link to post
Share on other sites

McArcher, I think you're biggest problem has been confusing 'server' with 'all clients'. That's the impression I've been getting, anyway. Running local commands on server will not show for anyone. For connecting players, use onPlayerConnected and refresh local commands (keep them in a handy script). When using variables, make sure to broadcast the change with publicVariable "myVar". So when myVar changes, run publicVariable "myVar" to make public what the variable has become. So if you make a vehicle (global), you do it on server. But if you name it you have to make it public (publicVariable "varName"). It gets confusing when some scripts work without making it public but others don't, so can throw off your searching for the answer. But this isn't much to do with CptBBQ's locality issues. It may well help someone though, as the biki and most help is geared toward SP or non-JIP co-op.

And as McArcher mentioned me in relation to that script, I must reference mikey, in whose breifing I first saw it. It is in hundreds of missions now, but I didn't write it myself.

Share this post


Link to post
Share on other sites

then, mikey is a great guy :) :pc:

(i have been asking for this respawn script and nobody gave right answer)

Share this post


Link to post
Share on other sites

Thanks for the kind replies =)

I already feared things wouldn´t stay that simple...^^

So, I have a few questions about that 'Event Handler' thing...

- well, first of all where would I add it? ;)

- I guess, I´ll have to replace 'player' with 'myplayer' in this case?

- will my script then behave as nicely as it does in single player? ^^

Luckily I won´t be scripting for more than two players, so JIP won´t be an issue. Hope that makes things a little easier.

Thanks again!

Cheers,

Bbq.

Share this post


Link to post
Share on other sites

'player' is a 'reserved' variable for the human controlled unit in Arma. So it's fine as is (MP-compatible). Though it may be easier to use the player varName unless you want to learn about 'if == var' or 'switch' later on (which you may need to anyway, depending on your plans).

Share this post


Link to post
Share on other sites

Couple of things to remember about player variable in MP is that

1) it refers to the unit which that client is controlling, thus it will be different unit for different players

2) player is always null in dedicated server (for example triggers with player in the condition will never go off etc)

Share this post


Link to post
Share on other sites

hmmm, as my scripts work right now, every player calls his own respawn script (i.e. respawn1.sqf and respawn2.sqf). So I think I´ll have to use the player names and make one eventhandler for each player.

So I´ve deleted the trigger and now call this .sqf from the init.sqs (also I removed the if (isServer) line from my script):

if ( isNil{myplayer getVariable "mk_killedEHadded"} ) then 
{
myplayer addEventHandler ["killed", 
{ 
	[] spawn {
		waitUntil { alive myplayer }; 
		execVM "respawn1.sqf";

	};	
}];
myplayer setVariable ["mk_killedEHadded", true];
};

Wich again works fine when hosted locally.

On the dedi the units aren´t deleted, so I get 9 new Ai´s but still have the old ones in my team after respawn.

I think if I can get around this everything would work.

Thanks for your help so far. And yes, I would love to learn about those other things you mentioned, but on another occasion. I have a feeling that I´ll stay for a while ;)

Edited by CptBBQ

Share this post


Link to post
Share on other sites

I have a problem again... not to flood with new topics, let me write here...

how can I make inventory of a crate JIP compatible. The script, that puts ammo in it is run on all clients and they see contents, but...

1. if someone takes someting from that crate, will other clients see that that thing disappeared from crate? (i don't have two armas to test it)

2. how to make JIP players see current (up to date) inventory of a crate ? how to syncronize it?

Edited by McArcher

Share this post


Link to post
Share on other sites

* bump *

Come on guys, this can´t be to hard, can it?

Reimann´s event handler works, but the "deletevehicle" part of my script isn´t executed.

What could be the reason for this? How could one fix this?

Please help.

Thanks in advance,

Bbq.

Share this post


Link to post
Share on other sites

Ok, I figured out the problem is that respawn1.sqf is called once via init.sqf.

When I skip it no errors occour but I start without my gear or my team. So I´d have to respawn once on the beginning of a game.

What would be the right way to trigger the function once at gamestart without causing troubles in multiplayer?

Please help =)

Share this post


Link to post
Share on other sites

Check if a Global variable already was created.

If (isNil "My_Global_Variable") then
{
      My_Global_Variable = True;

      // Do what ever you want here this will be executed once only. ( In multiplayer this will be executed once by the server and once by the player )
};

Share this post


Link to post
Share on other sites

ahh, I see. Reimann used that line on the event handler too. I guess it also only has to be added once. Im only starting to understand this stuff, so thank you.

Unfortunately I have to correct my last post: the script is executed correctly, but only for player1. There also is a player2 and I made sure the scripts are identical exept for unit names and variables of course. But he is still spawning loads of unsolicited AI´s at respawn.

Any ideas how this can be?

Cheers,

Bbq.

Edited by CptBBQ

Share this post


Link to post
Share on other sites

Alright, fixed it so far. It was just my stupidity getting in my way ^^

@SNKMAN: if I wanted it to be executed by the server only, could I just add this at the top?

 if (!isServer) exitWith {};

EDIT: I just tried and it dind´t work. But how would I ensure, that a script is executed once and only once?

And if thats not possible, how else would one spawn team members at the beginning of a multiplayer game in an orderly manner?

Edited by CptBBQ

Share this post


Link to post
Share on other sites

sorry for the triple post...

but this has become a general problem for me. When scripting for multiplayer (dedicated server), creating AI´s and vehicles is a pain in the a##. Most of the time, I get more units then ordered...

Event handlers seem to do the job, but I doubt there´s one EH for every situation...

For example, I need to spawn friendly AI and player gear at gamestart. And I need to spawn enemy AI when a certain trigger area is reached by blufor.

How do you guys get around such issues?

Are there any existing threads about this I´ve missed searching the forum (which I did quite a lot)?

Can someone refer me to any example scripts (scripted for multiplayer) that achieve the things I´ve mentioned above?

Is there a complete list of event handlers or is there an EH-Addon that could help?

I know, thats a lot of questions.. but I´d be happy to get an answer for any one of them.

Please, help me to help myself ;)

Cheers,

CptBBQ.

Share this post


Link to post
Share on other sites

Whenever you use createunit/vehicle, do it in one machine only. Simplest is to do it in server only.

So, use the isserver check.

Share this post


Link to post
Share on other sites

well, that is actually one of the first things I´ve tried.

I tried "if (!isServer) exitWith {}" and "if (isServer) then { ...myscript}".

In some cases it had no effect, in others parts of the script weren´t executed at all while even the "extra spawns" continued.

Thats when I came here ;)

So, what am I doing wrong?

Share this post


Link to post
Share on other sites

Well, its quite simple:

if (isserver) then {
 "USMC_Soldier" createUnit [getpos someObject, groupToWhichItJoins];
};

Share this post


Link to post
Share on other sites

I´ve got this

if (isServer) then {

Grp1 = Creategroup EAST;
_Leader="RU_Soldier" createUnit [getMarkerPos "Marker1", Grp1, "Grp1=this", 1, "Sergeant"];
_Unit2="RU_Soldier" createUnit [getMarkerPos "Marker1", Grp1, "", 1, "Corporal"];
_Unit3="RU_Soldier" createUnit [getMarkerPos "Marker1", Grp1, "", 1, "Corporal"];
_Unit4="RU_Soldier" createUnit [getMarkerPos "Marker1", Grp1, "", 1, "Corporal"];
_Unit5="RU_Soldier" createUnit [getMarkerPos "Marker1", Grp1, "", 1, "Corporal"];
_Unit6="RU_Soldier" createUnit [getMarkerPos "Marker1", Grp1, "", 1, "Corporal"];
_Unit7="RU_Soldier" createUnit [getMarkerPos "Marker1", Grp1, "", 1, "Corporal"];
exit;

};

Called by a trigger (which is placed in the editor). Strangely, resulting in 13 (if I haven´t miscounted) enemy AI´s spawning at Marker1...

EDIT:

in case it matters... the trigger fires on BluFor, present, once.

On Act.: [] exec "opfor1.sqf"

Edited by CptBBQ

Share this post


Link to post
Share on other sites

exit doesnt work, nor is it needed in sqf. You execute sqf script with execvm not exec.

Share this post


Link to post
Share on other sites

@Reimann: Did you host it on a dedicated server? Because for me it work´s fine hosted locally but not on a dedi.

I just made a test where I placed only the trigger and the marker on the map (and me as a player). When I enter the trigger area exactly 13 enemies are created (note that the script only calls for 7).

@shk: when I try to enter "execVM" in the OnAct line of a trigger the editor won't let me close it. It says "Type Script, expected Nothing". I found

[] exec "script.sqf" to be the only working syntax (within the editor). Besides, the script obviously gets called.

This is starting to get frustrating... I really have no idea what I´m doing wrong, or what else to try :(

Share this post


Link to post
Share on other sites

try nul = [] execVM "script.sqf" (assuming you have no return variable)

Share this post


Link to post
Share on other sites

Wohooo! It works :bounce3:

Thanks Murklor. Just out of curiosity: what does "nul = " do? ;)

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  

×