Appkit: /level_wrapper.lua — code sample - Stingray Lua API Reference

Appkit: /level_wrapper.lua — code sample

Code

--[[

The `LevelWrapper` manages an engine `Level` object and

<ul>
    <li>Loads the shading environment specfied for the Level in the editor</li>
    <li>Spawns the Level background</li>
    <li>Loads the level's BakedLighting map</li>
    <li>Manage cameras that are set as active cameras, that are not managed by an
    Appkit.CameraWrapper`. For example a camera unit added and managed in the
    Level Editor.</li>
    <li>Provides level object management so that Lua can register lua objects with a
    Level to receive update and shutdown calls automatically.</li>
</ul>

The `LevelWrapper` works with the `ComponentManager` to allow components to be
ticked per level, and works with `Appkit` to allow for different Tick ordering
relative to `World` update.

]]--

require 'core/appkit/lua/class'

Appkit.LevelWrapper = Appkit.class(Appkit.LevelWrapper)
local LevelWrapper = Appkit.LevelWrapper

local World = stingray.World
local Level = stingray.Level
local Application = stingray.Application
local ShadingEnvironment = stingray.ShadingEnvironment

local function load_shading_environment(self)
    local level = self.level

    -- Load the shading environment for the level if there is one.
    local env_name = nil

    if Level.has_data(level, "shading_environment") then
        env_name = Level.get_data(level, "shading_environment")
    end

    if env_name == nil or string.len(env_name) == 0 then
        print "Warning: No shading environment set in Level, applying default"
        local default_shading_environment_new = "core/stingray_renderer/environments/midday/midday"
        local default_shading_environment_old = "core/rendering/default_outdoor"
        env_name = default_shading_environment_new
        if Application.can_get("shading_environment", default_shading_environment_old)
            and not Application.can_get("shading_environment", default_shading_environment_new) then
            env_name = default_shading_environment_old
        end
    end

    local world = self.world
    self.shading_environment = World.create_shading_environment(world, env_name)
    require 'core/appkit/lua/app'
    Appkit.set_shading_environment(world, self.shading_environment, env_name)
end

-- level_name necessary for lightmap loading. It should match the original level
-- file resource name (not the test level resource name).
function LevelWrapper:init(level, level_name, should_set_shading_env)
    self.level = level
    self.world = Level.world(level)
    self.did_trigger_load_flow = false
    self.managed_objects = {}
    self.shading_environment = nil
    self.cameras_to_cleanup = {}

    Level.spawn_background(level)

    if should_set_shading_env and should_set_shading_env == true then
        load_shading_environment(self)
    end

    if stingray.Application.can_get("baked_lighting", level_name) then
        print ("Loading baked_lighting for `"..level_name..".level`")
        stingray.BakedLighting.map(self.world, level_name)
    end
end

function LevelWrapper:update(dt)
    Level.trigger_level_update(self.level)
    for _, callback in ipairs(self.managed_objects) do
        callback[1].update(callback[2], dt)
    end
end

function LevelWrapper:shutdown()
    Level.trigger_level_shutdown(self.level)

    -- Make sure that any cameras enabled via Level flow are not in the world render list.
    -- This is needed for Level-owned cameras that are enabled via the Appkit
    -- Enable Camera flow node but not tracked by Appkit.CameraWrapper.
    local world_wrapper = Appkit.get_managed_world_wrapper(self.world)
    for camera, _ in pairs(self.cameras_to_cleanup) do
        world_wrapper:set_camera_enabled(camera, nil, false) -- unit is only needed when enabling
    end
    self.cameras_to_cleanup = {}

    -- Now make sure all Appkit cameras are properly enabled in the world render list.
    -- Note: Lua cameras that are not using Appkit.CameraWrapper can possibly be
    -- left disabled if they were originally enabled then retrieved and disabled in the
    -- Level Flow!
    local CameraWrapper = require 'core/appkit/lua/camera_wrapper'
    CameraWrapper.refresh_enabled_cameras()

    -- Now can Shutdown level objects
    for _, object_pair in ipairs(self.managed_objects) do
        object_pair[1].shutdown(object_pair[2], self)
    end
    self.managed_objects = {}
    local ComponentManager = require 'core/appkit/lua/component_manager'
    ComponentManager.notify_managers_level_shutdown(self.level)

    stingray.BakedLighting.unmap(self.world)

    if self.shading_environment then
        World.destroy_shading_environment(self.world, self.shading_environment)
        self.shading_environment = nil
    end
end

function LevelWrapper:trigger_level_loaded_flow()
    local level = self.level
    if level and self.did_trigger_load_flow == false then
        Level.trigger_level_loaded(level)
        self.did_trigger_load_flow = true
    end
end

function LevelWrapper:set_shading_blend(options)
    if options then
        ShadingEnvironment.blend(self.shading_environment, options)
    else
        ShadingEnvironment.blend(self.shading_environment, {"default", 1})
    end
    ShadingEnvironment.apply(self.shading_environment)
end

-- Managed objects receive type.update(object, dt) and type.shutdown(object) calls
function LevelWrapper:manage_object(type, object)
    local list = self.managed_objects
    list[#list + 1] = {type, object}
end

-- Managed objects receive type.update(object, dt) and type.shutdown(object) calls
function LevelWrapper:unmanage_object(type, object)
    for i, callback in ipairs(self.managed_objects) do
        if callback[1] == type and callback[2] == object then
            table.remove(self.managed_objects, i)
            return
        end
    end
    print ("LevelWrapper:unmanage_object. Unabled to find ", type, object, "for removal.")
end

-- When a level unloads, we need a way to remove cameras that were placed in
-- the level and enabled via flow. For Appkit cameras (CameraWrapper),
-- this happens in the shutdown function. This means the Appkit Enable Camera flow
-- node requires the level to be an Appkit managed level.
function LevelWrapper:add_camera_to_cleanup(camera)
    self.cameras_to_cleanup[camera] = true
end

return LevelWrapper