From c782ef56f31ff788bf971635b4dae21cb382d18f Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 23 Feb 2023 13:40:46 +1100 Subject: [PATCH 01/26] rename file_util to FileUtils to follow the naming pattern --- .vscode/settings.json | 2 +- .../files/scripts/NoitaMpSettings.lua | 16 +- mods/noita-mp/files/scripts/Ui.lua | 4 +- .../scripts/init/init_package_loading.lua | 2 +- mods/noita-mp/files/scripts/net/Client.lua | 12 +- mods/noita-mp/files/scripts/net/Server.lua | 8 +- .../files/scripts/util/CustomProfiler.lua | 4 +- .../util/{file_util.lua => FileUtils.lua} | 291 +++++++++--------- .../noita-mp/files/scripts/util/NuidUtils.lua | 6 +- mods/noita-mp/init.lua | 8 +- .../lua_modules/share/lua/5.1/profiler.lua | 2 +- .../lua_modules/share/lua/5.1/sock.lua | 6 +- .../lua_modules/share/lua/5.1/zstd.lua | 2 +- mods/noita-mp/noita-mp-3.0.0-3.rockspec | 4 +- .../files/scripts/NoitaMpSettings_test.lua | 4 +- ...{file_util_test.lua => FileUtils_test.lua} | 16 +- .../files/scripts/util/NetworkUtils_test.lua | 4 +- 17 files changed, 191 insertions(+), 200 deletions(-) rename mods/noita-mp/files/scripts/util/{file_util.lua => FileUtils.lua} (68%) rename mods/noita-mp/tests/files/scripts/util/{file_util_test.lua => FileUtils_test.lua} (96%) diff --git a/.vscode/settings.json b/.vscode/settings.json index aa2ab46b3..ef68ef2a5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -44,7 +44,7 @@ }, "Lua.diagnostics.disable": [ "lowercase-global", - "undefined-field" + "deprecated" ], "files.associations": { "stdbool.h": "c", diff --git a/mods/noita-mp/files/scripts/NoitaMpSettings.lua b/mods/noita-mp/files/scripts/NoitaMpSettings.lua index 2d81139f3..f672bae7f 100644 --- a/mods/noita-mp/files/scripts/NoitaMpSettings.lua +++ b/mods/noita-mp/files/scripts/NoitaMpSettings.lua @@ -10,7 +10,7 @@ ------------------------------------------------------------------------------------------------------------------------ --- 'Imports' ------------------------------------------------------------------------------------------------------------------------ -local fu = require("file_util") +local fu = require("FileUtils") local lfs = require("lfs") local winapi = require("winapi") local json = require("json") @@ -23,9 +23,9 @@ NoitaMpSettings = {} function NoitaMpSettings.clearAndCreateSettings() local cpc = CustomProfiler.start("NoitaMpSettings.clearAndCreateSettings") - local settingsDir = fu.getAbsolutePathOfNoitaMpSettingsDirectory() - if fu.exists(settingsDir) then - fu.removeContentOfDirectory(settingsDir) + local settingsDir = fu.GetAbsolutePathOfNoitaMpSettingsDirectory() + if fu.Exists(settingsDir) then + fu.RemoveContentOfDirectory(settingsDir) Logger.info(Logger.channels.initialize, ("Removed old settings in '%s'!"):format(settingsDir)) else lfs.mkdir(settingsDir) @@ -51,9 +51,9 @@ function NoitaMpSettings.writeSettings(key, value) who = whoAmI() end local settingsFile = ("%s%s%s%s.json") - :format(fu.getAbsolutePathOfNoitaMpSettingsDirectory(), pathSeparator, pid, who) + :format(fu.GetAbsolutePathOfNoitaMpSettingsDirectory(), pathSeparator, pid, who) - if not fu.exists(settingsFile) then + if not fu.Exists(settingsFile) then fu.WriteFile(settingsFile, "{}") end @@ -75,9 +75,9 @@ function NoitaMpSettings.getSetting(key) local pid = winapi.get_current_pid() local settingsFile = ("%s%s%s%s.json") - :format(fu.getAbsolutePathOfNoitaMpSettingsDirectory(), pathSeparator, pid, whoAmI()) + :format(fu.GetAbsolutePathOfNoitaMpSettingsDirectory(), pathSeparator, pid, whoAmI()) - if not fu.exists(settingsFile) then + if not fu.Exists(settingsFile) then fu.WriteFile(settingsFile, "{}") end diff --git a/mods/noita-mp/files/scripts/Ui.lua b/mods/noita-mp/files/scripts/Ui.lua index 86608c5d9..a00a4002b 100644 --- a/mods/noita-mp/files/scripts/Ui.lua +++ b/mods/noita-mp/files/scripts/Ui.lua @@ -7,7 +7,7 @@ -- 'Imports' ---------------------------------------- local renderEzgui = dofile_once("mods/noita-mp/lua_modules/share/lua/5.1/ezgui/EZGUI.lua").init("mods/noita-mp/lua_modules/share/lua/5.1/ezgui") -local fu = require("file_util") +local fu = require("FileUtils") ---------------------------------------------------------------------------------------------------- --- Ui @@ -150,7 +150,7 @@ function Ui.new() local text = "" if foldingOpen then self.ezguiFoldingData.data.text = ("[- NoitaMP] %s eCache:%s pCache:%s nCache:%s %s") - :format(fu.getVersionByFile(), EntityCache.size(), CustomProfiler.getSize(), + :format(fu.GetVersionByFile(), EntityCache.size(), CustomProfiler.getSize(), NetworkUtils.getClientOrServer().getAckCacheSize(), GameGetFrameNum()) else self.ezguiFoldingData.data.text = ("[+ NoitaMP] eCache:%s pCache:%s nCache:%s %s") diff --git a/mods/noita-mp/files/scripts/init/init_package_loading.lua b/mods/noita-mp/files/scripts/init/init_package_loading.lua index 48c5a921b..424681e03 100644 --- a/mods/noita-mp/files/scripts/init/init_package_loading.lua +++ b/mods/noita-mp/files/scripts/init/init_package_loading.lua @@ -40,7 +40,7 @@ package.cpath = package.cpath .. ";" .. "mods\\noita-mp\\lua_modules\\lib\\lua\\5.1\\?.dll;" print("package.cpath = " .. package.cpath) -local fu = require("file_util") +local fu = require("FileUtils") --[[ NoitaMP additions ]] -- A list of paths to lua script modules local paths = { diff --git a/mods/noita-mp/files/scripts/net/Client.lua b/mods/noita-mp/files/scripts/net/Client.lua index e208c7e12..a8afa0207 100644 --- a/mods/noita-mp/files/scripts/net/Client.lua +++ b/mods/noita-mp/files/scripts/net/Client.lua @@ -10,7 +10,7 @@ local sock = require("sock") local util = require("util") local zstandard = require("zstd") local messagePack = require("MessagePack") -local fu = require("file_util") +local fu = require("FileUtils") ---------------------------------------------------------------------------------------------------- --- Client @@ -213,7 +213,7 @@ function Client.new(sockClient) local nuid = localPlayerInfo.nuid -- Could be nil. Timing issue. Will be set after this. self:send(NetworkUtils.events.playerInfo.name, - { NetworkUtils.getNextNetworkMessageId(), name, guid, fu.getVersionByFile(), nuid }) + { NetworkUtils.getNextNetworkMessageId(), name, guid, fu.GetVersionByFile(), nuid }) self:send(NetworkUtils.events.needModList.name, { NetworkUtils.getNextNetworkMessageId(), nil, nil}) @@ -341,9 +341,9 @@ function Client.new(sockClient) ("onPlayerInfo: Clients GUID %s isn't unique! Server will fix this!"):format(self.guid)) end - if fu.getVersionByFile() ~= tostring(data.version) then + if fu.GetVersionByFile() ~= tostring(data.version) then error(("Version mismatch: NoitaMP version of Server: %s and your version: %s") - :format(data.version, fu.getVersionByFile()), 3) + :format(data.version, fu.GetVersionByFile()), 3) self:disconnect() end @@ -434,7 +434,7 @@ function Client.new(sockClient) local entityId = localPlayerInfo.entityId self:send(NetworkUtils.events.playerInfo.name, - { NetworkUtils.getNextNetworkMessageId(), name, guid, fu.getVersionByFile(), nuid }) + { NetworkUtils.getNextNetworkMessageId(), name, guid, fu.GetVersionByFile(), nuid }) if not NetworkVscUtils.hasNetworkLuaComponents(entityId) then NetworkVscUtils.addOrUpdateAllVscs(entityId, name, guid, nil) @@ -638,8 +638,6 @@ function Client.new(sockClient) end local function onNeedModContent(data) - ---@module "file_util" - local fu = dofile_once("mods/noita-mp/files/scripts/util/file_util.lua") local cpc = CustomProfiler.start("Client.onNeedModContent") for _, v in ipairs(data.items) do local modName = v.name diff --git a/mods/noita-mp/files/scripts/net/Server.lua b/mods/noita-mp/files/scripts/net/Server.lua index 31129f9e6..b4c5cb960 100644 --- a/mods/noita-mp/files/scripts/net/Server.lua +++ b/mods/noita-mp/files/scripts/net/Server.lua @@ -8,7 +8,7 @@ ---------------------------------------- local sock = require("sock") local util = require("util") -local fu = require("file_util") +local fu = require("FileUtils") local zstandard = require("zstd") local messagePack = require("MessagePack") @@ -228,7 +228,7 @@ function Server.new(sockServer) end self:send(peer, NetworkUtils.events.playerInfo.name, - { NetworkUtils.getNextNetworkMessageId(), name, guid, fu.getVersionByFile(), nuid }) + { NetworkUtils.getNextNetworkMessageId(), name, guid, fu.GetVersionByFile(), nuid }) self:send(peer, NetworkUtils.events.seed.name, { NetworkUtils.getNextNetworkMessageId(), StatsGetValue("world_seed") }) @@ -312,9 +312,9 @@ function Server.new(sockServer) error(("onPlayerInfo data.version is empty: %s"):format(data.version), 3) end - if fu.getVersionByFile() ~= tostring(data.version) then + if fu.GetVersionByFile() ~= tostring(data.version) then error(("Version mismatch: NoitaMP version of Client: %s and your version: %s") - :format(data.version, fu.getVersionByFile()), 3) + :format(data.version, fu.GetVersionByFile()), 3) peer:disconnect() end diff --git a/mods/noita-mp/files/scripts/util/CustomProfiler.lua b/mods/noita-mp/files/scripts/util/CustomProfiler.lua index 7e6f36788..3de172152 100644 --- a/mods/noita-mp/files/scripts/util/CustomProfiler.lua +++ b/mods/noita-mp/files/scripts/util/CustomProfiler.lua @@ -20,7 +20,7 @@ CustomProfiler.threshold = 16.5 --ms = 60.60 fps CustomProfiler.ceiling = 1001 -- ms CustomProfiler.maxEntries = 25 -- entries per trace CustomProfiler.reportDirectory = ("%s%sNoitaMP-Reports%s%s") - :format(fu.getDesktopDirectory(), pathSeparator, pathSeparator, os.date("%Y-%m-%d_%H-%M-%S", os.time())) + :format(fu.GetDesktopDirectory(), pathSeparator, pathSeparator, os.date("%Y-%m-%d_%H-%M-%S", os.time())) CustomProfiler.reportFilename = "report.html" CustomProfiler.reportJsonFilenamePattern = "%s.json" @@ -147,7 +147,7 @@ function CustomProfiler.stop(functionName, customProfilerCounter) CustomProfiler.reportCache[functionName]["size"] and CustomProfiler.reportCache[functionName]["size"] >= CustomProfiler.maxEntries then - if not fu.exists(CustomProfiler.reportDirectory) then + if not fu.Exists(CustomProfiler.reportDirectory) then fu.MkDir(CustomProfiler.reportDirectory) end diff --git a/mods/noita-mp/files/scripts/util/file_util.lua b/mods/noita-mp/files/scripts/util/FileUtils.lua similarity index 68% rename from mods/noita-mp/files/scripts/util/file_util.lua rename to mods/noita-mp/files/scripts/util/FileUtils.lua index 850d456f8..f254db660 100644 --- a/mods/noita-mp/files/scripts/util/file_util.lua +++ b/mods/noita-mp/files/scripts/util/FileUtils.lua @@ -1,23 +1,21 @@ -local fu = {} -local ffi = require("ffi") -local watcher = require("watcher") -local lfs = require("lfs") -local json = require("json") -local util = require("util") - ------------------------------------------------------------------------------------------------------------------------ ---- Version ------------------------------------------------------------------------------------------------------------------------ -function fu.getVersionByFile() - local modsPath = fu.GetAbsoluteDirectoryPathOfNoitaMP() +---@class FileUtils +local FileUtils = {} +local ffi = require("ffi") +local watcher = require("watcher") +local lfs = require("lfs") +local json = require("json") +local util = require("util") + +--- @return string +function FileUtils.GetVersionByFile() + local modsPath = FileUtils.GetAbsoluteDirectoryPathOfNoitaMP() local versionAbsFilePath = ("%s%s.version"):format(modsPath, pathSeparator) - local content = fu.ReadFile(versionAbsFilePath, "*l") + local content = FileUtils.ReadFile(versionAbsFilePath, "*l") if not content or util.IsEmpty(content) then error(("Unable to read NoitaMP version. Check if '%s' exists!") - :format(fu.GetAbsolutePathOfNoitaRootDirectory() + "/.version"), 2) + :format(FileUtils.GetAbsolutePathOfNoitaRootDirectory() + "/.version"), 2) end - local jsonTable = json.decode(content) - local version = jsonTable.version + local version = json.decode(content).version Logger.info(Logger.channels.initialize, ("NoitaMP %s"):format(version)) return version end @@ -30,33 +28,27 @@ end --- Error if path is not a string. --- @param path string --- @return string path -function fu.ReplacePathSeparator(path) - if type(path) ~= "string" then - error("path is not a string") - end - if _G.is_windows then - --logger:debug("file_util.lua | windows detected replace / with \\") - path = string.gsub(path, "/", "\\") - elseif _G.is_linux then - --logger:debug("file_util.lua | unix detected replace \\ with /") - path = string.gsub(path, "\\", "/") - else +function FileUtils.ReplacePathSeparator(path) + if type(path) == "string" then + if _G.is_windows then + ---@diagnostic disable-next-line: redundant-return-value + return path:gsub("/", "\\") + elseif _G.is_linux then + ---@diagnostic disable-next-line: redundant-return-value + return path:gsub("\\", "/") + end error( - ("file_util.lua | Unable to detect OS(%s[%s]), therefore not able to replace path separator!"):format( - _G.os_name, - _G.os_arch - ), - 2 - ) + ("Unable to detect OS(%s[%s]), therefore not able to replace path separator!"):format(_G.os_name, _G.os_arch), + 2) end - return path + error("path is not a string", 2) end --- Removes trailing path separator in a string: \persistent\flags\ -> \persistent\flags. --- Error if path is not a string. --- @param path string any string, i.e. \persistent\flags\ --- @return string path \persistent\flags -function fu.RemoveTrailingPathSeparator(path) +function FileUtils.RemoveTrailingPathSeparator(path) if type(path) ~= "string" then error("path is not a string") end @@ -69,12 +61,8 @@ end ----------------------------------------------------------------------------------------------------------------------- --- eNet specific commands ----------------------------------------------------------------------------------------------------------------------- -function fu.getPidOfRunningEnetHostByPort() - --if _G.whoAmI() == _G.Client.iAm then - -- error("Makes no sense to get PID of eNet, when client!", 2) - -- return - --end - +--- @return number? +function FileUtils.GetPidOfRunningEnetHostByPort() local command = nil if _G.is_windows then command = ('netstat -abon | find /i "%s"'):format(_G.Server:getPort()) @@ -91,7 +79,7 @@ function fu.getPidOfRunningEnetHostByPort() return tonumber(pid) end -function fu.killProcess(pid) +function FileUtils.KillProcess(pid) local command = nil if _G.is_windows then command = ('taskkill /PID %s /F'):format(pid) @@ -107,40 +95,34 @@ end ---------------------------------------------------------------------------------------------------- local noitaRootDirectory = nil --- Sets root directory of noita.exe, i.e. C:\Program Files (x86)\Steam\steamapps\common\Noita -function fu.SetAbsolutePathOfNoitaRootDirectory() +function FileUtils.SetAbsolutePathOfNoitaRootDirectory() if _G.is_windows then noitaRootDirectory = assert(io.popen("cd"):read("*l"), - "Unable to run windows command 'cd' to get Noitas root directory!") + "Unable to run windows command 'cd' to get Noitas root directory!") elseif _G.is_linux then noitaRootDirectory = assert(io.popen("pwd"):read("*l"), - "Unable to run ubuntu command 'pwd' to get Noitas root directory!") + "Unable to run ubuntu command 'pwd' to get Noitas root directory!") else - error( - ("file_util.lua | Unable to detect OS(%s[%s]), therefore not able to replace path separator!"):format( - _G.os_name, - _G.os_arch - ), - 2 - ) + error(("file_util.lua | Unable to detect OS(%s[%s]), therefore not able to replace path separator!") + :format(_G.os_name, _G.os_arch), 2) end - - noitaRootDirectory = fu.ReplacePathSeparator(noitaRootDirectory) - + noitaRootDirectory = FileUtils.ReplacePathSeparator(noitaRootDirectory) if isTestLuaContext then Logger.trace(Logger.channels.testing, - ("Absolute path of Noitas root directory set to %s, but we need to fix path! Removing \\mods\\noita-mp.") - :format(noitaRootDirectory)) + ("Absolute path of Noitas root directory set to %s, but we need to fix path! Removing \\mods\\noita-mp.") + :format(noitaRootDirectory)) local i, _ = string.find(noitaRootDirectory, "mods") noitaRootDirectory = string.sub(noitaRootDirectory, 0, i - 1) Logger.trace(Logger.channels.testing, - ("NEW absolute path of Noitas root directory set to %s.") - :format(noitaRootDirectory)) + ("NEW absolute path of Noitas root directory set to %s.") + :format(noitaRootDirectory)) end end -function fu.GetAbsolutePathOfNoitaRootDirectory() +---@return string +function FileUtils.GetAbsolutePathOfNoitaRootDirectory() if not noitaRootDirectory then - fu.SetAbsolutePathOfNoitaRootDirectory() + FileUtils.SetAbsolutePathOfNoitaRootDirectory() end return noitaRootDirectory end @@ -153,7 +135,7 @@ end --- If DebugGetIsDevBuild() then Noitas installation path is returned: 'C:\Program Files (x86)\Steam\steamapps\common\Noita' --- otherwise it will return: '%appdata%\..\LocalLow\Nolla_Games_Noita' on windows --- @return string save06_parent_directory_path string of absolute path to '..\Noita' or '..\Nolla_Games_Noita' -function fu.GetAbsoluteDirectoryPathOfParentSave() +function FileUtils.GetAbsoluteDirectoryPathOfParentSave() local file = nil local command = nil local find_directory_name = nil @@ -188,73 +170,73 @@ function fu.GetAbsoluteDirectoryPathOfParentSave() if save06_parent_directory_path == nil or save06_parent_directory_path == "" then GamePrintImportant( - "Unable to find world files", - "Do yourself a favour and save&quit the game and start it again!", "" + "Unable to find world files", + "Do yourself a favour and save&quit the game and start it again!", "" ) end - save06_parent_directory_path = fu.ReplacePathSeparator(save06_parent_directory_path) + save06_parent_directory_path = FileUtils.ReplacePathSeparator(save06_parent_directory_path) return save06_parent_directory_path end --- Returns fullpath of save06 directory on devBuild or release --- @return string directory_path_of_save06 : noita installation path\save06 or %appdata%\..\LocalLow\Nolla_Games_Noita\save06 on windows and unknown for unix systems -function fu.GetAbsoluteDirectoryPathOfSave06() - local directory_path_of_save06 = fu.GetAbsoluteDirectoryPathOfParentSave() .. _G.pathSeparator .. "save06" +function FileUtils.GetAbsoluteDirectoryPathOfSave06() + local directory_path_of_save06 = FileUtils.GetAbsoluteDirectoryPathOfParentSave() .. _G.pathSeparator .. "save06" return directory_path_of_save06 end --- Returns the ABSOLUTE path of the mods folder. --- If fu.GetAbsolutePathOfNoitaRootDirectory() is not set yet, then it will be --- @return string fu.GetAbsolutePathOfNoitaRootDirectory() .. "/mods/noita-mp" -function fu.GetAbsoluteDirectoryPathOfNoitaMP() - if not fu.GetAbsolutePathOfNoitaRootDirectory() then - fu.SetAbsolutePathOfNoitaRootDirectory() +function FileUtils.GetAbsoluteDirectoryPathOfNoitaMP() + if not FileUtils.GetAbsolutePathOfNoitaRootDirectory() then + FileUtils.SetAbsolutePathOfNoitaRootDirectory() end - local p = fu.GetAbsolutePathOfNoitaRootDirectory() .. "/mods/noita-mp" - p = fu.ReplacePathSeparator(p) + local p = FileUtils.GetAbsolutePathOfNoitaRootDirectory() .. "/mods/noita-mp" + p = FileUtils.ReplacePathSeparator(p) return p end --- Returns the RELATIVE path of the mods folder. --- @return string "mods/noita-mp" -function fu.GetRelativeDirectoryPathOfNoitaMP() +function FileUtils.GetRelativeDirectoryPathOfNoitaMP() local p = "mods/noita-mp" - p = fu.ReplacePathSeparator(p) + p = FileUtils.ReplacePathSeparator(p) return p end --- Returns the RELATIVE path of the library folder required for this mod. --- @return string "/mods/noita-mp/files/libs" -function fu.GetRelativeDirectoryPathOfRequiredLibs() +function FileUtils.GetRelativeDirectoryPathOfRequiredLibs() local p = "mods/noita-mp/files/libs" - p = fu.ReplacePathSeparator(p) + p = FileUtils.ReplacePathSeparator(p) return p end --- Returns the ABSOLUTE path of the library folder required for this mod. --- If fu.GetAbsolutePathOfNoitaRootDirectory() is not set yet, then it will be --- @return string fu.GetAbsolutePathOfNoitaRootDirectory() .. "/mods/noita-mp/files/libs" -function fu.GetAbsoluteDirectoryPathOfRequiredLibs() - if not fu.GetAbsolutePathOfNoitaRootDirectory() then - fu.SetAbsolutePathOfNoitaRootDirectory() +function FileUtils.GetAbsoluteDirectoryPathOfRequiredLibs() + if not FileUtils.GetAbsolutePathOfNoitaRootDirectory() then + FileUtils.SetAbsolutePathOfNoitaRootDirectory() end - local p = fu.GetAbsolutePathOfNoitaRootDirectory() .. "/mods/noita-mp/files/libs" - p = fu.ReplacePathSeparator(p) + local p = FileUtils.GetAbsolutePathOfNoitaRootDirectory() .. "/mods/noita-mp/files/libs" + p = FileUtils.ReplacePathSeparator(p) return p end --- There is a world_state.xml per each saveSlot directory, which contains Globals. Nuid are stored in Globals. --- @param saveSlotAbsDirectoryPath string Absolute directory path to the current selected save slot. --- @return string absPath world_state.xml absolute file path -function fu.GetAbsDirPathOfWorldStateXml(saveSlotAbsDirectoryPath) +function FileUtils.GetAbsDirPathOfWorldStateXml(saveSlotAbsDirectoryPath) return ("%s%s%s"):format(saveSlotAbsDirectoryPath, pathSeparator, "world_state.xml") end --- see _G.saveSlotMeta ---@return table -function fu.getLastModifiedSaveSlots() - local save0 = fu.GetAbsoluteDirectoryPathOfParentSave() .. pathSeparator .. "save0" +function FileUtils.GetLastModifiedSaveSlots() + local save0 = FileUtils.GetAbsoluteDirectoryPathOfParentSave() .. pathSeparator .. "save0" local saveSlotLastModified = {} for i = 0, 6, 1 do @@ -263,7 +245,7 @@ function fu.getLastModifiedSaveSlots() watcher(save0X, function(lastModified) if lastModified > 0 then Logger.debug(Logger.channels.initialize, - ("SaveSlot(%s) directory was last modified at %s."):format("save0" .. i, lastModified)) + ("SaveSlot(%s) directory was last modified at %s."):format("save0" .. i, lastModified)) table.insert(saveSlotLastModified, { dir = save0X, lastModified = lastModified, slot = i }) end end) @@ -273,8 +255,8 @@ end --- Returns absolute path of NoitaMP settings directory, --- @return string absPath i.e. "C:\Program Files (x86)\Steam\steamapps\common\Noita\mods\noita-mp\settings" -function fu.getAbsolutePathOfNoitaMpSettingsDirectory() - return fu.GetAbsoluteDirectoryPathOfNoitaMP() .. pathSeparator .. "settings" +function FileUtils.GetAbsolutePathOfNoitaMpSettingsDirectory() + return FileUtils.GetAbsoluteDirectoryPathOfNoitaMP() .. pathSeparator .. "settings" end ---------------------------------------------------------------------------------------------------- @@ -284,7 +266,7 @@ end --- Checks if FILE or DIRECTORY exists --- @param absolutePath string full path --- @return boolean -function fu.exists(absolutePath) +function FileUtils.Exists(absolutePath) -- https://stackoverflow.com/a/21637809/3493998 if type(absolutePath) ~= "string" then error("Parameter 'absolutePath' '" .. tostring(absolutePath) .. "' is not type of string!", 2) @@ -293,12 +275,14 @@ function fu.exists(absolutePath) return exists end -function fu.IsFile(full_path) +--- @param full_path string +--- @return boolean +function FileUtils.IsFile(full_path) -- https://stackoverflow.com/a/21637809/3493998 if type(full_path) ~= "string" then error("file_util.lua | Parameter full_path '" .. tostring(full_path) .. "' is not type of string!") end - if not fu.exists(full_path) then + if not FileUtils.Exists(full_path) then --logger:debug("file_util.lua | Path '" .. tostring(full_path) .. "' does not exist!") return false end @@ -310,23 +294,27 @@ function fu.IsFile(full_path) return false end -function fu.IsDirectory(full_path) +--- @param full_path string +--- @return boolean +function FileUtils.IsDirectory(full_path) -- https://stackoverflow.com/a/21637809/3493998 if type(full_path) ~= "string" then error("file_util.lua | Parameter full_path '" .. tostring(full_path) .. "' is not type of string!") end - local exists = fu.exists(full_path) + local exists = FileUtils.Exists(full_path) --logger:debug("file_util.lua | Directory " .. full_path .. " exists = " .. tostring(exists)) - local is_file = fu.IsFile(full_path) + local is_file = FileUtils.IsFile(full_path) --logger:debug("file_util.lua | Is the directory a file? " .. full_path .. " is_file = " .. tostring(is_file)) return (exists and not is_file) end -function fu.ReadBinaryFile(file_fullpath) +--- @param file_fullpath string +--- @return string|number +function FileUtils.ReadBinaryFile(file_fullpath) if type(file_fullpath) ~= "string" then error("file_util.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") end - file_fullpath = fu.ReplacePathSeparator(file_fullpath) + file_fullpath = FileUtils.ReplacePathSeparator(file_fullpath) -- https://stackoverflow.com/a/31857671/3493998 local file = io.open(file_fullpath, "rb") -- r read mode and b binary mode if not file then @@ -337,11 +325,13 @@ function fu.ReadBinaryFile(file_fullpath) return content end -function fu.WriteBinaryFile(file_fullpath, file_content) +--- @param file_fullpath string +--- @param file_content any +function FileUtils.WriteBinaryFile(file_fullpath, file_content) if type(file_fullpath) ~= "string" then error("file_util.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") end - file_fullpath = fu.ReplacePathSeparator(file_fullpath) + file_fullpath = FileUtils.ReplacePathSeparator(file_fullpath) -- http://lua-users.org/wiki/FileInputOutput local fh = assert(io.open(file_fullpath, "wb")) fh:write(file_content) @@ -349,7 +339,9 @@ function fu.WriteBinaryFile(file_fullpath, file_content) fh:close() end -function fu.ReadFile(file_fullpath, mode) +--- @param file_fullpath string +--- @param mode string? +function FileUtils.ReadFile(file_fullpath, mode) if mode == nil then mode = "*a" end @@ -357,7 +349,7 @@ function fu.ReadFile(file_fullpath, mode) if type(file_fullpath) ~= "string" then error("file_util.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") end - file_fullpath = fu.ReplacePathSeparator(file_fullpath) + file_fullpath = FileUtils.ReplacePathSeparator(file_fullpath) -- https://stackoverflow.com/a/31857671/3493998 local file = io.open(file_fullpath, "r") if not file then @@ -368,11 +360,13 @@ function fu.ReadFile(file_fullpath, mode) return content end -function fu.WriteFile(file_fullpath, file_content) +--- @param file_fullpath string +---@param file_content string +function FileUtils.WriteFile(file_fullpath, file_content) if type(file_fullpath) ~= "string" then error("file_util.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") end - file_fullpath = fu.ReplacePathSeparator(file_fullpath) + file_fullpath = FileUtils.ReplacePathSeparator(file_fullpath) local segments = string.split(file_fullpath, pathSeparator) or {} local pathPerSegments = "" @@ -380,10 +374,10 @@ function fu.WriteFile(file_fullpath, file_content) -- recursively create directories local segment = segments[i] pathPerSegments = pathPerSegments .. segment .. pathSeparator - if not fu.exists(pathPerSegments) then + if not FileUtils.Exists(pathPerSegments) then if not pathPerSegments:contains(".") then -- dump check if it's a file - fu.MkDir(pathPerSegments) + FileUtils.MkDir(pathPerSegments) end end end @@ -395,12 +389,13 @@ function fu.WriteFile(file_fullpath, file_content) fh:close() end -function fu.MkDir(full_path) +--- @param full_path string +function FileUtils.MkDir(full_path) if type(full_path) ~= "string" then error("file_util.lua | Parameter file_fullpath '" .. tostring(full_path) .. "' is not type of string!") end -- https://stackoverflow.com/a/1690932/3493998 - full_path = fu.ReplacePathSeparator(full_path) + full_path = FileUtils.ReplacePathSeparator(full_path) local command = nil if _G.is_windows then @@ -411,8 +406,9 @@ function fu.MkDir(full_path) os.execute(command) end -function fu.AppendToFile(filenameAbsolutePath, appendContent) - -- TODO rework: have a look on plotly.lua ">>" +--- @param filenameAbsolutePath string +---@param appendContent string +function FileUtils.AppendToFile(filenameAbsolutePath, appendContent) local isEmpty = true local file = io.open(filenameAbsolutePath, "a+") for line in io.lines(filenameAbsolutePath) do @@ -427,18 +423,18 @@ function fu.AppendToFile(filenameAbsolutePath, appendContent) file:close() end ----comment --- http://lua-users.org/wiki/SplitJoin -> Example: Split a file path string into components. ---@param str any ---@return unknown -function fu.splitPath(str) +function FileUtils.SplitPath(str) return string.split(str, '[\\/]+') -- TODO: differ between windows and unix --parts = split_path("/usr/local/bin") --> {'usr','local','bin'} end -- Lua implementation of PHP scandir function -function fu.scanDir(directory) +--- @return string[] +function FileUtils.ScanDir(directory) local i, t, popen = 0, {}, io.popen local pfile = nil @@ -456,16 +452,14 @@ function fu.scanDir(directory) return t end -function fu.removeContentOfDirectory(absolutePath) +function FileUtils.RemoveContentOfDirectory(absolutePath) local successRmDir, errorRmDir = lfs.rmdir(absolutePath) - if not successRmDir or errorRmDir then local command = ('rmdir /s /q "%s"'):format(absolutePath) local success, exitCode, code = os.execute(command) Logger.debug(Logger.channels.testing, - ("Tried to remove directory. success=%s, exitCode=%s, code=%s"):format(success, exitCode, code)) + ("Tried to remove directory. success=%s, exitCode=%s, code=%s"):format(success, exitCode, code)) end - lfs.mkdir(absolutePath) end @@ -473,28 +467,29 @@ end --- 7zip stuff ---------------------------------------------------------------------------------------------------- -function fu.Find7zipExecutable() +function FileUtils.Find7zipExecutable() if is_windows then local f = io.popen("where.exe 7z", "r") if not f then error( - "Unable to find 7z.exe, please install 7z via https://7-zip.de/download.html and restart the Noita!", - 2 + "Unable to find 7z.exe, please install 7z via https://7-zip.de/download.html and restart the Noita!", + 2 ) os.exit() end local response = f:read("*a") - _G.seven_zip = tostring(fu.ReplacePathSeparator(response)) + _G.seven_zip = tostring(FileUtils.ReplacePathSeparator(response)) Logger.debug(Logger.channels.testing, "file_util.lua | Found 7z.exe: " .. _G.seven_zip) else error( - "Unfortunately unix systems aren't supported yet. Please consider https://github.com/Ismoh/NoitaMP/issues!", - 2 + "Unfortunately unix systems aren't supported yet. Please consider https://github.com/Ismoh/NoitaMP/issues!", + 2 ) end end -function fu.exists7zip() +--- @return boolean +function FileUtils.Exists7zip() if _G.seven_zip then return true else @@ -502,15 +497,14 @@ function fu.exists7zip() end end ----comment ---@param archive_name string server_save06_98-09-16_23:48:10 - without file extension (*.7z) ---@param absolute_directory_path_to_add_archive string "C:\Users\Ismoh-PC\AppData\LocalLow\Nolla_Games_Noita\save06" ---@param absolute_destination_path string "C:\Program Files (x86)\Steam\steamapps\common\Noita\mods\noita-mp\_" ---@return string|number content binary content of archive -function fu.Create7zipArchive(archive_name, absolute_directory_path_to_add_archive, absolute_destination_path) +function FileUtils.Create7zipArchive(archive_name, absolute_directory_path_to_add_archive, absolute_destination_path) assert( - fu.exists7zip(), - "Unable to find 7z.exe, please install 7z via https://7-zip.de/download.html and restart the Noita!" + FileUtils.Exists7zip(), + "Unable to find 7z.exe, please install 7z via https://7-zip.de/download.html and restart the Noita!" ) if type(archive_name) ~= "string" then @@ -518,41 +512,40 @@ function fu.Create7zipArchive(archive_name, absolute_directory_path_to_add_archi end if type(absolute_directory_path_to_add_archive) ~= "string" then error( - "file_util.lua | Parameter absolute_directory_path_to_add_archive '" .. - tostring(absolute_directory_path_to_add_archive) .. "' is not type of string!" + "file_util.lua | Parameter absolute_directory_path_to_add_archive '" .. + tostring(absolute_directory_path_to_add_archive) .. "' is not type of string!" ) end if type(absolute_destination_path) ~= "string" then error( - "file_util.lua | Parameter absolute_destination_path '" .. - tostring(absolute_destination_path) .. "' is not type of string!" + "file_util.lua | Parameter absolute_destination_path '" .. + tostring(absolute_destination_path) .. "' is not type of string!" ) end - absolute_directory_path_to_add_archive = fu.ReplacePathSeparator(absolute_directory_path_to_add_archive) - absolute_destination_path = fu.ReplacePathSeparator(absolute_destination_path) + absolute_directory_path_to_add_archive = FileUtils.ReplacePathSeparator(absolute_directory_path_to_add_archive) + absolute_destination_path = FileUtils.ReplacePathSeparator(absolute_destination_path) local command = 'cd "' .. - absolute_destination_path .. - '" && 7z.exe a -t7z ' .. archive_name .. ' "' .. absolute_directory_path_to_add_archive .. '"' + absolute_destination_path .. + '" && 7z.exe a -t7z ' .. archive_name .. ' "' .. absolute_directory_path_to_add_archive .. '"' Logger.debug(Logger.channels.testing, "file_util.lua | Running: " .. command) os.execute(command) local archive_full_path = absolute_destination_path .. _G.pathSeparator .. archive_name .. ".7z" - return fu.ReadBinaryFile(archive_full_path) + return FileUtils.ReadBinaryFile(archive_full_path) end ----comment ---@param archive_absolute_directory_path string path to archive location like "C:\Program Files (x86)\Steam\steamapps\common\Noita\mods\noita-mp\_" ---@param archive_name string server_save06_98-09-16_23:48:10.7z - with file extension (*.7z) ---@param extract_absolute_directory_path string "C:\Users\Ismoh-PC\AppData\LocalLow\Nolla_Games_Noita" -function fu.Extract7zipArchive(archive_absolute_directory_path, archive_name, extract_absolute_directory_path) - archive_absolute_directory_path = fu.ReplacePathSeparator(archive_absolute_directory_path) - extract_absolute_directory_path = fu.ReplacePathSeparator(extract_absolute_directory_path) +function FileUtils.Extract7zipArchive(archive_absolute_directory_path, archive_name, extract_absolute_directory_path) + archive_absolute_directory_path = FileUtils.ReplacePathSeparator(archive_absolute_directory_path) + extract_absolute_directory_path = FileUtils.ReplacePathSeparator(extract_absolute_directory_path) local command = 'cd "' .. - archive_absolute_directory_path .. - '" && 7z.exe x -aoa ' .. archive_name .. ' -o"' .. extract_absolute_directory_path .. '"' + archive_absolute_directory_path .. + '" && 7z.exe x -aoa ' .. archive_name .. ' -o"' .. extract_absolute_directory_path .. '"' Logger.debug(Logger.channels.testing, "file_util.lua | Running: " .. command) os.execute(command) end @@ -564,25 +557,25 @@ end ---------------------------------------------------------------------------------------------------- --- Credits to dextercd! -function fu.restartNoita() +function FileUtils.FestartNoita() require("ffi").cast("void(__fastcall*)()", 0x0066e120)() end -function fu.killNoitaAndRestart() +function FileUtils.KillNoitaAndRestart() local exe = "noita.exe" if DebugGetIsDevBuild() then exe = "noita_dev.exe" end - fu.removeContentOfDirectory(_G.saveSlotMeta.dir) + FileUtils.RemoveContentOfDirectory(_G.saveSlotMeta.dir) os.execute(('start "" %s -no_logo_splashes -save_slot %s -gamemode 4'):format(exe, - _G.saveSlotMeta.slot)) -- -gamemode 0 + _G.saveSlotMeta.slot)) -- -gamemode 0 os.exit() end --- This executes c code to sent SDL_QUIT command to the app -function fu.saveAndRestartNoita() +function FileUtils.SaveAndRestartNoita() ffi.cdef [[ typedef union SDL_Event { @@ -607,10 +600,10 @@ function fu.saveAndRestartNoita() exe = "noita_dev.exe" end os.execute(('start "" %s -no_logo_splashes -save_slot %s -gamemode 4'):format(exe, - _G.saveSlotMeta.slot)) -- -gamemode 0 + _G.saveSlotMeta.slot)) -- -gamemode 0 end -function fu.getAllFilesInDirectory(directory, fileExtension) +function FileUtils.GetAllFilesInDirectory(directory, fileExtension) local command = nil if _G.is_windows then command = "for /f tokens^=* %i in ('where /r \"" .. directory .. "\" *" .. fileExtension .. "')do @echo/ %~nxi" @@ -629,7 +622,7 @@ function fu.getAllFilesInDirectory(directory, fileExtension) return filenames end -function fu.getDesktopDirectory() +function FileUtils.GetDesktopDirectory() local command = nil if _G.is_windows then command = "echo %USERPROFILE%\\Desktop" @@ -644,4 +637,4 @@ function fu.getDesktopDirectory() return string.trim(content) end -return fu +return FileUtils diff --git a/mods/noita-mp/files/scripts/util/NuidUtils.lua b/mods/noita-mp/files/scripts/util/NuidUtils.lua index e8af3a0b4..b518e0c59 100644 --- a/mods/noita-mp/files/scripts/util/NuidUtils.lua +++ b/mods/noita-mp/files/scripts/util/NuidUtils.lua @@ -6,7 +6,7 @@ ---------------------------------------- --- 'Imports' ---------------------------------------- -local fu = require("file_util") +local fu = require("FileUtils") local nxml = require("nxml") ----------------- @@ -27,7 +27,7 @@ local function getNextNuid() -- Are there any nuids saved in globals, if so get the highest nuid? if not xmlParsed then local worldStateXmlAbsPath = fu.GetAbsDirPathOfWorldStateXml(_G.saveSlotMeta.dir) - if fu.exists(worldStateXmlAbsPath) then + if fu.Exists(worldStateXmlAbsPath) then local f = io.open(worldStateXmlAbsPath, "r") local xml = nxml.parse(f:read("*a")) f:close() @@ -64,7 +64,7 @@ function NuidUtils.getEntityIdsByKillIndicator() local cpc = CustomProfiler.start("NuidUtils.getEntityIdsByKillIndicator") local deadNuids = GlobalsUtils.getDeadNuids() local worldStateXmlAbsPath = fu.GetAbsDirPathOfWorldStateXml(_G.saveSlotMeta.dir) - if fu.exists(worldStateXmlAbsPath) then + if fu.Exists(worldStateXmlAbsPath) then local f = io.open(worldStateXmlAbsPath, "r") local xml = nxml.parse(f:read("*a")) f:close() diff --git a/mods/noita-mp/init.lua b/mods/noita-mp/init.lua index e29c833bb..a3bf67b57 100644 --- a/mods/noita-mp/init.lua +++ b/mods/noita-mp/init.lua @@ -7,7 +7,7 @@ end ---------------------------------------------------------------------------------------------------- dofile("mods/noita-mp/files/scripts/init/init_.lua") local util = require("util") -local fu = require("file_util") +local fu = require("FileUtils") local ui = require("Ui").new() Logger.debug(Logger.channels.initialize, "Starting to load noita-mp init.lua..") @@ -20,7 +20,7 @@ NoitaMpSettings.clearAndCreateSettings() -- Is used to stop Noita pausing game, when focus is gone (tab out game) ModMagicNumbersFileAdd("mods/noita-mp/files/data/magic_numbers.xml") fu.Find7zipExecutable() -local saveSlotsLastModifiedBeforeWorldInit = fu.getLastModifiedSaveSlots() +local saveSlotsLastModifiedBeforeWorldInit = fu.GetLastModifiedSaveSlots() ---------------------------------------------------------------------------------------------------- --- NoitaMP functions @@ -43,7 +43,7 @@ local function setSeedIfConnectedSecondTime() local saveSlotMetaDirectory = ModSettingGet("noita-mp.saveSlotMetaDirectory") CustomProfiler.stop("ModSettingGet", cpc1) if saveSlotMetaDirectory then - fu.removeContentOfDirectory(saveSlotMetaDirectory) + fu.RemoveContentOfDirectory(saveSlotMetaDirectory) else error("Unable to emptying selected save slot!", 2) end @@ -124,7 +124,7 @@ function OnWorldPreUpdate() EntityUtils.addOrChangeDetectionRadiusDebug(MinaUtils.getLocalMinaInformation().entityId) if not _G.saveSlotMeta then - local saveSlotsLastModifiedAfterWorldInit = fu.getLastModifiedSaveSlots() + local saveSlotsLastModifiedAfterWorldInit = fu.GetLastModifiedSaveSlots() for i = 1, #saveSlotsLastModifiedBeforeWorldInit do for j = 1, #saveSlotsLastModifiedAfterWorldInit do local saveSlotMeta diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/profiler.lua b/mods/noita-mp/lua_modules/share/lua/5.1/profiler.lua index d79b07312..445f485b5 100644 --- a/mods/noita-mp/lua_modules/share/lua/5.1/profiler.lua +++ b/mods/noita-mp/lua_modules/share/lua/5.1/profiler.lua @@ -77,7 +77,7 @@ new table using the matched key names: `profiler.configuration(overrides) ]] -local fu = require("file_util") +local fu = require("FileUtils") --[[ Configuration ]]-- diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/sock.lua b/mods/noita-mp/lua_modules/share/lua/5.1/sock.lua index c918062bf..59d9971bc 100644 --- a/mods/noita-mp/lua_modules/share/lua/5.1/sock.lua +++ b/mods/noita-mp/lua_modules/share/lua/5.1/sock.lua @@ -34,7 +34,7 @@ local sock = { local enet = require("enet") local util = require("util") -local fu = require("file_util") +local fu = require("FileUtils") _G.Logger.info(_G.Logger.channels.initialize, "lua-enet version = master branch 21.10.2015") _G.Logger.info(_G.Logger.channels.initialize, "enet version = " .. enet.linked_version()) -- 1.3.17 @@ -264,8 +264,8 @@ function Server:start(ip, port) if not self.host then --error("Failed to create the host. Is there another server running on :" .. self.port .. "?") self:log("", { "Failed to create the host. Is there another server running on :" .. self.port .. "?" }) - local pid = fu.getPidOfRunningEnetHostByPort() - fu.killProcess(pid) + local pid = fu.GetPidOfRunningEnetHostByPort() + fu.KillProcess(pid) return false end diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/zstd.lua b/mods/noita-mp/lua_modules/share/lua/5.1/zstd.lua index a45063b5a..5594c34cf 100644 --- a/mods/noita-mp/lua_modules/share/lua/5.1/zstd.lua +++ b/mods/noita-mp/lua_modules/share/lua/5.1/zstd.lua @@ -88,7 +88,7 @@ local arr_utint8_t = ffi_typeof "uint8_t[?]" local ptr_zstd_inbuffer_t = ffi_typeof "ZSTD_inBuffer[1]" local ptr_zstd_outbuffer_t = ffi_typeof "ZSTD_outBuffer[1]" -local fu = require("file_util") +local fu = require("FileUtils") local zstd = ffi_load(fu.GetAbsolutePathOfNoitaRootDirectory() .. "\\mods\\noita-mp\\lua_modules\\lib\\lua\\5.1\\libzstd") local file = assert(io.popen("zstd -vV", "r")) local zstdVersion = file:read("*a") diff --git a/mods/noita-mp/noita-mp-3.0.0-3.rockspec b/mods/noita-mp/noita-mp-3.0.0-3.rockspec index 9379e7d2b..cfbd64030 100644 --- a/mods/noita-mp/noita-mp-3.0.0-3.rockspec +++ b/mods/noita-mp/noita-mp-3.0.0-3.rockspec @@ -44,7 +44,7 @@ build = { ["files.scripts.util.NetworkVscUtils"] = "files/scripts/util/NetworkVscUtils.lua", ["files.scripts.util.NoitaComponentUtils"] = "files/scripts/util/NoitaComponentUtils.lua", ["files.scripts.util.NuidUtils"] = "files/scripts/util/NuidUtils.lua", - ["files.scripts.util.file_util"] = "files/scripts/util/file_util.lua", + ["files.scripts.util.FileUtils"] = "files/scripts/util/FileUtils.lua", ["files.scripts.util.GuidUtils"] = "files/scripts/util/GuidUtils.lua", ["files.scripts.util.util"] = "files/scripts/util/util.lua", init = "init.lua", @@ -62,7 +62,7 @@ build = { ["tests.files.scripts.util.NetworkUtils_test"] = "tests/files/scripts/util/NetworkUtils_test.lua", ["tests.files.scripts.util.NetworkVscUtils_test"] = "tests/files/scripts/util/NetworkVscUtils_test.lua", ["tests.files.scripts.util.NuidUtils_test"] = "tests/files/scripts/util/NuidUtils_test.lua", - ["tests.files.scripts.util.file_util_test"] = "tests/files/scripts/util/file_util_test.lua", + ["tests.files.scripts.util.FileUtils_test"] = "tests/files/scripts/util/FileUtils_test.lua", ["tests.files.scripts.util.GuidUtils_test"] = "tests/files/scripts/util/GuidUtils_test.lua", ["tests.files.scripts.util.util_test"] = "tests/files/scripts/util/util_test.lua", ["tests.init_test"] = "tests/init_test.lua", diff --git a/mods/noita-mp/tests/files/scripts/NoitaMpSettings_test.lua b/mods/noita-mp/tests/files/scripts/NoitaMpSettings_test.lua index dbf4d663f..ac58836c8 100644 --- a/mods/noita-mp/tests/files/scripts/NoitaMpSettings_test.lua +++ b/mods/noita-mp/tests/files/scripts/NoitaMpSettings_test.lua @@ -5,7 +5,7 @@ local params = ... local lu = require("luaunit") -local fu = require("file_util") +local fu = require("FileUtils") TestNoitaMpSettings = {} @@ -17,7 +17,7 @@ end function TestNoitaMpSettings:testClearAndCreateSettings() NoitaMpSettings.clearAndCreateSettings() - local files = fu.getAllFilesInDirectory(fu.getAbsolutePathOfNoitaMpSettingsDirectory(), "json") + local files = fu.GetAllFilesInDirectory(fu.GetAbsolutePathOfNoitaMpSettingsDirectory(), "json") lu.assertEquals(files, {}, "Settings directory wasn't empty!") end diff --git a/mods/noita-mp/tests/files/scripts/util/file_util_test.lua b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua similarity index 96% rename from mods/noita-mp/tests/files/scripts/util/file_util_test.lua rename to mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua index 7bbe7ee51..c6aa4bba2 100644 --- a/mods/noita-mp/tests/files/scripts/util/file_util_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua @@ -15,7 +15,7 @@ ModSettingGet = function(id) end local lu = require("luaunit") -local fu = require("file_util") +local fu = require("FileUtils") TestFileUtil = {} @@ -215,9 +215,9 @@ end ---------------------------------------------------------------------------------------------------- function TestFileUtil:testExists() - lu.assertNotIsTrue(fu.exists("nonexistingfile.asdf")) - lu.assertErrorMsgContains("is not type of string!", fu.exists) - lu.assertIsTrue(fu.exists(fu.GetAbsoluteDirectoryPathOfNoitaMP() .. "/mod.xml")) + lu.assertNotIsTrue(fu.Exists("nonexistingfile.asdf")) + lu.assertErrorMsgContains("is not type of string!", fu.Exists) + lu.assertIsTrue(fu.Exists(fu.GetAbsoluteDirectoryPathOfNoitaMP() .. "/mod.xml")) end function TestFileUtil:testIsFile() @@ -245,7 +245,7 @@ function TestFileUtil:testWriteBinaryFile() local full_path = fu.GetAbsolutePathOfNoitaRootDirectory() .. "/write-temporary-binary-test-file.txt" fu.WriteBinaryFile(full_path, "File Content") - lu.assertIsTrue(fu.exists(full_path)) + lu.assertIsTrue(fu.Exists(full_path)) os.remove(full_path) end @@ -262,7 +262,7 @@ function TestFileUtil:testWriteFile() local full_path = fu.GetAbsolutePathOfNoitaRootDirectory() .. "/write-temporary-test-file.txt" fu.WriteFile(full_path, "File Content") - lu.assertIsTrue(fu.exists(full_path)) + lu.assertIsTrue(fu.Exists(full_path)) os.remove(full_path) end @@ -283,9 +283,9 @@ end function TestFileUtil:testExists7zip() local old = _G.seven_zip _G.seven_zip = false -- mock - lu.assertNotIsTrue(fu.exists7zip()) + lu.assertNotIsTrue(fu.Exists7zip()) _G.seven_zip = true -- mock - lu.assertIsTrue(fu.exists7zip()) + lu.assertIsTrue(fu.Exists7zip()) _G.seven_zip = old end diff --git a/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua index c7ad444e9..525bc0b9e 100644 --- a/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua @@ -241,13 +241,13 @@ function TestNetworkUtils:testAlreadySentSeed() end function TestNetworkUtils:testAlreadySentPlayerInfo() - local fu = require("file_util") + local fu = require("FileUtils") -- [[ Prepare mocked data for sending PlayerInfo! ]] -- local networkMessageId = NetworkUtils.getNextNetworkMessageId() local name = "ClientOwnerName" local guid = GuidUtils:getGuid() - local version = fu.getVersionByFile() + local version = fu.GetVersionByFile() local nuid = nil local data = { From 7e1bf60c97e82ec7a07bc8333c5414c9debde377 Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Fri, 24 Feb 2023 08:50:50 +1100 Subject: [PATCH 02/26] rename util.lua to Utils.lua --- mods/noita-mp/config.lua | 14 +- .../files/scripts/NoitaMpSettings.lua | 8 +- mods/noita-mp/files/scripts/Ui.lua | 2 +- .../scripts/extensions/table_extensions.lua | 4 +- mods/noita-mp/files/scripts/net/Client.lua | 134 ++++++++-------- mods/noita-mp/files/scripts/net/Server.lua | 146 +++++++++--------- .../files/scripts/util/CustomProfiler.lua | 4 +- .../files/scripts/util/EntityUtils.lua | 16 +- .../noita-mp/files/scripts/util/FileUtils.lua | 40 ++--- .../noita-mp/files/scripts/util/GuidUtils.lua | 8 +- .../files/scripts/util/NetworkCacheUtils.lua | 54 +++---- .../files/scripts/util/NetworkUtils.lua | 4 +- .../files/scripts/util/NetworkVscUtils.lua | 4 +- .../scripts/util/{util.lua => Utils.lua} | 23 +-- mods/noita-mp/init.lua | 6 +- .../lua_modules/share/lua/5.1/sock.lua | 10 +- mods/noita-mp/tests/_initializeUnitTests.lua | 4 +- .../files/scripts/util/NetworkUtils_test.lua | 28 ++-- .../tests/files/scripts/util/util_test.lua | 14 +- 19 files changed, 262 insertions(+), 261 deletions(-) rename mods/noita-mp/files/scripts/util/{util.lua => Utils.lua} (89%) diff --git a/mods/noita-mp/config.lua b/mods/noita-mp/config.lua index 003259143..0869e597d 100644 --- a/mods/noita-mp/config.lua +++ b/mods/noita-mp/config.lua @@ -48,13 +48,13 @@ local NoitaApiModSettingGet = ModSettingGet local NoitaApiModSettingSetNextValue = ModSettingSetNextValue local NoitaApiModSettingGetNextValue = ModSettingGetNextValue -if not util then +if not Utils then if require then - util = require("util") + Utils = require("Utils") else -- when NoitaComponents with their own restricted LuaContext load this file, -- util isn't available! - util = dofile_once("mods/noita-mp/files/scripts/util/util.lua") + Utils = dofile_once("mods/noita-mp/files/scripts/util/Utils.lua") if not MinaUtils and not require then MinaUtils = dofile_once("mods/noita-mp/files/scripts/util/MinaUtils.lua") end @@ -74,7 +74,7 @@ end ModSettingGet = function(id) if id == "noita-mp.name" then local name = MinaUtils.getLocalMinaName() - if not util.IsEmpty(name) then + if not Utils.IsEmpty(name) then return name else name = NoitaApiModSettingGet(id) @@ -84,7 +84,7 @@ ModSettingGet = function(id) end if id == "noita-mp.guid" then local guid = MinaUtils.getLocalMinaGuid() - if not util.IsEmpty(guid) then + if not Utils.IsEmpty(guid) then return guid else guid = NoitaApiModSettingGet(id) @@ -108,13 +108,13 @@ end ModSettingGetNextValue = function(id) if id == "noita-mp.name" and name then local name = MinaUtils.getLocalMinaName() - if not util.IsEmpty(name) then + if not Utils.IsEmpty(name) then return name end end if id == "noita-mp.guid" and guid then local guid = MinaUtils.getLocalMinaGuid() - if not util.IsEmpty(guid) then + if not Utils.IsEmpty(guid) then return guid end end diff --git a/mods/noita-mp/files/scripts/NoitaMpSettings.lua b/mods/noita-mp/files/scripts/NoitaMpSettings.lua index f672bae7f..df9765657 100644 --- a/mods/noita-mp/files/scripts/NoitaMpSettings.lua +++ b/mods/noita-mp/files/scripts/NoitaMpSettings.lua @@ -14,7 +14,7 @@ local fu = require("FileUtils") local lfs = require("lfs") local winapi = require("winapi") local json = require("json") -local util = require("util") +local Utils = require("Utils") ------------------------------------------------------------------------------------------------------------------------ --- NoitaMpSettings @@ -36,11 +36,11 @@ end function NoitaMpSettings.writeSettings(key, value) local cpc = CustomProfiler.start("NoitaMpSettings.writeSettings") - if util.IsEmpty(key) or type(key) ~= "string" then + if Utils.IsEmpty(key) or type(key) ~= "string" then error(("'key' must not be nil or is not type of string!"):format(key), 2) end - if util.IsEmpty(value) or type(value) ~= "string" then + if Utils.IsEmpty(value) or type(value) ~= "string" then error(("'value' must not be nil or is not type of string!"):format(value), 2) end @@ -84,7 +84,7 @@ function NoitaMpSettings.getSetting(key) local contentString = fu.ReadFile(settingsFile) local contentJson = json.decode(contentString) - if util.IsEmpty(contentJson[key]) then + if Utils.IsEmpty(contentJson[key]) then error(("Unable to find '%s' in NoitaMpSettings: %s"):format(key, contentString), 2) end local value = contentJson[key] diff --git a/mods/noita-mp/files/scripts/Ui.lua b/mods/noita-mp/files/scripts/Ui.lua index a00a4002b..68db0f2c9 100644 --- a/mods/noita-mp/files/scripts/Ui.lua +++ b/mods/noita-mp/files/scripts/Ui.lua @@ -91,7 +91,7 @@ function Ui.new() showAddress = not showAddress end, copyAddress = function() - util.copyToClipboard(("%s:%s"):format(_G.Server:getAddress(), _G.Server:getPort())) + Utils.copyToClipboard(("%s:%s"):format(_G.Server:getAddress(), _G.Server:getPort())) end, kick = function(data, element, arg1) _G.Server.kick(arg1) diff --git a/mods/noita-mp/files/scripts/extensions/table_extensions.lua b/mods/noita-mp/files/scripts/extensions/table_extensions.lua index d3d2b0f5f..eb3ee52b9 100644 --- a/mods/noita-mp/files/scripts/extensions/table_extensions.lua +++ b/mods/noita-mp/files/scripts/extensions/table_extensions.lua @@ -210,8 +210,8 @@ function table.contentToString(tbl) if not tbl or type(tbl) ~= "table" then error("'tbl' must not be nil and type of table!", 2) end - if not util then - util = require("util") + if not Utils then + Utils = require("Utils") end --Logger.trace(Logger.channels.testing, ("tbl = %s"):format(util.pformat(tbl))) diff --git a/mods/noita-mp/files/scripts/net/Client.lua b/mods/noita-mp/files/scripts/net/Client.lua index a8afa0207..f6937b8e9 100644 --- a/mods/noita-mp/files/scripts/net/Client.lua +++ b/mods/noita-mp/files/scripts/net/Client.lua @@ -7,7 +7,7 @@ --- 'Imports' ---------------------------------------- local sock = require("sock") -local util = require("util") +local Utils = require("Utils") local zstandard = require("zstd") local messagePack = require("MessagePack") local fu = require("FileUtils") @@ -147,7 +147,7 @@ function Client.new(sockClient) end local data = { networkMessageId, event, NetworkUtils.events.acknowledgement.ack, os.clock() } self:send(NetworkUtils.events.acknowledgement.name, data) - Logger.debug(Logger.channels.network, ("Sent ack with data = %s"):format(util.pformat(data))) + Logger.debug(Logger.channels.network, ("Sent ack with data = %s"):format(Utils.pformat(data))) CustomProfiler.stop("Client.sendAck", cpc2) end @@ -156,26 +156,26 @@ function Client.new(sockClient) ------------------------------------------------------------------------------------------------ local function onAcknowledgement(data) local cpc3 = CustomProfiler.start("Client.onAcknowledgement") - Logger.debug(Logger.channels.network, "onAcknowledgement: Acknowledgement received.", util.pformat(data)) + Logger.debug(Logger.channels.network, "onAcknowledgement: Acknowledgement received.", Utils.pformat(data)) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onAcknowledgement data.networkMessageId is empty: %s"):format(data.networkMessageId), 2) end if not data.networkMessageId then error(("Unable to get acknowledgement with networkMessageId = %s, data = %s, peer = %s") - :format(networkMessageId, util.pformat(data), util.pformat(self)), 2) + :format(networkMessageId, Utils.pformat(data), Utils.pformat(self)), 2) end - if util.IsEmpty(data.event) then + if Utils.IsEmpty(data.event) then error(("onAcknowledgement data.event is empty: %s"):format(data.event), 2) end - if util.IsEmpty(data.status) then + if Utils.IsEmpty(data.status) then error(("onAcknowledgement data.status is empty: %s"):format(data.status), 2) end - if util.IsEmpty(data.ackedAt) then + if Utils.IsEmpty(data.ackedAt) then error(("onAcknowledgement data.ackedAt is empty: %s"):format(data.ackedAt), 2) end @@ -201,9 +201,9 @@ function Client.new(sockClient) --- @param data number not in use atm local function onConnect(data) local cpc4 = CustomProfiler.start("Client.onConnect") - Logger.debug(Logger.channels.network, "Connected to server!", util.pformat(data)) + Logger.debug(Logger.channels.network, "Connected to server!", Utils.pformat(data)) - if util.IsEmpty(data) then + if Utils.IsEmpty(data) then error(("onConnect data is empty: %s"):format(data), 3) end @@ -229,17 +229,17 @@ function Client.new(sockClient) --- @param data table data = { "name", "guid" } @see NetworkUtils.events.connect2.schema local function onConnect2(data) local cpc5 = CustomProfiler.start("Client.onConnect2") - Logger.debug(Logger.channels.network, "Another client connected.", util.pformat(data)) + Logger.debug(Logger.channels.network, "Another client connected.", Utils.pformat(data)) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onConnect2 data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.name) then + if Utils.IsEmpty(data.name) then error(("onConnect2 data.name is empty: %s"):format(data.name), 3) end - if util.IsEmpty(data.guid) then + if Utils.IsEmpty(data.guid) then error(("onConnect2 data.guid is empty: %s"):format(data.guid), 3) end @@ -256,9 +256,9 @@ function Client.new(sockClient) --- @param data number data(.code) = 0 local function onDisconnect(data) local cpc6 = CustomProfiler.start("Client.onDisconnect") - Logger.debug(Logger.channels.network, "Disconnected from server!", util.pformat(data)) + Logger.debug(Logger.channels.network, "Disconnected from server!", Utils.pformat(data)) - if util.IsEmpty(data) then + if Utils.IsEmpty(data) then error(("onDisconnect data is empty: %s"):format(data), 3) end @@ -285,17 +285,17 @@ function Client.new(sockClient) --- @param data table data { "name", "guid" } @see NetworkUtils.events.disconnect2.schema local function onDisconnect2(data) local cpc7 = CustomProfiler.start("Client.onDisconnect2") - Logger.debug(Logger.channels.network, "onDisconnect2: Another client disconnected.", util.pformat(data)) + Logger.debug(Logger.channels.network, "onDisconnect2: Another client disconnected.", Utils.pformat(data)) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onDisconnect2 data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.name) then + if Utils.IsEmpty(data.name) then error(("onDisconnect2 data.name is empty: %s"):format(data.name), 3) end - if util.IsEmpty(data.guid) then + if Utils.IsEmpty(data.guid) then error(("onDisconnect2 data.guid is empty: %s"):format(data.guid), 3) end @@ -314,25 +314,25 @@ function Client.new(sockClient) --- @param data table data { networkMessageId, name, guid } local function onPlayerInfo(data) local cpc8 = CustomProfiler.start("Client.onPlayerInfo") - Logger.debug(Logger.channels.network, "onPlayerInfo: Player info received.", util.pformat(data)) + Logger.debug(Logger.channels.network, "onPlayerInfo: Player info received.", Utils.pformat(data)) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onPlayerInfo data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.name) then + if Utils.IsEmpty(data.name) then error(("onPlayerInfo data.name is empty: %s"):format(data.name), 3) end - if util.IsEmpty(data.guid) then + if Utils.IsEmpty(data.guid) then error(("onPlayerInfo data.guid is empty: %s"):format(data.guid), 3) end - if util.IsEmpty(data.nuid) then + if Utils.IsEmpty(data.nuid) then error(("onPlayerInfo data.nuid is empty: %s"):format(data.nuid), 3) end - if util.IsEmpty(data.version) then + if Utils.IsEmpty(data.version) then error(("onPlayerInfo data.version is empty: %s"):format(data.version), 3) end @@ -362,17 +362,17 @@ function Client.new(sockClient) --- @param data table data { "networkMessageId", "oldGuid", "newGuid" } local function onNewGuid(data) local cpc9 = CustomProfiler.start("Client.onNewGuid") - Logger.debug(Logger.channels.network, ("onNewGuid: New GUID from server received."):format(util.pformat(data))) + Logger.debug(Logger.channels.network, ("onNewGuid: New GUID from server received."):format(Utils.pformat(data))) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onNewGuid data.networkMessageId is empty: %s"):format(data.networkMessageId), 2) end - if util.IsEmpty(data.oldGuid) then + if Utils.IsEmpty(data.oldGuid) then error(("onNewGuid data.oldGuid is empty: %s"):format(data.oldGuid), 2) end - if util.IsEmpty(data.newGuid) then + if Utils.IsEmpty(data.newGuid) then error(("onNewGuid data.newGuid is empty: %s"):format(data.newGuid), 2) end @@ -407,13 +407,13 @@ function Client.new(sockClient) --- @param data table data { networkMessageId, seed } local function onSeed(data) local cpc10 = CustomProfiler.start("Client.onSeed") - Logger.debug(Logger.channels.network, "onSeed: Seed from server received.", util.pformat(data)) + Logger.debug(Logger.channels.network, "onSeed: Seed from server received.", Utils.pformat(data)) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onSeed data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.seed) then + if Utils.IsEmpty(data.seed) then error(("onSeed data.seed is empty: %s"):format(data.seed), 3) end @@ -424,7 +424,7 @@ function Client.new(sockClient) local localSeed = tonumber(StatsGetValue("world_seed")) if localSeed ~= serversSeed then - --util.reloadMap(serversSeed) TODO enable again, when custom map/biome isn't used anymore + --Utils.reloadMap(serversSeed) TODO enable again, when custom map/biome isn't used anymore end local localPlayerInfo = MinaUtils.getLocalMinaInformation() @@ -456,49 +456,49 @@ function Client.new(sockClient) --- velocity { x, y }, filename } local function onNewNuid(data) local cpc11 = CustomProfiler.start("Client.onNewNuid") - Logger.debug(Logger.channels.network, ("Received a new nuid! data = %s"):format(util.pformat(data))) + Logger.debug(Logger.channels.network, ("Received a new nuid! data = %s"):format(Utils.pformat(data))) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onNewNuid data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.owner) then - error(("onNewNuid data.owner is empty: %s"):format(util.pformat(data.owner)), 3) + if Utils.IsEmpty(data.owner) then + error(("onNewNuid data.owner is empty: %s"):format(Utils.pformat(data.owner)), 3) end - if util.IsEmpty(data.localEntityId) then + if Utils.IsEmpty(data.localEntityId) then error(("onNewNuid data.localEntityId is empty: %s"):format(data.localEntityId), 3) end - if util.IsEmpty(data.newNuid) then + if Utils.IsEmpty(data.newNuid) then error(("onNewNuid data.newNuid is empty: %s"):format(data.newNuid), 3) end - if util.IsEmpty(data.x) then + if Utils.IsEmpty(data.x) then error(("onNewNuid data.x is empty: %s"):format(data.x), 3) end - if util.IsEmpty(data.y) then + if Utils.IsEmpty(data.y) then error(("onNewNuid data.y is empty: %s"):format(data.y), 3) end - if util.IsEmpty(data.rotation) then + if Utils.IsEmpty(data.rotation) then error(("onNewNuid data.rotation is empty: %s"):format(data.rotation), 3) end - if util.IsEmpty(data.velocity) then - error(("onNewNuid data.velocity is empty: %s"):format(util.pformat(data.velocity)), 3) + if Utils.IsEmpty(data.velocity) then + error(("onNewNuid data.velocity is empty: %s"):format(Utils.pformat(data.velocity)), 3) end - if util.IsEmpty(data.filename) then + if Utils.IsEmpty(data.filename) then error(("onNewNuid data.filename is empty: %s"):format(data.filename), 3) end - if util.IsEmpty(data.health) then + if Utils.IsEmpty(data.health) then error(("onNewNuid data.health is empty: %s"):format(data.health), 3) end - if util.IsEmpty(data.isPolymorphed) then + if Utils.IsEmpty(data.isPolymorphed) then error(("onNewNuid data.isPolymorphed is empty: %s"):format(data.isPolymorphed), 3) end @@ -529,41 +529,41 @@ function Client.new(sockClient) local function onEntityData(data) local cpc12 = CustomProfiler.start("Client.onEntityData") Logger.debug(Logger.channels.network, ("Received entityData for nuid = %s! data = %s") - :format(data.nuid, util.pformat(data))) + :format(data.nuid, Utils.pformat(data))) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onNewNuid data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.owner) then - error(("onNewNuid data.owner is empty: %s"):format(util.pformat(data.owner)), 3) + if Utils.IsEmpty(data.owner) then + error(("onNewNuid data.owner is empty: %s"):format(Utils.pformat(data.owner)), 3) end - --if util.IsEmpty(data.localEntityId) then + --if Utils.IsEmpty(data.localEntityId) then -- error(("onNewNuid data.localEntityId is empty: %s"):format(data.localEntityId), 3) --end - if util.IsEmpty(data.nuid) then + if Utils.IsEmpty(data.nuid) then error(("onNewNuid data.nuid is empty: %s"):format(data.nuid), 3) end - if util.IsEmpty(data.x) then + if Utils.IsEmpty(data.x) then error(("onNewNuid data.x is empty: %s"):format(data.x), 3) end - if util.IsEmpty(data.y) then + if Utils.IsEmpty(data.y) then error(("onNewNuid data.y is empty: %s"):format(data.y), 3) end - if util.IsEmpty(data.rotation) then + if Utils.IsEmpty(data.rotation) then error(("onNewNuid data.rotation is empty: %s"):format(data.rotation), 3) end - if util.IsEmpty(data.velocity) then - error(("onNewNuid data.velocity is empty: %s"):format(util.pformat(data.velocity)), 3) + if Utils.IsEmpty(data.velocity) then + error(("onNewNuid data.velocity is empty: %s"):format(Utils.pformat(data.velocity)), 3) end - if util.IsEmpty(data.health) then + if Utils.IsEmpty(data.health) then error(("onNewNuid data.health is empty: %s"):format(data.health), 3) end @@ -580,7 +580,7 @@ function Client.new(sockClient) NoitaComponentUtils.setEntityData(localEntityId, x, y, rotation, velocity, health) else Logger.warn(Logger.channels.network, ("Received entityData for self.nuid = %s! data = %s") - :format(data.nuid, util.pformat(data))) + :format(data.nuid, Utils.pformat(data))) end -- sendAck(data.networkMessageId) do not send ACK for position data, network will explode @@ -592,7 +592,7 @@ function Client.new(sockClient) local deadNuids = data.deadNuids or data or {} for i = 1, #deadNuids do local deadNuid = deadNuids[i] - if util.IsEmpty(deadNuid) or deadNuid == "nil" then + if Utils.IsEmpty(deadNuid) or deadNuid == "nil" then error(("onDeadNuids deadNuid is empty: %s"):format(deadNuid), 2) else EntityUtils.destroyByNuid(self, deadNuid) @@ -667,7 +667,7 @@ function Client.new(sockClient) -- self:on( -- "entityAlive", -- function(data) - -- logger:debug(util.pformat(data)) + -- logger:debug(Utils.pformat(data)) -- em:DespawnEntity(data.owner, data.localEntityId, data.nuid, data.isAlive) -- end @@ -676,7 +676,7 @@ function Client.new(sockClient) -- self:on( -- "entityState", -- function(data) - -- logger:debug(util.pformat(data)) + -- logger:debug(Utils.pformat(data)) -- local nc = em:GetNetworkComponent(data.owner, data.localEntityId, data.nuid) -- if nc then @@ -893,7 +893,7 @@ function Client.new(sockClient) if NetworkUtils.alreadySent(self, event, data) then Logger.debug(Logger.channels.network, ("Network message for %s for data %s already was acknowledged.") - :format(event, util.pformat(data))) + :format(event, Utils.pformat(data))) CustomProfiler.stop("Client.send", cpc19) return false end @@ -934,7 +934,7 @@ function Client.new(sockClient) } if isTestLuaContext then - print(("Sending need nuid for entity %s with data %s"):format(entityId, util.pformat(data))) + print(("Sending need nuid for entity %s with data %s"):format(entityId, Utils.pformat(data))) end self:send(NetworkUtils.events.needNuid.name, data) @@ -961,7 +961,7 @@ function Client.new(sockClient) NetworkUtils.getNextNetworkMessageId(), { compOwnerName, compOwnerGuid }, compNuid, x, y, rotation, velocity, health } - if util.IsEmpty(compNuid) then + if Utils.IsEmpty(compNuid) then -- this can happen, when entity spawned on client and network is slow Logger.debug(Logger.channels.network, "Unable to send entity data, because nuid is empty.") self.sendNeedNuid(compOwnerName, compOwnerGuid, entityId) diff --git a/mods/noita-mp/files/scripts/net/Server.lua b/mods/noita-mp/files/scripts/net/Server.lua index b4c5cb960..c54dd03e9 100644 --- a/mods/noita-mp/files/scripts/net/Server.lua +++ b/mods/noita-mp/files/scripts/net/Server.lua @@ -7,7 +7,7 @@ --- 'Imports' ---------------------------------------- local sock = require("sock") -local util = require("util") +local Utils = require("Utils") local fu = require("FileUtils") local zstandard = require("zstd") local messagePack = require("MessagePack") @@ -143,7 +143,7 @@ function Server.new(sockServer) end local data = { networkMessageId, event, NetworkUtils.events.acknowledgement.ack, os.clock() } self:sendToPeer(peer, NetworkUtils.events.acknowledgement.name, data) - Logger.debug(Logger.channels.network, ("Sent ack with data = %s"):format(util.pformat(data))) + Logger.debug(Logger.channels.network, ("Sent ack with data = %s"):format(Utils.pformat(data))) CustomProfiler.stop("Server.sendAck", cpc02) end @@ -152,9 +152,9 @@ function Server.new(sockServer) ------------------------------------------------------------------------------------------------ local function onAcknowledgement(data, peer) local cpc03 = CustomProfiler.start("Server.onAcknowledgement") - Logger.debug(Logger.channels.network, "onAcknowledgement: Acknowledgement received.", util.pformat(data)) + Logger.debug(Logger.channels.network, "onAcknowledgement: Acknowledgement received.", Utils.pformat(data)) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onAcknowledgement data.networkMessageId is empty: %s"):format(data.networkMessageId), 2) end @@ -163,15 +163,15 @@ function Server.new(sockServer) :format(networkMessageId, data, peer), 2) end - if util.IsEmpty(data.event) then + if Utils.IsEmpty(data.event) then error(("onAcknowledgement data.event is empty: %s"):format(data.event), 2) end - if util.IsEmpty(data.status) then + if Utils.IsEmpty(data.status) then error(("onAcknowledgement data.status is empty: %s"):format(data.status), 2) end - if util.IsEmpty(data.ackedAt) then + if Utils.IsEmpty(data.ackedAt) then error(("onAcknowledgement data.ackedAt is empty: %s"):format(data.ackedAt), 2) end @@ -199,13 +199,13 @@ function Server.new(sockServer) local function onConnect(data, peer) local cpc04 = CustomProfiler.start("Server.onConnect") Logger.debug(Logger.channels.network, ("Peer %s connected! data = %s") - :format(util.pformat(peer), util.pformat(data))) + :format(Utils.pformat(peer), Utils.pformat(data))) - if util.IsEmpty(peer) then + if Utils.IsEmpty(peer) then error(("onConnect peer is empty: %s"):format(peer), 3) end - if util.IsEmpty(data) then + if Utils.IsEmpty(data) then error(("onConnect data is empty: %s"):format(data), 3) end @@ -251,17 +251,17 @@ function Server.new(sockServer) --- @param peer table local function onDisconnect(data, peer) local cpc05 = CustomProfiler.start("Server.onDisconnect") - Logger.debug(Logger.channels.network, "Disconnected from server!", util.pformat(data)) + Logger.debug(Logger.channels.network, "Disconnected from server!", Utils.pformat(data)) - if util.IsEmpty(peer) then + if Utils.IsEmpty(peer) then error(("onConnect peer is empty: %s"):format(peer), 3) end - if util.IsEmpty(data) then + if Utils.IsEmpty(data) then error(("onDisconnect data is empty: %s"):format(data), 3) end - Logger.debug(Logger.channels.network, "Disconnected from server!", util.pformat(data)) + Logger.debug(Logger.channels.network, "Disconnected from server!", Utils.pformat(data)) -- Let the other clients know, that one client disconnected self:sendToAllBut(peer, NetworkUtils.events.disconnect2.name, { NetworkUtils.getNextNetworkMessageId(), peer.name, peer.guid, peer.nuid }) @@ -286,29 +286,29 @@ function Server.new(sockServer) --- @param data table data { networkMessageId, name, guid } local function onPlayerInfo(data, peer) local cpc06 = CustomProfiler.start("Server.onPlayerInfo") - Logger.debug(Logger.channels.network, "onPlayerInfo: Player info received.", util.pformat(data)) + Logger.debug(Logger.channels.network, "onPlayerInfo: Player info received.", Utils.pformat(data)) - if util.IsEmpty(peer) then + if Utils.IsEmpty(peer) then error(("onConnect peer is empty: %s"):format(peer), 3) end - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onPlayerInfo data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.name) then + if Utils.IsEmpty(data.name) then error(("onPlayerInfo data.name is empty: %s"):format(data.name), 3) end - if util.IsEmpty(data.guid) then + if Utils.IsEmpty(data.guid) then error(("onPlayerInfo data.guid is empty: %s"):format(data.guid), 3) end - --if util.IsEmpty(data.nuid) then + --if Utils.IsEmpty(data.nuid) then -- error(("onPlayerInfo data.nuid is empty: %s"):format(data.nuid), 3) --end - if util.IsEmpty(data.version) then + if Utils.IsEmpty(data.version) then error(("onPlayerInfo data.version is empty: %s"):format(data.version), 3) end @@ -349,49 +349,49 @@ function Server.new(sockServer) local function onNeedNuid(data, peer) local cpc07 = CustomProfiler.start("Server.onNeedNuid") Logger.debug(Logger.channels.network, ("Peer %s needs a new nuid. data = %s") - :format(util.pformat(peer), util.pformat(data))) + :format(Utils.pformat(peer), Utils.pformat(data))) - if util.IsEmpty(peer) then - error(("onNeedNuid peer is empty: %s"):format(util.pformat(peer)), 3) + if Utils.IsEmpty(peer) then + error(("onNeedNuid peer is empty: %s"):format(Utils.pformat(peer)), 3) end - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onNewNuid data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.owner) then - error(("onNewNuid data.owner is empty: %s"):format(util.pformat(data.owner)), 3) + if Utils.IsEmpty(data.owner) then + error(("onNewNuid data.owner is empty: %s"):format(Utils.pformat(data.owner)), 3) end - if util.IsEmpty(data.localEntityId) then + if Utils.IsEmpty(data.localEntityId) then error(("onNewNuid data.localEntityId is empty: %s"):format(data.localEntityId), 3) end - if util.IsEmpty(data.x) then + if Utils.IsEmpty(data.x) then error(("onNewNuid data.x is empty: %s"):format(data.x), 3) end - if util.IsEmpty(data.y) then + if Utils.IsEmpty(data.y) then error(("onNewNuid data.y is empty: %s"):format(data.y), 3) end - if util.IsEmpty(data.rotation) then + if Utils.IsEmpty(data.rotation) then error(("onNewNuid data.rotation is empty: %s"):format(data.rotation), 3) end - if util.IsEmpty(data.velocity) then - error(("onNewNuid data.velocity is empty: %s"):format(util.pformat(data.velocity)), 3) + if Utils.IsEmpty(data.velocity) then + error(("onNewNuid data.velocity is empty: %s"):format(Utils.pformat(data.velocity)), 3) end - if util.IsEmpty(data.filename) then + if Utils.IsEmpty(data.filename) then error(("onNewNuid data.filename is empty: %s"):format(data.filename), 3) end - if util.IsEmpty(data.health) then + if Utils.IsEmpty(data.health) then error(("onNewNuid data.health is empty: %s"):format(data.health), 3) end - if util.IsEmpty(data.isPolymorphed) then + if Utils.IsEmpty(data.isPolymorphed) then error(("onNewNuid data.isPolymorphed is empty: %s"):format(data.isPolymorphed), 3) end @@ -420,18 +420,18 @@ function Server.new(sockServer) local function onLostNuid(data, peer) local cpc08 = CustomProfiler.start("Server.onLostNuid") Logger.debug(Logger.channels.network, ("Peer %s lost a nuid and ask for the entity to spawn. data = %s") - :format(util.pformat(peer), util.pformat(data))) + :format(Utils.pformat(peer), Utils.pformat(data))) - if util.IsEmpty(peer) then - error(("onLostNuid peer is empty: %s"):format(util.pformat(peer)), 3) + if Utils.IsEmpty(peer) then + error(("onLostNuid peer is empty: %s"):format(Utils.pformat(peer)), 3) end - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onLostNuid data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.nuid) then - error(("onLostNuid data.nuid is empty: %s"):format(util.pformat(data.nuid)), 3) + if Utils.IsEmpty(data.nuid) then + error(("onLostNuid data.nuid is empty: %s"):format(Utils.pformat(data.nuid)), 3) end local nuid, entityId = GlobalsUtils.getNuidEntityPair(data.nuid) @@ -459,41 +459,41 @@ function Server.new(sockServer) local function onEntityData(data, peer) local cpc09 = CustomProfiler.start("Server.onEntityData") Logger.debug(Logger.channels.network, ("Received entityData for nuid = %s! data = %s") - :format(data.nuid, util.pformat(data))) + :format(data.nuid, Utils.pformat(data))) - if util.IsEmpty(data.networkMessageId) then + if Utils.IsEmpty(data.networkMessageId) then error(("onNewNuid data.networkMessageId is empty: %s"):format(data.networkMessageId), 3) end - if util.IsEmpty(data.owner) then - error(("onNewNuid data.owner is empty: %s"):format(util.pformat(data.owner)), 3) + if Utils.IsEmpty(data.owner) then + error(("onNewNuid data.owner is empty: %s"):format(Utils.pformat(data.owner)), 3) end - --if util.IsEmpty(data.localEntityId) then + --if Utils.IsEmpty(data.localEntityId) then -- error(("onNewNuid data.localEntityId is empty: %s"):format(data.localEntityId), 3) --end - if util.IsEmpty(data.nuid) then + if Utils.IsEmpty(data.nuid) then error(("onNewNuid data.nuid is empty: %s"):format(data.nuid), 3) end - if util.IsEmpty(data.x) then + if Utils.IsEmpty(data.x) then error(("onNewNuid data.x is empty: %s"):format(data.x), 3) end - if util.IsEmpty(data.y) then + if Utils.IsEmpty(data.y) then error(("onNewNuid data.y is empty: %s"):format(data.y), 3) end - if util.IsEmpty(data.rotation) then + if Utils.IsEmpty(data.rotation) then error(("onNewNuid data.rotation is empty: %s"):format(data.rotation), 3) end - if util.IsEmpty(data.velocity) then - error(("onNewNuid data.velocity is empty: %s"):format(util.pformat(data.velocity)), 3) + if Utils.IsEmpty(data.velocity) then + error(("onNewNuid data.velocity is empty: %s"):format(Utils.pformat(data.velocity)), 3) end - if util.IsEmpty(data.health) then + if Utils.IsEmpty(data.health) then error(("onNewNuid data.health is empty: %s"):format(data.health), 3) end @@ -519,7 +519,7 @@ function Server.new(sockServer) local deadNuids = data.deadNuids or data or {} for i = 1, #deadNuids do local deadNuid = deadNuids[i] - if util.IsEmpty(deadNuid) or deadNuid == "nil" then + if Utils.IsEmpty(deadNuid) or deadNuid == "nil" then error(("onDeadNuids deadNuid is empty: %s"):format(deadNuid), 2) else if peer then @@ -631,7 +631,7 @@ function Server.new(sockServer) -- Called when someone connects to the server -- self:on("connect", function(data, peer) - -- logger:debug(logger.channels.network, "Someone connected to the server:", util.pformat(data)) + -- logger:debug(logger.channels.network, "Someone connected to the server:", Utils.pformat(data)) -- local local_player_id = MinaUtils.getLocalMinaEntityId() -- local x, y, rot, scale_x, scale_y = EntityGetTransform(local_player_id) @@ -644,8 +644,8 @@ function Server.new(sockServer) -- self:on( -- "clientInfo", -- function(data, peer) - -- logger:debug(logger.channels.network, "on_clientInfo: data =", util.pformat(data)) - -- logger:debug(logger.channels.network, "on_clientInfo: peer =", util.pformat(peer)) + -- logger:debug(logger.channels.network, "on_clientInfo: data =", Utils.pformat(data)) + -- logger:debug(logger.channels.network, "on_clientInfo: peer =", Utils.pformat(peer)) -- setClientInfo(data, peer) -- end -- ) @@ -653,8 +653,8 @@ function Server.new(sockServer) -- self:on( -- "worldFilesFinished", -- function(data, peer) - -- logger:debug(logger.channels.network, "on_worldFilesFinished: data =", util.pformat(data)) - -- logger:debug(logger.channels.network, "on_worldFilesFinished: peer =", util.pformat(peer)) + -- logger:debug(logger.channels.network, "on_worldFilesFinished: data =", Utils.pformat(data)) + -- logger:debug(logger.channels.network, "on_worldFilesFinished: peer =", Utils.pformat(peer)) -- -- Send restart command -- peer:send("restart", { "Restart now!" }) -- end @@ -664,7 +664,7 @@ function Server.new(sockServer) -- self:on( -- "disconnect", -- function(data) - -- logger:debug(logger.channels.network, "on_disconnect: data =", util.pformat(data)) + -- logger:debug(logger.channels.network, "on_disconnect: data =", Utils.pformat(data)) -- end -- ) @@ -672,16 +672,16 @@ function Server.new(sockServer) -- self:on( -- "receive", -- function(data, channel, client) - -- logger:debug(logger.channels.network, "on_receive: data =", util.pformat(data)) - -- logger:debug(logger.channels.network, "on_receive: channel =", util.pformat(channel)) - -- logger:debug(logger.channels.network, "on_receive: client =", util.pformat(client)) + -- logger:debug(logger.channels.network, "on_receive: data =", Utils.pformat(data)) + -- logger:debug(logger.channels.network, "on_receive: channel =", Utils.pformat(channel)) + -- logger:debug(logger.channels.network, "on_receive: client =", Utils.pformat(client)) -- end -- ) -- self:on( -- "needNuid", -- function(data) - -- logger:debug(logger.channels.network, "%s (%s) needs a new nuid.", data.owner.name, data.owner.guid, util.pformat(data)) + -- logger:debug(logger.channels.network, "%s (%s) needs a new nuid.", data.owner.name, data.owner.guid, Utils.pformat(data)) -- local new_nuid = NuidUtils.getNextNuid() -- -- tell the clients that there is a new entity, they have to spawn, besides the client, who sent the request @@ -694,7 +694,7 @@ function Server.new(sockServer) -- self:on( -- "newNuid", -- function(data) - -- logger:debug(logger.channels.network, util.pformat(data)) + -- logger:debug(logger.channels.network, Utils.pformat(data)) -- if self.guid == data.owner.guid then -- logger:debug(logger.channels.network, @@ -711,7 +711,7 @@ function Server.new(sockServer) -- self:on( -- "entityAlive", -- function(data) - -- logger:debug(logger.channels.network, util.pformat(data)) + -- logger:debug(logger.channels.network, Utils.pformat(data)) -- self:sendToAll2("entityAlive", data) -- em:DespawnEntity(data.owner, data.localEntityId, data.nuid, data.isAlive) @@ -721,7 +721,7 @@ function Server.new(sockServer) -- self:on( -- "entityState", -- function(data) - -- logger:debug(logger.channels.network, util.pformat(data)) + -- logger:debug(logger.channels.network, Utils.pformat(data)) -- local nc = em:GetNetworkComponent(data.owner, data.localEntityId, data.nuid) -- if nc then @@ -842,7 +842,7 @@ function Server.new(sockServer) if NetworkUtils.alreadySent(peer, event, data) then Logger.debug(Logger.channels.network, ("Network message for %s for data %s already was acknowledged.") - :format(event, util.pformat(data))) + :format(event, Utils.pformat(data))) CustomProfiler.stop("Server.send", cpc022) return false end @@ -862,14 +862,14 @@ function Server.new(sockServer) function self:sendToAll(event, data) local cpc023 = CustomProfiler.start("Server.sendToAll") local sent = false - if util.IsEmpty(self.clients) then + if Utils.IsEmpty(self.clients) then Logger.trace(Logger.channels.testing, - ("Unable to send anything, when there are no clients %s!"):format(util.pformat(self.clients))) + ("Unable to send anything, when there are no clients %s!"):format(Utils.pformat(self.clients))) return sent end for i = 1, #self.clients do Logger.trace(Logger.channels.testing, - ("Sending event '%s' with data '%s' to client.name '%s'!"):format(event, util.pformat(data), + ("Sending event '%s' with data '%s' to client.name '%s'!"):format(event, Utils.pformat(data), self.clients[i].name)) sent = self:send(self.clients[i], event, data) end @@ -1026,7 +1026,7 @@ function Server.new(sockServer) NetworkUtils.getNextNetworkMessageId(), { compOwnerName, compOwnerGuid }, compNuid, x, y, rotation, velocity, health } - if util.IsEmpty(compNuid) then + if Utils.IsEmpty(compNuid) then ---- nuid must not be empty, when Server! --logger:error(logger.channels.network, "Unable to send entity data, because nuid is empty.") --return diff --git a/mods/noita-mp/files/scripts/util/CustomProfiler.lua b/mods/noita-mp/files/scripts/util/CustomProfiler.lua index 3de172152..68c6c3e98 100644 --- a/mods/noita-mp/files/scripts/util/CustomProfiler.lua +++ b/mods/noita-mp/files/scripts/util/CustomProfiler.lua @@ -9,7 +9,7 @@ local json = require("dkjson") local plotly = require("plotly") -local util = require("util") +local Utils = require("Utils") local fu = require("file_util") ---@class CustomProfiler @@ -83,7 +83,7 @@ function CustomProfiler.stop(functionName, customProfilerCounter) return 0 end - if util.IsEmpty(CustomProfiler.reportCache) then + if Utils.IsEmpty(CustomProfiler.reportCache) then return end diff --git a/mods/noita-mp/files/scripts/util/EntityUtils.lua b/mods/noita-mp/files/scripts/util/EntityUtils.lua index b4e50ed9b..a17048041 100644 --- a/mods/noita-mp/files/scripts/util/EntityUtils.lua +++ b/mods/noita-mp/files/scripts/util/EntityUtils.lua @@ -14,11 +14,11 @@ dofile("mods/noita-mp/config.lua") --- This is done by the following code: ------------------------------------------------------------------------------------------------------------------------ if require then - util = require("util") + Utils = require("Utils") else -- Fix stupid Noita sandbox issue. Noita Components does not have access to require. - if not util then - util = dofile("mods/noita-mp/files/scripts/util/util.lua") + if not Utils then + Utils = dofile("mods/noita-mp/files/scripts/util/Utils.lua") end if not EntityCache then @@ -198,7 +198,7 @@ function EntityUtils.isRemoteMinae(entityId) local client = clients[i] local clientsNuid = client.nuid local nuidRemote, entityIdRemote = GlobalsUtils.getNuidEntityPair(clientsNuid) - if not util.IsEmpty(entityIdRemote) and entityIdRemote == entityId then + if not Utils.IsEmpty(entityIdRemote) and entityIdRemote == entityId then CustomProfiler.stop("EntityUtils.isRemoteMinae", cpc) return true end @@ -213,7 +213,7 @@ function EntityUtils.isRemoteMinae(entityId) local client = Client.otherClients[i] local clientsNuid = client.nuid local nuidRemote, entityIdRemote = GlobalsUtils.getNuidEntityPair(clientsNuid) - if not util.IsEmpty(entityIdRemote) and entityIdRemote == entityId then + if not Utils.IsEmpty(entityIdRemote) and entityIdRemote == entityId then CustomProfiler.stop("EntityUtils.isRemoteMinae", cpc) return true end @@ -260,7 +260,7 @@ function EntityUtils.processAndSyncEntityNetworking() otherwise nuid isn't set when extracting parents. ]]-- for i = 1, #entityIds do local childEntityIds = EntityGetAllChildren(entityIds[i]) - if not util.IsEmpty(childEntityIds) then + if not Utils.IsEmpty(childEntityIds) then table.insertAllButNotDuplicates(entityIds, childEntityIds) end end @@ -536,11 +536,11 @@ function EntityUtils.destroyByNuid(peer, nuid) local cpc = CustomProfiler.start("EntityUtils.destroyByNuid") if not peer or type(peer) ~= "table" then - error(("EntityUtils.destroyByNuid: peer is not a table: %s"):format(util.pformat(peer)), 2) + error(("EntityUtils.destroyByNuid: peer is not a table: %s"):format(Utils.pformat(peer)), 2) end if not nuid then - error(("EntityUtils.destroyByNuid: nuid must not be nil: %s"):format(util.pformat(nuid)), 2) + error(("EntityUtils.destroyByNuid: nuid must not be nil: %s"):format(Utils.pformat(nuid)), 2) end if type(nuid) ~= "number" then diff --git a/mods/noita-mp/files/scripts/util/FileUtils.lua b/mods/noita-mp/files/scripts/util/FileUtils.lua index f254db660..fa72050d5 100644 --- a/mods/noita-mp/files/scripts/util/FileUtils.lua +++ b/mods/noita-mp/files/scripts/util/FileUtils.lua @@ -4,14 +4,14 @@ local ffi = require("ffi") local watcher = require("watcher") local lfs = require("lfs") local json = require("json") -local util = require("util") +local Utils = require("Utils") --- @return string function FileUtils.GetVersionByFile() local modsPath = FileUtils.GetAbsoluteDirectoryPathOfNoitaMP() local versionAbsFilePath = ("%s%s.version"):format(modsPath, pathSeparator) local content = FileUtils.ReadFile(versionAbsFilePath, "*l") - if not content or util.IsEmpty(content) then + if not content or Utils.IsEmpty(content) then error(("Unable to read NoitaMP version. Check if '%s' exists!") :format(FileUtils.GetAbsolutePathOfNoitaRootDirectory() + "/.version"), 2) end @@ -103,7 +103,7 @@ function FileUtils.SetAbsolutePathOfNoitaRootDirectory() noitaRootDirectory = assert(io.popen("pwd"):read("*l"), "Unable to run ubuntu command 'pwd' to get Noitas root directory!") else - error(("file_util.lua | Unable to detect OS(%s[%s]), therefore not able to replace path separator!") + error(("FileUtils.lua | Unable to detect OS(%s[%s]), therefore not able to replace path separator!") :format(_G.os_name, _G.os_arch), 2) end noitaRootDirectory = FileUtils.ReplacePathSeparator(noitaRootDirectory) @@ -160,7 +160,7 @@ function FileUtils.GetAbsoluteDirectoryPathOfParentSave() local line = "" while line ~= nil do line = file:read("*l") - --logger:debug("file_util.lua | GetAbsoluteDirectoryPathOfParentSave line = " .. line) + --logger:debug("FileUtils.lua | GetAbsoluteDirectoryPathOfParentSave line = " .. line) if string.find(line, find_directory_name) then save06_parent_directory_path = line break @@ -280,10 +280,10 @@ end function FileUtils.IsFile(full_path) -- https://stackoverflow.com/a/21637809/3493998 if type(full_path) ~= "string" then - error("file_util.lua | Parameter full_path '" .. tostring(full_path) .. "' is not type of string!") + error("FileUtils.lua | Parameter full_path '" .. tostring(full_path) .. "' is not type of string!") end if not FileUtils.Exists(full_path) then - --logger:debug("file_util.lua | Path '" .. tostring(full_path) .. "' does not exist!") + --logger:debug("FileUtils.lua | Path '" .. tostring(full_path) .. "' does not exist!") return false end local f = io.open(full_path) @@ -299,12 +299,12 @@ end function FileUtils.IsDirectory(full_path) -- https://stackoverflow.com/a/21637809/3493998 if type(full_path) ~= "string" then - error("file_util.lua | Parameter full_path '" .. tostring(full_path) .. "' is not type of string!") + error("FileUtils.lua | Parameter full_path '" .. tostring(full_path) .. "' is not type of string!") end local exists = FileUtils.Exists(full_path) - --logger:debug("file_util.lua | Directory " .. full_path .. " exists = " .. tostring(exists)) + --logger:debug("FileUtils.lua | Directory " .. full_path .. " exists = " .. tostring(exists)) local is_file = FileUtils.IsFile(full_path) - --logger:debug("file_util.lua | Is the directory a file? " .. full_path .. " is_file = " .. tostring(is_file)) + --logger:debug("FileUtils.lua | Is the directory a file? " .. full_path .. " is_file = " .. tostring(is_file)) return (exists and not is_file) end @@ -312,7 +312,7 @@ end --- @return string|number function FileUtils.ReadBinaryFile(file_fullpath) if type(file_fullpath) ~= "string" then - error("file_util.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") + error("FileUtils.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") end file_fullpath = FileUtils.ReplacePathSeparator(file_fullpath) -- https://stackoverflow.com/a/31857671/3493998 @@ -329,7 +329,7 @@ end --- @param file_content any function FileUtils.WriteBinaryFile(file_fullpath, file_content) if type(file_fullpath) ~= "string" then - error("file_util.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") + error("FileUtils.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") end file_fullpath = FileUtils.ReplacePathSeparator(file_fullpath) -- http://lua-users.org/wiki/FileInputOutput @@ -347,7 +347,7 @@ function FileUtils.ReadFile(file_fullpath, mode) end if type(file_fullpath) ~= "string" then - error("file_util.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") + error("FileUtils.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") end file_fullpath = FileUtils.ReplacePathSeparator(file_fullpath) -- https://stackoverflow.com/a/31857671/3493998 @@ -364,7 +364,7 @@ end ---@param file_content string function FileUtils.WriteFile(file_fullpath, file_content) if type(file_fullpath) ~= "string" then - error("file_util.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") + error("FileUtils.lua | Parameter file_fullpath '" .. tostring(file_fullpath) .. "' is not type of string!") end file_fullpath = FileUtils.ReplacePathSeparator(file_fullpath) @@ -392,7 +392,7 @@ end --- @param full_path string function FileUtils.MkDir(full_path) if type(full_path) ~= "string" then - error("file_util.lua | Parameter file_fullpath '" .. tostring(full_path) .. "' is not type of string!") + error("FileUtils.lua | Parameter file_fullpath '" .. tostring(full_path) .. "' is not type of string!") end -- https://stackoverflow.com/a/1690932/3493998 full_path = FileUtils.ReplacePathSeparator(full_path) @@ -479,7 +479,7 @@ function FileUtils.Find7zipExecutable() end local response = f:read("*a") _G.seven_zip = tostring(FileUtils.ReplacePathSeparator(response)) - Logger.debug(Logger.channels.testing, "file_util.lua | Found 7z.exe: " .. _G.seven_zip) + Logger.debug(Logger.channels.testing, "FileUtils.lua | Found 7z.exe: " .. _G.seven_zip) else error( "Unfortunately unix systems aren't supported yet. Please consider https://github.com/Ismoh/NoitaMP/issues!", @@ -508,17 +508,17 @@ function FileUtils.Create7zipArchive(archive_name, absolute_directory_path_to_ad ) if type(archive_name) ~= "string" then - error("file_util.lua | Parameter archive_name '" .. tostring(archive_name) .. "' is not type of string!") + error("FileUtils.lua | Parameter archive_name '" .. tostring(archive_name) .. "' is not type of string!") end if type(absolute_directory_path_to_add_archive) ~= "string" then error( - "file_util.lua | Parameter absolute_directory_path_to_add_archive '" .. + "FileUtils.lua | Parameter absolute_directory_path_to_add_archive '" .. tostring(absolute_directory_path_to_add_archive) .. "' is not type of string!" ) end if type(absolute_destination_path) ~= "string" then error( - "file_util.lua | Parameter absolute_destination_path '" .. + "FileUtils.lua | Parameter absolute_destination_path '" .. tostring(absolute_destination_path) .. "' is not type of string!" ) end @@ -529,7 +529,7 @@ function FileUtils.Create7zipArchive(archive_name, absolute_directory_path_to_ad local command = 'cd "' .. absolute_destination_path .. '" && 7z.exe a -t7z ' .. archive_name .. ' "' .. absolute_directory_path_to_add_archive .. '"' - Logger.debug(Logger.channels.testing, "file_util.lua | Running: " .. command) + Logger.debug(Logger.channels.testing, "FileUtils.lua | Running: " .. command) os.execute(command) local archive_full_path = absolute_destination_path .. _G.pathSeparator .. archive_name .. ".7z" @@ -546,7 +546,7 @@ function FileUtils.Extract7zipArchive(archive_absolute_directory_path, archive_n local command = 'cd "' .. archive_absolute_directory_path .. '" && 7z.exe x -aoa ' .. archive_name .. ' -o"' .. extract_absolute_directory_path .. '"' - Logger.debug(Logger.channels.testing, "file_util.lua | Running: " .. command) + Logger.debug(Logger.channels.testing, "FileUtils.lua | Running: " .. command) os.execute(command) end diff --git a/mods/noita-mp/files/scripts/util/GuidUtils.lua b/mods/noita-mp/files/scripts/util/GuidUtils.lua index f6767100b..07093fbc2 100644 --- a/mods/noita-mp/files/scripts/util/GuidUtils.lua +++ b/mods/noita-mp/files/scripts/util/GuidUtils.lua @@ -1,4 +1,4 @@ -local util = require("util") +local Utils = require("Utils") local socket = require("socket") local uuid = require("uuid") @@ -51,7 +51,7 @@ end --- @return string guid function GuidUtils:getGuid(inUsedGuids) local cpc = CustomProfiler.start("GuidUtils:getGuid") - if not util.IsEmpty(inUsedGuids) and #inUsedGuids > 0 then + if not Utils.IsEmpty(inUsedGuids) and #inUsedGuids > 0 then for i = 1, #inUsedGuids do if not GuidUtils.isPatternValid(inUsedGuids[i]) then error(("Already in used guid '%s' is not a valid guid!"):format(inUsedGuids[i]), 2) @@ -60,7 +60,7 @@ function GuidUtils:getGuid(inUsedGuids) ---@cast inUsedGuids table table.insertAllButNotDuplicates(self.cached_guid, inUsedGuids) - Logger.debug(Logger.channels.guid, ("Guid:getGuid() - inUsedGuids: %s"):format(util.pformat(inUsedGuids))) + Logger.debug(Logger.channels.guid, ("Guid:getGuid() - inUsedGuids: %s"):format(Utils.pformat(inUsedGuids))) end repeat @@ -81,7 +81,7 @@ function GuidUtils.isPatternValid(guid) if type(guid) ~= "string" then return false end - if util.IsEmpty(guid) then + if Utils.IsEmpty(guid) then return false end diff --git a/mods/noita-mp/files/scripts/util/NetworkCacheUtils.lua b/mods/noita-mp/files/scripts/util/NetworkCacheUtils.lua index 44a600a01..5bce4fe0a 100644 --- a/mods/noita-mp/files/scripts/util/NetworkCacheUtils.lua +++ b/mods/noita-mp/files/scripts/util/NetworkCacheUtils.lua @@ -10,7 +10,7 @@ ------------------------------------------------------------------------------------------------------------------------ --- 'Imports' ------------------------------------------------------------------------------------------------------------------------ -local util = require("util") +local Utils = require("Utils") local md5 = require("md5") ------------------------------------------------------------------------------------------------------------------------ @@ -20,11 +20,11 @@ NetworkCacheUtils = {} function NetworkCacheUtils.getSum(event, data) local cpc = CustomProfiler.start("NetworkCacheUtils.getSum") - Logger.trace(Logger.channels.testing, "getSum: " .. util.pformat(data)) - if not event or util.IsEmpty(event) or type(event) ~= "string" then + Logger.trace(Logger.channels.testing, "getSum: " .. Utils.pformat(data)) + if not event or Utils.IsEmpty(event) or type(event) ~= "string" then error(("Unable to calculate sum, when event is nil or not a string: '%s'"):format(event), 2) end - if not data or util.IsEmpty(data) or type(data) ~= "table" then + if not data or Utils.IsEmpty(data) or type(data) ~= "table" then error(("Unable to calculate sum, when data is nil or not a table: '%s'"):format(data), 2) end @@ -32,15 +32,15 @@ function NetworkCacheUtils.getSum(event, data) error(("Event '%s' shouldn't be cached!"):format(event), 2) end - Logger.trace(Logger.channels.testing, "data: " .. util.pformat(data)) + Logger.trace(Logger.channels.testing, "data: " .. Utils.pformat(data)) local dataCopy = NetworkUtils.getClientOrServer().zipTable(data, NetworkUtils.events[event].schema, event) - Logger.trace(Logger.channels.testing, "dataCopy zipped: " .. util.pformat(dataCopy)) + Logger.trace(Logger.channels.testing, "dataCopy zipped: " .. Utils.pformat(dataCopy)) if event ~= NetworkUtils.events.acknowledgement.name then -- when event is NOT acknowledgement, remove networkMessageId, -- but we need the networkMessageId to find the previous cached network message, when the event is acknowledgement dataCopy.networkMessageId = nil end - Logger.trace(Logger.channels.testing, "dataCopy without networkMessageId: " .. util.pformat(dataCopy)) + Logger.trace(Logger.channels.testing, "dataCopy without networkMessageId: " .. Utils.pformat(dataCopy)) local sum = "" if NetworkUtils.events[event].resendIdentifiers ~= nil then local newData = {} @@ -55,7 +55,7 @@ function NetworkCacheUtils.getSum(event, data) else sum = table.contentToString(dataCopy) end - Logger.trace(Logger.channels.testing, ("sum from %s = %s"):format(util.pformat(dataCopy), sum)) + Logger.trace(Logger.channels.testing, ("sum from %s = %s"):format(Utils.pformat(dataCopy), sum)) CustomProfiler.stop("NetworkCacheUtils.getSum", cpc) return sum end @@ -66,26 +66,26 @@ end --- function NetworkCacheUtils.set(peerGuid, networkMessageId, event, status, ackedAt, sendAt, data) local cpc = CustomProfiler.start("NetworkCacheUtils.set") - if not peerGuid or util.IsEmpty(peerGuid) or type(peerGuid) ~= "string" then + if not peerGuid or Utils.IsEmpty(peerGuid) or type(peerGuid) ~= "string" then error(("peerGuid '%s' must not be nil or empty or isn't type of string!"):format(peerGuid), 2) end - if not networkMessageId or util.IsEmpty(networkMessageId) or type(networkMessageId) ~= "number" then + if not networkMessageId or Utils.IsEmpty(networkMessageId) or type(networkMessageId) ~= "number" then error(("networkMessageId '%s' must not be nil or empty or isn't type of number!"):format(networkMessageId), 2) end - if not event or util.IsEmpty(event) or type(event) ~= "string" then + if not event or Utils.IsEmpty(event) or type(event) ~= "string" then error(("event '%s' must not be nil or empty or isn't type of string!"):format(event), 2) end - if not status or util.IsEmpty(status) or type(status) ~= "string" then + if not status or Utils.IsEmpty(status) or type(status) ~= "string" then error(("status '%s' must not be nil or empty or isn't type of string!"):format(status), 2) end - if not ackedAt or util.IsEmpty(ackedAt) or type(ackedAt) ~= "number" then + if not ackedAt or Utils.IsEmpty(ackedAt) or type(ackedAt) ~= "number" then error(("ackedAt '%s' must not be nil or empty or isn't type of number!"):format(ackedAt), 2) end - if not sendAt or util.IsEmpty(sendAt) or type(sendAt) ~= "number" then + if not sendAt or Utils.IsEmpty(sendAt) or type(sendAt) ~= "number" then error(("sendAt '%s' must not be nil or empty or isn't type of number!"):format(sendAt), 2) end - if not data or util.IsEmpty(data) or type(data) ~= "table" then - error(("data '%s' must not be nil or empty or isn't type of table!"):format(util.pformat(data)), 2) + if not data or Utils.IsEmpty(data) or type(data) ~= "table" then + error(("data '%s' must not be nil or empty or isn't type of table!"):format(Utils.pformat(data)), 2) end if not NetworkUtils.events[event].isCacheable then @@ -111,13 +111,13 @@ end --- @return table data { ackedAt, dataChecksum, event, messageId, sentAt, status} function NetworkCacheUtils.get(peerGuid, networkMessageId, event) local cpc = CustomProfiler.start("NetworkCacheUtils.get") - if not peerGuid or util.IsEmpty(peerGuid) or type(peerGuid) ~= "string" then + if not peerGuid or Utils.IsEmpty(peerGuid) or type(peerGuid) ~= "string" then error(("peerGuid '%s' must not be nil or empty or isn't type of string!"):format(peerGuid), 2) end - if not networkMessageId or util.IsEmpty(networkMessageId) or type(networkMessageId) ~= "number" then + if not networkMessageId or Utils.IsEmpty(networkMessageId) or type(networkMessageId) ~= "number" then error(("networkMessageId '%s' must not be nil or empty or isn't type of number!"):format(networkMessageId), 2) end - if not event or util.IsEmpty(event) or type(event) ~= "string" then + if not event or Utils.IsEmpty(event) or type(event) ~= "string" then error(("event '%s' must not be nil or empty or isn't type of string!"):format(event), 2) end @@ -138,7 +138,7 @@ function NetworkCacheUtils.get(peerGuid, networkMessageId, event) local data = NetworkCache.get(clientCacheId, event, tonumber(networkMessageId)) Logger.info(Logger.channels.cache, ("Get nCache by clientCacheId %s, event %s, networkMessageId %s, data %s") - :format(clientCacheId, event, networkMessageId, util.pformat(data))) + :format(clientCacheId, event, networkMessageId, Utils.pformat(data))) CustomProfiler.stop("NetworkCacheUtils.get", cpc) return data end @@ -146,14 +146,14 @@ end --- @return table cacheData { ackedAt, dataChecksum, event, messageId, sentAt, status} function NetworkCacheUtils.getByChecksum(peerGuid, event, data) local cpc = CustomProfiler.start("NetworkCacheUtils.getByChecksum") - if not peerGuid or util.IsEmpty(peerGuid) or type(peerGuid) ~= "string" then - error(("peerGuid '%s' must not be nil or empty or isn't type of string!"):format(util.pformat(peerGuid)), 2) + if not peerGuid or Utils.IsEmpty(peerGuid) or type(peerGuid) ~= "string" then + error(("peerGuid '%s' must not be nil or empty or isn't type of string!"):format(Utils.pformat(peerGuid)), 2) end - if not event or util.IsEmpty(event) or type(event) ~= "string" then - error(("event '%s' must not be nil or empty or isn't type of string!"):format(util.pformat(event)), 2) + if not event or Utils.IsEmpty(event) or type(event) ~= "string" then + error(("event '%s' must not be nil or empty or isn't type of string!"):format(Utils.pformat(event)), 2) end - if not data or util.IsEmpty(data) or type(data) ~= "table" then - error(("data '%s' must not be nil or empty or isn't type of table!"):format(util.pformat(data)), 2) + if not data or Utils.IsEmpty(data) or type(data) ~= "table" then + error(("data '%s' must not be nil or empty or isn't type of table!"):format(Utils.pformat(data)), 2) end if not NetworkUtils.events[event].isCacheable then @@ -166,7 +166,7 @@ function NetworkCacheUtils.getByChecksum(peerGuid, event, data) local cacheData = NetworkCache.getChecksum(clientCacheId, dataChecksum) Logger.info(Logger.channels.cache, ("Get nCache by clientCacheId %s, dataChecksum %s, event %s, cacheData %s") - :format(clientCacheId, dataChecksum, event, util.pformat(cacheData))) + :format(clientCacheId, dataChecksum, event, Utils.pformat(cacheData))) CustomProfiler.stop("NetworkCacheUtils.getByChecksum", cpc) return cacheData end diff --git a/mods/noita-mp/files/scripts/util/NetworkUtils.lua b/mods/noita-mp/files/scripts/util/NetworkUtils.lua index 36ab0e59e..98cbe3975 100644 --- a/mods/noita-mp/files/scripts/util/NetworkUtils.lua +++ b/mods/noita-mp/files/scripts/util/NetworkUtils.lua @@ -6,7 +6,7 @@ ------------------------------------------------------------------------------------------------------------------------ --- 'Imports' ------------------------------------------------------------------------------------------------------------------------ -local util = require("util") +local Utils = require("Utils") ------------------------------------------------------------------------------------------------------------------------ --- NetworkUtils @@ -201,7 +201,7 @@ function NetworkUtils.alreadySent(peer, event, data) if not data then error("'data' must not be nil!", 2) end - if util.IsEmpty(peer.clientCacheId) then + if Utils.IsEmpty(peer.clientCacheId) then Logger.info(Logger.channels.testing, ("peer.guid = '%s'"):format(peer.guid)) peer.clientCacheId = GuidUtils.toNumber(peer.guid) --error("peer.clientCacheId must not be nil!", 2) end diff --git a/mods/noita-mp/files/scripts/util/NetworkVscUtils.lua b/mods/noita-mp/files/scripts/util/NetworkVscUtils.lua index 930055a0f..25c9f70d0 100644 --- a/mods/noita-mp/files/scripts/util/NetworkVscUtils.lua +++ b/mods/noita-mp/files/scripts/util/NetworkVscUtils.lua @@ -402,10 +402,10 @@ function NetworkVscUtils.getAllVcsValuesByComponentIds(ownerNameCompId, ownerGui local compOwnerGuid = ComponentGetValue2(ownerGuidCompId, NetworkVscUtils.valueString) local compNuid = ComponentGetValue2(nuidCompId, NetworkVscUtils.valueString) - if util.IsEmpty(compOwnerName) then + if Utils.IsEmpty(compOwnerName) then error(("Something really bad went wrong! compOwnerName must not be empty: %s"):format(compOwnerName), 2) end - if util.IsEmpty(compOwnerGuid) then + if Utils.IsEmpty(compOwnerGuid) then error(("Something really bad went wrong! compOwnerGuid must not be empty: %s"):format(compOwnerGuid), 2) end diff --git a/mods/noita-mp/files/scripts/util/util.lua b/mods/noita-mp/files/scripts/util/Utils.lua similarity index 89% rename from mods/noita-mp/files/scripts/util/util.lua rename to mods/noita-mp/files/scripts/util/Utils.lua index e79ef6fbe..b985826b6 100644 --- a/mods/noita-mp/files/scripts/util/util.lua +++ b/mods/noita-mp/files/scripts/util/Utils.lua @@ -8,11 +8,12 @@ else pprint.defaults = {} end -local util = {} +--- @class Utils +local Utils = {} --- Wait for n seconds. ---@param s number seconds to wait -function util.Sleep(s) +function Utils.Sleep(s) if type(s) ~= "number" then error("Unable to wait if parameter 'seconds' isn't a number: " .. type(s)) end @@ -22,7 +23,7 @@ function util.Sleep(s) until os.clock() > ntime end -function util.IsEmpty(var) +function Utils.IsEmpty(var) -- if you change this also change NetworkVscUtils.lua -- if you change this also change table_extensions.lua if var == nil then @@ -38,14 +39,14 @@ function util.IsEmpty(var) end --https://noita.wiki.gg/wiki/Modding:_Utilities#Easier_entity_debugging -function util.str(var) +function Utils.Str(var) if type(var) == "table" then local s = "{ " for k, v in pairs(var) do if type(k) ~= "number" then k = '"' .. k .. '"' end - s = s .. "[" .. k .. "] = " .. util.str(v) .. "," + s = s .. "[" .. k .. "] = " .. Utils.Str(v) .. "," end return s .. "} " end @@ -53,7 +54,7 @@ function util.str(var) end --https://noita.wiki.gg/wiki/Modding:_Utilities#Easier_entity_debugging -function util.debug_entity(e) +function Utils.DebugEntity(e) local parent = EntityGetParent(e) local children = EntityGetAllChildren(e) local comps = EntityGetAllComponents(e) @@ -61,7 +62,7 @@ function util.debug_entity(e) local msg = "--- ENTITY DATA ---\n" msg = msg .. ("Parent: [" .. parent .. "] name = " .. (EntityGetName(parent) or "") .. "\n") - msg = msg .. (" Entity: [" .. util.str(e) .. "] name = " .. (EntityGetName(e) or "") .. "\n") + msg = msg .. (" Entity: [" .. Utils.Str(e) .. "] name = " .. (EntityGetName(e) or "") .. "\n") msg = msg .. (" Tags: " .. (EntityGetTags(e) or "") .. "\n") if (comps ~= nil) then for _, comp in ipairs(comps) do @@ -97,18 +98,18 @@ function util.debug_entity(e) Logger.debug(Logger.channels.testing, msg) end -function util.pformat(var) +function Utils.pformat(var) return pprint.pformat(var, pprint.defaults) end --- Reloads the whole world with a specific seed. No need to restart the game and use magic numbers. ---@param seed number max = 4294967295 -function util.reloadMap(seed) +function Utils.ReloadMap(seed) SetWorldSeed(seed) BiomeMapLoad_KeepPlayer("mods/noita-mp/files/scripts/DefaultBiomeMap.lua", "data/biome/_pixel_scenes.xml") end -function util.copyToClipboard(copy) +function Utils.CopyToClipboard(copy) local command = nil if _G.is_windows then command = ('echo "%s" | clip'):format(copy) @@ -118,4 +119,4 @@ function util.copyToClipboard(copy) os.execute(command) end -return util +return Utils diff --git a/mods/noita-mp/init.lua b/mods/noita-mp/init.lua index a3bf67b57..7231e0ddd 100644 --- a/mods/noita-mp/init.lua +++ b/mods/noita-mp/init.lua @@ -6,7 +6,7 @@ end --- Imports by dofile, dofile_once and require ---------------------------------------------------------------------------------------------------- dofile("mods/noita-mp/files/scripts/init/init_.lua") -local util = require("util") +local Utils = require("Utils") local fu = require("FileUtils") local ui = require("Ui").new() @@ -36,7 +36,7 @@ local function setSeedIfConnectedSecondTime() Logger.debug(Logger.channels.initialize, ("Servers world seed = %s"):format(seed)) if not seed and seed > 0 then if DebugGetIsDevBuild() then - util.Sleep(5) -- needed to be able to attach debugger again + Utils.Sleep(5) -- needed to be able to attach debugger again end local cpc1 = CustomProfiler.start("ModSettingGet") @@ -141,7 +141,7 @@ function OnWorldPreUpdate() ModSettingSetNextValue("noita-mp.saveSlotMetaDirectory", _G.saveSlotMeta.dir, false) CustomProfiler.stop("ModSettingSetNextValue", cpc1) Logger.info(Logger.channels.initialize, - ("Save slot found in '%s'"):format(util.pformat(_G.saveSlotMeta))) + ("Save slot found in '%s'"):format(Utils.pformat(_G.saveSlotMeta))) end end end diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/sock.lua b/mods/noita-mp/lua_modules/share/lua/5.1/sock.lua index 59d9971bc..dae0658ab 100644 --- a/mods/noita-mp/lua_modules/share/lua/5.1/sock.lua +++ b/mods/noita-mp/lua_modules/share/lua/5.1/sock.lua @@ -33,7 +33,7 @@ local sock = { } local enet = require("enet") -local util = require("util") +local Utils = require("Utils") local fu = require("FileUtils") _G.Logger.info(_G.Logger.channels.initialize, "lua-enet version = master branch 21.10.2015") @@ -71,7 +71,7 @@ local function zipTable(items, keys, event) if not key then error(("Missing data key for event '%s'! items = %s schema = %s") - :format(event, util.pformat(items), util.pformat(keys)), 2) + :format(event, Utils.pformat(items), Utils.pformat(keys)), 2) end data[key] = value @@ -150,7 +150,7 @@ function Logger:log(event, data) local time = os.date("%X") -- something like 24:59:59 local shortLine = ("%s [%s] %s"):format(time, event, data) local fullLine = ("%s [%s %s] %s"):format(time, self.source, event, - util.pformat(data)) --local fullLine = ("[%s][%s][%s] %s"):format(self.source, time, event, data) + Utils.pformat(data)) --local fullLine = ("[%s][%s][%s] %s"):format(self.source, time, event, data) -- The printed message may or may not be the full message local line = fullLine @@ -451,7 +451,7 @@ end function Server:sendToPeer(peer, event, data) local cpc = CustomProfiler.start("Server:sendToPeer") local networkMessageId = data[1] or data.networkMessageId - if util.IsEmpty(networkMessageId) then + if Utils.IsEmpty(networkMessageId) then error("networkMessageId is empty!", 3) end self.packetsSent = self.packetsSent + 1 @@ -967,7 +967,7 @@ end -- @param data The data to send. function Client:send(event, data) local networkMessageId = data[1] or data.networkMessageId - if util.IsEmpty(networkMessageId) then + if Utils.IsEmpty(networkMessageId) then error("networkMessageId is empty!", 3) end diff --git a/mods/noita-mp/tests/_initializeUnitTests.lua b/mods/noita-mp/tests/_initializeUnitTests.lua index 60cae0d40..eab88a68e 100644 --- a/mods/noita-mp/tests/_initializeUnitTests.lua +++ b/mods/noita-mp/tests/_initializeUnitTests.lua @@ -41,14 +41,14 @@ if not ModSettingGet then end if id == "noita-mp.name" then local name = MinaUtils.getLocalMinaName() - if util.IsEmpty(name) then + if Utils.IsEmpty(name) then name = "initializeUnitTests" end return name end if id == "noita-mp.guid" then local guid = MinaUtils.getLocalMinaGuid() - if util.IsEmpty(guid) then + if Utils.IsEmpty(guid) then guid = GuidUtils:getGuid() end return guid diff --git a/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua index 525bc0b9e..73ce5f64a 100644 --- a/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua @@ -22,7 +22,7 @@ if not Client then end local lu = require("luaunit") -local util = require("util") +local Utils = require("Utils") -- [[ Test ]] -- TestNetworkUtils = {} @@ -115,7 +115,7 @@ function TestNetworkUtils:testAlreadySentConnect2() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end -- [[ Send message ]] -- @@ -167,7 +167,7 @@ function TestNetworkUtils:testAlreadySentDisconnect2() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end -- [[ Send message ]] -- @@ -221,7 +221,7 @@ function TestNetworkUtils:testAlreadySentSeed() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end -- [[ Send message ]] -- @@ -278,7 +278,7 @@ function TestNetworkUtils:testAlreadySentPlayerInfo() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end -- [[ Send message ]] -- @@ -329,7 +329,7 @@ function TestNetworkUtils:testAlreadySentNewGuid() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end -- [[ Send message ]] -- @@ -398,7 +398,7 @@ function TestNetworkUtils:testAlreadySentNewNuid() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end -- [[ Send message ]] -- @@ -463,7 +463,7 @@ function TestNetworkUtils:testAlreadySentNeedNuidShouldReturnTrue() filename, health, EntityUtils.isEntityPolymorphed(entityId) } - print(("Let's see if this was already sent: entity %s with data %s"):format(entityId, util.pformat(data))) + print(("Let's see if this was already sent: entity %s with data %s"):format(entityId, Utils.pformat(data))) -- [[ Check if the message was already sent ]] -- lu.assertIs(NetworkUtils.alreadySent(Client, "needNuid", data), true, "The message was already sent, but the function NetworkUtils.alreadySent() returned false!") @@ -519,7 +519,7 @@ function TestNetworkUtils:testAlreadySentNeedNuidShouldReturnFalse() filename, health, EntityUtils.isEntityPolymorphed(entityId) } - print(("Let's see if this WASN'T already sent: entity %s with data %s"):format(entityId, util.pformat(data))) + print(("Let's see if this WASN'T already sent: entity %s with data %s"):format(entityId, Utils.pformat(data))) -- [[ Check if the message WASN'T already sent ]] -- lu.assertIs(NetworkUtils.alreadySent(Client, event, data), false, "The message WASN'T already sent, but the function NetworkUtils.alreadySent() returned true!") @@ -554,7 +554,7 @@ function TestNetworkUtils:testAlreadySentLostNuid() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end -- [[ Send message ]] -- @@ -604,13 +604,13 @@ function TestNetworkUtils:testAlreadySentDeadNuids() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end local originalDestroyByNuid = EntityUtils.destroyByNuid EntityUtils.destroyByNuid = function(peer, deadNuid) Logger.trace(Logger.channels.testing, ("Mocked 'EntityUtils.destroyByNuid' on '%s' destroyed a dead nuid '%s'!") - :format(util.pformat(peer), deadNuid)) + :format(Utils.pformat(peer), deadNuid)) end require("GlobalsUtils") local originalRemoveDeadNuid = GlobalsUtils.removeDeadNuid @@ -691,7 +691,7 @@ function TestNetworkUtils:testAlreadySentNeedModList() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end -- [[ Send message ]] -- @@ -759,7 +759,7 @@ function TestNetworkUtils:testAlreadySentNeedModContent() Client.connection.send = function(serializedMessage, sendChannel, sendMode) Logger.trace(Logger.channels.testing, ("Mocked 'self.connection:send(serializedMessage %s, self.sendChannel, self.sendMode)' executed!") - :format(util.pformat(serializedMessage))) + :format(Utils.pformat(serializedMessage))) end -- [[ Send message ]] -- diff --git a/mods/noita-mp/tests/files/scripts/util/util_test.lua b/mods/noita-mp/tests/files/scripts/util/util_test.lua index b7e028e7a..3e5e1f44d 100644 --- a/mods/noita-mp/tests/files/scripts/util/util_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/util_test.lua @@ -1,7 +1,7 @@ local params = ... local lu = require("luaunit") -local util = require("util") +local Utils = require("Utils") TestUtil = {} @@ -14,11 +14,11 @@ function TestUtil:tearDown() end function TestUtil:testSleep() - lu.assertErrorMsgContains("Unable to wait if parameter 'seconds' isn't a number:", util.Sleep, "seconds") + lu.assertErrorMsgContains("Unable to wait if parameter 'seconds' isn't a number:", Utils.Sleep, "seconds") local seconds_to_wait = 4 local timestamp_before = os.clock() - util.Sleep(seconds_to_wait) + Utils.Sleep(seconds_to_wait) local timestamp_after = os.clock() local diff = timestamp_before + seconds_to_wait Logger.debug(Logger.channels.testing,("timestamp_before=%s, timestamp_after=%s, diff=%s"):format(timestamp_before, timestamp_after, diff)) @@ -28,11 +28,11 @@ end function TestUtil:testIsEmpty() local tbl = {} table.insert(tbl, "1234") - lu.assertIsFalse(util.IsEmpty(tbl)) + lu.assertIsFalse(Utils.IsEmpty(tbl)) - lu.assertIsTrue(util.IsEmpty(nil)) - lu.assertIsTrue(util.IsEmpty("")) - lu.assertIsTrue(util.IsEmpty({})) + lu.assertIsTrue(Utils.IsEmpty(nil)) + lu.assertIsTrue(Utils.IsEmpty("")) + lu.assertIsTrue(Utils.IsEmpty({})) end lu.LuaUnit.run(params) From 19c5cfabb21622a8d9429ad5579e363a036231d5 Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:43:09 +1100 Subject: [PATCH 03/26] refactor the noita component scripts --- mods/noita-mp/files/scripts/net/Client.lua | 4 +- mods/noita-mp/files/scripts/net/Server.lua | 6 +-- .../lua_component_enabler.lua | 7 +-- .../scripts/noita-components/name_tags.lua | 29 +++--------- .../scripts/noita-components/nuid_debug.lua | 31 ++++-------- .../scripts/noita-components/nuid_updater.lua | 47 ++++--------------- .../files/scripts/util/EntityUtils.lua | 2 +- .../noita-mp/files/scripts/util/MinaUtils.lua | 6 +-- .../files/scripts/util/NetworkVscUtils.lua | 10 ++-- .../scripts/util/NoitaComponentUtils.lua | 2 +- 10 files changed, 41 insertions(+), 103 deletions(-) diff --git a/mods/noita-mp/files/scripts/net/Client.lua b/mods/noita-mp/files/scripts/net/Client.lua index f6937b8e9..c493f03da 100644 --- a/mods/noita-mp/files/scripts/net/Client.lua +++ b/mods/noita-mp/files/scripts/net/Client.lua @@ -378,7 +378,7 @@ function Client.new(sockClient) if data.oldGuid == self.guid then local entityId = MinaUtils.getLocalMinaInformation().entityId - local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVcsValuesByEntityId(entityId) + local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVscValuesByEntityId(entityId) self.guid = data.newGuid local cpc27 = CustomProfiler.start("ModSettingSet") @@ -955,7 +955,7 @@ function Client.new(sockClient) return end - --local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVcsValuesByEntityId(entityId) + --local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVscValuesByEntityId(entityId) local compOwnerName, compOwnerGuid, compNuid, filename, health, rotation, velocity, x, y = NoitaComponentUtils.getEntityData(entityId) local data = { NetworkUtils.getNextNetworkMessageId(), { compOwnerName, compOwnerGuid }, compNuid, x, y, rotation, velocity, health diff --git a/mods/noita-mp/files/scripts/net/Server.lua b/mods/noita-mp/files/scripts/net/Server.lua index c54dd03e9..7110fa43b 100644 --- a/mods/noita-mp/files/scripts/net/Server.lua +++ b/mods/noita-mp/files/scripts/net/Server.lua @@ -214,7 +214,7 @@ function Server.new(sockServer) local guid = localPlayerInfo.guid local entityId = localPlayerInfo.entityId local isPolymorphed = EntityUtils.isEntityPolymorphed(entityId) - local ownerName, ownerGuid, nuid = NetworkVscUtils.getAllVcsValuesByEntityId(entityId) + local ownerName, ownerGuid, nuid = NetworkVscUtils.getAllVscValuesByEntityId(entityId) if not nuid then nuid = NuidUtils.getNextNuid() @@ -444,7 +444,7 @@ function Server.new(sockServer) return end - --local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVcsValuesByEntityId(entityId) + --local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVscValuesByEntityId(entityId) local compOwnerName, compOwnerGuid, compNuid, filename, health, rotation, velocity, x, y = NoitaComponentUtils.getEntityData(entityId) local isPolymorphed = EntityUtils.isEntityPolymorphed(entityId) @@ -1020,7 +1020,7 @@ function Server.new(sockServer) return end - --local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVcsValuesByEntityId(entityId) + --local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVscValuesByEntityId(entityId) local compOwnerName, compOwnerGuid, compNuid, filename, health, rotation, velocity, x, y = NoitaComponentUtils.getEntityData(entityId) local data = { NetworkUtils.getNextNetworkMessageId(), { compOwnerName, compOwnerGuid }, compNuid, x, y, rotation, velocity, health diff --git a/mods/noita-mp/files/scripts/noita-components/lua_component_enabler.lua b/mods/noita-mp/files/scripts/noita-components/lua_component_enabler.lua index dd88e19e4..295ce6dd6 100644 --- a/mods/noita-mp/files/scripts/noita-components/lua_component_enabler.lua +++ b/mods/noita-mp/files/scripts/noita-components/lua_component_enabler.lua @@ -2,14 +2,9 @@ dofile_once("mods/noita-mp/files/scripts/init/init_logger.lua") EntityUtils = dofile_once("mods/noita-mp/files/scripts/util/EntityUtils.lua") NetworkVscUtils = dofile_once("mods/noita-mp/files/scripts/util/NetworkVscUtils.lua") - function enabled_changed(entityId, isEnabled) - if not EntityUtils.isEntityAlive(entityId) then - return - end - + if not EntityUtils.isEntityAlive(entityId) then return end if isEnabled == true then - if NetworkVscUtils.isNetworkEntityByNuidVsc(entityId) then NetworkVscUtils.enableComponents(entityId) end diff --git a/mods/noita-mp/files/scripts/noita-components/name_tags.lua b/mods/noita-mp/files/scripts/noita-components/name_tags.lua index 1488e205e..4684f0890 100644 --- a/mods/noita-mp/files/scripts/noita-components/name_tags.lua +++ b/mods/noita-mp/files/scripts/noita-components/name_tags.lua @@ -6,35 +6,20 @@ function PlayerNameFunction(entity_id, playerName) GuiStartFrame(gui) local screenWidth, screenHeight = GuiGetScreenDimensions(gui) screenWidth, screenHeight = screenWidth / 2, screenHeight / 2 + local x, y = EntityGetTransform(entity_id) + local camX, camY = GameGetCameraPos() - local x, y = EntityGetTransform(entity_id) - - local function getEntityPositionOnScreen() - local camX, camY = GameGetCameraPos() - return screenWidth + ((x - camX) * 1.5), screenHeight + ((y - camY) * 1.5) - end - - local entityX, entityY = getEntityPositionOnScreen() - local playerNameLength = string.len(playerName) - local playerNameMid = entityX - (playerNameLength * 2) - - GuiText(gui, playerNameMid, entityY, playerName) + GuiText(gui, ((screenWidth + ((x - camX) * 1.5)) - (string.len(playerName) * 2)), + (screenHeight + ((y - camY) * 1.5)), playerName) end local entityId = GetUpdatedEntityID() - -if not EntityUtils.isEntityAlive(entityId) then - return -end - +if not EntityUtils.isEntityAlive(entityId) then return end name = name or nil - if not name then local vsc = EntityGetComponentIncludingDisabled(entityId, "VariableStorageComponent") or {} for i = 1, #vsc do - local variable_storage_component_name = ComponentGetValue2(vsc[i], "name") or nil - if variable_storage_component_name == "noita-mp.nc_owner.name" then - -- see NetworkComponent.component_name_owner_username = "noita-mp.nc_owner.username" + if ComponentGetValue2(vsc[i], "name") == "noita-mp.nc_owner.name" then name = ComponentGetValue2(vsc[i], "value_string") end end @@ -42,4 +27,4 @@ end if name then PlayerNameFunction(entityId, name) -end +end \ No newline at end of file diff --git a/mods/noita-mp/files/scripts/noita-components/nuid_debug.lua b/mods/noita-mp/files/scripts/noita-components/nuid_debug.lua index 5979f7c60..64c6592ce 100644 --- a/mods/noita-mp/files/scripts/noita-components/nuid_debug.lua +++ b/mods/noita-mp/files/scripts/noita-components/nuid_debug.lua @@ -1,34 +1,19 @@ dofile_once("mods/noita-mp/files/scripts/init/init_logger.lua") dofile_once("mods/noita-mp/files/scripts/extensions/table_extensions.lua") +dofile_once("mods/noita-mp/files/scripts/extensions/mathExtensions.lua") EntityUtils = dofile_once("mods/noita-mp/files/scripts/util/EntityUtils.lua") NetworkVscUtils = dofile_once("mods/noita-mp/files/scripts/util/NetworkVscUtils.lua") NoitaComponentUtils = dofile_once("mods/noita-mp/files/scripts/util/NoitaComponentUtils.lua") - -function math.sign(v) - return (v >= 0 and 1) or -1 -end - -function math.round(v, bracket) - bracket = bracket or 1 - return math.floor(v / bracket + math.sign(v) * 0.5) * bracket -end - if ModSettingGet("noita-mp.toggle_debug") then - local entityId = GetUpdatedEntityID() - - if not EntityUtils.isEntityAlive(entityId) then - return - end + if not EntityUtils.isEntityAlive(entityId) then return end gui = gui or GuiCreate() GuiStartFrame(gui) - - local screenWidth, screenHeight = GuiGetScreenDimensions(gui) - screenWidth, screenHeight = screenWidth / 2, screenHeight / 2 + local screenWidth, screenHeight = GuiGetScreenDimensions(gui) + screenWidth, screenHeight = screenWidth / 2, screenHeight / 2 local compOwnerName, compOwnerGuid, compNuid, filename, health, rotation, velocity, x, y = NoitaComponentUtils.getEntityData(entityId) - local function getEntityPositionOnScreen() local camX, camY = GameGetCameraPos() return screenWidth + ((x - camX) * 1.5), screenHeight + ((y - camY) * 1.5) @@ -36,20 +21,21 @@ if ModSettingGet("noita-mp.toggle_debug") then local data = { owner = compOwnerName, - --guid = compOwnerGuid, + --guid = compOwnerGuid, nuid = compNuid, filename = filename, healthCurrent = health.current, healthMax = health.max, - --rotation = rotation, + --rotation = rotation, vX = velocity.x, vY = velocity.y, x = x, y = y } - table.setNoitaMpDefaultMetaMethods(data, "kv") + table.setNoitaMpDefaultMetaMethods(data, "kv") local i = 0 + for name, value in pairs(data) do local entityX, entityY = getEntityPositionOnScreen() local text = ("%s: %s"):format(name, value) @@ -58,6 +44,5 @@ if ModSettingGet("noita-mp.toggle_debug") then GuiText(gui, textMid, entityY + (i * 6), text) i = i + 1 end - data = nil end diff --git a/mods/noita-mp/files/scripts/noita-components/nuid_updater.lua b/mods/noita-mp/files/scripts/noita-components/nuid_updater.lua index 3e017a0db..59237d30a 100644 --- a/mods/noita-mp/files/scripts/noita-components/nuid_updater.lua +++ b/mods/noita-mp/files/scripts/noita-components/nuid_updater.lua @@ -3,35 +3,26 @@ dofile_once("mods/noita-mp/files/scripts/extensions/string_extensions.lua") EntityUtils = dofile_once("mods/noita-mp/files/scripts/util/EntityUtils.lua") NetworkVscUtils = dofile_once("mods/noita-mp/files/scripts/util/NetworkVscUtils.lua") GlobalsUtils = dofile_once("mods/noita-mp/files/scripts/util/GlobalsUtils.lua") +local executeOnAdded = GetValueBool("executeOnAdded", 1) -local executeOnAdded = GetValueBool("executeOnAdded", true) - ---#region local functions - ---#endregion - ---#region executeOnAdded = added() and executeOnRemove = remove() - -local function added() +if executeOnAdded then Logger.debug(Logger.channels.nuid, "nuid_updater.lua added..") local currentEntityId = GetUpdatedEntityID() - if not EntityUtils.isEntityAlive(currentEntityId) then - return - end - local ownerName, ownerGuid, nuid = NetworkVscUtils.getAllVcsValuesByEntityId(currentEntityId) + if not EntityUtils.isEntityAlive(currentEntityId) then return end + local ownerName, ownerGuid, nuid = NetworkVscUtils.getAllVscValuesByEntityId(currentEntityId) local globalsNuid, globalsEntityId = GlobalsUtils.getNuidEntityPair(nuid) - if currentEntityId ~= globalsEntityId then GlobalsUtils.setNuid(nuid, currentEntityId) Logger.debug(Logger.channels.nuid, ("nuid in noitas global storage was set: nuid = %s and entity_id = %s") - :format(nuid, currentEntityId)) + :format(nuid, currentEntityId)) end + SetValueBool("executeOnAdded", 0) end -local function remove() +if not executeOnAdded then Logger.debug(Logger.channels.nuid, "nuid_updater.lua remove..") local currentEntityId = GetUpdatedEntityID() - local ownerName, ownerGuid, nuid = NetworkVscUtils.getAllVcsValuesByEntityId(currentEntityId) + local ownerName, ownerGuid, nuid = NetworkVscUtils.getAllVscValuesByEntityId(currentEntityId) local globalsNuid, globalsEntityId = GlobalsUtils.getNuidEntityPair(nuid) if not globalsEntityId then @@ -41,24 +32,6 @@ local function remove() GlobalsUtils.setNuid(nuid, tonumber(currentEntityId * -1)) GlobalsUtils.setDeadNuid(nuid) Logger.debug(Logger.channels.nuid, - ("Entity (%s) was killed and nuid (%s) in noitas global storage was updated: old=%s and new=-%s") - :format(currentEntityId, nuid, globalsEntityId, tonumber(globalsEntityId * -1))) -end - ---#endregion - - ---#region Decision maker if executed on added or remove - -if executeOnAdded then - -- this was executed on added - added() - SetValueBool("executeOnAdded", false) + ("Entity (%s) was killed and nuid (%s) in noitas global storage was updated: old=%s and new=-%s") + :format(currentEntityId, nuid, globalsEntityId, tonumber(globalsEntityId * -1))) end - -if not executeOnAdded then - -- this was executed on remove - remove() -end - ---#endregion diff --git a/mods/noita-mp/files/scripts/util/EntityUtils.lua b/mods/noita-mp/files/scripts/util/EntityUtils.lua index a17048041..cb6664201 100644 --- a/mods/noita-mp/files/scripts/util/EntityUtils.lua +++ b/mods/noita-mp/files/scripts/util/EntityUtils.lua @@ -479,7 +479,7 @@ function EntityUtils.spawnEntity(owner, nuid, x, y, rotation, velocity, filename -- double check, if there is already an entity with this NUID and return the entity_id if EntityUtils.isEntityAlive(localEntityId) and NetworkVscUtils.hasNetworkLuaComponents(localEntityId) then - local ownerNameByVsc, ownerGuidByVsc, nuidByVsc = NetworkVscUtils.getAllVcsValuesByEntityId(localEntityId) + local ownerNameByVsc, ownerGuidByVsc, nuidByVsc = NetworkVscUtils.getAllVscValuesByEntityId(localEntityId) -- if guid is not equal, but nuid is the same, then something is broken for sure! if ownerGuidByVsc ~= remoteGuid and nuidByVsc == nuid then error(("Trying to spawn entity(%s) locally, but owner does not match: remoteOwner(%s) ~= localOwner(%s). remoteNuid(%s) ~= localNuid(%s)") diff --git a/mods/noita-mp/files/scripts/util/MinaUtils.lua b/mods/noita-mp/files/scripts/util/MinaUtils.lua index 4c6493959..9a83cf87a 100644 --- a/mods/noita-mp/files/scripts/util/MinaUtils.lua +++ b/mods/noita-mp/files/scripts/util/MinaUtils.lua @@ -78,7 +78,7 @@ function MinaUtils.getLocalMinaEntityId() local playerEntityIds = EntityGetWithTag("player_unit") for i = 1, #playerEntityIds do if NetworkVscUtils.hasNetworkLuaComponents(playerEntityIds[i]) then - local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVcsValuesByEntityId(playerEntityIds[i]) + local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVscValuesByEntityId(playerEntityIds[i]) if compOwnerGuid == localMinaGuid then EntityUtils.localPlayerEntityId = playerEntityIds[i] CustomProfiler.stop("MinaUtils.getLocalMinaEntityId", cpc) @@ -122,7 +122,7 @@ function MinaUtils.getLocalMinaInformation() NetworkVscUtils.addOrUpdateAllVscs(entityId, ownerName, ownerGuid, nuid) end - local _, _, nuid = NetworkVscUtils.getAllVcsValuesByEntityId(entityId) + local _, _, nuid = NetworkVscUtils.getAllVscValuesByEntityId(entityId) CustomProfiler.stop("MinaUtils.getLocalMinaInformation", cpc) return { name = ownerName, @@ -144,7 +144,7 @@ function MinaUtils.isLocalMinaPolymorphed() for c = 1, #componentIds do local isPlayer = ComponentGetValue2(componentIds[c], "is_player") if isPlayer then - local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVcsValuesByEntityId(polymorphedEntityIds[e]) + local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVscValuesByEntityId(polymorphedEntityIds[e]) if compOwnerGuid == localMinaGuid then EntityUtils.localPlayerEntityIdPolymorphed = polymorphedEntityIds[e] CustomProfiler.stop("MinaUtils.isLocalMinaPolymorphed", cpc) diff --git a/mods/noita-mp/files/scripts/util/NetworkVscUtils.lua b/mods/noita-mp/files/scripts/util/NetworkVscUtils.lua index 25c9f70d0..35138cd34 100644 --- a/mods/noita-mp/files/scripts/util/NetworkVscUtils.lua +++ b/mods/noita-mp/files/scripts/util/NetworkVscUtils.lua @@ -373,18 +373,18 @@ end --- Returns all Network Vsc values by its entity id. --- @param entityId number Entity Id provided by Noita --- @return string? ownerName, string? ownerGuid, number? nuid - nuid can be nil -function NetworkVscUtils.getAllVcsValuesByEntityId(entityId) - local cpc = CustomProfiler.start("NetworkVscUtils.getAllVcsValuesByEntityId") +function NetworkVscUtils.getAllVscValuesByEntityId(entityId) + local cpc = CustomProfiler.start("NetworkVscUtils.getAllVscValuesByEntityId") if not EntityUtils.isEntityAlive(entityId) then - CustomProfiler.stop("NetworkVscUtils.getAllVcsValuesByEntityId", cpc) + CustomProfiler.stop("NetworkVscUtils.getAllVscValuesByEntityId", cpc) return end local ownerNameCompId, ownerGuidCompId, nuidCompId, _, _ = getNetworkComponents(entityId) - CustomProfiler.stop("NetworkVscUtils.getAllVcsValuesByEntityId", cpc) + CustomProfiler.stop("NetworkVscUtils.getAllVscValuesByEntityId", cpc) if ownerNameCompId and ownerGuidCompId then return NetworkVscUtils.getAllVcsValuesByComponentIds(ownerNameCompId, ownerGuidCompId, nuidCompId) else - error(("getAllVcsValuesByEntityId: Got unexpected nil id. entityId, = %s ownerNameCompId = %s, ownerGuidCompId = %s, nuidCompId = %s") + error(("getAllVscValuesByEntityId: Got unexpected nil id. entityId, = %s ownerNameCompId = %s, ownerGuidCompId = %s, nuidCompId = %s") :format(entityId, ownerNameCompId, ownerGuidCompId, nuidCompId), 2) end end diff --git a/mods/noita-mp/files/scripts/util/NoitaComponentUtils.lua b/mods/noita-mp/files/scripts/util/NoitaComponentUtils.lua index d0240d828..fb1f06707 100644 --- a/mods/noita-mp/files/scripts/util/NoitaComponentUtils.lua +++ b/mods/noita-mp/files/scripts/util/NoitaComponentUtils.lua @@ -48,7 +48,7 @@ end --- @return string ownername, string ownerguid, number nuid, string filename, EntityHealthData health, number rotation, Vec2 velocity, number x, number y function NoitaComponentUtils.getEntityData(entityId) local cpc = CustomProfiler.start("NoitaComponentUtils.getEntityData") - local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVcsValuesByEntityId(entityId) + local compOwnerName, compOwnerGuid, compNuid = NetworkVscUtils.getAllVscValuesByEntityId(entityId) local hpCompId = EntityGetFirstComponentIncludingDisabled(entityId, "DamageModelComponent") local health = { current = 0, max = 0 } From 3b62e7da64a4892851312281b94eb54065e2d8b0 Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 2 Mar 2023 08:19:04 +1100 Subject: [PATCH 04/26] cleanup init files --- mods/noita-mp/files/scripts/init/init_.lua | 7 +- .../scripts/init/init_package_loading.lua | 70 ++++++++++--------- mods/noita-mp/init.lua | 36 ++++------ 3 files changed, 51 insertions(+), 62 deletions(-) diff --git a/mods/noita-mp/files/scripts/init/init_.lua b/mods/noita-mp/files/scripts/init/init_.lua index cc6cf24fb..af7250321 100644 --- a/mods/noita-mp/files/scripts/init/init_.lua +++ b/mods/noita-mp/files/scripts/init/init_.lua @@ -1,7 +1,6 @@ -- Init lua scripts to set necessary defaults, like lua paths, logger init and extensions print("Initialise paths, globals and extensions..") local varargs = { ... } - if varargs and #varargs > 0 then if require then print("ERROR: Do not add any arguments when running this script in-game!") @@ -18,12 +17,8 @@ dofile("mods/noita-mp/files/scripts/extensions/string_extensions.lua") dofile("mods/noita-mp/files/scripts/extensions/mathExtensions.lua") dofile("mods/noita-mp/files/scripts/extensions/ffi_extensions.lua") dofile("mods/noita-mp/files/scripts/extensions/globalExtensions.lua") - dofile("mods/noita-mp/files/scripts/init/init_package_loading.lua") dofile("mods/noita-mp/files/scripts/init/init_logger.lua") - --- We simply want to load all dependencies, when inGame and in init.lua-Context, --- and when in NoitaComponents or in unit testing!Ø require("MinaUtils") require("luaExtensions") require("NetworkCacheUtils") @@ -47,4 +42,4 @@ _G.whoAmI = function() return Client.iAm end return "UNKNOWN" -end \ No newline at end of file +end diff --git a/mods/noita-mp/files/scripts/init/init_package_loading.lua b/mods/noita-mp/files/scripts/init/init_package_loading.lua index 424681e03..3d77cf35c 100644 --- a/mods/noita-mp/files/scripts/init/init_package_loading.lua +++ b/mods/noita-mp/files/scripts/init/init_package_loading.lua @@ -7,7 +7,7 @@ function getNoitaMpRootDirectory() -- Check if we are inside of noita-mp directory. Don't forget to escape the dash! local startsAtI, endsAtI = string.find(currentDirectory, - "noita%-mp") -- https://stackoverflow.com/a/20223010/3493998 + "noita%-mp") -- https://stackoverflow.com/a/20223010/3493998 local noitaMpRootDirectory = nil if not startsAtI then error("The current directory is not inside the noita-mp directory. Please run it again somewhere inside the noita-mp directory.") @@ -35,15 +35,15 @@ package.path = package.path .. "mods\\noita-mp\\files\\scripts\\util\\?.lua;" print("package.path = " .. package.path) package.cpath = package.cpath .. ";" .. - -- [[ LuaRocks libraries ]]-- - noitaMpRootDirectory .. "\\lua_modules\\lib\\lua\\5.1\\?.dll;" .. - "mods\\noita-mp\\lua_modules\\lib\\lua\\5.1\\?.dll;" + -- [[ LuaRocks libraries ]]-- + noitaMpRootDirectory .. "\\lua_modules\\lib\\lua\\5.1\\?.dll;" .. + "mods\\noita-mp\\lua_modules\\lib\\lua\\5.1\\?.dll;" print("package.cpath = " .. package.cpath) -local fu = require("FileUtils") +local fu = require("FileUtils") --[[ NoitaMP additions ]] -- A list of paths to lua script modules -local paths = { +local paths = { -- [[ LuaRocks modules, running outside of noita.exe ]]-- noitaMpRootDirectory .. "/lua_modules/share/lua/5.1/{module}", noitaMpRootDirectory .. "/lua_modules/lib/lua/5.1/{module}", @@ -68,14 +68,14 @@ local paths = { } -- A list of paths to binary Lua modules -local module_paths = { +local module_paths = { "?.{extension}", "?/init.{extension}", "?/core.{extension}", } -- List of supported OS paired with binary file extension name -local extensions = { +local extensions = { Windows = "dll", Linux = "so", Mac = "dylib" @@ -83,10 +83,10 @@ local extensions = { -- os_name is a supplemental module for -- OS and CPU architecture detection -local os_name = require("os_name") +local os_name = require("os_name") --[[ NoitaMP additions ]] -package.path = default_package_path +package.path = default_package_path --[[ NoitaMP additions ]] -- A dot character represent current working directory local root_dir = "." @@ -96,11 +96,11 @@ local cpaths, lpaths = {}, {} local current_clib_extension = extensions[current_platform] --[[ NoitaMP additions ]] -_G.os_name = current_platform -_G.os_arch = current_architecture +_G.os_name = current_platform +_G.os_arch = current_architecture -- https://stackoverflow.com/a/14425862/3493998 -_G.pathSeparator = tostring(package.config:sub(1, 1)) +_G.pathSeparator = tostring(package.config:sub(1, 1)) if _G.os_name == "Windows" then _G.is_windows = true @@ -110,7 +110,7 @@ if _G.os_name == "Linux" then end print("init_package_loading.lua | Detected OS " .. _G.os_name .. - "(" .. _G.os_arch .. ") with path separator '" .. _G.pathSeparator .. "'.") +"(" .. _G.os_arch .. ") with path separator '" .. _G.pathSeparator .. "'.") --[[ NoitaMP additions ]] if current_clib_extension then @@ -122,30 +122,30 @@ if current_clib_extension then -- make a substitution for each module file path. for _, raw_module_path in ipairs(module_paths) do local module_path = path:gsub( - "{(%w+)}", - { - module = raw_module_path - } + "{(%w+)}", + { + module = raw_module_path + } ) -- add path for binary module cpaths[#cpaths + 1] = module_path:gsub( - "{(%w+)}", - { - extension = current_clib_extension - } + "{(%w+)}", + { + extension = current_clib_extension + } ) -- add paths for platform independent lua and luac modules lpaths[#lpaths + 1] = module_path:gsub( - "{(%w+)}", - { - extension = "lua" - } + "{(%w+)}", + { + extension = "lua" + } ) lpaths[#lpaths + 1] = module_path:gsub( - "{(%w+)}", - { - extension = "luac" - } + "{(%w+)}", + { + extension = "luac" + } ) end end @@ -161,20 +161,22 @@ if current_clib_extension then if destination_path then print("destination_path was set to export LPATH and CPATH!") - local lua_path_file = fu.RemoveTrailingPathSeparator(destination_path) .. _G.pathSeparator .. "lua_path.txt" + local lua_path_file = fu.RemoveTrailingPathSeparator(destination_path) .. + _G.pathSeparator .. "lua_path.txt" local lua_path_file_content = ";" .. package.path - local lua_cpath_file = fu.RemoveTrailingPathSeparator(destination_path) .. _G.pathSeparator .. "lua_cpath.txt" + local lua_cpath_file = fu.RemoveTrailingPathSeparator(destination_path) .. + _G.pathSeparator .. "lua_cpath.txt" local lua_cpath_file_content = ";" .. package.cpath fu.WriteFile(lua_path_file, lua_path_file_content) print("init_package_loading.lua | File (" .. lua_path_file .. - ") created with content: " .. lua_path_file_content) + ") created with content: " .. lua_path_file_content) fu.WriteFile(lua_cpath_file, lua_cpath_file_content) print("init_package_loading.lua | File (" .. lua_cpath_file .. - ") created with content: " .. lua_cpath_file_content) + ") created with content: " .. lua_cpath_file_content) else print("destination_path was not set. Export LPATH and CPATH will be skipped!") end diff --git a/mods/noita-mp/init.lua b/mods/noita-mp/init.lua index 7231e0ddd..0ce244a02 100644 --- a/mods/noita-mp/init.lua +++ b/mods/noita-mp/init.lua @@ -7,9 +7,8 @@ end ---------------------------------------------------------------------------------------------------- dofile("mods/noita-mp/files/scripts/init/init_.lua") local Utils = require("Utils") -local fu = require("FileUtils") -local ui = require("Ui").new() - +local fu = require("FileUtils") +local ui = require("Ui").new() Logger.debug(Logger.channels.initialize, "Starting to load noita-mp init.lua..") ---------------------------------------------------------------------------------------------------- @@ -73,14 +72,15 @@ function OnWorldInitialized() local archive_name = "server_save06_" .. os.date("%Y-%m-%d_%H-%M-%S") local destination = fu.GetAbsoluteDirectoryPathOfNoitaMP() .. pathSeparator .. "_" local archive_content = fu.Create7zipArchive(archive_name .. "_from_server", - fu.GetAbsoluteDirectoryPathOfSave06(), destination) - local msg = ("init.lua | Server savegame [%s] was zipped with 7z to location [%s]."):format(archive_name, - destination) + fu.GetAbsoluteDirectoryPathOfSave06(), destination) + local msg = ("init.lua | Server savegame [%s] was zipped with 7z to location [%s]."):format( + archive_name, + destination) Logger.debug(Logger.channels.initialize, msg) GamePrint(msg) local cpc1 = CustomProfiler.start("ModSettingSetNextValue") ModSettingSetNextValue("noita-mp.server_start_7zip_savegame", false, - false) -- automatically start the server again + false) -- automatically start the server again CustomProfiler.stop("ModSettingSetNextValue", cpc1) end CustomProfiler.stop("init.OnWorldInitialized", cpc) @@ -94,11 +94,11 @@ function OnPlayerSpawned(player_entity) if not GameHasFlagRun("nameTags_script_applied") then GameAddFlagRun("nameTags_script_applied") EntityAddComponent2(player_entity, - "LuaComponent", - { - script_source_file = "mods/noita-mp/files/scripts/noita-components/name_tags.lua", - execute_every_n_frame = 1, - }) + "LuaComponent", + { + script_source_file = "mods/noita-mp/files/scripts/noita-components/name_tags.lua", + execute_every_n_frame = 1, + }) end CustomProfiler.stop("init.OnPlayerSpawned", cpc) end @@ -141,7 +141,7 @@ function OnWorldPreUpdate() ModSettingSetNextValue("noita-mp.saveSlotMetaDirectory", _G.saveSlotMeta.dir, false) CustomProfiler.stop("ModSettingSetNextValue", cpc1) Logger.info(Logger.channels.initialize, - ("Save slot found in '%s'"):format(Utils.pformat(_G.saveSlotMeta))) + ("Save slot found in '%s'"):format(Utils.pformat(_G.saveSlotMeta))) end end end @@ -149,7 +149,6 @@ function OnWorldPreUpdate() Server.update() Client.update() - ui.update() local cpc1 = CustomProfiler.start("init.OnWorldPreUpdate.collectgarbage.count") @@ -162,14 +161,7 @@ function OnWorldPreUpdate() collectgarbage("collect") CustomProfiler.stop("init.OnWorldPreUpdate.collectgarbage.collect", cpc2) end - CustomProfiler.stop("init.OnWorldPreUpdate.collectgarbage.count", cpc1) + CustomProfiler.stop("init.OnWorldPreUpdate.collectgarbage.count", cpc1) CustomProfiler.stop("init.OnWorldPreUpdate", cpc) end - ---function OnWorldPostUpdate() --- local cpc = CustomProfiler.start("init.OnWorldPostUpdate") --- Server.update() --- Client.update() --- CustomProfiler.stop("init.OnWorldPostUpdate", cpc) ---end From 6f86a9ecca2c8616b8e02752d2579b5c9fc1c2cd Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 2 Mar 2023 08:22:39 +1100 Subject: [PATCH 05/26] ensure consistent naming of extension files --- .../extensions/{ffi_extensions.lua => ffiExtensions.lua} | 0 .../{string_extensions.lua => stringExtensions.lua} | 0 .../{table_extensions.lua => tableExtensions.lua} | 0 mods/noita-mp/files/scripts/init/init_.lua | 6 +++--- mods/noita-mp/files/scripts/noita-components/nuid_debug.lua | 2 +- .../files/scripts/noita-components/nuid_updater.lua | 2 +- mods/noita-mp/files/scripts/util/Utils.lua | 2 +- mods/noita-mp/noita-mp-3.0.0-3.rockspec | 6 +++--- 8 files changed, 9 insertions(+), 9 deletions(-) rename mods/noita-mp/files/scripts/extensions/{ffi_extensions.lua => ffiExtensions.lua} (100%) rename mods/noita-mp/files/scripts/extensions/{string_extensions.lua => stringExtensions.lua} (100%) rename mods/noita-mp/files/scripts/extensions/{table_extensions.lua => tableExtensions.lua} (100%) diff --git a/mods/noita-mp/files/scripts/extensions/ffi_extensions.lua b/mods/noita-mp/files/scripts/extensions/ffiExtensions.lua similarity index 100% rename from mods/noita-mp/files/scripts/extensions/ffi_extensions.lua rename to mods/noita-mp/files/scripts/extensions/ffiExtensions.lua diff --git a/mods/noita-mp/files/scripts/extensions/string_extensions.lua b/mods/noita-mp/files/scripts/extensions/stringExtensions.lua similarity index 100% rename from mods/noita-mp/files/scripts/extensions/string_extensions.lua rename to mods/noita-mp/files/scripts/extensions/stringExtensions.lua diff --git a/mods/noita-mp/files/scripts/extensions/table_extensions.lua b/mods/noita-mp/files/scripts/extensions/tableExtensions.lua similarity index 100% rename from mods/noita-mp/files/scripts/extensions/table_extensions.lua rename to mods/noita-mp/files/scripts/extensions/tableExtensions.lua diff --git a/mods/noita-mp/files/scripts/init/init_.lua b/mods/noita-mp/files/scripts/init/init_.lua index af7250321..da885eb3a 100644 --- a/mods/noita-mp/files/scripts/init/init_.lua +++ b/mods/noita-mp/files/scripts/init/init_.lua @@ -12,10 +12,10 @@ else print("no 'varargs' set.") end -dofile("mods/noita-mp/files/scripts/extensions/table_extensions.lua") -dofile("mods/noita-mp/files/scripts/extensions/string_extensions.lua") +dofile("mods/noita-mp/files/scripts/extensions/tableExtensions.lua") +dofile("mods/noita-mp/files/scripts/extensions/stringExtensions.lua") dofile("mods/noita-mp/files/scripts/extensions/mathExtensions.lua") -dofile("mods/noita-mp/files/scripts/extensions/ffi_extensions.lua") +dofile("mods/noita-mp/files/scripts/extensions/ffiExtensions.lua") dofile("mods/noita-mp/files/scripts/extensions/globalExtensions.lua") dofile("mods/noita-mp/files/scripts/init/init_package_loading.lua") dofile("mods/noita-mp/files/scripts/init/init_logger.lua") diff --git a/mods/noita-mp/files/scripts/noita-components/nuid_debug.lua b/mods/noita-mp/files/scripts/noita-components/nuid_debug.lua index 64c6592ce..2f0c39cb9 100644 --- a/mods/noita-mp/files/scripts/noita-components/nuid_debug.lua +++ b/mods/noita-mp/files/scripts/noita-components/nuid_debug.lua @@ -1,5 +1,5 @@ dofile_once("mods/noita-mp/files/scripts/init/init_logger.lua") -dofile_once("mods/noita-mp/files/scripts/extensions/table_extensions.lua") +dofile_once("mods/noita-mp/files/scripts/extensions/tableExtensions.lua") dofile_once("mods/noita-mp/files/scripts/extensions/mathExtensions.lua") EntityUtils = dofile_once("mods/noita-mp/files/scripts/util/EntityUtils.lua") NetworkVscUtils = dofile_once("mods/noita-mp/files/scripts/util/NetworkVscUtils.lua") diff --git a/mods/noita-mp/files/scripts/noita-components/nuid_updater.lua b/mods/noita-mp/files/scripts/noita-components/nuid_updater.lua index 59237d30a..d6d1db74a 100644 --- a/mods/noita-mp/files/scripts/noita-components/nuid_updater.lua +++ b/mods/noita-mp/files/scripts/noita-components/nuid_updater.lua @@ -1,5 +1,5 @@ dofile_once("mods/noita-mp/files/scripts/init/init_logger.lua") -dofile_once("mods/noita-mp/files/scripts/extensions/string_extensions.lua") +dofile_once("mods/noita-mp/files/scripts/extensions/stringExtensions.lua") EntityUtils = dofile_once("mods/noita-mp/files/scripts/util/EntityUtils.lua") NetworkVscUtils = dofile_once("mods/noita-mp/files/scripts/util/NetworkVscUtils.lua") GlobalsUtils = dofile_once("mods/noita-mp/files/scripts/util/GlobalsUtils.lua") diff --git a/mods/noita-mp/files/scripts/util/Utils.lua b/mods/noita-mp/files/scripts/util/Utils.lua index b985826b6..a41bac73e 100644 --- a/mods/noita-mp/files/scripts/util/Utils.lua +++ b/mods/noita-mp/files/scripts/util/Utils.lua @@ -25,7 +25,7 @@ end function Utils.IsEmpty(var) -- if you change this also change NetworkVscUtils.lua - -- if you change this also change table_extensions.lua + -- if you change this also change tableExtensions.lua if var == nil then return true end diff --git a/mods/noita-mp/noita-mp-3.0.0-3.rockspec b/mods/noita-mp/noita-mp-3.0.0-3.rockspec index cfbd64030..49bf38856 100644 --- a/mods/noita-mp/noita-mp-3.0.0-3.rockspec +++ b/mods/noita-mp/noita-mp-3.0.0-3.rockspec @@ -21,11 +21,11 @@ build = { ["files.scripts.DefaultBiomeMap"] = "files/scripts/DefaultBiomeMap.lua", ["files.scripts.Ui"] = "files/scripts/Ui.lua", ["files.scripts.biome.testingRoom"] = "files/scripts/biome/testingRoom.lua", - ["files.scripts.extensions.ffi_extensions"] = "files/scripts/extensions/ffi_extensions.lua", + ["files.scripts.extensions.ffiExtensions"] = "files/scripts/extensions/ffiExtensions.lua", ["files.scripts.extensions.globalExtensions"] = "files/scripts/extensions/globalExtensions.lua", ["files.scripts.extensions.mathExtensions"] = "files/scripts/extensions/mathExtensions.lua", - ["files.scripts.extensions.string_extensions"] = "files/scripts/extensions/string_extensions.lua", - ["files.scripts.extensions.table_extensions"] = "files/scripts/extensions/table_extensions.lua", + ["files.scripts.extensions.stringExtensions"] = "files/scripts/extensions/stringExtensions.lua", + ["files.scripts.extensions.tableExtensions"] = "files/scripts/extensions/tableExtensions.lua", ["files.scripts.init.init_"] = "files/scripts/init/init_.lua", ["files.scripts.init.init_logger"] = "files/scripts/init/init_logger.lua", ["files.scripts.init.init_package_loading"] = "files/scripts/init/init_package_loading.lua", From e0e194dd1cc4bc39151b43c42550610f7a235683 Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 2 Mar 2023 08:36:32 +1100 Subject: [PATCH 06/26] rename test files --- mods/noita-mp/noita-mp-3.0.0-3.rockspec | 4 ++-- .../{string_extensions_test.lua => stringExtensions_test.lua} | 0 .../{table_extensions_test.lua => tableExtensions_test.lua} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename mods/noita-mp/tests/files/scripts/extensions/{string_extensions_test.lua => stringExtensions_test.lua} (100%) rename mods/noita-mp/tests/files/scripts/extensions/{table_extensions_test.lua => tableExtensions_test.lua} (100%) diff --git a/mods/noita-mp/noita-mp-3.0.0-3.rockspec b/mods/noita-mp/noita-mp-3.0.0-3.rockspec index 49bf38856..ec56cfac8 100644 --- a/mods/noita-mp/noita-mp-3.0.0-3.rockspec +++ b/mods/noita-mp/noita-mp-3.0.0-3.rockspec @@ -51,8 +51,8 @@ build = { modSettingsUpdater = "modSettingsUpdater.lua", settings = "settings.lua", ["tests.config_test"] = "tests/config_test.lua", - ["tests.files.scripts.extensions.string_extensions_test"] = "tests/files/scripts/extensions/string_extensions_test.lua", - ["tests.files.scripts.extensions.table_extensions_test"] = "tests/files/scripts/extensions/table_extensions_test.lua", + ["tests.files.scripts.extensions.stringExtensions_test"] = "tests/files/scripts/extensions/stringExtensions_test.lua", + ["tests.files.scripts.extensions.tableExtensions_test"] = "tests/files/scripts/extensions/tableExtensions_test.lua", ["tests.files.scripts.init.init__test"] = "tests/files/scripts/init/init__test.lua", ["tests.files.scripts.init.init_logger_test"] = "tests/files/scripts/init/init_logger_test.lua", ["tests.files.scripts.init.init_package_loading_test"] = "tests/files/scripts/init/init_package_loading_test.lua", diff --git a/mods/noita-mp/tests/files/scripts/extensions/string_extensions_test.lua b/mods/noita-mp/tests/files/scripts/extensions/stringExtensions_test.lua similarity index 100% rename from mods/noita-mp/tests/files/scripts/extensions/string_extensions_test.lua rename to mods/noita-mp/tests/files/scripts/extensions/stringExtensions_test.lua diff --git a/mods/noita-mp/tests/files/scripts/extensions/table_extensions_test.lua b/mods/noita-mp/tests/files/scripts/extensions/tableExtensions_test.lua similarity index 100% rename from mods/noita-mp/tests/files/scripts/extensions/table_extensions_test.lua rename to mods/noita-mp/tests/files/scripts/extensions/tableExtensions_test.lua From 1a29098bf1d7261667ab785e6a2145a74c92559d Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 2 Mar 2023 08:40:24 +1100 Subject: [PATCH 07/26] clean Ui file --- mods/noita-mp/files/scripts/Ui.lua | 42 ++++++++++++++---------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/mods/noita-mp/files/scripts/Ui.lua b/mods/noita-mp/files/scripts/Ui.lua index 68db0f2c9..968c699f8 100644 --- a/mods/noita-mp/files/scripts/Ui.lua +++ b/mods/noita-mp/files/scripts/Ui.lua @@ -6,15 +6,16 @@ ---------------------------------------- -- 'Imports' ---------------------------------------- -local renderEzgui = dofile_once("mods/noita-mp/lua_modules/share/lua/5.1/ezgui/EZGUI.lua").init("mods/noita-mp/lua_modules/share/lua/5.1/ezgui") -local fu = require("FileUtils") +local renderEzgui = dofile_once("mods/noita-mp/lua_modules/share/lua/5.1/ezgui/EZGUI.lua").init( + "mods/noita-mp/lua_modules/share/lua/5.1/ezgui") +local fu = require("FileUtils") ---------------------------------------------------------------------------------------------------- --- Ui --- @see PlayerList.xml --- @see FoldingMenu.xml ---------------------------------------------------------------------------------------------------- -Ui = {} +Ui = {} ---------------------------------------- -- Global private variables: @@ -50,7 +51,7 @@ end --- Ui constructor ---------------------------------------------------------------------------------------------------- function Ui.new() - local self = {} + local self = {} ------------------------------------ -- Private variables: @@ -87,31 +88,31 @@ function Ui.new() cellWidth = 50, }, methods = { - toggleAddress = function() + toggleAddress = function() showAddress = not showAddress end, - copyAddress = function() + copyAddress = function() Utils.copyToClipboard(("%s:%s"):format(_G.Server:getAddress(), _G.Server:getPort())) end, - kick = function(data, element, arg1) + kick = function(data, element, arg1) _G.Server.kick(arg1) end, - ban = function(data, element, arg1) + ban = function(data, element, arg1) _G.Server.ban(arg1) end, - start = function() + start = function() _G.Server.start(nil, nil) end, - stop = function() + stop = function() _G.Server.stop() end, - connect = function() + connect = function() _G.Client.connect() end, - disconnect = function() + disconnect = function() _G.Client.disconnect() end, - toggleDebug = function() + toggleDebug = function() debug = not debug end, reportCustomProfiler = function() @@ -150,12 +151,12 @@ function Ui.new() local text = "" if foldingOpen then self.ezguiFoldingData.data.text = ("[- NoitaMP] %s eCache:%s pCache:%s nCache:%s %s") - :format(fu.GetVersionByFile(), EntityCache.size(), CustomProfiler.getSize(), - NetworkUtils.getClientOrServer().getAckCacheSize(), GameGetFrameNum()) + :format(fu.GetVersionByFile(), EntityCache.size(), CustomProfiler.getSize(), + NetworkUtils.getClientOrServer().getAckCacheSize(), GameGetFrameNum()) else self.ezguiFoldingData.data.text = ("[+ NoitaMP] eCache:%s pCache:%s nCache:%s %s") - :format(EntityCache.size(), CustomProfiler.getSize(), - NetworkUtils.getClientOrServer().getAckCacheSize(), GameGetFrameNum()) + :format(EntityCache.size(), CustomProfiler.getSize(), + NetworkUtils.getClientOrServer().getAckCacheSize(), GameGetFrameNum()) end renderEzgui(0, height - 10, "mods/noita-mp/files/data/ezgui/FoldingMenu.xml", self.ezguiFoldingData) @@ -181,9 +182,6 @@ function Ui.new() }) table.insertAllButNotDuplicates(player, _G.Server.clients) for i = 2, #player do - --player[i].name = string.ExtendOrCutStringToLength(player[i].name, 12, ".", true) - --player[i].health = { current = i, max = 2 } - --player[i].transform = { x = 123, y = 12334 } player[i].rtt = player[i]:getRoundTripTime() end else @@ -271,7 +269,7 @@ function Ui.new() if clicked then missingModGuiDismissed = true Client:send(NetworkUtils.events.needModContent.name, - { NetworkUtils.getNextNetworkMessageId(), Client.missingMods }) + { NetworkUtils.getNextNetworkMessageId(), Client.missingMods }) end if hovered then missingModGuiButton1Hovered = true @@ -318,7 +316,6 @@ function Ui.new() GuiZSetForNextWidget(gui, 110) GuiImageNinePiece(gui, npID, 73, 73, w + 3, y - 71) end - end ------------------------------------ @@ -328,7 +325,6 @@ function Ui.new() drawFolding() drawMenu() drawModConflictWarning() - if EntityCache.size() >= EntityUtils.maxPoolSize then gui = gui or GuiCreate() GuiStartFrame(gui) From de45a6a83007597dcda81a719c7e124571b4cc00 Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 2 Mar 2023 09:28:19 +1100 Subject: [PATCH 08/26] fix custom profiler using old fileutils path --- mods/noita-mp/files/scripts/util/CustomProfiler.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/noita-mp/files/scripts/util/CustomProfiler.lua b/mods/noita-mp/files/scripts/util/CustomProfiler.lua index 68c6c3e98..2dfea10aa 100644 --- a/mods/noita-mp/files/scripts/util/CustomProfiler.lua +++ b/mods/noita-mp/files/scripts/util/CustomProfiler.lua @@ -10,7 +10,7 @@ local json = require("dkjson") local plotly = require("plotly") local Utils = require("Utils") -local fu = require("file_util") +local fu = require("FileUtils") ---@class CustomProfiler CustomProfiler = {} From 77c89ba02131f284624c75d36dc977ef9c95cae9 Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 2 Mar 2023 13:40:13 +1100 Subject: [PATCH 09/26] fix failing tests --- mods/noita-mp/files/scripts/util/FileUtils.lua | 4 ++-- mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/noita-mp/files/scripts/util/FileUtils.lua b/mods/noita-mp/files/scripts/util/FileUtils.lua index fa72050d5..a84b5ca72 100644 --- a/mods/noita-mp/files/scripts/util/FileUtils.lua +++ b/mods/noita-mp/files/scripts/util/FileUtils.lua @@ -30,10 +30,10 @@ end --- @return string path function FileUtils.ReplacePathSeparator(path) if type(path) == "string" then - if _G.is_windows then + if (_G.is_windows or _G.os_name == "Windows") then ---@diagnostic disable-next-line: redundant-return-value return path:gsub("/", "\\") - elseif _G.is_linux then + elseif (_G.is_linux) then ---@diagnostic disable-next-line: redundant-return-value return path:gsub("\\", "/") end diff --git a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua index c6aa4bba2..fbc17a245 100644 --- a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua @@ -86,7 +86,7 @@ function TestFileUtil:testReplacePathSeparatorUnknownOs() _G.is_windows = false -- TODO: is there a better way to mock? _G.is_linux = false -- TODO: is there a better way to mock? - lu.assertErrorMsgContains("file_util.lua | Unable to detect OS", fu.ReplacePathSeparator, "path doesnt matter") + lu.assertErrorMsgContains("FileUtils.lua | Unable to detect OS", fu.ReplacePathSeparator, "path doesnt matter") _G.is_windows = old_is_windows _G.is_linux = old_is_linux @@ -118,7 +118,7 @@ function TestFileUtil:testSetAbsolutePathOfNoitaRootDirectoryUnknownOs() _G.is_windows = false -- TODO: is there a better way to mock? _G.is_linux = false -- TODO: is there a better way to mock? - lu.assertErrorMsgContains("file_util.lua | Unable to detect OS", fu.SetAbsolutePathOfNoitaRootDirectory, + lu.assertErrorMsgContains("FileUtils.lua | Unable to detect OS", fu.SetAbsolutePathOfNoitaRootDirectory, "path doesnt matter") _G.is_windows = old_is_windows From d9ed7f1fcc8dc841010b64e82d93f375c7ac8894 Mon Sep 17 00:00:00 2001 From: Ismoh <12631485+Ismoh@users.noreply.github.com> Date: Sun, 5 Mar 2023 14:55:04 +0100 Subject: [PATCH 10/26] #113 Added some logging. --- .../lua_modules/share/lua/5.1/os_name.lua | 1 + .../files/scripts/util/FileUtils_test.lua | 39 +++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/os_name.lua b/mods/noita-mp/lua_modules/share/lua/5.1/os_name.lua index 51c116796..6f1c8eb2f 100644 --- a/mods/noita-mp/lua_modules/share/lua/5.1/os_name.lua +++ b/mods/noita-mp/lua_modules/share/lua/5.1/os_name.lua @@ -27,6 +27,7 @@ local function getOS() raw_os_name = (raw_os_name):lower() raw_arch_name = (raw_arch_name):lower() + print(("Detected os '%s' on arch '%s'!"):format(raw_os_name, raw_arch_name)) local os_patterns = { ["windows"] = "Windows", diff --git a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua index fbc17a245..83c71e6dd 100644 --- a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua @@ -32,7 +32,11 @@ function TestFileUtil:setUp() end function TestFileUtil:tearDown() - + -- Make sure OS detection isn't broken, when changed in tests + _G.is_windows = true + _G.is_linux = false + local current_platform, current_architecture = os_name.getOS() + _G.pathSeparator = tostring(package.config:sub(1, 1)) end ---------------------------------------------------------------------------------------------------- @@ -40,42 +44,42 @@ end ---------------------------------------------------------------------------------------------------- function TestFileUtil:testReplacePathSeparatorOnWindows() - local old_is_windows = _G.is_windows - local old_is_linux = _G.is_linux + local old_is_windows = _G.is_windows + local old_is_linux = _G.is_linux local old_pathSeparator = _G.pathSeparator - _G.is_windows = true -- TODO: is there a better way to mock? - _G.is_linux = false -- TODO: is there a better way to mock? + _G.is_windows = true -- TODO: is there a better way to mock? + _G.is_linux = false -- TODO: is there a better way to mock? _G.pathSeparator = "\\" -- TODO: is there a better way to mock? - local path_unix = "/test/path/123" - local path_windows = fu.ReplacePathSeparator(path_unix) + local path_unix = "/test/path/123" + local path_windows = fu.ReplacePathSeparator(path_unix) lu.assertNotEquals(path_unix, path_windows) lu.assertEquals([[\test\path\123]], path_windows) - _G.is_windows = old_is_windows - _G.is_linux = old_is_linux + _G.is_windows = old_is_windows + _G.is_linux = old_is_linux _G.pathSeparator = old_pathSeparator end function TestFileUtil:testReplacePathSeparatorOnUnix() - local old_is_windows = _G.is_windows - local old_is_linux = _G.is_linux + local old_is_windows = _G.is_windows + local old_is_linux = _G.is_linux local old_pathSeparator = _G.pathSeparator - _G.is_windows = false -- TODO: is there a better way to mock? - _G.is_linux = true -- TODO: is there a better way to mock? + _G.is_windows = false -- TODO: is there a better way to mock? + _G.is_linux = true -- TODO: is there a better way to mock? _G.pathSeparator = "/" -- TODO: is there a better way to mock? - local path_windows = "\\test\\path\\123" - local path_unix = fu.ReplacePathSeparator(path_windows) + local path_windows = "\\test\\path\\123" + local path_unix = fu.ReplacePathSeparator(path_windows) lu.assertNotEquals(path_windows, path_unix) lu.assertEquals("/test/path/123", path_unix) - _G.is_windows = old_is_windows - _G.is_linux = old_is_linux + _G.is_windows = old_is_windows + _G.is_linux = old_is_linux _G.pathSeparator = old_pathSeparator end @@ -126,6 +130,7 @@ function TestFileUtil:testSetAbsolutePathOfNoitaRootDirectoryUnknownOs() end function TestFileUtil:testGetAbsolutePathOfNoitaRootDirectory() + Logger.trace(Logger.channels.testing, ("Need to verify absolute path of root noita: %s"):format(fu.GetAbsolutePathOfNoitaRootDirectory())) lu.assertStrContains(fu.GetAbsolutePathOfNoitaRootDirectory(), _G.pathSeparator) -- TODO: Need a better test for this! end From d8fd5a3511131815d67fe9940024fafd43303191 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 5 Mar 2023 13:56:21 +0000 Subject: [PATCH 11/26] Updated version to v4.1.0-alpha+1184 in https://github.com/Ismoh/NoitaMP/pull/114 --- mods/noita-mp/.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/noita-mp/.version b/mods/noita-mp/.version index ee77ebac6..e7e117165 100644 --- a/mods/noita-mp/.version +++ b/mods/noita-mp/.version @@ -1 +1 @@ -{"version":"v4.0.1-alpha+792"} +{"version":"v4.1.0-alpha+1184"} From 54fed471fe416f025323cba64e240a732a270a0d Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 5 Mar 2023 13:56:25 +0000 Subject: [PATCH 12/26] Updated version to v4.1.0-alpha+1195 in https://github.com/Ismoh/NoitaMP/pull/114 --- mods/noita-mp/.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/noita-mp/.version b/mods/noita-mp/.version index e7e117165..e996d00ff 100644 --- a/mods/noita-mp/.version +++ b/mods/noita-mp/.version @@ -1 +1 @@ -{"version":"v4.1.0-alpha+1184"} +{"version":"v4.1.0-alpha+1195"} From 9b3b3ae2fedba31064b4a939c4f743d669aa33b8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 5 Mar 2023 13:57:22 +0000 Subject: [PATCH 13/26] Updated CHANGELOG.md in https://github.com/Ismoh/NoitaMP/pull/114 --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10c16ab52..cfb454292 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [v4.1.0-alpha+1195](https://github.com/Ismoh/NoitaMP/tree/v4.1.0-alpha+1195) (05.03.2023) + +[Full Changelog](https://github.com/Ismoh/NoitaMP/compare/v4.1.0-alpha+1184...v4.1.0-alpha+1195) + +## [v4.1.0-alpha+1184](https://github.com/Ismoh/NoitaMP/tree/v4.1.0-alpha+1184) (05.03.2023) + +[Full Changelog](https://github.com/Ismoh/NoitaMP/compare/v4.0.1-alpha+792...v4.1.0-alpha+1184) + +**Implemented enhancements:** + +- Developer want to sync children and components [\#107](https://github.com/Ismoh/NoitaMP/issues/107) [[enhancement](https://github.com/Ismoh/NoitaMP/labels/enhancement)] + +**Closed issues:** + +- Update CHANGELOG.md [\#112](https://github.com/Ismoh/NoitaMP/issues/112) [[documentation](https://github.com/Ismoh/NoitaMP/labels/documentation)] [[github_actions](https://github.com/Ismoh/NoitaMP/labels/github_actions)] + ## [v4.0.1-alpha+792](https://github.com/Ismoh/NoitaMP/tree/v4.0.1-alpha+792) (17.02.2023) [Full Changelog](https://github.com/Ismoh/NoitaMP/compare/v4.0.0-alpha+1302...v4.0.1-alpha+792) From b431b5f2471f4db5a854819f3b6fd487054e5024 Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Wed, 8 Mar 2023 08:54:20 +1100 Subject: [PATCH 14/26] remove line causing test env to fail --- mods/noita-mp/files/scripts/util/FileUtils.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/noita-mp/files/scripts/util/FileUtils.lua b/mods/noita-mp/files/scripts/util/FileUtils.lua index a84b5ca72..e3555c51d 100644 --- a/mods/noita-mp/files/scripts/util/FileUtils.lua +++ b/mods/noita-mp/files/scripts/util/FileUtils.lua @@ -30,7 +30,7 @@ end --- @return string path function FileUtils.ReplacePathSeparator(path) if type(path) == "string" then - if (_G.is_windows or _G.os_name == "Windows") then + if (_G.is_windows) then ---@diagnostic disable-next-line: redundant-return-value return path:gsub("/", "\\") elseif (_G.is_linux) then From 954d01055201a73ec1b01324c37790f84e2d38f1 Mon Sep 17 00:00:00 2001 From: Ismoh <12631485+Ismoh@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:26:20 +0100 Subject: [PATCH 15/26] #113 Fixed os detections. --- .../scripts/init/init_package_loading.lua | 28 ++++++++-------- .../files/scripts/util/FileUtils_test.lua | 32 +++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/mods/noita-mp/files/scripts/init/init_package_loading.lua b/mods/noita-mp/files/scripts/init/init_package_loading.lua index 3d77cf35c..0c2b9e5e6 100644 --- a/mods/noita-mp/files/scripts/init/init_package_loading.lua +++ b/mods/noita-mp/files/scripts/init/init_package_loading.lua @@ -90,24 +90,26 @@ package.path = default_package_path --[[ NoitaMP additions ]] -- A dot character represent current working directory local root_dir = "." -local current_platform, current_architecture = os_name.getOS() - -local cpaths, lpaths = {}, {} -local current_clib_extension = extensions[current_platform] --[[ NoitaMP additions ]] -_G.os_name = current_platform -_G.os_arch = current_architecture - --- https://stackoverflow.com/a/14425862/3493998 -_G.pathSeparator = tostring(package.config:sub(1, 1)) - -if _G.os_name == "Windows" then +_G.is_windows = true +_G.is_linux = false +_G.pathSeparator = tostring(package.config:sub(1, 1)) +local current_platform, current_architecture = os_name.getOS() +if current_platform == "Windows" then _G.is_windows = true -end -if _G.os_name == "Linux" then + _G.is_linux = false + _G.pathSeparator = "\\" +else + _G.is_windows = false _G.is_linux = true + _G.pathSeparator = "/" end +_G.os_name = current_platform +_G.os_arch = current_architecture + +local cpaths, lpaths = {}, {} +local current_clib_extension = extensions[current_platform] print("init_package_loading.lua | Detected OS " .. _G.os_name .. "(" .. _G.os_arch .. ") with path separator '" .. _G.pathSeparator .. "'.") diff --git a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua index 83c71e6dd..50e23e4b5 100644 --- a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua @@ -16,6 +16,7 @@ end local lu = require("luaunit") local fu = require("FileUtils") +local os_name = require("os_name") TestFileUtil = {} @@ -33,10 +34,19 @@ end function TestFileUtil:tearDown() -- Make sure OS detection isn't broken, when changed in tests - _G.is_windows = true - _G.is_linux = false + _G.is_windows = true + _G.is_linux = false + _G.pathSeparator = tostring(package.config:sub(1, 1)) local current_platform, current_architecture = os_name.getOS() - _G.pathSeparator = tostring(package.config:sub(1, 1)) + if current_platform == "Windows" then + _G.is_windows = true + _G.is_linux = false + _G.pathSeparator = "\\" + else + _G.is_windows = false + _G.is_linux = true + _G.pathSeparator = "/" + end end ---------------------------------------------------------------------------------------------------- @@ -83,19 +93,6 @@ function TestFileUtil:testReplacePathSeparatorOnUnix() _G.pathSeparator = old_pathSeparator end -function TestFileUtil:testReplacePathSeparatorUnknownOs() - local old_is_windows = _G.is_windows - local old_is_linux = _G.is_linux - - _G.is_windows = false -- TODO: is there a better way to mock? - _G.is_linux = false -- TODO: is there a better way to mock? - - lu.assertErrorMsgContains("FileUtils.lua | Unable to detect OS", fu.ReplacePathSeparator, "path doesnt matter") - - _G.is_windows = old_is_windows - _G.is_linux = old_is_linux -end - function TestFileUtil:testRemoveTrailingPathSeparator() local path = tostring(_G.pathSeparator .. "persistent" .. _G.pathSeparator .. "flags" .. _G.pathSeparator) local result = fu.RemoveTrailingPathSeparator(path) @@ -130,7 +127,8 @@ function TestFileUtil:testSetAbsolutePathOfNoitaRootDirectoryUnknownOs() end function TestFileUtil:testGetAbsolutePathOfNoitaRootDirectory() - Logger.trace(Logger.channels.testing, ("Need to verify absolute path of root noita: %s"):format(fu.GetAbsolutePathOfNoitaRootDirectory())) + Logger.trace(Logger.channels.testing, + ("Need to verify absolute path of root noita: %s"):format(fu.GetAbsolutePathOfNoitaRootDirectory())) lu.assertStrContains(fu.GetAbsolutePathOfNoitaRootDirectory(), _G.pathSeparator) -- TODO: Need a better test for this! end From 45cbb1e6ab2c5a0e2d4eec14a04c09118ed5bc5d Mon Sep 17 00:00:00 2001 From: Ismoh <12631485+Ismoh@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:30:09 +0100 Subject: [PATCH 16/26] #113 Manually fixed version, because of workflow issue some days ago. --- mods/noita-mp/.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/noita-mp/.version b/mods/noita-mp/.version index e996d00ff..6f6bee8b7 100644 --- a/mods/noita-mp/.version +++ b/mods/noita-mp/.version @@ -1 +1 @@ -{"version":"v4.1.0-alpha+1195"} +{"version":"v4.0.1-alpha+1195"} From 92dd211f12eb78ea8358f77111de766d66b1c8a4 Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 9 Mar 2023 08:25:10 +1100 Subject: [PATCH 17/26] Change way that the test files are run --- mods/noita-mp/lua_modules/lib/lua/5.1/lfs.dll | Bin 16896 -> 16896 bytes mods/noita-mp/noita-mp-3.0.0-3.rockspec | 4 ++-- mods/noita-mp/output.txt | Bin 0 -> 546714 bytes mods/noita-mp/tests/config_test.lua | 15 --------------- .../files/scripts/NoitaMpSettings_test.lua | 11 +---------- .../extensions/stringExtensions_test.lua | 6 ------ .../extensions/tableExtensions_test.lua | 8 +------- .../tests/files/scripts/init/init__test.lua | 6 ------ .../files/scripts/init/init_logger_test.lua | 8 +------- .../init/init_package_loading_test.lua | 7 +------ .../tests/files/scripts/net/Server_test.lua | 6 ------ .../files/scripts/util/EntityCache_test.lua | 7 +------ .../files/scripts/util/EntityUtils_test.lua | 6 ------ .../files/scripts/util/FileUtils_test.lua | 7 +------ .../files/scripts/util/GlobalsUtils_test.lua | 6 ------ .../files/scripts/util/GuidUtils_test.lua | 5 ----- .../tests/files/scripts/util/Logger_test.lua | 10 ---------- .../scripts/util/NetworkCacheUtils_test.lua | 10 +--------- .../files/scripts/util/NetworkUtils_test.lua | 6 +----- .../scripts/util/NetworkVscUtils_test.lua | 6 ------ .../files/scripts/util/NuidUtils_test.lua | 8 +------- .../tests/files/scripts/util/util_test.lua | 7 +------ mods/noita-mp/tests/init_test.lua | 15 --------------- ...ializeUnitTests.lua => unitTestRunner.lua} | 15 +++++++-------- 24 files changed, 19 insertions(+), 160 deletions(-) create mode 100644 mods/noita-mp/output.txt delete mode 100644 mods/noita-mp/tests/config_test.lua delete mode 100644 mods/noita-mp/tests/init_test.lua rename mods/noita-mp/tests/{_initializeUnitTests.lua => unitTestRunner.lua} (93%) diff --git a/mods/noita-mp/lua_modules/lib/lua/5.1/lfs.dll b/mods/noita-mp/lua_modules/lib/lua/5.1/lfs.dll index 2ac5df5beed1d4316b9e23152fac98e2b31f140f..a7455084113853720d4d3ecd28d2c0a1d18ffe8c 100644 GIT binary patch delta 2978 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 Vo!$_u795`QxpnvC_*2=F|9?u Date: Thu, 9 Mar 2023 00:53:50 +0100 Subject: [PATCH 18/26] Delete init_logger_test.lua Not needed anymore --- .../tests/files/scripts/init/init_logger_test.lua | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 mods/noita-mp/tests/files/scripts/init/init_logger_test.lua diff --git a/mods/noita-mp/tests/files/scripts/init/init_logger_test.lua b/mods/noita-mp/tests/files/scripts/init/init_logger_test.lua deleted file mode 100644 index 226a7dc6e..000000000 --- a/mods/noita-mp/tests/files/scripts/init/init_logger_test.lua +++ /dev/null @@ -1,9 +0,0 @@ -TestInitLogger = {} - -function TestInitLogger:setUp() - -end - -function TestInitLogger:tearDown() - -end \ No newline at end of file From 2a3e48cdd023d0e8e403f49e650ff93aab3144cc Mon Sep 17 00:00:00 2001 From: Torben H Date: Thu, 9 Mar 2023 00:59:09 +0100 Subject: [PATCH 19/26] Update unitTestRunner.lua Slightly reformatting --- mods/noita-mp/tests/unitTestRunner.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/noita-mp/tests/unitTestRunner.lua b/mods/noita-mp/tests/unitTestRunner.lua index 244fde814..d575c411c 100644 --- a/mods/noita-mp/tests/unitTestRunner.lua +++ b/mods/noita-mp/tests/unitTestRunner.lua @@ -1,8 +1,8 @@ _G.isTestLuaContext = true +local params = ... dofile("../noita-mp/files/scripts/init/init_package_loading.lua") local lfs = require("lfs") -local params = ... lu = require("luaunit") --- Returns a list of all files in a directory @@ -98,4 +98,4 @@ for _, testFile in ipairs(testFiles) do print("Loaded test " .. testFile) end -lu.LuaUnit.run(params) \ No newline at end of file +lu.LuaUnit.run(params) From 02f9a580ccf99e8dffebf4a0f2d0191b0eadd019 Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 9 Mar 2023 11:58:57 +1100 Subject: [PATCH 20/26] remove output.txt --- mods/noita-mp/output.txt | Bin 546714 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 mods/noita-mp/output.txt diff --git a/mods/noita-mp/output.txt b/mods/noita-mp/output.txt deleted file mode 100644 index 0d1b4912077501b5f41f7b878a4b0916e679f700..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 546714 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 Vo!$_u795`QxpnvC_*2=F|9?u Date: Thu, 9 Mar 2023 13:57:05 +1100 Subject: [PATCH 21/26] remove unneeded luaunit call --- mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua index 440addf5b..83aa6a04e 100644 --- a/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua @@ -19,7 +19,6 @@ if not Client then require("Client") end -local lu = require("luaunit") local Utils = require("Utils") -- [[ Test ]] -- From ff6bbb40023eea641b2baa24e806d9254c8acf9a Mon Sep 17 00:00:00 2001 From: Gustavo <77560533+ofoxsmith@users.noreply.github.com> Date: Thu, 9 Mar 2023 20:13:44 +1100 Subject: [PATCH 22/26] remove mocking and require calls from each test file that should be moved to the main file --- .../extensions/tableExtensions_test.lua | 16 +----- .../files/scripts/util/EntityCache_test.lua | 1 - .../files/scripts/util/FileUtils_test.lua | 15 ------ .../files/scripts/util/GuidUtils_test.lua | 9 +--- .../tests/files/scripts/util/Logger_test.lua | 9 ---- .../scripts/util/NetworkCacheUtils_test.lua | 49 ------------------- .../files/scripts/util/NetworkUtils_test.lua | 17 ------- .../util/{util_test.lua => Utils_test.lua} | 2 - 8 files changed, 2 insertions(+), 116 deletions(-) rename mods/noita-mp/tests/files/scripts/util/{util_test.lua => Utils_test.lua} (96%) diff --git a/mods/noita-mp/tests/files/scripts/extensions/tableExtensions_test.lua b/mods/noita-mp/tests/files/scripts/extensions/tableExtensions_test.lua index 2565699c4..21cea47ac 100644 --- a/mods/noita-mp/tests/files/scripts/extensions/tableExtensions_test.lua +++ b/mods/noita-mp/tests/files/scripts/extensions/tableExtensions_test.lua @@ -1,21 +1,7 @@ TestTableExtensions = {} function TestTableExtensions:setUp() - -- Make absolutely sure, that the already mocked Noita API function is not overwritten - local mockedModSettingGet = ModSettingGet - ModSettingGet = function(id) - if string.contains(id, "noita-mp.log_level_") then - return { "off", "OFF" } - end - if id == "noita-mp.name" then - return "testName" - end - if id == "noita-mp.guid" then - return GuidUtils:getGuid() - end - - mockedModSettingGet(id) - end + end function TestTableExtensions:tearDown() diff --git a/mods/noita-mp/tests/files/scripts/util/EntityCache_test.lua b/mods/noita-mp/tests/files/scripts/util/EntityCache_test.lua index 15888343c..7a1fd36b7 100644 --- a/mods/noita-mp/tests/files/scripts/util/EntityCache_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/EntityCache_test.lua @@ -1,4 +1,3 @@ -require("luaExtensions") TestEntityCache = {} local guid1 = GuidUtils:getGuid() diff --git a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua index 5e128f316..4ba5d0484 100644 --- a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua @@ -1,18 +1,3 @@ ---- Make absolutely sure, that the already mocked Noita API function is not overwritten -local mockedModSettingGet = ModSettingGet -ModSettingGet = function(id) - if string.contains(id, "noita-mp.log_level_") then - return { "trace, debug, info, warn", "TRACE" } - end - - if mockedModSettingGet then - mockedModSettingGet(id) - end - - error(("Mod setting '%s' is not mocked! Add it!"):format(id), 2) -end - -local fu = require("FileUtils") local os_name = require("os_name") TestFileUtil = {} diff --git a/mods/noita-mp/tests/files/scripts/util/GuidUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/GuidUtils_test.lua index 13a1cf7cf..a6f4d5fa5 100644 --- a/mods/noita-mp/tests/files/scripts/util/GuidUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/GuidUtils_test.lua @@ -1,14 +1,7 @@ -local GuidUtils = require("GuidUtils") - TestGuidUtils = {} function TestGuidUtils:setUp() - -- Make absolutely sure, that the already mocked Noita API function is not overwritten - local mockedDebugGetIsDevBuild = DebugGetIsDevBuild - -- Mock Noita Api global functions - DebugGetIsDevBuild = function() - return DebugGetIsDevBuild or false - end + end function TestGuidUtils:tearDown() diff --git a/mods/noita-mp/tests/files/scripts/util/Logger_test.lua b/mods/noita-mp/tests/files/scripts/util/Logger_test.lua index ff711c7ff..3e7e9a8b4 100644 --- a/mods/noita-mp/tests/files/scripts/util/Logger_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/Logger_test.lua @@ -2,15 +2,6 @@ TestLogger = {} TestLogger.mockedLogLevel = { "trace, debug, info, warn", "TRACE" } function TestLogger:setUp() - -- Make absolutely sure, that the already mocked Noita API function is not overwritten - local mockedModSettingGet = ModSettingGet - ---@param id string - ModSettingGet = function(id) - if string.contains(id, "noita-mp.log_level_") then - return TestLogger.mockedLogLevel - end - mockedModSettingGet(id) - end end diff --git a/mods/noita-mp/tests/files/scripts/util/NetworkCacheUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/NetworkCacheUtils_test.lua index 993d3fc61..cbc12f146 100644 --- a/mods/noita-mp/tests/files/scripts/util/NetworkCacheUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/NetworkCacheUtils_test.lua @@ -1,49 +1,3 @@ ---- Make absolutely sure, that the already mocked Noita API function is not overwritten -local mockedModSettingGetNextValue = ModSettingGetNextValue -ModSettingGetNextValue = function(id) - if id == "noita-mp.guid" then - return GuidUtils:getGuid() - end - - if mockedModSettingGetNextValue then - mockedModSettingGetNextValue(id) - end - - error(("Trying to access '%s', but it isn't mocked yet!"):format(id), 2) -end - -if not ModSettingSetNextValue then - ModSettingSetNextValue = function(id) - Logger.trace(Logger.channels.testing, ("Mocked ModSettingSetNextValue id %s."):format(id)) - return id - end -end - ---- Make absolutely sure, that the already mocked Noita API function is not overwritten -local mockedModSettingGet = ModSettingGet -ModSettingGet = function(id) - if string.contains(id, "noita-mp.log_level_") then - return { "trace, debug, info, warn", "TRACE" } - end - if id == "noita-mp.name" then - return "noita-mp.name" - end - if id == "noita-mp.guid" then - return GuidUtils:getGuid() - end - - if mockedModSettingGet then - mockedModSettingGet(id) - end - - error(("Mod setting '%s' is not mocked! Add it!"):format(id), 2) -end - --- [[ require ]] -- -require("NetworkUtils") -require("NetworkCacheUtils") -require("luaExtensions") -require("CustomProfiler") if not Server then require("Server") end @@ -51,9 +5,6 @@ if not Client then require("Client") end -local lu = require("luaunit") - --- [[ Test ]] -- TestNetworkCacheUtils = {} --- Setup function for each test. diff --git a/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua index 83aa6a04e..0d2b97d10 100644 --- a/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua @@ -1,17 +1,3 @@ --- [[ Mock Noita API functions, which are needed before/during require is used ]] -- -mockedModSettingGetNextValue = ModSettingGetNextValue -ModSettingGetNextValue = function(id) - if mockedModSettingGetNextValue then - mockedModSettingGetNextValue(id) - end -end - --- [[ require ]] -- -require("luaExtensions") -require("EntityUtils") -require("NetworkUtils") -require("GuidUtils") -require("CustomProfiler") if not Server then require("Server") end @@ -19,9 +5,6 @@ if not Client then require("Client") end -local Utils = require("Utils") - --- [[ Test ]] -- TestNetworkUtils = {} --- Setup function for each test. diff --git a/mods/noita-mp/tests/files/scripts/util/util_test.lua b/mods/noita-mp/tests/files/scripts/util/Utils_test.lua similarity index 96% rename from mods/noita-mp/tests/files/scripts/util/util_test.lua rename to mods/noita-mp/tests/files/scripts/util/Utils_test.lua index 332c45191..f1cdbbf47 100644 --- a/mods/noita-mp/tests/files/scripts/util/util_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/Utils_test.lua @@ -1,5 +1,3 @@ -local Utils = require("Utils") - TestUtil = {} function TestUtil:setUp() From d1d4f942dd102ce2950e2331438f2f3a5e0bdd25 Mon Sep 17 00:00:00 2001 From: Ismoh <12631485+Ismoh@users.noreply.github.com> Date: Thu, 9 Mar 2023 11:43:11 +0100 Subject: [PATCH 23/26] #113 Fixed ffiExtensions issue where it was loaded more than once. Added lfs_ffi again, but will be removed soon again, I assume. --- .../scripts/extensions/ffiExtensions.lua | 103 +- .../files/scripts/init/init_logger.lua | 2 +- mods/noita-mp/lua_modules/lib/lua/5.1/lfs.dll | Bin 16896 -> 16896 bytes .../lua_modules/share/lua/5.1/lfs.lua | 1 + .../lua_modules/share/lua/5.1/lfs_ffi.lua | 1339 +++++++++++++++++ ...0-3.rockspec => noita-mp-4.0.1-4.rockspec} | 104 +- 6 files changed, 1456 insertions(+), 93 deletions(-) create mode 100644 mods/noita-mp/lua_modules/share/lua/5.1/lfs.lua create mode 100644 mods/noita-mp/lua_modules/share/lua/5.1/lfs_ffi.lua rename mods/noita-mp/{noita-mp-3.0.0-3.rockspec => noita-mp-4.0.1-4.rockspec} (64%) diff --git a/mods/noita-mp/files/scripts/extensions/ffiExtensions.lua b/mods/noita-mp/files/scripts/extensions/ffiExtensions.lua index 85534ed9f..5435fb2f8 100644 --- a/mods/noita-mp/files/scripts/extensions/ffiExtensions.lua +++ b/mods/noita-mp/files/scripts/extensions/ffiExtensions.lua @@ -4,11 +4,17 @@ if not jit or jit.os ~= "Windows" then return end +if executedAlready then + return +else + executedAlready = true +end + local ffi = require("ffi") -local C = ffi.C +local C = ffi.C -ffi.cdef[[ +ffi.cdef [[ typedef bool BOOL; typedef uint16_t WORD; typedef uint32_t DWORD; @@ -95,37 +101,37 @@ BOOL ReadFile( DWORD GetLastError(); ]] -local EXIT_FAILURE = 1 +local EXIT_FAILURE = 1 local STARTF_USESHOWWINDOW = 1 local STARTF_USESTDHANDLES = 0x100 -local SW_HIDE = 0 -local CREATE_NO_WINDOW = 0x8000000 -local INFINITE = -1 -local HANDLE_FLAG_INHERIT = 1 -local STD_INPUT_HANDLE = -10 -local STD_ERROR_HANDLE = -12 -local ERROR_BROKEN_PIPE = 109 +local SW_HIDE = 0 +local CREATE_NO_WINDOW = 0x8000000 +local INFINITE = -1 +local HANDLE_FLAG_INHERIT = 1 +local STD_INPUT_HANDLE = -10 +local STD_ERROR_HANDLE = -12 +local ERROR_BROKEN_PIPE = 109 function os.execute(commandLine) - local si = ffi.new("STARTUPINFOA") - si.cb = ffi.sizeof(si) - si.dwFlags = STARTF_USESHOWWINDOW + local si = ffi.new("STARTUPINFOA") + si.cb = ffi.sizeof(si) + si.dwFlags = STARTF_USESHOWWINDOW si.wShowWindow = SW_HIDE - local pi = ffi.new("PROCESS_INFORMATION") + local pi = ffi.new("PROCESS_INFORMATION") if not C.CreateProcessA(nil, "cmd /C " .. commandLine, nil, nil, 0, CREATE_NO_WINDOW, nil, nil, si, pi) then return EXIT_FAILURE end C.WaitForSingleObject(pi.hProcess, INFINITE) local exitcode = ffi.new("DWORD[1]") - local ok = C.GetExitCodeProcess(pi.hProcess, exitcode) + local ok = C.GetExitCodeProcess(pi.hProcess, exitcode) C.CloseHandle(pi.hProcess) C.CloseHandle(pi.hThread) return ok and exitcode[0] or EXIT_FAILURE end -local pfile = {} -local pfile_mt = {__index = pfile} +local pfile = {} +local pfile_mt = { __index = pfile } local function checkclosed(pfile) if pfile.pi == nil then @@ -152,33 +158,39 @@ function pfile:read(n) end if type(n) == "number" then - if not fetch(function() return #self.buffer < n end) then + if not fetch(function() + return #self.buffer < n + end) then return nil end - local out = self.buffer:sub(1, n) + local out = self.buffer:sub(1, n) self.buffer = self.buffer:sub(n + 1) if out == "" then out = nil end return out elseif n == "*a" then - if not fetch(function() return true end) then + if not fetch(function() + return true + end) then return nil end - local out = self.buffer + local out = self.buffer self.buffer = "" return out elseif n == "*l" then - if not fetch(function() return not self.buffer:find("\n", nil, true) end) then + if not fetch(function() + return not self.buffer:find("\n", nil, true) + end) then return nil end local out local npos = self.buffer:find("\n", nil, true) if npos then - out = self.buffer:sub(1, npos-1) - self.buffer = self.buffer:sub(npos+1) + out = self.buffer:sub(1, npos - 1) + self.buffer = self.buffer:sub(npos + 1) else - out = self.buffer + out = self.buffer self.buffer = "" if out == "" then out = nil @@ -192,7 +204,9 @@ end function pfile:lines() checkclosed(self) - return function() return self:read("*l") end + return function() + return self:read("*l") + end end function pfile:close() @@ -201,27 +215,28 @@ function pfile:close() C.CloseHandle(self.pipe_outRd[0]) C.WaitForSingleObject(pi.hProcess, INFINITE) local res = C.CloseHandle(pi.hProcess) and C.CloseHandle(pi.hThread) - self.pi = nil + self.pi = nil return res end function io.popen(commandLine) - local sa = ffi.new("SECURITY_ATTRIBUTES", ffi.sizeof("SECURITY_ATTRIBUTES"), nil, true) + local sa = ffi.new("SECURITY_ATTRIBUTES", ffi.sizeof("SECURITY_ATTRIBUTES"), nil, true) - local pipe_outRd, pipe_outWr=ffi.new("HANDLE[1]"), ffi.new("HANDLE[1]") - if not C.CreatePipe(pipe_outRd, pipe_outWr, sa, 0) or not C.SetHandleInformation(pipe_outRd[0], HANDLE_FLAG_INHERIT, 0) then + local pipe_outRd, pipe_outWr = ffi.new("HANDLE[1]"), ffi.new("HANDLE[1]") + if not C.CreatePipe(pipe_outRd, pipe_outWr, sa, 0) or not C.SetHandleInformation(pipe_outRd[0], HANDLE_FLAG_INHERIT, + 0) then return end - local si = ffi.new("STARTUPINFOA") - si.cb = ffi.sizeof(si) - si.dwFlags = STARTF_USESHOWWINDOW + STARTF_USESTDHANDLES + local si = ffi.new("STARTUPINFOA") + si.cb = ffi.sizeof(si) + si.dwFlags = STARTF_USESHOWWINDOW + STARTF_USESTDHANDLES si.wShowWindow = SW_HIDE - si.hStdInput = C.GetStdHandle(STD_INPUT_HANDLE) - si.hStdOutput = pipe_outWr[0] - si.hStdError = C.GetStdHandle(STD_ERROR_HANDLE) + si.hStdInput = C.GetStdHandle(STD_INPUT_HANDLE) + si.hStdOutput = pipe_outWr[0] + si.hStdError = C.GetStdHandle(STD_ERROR_HANDLE) - local pi = ffi.new("PROCESS_INFORMATION") + local pi = ffi.new("PROCESS_INFORMATION") if not C.CreateProcessA(nil, "cmd /C " .. commandLine, nil, nil, 1, CREATE_NO_WINDOW, nil, nil, si, pi) then return end @@ -229,11 +244,11 @@ function io.popen(commandLine) local size = 4096 return setmetatable({ - pi = pi, - pipe_outRd = pipe_outRd, - size = size, - byteBuf = ffi.new("char[?]", size), - bytesRead = ffi.new("DWORD[1]"), - buffer = "" - }, pfile_mt) + pi = pi, + pipe_outRd = pipe_outRd, + size = size, + byteBuf = ffi.new("char[?]", size), + bytesRead = ffi.new("DWORD[1]"), + buffer = "" + }, pfile_mt) end diff --git a/mods/noita-mp/files/scripts/init/init_logger.lua b/mods/noita-mp/files/scripts/init/init_logger.lua index 5d9b59463..95ed342e1 100644 --- a/mods/noita-mp/files/scripts/init/init_logger.lua +++ b/mods/noita-mp/files/scripts/init/init_logger.lua @@ -6,5 +6,5 @@ if not _G.Logger then end Logger.info(Logger.channels.initialize, "_G.Logger initialised!") else - error("ERROR: Unable to init Logger! _G.Logger is nil.", 2) + Logger.info(Logger.channels.initialize, "_G.Logger was already initialised!") end diff --git a/mods/noita-mp/lua_modules/lib/lua/5.1/lfs.dll b/mods/noita-mp/lua_modules/lib/lua/5.1/lfs.dll index a7455084113853720d4d3ecd28d2c0a1d18ffe8c..2ac5df5beed1d4316b9e23152fac98e2b31f140f 100644 GIT binary patch delta 2973 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 MAXPATH - 2 then + error('path too long: ' .. path) + end + local dir_obj = setmetatable({ + _pattern = path..'/*', + closed = false, + }, dirmeta) + return iterator, dir_obj + end + + local wdirmeta = {__index = { + next = witerator, + close = close, + }} + + function _M.wdir(path) + if #path > MAXPATH - 2 then + error('path too long: ' .. path) + end + local dir_obj = setmetatable({ + _pattern = path..'/*', + closed = false, + }, wdirmeta) + return witerator, dir_obj + end + + function _M.dir(path) + if _M.unicode then + return _M.wdir(path) + else + return _M.sdir(path) + end + end + + ffi.cdef([[ + int _fileno(struct FILE *stream); + int fseek(struct FILE *stream, long offset, int origin); + long ftell(struct FILE *stream); + int _locking(int fd, int mode, long nbytes); + ]]) + + local mode_ltype_map = { + r = 2, -- LK_NBLCK + w = 2, -- LK_NBLCK + u = 0, -- LK_UNLCK + } + local SEEK_SET = 0 + local SEEK_END = 2 + + local function lock(fh, mode, start, len) + local lkmode = mode_ltype_map[mode] + if not len or len <= 0 then + if lib.fseek(fh, 0, SEEK_END) ~= 0 then + return nil, errno() + end + len = lib.ftell(fh) + end + if not start or start <= 0 then + start = 0 + end + if lib.fseek(fh, start, SEEK_SET) ~= 0 then + return nil, errno() + end + local fd = lib._fileno(fh) + if lib._locking(fd, lkmode, len) == -1 then + return nil, errno() + end + return true + end + + function _M.lock(filehandle, mode, start, length) + if mode ~= 'r' and mode ~= 'w' then + error("lock: invalid mode") + end + if io.type(filehandle) ~= 'file' then + error("lock: invalid file") + end + local ok, err = lock(filehandle, mode, start, length) + if not ok then + return nil, err + end + return true + end + + function _M.unlock(filehandle, start, length) + if io.type(filehandle) ~= 'file' then + error("unlock: invalid file") + end + local ok, err = lock(filehandle, 'u', start, length) + if not ok then + return nil, err + end + return true + end +else + ffi.cdef([[ + char *getcwd(char *buf, size_t size); + int chdir(const char *path); + int rmdir(const char *pathname); + typedef unsigned int mode_t; + int mkdir(const char *pathname, mode_t mode); + typedef size_t time_t; + struct utimebuf { + time_t actime; + time_t modtime; + }; + int utime(const char *file, const struct utimebuf *times); + int link(const char *oldpath, const char *newpath); + int symlink(const char *oldpath, const char *newpath); + ]]) + + function _M.chdir(path) + if lib.chdir(path) == 0 then + return true + end + return nil, errno() + end + + function _M.currentdir() + local size = MAXPATH + while true do + local buf = ffi.new("char[?]", size) + if lib.getcwd(buf, size) ~= nil then + return ffi_str(buf) + end + local err = errno() + if err ~= ERANGE then + return nil, err + end + size = size * 2 + end + end + + function _M.mkdir(path, mode) + if lib.mkdir(path, mode or 509) == 0 then + return true + end + return nil, errno() + end + + function _M.rmdir(path) + if lib.rmdir(path) == 0 then + return true + end + return nil, errno() + end + + function _M.touch(path, actime, modtime) + local buf + + if type(actime) == "number" then + modtime = modtime or actime + buf = ffi.new("struct utimebuf") + buf.actime = actime + buf.modtime = modtime + end + + local p = ffi.new("unsigned char[?]", #path + 1) + ffi.copy(p, path) + + if lib.utime(p, buf) == 0 then + return true + end + return nil, errno() + end + + function _M.setmode() + return true, "binary" + end + + function _M.link(old, new, symlink) + local f = symlink and lib.symlink or lib.link + if f(old, new) == 0 then + return true + end + return nil, errno() + end + + local dirent_def + if OS == 'OSX' or OS == 'BSD' then + dirent_def = [[ + /* _DARWIN_FEATURE_64_BIT_INODE is NOT defined here? */ + struct dirent { + uint32_t d_ino; + uint16_t d_reclen; + uint8_t d_type; + uint8_t d_namlen; + char d_name[256]; + }; + ]] + else + dirent_def = [[ + struct dirent { + int64_t d_ino; + size_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; + }; + ]] + end + ffi.cdef(dirent_def .. [[ + typedef struct __dirstream DIR; + DIR *opendir(const char *name); + struct dirent *readdir(DIR *dirp); + int closedir(DIR *dirp); + ]]) + + local function close(dir) + if dir._dentry ~= nil then + lib.closedir(dir._dentry) + dir._dentry = nil + dir.closed = true + end + end + + local function iterator(dir) + if dir.closed ~= false then error("closed directory") end + + local entry = lib.readdir(dir._dentry) + if entry ~= nil then + return ffi_str(entry.d_name) + else + close(dir) + return nil + end + end + + local dir_obj_type = ffi.metatype([[ + struct { + DIR *_dentry; + bool closed; + } + ]], + {__index = { + next = iterator, + close = close, + }, __gc = close + }) + + function _M.dir(path) + local dentry = lib.opendir(path) + if dentry == nil then + error("cannot open "..path.." : "..errno()) + end + local dir_obj = ffi.new(dir_obj_type) + dir_obj._dentry = dentry + dir_obj.closed = false; + return iterator, dir_obj + end + + local SEEK_SET = 0 + local F_SETLK = (OS == 'Linux') and 6 or 8 + local mode_ltype_map + local flock_def + if OS == 'Linux' then + flock_def = [[ + struct flock { + short int l_type; + short int l_whence; + int64_t l_start; + int64_t l_len; + int l_pid; + }; + ]] + mode_ltype_map = { + r = 0, -- F_RDLCK + w = 1, -- F_WRLCK + u = 2, -- F_UNLCK + } + else + flock_def = [[ + struct flock { + int64_t l_start; + int64_t l_len; + int32_t l_pid; + short l_type; + short l_whence; + }; + ]] + mode_ltype_map = { + r = 1, -- F_RDLCK + u = 2, -- F_UNLCK + w = 3, -- F_WRLCK + } + end + + ffi.cdef(flock_def..[[ + int fileno(struct FILE *stream); + int fcntl(int fd, int cmd, ... /* arg */ ); + int unlink(const char *path); + ]]) + + local function lock(fd, mode, start, len) + local flock = ffi.new('struct flock') + flock.l_type = mode_ltype_map[mode] + flock.l_whence = SEEK_SET + flock.l_start = start or 0 + flock.l_len = len or 0 + if lib.fcntl(fd, F_SETLK, flock) == -1 then + return nil, errno() + end + return true + end + + function _M.lock(filehandle, mode, start, length) + if mode ~= 'r' and mode ~= 'w' then + error("lock: invalid mode") + end + if io.type(filehandle) ~= 'file' then + error("lock: invalid file") + end + local fd = lib.fileno(filehandle) + local ok, err = lock(fd, mode, start, length) + if not ok then + return nil, err + end + return true + end + + function _M.unlock(filehandle, start, length) + if io.type(filehandle) ~= 'file' then + error("unlock: invalid file") + end + local fd = lib.fileno(filehandle) + local ok, err = lock(fd, 'u', start, length) + if not ok then + return nil, err + end + return true + end +end + +-- lock related +local dir_lock_struct +local create_lockfile +local delete_lockfile + +if OS == 'Windows' then + ffi.cdef([[ + typedef const wchar_t* LPCWSTR; + typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + void *lpSecurityDescriptor; + int bInheritHandle; + } SECURITY_ATTRIBUTES; + typedef SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES; + void *CreateFileW( + LPCWSTR lpFileName, + DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, + void *hTemplateFile + ); + + int CloseHandle(void *hObject); + ]]) + + local GENERIC_WRITE = 0x40000000 + local CREATE_NEW = 1 + local FILE_NORMAL_DELETE_ON_CLOSE = 0x04000080 + + dir_lock_struct = 'struct {void *lockname;}' + + function create_lockfile(dir_lock, _, lockname) + lockname = wchar_t(lockname) + dir_lock.lockname = lib.CreateFileW(lockname, GENERIC_WRITE, 0, nil, CREATE_NEW, + FILE_NORMAL_DELETE_ON_CLOSE, nil) + return dir_lock.lockname ~= ffi.cast('void*', -1) + end + + function delete_lockfile(dir_lock) + return lib.CloseHandle(dir_lock.lockname) + end +else + dir_lock_struct = 'struct {char *lockname;}' + function create_lockfile(dir_lock, path, lockname) + dir_lock.lockname = ffi.new('char[?]', #lockname + 1) + ffi.copy(dir_lock.lockname, lockname) + return lib.symlink(path, lockname) == 0 + end + + function delete_lockfile(dir_lock) + return lib.unlink(dir_lock.lockname) + end +end + +local function unlock_dir(dir_lock) + if dir_lock.lockname ~= nil then + dir_lock:delete_lockfile() + dir_lock.lockname = nil + end + return true +end + +local dir_lock_type = ffi.metatype(dir_lock_struct, + {__gc = unlock_dir, + __index = { + free = unlock_dir, + create_lockfile = create_lockfile, + delete_lockfile = delete_lockfile, + }} +) + +function _M.lock_dir(path, _) + -- It's interesting that the lock_dir from vanilla lfs just ignores second paramter. + -- So, I follow this behavior too :) + local dir_lock = ffi.new(dir_lock_type) + local lockname = path .. '/lockfile.lfs' + if not dir_lock:create_lockfile(path, lockname) then + return nil, errno() + end + return dir_lock +end + +-- stat related +local stat_func +local lstat_func +if OS == 'Linux' then + ffi.cdef([[ + long syscall(int number, ...); + ]]) + local ARCH = ffi.arch + -- Taken from justincormack/ljsyscall + local stat_syscall_num + local lstat_syscall_num + if ARCH == 'x64' then + ffi.cdef([[ + typedef struct { + unsigned long st_dev; + unsigned long st_ino; + unsigned long st_nlink; + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int __pad0; + unsigned long st_rdev; + long st_size; + long st_blksize; + long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned long st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + long __unused[3]; + } lfs_stat; + ]]) + stat_syscall_num = 4 + lstat_syscall_num = 6 + elseif ARCH == 'x86' then + ffi.cdef([[ + typedef struct { + unsigned long long st_dev; + unsigned char __pad0[4]; + unsigned long __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned long st_uid; + unsigned long st_gid; + unsigned long long st_rdev; + unsigned char __pad3[4]; + long long st_size; + unsigned long st_blksize; + unsigned long long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned int st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + unsigned long long st_ino; + } lfs_stat; + ]]) + stat_syscall_num = IS_64_BIT and 106 or 195 + lstat_syscall_num = IS_64_BIT and 107 or 196 + elseif ARCH == 'arm' then + if IS_64_BIT then + ffi.cdef([[ + typedef struct { + unsigned long st_dev; + unsigned long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long st_rdev; + unsigned long __pad1; + long st_size; + int st_blksize; + int __pad2; + long st_blocks; + long st_atime; + unsigned long st_atime_nsec; + long st_mtime; + unsigned long st_mtime_nsec; + long st_ctime; + unsigned long st_ctime_nsec; + unsigned int __unused4; + unsigned int __unused5; + } lfs_stat; + ]]) + stat_syscall_num = 106 + lstat_syscall_num = 107 + else + ffi.cdef([[ + typedef struct { + unsigned long long st_dev; + unsigned char __pad0[4]; + unsigned long __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned long st_uid; + unsigned long st_gid; + unsigned long long st_rdev; + unsigned char __pad3[4]; + long long st_size; + unsigned long st_blksize; + unsigned long long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned int st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + unsigned long long st_ino; + } lfs_stat; + ]]) + stat_syscall_num = 195 + lstat_syscall_num = 196 + end + elseif ARCH == 'ppc' or ARCH == 'ppcspe' then + ffi.cdef([[ + typedef struct { + unsigned long long st_dev; + unsigned long long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long long st_rdev; + unsigned long long __pad1; + long long st_size; + int st_blksize; + int __pad2; + long long st_blocks; + int st_atime; + unsigned int st_atime_nsec; + int st_mtime; + unsigned int st_mtime_nsec; + int st_ctime; + unsigned int st_ctime_nsec; + unsigned int __unused4; + unsigned int __unused5; + } lfs_stat; + ]]) + stat_syscall_num = IS_64_BIT and 106 or 195 + lstat_syscall_num = IS_64_BIT and 107 or 196 + elseif ARCH == 'mips' or ARCH == 'mipsel' then + ffi.cdef([[ + typedef struct { + unsigned long st_dev; + unsigned long __st_pad0[3]; + unsigned long long st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + unsigned long st_rdev; + unsigned long __st_pad1[3]; + long long st_size; + time_t st_atime; + unsigned long st_atime_nsec; + time_t st_mtime; + unsigned long st_mtime_nsec; + time_t st_ctime; + unsigned long st_ctime_nsec; + unsigned long st_blksize; + unsigned long __st_pad2; + long long st_blocks; + long __st_padding4[14]; + } lfs_stat; + ]]) + stat_syscall_num = IS_64_BIT and 4106 or 4213 + lstat_syscall_num = IS_64_BIT and 4107 or 4214 + end + + if stat_syscall_num then + stat_func = function(filepath, buf) + return lib.syscall(stat_syscall_num, filepath, buf) + end + lstat_func = function(filepath, buf) + return lib.syscall(lstat_syscall_num, filepath, buf) + end + else + ffi.cdef('typedef struct {} lfs_stat;') + stat_func = function() error("TODO support other Linux architectures") end + lstat_func = stat_func + end +elseif OS == 'Windows' then + ffi.cdef([[ + typedef __int64 __time64_t; + typedef struct { + unsigned int st_dev; + unsigned short st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + unsigned int st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + } lfs_stat; + + int _stat64(const char *path, lfs_stat *buffer); + int _wstat64(const wchar_t *path, lfs_stat *buffer); + ]]) + + stat_func = function(filepath, buf) + if _M.unicode then + local szfp = win_utf8_to_unicode(filepath); + return lib._wstat64(szfp, buf) + else + return lib._stat64(filepath, buf) + end + end + lstat_func = stat_func +elseif OS == 'OSX' then + ffi.cdef([[ + struct lfs_timespec { + time_t tv_sec; + long tv_nsec; + }; + typedef struct { + uint32_t st_dev; + uint16_t st_mode; + uint16_t st_nlink; + uint64_t st_ino; + uint32_t st_uid; + uint32_t st_gid; + uint32_t st_rdev; + struct lfs_timespec st_atimespec; + struct lfs_timespec st_mtimespec; + struct lfs_timespec st_ctimespec; + struct lfs_timespec st_birthtimespec; + int64_t st_size; + int64_t st_blocks; + int32_t st_blksize; + uint32_t st_flags; + uint32_t st_gen; + int32_t st_lspare; + int64_t st_qspare[2]; + } lfs_stat; + int stat64(const char *path, lfs_stat *buf); + int lstat64(const char *path, lfs_stat *buf); + ]]) + stat_func = lib.stat64 + lstat_func = lib.lstat64 +elseif OS == 'BSD' then + ffi.cdef([[ + struct lfs_timespec { + time_t tv_sec; + long tv_nsec; + }; + typedef struct { + uint32_t st_dev; + uint32_t st_ino; + uint16_t st_mode; + uint16_t st_nlink; + uint32_t st_uid; + uint32_t st_gid; + uint32_t st_rdev; + struct lfs_timespec st_atimespec; + struct lfs_timespec st_mtimespec; + struct lfs_timespec st_ctimespec; + int64_t st_size; + int64_t st_blocks; + int32_t st_blksize; + uint32_t st_flags; + uint32_t st_gen; + int32_t st_lspare; + struct lfs_timespec st_birthtimespec; + } lfs_stat; + int stat(const char *path, lfs_stat *buf); + int lstat(const char *path, lfs_stat *buf); + ]]) + stat_func = lib.stat + lstat_func = lib.lstat +else + ffi.cdef('typedef struct {} lfs_stat;') + stat_func = function() error('TODO: support other posix system') end + lstat_func = stat_func +end + +local STAT = { + FMT = 0xF000, + FSOCK = 0xC000, + FLNK = 0xA000, + FREG = 0x8000, + FBLK = 0x6000, + FDIR = 0x4000, + FCHR = 0x2000, + FIFO = 0x1000, +} + +local ftype_name_map = { + [STAT.FREG] = 'file', + [STAT.FDIR] = 'directory', + [STAT.FLNK] = 'link', + [STAT.FSOCK] = 'socket', + [STAT.FCHR] = 'char device', + [STAT.FBLK] = "block device", + [STAT.FIFO] = "named pipe", +} + +local function mode_to_ftype(mode) + local ftype = band(mode, STAT.FMT) + return ftype_name_map[ftype] or 'other' +end + +local function mode_to_perm(mode) + local perm_bits = band(mode, tonumber(777, 8)) + local perm = new_tab(9, 0) + local i = 9 + while i > 0 do + local perm_bit = band(perm_bits, 7) + perm[i] = (band(perm_bit, 1) > 0 and 'x' or '-') + perm[i-1] = (band(perm_bit, 2) > 0 and 'w' or '-') + perm[i-2] = (band(perm_bit, 4) > 0 and 'r' or '-') + i = i - 3 + perm_bits = rshift(perm_bits, 3) + end + return concat(perm) +end + +local function time_or_timespec(time, timespec) + local t = tonumber(time) + if not t and timespec then + t = tonumber(timespec.tv_sec) + end + return t +end + +local attr_handlers = { + access = function(st) return time_or_timespec(st.st_atime, st.st_atimespec) end, + blksize = function(st) return tonumber(st.st_blksize) end, + blocks = function(st) return tonumber(st.st_blocks) end, + change = function(st) return time_or_timespec(st.st_ctime, st.st_ctimespec) end, + dev = function(st) return tonumber(st.st_dev) end, + gid = function(st) return tonumber(st.st_gid) end, + ino = function(st) return tonumber(st.st_ino) end, + mode = function(st) return mode_to_ftype(st.st_mode) end, + modification = function(st) return time_or_timespec(st.st_mtime, st.st_mtimespec) end, + nlink = function(st) return tonumber(st.st_nlink) end, + permissions = function(st) return mode_to_perm(st.st_mode) end, + rdev = function(st) return tonumber(st.st_rdev) end, + size = function(st) return tonumber(st.st_size) end, + uid = function(st) return tonumber(st.st_uid) end, +} +local mt = { + __index = function(self, attr_name) + local func = attr_handlers[attr_name] + return func and func(self) + end +} +local stat_type = ffi.metatype('lfs_stat', mt) + +-- Add target field for symlinkattributes, which is the absolute path of linked target +local get_link_target_path +if OS == 'Windows' then + local ENOSYS = 40 + function get_link_target_path() + return nil, "could not obtain link target: Function not implemented ",ENOSYS + end +else + + ffi.cdef('ssize_t readlink(const char *path, char *buf, size_t bufsize);') + local EINVAL = 22 + function get_link_target_path(link_path, statbuf) + local size = statbuf.st_size + size = size == 0 and MAXPATH or size + local buf = ffi.new('char[?]', size + 1) + local read = lib.readlink(link_path, buf, size) + if read == -1 then + return nil, "could not obtain link target: "..errno(), ffi.errno() + end + if read > size then + return nil, "not enought size for readlink: "..errno(), ffi.errno() + end + buf[size] = 0 + return ffi_str(buf) + end +end + +local buf = ffi.new(stat_type) +local function attributes(filepath, attr, follow_symlink) + local func = follow_symlink and stat_func or lstat_func + if func(filepath, buf) == -1 then + return nil, string.format("cannot obtain information from file '%s' : %s",tostring(filepath),errno()), ffi.errno() + end + + local atype = type(attr) + if atype == 'string' then + local value, err, errn + if attr == 'target' and not follow_symlink then + value, err, errn = get_link_target_path(filepath, buf) + return value, err, errn + else + value = buf[attr] + end + if value == nil then + error("invalid attribute name '" .. attr .. "'") + end + return value + else + local tab = (atype == 'table') and attr or {} + for k, _ in pairs(attr_handlers) do + tab[k] = buf[k] + end + if not follow_symlink then + tab.target = get_link_target_path(filepath, buf) + end + return tab + end +end + +function _M.attributes(filepath, attr) + return attributes(filepath, attr, true) +end + +function _M.symlinkattributes(filepath, attr) + return attributes(filepath, attr, false) +end + +_M.unicode = HAVE_WFINDFIRST +_M.unicode_errors = false +--this would error with _M.unicode_errors = true +--local cad = string.char(0xE0,0x80,0x80)--,0xFD,0xFF) + +return _M diff --git a/mods/noita-mp/noita-mp-3.0.0-3.rockspec b/mods/noita-mp/noita-mp-4.0.1-4.rockspec similarity index 64% rename from mods/noita-mp/noita-mp-3.0.0-3.rockspec rename to mods/noita-mp/noita-mp-4.0.1-4.rockspec index 859729201..79f64ab2a 100644 --- a/mods/noita-mp/noita-mp-3.0.0-3.rockspec +++ b/mods/noita-mp/noita-mp-4.0.1-4.rockspec @@ -1,6 +1,6 @@ rockspec_format = "3.0" package = "noita-mp" -version = "3.0.0-3" -- Needs to be updated manually and the same as in `.version` file. +version = "4.0.1-4" -- Needs to be updated manually and the same as in `.version` file. source = { url = "git+https://github.com/Ismoh/NoitaMP.git" } @@ -9,64 +9,72 @@ description = { license = "GNU GPL v3" } dependencies = { - "lua ~> 5.1", + "lua = 5.1", + "dkjson = 2.6-1", + "lua-path = 0.3.1-2", + "luacov = 0.15.0-1", + "luacov-coveralls = 0.2.3-1", "luafilesystem = 1.8.0-1", - "luafilesystem-ffi = scm-1", + "luajit-zstd = 0.2.3-1", + "luaposix = 36.1-1", + "luasocket = 3.1.0-1", "luaunit = 3.4-1", + "uuid = 0.3-1", + "winapi = 1.4.2-1" } build = { type = "builtin", modules = { -- change this to copy_directories? Does package path work without `modules`? - config = "config.lua", - ["files.scripts.DefaultBiomeMap"] = "files/scripts/DefaultBiomeMap.lua", - ["files.scripts.Ui"] = "files/scripts/Ui.lua", - ["files.scripts.biome.testingRoom"] = "files/scripts/biome/testingRoom.lua", + config = "config.lua", + ["files.scripts.DefaultBiomeMap"] = "files/scripts/DefaultBiomeMap.lua", + ["files.scripts.Ui"] = "files/scripts/Ui.lua", + ["files.scripts.biome.testingRoom"] = "files/scripts/biome/testingRoom.lua", ["files.scripts.extensions.ffiExtensions"] = "files/scripts/extensions/ffiExtensions.lua", - ["files.scripts.extensions.globalExtensions"] = "files/scripts/extensions/globalExtensions.lua", - ["files.scripts.extensions.mathExtensions"] = "files/scripts/extensions/mathExtensions.lua", + ["files.scripts.extensions.globalExtensions"] = "files/scripts/extensions/globalExtensions.lua", + ["files.scripts.extensions.mathExtensions"] = "files/scripts/extensions/mathExtensions.lua", ["files.scripts.extensions.stringExtensions"] = "files/scripts/extensions/stringExtensions.lua", ["files.scripts.extensions.tableExtensions"] = "files/scripts/extensions/tableExtensions.lua", - ["files.scripts.init.init_"] = "files/scripts/init/init_.lua", - ["files.scripts.init.init_logger"] = "files/scripts/init/init_logger.lua", - ["files.scripts.init.init_package_loading"] = "files/scripts/init/init_package_loading.lua", - ["files.scripts.net.Client"] = "files/scripts/net/Client.lua", - ["files.scripts.net.Server"] = "files/scripts/net/Server.lua", - ["files.scripts.noita-components.dump_logger"] = "files/scripts/noita-components/dump_logger.lua", - ["files.scripts.noita-components.lua_component_enabler"] = "files/scripts/noita-components/lua_component_enabler.lua", - ["files.scripts.noita-components.name_tags"] = "files/scripts/noita-components/name_tags.lua", - ["files.scripts.noita-components.nuid_debug"] = "files/scripts/noita-components/nuid_debug.lua", - ["files.scripts.noita-components.nuid_updater"] = "files/scripts/noita-components/nuid_updater.lua", - ["files.scripts.util.CoroutineUtils"] = "files/scripts/util/CoroutineUtils.lua", - ["files.scripts.util.CustomProfiler"] = "files/scripts/util/CustomProfiler.lua", - ["files.scripts.util.EntityUtils"] = "files/scripts/util/EntityUtils.lua", - ["files.scripts.util.GlobalsUtils"] = "files/scripts/util/GlobalsUtils.lua", - ["files.scripts.util.NetworkUtils"] = "files/scripts/util/NetworkUtils.lua", - ["files.scripts.util.NetworkVscUtils"] = "files/scripts/util/NetworkVscUtils.lua", - ["files.scripts.util.NoitaComponentUtils"] = "files/scripts/util/NoitaComponentUtils.lua", - ["files.scripts.util.NuidUtils"] = "files/scripts/util/NuidUtils.lua", - ["files.scripts.util.FileUtils"] = "files/scripts/util/FileUtils.lua", - ["files.scripts.util.GuidUtils"] = "files/scripts/util/GuidUtils.lua", - ["files.scripts.util.util"] = "files/scripts/util/util.lua", - init = "init.lua", - modSettingsUpdater = "modSettingsUpdater.lua", - settings = "settings.lua", - ["tests.config_test"] = "tests/config_test.lua", + ["files.scripts.init.init_"] = "files/scripts/init/init_.lua", + ["files.scripts.init.init_logger"] = "files/scripts/init/init_logger.lua", + ["files.scripts.init.init_package_loading"] = "files/scripts/init/init_package_loading.lua", + ["files.scripts.net.Client"] = "files/scripts/net/Client.lua", + ["files.scripts.net.Server"] = "files/scripts/net/Server.lua", + ["files.scripts.noita-components.dump_logger"] = "files/scripts/noita-components/dump_logger.lua", + ["files.scripts.noita-components.lua_component_enabler"] = "files/scripts/noita-components/lua_component_enabler.lua", + ["files.scripts.noita-components.name_tags"] = "files/scripts/noita-components/name_tags.lua", + ["files.scripts.noita-components.nuid_debug"] = "files/scripts/noita-components/nuid_debug.lua", + ["files.scripts.noita-components.nuid_updater"] = "files/scripts/noita-components/nuid_updater.lua", + ["files.scripts.util.CoroutineUtils"] = "files/scripts/util/CoroutineUtils.lua", + ["files.scripts.util.CustomProfiler"] = "files/scripts/util/CustomProfiler.lua", + ["files.scripts.util.EntityUtils"] = "files/scripts/util/EntityUtils.lua", + ["files.scripts.util.GlobalsUtils"] = "files/scripts/util/GlobalsUtils.lua", + ["files.scripts.util.NetworkUtils"] = "files/scripts/util/NetworkUtils.lua", + ["files.scripts.util.NetworkVscUtils"] = "files/scripts/util/NetworkVscUtils.lua", + ["files.scripts.util.NoitaComponentUtils"] = "files/scripts/util/NoitaComponentUtils.lua", + ["files.scripts.util.NuidUtils"] = "files/scripts/util/NuidUtils.lua", + ["files.scripts.util.FileUtils"] = "files/scripts/util/FileUtils.lua", + ["files.scripts.util.GuidUtils"] = "files/scripts/util/GuidUtils.lua", + ["files.scripts.util.util"] = "files/scripts/util/util.lua", + init = "init.lua", + modSettingsUpdater = "modSettingsUpdater.lua", + settings = "settings.lua", + ["tests.config_test"] = "tests/config_test.lua", ["tests.files.scripts.extensions.stringExtensions_test"] = "tests/files/scripts/extensions/stringExtensions_test.lua", ["tests.files.scripts.extensions.tableExtensions_test"] = "tests/files/scripts/extensions/tableExtensions_test.lua", - ["tests.files.scripts.init.init__test"] = "tests/files/scripts/init/init__test.lua", - ["tests.files.scripts.init.init_logger_test"] = "tests/files/scripts/init/init_logger_test.lua", - ["tests.files.scripts.init.init_package_loading_test"] = "tests/files/scripts/init/init_package_loading_test.lua", - ["tests.files.scripts.net.Server_test"] = "tests/files/scripts/net/Server_test.lua", - ["tests.files.scripts.util.EntityUtils_test"] = "tests/files/scripts/util/EntityUtils_test.lua", - ["tests.files.scripts.util.GlobalsUtils_test"] = "tests/files/scripts/util/GlobalsUtils_test.lua", - ["tests.files.scripts.util.NetworkUtils_test"] = "tests/files/scripts/util/NetworkUtils_test.lua", - ["tests.files.scripts.util.NetworkVscUtils_test"] = "tests/files/scripts/util/NetworkVscUtils_test.lua", - ["tests.files.scripts.util.NuidUtils_test"] = "tests/files/scripts/util/NuidUtils_test.lua", - ["tests.files.scripts.util.FileUtils_test"] = "tests/files/scripts/util/FileUtils_test.lua", - ["tests.files.scripts.util.GuidUtils_test"] = "tests/files/scripts/util/GuidUtils_test.lua", - ["tests.files.scripts.util.util_test"] = "tests/files/scripts/util/util_test.lua", - ["tests.init_test"] = "tests/init_test.lua", - ["tests.unitTestRunner"] = "tests/unitTestRunner.lua" + ["tests.files.scripts.init.init__test"] = "tests/files/scripts/init/init__test.lua", + ["tests.files.scripts.init.init_logger_test"] = "tests/files/scripts/init/init_logger_test.lua", + ["tests.files.scripts.init.init_package_loading_test"] = "tests/files/scripts/init/init_package_loading_test.lua", + ["tests.files.scripts.net.Server_test"] = "tests/files/scripts/net/Server_test.lua", + ["tests.files.scripts.util.EntityUtils_test"] = "tests/files/scripts/util/EntityUtils_test.lua", + ["tests.files.scripts.util.GlobalsUtils_test"] = "tests/files/scripts/util/GlobalsUtils_test.lua", + ["tests.files.scripts.util.NetworkUtils_test"] = "tests/files/scripts/util/NetworkUtils_test.lua", + ["tests.files.scripts.util.NetworkVscUtils_test"] = "tests/files/scripts/util/NetworkVscUtils_test.lua", + ["tests.files.scripts.util.NuidUtils_test"] = "tests/files/scripts/util/NuidUtils_test.lua", + ["tests.files.scripts.util.FileUtils_test"] = "tests/files/scripts/util/FileUtils_test.lua", + ["tests.files.scripts.util.GuidUtils_test"] = "tests/files/scripts/util/GuidUtils_test.lua", + ["tests.files.scripts.util.util_test"] = "tests/files/scripts/util/util_test.lua", + ["tests.init_test"] = "tests/init_test.lua", + ["tests.unitTestRunner"] = "tests/unitTestRunner.lua" }, } test = { From 0668d2c240bd519aa4d963a4738dab9fa1476d0f Mon Sep 17 00:00:00 2001 From: Ismoh <12631485+Ismoh@users.noreply.github.com> Date: Thu, 9 Mar 2023 11:51:36 +0100 Subject: [PATCH 24/26] #113 Fixed recursive unitTestRunner execution. --- mods/noita-mp/tests/unitTestRunner.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/noita-mp/tests/unitTestRunner.lua b/mods/noita-mp/tests/unitTestRunner.lua index d575c411c..dd5450876 100644 --- a/mods/noita-mp/tests/unitTestRunner.lua +++ b/mods/noita-mp/tests/unitTestRunner.lua @@ -9,7 +9,7 @@ lu = require("luaunit") function getAllFilesInside(folder) local files = {} for entry in lfs.dir(folder) do - if entry ~= "." and entry ~= ".." and not entry:find("_initializeUnitTests") then + if entry ~= "." and entry ~= ".." and not entry:find("unitTestRunner") then local path = folder .. "/" .. entry local mode = lfs.attributes(path, "mode") if mode == "file" then @@ -95,7 +95,7 @@ dofile("mods/noita-mp/files/scripts/init/init_.lua") for _, testFile in ipairs(testFiles) do dofile(testFile) - print("Loaded test " .. testFile) + print("Loaded test " .. _ .. " " .. testFile) end lu.LuaUnit.run(params) From 222004430b4e71ab93118f4da08fe715f3c09f14 Mon Sep 17 00:00:00 2001 From: Ismoh <12631485+Ismoh@users.noreply.github.com> Date: Thu, 9 Mar 2023 11:53:33 +0100 Subject: [PATCH 25/26] #113 Removed unnecessary lfs_ffi again. Removed hack, for not loading ffiExtensions more than once, but this hided the initial error. --- .../scripts/extensions/ffiExtensions.lua | 6 - .../lua_modules/share/lua/5.1/lfs.lua | 1 - .../lua_modules/share/lua/5.1/lfs_ffi.lua | 1339 ----------------- 3 files changed, 1346 deletions(-) delete mode 100644 mods/noita-mp/lua_modules/share/lua/5.1/lfs.lua delete mode 100644 mods/noita-mp/lua_modules/share/lua/5.1/lfs_ffi.lua diff --git a/mods/noita-mp/files/scripts/extensions/ffiExtensions.lua b/mods/noita-mp/files/scripts/extensions/ffiExtensions.lua index 5435fb2f8..a239d8112 100644 --- a/mods/noita-mp/files/scripts/extensions/ffiExtensions.lua +++ b/mods/noita-mp/files/scripts/extensions/ffiExtensions.lua @@ -4,12 +4,6 @@ if not jit or jit.os ~= "Windows" then return end -if executedAlready then - return -else - executedAlready = true -end - local ffi = require("ffi") local C = ffi.C diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/lfs.lua b/mods/noita-mp/lua_modules/share/lua/5.1/lfs.lua deleted file mode 100644 index 066c7ed30..000000000 --- a/mods/noita-mp/lua_modules/share/lua/5.1/lfs.lua +++ /dev/null @@ -1 +0,0 @@ -return require"lfs_ffi" \ No newline at end of file diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/lfs_ffi.lua b/mods/noita-mp/lua_modules/share/lua/5.1/lfs_ffi.lua deleted file mode 100644 index 3da28c561..000000000 --- a/mods/noita-mp/lua_modules/share/lua/5.1/lfs_ffi.lua +++ /dev/null @@ -1,1339 +0,0 @@ -local bit = require "bit" -local ffi = require "ffi" - - -local band = bit.band -local rshift = bit.rshift -local lib = ffi.C -local ffi_str = ffi.string -local concat = table.concat -local has_table_new, new_tab = pcall(require, "table.new") -if not has_table_new or type(new_tab) ~= "function" then - new_tab = function () return {} end -end - - -local _M = { - _VERSION = "0.1", -} - --- common utils/constants -local IS_64_BIT = ffi.abi('64bit') -local ERANGE = 'Result too large' - -if not pcall(ffi.typeof, "ssize_t") then - -- LuaJIT 2.0 doesn't have ssize_t as a builtin type, let's define it - ffi.cdef("typedef intptr_t ssize_t") -end - -ffi.cdef([[ - char* strerror(int errnum); -]]) - -local function errno() - return ffi_str(lib.strerror(ffi.errno())) -end - -local OS = ffi.os --- sys/syslimits.h -local MAXPATH -local MAXPATH_UNC = 32760 -local HAVE_WFINDFIRST = true -local wchar_t -local win_utf8_to_unicode -local win_unicode_to_utf8 -if OS == 'Windows' then - MAXPATH = 260 - ffi.cdef([[ - typedef int mbstate_t; - /* - In VC2015, M$ change the definition of mbstate_t to this and breaks the ABI. - */ - typedef struct _Mbstatet - { // state of a multibyte translation - unsigned long _Wchar; - unsigned short _Byte, _State; - } _Mbstatet; - typedef _Mbstatet mbstate_t; - - size_t mbrtowc(wchar_t* pwc, - const char* s, - size_t n, - mbstate_t* ps); - ]]) - - function wchar_t(s) - local mbstate = ffi.new('mbstate_t[1]') - local wcs = ffi.new('wchar_t[?]', #s + 1) - local i = 0 - local offset = 0 - local len = #s - while true do - local processed = lib.mbrtowc( - wcs + i, ffi.cast('const char *', s) + offset, len, mbstate) - if processed <= 0 then break end - i = i + 1 - offset = offset + processed - len = len - processed - end - return wcs - end - -elseif OS == 'Linux' then - MAXPATH = 4096 -else - MAXPATH = 1024 -end - --- misc -if OS == "Windows" then - local utime_def - if IS_64_BIT then - utime_def = [[ - typedef __int64 time_t; - struct __utimebuf64 { - time_t actime; - time_t modtime; - }; - typedef struct __utimebuf64 utimebuf; - int _utime64(unsigned char *file, utimebuf *times); - ]] - else - utime_def = [[ - typedef __int32 time_t; - struct __utimebuf32 { - time_t actime; - time_t modtime; - }; - typedef struct __utimebuf32 utimebuf; - int _utime632(unsigned char *file, utimebuf *times); - ]] - end - - ffi.cdef([[ - char *_getcwd(char *buf, size_t size); - wchar_t *_wgetcwd(wchar_t *buf, size_t size); - int _chdir(const char *path); - int _wchdir(const wchar_t *path); - int _rmdir(const char *pathname); - int _wrmdir(const wchar_t *pathname); - int _mkdir(const char *pathname); - int _wmkdir(const wchar_t *pathname); - ]] .. utime_def .. [[ - typedef wchar_t* LPTSTR; - typedef unsigned char BOOLEAN; - typedef unsigned long DWORD; - BOOLEAN CreateSymbolicLinkW( - LPTSTR lpSymlinkFileName, - LPTSTR lpTargetFileName, - DWORD dwFlags - ); - - int _fileno(struct FILE *stream); - int _setmode(int fd, int mode); - ]]) - - ffi.cdef([[ - - size_t wcslen(const wchar_t *str); - wchar_t *wcsncpy(wchar_t *strDest, const wchar_t *strSource, size_t count); - - int WideCharToMultiByte( - unsigned int CodePage, - DWORD dwFlags, - const wchar_t* lpWideCharStr, - int cchWideChar, - char* lpMultiByteStr, - int cbMultiByte, - const char* lpDefaultChar, - int* lpUsedDefaultChar); - - int MultiByteToWideChar( - unsigned int CodePage, - DWORD dwFlags, - const char* lpMultiByteStr, - int cbMultiByte, - wchar_t* lpWideCharStr, - int cchWideChar); - - ]]) - ffi.cdef[[ - - uint32_t GetLastError(); - uint32_t FormatMessageA( - uint32_t dwFlags, - const void* lpSource, - uint32_t dwMessageId, - uint32_t dwLanguageId, - char* lpBuffer, - uint32_t nSize, - va_list *Arguments - ); - ]] - -- Some helper functions - local function error_win(lvl) - local errcode = ffi.C.GetLastError() - local str = ffi.new("char[?]",1024) - local FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; - local FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; - local numout = ffi.C.FormatMessageA(bit.bor(FORMAT_MESSAGE_FROM_SYSTEM, - FORMAT_MESSAGE_IGNORE_INSERTS), nil, errcode, 0, str, 1023, nil) - if numout == 0 then - error("Windows Error: (Error calling FormatMessage)", lvl) - else - error("Windows Error: "..ffi.string(str, numout), lvl) - end - end - local CP_UTF8 = 65001 - local WC_ERR_INVALID_CHARS = 0x00000080 - local MB_ERR_INVALID_CHARS = 0x00000008 - function win_utf8_to_unicode(szUtf8) - local dwFlags = _M.unicode_errors and MB_ERR_INVALID_CHARS or 0 - local nLenWchar = lib.MultiByteToWideChar(CP_UTF8, dwFlags, szUtf8, -1, nil, 0 ); - if nLenWchar ==0 then error_win(2) end - local szUnicode = ffi.new("wchar_t[?]",nLenWchar) - nLenWchar = lib.MultiByteToWideChar(CP_UTF8, dwFlags, szUtf8, -1, szUnicode, nLenWchar); - if nLenWchar ==0 then error_win(2) end - return szUnicode, nLenWchar - end - _M.win_utf8_to_unicode = win_utf8_to_unicode - function win_unicode_to_utf8( szUnicode) - local dwFlags = _M.unicode_errors and WC_ERR_INVALID_CHARS or 0 - local nLen = lib.WideCharToMultiByte(CP_UTF8, dwFlags, szUnicode, -1, nil, 0, nil, nil); - if nLen ==0 then error_win(2) end - local str = ffi.new("char[?]",nLen) - nLen = lib.WideCharToMultiByte(CP_UTF8, dwFlags, szUnicode, -1, str, nLen, nil, nil); - if nLen ==0 then error_win(2) end - return str - end - _M.win_unicode_to_utf8 = win_unicode_to_utf8 - local CP_ACP = 0 - function _M.win_utf8_to_acp(utf) - local szUnicode = win_utf8_to_unicode(utf) - local dwFlags = _M.unicode_errors and WC_ERR_INVALID_CHARS or 0 - local nLen = lib.WideCharToMultiByte(CP_ACP, dwFlags, szUnicode, -1, nil, 0, nil, nil); - if nLen ==0 then error_win(2) end - local str = ffi.new("char[?]",nLen) - nLen = lib.WideCharToMultiByte(CP_ACP, dwFlags, szUnicode, -1, str, nLen, nil, nil); - if nLen ==0 then error_win(2) end - return ffi_str(str) - end - function _M.chdir(path) - if _M.unicode then - local uncstr = win_utf8_to_unicode(path) - if lib._wchdir(uncstr) == 0 then return true end - else - if type(path) ~= 'string' then - error('path should be a string') - end - if lib._chdir(path) == 0 then - return true - end - end - return nil, errno() - end - - function _M.currentdir() - if _M.unicode then - local buf = ffi.new("wchar_t[?]",MAXPATH_UNC) - if lib._wgetcwd(buf, MAXPATH_UNC) ~= nil then - local buf_utf = win_unicode_to_utf8(buf) - return ffi_str(buf_utf) - end - error("error in currentdir") - else - local size = MAXPATH - while true do - local buf = ffi.new("char[?]", size) - if lib._getcwd(buf, size) ~= nil then - return ffi_str(buf) - end - local err = errno() - if err ~= ERANGE then - return nil, err - end - size = size * 2 - end - end - end - - function _M.mkdir(path) - if _M.unicode then - local unc_str = win_utf8_to_unicode(path) - if lib._wmkdir(unc_str) == 0 then - return true - end - else - if type(path) ~= 'string' then - error('path should be a string') - end - if lib._mkdir(path) == 0 then - return true - end - end - return nil, errno() - end - - function _M.rmdir(path) - if _M.unicode then - local unc_str = win_utf8_to_unicode(path) - if lib._wrmdir(unc_str) == 0 then - return true - end - else - if type(path) ~= 'string' then - error('path should be a string') - end - if lib._rmdir(path) == 0 then - return true - end - end - return nil, errno() - end - - function _M.touch(path, actime, modtime) - local buf - - if type(actime) == "number" then - modtime = modtime or actime - buf = ffi.new("utimebuf") - buf.actime = actime - buf.modtime = modtime - end - - local p = ffi.new("unsigned char[?]", #path + 1) - ffi.copy(p, path) - local utime = IS_64_BIT and lib._utime64 or lib._utime32 - if utime(p, buf) == 0 then - return true - end - return nil, errno() - end - - function _M.setmode(file, mode) - if io.type(file) ~= 'file' then - error("setmode: invalid file") - end - if mode ~= nil and (mode ~= 'text' and mode ~= 'binary') then - error('setmode: invalid mode') - end - mode = (mode == 'text') and 0x4000 or 0x8000 - local prev_mode = lib._setmode(lib._fileno(file), mode) - if prev_mode == -1 then - return nil, errno() - end - return true, (prev_mode == 0x4000) and 'text' or 'binary' - end - - local function check_is_dir(path) - return _M.attributes(path, 'mode') == 'directory' and 1 or 0 - end - - function _M.link(old, new) - local is_dir = check_is_dir(old) - if lib.CreateSymbolicLinkW( - wchar_t(new), - wchar_t(old), is_dir) ~= 0 then - return true - end - return nil, errno() - end - - local findfirst - local findnext - local wfindfirst - local wfindnext - if IS_64_BIT then - ffi.cdef([[ - typedef struct _finddata64_t { - uint64_t attrib; - uint64_t time_create; - uint64_t time_access; - uint64_t time_write; - uint64_t size; - char name[]] .. MAXPATH ..[[]; - } _finddata_t; - intptr_t _findfirst64(const char *filespec, _finddata_t *fileinfo); - int _findnext64(intptr_t handle, _finddata_t *fileinfo); - int _findclose(intptr_t handle); - typedef struct _wfinddata_t { //is _wfinddata64_t - uint64_t attrib; - uint64_t time_create; - uint64_t time_access; - uint64_t time_write; - uint64_t size; - wchar_t name[]] .. MAXPATH ..[[]; - } _wfinddata_t; - intptr_t _wfindfirst64(const wchar_t *filespec, struct _wfinddata_t *fileinfo); - int _wfindnext64(intptr_t handle,struct _wfinddata_t *fileinfo); - - ]]) - findfirst = lib._findfirst64 - findnext = lib._findnext64 - wfindfirst = lib._wfindfirst64 - wfindnext = lib._wfindnext64 - else - ffi.cdef([[ - typedef struct _finddata32_t { - uint32_t attrib; - uint32_t time_create; - uint32_t time_access; - uint32_t time_write; - uint32_t size; - char name[]] .. MAXPATH ..[[]; - } _finddata_t; - intptr_t _findfirst32(const char* filespec, _finddata_t* fileinfo); - int _findnext32(intptr_t handle, _finddata_t *fileinfo); - - intptr_t _findfirst(const char* filespec, _finddata_t* fileinfo); - int _findnext(intptr_t handle, _finddata_t *fileinfo); - - typedef struct _wfinddata_t { - uint32_t attrib; - uint32_t time_create; - uint32_t time_access; - uint32_t time_write; - uint32_t size; - wchar_t name[]] .. MAXPATH ..[[]; - } _wfinddata_t; - intptr_t _wfindfirst( - const wchar_t *filespec, - struct _wfinddata_t *fileinfo - ); - intptr_t _wfindfirst32( - const wchar_t *filespec, - struct _wfinddata_t *fileinfo - ); - - int _wfindnext( - intptr_t handle, - struct _wfinddata_t *fileinfo - ); - int _wfindnext32( - intptr_t handle, - struct _wfinddata_t *fileinfo - ); - int _findclose(intptr_t handle); - ]]) - local ok - ok,findfirst = pcall(function() return lib._findfirst32 end) - if not ok then findfirst = lib._findfirst end - ok,findnext = pcall(function() return lib._findnext32 end) - if not ok then findnext = lib._findnext end - ok,wfindfirst = pcall(function() return lib._wfindfirst end) - if not ok then ok,wfindfirst = pcall(function() return lib._wfindfirst32 end) end - if not ok then HAVE_WFINDFIRST = false end - ok,wfindnext = pcall(function() return lib._wfindnext end) - if not ok then ok,wfindnext = pcall(function() return lib._wfindnext32 end) end - end - - local function findclose(dentry) - if dentry and dentry.handle ~= -1 then - lib._findclose(dentry.handle) - dentry.handle = -1 - end - end - - local dir_type = ffi.metatype("struct {intptr_t handle;}", { - __gc = findclose - }) - - local function close(dir) - findclose(dir._dentry) - dir.closed = true - end - - local function iterator(dir) - if dir.closed ~= false then error("closed directory") end - local entry = ffi.new("_finddata_t") - if not dir._dentry then - dir._dentry = ffi.new(dir_type) - dir._dentry.handle = findfirst(dir._pattern, entry) - if dir._dentry.handle == -1 then - dir.closed = true - return nil, errno() - end - return ffi_str(entry.name) - end - - if findnext(dir._dentry.handle, entry) == 0 then - return ffi_str(entry.name) - end - close(dir) - return nil - end - - local function witerator(dir) - if dir.closed ~= false then error("closed directory") end - local entry = ffi.new("_wfinddata_t") - if not dir._dentry then - dir._dentry = ffi.new(dir_type) - local szPattern = win_utf8_to_unicode(dir._pattern); - dir._dentry.handle = wfindfirst(szPattern, entry) - if dir._dentry.handle == -1 then - dir.closed = true - return nil, errno() - end - local szName = win_unicode_to_utf8(entry.name)--, -1, szName, 512); - return ffi_str(szName) - end - - if wfindnext(dir._dentry.handle, entry) == 0 then - local szName = win_unicode_to_utf8(entry.name)--, -1, szName, 512); - return ffi_str(szName) - end - close(dir) - return nil - end - - local dirmeta = {__index = { - next = iterator, - close = close, - }} - - function _M.sdir(path) - if #path > MAXPATH - 2 then - error('path too long: ' .. path) - end - local dir_obj = setmetatable({ - _pattern = path..'/*', - closed = false, - }, dirmeta) - return iterator, dir_obj - end - - local wdirmeta = {__index = { - next = witerator, - close = close, - }} - - function _M.wdir(path) - if #path > MAXPATH - 2 then - error('path too long: ' .. path) - end - local dir_obj = setmetatable({ - _pattern = path..'/*', - closed = false, - }, wdirmeta) - return witerator, dir_obj - end - - function _M.dir(path) - if _M.unicode then - return _M.wdir(path) - else - return _M.sdir(path) - end - end - - ffi.cdef([[ - int _fileno(struct FILE *stream); - int fseek(struct FILE *stream, long offset, int origin); - long ftell(struct FILE *stream); - int _locking(int fd, int mode, long nbytes); - ]]) - - local mode_ltype_map = { - r = 2, -- LK_NBLCK - w = 2, -- LK_NBLCK - u = 0, -- LK_UNLCK - } - local SEEK_SET = 0 - local SEEK_END = 2 - - local function lock(fh, mode, start, len) - local lkmode = mode_ltype_map[mode] - if not len or len <= 0 then - if lib.fseek(fh, 0, SEEK_END) ~= 0 then - return nil, errno() - end - len = lib.ftell(fh) - end - if not start or start <= 0 then - start = 0 - end - if lib.fseek(fh, start, SEEK_SET) ~= 0 then - return nil, errno() - end - local fd = lib._fileno(fh) - if lib._locking(fd, lkmode, len) == -1 then - return nil, errno() - end - return true - end - - function _M.lock(filehandle, mode, start, length) - if mode ~= 'r' and mode ~= 'w' then - error("lock: invalid mode") - end - if io.type(filehandle) ~= 'file' then - error("lock: invalid file") - end - local ok, err = lock(filehandle, mode, start, length) - if not ok then - return nil, err - end - return true - end - - function _M.unlock(filehandle, start, length) - if io.type(filehandle) ~= 'file' then - error("unlock: invalid file") - end - local ok, err = lock(filehandle, 'u', start, length) - if not ok then - return nil, err - end - return true - end -else - ffi.cdef([[ - char *getcwd(char *buf, size_t size); - int chdir(const char *path); - int rmdir(const char *pathname); - typedef unsigned int mode_t; - int mkdir(const char *pathname, mode_t mode); - typedef size_t time_t; - struct utimebuf { - time_t actime; - time_t modtime; - }; - int utime(const char *file, const struct utimebuf *times); - int link(const char *oldpath, const char *newpath); - int symlink(const char *oldpath, const char *newpath); - ]]) - - function _M.chdir(path) - if lib.chdir(path) == 0 then - return true - end - return nil, errno() - end - - function _M.currentdir() - local size = MAXPATH - while true do - local buf = ffi.new("char[?]", size) - if lib.getcwd(buf, size) ~= nil then - return ffi_str(buf) - end - local err = errno() - if err ~= ERANGE then - return nil, err - end - size = size * 2 - end - end - - function _M.mkdir(path, mode) - if lib.mkdir(path, mode or 509) == 0 then - return true - end - return nil, errno() - end - - function _M.rmdir(path) - if lib.rmdir(path) == 0 then - return true - end - return nil, errno() - end - - function _M.touch(path, actime, modtime) - local buf - - if type(actime) == "number" then - modtime = modtime or actime - buf = ffi.new("struct utimebuf") - buf.actime = actime - buf.modtime = modtime - end - - local p = ffi.new("unsigned char[?]", #path + 1) - ffi.copy(p, path) - - if lib.utime(p, buf) == 0 then - return true - end - return nil, errno() - end - - function _M.setmode() - return true, "binary" - end - - function _M.link(old, new, symlink) - local f = symlink and lib.symlink or lib.link - if f(old, new) == 0 then - return true - end - return nil, errno() - end - - local dirent_def - if OS == 'OSX' or OS == 'BSD' then - dirent_def = [[ - /* _DARWIN_FEATURE_64_BIT_INODE is NOT defined here? */ - struct dirent { - uint32_t d_ino; - uint16_t d_reclen; - uint8_t d_type; - uint8_t d_namlen; - char d_name[256]; - }; - ]] - else - dirent_def = [[ - struct dirent { - int64_t d_ino; - size_t d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[256]; - }; - ]] - end - ffi.cdef(dirent_def .. [[ - typedef struct __dirstream DIR; - DIR *opendir(const char *name); - struct dirent *readdir(DIR *dirp); - int closedir(DIR *dirp); - ]]) - - local function close(dir) - if dir._dentry ~= nil then - lib.closedir(dir._dentry) - dir._dentry = nil - dir.closed = true - end - end - - local function iterator(dir) - if dir.closed ~= false then error("closed directory") end - - local entry = lib.readdir(dir._dentry) - if entry ~= nil then - return ffi_str(entry.d_name) - else - close(dir) - return nil - end - end - - local dir_obj_type = ffi.metatype([[ - struct { - DIR *_dentry; - bool closed; - } - ]], - {__index = { - next = iterator, - close = close, - }, __gc = close - }) - - function _M.dir(path) - local dentry = lib.opendir(path) - if dentry == nil then - error("cannot open "..path.." : "..errno()) - end - local dir_obj = ffi.new(dir_obj_type) - dir_obj._dentry = dentry - dir_obj.closed = false; - return iterator, dir_obj - end - - local SEEK_SET = 0 - local F_SETLK = (OS == 'Linux') and 6 or 8 - local mode_ltype_map - local flock_def - if OS == 'Linux' then - flock_def = [[ - struct flock { - short int l_type; - short int l_whence; - int64_t l_start; - int64_t l_len; - int l_pid; - }; - ]] - mode_ltype_map = { - r = 0, -- F_RDLCK - w = 1, -- F_WRLCK - u = 2, -- F_UNLCK - } - else - flock_def = [[ - struct flock { - int64_t l_start; - int64_t l_len; - int32_t l_pid; - short l_type; - short l_whence; - }; - ]] - mode_ltype_map = { - r = 1, -- F_RDLCK - u = 2, -- F_UNLCK - w = 3, -- F_WRLCK - } - end - - ffi.cdef(flock_def..[[ - int fileno(struct FILE *stream); - int fcntl(int fd, int cmd, ... /* arg */ ); - int unlink(const char *path); - ]]) - - local function lock(fd, mode, start, len) - local flock = ffi.new('struct flock') - flock.l_type = mode_ltype_map[mode] - flock.l_whence = SEEK_SET - flock.l_start = start or 0 - flock.l_len = len or 0 - if lib.fcntl(fd, F_SETLK, flock) == -1 then - return nil, errno() - end - return true - end - - function _M.lock(filehandle, mode, start, length) - if mode ~= 'r' and mode ~= 'w' then - error("lock: invalid mode") - end - if io.type(filehandle) ~= 'file' then - error("lock: invalid file") - end - local fd = lib.fileno(filehandle) - local ok, err = lock(fd, mode, start, length) - if not ok then - return nil, err - end - return true - end - - function _M.unlock(filehandle, start, length) - if io.type(filehandle) ~= 'file' then - error("unlock: invalid file") - end - local fd = lib.fileno(filehandle) - local ok, err = lock(fd, 'u', start, length) - if not ok then - return nil, err - end - return true - end -end - --- lock related -local dir_lock_struct -local create_lockfile -local delete_lockfile - -if OS == 'Windows' then - ffi.cdef([[ - typedef const wchar_t* LPCWSTR; - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - void *lpSecurityDescriptor; - int bInheritHandle; - } SECURITY_ATTRIBUTES; - typedef SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES; - void *CreateFileW( - LPCWSTR lpFileName, - DWORD dwDesiredAccess, - DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, - DWORD dwFlagsAndAttributes, - void *hTemplateFile - ); - - int CloseHandle(void *hObject); - ]]) - - local GENERIC_WRITE = 0x40000000 - local CREATE_NEW = 1 - local FILE_NORMAL_DELETE_ON_CLOSE = 0x04000080 - - dir_lock_struct = 'struct {void *lockname;}' - - function create_lockfile(dir_lock, _, lockname) - lockname = wchar_t(lockname) - dir_lock.lockname = lib.CreateFileW(lockname, GENERIC_WRITE, 0, nil, CREATE_NEW, - FILE_NORMAL_DELETE_ON_CLOSE, nil) - return dir_lock.lockname ~= ffi.cast('void*', -1) - end - - function delete_lockfile(dir_lock) - return lib.CloseHandle(dir_lock.lockname) - end -else - dir_lock_struct = 'struct {char *lockname;}' - function create_lockfile(dir_lock, path, lockname) - dir_lock.lockname = ffi.new('char[?]', #lockname + 1) - ffi.copy(dir_lock.lockname, lockname) - return lib.symlink(path, lockname) == 0 - end - - function delete_lockfile(dir_lock) - return lib.unlink(dir_lock.lockname) - end -end - -local function unlock_dir(dir_lock) - if dir_lock.lockname ~= nil then - dir_lock:delete_lockfile() - dir_lock.lockname = nil - end - return true -end - -local dir_lock_type = ffi.metatype(dir_lock_struct, - {__gc = unlock_dir, - __index = { - free = unlock_dir, - create_lockfile = create_lockfile, - delete_lockfile = delete_lockfile, - }} -) - -function _M.lock_dir(path, _) - -- It's interesting that the lock_dir from vanilla lfs just ignores second paramter. - -- So, I follow this behavior too :) - local dir_lock = ffi.new(dir_lock_type) - local lockname = path .. '/lockfile.lfs' - if not dir_lock:create_lockfile(path, lockname) then - return nil, errno() - end - return dir_lock -end - --- stat related -local stat_func -local lstat_func -if OS == 'Linux' then - ffi.cdef([[ - long syscall(int number, ...); - ]]) - local ARCH = ffi.arch - -- Taken from justincormack/ljsyscall - local stat_syscall_num - local lstat_syscall_num - if ARCH == 'x64' then - ffi.cdef([[ - typedef struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned long st_nlink; - unsigned int st_mode; - unsigned int st_uid; - unsigned int st_gid; - unsigned int __pad0; - unsigned long st_rdev; - long st_size; - long st_blksize; - long st_blocks; - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned long st_mtime_nsec; - unsigned long st_ctime; - unsigned long st_ctime_nsec; - long __unused[3]; - } lfs_stat; - ]]) - stat_syscall_num = 4 - lstat_syscall_num = 6 - elseif ARCH == 'x86' then - ffi.cdef([[ - typedef struct { - unsigned long long st_dev; - unsigned char __pad0[4]; - unsigned long __st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned long st_uid; - unsigned long st_gid; - unsigned long long st_rdev; - unsigned char __pad3[4]; - long long st_size; - unsigned long st_blksize; - unsigned long long st_blocks; - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned int st_mtime_nsec; - unsigned long st_ctime; - unsigned long st_ctime_nsec; - unsigned long long st_ino; - } lfs_stat; - ]]) - stat_syscall_num = IS_64_BIT and 106 or 195 - lstat_syscall_num = IS_64_BIT and 107 or 196 - elseif ARCH == 'arm' then - if IS_64_BIT then - ffi.cdef([[ - typedef struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - unsigned long st_rdev; - unsigned long __pad1; - long st_size; - int st_blksize; - int __pad2; - long st_blocks; - long st_atime; - unsigned long st_atime_nsec; - long st_mtime; - unsigned long st_mtime_nsec; - long st_ctime; - unsigned long st_ctime_nsec; - unsigned int __unused4; - unsigned int __unused5; - } lfs_stat; - ]]) - stat_syscall_num = 106 - lstat_syscall_num = 107 - else - ffi.cdef([[ - typedef struct { - unsigned long long st_dev; - unsigned char __pad0[4]; - unsigned long __st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned long st_uid; - unsigned long st_gid; - unsigned long long st_rdev; - unsigned char __pad3[4]; - long long st_size; - unsigned long st_blksize; - unsigned long long st_blocks; - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned int st_mtime_nsec; - unsigned long st_ctime; - unsigned long st_ctime_nsec; - unsigned long long st_ino; - } lfs_stat; - ]]) - stat_syscall_num = 195 - lstat_syscall_num = 196 - end - elseif ARCH == 'ppc' or ARCH == 'ppcspe' then - ffi.cdef([[ - typedef struct { - unsigned long long st_dev; - unsigned long long st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - unsigned long long st_rdev; - unsigned long long __pad1; - long long st_size; - int st_blksize; - int __pad2; - long long st_blocks; - int st_atime; - unsigned int st_atime_nsec; - int st_mtime; - unsigned int st_mtime_nsec; - int st_ctime; - unsigned int st_ctime_nsec; - unsigned int __unused4; - unsigned int __unused5; - } lfs_stat; - ]]) - stat_syscall_num = IS_64_BIT and 106 or 195 - lstat_syscall_num = IS_64_BIT and 107 or 196 - elseif ARCH == 'mips' or ARCH == 'mipsel' then - ffi.cdef([[ - typedef struct { - unsigned long st_dev; - unsigned long __st_pad0[3]; - unsigned long long st_ino; - mode_t st_mode; - nlink_t st_nlink; - uid_t st_uid; - gid_t st_gid; - unsigned long st_rdev; - unsigned long __st_pad1[3]; - long long st_size; - time_t st_atime; - unsigned long st_atime_nsec; - time_t st_mtime; - unsigned long st_mtime_nsec; - time_t st_ctime; - unsigned long st_ctime_nsec; - unsigned long st_blksize; - unsigned long __st_pad2; - long long st_blocks; - long __st_padding4[14]; - } lfs_stat; - ]]) - stat_syscall_num = IS_64_BIT and 4106 or 4213 - lstat_syscall_num = IS_64_BIT and 4107 or 4214 - end - - if stat_syscall_num then - stat_func = function(filepath, buf) - return lib.syscall(stat_syscall_num, filepath, buf) - end - lstat_func = function(filepath, buf) - return lib.syscall(lstat_syscall_num, filepath, buf) - end - else - ffi.cdef('typedef struct {} lfs_stat;') - stat_func = function() error("TODO support other Linux architectures") end - lstat_func = stat_func - end -elseif OS == 'Windows' then - ffi.cdef([[ - typedef __int64 __time64_t; - typedef struct { - unsigned int st_dev; - unsigned short st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - unsigned int st_rdev; - __int64 st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - } lfs_stat; - - int _stat64(const char *path, lfs_stat *buffer); - int _wstat64(const wchar_t *path, lfs_stat *buffer); - ]]) - - stat_func = function(filepath, buf) - if _M.unicode then - local szfp = win_utf8_to_unicode(filepath); - return lib._wstat64(szfp, buf) - else - return lib._stat64(filepath, buf) - end - end - lstat_func = stat_func -elseif OS == 'OSX' then - ffi.cdef([[ - struct lfs_timespec { - time_t tv_sec; - long tv_nsec; - }; - typedef struct { - uint32_t st_dev; - uint16_t st_mode; - uint16_t st_nlink; - uint64_t st_ino; - uint32_t st_uid; - uint32_t st_gid; - uint32_t st_rdev; - struct lfs_timespec st_atimespec; - struct lfs_timespec st_mtimespec; - struct lfs_timespec st_ctimespec; - struct lfs_timespec st_birthtimespec; - int64_t st_size; - int64_t st_blocks; - int32_t st_blksize; - uint32_t st_flags; - uint32_t st_gen; - int32_t st_lspare; - int64_t st_qspare[2]; - } lfs_stat; - int stat64(const char *path, lfs_stat *buf); - int lstat64(const char *path, lfs_stat *buf); - ]]) - stat_func = lib.stat64 - lstat_func = lib.lstat64 -elseif OS == 'BSD' then - ffi.cdef([[ - struct lfs_timespec { - time_t tv_sec; - long tv_nsec; - }; - typedef struct { - uint32_t st_dev; - uint32_t st_ino; - uint16_t st_mode; - uint16_t st_nlink; - uint32_t st_uid; - uint32_t st_gid; - uint32_t st_rdev; - struct lfs_timespec st_atimespec; - struct lfs_timespec st_mtimespec; - struct lfs_timespec st_ctimespec; - int64_t st_size; - int64_t st_blocks; - int32_t st_blksize; - uint32_t st_flags; - uint32_t st_gen; - int32_t st_lspare; - struct lfs_timespec st_birthtimespec; - } lfs_stat; - int stat(const char *path, lfs_stat *buf); - int lstat(const char *path, lfs_stat *buf); - ]]) - stat_func = lib.stat - lstat_func = lib.lstat -else - ffi.cdef('typedef struct {} lfs_stat;') - stat_func = function() error('TODO: support other posix system') end - lstat_func = stat_func -end - -local STAT = { - FMT = 0xF000, - FSOCK = 0xC000, - FLNK = 0xA000, - FREG = 0x8000, - FBLK = 0x6000, - FDIR = 0x4000, - FCHR = 0x2000, - FIFO = 0x1000, -} - -local ftype_name_map = { - [STAT.FREG] = 'file', - [STAT.FDIR] = 'directory', - [STAT.FLNK] = 'link', - [STAT.FSOCK] = 'socket', - [STAT.FCHR] = 'char device', - [STAT.FBLK] = "block device", - [STAT.FIFO] = "named pipe", -} - -local function mode_to_ftype(mode) - local ftype = band(mode, STAT.FMT) - return ftype_name_map[ftype] or 'other' -end - -local function mode_to_perm(mode) - local perm_bits = band(mode, tonumber(777, 8)) - local perm = new_tab(9, 0) - local i = 9 - while i > 0 do - local perm_bit = band(perm_bits, 7) - perm[i] = (band(perm_bit, 1) > 0 and 'x' or '-') - perm[i-1] = (band(perm_bit, 2) > 0 and 'w' or '-') - perm[i-2] = (band(perm_bit, 4) > 0 and 'r' or '-') - i = i - 3 - perm_bits = rshift(perm_bits, 3) - end - return concat(perm) -end - -local function time_or_timespec(time, timespec) - local t = tonumber(time) - if not t and timespec then - t = tonumber(timespec.tv_sec) - end - return t -end - -local attr_handlers = { - access = function(st) return time_or_timespec(st.st_atime, st.st_atimespec) end, - blksize = function(st) return tonumber(st.st_blksize) end, - blocks = function(st) return tonumber(st.st_blocks) end, - change = function(st) return time_or_timespec(st.st_ctime, st.st_ctimespec) end, - dev = function(st) return tonumber(st.st_dev) end, - gid = function(st) return tonumber(st.st_gid) end, - ino = function(st) return tonumber(st.st_ino) end, - mode = function(st) return mode_to_ftype(st.st_mode) end, - modification = function(st) return time_or_timespec(st.st_mtime, st.st_mtimespec) end, - nlink = function(st) return tonumber(st.st_nlink) end, - permissions = function(st) return mode_to_perm(st.st_mode) end, - rdev = function(st) return tonumber(st.st_rdev) end, - size = function(st) return tonumber(st.st_size) end, - uid = function(st) return tonumber(st.st_uid) end, -} -local mt = { - __index = function(self, attr_name) - local func = attr_handlers[attr_name] - return func and func(self) - end -} -local stat_type = ffi.metatype('lfs_stat', mt) - --- Add target field for symlinkattributes, which is the absolute path of linked target -local get_link_target_path -if OS == 'Windows' then - local ENOSYS = 40 - function get_link_target_path() - return nil, "could not obtain link target: Function not implemented ",ENOSYS - end -else - - ffi.cdef('ssize_t readlink(const char *path, char *buf, size_t bufsize);') - local EINVAL = 22 - function get_link_target_path(link_path, statbuf) - local size = statbuf.st_size - size = size == 0 and MAXPATH or size - local buf = ffi.new('char[?]', size + 1) - local read = lib.readlink(link_path, buf, size) - if read == -1 then - return nil, "could not obtain link target: "..errno(), ffi.errno() - end - if read > size then - return nil, "not enought size for readlink: "..errno(), ffi.errno() - end - buf[size] = 0 - return ffi_str(buf) - end -end - -local buf = ffi.new(stat_type) -local function attributes(filepath, attr, follow_symlink) - local func = follow_symlink and stat_func or lstat_func - if func(filepath, buf) == -1 then - return nil, string.format("cannot obtain information from file '%s' : %s",tostring(filepath),errno()), ffi.errno() - end - - local atype = type(attr) - if atype == 'string' then - local value, err, errn - if attr == 'target' and not follow_symlink then - value, err, errn = get_link_target_path(filepath, buf) - return value, err, errn - else - value = buf[attr] - end - if value == nil then - error("invalid attribute name '" .. attr .. "'") - end - return value - else - local tab = (atype == 'table') and attr or {} - for k, _ in pairs(attr_handlers) do - tab[k] = buf[k] - end - if not follow_symlink then - tab.target = get_link_target_path(filepath, buf) - end - return tab - end -end - -function _M.attributes(filepath, attr) - return attributes(filepath, attr, true) -end - -function _M.symlinkattributes(filepath, attr) - return attributes(filepath, attr, false) -end - -_M.unicode = HAVE_WFINDFIRST -_M.unicode_errors = false ---this would error with _M.unicode_errors = true ---local cad = string.char(0xE0,0x80,0x80)--,0xFD,0xFF) - -return _M From 19a047bae2376bc9e0ba9bbbada0a0d992afe81b Mon Sep 17 00:00:00 2001 From: Ismoh <12631485+Ismoh@users.noreply.github.com> Date: Fri, 10 Mar 2023 00:00:43 +0100 Subject: [PATCH 26/26] #113 Fixed Logger. --- mods/noita-mp/files/scripts/util/Logger.lua | 8 +++----- .../tests/files/scripts/util/FileUtils_test.lua | 15 +++++++-------- .../tests/files/scripts/util/Logger_test.lua | 10 ++++++++-- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/mods/noita-mp/files/scripts/util/Logger.lua b/mods/noita-mp/files/scripts/util/Logger.lua index 6799b6058..49e6bc8bf 100644 --- a/mods/noita-mp/files/scripts/util/Logger.lua +++ b/mods/noita-mp/files/scripts/util/Logger.lua @@ -65,7 +65,7 @@ function Logger.log(level, channel, message) error("There is a directive (%) in your log message. Use string.format! Message = '" .. message .. "'", 2) end - if level == "off" then + if string.lower(level) == "off" then return false end @@ -94,11 +94,9 @@ function Logger.log(level, channel, message) -- add file name to logs: https://stackoverflow.com/a/48469960/3493998 local file_name = debug.getinfo(2, "S").source:sub(2) file_name = file_name:match("^.*/(.*)$") or file_name - msg = ("%s [%s][%s] %s \n(in %s)") - :format(time, level, channel, message, file_name) + msg = ("%s [%s][%s] %s \n(in %s)"):format(time, level, channel, message, file_name) else - msg = ("%s [%s][%s] %s") - :format("--:--:--", level, channel, message) + msg = ("%s [%s][%s] %s"):format("--:--:--", level, channel, message) end print(msg) diff --git a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua index 4ba5d0484..714152a1d 100644 --- a/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/FileUtils_test.lua @@ -1,9 +1,8 @@ -local os_name = require("os_name") - -TestFileUtil = {} +local os_name = require("os_name") +local fu = require("FileUtils") +TestFileUtil = {} function TestFileUtil:setUp() - -- Mock Noita Api global functions _G.DebugGetIsDevBuild = function() return false @@ -21,12 +20,12 @@ function TestFileUtil:tearDown() _G.pathSeparator = tostring(package.config:sub(1, 1)) local current_platform, current_architecture = os_name.getOS() if current_platform == "Windows" then - _G.is_windows = true - _G.is_linux = false + _G.is_windows = true + _G.is_linux = false _G.pathSeparator = "\\" else - _G.is_windows = false - _G.is_linux = true + _G.is_windows = false + _G.is_linux = true _G.pathSeparator = "/" end end diff --git a/mods/noita-mp/tests/files/scripts/util/Logger_test.lua b/mods/noita-mp/tests/files/scripts/util/Logger_test.lua index 3e7e9a8b4..95647e64f 100644 --- a/mods/noita-mp/tests/files/scripts/util/Logger_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/Logger_test.lua @@ -1,12 +1,18 @@ TestLogger = {} TestLogger.mockedLogLevel = { "trace, debug, info, warn", "TRACE" } +local globalModSettingsGet = ModSettingGet function TestLogger:setUp() - + ModSettingGet = function(id) + if string.contains(id, "noita-mp.log_level_") then + return TestLogger.mockedLogLevel + end + globalModSettingsGet(id) + end end function TestLogger:tearDown() - + ModSettingGet = globalModSettingsGet end function TestLogger:errors()