Merge branch 'main' into actorframes
This commit is contained in:
commit
f8903ee5bc
26
main.xml
26
main.xml
|
@ -19,7 +19,7 @@
|
||||||
-- https://github.com/XeroOl/notitg-mirin/blob/0fbff2ee93d905feeb58c4aac4fe7f5f9ebc9647/template/std.lua#L17
|
-- https://github.com/XeroOl/notitg-mirin/blob/0fbff2ee93d905feeb58c4aac4fe7f5f9ebc9647/template/std.lua#L17
|
||||||
oat.package = {
|
oat.package = {
|
||||||
-- uranium template loader path
|
-- uranium template loader path
|
||||||
path = 'src/?.lua;src/?/init.lua;template/?.lua',
|
path = 'src/?.lua;src/?/init.lua;template/?.lua;template/?/init.lua',
|
||||||
preload = {},
|
preload = {},
|
||||||
loaded = {},
|
loaded = {},
|
||||||
loaders = {
|
loaders = {
|
||||||
|
@ -106,12 +106,33 @@
|
||||||
oat.dw = DISPLAY:GetDisplayWidth()
|
oat.dw = DISPLAY:GetDisplayWidth()
|
||||||
oat.dh = DISPLAY:GetDisplayHeight()
|
oat.dh = DISPLAY:GetDisplayHeight()
|
||||||
|
|
||||||
|
oat.useProfiler = false
|
||||||
|
oat.profilerInfo = {}
|
||||||
|
|
||||||
local uraniumFunc = {}
|
local uraniumFunc = {}
|
||||||
|
|
||||||
|
local debugCache = {}
|
||||||
function uraniumFunc:call(event, ...)
|
function uraniumFunc:call(event, ...)
|
||||||
if self._callbacks[event] then
|
if self._callbacks[event] then
|
||||||
|
profilerInfo[event] = {}
|
||||||
for _, callback in ipairs(self._callbacks[event]) do
|
for _, callback in ipairs(self._callbacks[event]) do
|
||||||
callback(unpack(arg))
|
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
|
end
|
||||||
end
|
end
|
||||||
|
@ -200,6 +221,7 @@
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
resetActor = reset
|
||||||
|
|
||||||
-- runs once during ScreenReadyCommand, before the user code is loaded
|
-- runs once during ScreenReadyCommand, before the user code is loaded
|
||||||
-- hides various actors that are placed by the theme
|
-- hides various actors that are placed by the theme
|
||||||
|
|
|
@ -0,0 +1,339 @@
|
||||||
|
---@diagnostic disable: lowercase-global
|
||||||
|
-- Convenience shortcuts
|
||||||
|
|
||||||
|
local sqrt = math.sqrt
|
||||||
|
local sin = math.sin
|
||||||
|
local asin = math.asin
|
||||||
|
local cos = math.cos
|
||||||
|
local pow = math.pow
|
||||||
|
local exp = math.exp
|
||||||
|
local pi = math.pi
|
||||||
|
local abs = math.abs
|
||||||
|
|
||||||
|
xero()
|
||||||
|
-- ===================================================================== --
|
||||||
|
|
||||||
|
-- Utility functions
|
||||||
|
|
||||||
|
--- Flip any easing function, making it go from 1 to 0
|
||||||
|
-- Example use:
|
||||||
|
-- ```lua
|
||||||
|
-- ease {0, 20, flip(outQuad), 50, 'modname'}
|
||||||
|
-- ```
|
||||||
|
flip = setmetatable({}, {
|
||||||
|
__call = function(self, fn)
|
||||||
|
self[fn] = self[fn] or function(x) return 1 - fn(x) end
|
||||||
|
return self[fn]
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Mix two easing functions together into a new ease
|
||||||
|
-- the new ease starts by acting like the first argument, and then ends like the second argument
|
||||||
|
-- Example: ease {0, 20, blendease(inQuad, outQuad), 100, 'modname'}
|
||||||
|
blendease = setmetatable({}, {
|
||||||
|
__index = function(self, key)
|
||||||
|
self[key] = {}
|
||||||
|
return self[key]
|
||||||
|
end,
|
||||||
|
__call = function(self, fn1, fn2)
|
||||||
|
if not self[fn1][fn2] then
|
||||||
|
local transient1 = fn1(1) <= 0.5
|
||||||
|
local transient2 = fn2(1) <= 0.5
|
||||||
|
if transient1 and not transient2 then
|
||||||
|
error('blendease: the first argument is a transient ease, but the second argument doesn\'t match')
|
||||||
|
end
|
||||||
|
if transient2 and not transient1 then
|
||||||
|
error('blendease: the second argument is a transient ease, but the first argument doesn\'t match')
|
||||||
|
end
|
||||||
|
self[fn1][fn2] = function(x)
|
||||||
|
local mixFactor = 3*x^2-2*x^3
|
||||||
|
return (1 - mixFactor) * fn1(x) + mixFactor * fn2(x)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self[fn1][fn2]
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
local function param1cache(self, param1)
|
||||||
|
self.cache[param1] = self.cache[param1] or function(x)
|
||||||
|
return self.fn(x, param1)
|
||||||
|
end
|
||||||
|
return self.cache[param1]
|
||||||
|
end
|
||||||
|
|
||||||
|
local param1mt = {
|
||||||
|
__call = function(self, x, param1)
|
||||||
|
return self.fn(x, param1 or self.dp1)
|
||||||
|
end,
|
||||||
|
__index = {
|
||||||
|
param = param1cache,
|
||||||
|
params = param1cache,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Declare an easing function taking one custom parameter
|
||||||
|
function with1param(fn, defaultparam1)
|
||||||
|
return setmetatable({
|
||||||
|
fn = fn,
|
||||||
|
dp1 = defaultparam1,
|
||||||
|
cache = {},
|
||||||
|
}, param1mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function param2cache(self, param1, param2)
|
||||||
|
self.cache[param1] = self.cache[param1] or {}
|
||||||
|
self.cache[param1][param2] = self.cache[param1][param2] or function(x)
|
||||||
|
return self.fn(x, param1, param2)
|
||||||
|
end
|
||||||
|
return self.cache[param1][param2]
|
||||||
|
end
|
||||||
|
|
||||||
|
local param2mt = {
|
||||||
|
__call = function(self, x, param1, param2)
|
||||||
|
return self.fn(x, param1 or self.dp1, param2 or self.dp2)
|
||||||
|
end,
|
||||||
|
__index = {
|
||||||
|
param=param2cache,
|
||||||
|
params=param2cache,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Declare an easing function taking two custom parameters
|
||||||
|
function with2params(fn, defaultparam1, defaultparam2)
|
||||||
|
return setmetatable({
|
||||||
|
fn = fn,
|
||||||
|
dp1 = defaultparam1,
|
||||||
|
dp2 = defaultparam2,
|
||||||
|
cache = {},
|
||||||
|
}, param2mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ===================================================================== --
|
||||||
|
|
||||||
|
-- Easing functions
|
||||||
|
|
||||||
|
function bounce(t) return 4 * t * (1 - t) end
|
||||||
|
function tri(t) return 1 - abs(2 * t - 1) end
|
||||||
|
function bell(t) return inOutQuint(tri(t)) end
|
||||||
|
function pop(t) return 3.5 * (1 - t) * (1 - t) * sqrt(t) end
|
||||||
|
function tap(t) return 3.5 * t * t * sqrt(1 - t) end
|
||||||
|
function pulse(t) return t < .5 and tap(t * 2) or -pop(t * 2 - 1) end
|
||||||
|
|
||||||
|
function spike(t) return exp(-10 * abs(2 * t - 1)) end
|
||||||
|
function inverse(t) return t * t * (1 - t) * (1 - t) / (0.5 - t) end
|
||||||
|
|
||||||
|
local function popElasticInternal(t, damp, count)
|
||||||
|
return (1000 ^ -(t ^ damp) - 0.001) * sin(count * pi * t)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tapElasticInternal(t, damp, count)
|
||||||
|
return (1000 ^ -((1 - t) ^ damp) - 0.001) * sin(count * pi * (1 - t))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pulseElasticInternal(t, damp, count)
|
||||||
|
if t < .5 then
|
||||||
|
return tapElasticInternal(t * 2, damp, count)
|
||||||
|
else
|
||||||
|
return -popElasticInternal(t * 2 - 1, damp, count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
popElastic = with2params(popElasticInternal, 1.4, 6)
|
||||||
|
tapElastic = with2params(tapElasticInternal, 1.4, 6)
|
||||||
|
pulseElastic = with2params(pulseElasticInternal, 1.4, 6)
|
||||||
|
|
||||||
|
impulse = with1param(function(t, damp)
|
||||||
|
t = t ^ damp
|
||||||
|
return t * (1000 ^ -t - 0.001) * 18.6
|
||||||
|
end, 0.9)
|
||||||
|
|
||||||
|
function instant() return 1 end
|
||||||
|
function linear(t) return t end
|
||||||
|
function inQuad(t) return t * t end
|
||||||
|
function outQuad(t) return -t * (t - 2) end
|
||||||
|
function inOutQuad(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 * t ^ 2
|
||||||
|
else
|
||||||
|
return 1 - 0.5 * (2 - t) ^ 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function outInQuad(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 - 0.5 * (1 - t) ^ 2
|
||||||
|
else
|
||||||
|
return 0.5 + 0.5 * (t - 1) ^ 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function inCubic(t) return t * t * t end
|
||||||
|
function outCubic(t) return 1 - (1 - t) ^ 3 end
|
||||||
|
function inOutCubic(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 * t ^ 3
|
||||||
|
else
|
||||||
|
return 1 - 0.5 * (2 - t) ^ 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function outInCubic(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 - 0.5 * (1 - t) ^ 3
|
||||||
|
else
|
||||||
|
return 0.5 + 0.5 * (t - 1) ^ 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function inQuart(t) return t * t * t * t end
|
||||||
|
function outQuart(t) return 1 - (1 - t) ^ 4 end
|
||||||
|
function inOutQuart(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 * t ^ 4
|
||||||
|
else
|
||||||
|
return 1 - 0.5 * (2 - t) ^ 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function outInQuart(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 - 0.5 * (1 - t) ^ 4
|
||||||
|
else
|
||||||
|
return 0.5 + 0.5 * (t - 1) ^ 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function inQuint(t) return t ^ 5 end
|
||||||
|
function outQuint(t) return 1 - (1 - t) ^ 5 end
|
||||||
|
function inOutQuint(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 * t ^ 5
|
||||||
|
else
|
||||||
|
return 1 - 0.5 * (2 - t) ^ 5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function outInQuint(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 - 0.5 * (1 - t) ^ 5
|
||||||
|
else
|
||||||
|
return 0.5 + 0.5 * (t - 1) ^ 5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function inExpo(t) return 1000 ^ (t - 1) - 0.001 end
|
||||||
|
function outExpo(t) return 1.001 - 1000 ^ -t end
|
||||||
|
function inOutExpo(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 * 1000 ^ (t - 1) - 0.0005
|
||||||
|
else
|
||||||
|
return 1.0005 - 0.5 * 1000 ^ (1 - t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function outInExpo(t)
|
||||||
|
if t < 0.5 then
|
||||||
|
return outExpo(t * 2) * 0.5
|
||||||
|
else
|
||||||
|
return inExpo(t * 2 - 1) * 0.5 + 0.5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function inCirc(t) return 1 - sqrt(1 - t * t) end
|
||||||
|
function outCirc(t) return sqrt(-t * t + 2 * t) end
|
||||||
|
function inOutCirc(t)
|
||||||
|
t = t * 2
|
||||||
|
if t < 1 then
|
||||||
|
return 0.5 - 0.5 * sqrt(1 - t * t)
|
||||||
|
else
|
||||||
|
t = t - 2
|
||||||
|
return 0.5 + 0.5 * sqrt(1 - t * t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function outInCirc(t)
|
||||||
|
if t < 0.5 then
|
||||||
|
return outCirc(t * 2) * 0.5
|
||||||
|
else
|
||||||
|
return inCirc(t * 2 - 1) * 0.5 + 0.5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function outBounce(t)
|
||||||
|
if t < 1 / 2.75 then
|
||||||
|
return 7.5625 * t * t
|
||||||
|
elseif t < 2 / 2.75 then
|
||||||
|
t = t - 1.5 / 2.75
|
||||||
|
return 7.5625 * t * t + 0.75
|
||||||
|
elseif t < 2.5 / 2.75 then
|
||||||
|
t = t - 2.25 / 2.75
|
||||||
|
return 7.5625 * t * t + 0.9375
|
||||||
|
else
|
||||||
|
t = t - 2.625 / 2.75
|
||||||
|
return 7.5625 * t * t + 0.984375
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function inBounce(t) return 1 - outBounce(1 - t) end
|
||||||
|
function inOutBounce(t)
|
||||||
|
if t < 0.5 then
|
||||||
|
return inBounce(t * 2) * 0.5
|
||||||
|
else
|
||||||
|
return outBounce(t * 2 - 1) * 0.5 + 0.5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function outInBounce(t)
|
||||||
|
if t < 0.5 then
|
||||||
|
return outBounce(t * 2) * 0.5
|
||||||
|
else
|
||||||
|
return inBounce(t * 2 - 1) * 0.5 + 0.5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function inSine(x) return 1 - cos(x * (pi * 0.5)) end
|
||||||
|
function outSine(x) return sin(x * (pi * 0.5)) end
|
||||||
|
function inOutSine(x)
|
||||||
|
return 0.5 - 0.5 * cos(x * pi)
|
||||||
|
end
|
||||||
|
function outInSine(t)
|
||||||
|
if t < 0.5 then
|
||||||
|
return outSine(t * 2) * 0.5
|
||||||
|
else
|
||||||
|
return inSine(t * 2 - 1) * 0.5 + 0.5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function outElasticInternal(t, a, p)
|
||||||
|
return a * pow(2, -10 * t) * sin((t - p / (2 * pi) * asin(1/a)) * 2 * pi / p) + 1
|
||||||
|
end
|
||||||
|
local function inElasticInternal(t, a, p)
|
||||||
|
return 1 - outElasticInternal(1 - t, a, p)
|
||||||
|
end
|
||||||
|
function inOutElasticInternal(t, a, p)
|
||||||
|
return t < 0.5
|
||||||
|
and 0.5 * inElasticInternal(t * 2, a, p)
|
||||||
|
or 0.5 + 0.5 * outElasticInternal(t * 2 - 1, a, p)
|
||||||
|
end
|
||||||
|
function outInElasticInternal(t, a, p)
|
||||||
|
return t < 0.5
|
||||||
|
and 0.5 * outElasticInternal(t * 2, a, p)
|
||||||
|
or 0.5 + 0.5 * inElasticInternal(t * 2 - 1, a, p)
|
||||||
|
end
|
||||||
|
|
||||||
|
inElastic = with2params(inElasticInternal, 1, 0.3)
|
||||||
|
outElastic = with2params(outElasticInternal, 1, 0.3)
|
||||||
|
inOutElastic = with2params(inOutElasticInternal, 1, 0.3)
|
||||||
|
outInElastic = with2params(outInElasticInternal, 1, 0.3)
|
||||||
|
|
||||||
|
function inBackInternal(t, a) return t * t * (a * t + t - a) end
|
||||||
|
function outBackInternal(t, a) t = t - 1 return t * t * ((a + 1) * t + a) + 1 end
|
||||||
|
function inOutBackInternal(t, a)
|
||||||
|
return t < 0.5
|
||||||
|
and 0.5 * inBackInternal(t * 2, a)
|
||||||
|
or 0.5 + 0.5 * outBackInternal(t * 2 - 1, a)
|
||||||
|
end
|
||||||
|
function outInBackInternal(t, a)
|
||||||
|
return t < 0.5
|
||||||
|
and 0.5 * outBackInternal(t * 2, a)
|
||||||
|
or 0.5 + 0.5 * inBackInternal(t * 2 - 1, a)
|
||||||
|
end
|
||||||
|
|
||||||
|
inBack = with1param(inBackInternal, 1.70158)
|
||||||
|
outBack = with1param(outBackInternal, 1.70158)
|
||||||
|
inOutBack = with1param(inOutBackInternal, 1.70158)
|
||||||
|
outInBack = with1param(outInBackInternal, 1.70158)
|
|
@ -0,0 +1,19 @@
|
||||||
|
xero = oat
|
||||||
|
xero.foreground = oat._main
|
||||||
|
xero.MIRIN_VERSION = 'URANIUM-5.0.1'
|
||||||
|
|
||||||
|
|
||||||
|
-- Load all of the core .lua files
|
||||||
|
-- The order DOES matter here:
|
||||||
|
-- std.lua needs to be loaded first
|
||||||
|
-- template.lua needs to be last
|
||||||
|
require('stdlib.mirin.std')
|
||||||
|
require('stdlib.mirin.sort')
|
||||||
|
require('stdlib.mirin.ease')
|
||||||
|
require('stdlib.mirin.template')
|
||||||
|
|
||||||
|
local xeroActorsAF = Quad()
|
||||||
|
|
||||||
|
function uranium.init()
|
||||||
|
xero.init_command(xeroActorsAF)
|
||||||
|
end
|
|
@ -0,0 +1,152 @@
|
||||||
|
--[[
|
||||||
|
this is based on code from Dirk Laurie and Steve Fisher,
|
||||||
|
used under license as follows:
|
||||||
|
|
||||||
|
|
||||||
|
Copyright © 2013 Dirk Laurie and Steve Fisher.
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the 'Software'),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
(modifications by Max Cahill 2018, 2020)
|
||||||
|
(modifications by XeroOl 2021)
|
||||||
|
|
||||||
|
Found at: https://github.com/1bardesign/batteries/blob/master/sort.lua
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- `sort` object, container of the following methods
|
||||||
|
local sort = {}
|
||||||
|
-- Tunable threshold, deciding between the insertion sort and merge sort
|
||||||
|
sort.max_chunk_size = 32
|
||||||
|
|
||||||
|
|
||||||
|
-- ===================================================================== --
|
||||||
|
|
||||||
|
-- Internal implementations
|
||||||
|
|
||||||
|
|
||||||
|
-- Insertion sort on a section of an array
|
||||||
|
function sort._insertion_sort_impl(array, first, last, less)
|
||||||
|
for i = first + 1, last do
|
||||||
|
local k = first
|
||||||
|
local v = array[i]
|
||||||
|
for j = i, first + 1, -1 do
|
||||||
|
if less(v, array[j - 1]) then
|
||||||
|
array[j] = array[j - 1]
|
||||||
|
else
|
||||||
|
k = j
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
array[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Merge sort on two sorted portions of an array
|
||||||
|
function sort._merge(array, workspace, low, middle, high, less)
|
||||||
|
local i, j, k
|
||||||
|
i = 1
|
||||||
|
-- copy first half of array to auxiliary array
|
||||||
|
for j = low, middle do
|
||||||
|
workspace[i] = array[j]
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
-- sieve through
|
||||||
|
i = 1
|
||||||
|
j = middle + 1
|
||||||
|
k = low
|
||||||
|
while true do
|
||||||
|
if (k >= j) or (j > high) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if less(array[j], workspace[i]) then
|
||||||
|
array[k] = array[j]
|
||||||
|
j = j + 1
|
||||||
|
else
|
||||||
|
array[k] = workspace[i]
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
k = k + 1
|
||||||
|
end
|
||||||
|
-- copy back any remaining elements of first half
|
||||||
|
for k = k, j - 1 do
|
||||||
|
array[k] = workspace[i]
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Recursive merge sort implementation
|
||||||
|
function sort._merge_sort_impl(array, workspace, low, high, less)
|
||||||
|
if high - low <= sort.max_chunk_size then
|
||||||
|
sort._insertion_sort_impl(array, low, high, less)
|
||||||
|
else
|
||||||
|
local middle = math.floor((low + high) / 2)
|
||||||
|
sort._merge_sort_impl(array, workspace, low, middle, less)
|
||||||
|
sort._merge_sort_impl(array, workspace, middle + 1, high, less)
|
||||||
|
sort._merge(array, workspace, low, middle, high, less)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Default comparison function: sort from smallest to biggest
|
||||||
|
local function default_less(a, b)
|
||||||
|
return a < b
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Setup a sorting algorithm, check the validity of the comparator,
|
||||||
|
-- and determine if a case is trivial (no sorting needed)
|
||||||
|
function sort._sort_setup(array, less)
|
||||||
|
less = less or default_less
|
||||||
|
local n = #array
|
||||||
|
--trivial cases; empty or 1 element
|
||||||
|
local trivial = (n <= 1)
|
||||||
|
if not trivial then
|
||||||
|
--check less
|
||||||
|
if less(array[1], array[1]) then
|
||||||
|
error('invalid order function for sorting; less(v, v) should not be true for any v.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--setup complete
|
||||||
|
return trivial, n, less
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Public method: merge sort on an array. If the array length is
|
||||||
|
-- less than `max_chunk_size`, an insertion sort will be done instead.
|
||||||
|
function sort.stable_sort(array, less)
|
||||||
|
--setup
|
||||||
|
local trivial, n, less = sort._sort_setup(array, less)
|
||||||
|
if not trivial then
|
||||||
|
--temp storage; allocate ahead of time
|
||||||
|
local workspace = {}
|
||||||
|
local middle = math.ceil(n / 2)
|
||||||
|
workspace[middle] = array[1]
|
||||||
|
--dive in
|
||||||
|
sort._merge_sort_impl( array, workspace, 1, n, less )
|
||||||
|
end
|
||||||
|
return array
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Public method (currently not exposed): insertion sort
|
||||||
|
function sort.insertion_sort(array, less)
|
||||||
|
--setup
|
||||||
|
local trivial, n, less = sort._sort_setup(array, less)
|
||||||
|
if not trivial then
|
||||||
|
sort._insertion_sort_impl(array, 1, n, less)
|
||||||
|
end
|
||||||
|
return array
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Exports
|
||||||
|
xero.unstable_sort = table.sort
|
||||||
|
xero.stable_sort = sort.stable_sort
|
|
@ -0,0 +1,249 @@
|
||||||
|
-- Environments
|
||||||
|
--[[
|
||||||
|
-- Create the xero environment, in which everything is
|
||||||
|
setmetatable(xero, {
|
||||||
|
-- if something isn't found in the xero table, fall back to a _G lookup
|
||||||
|
__index = _G,
|
||||||
|
|
||||||
|
-- Calling xero() sets the environment of the current function
|
||||||
|
-- Calling xero(func) returns `func` with the xero environment applied
|
||||||
|
__call = function(self, f)
|
||||||
|
setfenv(f or 2, self)
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
-- make require work
|
||||||
|
xero.package = {
|
||||||
|
-- mirin template loader path
|
||||||
|
path = 'lua/?.lua;lua/?/init.lua;plugins/?.lua;plugins/?/init.lua',
|
||||||
|
preload = {},
|
||||||
|
loaded = {},
|
||||||
|
loaders = {
|
||||||
|
function(modname)
|
||||||
|
local preload = xero.package.preload[modname]
|
||||||
|
return preload or 'no field xero.package.preload[\''..modname..'\']'
|
||||||
|
end,
|
||||||
|
function(modname)
|
||||||
|
local errors = {}
|
||||||
|
-- get the filename
|
||||||
|
local filename = string.gsub(modname, '%.', '/')
|
||||||
|
for path in (string.gfind or string.gmatch)(xero.package.path, '[^;]+') do
|
||||||
|
-- get the file path
|
||||||
|
local filepath = xero.dir .. string.gsub(path, '%?', filename)
|
||||||
|
-- check if file exists
|
||||||
|
if not GAMESTATE:GetFileStructure(filepath) then
|
||||||
|
table.insert(errors, 'no file \''..filepath..'\'')
|
||||||
|
else
|
||||||
|
local loader, err = loadfile(filepath)
|
||||||
|
-- check if file loads properly
|
||||||
|
if err then
|
||||||
|
error(err, 3)
|
||||||
|
elseif loader then
|
||||||
|
return xero(loader)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(errors, '\n')
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function xero.require(modname)
|
||||||
|
local loaded = xero.package.loaded
|
||||||
|
if not loaded[modname] then
|
||||||
|
local errors = {'module \''..modname..'\' not found:'}
|
||||||
|
local chunk
|
||||||
|
for _, loader in ipairs(xero.package.loaders) do
|
||||||
|
local result = loader(modname)
|
||||||
|
if type(result) == 'string' then
|
||||||
|
table.insert(errors, result)
|
||||||
|
elseif type(result) == 'function' then
|
||||||
|
chunk = result
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not chunk then
|
||||||
|
error(table.concat(errors, '\n'), 2)
|
||||||
|
end
|
||||||
|
loaded[modname] = chunk()
|
||||||
|
if loaded[modname] == nil then
|
||||||
|
loaded[modname] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return loaded[modname]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply the environment. :)
|
||||||
|
xero()
|
||||||
|
|
||||||
|
--- Create the strict environment, forbidding creating any variable
|
||||||
|
--- This environment is not related to the xero table, and won't fetch
|
||||||
|
--- values from it, unless explicitely prefixed with `xero.`
|
||||||
|
xero.strict = setmetatable({}, {
|
||||||
|
-- Allow access to _G elements, containing all game methods
|
||||||
|
__index = _G,
|
||||||
|
-- Prevent creating any variable
|
||||||
|
__newindex = function(s, t)
|
||||||
|
error(t)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
]]
|
||||||
|
-- ===================================================================== --
|
||||||
|
|
||||||
|
-- Utility functions
|
||||||
|
|
||||||
|
|
||||||
|
--- Returns a shallow copy of the table `src`
|
||||||
|
function copy(src)
|
||||||
|
local dest = {}
|
||||||
|
for k, v in pairs(src) do
|
||||||
|
dest[k] = v
|
||||||
|
end
|
||||||
|
return dest
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clear a table's contents, leaving it empty.
|
||||||
|
-- Useful for resetting a table containing metatables.
|
||||||
|
function clear(t)
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
t[k] = nil
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clear a table's contents, when the table only contains 'logical' indexes
|
||||||
|
-- (as in: contiguous numerical indexes from 1 to #table)
|
||||||
|
function iclear(t)
|
||||||
|
for i = 1, #t do
|
||||||
|
table.remove(t)
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Move global functions to the xero table, allowing for slightly faster
|
||||||
|
-- performance due to not having to go back and forth between xero and _G.
|
||||||
|
--[[
|
||||||
|
xero.xero = _G.xero
|
||||||
|
xero.type = _G.type
|
||||||
|
xero.print = _G.print
|
||||||
|
xero.pairs = _G.pairs
|
||||||
|
xero.ipairs = _G.ipairs
|
||||||
|
xero.unpack = _G.unpack
|
||||||
|
xero.tonumber = _G.tonumber
|
||||||
|
xero.tostring = _G.tostring
|
||||||
|
xero.math = copy(_G.math)
|
||||||
|
xero.table = copy(_G.table)
|
||||||
|
xero.string = copy(_G.string)
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- ===================================================================== --
|
||||||
|
|
||||||
|
-- Data structure for all the `func` declarations.
|
||||||
|
-- This custom data structure smartly handles func priorities, so the order
|
||||||
|
-- they're declared in mods.xml is respected no matter what.
|
||||||
|
-- This data structure is generic enough to be used for any context, but
|
||||||
|
-- that is not the case for now.
|
||||||
|
|
||||||
|
|
||||||
|
local methods = {}
|
||||||
|
|
||||||
|
function methods:add(obj)
|
||||||
|
local stage = self.stage
|
||||||
|
self.n = self.n + 1
|
||||||
|
stage.n = stage.n + 1
|
||||||
|
stage[stage.n] = obj
|
||||||
|
end
|
||||||
|
|
||||||
|
function methods:remove()
|
||||||
|
local swap = self.swap
|
||||||
|
swap[swap.n] = nil
|
||||||
|
swap.n = swap.n - 1
|
||||||
|
self.n = self.n - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function methods:next()
|
||||||
|
if self.n == 0 then return end
|
||||||
|
|
||||||
|
local swap = self.swap
|
||||||
|
local stage = self.stage
|
||||||
|
local list = self.list
|
||||||
|
|
||||||
|
if swap.n == 0 then
|
||||||
|
stable_sort(stage, self.reverse_comparator)
|
||||||
|
end
|
||||||
|
if stage.n == 0 then
|
||||||
|
if list.n == 0 then
|
||||||
|
while swap.n ~= 0 do
|
||||||
|
list.n = list.n + 1
|
||||||
|
list[list.n] = swap[swap.n]
|
||||||
|
swap[swap.n] = nil
|
||||||
|
swap.n = swap.n - 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
swap.n = swap.n + 1
|
||||||
|
swap[swap.n] = list[list.n]
|
||||||
|
list[list.n] = nil
|
||||||
|
list.n = list.n - 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if list.n == 0 then
|
||||||
|
swap.n = swap.n + 1
|
||||||
|
swap[swap.n] = stage[stage.n]
|
||||||
|
stage[stage.n] = nil
|
||||||
|
stage.n = stage.n - 1
|
||||||
|
else
|
||||||
|
if self.comparator(list[list.n], stage[stage.n]) then
|
||||||
|
swap.n = swap.n + 1
|
||||||
|
swap[swap.n] = list[list.n]
|
||||||
|
list[list.n] = nil
|
||||||
|
list.n = list.n - 1
|
||||||
|
else
|
||||||
|
swap.n = swap.n + 1
|
||||||
|
swap[swap.n] = stage[stage.n]
|
||||||
|
stage[stage.n] = nil
|
||||||
|
stage.n = stage.n - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return swap[swap.n]
|
||||||
|
end
|
||||||
|
|
||||||
|
local mt = {__index = methods}
|
||||||
|
|
||||||
|
function perframe_data_structure(comparator)
|
||||||
|
return setmetatable({
|
||||||
|
comparator = comparator,
|
||||||
|
reverse_comparator = function(a, b) return comparator(b, a) end,
|
||||||
|
stage = {n = 0},
|
||||||
|
list = {n = 0},
|
||||||
|
swap = {n = 0},
|
||||||
|
n = 0,
|
||||||
|
}, mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- the behavior of a stringbuilder
|
||||||
|
local stringbuilder_mt = {
|
||||||
|
__index = {
|
||||||
|
-- :build() method converts a stringbuilder into a string, with optional delimiter
|
||||||
|
build = table.concat,
|
||||||
|
-- :clear() method empties the stringbuilder
|
||||||
|
clear = iclear,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- calling a stringbuilder appends to it
|
||||||
|
__call = function(self, a)
|
||||||
|
table.insert(self, tostring(a))
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- stringbuilder can convert to a string
|
||||||
|
__tostring = table.concat,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- stringbuilder constructor
|
||||||
|
function stringbuilder()
|
||||||
|
return setmetatable({}, stringbuilder_mt)
|
||||||
|
end
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,56 @@
|
||||||
|
PROFILER_ENABLED = true
|
||||||
|
profilerShowing = 'update'
|
||||||
|
|
||||||
|
local easable = require('stdlib.easable')
|
||||||
|
|
||||||
|
local text = BitmapText()
|
||||||
|
local quad = Quad()
|
||||||
|
|
||||||
|
oat.useProfiler = true
|
||||||
|
|
||||||
|
if PROFILER_ENABLED then
|
||||||
|
local max = easable(0)
|
||||||
|
|
||||||
|
local function draw()
|
||||||
|
if not profilerInfo[profilerShowing] then return end
|
||||||
|
|
||||||
|
quad:diffuse(0.2, 1, 0.2, 0.9)
|
||||||
|
quad:align(0, 0)
|
||||||
|
text:align(0, 0)
|
||||||
|
text:shadowlength(0)
|
||||||
|
|
||||||
|
table.sort(profilerInfo[profilerShowing], function(a, b) return a.t > b.t end)
|
||||||
|
local maxt = 0
|
||||||
|
for i, e in ipairs(profilerInfo[profilerShowing]) do
|
||||||
|
maxt = math.max(maxt, e.t)
|
||||||
|
quad:zoomto(e.t / max.a * sw * 0.4, 24)
|
||||||
|
quad:xy(0, i * 24)
|
||||||
|
quad:Draw()
|
||||||
|
|
||||||
|
text:settext((math.floor(e.t * 100000) / 100) .. 'ms')
|
||||||
|
text:xy(0, i * 24)
|
||||||
|
text:zoom(0.3)
|
||||||
|
text:diffuse(0.2, 0.2, 0.2, 0.9)
|
||||||
|
text:Draw()
|
||||||
|
text:settext(e.src)
|
||||||
|
text:xy(0, i * 24 + 12)
|
||||||
|
text:zoom(0.2)
|
||||||
|
text:diffuse(0.1, 0.1, 0.1, 0.9)
|
||||||
|
text:Draw()
|
||||||
|
end
|
||||||
|
|
||||||
|
max:set(maxt)
|
||||||
|
|
||||||
|
text:diffuse(1, 1, 1, 1)
|
||||||
|
text:xy(0, 0)
|
||||||
|
text:zoom(0.5)
|
||||||
|
text:shadowlength(3)
|
||||||
|
text:settext('Profiler - ' .. profilerShowing)
|
||||||
|
text:Draw()
|
||||||
|
end
|
||||||
|
|
||||||
|
function uranium.update(dt)
|
||||||
|
max(dt * 12)
|
||||||
|
draw()
|
||||||
|
end
|
||||||
|
end
|
10
typings.lua
10
typings.lua
|
@ -58,6 +58,7 @@ function ActorFrame() end
|
||||||
---@param actor Actor
|
---@param actor Actor
|
||||||
--- Resets an actor to its initial state
|
--- Resets an actor to its initial state
|
||||||
function reset(actor) end
|
function reset(actor) end
|
||||||
|
resetActor = reset
|
||||||
|
|
||||||
---@param frame ActorFrame
|
---@param frame ActorFrame
|
||||||
---@param actor Actor
|
---@param actor Actor
|
||||||
|
@ -114,4 +115,11 @@ uranium.update = function() end
|
||||||
function uranium:call(event, ...) end
|
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
|
||||||
|
---@field public t number
|
||||||
|
---@field public src string
|
||||||
|
|
||||||
|
---@type table<string, ProfilerInfo>
|
||||||
|
profilerInfo = {}
|
Loading…
Reference in New Issue