Jump to content
Sign in to follow this  
Pyrodox

Extraction script with weird results...

Recommended Posts

Can anyone help me out? I am using this script to call an extraction helo. It works fine in singleplayer, and if I host an MP server. However, if I try it on my dedicated server, the helo takes off and starts flying down to 0,0,0 and completely ignores the position of the player calling the script.

It is called through a radio alpha trigger.

_helomarker = createMarker ["HELILAND", position player]
HELIH1 setPos (getMarkerPos "HELILAND")
HELO1 doMove (getMarkerPos "HELILAND")
#ENROUTE
? (HELO1 distance HELIH1 < 100) : goto "LAND"
~0.01
goto "ENROUTE"
#LAND
doStop HELO1
HELO1 land "GET IN"
deleteMarker _helomarker
exit

Edited by Pyrodox

Share this post


Link to post
Share on other sites

Markers are local. Just use the position of the player, rather than creating a marker there.

Share this post


Link to post
Share on other sites

MP scripting is more difficult than SP as you have to deal with locality (eg, player is a different object on each client, and nothing on the server)

Some recommended Biki articles: Locality_in_Multiplayer and the unsearchable 6thSense.eu:EG

Share this post


Link to post
Share on other sites
Markers are local. Just use the position of the player, rather than creating a marker there.

I thought Markers were global with createMarker http://community.bistudio.com/wiki/createMarker

And I've tried using doMove (position player) but get the same results on the dedicated server, whenever I call the script from a client the helo moves to 0,0,0 however it does move/create vehicles at the player's location (I made it spawn a smoke grenade to see where it was calling the helo.)

Share this post


Link to post
Share on other sites
MP scripting is more difficult than SP as you have to deal with locality (eg, player is a different object on each client, and nothing on the server)

Some recommended Biki articles: Locality_in_Multiplayer and the unsearchable 6thSense.eu:EG

I was thinking it might be something with locality, I've read those websites and I still just can't seem to get it.

I thought the "player" unit was local to each computer, but even when I tell the helo to doMove to "position player" when I call it on the dedicated server, the helo flies directly to 0,0,0

Does this have anything to do with the trigger? Is it something like the Radio Alpha trigger is calling the script from within the mission, therefore it thinks the "player" is the server on a dedicated server?

Is there any way I can use a Radio Alpha trigger in MP while telling the helo "doMove position player" and have it go to the actual player, not the server "null" player?

Share this post


Link to post
Share on other sites

Just to make matters worse the "player" variable is a special case. It defines the player local to each client. So when connected to a dedicated server the variable player on my PC is me and the variable player on your PC is you. The problem you are probably running into is that on a dedicated server, as opposed to a local server, there is no player local to it and the chopper doesn't know where to go (thats of course if the extraction script is running local to the server) - if that makes any sense.

A simple way around this is to name the playable unit in the editor that can call the extraction, eg p1, then in your extraction script put something like

HELO1 doMove (getPos p1);

Share this post


Link to post
Share on other sites
Just to make matters worse the "player" variable is a special case. It defines the player local to each client. So when connected to a dedicated server the variable player on my PC is me and the variable player on your PC is you. The problem you are probably running into is that on a dedicated server, as opposed to a local server, there is no player local to it and the chopper doesn't know where to go (thats of course if the extraction script is running local to the server) - if that makes any sense.

A simple way around this is to name the playable unit in the editor that can call the extraction, eg p1, then in your extraction script put something like

HELO1 doMove (getPos p1);

Tried using p1, doesn't seem to work at all with that...

I'm getting really confused with why certain things are working or not working.

I used addaction to add the script to a single unit, tested it, works fine in SP, whether it's _this select 0 from the addaction itself, or putting "player" in... It refuses to work, at all, on the dedicated server, though.

Can a player not issue commands like doMove to AI units already placed on the map in MP?

When it is set as "player" in the script, and run through a Radio Alpha trigger, it works fine in SP but in MP the helo flies to 0,0,0

When it is set as a static name of the unit in the script, or run through an addaction menu item on a specific unit, it works just fine in SP, but in MP it does absolutely nothing.

This behaviour leads me to believe you can not control an AI helicopter with script commands outside the server itself in MP, is this the case?

I've tried converting it over to SQF as well, this is what I'm using now:

HELIH1 setPos getPos player;
HELO1 doMove getPos player;
HELO1 setBehaviour "CARELESS";
waitUntil {HELO1 distance HELIH1 <= 100};
doStop HELO1;
HELO1 land "GET IN";
waitUntil {{alive _X && !(_X in crew HELO1)} count (units group player) <= 0};
HELO1 doMove getPos HELIH2;
HELO1 setBehaviour "CARELESS";
waitUntil {HELO1 distance HELIH2 <= 100};
doStop HELO1;
HELO1 land "LAND";

