Hotswapping

This commit is contained in:
qfx 2020-01-27 00:43:20 +02:00
parent 2f4fbad405
commit c30480520f
4 changed files with 156 additions and 16 deletions

View File

@ -55,7 +55,8 @@ element.__index = element
setmetatable(element,{ setmetatable(element,{
__call = function(cls, ...) __call = function(cls, ...)
local self local self
if type(...)=='function' then local func, loader = ...
if type(func)=='function' then
self = setmetatable({}, element) self = setmetatable({}, element)
self.renderer = ... self.renderer = ...
self.classless = true self.classless = true
@ -64,7 +65,14 @@ setmetatable(element,{
self.classless = false self.classless = false
end end
self:new(...) if loader then
local function f(newFunc)
self:reLoader(newFunc)
end
loader(f)
end
self:new()
return self return self
end end
@ -77,6 +85,7 @@ function element:updater() end
function element:constructor() end function element:constructor() end
--Control functions --Control functions
--The new function that should be used for element creation --The new function that should be used for element creation
function element:new() function element:new()
@ -109,6 +118,12 @@ function element:new()
end end
end end
--Hotswapping code
function element:reLoader(newFunc)
self.renderer = newFunc
self.context:bubbleUpdate()
end
--Called once dimensions are validated --Called once dimensions are validated
function element:setup() function element:setup()
self.state = self.state =
@ -156,13 +171,12 @@ function element:setup()
--Classless rendering --Classless rendering
if self.classless then if self.classless then
self.classlessData.loadEffect = function (func) self.classlessData.loadEffect = function (func)
if self.classlessData.loadCaptured then if self.classlessData.loaded and self.classlessData.loadCaptured then
return unpack(self.classlessData.loadCaptured) return self.classlessData.loadCaptured
else elseif not self.classlessData.loaded then
self.classlessData.loadCaptured = func() self.classlessData.loadCaptured = func()
if type(self.classlessData.loadCaptured) == 'table' then self.classlessData.loaded = true
return unpack(self.classlessData.loadCaptured) if self.classlessData.loadCaptured then
elseif self.classlessData.loadCaptured then
return self.classlessData.loadCaptured return self.classlessData.loadCaptured
end end
end end
@ -184,7 +198,11 @@ function element:setup()
self.classlessState[indice].state = set self.classlessState[indice].state = set
self.context:bubbleUpdate() self.context:bubbleUpdate()
end end
return self.classlessState[indice].state, self.classlessState[indice].setState
self.classlessState[indice].getState = function()
return self.classlessState[indice].state
end
return self.classlessState[indice].state, self.classlessState[indice].setState, self.classlessState[indice].getState
end end
end end
end end
@ -193,15 +211,28 @@ end
function element:classlessRender() function element:classlessRender()
self.inputContext:set() self.inputContext:set()
self.settings.indice = 0 self.settings.indice = 0
if type(self.renderer)=='function' then
local denv = getfenv(self.renderer)
denv['useState'] = self.classlessData.useState
denv['loadEffect'] = self.classlessData.loadEffect
local denv = getfenv(self.renderer) local status,err = pcall(self.renderer,self.parameters, self.view.w, self.view.h)
denv['useState'] = self.classlessData.useState
denv['loadEffect'] = self.classlessData.loadEffect
self.renderer(self.parameters, self.view.w, self.view.h) if not status then
love.graphics.setColor(1,0,0)
love.graphics.rectangle('line',0,0,self.view.w,self.view.h)
love.graphics.setColor(1,1,1)
love.graphics.printf("Error: "..err,0,0,self.view.w)
end
denv['useState'] = nil denv['useState'] = nil
denv['loadEffect'] = nil denv['loadEffect'] = nil
elseif type(self.renderer)=='string' then
love.graphics.setColor(1,0,0)
love.graphics.rectangle('line',0,0,self.view.w,self.view.h)
love.graphics.setColor(1,1,1)
love.graphics.printf("Error: "..self.renderer,0,0,self.view.w)
end
self.inputContext:unset() self.inputContext:unset()
end end

106
debugLoader.lua Normal file
View File

@ -0,0 +1,106 @@
local path = string.sub(..., 1, string.len(...) - string.len(".debugLoader"))
local helium = require(path..'.dummy')
local elements = {}
local debugLoader = {}
--Return level: 1--string; 2--chunk; 3--return value; default: element factory
local function loader(path)
local succ = true
--File string
local fileContents, err = love.filesystem.read(path)
if fileContents==nil then
print('Error loading ',path,':',tostring(err),', will continue watching!')
succ = false
end
local t, lastLoaded
if succ then
t = love.filesystem.getInfo(path)
lastLoaded = t['modtime']
end
--Chunk
local status, err
if succ then
status, err = pcall(loadstring,fileContents)
end
if status==false or status==nil then
print('Error compiling ',path,':',tostring(err),', will continue watching!')
succ = false
end
--Return values
local ret
if succ then
succ, ret = pcall(err,path)
if not succ then
print('Error calling ',path,':',tostring(ret))
end
end
return fileContents, err, ret, lastLoaded
end
debugLoader.loader = function(path,returnLevel)
local level = returnLevel or 6
if elements[path] then
return elements[path][level]
end
local setfuncs = {}
local fileContents, func, ret, lastLoaded = loader(path)
local reloader = function(setFunc)
setfuncs[#setfuncs+1] = setFunc
end
local factory = function()
return helium.element(ret, reloader)
end
elements[path] = { fileContents, func, ret, path, lastLoaded, factory, setfuncs = setfuncs }
return elements[path][level]
end
local counter = 0
function debugLoader.update(dt)
counter = counter+dt
if counter>2 then
for ind, elem in pairs(elements) do
--Get the current last save time
local t = love.filesystem.getInfo(elem[4])
local ll = t['modtime']
if ll ~= elem[5] then
--If last save time differs then start reload sequence
local _, _, ret, lastLoaded = loader(elem[4])
local setfuncs = {}
local reloader = function(setFunc)
setfuncs[#setfuncs+1] = setFunc
end
local factory = function()
return helium.element(ret, reloader)
end
elem[5] = lastLoaded
elem[6] = factory
for i, func in ipairs(elem.setfuncs) do
func(ret)
end
end
end
counter = 0
end
end
HeliumLoader = debugLoader.loader
return debugLoader

View File

@ -1 +1,2 @@
--thicc
return {} return {}

View File

@ -8,6 +8,7 @@ local helium = require(path..".dummy")
helium.utils = require(path..".utils") helium.utils = require(path..".utils")
helium.element = require(path..".core.element") helium.element = require(path..".core.element")
helium.input = require(path..".core.input") helium.input = require(path..".core.input")
helium.debugLoader = require(path..".debugLoader")
helium.elementBuffer = {} helium.elementBuffer = {}
function helium.render() function helium.render()
@ -99,7 +100,8 @@ function love.run()
-- Call update and draw -- Call update and draw
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
helium.update() helium.update(dt)
helium.debugLoader.update(dt)
if love.graphics and love.graphics.isActive() then if love.graphics and love.graphics.isActive() then
love.graphics.clear(love.graphics.getBackgroundColor()) love.graphics.clear(love.graphics.getBackgroundColor())