From db7d0db7eca227f10886295c33f6ebf2f7f33b35 Mon Sep 17 00:00:00 2001 From: "Jill \"oatmealine\" Monoids" Date: Thu, 4 May 2023 16:38:02 +0300 Subject: [PATCH] switch template to lua files --- main.xml | 787 +----------------- uranium/main.lua | 786 +++++++++++++++++ .../release_blank.lua | 0 3 files changed, 787 insertions(+), 786 deletions(-) create mode 100644 uranium/main.lua rename release_blank.lua => uranium/release_blank.lua (100%) diff --git a/main.xml b/main.xml index e8a5ab7..806a7d5 100644 --- a/main.xml +++ b/main.xml @@ -79,792 +79,7 @@ oat() - local function copy(src) - local dest = {} - for k, v in pairs(src) do - dest[k] = v - end - return dest - end - - oat.oat = _G.oat - oat.type = _G.type - 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 + require 'uranium.main' -- 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 diff --git a/uranium/main.lua b/uranium/main.lua new file mode 100644 index 0000000..c53dacb --- /dev/null +++ b/uranium/main.lua @@ -0,0 +1,786 @@ +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) + +scx = SCREEN_CENTER_X +scy = SCREEN_CENTER_Y +sw = SCREEN_WIDTH +sh = SCREEN_HEIGHT +dw = DISPLAY:GetDisplayWidth() +dh = DISPLAY:GetDisplayHeight() + +useProfiler = false +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 + _main: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]) + actorAssociationTable[actor] = {} + 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]) + 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('uranium.release') end) then + oat._release = require('uranium.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 + + _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 \ No newline at end of file diff --git a/release_blank.lua b/uranium/release_blank.lua similarity index 100% rename from release_blank.lua rename to uranium/release_blank.lua