When called in MP through

_null = [] spawn "call_helo.sqf"

in an on activation line of a Radio Alpha trigger, the helo takes off and flies to 0,0,0 so I'm assuming the "player" in this instance is the server itself. Works as intended in SP.

When called in MP through

this addaction ["Call Helo", "call_helo.sqf"];

it does nothing. Works as intended in SP.

Edited by Pyrodox

Share this post


Link to post
Share on other sites
Tried using p1, doesn't seem to work at all with that...

I'm getting really confused with why certain things are working or not working.

I used addaction to add the script to a single unit, tested it, works fine in SP, whether it's _this select 0 from the addaction itself, or putting "player" in... It refuses to work, at all, on the dedicated server, though.

Can a player not issue commands like doMove to AI units already placed on the map in MP?

When it is set as "player" in the script, and run through a Radio Alpha trigger, it works fine in SP but in MP the helo flies to 0,0,0

When it is set as a static name of the unit in the script, or run through an addaction menu item on a specific unit, it works just fine in SP, but in MP it does absolutely nothing.

This behaviour leads me to believe you can not control an AI helicopter with script commands outside the server itself in MP, is this the case?

I've tried converting it over to SQF as well, this is what I'm using now:

HELIH1 setPos getPos player;
HELO1 doMove getPos player;
HELO1 setBehaviour "CARELESS";
waitUntil {HELO1 distance HELIH1 <= 100};
doStop HELO1;
HELO1 land "GET IN";
waitUntil {{alive _X && !(_X in crew HELO1)} count (units group player) <= 0};
HELO1 doMove getPos HELIH2;
HELO1 setBehaviour "CARELESS";
waitUntil {HELO1 distance HELIH2 <= 100};
doStop HELO1;
HELO1 land "LAND";

When called in MP through

_null = [] spawn "call_helo.sqf"

in an on activation line of a Radio Alpha trigger, the helo takes off and flies to 0,0,0 so I'm assuming the "player" in this instance is the server itself. Works as intended in SP.

When called in MP through

this addaction ["Call Helo", "call_helo.sqf"];

it does nothing. Works as intended in SP.

you're correct, it is a locality issue.

the helicopter you're trying to command is local to the server and not to the player so telling the helicopter where to go would have to be run on the server and not on the client.

what i've read about locality is:

player and his group is local to the client machine.

AI units without any player and logics are local to the hosting machine.

my suggestion is try to make it only execute on the server machine and pass the position on where its supposed to go with a publicvariable and try if it still goes crazy.

EDIT:

this will require either building two scripts to execute one on the client to get the position array and another to execute on the server to use that array and tell the helicopter where to go.

or you can try and forge them into one script by making it check if the machine executing it is either a server or a player.

Edited by soccerboy

Share this post


Link to post
Share on other sites

Hmm, is there any way to find out which unit is triggering the radio alpha? Then instead of using "player" in the script, I can set up a variable for whoever triggered the command to be the target, then use isServer to make it only run on the server.

I tried the "list" command but it doesn't seem to work on Radio Alpha triggers.

Edited by Pyrodox

Share this post


Link to post
Share on other sites
Hmm, is there any way to find out which unit is triggering the radio alpha? Then instead of using "player" in the script, I can set up a variable for whoever triggered the command to be the target, then use isServer to make it only run on the server.

I tried the "list" command but it doesn't seem to work on Radio Alpha triggers.

triggers are global so they exist on all machines. so i don't think you can achieve what you're trying to do with a trigger because triggers don't pass unit information on who triggered it as far as i know.

the way i imagine triggers work is the unit calling the trigger just transmits a global variable like for instance "alpha = true" so there is no real fingerprint on who called it however, i'm not 100% sure on this.

Share this post


Link to post
Share on other sites

Of course triggers have information on who is in them. The game will check everything that is in them, which is useful for a great many things. But it's not an efficient way to do this.

It seems addAction is purely local, including any script called from it. A radio trigger works, though I needed to call it to an object rather than the player, despite being able to call the object to the player:

trig setpos getpos player;
_pos = [(getpos trig) select 0, (getpos trig) select 1,0];
wp = grp1 addWaypoint [_pos, 0];

I have used a waypoint, but I'm sure there are other methods that I'm not about to test right now. 'trig' is the name of the trigger with the radio in it, which calls the script, and helo1 has grp1 = group this in its init.

Share this post


Link to post
Share on other sites

In general, SP mode is the client and server combined. So you can script a long way in SP and its great untill you switch to MP and find everything breaks due to locality. It is helpful understand the basic concepst of client and server coupled with the locality rules of the game (like AI is local to server) and try to consider that when scripting in SP.

