Closed icomrade closed 8 years ago
Snap building doesn't snap properly, at least on metal floors, they snap slightly below where they should have: http://images.akamai.steamusercontent.com/ugc/262717416883152107/0659F4D2AB5A634328A759D9A07C6B09058AFE84/
So I converted/upgraded an existing database and there seems to be a problem with the order things are getting spawned in, or gravity or something. If you have helicopters sitting on metal floors they have a tendency to explode or fall through the metal floors (or the floors haven't been created yet).
This is what happens right after a server restart and the first player logs in: http://images.akamai.steamusercontent.com/ugc/262717416883168080/792D5168BAF57F9F4135B05562EFDF3A953596BD/
This is what it would have looked like under normal conditions: http://images.akamai.steamusercontent.com/ugc/262717416883183084/D979A78D1805D6EFE83625C68289F4BF2AF16106/
@ndavalos try commenting out line 254 in server_monitor.sqf: _object setVelocity [0,0,1];
repacking your dayz_server.pbo and reloading the server. This may be the reason vehicles are falling before buildables load
@icomrade that sort of fixed it, this is the end result: http://images.akamai.steamusercontent.com/ugc/262717416883351903/6C36FF6D8101A13404356A87ACFB8FE6BFAC49C4/
The helis in the air are normally sitting on the floors, haven't moved them in months lol.
I can provide you with a database if you want to play with it, well maybe not lol, all my objects still have coins in the inventory, I had to change the inventory function in server_monitor.sqf to handle that.
Well that's interesting, they should load in exactly when the DB has them saved. The database would be helpful for this so if you can provide it that would be appreciated. I'm in the epoch discord if you want to send it to me there, or PM me on the epoch forums http://epochmod.com/forum/profile/11576-icomrade/
@ndavalos Alright, ifor you're planning on doing that base your new Dll on this repo: https://github.com/icomrade/DayZhiveEpoch if you want to merge in your changes I can add you as a collaborator so they get added to the pull request at the original repo which mine was forked from
@icomrade lol unfortunately I don't do c, I probably should have learned it at some point, maybe on day...I work in Delphi (pascal) professionally, so that's what it'll be written in :)
@icomrade so after experimenting with spawning in vehicles, this sort of solves the problem with things blowing up when spawned, and sets their proper location. It also spawns vehicles in faster: _object = createVehicle [_type, [0,0,0], [], 0, if (_type in DayZ_nonCollide) then {"NONE"} else {"CAN_COLLIDE"}]; _object allowDamage false; _object enableSimulation false; _object setPos _pos; _object setDir _dir; _object allowDamage true; _object enableSimulation true;
This was just experimenting though. createvehicle with position [0,0,0] is actually faster than specifying the position when creating it, then do a setdir/setpos after. Only problem is things spawned in on pitched terrain don't sit on the terrain lol. So if a vehicle is on a hill it will be level instead of having it actually resting on the terrain, I'm sure it has to do with the enablesimulation I put in. If I take that out, they sit on the ground properly. Using this method also had very little in the way of destroyed vehicles after spawning in. I think only 4 of them blew up. Also note, the m240 nets at the base in the cave all appeared where they're supposed to be placed after using this method.
It still caused a couple helis to explode that were on metal floors, but something to look at if you're going to look at that issue. It was merlins that blew up @003131 in the database I provided you.
SetVelocity is used to sit the vehicle on the ground properly, it initializes physics after spawn in. That's why after you commented that line out some vehicles were floating in the air. I'm more concerned as to why you have some vehicles spawning in 10 feet above the platform they were landed on. There may be some inconsistencies between saving and spawning vehicles.
@icomrade I'm not sure if they're spawning in with CAN_COLLIDE, or not, didn't bother logging that. If they are, then yeah they should go exactly where you put them, if not then the engine will adjust things.
Edit: as a side note, I did setpos myself where one of the merlins was in the db and it was exact. I'll have to do that with one of the floaters.
@icomrade so I wrote my own function in a dll to load up the list of objects to spawn. Takes 1-2 seconds for it to load the array, but I'm not sure if you would even want to do this since it is very unconventional. I'm basically opening a query in the dll with the first call and deleting the previous copy of the sqf generated, the second call tells it to create an sqf in the arma directory then has the engine execute that file.
server_loadobjectscript = {
private["_key","_resultArray","_data"];
_key = _this;
_data = "dpfunctions" callExtension _key;
_resultArray = call compile _data;
diag_log format["start load: %1",diag_ticktime];
call compile preprocessFileLineNumbers format['\objectspawn\object%1.sqf',DZ_Server_Instance];
diag_log format["end load: %1",diag_ticktime];
_resultArray
};
The contents of the file look something like this:
DZ_Object_Array = [];
_myArray = ["OBJ","60668","LockboxStorageLocked","10289",[233.257,[291.606,2181.45,0]],[[[],[]],[["Machete_Swing","ItemBriefcase100oz","ItemBriefcase70oz","ItemGoldBar3oz","ItemBriefcaseS80oz","ItemSilverBar7oz","ItemBriefcaseS90oz","ItemSilverBar6oz","ItemGoldBar6oz"],[1,9,1,1,1,1,1,1,1]],[["DZ_LargeGunBag_EP1"],[1]]],[],0,0,0];DZ_Object_Array set [count DZ_Object_Array, _myArray];
It's very unconventional, but it prevents repeated calls to a dll, and is extremely fast. Something to think about I guess. It also overcomes the 4096 byte boundary for returning data.
I looked at the code in hive and it appears to be doing some stuff that you could actually just schedule an event on the database to handle every night or whatever. The fixing uids I actually have an event scheduled to do that:
delimiter //
CREATE EVENT `fix_objectuids`
ON SCHEDULE
EVERY 1 DAY STARTS '2016-03-27 01:00:00'
ON COMPLETION NOT PRESERVE
ENABLE
COMMENT ''
DO BEGIN
update object_data set objectuid = objectuid + objectid where objectuid in (
select distinct objectuid from (
select objectuid, count(*) from object_data group by objectuid having count(*) > 1) t1);
END
//
delimiter ;
Not sure what to tell you about the increase of time though, populateObjects should do as little as possible. You may consider moving most of the code in there that doesn't involve returning objects to a separate function. When arma loads an extension, that extension stays in memory, so anything that is in memory for the dll will remain. For instance, if you open a query object, that object retains it data and state until the arma server process actually exits. At no point does arma unload the dll.
The method I worked out was:
I think part of the problem is you're opening and executing queries for every single record in object_data from server_monitor. That's a lot of overhead, especially when you are hitting mysql 7k times. I would suggest the first call to hive where it gets the object count should execute all that extra code you have in populateObjects, then populateObjects simply returns objects and whatever REALLY needs to be done while doing that. You'll have to evaluate what is absolutely essential for populateObjects to do.
The hiveExt already loads everything in one query and iterates through the elements to ensure the data is valid and builds an array of objects to send to the server to spawn in SQF. I think the ObjID Fix is best executed sever restart, but in reality I suppose it doesn't really need to be, but I don't know if the overhead of this is noticeable. On another note using code blocks is helpful, surround your code with 3 back ticks: ```
auto worldObjsRes = getDB()->queryParams("SELECT `ObjectID`, `Classname`, `CharacterID`, `Worldspace`, `Inventory`, `Hitpoints`, `Fuel`, `Damage`, `StorageCoins` FROM `%s` WHERE `Instance`=%d AND `Classname` IS NOT NULL", _objTableName.c_str(), serverId);
if (!worldObjsRes)
{
_logger.error("Failed to fetch objects from database");
return;
}
while (worldObjsRes->fetchRow())
{
...
All of the objects/strings/pointers etc. should be destroyed and removed from memory once the initial load of the object_data table is done. I'm not sure why it wouldn't be cleaned up by the compiler since once populateObjects finishes everything referenced is no longer in scope and similarly so with streamObjects. I may be missing something, plus I'm not all that experienced with C++ so I probably wouldn't be able to identify the problem.
Also I think the biggest issue with increased load time is the modified servermonitor file, I noticed whether the DB was new, empty or populated the minimum load time is ~30 seconds. We definitely need to look into performance optimization.
@icomrade In server_monitor it does this:
if (_status == "ObjectStreamStart") then {
_hiveLoaded = true;
_val = _result select 1;
//Stream Objects
diag_log ("HIVE: Commence Object Streaming...");
for "_i" from 1 to _val do {
_result = _key call server_hiveReadWriteLarge;
_status = _result select 0;
_myArray set [count _myArray,_result];
};
diag_log ("HIVE: Streamed " + str(_val) + " objects");
Which, I don't do c++, but from reading the code it appears to open a query each call:
auto worldObjsRes = getDB()->queryParams("SELECT `ObjectID`, `Classname`, `CharacterID`, `Worldspace`, `Inventory`, `Hitpoints`, `Fuel`, `Damage`, `StorageCoins` FROM `%s` WHERE `Instance`=%d AND `Classname` IS NOT NULL", _objTableName.c_str(), serverId);
if (!worldObjsRes)
{
_logger.error("Failed to fetch objects from database");
return;
}
But again, I don't do c++ so I could be misinterpreting that in populateObjects as executing the query each call, or misinterpreting what server_monitor is doing in relation to calling the dll.
The rest of server_monitor is taking too long as well. The script is getting suspended during execution causing it to take around 80 seconds to spawn in 7k. There's some stuff that could probably be done to fix it completely. @eraser1 mentioned maybe moving to an fsm to spawn things in unscheduled and control the entire process better.
@icomrade also, change the query to load the objects to only get those with damage < 1 to reduce the object count instead of having to evaluate it in sqf.
That SQL query is only executed once, I think the subsequent calls of child 302 return a single object. once the initial load of the object_data table _srvObjects is no longer empty so it should go to the else condition.
https://github.com/icomrade/DayZhiveEpoch/blob/master/Hive/Source/HiveLib/HiveExtApp.cpp#L300-L343
I have a server_monitor.sqf that I was testing that uses spawn and tries to create vehicles in multiple threads in parallel. I still have to tweak it, but on average it saves ~10 seconds with 4000 objects in the DB.
Edit: I do agree there is a lot of overhead with this method but I believe there is a limit with the amount of data callExtension can return as mentioned here: https://github.com/EpochModTeam/DayZ-Epoch/issues/1197 So I don't know if this is going to be an issue with returning everything in one array.
I have a server_monitor.sqf that I was testing that uses spawn and tries to create vehicles in multiple threads in parallel. I still have to tweak it, but on average it saves ~10 seconds with 4000 objects in the DB.
SQF threads never really run "parallel", only a single statement of SQF is ever executed in any given instant. It appears to be saving time either because of lots of other SQF "threads" that have been spawned from other scripts, thereby artificially increasing the priority of object spawning, simply by the presence of more threads, or you simply measured the time of completion of the server_monitor code, which doesn't measure the actual time taken to spawn the objects.
I just managed to spawn in 7k+ objects in 30 seconds and set all the properties on them after the fact in 20 with the method I developed last night. I changed my methodology to create an sqf to load up the object array with actual objects and create them. After the engine runs it, it signals the clients that login is ok and spawns a thread to update all the properties on the objects like damage, hitpoints, inventory etc.
@icomrade some suggestions for optimizing:
As @eraser1 suggested, using an fsm to create the objects probably will significantly lower the cost of spawning everything in. My new method (not the fsm) takes anywhere from 40-60 seconds to spawn everything and add inventory as opposed to 2 minutes.
Between a well written server_monitor.sqf and a well written FSM version I doubt there will be a meaningful difference. Rewriting the whole server startup process as an fsm may be more beneficial but since server_monitor.sqf is relatively simple in its condition checking there may not be a huge benefit. Even just moving simple things to the HiveEXT like typename checks will probably offer more performance benefit than moving to an fsm.
That is actually my point. Running the entire server startup sequence unscheduled could make a very significant difference.
Also, not just the server startup sequence, but I also found that running the player login system helped with player login times significantly under load.
I did some profiling of the various functions of server_monitor and the engine was pausing the script anywhere from 20ms to 100ms randomly while setting up objects. Some objects would create and update in 1ms, some 20ms and some 100ms. So running scheduled is going to have some issues, especially when you have around 6 or 7k objects.
A couple of observations on the server_monitor performance. changing server_monitor to call compile instead of execVM decreases the total callExetension time for the HiveEXT by 5x (3s vs 15s for 4100 items). I believe the max number of loop iterations in a called environment is 10,000 so it's probably not an appropriate change.
I've moved some stuff and changed some stuff and was able to shave some time off load in, but it's still far from where it should be. with 4100 objects the } forEach _myArray;
loop takes ~200 seconds still.
@icomrade few suggestions:
OR use an fsm :P Figure out what is critical for clients to log in and do that first, do the rest after you let clients log in. If you log the tick time for every part of object creation, you'll see the main reason everything takes so long is because the engine is suspending the thread anywhere from 20-100ms while server_monitor is doing it's thing. This is killer when you have a large number of objects. The reason each iteration through the object array is taking 200 seconds is the engine suspending the thread.
Pretty much every millisecond counts to getting the server ready for clients.
I believe the max number of loop iterations in a called environment is 10,000~~
This only applies to while loops, not "forEach" or "for" loops.
@icomrade got 7k objects read in and spawned in 17 seconds using my method.
@ndavalos is there anything you've done that is different than the current server_monitor. If you've changed something reply with a link that points to the line number and file
@icomrade I practically rewrote server_monitor, but some of the optimizations I've done are:
https://github.com/EpochModTeam/DayZ-Epoch/blob/master/SQF/dayz_server/system/server_monitor.sqf#L203 Is now: _cargo = _inventory; if (_storageMoney > 0) then {_object setVariable [Z_BankMoneyVariable, _storageMoney, true];}; //diag_log format["%1, %2",_object,_cargo]; _weaponcargo = _inventory select 0 select 0; _magcargo = _inventory select 1 select 0; _backpackcargo = _inventory select 2 select 0;
_weaponqty = _inventory select 0 select 1;
{_object addWeaponCargoGlobal [_x, _weaponqty select _foreachindex];} foreach _weaponcargo;
_magqty = _inventory select 1 select 1;
{_object addMagazineCargoGlobal [_x, _magqty select _foreachindex];} foreach _magcargo;
_backpackqty = _inventory select 2 select 1;
{_object addBackpackCargoGlobal [_x, _backpackqty select _foreachindex];} foreach _backpackcargo;
You'll also need to add: if (_storageMoney > 0) then {_object setVariable [Z_BankMoneyVariable, _storageMoney, true];}; To the locked storage inventory spot: https://github.com/EpochModTeam/DayZ-Epoch/blob/master/SQF/dayz_server/system/server_monitor.sqf#L190 Because you can't have locked storage in the DZE_MoneyStorageClasses array due to it's usage in fn_selfActions
Curious if it would be possible to fix the models for safes, depending on the lighting conditions you end up with transparent safes: http://images.akamai.steamusercontent.com/ugc/1617176672223319624/FAF311342D8CFE63CCD4B6C3EC175EBC37D10531/
I believe that is to do with your graphics settings, when you have ATOC turned on it will do this. Door frames/cinder doors also become see through
@oiad you're right, as long as the setting does not include grass it's fine. So basically just trees.
Normal SUVs have extremely strong armor and glasses. If you dont shoot on the engine it is really hard to destroy that vehicle. If you shoot the side from the SUV it takes very low damage. I think this is not the intention.
I think SUVs are fairly weak in contrast to other vehicles, I don't think anyone really has an issue with the amount of armor. I mean they are technically utility vehicles, I'd expect them to be stronger than a regular car.
@icomrade Did you check the SUVs ingame? I cant destroy an SUV with 4 AK74 mags if I shoot only on the right or left side of the vehicle. The SUV is like an HMMWV right now.
Ak74 is 5.56 it's a very weak gun, 5.56 is very weak in Arma 3 also, and is weak against players as well so I wouldn't expect it to destroy a vehicle quickly. Honestly I don't think there's anything wrong with the sun, if your looking to destroy a vehicle use an appropriate weapon like a 7.62 gun or lmg
Tested now with M240. After 5 mags in the left side the SUV did not blow up. A HMMWV blows up after 3 mags. So basically you have to hit the SUV directly on the front engine. Am I totally wrong here or is a bit too much? Perhaps Im just too familiar with the old epoch vehicles and it seems only for me too much.
Armor of the SUV is 25 unless you are using an upgraded SUV (armor upgrade gives 60 armor), the HMMV is 40. if the SUV doesn't get damaged from the side I don't think it's something that can be fixed from the configs, the model itself would need to have the engine hit points modified.
@icomrade this file: https://github.com/EpochModTeam/DayZ-Epoch/blob/master/SQF/dayz_code/system/scheduler/sched_spawnCheck.sqf Has this code:
#include "scheduler.hpp"
sched_spawnCheck_init = { []spawn{} };
sched_spawnCheck = {
HIDE_FSM_VARS
if (scriptDone _this) then {
_this = [] execVM '\z\addons\dayz_code\compile\player_spawnCheck.sqf'; // stuffed with "sleep" commands, can't put it in scheduler
};
_this;
};
but that is defined as a variable in compiles: player_spawnCheck = compile preprocessFileLineNumbers "\z\addons\dayz_code\compile\player_spawnCheck.sqf";
Is there any way of making that use what's defined in compiles instead? I need to override this function, but by doing it this way, I can't without overriding a bunch of other stuff as it currently stands just to get to this one function.
you'll need to edit sched_init.sqf or create a folder of the structure exactly replicating the path of _base (in sched_init.sqf) and place your custom sched_spawnCheck.sqf in it. so it would be [Mission root]\z\addons\dayz_code\system\scheduler\sched_spawnCheck.sqf. you will also need to overwrite player_spawnCheck
@icomrade I was hoping it could just be changed to
sched_spawnCheck_init = { []spawn{} };
sched_spawnCheck = {
HIDE_FSM_VARS
if (scriptDone _this) then {
_this = [] spawn player_spawnCheck '; // stuffed with "sleep" commands, can't put it in scheduler
};
_this;
};
Since player_spawnCheck is defined in compiles already, makes it much simpler to override the function without having to replicate the scheduler.
I'm basically adding 1 line to that file to do an extra check for plot poles and safezones to prevent loot and zombies from spawning within plot pole radius (or safezone radius).
If it's not a good idea due to spawn adding a new scheduled environment then that's ok and I'll just replicate the scheduler, unless of course you feel like adding one thing to spawncheck to check to see if a variable is defined and executing the code in the variable for additional checks people can add without having to override the code.
Something like:
if !(isNil "DZE_ExtraSpawnCheck") then {
_doNothing = _position call check_spawning_distance;
};
if (_doNothing) exitwith {};
@ebaydayz Well, execvm adds a thread to the main scheduled environment, spawn creates a new thread and scheduled environment (that runs alongside the main scheduled environment). That's really the difference between the two (aside from calling convention and error reporting). I don't really see a problem with that one being spawned, hell it might even improve it's performance instead of stacking it in the main scheduled environment. Either way I can deal with it, just tossing out some suggestions since it's already compiled in compiles as a variable, but that variable isn't being referenced anywhere in the mod. The other alternative would be good too, or some variation thereof. I wouldn't mind having that one little thing in there (however it's implemented) to allow for additional checks on whether or not to run the spawning code. That way I'm not overriding an entire file to add 1 line of code :)
You don't have to replicate the scheduler, I don't think I let on that you have to recreate the folder structure. Same concept behind the BIS Init error fix I added to the missions, since the path in https://github.com/EpochModTeam/DayZ-Epoch/blob/master/SQF/dayz_code/system/scheduler/sched_init.sqf doesn't have a preceeding \ it can be overwritten by a file in the mission. Also look at the referenced file to see why just overwriting only the compile won't work.
@icomrade Ah, I see the missing "\" at the beginning of the base path. I would however prefer not to override any code if at all possible. It's just a pain to deal with, so I try and avoid it, especially for a 1 line change.
@ebaydayz I believe I was basing my assumption about scheduled environment based on the comments on spawn in the wiki.
Honestly it's not a big deal, adding a replication of the file vs overwriting the compile is a difference of 2 lines of code in this case.
@icomrade actually what I was referring to is second option of adding something to player spawn check instead of having to override anything. That way if there's a base change in the mod, there's no need to try and keep things in sync
So in player_spawncheck.sqf something like:
if !(isNil "DZE_ExtraSpawnCheck") then {
_doNothing = [_position, _spawnableObjects, _speed, _radius, _spawnZedRadius, _maxlocalspawned, _maxControlledZombies, _maxWeaponHolders, _currentWeaponHolders, _inVehicle] call DZE_ExtraSpawnCheck; //return result is assigned to _doNothing
};
if (_doNothing) exitwith {};
I modified the Hive to write to a file and have the server read form it, eliminating the need for callExtension nested in a loop. The file is named uniquely per startup based on the init key and is placed in the A2 root directory. Unfortunately I cannot truncate or delete the file until the next restart since OA locks the file once it is read by the engine. I'm concerned that this is a security issue as there's essentially a plain text DB dump of the objectData table sitting in the OA directory. I'm curious if anyone knows of a way to unlock the file once it's loaded by OA, or even write to the file using in sqf. #include, preprocessfile, loadfile all lock the file, htmlLoad won't work since the dedicated has no display, if there's a non-locking way to read a file I'd love to know of it.
On a performance note this only saves 2-3 seconds with 7000 objects, but it will fix https://github.com/EpochModTeam/DayZ-Epoch/issues/1197 if this was the issue (I feel it's unlikely).
Nah there's really no way to unlock the file. I'm leaving them with the same name and deleting them in the dll before writing a new one on restart. Most people run their db on the same machine, so there's really no difference, they'd have the credentials for the db anyways since you don't encrypt them in the hive.ini file. I use a specific folder for the file, not the root, you can load from a specific directory just using "\mydir\myfile.sqf" . I'm getting a consistent 20-30 second startup with my server_monitor and dll, hive gives me about 75 seconds + so I think your problem is elsewhere not the iterations if hive only takes a few seconds normally now.
I didn't expect a huge performance increase since the loop only took a couple seconds to complete anyway. I'm curious as to why there's such disparity in the load times experienced with the 2 versions of the server_monitor file. Looking at the server_monitor you sent me a while ago, you removed all the worldspace crap which I've been looking to do for a while and you've also removed that config lookup which is intensive, also a lot is missing so I assume the rest is handled elsewhere. I don't think moving the networked commands (setvariable) to a spawn is making a difference since I completely commented them out with no meaningful difference.
Also, did I assume you tested with the server_monitor I committed yesterday, it should be quite a bit better than previous versions.
When the Hrotor from a heli is to 100% damaged the chopper can still fly. This is an old epoch bug perhaps an arma bug? Can we fix that?
@icomrade just tested the new server_monitor etc. Loads you in within a minute with 7.5k objects. I got a retrying authentication though at some point, not sure what that was about. Otherwise it's loading fairly well.
I remember two old epoch or arma2 bugs. Im not sure from which it comes.
When someone eject from a flying little bird, the little bird gets heavyle or fully damaged.
Switching between the gunners in a flying chopper can result in ejecting from the chopper without a parachut. E.g. When you are on the left gun from a UH1H and you switch to the right gun there is a chance that you just fall out of the chopper without a parachut. Tested with UH1H and Mi17.
Post all issues pertaining to the first release candidate of the Epoch 1.0.6 update here.
Known issues from the previous topic:
Bunny hop with no weapon triggers an invisible weapon switch (bug in vanilla)Some ammo types have no right click re-combine optionDO NOT run test buils with infistar or other mods that are not updated to work with 1.0.6. You MUST use the new HiveExt.DLL if you are running a server, the new dll requires visual c++ redistributable 2015.