Weird SE_DeleteUnit()

All discussions & material related to Command's Lua interface

Moderators: angster, RoryAndersonCDT, michaelm75au, MOD_Command

Post Reply
User avatar
vettim89
Posts: 3668
Joined: Fri Jul 13, 2007 11:38 pm
Location: Toledo, Ohio

Weird SE_DeleteUnit()

Post by vettim89 »

Pardon the extraneous 'prints' in this code as I was trying to parse through the lines

Code: Select all

local b=ScenEdit_GetUnit({name='Banak [Diversionary Air Base]', guid='W7ZXL3-0HM0RFF6Q2498'})
print(#b.hostedUnits['Aircraft'])
for i=1,#b.hostedUnits['Aircraft'] do
local g=b.hostedUnits['Aircraft'][i]
print(g)
local u=ScenEdit_GetUnit({guid=g})
ScenEdit_DeleteUnit({guid=u.guid})
end
So when I run that it only deletes aircraft #1,3,5,&7. Aircraft #2,4,6,&8 are remaining and the console is giving me this error: 'ScenEdit_GetUnit 0 : 'Need to define a Name or Guid to identify a unit. Preferably a Guid or Side & Name.' Why is the code skipping/having a problem with the even numbers?
"We have met the enemy and they are ours" - Commodore O.H. Perry
User avatar
nukkxx5058
Posts: 3141
Joined: Thu Feb 03, 2005 2:57 pm
Location: France

Re: Weird SE_DeleteUnit()

Post by nukkxx5058 »

It's because when you delete the aircraft, your i counter skips one number.

i= 1 --> delete aircraft i=1
i= 2 --> delete aircraft i=2 BUT it's aircraft #2 in the new list after having deleted the first aircraft. So for your second loop, you are skipping the new aircraft #1 (after deletion)

Hope I'm clear enough :-)
Winner of the first edition of the Command: Modern Operations COMPLEX PBEM Tournament (IKE) (April 2022) :-)
User avatar
vettim89
Posts: 3668
Joined: Fri Jul 13, 2007 11:38 pm
Location: Toledo, Ohio

Re: Weird SE_DeleteUnit()

Post by vettim89 »

Of course! That makes perfect sense now that your point it out. Can you make a 'for' loop counter backwards?

Perhaps I need to use a do/while loop instead
"We have met the enemy and they are ours" - Commodore O.H. Perry
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

Re: Weird SE_DeleteUnit()

Post by KnightHawk75 »

vettim89 wrote: Mon May 09, 2022 12:04 am Of course! That makes perfect sense now that your point it out. Can you make a 'for' loop counter backwards?

Perhaps I need to use a do/while loop instead
No you should not use a do\while.
You can use a decrementing for if you want and it will technically address your specific issue in this specific case, however it may not work for you in other cases. How to go backwards: for i=#sometable,1,-1 do print(i); end

The issue is you are indirectly making deletes to the object being looped during the loop which changes things on each iteration. Don't if you can avoid it. Often you will want to either deep-copy the table first, or run through it grabbing what you need first, and then a second time to do the actions.

--using decrementing for loop which will technically work for this very specific example.

Code: Select all

function DeleteAllHostedUnits1(u)
  if ((u ~= nil) and u.hostedUnits ~=nil) and u.hostedUnits.Aircraft ~=nil then
    local tmptable = u.hostedUnits.Aircraft  -- make a copy as the original may be reevaluated\updates during the for.
    for i=#u.hostedUnits.Aircraft,1,-1 do
     --There is no need to get each unit, unless doing something else first, line removed.
      print('deleting unit ' .. i .. ' with guid ' .. u.hostedUnits.Aircraft[i] .. ' that was hosted on ' .. u.name)
      pcall(ScenEdit_DeleteUnit,{guid=u.hostedUnits.Aircraft[i]});
    end
  end
end

DeleteAllHostedUnits1(ScenEdit_GetUnit({name='SUA1', guid='4FH7PU-0HMHHATCAVSIG'}));
--using simple copy by value first.

Code: Select all

function DeleteAllHostedUnits2(u)
  if ((u ~= nil) and u.hostedUnits ~=nil) and u.hostedUnits.Aircraft ~=nil then
    local tmptable = {};
    for i = 1,#u.hostedUnits.Aircraft do tmptable[i]=u.hostedUnits.Aircraft[i]; end -- made clean copy of just the values we need
    for k,v in ipairs(tmptable) do --operate on the copy you could not use idx or pairs here it doesn't matter just a sample.
      pcall(ScenEdit_DeleteUnit,{guid=v});
      print('deleted unit ' .. k .. ' with guid ' .. v .. ' that was hosted on ' .. u.name)
    end
  end
end

DeleteAllHostedUnits2(ScenEdit_GetUnit({name='SUA1', guid='4FH7PU-0HMHHATCAVSIG'}));
Using a deep-copy for more involved tables\objects, ie values that are tables themselves. (duplicate by-value not reference whole structure)

Code: Select all

local gKH={}  --added just so I didn't have to change anything for this posted snippet.
gKH.base = {}; --added just so I didn't have to change anything for this posted snippet.

---Function to make a true copy an existing table into a real new table that has no references to old table.
-- Rarely needed, but when you really do you do.
-- Used by RandomUnitGenerator during recursion to avoid some refference problems.
-- original code from:
-- https://stackoverflow.com/questions/640642/how-do-you-copy-a-lua-table-by-value
---@param o table @table to copy
---@param seen? table @table used during recursion
---@return table @an unreferenced copy of the table fed to it.
function gKH.base.deepcopy(o, seen)
  seen = seen or {}
  if o == nil then return nil end
  if seen[o] then return seen[o] end

  local no
  if type(o) == 'table' then
    no = {}
    seen[o] = no

    for k, v in next, o, nil do
      no[gKH.base.deepcopy(k, seen)] = gKH.base.deepcopy(v, seen)
    end
    setmetatable(no, gKH.base.deepcopy(getmetatable(o), seen))
  else -- number, string, boolean, etc
    no = o
  end
  return no
end

--usage
function DeleteAllHostedUnits3(u)
  if ((u ~= nil) and u.hostedUnits ~=nil) and u.hostedUnits.Aircraft ~=nil then
    local tmptable = gKH.base.deepcopy(u.hostedUnits.Aircraft);  --byvalue copy of entire table.
    for k,v in ipairs(tmptable) do  -- could use idx or pairs method this is just a quick sample.
      pcall(ScenEdit_DeleteUnit,{guid=v});
      print('deleted unit ' .. k .. ' with guid ' .. v .. ' that was hosted on ' .. u.name)
    end
  end
end
DeleteAllHostedUnits3(ScenEdit_GetUnit({name='SUA1', guid='4FH7PU-0HMHHATCAVSIG'}));
Post Reply

Return to “Lua Legion”