utils.lua: Converting fuel values

Place to ask discuss and request the modding support of Factorio. Don't request mods here.
Post Reply
Pi-C
Smart Inserter
Smart Inserter
Posts: 1654
Joined: Sun Oct 14, 2018 8:13 am
Contact:

utils.lua: Converting fuel values

Post by Pi-C »

I've run into an unexpected problem while trying to manipulate fuel values. There is a function in data/core/lualib/utils.lua that allows to convert a fuel value to a number:

Code: Select all

local energy_chars =
{
  k = 10^3,
  K = 10^3,
  M = 10^6,
  G = 10^9,
  T = 10^12,
  P = 10^15,
  E = 10^18,
  Z = 10^21,
  Y = 10^24
}

function util.parse_energy(energy)

  local ending = energy:sub(energy:len())
  if not (ending == "J" or ending == "W") then
    error(ending.. " is not a valid unit of energy")
  end

  local multiplier = (ending == "W" and  1 / 60) or 1
  local magnitude = energy:sub(energy:len() - 1, energy:len() - 1)

  if tonumber(magnitude) then
    return tonumber(energy:sub(1, energy:len()-1)) * multiplier
  end

  multiplier = multiplier * (energy_chars[magnitude] or error(magnitude.. " is not valid magnitude"))
  return tonumber(energy:sub(1, energy:len()-2)) * multiplier

end
So I used that function to get the numeric value and do some calculations. But the values are long numbers that are hard to read (compare "1GJ" and "1000000000J"), so I wanted to convert the result back to the original form. Unfortunately, the library doesn't allow that. The only thing I could find that comes close to what I needed is this function:

Code: Select all


function util.format_number(amount, append_suffix)
  local suffix = ""
  if append_suffix then
    local suffix_list =
      {
        ["T"] = 1000000000000,
        ["B"] = 1000000000,
        ["M"] = 1000000,
        ["k"] = 1000
      }
    for letter, limit in pairs (suffix_list) do
      if math.abs(amount) >= limit then
        amount = math.floor(amount/(limit/10))/10
        suffix = letter
        break
      end
    end
  end
  local formatted, k = amount
  while true do
    formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
    if (k==0) then
      break
    end
  end
  return formatted..suffix
end
But this function only contains a subset of the magnitude prefixes available in util.parse_energy. Even worse, the prefix for 10^9 is "B" instead of "G", so things will break if you use util.format_number to shorten an energy value!

It's really not that hard to write a function that converts a fuel value in long format to the short form again, so I've done that. But is it really necessary that everybody reinvents the wheel if there already is a common library that all mods can use? I'm well aware that the game takes care of the formatting eventually, so no matter what format we use when setting fuel_value, the players will get to see it properly formatted. However, it would be a really useful addition for modders!

Readability is very important, especially during debugging. If I change a setting, I want to check that it has been set correctly, and it really makes a difference whether or not I can see at a glance that a setting has an unreasonable value. Counting zeroes unnecessarily is boring, and prone to mistakes. Therefore, I'd like to see such a function officially implemented. Would you do that, please?
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!

Post Reply

Return to “Modding interface requests”