local_publishobj.sqf = My head is exploding

Graz

Well-Known Member
I've had a look at the Dayz Code quite extensively but how to write a script to spawn a vehicle that is saved to the database is becoming a little beyond me.

Basically I want to have a server script that can spawn a persistent vehicle. It's linked to conditions and is set to run randomly through the mission. ie dynamic vehicle respawns.

The issue I'm having, is how do I make this save to the hive??

The two current thoughts, I'll use lada an an example.

Do I run the createvehicle and then run the dayz hive scripts.

eg createvehicle lines
setinit = this execVM =>one of the compiles?<=

Or is it part of the spawn and is actually code?

Has anyone spawned a vehicle and had it save to the hive in game? How did you do it?
 
im working on this code atm actually, basically you can't use local publish to save vehicles because the hiveext.dll doesn't use the key to save to that table, infact there is no existing code that will "insert" into the instance vehicle table. additionally i have come to the conclusion that it can't be possible to save to that table unless you use the custom mysql keys which are keys 999 and 998, 999 seems to return values and do some partial changing. while 998 is just a strait execute this in mysql key.

If you go to the WastelandZ thread there is some information there about how i was trying to save to the db, so far this is a script i have been calling to create my test vehicle while getting all the bugs out:

Code:
waitUntil{allowConnection};
    _type = "UH1H_DZ";
    _dir = (random 360);
    _pos =[13485,4421,0];
    //http://forums.bistudio.com/showthread.php?103108-BIS_fnc_findSafePos
    _newPos = [_pos, 10, 200, 10, 0, 500, 0] call BIS_fnc_findSafePos;
    diag_log format["Attempting to spawn new vehicle: %1 at location %2",_type,str(_newPos)];
  // _newVehicle = ["UH1H_DZ",_newPosr] call object_spawnGoodVehicle;  //object_spawnDamVehicle;
 
    _veh = _type createVehicle _newPos; // [,, [], 0, "CAN_COLLIDE"];
    _veh setDir _dir;
    _veh setPos getPos _veh;
 
    //_veh setVariable ["ObjectID",1,true];
   
    _veh setVariable ["ObjectID", _veh call dayz_objectUID, true];
 
    _hitpoints = _veh call vehicle_getHitpoints;
    _dam = 0.05;
    _veh setFuel 1;
    _veh call fnc_vehicleEventHandler;
    {
        _hit = [_veh,_x] call object_getHit;
        _selection = getText (configFile >> "CfgVehicles" >> (typeOf _veh) >> "HitPoints" >> _x >> "name");
        if (_hit > 0) then {_array set [count _array,[_selection,_hit]]};
    } forEach _hitpoints;
       
      dayz_serverObjectMonitor set [count dayz_serverObjectMonitor,_veh];
     
      [_veh] execVM "fixes\fn_save_vehicle.sqf";
      [_veh,_type] spawn server_updateObject;
 
    //dayzUpdateCleanFSM = _veh;
    //publicVariable "dayzUpdateCleanFSM";
   
 
//if (isServer) then {
//[0,_veh,[_dir,_newPos],_type] call local_publishObj;
//};
now i just need the save code which is where your at also


As you can see i also though i might be able to use local publishobj to save vehicles however its not going to work because of the way hiveext.dll takes the queries.

While doing some testing this is what i have determined, you have to have a world_vehicle.id for the _type of vehicle your tring to save, there could be a mysql insert that has a select query

I have some code another user sent me and im working on that however im also working on this AI change so that ai units attack zeds and thats holding me up at this time from working on some type of save vehicle to db code.
 
It looks like you were further along.

I'm actually having trouble getting vehicles to spawn - period. Standard CreateVehicle commands are "blocked" and the vehicle is deleted when running it on Dayz.

Have you managed to get a vehicle spawning in game that isn't persistent?

Alternatively: http://forums.bistudio.com/showthread.php?111484-ArmA2-Persistent-Database-Scripts-WIP

It might be time to just look at writing a new script for writing to the database.
 
Thats now part of mso and not activly being worked on, modify your server cleanup.fsm in the server.pbo file general cleanup box there is some code that says killing the hacker
 
