setVariable – Talk

From Bohemia Interactive Community
Revision as of 07:06, 2 March 2007 by Donnervogel_bi_wiki (talk | contribs) (This would be ideal for FSM scripts if it would work for soldier units)
Jump to navigation Jump to search

setVariable local or global in Multiplayer

Is this variable space local or global in multiplayer environment? If it is local, is there any way to transmit it across to all client in MP environment?

--Feersum 16:11, 19 July 2006 (CEST)


From what I know it is local. Afaik there's no way to transmit it. But remember that this info may change, as ArmA is not yet done. Maybe we can get a statement of Suma here, he should know more...

--raedor 16:14, 19 July 2006 (CEST)

Ok, explicit synchronization would probably be best solution, both from scripting and bandwidth point of view. For purely AI or player-controlled objects this isn't much of a problem even if they cannot be synchronized because all objects are local for either server or client and scripts that are interested in such variables run mostly local to that vehicle. There are however some cases like pilot controlled jump lights in F-27 Fokker paratrooper plane in FDFMod, where pilot could enable red/yellow/green jump light, and other players in cargo would see appropriate jump light textures in cargo area via setObjectTexture. In OFP:R it would require fake animation and scripts that check status of that animation repeatedly, some way of making object variables global would make such cases a lot cleaner to implement (we never got it to work really right :). All it would need then is an EventHandler to catch when object variables are synced... --Feersum 02:57, 20 July 2006 (CEST)
It is local, and there is no automatic synchronization planned. The whole object synchronization on our engine should be viewed as unreliable and non-guaranteed, and synchronizing object variables this way would probably make a lot of confusion. I think we could add some explicit synchronization mechanism if desired, similar to publicVariable. --Suma 19:43, 19 July 2006 (CEST)
I think that a synchronization mechanism is definitely needed. As Feersum already stated, without such a mechanism we would still need some ugly hacks using magazines to set global object properties. And since Multiplayer and the scripting developments on the Multiplayer sector are what kept OFP alive for the longest time, this is of no minor importance.
From the scripter's point of view, there are several possibilities to implement this. One is to keep two different commands: setVariable to set a local property, setPublicVariable to set a public property. Only I guess that this version would be a problem for the engine, since it would require the engine to constantly synchronize public properties, which it seems it isn't made for.
So the second possibility is a synchronization mechanism à la publicVariable, which could handle the matter in two different ways. First, f.i. publicObject object could synchronize all object properties over the net. I think though that this is no perfect solution, since it would be impossible or very hard for the scripter to seperate public from local variables. So, one of the best solutions would IMO be f.i. to create an extended version of publicVariable of such a syntax: object publicVariables ["property1", "property2" <, ...>] which would synchronize the given object variables over the net. Since this doesn't seem to be much different from publicVariable, I hope that it wouldn't be as hard to implement in the engine . . . --hardrock 01:12, 21 July 2006 (CEST)
Yes, the object publicVariables xxxx is exactly along the lines of what I was suggesting. --Suma 17:15, 21 July 2006 (CEST)

In my opinion, they should be by default global or there should be function to sync object local variables across all the clients or we will never get rid of ugly hack like defining "fake" animations to have per-object global numeric variables. Of course that could get very interesting if you transmit unit/vehicle/object references and they are still local for each client...

--Feersum 16:24, 19 July 2006 (CEST)

@MP behaviour: Same here :)

--raedor 16:44, 19 July 2006 (CEST)

