razzored 37 Posted January 9, 2022 Hey so i've been working with a script that handles "random" item spawning fairly well. Initially it seemed like it would work rather well in multiplayer (from first glans) While that may still be true (in hosted) the script has been incapable of functioning on dedicated server and will not take player positions into account very well. Instead of spawning items around players in each their respective area.. atm it will X AMOUNT OF PLAYERS double the amount of loot around EVERY player and suddenly make a new loot respawn timer for each player, so after 10 people are on, loot will constantly respawn and where ever someone goes, mountains of loot will gradually build up and tear away every last fps. Im having some problems identifying where these issues are coming from. CREDIT to Samscodeco for originally designing this 2 years ago, i just wish he would have been a little more precise about the workings/ limits of it. Spoiler // Gets item with the lowest chance of spawning from list _getLowestChance = { _itemList = _this select 0; _currentLowestChance = 101; _currentWithLowestChance = []; { _entryToCheck = _x; _classToCheck = _x select 0; _chanceToCheck = _x select 1; if (_chanceToCheck < _currentLowestChance) then { _currentLowestChance = _chanceToCheck; _currentWithLowestChance = []; _currentWithLowestChance pushBack _entryToCheck; } else { if (_chanceToCheck == _currentLowestChance) then { _currentWithLowestChance pushBack _entryToCheck; }; }; } forEach _itemList; _currentWithLowestChance; }; // Gets the correct array depending on loot type _getLootTable = { _lootType = _this select 0; // Loot Categories // Get correct array to spawn items from _lootArray = []; switch (_lootType) do { case 1: { _lootArray = scclootCivil; }; case 2: { _lootArray = scclootIndustrial; }; case 3: { _lootArray = scclootMilitary; }; case 4: { _lootArray = scclootMedical; }; case 5: { _lootArray = scclootSupermarket; }; default { _lootArray = scclootDefault; }; }; _lootArray; }; while {scclootEnableSpawn} do { scclootSpawnerActive = true; waitUntil {!scclootCleanupActive}; // Vars for debug messages _lootContainerCount = 0; _lootSpawnedThisPass = 0; _buildingsWithoutLootThisPass = 0; _buildingsBlacklistedThisPass = 0; { _currentPlayer = _x; // Only try to spawn loot if the player is alive if (alive _currentPlayer) then { // Get array of all buildings within range of the player _buildings = nearestObjects [getPos _currentPlayer,["building"],scclootSpawnRange]; // For every building within range of the player { _buildingObject = _x; _buildingAlreadyHasLoot = false; _buildingIsOnBlacklist = false; _currentBuildingClass = typeOf _buildingObject; // Check if building is blacklisted from spawning loot if (count scclootBlacklistBuildings > 0) then { { _currentBlacklistBuilding = _x; if ((toLowerANSI _currentBuildingClass) == _currentBlacklistBuilding) then { _buildingIsOnBlacklist = true; _buildingsBlacklistedThisPass = _buildingsBlacklistedThisPass + 1; }; } forEach scclootBlacklistBuildings; }; if (!_buildingIsOnBlacklist) then { // Check if building has custom positions _isBuildingCustom = false; if ((toLowerANSI _currentBuildingClass) in scclootCustomPosClassnames) then { _isBuildingCustom = true; }; // Only try to spawn if the building has positions _numBuildingPositions = count ([_buildingObject] call BIS_fnc_buildingPositions); if (_numBuildingPositions > 0 || _isBuildingCustom) then { if (count scclootCurrentBuildingsWithLoot > 0) then { // Check if building already has loot spawned { if (_x select 0 == _buildingObject) then { _buildingAlreadyHasLoot = true; }; } forEach scclootCurrentBuildingsWithLoot; }; // If building does not have any loot spawned if (!_buildingAlreadyHasLoot) then { _currentBuildingLootSpots = []; // Convert the object to a building classname _currentBuildingType = 0; // Search for current building in the loot config to get its loot spawn type { if ((toLowerANSI _currentBuildingClass) == (toLowerANSI (_x select 0))) then { _currentBuildingType = _x select 1; }; } forEach scclootListBuildings; _currentBuildingLootArray = [_currentBuildingType] call _getLootTable; // Get array of all building positions _buildingPositions = []; if (_isBuildingCustom) then { _customPositionsRelative = []; { _entryName = _x select 0; _entryPos = _x select 1; if (_entryName == (toLowerANSI _currentBuildingClass)) then { _customPositionsRelative = _entryPos; }; } forEach scclootCustomPosBuildings; { _buildingPositions pushBack (_buildingObject modelToWorld _x); } forEach _customPositionsRelative; } else { _buildingPositions = [_x] call BIS_fnc_buildingPositions; }; // Iterate through usable building positions { // Select which items can spawn at the current position _randomNumber = [1,100] call BIS_fnc_randomInt; _possibleItemsToSpawn = []; { if (_x select 1 >= _randomNumber) then { _possibleItemsToSpawn pushBack _x; }; } forEach _currentBuildingLootArray; // Only try to spawn items if there are items to spawn if ((count _possibleItemsToSpawn) > 0) then { // Give rarest loot that can spawn priority _itemsToSpawnFinal = [_possibleItemsToSpawn] call _getLowestChance; _itemToSpawn = selectRandom _itemsToSpawnFinal; // Spawn the item _itemToSpawnClass = _itemToSpawn select 0; _itemBox = createVehicle ["WeaponHolderSimulated", [0,0,0], [], 0, "CAN_COLLIDE"]; if (_itemToSpawnClass isKindOf "bag_base") then { _itemBox addBackpackCargoGlobal [_itemToSpawnClass,1]; } else { _itemBox addItemCargoGlobal [_itemToSpawnClass,1]; }; // Get magazines from config _itemToSpawnIsWeapon = 0; _itemMags = getArray (configFile >> "CfgWeapons" >> _itemToSpawnClass >> "magazines"); // If item has associated magazines, spawn some if (count _itemMags > 0) then { _mag = _itemMags select (floor (random (count _itemMags))); _numberOfMagsToSpawn = [scclootMinMagazinesToSpawn,scclootMaxMagazinesToSpawn] call BIS_fnc_randomInt; _itemBox addMagazineCargoGlobal [_mag,_numberOfMagsToSpawn]; }; _posToSpawnLoot = _x; // Try to move loot using setVehiclePosition to avoid floor clipping. If this is not possible, use setPos with a Y offset instead. if (!(_itemBox setVehiclePosition [_posToSpawnLoot, [], 0, "CAN_COLLIDE"])) then { _lootSpawnPositionOffset = 1; _posToSpawnLoot set [2,(_posToSpawnLoot select 2) + _lootSpawnPositionOffset]; _itemBox setPos _posToSpawnLoot; }; // Add the item box to the list of item boxes for the current building _currentBuildingLootSpots pushBack _itemBox; _lootSpawnedThisPass = _lootSpawnedThisPass + 1; } } forEach _buildingPositions; // Add building and all associated item boxes to array _arrayEntry = [_buildingObject, _currentBuildingLootSpots]; scclootCurrentBuildingsWithLoot pushBack _arrayEntry; _buildingsWithoutLootThisPass = _buildingsWithoutLootThisPass + 1; }; }; }; } forEach _buildings; // Get nearby containers if (count scclootContainers > 0) then { // Iterate through containers { _containerName = _x select 0; _containerType = _x select 1; _containerObj = missionNamespace getVariable [_containerName, objNull]; _containerLootArray = [_containerType] call _getLootTable; // If player is within range if (_currentPlayer distance _containerObj < scclootSpawnRange) then { if (!(_containerObj in scclootCurrentContainersWithLoot)) then { // Select which items can spawn at the current position _randomNumber = [1,100] call BIS_fnc_randomInt; _possibleItemsToSpawn = []; { if (_x select 1 >= _randomNumber) then { _possibleItemsToSpawn pushBack _x; }; } forEach _containerLootArray; _itemToSpawnClass = ""; // Only try to spawn items if there are items to spawn if ((count _possibleItemsToSpawn) > 0) then { // Give rarest loot that can spawn priority _itemsToSpawnFinal = [_possibleItemsToSpawn] call _getLowestChance; _itemToSpawn = selectRandom _itemsToSpawnFinal; // Spawn the item _itemToSpawnClass = _itemToSpawn select 0; if (_itemToSpawnClass isKindOf "bag_base") then { _itemBox addBackpackCargoGlobal [_itemToSpawnClass,1]; } else { _itemBox addItemCargoGlobal [_itemToSpawnClass,1]; }; }; // Get magazines from config _itemToSpawnIsWeapon = 0; _itemMags = getArray (configFile >> "CfgWeapons" >> _itemToSpawnClass >> "magazines"); // If item has associated magazines, spawn some if (count _itemMags > 0) then { _mag = _itemMags select (floor (random (count _itemMags))); _numberOfMagsToSpawn = [scclootMinMagazinesToSpawn,scclootMaxMagazinesToSpawn] call BIS_fnc_randomInt; _containerObj addMagazineCargoGlobal [_mag,_numberOfMagsToSpawn]; }; scclootCurrentContainersWithLoot pushBack _containerObj; }; _lootContainerCount = _lootContainerCount + 1; }; } forEach scclootContainers; }; }; } forEach allPlayers; // Write debug output if (scclootDebugMessages) then { _debugMsg = ""; if (_lootSpawnedThisPass > 0) then { _debugMsg = format ["[SCCLoot] Successfully created %1 items in %2 buildings (%3 blacklisted, %4 containers)", _lootSpawnedThisPass, _buildingsWithoutLootThisPass, _buildingsBlacklistedThisPass, _lootContainerCount]; } else { _debugMsg = format ["[SCCLoot] No more loot was spawned this pass (%1 buildings blacklisted)", _buildingsBlacklistedThisPass]; }; systemChat _debugMsg; }; scclootSpawnerActive = false; sleep scclootSpawnWaitTime; }; Now there are some other sqf's in the overall package, but i am 99% certain that this is the one that is causing the issues (or rather, not working on dedicated and thus responsible for the undesired side effects). Hope there's some keen eyes out there who's down to help me out. Share this post Link to post Share on other sites
pierremgi 4737 Posted January 9, 2022 Spawning something should stay (most of the time) on server. So, depending on where you are calling this script. Each time yo ask for help in MP, you should give information about where you are calling the codes. 2 Share this post Link to post Share on other sites
razzored 37 Posted January 9, 2022 Ah ofc, sorry. Calling it through mission Init file Spoiler [] execVM "SCCLoot\lootInit.sqf"; Which calls a file in a sub folder that just runs the spawn script i posted and a cleanup script, why they are in 2 seperate scripts is beyond me, though i do see some of the applications in doing so. Heres the Lootinit Spoiler scclootCurrentBuildingsWithLoot = []; scclootCurrentContainersWithLoot = []; while {true} do { if (scclootDebugMessages) then { systemChat "[SCCLoot] Running loot spawner..."; }; _lootSpawnScript = [] execVM "SCCLoot\System\lootSpawn.sqf"; _lootSpawnCleanup = [] execVM "SCCLoot\System\lootCleanup.sqf"; sleep scclootWaitTime; }; Share this post Link to post Share on other sites
Harzach 2505 Posted January 9, 2022 25 minutes ago, razzored said: Calling it through mission Init file Which means a new iteration is introduced every time a player joins. Call it from initServer.sqf instead, as @pierremgi hinted at. 1 Share this post Link to post Share on other sites
razzored 37 Posted January 10, 2022 That makes alot of sense actually, i might have had the script so much under the microscope i completely failed to consider that aspect, will test asap, but i'd imagine it will solve it as anything that works similar to this, i tend to run through initserver.. 1 Share this post Link to post Share on other sites
razzored 37 Posted January 16, 2022 Worked perfectly, what a oversight. Share this post Link to post Share on other sites