Assert in BP2-14, 22.2 Stable
Assert: "Objects[aip->target_objnum].type == OBJ_SHIP || Objects[aip->target_objnum].type == OBJ_WEAPON || Objects[aip->target_objnum].type == OBJ_DEBRIS || Objects[aip->target_objnum].type == OBJ_ASTEROID || Objects[aip->target_objnum].type == OBJ_WAYPOINT" File: aicode.cpp Line: 10027 This function just discovered that Gemini 2 has an invalid target object type of 0. This is bad. Please report!
ntdll.dll! NtWaitForSingleObject + 20 bytes
KERNELBASE.dll! WaitForSingleObjectEx + 142 bytes
fs2_open_22_2_0_x64_AVX-FASTDBG.exe!
Use Debug to break into Debugger, Exit will close the application.
ntdll.dll! NtWaitForSingleObject + 20 bytes
KERNELBASE.dll! WaitForSingleObjectEx + 142 bytes
fs2_open_22_2_0_x64_AVX-FASTDBG.exe!
Further detail from an initial investigation:
- this is not trivially reproducable
- the crash happens, specifically, in
guard_object_was_hitwhen checking whether the reference to the object being guarded is still valid - according to @MoerasGrizzly, the guarded ship was still present in mission when this assertion fired
Reproducing this has been nigh impossible. and yet....
Based on a multi hour code dive, merged PR #5050 may in fact fix this issue.
The suspected cause is this:
- On the frame where a ship died, its
should_be_deadwas applied and all ai references to it are cleared. - Coders assume everything is good because all the ai info is cleared and the ship will be removed at the end of the frame.
- After the application of the flag but before the end of the frame, one of the object or ship loops in the ai code chooses the dying ship to be the target of another ship.
- The object is cleared at the end of the frame and the object type becomes
OBJ_NONE, aka 0, but the ai info is not searched and purged again, since that is done when the flag is applied. - On one of the immediately subsequent frames, the second ship's target is not changed because there is a timestamp that limits target changes.
- The ship that ship 2 is guarding is hit and it attempts to figure out if it should switch targets, but the old target is invalid, triggering the assert.
5050 fixes this by adding a check for the should_be_dead flag to most of these loops, except where it does no harm and changes behavior.
@MoerasGrizzly please report if you encounter this bug again after 23.0 is released.
Now that 23.0 has been released and 23.2 is on the verge of release, I'd say this has indeed been fixed.