Jump to content

Scripting API - Event.dead not called if an object isn't immediately dead


Recommended Posts

  • 4 weeks later...

Bumping the thread for more visibility. It's kinda crazy that they broke such a crucial api functionality that many scripts use to create worthwhile missions and training environments, and then haven't fixed it for almost a year.  Please get this fixed so the scripting and multiplayer community can continue to prop up your game for you despite the lack of dynamic campaigns or many useful mission making features in the base game.


Edited by CarlosNO2
  • Like 1
Link to comment
Share on other sites

  • 2 months later...
  • 3 weeks later...
  • 2 months later...

As of Jan. 2023, this issue seem to still be present.  You cannot getGroup() on the event.initiator of a UNIT_LOST if the unit was a ground unit.  Seems to work for aircraft (probably due to timing - the aircraft is likely still in the process of crashing and is still a valid unit)

Link to comment
Share on other sites

  • 3 months later...

I still have lots of issues with the getGroup() bug.

I have been trying to figure out exactly what is going on and have created a test mission where there is one apache(client) throwing hellfires at red BTR-80(ROE: weapons hold).
I notice that every time a unit is killed, it is rather instantly followed by another kill event. Now this causes some issues obviously since Event is then overwritten by this new Event and Event.target. So to test my theses, I set up a few if statements which each had a outText involved, so I could see where in the code I was.

 

if Event.id == world.event.S_EVENT_KILL then

		trigger.action.outText("Kill event registered", 5)
		
	if Event.initiator:getPlayerName() ~= nil then
			
		trigger.action.outText("Object was killed by a human player", 5)
					
		UnitID = Event.target.id_					-- Made global so i could call a function and test the code below a little while later
										
			for index, data in pairs(mist.DBs.deadObjects) do
				if UnitID == data.objectData.unit.id_ then
						trigger.action.outText("Database match found", 5)
					local GroupName = data.objectData.groupName
					break
				end
					trigger.action.outText("No databasematch found", 5)
			end

			if GroupName ~= nil then
			trigger.action.outText("Group name of killed vehicle is: "..GroupName, 5)
			end
			trigger.action.outText("Groupname has not been defined", 5)		-- Notice this is the last output on screen, before a new killevent is triggered.
		end										-- The loop above doesn't provide any data.
	end

 

AFGJ81rQlBHbTNdpmllpGVfR8APOUukzSw8scmK7

 

Note the two kill events in line 1 and 4. Note also that the for loop in the code does not capture data from the mist.DBs.deadObjects database.
If I just a few seconds later, trigger my function from the F10 menu, the image above is shown, with the data from the same database.
Unless I'm missing something here, it seems that when the kill event occurs and I write a code to get the groupName off from the database, the data has not been written yet.
Of course I can't tell what getGroup() method does to fetch data, but if it is done in a similar fashion then timing here seems to be the issue.

Any thoughts ?

Oh, here is the code from the test fuction called from the F10 menu:
 

function test()
	
	for index, data in pairs(mist.DBs.deadObjects) do
		trigger.action.outText(mist.utils.tableShow(data), 5)
				
			if UnitID == data.objectData.unit.id_ then
				trigger.action.outText(data.objectData.groupName, 5)		-- This is the outtext displayed at the very bottom
			end
	end
end

 


Edited by Chesster
Added test code, and removed broken image link
Link to comment
Share on other sites

  • 3 weeks later...

This is really breaking a lot of stuff. I use landmines in a couple missions, to "kill" patrols of vehicles randomly roaming the area. In the past, I simply used the dead event and verified the coalition and then fetched the unit and used getPoint() to spawn casualties for MEDEVAC and or defending ground troops and ambushes etc. based on the location of the dead/killed unit(!).

This does no longer work, as a lot of the get-functions do no longer work?

Can't we just get one(!) event that fires before that change to static happens? Maybe s_event_unit_lost or s_event_kill and then switch to the static object and fire the dead event?

This is utterly frustrating and as others pointed out, it affects a lot of useful scripts in mission building and especially more dynamic multiplayer missions.

I can't see, why this is difficult to fix, we just need one of the three(!) events related to a dying/dead unit to remain the information to provide with getGroup(), getCategory(), getPoint(), getTypeName(), getAttributes() etc.