well, im a noob at scripting, but hackers/scripters have been able to make more than local vehicles - however, not saving them in DB (Local=Only them can see them). I don't know how, but we could hope an old hacker will come in here and tell us how to do that.
 
making them is not the issue, i can make them, if youwant them to be repairable and save between restarts we need a new key/function

I have been working on getting AI to target zeds and bandits which im just about ready to release later today hopefully. after that my next task to get vehicle saving after restarts working with saving to the db on newly spawned vehicles

once i fix those two issues i can go back to porting wasteland to a dayz mission......


the vehicle generator code above works, infact the vehicle will take damage, you just can't repair it and you can't save its contents, but like i said i got side tracked with this ai fix for my server
 
well, my believe as a noob scripter is, that the server checks if vehicle have been spawned, if a vehicle has been spawned as in a createvehicle method, it will hive write.
 
negative, the server spawns all vehicles on start, this code is in the server_monitor, once it launches the server_cleanup.fsm, the fsm creates an array and copies a list of the vehicles to itself, first check is if this object exists as a player and is not in the array, if that condition is true then the damage gets set to 1 and you see "killing a hacker" in the server logs.

there is no way a function currently built into dayz can save to the instance vehicle table, perhaps in the dayz servers with the object table but not on bliss.

Bliss breaks up the vehicle into 3 tables, the vehicle table can be though of as the class definition table, it tells the game what a AH6x_DZ is, the 2nd table from there is the world_vehicle table, it tells the game where those object appear in game, now here is where the trickey part comes into play, the 3rd table is the instance_vehicle table, that table tells the game what objects are currently in game. however being a good rdbms when you pull this data you link the vehicle from the instance table to the vehicle table via the world instance table. so you need to know where it spawned in order to figure out what it is.

on bliss there is no harm in having multiple vehicles assigned to the same world_vehicle.id at least not that i can tell at this moment.

at the bare minimum you need the world vehicle id to save a vehicle to the instance table, and there is no key combination for getting this or setting the later.
 
The normal dayz servers use an object table with everything in there i think sanct or pwn is setup like that, im going to be working on active saving this week end hit me up if you want to work together on this
 
Leolilu was kind enough to help me on this problem and get me going on some code using bliss 4.x; thank you with out your help i would still be messing with one of the other functions.

this is the beginning of the server_saveVehicle function im working on this weekend, the bottom part is missing a loop to go though the _count. this will return the 1st id for the vehicle in the hive, however if there is more than one entry in the world_vehicle table it will screw stuff up probably, don't use this on production. im too tired to keep working on this so im gonna crash and then work on this later i just wanted to share and have a back up.

I really need to just write a wrapper that i can understand in the SQF side, there isn't really any documentation anywhere on this.


Code:
if (isServer) then {
    hiveInUse = true; 
    _serverMonitor = [] execVM "\z\addons\dayz_server\system\server_monitor.sqf";
    server_saveVehicle =    compile preprocessFileLineNumbers "fixes\server_saveVehicle.sqf";
    "dayzSaveVehicle" addPublicVariableEventHandler {_id = (_this select 1) spawn server_saveVehicle};
};

Code:
private ["_targetObj","_targetClass","_targetPos","_targetDir","_targetDir","_isVehicle"];
_targetObj = _this select 0;
_targetClass = typeOf _targetObj;
_targetPos = getPos _targetObj;
_targetDir = getDir _targetObj;
_isVehicle = cursorTarget isKindOf "AllVehicles";
  diag_log("SERVER: Attempting to find world Vehicle id.");
//Send the key
 
        //GET DATA
      _key = format["CHILD:999:select world_vehicle.id from world_vehicle, vehicle where vehicle.id = world_vehicle.vehicle_id and vehicle.class_name = '?' and world_vehicle.world_id = '%2':[""%1""]:", _targetClass,1];
      diag_log ("Sending Query 1:  " + str(_key));
      _data = "HiveEXT" callExtension _key;
      //Process result
      _result = call compile format ["%1", _data];
      _status = _result select 0;
      _count = _result select 1;
      //writes the result in your server log
      diag_log ("My Result:  " + str(_result));
 
        if (_status == "CustomStreamStart") then {
        diag_log ("Fetching: " + str(_count) +" rows");
      //Start loop on _count here
        diag_log ("Sending Query 2:  " + str(_key));
        _data = "HiveEXT" callExtension _key;
        //Process result
        _result = call compile format ["%1", _data];
        //writes the result in your server log
        diag_log ("My Result:  " + str(_result));
      //end loop on _count here
        };

