OFPEC Forum
Editors Depot - Mission Editing and Scripting => OFP - Editing/Scripting Multiplayer => Topic started by: General Barron on 31 Mar 2005, 02:32:26
-
Greetings all,
I've recently started trying my hand at multiplayer editing and scripting. I've read snYpir's excellent MP editing tutorial, which gave me a great start; however, it doesn't go into much detail about scripting in particular, and I haven't been able to find another tutorial that does. One thing that I have found thru tinkering around in MP is that many commands work in very unexpected ways. So my question to all of you MP gurus is the following:
How does each scripting command work in a MP environment?
I want to know about every command possible. I'm not concerend with how the command works in general/SP, since the com ref tells this. I'm more interested in the following questions (plus any others you can think of):
??? Will the effect of the command be seen by all computers (globally), or only by the client it was run on (locally)?
??? What happens when you pass a local object to the command? What about a remote object?
??? How is the AI affected by this command in all of the above situations (if applicable)?
??? Is there anything else that must be done to get the command working properly in MP? Are there any other ways this command behaves differently in MP than in SP?
With that said, I hope to hear from everyone. I'll post new commands as I discover how they work in MP, and if everyone else does the same (and posts what they know already), then as a community we can get this all figured out, and cut down the questions by about 1/2 on this forum :).
-
This post will be modified to contain a list of all commands contributed so far. Please don't post a command that has already been posted, unless you need to correct errors or add to another person's post. In rough alphabetical order:
Commands posted so far:
action
animate
animationPhase
addAction
camCreate*
createVehicle
cutObj
cutRsc
deleteVehicle
distance
drop*
leader*
move
objStatus
player
publicVariable
random
side*
skipTime
setpos
setvelocity
setdammage
setViewDistance
setFog
setOvercast
setRain
skipTime
titleText
titleCut
titleCut
titleRsc
*command needs more research/clarification
Edit
Check my post on this page here (http://www.ofpec.com/yabbse/index.php?board=7;action=display;threadid=22956;start=30). There I have posted a list created by Spinor of CoC, which lists how most commands work in MP.
-
Leader
In MP this command will always return the original leader of a group, even after he dies (at which time it will return his corpse, which become static objects on the 'civilian' side). Notice that in SP, this command will always return the current leader of a group (so it will always return a living unit when the group has at least one member).
This may not stay true after adding new units to the group via the "join" or "createunit" commands. (need more research)
This command will work on local or remote objects (if a unit is passed). If passed a group, the group must be defined locally.
move
This command will only work if the passed groupname is defined on all computers. This can be a problem if you want to spawn units into groups after the start of the mission, because if you put the following in a unit's init field:
groupA = group this; deletevehicle this
Then groupA will NOT be defined on all clients. There MUST be a delay between the group assignment and deleting the unit (figuring this one out caused me great headache).
player
This command will return something different on each computer. It will always return the current body of the player who's computer runs the command. On a dedicated server this command will return null (can be detected by the "isnull" command).
setpos
setvelocity
setdammage
what else?
These commands all work normally in MP, regardless of what computer they are run on, or whether the object affected is local or remote. For example, a client using the "setdammage" command on a unit local to the server WILL injure/heal that unit.
SetFog
SetOvercast
SetRain
Skiptime
The environemental changes from these commands will ONLY take place on the computer where the command is run from. It is entirely possible for one client to see day, while another sees night, for example.
How is the AI affected by this? Does the AI use the environmental settings of the computer it is local to (for vision ranges)?
Camcreate
The effects of this command will only be seen by the computer the command is run from. This means camera cutscenes must be started on each computer individually. Ordinance made with this command that would normally hurt units (such as shells and bullets) will NOT hurt units in MP (for example, a shell will explode but will not cause any damage). Objects and vehicles should NOT be created with this (createvehicle should be used instead).
-
Yay. This thread is long overdue.
Re: Leader. So, if the leader dies, even if a new leader takes his place, the old one (corpse) still remains leader? Also: if normal respawn (like paintball respawn) is activated, and the leader is killed and respawns back into the group (still leader), will the leader command return his new incarnation, or the old corpse?
Re: Init fields. I understand now; an init field is local to whichever computer the unit belongs to.
Re: camcreate. I *think* that you might be wrong about camcreate. I tried running a script in a mp game with 1 client, 1 server, with the line
? local server: sh = "shell125" camcreate getpos aa
where server was a game logic, aa was the name of the soldier the server inhabited. The explosion was visible from, and killed, both players.
Here is an updated version of camcreate, which i will delete if it subsequently turns out to be wrong ;)
Camcreate
The effects of this will be seen and felt from all computers, similarly to createvehicle. If camcreate runs only on the server, the results *will* affect all clients; ordinance *will* hurt all clients. If camcreate runs on all clients, the command wil be repeated, once for each client, and once for the server.
Createvehicle
The effects of this are similar to camcreate. Two important distinctions - firstly, createvehicle offsets the object it creates to fit in with nearby objects' collision radii. Camcreate does not. Secondly vehicles created by createvehicle will be usable; vehicles created with camcreate will not be.
-
deleteVehicle
works normal in MP, regardles of locality. If a vehicle is deleted on a client machine it's deleted on the server. If it's deleted on the server it's deleted on the clients.
distance
May return a different value on client and server and the result is rather unnpredictable. The reason for this is lag. Since the client machines are somewhat slower than the server it's possible that a condition like unitOne distance unitTwo <50 will be set to true on the server while it is still false on the client machines. Solution: Never, ever measure distance on the clients.
objStatus
Status "ACTIVE", "FAILED", "DONE","HIDDEN" is local and may be different on all machines. Thus it is possible that an objective that is completed on a client will not be registered by the server.
-
A few observations from my travels . . .
titlecut
The comref says that this command is obsolete but it still works for me and I'm patched to v1.96. Titlecuts are local to each machine so you can fade one guy to black while all others retain normal vision etc.
particle drops
These USED to be local but it seems that since about v1.91 or so these are now run on all machines. It used to be very annoying lighting a fire via a script and having it burning on just one machine . . .
setViewdistance
This is local to each machine. If you wanted, you could blind one guy while all other players had 5 km visibility.
random
Again, local to each machine. If you're running a script on all machines that uses a random function you will need to make sure that just ONE machine rolls the dice then passes it's results to all other machines via a server routine, otherwise all of your results will be out of whack.
skipTime
Again, is local to each machine. What's worse, script execution is partially clock speed dependant. So if the skipTime script has a pause of (say) 0.1 second between cycles then my machine might take 0.10003 seconds to execute while yours takes 0.100037 seconds to do it. This does add up over time so that two machines running the same script at supposedly the same time will find themselves out of sync in very short order.
The best solution to this problem is to again have one machine carry out the skipTime function then broadcast the resulting time (via the daytime command) to all other machines via a server loop, while all other machines just read the publicVariable each cycle and skipTime accordingly.
That's all I can think of for now.
roni
-
This is the best thread idea for ages. This should be pinned ;) :D
-
I have a question :) In my MP mission which I'm building I have defined several groups using the init lines of the respective units of the groups. I assume from this thread now that it is likely that only the server's machine will recognise these groups.
So my question is where can I execute a script that will define the groups on all machines (including clients). Should I put it in the init.sqs file or something ???
-
Great! Thanks for the feedback so far. I sure hope this thread gets filled to the brim...
This is the best thread idea for ages.
Yeah, it's so good, it's been thought of 1,000,000 times before... just no one has ever made a really organized post for it I suppose. :D
Re: Init fields. I understand now; an init field is local to whichever computer the unit belongs to.
I don't think this is true. I've run assignment statements thru an init field (groupA = group this), and the variable is set on all machines. I believe the issue with deleting units from the init field is just one specific oddity in ofp.
Re: Leader. So, if the leader dies, even if a new leader takes his place, the old one (corpse) still remains leader?
Yes, the corpse will remain the leader. I have not yet done much research into the specifics (like if the leader ever changes), but I did notice that after killing a group leader, his corpse was returned with this command. Since this NEVER happens in SP, I wrote it down, as an example of "other MP issues" that might arise from a command other than locality.
Re: camcreate
I'm pretty sure I've had different results with this command than you suggest, but hopefully some MP experts with WAY more experience than me to set us all straight. :)
Just for completeness:
titlersc
cutobj
cutrsc
titletext
cuttext
These commands all behave like titlecut (above).
-
I have a question :) In my MP mission which I'm building I have defined several groups using the init lines of the respective units of the groups. I assume from this thread now that it is likely that only the server's machine will recognise these groups.
So my question is where can I execute a script that will define the groups on all machines (including clients). Should I put it in the init.sqs file or something ???
You posted this while I was typing up my last post, but I'll clarify the point in a new one.
If you define the group in a unit's init field, it will be defined on all machines. However, if you delete the unit right after you define the group (i.e. no delay in between), it will NOT be defined on all machines.
Incorrect:
groupA = group this; deletevehicle this
Correct:
groupA = group this; this exec "delete.sqs"
delete.sqs:
~2
deletevehicle _this
-
publicVariable
*** Erroneous theory deleted to avoid confusion - see correct explanation in GB's post below ***
-
@publicvariable
Err.... I believe you are incorrect about how this command behaves. It does not "declare" a variable as public. Rather, it "broadcasts" the variable to all computers at the time you use the command. So if you had the following script run on the server:
a = 4
publicvariable "a"
a = 6
Then "a" would be 4 on all computers, except on the server, where it would be 6. Each of those computers could then change their own, personal "a" variable as much as they like. However, once any computer broadcast "a" with the publicvariable command again, then everyone else's "a" would be set to that one value (after which they could be changed again, and so on).
Basically, "publicvariable" should really be thought of as "broadcast public variable".
An important note about this, however, is that there will be a slight delay between when the variable is sent from a machine, and when it is recieved on every other machine (depending on ping). Usually this isn't to worry about, but for time-sensitive data, it could be.
-
*** post deleted as above ***
-
*leader
move
objStatus
player
random
Random is baaaaaad...if you got, i.e a=(random 100) in a script, then each computer gets it's own a, so the best thing is to either run the script only on server (if possible), or run only the random stuff on the server and publicvariable it to every one else.
-
Re: publicVariable - In use (if not in fact) there are three different types of variables, not two - private, public and "shared public".
Private variables
As we all know ( :P ) private variables are local only to the script in which they appear. So for instance - I could write one script that spawns another script any number of times and have each of these spawned scripts use the same private variable at the same time. This is not a problem as each variable is only relevant within its own environment.
Example -
;parent.sqs
_x=10
#loop
this exec "offspring.sqs"
_x=_x-1
~1
if _x >0 then goto "loop"
;offspring.sqs
_x=10
#loop
"Shell73" camCreate (getPos player)
_x=_x-1
~1
if _x >0 then goto "loop"
parent.sqs will spawn offspring.sqs ten times and each of these spawned scripts will in turn camCreate a Shell73 on the head of the player ten times (100 Shell73's in total). :noo: :beat:
In this case _x is used in the parent script AND in each of the spawned offspring scripts. At any given time the value of this variable will be different in each and every script, but this won't matter as they are only ever referred to internally. The _x in parent.sqs has absolutely nothing in common with the _x in any other script that uses that same variable name apart from the label "_x".
Public variables
Unlike private variables, public variables DO care about other scripts, but only if they are running on the same machine !. In this way you can create a "persistent" variable that can be set by one script (eg init.sqs) and then modify it throughout the mission by running other scripts (eg via addActions, triggers etc).
Example -
;init.sqs
playerCanteens = 12
;drinkWater.sqs
if playerCanteens < 1 then exit
playerCanteens = playerCanteens - 1
<player effects go in here>
:
In this instance init.sqs sets the variable at the outset and each use of the script drinkWater.sqs reduces it. playerCanteens may also be reduced by other scripts or influences (eg - triggers), but again, only if they are called on that machine.
In fact, the above scripts could be run simultaneously on all machines running in an MP mission and there would be no problem - each machine would update it's own version so that I might be completely out of canteens while you still had nine left, for example.
"Shared Public" variables
This is the same as above, but in this case other machines DO affect the variable. To make a public variable "shared" all you have to do is execute the command "publicVariable XXX" where XX is the variable to be broadcast.
Taking the above example as a start, if one machine were to broadcast "publicVariable playerCanteens" then the current value of ITS version of playerCanteens would be broadcast to all other machines, instantly updating them to this value. So if I was empty and you still had nine left, and I broadcast my value then you and every other player in the game would now also be empty. And I would instantly become very unpopular ! :P :P
Note that in most cases publicVariables will want to be shared, but not always.
The above sample is a good example of when you WOULD NOT want to broadcast it. In this case one script works for all players, each running their own version and keeping track of their own canteen levels - there is no need to write one version of the script for each player.
A good example of when you WOULD want to broadcast it would be a scoring script - one machine would update the score then broadcast this to all other machines, the others would just read the broadcast value and update their own version of this variable accordingly.
Server loops and client loops
This brings up the best way to use shared public variables - server loops and client loops. Check out the following time dilation script -
; timeDilation.sqs
; set time dilation factor
_dilationFactor = 1/1200
; Send client machines to client loop
? !(local server) : goto "clientloop"
; This loop runs continuously on host machine actioning time dilation.
; Time dilation is sent to all client machines via public variable declaration
#serverloop
skipTime _dilationFactor
realTime = daytime
publicVariable "realTime"
; Pause, continue loop
~0.1
goto "serverloop"
#clientloop
; This loop runs continuously on all client machines actioning time dilation.
; Dilation factor is derived continuously from public variable realTime distributed by host machine
? realTime > daytime : skipTime (realTime - daytime)
; Pause, continue loop
~0.1
goto "clientloop"
This script uses a server loop which update the server's game time and broadcasts this to the network, and a client loop which simply receives the server-determined game time and update its own local game time accordingly. This saves having to write two scripts and makes it easier for a scripter to understand and edit it.
Converting "public" and "private" variables
Once you have defined a variable you can convert for what type to another by simply reassigning it. For example - you might have a private variable that runs within a script that at its conclusion spits out a public version of the same value. The syntax is simple - all you do is drop the preceding underscore in the public version (eg - playerCanteens = _playerCanteens)
For instance, you might want to run one single script on 10 different units that returns ten different values, then takes the highest or lowest one of these values. Similarly, you might want to run a script on ten different PLAYERS (ie machines), then take the highest or lowest of these results. In this case, the script would run, the public variable would be assigned, then it would be broadcast to the network. (eg - playerCanteens = _playerCanteens, publicVariable playerCanteens)
Well, that's my latest two cents on the subject. Once again, I started writing and my fingers got ahead of me. I apologise in advance for any poorly written or boneheadly obvious info contained in this post.
Cheers all
roni
-
Re: Init fields. I understand now; an init field is local to whichever computer the unit belongs to.
I don't think this is true. I've run assignment statements thru an init field (groupA = group this), and the variable is set on all machines.
oops, i meant to edit that out, once i changed my conclusion about camcreate. Ah well, never mind, let it sit there in all it's incorrect glory for the time being.
Re: camcreate
I'm pretty sure I've had different results with this command than you suggest, but hopefully some MP experts with WAY more experience than me to set us all straight. :)
Yeah, hopefully that will happen. I was just stating my findings after a quick 2-computer lan, I tried to be accurate but i could be wrong. On the othe hand, if 'drop' now runs on all machines, maybe camcreate has been changed too.
skipTime
Again, is local to each machine. What's worse, script execution is partially clock speed dependant. So if the skipTime script has a pause of (say) 0.1 second between cycles then my machine might take 0.10003 seconds to execute while yours takes 0.100037 seconds to do it. This does add up over time so that two machines running the same script at supposedly the same time will find themselves out of sync in very short order.
The best solution to this problem is to again have one machine carry out the skipTime function then broadcast the resulting time (via the daytime command) to all other machines via a server loop, while all other machines just read the publicVariable each cycle and skipTime accordingly.
Now that's a smart solution...
-
Ok I have an interesting question ;) I have a script in my MP mission which calls for a helicopter to extract the squad once two enemy squads are either all dead or all fleeing. I have a trigger which calls the extraction script when the variables attached to the squads become true. So my question is...
Do I have to broadcast the true/false variables to the clients machines in the sensor scripts for the trigger to become active on their machines ???
I'd appreciate your help, and I hope I have made myself clear (I normally dont :D) ;)
-
side
A useful command since it returns wich side each client player is in a DM game. Can be used to send different messages to different sides or to make separate briefings for east and west.
Example of a message shown to everyone who is not east:
?side player != east : hint "You must be playing on the west side, because you are not east"
The game reportedly recognizes 6 sides (and one unit can sometimes fall in to two categorys at the same time). The sides are:
East (tested, I never had any problems with it)
West (tested, I never had any problems with it)
Civilian (never tested myself)
Resistance or GUER (tested, had problems)
Enemy (never tested myself)
Friendly (never tested myself)
My experince is that the game don't always accept the syntax "resistance" and "guer" however. Sometimes resistance works, sometimes guer and sometimes neither will work (when making separate briefings for instance). East and West works perfect, though.
Taken from the on line comref:
The side of a dead unit (or any inanimate object) will always be civilian. The side of a "rouge" unit (one who killed too many friendlies) will be enemy.
However, the side of the unit's GROUP will always remain the same (east/west/res). So often it may be best to use the syntax:
side (group unit)
The comref also states that "friendly" is the side of a unit that is friendly to all other units. I've never tested it but I assume it is equal to "civilian" or "resistance" (if resistance is set to be friendly to both east and west in the editor).
-
Createvehicle
The effects of this are similar to camcreate. Two important distinctions - firstly, createvehicle offsets the object it creates to fit in with nearby objects' collision radii. Camcreate does not. Secondly vehicles created by createvehicle will be usable; vehicles created with camcreate will not be.
And 1 vehicle is created for every machine, so if 4 players are playing on a dedicated server, and the script is running for everyone, the amount will be 1+4=5 :P
-
The result of this great thread should go in OFPEC's online cmd.ref.
-
Ok I have an interesting question ;) I have a script in my MP mission which calls for a helicopter to extract the squad once two enemy squads are either all dead or all fleeing. I have a trigger which calls the extraction script when the variables attached to the squads become true. So my question is...
Do I have to broadcast the true/false variables to the clients machines in the sensor scripts for the trigger to become active on their machines ???
I'd appreciate your help, and I hope I have made myself clear (I normally dont :D) ;)
Can anyone answer my question ??? I'd appreciate it as I need to sort it for an MP mission I will be playing with my mate 8)
-
Lets' do
- action
- animate
- animationPhase
shall we? :)
Command: action - makes a unit perform an action
Syntax: actor action [ actionstring, target ]
Scope/results: Use it where actor is local. Results/effects seen on all nodes
Example: dude action ["EJECT",somehelo]
Common misuse, giving issues in MP:
* players in MP and his AI loonies not getting ejected from planes. Likely reason: ejection script runs on one machine only. >Bzzzt!<
Best practice
The fix? Make sure that 1) it runs on all machines and 2) enclose the eject action call with
? local _dude: _dude action ["EJECT",_transport]
or similar locality check.
Command: animate - runs animated parts of a model
Syntax: object animate [ animation, phase ]
Scope/results: one call affects all nodes in MP
Example: myplane animate ["cargodoor", 0.5]
Common misuse, giving issues in MP:
Animated part controlled by the same script running on all machines, each one having a go at calling animate at different times. This leads to the affected vehicle doing some really funky stuff in MP. I recently witnessed a certain radar tower dish do this... while the indended effect was to have it rotate nice and slowly, the multiple animate calls from different players' machines had it jittering and not knowing if it was coming or going... ;D
Best practice
Make sure only one machine (not necessarily the server, mind you) does the animate for a certain animated part at a time. Again, this can be done by a simple locality check, should the object to be animated have a script running on many machines.
Command: animationPhase - return the current phase of an animation. Value returned is a number between 0 and 1.
Syntax: object animationPhase animation
Scope/results: phase returned might differ between machines. See below for dedicated server gotcha!
Example: _doorPhase = myplane animationPhase "cargodoor"
Common misuse, giving issues in MP:
OFP feature/bug: sadly, animationPhase ALWAYS returns 0 on dedicated servers
May addons have lots of nifty functionality that uses invisible animations internal to the model as state variables to coordinate these extra features. (cargo loading, towing, rappelling, CAS support feature...the list goes on). In what must be one of the top showstopper bugs/features of OFP, animationState is useless on dedicated servers. In actuality, this breaks a lot of otherwise fantastic functionality in addons out there, rendering them if not useless but at least shaky for MP useage.
Normal OFP clients, arent't affected - the state of an animation is transferred just fine from machine A to all others if/should a script on machine A issue animate on a part. All other machines except the dedicated server can then read the current state of the animation just fine.
Take the example of the jittery radar dish I exemplified above. The rotation of that dish is governed by a script that checks the state of the radar animation in order to keep it spinning. In the current version of the addon with that radar, the rotation script runs on all machines, including the dedicated server, if available. The result is that the rotation monitor script on the deddy basically doesn't do anything since it's waiting in vain for the animation state to change from 0. All player clients, however, have scripts that ever so often detects that the dish has turned one whole revolution and issues another animate call. The end result? A very jittery/shaky radar dish that doesn't really work in MP.
Side note: on camCreate
A camCreated LGB (bomb) on player A:s machine will not be seen on player B's machine. However, the resulting explosion on A's machine will most certainly kill player B should he be unfortunate enough to stand where the bomb lands. ;D
-
@Chris330
You do indeed pose an interesting question. However, your question doesn't specifically relate to scripting commands, so I'd ask that you start a new thread with your question, instead of trying to get it answered in here. 8)
Some clarification about "side"
There is a difference between the "side" data type (data type as in "string", "object", "group", "number", etc) and what gets displayed when you convert a side into a string. For the data type, case does not matter. For example:
West == WEST == west == WeSt
However, when you convert a side into a string, it is ALWAYS converted into a very case-specific string (an example of converting a side to a string: hint format["%1", side player]). Here are the ones I know off the top of my head:
Side String conversion
west "WEST"
east "EAST"
resistance "GUER"
civilian "CIV" (not entirely sure)
enemy "ENEMY"
I suspect the reason nomineshine has had problems with using the resistance side, for example, is because he did not recognize the difference between when he was using the side as a SIDE data type, or when he was converting it to a STRING data type. For example, this will always return false, even though it may seem like it would work:
format["%1", side unit] == resistance
Just for the record, this same sort of "string conversion" via the format command can be done with most other data types as well, such as GROUP, NUMBER, BOOL, etc, and it is the only way to pass additional information to certain commands (such as addeventhandler or createunit). But at this point I'm getting way off track...
-
And 1 vehicle is created for every machine, so if 4 players are playing on a dedicated server, and the script is running for everyone, the amount will be 1+4=5 :P
Likewise with camcreate, I think I found. I reiterate: that was from a test on a 2-person lan, I could be wrong. When I put xyz="t80" camcreate poswherever in an init field, two t80s were created, just like createvehicle would have done in the same position (minus the obvious differences).
OK, as a multiplayer scripting neophyte, I need some clarification as to what 'local' and 'global' mean exactly. This is what I think they mean at the moment:
Global:
When a command is run on a single client, the effects occur on all computers. If the command is run on n clients (plus the server), the effect occurs n times, with each effect visible to all computers.
Local:
When a command is run on a single client, the effects of that command are seen (and felt) only on that client. When the command is run on n clients, the effect occurs once once on all computers.
So,
Global execution + Global command = Repeated execution on all computers
Global execution + Local command = Single execution on all computers
Local execution + Global command = Single execution on all computers
Local execution + Local command = Single execution on one computer
where 'global execution' is for example in an init field, or in a script run from an init field. 'Local execution' is in a script after the conditional '? local <object>'.
Question: does init.sqs run on all clients at the start of a mission, or just the server?
-
Fragorl, your understanding of "global" and "local" with regards to the effects of scripting commands is indeed a sound one.
I believe the confusion out there has arisen from the usage of those terms both for describing the effects of commands and the so-called scope of variables.
"Global" and "local" effect script commands
...and their effects: see Fragorls post just above. That summarises it quite well.
Variable scope ("reach")
This is where the use of the word "global" above conflicts with the normal understanding of "global variables" in the context of programming languages and OFP scripting. In OFP terms that classical terminology goes like this:
A local variable (the ones who have names beginning with an underscore, e.g _myvar) is one that can only be reached by the script that's using it (or functions called from it, but we'll leave that aside for now).
A global variable is one whose value can be reached (read and written to) by all scripts running on one computer.
What do we then call variables that are handled in such a way as to have their values synchronised on all machines using publicVariable? It has been suggested to simply call such variables, well, "public variables".
However, earlier in this thread, Roni used the terms private/public/shared public for these variables, and perhaps that is a terminology better suited to use, since it avoids confusing variable scope with script command scope. Actually, I think private/global/public would be even better.
Question: does init.sqs run on all clients at the start of a mission, or just the server?
The init.sqs of a mission will be run on all machines, both server and clients, when the mission starts.
-
When I put xyz="t80" camcreate poswherever in an init field, two t80s were created, just like createvehicle would have done in the same position (minus the obvious differences).
Init fields are run on each individual computer, so in your case, the camcreate command was run on both computers in the LAN.
Question: does init.sqs run on all clients at the start of a mission, or just the server?
All computers.
I need some clarification as to what 'local' and 'global' mean exactly.
I wouldn't split hairs too much on this point. The definitions aren't provided by BIS, so they might differ from person to person. Basically, there are two factors to consider in terms of "locality" in MP:
Local / Remote objects: an object is only "local" to one computer at a time. A player's 'body', squad, and vehicles under the control of them are local to that player's computer. Objects and units not under any player's control will always be local to the server. You can check to see if an object is local using the "local" command. (As a side note, if you convert an object to a string (hint format["%1", object1]), then it will have "remote" at the end if that object is not local). Some commands might behave differently if you pass them a remote object instead of a local object, which is what this thread is meant to find out.
Local / Public effects: the effects of some commands will only happen on the computer from which that command was run (or example, the weather commands and skiptime commands). The effects of other commands will be seen by ALL computers, regardless of which computer runs the command (for example, the setdammage command). This is the other main thing I hope to find out with this thread.
Other confusing uses of locality
There are many other ways to use the terms "local" and "global", which is why I'm trying to avoid using them altogether. Using the terms in too many different situations just confuses me, which is why I used "public" instead of "global" above. But here are some other, different places where you could use the term:
Local/Private & Global variables: I would hope everyone knows the difference between the two in SP. In MP they work exactly the same way, but note that each computer has its own variables (even global ones). The "publicvariable" command, as explained above, will force all computers to set the specified global variable to the value that was on the computer executing the command, at the time it was executed (wordy explaination, see Roni's post above for a better one).
Scripts/commands running locally: A script (or scripting command) is run on a specific computer. The same script can be run on all computers at the same time, but really each individual computer is running it's own script. They all have the same script, but anything random in the script can cause it to run differently on each computer.
Scripting commands run from the mission editor can be confusing. Triggers can run on one computer, but not on another, from my understanding. Basically, I would assume that, like scripts, each individual computer gets its own "copy" of the mission's triggers/waypoints/etc, and runs them individually on that machine. I may be wrong on this point though, and I sure as heck would like more clarification, since it definately deals with how scripting commands work in MP.
Anyway, my only point is that the terms global/local can get confusing, and it seems best to think in terms of computers. Basically: "what computer is executing this command?", and also "how will this affect other computers on the network?".
A good way to test mp scripting
This is assuming you have 2+ computers hooked together, near enough to each other that you can observe both without having to walk to a different room. Make a mission on desert island, and use Vektorboson's scripting console (in the ed depot) that can be called via an action added to all players. This way you can type in scripting commands on both computers without having to hop in/out of the mission editor, and those commands will only be executed on the computer it was typed in on. You can also monitor the status of variables, and see how it may be different fom computer to computer.
-
AddAction
The action added will ONLY appear to the computer who executed the command. So if the server adds an action to an object, none of the player's or their AI will be able to see/use the action (unless the server also has a player; i.e. is not dedicated). If a client adds an action to that machine's player, then only THAT player (and AI under his command) will be able to see/use that action. So if you want all players to be able to see and use an action, you have to make sure the addaction command is run on all computers.
When a player uses the action, the attatched script will only be run on that player's computer.
-
While you're at AddAction, i'd like to keep one question open:
There's the case that when one player is standing close to another
player, which has an added Action, and the first player will be able
to execute the action.
Where the script will be executed?
On both player's machines?
On player A machine?
On player B machine?
Sorry, but at the mo i ain't got chance to test it :(
~S~ CD
-
Triggers can run on one computer, but not on another, from my understanding. Basically, I would assume that, like scripts, each individual computer gets its own "copy" of the mission's triggers/waypoints/etc, and runs them individually on that machine. I may be wrong on this point though, and I sure as heck would like more clarification, since it definately deals with how scripting commands work in MP.
I've had this problem with "not present" triggers:
In a MP DeathMatch I made, there was two triggers checking, respectively, if WEST and RESISTANCE was "not present". Both triggers covered the entire map. When either was true, a triggerbased text informed you that mission was acomplished.
It worked perfectly in the editor and in SP mode. In MP it didn't. When a WEST-player was acting as server, the "west not present" trigger fired instantly on RESISTANCE-player's computer. When RESISTANCE-player was server it worked the other way around ("resistance not present" fired on WEST client).
Since the trigger only fired on the client, I'm quite sure that triggers are unique to every computer in the game. If I remember it correctly, I tried to create an alternative by changing the trigger condition "this" to "local server AND this". Thus preventing the client from firing the trigger. But I abandoned this idea and never tested it (and I suspect it would prevent the clients from ever seeing the text).
I still don't know the solution to the problem, but maybe this example can shed some light on the issue at hand to the Mp gurus.
-
Triggers can run on one computer, but not on another, from my understanding. Basically, I would assume that, like scripts, each individual computer gets its own "copy" of the mission's triggers/waypoints/etc, and runs them individually on that machine. I may be wrong on this point though, and I sure as heck would like more clarification, since it definately deals with how scripting commands work in MP.
Don't think computers got it's own copy of the waypoints, but if it's like that, then I would think the units would stop if there was something wrong with one of the waypoints on a computer.
And that triggers are local, that I can confirme. In the mission I'm making (which I mailed you about :P) I've got a trigger with east not present, activated once. When it is activated it changes the first objective to "Done" and shows a hint. And one time we tested it, this trigger was activated for everyone else than me :o Everyone else got a hint saying the first objective was done, and the objective changed, but nothing happened for me. Dunno what went wrong. It only happened once, but that proves that triggers are local.
-
I have found that the most important thing you can do in MP maps, is to make a game logic and name it server . This will almost magically solve many MP issues. As for the createvehicle, only run it on the server, and it will appear on all connected comps. The first line should be:
?!(local server):exit
And as stated above, publicvariable is also one of the most important commands
-
Setdamage (and Setdammage) does not revitalize a dead (non player) unit when there is respawn and the unit was registered as dead (killed eventhandler triggered, alive unit returns false).
It will actually revitalize the unit if it is immediatly triggered when damage unit reaches 1 (but then killed eventhandler won't fire, alive returns true).
Will not work:
@!alive _unit
_unit setdamage 0
Will work:
@damage _unit >= 1
_unit setdamage 0
Took quite some time and nerves to find out what was wrong.
h
-
I knew somebody had to have figured most of this stuff out before. Turns out Spinor from CoC made a nice little reference about commands in MP. I got it from Crashdome, who is supposedly going to fix it up and post it in the ed depot. In the meantime, here it is:
Compiled by Spinor for Coc
With input from bn880,CrashDome,Dinger
Tested on OFP 1.96 (Non-dedicated server + one client)
Notes:
----------------------------------------------------------------------------------------
local
-> this is a command that is completely local i.e. its argument(s) must be
local and both its result and/or effect are only local,
naturally, all mathematical and logical commands belong to this group,
the same is true for all interface stuff like dialogs etc.
constant
-> this denotes a constant value, hence the same on all machines
works on (non)local obj/unit/grp/vehicle
-> this command works no matter if the obj/unit/grp/vehicle is local on this
machine or not; beware though: results/effects may differ due to lag/desynch
between machines
works on (non)local obj, but has only local effect
-> although this command also works on both local and nonlocal objects,
its effect is only local, i.e. it is not synchronized between machines
EXAMPLE: sideChat, sideRadio etc.
works only on local obj/unit/grp/vehicle, (temp)
-> this command is only funcional if applied on a obj/unit/grp/vehicle
that is local to this machine;
temp signifies that the command may be applied to a nonlocal object
but the effect is only shortlived: it will be removed during synchro
Command List:
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
#
------------------------------------------------------------------------------------------
- a local
a - b local
arrayA - arrayB local
! a local
a != b local
side1 != side2 local
a != b local
obj1 != obj2 works on (non)local objects
grp1 != grp2 works on (non)local groups
a % b local
a && b local
a * b local
a / b local
a ^ b local
a || b local
stringA + stringB local
arrayA + arrayB local
+ a local
a + b local
a < b local
a <= b local
grp1 == grp2 works on (non)local groups
side1 == side2 local
a == b local
obj1 == obj2 works on (non)local objects
a == b local
a > b local
a >= b local
A
------------------------------------------------------------------------------------------
abs x local
accTime always 1 in MP
acos x local
unit action action works only on local unit (tested only with "EJECT")
unit addAction action works only on local unit, temp
object addEventHandler handler works on (non)local unit, has local effect (added handler executes only on local machine)
unit addMagazine weaponName works only on local unit, temp
unit addMagazineCargo magazines works on (non)local unit, but has only local effect, i.e. added items are only visible on local machine
addMagazinePool Null non-functional in MP
unit addRating number works only on local unit, temp
unit addScore score works on (non)local unit, but has only local effect
unit addWeapon weaponName works only on local unit, temp
unit addWeaponCargo weapons works on (non)local unit, but has only local effect, i.e. added items are only visible on local machine
addWeaponPool [name, count] non-functional in MP
alive obj works on (non)local unit
unit allowFleeing courage ?????
unitArray allowGetIn allow ?????
unit ammo magazine works on (non)local unit
a and b local
object animate [animation, phase] ?????
object animationPhase animation ?????
asin x local
soldier assignAsCargo vehicle ?????
soldier assignAsCommander vehicle ?????
soldier assignAsDriver vehicle ?????
soldier assignAsGunner vehicle ?????
atan x local
x atan2 y local
atg x local
B
------------------------------------------------------------------------------------------
behaviour unit works on (non)local unit
benchmark local, returns benchmark of local machine
building buildingPos index works on (non)local building, i.e. also on clients
buttonAction idc local
buttonSetAction [idc, action] local
C
------------------------------------------------------------------------------------------
cadetMode constant
pars call body local
call code local
camera camCommand command local
camera camCommit time local
camCommitted camera local
type camCreate position local
camDestroy camera local
camera cameraEffect effect local
cameraOn local
camera camSetBank bank local
camera camSetDir direction local
camera camSetDive dive local
camera camSetFov fieldOfView local
camera camSetFovRange fovRange local
camera camSetPos position local
camera camSetRelPos position local
camera camSetTarget position local
camera camSetTarget target local
canFire vehicle works on (non)local vehicle
canMove vehicle works on (non)local vehicle
canStand soldier works on (non)local unit
captive unit works on (non)local unit
civilian constant
clearMagazineCargo unit works on (non)local unit, but has only local effect
clearMagazinePool non-functional in MP
clearWeaponCargo unit works on (non)local unit, but has only local effect
clearWeaponPool non-functional in MP
closeDialog idc local
combatMode grp works on (non)local unit/grp
commander vehicle works on (non)local vehicle
unit commandFire target works only on local unit, temp
unit commandFollow formationLeader works only on local unit
unit commandMove position works on (non)local unit
commandStop unit works on (non)local unit
unit commandTarget position works only on local unit
unit commandWatch position works only on local unit
unit commandWatch target works only on local unit
comment comment local
cos x local
condition count array local
count array local
unit countEnemy array works on (non)local unit
unit countFriendly array works on (non)local unit
side countSide array works on (non)local unit
typeName countType array works on (non)local unit
unit countUnknown array works on (non)local unit
createDialog name local
type createUnit unitInfo works on (non)local spawn group, has global effect, Init line is executed on all machines (with caveats)
type createVehicle pos has global effect
crew vehicle works on (non)local vehicle
ctrlEnable [idc, enable] local
ctrlEnabled idc local
ctrlSetText [idc, text] local
ctrlShow [idc, show] local
ctrlText idc local
ctrlVisible idc local
cutObj effect local
cutRsc effect local
cutText effect local
D
------------------------------------------------------------------------------------------
damage object works on (non)local object, rounding error on nonlocal object
daytime returns local time of day, can differ between machines (skiptime and desynch!!)
deg x local
deleteIdentity identityName non-functional in MP
deleteStatus statusName non-functional in MP
deleteVehicle object works on (non)local unit?, causes game freeze in console?
dialog local
direction object works on (non)local unit
unit disableAI section works only on local unit
disableUserInput disable local
obj1 distance obj2 works on (non)local objects
while do code local
unit doFire target works only on local unit
unit doFollow position works only on local unit
unit doMove position works on (non)local unit
doStop unit works on (non)local unit
unit doTarget position works only on local unit
unit doWatch position works only on local unit
unit doWatch target works only on local unit
driver vehicle works on (non)local vehicle
drop array local effect
E
------------------------------------------------------------------------------------------
east constant
ifCode else elseCode local
enableEndDialog local effect
enableRadio enable local effect
enemy local
vehicle engineOn bool works only on local vehicle, temp
estimatedTimeLeft timeLeft ?????
argument exec script local
exit local
exp x local
F
------------------------------------------------------------------------------------------
time fadeMusic volume local effect
time fadeSound volume local effect
false constant
fillWeaponsFromPool person non-functional in MP
unit fire weaponName works on (non)local unit, direction of fire not synchronized?
unit fire array works on (non)local unit, direction of fire not synchronized?
flag unit ?????
flagowner flag ?????
fleeing unit works on (non)local unit
helicopter flyInHeight height works only on local vehicle
forceEnd ?????
forceMap show local
command forEach array local
format format local
formation grp works on (non)local grp
formLeader unit works on (non)local unit
friendly local
fuel vehicle works on (non)local vehicle
G
------------------------------------------------------------------------------------------
getDammage obj works on (non)local obj, rounding error on nonlocal obj
getDir obj works on (non)local obj
getMarkerColor marker local
getMarkerPos markerName local
getMarkerSize marker local
getMarkerType marker local
getPos obj works on (non)local unit
getWPPos waypoint works on (non)local group
unit globalChat chatText works on (non)local unit, but has only local effect
unit globalRadio radioName works on (non)local unit, but has only local effect
goto label local
group obj works on (non)local obj
unit groupChat chatText works on (non)local unit, but has only local effect
unit groupRadio radioName works on (non)local unit, but has only local effect
grpNull local
gunner vehicle works on (non)local vehicle
H
------------------------------------------------------------------------------------------
handsHit soldier works on (non)local unit
unit hasWeapon weaponName works on (non)local unit
hint text local effect
hintC text local effect
hintCadet text local effect
I
------------------------------------------------------------------------------------------
if condition local
x in array local
soldier in vehicle works on (non)local unit/vehicle
fireplace inflame burn works on (non)local fireplace
inflamed fireplace works on (non)local fireplace
isEngineOn vehicle works on (non)local vehicle
isNull grp works on (non)local grp
isNull obj works on (non)local obj
J
------------------------------------------------------------------------------------------
unitArray join group works on (non)local unitArray/group
K
------------------------------------------------------------------------------------------
unit knowsAbout target works properly only on local unit, targer can be nonlocal
L
------------------------------------------------------------------------------------------
helicopter land mode works only on local vehicle
lbAdd [idc, text] local
lbClear idc local
lbColor [idc, index] local
lbCurSel idc local
lbData [idc, index] local
lbDelete [idc, index] local
lbPicture [idc, index] local
lbSetColor [idc, index, color] local
lbSetCurSel [idc, index] local
lbSetData [idc, index, data] local
lbSetPicture [idc, index, name] local
lbSetValue [idc, index, value] local
lbSize idc local
lbText [idc, index] local
lbValue [idc, index] local
leader unit works on (non)local unit
leader grp works on (non)local grp
group leaveVehicle vehicle works only on local group/unit
lightIsOn lamppost ?????
list trigger triggers are synchronized, hence should returns globally synchronized result, sequence may differ
ln x local
loadFile filename local
person loadIdentity name non-functional in MP
object loadStatus name non-functional in MP
local obj returns locality status of obj, hence local result
localize stringName local result, depending on language setting of machine
vehicle lock lock works only on local vehicle, temp
locked unit works on (non)local unit
group lockWP lockWP works only on local group
log x local
M
------------------------------------------------------------------------------------------
magazines vehicle works on (non)local vehicle
mapAnimAdd frame local
mapAnimClear local
mapAnimCommit local
mapAnimDone local
markerColor markerName local
markerPos markerName local
markerSize markerName local
markerType markerName local
missionName global, the same on all machines
missionStart local, may slightly differ between machines
a mod b local
group move pos works only on local group
soldier moveInCargo vehicle works only on local unit
soldier moveInCommander vehicle works only on local unit
soldier moveInDriver vehicle works only on local unit
soldier moveInGunner vehicle works only on local unit
musicVolume local
N
------------------------------------------------------------------------------------------
name object works on (non)local object
nearestBuilding obj works on (non)local obj
nearestObject pos also finds nonlocal objects
nil local
not a local
O
------------------------------------------------------------------------------------------
object id correctly points to map object also on clients
objNull constant
objective objStatus status local
onBriefingGear sound local
onBriefingGroup sound local
onBriefingNotes sound local
onBriefingPlan sound local
onMapSingleClick command local
a or b local
unitArray orderGetIn order only works on local unit
P
------------------------------------------------------------------------------------------
pi constant
pickWeaponPool obj non-functional in MP
player local, player on this machine
playersNumber side returns playable units per side, same on all machines, always zero in SP
soldier playMove moveName only works on local unit, effect is then global
playMusic name local effect
playMusic nameAndPos local effect
playSound name local effect
position object works on (non)local obj
preprocessFile filename local
primaryWeapon vehicle works on (non)local unit
private variableName local
private variableNameList local
publicVariable varName synchronizes varName on all machines with value on local machine
putWeaponPool obj non-functional in MP
Q
------------------------------------------------------------------------------------------
queryMagazinePool name non-functional in MP
queryWeaponPool name non-functional in MP
R
------------------------------------------------------------------------------------------
rad x local
random x local
rating unit works on (non)local unit
unit removeAction index only works on local unit
object removeAllEventHandlers handlerType works on (non)local unit, effect is local
removeAllWeapons unit only works on local unit
object removeEventHandler handler works on (non)local unit, effect is local
unit removeMagazine weaponName only works on local unit
unit removeMagazines weaponName only works on local unit
unit removeWeapon weaponName only works on local unit
requiredVersion version local effect, depending on OFP version on machine
resistance constant
array resize count local
group reveal unit works on (non)local group/unit
S
------------------------------------------------------------------------------------------
saveGame non-functional in MP
person saveIdentity name non-functional in MP
object saveStatus name non-functional in MP
saveVar varName non-functional in MP
unit say speechName works on (non)local unit, but is local in its effect
score unit works on (non)local group/unit, but results can differ between machines due to non-synchro of addScore
scudState scud ?????
secondaryWeapon vehicle works on (non)local unit
array select index local
unit selectWeapon weapon ?????
array set element local
setAccTime accFactor non-functional in MP
vehicle setAmmoCargo ammoCargo ?????
group setBehaviour behaviour only works on local unit/group, temp
person setCaptive captive only works on local unit, temp
group setCombatMode mode only works on local group, temp
object setDamage damage works on (non)local obj, rounding error on nonlocal obj
obj setDammage dammage works on (non)local obj, rounding error on nonlocal obj
obj setDir heading only works on local obj, temp
person setFace soldier works on (non)local unit, but effect is only local
person setFaceAnimation blink works on (non)local unit, but effect is only local
flag setFlagOwner owner ?????
flag setFlagSide side ?????
flag setFlagTexture texture ?????
time setFog fog local effect, not synchronized!
group setFormation formation only works on local group, temp
group setFormDir heading only works on local group, temp
vehicle setFuel ammount only works on local vehicle, temp
vehicle setFuelCargo ammount ?????
group setGroupId id works on (non)local group, but effect is only local
person setIdentity identity ?????
marker setMarkerColor color local
markerName setMarkerPos pos local
marker setMarkerSize size local
markerName setMarkerType markerType local
person setMimic mimic works on (non)local unit, but effect is only local
object setObjectTexture texture ?????
time setOvercast overcast local effect, not synchronized
obj setPos pos works on (non)local unit
index setRadioMsg text local
time setRain rainDensity local effect, not synchrinized
vehicle setRepairCargo ammount ?????
vehicle setSkill skill only works on local unit, temp
group setSpeedMode mode only works on local group, temp
setTerrainGrid grid local effect, not synchronized!
unit setUnitPos mode only works on local unit
vehicle setVelocity [x, z, y] only works on local object
setViewDistance distance local effect, not synchronized!
waypoint setWPPos position only works on local group
showCinemaBorder show local
showCompass show local
showGps show local
showMap show local
shownCompass local
shownGps local
shownMap local
shownPad local
shownRadio local
shownWarrant local
shownWatch local
showPad show local
showRadio show local
showWarrant show local
showWatch show local
side unit works on (non)local unit
unit sideChat chatText works on (non)local unit, but effect is only local
unit sideRadio radioName works on (non)local unit, but effect is only local
sin x local
skill person works on (non)local unit, rounding error on nonlocal unit
skipTime duration local effect, not synchronized!
sliderPosition idc local
sliderRange idc local
sliderSetPosition [idc, pos] local
sliderSetRange [idc, min, max] local
sliderSetSpeed [idc, line, page]local
sliderSpeed idc local
someAmmo unit works on (non)local unit
soundVolume local
speed obj works on (non)local obj
speedMode grp works on (non)local grp
sqrt x local
unit stop stop works only on local unit
stopped unit works only on local unit
unit switchCamera mode works on (non)local unit, but effect is only local
lamppost switchLight mode ?????
soldier switchMove moveName works on (non)local unit, but when used on nonlocal unit, effect is also only local
T
------------------------------------------------------------------------------------------
tan x local
tg x local
if then else local
if then codeToExecute local
time local, may slightly differ between machines
titleCut effect local effect
titleObj effect local effect
titleRsc effect local effect
titleText effect local effect
true constant
typeOf obj works on (non)local obj
U
------------------------------------------------------------------------------------------
unassignVehicle unit only works on local unit
unitReady unit works on (non)local unit
units unit works on (non)local unit
units grp works on (non)local grp
V
------------------------------------------------------------------------------------------
vehicle unit works on (non)local unit
unit vehicleChat chatText works on (non)local unit, but effect is only local
unit vehicleRadio radioName works on (non)local unit, but effect is only local
velocity vehicle works on (non)local unit
W
------------------------------------------------------------------------------------------
waypointPosition waypoint works on (non)local group
weapons vehicle works on (non)local unit
west constant
while condition local
However, as demonstrated by hermano and many other's posts, there are quite a few little "irks" in the way commands behave in MP, aside from whether they have local or global effects. So please, other input is still extremely welcome. :)
-
Great list,
thanks General, CrashDome!
By the way, I'm not sure if the info about savestatus is right, it seems to work for vehicles and gamelogics (at least the damage of the vehicle can be saved and restored, for gamelogics also skill afaik). Won't work for man (and child objects).
h
-
Great list,
thanks General, CrashDome!
By the way, I'm not sure if the info about savestatus is right, it seems to work for vehicles and gamelogics (at least the damage of the vehicle can be saved and restored, for gamelogics also skill afaik). Won't work for man (and child objects).
h
Ha! You're sharp. Crashdome even posted a comment about that (in the forums where he posted this). His SOW mod uses savestatus extensively to allow saving across MP missions, so obviously it works in MP. Didn't know about the specific limitations you mentioned though ;)
-
A good find, General Barron!
This list confirms most if not all of the commands that were previously mentioned in this thread, which is always nice :)
EDIT:
I'm still a bit hazy on camcreate versus createvehicle- the list here definitely says they are different, with createvehicle being global, camcreate being local, but I still found them to behave in exactly the same when I ran my 2 person lan test. A shell camcreated on the server-side only killed both players. Placing a "T80" createvehicle ... in the initfield of a unit created 2 t80s, each visible from both players. Substituting createvehicle for camcreate once again produced 2 T80s, each visible from both players.
-
Indeed, createvehicle can't be totally global, cause you will get 1 vehicle for every client+server...which is annoying :-\
-
To really see the difference between the two, you should set up a mission with a scripting console (Vectorboson's is a good one). Commands typed into the console will only be executed on that specific client.
Using the camcreate command will make an object that is only visible on the machine the command was run from. Using the createvehicle command in the same situation will make the object visible on ALL clients.
A shell camcreated on the server-side only killed both players.
I haven't experienced or confirmed this myself. However, that would be a special exception for the server only. Camcreating shells on clients creates a shell that does no damage.
Placing a "T80" createvehicle ... in the initfield of a unit created 2 t80s, each visible from both players. Substituting createvehicle for camcreate once again produced 2 T80s, each visible from both players.
Init fields are run on EVERY client. So the camcreate and createvehicle commands were run twice: once on each client, resulting in 2 vehicles total.
Okay, now I get it. The 'camcreate' command should have only made one vehicle visible on each client, since I just said the created object would only be visible where the command was issued. :-\
I guess I don't have enough MP experience to give straight answers here... However, I know that the camcreate/createvehicle commands are very basic to MP, so the answer to your questions has to be widely known to experienced MP editors. :)
-
yes - that was my point ;)
it sounds to me that one possibility is that somewhere along the line, perhps one of the more recent patches like 191, 195 or 196 made some changes to the commands that they didnt tell us about
-
Ha! You're sharp. Crashdome even posted a comment about that (in the forums where he posted this). His SOW mod uses savestatus extensively to allow saving across MP missions, so obviously it works in MP. Didn't know about the specific limitations you mentioned though ;)
Thanks ;)
There is another limitation I forgot to mention. Savestatus of an undamaged object will only work if there is no damaged status saved with the same name, calling deletestatus before saving will solve this.
Besides: I'm around the sow forums sometimes and actually plan to join CrashDome in creating a sow campaign, the sow scripts are really fine, the only other scripts of such quality I've seen so far are coc's.
h
-
Must a publicVariable be defined on all machines before it can be broadcast? That is, if the global boolean variable bVar is defined only on one client and that client broadcasts via publicVariable "bVar", will bVar be then defined on all machines? Must there be a delay between creating(or assigning a new value to) a variable and broadcasting it?
-
There should be a small delay at least
-
Must a publicVariable be defined on all machines before it can be broadcast? Must there be a delay between creating(or assigning a new value to) a variable and broadcasting it?
No and no.
-
Could this thread be pinned? It is sinking...
-
I don't know anything about MP and I haven't studied the thread, but there is clearly some good stuff here.
The forum is not the right place for storing information: the Editors Depot is the place for that. However the forum can be a good place for collecting information, and sharing and discussing experiences of how commands work. This sort of behaviour is to be encouraged. :thumbsup:
Consequently I've made this thread a sticky temporarily. However in the fullness of time (say, in the next month or two) I expect somebody to turn the information here into a tutorial. Giving credit where it is due of course. However, in the long term if its not useful enough to be a tute, it's not useful enough to be a sticky.
-
Understood mac. It's just that I was searching for this thread the other day and had trouble finding it, it had sunk so quickly.
It seems to me there is still much disagreement over how certain commands behave in MP. I think it would it be safe to say that with the exception of createVehicleand deleteVehicle, a command should executed on all clients if you want the effects to be observed on all clients.
Is redundancy an issue with any other commands? I know that the *Radio commands only need be executed on one client to be seen by all, but if a trigger executes a sideRadio command, for example, is the message displayed once or multiple times on each client?
If I am using setWPPos or move for enemy AI (local to the server), does it cause problems to execute these commands on every client instead of only on the server?
Are there any situations where executing commands on all clients would cause problems other than unnecessary cpu load?
-
Is redundancy an issue with any other commands?
Yes. See "join" below.
I know that the *Radio commands only need be executed on one client to be seen by all, but if a trigger executes a sideRadio command, for example, is the message displayed once or multiple times on each client?
I wasn't aware that *Radio behaved differently from *Chat, which definitiely only has effect on the machine where it is issued. In other words: to have all nodes see the output of a *Chat, it has to be run on all nodes (possibly with the exception of a dedicated server, since that would be uneccessary)
If I am using setWPPos or move for enemy AI (local to the server), does it cause problems to execute these commands on every client instead of only on the server?
There could be problems. Let's say "script X" handles the moving around of a certain group and that script happens to run on all machines. Also, "X" will dynamically adapt the placement of waypoints and ordering of movement based on several external factors. Now, during an MP session, due to desync and packet loss and whatnot, the subset of the current gamestate that X needs to function might be different on different machines. The result would then be script X on machine A moving a waypoint to point P1 whereas the same script on machine B tries to move it to P2.
Therefore, the best practice is to issue these where the affected unit/group is local. (Now, move will only have an effect on the machine where the unit/group that move operates on is local)
Are there any situations where executing commands on all clients would cause problems other than unnecessary cpu load?
Yes. One example that comes to mind and that is very common is the use of the join command in waypoints or triggers. I have played several missions where the MP player group meets up with some other entity (classical "rescue VIP"-type missions) that then joins the player group. Since the mission maker was unaware of the many pitfalls of MP mission making, the result in-game will be several repeated calls for the VIP to join the squad:
5, join 1
5, ready
5, join 1
5, ready
5, join 1
5, ready
5, join 1
5, ready
5, join 1
5, ready
Now that's HIGHLY annoying!
-
I'm so glad this forum was made a sticky, albiet a temporary. Tyring to find this info over last 2 years has been a nightmare! Try not knowing this stuff when making a CTI...without 2 computers to trial it on!!
e.g. 1) make script
2) replicate as needed
3) found out command has MP issues
4) edit all 10 scripts to source out to a script that is only executed on server/client
Nice work on getting this topic started and maintained General Barron! Now if we can convince someone to make the tutorial or even better get HAMMY to include this info in his executable Command Reference 1.91 that would be great.
----------------------
I've taught myself OFP scripting from the ground-up (i.e. I know no other programming type language :) what better way to learn than OFP) and I've been making a CTI for the last 2 years based on the MFCTI core.
CTI maps use a lot of arrays, so my question is:
How are arrays effected by locality in a MP setting with a dedicated server?
e.g.
If I have an array defined at the start of a map in a script run on all machines (for CTI scripters this would be "Main\initserver.sqs") but I dynamically edit (contents not size for now) that array with different objects and sub-arrays, how is this handled in a MP setting?
1) global script = defines array
2) local to player script edits array = array contents edited/updated on all computers?
3) local to server script edits array = array edited/updated on all computers?
Now I've learnt the difference between variables, arrays, functions, commands, scripts etc. through various sources but here's the problem I have:
1) 'arrays' can hold 'objects' which can be defined as a 'variable'
e.g. Var1 = vehicle1;subArray = [Var1];mainArray = [subArray]
i.e. mainArray = [[vehicle1]]
2) Now if Var1 changes to vehicle2 via a local to player script, does the contents of Array1 change?
e.g. local: Var1 = vehicle2
server: subArray = [Var1]
mainArray = [[?]]
I know it might seem off-topic in relation to the thread, but in relation to the 'PublicVariable' command, does this have to be done OR can be used (sorry for my lack of understanding in this department) with arrays?
Therefore, is it better to use arrays with multiple contents or mutliple variables that are broadcasted via the 'PublicVariable' command?
I'm of the mind that the former is better than the latter as I've read somewhere that arrays hold the information better whereas using variables can be erroneous in a MP setting?
---------------
Sorry if this is off-topic, but it was in a way in relation to the 'PublicVariable' command so it seemed fitting. Feel free to move this as a serperate topic. :)
-
Good Q's, and I'd say that they are all on topic. I don't have much time for a reply, but I can add more later if needed.
The main issue here is how variables are handled in an MP environment. The answer is the same for all types of variables, including arrays.
Even though the global arrays are initialized at the same time, and with the same data, on every node (computer+server), each node stores its own array, completely separate from the rest. Later changes made to one node's array will NOT affect the other nodes (even though the array has the same name, and is global). The same is true for all other variable types.
Pretty much the only way you can have one node affect the variables on other nodes is with the 'publicvariable' command; which BTW doesn't support arrays, strings, and a few other types.
---------------
What I would HIGHLY recommend to ANYONE using fairly complex MP scripting, is that they use the CoC's Network Services 2 (http://www.thechainofcommand.com/docs/LIBNETWORK/archive/CoC_NS_2_Pack.zip). It has built in functions for sharing arrays across the network, as well as a couple other extremely handy functions. The documentation is a little hard to understand at first, but it is pretty straightforward once you get the hang of it, and it makes things about 1000x easier to script.
Crashdome had started making a tutorial on how to use the NS. I will have to see the status of that tut, and possibly finish it myself. I swear to you NS will make your life easier, especially with something as complex as CTI.
-
Dear all,
I have a question. This is a script I have been writing which works fine on single player but has not been tested on multiplayer. There's no need to get bogged down in the script too much all I need to know is because game logic units are always local to the server, does this mean that their positions are always defined on the server and broadcast to the clients? Or, do I have to instruct the client machine(s) to change the postions of the game logics too, or can I just get away with altering their positions on the server?
The following script has been made assuming that the client machine(s) do not have to update the positions of the game logics. Rather it has been made assuming that the positions of the game logics in the mission are determined and broadcast globally by the server. Have a look at it. I have annotated the bits I need some clarification on (they are only small parts of the script).
Please note it is a camera script which utilises two game logic units. One named cameraeffect1 and one named cameraeffect2.
//I think this bit is now okay as I understand that camcreate
//must be executed on the client machines too. :D
_camoffx = _this select 0
_camoffy = _this select 1
_helo = _this select 2
_cam1 = "camera" camcreate [0,0,0]
_cam1 cameraeffect ["internal", "back"]
_cam1 camsettarget cameraeffect1
_cam1 camsetrelpos [0,0,0]
_cam1 camcommit 0
#start
?not local server : goto "checkserverready"
//If this is not the server machine then goto the loop that
//waits for the server to finish the maths
_BankPitch = _helo call GetBankPitch
_Pitch = _BankPitch select 1
_sinangle = sin(_Pitch)
_cosangle = cos(_Pitch)
;evaluate where camsetrelpos command should set the camera to for _camoffy
e = (_sinangle) * (_camoffy)
a = (_cosangle) * (_camoffy)
//broadcast the camsetrelpos variables to the client(s)
publicvariable "a"
publicvariable "e"
;get heading of helicopter and evaluate x and y offsets for the game logics for _camoffx
_heading = getdir _helo
_angle = 360 - _heading
_xa = (cos (_angle)) * _camoffx
_ya = (sin (_angle)) * _camoffx
;Get position co-ordinates of helicopter
_xh = getpos _helo select 0
_yh = getpos _helo select 1
//The interesting bit. Will this automatically update the
//game logics' positions on the client?
;Position the game logics
cameraeffect2 setpos [(_xh + _xa),(_yh + _ya),0]
_dist = _helo distance cameraeffect2
_height = sqrt ((_dist^2)-(_camoffx^2))
cameraeffect1 setpos [(_xh + _xa),(_yh + _ya),_height]
cameraeffect1 setdir _heading
logiccomplete = true
//Client waits for server to finish then camsetrelpos variables
//are issued.
#checkserverready
?logiccomplete : goto "camerapositioning"
goto "checkserverready"
#camerapositioning
_cam1 camsetrelpos [0,a,e]
_cam1 camcommit 0
~0.001
logiccomplete = false
?camend : goto "finish"
goto "start"
#finish
_cam1 CameraEffect ["TERMINATE", "BACK"]
CamDestroy _cam1
exit
8)