celludriel 79 Posted February 13, 2017 Hey, I'm trying to trigger following eventhandler, that is attached to a "CargoNet_01_box_F": // create the eventhandler ContainerOpened that will reduce the supply drops and clean up the marker _drop addEventHandler ["ContainerOpened",{ [["Supply drop opened"]] call CTISHR_fnc_ctiLog; _container = (_this select 0); _currentSupplyDrops = missionNamespace getVariable "CURRENT_AMOUNT_OF_SUPPLY_DROPS"; missionNamespace setVariable ["CURRENT_AMOUNT_OF_SUPPLY_DROPS", (_currentSupplyDrops - 1)]; _markerName = _container getVariable "supplydropMarkerName"; deleteMarker _markerName; }]; This code runs serverside after spawning a "CargoNet_01_box_F", _drop contains that object. Yet when I open the inventory the eventhandler never triggers. This might be a clue, I believe the following appears in the serverlog when I do: 18:36:03 Error: Object(3 : 5) not found I hope it is releated cause I do have a lot of logging flying by at the moment I try it. Not that this error is saying much. Can it be this eventhandler only lives on my dedicated servers and when a player opens the box the box on the client side doesn't have the eventhandler ? I don't see any options to sync the eventhandler and MPEventHandler doesn't seem to be much of an option either. another attempt but still a nogo _drop addEventHandler ["ContainerOpened",{ [["Supply drop opened"]] call CTISHR_fnc_ctiLog; _container = (_this select 0); [_container] remoteExecCall ["SD_fnc_containerOpened", 2]; }]; function body if(!isDedicated) exitWith {}; params ["_container"]; [["Supply drop opened"]] call CTISHR_fnc_ctiLog; _currentSupplyDrops = missionNamespace getVariable "CURRENT_AMOUNT_OF_SUPPLY_DROPS"; missionNamespace setVariable ["CURRENT_AMOUNT_OF_SUPPLY_DROPS", (_currentSupplyDrops - 1)]; _markerName = _container getVariable "supplydropMarkerName"; deleteMarker _markerName; Same error appeared: 19:13:30 Error: Object(3 : 4) not found Wish I had more information about that error :( Share this post Link to post Share on other sites
igneous01 19 Posted February 13, 2017 How is the supply crate being created? With CreateVehicle or CreateVehicleLocal? Is there only 1 supply crate that all clients see, or does each client have their own version of the supply crate? The addHandler call should be run on the machine that 'owns' the crate. That means if the server created the crate, this could should only run on the server. What does CTISHR_fnc_ctiLog do? Is it just logging using diag_log? if there's other stuff happening here you need to check the locality of it. Share this post Link to post Share on other sites
celludriel 79 Posted February 13, 2017 Vehicle creation private _obj = createVehicle [_objectType, _supplyDropStart, [], 0, "NONE"]; Server is creating the supply create with this, I would think this crate is synced to each client ? Don't worry about ctiLog it's the simplest of functions params ["_logdata"]; if (DEBUG_ENABLED) then { diag_log format _logdata }; I guess the eventHandler isn't know on all the clients then, only explaination I have. I can solve the problem another way, but just for once I liked to see the eventHandlers of arma 3 do what they are supposed to do ! I guess they will work in a singleplayer environment when you make the handler on the client and run it on the client, but bleh so limiting. Share this post Link to post Share on other sites
igneous01 19 Posted February 13, 2017 Looking at the ContainerOpened event on the wiki, the arguments you pass in don't have to be local, but the effect of the add handler call is local to the machine. So as you have it setup now it should work, but I think this note gives a clue: Quote Triggers when cargo container is accessed by player. This event handler is similar to "InventoryOpened" EH, but needs to be assigned to the container rather than the player and cannot be overridden. Note: will trigger only for the unit opening container.. Maybe try adding the handler on all machines? The description seems a bit contradictory (what does it mean override? You should be able to add multiple handlers to this event). Do you see it logging the message at least when you run it currently? 1 Share this post Link to post Share on other sites
Larrow 2822 Posted February 14, 2017 9 hours ago, igneous01 said: The addHandler call should be run on the machine that 'owns' the crate. That means if the server created the crate, this could should only run on the server. Although the crate is created on the server the event needs to be added on each clients machine for it to trigger when a client opens it. Crate is added on the server. Client has event added so crate would be non local ( Global Argument ), when player opens the crate code is run ( Effect Local ). Something like... //Server TAG_fnc_suppliesOpened = { params[ "_container" ]; //Remove function call for container from JIP queue remoteExec [ "", format[ "crate_%1", _container call BIS_fnc_netId ] ]; //Tell all clients to remove their EH [ "REM", _container ] remoteExec [ "TAG_fnc_handleContainerEH", 0 ]; //No JIP they ether have the event or do not [["Supply drop opened"]] call CTISHR_fnc_ctiLog; _currentSupplyDrops = missionNamespace getVariable "CURRENT_AMOUNT_OF_SUPPLY_DROPS"; missionNamespace setVariable ["CURRENT_AMOUNT_OF_SUPPLY_DROPS", (_currentSupplyDrops - 1)]; _markerName = _container getVariable "supplydropMarkerName"; deleteMarker _markerName; }; //Where you create supply drop private _obj = createVehicle [_objectType, _supplyDropStart, [], 0, "NONE"]; _obj setVariable [ "supplydropMarkerName", /*name_of_marker*/ ]; //RE with Unique JIP queue name based off of object NetID [ "ADD", _obj ] remoteExec [ "TAG_fnc_handleContainerEH", 0, format[ "crate_%1", _obj call BIS_fnc_netId ] ]; //Clients TAG_fnc_handleContainerEH = { params[ "_mode", "_crate" ]; switch ( toUpper _mode ) do { case "ADD" : { //Add EH locally to client _openedEH = _crate addEventHandler [ "ContainerOpened", { params[ "_container", "_unit" ]; //handle opening on server [ _container ] remoteExec [ "TAG_fnc_suppliesOpened", 2 ]; }]; //Store local EH handle on the container _crate setVariable[ "openedEH", _openedEH ]; }; case "REM" : { //Get local EH handle _EH = _crate getVariable "openedEH"; if !( isNil "_EH" ) then { //Remove the local EH _crate removeEventHandler [ "ContainerOpened", _EH ]; }; }; }; }; Untested. 1 Share this post Link to post Share on other sites
celludriel 79 Posted February 14, 2017 Ok Igneous and Larrow I'm see how it works then. I have a few concerns though, most importantly JIT. New clients need to get the event handlers, now this is probably not to hard to accomplish. It does seems a lot of data that needs to be synced all the time though with a lot that can go wrong. I'm getting the feeling although I can get it to work like this I have to look for a better solution to the issue. I'm doing all this just to lower the counter for current drops if a player "finds" one of the supply drops. Preferably I want the server to handle this logic, the clients shouldn't have to do any work for this. So sending over eventhandlers to clients ... sounds ... yukkie ... I could spawn a monitor thread at server side that checks every five seconds if there is a player near to the drop, when it is the players have "found" the drop and I can do cleanup severside. Sounds cleaner then the monkeywork I'm doing now. However I'm sure I might have to do other eventhandling at one point where this knowledge comes in handy. Thanks for brainstorming with me ! Share this post Link to post Share on other sites
Larrow 2822 Posted February 14, 2017 1 hour ago, celludriel said: I have a few concerns though, most importantly JIT. New clients need to get the event handlers, now this is probably not to hard to accomplish. As easy as adding a unique String for the JIP part of remoteExec. Changed code above to handle JIP by adding a unique JIP queue name based of the objects NetID. 1 hour ago, celludriel said: It does seems a lot of data that needs to be synced all the time though with a lot that can go wrong. I dont see a lot of data that needs to be kept in sync, you send a reference of an Object and a String across the network via remoteExec, any JIP also receive the Object and String with function call and the engine just handles the crate EH. Once opened by someone all clients remove their events and the server removes the RE call from the queue. 1 hour ago, celludriel said: Preferably I want the server to handle this logic, the clients shouldn't have to do any work for this. Would not call it much work, its not like their keeping track of anything, all they do is either add or remove an event. You could even move the remove event from the clients ContainerOpened EH and add it to the server function instead (see changed code). 1 hour ago, celludriel said: So sending over eventhandlers to clients ... sounds ... yukkie ... I could spawn a monitor thread at server side that checks every five seconds if there is a player near to the drop, when it is the players have "found" the drop and I can do cleanup severside. Its a object reference and a String that is pretty much forgotten about until the engine comes to fire it off. I would much prefer to add a client event than add another thread to the servers scheduler. Why start up a scheduler thread on the server when you can just let the engine handle an event for you. 1 Share this post Link to post Share on other sites
celludriel 79 Posted February 14, 2017 You make some valid points, guess I've always been client shy, the less responsibility to my clients the happier I am. I do this in my day job as well, although I have to admit, there I have loadbalancing and server sharding ... so yeah ... programming sqf is a whole other beast Share this post Link to post Share on other sites
celludriel 79 Posted February 14, 2017 Thanks Larrow, I got it to work with your implementation. For those interested you can see what I wrote here: https://github.com/Celludriel/Simple_CTI/tree/develop/custom/modules/SupplyDropModule I wonder though, syncing eventhandlers to clients is something that happens often in code. I think this can be written more generic where we send the handling of the event to the client in the form of a parameter. Then the function to add or remove eventhandlers on client side can be totally generic and reusable. For now I'll keep it as is, but if I have to do this more often in the future I might refactor this to something generic if possible. Share this post Link to post Share on other sites