this is just half of saving vehicles to the dbase but this will lookup the world_vehicle.id by vehicle class.
 
This is a stored procedure i'm playing with, it requires the world_vehicle.id and returns the instance_vehicle.id

Code:
CREATE DEFINER=`dayz`@`localhost` PROCEDURE `proc_saveVehicle`(IN `p_worldvehicleid` BIGINT(20))
BEGIN
INSERT INTO `instance_vehicle`(`world_vehicle_id`,`last_updated`, `created`) VALUES (p_worldvehicleid,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP);
select LAST_INSERT_ID();
END

Basically what should happen is the vehicle gets inserted into the db, then the damage handler should be able to start updating it.
 
Initilization code:
Code:
    fn_getWorldVehicleID =  compile preprocessFileLineNumbers "fixes\fn_getWorldVehicleID.sqf"; //Obtains a world_vehicle.id using a classname that is in the vehicle table
    fn_saveVehicle =  compile preprocessFileLineNumbers "fixes\fn_saveVehicle.sqf";            //This creates a new entry in the instance vehicle table with the supplied world_vehicle.id
    //user server_saveVehicle or the event handler
    server_saveVehicle =    compile preprocessFileLineNumbers "fixes\server_saveVehicle.sqf";  //Saves target Object Vehicle to the instance_vehicle if it has a valid world id.
    "dayzSaveVehicle" addPublicVariableEventHandler {_id = (_this select 1) spawn server_saveVehicle};  //This is a event handler to call this function from client side

MySql Stored procedure
Code:
CREATE DEFINER=`dayz`@`localhost` PROCEDURE `proc_saveVehicle`(IN `p_worldvehicleid` BIGINT(20))
BEGIN
INSERT INTO `instance_vehicle`(`world_vehicle_id`,`last_updated`, `created`) VALUES (p_worldvehicleid,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP);
select LAST_INSERT_ID();
END

server_saveVehicle.sqf
Code:
private ["_targetObj","_targetClass","_targetPos","_targetDir","_targetDir","_targetWorldVehicleID","_targetInstanceVehicleID"];
_targetObj = _this select 0;
_targetClass = typeOf _targetObj;
_targetPos = getPos _targetObj;
_targetDir = getDir _targetObj;
_targetWorldVehicleID = 0;
_targetInstanceVehicleID = 0;
 
diag_log("SERVER: Attempting to save "+ str(_targetClass)+" at "+str(_targetPos));
_targetWorldVehicleID = [_targetObj] call fn_getWorldVehicleID;
if (_targetWorldVehicleID > 0) then {
diag_log ("SERVER: Vehicle ID:  " + str(_targetWorldVehicleID));
_targetInstanceVehicleID = [_targetWorldVehicleID] call fn_saveVehicle;
diag_log ("SERVER: Saved new vehicle "+ str(_targetClass)+" id " + str(_targetInstanceVehicleID));
 
_targetObj setVariable ["lastUpdate",time];
_targetObj setVariable ["ObjectID", _targetInstanceVehicleID, true];
_targetObj setVariable ["CharacterID", 0, true];
_targetObj call fnc_vehicleEventHandler;
dayz_serverObjectMonitor set [count dayz_serverObjectMonitor,_targetObj];
 
} else {
diag_log ("SERVER: Vehicle Class: " + str(_targetClass) +" does not have entry in world_vehicle table, unable to save this type of vehicle");
};