I have to correct myself here. This command better stays local. setVehicleInit can be used for global execution of this command (this saves bandwidth performance when you don't want to have the variables public). --raedor 19:18, 19 July 2006 (CEST)
Well, than you'll have a problem when a vehicle is "given" from one player to the other, because the new player doesn't have all the vehicle variables set. So either it should be global, or there should be a way to send all varaibles attached to the vehicle to someone else, like publicVariable but with more parameters. --TeRp 12:26, 20 July 2006 (CEST)
I have to admit a few other things here. First, there might be objectvariables which should be local to the vehicle and even objectvariables which should be global (e.g. like Feersum's light example). Even if setVehicleInit might be a solution to publicate some variables, there still might be variables which the author want's to stay local to the vehicles crew (e.g. the remaining smoke launcher ammo is only important to the crew of the vehicle) but have to be transfered to another client which enters a vehicle. In this case, you need a eventhandler thingy which transfers the valid local objectvariables to the new crewmember, which might be a problem too (how to determine, which of those local variables of the crew is valid?). Another problem with setVehicleInit is that players who have joined in progress (after the setVehicleInit command) do not have the variables set. So all in all, I highly recommend to use a kind of global / local objectvariables thingy which is in some way connected to the object/vehicle and not to a player. local objectvariables get transfered to new crewmembers when they enter the vehicle and can be unset when leaving the vehicle, global variables should be broadcasted to all players when set or when new players connect. --TeRp 13:48, 20 July 2006 (CEST).


I think the main problem we're discussing here is that there is no clean way of handling MP scripts. Over the years people have come up with several different methods to handle the syncronisation of MP scripts across the network, which all have their problems:

  • publicVariable command:
    • Doesn't work with strings or arrays.
    • Requires active waiting (polling) to check when publicVariable was used.
    • Hard to send structured data like values attached to an object. Requires the scripter to implement a whole protocol to get this done reliable.
  • Switches / fake animations:
    • Only works within a certain distance of the model
    • Needs to be setup in the model
    • Only works with numeric values
    • Requires active waiting (polling) to check when a switch was changed
    • Requires the object to be known. Either the object itself needs to start an init script or the script needs to allready know the object.
    • Can't be used to send objects as there is no way to dynamically assiciate new things to the predefined switches
  • Magazines / Weapons
    • Needs to be setup in the config
    • Very limited usage since only the predefined magazines / weapons from the config can be used
    • Requires active waiting (polling) to check when the magazines of an object were changed
    • Requires the object to be known. Either the object itself needs to start an init script or the script needs to allready know the object.
    • Can't be used to send objects as there is no way to dynamically assiciate new things to the predefined magazines / weapons
  • Fired eventhandler
    • Needs to be setup in the config
    • Very limited usage since only the predefined magazines / weapons from the config can be used
    • Can't be used to send objects as there is no way to dynamically assiciate new things to the predefined magazines / weapons that are fired.
  • (something else?)

All of those only work for some situations but not for others. Those problems even led to the development of CoC network services, which is complete overkill in my opinion if you just need to send some structured data across the net in MP.

SetVehicleInit also doesn't work for all cases since it takes a string and you can't send object references that way.

The easiest and cleanest solution I can see is to enhance the publicVariable command to also being able to send strings and arrays (like hardrock also suggested above). To get rid of the active waiting I would also suggest a publicVariable eventhandler that triggers when publicVariable was used (like Feersum mentioned). That way structured and associated data can be sent easily by sending arrays that contain the object and the associated data. The command was meant for MP syncronisation of scripts anyway so I think this would be the best candidate to do exactly that. Everything else would just be adding another workaround to the long list.

For the problem with setVariable , I think the cleanest way would be to require the command only to be executed where the object is local and automatically transfer the settings when the locality of the object changes. That way the settings would allways be consistent and getting or changing them locally wouldn't be a problem with the suggestions for the publicVariable command above. Have it return a boolean to see if it succeeded and you even have a failsave for the rare case when locality changes right between checking for locality and setting variables.

Locality changes aren't that common so net traffic would be kept low compared to syncronizing the data everytime it changes and if someone really needs to set or read the settings non-locally he could do that via publicVariable. --Romolus 14:52, 21 July 2006 (CEST)

The locality changes aren't always voluntary. If the person dropped, say internet connection went down, there is no way to transfer it. Besides, the scripts that use the variable are usually also run only where it was local. Do you want to transfer their state too? And what about other nonglobals that script might be using? What happens when they would conflict with a value local to this instance? I think the most fundamental problems here are related to the fact that we are, after all, producing code that will run on several separate computers, and we have few guarantees. Well, other than that the server stays running and connected, as otherwise it terminates anyway. --MaHuJa 22:54, 29 December 2006 (CET)
A few notes:
SetVehicleInit contains an object reference -- namely this. If you can setVariable to an object, you should be able to SetVehicleInit to broadcast the value of those objects: just try MyObject setVehicleInit {this setVariable ["Barney", 666]}
I'll confess that 95% of the time, I use CoC_NS for its remoteCall function. That said, setVariable combined with setVehicleInit should take care of most of our problems -- but we'll need to test it.
The big question mark is still JIP and how that's going to affect variables. And well, have to wait and see on that one; then do some serious tests. Having done a lot of work with MP registration and synchronisation, it's clear to me that how JIP his implemented will have serious implications for MP scripting, and we can't really give any ArmA advice until we know how JIP works.
But for my opinion, MP scripting needs to be a little "stone-aged" to reduce the amount of abuse you see. using publicVariable to transmit arrays and strings can be dangerous. What happens when someone repeatedly PV's a string that over the course of the game grows to 4kb? Or an array of enormous dimensions? High-level MP scripting commands is not the way to go: the scripter must at least have the opportunity to think about bandwidth management, and as it stands, the few MP commands that are out there, such as CreateVehicle are routinely abused, even by experienced teams.Dinger 16:56, 14 August 2006 (CEST)
That sounds like a perfect argument for engine-level syncronization of properties. Properties should be tagged "syncronizable" if needed. The object's position and other wordly data is syncronized even if it is non-guaranteed. Tagging a custom property should be a possibility. Allow the author to dictate that a certain value should be consistantly updated with other data.
If I say that array [1,2,3,4,5] needs to exist on all machines, it should have, as Suma suggests, simply an explicit capability to be sent when requested. However, if object X has a property that requires constant updating, should it not be done by the engine along with the other data? At some point, the client will get the data and action will be taken appropriately if scripted properly. If the client never gets the data, then that is equivalent to seeing a unit running in place or warping all over. You have far more problems than syncronizing a single property if that happens. Sure you could have abuse of a "syncronizable" property.. but that will always happen with any command and it also provides a way to seperate the "men from the boys" so-to-speak.
Bandwidth should also be a concern at engine level. Why do I need to use low-level commands and write a 30 line function just to send data for every situation I need to send something? Especially when others might be doing something similar within their creations. How can you ever assume bandwidth when a mission is a culmination of unpredictable addons? If someone allows 4kb of data to be sent as a result of their addon/script, then that is their own fault. Why do I need to pay the price? Note: I do agree it would be nice to manage badwidth but the truth is you can only manage what you create and you are at the mercy of everyone else's product you use - let alone other factors like # of people playing in MP --CrashDome 06:56, 15 August 2006 (CEST)
Interesting idea, however things may be not as easy as they look. To avoid enourmous bandwidth usage, it is not possible to synchronize every change in every property. For internal properties like position or animation state error metrics are known by the engine, and as a result the engine is able to prioritize what to send based on those metrics and player position. If some automatic object synchronization is to be added into the scripting, there is no way engine could know this error metrics, and the script would need to provide it somehow. (Error metrics should be some function, which is given old and new values and camera position as an input, and it is responsible to estimate how important the change is). While this is possible, it could cause significant CPU load, which would grow with the number of values registered for synchronization and with number of clients (recipients) connected, as the error metrics needs to be caculated for each of them. --Suma 10:21, 15 August 2006 (CEST)
I'm with Dinger when he sais that MP scripting needs to become more "stone-aged" to reduce the amount of abuse.
I my opinion, the publicVariable command would be the only legitimate candidate to handle syncronisation in MP. publicVariable is the only command that is dedicated to do this without much side-effects. So why is everyone using other stuff to get things done and not just publicVariable?
I think the answer to that is that the publicVariable command is lacking some features that makes it as complicated to use for many tasks so that you'll need CoC_NS (or do your home brew of it), or abuse other commands that seem to do the job. And those lacking features are eactly those:
  • Not being able to send arrays.
    In 99% of the cases, sending just one variable is not enough. Most time you have an object and a property that belongs to the object or a function and arguments for that function that you want to get across the net in MP.
    So in all those cases you would have to script your own network protocol, just to get two variables across that belong together. In all those cases you need to get the same ammount of data across whether you use several publicVariable calls or just send the array via one publicVariable call. So nothing is gained by not allowing to send arrays.
  • Not having an eventhandler to trigger when publicVariable was used.
    To handle this, right now you either have to do active waiting (the @ command) for every variable you want to update, or if you want to make it more efficient, use CoC_NS or your own version of a network protocol.
    This is why things like the fired eventhandler are abused by so many. It's too much of a hassle to use CoC_NS or write your own protocol when there are other commands that seem to do the job.
    Having an eventhandler for the publicVariable command would deal with that once and for all without having any side effects like using the fired eventhandler of an object or similar.
  • Not being able to send strings.
    This isn't really a big thing as most of the time you can get away with using string tables or function-lookup-lists, even in addons since the init eventhandler is broadcasted. But in some rare cases you simply need to send some user input across the net that you can't predict with string tables.
    It has been prooven that it's still possible to send strings, but the methods are far from being efficient. Since those methods are the only way to do it, people will use them to get what they want. Simple as that.
    So again, nothing is gained by not being able to send strings with publicVariable. Only that people use less efficient methods to get it done anyway.
As this list shows, there are allready ways to get around those limitations and they are used. The options are either using CoC_NS or some self written version of it or abusing other commands.
From a programming point of view, it would make sense if everyone would just use CoC_NS, so why not just offer that functionality with the engine and therfor do it in the most efficient way possible?
Adding the 3 mentioned features to the publicVariable command would do the trick for all cases on a low-level basis in the most efficient way.
Automatic syncronisation wouldn't even be needed for things like setVariable, since the variables could be sent via publicVariable only when really needed. Of course this puts the responsibility into the hands of the scripter, but that should be countered by teaching people how to do things properly instead of just limiting the possibilities. This Wiki would be the perfect place to show the correct and efficient use for such a enhanced publicVariable command. Sending 4kb strings and huge arrays isn't needed in most cases, so people just have to be told how to do things instead.
Adding high-level commands like setVehicleInit or adding automatic syncronisation, only makes things more complicated, prone to abuse and most of all: Still doesn't cover all the cases. The setVariable problem is just one example of how MP scripting is one big mess right now, once you want your addons work properly in MP. There are many more and solving this setVariable problem by a special case solution doesn't help all the other cases.
It's not that things can't be done right now. Even things like setVariable or setVehicleInit and getting it all syncronised can be done right now in OFP with CoC_NS. So it's not about how to make things possible, but how to make MP scripting easier to understand, less complicated and more efficient.
And I think all that could be done by adding those 3 features to publicVariable and be done with all the MP scripting problems once and for all. No more weird abusing of other commands and techniques or scripting yourself a third arm by implementing your own network protocol.
Just one command handling it all and having guidelines and how-to's in this Wiki of how to do things with it.
In my eyes, that would be the single most helpfull enhancement to scripting since the first release of OFP (hence the long comments, sorry for that) --rom 11:37, 15 August 2006 (CEST)
OK, I can understand the reason not to automatically syncronize specific properties. However, I still don't understand why the need to include arrays and strings into publicVariable. As having used it to it's limits, I can definately verify that (as Suma said) it is non-guaranteed and unreliable. Why on earth does everyone want to expand on and utilize something such as this? It isn't a question of what it can handle as much as it is a question of how does it handle it. I've used pV to send literally thousands of integers... not because I just wanted to have fun either.. it was to ensure clients had syncronized copies of an inventory at the start of mission so that when they pulled up a menu it didn't kill the server trying to send everything then. It failed. Miserably. On top of that, it took forever because I needed to delay each send. Also, pV sends as a broadcast. So, if there are 5 clients, then you send 5 packets to possibly 4 clients that don't need it. IMO, CoC_NS allowed every possible solution to minimize the CPU and Bandwidth hit at scriptors descretion. Sure they were hacks, but they were far more efficient than pV despite this! So unless pV gets a huge overhaul I refuse to use it. "Stone-aging" the process simply caters entirely to those who don't send as much data as the rest of us(maybe an integer or array here or there) , but it leaves the rest of us to fend for ourselves again. I have alot in store for ArmA that is currently limited by OFP. ArmA's new features opened up most of those limitations, but if there is no CoC_NS equivalent, than I guess it is back to being limited by the engine and not worth working on. --CrashDome 15:49, 15 August 2006 (CEST)

Hellooooo... This is a Wiki, not a forum, in case you people forgot...;)

Let's not get distracted into discussions about what could and should be included in some commands. The discussion pages here should be for settling ambiguities or mistakes in the article, but not to indulge int fundamental discussions like this.

There shouldn't be more information on the talk page than there is on the article page. The talk page shouldn't be required reading for someone who's looking for information.

There is a lot of valuable information here on the talk page now (most of which is going to waste, since people won't neccessarily look on the talk page to find information, and also because these pages are purged occasionally), so it would be good if somebody could summarize all this, and either put it into the article or create a new one that covers this subject in particular. --Kronzky 16:50, 15 August 2006 (CEST)

Much of the information would be better moved into a (more coherent, I would hope) Multiplayer scripting page. --MaHuJa 22:54, 29 December 2006 (CET)

Meaning of setVariable

Is it a way to have local variable to an object, like a real Object Langage (C++, Java...) ? Example:

  Class Myclass
  {
     Attribute1 = ...
     Attirbute2 = ...
     Method1() {}
     Method2() {}
  }

I hope it is, allowed us to attach some special thing to an unique object on map, because the only solution we have today is boolean animation in p3d models.

Can you explain that BI and improve our dreams? :)

--SoldierIsNotHistory 16:49, 19 July 2006 (CEST)

I'm not BI, but with this command you can attach a certain variable with a certain value to a certain object. You can attach a variable with the same name to different objects and with different values. --raedor 19:18, 19 July 2006 (CEST)

Is it comparable with the function fGet- and fSetProperty by hardrock from the mapfact forums? --T_D 11:59, 20 July 2006 (CEST)

Yes. --hardrock 13:46, 20 July 2006 (CEST)

This would be ideal for FSM scripts if it would work for soldier units

Is there a good reason why this feature is only limited to vehicles and does not work for soldiers? I was playing around with FSM editors and found such a feature would be ideal to attach attributes to soldiers in a squad. The main problem of FSM scripting seems to be that every script gets executed for every unit all the time. This function would provide a way to be more selective without running partially very long functions every time to determine if a unit does satisfy all conditions for a certain task. Because seeing how often FSM scripts get executed and that no delays seem to be possible this is extremely CPU hogging with large amounts of units and complicated scripts. Donnervogel 07:06, 2 March 2007 (CET)