Jump to content
Sign in to follow this  
[aps]gnat

MP Locality advice for Addon scripts

Recommended Posts

The whole locality thing does my head in .... looking for some advice on tuning these scripts to work in MP.

These work fine in SP (and most can be found inside the beta PBO release of my Subs)

INIT.SQS

- Called from the addons INIT Eventhandler

- If not ISSERVER, exits

- Runs ARM.SQF

- Runs mando_missileinit.sqf

ARM.SQF

- Main looping Sub monitoring scipt

- If not ISSERVER, exits

- Checks animationPhase on the Subs "dive" animation

- Checks if PLAYER is in the Sub or not, modifies automatic behaviour according (like auto diving when AI crew see danger)

- Uses createvehicle and createUnit to attachto a dummy radar profile vehicle to the sub when Sub on surface of water (surfaced detected via animationPhase of dive animation)

- Deletes the dummy vehicle when sub dives

- Animates the crew proxy between the conning tower and the bridge dependant on dive status.

DIVE.SQF

- One shot script whenever crew member triggers (UserActions) a depth change on the of the Subs addon menu

- Entry of script has 3 parameters : [this, depth, boolean - absolute depth or change in depth]

- If not ISSERVER, exits

- Checks the current animationPhase of the addons dive animation

- Adjust the addons dive animation via 'animate' command to set a new dive depth

FIREMISSILE.SQF

- Called from the addons FIRED Eventhandler

- If not ISSERVER, exits

- If a missile was fired, uses commands like;

nearestobject

Setvelocity

setVectorDir

to reposition the missile and let it fly again.

- If it was a "dummybullet", use nearestobject to grab it and use deletevehicle to delete it

- If it was a "dummybullet" trigger the TARGETTORPEDO script

TARGETTORPEDO.SQF

- No test like ISSERVER (hmmm, I guess because I call it from FireMissile)

- Gets the direction of that fired dummybullet and uses createTrigger to generate and lay a Trigger from the Sub in that direction for 5000 meters.

- Trigger is ANY and PRESENT

- Grab a LIST of whats in the Trigger

- Filter the LIST for Type "Ship"

- Find the closest one

- Make it the Target and trigger MandoMissile scipts to launch a Torpedo at it.

- Adjust the ammo level of the Sub accordingly

- Remove the detector trigger (deletevehicle trigger)

..... any advice appreciated :)

Share this post


Link to post
Share on other sites

Arm.sqf:

