Jump to content

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


Recommended Posts

also bump, this is a critical issue.

  • Thanks 2

ChromiumDis.png

Author of DSMC, mod to enable scenario persistency and save updated miz file

Stable version & site: https://dsmcfordcs.wordpress.com/

Openbeta: https://github.com/Chromium18/DSMC

 

The thing is, helicopters are different from planes. An airplane by it's nature wants to fly, and if not interfered with too strongly by unusual events or by a deliberately incompetent pilot, it will fly. A helicopter does not want to fly. It is maintained in the air by a variety of forces in opposition to each other, and if there is any disturbance in this delicate balance the helicopter stops flying; immediately and disastrously.

Link to comment
Share on other sites

On 3/20/2022 at 6:23 PM, Apple said:

Since the last BETA update, the event.dead isn't called, if a unit isn't immediately dead, see attached demo. The death is registered in the ME event log, but the API isn't called. Reported by dcs-online.de and [WP] Stingray in the Moose Discord.

event dead test.miz 8.62 kB · 13 downloads

Hi, I'm not completely sure that I don't miss something but : I did some tests tonight with both KILL and DEAD script events and I had no issue (player/client vs dynamically spawn or ME created targets.

I played the "event dead test.miz" and env.info does work for the damaged vehicle burning and then exploding (but info only wrote event ID - 8 - and initiator - Ground-1-1 - in DCS.txt/log, because there is no weapon or target for dead event). So is the issue solved since march ? Is the issue online/multiplayer specific ?

Personnaly the only problem I had with my script, for scoring based on KILL event, was that the target (I want to track units only) can be a unit or a static (directly destroyed target or burning target), so I changed code for : (Object.getCategory(event.target) == 3 or Object.getCategory(event.target) == 1) for script to work again in all cases. But no issues with event.

Link to comment
Share on other sites

3 hours ago, toutenglisse said:

Hi, I'm not completely sure that I don't miss something but : I did some tests tonight with both KILL and DEAD script events and I had no issue (player/client vs dynamically spawn or ME created targets.

I played the "event dead test.miz" and env.info does work for the damaged vehicle burning and then exploding (but info only wrote event ID - 8 - and initiator - Ground-1-1 - in DCS.txt/log, because there is no weapon or target for dead event). So is the issue solved since march ? Is the issue online/multiplayer specific ?

Personnaly the only problem I had with my script, for scoring based on KILL event, was that the target (I want to track units only) can be a unit or a static (directly destroyed target or burning target), so I changed code for : (Object.getCategory(event.target) == 3 or Object.getCategory(event.target) == 1) for script to work again in all cases. But no issues with event.

The problem comes when you try to identify whether the target was a ground unit or a ship for example.

Unit.Category has different values than StaticObject.Category. Once a dead unit starts reporting as static, you can no longer tell weather it was static or unit before death, and you wont know how to interpret its getDesc().category.

A getDesc().category value of 2 can be either a GROUND_UNIT if the target was a unit before death, or a WEAPON if it was a staticobject, and you have no way of telling which it is, because the Object.getCategory() has started reporting it as static after death, regardless of what it started out as.

  • Thanks 1
Link to comment
Share on other sites

On 5/13/2022 at 7:28 AM, Dzsekeb said:

The problem comes when you try to identify whether the target was a ground unit or a ship for example.

Unit.Category has different values than StaticObject.Category. Once a dead unit starts reporting as static, you can no longer tell weather it was static or unit before death, and you wont know how to interpret its getDesc().category.

A getDesc().category value of 2 can be either a GROUND_UNIT if the target was a unit before death, or a WEAPON if it was a staticobject, and you have no way of telling which it is, because the Object.getCategory() has started reporting it as static after death, regardless of what it started out as.

On my side everything seems to be correctly identified, using event.target:getDesc()["category"]. (target for KILL event is initiator for DEAD event but it acts the same).

Edit : removed useless stuff


Edited by toutenglisse
Link to comment
Share on other sites

The point is that the first shouldn't be a category 3 static, if it was a unit it should be category 1. From hoggit:

Object.Category
  UNIT    1
  WEAPON  2
  STATIC  3
  BASE    4
  SCENERY 5
  Cargo   6
  • Thanks 1

ChromiumDis.png

Author of DSMC, mod to enable scenario persistency and save updated miz file

Stable version & site: https://dsmcfordcs.wordpress.com/

Openbeta: https://github.com/Chromium18/DSMC

 

The thing is, helicopters are different from planes. An airplane by it's nature wants to fly, and if not interfered with too strongly by unusual events or by a deliberately incompetent pilot, it will fly. A helicopter does not want to fly. It is maintained in the air by a variety of forces in opposition to each other, and if there is any disturbance in this delicate balance the helicopter stops flying; immediately and disastrously.

Link to comment
Share on other sites

11 minutes ago, toutenglisse said:

On my side everything seems to be correctly identified, using event.target:getDesc()["category"]. (target for KILL event is initiator for DEAD event but it acts the same).

Some examples here (with corresponding pictures) : Static unit BTR82 burning does trigger KILL when explodes and getDesc() returns ground unit and correct points awarded,

Static-damaged-BTR.jpg

Static structures idem (Static outpost damaged then exploding get correct getDesc() - "ground unit" 80pts, and Static TV tower get correct "structure" 180pts),

Static-structures-killed.jpg

Ships unit are also correctly identified by getDesc() - "ship" 220pts, but even finishing last % lifepoint with guns they get killed immediately, while they still exist, burning before exploding/sinking, so they always show as units when killed/dead.

Kilo-unit-gun-killed.jpg

I assume in your examples "target object category" is event.target:getCategory(), and "target category" is event.target:getDesc()['category']


If object category returns as 3, it means its a static object, in which case getDesc()['category'] should be compared to the StaticObject.Category enum, NOT Unit.Category.

According to StaticObject.Category everything that died in your first two examples was a StaticObject of category STATIC, not a UNIT.

Your third example shows object.category as 1 which correctly means UNIT, but then strangely the subtype seems to also be 1, which means helicopter, not 3 for ship.

Link to comment
Share on other sites

27 minutes ago, Dzsekeb said:

I assume in your examples "target object category" is event.target:getCategory(), and "target category" is event.target:getDesc()['category']...

No, I just used Object.getCategory(event.target) for the first and event.target:getCategory() for the second, just to see if they return the same number, which they do.

event.target:getDesc()["category"] returns correctly 0 for plane, 1 for helo, 2 for ground (with an added difference between soldiers and vehicles using string.match), 3 for ships and 4 for structures, whatever the state of the target:getCategory (unit or static for initial unit, or static for initial static). EDIT : it is what gives me the points, relative to unit category.

At least it is what occurs on my script and in SP conditions.

@chromium yes, but while it is now a fact that an initially unit can be 1 (unit) or 3 (static), relative to destroyed on impact or battle damaged not yet destroyed, my concern is that I don't see an issue to correctly identifying the target category with getDesc, but I am 80% sure it is because I miss something - my case seems to work "perfectly" but it is just my case.

The thing is that the inital OP concern is event (dead or kill) not firing when target is not immediately destroyed on impact but BDA, which I don't see (it does fire on all cases on my side).


Edited by toutenglisse
in post
Link to comment
Share on other sites

The point is the "fact", what we're asking for is a call on unit deaths to be able to make a distinction between  (for example) a static BTR-82A killed and a unit BTR-82A killed.

And for many script/mod this is a very important thing.


Edited by chromium

ChromiumDis.png

Author of DSMC, mod to enable scenario persistency and save updated miz file

Stable version & site: https://dsmcfordcs.wordpress.com/

Openbeta: https://github.com/Chromium18/DSMC

 

The thing is, helicopters are different from planes. An airplane by it's nature wants to fly, and if not interfered with too strongly by unusual events or by a deliberately incompetent pilot, it will fly. A helicopter does not want to fly. It is maintained in the air by a variety of forces in opposition to each other, and if there is any disturbance in this delicate balance the helicopter stops flying; immediately and disastrously.

Link to comment
Share on other sites

12 minutes ago, chromium said:

The point is the "fact", what we're asking for is a call on unit deaths to be able to make a distinction between  (for example) a static BTR-82A killed and a unit BTR-82A killed.

And for many script/mod this is a very important thing.

 

Got it, effectively they act/return exactly the same when not destroyed/dead on impact, but after burning.

Link to comment
Share on other sites

@chromium FWIW I added a small check in my KILL event, a BIRTH event that updates unit only nameTable, so when a KILL happens (would be same for death) a message tells if it was initially a Unit or a StaticObject.

Here the code I use for event (I put a comment before any external table/sound so it can run standalone - uses Mist) :

Spoiler
function KillEvent(event)

		if event.id == world.event.S_EVENT_BIRTH then
		MissionUnits = mist.makeUnitTable({'[all]'}, 'static')
		elseif event.id == world.event.S_EVENT_KILL then
		trigger.action.outText('target object category: ' .. event.target:getCategory(),10)
		local UnitTrue = 0
		if #MissionUnits > 0 then
		for k, name in pairs(MissionUnits) do
		if event.target:getName() == name then
		trigger.action.outText('Initially target object category was a Unit',10)
		UnitTrue = UnitTrue + 1
		end
		end
		if UnitTrue == 0 then
		trigger.action.outText('Initially target object category was a Static Object',10)
		end
		end
		for h = 1, 2 do
		local AllHumanUnits = coalition.getPlayers(h)
		if event.initiator ~= nil and event.target ~= nil and (Object.getCategory(event.target) == 3 or Object.getCategory(event.target) == 1) and event.target:getCoalition() == event.initiator:getCoalition() then
		for i = 1, #AllHumanUnits do
		if event.initiator == AllHumanUnits[i] then
		HumanId = AllHumanUnits[i]:getGroup():getID()
		trigger.action.outTextForGroup(HumanId, 'You killed a friendly unit. Reseting support points.',5)
		--trigger.action.outSoundForGroup(HumanId, 'l10n/DEFAULT/FRIENDLYKILL.ogg')
		--HumDataTable[HumanId][2] = 0
		end
		end
		elseif event.initiator ~= nil and event.target ~= nil and (Object.getCategory(event.target) == 3 or Object.getCategory(event.target) == 1) and event.target:getCoalition() ~= event.initiator:getCoalition() then
		for i = 1, #AllHumanUnits do
		if event.initiator == AllHumanUnits[i] then
		HumanId = AllHumanUnits[i]:getGroup():getID()
		if event.target:getDesc()["category"] == 0 then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 150 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 150
		elseif event.target:getDesc()["category"] == 1 then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 110 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 110
		elseif event.target:getDesc()["category"] == 2 then
		local typeName = string.lower(event.target:getTypeName().."")
		if string.match(typeName, "infantry") or string.match(typeName, "paratrooper")  or string.match(typeName, "comm")
		or string.match(typeName, "manpad") or string.match(typeName, "soldier") then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' killed. 20 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 20
		else
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 80 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 80
		end
		elseif event.target:getDesc()["category"] == 3 then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 220 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 220
		elseif event.target:getDesc()["category"] == 4 then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 180 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 180
		end
		end
		end
		end
		end
		end

end
mist.addEventHandler(KillEvent)

 

Edit : removed useless stuff


Edited by toutenglisse
in post
Link to comment
Share on other sites

On 5/13/2022 at 3:05 PM, toutenglisse said:

The thing is that the inital OP concern is event (dead or kill) not firing when target is not immediately destroyed on impact but BDA, which I don't see (it does fire on all cases on my side).

I'm pretty sure that some of this is attributed to the way our code is structured. Since people tend to code the way they structure the world in their minds, I can easily imagine (because some of my code works the same way) that one of the first guards in the event processor is something like this:

if event.target:getCategory() ~= 1 then return end -- not a ground unit, ignore

So their particular implementation for a death event might fire, but since a core assumption (objects don't change category over their life cycle) no longer holds true, it fails. As a result, a lot of code has to be examined, and it makes us wonder what other central unit life cycle assumptions no longer hold true or may change without notice. 

  • Like 1
Link to comment
Share on other sites

Il 13/5/2022 at 18:35, toutenglisse ha scritto:

@chromium FWIW I added a small check in my KILL event, a BIRTH event that updates unit only nameTable, so when a KILL happens (would be same for death) a message tells if it was initially a Unit or a StaticObject. Picture example with a dynamically spawned unit that gets BDA, then explodes as a static, but identified as initially Unit.

Here the code I use for event (I put a comment before any external table/sound so it can run standalone - uses Mist) :

  Mostra contenuto nascosto
function KillEvent(event)

		if event.id == world.event.S_EVENT_BIRTH then
		MissionUnits = mist.makeUnitTable({'[all]'}, 'static')
		elseif event.id == world.event.S_EVENT_KILL then
		trigger.action.outText('target object category: ' .. event.target:getCategory(),10)
		local UnitTrue = 0
		if #MissionUnits > 0 then
		for k, name in pairs(MissionUnits) do
		if event.target:getName() == name then
		trigger.action.outText('Initially target object category was a Unit',10)
		UnitTrue = UnitTrue + 1
		end
		end
		if UnitTrue == 0 then
		trigger.action.outText('Initially target object category was a Static Object',10)
		end
		end
		for h = 1, 2 do
		local AllHumanUnits = coalition.getPlayers(h)
		if event.initiator ~= nil and event.target ~= nil and (Object.getCategory(event.target) == 3 or Object.getCategory(event.target) == 1) and event.target:getCoalition() == event.initiator:getCoalition() then
		for i = 1, #AllHumanUnits do
		if event.initiator == AllHumanUnits[i] then
		HumanId = AllHumanUnits[i]:getGroup():getID()
		trigger.action.outTextForGroup(HumanId, 'You killed a friendly unit. Reseting support points.',5)
		--trigger.action.outSoundForGroup(HumanId, 'l10n/DEFAULT/FRIENDLYKILL.ogg')
		--HumDataTable[HumanId][2] = 0
		end
		end
		elseif event.initiator ~= nil and event.target ~= nil and (Object.getCategory(event.target) == 3 or Object.getCategory(event.target) == 1) and event.target:getCoalition() ~= event.initiator:getCoalition() then
		for i = 1, #AllHumanUnits do
		if event.initiator == AllHumanUnits[i] then
		HumanId = AllHumanUnits[i]:getGroup():getID()
		if event.target:getDesc()["category"] == 0 then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 150 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 150
		elseif event.target:getDesc()["category"] == 1 then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 110 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 110
		elseif event.target:getDesc()["category"] == 2 then
		local typeName = string.lower(event.target:getTypeName().."")
		if string.match(typeName, "infantry") or string.match(typeName, "paratrooper")  or string.match(typeName, "comm")
		or string.match(typeName, "manpad") or string.match(typeName, "soldier") then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' killed. 20 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 20
		else
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 80 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 80
		end
		elseif event.target:getDesc()["category"] == 3 then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 220 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 220
		elseif event.target:getDesc()["category"] == 4 then
		trigger.action.outTextForGroup(HumanId, event.target:getDesc()["displayName"] .. ' destroyed. 180 support points earned.',5)
		--HumDataTable[HumanId][2] = HumDataTable[HumanId][2] + 180
		end
		end
		end
		end
		end
		end

end
mist.addEventHandler(KillEvent)

 

BDA-then-Kill-DynSpwn-Unit.jpg

This should not going to work if the objects is not spawned, cause birth event don't fire on units already present in the mission file except for aircrafts.

ChromiumDis.png

Author of DSMC, mod to enable scenario persistency and save updated miz file

Stable version & site: https://dsmcfordcs.wordpress.com/

Openbeta: https://github.com/Chromium18/DSMC

 

The thing is, helicopters are different from planes. An airplane by it's nature wants to fly, and if not interfered with too strongly by unusual events or by a deliberately incompetent pilot, it will fly. A helicopter does not want to fly. It is maintained in the air by a variety of forces in opposition to each other, and if there is any disturbance in this delicate balance the helicopter stops flying; immediately and disastrously.

Link to comment
Share on other sites

10 hours ago, chromium said:

This should not going to work if the objects is not spawned, cause birth event don't fire on units already present in the mission file except for aircrafts.

It does work with mission editor created units (I put a BTR82 unit and a BTR82 static and both were correctly identified when destroyed after burning).

EDIT : that said, I have dynamic units spawning at start of the mission where I tested it (even the player slots are client) so I have not verified that BIRTH event fires with ME units specifically. But you can still run a MissionUnits = mist.makeUnitTable({'[all]'}, 'static') at mission start if it doesn't, and check for initially static or unit at death/kill will work.

EDIT 2 : I've just verified in a new mission with only Mist and the "Killevent", 1 "player" F18 with AP rounds, 1 Unit and 1 Static BTR82, and effectively Birth event doesn't fire (script error because MissionUnits table doesn't exist) . But then I just added MissionUnits = mist.makeUnitTable({'[all]'}, 'static') before "Killevent" script and it worked.

Edit : removed useless stuff

 


Edited by toutenglisse
in post
Link to comment
Share on other sites

to be honest, I'm not looking for a workaround. I'm going to wait for the fix. I have an entire mod (DSMC), that I won't run on other scripts as mist or else, of thousands lines of code... and it must be reliable as rock solid or else it won't work. I can't rework one of the core brick of the mod due to a reported bug... since it's reported, I assume this is a recognized bug and it will be fixed.

  • Thanks 1

ChromiumDis.png

Author of DSMC, mod to enable scenario persistency and save updated miz file

Stable version & site: https://dsmcfordcs.wordpress.com/

Openbeta: https://github.com/Chromium18/DSMC

 

The thing is, helicopters are different from planes. An airplane by it's nature wants to fly, and if not interfered with too strongly by unusual events or by a deliberately incompetent pilot, it will fly. A helicopter does not want to fly. It is maintained in the air by a variety of forces in opposition to each other, and if there is any disturbance in this delicate balance the helicopter stops flying; immediately and disastrously.

Link to comment
Share on other sites

  • 3 weeks later...
  • ED Team
22.03.2022 в 00:48, Grimes сказал:

This was discovered and reported on Saturday. 

Jeff, please contact me in Discord regarding this issue.

Men may keep a sort of level of good, but no man has ever been able to keep on one level of evil. That road goes down and down.  
Можно держаться на одном уровне добра, но никому и никогда не удавалось удержаться на одном уровне зла. Эта дорога ведёт вниз и вниз.

G.K. Chesterton

DCS World 2.5: Часто задаваемые вопросы

Link to comment
Share on other sites

  • 2 weeks later...

Would be nice to have this fix soon,.. I have many scripts failing..

Does this also involves infantry?  Having the same issue while calling the getGroup on a dead unit...  or this is not allowed anymore?

 


Edited by MarcosR
Link to comment
Share on other sites

12 hours ago, MarcosR said:

Would be nice to have this fix soon,.. I have many scripts failing..

Does this also involves infantry?  Having the same issue while calling the getGroup on a dead unit...  or this is not allowed anymore?

 

 

You can't getGroup of a static object, which the dead unit now is...

Link to comment
Share on other sites

13 hours ago, MarcosR said:

Having the same issue while calling the getGroup on a dead unit.

This is one of the main stumbling blocks for many scripts: when the dead event occurs, many scripts access the unit's group via getGroup(). Static objects have (currently) no getGroup() method implemented, so the invocation fails and your mission breaks when the unit is replaced by a static object and that static object subsequently invokes a dead event. There currently is no remedy if your code depends on retrieving the group (to track if a specific group has been destroyed) - you'll have to resort to regularly iterate all interesting groups and determine if they are still alive. If you are accessing the group just for completeness, something similar to

local theGroup = nil
if theUnit.getGroup then 
	theGroup = theUnit:getGroup()
end

if theGroup then 
  -- do whatever you want with the group
else
  -- we probably have a static object 
end

should help in your code.

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...