Jump to content

Is there anyway to get the amount of cloud cover (oktas) from any of the API / env.mission i.e. FEW / SCT / BKN / OVC ?


Recommended Posts

Posted (edited)

The only thing missing from my automated METAR script is the description of the type of cloud coverage.

I can't see where this is hiding.

Has anyone solved this already? If so would you elucidate please? 

Thanks

Edited by Elphaba
  • TEMPEST.114 changed the title to Is there anyway to get the amount of cloud cover (oktas) from any of the API / env.mission i.e. FEW / SCT / BKN / OVC ?
Posted

If you are talking about the preset clouds, the density property is found at: \Config\Effects\clouds.lua

If you are talking about manual settings, the slider has 10 increments so you would need to adjust from octas. I did it like this:

	local function getCoverage(c)
		-- instead of using octals, split into ten parts for cloud density slider in ME
		if c < .3 then -- 1-2
			return "FEW", 1
		elseif c > .2 and c < .6 then -- 3-5
			return "SCT", 2
		elseif c > .5 and c < .9 then -- 6-8
			return "BKN", 3
		end
		return "OVC", 4 -- 9-10
	end

 

Posted
On 3/13/2023 at 1:20 PM, Chump said:
getCoverage(c)

that's awesome! but where are you getting 'c' from? 

Is the density in clouds.lua read and stored in env.mission that I can read at runtime? 

Posted (edited)
3 hours ago, Elphaba said:

that's awesome! but where are you getting 'c' from? 

Is the density in clouds.lua read and stored in env.mission that I can read at runtime? 

I modified the getCoverage() function so that it only contains pertinent information now. You can try something like this to get cloud density now:

local function getCoverage(coverage)
    -- instead of using octals, split into ten parts for cloud density slider in ME
    if coverage < .3 then -- 1-2
        return "FEW"
    elseif coverage > .2 and coverage < .6 then -- 3-5
        return "SCT"
    elseif coverage > .5 and coverage < .9 then -- 6-8
        return "BKN"
    end
    return "OVC" -- 9-10
end

local weather = env.mission.weather
if weather.atmosphere_type == 0 then -- no dynamic weather
    local preset = weather.clouds.preset
    if preset then
        local CloudPresets = dofile("Config\\Effects\\getCloudsPresets.lua")
        local cloudPreset = CloudPresets[preset]
        if cloudPreset then
          for _, layer in ipairs(cloudPreset.layers) do
              if layer.coverage > 0 then
                  local c = getCoverage(layer.coverage)
                  -- c will contain "FEW", "BKN", etc.
              end
          end
      end
    else
        local c = getCoverage(weather.clouds.density / 10)
        -- c will contain "FEW", "BKN", etc.
    end
end
Edited by Chump
fixed typos
Posted
25 minutes ago, Chump said:

I modified the getCoverage() function so that it only contains pertinent information now. You can try something like this to get cloud density now:

local function getCoverage(coverage)
	-- instead of using octals, split into ten parts for cloud density slider in ME
	if coverage < .3 then -- 1-2
		return "FEW"
	elseif coverage > .2 and coverage < .6 then -- 3-5
		return "SCT"
	elseif coverage > .5 and coverage < .9 then -- 6-8
		return "BKN"
	end
	return "OVC" -- 9-10
end

local weather = env.mission.weather
if weather.atmosphere_type == 0 then -- no dynamic weather
	local preset = weather.clouds.preset
	if preset then
		local CloudPresets = dofile("Config\\Effects\\getCloudsPresets.lua")
		local cloudPreset = CloudPresets.preset
		for _, layer in ipairs(p.layers) do
			if layer.coverage > 0 then
				local c = getCoverage(layer.coverage)
				-- c will contain "FEW", "BKN", etc.
			end
		end
	else
		local c = getCoverage(weather.clouds.density / 10)
		-- c will contain "FEW", "BKN", etc.
	end
end

That's wonderful and very clear code, I can follow that. 

But this means I have to desanitise the server right so I can do the 'dofile'? 

I was trying to avoid that. Maybe if the clouds.lua doesn't change much I can just hardcode it in? 

Posted
32 minutes ago, Chump said:

I modified the getCoverage() function so that it only contains pertinent information now. You can try something like this to get cloud density now:

local function getCoverage(coverage)
	-- instead of using octals, split into ten parts for cloud density slider in ME
	if coverage < .3 then -- 1-2
		return "FEW"
	elseif coverage > .2 and coverage < .6 then -- 3-5
		return "SCT"
	elseif coverage > .5 and coverage < .9 then -- 6-8
		return "BKN"
	end
	return "OVC" -- 9-10
end

local weather = env.mission.weather
if weather.atmosphere_type == 0 then -- no dynamic weather
	local preset = weather.clouds.preset
	if preset then
		local CloudPresets = dofile("Config\\Effects\\getCloudsPresets.lua")
		local cloudPreset = CloudPresets.preset
		for _, layer in ipairs(p.layers) do
			if layer.coverage > 0 then
				local c = getCoverage(layer.coverage)
				-- c will contain "FEW", "BKN", etc.
			end
		end
	else
		local c = getCoverage(weather.clouds.density / 10)
		-- c will contain "FEW", "BKN", etc.
	end
