Compare commits
11 Commits
dcdf9cbd49
...
215aab41d3
Author | SHA1 | Date |
---|---|---|
Jill | 215aab41d3 | |
Jill | 1bc3604f9f | |
Jill | 6a0cb734db | |
Jill | b34c18da8a | |
Jill | e8cb599dde | |
Jill | 3ceba9bafc | |
Jill | 78f78c96db | |
Jill | 9821df6c2e | |
Jill | dd7234cc9e | |
Jill | 57225d526c | |
Jill | db7d0db7ec |
794
main.xml
794
main.xml
|
@ -1,7 +1,6 @@
|
||||||
<Layer Type="ActorFrame" InitCommand="%function(self)
|
<Layer Type="ActorFrame" InitCommand="%function(self)
|
||||||
_G.oat = {}
|
_G.oat = {}
|
||||||
oat._main = self
|
oat._main = self
|
||||||
oat.dir = GAMESTATE:GetCurrentSong():GetSongDir()
|
|
||||||
|
|
||||||
setmetatable(oat, {
|
setmetatable(oat, {
|
||||||
-- if something isn't found in the table, fall back to a global lookup
|
-- if something isn't found in the table, fall back to a global lookup
|
||||||
|
@ -14,6 +13,9 @@
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
uranium = {}
|
||||||
|
uranium.dir = GAMESTATE:GetCurrentSong():GetSongDir()
|
||||||
|
|
||||||
-- make require work
|
-- make require work
|
||||||
-- stolen from mirin template
|
-- stolen from mirin template
|
||||||
-- https://github.com/XeroOl/notitg-mirin/blob/0fbff2ee93d905feeb58c4aac4fe7f5f9ebc9647/template/std.lua#L17
|
-- https://github.com/XeroOl/notitg-mirin/blob/0fbff2ee93d905feeb58c4aac4fe7f5f9ebc9647/template/std.lua#L17
|
||||||
|
@ -33,7 +35,7 @@
|
||||||
local filename = string.gsub(modname, '%.', '/')
|
local filename = string.gsub(modname, '%.', '/')
|
||||||
for path in (string.gfind or string.gmatch)(oat.package.path, '[^;]+') do
|
for path in (string.gfind or string.gmatch)(oat.package.path, '[^;]+') do
|
||||||
-- get the file path
|
-- get the file path
|
||||||
local filepath = oat.dir .. string.gsub(path, '%?', filename)
|
local filepath = uranium.dir .. string.gsub(path, '%?', filename)
|
||||||
-- check if file exists
|
-- check if file exists
|
||||||
if not GAMESTATE:GetFileStructure(filepath) then
|
if not GAMESTATE:GetFileStructure(filepath) then
|
||||||
table.insert(errors, 'no file \''..filepath..'\'')
|
table.insert(errors, 'no file \''..filepath..'\'')
|
||||||
|
@ -79,792 +81,10 @@
|
||||||
|
|
||||||
oat()
|
oat()
|
||||||
|
|
||||||
local function copy(src)
|
require 'uranium.main'
|
||||||
local dest = {}
|
|
||||||
for k, v in pairs(src) do
|
|
||||||
dest[k] = v
|
|
||||||
end
|
|
||||||
return dest
|
|
||||||
end
|
|
||||||
|
|
||||||
oat.oat = _G.oat
|
-- Needed by StepMania, in order to not kill lua mods early
|
||||||
oat.type = _G.type
|
self:sleep(9e9)
|
||||||
oat.print = _G.print
|
|
||||||
oat.pairs = _G.pairs
|
|
||||||
oat.ipairs = _G.ipairs
|
|
||||||
oat.unpack = _G.unpack
|
|
||||||
oat.tonumber = _G.tonumber
|
|
||||||
oat.tostring = _G.tostring
|
|
||||||
oat.math = copy(_G.math)
|
|
||||||
oat.table = copy(_G.table)
|
|
||||||
oat.string = copy(_G.string)
|
|
||||||
|
|
||||||
oat.scx = SCREEN_CENTER_X
|
|
||||||
oat.scy = SCREEN_CENTER_Y
|
|
||||||
oat.sw = SCREEN_WIDTH
|
|
||||||
oat.sh = SCREEN_HEIGHT
|
|
||||||
oat.dw = DISPLAY:GetDisplayWidth()
|
|
||||||
oat.dh = DISPLAY:GetDisplayHeight()
|
|
||||||
|
|
||||||
oat.useProfiler = false
|
|
||||||
oat.profilerInfo = {}
|
|
||||||
local resetOnFrameStartCfg = false
|
|
||||||
local resetOnFrameStartActors = {}
|
|
||||||
|
|
||||||
local uraniumFunc = {}
|
|
||||||
|
|
||||||
local debugCache = {}
|
|
||||||
function uraniumFunc:call(event, ...)
|
|
||||||
if self._callbacks[event] then
|
|
||||||
profilerInfo[event] = {}
|
|
||||||
for _, callback in ipairs(self._callbacks[event]) do
|
|
||||||
local start = os.clock()
|
|
||||||
local res = callback(unpack(arg))
|
|
||||||
local dur = os.clock() - start
|
|
||||||
|
|
||||||
if oat.useProfiler then
|
|
||||||
if not debugCache[callback] then
|
|
||||||
debugCache[callback] = debug.getinfo(callback, 'Sl') -- cached cus debug.getinfo is EXPENSIVE
|
|
||||||
end
|
|
||||||
local finfo = debugCache[callback]
|
|
||||||
|
|
||||||
table.insert(profilerInfo[event], {
|
|
||||||
src = finfo.short_src .. ':' .. finfo.linedefined,
|
|
||||||
t = dur
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
if res ~= nil then return res end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local uraniumMeta = {}
|
|
||||||
|
|
||||||
function uraniumMeta:__newindex(key, value)
|
|
||||||
if self._callbacks[key] then
|
|
||||||
table.insert(self._callbacks[key], value)
|
|
||||||
else
|
|
||||||
self._callbacks[key] = {value}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
uraniumMeta.__index = uraniumFunc
|
|
||||||
|
|
||||||
uranium = setmetatable({_callbacks = {}}, uraniumMeta)
|
|
||||||
|
|
||||||
function backToSongWheel(message)
|
|
||||||
if message then
|
|
||||||
SCREENMAN:SystemMessage(message)
|
|
||||||
print(message)
|
|
||||||
end
|
|
||||||
GAMESTATE:FinishSong()
|
|
||||||
-- disable update_command
|
|
||||||
self:hidden(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
local hasExited = false
|
|
||||||
local function exit()
|
|
||||||
if hasExited then return end
|
|
||||||
hasExited = true
|
|
||||||
uranium:call('exit')
|
|
||||||
-- good templates clean up after themselves
|
|
||||||
uranium = nil
|
|
||||||
_G.oat = nil
|
|
||||||
oat = nil
|
|
||||||
_main:hidden(1)
|
|
||||||
collectgarbage()
|
|
||||||
end
|
|
||||||
|
|
||||||
local actorsInitialized = false -- if true, no new actors can be created
|
|
||||||
local actorsInitializing = false -- the above but a bit more explicit
|
|
||||||
|
|
||||||
local luaobj
|
|
||||||
|
|
||||||
local globalQueue = {} -- for resetting
|
|
||||||
|
|
||||||
local patchedFunctions = {}
|
|
||||||
local function patchFunction(f, obj)
|
|
||||||
if not patchedFunctions[f] then patchedFunctions[f] = {} end
|
|
||||||
if not patchedFunctions[f][obj] then
|
|
||||||
patchedFunctions[f][obj] = function(...)
|
|
||||||
arg[1] = obj
|
|
||||||
local results
|
|
||||||
local status, result = pcall(function()
|
|
||||||
-- doing it this way instead of returning because lua
|
|
||||||
-- offers no way of grabbing everything BUT the first
|
|
||||||
-- argument out of pcall
|
|
||||||
results = {f(unpack(arg))}
|
|
||||||
end)
|
|
||||||
if not status then
|
|
||||||
error(result, 2)
|
|
||||||
else
|
|
||||||
return unpack(results)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return patchedFunctions[f][obj]
|
|
||||||
end
|
|
||||||
|
|
||||||
local function onCommand(self)
|
|
||||||
actorsInitialized = true
|
|
||||||
actorsInitializing = false
|
|
||||||
local resetOnFrameStartActors_ = {}
|
|
||||||
for k,v in pairs(resetOnFrameStartActors) do
|
|
||||||
resetOnFrameStartActors_[k.__raw] = v
|
|
||||||
end
|
|
||||||
resetOnFrameStartActors = resetOnFrameStartActors_
|
|
||||||
uranium:call('init')
|
|
||||||
end
|
|
||||||
|
|
||||||
function reset(actor)
|
|
||||||
if not actorsInitialized then error('uranium: cannot reset an actor during initialization', 2) end
|
|
||||||
for _, q in ipairs(globalQueue) do
|
|
||||||
local queueActor = q[1]
|
|
||||||
if queueActor == actor.__raw then
|
|
||||||
local v = q[2]
|
|
||||||
|
|
||||||
local func = queueActor[v[1]]
|
|
||||||
if not func then
|
|
||||||
-- uhmmm ??? hm. what do we do??
|
|
||||||
else
|
|
||||||
patchFunction(func, queueActor)(unpack(v[2]))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
resetActor = reset
|
|
||||||
|
|
||||||
-- runs once during ScreenReadyCommand, before the user code is loaded
|
|
||||||
-- hides various actors that are placed by the theme
|
|
||||||
local function hideThemeActors()
|
|
||||||
for _, element in ipairs {
|
|
||||||
'Overlay', 'Underlay',
|
|
||||||
'ScoreP1', 'ScoreP2',
|
|
||||||
'LifeP1', 'LifeP2',
|
|
||||||
'PlayerOptionsP1', 'PlayerOptionsP2', 'SongOptions',
|
|
||||||
'LifeFrame', 'ScoreFrame',
|
|
||||||
'DifficultyP1', 'DifficultyP2',
|
|
||||||
'BPMDisplay',
|
|
||||||
'MemoryCardDisplayP1', 'MemoryCardDisplayP2'
|
|
||||||
} do
|
|
||||||
local child = SCREENMAN(element)
|
|
||||||
if child then child:hidden(1) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
GAMESTATE:ApplyModifiers('clearall')
|
|
||||||
|
|
||||||
local drawfunctionArguments = {}
|
|
||||||
local specialActorFrames = {} -- ones defined specifically; here for drawfunction jank
|
|
||||||
|
|
||||||
function setDrawFunction(frame, func)
|
|
||||||
--if not frame.__raw then error('uranium: cannot set actorframe drawfunction during module loadtime! put this in uranium.init or actor:addcommand(\'Init\', ...)', 2) end
|
|
||||||
if not frame.SetDrawFunction then error('uranium: expected an actorframe but got something that doesn\'t even bother to implement SetDrawFunction', 2) end
|
|
||||||
if type(func) ~= 'function' then error('uranium: tried to set a drawfunction to a.. ' .. type(func) .. '?? the hell', 2) end
|
|
||||||
frame:SetDrawFunction(function()
|
|
||||||
for i = 1, frame:GetNumChildren() do
|
|
||||||
local a = frame:GetChildAt(i - 1)
|
|
||||||
if specialActorFrames[a] == false then
|
|
||||||
a:Draw()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local args = drawfunctionArguments[frame]
|
|
||||||
if args then
|
|
||||||
func(unpack(args))
|
|
||||||
else
|
|
||||||
func()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
function setShader(actor, shader)
|
|
||||||
if not shader.__raw then
|
|
||||||
function uranium.init() setShader(actor, shader) end
|
|
||||||
else
|
|
||||||
actor:SetShader(shader.__raw)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function setShaderfuck(shader)
|
|
||||||
if not shader.__raw then
|
|
||||||
function uranium.init() setShaderfuck(shader) end
|
|
||||||
else
|
|
||||||
DISPLAY:ShaderFuck(shader.__raw)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function clearShaderfuck()
|
|
||||||
DISPLAY:ClearShaderFuck()
|
|
||||||
end
|
|
||||||
|
|
||||||
function resetOnFrameStart(bool)
|
|
||||||
resetOnFrameStartCfg = bool
|
|
||||||
end
|
|
||||||
|
|
||||||
function resetActorOnFrameStart(actor, bool)
|
|
||||||
if bool == nil then bool = not resetOnFrameStartCfg end
|
|
||||||
resetOnFrameStartActors[actor.__raw or actor] = bool
|
|
||||||
end
|
|
||||||
|
|
||||||
local actorAssociationTable = {}
|
|
||||||
|
|
||||||
function getChildren(frame)
|
|
||||||
local c = actorAssociationTable[frame]
|
|
||||||
if c then
|
|
||||||
return c
|
|
||||||
else
|
|
||||||
error('uranium: actorframe doesn\'t exist (or isn\'t an actorframe)', 2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- actors
|
|
||||||
|
|
||||||
local actorQueue = {}
|
|
||||||
local actorAssociationQueue = {}
|
|
||||||
|
|
||||||
local actorTree = {}
|
|
||||||
local currentPath
|
|
||||||
local pastPaths = {}
|
|
||||||
local currentActor = nil
|
|
||||||
|
|
||||||
local function findFirstActor(path)
|
|
||||||
for i, v in ipairs(path) do
|
|
||||||
if v.type or v.file then
|
|
||||||
return v, i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function findFirstActorFrame(path)
|
|
||||||
for i, v in ipairs(path) do
|
|
||||||
if not v.type and not v.file then
|
|
||||||
return v, i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
oat._actor = {}
|
|
||||||
|
|
||||||
local function nextActor()
|
|
||||||
local new, idx = findFirstActor(currentPath)
|
|
||||||
if not new then
|
|
||||||
currentActor = nil
|
|
||||||
else
|
|
||||||
currentActor = new
|
|
||||||
table.remove(currentPath, idx)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.recurse(forceActor)
|
|
||||||
local newFrame, idx = findFirstActorFrame(currentPath)
|
|
||||||
local newActor = findFirstActor(currentPath)
|
|
||||||
if newFrame and not (newActor and forceActor) then
|
|
||||||
table.insert(pastPaths, currentPath)
|
|
||||||
currentPath = currentPath[idx]
|
|
||||||
table.remove(pastPaths[#pastPaths], idx)
|
|
||||||
return true
|
|
||||||
elseif newActor then
|
|
||||||
table.insert(pastPaths, currentPath)
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.recurseLast()
|
|
||||||
return oat._actor.recurse(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.endRecurse()
|
|
||||||
currentPath = table.remove(pastPaths, #pastPaths)
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.cond()
|
|
||||||
return currentActor ~= nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.hasShader()
|
|
||||||
return oat._actor.cond() and (currentActor.frag ~= nil or currentActor.vert ~= nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.noShader()
|
|
||||||
nextActor()
|
|
||||||
return oat._actor.cond() and not oat._actor.hasShader()
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.type()
|
|
||||||
return currentActor.type
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.file()
|
|
||||||
return currentActor.file
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.frag()
|
|
||||||
return currentActor.frag or 'nop.frag'
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.vert()
|
|
||||||
return currentActor.vert or 'nop.vert'
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.font()
|
|
||||||
return currentActor.font
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.init(self)
|
|
||||||
currentActor.init(self)
|
|
||||||
self:removecommand('Init')
|
|
||||||
currentActor = nil -- to prevent any weirdness
|
|
||||||
end
|
|
||||||
|
|
||||||
function oat._actor.initFrame(self)
|
|
||||||
self:removecommand('Init')
|
|
||||||
self:SetDrawFunction(function()
|
|
||||||
for i = 1, self:GetNumChildren() do
|
|
||||||
local a = self:GetChildAt(i - 1)
|
|
||||||
if specialActorFrames[a] == false then
|
|
||||||
a:Draw()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
if currentPath.init then
|
|
||||||
currentPath.init(self)
|
|
||||||
currentPath.init = nil
|
|
||||||
specialActorFrames[self] = true
|
|
||||||
else
|
|
||||||
specialActorFrames[self] = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local actorMethodOverrides = {
|
|
||||||
Draw = function(self, ...)
|
|
||||||
drawfunctionArguments[self] = arg
|
|
||||||
self.__raw:Draw()
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
local function createProxyActor(name)
|
|
||||||
local queue = {}
|
|
||||||
local initCommands = {}
|
|
||||||
local lockedActor
|
|
||||||
local queueRepresentation
|
|
||||||
|
|
||||||
return setmetatable({}, {
|
|
||||||
__index = function(self, key)
|
|
||||||
if key == '__raw' then
|
|
||||||
return lockedActor
|
|
||||||
end
|
|
||||||
if lockedActor then
|
|
||||||
if actorMethodOverrides[key] then
|
|
||||||
return actorMethodOverrides[key]
|
|
||||||
else
|
|
||||||
local val = lockedActor[key]
|
|
||||||
if type(val) == 'function' then
|
|
||||||
return patchFunction(val, lockedActor)
|
|
||||||
end
|
|
||||||
return val
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if key == '__queue' then
|
|
||||||
return queueRepresentation
|
|
||||||
end
|
|
||||||
if key == '__queueRepresentation' then
|
|
||||||
return function(q)
|
|
||||||
queueRepresentation = q
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if key == '__lock' then
|
|
||||||
return function(actor)
|
|
||||||
if lockedActor then return end
|
|
||||||
for _, v in ipairs(queue) do
|
|
||||||
local func = actor[v[1]]
|
|
||||||
if not func then
|
|
||||||
error(
|
|
||||||
'uranium: error on \'' .. name .. '\' initialization on ' .. v[3].short_src .. ':' .. v[3].currentline .. ':\n' ..
|
|
||||||
'you\'re calling a function \'' .. v[1] .. '\' on a ' .. name .. ' which doesn\'t exist!:\n'
|
|
||||||
)
|
|
||||||
else
|
|
||||||
local success, result = pcall(function()
|
|
||||||
patchFunction(func, actor)(unpack(v[2]))
|
|
||||||
end)
|
|
||||||
if not success then
|
|
||||||
error(
|
|
||||||
'uranium: error on \'' .. name .. '\' initialization on ' .. v[3].short_src .. ':' .. v[3].currentline .. ':\n' ..
|
|
||||||
result
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- now that we know there's no poisonous methods in queue, let's offload them
|
|
||||||
for _, v in ipairs(queue) do
|
|
||||||
table.insert(globalQueue, {actor, v})
|
|
||||||
end
|
|
||||||
-- let's also properly route everything from the proxied actor to the actual actor
|
|
||||||
lockedActor = actor
|
|
||||||
-- and now let's run the initcommands
|
|
||||||
for _, c in ipairs(initCommands) do
|
|
||||||
local func = c[1]
|
|
||||||
local success, result = pcall(function()
|
|
||||||
func(actor)
|
|
||||||
end)
|
|
||||||
if not success then
|
|
||||||
error(
|
|
||||||
'uranium: error on \'' .. name .. '\' InitCommand defined on ' .. v[3].short_src .. ':' .. v[3].currentline .. ':\n' ..
|
|
||||||
result
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- to make mr. Garbage Collector's job easier
|
|
||||||
initCommands = {}
|
|
||||||
queueRepresentation = nil
|
|
||||||
queue = {}
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return function(...)
|
|
||||||
if actorsInitialized then return end
|
|
||||||
if key == 'addcommand' and arg[2] == 'Init' then
|
|
||||||
table.insert(initCommands, {arg[3], debug.getinfo(2, 'Sl')})
|
|
||||||
else
|
|
||||||
table.insert(queue, {key, arg, debug.getinfo(2, 'Sl')})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
__newindex = function()
|
|
||||||
error('uranium: cannot set properties on actors!', 2)
|
|
||||||
end,
|
|
||||||
__tostring = function() return 'Proxy of ' .. name end,
|
|
||||||
__name = name
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
local function createGenericFunc(type)
|
|
||||||
return function()
|
|
||||||
if actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
local actor = createProxyActor(type)
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = type,
|
|
||||||
init = function(a)
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
actor.__queueRepresentation(actorQueue[#actorQueue])
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Quad = createGenericFunc('Quad')
|
|
||||||
ActorProxy = createGenericFunc('ActorProxy')
|
|
||||||
Polygon = createGenericFunc('Polygon')
|
|
||||||
ActorFrameTexture = createGenericFunc('ActorFrameTexture')
|
|
||||||
|
|
||||||
function Sprite(file)
|
|
||||||
if actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
--if not file then error('uranium: cannot create a Sprite without a file', 2) end
|
|
||||||
local actor = createProxyActor('Sprite')
|
|
||||||
local type = nil
|
|
||||||
if not file then type = 'Sprite' end
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = type,
|
|
||||||
file = file and oat.dir .. file,
|
|
||||||
init = function(a)
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
actor.__queueRepresentation(actorQueue[#actorQueue])
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
function ActorFrame()
|
|
||||||
if actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
local actor = createProxyActor('ActorFrame')
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = 'ActorFrame',
|
|
||||||
init = function(a)
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
actor.__queueRepresentation(actorQueue[#actorQueue])
|
|
||||||
actorAssociationTable[actor] = {}
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
local function isShaderCode(str)
|
|
||||||
return string.find(str or '', '\n')
|
|
||||||
end
|
|
||||||
|
|
||||||
function Shader(frag, vert)
|
|
||||||
if actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
local actor = createProxyActor('RageShaderProgram')
|
|
||||||
|
|
||||||
local fragFile = frag
|
|
||||||
local vertFile = vert
|
|
||||||
|
|
||||||
local isFragShaderCode = isShaderCode(frag)
|
|
||||||
local isVertShaderCode = isShaderCode(vert)
|
|
||||||
|
|
||||||
if isFragShaderCode then fragFile = nil end
|
|
||||||
if isVertShaderCode then vertFile = nil end
|
|
||||||
|
|
||||||
if (frag and vert) and ((isFragShaderCode and not isVertShaderCode) or (not isFragShaderCode and isVertShaderCode)) then
|
|
||||||
error('uranium: cannot create a shader with 1 shader file and 1 shader code block', 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = 'Sprite',
|
|
||||||
frag = fragFile and ('../' .. fragFile) or 'nop.frag',
|
|
||||||
vert = vertFile and ('../' .. vertFile) or 'nop.vert',
|
|
||||||
init = function(a)
|
|
||||||
a:hidden(1)
|
|
||||||
actor.__lock(a:GetShader())
|
|
||||||
|
|
||||||
-- shader code stuff
|
|
||||||
if isFragShaderCode or isVertShaderCode then
|
|
||||||
a:GetShader():compile(vert or '', frag or '')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
actor.__queueRepresentation(actorQueue[#actorQueue])
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
function Texture(file)
|
|
||||||
if actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
if not file then error('uranium: cannot create a texture without a file', 2) end
|
|
||||||
local actor = createProxyActor('RageTexture')
|
|
||||||
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
file = file and oat.dir .. file,
|
|
||||||
init = function(a)
|
|
||||||
a:hidden(1)
|
|
||||||
actor.__lock(a:GetTexture())
|
|
||||||
end
|
|
||||||
})
|
|
||||||
actor.__queueRepresentation(actorQueue[#actorQueue])
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
function Model(file)
|
|
||||||
if actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
if not file then error('uranium: cannot create a Model without a file', 2) end
|
|
||||||
local actor = createProxyActor('Model')
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = nil,
|
|
||||||
file = file and oat.dir .. file,
|
|
||||||
init = function(a)
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
actor.__queueRepresentation(actorQueue[#actorQueue])
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
function BitmapText(font, text)
|
|
||||||
if actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
local actor = createProxyActor('BitmapText')
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = 'BitmapText',
|
|
||||||
font = font or 'common',
|
|
||||||
init = function(a)
|
|
||||||
if text then a:settext(text) end
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
actor.__queueRepresentation(actorQueue[#actorQueue])
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
function ActorSound(file)
|
|
||||||
if actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
|
||||||
if actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
|
||||||
if not file then error('uranium: cannot create an ActorSound without a file', 2) end
|
|
||||||
local actor = createProxyActor('ActorSound')
|
|
||||||
table.insert(actorQueue, {
|
|
||||||
type = 'ActorSound',
|
|
||||||
file = oat.dir .. file,
|
|
||||||
init = function(a)
|
|
||||||
actor.__lock(a)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
actor.__queueRepresentation(actorQueue[#actorQueue])
|
|
||||||
return actor
|
|
||||||
end
|
|
||||||
|
|
||||||
function addChild(frame, actor)
|
|
||||||
if not frame or not actor then
|
|
||||||
error('uranium: frame and actor must both Exist', 2)
|
|
||||||
end
|
|
||||||
if actorsInitializing then
|
|
||||||
error('uranium: cannot create frame-child associations during actor initialization', 2)
|
|
||||||
end
|
|
||||||
if actorsInitialized then
|
|
||||||
error('uranium: cannot create frame-child associations after actors have been initialized', 2)
|
|
||||||
end
|
|
||||||
if not frame.__lock then
|
|
||||||
error('uranium: ActorFrame passed into addChild must be one instantiated with ActorFrame()!', 2)
|
|
||||||
end
|
|
||||||
if not actor.__lock then
|
|
||||||
error('uranium: trying to add a child to an ActorFrame that isn\'t an actor; please read the first half of \'ActorFrame\'', 2)
|
|
||||||
end
|
|
||||||
actorAssociationQueue[actor.__queue] = frame.__queue
|
|
||||||
table.insert(actorAssociationTable[frame], actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function transformQueueToTree()
|
|
||||||
local tree = {}
|
|
||||||
local paths = {}
|
|
||||||
local iter = 0
|
|
||||||
while #actorQueue > 0 do
|
|
||||||
iter = iter + 1
|
|
||||||
if iter > 99999 then
|
|
||||||
error('uranium: failed to transform queue to tree: reached maximum iteration limit! is there an actor with an invalid actorframe?')
|
|
||||||
end
|
|
||||||
for i = #actorQueue, 1, -1 do
|
|
||||||
v = actorQueue[i]
|
|
||||||
local insertInto
|
|
||||||
if not actorAssociationQueue[v] then
|
|
||||||
insertInto = tree
|
|
||||||
else
|
|
||||||
if paths[actorAssociationQueue[v]] then
|
|
||||||
insertInto = paths[actorAssociationQueue[v]]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if insertInto then
|
|
||||||
if v.type == 'ActorFrame' then
|
|
||||||
table.insert(insertInto, {init = v.init})
|
|
||||||
table.remove(actorQueue, i)
|
|
||||||
paths[v] = insertInto[#insertInto]
|
|
||||||
else
|
|
||||||
table.insert(insertInto, v)
|
|
||||||
table.remove(actorQueue, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
actorTree = tree
|
|
||||||
end
|
|
||||||
|
|
||||||
local lastt = GAMESTATE:GetSongTime()
|
|
||||||
local function screenReadyCommand(self)
|
|
||||||
hideThemeActors()
|
|
||||||
self:hidden(0)
|
|
||||||
oat._actor = {}
|
|
||||||
|
|
||||||
actorQueue = {}
|
|
||||||
actorAssociationQueue = {}
|
|
||||||
|
|
||||||
actorTree = {}
|
|
||||||
currentPath = nil
|
|
||||||
pastPaths = {}
|
|
||||||
currentActor = nil
|
|
||||||
|
|
||||||
collectgarbage()
|
|
||||||
|
|
||||||
local errored = false
|
|
||||||
local firstrun = true
|
|
||||||
local playersLoaded = false
|
|
||||||
self:addcommand('Update', function()
|
|
||||||
if errored then
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
errored = true
|
|
||||||
|
|
||||||
if P1 and P2 then
|
|
||||||
playersLoaded = true
|
|
||||||
end
|
|
||||||
if playersLoaded and not P1 and not P2 then -- sora exit hack
|
|
||||||
exit()
|
|
||||||
end
|
|
||||||
|
|
||||||
t = os.clock()
|
|
||||||
b = GAMESTATE:GetSongBeat()
|
|
||||||
local dt = t - lastt
|
|
||||||
lastt = t
|
|
||||||
|
|
||||||
if firstrun then
|
|
||||||
firstrun = false
|
|
||||||
dt = 0
|
|
||||||
self:GetChildren()[2]:hidden(1)
|
|
||||||
uranium:call('ready')
|
|
||||||
end
|
|
||||||
|
|
||||||
drawfunctionArguments = {}
|
|
||||||
|
|
||||||
for _, q in ipairs(globalQueue) do
|
|
||||||
local enabled = resetOnFrameStartCfg
|
|
||||||
|
|
||||||
local actor = q[1]
|
|
||||||
local v = q[2]
|
|
||||||
|
|
||||||
local pref = resetOnFrameStartActors[actor]
|
|
||||||
if pref ~= nil then enabled = pref end
|
|
||||||
|
|
||||||
if enabled then
|
|
||||||
local func = actor[v[1]]
|
|
||||||
if not func then
|
|
||||||
-- uhmmm ??? hm. what do we do??
|
|
||||||
else
|
|
||||||
patchFunction(func, actor)(unpack(v[2]))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
uranium:call('preUpdate', dt)
|
|
||||||
uranium:call('update', dt)
|
|
||||||
uranium:call('postUpdate', dt)
|
|
||||||
|
|
||||||
errored = false
|
|
||||||
|
|
||||||
return 0
|
|
||||||
end)
|
|
||||||
self:luaeffect('Update')
|
|
||||||
end
|
|
||||||
|
|
||||||
if not pcall(function() oat._release = require('release') end) then
|
|
||||||
oat._release = require('release_blank')
|
|
||||||
end
|
|
||||||
|
|
||||||
local success, result = pcall(function()
|
|
||||||
require('main')
|
|
||||||
end)
|
|
||||||
|
|
||||||
if success then
|
|
||||||
luaobj = result
|
|
||||||
|
|
||||||
print('---')
|
|
||||||
|
|
||||||
actorsInitializing = true
|
|
||||||
transformQueueToTree()
|
|
||||||
--Trace(fullDump(actorTree))
|
|
||||||
currentPath = actorTree
|
|
||||||
|
|
||||||
self:addcommand('On', onCommand)
|
|
||||||
self:addcommand('Ready', screenReadyCommand)
|
|
||||||
self:addcommand('Off', exit)
|
|
||||||
self:addcommand('SaltyReset', exit)
|
|
||||||
self:addcommand('WindowFocus', function()
|
|
||||||
uranium:call('focus', true)
|
|
||||||
end)
|
|
||||||
self:addcommand('WindowFocusLost', function()
|
|
||||||
uranium:call('focus', false)
|
|
||||||
end)
|
|
||||||
self:queuecommand('Ready')
|
|
||||||
else
|
|
||||||
Trace('got an error loading main.lua!')
|
|
||||||
Trace(result)
|
|
||||||
backToSongWheel('loading .lua file failed, check log for details')
|
|
||||||
error('uranium: loading main.lua file failed:\n' .. result)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- NotITG and OpenITG have a long standing bug where the InitCommand on an actor can run twice in certain cases.
|
-- NotITG and OpenITG have a long standing bug where the InitCommand on an actor can run twice in certain cases.
|
||||||
-- By removing the command after it's done, it can only ever run once
|
-- By removing the command after it's done, it can only ever run once
|
||||||
|
|
|
@ -17,4 +17,15 @@ function self.aft(self)
|
||||||
self:Create()
|
self:Create()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function self.aftSetup()
|
||||||
|
local a = ActorFrameTexture()
|
||||||
|
local b = Sprite()
|
||||||
|
uranium.on('init', function()
|
||||||
|
self.aft(a)
|
||||||
|
self.sprite(b)
|
||||||
|
b:SetTexture(a:GetTexture())
|
||||||
|
end)
|
||||||
|
return a, b
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
|
@ -1,72 +1,42 @@
|
||||||
require('stdlib.util')
|
|
||||||
|
|
||||||
---@class easable
|
---@class easable
|
||||||
---@field public a number @the eased value
|
---@field eased number | any
|
||||||
---@field public toa number @the target, uneased value
|
---@field target number | any
|
||||||
local eas = {}
|
---@field speed number
|
||||||
|
local easable = {}
|
||||||
|
|
||||||
---@param new number @New value to ease to
|
--- move towards a new target
|
||||||
---@return void
|
function easable:set(n)
|
||||||
function eas:set(new)
|
self.target = n
|
||||||
self.toa = new
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param new number @New value
|
--- move towards a new target additively
|
||||||
---@return void
|
function easable:add(n)
|
||||||
function eas:reset(new)
|
self.target = self.target + n
|
||||||
self.toa = new
|
|
||||||
self.a = new
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param new number @How much to add to current value to ease to
|
--- set both the eased value and the target
|
||||||
---@return void
|
function easable:reset(n)
|
||||||
function eas:add(new)
|
self.target = n
|
||||||
self.toa = self.toa + new
|
self.eased = n
|
||||||
end
|
end
|
||||||
|
|
||||||
local easmeta = {}
|
---@param dt number
|
||||||
|
function easable:update(dt)
|
||||||
easmeta.__index = eas
|
self.eased = math.pow(self.speed, -dt) * (self.eased - self.target) + self.target
|
||||||
easmeta.__name = 'easable'
|
|
||||||
|
|
||||||
function easmeta.__add(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) + ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__sub(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) - ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__mul(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) * ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__div(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) / ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__mod(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) % ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__eq(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) == ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__lt(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) < ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
|
||||||
function easmeta.__le(a, b)
|
|
||||||
return ((type(a) == 'table' and a.a) and a.a or a) <= ((type(b) == 'table' and b.a) and b.a or b)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function easmeta:__call(dt)
|
function easable:__tostring()
|
||||||
self.a = mix(self.a, self.toa, dt)
|
return 'easable (' .. self.eased .. ' towards ' .. self.target .. ')'
|
||||||
end
|
|
||||||
function easmeta:__tostring()
|
|
||||||
return tostring(self.a)
|
|
||||||
end
|
|
||||||
function easmeta:__unm(self)
|
|
||||||
return -self.a
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param default number
|
easable.__index = easable
|
||||||
|
easable.__name = 'easable'
|
||||||
|
|
||||||
---@return easable
|
---@return easable
|
||||||
return function(default)
|
return function(default, speed)
|
||||||
default = default or 0
|
return setmetatable({
|
||||||
return setmetatable({a = default, toa = default}, easmeta)
|
eased = default,
|
||||||
|
target = default,
|
||||||
|
speed = speed and math.pow(2, speed) or 2
|
||||||
|
}, easable)
|
||||||
end
|
end
|
|
@ -8,9 +8,9 @@ return function()
|
||||||
P2:SetNoteDataFromLua({})
|
P2:SetNoteDataFromLua({})
|
||||||
end
|
end
|
||||||
|
|
||||||
function uranium.update()
|
uranium.on('update', function()
|
||||||
if b >= 1 then
|
if b >= 1 then
|
||||||
GAMESTATE:SetSongBeat(b % 1)
|
GAMESTATE:SetSongBeat(b % 1)
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
end
|
end
|
|
@ -106,7 +106,7 @@ function self.isDown(i, pn)
|
||||||
return self.getInput(i, pn) ~= -1
|
return self.getInput(i, pn) ~= -1
|
||||||
end
|
end
|
||||||
|
|
||||||
function uranium.init()
|
uranium.on('init', function()
|
||||||
for pn = 1, 2 do
|
for pn = 1, 2 do
|
||||||
for j, v in pairs(self.inputType) do
|
for j, v in pairs(self.inputType) do
|
||||||
local j = j -- lua scope funnies
|
local j = j -- lua scope funnies
|
||||||
|
@ -124,6 +124,6 @@ function uranium.init()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
|
|
||||||
return self
|
return self
|
|
@ -14,6 +14,6 @@ require('stdlib.mirin.sort')
|
||||||
require('stdlib.mirin.ease')
|
require('stdlib.mirin.ease')
|
||||||
require('stdlib.mirin.template')
|
require('stdlib.mirin.template')
|
||||||
|
|
||||||
function uranium.init()
|
uranium.on('init', function()
|
||||||
xero.init_command(xeroActorsAF)
|
xero.init_command(xeroActorsAF)
|
||||||
end
|
end)
|
|
@ -1,14 +1,14 @@
|
||||||
local oldAutoplay
|
local oldAutoplay
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
function uranium.ready()
|
uranium.on('ready', function()
|
||||||
oldAutoplay = PREFSMAN:GetPreference('AutoPlay')
|
oldAutoplay = PREFSMAN:GetPreference('AutoPlay')
|
||||||
PREFSMAN:SetPreference('AutoPlay', 0)
|
PREFSMAN:SetPreference('AutoPlay', 0)
|
||||||
end
|
end)
|
||||||
|
|
||||||
function uranium.exit()
|
uranium.on('exit', function()
|
||||||
if oldAutoplay and oldAutoplay ~= 0 then
|
if oldAutoplay and oldAutoplay ~= 0 then
|
||||||
PREFSMAN:SetPreference('AutoPlay', oldAutoplay)
|
PREFSMAN:SetPreference('AutoPlay', oldAutoplay)
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
end
|
end
|
|
@ -49,8 +49,8 @@ if PROFILER_ENABLED then
|
||||||
text:Draw()
|
text:Draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
function uranium.postUpdate(dt)
|
uranium.on('postUpdate', function(dt)
|
||||||
max(dt * 12)
|
max(dt * 12)
|
||||||
draw()
|
draw()
|
||||||
end
|
end)
|
||||||
end
|
end
|
|
@ -176,18 +176,18 @@ function self.getLastSave()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function uranium.init()
|
uranium.on('init', function()
|
||||||
loadedSavedata = true
|
loadedSavedata = true
|
||||||
if savedataName then
|
if savedataName then
|
||||||
self.load()
|
self.load()
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
|
|
||||||
function self.enableAutosave()
|
function self.enableAutosave()
|
||||||
checkIfInitialized()
|
checkIfInitialized()
|
||||||
function uranium.exit()
|
uranium.on('exit', function()
|
||||||
self.save(true)
|
self.save(true)
|
||||||
end
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
|
@ -40,7 +40,7 @@ function self:unscheduleInTicks(i)
|
||||||
scheduledTicks[i] = nil
|
scheduledTicks[i] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function uranium.update(dt)
|
uranium.on('update', function(dt)
|
||||||
for k, s in pairs(scheduledTicks) do
|
for k, s in pairs(scheduledTicks) do
|
||||||
s[1] = s[1] - 1
|
s[1] = s[1] - 1
|
||||||
if s[1] <= 0 then
|
if s[1] <= 0 then
|
||||||
|
@ -56,6 +56,6 @@ function uranium.update(dt)
|
||||||
scheduled[k] = nil
|
scheduled[k] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
|
|
||||||
return self
|
return self
|
103
typings.lua
103
typings.lua
|
@ -1,7 +1,7 @@
|
||||||
---@meta
|
---@meta
|
||||||
|
|
||||||
-- cleaning up some notitg typing jank... ehe
|
-- cleaning up some notitg typing jank... ehe
|
||||||
---@alias int number
|
---@alias int integer
|
||||||
---@alias float number
|
---@alias float number
|
||||||
---@alias Quad Actor
|
---@alias Quad Actor
|
||||||
---@alias void nil
|
---@alias void nil
|
||||||
|
@ -16,82 +16,6 @@ PROFILEMAN = {}
|
||||||
---@type RageInput
|
---@type RageInput
|
||||||
INPUTMAN = {}
|
INPUTMAN = {}
|
||||||
|
|
||||||
---@return Quad
|
|
||||||
--- Defines a Quad actor.
|
|
||||||
function Quad() end
|
|
||||||
---@return ActorProxy
|
|
||||||
--- Defines an ActorProxy actor.
|
|
||||||
function ActorProxy() end
|
|
||||||
---@return Polygon
|
|
||||||
--- Defines a Polygon actor.
|
|
||||||
function Polygon() end
|
|
||||||
---@param file string | nil
|
|
||||||
---@return Sprite
|
|
||||||
--- Defines a Sprite actor.
|
|
||||||
function Sprite(file) end
|
|
||||||
---@param file string
|
|
||||||
---@return RageTexture
|
|
||||||
--- Defines a texture.
|
|
||||||
function Texture(file) end
|
|
||||||
---@param file string
|
|
||||||
---@return Model
|
|
||||||
--- Defines a Model actor.
|
|
||||||
function Model(file) end
|
|
||||||
---@param font string?
|
|
||||||
---@param text string?
|
|
||||||
---@return BitmapText
|
|
||||||
--- Defines a BitmapText actor.
|
|
||||||
function BitmapText(font, text) end
|
|
||||||
---@param file string
|
|
||||||
---@return ActorSound
|
|
||||||
--- Defines an ActorSound actor.
|
|
||||||
function ActorSound(file) end
|
|
||||||
---@return ActorFrameTexture
|
|
||||||
--- Defines an ActorFrameTexture actor.
|
|
||||||
function ActorFrameTexture() end
|
|
||||||
---@param frag string | nil
|
|
||||||
---@param vert string | nil
|
|
||||||
---@return RageShaderProgram
|
|
||||||
--- Defines a shader. `frag` and `vert` can either be filenames or shader code.
|
|
||||||
function Shader(frag, vert) end
|
|
||||||
---@return ActorFrame
|
|
||||||
---@see addChild
|
|
||||||
--- Defines an ActorFrame. Add children to it with `addChild`.
|
|
||||||
function ActorFrame() end
|
|
||||||
|
|
||||||
---@param actor Actor
|
|
||||||
--- Resets an actor to its initial state
|
|
||||||
function reset(actor) end
|
|
||||||
resetActor = reset
|
|
||||||
|
|
||||||
---@param frame ActorFrame
|
|
||||||
---@param actor Actor
|
|
||||||
--- Adds a child to an ActorFrame. **Please be aware of the side-effects!**
|
|
||||||
function addChild(frame, actor) end
|
|
||||||
|
|
||||||
---@param frame ActorFrame
|
|
||||||
---@param func function
|
|
||||||
--- SetDrawFunction with special behavior to account for Uranium's actor loading scheme.
|
|
||||||
function setDrawFunction(frame, func) end
|
|
||||||
|
|
||||||
---@param actor Actor
|
|
||||||
---@param shader RageShaderProgram
|
|
||||||
function setShader(actor, shader) end
|
|
||||||
|
|
||||||
-- Toggle actor resetting on frame start behavior by default.
|
|
||||||
---@param bool boolean
|
|
||||||
function resetOnFrameStart(bool) end
|
|
||||||
|
|
||||||
-- Toggle actor resetting on frame start for individual actors. `bool` defaults to the opposite of your `resetOnFrameStart` config
|
|
||||||
---@param actor Actor
|
|
||||||
---@param bool boolean | nil
|
|
||||||
function resetActorOnFrameStart(actor, bool) end
|
|
||||||
|
|
||||||
-- Gets every child of an ActorFrame. More accurate than :GetChildren()
|
|
||||||
---@param frame ActorFrame
|
|
||||||
---@return Actor[]
|
|
||||||
function getChildren(frame) end
|
|
||||||
|
|
||||||
---@type number
|
---@type number
|
||||||
--- A simple timer. Ticks upwards at a rate of 1/sec.
|
--- A simple timer. Ticks upwards at a rate of 1/sec.
|
||||||
---
|
---
|
||||||
|
@ -127,26 +51,11 @@ dw = 0
|
||||||
--- The display height.
|
--- The display height.
|
||||||
dh = 0
|
dh = 0
|
||||||
|
|
||||||
--- The Uranium Template table! Mostly callback-related stuff goes here.
|
|
||||||
uranium = {}
|
|
||||||
|
|
||||||
--- A callback for initialization. Called on `OnCommand`.
|
|
||||||
uranium.init = function() end
|
|
||||||
--- A callback for updates. Called every frame. Draw stuff here!
|
|
||||||
uranium.update = function() end
|
|
||||||
|
|
||||||
---@param event string
|
|
||||||
---@param ... any
|
|
||||||
---@return any
|
|
||||||
--- Call a defined callback.
|
|
||||||
function uranium:call(event, ...) end
|
|
||||||
|
|
||||||
--- Equivalent to a modfile-sandboxed `_G`, similar to Mirin's `xero`. You shouldn't need this; and if you do, *what are you doing?*
|
--- Equivalent to a modfile-sandboxed `_G`, similar to Mirin's `xero`. You shouldn't need this; and if you do, *what are you doing?*
|
||||||
oat = _G
|
oat = _G
|
||||||
|
|
||||||
---@class ProfilerInfo
|
--- The Uranium Template table! All template-related functionality is stored here.
|
||||||
---@field public t number
|
uranium = {}
|
||||||
---@field public src string
|
---@type string
|
||||||
|
--- A shorthand for `GAMESTATE:GetCurrentSong():GetSongDir()`.
|
||||||
---@type table<string, ProfilerInfo>
|
uranium.dir = nil
|
||||||
profilerInfo = {}
|
|
|
@ -0,0 +1,601 @@
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
M._actorsInitialized = false -- if true, no new actors can be created
|
||||||
|
M._actorsInitializing = false -- the above but a bit more explicit
|
||||||
|
|
||||||
|
local drawfunctionArguments = {}
|
||||||
|
local specialActorFrames = {} -- ones defined specifically; here for drawfunction jank
|
||||||
|
|
||||||
|
---@param frame ActorFrame
|
||||||
|
---@param func function
|
||||||
|
--- SetDrawFunction with special behavior to account for Uranium's actor loading scheme.
|
||||||
|
function setDrawFunction(frame, func)
|
||||||
|
--if not frame.__raw then error('uranium: cannot set actorframe drawfunction during module loadtime! put this in uranium.init or actor:addcommand(\'Init\', ...)', 2) end
|
||||||
|
if not frame.SetDrawFunction then error('uranium: expected an actorframe but got something that doesn\'t even bother to implement SetDrawFunction', 2) end
|
||||||
|
if type(func) ~= 'function' then error('uranium: tried to set a drawfunction to a.. ' .. type(func) .. '?? the hell', 2) end
|
||||||
|
frame:SetDrawFunction(function()
|
||||||
|
for i = 1, frame:GetNumChildren() do
|
||||||
|
local a = frame:GetChildAt(i - 1)
|
||||||
|
if specialActorFrames[a] == false then
|
||||||
|
a:Draw()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local args = drawfunctionArguments[frame]
|
||||||
|
if args then
|
||||||
|
func(unpack(args))
|
||||||
|
else
|
||||||
|
func()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param actor Actor
|
||||||
|
---@param shader RageShaderProgram
|
||||||
|
function setShader(actor, shader)
|
||||||
|
if not shader.__raw then
|
||||||
|
uranium.on('init', function() setShader(actor, shader) end)
|
||||||
|
else
|
||||||
|
actor:SetShader(shader.__raw)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function setShaderfuck(shader)
|
||||||
|
if not shader.__raw then
|
||||||
|
uranium.on('init', function() setShaderfuck(shader) end)
|
||||||
|
else
|
||||||
|
DISPLAY:ShaderFuck(shader.__raw)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function clearShaderfuck()
|
||||||
|
DISPLAY:ClearShaderFuck()
|
||||||
|
end
|
||||||
|
|
||||||
|
oat._actorAssociationTable = {}
|
||||||
|
|
||||||
|
-- Gets every child of an ActorFrame. More accurate than :GetChildren()
|
||||||
|
---@param frame ActorFrame
|
||||||
|
---@return Actor[]
|
||||||
|
function getChildren(frame)
|
||||||
|
local c = oat._actorAssociationTable[frame]
|
||||||
|
if c then
|
||||||
|
return c
|
||||||
|
else
|
||||||
|
error('uranium: actorframe doesn\'t exist (or isn\'t an actorframe)', 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local patchedFunctions = {}
|
||||||
|
function oat._patchFunction(f, obj)
|
||||||
|
if not patchedFunctions[f] then patchedFunctions[f] = {} end
|
||||||
|
if not patchedFunctions[f][obj] then
|
||||||
|
patchedFunctions[f][obj] = function(...)
|
||||||
|
arg[1] = obj
|
||||||
|
local results
|
||||||
|
local status, result = pcall(function()
|
||||||
|
-- doing it this way instead of returning because lua
|
||||||
|
-- offers no way of grabbing everything BUT the first
|
||||||
|
-- argument out of pcall
|
||||||
|
results = {f(unpack(arg))}
|
||||||
|
end)
|
||||||
|
if not status then
|
||||||
|
error(result, 2)
|
||||||
|
else
|
||||||
|
return unpack(results)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return patchedFunctions[f][obj]
|
||||||
|
end
|
||||||
|
|
||||||
|
M._globalQueue = {} -- for resetting
|
||||||
|
|
||||||
|
---@param actor Actor
|
||||||
|
--- Resets an actor to its initial state
|
||||||
|
function reset(actor)
|
||||||
|
if not M._actorsInitialized then error('uranium: cannot reset an actor during initialization', 2) end
|
||||||
|
for _, q in ipairs(M._globalQueue) do
|
||||||
|
local queueActor = q[1]
|
||||||
|
if queueActor == actor.__raw then
|
||||||
|
local v = q[2]
|
||||||
|
|
||||||
|
local func = queueActor[v[1]]
|
||||||
|
if not func then
|
||||||
|
-- uhmmm ??? hm. what do we do??
|
||||||
|
else
|
||||||
|
oat._patchFunction(func, queueActor)(unpack(v[2]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
resetActor = reset
|
||||||
|
|
||||||
|
M._actorQueue = {}
|
||||||
|
M._actorAssociationQueue = {}
|
||||||
|
|
||||||
|
M._actorTree = {}
|
||||||
|
M._currentPath = nil
|
||||||
|
M._pastPaths = {}
|
||||||
|
M._currentActor = nil
|
||||||
|
|
||||||
|
local function findFirstActor(path)
|
||||||
|
for i, v in ipairs(path) do
|
||||||
|
if v.type or v.file then
|
||||||
|
return v, i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function findFirstActorFrame(path)
|
||||||
|
for i, v in ipairs(path) do
|
||||||
|
if not v.type and not v.file then
|
||||||
|
return v, i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
oat._actor = {}
|
||||||
|
|
||||||
|
local function nextActor()
|
||||||
|
local new, idx = findFirstActor(M._currentPath)
|
||||||
|
if not new then
|
||||||
|
M._currentActor = nil
|
||||||
|
else
|
||||||
|
M._currentActor = new
|
||||||
|
table.remove(M._currentPath, idx)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.recurse(forceActor)
|
||||||
|
local newFrame, idx = findFirstActorFrame(M._currentPath)
|
||||||
|
local newActor = findFirstActor(M._currentPath)
|
||||||
|
if newFrame and not (newActor and forceActor) then
|
||||||
|
table.insert(M._pastPaths, M._currentPath)
|
||||||
|
M._currentPath = M._currentPath[idx]
|
||||||
|
table.remove(M._pastPaths[#M._pastPaths], idx)
|
||||||
|
return true
|
||||||
|
elseif newActor then
|
||||||
|
table.insert(M._pastPaths, M._currentPath)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.recurseLast()
|
||||||
|
return oat._actor.recurse(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.endRecurse()
|
||||||
|
M._currentPath = table.remove(M._pastPaths, #M._pastPaths)
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.cond()
|
||||||
|
return M._currentActor ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.hasShader()
|
||||||
|
return oat._actor.cond() and (M._currentActor.frag ~= nil or M._currentActor.vert ~= nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.noShader()
|
||||||
|
nextActor()
|
||||||
|
return oat._actor.cond() and not oat._actor.hasShader()
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.type()
|
||||||
|
return M._currentActor.type
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.file()
|
||||||
|
return M._currentActor.file
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.frag()
|
||||||
|
return M._currentActor.frag or 'nop.frag'
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.vert()
|
||||||
|
return M._currentActor.vert or 'nop.vert'
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.font()
|
||||||
|
return M._currentActor.font
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.init(self)
|
||||||
|
M._currentActor.init(self)
|
||||||
|
self:removecommand('Init')
|
||||||
|
M._currentActor = nil -- to prevent any weirdness
|
||||||
|
end
|
||||||
|
|
||||||
|
function oat._actor.initFrame(self)
|
||||||
|
self:removecommand('Init')
|
||||||
|
self:SetDrawFunction(function()
|
||||||
|
for i = 1, self:GetNumChildren() do
|
||||||
|
local a = self:GetChildAt(i - 1)
|
||||||
|
if specialActorFrames[a] == false then
|
||||||
|
a:Draw()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if M._currentPath.init then
|
||||||
|
M._currentPath.init(self)
|
||||||
|
M._currentPath.init = nil
|
||||||
|
specialActorFrames[self] = true
|
||||||
|
else
|
||||||
|
specialActorFrames[self] = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local actorMethodOverrides = {
|
||||||
|
Draw = function(self, ...)
|
||||||
|
drawfunctionArguments[self] = arg
|
||||||
|
self.__raw:Draw()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
-- todo: probably make this more sane
|
||||||
|
local function createProxyActor(name)
|
||||||
|
local queue = {}
|
||||||
|
local initCommands = {}
|
||||||
|
local lockedActor
|
||||||
|
local queueRepresentation
|
||||||
|
|
||||||
|
return setmetatable({}, {
|
||||||
|
__index = function(self, key)
|
||||||
|
if key == '__raw' then
|
||||||
|
return lockedActor
|
||||||
|
end
|
||||||
|
if lockedActor then
|
||||||
|
if actorMethodOverrides[key] then
|
||||||
|
return actorMethodOverrides[key]
|
||||||
|
else
|
||||||
|
local val = lockedActor[key]
|
||||||
|
if type(val) == 'function' then
|
||||||
|
return oat._patchFunction(val, lockedActor)
|
||||||
|
end
|
||||||
|
return val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if key == '__queue' then
|
||||||
|
return queueRepresentation
|
||||||
|
end
|
||||||
|
if key == '__queueRepresentation' then
|
||||||
|
return function(q)
|
||||||
|
queueRepresentation = q
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if key == '__lock' then
|
||||||
|
return function(actor)
|
||||||
|
if lockedActor then return end
|
||||||
|
for _, v in ipairs(queue) do
|
||||||
|
local func = actor[v[1]]
|
||||||
|
if not func then
|
||||||
|
error(
|
||||||
|
'uranium: error on \'' .. name .. '\' initialization on ' .. v[3].short_src .. ':' .. v[3].currentline .. ':\n' ..
|
||||||
|
'you\'re calling a function \'' .. v[1] .. '\' on a ' .. name .. ' which doesn\'t exist!:\n'
|
||||||
|
)
|
||||||
|
else
|
||||||
|
local success, result = pcall(function()
|
||||||
|
oat._patchFunction(func, actor)(unpack(v[2]))
|
||||||
|
end)
|
||||||
|
if not success then
|
||||||
|
error(
|
||||||
|
'uranium: error on \'' .. name .. '\' initialization on ' .. v[3].short_src .. ':' .. v[3].currentline .. ':\n' ..
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- now that we know there's no poisonous methods in queue, let's offload them
|
||||||
|
for _, v in ipairs(queue) do
|
||||||
|
table.insert(M._globalQueue, {actor, v})
|
||||||
|
end
|
||||||
|
-- let's also properly route everything from the proxied actor to the actual actor
|
||||||
|
lockedActor = actor
|
||||||
|
-- and now let's run the initcommands
|
||||||
|
for _, c in ipairs(initCommands) do
|
||||||
|
local func = c[1]
|
||||||
|
local success, result = pcall(function()
|
||||||
|
func(actor)
|
||||||
|
end)
|
||||||
|
if not success then
|
||||||
|
error(
|
||||||
|
'uranium: error on \'' .. name .. '\' InitCommand defined on ' .. v[3].short_src .. ':' .. v[3].currentline .. ':\n' ..
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- to make mr. Garbage Collector's job easier
|
||||||
|
initCommands = {}
|
||||||
|
queueRepresentation = nil
|
||||||
|
queue = {}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return function(...)
|
||||||
|
if M._actorsInitialized then return end
|
||||||
|
if key == 'addcommand' and arg[2] == 'Init' then
|
||||||
|
table.insert(initCommands, {arg[3], debug.getinfo(2, 'Sl')})
|
||||||
|
else
|
||||||
|
table.insert(queue, {key, arg, debug.getinfo(2, 'Sl')})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
__newindex = function()
|
||||||
|
error('uranium: cannot set properties on actors!', 2)
|
||||||
|
end,
|
||||||
|
__tostring = function() return 'Proxy of ' .. name end,
|
||||||
|
__name = name
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function createGenericFunc(type)
|
||||||
|
return function()
|
||||||
|
if M._actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
||||||
|
if M._actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
||||||
|
local actor = createProxyActor(type)
|
||||||
|
table.insert(M._actorQueue, {
|
||||||
|
type = type,
|
||||||
|
init = function(a)
|
||||||
|
actor.__lock(a)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
actor.__queueRepresentation(M._actorQueue[#M._actorQueue])
|
||||||
|
return actor
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Defines a Quad actor.
|
||||||
|
---@type fun(): Quad
|
||||||
|
Quad = createGenericFunc('Quad')
|
||||||
|
--- Defines an ActorProxy actor.
|
||||||
|
---@type fun(): ActorProxy
|
||||||
|
ActorProxy = createGenericFunc('ActorProxy')
|
||||||
|
--- Defines a Polygon actor.
|
||||||
|
---@type fun(): Polygon
|
||||||
|
Polygon = createGenericFunc('Polygon')
|
||||||
|
--- Defines an ActorFrameTexture actor.
|
||||||
|
---@type fun(): ActorFrameTexture
|
||||||
|
ActorFrameTexture = createGenericFunc('ActorFrameTexture')
|
||||||
|
|
||||||
|
---@param file string | nil
|
||||||
|
---@return Sprite
|
||||||
|
--- Defines a Sprite actor.
|
||||||
|
function Sprite(file)
|
||||||
|
if M._actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
||||||
|
if M._actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
||||||
|
--if not file then error('uranium: cannot create a Sprite without a file', 2) end
|
||||||
|
local actor = createProxyActor('Sprite')
|
||||||
|
local type = nil
|
||||||
|
if not file then type = 'Sprite' end
|
||||||
|
table.insert(M._actorQueue, {
|
||||||
|
type = type,
|
||||||
|
file = file and uranium.dir .. file,
|
||||||
|
init = function(a)
|
||||||
|
actor.__lock(a)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
actor.__queueRepresentation(M._actorQueue[#M._actorQueue])
|
||||||
|
return actor
|
||||||
|
end
|
||||||
|
|
||||||
|
---@return ActorFrame
|
||||||
|
---@see addChild
|
||||||
|
--- Defines an ActorFrame. Add children to it with `addChild`.
|
||||||
|
function ActorFrame()
|
||||||
|
if M._actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
||||||
|
if M._actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
||||||
|
local actor = createProxyActor('ActorFrame')
|
||||||
|
table.insert(M._actorQueue, {
|
||||||
|
type = 'ActorFrame',
|
||||||
|
init = function(a)
|
||||||
|
actor.__lock(a)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
actor.__queueRepresentation(M._actorQueue[#M._actorQueue])
|
||||||
|
oat._actorAssociationTable[actor] = {}
|
||||||
|
return actor
|
||||||
|
end
|
||||||
|
|
||||||
|
local function isShaderCode(str)
|
||||||
|
return string.find(str or '', '\n')
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param frag string | nil
|
||||||
|
---@param vert string | nil
|
||||||
|
---@return RageShaderProgram
|
||||||
|
--- Defines a shader. `frag` and `vert` can either be filenames or shader code.
|
||||||
|
function Shader(frag, vert)
|
||||||
|
if M._actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
||||||
|
if M._actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
||||||
|
local actor = createProxyActor('RageShaderProgram')
|
||||||
|
|
||||||
|
local fragFile = frag
|
||||||
|
local vertFile = vert
|
||||||
|
|
||||||
|
local isFragShaderCode = isShaderCode(frag)
|
||||||
|
local isVertShaderCode = isShaderCode(vert)
|
||||||
|
|
||||||
|
if isFragShaderCode then fragFile = nil end
|
||||||
|
if isVertShaderCode then vertFile = nil end
|
||||||
|
|
||||||
|
if (frag and vert) and ((isFragShaderCode and not isVertShaderCode) or (not isFragShaderCode and isVertShaderCode)) then
|
||||||
|
error('uranium: cannot create a shader with 1 shader file and 1 shader code block', 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(M._actorQueue, {
|
||||||
|
type = 'Sprite',
|
||||||
|
frag = fragFile and ('../' .. fragFile) or 'nop.frag',
|
||||||
|
vert = vertFile and ('../' .. vertFile) or 'nop.vert',
|
||||||
|
init = function(a)
|
||||||
|
a:hidden(1)
|
||||||
|
actor.__lock(a:GetShader())
|
||||||
|
|
||||||
|
-- shader code stuff
|
||||||
|
if isFragShaderCode or isVertShaderCode then
|
||||||
|
a:GetShader():compile(vert or '', frag or '')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
actor.__queueRepresentation(M._actorQueue[#M._actorQueue])
|
||||||
|
return actor
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param file string
|
||||||
|
---@return RageTexture
|
||||||
|
--- Defines a texture.
|
||||||
|
function Texture(file)
|
||||||
|
if M._actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
||||||
|
if M._actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
||||||
|
if not file then error('uranium: cannot create a texture without a file', 2) end
|
||||||
|
local actor = createProxyActor('RageTexture')
|
||||||
|
|
||||||
|
table.insert(M._actorQueue, {
|
||||||
|
file = file and uranium.dir .. file,
|
||||||
|
init = function(a)
|
||||||
|
a:hidden(1)
|
||||||
|
actor.__lock(a:GetTexture())
|
||||||
|
end
|
||||||
|
})
|
||||||
|
actor.__queueRepresentation(M._actorQueue[#M._actorQueue])
|
||||||
|
return actor
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param file string
|
||||||
|
---@return Model
|
||||||
|
--- Defines a Model actor.
|
||||||
|
function Model(file)
|
||||||
|
if M._actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
||||||
|
if M._actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
||||||
|
if not file then error('uranium: cannot create a Model without a file', 2) end
|
||||||
|
local actor = createProxyActor('Model')
|
||||||
|
table.insert(M._actorQueue, {
|
||||||
|
type = nil,
|
||||||
|
file = file and uranium.dir .. file,
|
||||||
|
init = function(a)
|
||||||
|
actor.__lock(a)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
actor.__queueRepresentation(M._actorQueue[#M._actorQueue])
|
||||||
|
return actor
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param font string?
|
||||||
|
---@param text string?
|
||||||
|
---@return BitmapText
|
||||||
|
--- Defines a BitmapText actor.
|
||||||
|
function BitmapText(font, text)
|
||||||
|
if M._actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
||||||
|
if M._actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
||||||
|
local actor = createProxyActor('BitmapText')
|
||||||
|
table.insert(M._actorQueue, {
|
||||||
|
type = 'BitmapText',
|
||||||
|
font = font or 'common',
|
||||||
|
init = function(a)
|
||||||
|
if text then a:settext(text) end
|
||||||
|
actor.__lock(a)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
actor.__queueRepresentation(M._actorQueue[#M._actorQueue])
|
||||||
|
return actor
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param file string
|
||||||
|
---@return ActorSound
|
||||||
|
--- Defines an ActorSound actor.
|
||||||
|
function ActorSound(file)
|
||||||
|
if M._actorsInitializing then error('uranium: cannot create an actor during actor initialization!!', 2) end
|
||||||
|
if M._actorsInitialized then error('uranium: cannot create an actor during runtime!!', 2) end
|
||||||
|
if not file then error('uranium: cannot create an ActorSound without a file', 2) end
|
||||||
|
local actor = createProxyActor('ActorSound')
|
||||||
|
table.insert(M._actorQueue, {
|
||||||
|
type = 'ActorSound',
|
||||||
|
file = uranium.dir .. file,
|
||||||
|
init = function(a)
|
||||||
|
actor.__lock(a)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
actor.__queueRepresentation(M._actorQueue[#M._actorQueue])
|
||||||
|
return actor
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param frame ActorFrame
|
||||||
|
---@param actor Actor
|
||||||
|
--- Adds a child to an ActorFrame. **Please be aware of the side-effects!**
|
||||||
|
function addChild(frame, actor)
|
||||||
|
if not frame or not actor then
|
||||||
|
error('uranium: frame and actor must both Exist', 2)
|
||||||
|
end
|
||||||
|
if M._actorsInitializing then
|
||||||
|
error('uranium: cannot create frame-child associations during actor initialization', 2)
|
||||||
|
end
|
||||||
|
if M._actorsInitialized then
|
||||||
|
error('uranium: cannot create frame-child associations after actors have been initialized', 2)
|
||||||
|
end
|
||||||
|
if not frame.__lock then
|
||||||
|
error('uranium: ActorFrame passed into addChild must be one instantiated with ActorFrame()!', 2)
|
||||||
|
end
|
||||||
|
if not actor.__lock then
|
||||||
|
error('uranium: trying to add a child to an ActorFrame that isn\'t an actor; please read the first half of \'ActorFrame\'', 2)
|
||||||
|
end
|
||||||
|
M._actorAssociationQueue[actor.__queue] = frame.__queue
|
||||||
|
table.insert(oat._actorAssociationTable[frame], actor)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M._transformQueueToTree()
|
||||||
|
local tree = {}
|
||||||
|
local paths = {}
|
||||||
|
local iter = 0
|
||||||
|
while #M._actorQueue > 0 do
|
||||||
|
iter = iter + 1
|
||||||
|
if iter > 99999 then
|
||||||
|
error('uranium: failed to transform queue to tree: reached maximum iteration limit! is there an actor with an invalid actorframe?')
|
||||||
|
end
|
||||||
|
for i = #M._actorQueue, 1, -1 do
|
||||||
|
v = M._actorQueue[i]
|
||||||
|
local insertInto
|
||||||
|
if not M._actorAssociationQueue[v] then
|
||||||
|
insertInto = tree
|
||||||
|
else
|
||||||
|
if paths[M._actorAssociationQueue[v]] then
|
||||||
|
insertInto = paths[M._actorAssociationQueue[v]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if insertInto then
|
||||||
|
if v.type == 'ActorFrame' then
|
||||||
|
table.insert(insertInto, {init = v.init})
|
||||||
|
table.remove(M._actorQueue, i)
|
||||||
|
paths[v] = insertInto[#insertInto]
|
||||||
|
else
|
||||||
|
table.insert(insertInto, v)
|
||||||
|
table.remove(M._actorQueue, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M._actorTree = tree
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.prepareForActors()
|
||||||
|
M._actorsInitializing = true
|
||||||
|
M._transformQueueToTree()
|
||||||
|
--Trace(fullDump(M._actorTree))
|
||||||
|
M._currentPath = M._actorTree
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.finalize()
|
||||||
|
oat._actor = nil
|
||||||
|
|
||||||
|
M._actorQueue = nil
|
||||||
|
M._actorAssociationQueue = nil
|
||||||
|
|
||||||
|
M._actorTree = nil
|
||||||
|
M._currentPath = nil
|
||||||
|
M._pastPaths = nil
|
||||||
|
M._currentActor = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
|
@ -0,0 +1,36 @@
|
||||||
|
-- Internal module for Uranium's configuration system, meant to be used
|
||||||
|
-- for other systems to access the values.
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
-- Uranium's configuration system, providing methods to configure parts
|
||||||
|
-- of the template.
|
||||||
|
uranium.config = {}
|
||||||
|
|
||||||
|
M.resetOnFrameStart = false
|
||||||
|
|
||||||
|
-- Toggle actor resetting on frame start behavior by default.
|
||||||
|
---@param bool boolean
|
||||||
|
function uranium.config.resetOnFrameStart(bool)
|
||||||
|
M.resetOnFrameStart = bool
|
||||||
|
end
|
||||||
|
|
||||||
|
---@type table<Actor, boolean>
|
||||||
|
M.resetActorOnFrameStart = {}
|
||||||
|
|
||||||
|
-- Toggle actor resetting on frame start for individual actors. `bool` defaults to the opposite of your `resetOnFrameStart` config
|
||||||
|
---@param actor Actor
|
||||||
|
---@param bool boolean | nil
|
||||||
|
function uranium.config.resetActorOnFrameStart(actor, bool)
|
||||||
|
if bool == nil then bool = not M.resetOnFrameStart end
|
||||||
|
M.resetActorOnFrameStart[actor.__raw or actor] = bool
|
||||||
|
end
|
||||||
|
|
||||||
|
M.hideThemeActors = true
|
||||||
|
|
||||||
|
-- Toggle if theme actors (lifebars, scores, song names, etc.) are hidden. Must be toggled **before** `init`.
|
||||||
|
---@param bool boolean
|
||||||
|
function uranium.config.hideThemeActors(bool)
|
||||||
|
M.hideThemeActors = bool
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
|
@ -0,0 +1,33 @@
|
||||||
|
-- indexing things on _G is slower than
|
||||||
|
-- having access to them in a local `oat` table
|
||||||
|
-- that already acts as _G, so we move commonly
|
||||||
|
-- use values over
|
||||||
|
|
||||||
|
local function copy(src)
|
||||||
|
local dest = {}
|
||||||
|
for k, v in pairs(src) do
|
||||||
|
dest[k] = v
|
||||||
|
end
|
||||||
|
return dest
|
||||||
|
end
|
||||||
|
|
||||||
|
oat = _G.oat
|
||||||
|
type = _G.type
|
||||||
|
print = _G.print
|
||||||
|
pairs = _G.pairs
|
||||||
|
ipairs = _G.ipairs
|
||||||
|
unpack = _G.unpack
|
||||||
|
tonumber = _G.tonumber
|
||||||
|
tostring = _G.tostring
|
||||||
|
math = copy(_G.math)
|
||||||
|
table = copy(_G.table)
|
||||||
|
string = copy(_G.string)
|
||||||
|
|
||||||
|
-- convinience shortcuts employed by most templates
|
||||||
|
|
||||||
|
scx = SCREEN_CENTER_X
|
||||||
|
scy = SCREEN_CENTER_Y
|
||||||
|
sw = SCREEN_WIDTH
|
||||||
|
sh = SCREEN_HEIGHT
|
||||||
|
dw = DISPLAY:GetDisplayWidth()
|
||||||
|
dh = DISPLAY:GetDisplayHeight()
|
|
@ -0,0 +1,51 @@
|
||||||
|
useProfiler = false
|
||||||
|
|
||||||
|
---@class ProfilerInfo
|
||||||
|
---@field public t number
|
||||||
|
---@field public src string
|
||||||
|
|
||||||
|
---@type table<string, ProfilerInfo>
|
||||||
|
profilerInfo = {}
|
||||||
|
|
||||||
|
local callbacks = {}
|
||||||
|
|
||||||
|
local debugCache = {}
|
||||||
|
|
||||||
|
---@param event string
|
||||||
|
---@param ... any
|
||||||
|
---@return any
|
||||||
|
--- Call a defined callback.
|
||||||
|
function uranium.call(event, ...)
|
||||||
|
if callbacks[event] then
|
||||||
|
profilerInfo[event] = {}
|
||||||
|
for _, callback in ipairs(callbacks[event]) do
|
||||||
|
local start = os.clock()
|
||||||
|
local res = callback(unpack(arg))
|
||||||
|
local dur = os.clock() - start
|
||||||
|
|
||||||
|
if useProfiler then
|
||||||
|
if not debugCache[callback] then
|
||||||
|
debugCache[callback] = debug.getinfo(callback, 'Sl') -- cached cus debug.getinfo is EXPENSIVE
|
||||||
|
end
|
||||||
|
local finfo = debugCache[callback]
|
||||||
|
|
||||||
|
table.insert(profilerInfo[event], {
|
||||||
|
src = finfo.short_src .. ':' .. finfo.linedefined,
|
||||||
|
t = dur
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if res ~= nil then return res end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param event string
|
||||||
|
---@param f function
|
||||||
|
--- Register a callback handler.
|
||||||
|
function uranium.on(event, f)
|
||||||
|
if not callbacks[event] then
|
||||||
|
callbacks[event] = {}
|
||||||
|
end
|
||||||
|
table.insert(callbacks[event], f)
|
||||||
|
end
|
|
@ -0,0 +1,175 @@
|
||||||
|
require 'uranium.constants'
|
||||||
|
require 'uranium.events'
|
||||||
|
local actors = require 'uranium.actors'
|
||||||
|
local config = require 'uranium.config'
|
||||||
|
|
||||||
|
local hasExited = false
|
||||||
|
local function exit()
|
||||||
|
if hasExited then return end
|
||||||
|
hasExited = true
|
||||||
|
uranium.call('exit')
|
||||||
|
-- good templates clean up after themselves
|
||||||
|
uranium = nil
|
||||||
|
_G.oat = nil
|
||||||
|
---@diagnostic disable-next-line: assign-type-mismatch
|
||||||
|
oat = nil
|
||||||
|
_main:hidden(1)
|
||||||
|
collectgarbage()
|
||||||
|
end
|
||||||
|
|
||||||
|
function backToSongWheel(message)
|
||||||
|
if message then
|
||||||
|
SCREENMAN:SystemMessage(message)
|
||||||
|
print(message)
|
||||||
|
end
|
||||||
|
exit()
|
||||||
|
GAMESTATE:FinishSong()
|
||||||
|
-- disable update_command
|
||||||
|
_main:hidden(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function onCommand(self)
|
||||||
|
actors._actorsInitialized = true
|
||||||
|
actors._actorsInitializing = false
|
||||||
|
local resetOnFrameStartActors_ = {}
|
||||||
|
for k,v in pairs(config.resetActorOnFrameStart) do
|
||||||
|
resetOnFrameStartActors_[k.__raw] = v
|
||||||
|
end
|
||||||
|
config.resetActorOnFrameStart = resetOnFrameStartActors_
|
||||||
|
uranium.call('init')
|
||||||
|
end
|
||||||
|
|
||||||
|
-- runs once during ScreenReadyCommand, before the user code is loaded
|
||||||
|
-- hides various actors that are placed by the theme
|
||||||
|
local function hideThemeActors()
|
||||||
|
for _, element in ipairs {
|
||||||
|
'Overlay', 'Underlay',
|
||||||
|
'ScoreP1', 'ScoreP2',
|
||||||
|
'LifeP1', 'LifeP2',
|
||||||
|
'PlayerOptionsP1', 'PlayerOptionsP2', 'SongOptions',
|
||||||
|
'LifeFrame', 'ScoreFrame',
|
||||||
|
'DifficultyP1', 'DifficultyP2',
|
||||||
|
'BPMDisplay',
|
||||||
|
'MemoryCardDisplayP1', 'MemoryCardDisplayP2'
|
||||||
|
} do
|
||||||
|
local child = SCREENMAN(element)
|
||||||
|
if child then child:hidden(1) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
GAMESTATE:ApplyModifiers('clearall')
|
||||||
|
|
||||||
|
local lastt = GAMESTATE:GetSongTime()
|
||||||
|
local function screenReadyCommand(self)
|
||||||
|
actors.finalize()
|
||||||
|
|
||||||
|
if config.hideThemeActors then
|
||||||
|
hideThemeActors()
|
||||||
|
end
|
||||||
|
|
||||||
|
self:hidden(0)
|
||||||
|
|
||||||
|
collectgarbage()
|
||||||
|
|
||||||
|
local errored = false
|
||||||
|
local firstrun = true
|
||||||
|
local playersLoaded = false
|
||||||
|
self:addcommand('Update', function()
|
||||||
|
if errored then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
errored = true
|
||||||
|
|
||||||
|
local P1, P2 = SCREENMAN('PlayerP1'), SCREENMAN('PlayerP2')
|
||||||
|
if P1 and P2 then
|
||||||
|
playersLoaded = true
|
||||||
|
end
|
||||||
|
if playersLoaded and not P1 and not P2 then -- sora exit hack
|
||||||
|
exit()
|
||||||
|
end
|
||||||
|
|
||||||
|
t = os.clock()
|
||||||
|
b = GAMESTATE:GetSongBeat()
|
||||||
|
local dt = t - lastt
|
||||||
|
lastt = t
|
||||||
|
|
||||||
|
if firstrun then
|
||||||
|
firstrun = false
|
||||||
|
dt = 0
|
||||||
|
self:GetChildren()[2]:hidden(1)
|
||||||
|
uranium.call('ready')
|
||||||
|
end
|
||||||
|
|
||||||
|
drawfunctionArguments = {}
|
||||||
|
|
||||||
|
for _, q in ipairs(actors._globalQueue) do
|
||||||
|
local enabled = config.resetOnFrameStart
|
||||||
|
|
||||||
|
local actor = q[1]
|
||||||
|
local v = q[2]
|
||||||
|
|
||||||
|
local pref = config.resetActorOnFrameStart[actor]
|
||||||
|
if pref ~= nil then enabled = pref end
|
||||||
|
|
||||||
|
if enabled then
|
||||||
|
local func = actor[v[1]]
|
||||||
|
if not func then
|
||||||
|
-- uhmmm ??? hm. what do we do??
|
||||||
|
else
|
||||||
|
oat._patchFunction(func, actor)(unpack(v[2]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
uranium.call('preUpdate', dt)
|
||||||
|
uranium.call('update', dt)
|
||||||
|
uranium.call('postUpdate', dt)
|
||||||
|
|
||||||
|
errored = false
|
||||||
|
|
||||||
|
return 0
|
||||||
|
end)
|
||||||
|
self:luaeffect('Update')
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class UraniumRelease
|
||||||
|
---@field branch string
|
||||||
|
---@field commit string
|
||||||
|
---@field version string
|
||||||
|
---@field name string
|
||||||
|
---@field prettyName string
|
||||||
|
---@field homeURL string
|
||||||
|
|
||||||
|
---@type UraniumRelease
|
||||||
|
uranium.release = {}
|
||||||
|
|
||||||
|
if not pcall(function() uranium.release = require('uranium.release') end) then
|
||||||
|
uranium.release = require('uranium.release_blank')
|
||||||
|
end
|
||||||
|
|
||||||
|
local success, result = pcall(function()
|
||||||
|
return require('main')
|
||||||
|
end)
|
||||||
|
|
||||||
|
if success then
|
||||||
|
print('---')
|
||||||
|
|
||||||
|
actors.prepareForActors()
|
||||||
|
|
||||||
|
_main:addcommand('On', onCommand)
|
||||||
|
_main:addcommand('Ready', screenReadyCommand)
|
||||||
|
_main:addcommand('Off', exit)
|
||||||
|
_main:addcommand('SaltyReset', exit)
|
||||||
|
_main:addcommand('WindowFocus', function()
|
||||||
|
uranium.call('focus', true)
|
||||||
|
end)
|
||||||
|
_main:addcommand('WindowFocusLost', function()
|
||||||
|
uranium.call('focus', false)
|
||||||
|
end)
|
||||||
|
_main:queuecommand('Ready')
|
||||||
|
else
|
||||||
|
Trace('got an error loading main.lua!')
|
||||||
|
Trace(result)
|
||||||
|
backToSongWheel('loading .lua file failed, check log for details')
|
||||||
|
error('uranium: loading main.lua file failed:\n' .. result)
|
||||||
|
end
|
Loading…
Reference in New Issue