mirror of
https://github.com/Dadido3/noita-mapcap.git
synced 2024-11-18 17:17:31 +00:00
Fix compatibility stuff
- Make dofile more conform to standard lua - Move dofile from live-reload.lua to compatibility.lua - Let dofile and require throw errors on script errors - Fix bug in recursion detection - Remove Noita's dofile annotation - Fix some EmmyLua annotations - Improve print replacement
This commit is contained in:
parent
e863ba459b
commit
403167b366
@ -1416,10 +1416,6 @@ function SetValueBool(key, value) end
|
|||||||
---@param default_value number
|
---@param default_value number
|
||||||
---@return boolean
|
---@return boolean
|
||||||
function GetValueBool(key, default_value) end
|
function GetValueBool(key, default_value) end
|
||||||
---Returns the script's return value, if any. Returns nil,error_string if the script had errors.
|
|
||||||
---@param filename string
|
|
||||||
---@return any script_return_type, string|nil error_string
|
|
||||||
function dofile(filename) end
|
|
||||||
---Runs the script only once per lua context, returns the script's return value, if any. Returns nil,error_string if the script had errors. For performance reasons it is recommended scripts use dofile_once(), unless the standard dofile behaviour is required.
|
---Runs the script only once per lua context, returns the script's return value, if any. Returns nil,error_string if the script had errors. For performance reasons it is recommended scripts use dofile_once(), unless the standard dofile behaviour is required.
|
||||||
---@param filename string
|
---@param filename string
|
||||||
---@return any script_return_type, string|nil error_string
|
---@return any script_return_type, string|nil error_string
|
||||||
|
@ -10,14 +10,16 @@
|
|||||||
if _NoitaAPICompatibilityWrapperGuard_ then return function(dummy) end end
|
if _NoitaAPICompatibilityWrapperGuard_ then return function(dummy) end end
|
||||||
_NoitaAPICompatibilityWrapperGuard_ = true
|
_NoitaAPICompatibilityWrapperGuard_ = true
|
||||||
|
|
||||||
-- Override print function to behave more like the standard lua one.
|
|
||||||
local oldPrint = print
|
local oldPrint = print
|
||||||
function print(...)
|
|
||||||
local arg = { ... }
|
|
||||||
local stringArgs = {}
|
|
||||||
|
|
||||||
for i, v in ipairs(arg) do
|
-- Emulated print function that behaves more like the standard lua one.
|
||||||
table.insert(stringArgs, tostring(v))
|
function print(...)
|
||||||
|
local n = select("#", ...)
|
||||||
|
|
||||||
|
--for i, v in ipairs(arg) do
|
||||||
|
local stringArgs = {}
|
||||||
|
for i = 1, n do
|
||||||
|
table.insert(stringArgs, tostring(select(i, ...)))
|
||||||
end
|
end
|
||||||
|
|
||||||
oldPrint(unpack(stringArgs))
|
oldPrint(unpack(stringArgs))
|
||||||
@ -42,25 +44,40 @@ package.loaded = package.loaded or {
|
|||||||
--os = os,
|
--os = os,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local oldDofile = dofile
|
||||||
|
|
||||||
|
---Emulated dofile to execute a lua script from disk and circumvent any caching.
|
||||||
|
---Noita for some reason caches script files (Or loads them into its virtual filesystem)(Or caches compiled bytecode), so reloading script files from disk does not work without this.
|
||||||
|
---
|
||||||
|
---This conforms more with standard lua.
|
||||||
|
---@param path string
|
||||||
|
---@return any ...
|
||||||
|
function dofile(path)
|
||||||
|
local func, err = loadfile(path)
|
||||||
|
if not func then error(err) end
|
||||||
|
|
||||||
|
return func()
|
||||||
|
end
|
||||||
|
|
||||||
local oldRequire = require
|
local oldRequire = require
|
||||||
|
|
||||||
local recursionSet = {}
|
local recursionSet = {}
|
||||||
local recursionLast
|
|
||||||
|
|
||||||
---Emulated require function in case the Lua API is restricted.
|
---Emulated require function in case the Lua API is restricted.
|
||||||
---It's probably good enough for most usecases.
|
---It's probably good enough for most usecases.
|
||||||
---
|
---
|
||||||
---We need to override the default require in any case, as only dofile can access stuff in the virtual filesystem.
|
---We need to override the default require in any case, as only dofile and loadfile can access stuff in the virtual filesystem.
|
||||||
---@param modName string
|
---@param modName string
|
||||||
---@return any
|
---@return any ...
|
||||||
function require(modName)
|
function require(modName)
|
||||||
-- Check if package was already loaded, return previous result.
|
-- Check if package was already loaded, return previous result.
|
||||||
if package.loaded[modName] ~= nil then return package.loaded[modName] end
|
if package.loaded[modName] ~= nil then return package.loaded[modName] end
|
||||||
|
|
||||||
if recursionSet[modName] then
|
if recursionSet[modName] then
|
||||||
error(string.format("Cyclic dependency with module %q called by %q", modName, recursionLast))
|
recursionSet = {}
|
||||||
|
error(string.format("Cyclic dependency with module %q", modName))
|
||||||
end
|
end
|
||||||
recursionSet[modName], recursionLast = true, modName
|
recursionSet[modName] = true
|
||||||
|
|
||||||
local notFoundStr = ""
|
local notFoundStr = ""
|
||||||
|
|
||||||
@ -71,7 +88,7 @@ function require(modName)
|
|||||||
|
|
||||||
if res == nil then res = true end
|
if res == nil then res = true end
|
||||||
package.loaded[modName] = res
|
package.loaded[modName] = res
|
||||||
recursionSet[modName], recursionLast = nil, nil
|
recursionSet[modName] = nil
|
||||||
return res
|
return res
|
||||||
else
|
else
|
||||||
notFoundStr = notFoundStr .. string.format("\tno field package.preload['%s']\n", modName)
|
notFoundStr = notFoundStr .. string.format("\tno field package.preload['%s']\n", modName)
|
||||||
@ -84,14 +101,22 @@ function require(modName)
|
|||||||
local filePath = string.gsub(pathEntry, "?", modPath, 1) -- Insert modPath into "?" placeholder.
|
local filePath = string.gsub(pathEntry, "?", modPath, 1) -- Insert modPath into "?" placeholder.
|
||||||
local fixedPath = string.gsub(filePath, "^%.[\\/]", "") -- Need to remove "./" or ".\" at the beginning, as Noita allows only "data" and "mods".
|
local fixedPath = string.gsub(filePath, "^%.[\\/]", "") -- Need to remove "./" or ".\" at the beginning, as Noita allows only "data" and "mods".
|
||||||
if fixedPath:sub(1, 4) == "data" or fixedPath:sub(1, 4) == "mods" then -- Ignore everything other than data and mod root path elements. It's not perfect, but this is just there to prevent console spam.
|
if fixedPath:sub(1, 4) == "data" or fixedPath:sub(1, 4) == "mods" then -- Ignore everything other than data and mod root path elements. It's not perfect, but this is just there to prevent console spam.
|
||||||
local res, err = dofile(fixedPath)
|
local func, err = loadfile(fixedPath)
|
||||||
if err then
|
if func then
|
||||||
notFoundStr = notFoundStr .. string.format("\tno file '%s'\n", filePath)
|
local state, res = pcall(func)
|
||||||
else
|
if not state then
|
||||||
|
recursionSet = {}
|
||||||
|
error(res)
|
||||||
|
end
|
||||||
if res == nil then res = true end
|
if res == nil then res = true end
|
||||||
package.loaded[modName] = res
|
package.loaded[modName] = res
|
||||||
recursionSet[modName], recursionLast = nil, nil
|
recursionSet[modName] = nil
|
||||||
return res
|
return res
|
||||||
|
elseif err and err:sub(1, 45) == "Error loading lua script - file doesn't exist" then -- I hate to do that.
|
||||||
|
notFoundStr = notFoundStr .. string.format("\tno file '%s'\n", filePath)
|
||||||
|
else
|
||||||
|
recursionSet = {}
|
||||||
|
error(err)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
notFoundStr = notFoundStr .. string.format("\tnot allowed '%s'\n", filePath)
|
notFoundStr = notFoundStr .. string.format("\tnot allowed '%s'\n", filePath)
|
||||||
@ -102,14 +127,14 @@ function require(modName)
|
|||||||
if oldRequire then
|
if oldRequire then
|
||||||
local ok, res = pcall(oldRequire, modName)
|
local ok, res = pcall(oldRequire, modName)
|
||||||
if ok then
|
if ok then
|
||||||
recursionSet[modName], recursionLast = nil, nil
|
recursionSet[modName] = nil
|
||||||
return res
|
return res
|
||||||
else
|
else
|
||||||
notFoundStr = notFoundStr .. string.format("\toriginal require:%s", res)
|
notFoundStr = notFoundStr .. string.format("\toriginal require:%s", res)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
recursionSet[modName], recursionLast = nil, nil
|
recursionSet = {}
|
||||||
error(string.format("module %q not found:\n%s", modName, notFoundStr))
|
error(string.format("module %q not found:\n%s", modName, notFoundStr))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,31 +5,12 @@
|
|||||||
|
|
||||||
-- Allows Noita mods to reload themselves every now and then.
|
-- Allows Noita mods to reload themselves every now and then.
|
||||||
-- This helps dramatically with development, as we don't have to restart Noita for every change.
|
-- This helps dramatically with development, as we don't have to restart Noita for every change.
|
||||||
-- To accomplish this, we need to override the default behavior of dofile and some other things.
|
|
||||||
|
|
||||||
local LiveReload = {}
|
local LiveReload = {}
|
||||||
|
|
||||||
local oldDofile = dofile
|
|
||||||
---Overwritten dofile to execute a lua script from disk and cirumvent any caching.
|
|
||||||
---Noita for some reason caches script files (Or loads them into its virtual filesystem)(Or caches compiled bytecode), so reloading script files from disk does not work without this.
|
|
||||||
---
|
|
||||||
---This is not fully conform the the standard lua implementation, but so isn't Noita's implementation.
|
|
||||||
---@param path string
|
|
||||||
---@return any result
|
|
||||||
---@return string|nil err
|
|
||||||
function dofile(path) ---TODO: Consider moving dofile into compatibility.lua
|
|
||||||
local func, err = loadfile(path)
|
|
||||||
if not func then return nil, err end
|
|
||||||
|
|
||||||
local status, res = pcall(func)
|
|
||||||
if not status then return nil, res end
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
end
|
|
||||||
|
|
||||||
---Reloads the mod's init file in the given interval in frames.
|
---Reloads the mod's init file in the given interval in frames.
|
||||||
---For reloading to work correctly, the mod has to be structured in a special way.
|
---For reloading to work correctly, the mod has to be structured in a special way.
|
||||||
---Like the usage of require and namespaces.
|
---Like the usage of require, namespaces, correct error handling, ...
|
||||||
---
|
---
|
||||||
---Just put this into your `OnWorldPreUpdate` or `OnWorldPostUpdate` callback:
|
---Just put this into your `OnWorldPreUpdate` or `OnWorldPostUpdate` callback:
|
||||||
---
|
---
|
||||||
@ -42,11 +23,7 @@ function LiveReload:Reload(modPath, interval)
|
|||||||
if self.Counter < interval then return end
|
if self.Counter < interval then return end
|
||||||
self.Counter = nil
|
self.Counter = nil
|
||||||
|
|
||||||
local res, err = dofile(modPath .. "init.lua")
|
dofile(modPath .. "init.lua")
|
||||||
if err then
|
|
||||||
print(string.format("Error reloading mod: %s", err))
|
|
||||||
error(string.format("Error reloading mod: %s", err))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return LiveReload
|
return LiveReload
|
||||||
|
4
init.lua
4
init.lua
@ -24,7 +24,7 @@ end
|
|||||||
local CameraAPI = require("noita-api.camera")
|
local CameraAPI = require("noita-api.camera")
|
||||||
local Coords = require("coordinates")
|
local Coords = require("coordinates")
|
||||||
local DebugAPI = require("noita-api.debug")
|
local DebugAPI = require("noita-api.debug")
|
||||||
--local LiveReload = require("noita-api.live-reload")
|
local LiveReload = require("noita-api.live-reload")
|
||||||
local Vec2 = require("noita-api.vec2")
|
local Vec2 = require("noita-api.vec2")
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
@ -120,7 +120,7 @@ function OnWorldPostUpdate()
|
|||||||
Message:CatchException("OnWorldPostUpdate", function()
|
Message:CatchException("OnWorldPostUpdate", function()
|
||||||
-- Reload mod every 60 frames.
|
-- Reload mod every 60 frames.
|
||||||
-- This allows live updates to the mod while Noita is running.
|
-- This allows live updates to the mod while Noita is running.
|
||||||
-- !!! DISABLE THIS LINE AND THE CORRESPONDING REQUIRE BEFORE COMMITTING !!!
|
-- !!! DISABLE THE FOLLOWING LINE BEFORE COMMITTING !!!
|
||||||
--LiveReload:Reload("mods/noita-mapcap/", 60)
|
--LiveReload:Reload("mods/noita-mapcap/", 60)
|
||||||
|
|
||||||
-- Run checks every 60 frames.
|
-- Run checks every 60 frames.
|
||||||
|
Loading…
Reference in New Issue
Block a user