That way you can test in SP and go to MP quicker instead of having to go back later and sort everything out.

So I will share my method here to contribute to this thread and hopefully clarify how you can deal with locality in Arma2. Basically you use publicvariable command.

In the past, Publicvariable command only worked for strings and integers.

Now it seems publicvariable supports objects arrays and more so there are easier ways than I ultimately used. You can send objects and arrays over the network with this command but the server will allways have to be ready to deal with them.

I start with creating two basic arrays. One list of players and another list of strings that reference the players.

I give a name to every playable unit in the editor and put that in the init script as an array for ALL MACHINES:

;  init.sqs

Make array of players
playerlist = [objnull,playername1,playername2,playername3]

;Make global variables for player status array
playerstatus1 = "RDY"
playerstatus2 = "RDY"
playerstatus3 = "RDY"

playerstatlist = ["",playerstatus1,playerstatus2,playerstatus3]

[] exec "serverloop1.sqs"
exit

Now I have prepared the base variables and started the service engine for any script I want to allow a client on the MP session to contact the server and give it appropriate information to do what it wants. There is more to add but this is the basic form for a clean example and it can be both scaled up and easily cloned into new uses easily.

Note that I put objnull and "" in the first position on the arrays because I want the first relevant item in the array to be select 1 and not select 0. It just makes it easier for me to work with the arrays as a general practice. I want listed item 1 to be select 1, not listed item 1 is select 0

On the client, your action script or EH or whatever occurs to start things can find its number on the array and publicvariable its status variable string to "TRANS" and if the server is checking that variable by running a simple loop, it will then have enough info to both know that a certain player in the array list will need a transport and where they are. The server can getpos the player at that time and use it for the domove or addwaypoint command.

client code:

example: Player execs an action that does:

[player] exec "pickmeup.sqs"

;pickmeup.sqs
_counter = 0
_timer =  3

#START
~_timer
? player == playerlist select _counter:goto "Found"
? _counter >= count playerlist - 1:goto "Error"
_counter = _counter + 1
goto "Start"

#ERROR
;In case there is a problem for some reason, exit script and tell user about it
hint "Error: no player found in list!"
exit


#FOUND
;Set the global variable to new value and pubvar the variable to tell server

? _counter == 1:playerstatus1 = "TRANS"
? _counter == 1:publicvariable playerstatus1
? _counter == 2:playerstatus2 = "TRANS"
? _counter == 2:publicvariable playerstatus2
? _counter == 3:playerstatus3 = "TRANS"
? _counter == 3:publicvariable playerstatus3
exit

(this is a rough example and could be done a dozen better ways.)

The player checks itself against the player list to find his count in the list so that the correct status variable on the other list can be updated. Publicvariable command sends the information from the client to the server to address locality.

I want these variables to be outside of the arrays because I want pubvar to only change one variable and not pubvar an array and potentially overwrite another client who may have wanted pickup and now wont because his status was overwritten before the server looped and checked his variable!

So now the script should handle multiple callers at the same time.

Over on the server a loop will run during the entire mission:


;serverloop.sqs can be run at init as [] exec serverloop.sqs
;Service engine script that starts the code on the server as needed

;make sure script runs only on server
?!(isServer):exit

;Set heartbeat for server loop, performance tuning value, lower will mean faster process but higher load on cpu.
_timer = 5

#START
;Update player status array
playerstatlist = ["",playerstatus1,playerstatus2,playerstatus3]
_counter = 0

#START2
~_timer
_status = playerstatlist select _counter
? _status != "RDY":goto "Check"
? _counter >= count playerlist - 1:goto "Start"
_counter = _counter + 1
goto "Start2"


#CHECK
; Tell server who the client is by using the list.
_caller = playerlist select _counter
? _status == "TRANS":hintsilent format ["player number %1 needs transport....",_counter]
? _status == "TRANS":heli domove getpos _caller
? _status == "TRANS":playerlist [_counter,"RDY"]
? _status == "DEAD": hintsilent format [ "player number %1 is dead!"]



goto "Start"

The players status is changed to "RDY" so that it does not trigger the loop again. It would be simple to add a check here to run any script you want on the server to pickup the unit now because your code is local on the server, you know who the caller is and you are now past locality issues. I threw in a dead check that will affect basically nothing yet. Its just to show how easy it is to start to add a new check.

That is "basically" it. Use of mapclick or Dialogs will be key in giving the client more advanced options but its not hard to get started. It was a bear for me to get my head around it so I hope this was helpful.

There are also BIS functions that make mp scripting easier but I havent tested them.

http://www.armaholic.com/page.php?id=6231

CBA addon has a network part for this exact reason. More advanced and automated network functions that accomplish the same thing I have done and more that should make things easier. I just came up with a way that works for me and stuck with it.

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  

×