end

And what do you do if it's dynamic weather? Is that not available at all from the api? 

Posted
1 hour ago, Elphaba said:

But this means I have to desanitise the server right so I can do the 'dofile'? 

I was trying to avoid that. Maybe if the clouds.lua doesn't change much I can just hardcode it in? 

It isn't the dofile() that is the issue. It is the other functions that are called by the scripts. getCloudsPresets.lua will work fine without desanitization, but clouds.lua contains a translation method:

readableName = '01 ##'.. _('Few Scattered Clouds \nMETAR: FEW/SCT 7/8'),

-- pretty much defined as
local function _(text) 
	return gettext.translate(text) 
end

I suppose that you have an option of redefining this function to simply return the passed-in string:

function _(s) return s end

You could define this in the clouds.lua file so that you did not have to define it globally (not sure what would break).

Here is some sample code that should give you an idea of how it works:

--[[ NOTE:
-- this method is used in clouds.lua for translations
-- not translating, just returning string
-- redefining it here could have a side-effect on translations
-- it will also not allow you to use the throwaway variable in loops
--]]
function _(s) return s end

local function getCoverage(coverage)
	-- instead of using octals, split into ten parts for cloud density slider in ME
	if coverage < .3 then -- 1-2
		return "FEW"
	elseif coverage > .2 and coverage < .6 then -- 3-5
		return "SCT"
	elseif coverage > .5 and coverage < .9 then -- 6-8
		return "BKN"
	end
	return "OVC" -- 9-10
end

local weather = env.mission.weather
if weather.atmosphere_type == 0 then -- no dynamic weather
	local preset = weather.clouds.preset
	if preset then
		local CloudPresets = dofile("Config\\Effects\\getCloudsPresets.lua")
		local cloudPreset = CloudPresets[preset]
		if cloudPreset then
			for i, layer in ipairs(cloudPreset.layers) do -- NOTE: added index variable here instead of using throwaway
				if layer.coverage > 0 then
					trigger.action.outText(string.format("%sm: %s", layer.altitudeMin, getCoverage(layer.coverage)), 5)
				end
			end
		end
	else
		local clouds = weather.clouds
		trigger.action.outText(string.format("%sm: %s", clouds.base, getCoverage(clouds.density / 10)), 5)
	end
end

Unfortunately, I have not found a good set of useful methods for clouds from the weather.dll to support dynamic weather.

Hope this helps!

  • Thanks 1
Posted
4 hours ago, Chump said:

It isn't the dofile() that is the issue. It is the other functions that are called by the scripts. getCloudsPresets.lua will work fine without desanitization, but clouds.lua contains a translation method:

readableName = '01 ##'.. _('Few Scattered Clouds \nMETAR: FEW/SCT 7/8'),

-- pretty much defined as
local function _(text) 
	return gettext.translate(text) 
end

I suppose that you have an option of redefining this function to simply return the passed-in string:

function _(s) return s end

You could define this in the clouds.lua file so that you did not have to define it globally (not sure what would break).

Here is some sample code that should give you an idea of how it works:

--[[ NOTE:
-- this method is used in clouds.lua for translations
-- not translating, just returning string
-- redefining it here could have a side-effect on translations
-- it will also not allow you to use the throwaway variable in loops
--]]
function _(s) return s end

local function getCoverage(coverage)
	-- instead of using octals, split into ten parts for cloud density slider in ME
	if coverage < .3 then -- 1-2
		return "FEW"
	elseif coverage > .2 and coverage < .6 then -- 3-5
		return "SCT"
	elseif coverage > .5 and coverage < .9 then -- 6-8
		return "BKN"
	end
	return "OVC" -- 9-10
end

local weather = env.mission.weather
if weather.atmosphere_type == 0 then -- no dynamic weather
	local preset = weather.clouds.preset
	if preset then
		local CloudPresets = dofile("Config\\Effects\\getCloudsPresets.lua")
		local cloudPreset = CloudPresets[preset]
		if cloudPreset then
			for i, layer in ipairs(cloudPreset.layers) do -- NOTE: added index variable here instead of using throwaway
				if layer.coverage > 0 then
					trigger.action.outText(string.format("%sm: %s", layer.altitudeMin, getCoverage(layer.coverage)), 5)
				end
			end
		end
	else
		local clouds = weather.clouds
		trigger.action.outText(string.format("%sm: %s", clouds.base, getCoverage(clouds.density / 10)), 5)
	end
end

Unfortunately, I have not found a good set of useful methods for clouds from the weather.dll to support dynamic weather.

Hope this helps!

You can redefine a function in another table/file? Wow...

Thank you for all this and for taking the time to go through it. ❤️

  • Recently Browsing   0 members

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