Jump to content

Trouble with Script - unit == null is skipped but crashed on "unit doesn't exist"


Go to solution Solved by cfrag,

Recommended Posts

Posted

Hi all,

I'm not a programmer and relatively new to lua and DCS MSE.  I am not asking for someone to rewrite, or write the script, just point me in a direction, or explain to me why it is doing what it's doing.  Als I will attach the full script at the end.  At the end of the script is a comment section containing an outline of the script and what I think the flow is.

I am trying to write a script that will display a F10Other menu to clients that enter a helo.  They can choose one of two options that will give them the bearing and distance to a "hot Landing Zone".  I use the scheduleFunction to repeat the message of distance and bearing every 20 seconds. So far I have only tested by myself.  It seems to work up until the point I select another aircraft, or if I crash.

FIRST ISSUE

Once I leave the current unit, or crash, I get an error message about 20-30 seconds later stating the "unit does not exist".  What confuses me is right before the line that the scripts crashes, I have a check to see if the unit is nill, if it is nill, then it isn't supposed to execute the line that crashes.  I've attached a screenshot showing the error message and the related section of the script.

The section of script is 

   local function inFlightDistHead(tempTBL, time) 
     local ourArgument = tempTBL[1]
     local uObject = tempTBL[2]
     local landingZone = tempTBL[3]
     local gID = tempTBL[4]
     -- add slight delay for multiplayer timing
     for i = 1, 333333333 do --[[ do nothing ]] end
     
     -- Simple error check
     if uObject == nil then
        trigger.action.outText(" Sorry, but uint object is nil",15)  
        ourArgument= 1
       
--      trigger.action.outText("Unit life is ".. uObject:getLife(), 10)    
     -- trigger.action.outTextForGroup(gID,"Inside schedule function ourArgument is  " .. ourArgument.. ' and the landing zone is ' .. landingZone .. ' degrees',  10)
     elseif ourArgument == 53 and timer.getTime() < 1800 then
      trigger.action.outText("INSIDE LOOP: Unit life is ".. uObject:getLife(),10)   --  THIS IS THE LINE TWHERE THE "UNIT DOES NOT EXIST OCCURS   

      local cDistance, cHeading = distanceHeading(uObject, landingZone)
      trigger.action.outTextForGroup(gID, "Distance to " .. landingZone .. " is " .. cDistance.. ' nm at a heading of ' .. cHeading .. ' degrees',  10)
      trigger.action.outSoundForCoalition(2 , "shiny-sound-effect.ogg" )
      -- Keep going AKA_Message_Output
      return (time + msgInterval)
     else
      -- That's it we're done looping
      trigger.action.outTextForGroup(gID, '\n===========================\nMaximum time exceeded\nMax time was set to 1800 \n===========================\n',  10)
      return nil
     end
   end        -- "end' assocaited iwth inFlightDistHead(tempTBL, time)

Now, I tried to get fancy and this function is inside other function that I set up as an overarching function/wrapper.  I don't know if that could cause this issue or not due to something being out of scope?

SECOND ISSUE
I am trying to use the world.eventHandler to see if I can tell when a unit has been exited.  I have added S_EVENT_PLAYER_LEFT tas a check, but I don't seem to get that activated when I leave an aircraft.  In the section of code below, I DO get the debug message when I crash but not when I just choose a different slot.

 

elseif ((event.id == world.event.S_EVENT_EJECTION and event.initiator ~= nil) or
				(event.id == world.event.S_EVENT_PILOT_DEAD and event.initiator ~= nil) or
				(event.id == world.event.S_EVENT_CRASH and event.initiator ~= nil) or
        (event.id == world.event.S_EVENT_PLAYER_LEFT and event.initiator ~= nil) or          -- added to mine, not in Relent's S_EVENT_UNIT_LOST
        (event.id == world.event.S_EVENT_UNIT_LOST and event.initiator ~= nil) or            -- added to mine, not in Relent's S_EVENT_UNIT_LOST
				(event.id == world.event.S_EVENT_DEAD and event.initiator ~= nil)) then
			local leftUnit = event.initiator
          if (debugFlagHotLZ == 1) then
            trigger.action.outText("leftUnit loop Event ID is = " .. event.id,5)
          end

 

 

Thanks in advance for any and all help.


null

image.png

Hot_LZ_Challenge_v0_19.lua

----------------

AKA_Clutter

 