Please, give us a way to monitor and use dead units in scripts, again, without crazy workarounds ( to monitor position before a dead event we would need to update the position A LOT and that's definitely hitting performance, especially in larger MP missions).

  • Like 2

Shagrat

 

- Flying Sims since 1984 -:pilotfly:

Win 10 | i5 10600K@4.1GHz | 64GB | GeForce RTX 3090 - Asus VG34VQL1B  | TrackIR5 | Simshaker & Jetseat | VPForce Rhino Base & VIRPIL T50 CM2 Stick on 200mm curved extension | VIRPIL T50 CM2 Throttle | VPC Rotor TCS Plus/Apache64 Grip | MFG Crosswind Rudder Pedals | WW Top Gun MIP | a hand made AHCP | 2x Elgato StreamDeck (Buttons galore)

Link to comment
Share on other sites

  • 3 months later...

I wouldn't be surprised if this is related to the world.removeJunk() method crashing. 

When a unit's health is reduced all the way, the unit becomes nil in memory. Meanwhile, it continues to burn, only to explode much later. Once it explodes, the original model is replaced with a destroyed model and then sends a kill event. It appears cleaning the server with removeJunk() has a much higher likelihood of crashing the server when damaged nil units exist like this.

The introduction of a critical damage event would be nice, but I feel like the most important thing is not making units nil before complete transition to death model after the kill event. That should solve a lot of problems preventing the community from gaining momentum with mission building.

I've been able to form workarounds for tracking the complete destruction of groups, but it requires building a mirrored table of names and does nothing to help the removeJunk() or other issues

Link to comment
Share on other sites

10 hours ago, FusRoPotato said:

When a unit's health is reduced all the way, the unit becomes nil in memory.

Are you sure about that? From what I surmise (no deeper knowledge on my part either) is that the following happens:

  • When an AI unit's health is reduced to zero and it is determined that the unit is to enter the 'cook-off' phase rather than exploding outright, the AI unit is removed from the game (not necessarily nilled, but it is entirely possible that the memory structure in the C backend is freed). The reference (pointer) to the table that represents the AI unit in the Lua glue will now return nil when you try the Unit.getByName() accessor. However, if you are using a stale pointer to the unit that you had allocated before the unit went into cooking-off, you'll likely receive an error, as that reference points to a no-longer existing table/structure. This is one of the issues that pre-existing scripts can run into.
  • No "death" event is invoked by the game (which leads us into this threat's main point)
  • Instead of the (AI) Unit, for cooking-off purposes, DCS inserts a static object with the same name and type as the Unit that it just removed. Since unit names in DCS must be unique, this static object effectively replaces the Unit.
  • After a while a "death" event is invoked, with the Static Object as initiator, not not the Unit that originally caused it. This can result in havoc in your scripts if you name-check and match with a cached former AI Unit because that unit's reference is stale. As it is now, it has resulted in may unexpected behaviors in many scripts that assume that - after name-matching - the initiator is a Unit, not Static Object.
  • Once the static death event was sent, the static is replaced by yet another model, a wreckage, that can't be accessed through DCS means, and that can only be removed with removeJunk().
  • After a while, the game removes the wreckage as well <-- this is where I suspect the root cause for removeJunk()'s crashes
     
10 hours ago, FusRoPotato said:

I wouldn't be surprised if this is related to the world.removeJunk() method crashing.

Although there might be a connection, I don't see this as a stringent one, because...

10 hours ago, FusRoPotato said:

It appears cleaning the server with removeJunk() has a much higher likelihood of crashing the server when damaged nil units exist like this.

Not that I have any proof, I'm merely guessing here, but I think that there's a probability that when DCS removes wreckage after some time (last bullet point in my enumeration above), it sometimes forgets to clear that table entry, and eventually a removeJunk() call into the C backend will crash while trying to access a stale link from the wreckage table. And the reason that this seemingly only happens on servers is simply because server missions tend to run for much, much longer, increasing the likelihood of it to happen.

So I theorize (no proof) that removeJunk() sometimes fails because internally, DCS occasionally screws up some wreckage table when it removes the wreckage after a long wait and forgets to remove a reference in a related table. This would have happened even if we had access to removeJunk() before ED changed the death notification order of events. I guess we'll never know, except that I hope that eventually this is remedied.


Edited by cfrag
  • Like 2
Link to comment
Share on other sites

2 hours ago, cfrag said:

Not that I have any proof, I'm merely guessing here,

It all sounds like very good guesswork to me. We had experimented in the past and found that cleaning junk immediately after sending vehicles into the cookoff state would have a high chance of causing both server and client crashes. Using an internal timer that resets on death/kill events to delay cleaning reduced crashing by quite a bit, but it was still fallible for avoiding cooked off vehicles. It would still crash after several hours on average. Now I'm wondering if it'd be worth a shot to reset the countdown on detected ground unit hits instead. If it works, I'd be more sure about it.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...