On OFP and ArmA1 dedicated servers, the command animationPhase always returned 0. I don't know if it's still the same in ArmA2, you might want to check that. If it still returns 0 always, you have to work around it (in singleplayer games and multiplayer games with a client-host you don't need to do that of course).

By manually monitoring the latest set animation phase:

Simply store the value you used in the animate command, in the variable space of the submarine. In the init-script you have to store the default anim-phase value first of course. And then, whenever you want to check the anim-phase on the dedicated server, read the value from there. To make sure that those two values (value stored in variable space and value read by animationPhase) match at all times (during the animation they don't match of course) execute the animation and the storing of the value only on the server.

And that brings me to the next script (dive.sqf):

Set up a pvEh on the server that listens to dive requests of the clients. The clients just send a message via publicVariable containing the three parameters of the script. All the checks and the animate command (along with storing the new latest anim-phase) are executed on the server, the clients just send the requests.

So far this setup is strictly for mp games with dedicated servers, to have it still working in the other two possible environments arrange the script triggered by the useraction (run on client) this way :

if(isServer) then {
// do as the server would do
} else {
// send a request message
};

firemissile.sqf should work fine the way it is.

targettorpedo.sqf:

Instead of creating a trigger you could also use nearestObjects which directly looks for vehicles of the type "Ship". That could reduce the risk of lag, as ArmA doesn't have to syncronise the created trigger with all clients (there's no 'createTriggerLocal' afaik). If nearestObjects with a 2,5km radius (when run on the center of the location to search at) is not performant enough, you could do this:

Add a extended init-eH to the vehicle class "Ship" and store all those ever created vehicles in an array. When fired, retrieve all the vehicles from it that are inside the given area.

Edited by dengibtsschon
typos

Share this post


Link to post
Share on other sites

Thanks mate.

Couple comments, new questions;

For the animationPhase problem, is there are command to detect is the vehicle is Local to that machine I wonder. (like this isLocal) I assume it has to be local to 1 PC somewhere.

The Dive script.

No, I can't use global (generally my golden rule anyway). Its ok to use global variables when youre the Mission Maker and you control everything within that game, but its no good when you are just the addon maker. Users of your addon could do things you never catered for.

But, the isLocal solution may well be the solution here as well.

Another but; I've always assumed that anyone who has accesses and uses an addons action menu will always trigger the resulting action on the "local" version of the addon, and not on all client versions. Anyone confirm?

The targettorpedo.

The trigger is 5000 meters long, but only 20 meters wide, so its not going to case too much lag I think.

Nice idea on the extended eH though .... something to think about.

EDIT:

A vehicle is always local to the client of its driver.

Empty vehicles/objects placed in the mission editor are local to the server.

This is from the BIKI, but dates back to OFP.

The assumption is a spawned empty vehicle is local to server, and even if a driver has left the vehicle and its empty, it still stays local to the driver until a new driver gets in.

Is this still true for ArmA2?

And there is a LOCAL command. This may help a lot.

Edited by [APS]Gnat

Share this post


Link to post
Share on other sites

Hi Gnat,

Scripting for MP as you know is a bitch. The hardest thing when scripting for MP for vehicles is knowing their locality. As you're probably aware if a player is the pilot/driver of a vehicle then the vehicle is local to the pilot - if you're in the cargo and its an AI pilot/driver then the vehicle is local to the server but if the pilot/driver is a player its local to the player pilot again. This can cause all sorts of headaches. As you've started to discover the isServer, local and their negatives !isServer and !local are going to become you're new best friends.

Another thing is in ArmA2 you can define global variables in a new way using the setVariable and getVariable commands and send them across the network using a true switch in their definition. These can be defined for specific vehicles using the ingame identifier of the vehicle (it does not need to be named in the editor) so you can do something like this in your script

_sub setVariable ["Gnat_submersedState", true, true];

- the second true sends the variable across the network and now everyone both client and server will know the state of the sub - I cannot stress enough how useful this is for MP coding.

As you suggest an "action" will trigger local to the player however, depending on the code and commands used it may have a global effect.

On a related note a piece of code that I use in MP addons that is called by an action looks like this (using the fast rope scripts as an example):

if (local _heli) then
{
 nul = [_heli] execVM "\norrn_dbo_fastrope\scripts\draw_ropes.sqf";
 nul = [_heli] execVM "\norrn_dbo_fastrope\scripts\draw_ropes1.sqf";
} else {
_heli setVehicleInit "nul = [this] execVM '\norrn_dbo_fastrope\scripts\draw_ropes.sqf'; nul = [this] execVM '\ad_helos\FastRope\scripts\draw_ropes1.sqf'";
processINitCommands;
};

Essentially, the action calls this script then if the chopper is local to the player it runs the script locally but if the chopper is not local it runs it on all computers connected to the mission, however at the start of the draw_ropes scripts (ie. the scripts called by this code) there is a

if(!local _chopper) exitWith {};

statement to prevent the script running on any PCs not local to the chopper.

Sorry this all so convoluted but I hope it makes some sense.

norrin

Edited by norrin

Share this post


Link to post
Share on other sites

Thanks Norrin, all of that great info make sense, I just have to get my slow brain to absorb it so I can apply to my addons.

I might have to break my golden rule, setVariable and getVariable do sound interesting ;)

Share this post


Link to post
Share on other sites
The assumption is a spawned empty vehicle is local to server, and even if a driver has left the vehicle and its empty, it still stays local to the driver until a new driver gets in.

Is this still true for ArmA2?

Thats what I always thought, until I was recently told different. Spawned vehicles are local to the client or server that spawns them. So a vehicle created as a result of a user action, will be local to the player.

I tested it, just to be sure. It does appear to be the case.

Share this post


Link to post
Share on other sites

I would say so too.I have made missions in the past for dedi server and have used an action that allows players to create the vehicles they want .I didnt do it correctly at first and had "invisible" tanks driving around with humans in them.They and I were there but noone could see each other.

Share this post


Link to post
Share on other sites
Another but; I've always assumed that anyone who has accesses and uses an addons action menu will always trigger the resulting action on the "local" version of the addon, and not on all client versions. Anyone confirm?

The way you phrase it is a bit mindboggling. Well, here's my understanding of addon locality:

  1. All addon code (called by action menu or eventhandlers or whatever) will be started on each machine. It is up to YOU to either allow or deny further execution on each machine by using "isServer" (see *1 below).
  2. A good example of a server only addon would be a time server. You only want one instance of that of course. In that case your first line of code would be checking "isServer" and quit if false.
  3. A good example of a client only addon would be particle effects - you can't use particles as MP objects anyway, so quit if "isServer" is true - then it will run only on clients.
  4. If a player on a server machine calls the timeserver script it will be run and do what is supposed to do; if a player on a local machine manages to call the script it will also be started but it will quit rightaway.
  5. You can add menu actions to each player. If the related action starts a script from an addon - back to statement #1. It will be started locally but you need to determine where it can run.
  6. If you want a server only addon only to be controlled by player action menus then I would see two options.
    1: You will always be the player on the server machine - in that case you can start your addon script and it will run fine. In any case you always need someone playing on the server to call the script successfully.
    2: You use a dedicated server. In that case the architecture of the addon needs to be a loop checking for global variables. The player action menu would need to call script that sets a global var. Basically the "remote control" principle. In that case you might even only install the addon on your dedicated server - no need for client side installation.

My 2 cents - hope there's no twist in there. Seems to work fine for me at least :)

VictorFarbau

*1 = You could of course do an "isServer" check in the action menu code already - that way you might also control who is allowed to call the code in the 1st place.

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  

×