Jump to content

Recommended Posts

Posted (edited)

Hi,

 

Had a strange issue with a mission I've been building, the script kept aborting abruptly. Digging deeper I noticed this in the removeFunction() method

 

mist.removeFunction = function(id)
 for i = 1, #Tasks do
  if Tasks[i].id == id then
   table.remove(Tasks, i)
  end
 end
end

 

I'm not a lua expert by no means but I think you can't do this. Removing an item from a table whilst you are iterating through it? Won't lua shift the elements down by one after you remove (thus causing you to skip the next one). Also, won't the #Tasks now be out of date by 1, therefore causing you to run off the end of the array and give you a nil access on the last item? Two ways I can think of solving this 1) Iterate backwards through the table or 2) If you know that the function Id will only exist once then add a break statement after the remove

 

mist.removeFunction = function(id)
 for i = 1, #Tasks do
  if Tasks[i].id == id then
   table.remove(Tasks, i)
   break
  end
 end
end

 

I modified my mist file and it seemed to fix the issue (well, I only tested it 2 times so there could still be an issue with my code)

 

Cheers,

Stacker.

Edited by Stacker

i7-4790K@4.7GHz : EVGA 1070 SC : 16GB Corsair Vengence Pro : 2xEVO 840 SSD : EVGA 850W PSU : CORSAIR H100i Cooler : ASUS Z97-AR MB : CORSAIR OBSIDIAN 750D FULL TOWER

Posted

Shouldn't matter what the index is, as its checking to see if the table entry 'id' matches the value passed to the function. The index can change but each table value will have a unique id. When iterating through a table using #Tasks (size of tasks) it will stop on the first nil value. In comparison if we used "for i, taskData in pairs(Tasks) do" it will iterate through every single entry in the table for the size of the table. Yes table.remove does re-adjust the table, but the change won't effect the current process of iterating through the table.

The right man in the wrong place makes all the difference in the world.

Current Projects:  Grayflag ServerScripting Wiki

Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread)

 SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum

Posted

I tried this from the standalone lua compiler

 

mist={}
Tasks = { {id='A'}, {id='B'}, {id='C'}, {id='D'}, {id='E'}}
mist.removeFunction = function(id)
 for i = 1,#Tasks do
print('Tasks['..i..'].id ='..Tasks[i].id)
  if Tasks[i].id == id then
 print('Removed')
   table.remove(Tasks, i)
  end
 end
end

mist.removeFunction('E')

 

The output will be this

 

Tasks[1].id =A
Tasks[2].id =B
Tasks[3].id =C
Tasks[4].id =D
Tasks[5].id =E
Removed

 

Now try removing something in the middle of that list

 

mist.removeFunction('C')

 

I get the following result

 

Tasks[1].id =A
Tasks[2].id =B
Tasks[3].id =C
Removed
Tasks[4].id =E
lua: mistTest.lua:8: attempt to index field '?' (a nil value)
stack traceback:
mistTest.lua:8: in function 'removeFunction'
mistTest.lua:17: in main chunk
[C]: ?
>Exit code: 1

 

Two things wrong here - Notice the sequence I've iterated - A,B,C,E.

 

I've request to remove 'C' but it's skipped 'D'. Why? Because D was shifted down into 'C's position and then then loop iterator moved to the next index value.

 

Also, notice our a attempt to access the last item get's a nil exeption. Why? My guess is that #Tasks only seems to be evaluated once at the start of the loop so the for() is trying to access the 5th element.

 

If you modify the loop to run backwards you won't get these errors

 

mist={}
Tasks = { {id='A'}, {id='B'}, {id='C'}, {id='D'}, {id='E'}}
mist.removeFunction = function(id)
 for i = #Tasks,1,-1 do
print('Tasks['..i..'].id ='..Tasks[i].id)
  if Tasks[i].id == id then
 print('Removed')
   table.remove(Tasks, i)
  end
 end
end

mist.removeFunction('C')

 

Output will be this

 

Tasks[5].id =E
Tasks[4].id =D
Tasks[3].id =C
Removed
Tasks[2].id =B
Tasks[1].id =A

  • Like 1

i7-4790K@4.7GHz : EVGA 1070 SC : 16GB Corsair Vengence Pro : 2xEVO 840 SSD : EVGA 850W PSU : CORSAIR H100i Cooler : ASUS Z97-AR MB : CORSAIR OBSIDIAN 750D FULL TOWER

Posted
Hi,

 

