Practical BAR Modding Notes from Modding-0105

Real Lua patterns from active BAR modders working with unitdefs, buildoptions, and nested tables. Skip the guesswork.

Tags: modding, tweakdefs, lua, unitdefs, buildoptions

Editing buildoptions in tweakdefs without breaking the build menu

The single most common mistake new BAR modders make involves buildoptions. Direct assignment to def.buildOptions or def.buildoptions creates malformed menus when the nested table structure is wrong. The fix requires iterating through the existing buildOptions array and removing bad entries rather than replacing the whole table.

The working pattern loops through unitDefs, checks each entry for a buildOptions table, collects invalid indices, and removes them in reverse order to avoid index shifting:

for name, def in pairs(unitDefs) do
  local badOptions = {}
  local buildOptions = def.buildOptions or def.buildoptions
  if buildOptions then
    for i, option in ipairs(buildOptions) do
      if unitDefs[option] == nil then
        table.insert(badOptions, i)
      end
    end
    if #badOptions > 0 then
      local removed = 0
      for _, badIndex in ipairs(badOptions) do
        table.remove(buildOptions, badIndex - removed)
        removed = removed + 1
      end
    end
  end
end

This keeps the build menu intact while stripping out references to units that do not exist in the current game state.

Updating widgets without reinitializing everything on every click

A recurring pain point involves widget performance. Updating the entire widget from scratch on every mouse click creates visible stutter, especially on larger unit rosters. The solution spreads updates across multiple frames and only changes what actually needs changing.

Instead of recreating all tables on each interaction, modders should track state deltas. Only the units that changed between frames require table rebuilds. This reduces CPU load and keeps the interface responsive during matches. Players requesting this approach consistently report smoother performance after refactoring their update loops.

Filtering units with lookup tables instead of long if statements

Hardcoded chains like if name=="armmex" or name=="armflea" or name=="armck" grow unmanageable fast. A cleaner approach uses a dedicated lookup table:

local targetUnits = {
  armmex = true,
  armflea = true,
  armck = true,
}

for name, ud in pairs(UnitDefs) do
  if targetUnits[name] then
    -- apply changes
  end
end

This pattern scales to dozens of units without turning into an unreadable wall of string comparisons. Adding or removing a unit requires a single line change in the table definition.

Key takeaways from the community

Three durable lessons emerge from these discussions. Use code blocks when asking for help. Raw inline code gets mangled and wastes everyone time. Update incrementally instead of rebuilding from scratch on every interaction. Spreading work across frames produces smoother results. Replace chained conditionals with lookup tables. Readability matters when code gets complex.

Creed of Champions

BAR modding rewards clean code and clean communication. Teams that share well-formatted snippets and fix problems without blame move faster and learn more. The community that practices this stays fun and productive for everyone.

Crd is the first really comfortable community I have been a part of. Everyone is nice and kind, the atmosphere is relaxed, and I am not getting yelled at for not being optimal.
Advertisement