dlegion 98 Posted June 29, 2018 hello guys, i'm working on a new and more efficient version of the "bubble around player" script. this time i wish to make it as slim as possible, to keep up performance and make it user-friendly to allow more people use it easily in theyr missions! the idea stay the same: a size-customizable " bubble" around playerS (MP , JIP) that simply spawns and de-spawns selected AI units in a defined range. i really need help with idea how create this. here's part of the code i'm trying to write: playerSarray = []; {playerSarray = playerSarray + [_x];} forEach playableUnits; randomplayer = playerarray call BIS_fnc_selectRandom; randomplayerpos = getPos randomplayer; private _grpDveh = [[randomplayerpos, 5, 25, 5, 0, 0.3, 0,playerspos] call BIS_fnc_findSafePos,independent,10] call BIS_fnc_spawnGroup; // here is the first problem, it works, but actually it consider just 1 player to calculate the spawn distances, i wish it spawn far from ALL players, not just the randomly selected one! thanks for any help! Share this post Link to post Share on other sites
KC Grimes 79 Posted June 29, 2018 Take a look at the Code Optimization page on the biki, which will help with some ideas on how to slim down. You use a forEach to define playerSarray as playableUnits. If you were checking for a specific condition this would make some sense, but it seems you are not, so instead just directly define playerSarray as playableUnits. Use the selectRandom command instead of the function BIS_fnc_selectRandom. On that note, you are selecting from "playerarray" but you previously defined "playerSarray". Was "playerarray" defined earlier in code that you did not include? Same thing happens later, you use "playerspos" and not the defined "randomplayerpos". Slimmer means fewer definitions of variables/number of lines. Only referencing "randomplayerpos" once? Then don't make it a variable, just execute the command directly where you are using the variable. I do not understand your comment in the code snippet. For anything further we may need to see more of the code. 1 Share this post Link to post Share on other sites
dlegion 98 Posted June 29, 2018 really thanks for the help !! here is the actual code i wish to make simpler: Spoiler //////////////////////////////////////////////////////// D_FarFromAll = { uiSleep 1; params ["_pos", "_limit"]; // Read the parameters sent to the function into these variables. // First assume that the position is far from all players. private _farFromAll = true; // Loop through all players in a forEach loop. { // If the distance from the position to the player is less than the distance limit, then the position is not far from all if (_pos distance _x < _limit) then { _farFromAll = false; }; } forEach playableUnits; // was: forEach call BIS_fnc_listPlayers; // Return the value in _farFromAll (do not write a semicolon after a return value) _pos = nil; _limit = nil; _farFromAll }; ///////////////////////////////////////////////////////// DFN_Patrol = { private _grp = _this select 0; private _pos = _this select 1; private _maxDist = _this select 2; private _Dry = _this select 3; private _Dspeed = _this select 4; uiSleep 1; _grp setBehaviour "AWARE"; //Create a string of randomly placed waypoints. private ["_prevPos"]; _prevPos = _pos; for "_i" from 0 to 3 do //was for "_i" from 0 to (2 + (floor (random 3))) do { private ["_wp", "_newPos"]; _newPos = [_prevPos, 150, _maxDist, 0.5, _Dry, 0.3, 0] call BIS_fnc_findSafePos; //D 2 = must be in water (0 = land) private _prevPos = _newPos; _wp = _grp addWaypoint [_newPos, 0]; _wp setWaypointType "MOVE"; _wp setWaypointCompletionRadius 200; //Set the group speed and formation at the first waypoint. if (_i == 0) then { _wp setWaypointSpeed _Dspeed; //or LIMITED or FULL _wp setWaypointFormation "COLUMN"; }; _grp setBehaviour "SAFE"; }; //Cycle back to the first position. private ["_wp"]; _wp = _grp addWaypoint [_pos, 0]; _wp setWaypointType "CYCLE"; _wp setWaypointCompletionRadius 200; _grp = nil; _pos = nil; _maxDist = nil; _Dry = nil; _Dspeed = nil; _i = nil; _newPos = nil; _prevPos = nil; _wp = nil; true }; ///////////////////////////////////////////////////////////// DFN_Dspawn = { uiSleep 1; private _maxDist = (_this select 0); private _minDist = (_this select 1); private _Dside = (_this select 2); private _DWPrange = (_this select 3); // 3000 private _Dtype = (_this select 4); private _DFNtype = (_this select 5); private _Dry = (_this select 6); //0 = land only 1=waterORland 2=water only private _Dspeed = (_this select 7); waitUntil{sleep 3;(count playableUnits) > 0}; private _allPPos = []; {_allPPos pushBack getpos _x} foreach playableUnits; //was allplayers private _RPPos = selectRandom _allPPos; private _Darea = [_RPPos, _minDist, _maxDist, 12, _Dry, 0.5, 0] call BIS_fnc_findSafePos; private _grpDveh = [_Darea,_Dside,_Dtype] call BIS_fnc_spawnGroup; // SPAWNER _grpDveh deleteGroupWhenEmpty true; [_grpDveh, _Darea, _DWPrange,_Dry,_Dspeed] call DFN_Patrol; // for patrol private _Dveh = vehicle leader _grpDveh; _Dveh setVariable ["NOT_remove",true,false]; // TO SAVE FROM CLEAN SCRIPT private _crewDveh = crew _Dveh; private _unitsDveh = units _grpDveh; // HINT "SPAWNED"; waitUntil { sleep 10; [(getPos _Dveh), _maxDist] call D_FarFromAll || !alive _Dveh }; // waituntil to allow side mission // variable to trigger side mission if !([(getPos _Dveh), _maxDist] call D_FarFromAll) then { if (_Dveh isKindOf "boat_F") then {sideSEA = true}; // SIDE MISSION SEA if (_Dveh isKindOf "tank") then {sideTANK = true}; // SIDE MISSION TANK }; uiSleep 1; if (!alive _Dveh) then {uiSleep 8}; // waitUntil { sleep 60; [(getPos _Dveh), 50] call D_FarFromAll}; // to go on // {deleteVehicle _x} forEach _crewDveh; {deleteVehicle _x} forEach (_unitsDveh + _crewDveh); deletevehicle _Dveh; // HINT "DELETED"; uiSleep 1; [_maxDist,_minDist,_Dside,_Dspeed] spawn _DFNtype; _maxDist = nil; _minDist = nil; _Dside = nil; _DWPrange = nil; _Dtype = nil; _DFNtype = nil; _Dry = nil; _Dspeed = nil; _allPPos = nil; _RPPos = nil; _Darea = nil; _grpDveh = nil; _Dveh = nil; _crewDveh = nil; _unitsDveh = nil; }; /////////////////////////////////////////////////////////////////// DFN_CARS = { private _Dtype = selectRandom ["C_Offroad_01_F", "C_Offroad_01_repair_F", "C_Quadbike_01_F", "C_Hatchback_01_F", "C_Hatchback_01_sport_F", "C_SUV_01_F", "C_Van_01_transport_F", "C_Van_01_box_F", "C_Van_01_fuel_F"]; private _maxDist = (_this select 0); private _minDist = (_this select 1); private _Dside = (_this select 2); private _DWPrange = 6000; [_maxDist,_minDist,_Dside,_DWPrange,[_Dtype],DFN_CARS,0,"FULL"] spawn DFN_Dspawn; _maxDist = nil; _minDist = nil; _Dside = nil; _DWPrange = nil; _Dtype = nil; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////// DFN_CARS is an example , i have also similar function tailored for military vehicles, infantry, helicopters, boats, planes ecc. as it is now...it works, but i feel it can be simpified, and as younoticed i'm a bit in "tunnelvision", often overcomplicating things! Maybe its "oversimplifyng", but i had in mind something like this: [center, minDist, maxDist, objDist, waterMode, maxGrad, shoreMode, blacklistPos, defaultPos] call BIS_fnc_findSafePos in this substitute "center" OR "blacklist" with ALL-PLAYERS-POSITION_ARRAY ...but it gives an error :( then put the previous into this: private _grpDveh = [[center, minDist, maxDist, objDist, waterMode, maxGrad, shoreMode, blacklistPos, defaultPos] call BIS_fnc_findSafePos,independent,10] call BIS_fnc_spawnGroup; _grpDveh deleteGroupWhenEmpty true; so in theory at this point i just have to find a way to make them move (maybe patrol houses too) and delete them when too far from players, and its done! but i'm too confused right now, and i need your help guys ! thanks a lot! Share this post Link to post Share on other sites
dlegion 98 Posted June 29, 2018 right now i came up with: randomplayer = playableUnits call BIS_fnc_selectRandom; randomplayerpos = getPos randomplayer; private _grpDveh = [[randomplayerpos, 5, 25, 5, 0, 0.3, 0,[[p1,20],[p2,20],[p3,20]]] call BIS_fnc_findSafePos,independent,1] call BIS_fnc_spawnGroup; it works, but i need a more efficient way to call every player , instead of calling them 1 by one like now (p1, p2,p3 ecc... up to 64 !! ) i thinked about : playerspos = []; {playersPos pushBack getpos _x} foreach playableUnits; ...and it kinda works, but the problem is that there is need to assign a range too (for example the number "20" in [p1,20] ). i have no idea how do it! thanks again ========== E D I T ================ idea of the moment...maybe this could work...will test tomorrow.... playerSarray = []; {playerSarray = playerSarray + [_x];playerSarray = playerSarray + [20] } foreach playableUnits; private _grpDveh = [[randomplayerpos, 5, 25, 5, 0, 0.3, 0,[playerSarray]] call BIS_fnc_findSafePos,independent,1] call BIS_fnc_spawnGroup; Share this post Link to post Share on other sites
Sgt. Dennenboom 98 Posted June 29, 2018 4 hours ago, dlegion said: here is the actual code i wish to make simpler: This is run on the server right? What is the context this script would be used in? Do you know why the script uses "playableUnits" instead of "allPlayers"? There is some massive potential for optimization in this script, but as they say: premature optimization is the root of all evil. You'll have to find a balance between optimization and readability. Doing something like: playerSarray = []; {playerSarray = playerSarray + [_x];playerSarray = playerSarray + [20] } foreach playableUnits; Is very inefficient and won't actually work since it creates a blacklist array with the wrong format. Rather do: _posBlacklist = playableUnits apply {[_x,20]}; _posRandom = [randomplayerpos,5,25,5,0,0.3,0,_posBlacklist] call BIS_fnc_findSafePos I'll look into the rest of the script tomorrow 1 Share this post Link to post Share on other sites
dlegion 98 Posted June 30, 2018 Ultra, ultra THANKS ! yes, its run on server, the context is a mission running 24/7 (but i set a reboot every night), so this script in theory keep working all the time. i use playableunits instead of allplayers because it returns only alive players, that are the one i care to create the bubble around, but if you think its better use allplayers, i will do! my wish is to make a script useful to the community, simple to use and configure even for people not used to scripts. thanks again! ============ E D I T =============== done as you say, tested, it works perfectly ! randomplayer = selectRandom playableUnits; randomplayerpos = getPos randomplayer; _posBlacklist = playableUnits apply {[_x,20]}; private _grpDveh = [[randomplayerpos, 5, 25, 5, 0, 0.3, 0,_posBlacklist] call BIS_fnc_findSafePos,independent,1] call BIS_fnc_spawnGroup; _grpDveh deleteGroupWhenEmpty true; now the next and last question is about spawned units randomization, patrol waypoints and de-spawn conditions. As you can see, my old approach was to manually define each unit, and then select it randomly, this gives a great customization (i can set more or less of each single unit type) but for sure its not very user-friendly, probably is not very efficient too, and is not open to new units added by patches, new DLCs ecc... (i mean that you have to manually add them if you want them, a bit complex). define for each type its own waypoint range and spawn/de-spawn ranges was very good for customization (i had a great control over it), but again i feel its very inefficient and not good for performance... really thanks for your help! ================ E D I T 2 ========================= for de-spawing, when too far (maybe i will add "or dead" too), i was thinking about this: {uiSleep 0.2; if (_x getVariable "FARdelete") then {if (_x distance ({_x} foreach allplayers) > 5) then {deleteVehicle _x;}}} foreach allUnits; ...and repeat this code forever every 30 seconds. what do you think about it ? will it be enought delete units, or i must also delete groups or something else i should take care of to "perfect clean" ? FARdelete variable to discriminate "bubble units" to remove when far away from players, and units to never remove even if far away. thanks again ! Share this post Link to post Share on other sites
pierremgi 4885 Posted June 30, 2018 A sleep inside your forEach loop for allUnits is weird. You should spawn the code instead: { _x spawn {} } forEach allUnits. That's for theory. Your approach is wrong, anyway. You are deleting some units far from any player??? So, I'm not sure the "far" condition is respectful for closer players... (far for one, close for another one). 1 Share this post Link to post Share on other sites
dlegion 98 Posted June 30, 2018 the sleep inside forEach is for better distribute the performance drop over time. do you think its useless ? consider i will have around 100 units spawned with that system... can you please explain how and why its better spawn the code? thanks :) i think i'm deleting the correct units...in this test case scenario the ones that are at distance bigger than 5 meters. whats wrong here ? thanks for your help ! Share this post Link to post Share on other sites
dlegion 98 Posted June 30, 2018 actual SPAWNER.sqf (MRAP just for vehicle testing purposes) while {true} do { uiSleep 1; _ALLspawned = []; {if (_x getVariable "FARdelete") then {_ALLspawned pushBack _x};} forEach allUnits; _activeUnits = count _ALLspawned; if (_activeUnits < 10) then { randomplayer = selectRandom playableUnits; randomplayerpos = getPos randomplayer; _posBlacklist = playableUnits apply {[_x,20]}; private _grpDveh = [[randomplayerpos, 5, 25, 5, 0, 0.3, 0,_posBlacklist] call BIS_fnc_findSafePos,independent,["I_MRAP_03_hmg_F"]] call BIS_fnc_spawnGroup; _grpDveh deleteGroupWhenEmpty true; {_x setVariable ["FARdelete",true,false];} forEach (units _grpDveh); {(vehicle _X) setVariable ["FARdelete",true,false];} forEach (units _grpDveh); }; }; and actual DELETEai.sqf while {true} do { uiSleep 3; {uiSleep 0.1;if (_x getVariable "FARdelete") then {if (_x distance ({_x} foreach allplayers) > 5) then {deleteVehicle _x;}}} foreach allUnits; {uiSleep 0.1;if (_x getVariable "FARdelete") then {if (_x distance ({_x} foreach allplayers) > 5) then {deleteVehicle _x;}}} foreach vehicles; }; ...the result is good, i dont know if its good performance-wise too , or if it can be made even slimmer.... (quite sure the repetition units-vehicles can be avoided somehow...) the problem still needing an answer is how randomize units in efficient way, so it can randomly spawn every possible military unit/vehicle of its faction... Share this post Link to post Share on other sites
Sgt. Dennenboom 98 Posted June 30, 2018 26 minutes ago, dlegion said: the problem still needing an answer is how randomize units in efficient way, so it can randomly spawn every possible military unit/vehicle of its faction... The most efficient way is to define an array of classnames, but is not dynamic. Instead you could pull a bunch of classnames from the "CfgVehicles" config using the configProperties/configClasses commands in which you filter for scope, vehicle type and side/faction. This should only be done once, at the start of the script. You should also remember not to spawn a new script for every single vehicle. It's much better in my opinion to have one script that handles every vehicle, with sleeps in it to prevent performance decreases. 1 Share this post Link to post Share on other sites
dlegion 98 Posted June 30, 2018 Oh yeah !! Thanks for the info, will try to do as you say! Its not very clear ti me the part about cfgvehicles.....can you please give an example of what can i do with it ? Thanks man !! Share this post Link to post Share on other sites
Sgt. Dennenboom 98 Posted July 1, 2018 For example, a way to get the class of every single available object in the game: _allObjectClasses = ("getNumber (_x >> 'scope') == 2" configClasses (configFile >> "CfgVehicles")) apply {configName _x}; The string is used to filter more thoroughly. To get a list of all civilian cars in the game: _allCivilianCarClasses = (" (getNumber (_x >> 'scope') == 2) // 0:private, 1:protected, 2:public and {(getNumber (_x >> 'side') == 3) // 0:east, 1:west, 2:indep, 3:civ and {(getText (_x >> 'vehicleClass') == 'Car')}} // 'Car', 'Armored', 'Ship', 'Air', etc... " configClasses (configFile >> "CfgVehicles")) apply {configName _x}; The config values you can filter for can be found here, or in the in-game config viewer. 1 Share this post Link to post Share on other sites
dlegion 98 Posted July 2, 2018 i'm breaking my head.....i'm sorry but ...where you find 'car', 'armored' ecc? i'm also stuck into a "logic problem": how can i set it so i have ( for example) at least 1 tank, 1 AAA, 10 infantry ecc..? because in theory it can spawn 100 infantry and no vehicles, or the opposite! please, may i have a working example of a "total random" choosing randomly between ALL independent INFANTRY, ARMORED (i think APC and AAA are included?), CARS, HELICOPTERS and PLANES ? huge thanks! PS: i'm keeping reading this page : https://community.bistudio.com/wiki/configClasses ...but cant get it to work... Share this post Link to post Share on other sites
dlegion 98 Posted July 2, 2018 finally i made it work! Spoiler //////// MANUAL SETTINGS //////// _MaxUnits = 50; // number of units to spawn _MinDist = 50; // minimum distance to players , number in meters _MaxDist = 200; // maximum distance to players , number in meters _OnWater = 0; // spawn on land OR water, 0 on land, 2 on water , 1 water or land _Dside = independent; // the side faction of spawned unit, can be WEST, EAST, INDEPENDENT, CIVILIAN _Dtype = "I_MRAP_03_hmg_F"; // the type of unit to spawn, can be more than 1, for example: "I_MRAP_03_hmg_F","I_MRAP_03_hmg_F" //////////////////END OF MANUAL SETTINGS, DO NOT EDIT UNDER THIS LINE//////////////////////////////////////// _allINDEP = "(getNumber (_x >> 'scope') == 2) and {(getNumber (_x >> 'side') == 2)}" configClasses (configFile >> "CfgVehicles"); while {true} do { _DtypeC = selectRandom _allINDEP; _Dtype = configName _DtypeC; uiSleep 0; _ALLspawned = []; {if (_x getVariable "FARdelete") then {_ALLspawned pushBack _x};} forEach allUnits; _activeUnits = count _ALLspawned; if (_activeUnits < _MaxUnits && (count playableUnits) > 0) then { randomplayer = selectRandom playableUnits; randomplayerpos = getPos randomplayer; _posBlacklist = playableUnits apply {[_x,_MinDist]}; private _grpDveh = [[randomplayerpos, _MinDist, _MaxDist, 10, _OnWater, 0.3, 0,_posBlacklist] call BIS_fnc_findSafePos,_Dside,[_Dtype]] call BIS_fnc_spawnGroup; _grpDveh deleteGroupWhenEmpty true; {_x setVariable ["FARdelete",true,false];} forEach (units _grpDveh); {(vehicle _X) setVariable ["FARdelete",true,false];} forEach (units _grpDveh); }; }; yeah! now i have to find a cheap way to make boats appear and patrol water , vehicles patrol roads , infantry patrol houses ecc.. any help is welcome :) Share this post Link to post Share on other sites
dlegion 98 Posted July 3, 2018 i found a simple way to discriminate the types of units spawned: Spoiler //////// MANUAL SETTINGS //////// _MaxUnits = 50; // number of units to spawn _MinDistMEN = 30; // minimum distance to players for MEN, number in meters _MaxDistMEN = 35; // maximum distance to players for MEN, number in meters _MinDistLAND = 50; // minimum distance to players for LAND VEHICLES, number in meters _MaxDistLAND = 55; // maximum distance to players for LAND VEHICLES, number in meters _MinDistAIR = 50; // minimum distance to players for AIR, number in meters _MaxDistAIR = 200; // maximum distance to players for AIR, number in meters _MinDistSHIP = 10; // minimum distance to players for BOATs, number in meters _MaxDistSHIP = 20; // maximum distance to players for BOATs, number in meters _MinDistMINE = 50; // minimum distance to players for MINES, number in meters _MaxDistMINE = 200; // maximum distance to players for MINES, number in meters _Dside = independent; // the side faction of spawned unit, can be WEST, EAST, INDEPENDENT, CIVILIAN //////////////////END OF MANUAL SETTINGS, DO NOT EDIT UNDER THIS LINE//////////////////////////////////////// _MinDist = 0; _MaxDist = 100; _OnWater = 0; // spawn on land OR water, 0 on land, 2 on water , 1 water or land //_Dtype = "I_MRAP_03_hmg_F"; // the type of unit to spawn, can be more than 1, for example: "I_MRAP_03_hmg_F","I_MRAP_03_hmg_F" , AIR, SHIP, LAND (subType CAManBase), _allINDEP = "(getNumber (_x >> 'scope') == 2) and {(getNumber (_x >> 'side') == 2)}" configClasses (configFile >> "CfgVehicles"); while {true} do { _DtypeN = selectRandom _allINDEP;_Dtype = configName _DtypeN; if (_Dtype isKindOf "LAND") then {_OnWater = 0;_MinDist = _MinDistLAND;_MaxDist = _MaxDistLAND;if (_Dtype isKindOf "CAManBase") then {_MinDist = _MinDistMEN;_MaxDist = _MaxDistMEN;};}; if (_Dtype isKindOf "AIR") then {_OnWater = 1;_MinDist = _MinDistAIR;_MaxDist = _MaxDistAIR;}; if (_Dtype isKindOf "SHIP") then {_OnWater = 2;_MinDist = _MinDistSHIP;_MaxDist = _MaxDistSHIP;}; uiSleep 0; _ALLspawned = []; {if (_x getVariable "FARdelete") then {_ALLspawned pushBack _x};} forEach allUnits; _activeUnits = count _ALLspawned; if (_activeUnits < _MaxUnits && (count playableUnits) > 0) then { randomplayer = selectRandom playableUnits; randomplayerpos = getPos randomplayer; _posBlacklist = playableUnits apply {[_x,_MinDist]}; private _grpDveh = [[randomplayerpos, _MinDist, _MaxDist, 10, _OnWater, 0.3, 0,_posBlacklist] call BIS_fnc_findSafePos,_Dside,[_Dtype]] call BIS_fnc_spawnGroup; _grpDveh deleteGroupWhenEmpty true; {_x setVariable ["FARdelete",true,false];} forEach (units _grpDveh); {(vehicle _X) setVariable ["FARdelete",true,false];} forEach (units _grpDveh); }; }; now i have no idea how make infantry spawn in groups of more than 1 unit (lets say 2-4 units). groups of 1 single soldier are not very realistic.... any help is welcome ! thanks ! Share this post Link to post Share on other sites
Grumpy Old Man 3546 Posted July 3, 2018 On 6/30/2018 at 7:28 PM, dlegion said: the sleep inside forEach is for better distribute the performance drop over time. do you think its useless ? consider i will have around 100 units spawned with that system... can you please explain how and why its better spawn the code? thanks :) i think i'm deleting the correct units...in this test case scenario the ones that are at distance bigger than 5 meters. whats wrong here ? thanks for your help ! A sleep won't save you in most cases since it will take longer the more units you want to spawn, if you sleep for 0.1 per unit that's still 10 seconds, which can be an eternity if you want stuff to happen fast. I'd also say it's better to write your own functions instead of using BIS_fnc_spawnGroup, since you have more control about how you want to tackle performance. As an example consider spawning 100 random unit types on random positions 100m around the player: _spawn = [] spawn { sleep 3; _types = "getNumber (_x >> 'side') isEqualTo 1 AND configName _x isKindOf 'CAManBase' AND getNumber (_x >> 'scope') >= 2" configClasses (configFile >> "CfgVehicles"); _types = _types apply {configName _x}; systemchat "Starting spawn"; _initTime = diag_tickTime; for "_i" from 1 to 100 do { selectRandom _types createunit [player getpos [100,random 360],creategroup west] }; _endTime = diag_tickTime; systemchat format ["Spawn finished in %1",_endTime - _inittime]; copyToClipboard format ["Spawn finished in %1",_endTime - _inittime]; }; oneachframe {hintsilent format ["FPS: %1\nUnits: %2", round diag_fps,count allUnits]} This takes 1.28 seconds the first time I run it, fps dropping from a steady 60 down to 40-44. On the second run it only 0.89 second with stable 60fps. Weird huh? Let's take a look. What actually happens is, the first time you spawn some unit, the game has to load textures, models and whatnot into memory. This leads to an fps drop and increases the load time by more than 40% in this case. Fortunately there's a command that can handle the data loading when combined with a simple waitUntil check, so you can spawn in anything without a performance loss. Adjusting the above snippet looks like this: _spawn = [] spawn { sleep 3; _types = "getNumber (_x >> 'side') isEqualTo 1 AND configName _x isKindOf 'CAManBase' AND getNumber (_x >> 'scope') >= 2" configClasses (configFile >> "CfgVehicles"); _types = _types apply {configName _x}; systemchat "Starting spawn"; _initTime = diag_tickTime; { waitUntil {100 preloadObject _x}; } forEach _types; systemchat "Preload finished"; for "_i" from 1 to 100 do { selectRandom _types createunit [player getpos [100,random 360],creategroup west] }; _endTime = diag_tickTime; systemchat format ["Spawn finished in %1",_endTime - _inittime]; copyToClipboard format ["Spawn finished in %1",_endTime - _inittime]; }; oneachframe {hintsilent format ["FPS: %1\nUnits: %2", round diag_fps,count allUnits]} This will let you spawn anything without having an fps drop. Now the downside is the waitUntil loop. preloadObject most likely finishes way faster than it takes to render a single frame, which is 16.6667ms. waitUntil runs once each frame, so you'll have a most likely guaranteed delay between every spawn of around 16ms. This is the reason spawning 100 units took around 3 seconds on the first run, and 0.8 seconds on the second run, on my rig. Now what's faster than waitUntil? A while loop. While loops run as fast as possible, that's what you want: _spawn = [] spawn { sleep 3; _types = "getNumber (_x >> 'side') isEqualTo 1 AND configName _x isKindOf 'CAManBase' AND getNumber (_x >> 'scope') >= 2" configClasses (configFile >> "CfgVehicles"); _types = _types apply {configName _x}; systemchat "Starting spawn"; _initTime = diag_tickTime; { while {!(100 preloadObject _x)} do {}; } forEach _types; systemchat "Preload finished"; for "_i" from 1 to 100 do { selectRandom _types createunit [player getpos [100,random 360],creategroup west] }; _endTime = diag_tickTime; systemchat format ["Spawn finished in %1",_endTime - _inittime]; copyToClipboard format ["Spawn finished in %1",_endTime - _inittime]; }; oneachframe {hintsilent format ["FPS: %1\nUnits: %2", round diag_fps,count allUnits]} Using a while loop took took the same time on the initial run, roughly 3 seconds, but every run after that a mere 0.4 seconds for 100 units. Twice as fast compared to the waituntil example above, since wile isn't locked to every frame. Looks like a winner here, no sleep needed, runs as fast as possible without affecting fps. Note that to properly test this, you need to restart arma between every test, since stuff loaded to memory, like models and textures, stays even when leaving the editor/changing missions. Cheers 3 Share this post Link to post Share on other sites
dlegion 98 Posted July 3, 2018 grumpy... you are really a master scripter! ultra thanks for this clear, well-made and detailed explanation with examples! finally you explained a thing i noticed in the past but have no idea was the reason behind it (or how improve it)! really really thanks ! now i kinda feel guilty to not have explained it before, in my mind it was kinda obvious, anyway i'm sorry about it: in fact time is not a problem at all....because this "ambient AI bubble" is meant to populate the otherwise empty map, so actually there's no hurry to do it, because i usually spawn AI at range from 2000m+ , to not "harm" players or appear under theyr eyes. the idea is to spawn units "just beyond typical players horizon" ...that in my experience is around 2km except for pilots or "extreme range enthusiast snipers". then this units will patrol randomly....so they can randomly go in the direction of players (and maybe spot&fight them) or simply go in another direction until too far from players, and get deleted by the other script. and the cycle will restart forever. so...really thanks for this awesome explanation, i will make treasure of it for the other scripts! what really scares me, is the long-term performance. i mean: on a dedicated server, after 24 hours of running, will it impact somehow ? and how clear it to keep the cycle clean as if was it first hour running? i assign every spawned unit a variable...i have to destroy it manually before delete? huge thanks again man! Share this post Link to post Share on other sites
dlegion 98 Posted July 3, 2018 every game object is considered civilian, i've troubles filtering real units (like men, cars, planes ecc..) from buildings! any idea on this ? _allINDEP = "(getNumber (_x >> 'scope') == 2) and {(getNumber (_x >> 'side') == 3) and {(getText (_x >> 'vehicleClass') == 'Car')}}" configClasses (configFile >> "CfgVehicles"); i dont know where find classes like: ['Armored', 'Car', 'Air'] , or even better a classes tree to better understand! Share this post Link to post Share on other sites
Grumpy Old Man 3546 Posted July 3, 2018 5 hours ago, dlegion said: grumpy... you are really a master scripter! ultra thanks for this clear, well-made and detailed explanation with examples! finally you explained a thing i noticed in the past but have no idea was the reason behind it (or how improve it)! really really thanks ! now i kinda feel guilty to not have explained it before, in my mind it was kinda obvious, anyway i'm sorry about it: in fact time is not a problem at all....because this "ambient AI bubble" is meant to populate the otherwise empty map, so actually there's no hurry to do it, because i usually spawn AI at range from 2000m+ , to not "harm" players or appear under theyr eyes. the idea is to spawn units "just beyond typical players horizon" ...that in my experience is around 2km except for pilots or "extreme range enthusiast snipers". then this units will patrol randomly....so they can randomly go in the direction of players (and maybe spot&fight them) or simply go in another direction until too far from players, and get deleted by the other script. and the cycle will restart forever. so...really thanks for this awesome explanation, i will make treasure of it for the other scripts! what really scares me, is the long-term performance. i mean: on a dedicated server, after 24 hours of running, will it impact somehow ? and how clear it to keep the cycle clean as if was it first hour running? i assign every spawned unit a variable...i have to destroy it manually before delete? huge thanks again man! Regarding the view distance you can retrieve it using viewDistance, add 100m to it and the player will never see units spawn. About performance it's trial and error mostly. Depends on how many units are going to be killed, if you track everything you spawn and take care to remove it when no player is around and a certain time has passed. Never ran any mission for longer than 8 hours tops but didn't notice anything out of the ordinary. The question is, is it absolutely necessary for the mission to run 24 hours or more? It's enough to simply delete stuff, no need to destroy it first, if I understood right. 33 minutes ago, dlegion said: every game object is considered civilian, i've troubles filtering real units (like men, cars, planes ecc..) from buildings! any idea on this ? _allINDEP = "(getNumber (_x >> 'scope') == 2) and {(getNumber (_x >> 'side') == 3) and {(getText (_x >> 'vehicleClass') == 'Car')}}" configClasses (configFile >> "CfgVehicles"); i dont know where find classes like: ['Armored', 'Car', 'Air'] , or even better a classes tree to better understand! Use isKindOf and check your brackets. Also added apply so you'll get the config class names instead of config paths: _allINDEPCars = "(getNumber (_x >> 'scope') >= 2) and {getText (_x >> 'faction' isEqualTo 'IND_F')} and {configName _x isKindOf 'Car'}" configClasses (configFile >> "CfgVehicles"); //returns ["I_Quadbike_01_F","I_MRAP_03_F","I_MRAP_03_hmg_F","I_MRAP_03_gmg_F","I_Truck_02_covered_F","I_Truck_02_transport_F","I_Truck_02_ammo_F","I_Truck_02_box_F","I_Truck_02_medical_F","I_Truck_02_fuel_F","I_Truck_02_MRL_F","I_APC_Wheeled_03_cannon_F","I_UGV_01_F","I_UGV_01_rcws_F"] You can search for factions and sides in the config, as long as the addon makers configure this properly it should work fine. Only buildings (most static weapons are buildings) and some objects are civilian side. Cheers 2 Share this post Link to post Share on other sites
dlegion 98 Posted July 4, 2018 eh... 16 hours ago, Grumpy Old Man said: The question is, is it absolutely necessary for the mission to run 24 hours or more? eh....sadly yes, its a persistent mission, its supposed to run endless (but for obvious tecnical limit server machine reboot every night), and in fact previous version was running ok for at least 3 days , so my target is still "at least 24h". hem...sorry but the latest part is very confusin for me.... i just wish to filter civilians "human" or "human driven" units, so civilian infantry and civilian vehicles, and mines too. and i still cant understand how do it thanks for your help! ============= E D I T ================ i still cant understand where to search for a tree-list of this classes ! thats probably the key problem! Share this post Link to post Share on other sites
dlegion 98 Posted July 4, 2018 a specific problem: Spoiler _MaxMines = 3; // number of units to spawn _loop = 2; // time between 1 spawn and next one, for more performance use higher number _MinDistMINE = 10; // minimum distance to players for MINEs, number in meters 200 _MaxDistMINE = 15; // maximum distance to players for MINEs, number in meters 500 //////////////////END OF MANUAL SETTINGS, DO NOT EDIT UNDER THIS LINE//////////////////////////////////////// _OnWater = 0; // spawn on land OR water, 0 on land, 2 on water , 1 water or land _allmines = ["ModuleMine_ATMine_F","ModuleMine_APERSMine_F"]; while {true} do { uiSleep _loop; // for more performance use higher number _ALLspawned = []; {if (!isNil {_x getVariable "FARdelete"}) then {_ALLspawned pushBack _x};} forEach allmines; // {if !(isNil {_x getVariable "FARdelete"}) then {_ALLspawned append [_x]};} forEach allmines; _activeUnits = count _ALLspawned; _Dmines = count allmines; // str (_activeUnits) + " ACTIVE MINES" remoteExecCall ["hint"]; str (_Dmines) + " ACTIVE MINES" remoteExecCall ["hint"]; if (_activeUnits < _MaxMines && (count playableUnits) > 0) then { _Dtype = selectRandom _allmines; randomplayer = selectRandom playableUnits; randomplayerpos = getPos randomplayer; _posBlacklist = playableUnits apply {[_x,_MinDistMINE]}; _minePOS = [randomplayerpos, _MinDistMINE, _MaxDistMINE, 10, _OnWater, 0.3, 0,_posBlacklist] call BIS_fnc_findSafePos; _Dmine = _Dtype createVehicle _minePOS; _Dmine setVariable ["FARdelete",_MaxDistMINE,false]; }; }; this code spawns mines....without end. it keep spawning them endlessly! (while it should stop at _MaxMines , set to 3) any idea? ========= E D I T ============ i fear i found why...its a sort of know problem: ...so no variables to mines...BUT i noticed you still can give a name to the mine..hehehe..so its a kind of "variable"... now i have no idea how i can spawn everytime a different name, everytime starting with "DELETE" (for example the script should spawn the first time a mine named "DELETEmine1", the second time a mine named "DELETEmine2" ecc.. what i know is that this code below should work to discriminate (and for example delete) every object with "DELETE" in its name : {_prefix = [_x,0,5] call BIS_fnc_trimString;if(_prefix == "DELETE") then {deleteVehicle _x;};} foreach (allMissionObjects ""); help plz :) Share this post Link to post Share on other sites
dlegion 98 Posted July 4, 2018 for now i found a satisfactory solution, doing this: Spoiler //////// MANUAL SETTINGS //////// _loop = 30; // time between 1 spawn and next one, for more performance use higher number _MinDistMINE = 300; // minimum distance to players for MINEs, number in meters 200 , to have "more mines" use lower numbers! _MaxDistMINE = 500; // maximum distance to players for MINEs, number in meters 500 , to have "more mines" use lower numbers! //////////////////END OF MANUAL SETTINGS, DO NOT EDIT UNDER THIS LINE//////////////////////////////////////// _allmines = ["ATMine","APERSMine","underWaterMine"]; // MINES TYPES OLD ["ModuleMine_ATMine_F","ModuleMine_APERSMine_F"]; _Dmine = createMine ["apersmine",[0000.00, 0000.00, -1000], [], 0]; uiSLeep 0.5; _Dmine setdamage 1; while {true} do { uiSleep _loop; // for more performance use higher number _OnWater = 0; // spawn on land OR water, 0 on land, 2 on water , 1 water or land _Wmine = FALSE; if (!(alive _Dmine) && (count playableUnits) > 0) then { _Dtype = selectRandom _allmines; if (_Dtype isKindOf "underWaterMine") then {_OnWater = 2;_Wmine = true;}; randomplayer = selectRandom playableUnits; randomplayerpos = getPos randomplayer; _posBlacklist = playableUnits apply {[_x,_MinDistMINE]}; _minePOS = [randomplayerpos, _MinDistMINE, _MaxDistMINE, 5, _OnWater, 0.3, 0,_posBlacklist] call BIS_fnc_findSafePos; _Dmine = createMine [_Dtype, _minepos, [], 0]; if (_Wmine) then {_Dmine setpos [getpos _Dmine select 0,getpos _Dmine select 1,(getpos _Dmine select 2)-0.5]}; }; _farFromAll = true; {if (_Dmine distance2D _x < _MaxDistMINE) then {_farFromAll = false;};} forEach playableUnits; if (_farFromALL) then {deleteVehicle _Dmine;hint "CANCELLA E RIPOSIZIONA MINA"}; }; mines encounter "frequency" can be set by setting distance. far from perfect, but works (with underwater mines too!). Share this post Link to post Share on other sites
Sgt. Dennenboom 98 Posted July 4, 2018 9 hours ago, dlegion said: i still cant understand where to search for a tree-list of this classes ! thats probably the key problem! Editor > Tools > Config Viewer. Objects/vehicles/units are in "CfgVehicles" Mines are in "CfgAmmo" 1 Share this post Link to post Share on other sites
dlegion 98 Posted July 11, 2018 hello guys! i've been busy coding stuff, and thanks to your precius teachings i learned to solve most problems....but the one i have now its a kind of problem i have difficulties to understand: i've scripted some addAction (like arsenal, save loadout, capture a soldier, save an hostage ecc...) and they work good in editor, also in MP if i'm in the server before spawn the function, the problem starts if i join after the function has been called. a pratical example is the mobile HQ (MHQ from now on) , a vehicle with addaction arsenal on it. if it respawns while player is in the server, all works, action can be seen and used.....but...if the player joins after the vehicle respawned, he cannot see the action at all. now using your teaching i'm quite sure that i must use RemoteExec, but on a quite complex situation i've tried for this entire day, and still can't get it to work. for example my actual code , executed at vehicle respawn, is : [[_this,["<t color='#ff0000'>ARSENAL</t>",{["Open", true] spawn BIS_fnc_arsenal}]],"addAction",true,false] spawn BIS_fnc_MP; [[_this,["<t color='#67DF0C'>SAVE Loadout</t>",{[player, [missionNamespace, "inventory_var"]] call BIS_fnc_saveInventory;hintSilent "Loadout saved";}, "", 12, false, false, "", ""]],"addAction",true,false] spawn BIS_fnc_MP ; [_this, -1,nil, "LIGHT"] execVM "R3F_LOG\USER_FUNCT\init_creation_factory.sqf"; this work on dedicated, but as i say not for JIP. how can i convert this into RemoteExec ? thanks! Share this post Link to post Share on other sites
pierremgi 4885 Posted July 12, 2018 if (isServer) then { < _veh = spawn your vehicle> ; // what ever command/function you are using [_veh, ["<t color='#ff0000'>ARSENAL</t>",{["Open", true] spawn BIS_fnc_arsenal} ] ] remoteExec ["addAction",0,true] ; }; That works in MP and JIP. 1 Share this post Link to post Share on other sites