Had a strange issue with a mission I've been building, the script kept aborting abruptly. Digging deeper I noticed this in the removeFunction() method

 

mist.removeFunction = function(id)
 for i = 1, #Tasks do
  if Tasks[i].id == id then
   table.remove(Tasks, i)
  end
 end
end

 

I'm not a lua expert by no means but I think you can't do this. Removing an item from a table whilst you are iterating through it? Won't lua shift the elements down by one after you remove (thus causing you to skip the next one). Also, won't the #Tasks now be out of date by 1, therefore causing you to run off the end of the array and give you a nil access on the last item? Two ways I can think of solving this 1) Iterate backwards through the table or 2) If you know that the function Id will only exist once then add a break statement after the remove

 

mist.removeFunction = function(id)
 for i = 1, #Tasks do
  if Tasks[i].id == id then
   table.remove(Tasks, i)
   break
  end
 end
end

 

I modified my mist file and it seemed to fix the issue (well, I only tested it 2 times so there could still be an issue with my code)

 

Cheers,

Stacker.

Yup thanks for pointing that one out! I think I wrote that code without thinking about it too much, and then never tested it :blush: (it is, after all, a function you will rarely, if ever, need).

 

Anyway, there is no problem with removing entries from the table you are iterating through. The problem with this code is but the fact that the numeric for only evaluates the conditions ONCE. So you should get an attempt to index nil value error with the way this function is written.

 

I had other code that I've used quite a bit that's very similar, but it uses a while loop and a variable that is incremented or not (depending on whether or not the table had an entry that was removed), and maybe I just logically copied it and changed it to a for without thinking about it. Anyway, that implementation would look like this:

mist.removeFunction = function(id)
local i = 1
while i <= #Tasks do
	if Tasks[i].id == id then
		table.remove(Tasks, i)
	else
		i = i + 1
	end
end
end

That code would work just fine, and could even handle the case of there being multiple matching entries in the table that need to be removed.

 

The major difference to understand is that the while loop evaluates the condition every time the loop loops, while the for loop just does the evaluation once.

 

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

 

Anyway, internally mist.removeFunction is used for nothing and all it would cause would be that when you tried to use it, the script that tried to run it would not work, raising an attempt to index nil value error. So if you were not using it, that was not the reason you had a problem.

 

NOW LISTEN CAREFULLY: There was a bug a few versions of DCS ago where timer.scheduleFunction (upon which mist.scheduleFunction is dependent) would just stop working when the host's aircraft crashed (odd, huh?!?!). Other things likely triggered the bug too, but I never found them. It is possible this bug came back or was never really fixed in the first place. Maybe this bug was only fixed for the case of the host's aircraft crashing, and you found a new, different way to trigger it. I SURE hope not, a bug like that is absolutely devastating to Lua scripting in DCS! timer.scheduleFunction must NEVER fail, it's one of the foundations on which the whole stack of cards is built!

 

Anyway, if you were NOT using mist.removeFunction, then please let me know! It is possible you stumbled across a major problem with the scripting engine!

Intelligent discourse can only begin with the honest admission of your own fallibility.

Member of the Virtual Tactical Air Group: http://vtacticalairgroup.com/

Lua scripts and mods:

MIssion Scripting Tools (Mist): http://forums.eagle.ru/showthread.php?t=98616

Slmod version 7.0 for DCS: World: http://forums.eagle.ru/showthread.php?t=80979

Now includes remote server administration tools for kicking, banning, loading missions, etc.

Posted

I was using it because my script was adding/removing schedule functions dynamically. Yeah, I saw that other loop iteration technique you are referring to using the while() loop. Anyway, with the tweak you mentioned it's now solved, cheers!

i7-4790K@4.7GHz : EVGA 1070 SC : 16GB Corsair Vengence Pro : 2xEVO 840 SSD : EVGA 850W PSU : CORSAIR H100i Cooler : ASUS Z97-AR MB : CORSAIR OBSIDIAN 750D FULL TOWER

Posted (edited)

Hi, can I use above code to remove a triggered action as well?

 

I want to remove or reset :

 

trigger.action.radioTransmission('SirenLoop.ogg', PilotPosition, 0, true, 250000, 1000);

when unit is dead

 

Group.getByName('Downed Pilot Group'):destroy()

above must be able to reactivate on another trigger

 

Edit: Found this

 

{     id = 'DeactivateBeacon',     params = {     }   }

 

how will I implement this?

Edited by Midnight

Midnite Signature.jpg

  • Recently Browsing   0 members

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