-- https://github.com/ggabriel96/lasso
local skynet = require "skynet"

local default_smoothing = 0.75
local default_simulations = 60 -- 多少帧

local MainLoop = class("MainLoop")

function MainLoop:initialize(simulations_per_second, fps_smoothing)
    self.loop_status = {
        fps = 0,
        time_frame = 0,
        time_total_elapsed = 0,
        time_total_simulated = 0,
        time_simulation_available = 0,
        tick = 0,
        time_prev = self:get_time(),
        time_curr = self:get_time(),
    }

    -- 1 秒 按 100 做单位(skynet 进度到 10ms 的原因)
    self.delta = 100 / (simulations_per_second or default_simulations)
    self.fps_smoothing = fps_smoothing or default_smoothing
end

function MainLoop:get_time()
    return skynet.now()
end

function MainLoop:compute_fps()
    self.loop_status.fps = math.floor(self.loop_status.fps * self.fps_smoothing) +
                               math.floor((1 / self.loop_status.time_frame) * (1.0 - self.fps_smoothing))
end

-- game_logic 需要实现 方法 init simulate render is_done terminate
function MainLoop:run(game_logic)
    game_logic:init()

    while not game_logic:is_done() do
        self.loop_status.time_curr = self:get_time()
        self.loop_status.time_frame = self.loop_status.time_curr - self.loop_status.time_prev

        self.loop_status.time_simulation_available = self.loop_status.time_simulation_available +
                                                         self.loop_status.time_frame

        while (self.loop_status.time_simulation_available >= self.delta) do
            self.loop_status.tick = self.loop_status.tick + 1

            -- if self.loop_status.tick % 10 == 0 then
            --     skynet.error("MainLoop tick", self.loop_status.tick, "++++", os.time())
            -- end

            game_logic:simulate(self.loop_status, self.delta)

            self.loop_status.time_simulation_available = self.loop_status.time_simulation_available - self.delta
            self.loop_status.time_total_simulated = self.loop_status.time_total_simulated + self.delta
        end

        self:compute_fps()

        game_logic:render(self.loop_status, self.delta)

        self.loop_status.time_total_elapsed = self.loop_status.time_total_elapsed + self.loop_status.time_frame
        self.loop_status.time_prev = self.loop_status.time_curr

        -- 让出 cpu
        skynet.sleep(1)
    end

    game_logic:terminate()
end

return MainLoop