Win 10 Pro, Intel i7 12700k @4.6 GHz, EVGA RTX 3080  FTW, Ultra 64 GB G.Skill DDR4 3600 RAM, Acer 27" flat screen, HP Reverb G2, TM Warthog HOTAS with Virpil warBRD base, MFG Rudder Pedals, Virpil TCS Rotor Base with AH-64Dcollective, TrackIR 5 Pro w/Vector Expansion, PointCTRL.

  • Solution
Posted (edited)
13 hours ago, AKA_Clutter said:

FIRST ISSUE

Once I leave the current unit, or crash, I get an error message about 20-30 seconds later stating the "unit does not exist".

Ah, the joys of DCS, mixed with one's own expectations. You already have all the pieces of the puzzle, and I think that you implicitly believe that one thing means the other (in a perfect world it would, but not Lua/DCS).

Let's go through the the steps one by one.

  1. You enter your aircraft "Crasher" and depart. A status display call is scheduled in 20 seconds with a reference to your unit "Crasher". In computing terms, a 'reference' points to the memory location that contains data, here the data for unit "Crasher"
  2. One second later you crash your aircraft "Crasher" and it is removed from the game. The memory for that unit is freed - made available for other purposes. Your reference to "Crasher" still points to the memory location formerly assigned to "Crasher". 
  3. 19 seconds later, your scheduled status display function is invoked. As part of the params that are retained is a reference to the (now crashed and invalidated) unit "Crasher" in uObject.
  4. Your code checks if uObject == nil. Your reference to "Crasher" STILL points to to the memory location that formerly contained the (now deleted) unit, meaning it is not nil, so the check correctly fails
  5. in Line 395 you now access uObject's method getLife() member via "uObject:getLife()". Unfortunately, uObject is no longer a valid object, and you get the "Unit doesn't exits" error

So this is correct. A reference to a unit isn't nilled when the unit is destroyed, and a nilcheck to a cached unit (a saved unit reference) will not save you from this.

So, how do you protect against that? Many ways, one is to save the unit's name instead, and directly retrieve the unit by name before you try to access it:

uObject = Unit.getByName(uName)
if not uObject then 
	trigger.action.outText("Sorry, but unit object is nil",15) -- some spelling corrected
	return 
end 

 

   

Edited by cfrag
  • Like 2
Posted
13 hours ago, AKA_Clutter said:

SECOND ISSUE
I am trying to use the world.eventHandler to see if I can tell when a unit has been exited.  I have added S_EVENT_PLAYER_LEFT tas a check, but I don't seem to get that activated

DCS's event API is a cruel joke on us mission creators. That event ID is only invoked every second blue moon for players who have two children or less and can't be relied upon. 

  • Like 3
Posted

@cfrag


See I told you I was a noob at programming/lua/DCS MSE

Thanks once again.

Issue 1

2 hours ago, cfrag said:

Ah, the joys of DCS, mixed with one's own expectations. You already have all the pieces of the puzzle, and I think that you implicitly believe that one thing means the other (in a perfect world it would, but not Lua/DCS).

Let's go through the the steps one by one.

  1. ...
  2. ...
  3. ...
  4. Your code checks if uObject == nil. Your reference to "Crasher" STILL points to to the memory location that formerly contained the (now deleted) unit, meaning it is not nil, so the check correctly fails
  5. ...

So this is correct. A reference to a unit isn't nilled when the unit is destroyed, and a nilcheck to a cached unit (a saved unit reference) will not save you from this.

So, how do you protect against that? Many ways, one is to save the unit's name instead, and directly retrieve the unit by name before you try to access it:

  

 

Yeap, I wasn't thinking in programing terms in that "=" isn't equal but "assign".  programing 101.

And I will try other ways to protect against this.  As I have it, I could use the group ID in a similar fashion , but that would only work with 1 unit per group.

 

 

2 hours ago, cfrag said:

DCS's event API is a cruel joke on us mission creators. That event ID is only invoked every second blue moon for players who have two children or less and can't be relied upon. 

I thought it might be something like this.  DCS MSE has many dead-end rabbit holes, or so I have read.

Thanks again for the help.  Now to go update the script.

----------------

AKA_Clutter

 

Win 10 Pro, Intel i7 12700k @4.6 GHz, EVGA RTX 3080  FTW, Ultra 64 GB G.Skill DDR4 3600 RAM, Acer 27" flat screen, HP Reverb G2, TM Warthog HOTAS with Virpil warBRD base, MFG Rudder Pedals, Virpil TCS Rotor Base with AH-64Dcollective, TrackIR 5 Pro w/Vector Expansion, PointCTRL.

  • Recently Browsing   0 members

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