fn_saveVehicle.sqf
Code:
private ["_instanceVehicleID","_targetObj","_targetClass","_key","_data","_status","_result","_count"];
_targetClass = _this select 0;
_instanceVehicleID = 0;
diag_log ("Attempting to save to DB: " + str(_targetClass));
if (_targetClass > 0) then {
//Wait for HIVE to be free
waitUntil{!hiveInUse};
hiveInUse = true;
//Send request
    _key = format["CHILD:999:CALL `proc_saveVehicle` ('?'):[%1]:",_targetClass];
    diag_log ("Sending Query 1:  " + str(_key));
    _data = "HiveEXT" callExtension _key;
 
    _result = call compile format ["%1", _data];
    _status = _result select 0;
    _count = _result select 1;
    diag_log ("My Result:  " + str(_result));
    if (_status == "CustomStreamStart") then {
        diag_log ("Fetching: " + str(_count) +" rows");
            for "_i" from 1 to _count do {     
                diag_log ("Sending Query 2:  " + str(_key));
                _data = "HiveEXT" callExtension _key;
                _result = call compile format ["%1", _data];
                _instanceVehicleID = _result select 0;
                };     
            if (_count > 0) then {
                diag_log ("Vehicle saved with id " + str(_instanceVehicleID));         
            } else {
                diag_log ("ERROR: something went to shit!");
            };     
        };
//Release HIVE
hiveInUse = false;
} else {
diag_log ("ERROR: An attempt to save a vehicle with no valid world vehicle id was made.");
diag_log ("ERROR: Target vehicle class sent was " + str(_targetClass));
};
_instanceVehicleID

fn_getWorldVehicleID.sqf
Code:
private ["_saveWorldVehicleID","_targetObj","_targetClass","_key","_data","_status","_result"];
_saveWorldVehicleID = 0;
_targetObj = _this select 0;
_targetClass = typeOf _targetObj;
//Wait for HIVE to be free
waitUntil{!hiveInUse};
hiveInUse = true;
//Send request
      _key = format["CHILD:999:select world_vehicle.id from world_vehicle, vehicle where vehicle.id = world_vehicle.vehicle_id and vehicle.class_name = '?' and world_vehicle.world_id = '%2':[""%1""]:", _targetClass,1];
      diag_log ("Sending Query 1:  " + str(_key));
        _data = "HiveEXT" callExtension _key;   
        // _results = ["CustomStreamStart",#]  <-this is what we get back from the above query
      _result = call compile format ["%1", _data];
      _status = _result select 0;
      _count = _result select 1;
      diag_log ("My Result:  " + str(_result));
        //If we found something we get an array back, the first element will say "CustomStreamStart" the second element is the number of items we are going to get back.
        if (_status == "CustomStreamStart") then {
        diag_log ("Fetching: " + str(_count) + " rows");
            //We meed to retrieve _count times from the hive with the old query or else stuff gets screwed up, this can be corrected by usings limit 1.
            for "_i" from 1 to _count do {     
                //We sent the same key again to get the first result, if there is more than 1 _count then this is going to need to run again, each time with the same _key
                diag_log ("Sending Query 2:  " + str(_key));
                _data = "HiveEXT" callExtension _key;
                _result = call compile format ["%1", _data];
                //_result = [1] , dont forget to select it or else this will screw shit up.
                //the returned result is an array for each col returned from mysql, we want the first element element
                _saveWorldVehicleID = _result select 0;
                };     
            if (_count > 0) then {
                diag_log ("Found world_vehicle.id: " + str(_saveWorldVehicleID));         
            } else {
                diag_log ("ERROR: " + str(_targetClass) +" class has no data in world_vehicle table!");
            };     
        };
//Release HIVE
hiveInUse = false;
_saveWorldVehicleID


I need to test the whole thing and make sure its actually going to make the vehicle work, now to get some spawned vehicles on my test server and see if i can make them store into the dbase. this doesn't create some random vehicle id either it uses the auto increment from mysql to get the next id up, hence the need for the stored procedure.
 
this isn't 100% because at this time im only able to spawn and save the first vehicle,where the second call indicates that the stored procedure is still connected and then the server crashes with a mysql error indicating that the two queries are being sent to the database
 
This is absolutely stellar work! Would it be easier to assign random ID slots (like 987000 to 988000) for your code? That way it can do a different incremental?
 
Back
Top