Jump to content


  • Content Count

  • Joined

  • Last visited

  • Medals

Posts posted by jwllorens

  1. 2 hours ago, x3kj said:

    According to whats in the changelogs... i assume the hitpoints are already balanced for heat simulation via submunition, but the submunition for HEAT isnt implemented yet fully in the branch.


    Which is wierd, because in my tests, HEAT is more effective against medium and light armor than either HE or APFSDS.


    I found during the campaign too, when you are on the last mission and fighting loads of Rhinos, HEAT rounds can knock them out in one go while APFSDS seems to get eaten by slat armor or reactive plates. 


    Slat armor and reactive plates should be more effective against HEAT, no?  Only marginally effective against kinetic penetrators?

  2. I know it is pretty late in development, but what are the chances of getting a few more bits of functionality for munitions?


    Specifically, in real life, the MRLS fires GPS guided missiles, usually with unitary warheads now that can be detonated in an airburst mode.  In real life, the airburst detonation is one of the coolest explosion effects out there. Any chance we could get something like this in game?  The missiles on the sandstorm should be a lot more accurate to simulate GPS tracking, and switching fire modes could switch between airburst (larger indirect damage radius with lower damage lethal to light vehicles and infantry) or impact modes (smaller indirect damage radius with higher damage to armored vehicles or perhaps buildings too.)  It would also be really nice if we got a few extra magazines that we could swap out via script, such as one with cluster munition dispensing missiles (to simulate the cluster missiles that are currently being phased out of the U.S. arsenal in favor of the unitary warheads due to concerns about collateral damage and submunitions.)  Should be doable with the recent functionality improvements to submunitions, fits with the theme of the Tanks DLC, and gives a bit of a throwback to the theme of the Orange DLC.


    It would also be really nice to see proximity fuzes represented in the game.  Impact fuzes on anti-aircraft cannon shells haven't really been used since the 40's in any substantial capacity.  It would be really cool if the Cheetah and Tigris 35mm guns fired shells that detonated when in proximity to a nearby vehicle.  


    Another thing I would love to see is airburst functionality with a rangefinder for some munitions.  I'd love to see this on various HE ammunition, anything from 25mm (stationary GMGs) to 30mm and 40mm (such as the Gorgon or Marshall) all the way up to 105, 120, and 125mm HE tank shells.  The way it would work would be simple.  Press F to change the fire mode to airburst, laze a target, then fire.  The shell would detonate just a meter or so beyond the range that was lazed.  Would go a long way to simulate the real functionality of the 25mm GMG and would really fit in the armaverse.


    The final thing that I would like to add is PLEASE fix 20mm HE rounds.  These things have pretty much zero indirect hit damage and terrible penetration, as another poster already pointed out.  A 12.5mm is more effective at killing light vehicles and infantry in game. 

    • Like 2


    All that aside, I would have liked to have seen the mine dispenser work as the flip slide of the UXO/mine coin, as a strategic area denial option that requires more work and direct player interaction to use, but in the theme of the DLC provides an option that is much less indiscriminate and safer for noncombatants than traditional landmines that are lamented over by the main characters in the story (for good reason).  Plus, I really want some airburst functionality in this game.  There are already weapons in the game that are weak representations of their real-life counterparts due to the lack of airburst functionality, like the XM307 static grenade launcher that is in the game.  

  4. It looks like the mine dispenser is based on the M7 Spider networked mine in the US arsenal.  However, it really doesn't work like it would in real life.  A gadget as sophisticated as this, or at least as it looks in-game, shouldn't disperse mines like that.  In real life, the M7 spider, which looks VERY similar, detects enemies via tripwire and a man-in-the-loop can then tell the spider to launch an air bursting grenade in the direction of the victim.  It specifically works this way so as to AVOID the limitations and dangers of traditional landmines, however the one in the game is the opposite.  While it looks new-age and advanced, it is the most dangerous and controversial weapon in the game other than the cluster bombs because it scatters so many indiscriminate mines, and would be even more dangerous to noncombatants years after the war than a single well placed older generation bounding mine.  


    For the mine dispenser, it would be very cool to see it work more similarly to how it does in real life.  The dispenser would then instead be a UAV controlled by the UAV terminal.  Unlike most UAVs though, it would not have a functional camera, and instead, opening the AV camera while not directly controlling the dispenser would bring up a sort of "radar" centered on the dispenser that would highlight any soldier or vehicle that crosses into its lethal arc as a blinking red dot.  Firing the dispenser would be accomplished through an action in the action menu, which would lob a grenade in the direction of a random vehicle or man within its lethal radius (with a high arc) that would airburst.  Alternatively, you could set the dispenser to be autonomous and then it would automatically fire on ANY man or soldier that walks into its lethal arc after a short delay, because in autonomous mode it becomes indiscriminate like a normal landmine, and the player would then have to deal with the consequences of that choice to use it in this mode.  


    The dispenser would then provide a tactical area denial option that is unique from other mines in the game in that it is not a hazard to civilians if used correctly, but requiring a man in the loop. 


    That would be a lot of work though.  Another alternative is to simply put a self destruct timer on the mines it creates, having them detonate automatically X minutes after they hit the ground and arm themselves.  15 minutes should be fine.  This would also be nice for use of the dispenser in multiplayer PvP games, from a performance perspective.

  5. Just now, road runner said:

    Well technically if you carried the round, you're still the same weight loaded or unloaded, the overall mass remains the same, what does happen is the gross weight of the weapon increases, once loaded, same with any weapons platform, if you're carrying for example the AT weapon and 2 rounds, your gross weight shouldn't change if you load a round into it, the weight is still on your person, however as soon as you fire, you should be 3KG's lighter or whatever the weight of the round was, as that's no longer on your person.

    The players gross weight shouldn't change at all until you remove an item/ammo etc. What might be happening here is that an algorithm might be trying to compensate for the increase in the WEAPONs weight, but to do this, which makes sense when you think about it, it's adding to the players overall weight as well.


    I get all that.  I'm just saying that if I am lugging around a couple hundred lbs of missiles and a launcher, I'd imagine that it would be easier to do so if most of that weight was in a backpack rather than a metal tube with sights and handles and whatnot poking out of it, slung over my shoulder.  I'm just saying that if the encumbrance system represents how easy it is for the character to move about rather than how much weight he is carrying, then it isn't that big of a bug and could even be a feature.  


    My point is that trying to carry 50lbs of 2"x4"s while wearing a swimsuit would be harder than carrying 100lbs of fishing weights while wearing a backpack.

    • Like 1

  6. 2 minutes ago, jarrad96 said:

    @jwllorens - It's the reverse, you are heavier when loaded, not unloaded. 


    I think that is what I said.  Heavier when the tube has a missile in it.  Not as heavy when the tube is unloaded, and the missile neatly packed in a backpack.  Or, instead of heavy, "unwieldy."  But I've never carried a pack full of missiles nor a launcher, so I dunno.  I suppose I'm just fishing for a reason why gaining load equivalent to half the weight of a missile after loading it into the launcher doesn't bother me.

  7. I REALLY hope it is a revamp of the high command (and commanding system in general).  


    A "new perspective" could easily be the perspective of a commander.  


    I'd love to see a high command that we can hook into with scripts, and is more streamlined and functional.  Commanding AI to board and unload from helicopters and whatnot should be easy and fast.  Commanding stationary gun teams to unpack and point a gun in a certain direction.  Commanding artillery to fire.  A better waypoint system that allows us to input waypoint parameters before placing it down, and some stronger and smoother waypoint functionality.


    Imagine a high command where you could tell a rifle squad to load up into a helicopter, tell the helicopter to land on the far side of a forest and the rifle squad to disembark, then have the rifle squad move up to a treeline outside of a village and wait while a mortar squad sets up somewhere, and then queue up waypoints to have the mortar squad fire some rounds into the villiage at a specific time of day, and have the rifle squad move in 40 seconds after.  


    I would LOVE this.  


    I wouldn't be mad about more naval assets though.  Some fast attack craft would be nice, naval artillery in the form of mortars, anti air, ect.  Landing craft would be cool with the new vehicle in vehicle transport.  Nothing huge, we don't need destroyers, that would just be silly given the map sizes.  But some gun boats larger and more varied than what we have would be cool.



    Personally, I hope it is NOT VR.  I don't care how cool it is, I wont pay out the ---- to wear something on my face while I play.  I'll be skipping that DLC if it is VR, and I think the VR community is still a minority of players, so from a business standpoint it doesn't sound smart to dedicate resources to that.  I hope its not VR....

    • Like 4

  8. All of this is very cool.  I really want to see this new tech used to broaden the gameplay of various vehicles, not just jets.  Specifically, I would love to see more variety in missile guidance, both from shoulder fired weapons and from vehicles.


    Shoulder fired missiles:

    -For gameplay reasons and balance, it would be nice if the NLAW functioned more like the M47 Dragon and was SACLOS guided.  NATO doesn't have a light anti-tank weapon that is comparable to the RPG, so it would help from a balance perspective to ditch the fire and forget capabilities of the NLAW in favor of SACLOS. It would also diversify the gameplay by having an anti-tank weapon that has to be guided with SACLOS, as there is little reason to use the SACLOS functionality on the Titan AT when you can just lock on and let it loose.

    -A top-attack mode would be amazing for the Titan AT.  If this weapon is analogous to the FGM148 Javelin, it would be very cool if we could lock on to and do a top attack on any point aimed at in the game world with the Titan AP missile as well.  The Javelin can lock on to much more than just vehicles, and can be used to target structures and more.  Call of Duty was the last time I saw this type of functionality, but it really would have a place in a game like ArmA where its tactical use could be realized and enjoyed.


    On the topic of RWR and warnings:

    -ARH and SARH are the easiest types of guidance to detect, as they require only a radar receiver on board the vehicle to pick up the targeting signal.  Both requires that either the missile or firing platform "illuminate" the target with a radar emitter, which makes it easy for the target to know when they are being targeted.  (SARH is much more common than ARH, so I would love to see aircraft having to maintain a lock on a target to guide a missile in to a kill while the target tries to ditch the lock by dipping lower or dumping chaff).

    -Laser guidance is also fairly easy to detect, though I am not sure the tech in ArmA exists to implement any sort of warning that your vehicle is being lased or there is an enemy laser marker nearby.  This requires another dedicated sensor (LWR), however. 

    -IR, non-laser guided SACLOS such as wire guidance, contrast seekers, and Passive Radar homing threats are much harder to detect.  These guidance types do not require any signal to be emitted, and incoming ordnance with these guidance types must be detected with some sort of on-board sensor.  Modern active protection systems often use some combination of auditory and radar sensors to detect the noise when the weapon is fired and radar to track the trajectory.  Of course, these weapon types have a smaller radar cross section, so they would be detected far later (at a close distance) than non-stealth aircraft (a high-flying Orca, for example.)  


    I guess the best way to do this is to lump in detection of IR missiles with "passive radar" detection.  It isn't unrealistic to assume that any vehicle with IR missile detection will also detect radar emitters.  


    AI and countermeasures:

    -AI should drop flares and chaff not all at once and immediately when a missile is fired, but in bursts at short intervals once the missile is detected depending on the above factors.  Each flare dropped should have a chance of distracting the missile, depending on the missiles resistance to countermeasures (this chance would apply to players as well).  


    GPS guidance:

    I would really love you guys if some sort of GPS guidance was implemented in the game.  Hell, it could even be implemented through the in-game map and marker system fairly easily.  If the player has a GPS or is in a vehicle equipped with GPS, then when placing a marker on the map a new marker type option is available called "GPS Marker" with a unique icon.  Unlike other markers, these would not be shared across the current radio channel and players would have to verbally communicate coordinates to other players with a GPS.  Then, with a GPS guided weapon equipped (some bombs or artillery rockets/shells) the player could tap "R" to flip through the GPS markers and soft-lock on to them, and they would be labelled in 3D on the HUD with the text given to them on the map so you could identify which is which when flipping through them.  It would be great to see this on the self-propelled guns, the Scorcher, and maybe on some bombs included in the jets DLC.  Simply aim at the marker until you get a solid lock, release the bomb or fire the rocket, and you will get pinpoint accuracy.  


    New jet loadouts:

    -I know you guys aren't planning on having a way to adjust a vehicle loadout on the fly, but it would be cool if some new weapons were included for these vehicles and the vehicles were included in the game as new assets, just with different loadouts.  The Buzzard AA and CAS versions are examples of what I am talking about.  With the GPS system I mentioned before, these could be included on a more bomb-heavy loadout for the Wipeout and Neophron.  There could also be a more missile heavy loadout for anti-armor missions, and the existing loadouts would best be described as multirole.  Assuming the new DLC jets are fighter craft, they could have AA, CAS, and multirole loadouts as well.  

    -It would also be great if addWeaponTurret worked better on aircraft and the weapon's ammo were visually represented.  For example, if you try to move the DAR missiles on the Falcon UAV from the gunner seat to the pilot seat (because the Falcon AI doesn't work) then you lose the CCIP and the rocket pods don't visually appear to have rockets in them.  With a wider variety of weapons in the Jets DLC, this could be used to great effect by players to design their own custom loadouts in missions.  




    I know it is a lot, but I love this game!


    Off topic, but it would be really nice to get a different version of the artillery computer as an option in the difficulty settings for the scenario, instead of a point and click map, it would open a window where we could input coordinates, select an ammo type and propellant load from those available on the vehicle, and it would give an azimuth and elevation.  The current artillery computer is frustrating if you want a scenario with artillery and want to use the built-in radio spotting, because artillery targets come up as targets that you just click on and there is no player communication.  Alternatively, you can turn off the automatic marking of enemies on the map to encourage communication, but then the communication required just to engage infantry becomes a bit much for players like me that are more casual.  An optional more hands-on artillery computer is a solid middle ground.

    • Like 5

  9. Ive been trying several ways but none is working.


    This is what im working with now:


    _pos = GetPosATL p1; (p1 is the units name in editor)


    It seems to work, however the icon of the player and name changes. So it doesnt show what role the player has, or their name just the "SE of ..." thingy.

    Any way to adjust the height while still keeping the spawn working as before?


    I don't know if this is helpful, but I use this to create a variable in the object namespace of the player object when they respawn.  This variable contains the string which is identical to the string that is displayed by the "role" that they selected in the respawn screen.  


    I use this to create roles like "pilot" with the BIS default respawn screen and enforce other custom restrictions such as only allowing pilots to get in the driver seat of aircraft.


    You may be able to look at the respawn functions in the functions viewer in the editor and find some important variables, and use those in a function similar to this to get a reference to the player object that the respawn position is on, and then setPos the respawning player after they spawn to a more suitable location.

    params [
    ["_unit", objNull, [objNull], 1]
    _rList = uiNamespace getVariable (["BIS_RscRespawnControlsMap_ctrlRoleList", "BIS_RscRespawnControlsSpectate_ctrlRoleList"] select (uiNamespace getVariable ["BIS_RscRespawnControlsSpectate_shown", false]));
    _rName = _rList lbText (lbCurSel _rList);
    _unit setVariable ["JWL_respawnRole",(toUpper _rName)];

    I call this function from onPlayerRespawn.sqf, and pass the new unit ("_this select 0" in onPlayerRespawn.sqf) as the only parameter.

  10. That isn't really what "switch do" is for. 



    Try using setVariable to set a missionNamespace variable to either 1 or 0.


    On your keypress, retrieve the variable, then do one of two things.


    If the variable is 0, then run the script and set the variable to 1.


    If the variable is 1, then set the variable to 0.



    In the script itself, I am assuming it is already a loop, so in the loop check the variable as well.  If the variable is 0, then abort the script.  You could do "if ((missionNamespace getVariable "myToggle") == 0) exitWith {terminate _thisScript;};" 

  11. If you want to accomplish something like this and you are new to scripting, then your first step is to break down what you want to do into the smallest individual tasks you can.


    In your case, you want runway lights to turn on and off in sequence.


    So break that down.  What do you actually need to tell the ArmA engine to do in order to accomplish that?




    Well, the first task seems pretty obvious to me.  You need to obtain references to the objects (the runway lights) themselves.  You can't do anything to them if you can't reference them.  Then you need to organize them by distance to the end of the runway.  Then you need to calculate a time to toggle whether they are on or off based on their distance from the end of the runway.  Then you need to toggle whether they are on or off at this calculated time.




    Start with the first task.  Do a little research about nearEntities, nearestObjects, and other similar commands on the BI wiki and choose one that you think is most suitable for returning a list of runway lights.  (hint: you need to find out what the class names of the runway lights are to pass to the command (dig around the 3DEN editor for runway lights), runway lights are probably NOT considered "alive" (but they might be so don't write off a command alltogether!), and you are going to want the runway lights to be ordered from nearest to furthest in the list returned by the command (but remember you can sort the list by distance if the command doesn't do it automatically if you have to)).



    Do that, and then you can actually start trying things.

  12. I realized that rarely would you need the most prolific element in an array without needing all the elements that were considered but rejected.  Rather than repeat the task of isolating all unique elements in the array, I took a look at my function and poked around to see if I could re-use the results of some of the operations that were performed for finding the most prolific element in order to also return the unique elements that were not the most prolific.


    Why?  For example, if you need the most prolific element to do some task (choose one of many markers and change the color to indicate that the region is "active", in my case) then you would also need all the elements that were rejected in order to iterate through them and ensure that they do not need to have their color changed back if they were previously active.


    So I adapted the function to return an array in the following form:




    where _arrayOfAllOtherElements contains only unique values from the original array passed to the function that were also not the most prolific element.

    params ["_array"];_elmts = [];
      _elmts pushBackUnique _x;
    } count _array;
    _elmts2 = _elmts apply {
      _y = _x;
      [({_y isEqualTo _x} count _array),_y]
    sort _elmts2 false;
    _mCom = (_elmts2 select 0) select 1;
    _lCom = (_elmts - _mCom);

    I don't know.  It "looks" fast, it is just a few lines of code.  


    But it does use two loops, one of which is n^2 (ouch).  Could have scary overhead if you pass it a huge array.  For my purposes I will be passing it an array that is equal to the number of players on the server.  So it will run one loop equal to the number of array elements passed to it, and another n^2 loop equal to the number of unique elements in the array times the number of elements in the array that was passed to the function.

  13. I have an array of strings, eg:  ["tskATK_LumberYard_WEST","tskATK_DieselPlant_WEST","tskATK_LumberYard_WEST","tskATK_LumberYard_WEST","tskATK_TempleRuins_WEST","tskATK_DieselPlant_WEST"]


    I need to return the string that appears most often in this array.  Is there a command to do this?  Or a fast way to do this?


    In the above example, I would need it to return "tskATK_LumberYard_WEST" because this string appears three times in the array, which is more than any other string appears in the array..

  14. _LampList = nearestObjects[BaseCargoHouse, [
    ], 600];
    _hitpoint = 0.97;;
    _switch = missionNamespace getVariable "Lamp_var_OnOff";
    if (_switch == 1) then [{
          _hitpoint = 0; 
          missionNamespace setVariable ["Lamp_var_OnOff",0,true];
          missionNamespace setVariable ["Lamp_var_OnOff",1,true];
    		_x setHit ["light_1_hitpoint", _hitpoint];
    		_x setHit ["light_2_hitpoint", _hitpoint];
    		_x setHit ["light_3_hitpoint", _hitpoint];
    		_x setHit ["light_4_hitpoint", _hitpoint];
    } forEach _LampList;

    I would recommend you do your "nearestObjects" line once at server initialization, and store the result in a missionNamespace variable.  Then, use remoteExec from the server to all clients to add the action to turn the lights on and off.  Then, within each addaction, the addaction code should be written to remoteExec to the server and will run on the server.  


    So let the server do the work, just have the addaction itself be client side, but the code in the addaction gets run on the server.  Then you keep all your variables local to the server (false in the third parameter for setVariable command), and you dont have to run nearestObjects every time which is a pretty expensive command.

  15. you can use some defensive programming techniques, sanity checks and holding a copy of the variable as private variable, to protect mission-critical variables from unwanted interference. 


    The main weakness with randomized variables is detection in BattlEye publicvariable.txt, and worrying about the few who can bypass battleye/antihack isn't worth the trouble IMO. Once they're "inside" and manipulating memory and variables, is a waste of time to protect against.



    Interesting but I am not sure I understand.  I have never hosted a server before.  I did some digging and it looks like battleeye blocks publicVariable except when it is used on the exclusions listed in publicVariable.txt.  Which means this is pointless anyways because you can use battleye to block publicVariable.


    Anyways, the randomized variables should be completely local so why would battleEye need an exclusion for them if the intent is to hide them from publicVariable?


    Also, do you have any good links that discuss usage of these filters and how battleeye works?

  16. If you are going to that extent you should use cfgFunctions


    Its a one off function that compiles three other functions.  If I defined the other three functions through cfgFunctions, they wouldn't be randomized now would they?  The point is that it uses format to create a string with some random elements (but that random element is shared across the three functions) and then compiles the functions.  To my knowledge, I cant create a string on the fly and then compileFinal the string into a function when registering it to the functions library.  The "backup" variables would have some hard coded value appended to their names and anyone could de-pbo the mission, look up that value, and circumvent the whole system by publicVariable'ing that backup variable instead. 


    The point is that the actual function code itself for all three functions is dynamic and will be different during each mission.  By having functions with code that changes itself at the start of each mission, I don't have to store that little randomized string anywhere and risk it getting publicVariable'd by a hacker, which would allow the hacker to override the randomized number with his own number and henceforth overwrite any other server variable.


    I'm not worried about it being an execVM.  The script is only ever run once and only on the server, one little execVM isn't going to hurt and since I am only running it once there is no reason to load the script into memory as a function and keep it there if I am never calling it again.  As for the three functions that the script compiles, well, they work just as if they were in the functions library, and once the functions are randomized and then compiled, they stay in memory waiting to be called.

  17. Want fairly random strings? use toString with rounded random numbers.



    I came up with a solution that I think is probably better.  


    I execVM this code from initServer.sqf

    _nums = [];
    _nums resize 10;
    _nums = "_" + ((_nums apply {str (round (random 9))}) joinString "");
    _fnc = format ["
      params [""_varName"",""_value""];
      _var = missionNamespace getVariable _varName;
      if (isNil ""_var"") then [{
        missionNamespace setVariable [_varName,(+ _value),true];
        missionNamespace setVariable [(_varName + ""%1""),(+ _value),false];
        _varName addPublicVariableEventHandler {
          missionNamespace setVariable [(_this select 0),(+ (missionNamespace getVariable ((_this select 0) + ""%1""))),true];
          diag_log format [""WARNING: JWL_fnc_createVariableSecure: Attempt to override variable name """"%2""""."",(_this select 0)];
        diag_log format [""ERROR: JWL_fnc_createVariableSecure: Variable name """"%2"""" already in use."",_varName];
    JWL_fnc_createArraySecure = compileFinal _fnc;
    _fnc = format ["
      params [""_varName"",""_value""];
      _var = missionNamespace getVariable (_varName + ""%1"");
      if (isNil ""_var2"") then [{
        diag_log format [""ERROR: JWL_fnc_setVariableSecure: Variable name """"%2"""" is not a secure variable."",_varName];
        [_var,_value] call JWL_fnc_setArrayData;
        missionNamespace setVariable [_varName,(+ var),true];
    JWL_fnc_setArraySecure = compileFinal _fnc;
    _fnc = format ["
      params [""_varName""];
      _var = + (missionNamespace getVariable (_varName + ""%1""));
      if (isNil ""_var"") then [{
        diag_log format [""ERROR: JWL_fnc_getVariableSecure: Variable name """"%2"""" is not a secure variable."",_varName];
    JWL_fnc_getArraySecure = compileFinal _fnc;

    So basically, this creates three functions that are read only, and at initialization they are randomized a bit.  


    JWL_fnc_createArraySecure is the function I use to initialize a global variable using this framework.  It creates a pair of missionNamespace variables.  One is simply given the name specified in the parameter, and the other has a randomized string appended to the name.  This randomized string is randomized at mission initialization and then hardcoded into the functions themselves, and is not stored anywhere but in the function (and of course the variable names themselves once they are created).  The variables are copies of each other, and not pointers to the same array, so changing one will not change the other. When that public variable is overwritten by the publicVariable command, the event handler takes the array in the randomized local variable and copies it to the public variable, thereby overwriting any changes made to it by publicVariable.  Then it logs a warning to the RPT file.


    JWL_fnc_setArraySecure allows me to set individual elements in the array, even if the element is nested.  It takes parameters in this form:

    [_varName,_data] where _varName is a string that references the global array, and data is an array of elements.  _data would look like this [[_value1,_path1],[_value2,_path2],[_value3,_path3]].  Each path is in the form [_index1,_index2,_index3].  It works by getting a pointer to the array in the local randomized variable, editing the array through the pointer, and then copying the array over to the public version of the variable and broadcasting the public array.


    JWL_fnc_getArraySecure simply retrieves the data from the global array and returns a copy of it, which I use whenever I am working with the data and changing it but do not want to override the array (I have some functions that get these arrays which contain all sorts of stuff, and then strip off some data that I don't need and organize them for other purposes).  This one only really protects the array from changes made locally and makes it easier to see in my code when I am copying or pointing to the arrays, because I don't want to accidently alter a global variable or the randomized backup variable without changing both at the same time.


    the same principle could probably be applied without the deep copies, I'll have to test and see how publicVariable works with that.  






    But as I said before, is there even a point to doing this at all?  

  18. Thanks for trying to help, all.


    But frankly, this is not helping! I would benefit from examples, for one thing. Let me be more clear about what I don't understand and what might help.


    Say I want to put a trigger on the map to detect BluFor Present. Let's skip the fact that triggers on the map have their own sets of problem for now. And when the trigger conditions become true, I want to run a script called myScript1.sqf. It has no arguments. How would I script that with remoteExec?


    Another example, I want to addAction to an object to hide it (aka run a script that makes it drop into the ground then deleteVehicle's it. I'm thinking it's better to put the code in the initFramework.sqf rather than in the init box of the object - would there be a difference in how remoteExec would be used there? How would I code it if the script is called hideObject.sqf?


    Let's just start with those examples. I'm sure I'll have questions after seeing the syntax!


    Thanks in advance for the help!



    Ok, well as for the trigger, it depends what you want to do with the script really.  Do you want the execVM script to fire ONLY on the server when the trigger is activated?  Or do you want it to fire on every client and the server?  It all depends on what you are trying to accomplish, as there are many ways to go about it and the nature of what you are trying to do will guide you to the best solution.


    In general, unless you are only doing things to the player's UI, or making some hints pop up, or something else that is super client-local and relatively simple in your execVM script, then you probably only want the trigger on the server.  Then from the execVM'ed script you can remoteExec any little local stuff to the clients if you have to, but most of the script probably should run only on the server.  So, in the 3DEN editor, tick the little box in the trigger's property window that says "server only."  This will prevent a copy of the trigger with the same parameters from being created on every client at mission initialization, and therefore prevent your script from firing on every computer.  Then just put execVM "myScript.sqf"; into the on Act box of the trigger.


    As for how to use remoteExec.  Well, I have an example that I will show you for something I am doing in my mission.  It is a little long and there is a lot of other stuff going on, but just bear with it and see if you can make sense of what is happening.

    //start setting up all the objectives.{
      _area = _x;
      //Create readable name from variable name by inserting spaces
      _name = _area call JWL_fnc_spacer;
      //get the flag variable, store it, delete global public variable, change texture.
      _flag = missionNamespace getVariable ("JWL_areaFlag_" + _area);
      missionNamespace setVariable [("JWL_flag_" + _area),nil,true];
      _flag setFlagTexture "a3\data_f_exp\flags\flag_synd_co.paa";
      //create additional markers to determine activation area and to hightlight the border of each area
      ("JWL_areaZone_" + _area) setMarkerColor "ColorGrey";
      ("JWL_areaZone_" + _area) setMarkerAlpha 0.75;
      _posn = (markerPos ("JWL_areaZone_" + _area));
      _size = (markerSize ("JWL_areaZone_" + _area));
      _rotn = (markerDir ("JWL_areaZone_" + _area));
      _actvMarker = createMarker [("JWL_areaTrgr_" + _area),_posn];
      _actvMarker setMarkerShape "ELLIPSE";
      _actvMarker setMarkerDir _rotn;
      _actvMarker setMarkerSize [((_size select 0) + (paramsArray select 0)),((_size select 1) + (paramsArray select 0))];
      _actvMarker setMarkerAlpha 0;
      _brdrMarker = createMarker [("JWL_areaBrdr_" + _area),_posn];
      _brdrMarker setMarkerShape "ELLIPSE";
      _brdrMarker setMarkerBrush "Border";
      _brdrMarker setMarkerColor "ColorGUER";
      _brdrMarker setMarkerSize _size;
      _brdrMarker setMarkerDir _rotn;
      //create respawn array in form of [[pos1,pos2,pos3],[rIndex1,rIndex2,rIndex3]]
      //make sure that if a respawn point is inside a building, that building cant be destroyed
      _rArr = [];
        _logic = missionNamespace getVariable ("JWL_areaRspn_" + _area + _x);
        if (!(isNil "_logic")) then {
          _lPos = getPosWorld _logic;
          _nBlg = nearestBuilding _lPos;
          if ([_logic,_nBlg] call JWL_fnc_inBuilding) then {
            _nBlg allowDamage false;
          deleteVehicle _logic;
          _rArr pushBack _lPos;
      } count ["_1","_2","_3","_4","_5"];
      _rArr = [_rArr,[]];
      //create secure array with all the data about the area, protected from publicVariable
      [("JWL_areaData_" + _area),[_name,true,independent,_flag,_rArr,[]]] call JWL_fnc_createArraySecure;
      //add capture action to all the flags, make sure JIP = true
      _grbg = [
        (format ["Capture %1",_name]),
        (format ["((_target distanceSqr _this) < 25) && (((JWL_areaData_%1) select 2) != (side _this)) && ((JWL_areaData_%1) select 1)",_x]),
        {[((_this select 3) select 0),(side (_this select 1))] remoteExecCall ["JWL_fnc_captureArea",2];},
      ] remoteExecCall ["BIS_fnc_holdActionAdd",([0,-2] select (isMultiplayer && isDedicated)),true];
    } count _this;

    First thing to note is that this script runs ONCE on the server.


    As you can see, it is one big "count" loop.  So it iterates through all elements in the array _this and then does all the code in the brackets.  _this is an array of strings, such as ["LumberYard","DieselPlant","Airport"].  But once it iterates through all of them the script is done and is discarded.


    Inside the loop, first it saves the current element, eg. "DieselPlant" into the variable _area with _area = _x;  It does this so I can access the current element inside of any loops within the main loop later on, since _x will refer to something else in that case.


    Next it takes the current element and turns it into something I can use later on in the UI, eg. "LumberYard" -> "Lumber Yard".


    Then it finds a specially named flagpole, gets a reference to it, deletes the global public variable, and sets the texture.  The reference to the flag is used later and stored elsewhere.


    Then it sets up a bunch of markers and junk which I use in the mission for some other stuff, but markers created with createMarker are global so changes made to them on the server show up everywhere.  


    Then it starts up a mini-loop and finds some specially named game logics that I have placed, determines if they are in a building and if so makes the building invulnerable, and then creates an array with each of their positions in it and deletes the logic afterwards.  This is just to permanently store the positions at the start so I can dynamically create respawn points on them in the mission.


    Now, finally, we get to the remoteExecCall part.


    this part:

      _grbg = [
        (format ["Capture %1",_name]),
        (format ["((_target distanceSqr _this) < 25) && (((JWL_areaData_%1) select 2) != (side _this)) && ((JWL_areaData_%1) select 1)",_x]),
        {[((_this select 3) select 0),(side (_this select 1))] remoteExecCall ["JWL_fnc_captureArea",2];},
      ] remoteExecCall ["BIS_fnc_holdActionAdd",([0,-2] select (isMultiplayer && isDedicated)),true];

    It looks scary, but all it is doing is executing the function "BIS_fnc_holdActionAdd" on every client, including JIP players.  BIS_fnc_holdActionAdd must be executed locally on the client that you want to have the action, so I have to remoteExecCall the function from the server to get it on to every client.  Lets turn all the crazy parameters into one variable name so it is easier to see what is going on.

    _grbg = _holdActionParamsArray remoteExecCall ["BIS_fnc_holdActionAdd",([0,-2] select (isMultiplayer && isDedicated)),true];

    Ok, now that all the parameters for "BIS_fnc_holdActionAdd" are referenced by the array _holdActionParamsArray we can see what is happening with remoteExecCall a little better.


    First off, _grbg is the return value of remoteExecCall.  If JIP is set to true in the command, it will return the JIP ID of the command in the JIP queue.  This is not important to me because I don't need to ever manually remove this from the JIP queue using this ID, so I named this variable _grbg.  However, for some reason I get script errors without catching the return value in a variable when JIP = true, so I have to include it.


    Alright, look at the array after remoteExecCall.  The array before it are the parameters passed to the function called by remoteExecCall, but the array after it consists of three elements that are the parameters for the remoteExecCall command itself.  


    "BIS_fnc_holdActionAdd" this is the function that will be executed on the target machine


    ([0,-2] select (isMultiplayer && isDedicated)) is the ID of the target machine.  In this case, it will resolve to 0 in most cases and execute "BIS_fnc_holdActionAdd" on every machine on the network.  However, only if the mission is run in multiplayer in a dedicated server it will resolve to "-2" and execute "BIS_fnc_holdActionAdd" on every machine but the server.  This is a good way to always execute your function on every machine that has a player behind it no matter whether you are playing singleplayer or multiplayer.


    true simply tells remoteExecCall to add the function to the JIP queue.  This means if a player joins the mission after it has started, they will immediately run "BIS_fnc_holdActionAdd" on their computer.  


    So you can see that I am using remoteExecCall here to execute "BIS_fnc_holdActionAdd" on every player's computer, without running the entire setup script anywhere but the server.



    Now, lets go back to _holdActionParamsArray.  The array itself is not important, it is just all sorts of parameters for "BIS_fnc_holdActionAdd."  However, one of the parameters is a code block that is executed locally on the machine when the hold action is completed.  So when a player holds spacebar and the action finishes, it runs this code ONLY on that player's computer.  Well, I have another remoteExecCall in there too.


    This is the specific parameter.

       //.... a bunch of params
        {[((_this select 3) select 0),(side (_this select 1))] remoteExecCall ["JWL_fnc_captureArea",2];},
       //.... a bunch more params

    "JWL_fnc_captureArea" is a function that I wrote that I only want to execute on the server.  But the code in this parameter is executed only on the local client that used the hold action.  So here I use remoteExecCall again to run a function on a server from a client, the reverse of what I did before by adding the hold action to every client from the server.


    The parameters I am passing to "JWL_fnc_captureArea" are in front of remoteExecCall.  


    The parameters I am passing to remoteExecCall are again behind the command.


    Once again, the first parameter is the function I want to run on the remote machine, in this case "JWL_fnc_captureArea"


    The second parameter is again the target machine, in this case, it is 2, which means the server.  So this will execute on the server machine whether the server is a player, a dedicated server, or even your own computer if you are hosting.


    In this case, JIP is not important, so I left the third parameter blank and it will default to false and not add anything to the JIP queue.  

  19. So the whole whitelist thing with remoteExec is cool, and we can prevent people from executing anything but functions we have pre-defined on remote machines.


    Even though we can stop someone from executing this code on remote machines, how about players executing commands locally with global effect?


    Say there are some important global variables on the server that are not made public and are used for keeping track of things like "money" that each player has to spend on vehicles and whatnot.  How do we prevent clients from using publicVariable to broadcast a new value and overwrite the variable on the server?  I also have some variables that are critical to the mission actually working, and if someone publicVariabled something with the same variable name and overwrote the variable on the server it would all come crashing down.


    well, here is my approach, but it seems inefficient.  I don't even know if this is necessary.



    I am doing this only on the server during initialization to create a randomized string and store it in parsingNamespace so that it is protected from publicVariable.  

    #define _nums ["1","2","3","4","5","6","7","8","9","0"]
    _keyCode = "_";
    for "_i" from 1 to 10 do {
      _keyCode = (_keyCode + (selectRandom _nums));
    parsingNamespace setVariable ["JWL_keyCode",_keyCode];

    then when I initialize the variables or later need to retrieve them or set them, I just do this:

    missionNamespace setVariable [("MyVariableName" + (parsingNamespace getVariable "JWL_keyCode")),_someValue];
    //or this to get it
    missionNamespace getVariable ("MyVariableName" + (parsingNamespace getVariable "JWL_keyCode"));

    I don't have to call get or set very often as most of the variables are arrays and I can just keep a reference to them as a local variable in the script and alter them from there, but I can access it from other scripts if needed.  


    So I guess the idea is that all these variables have names with this randomized string appended to it, and only the server knows what this string is, so you can't really overwrite the variables without knowing this string.  So even if you looked at the script, you wouldn't have a way of knowing any of the variable names because they are randomized when the mission is initialized.  


    Since none of the variables with randomized names are ever broadcast to the clients, there wouldn't be a way for clients to get the randomized string at runtime either.  Instead, if the variable needs to be broadcast, a copy is made without the randomized name and that is broadcast instead.


    So I guess nobody could wipe variables critical to the mission scripts working, or set the variable that contains their current amount of money to 4 trillion or something.  




    Am I just wasting my own time?  Should I even be worried about this stuff?

  20. I personally don't bother too much with the security stuff of remoteExec, I've only encountered 3 clowns that did anything malicious to a server, most of those back before battleye security was strengthened further with the launcher.  I've got more pressing problems to worry about in my mission rather than setting up a complex list of what clients can't/can do. Regardless it can be useful if you feel your mission needs it, everything else you need to know is explained above.



    Depending on how you set up your scripts, it can actually be very easy.


    Since the server can always remoteExec anything regardless of what is in description.ext, you really only have to whitelist the stuff that clients will be remoteExec'ing to the server or other clients. 


    I only have four functions whitelisted.  3 are BIS functions required for some some of the init scripts to work in multiplayer and the last one is mine.  Most of my scripting happens on the server and rarely to clients need to actually send anything to the server.

  21. Don't worry about using BIS_fnc_MP anymore.  BIS_fnc_MP used to be a purely scripted way of executing code on remote machines, but as mentioned above, it lacked security and was slower than a purely engine based solution.


    So, BIS created remoteExec.  remoteExec allows the mission maker to directly specify what clients can and cannot do in the description.ext, so you can make sure that nobody is running malicious code on your server or client from their computer.  


    So what happened to BIS_fnc_MP now that we have remoteExec?  Well, BIS_fnc_MP was basically just re-written so that it just calls remoteExec.  There is no point in using it all when writing new code, they just re-wrote it to continue working but use remoteExec because it ensures that all old missions and stuff that used BIS_fnc_MP will still work.


    To use remoteExec, it is really easy.  


    [_parameter1,_parameter2,_parameter3] remoteExec [myFunctionName,_targets,_jip];


    _parameter1, 2, 3, are just the parameters that you want to pass to myFunction.  Note that these parameters are passed as they exist on the local machine that is calling remoteExec, not how they will look on the target machine.  So passing "player" as a parameter in remoteExec will retrieve the player on the local machine, THEN send it over to the target, and myFunction will execute code with the parameter referencing the player back on the machine that called remoteExec.  If, however, myFunction contains something like the "player" command, it will retrieve the player within the function code on the target machine, and therefore player will reference the player on the target machine.


    myFunction is the function you want to execute on the target machine, and pass those parameters to.  You can define functions in description.ext and just call them by name here.  It works with BIS functions too.  This is the easiest way to do this.  note that myFunctionName needs to be a string.  For example, "BIS_fnc_holdActionAdd" with the quotes like that.  


    _targets defines where you want to execute the function.  This is a very powerful parameter.  You can put in all sorts of stuff here to target only the machine you want to run the code on.  Use the number 0 to run the function everywhere.  Use 2 to run the function on the server.  Use ([0,-2] select (isMultiplayer && isDedicated)) to run the code on every machine with a player. You can also put an object in here, and the function will execute where the object is local, or specify a specific machine by using its ownerID.


    _jip is a little complex. I don't really have time to explain it now and don't really understand it myself.

    • Like 1

  22. Alright, I haven't tested this, but thinking through the following script, I am pretty sure this is how it works.

    _variable1 = 5;
    _variable2 = _variable1;
    //_variable2 is now a copy of _variable1.  Any change to either will have no effect on the other.
    _variable1 = "hello world";
    hint str _variable2; //will display the number 5.
    //Arrays are a little different.
    _array1 = [[1,2,3],[4,5,6]];
    _array2 = _array1;
    //_array2 and _array1 are both pointers to the array.  Any change made to either _array1 or _array2 will be reflected by both variables.
    _array1 pushBack [7,8,9];
    hint str _array1;  //will obviously display [[1,2,3],[4,5,6],[7,8,9]]
    sleep 5;
    hint str _array2; //will also display [[1,2,3],[4,5,6],[7,8,9]]
    //we can also maintain pointers to the same array in different scripts, and therefore manipulate data in one script from another script.
    _array1 spawn {
      _array3 = _this;
      _array3 set [0,"Tom"];
      _array3 set [1,"Dick"];
      _array3 set [2,"Harry"];
    sleep 5;
    hint str _array2;  //will display ["Tom","Dick","Harry"]
    //what happens if we start changing the variables?  
    _array2 = "sausages";
    sleep 5;
    hint str _array1; //will hint ["Tom","Dick","Harry"]
    hint str _array2; //will hint sausages.
    //So the array still exists out there, but _array2 no longer points to it.  How can we destroy the array?
    _array1 = nil;
    //The array ["Tom","Dick","Harry"] is now gone and no longer in memory.
    //The array is not destroyed because we set the pointer _array1 to nil.
    //The array is destroyed because there are no more pointers that point to it.
    //What about other methods of getting and setting variables?
    myGlobalVariable = ["cheese","burger"];
    //Now we have a global variable that points to ["cheese","burger"]
    //Lets see what happens if we start passing this global variable around all over the place.
    _myVar1 = missionNamespace getVariable "myGlobalVariable";
    _myVar2 = myGlobalVariable;
    sleep 5;
    _myVar1 pushBack "with";
    hint str myGlobalVariable; //will display ["cheese","burger","with"]
    sleep 5;
    _myVar2 pushBack "pickles";
    hint str myGlobalVariable;  //will display ["cheese","burger","with","pickles"]
    _myVar2 spawn {
      _this set [3,"tomatoes"];
    sleep 5;
    hint str myGlobalVariable; //will display ["cheese","burger","with","tomatoes"]
    missionNamespace setVariable ["myGlobalVariable",["communism","capitalism"]];
    //myGlobalVariable should now point to a different array, in this case, ["communism","capitalism"]
    hint str myGlobalVariable; //will display ["communism","capitalism"]
    //however, our array ["cheese","burger","with","tomatoes"] is not gone, it still exists in memory because we have some local variables pointing to it
    //this is important to note.  _myVar1 and _myVar2 do not point to the myGlobalVariable pointer, they instead point directly to the original array.
    //setting the myGlobalVariable pointer to point at a new array does not redirect variables that were defined with _varName = myGlobalVariable
    sleep 5;
    hint str _myVar1;  //will display ["cheese","burger","with","tomatoes"];
    //but what if we want changes in an array done to an array to be unique to that variable and not reflected in all other variables pointing to the same array?
    //We make a copy of the array
    _myVar2 = + _myVar1;
    _myVar2 deleteAt 0;
    hint str _myVar1; //will display ["cheese","burger","with","tomatoes"]
    sleep 5;
    hint str _myVar2;  //will display ["burger","with","tomatoes"]
    //note that using + makes a deep copy.  Lets examine what that means using some new arrays.  First we will redefine our old variables.
    _myVar1 = [["ham","burger"],["hot","dog"]];
    _myVar2 = + _myVar1;
    _mySubArray = _myVar2 select 0;
    _mySubArray set [0,"tofu"];
    hint str _myVar1; //will display [["ham","burger"],["hot","dog"]]
    sleep 5;
    hint str _myVar2; //will display [["tofu","burger"],["hot","dog"]]
    • Like 1