diff --git a/extensions/extensions.pyproj b/extensions/extensions.pyproj
index 127cbc8..177f469 100644
--- a/extensions/extensions.pyproj
+++ b/extensions/extensions.pyproj
@@ -20,14 +20,19 @@
false
+
+
+
+
+
-
+
-
+
@@ -65,7 +70,7 @@
-
+
@@ -80,20 +85,16 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
-
@@ -103,8 +104,8 @@
-
-
+
+
@@ -112,7 +113,14 @@
+
+
+
+
+
+
+
@@ -124,28 +132,26 @@
-
+
-
+
-
+
-
-
-
- Code
-
-
+
+
+
+
@@ -178,7 +184,7 @@
-
+
@@ -191,7 +197,7 @@
-
+
@@ -208,7 +214,7 @@
-
+
@@ -218,18 +224,18 @@
Code
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
@@ -237,17 +243,17 @@
-
-
-
-
+
+
+
+
-
-
+
+
diff --git a/extensions/sn_better_target_monitor/content.xml b/extensions/sn_better_target_monitor/content.xml
index 1353f36..70a56b0 100644
--- a/extensions/sn_better_target_monitor/content.xml
+++ b/extensions/sn_better_target_monitor/content.xml
@@ -2,9 +2,9 @@
diff --git a/extensions/sn_better_target_monitor/ui.xml b/extensions/sn_better_target_monitor/ui.xml
new file mode 100644
index 0000000..61203cd
--- /dev/null
+++ b/extensions/sn_better_target_monitor/ui.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/extensions/sn_better_target_monitor/lua/Target_Monitor.lua b/extensions/sn_better_target_monitor/ui/Target_Monitor.lua
similarity index 99%
rename from extensions/sn_better_target_monitor/lua/Target_Monitor.lua
rename to extensions/sn_better_target_monitor/ui/Target_Monitor.lua
index 6e3c8e8..847ad52 100644
--- a/extensions/sn_better_target_monitor/lua/Target_Monitor.lua
+++ b/extensions/sn_better_target_monitor/ui/Target_Monitor.lua
@@ -1,4 +1,4 @@
-
+Lua_Loader.define("extensions.sn_better_target_monitor.lua.Target_Monitor",function(require)
------------------------------------------------------------------------------
--[[
The high level of the monitor is handled in monitors.lua.
@@ -1764,7 +1764,6 @@ function L.Get_X3_Class(macroclass, purpose, shiptype)
end
------------------------------------------------------------------------------
-L.Init_TargetMonitor()
--[[
@@ -1830,4 +1829,5 @@ end
]]
-return L
\ No newline at end of file
+return L,L.Init_TargetMonitor
+end)
\ No newline at end of file
diff --git a/extensions/sn_better_target_monitor/lua_interface.txt b/extensions/sn_better_target_monitor/ui/lua_interface.lua
similarity index 50%
rename from extensions/sn_better_target_monitor/lua_interface.txt
rename to extensions/sn_better_target_monitor/ui/lua_interface.lua
index b853a32..cdef3b3 100644
--- a/extensions/sn_better_target_monitor/lua_interface.txt
+++ b/extensions/sn_better_target_monitor/ui/lua_interface.lua
@@ -5,5 +5,7 @@ path will be maintained between github development files and steam style
release files.
]]
-
-return require("extensions.sn_better_target_monitor.lua.Target_Monitor")
\ No newline at end of file
+Lua_Loader.define("extensions.sn_better_target_monitor.lua_interface",function(require)
+ -- TODO: Need to determine if we need to Init this
+ return require("extensions.sn_better_target_monitor.lua.Target_Monitor")
+end)
\ No newline at end of file
diff --git a/extensions/sn_extra_game_options/ui.xml b/extensions/sn_extra_game_options/ui.xml
new file mode 100644
index 0000000..c117f5c
--- /dev/null
+++ b/extensions/sn_extra_game_options/ui.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/extensions/sn_extra_game_options/lua/Custom_Options.lua b/extensions/sn_extra_game_options/ui/Custom_Options.lua
similarity index 99%
rename from extensions/sn_extra_game_options/lua/Custom_Options.lua
rename to extensions/sn_extra_game_options/ui/Custom_Options.lua
index 0412907..29727f7 100644
--- a/extensions/sn_extra_game_options/lua/Custom_Options.lua
+++ b/extensions/sn_extra_game_options/ui/Custom_Options.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_extra_game_options.lua.Custom_Options",function(require)
--[[
This module implements a custom options menu entry, separate from the
general api, for changing various behaviors of interest.
@@ -1321,4 +1322,5 @@ L.Init_Hide_Modified()
------------------------------------------------------------------------------
-- Final init.
-L.Init()
\ No newline at end of file
+return nil,L.Init
+)
\ No newline at end of file
diff --git a/extensions/sn_hotkey_collection/ui.xml b/extensions/sn_hotkey_collection/ui.xml
new file mode 100644
index 0000000..21b3116
--- /dev/null
+++ b/extensions/sn_hotkey_collection/ui.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/extensions/sn_hotkey_collection/lua/Hotkeys.lua b/extensions/sn_hotkey_collection/ui/Hotkeys.lua
similarity index 98%
rename from extensions/sn_hotkey_collection/lua/Hotkeys.lua
rename to extensions/sn_hotkey_collection/ui/Hotkeys.lua
index dd15f53..a9b8ba3 100644
--- a/extensions/sn_hotkey_collection/lua/Hotkeys.lua
+++ b/extensions/sn_hotkey_collection/ui/Hotkeys.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_hotkey_collection.lua.Hotkeys",function(require)
--[[
Lua side of hotkey api, for doing things only lua can do.
]]
@@ -213,4 +214,5 @@ function L.Reset_Zoom()
end
-- Final init.
-L.Init()
\ No newline at end of file
+return nil,L.Init
+)
\ No newline at end of file
diff --git a/extensions/sn_measure_fps/ui.xml b/extensions/sn_measure_fps/ui.xml
new file mode 100644
index 0000000..bdc9541
--- /dev/null
+++ b/extensions/sn_measure_fps/ui.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/extensions/sn_measure_fps/lua/Measure_FPS.lua b/extensions/sn_measure_fps/ui/Measure_FPS.lua
similarity index 86%
rename from extensions/sn_measure_fps/lua/Measure_FPS.lua
rename to extensions/sn_measure_fps/ui/Measure_FPS.lua
index 899392d..1f30702 100644
--- a/extensions/sn_measure_fps/lua/Measure_FPS.lua
+++ b/extensions/sn_measure_fps/ui/Measure_FPS.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_measure_fps.lua.Measure_FPS",function(require)
--[[
Bounces fps sample data back to md.
]]
@@ -29,6 +30,5 @@ function L.Get_Sample()
})
end
-Init()
-
-return
\ No newline at end of file
+return nil,Init
+)
\ No newline at end of file
diff --git a/extensions/sn_measure_perf/ui.xml b/extensions/sn_measure_perf/ui.xml
new file mode 100644
index 0000000..109e88f
--- /dev/null
+++ b/extensions/sn_measure_perf/ui.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/extensions/sn_measure_perf/lua/Measure_Perf.lua b/extensions/sn_measure_perf/ui/Measure_Perf.lua
similarity index 97%
rename from extensions/sn_measure_perf/lua/Measure_Perf.lua
rename to extensions/sn_measure_perf/ui/Measure_Perf.lua
index 775fce4..610f33a 100644
--- a/extensions/sn_measure_perf/lua/Measure_Perf.lua
+++ b/extensions/sn_measure_perf/ui/Measure_Perf.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_better_target_monitor.lua.Target_Monitor",function(require)
--[[
Lua side of performance profiling.
]]
@@ -33,7 +34,6 @@ function L.Bounce_Test(_, count)
end
-Init()
--[[
@@ -144,4 +144,5 @@ Test_Init()
-return
\ No newline at end of file
+return nil,Init
+)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/lua_interface.txt b/extensions/sn_mod_support_apis/lua_interface.txt
deleted file mode 100644
index 4738754..0000000
--- a/extensions/sn_mod_support_apis/lua_interface.txt
+++ /dev/null
@@ -1,13 +0,0 @@
---[[
-Lightweight lua wrapper on some exported api functions.
-Other extensions using these lua apis should 'require' this file, as its
-path will be maintained between github development files and steam style
-release files.
-]]
-
-local L = {}
-L.Library = require("extensions.sn_mod_support_apis.lua.Library")
-L.Pipes = require("extensions.sn_mod_support_apis.lua.named_pipes.Pipes")
-L.Time = require("extensions.sn_mod_support_apis.lua.time.Interface")
-
-return L
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/md/Simple_Menu_API.xml b/extensions/sn_mod_support_apis/md/Simple_Menu_API.xml
index ec658a0..a6c7794 100644
--- a/extensions/sn_mod_support_apis/md/Simple_Menu_API.xml
+++ b/extensions/sn_mod_support_apis/md/Simple_Menu_API.xml
@@ -178,6 +178,9 @@ Complex properties:
+
diff --git a/extensions/sn_mod_support_apis/ui.xml b/extensions/sn_mod_support_apis/ui.xml
new file mode 100644
index 0000000..89cc64d
--- /dev/null
+++ b/extensions/sn_mod_support_apis/ui.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extensions/sn_mod_support_apis/lua/Library.lua b/extensions/sn_mod_support_apis/ui/Library.lua
similarity index 98%
rename from extensions/sn_mod_support_apis/lua/Library.lua
rename to extensions/sn_mod_support_apis/ui/Library.lua
index 8a1fde1..c808926 100644
--- a/extensions/sn_mod_support_apis/lua/Library.lua
+++ b/extensions/sn_mod_support_apis/ui/Library.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.Library",function(require)
--[[
Library functions to be shared across apis.
@@ -266,4 +267,5 @@ function FIFO.Is_Empty (fifo)
end
-return L
\ No newline at end of file
+return L
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/ui/Lua_Loader.lua b/extensions/sn_mod_support_apis/ui/Lua_Loader.lua
new file mode 100644
index 0000000..ee23c78
--- /dev/null
+++ b/extensions/sn_mod_support_apis/ui/Lua_Loader.lua
@@ -0,0 +1,323 @@
+--[[
+Simple api for loading in mod lua files, and for accessing ui userdata.
+This works around a bug in the x4 ui.xml style lua loading which fails
+to initialize the globals table.
+
+Usage is kept simple:
+ When the ui reloads or a game is loaded, a ui event is raised.
+ User MD code will set up a cue to trigger on this event and signal to
+ lua which file to load.
+ Lua will then "require" the file, effectively loading it into the game.
+
+This lua file is itself included by modding an official ui.xml. Lua added
+in this way is imported correctly into X4, though there are limited
+official ui.xml files which can be modified in this way.
+
+
+Example from MD:
+
+
+
+
+
+
+
+
+
+
+Here, the cue name can be anything, and the param is the specific
+path to the lua file to load, without extension.
+The file extension may be ".lua" or ".txt", where the latter may be
+needed to distribute lua files through steam workshop.
+The lua file needs to be loose, not packed in a cat/dat.
+
+When a loading is complete, a message is printed to the debuglog, and
+a ui signal is raised. The "control" field will be "Loaded " followed
+by the original file_path. This can be used to set up loading
+dependencies, so that one lua file only loads after a prior one.
+
+Example dependency condition:
+
+
+
+
+
+
+This api also provides for saving data into the uidata.xml file.
+All such saved data is in the __MOD_USERDATA global table.
+Each individual mod should add a unique key to this table, and save its
+data under that key. Nested tables are supported.
+Care should be used in the top level key, to avoid cross-mod conflicts.
+
+To enable early loading of the Userdata handler, this will also support
+an early ready signal, which resolves before the normal ready.
+- On reloadui or md signalling Priority_Signal, send Priority_Ready.
+- Next frame, md cues which listen to this may signal to load their lua.
+- Md side will see Priority_Ready, and send Signal.
+- Back end of frame, priority lua files load, and api signals standard Ready.
+- Next frame, md cues which listen to Ready may signal to load their lua.
+
+TODO: allow for more md arguments, including specifying dependendencies
+which are resolved at this level (eg. store and delay the require until
+all dependencies are met).
+]]
+
+Lua_Loader = {}
+
+local modules = {
+
+}
+
+local function Send_Priority_Ready()
+ --DebugError("LUA Loader API: Signalling 'Lua_Loader, Priority_Ready'")
+ -- Send a ui signal, telling all md cues to rerun.
+ AddUITriggeredEvent("Lua_Loader", "Priority_Ready")
+end
+
+local function Send_Ready()
+ --DebugError("LUA Loader API: Signalling 'Lua_Loader, Ready'")
+ -- Send a ui signal, telling all md cues to rerun.
+ AddUITriggeredEvent("Lua_Loader", "Ready")
+end
+
+local function IsWhitelistedInProtectedUI(name)
+ return name == "ffi" or name == "utf8"
+end
+
+local function IsReserved(name)
+ return name ~= nil and type(name) == "string" and (name == "bit" or name == "Color" or name == "coroutine" or name == "debug" or name == "ffi" or name == "math" or name == "Matrix" or name == "package" or name == "Rotation" or name == "string" or name == "table" or name == "utf8" or name == "Vector" or name == "_G" or string.find(name, "^jit%."))
+end
+
+local function Lua_Loader_Require_Helper(name, methodName, requestorName)
+ if type(name) ~= "string" then
+ error("Invalid call to "..methodName..". Given name must be a string but is '"..type(name).."''")
+ end
+ if requestorName ~= nil and type(requestorName) ~= "string" then
+ error("Invalid call to "..methodName..". Given requestorName must be nil or a string but is '"..type(requestorName).."''")
+ end
+
+ local module = modules[name]
+ if module == nil then
+ return false
+ end
+
+ local status = module.status
+
+ if status ~= "defined" then
+ if status == "executing" then
+ if requestorName == nil and type(requestorName) == "string" then
+ error("Invalid call to "..methodName..". Cyclical dependency detected in '"..requestorName.."' and '"..name.."''")
+ end
+ elseif status == "faulted" then
+ error("Failed to require the module '"..name.."' as it encountered an error whilst being defined.\n"..module.exports)
+ end
+
+ error("Invalid call to "..methodName..". Required module whilst is was being defined '"..name.."''")
+ end
+
+ local moduleInit = module.init
+
+ return true,module.exports,module.init
+end
+
+local function on_Load_Lua_File(_, file_path)
+ -- First look for our modules
+ local success,exports,init = Lua_Loader_Require_Helper(file_path, "Lua_Loader.Load")
+
+ if success then
+ if init ~= nil and type(init) == "function" then
+ init()
+ end
+ else
+ local localPackage = package
+ local packagePath = nil
+
+ -- When Protected UI is enabled it seems that the `package` global is nil, but we want the actual error from require as it might be something else.
+ if localPackage ~= nil then
+ local packagePath = localPackage.path
+
+ local customPackagePath = "?.txt"
+ ---- Removing the debug message; if a user really wants to know,
+ ---- they can listen to the ui event.
+ --DebugError("LUA Loader API: loading "..file_path..", package path:"..customPackagePath)
+
+ -- Since lua files cannot be distributed with steam workshop stuff,
+ -- but txt can, use a trick to change the package search path to
+ -- also look for txt files (which can be put on steam).
+ -- This is done on every load, since the package.path was observed to
+ -- get reset after Init runs (noticed in x4 3.3hf1).
+ localPackage.path = customPackagePath
+ end
+
+ success, exports = pcall(baseRequire, file_path)
+
+ -- Restore package.path to the original value
+ if localPackage ~= nil then
+ localPackage.path = packagePath
+ elseif not IsWhitelistedInProtectedUI(name) and success and exports == nil then
+ local protectedUIError = "require(\""..file_path.."\") : Only whitelisted modules are allowed in Protected UI Mode."
+ DebugError("If you see the following error, then a lua file for a mod has filed to load:\n"..protectedUIError.."\n\nIf you're confident about the source of ALL of your mods then you will need to disable Protected UI Mode for this mod to function.\n\nAdvice for mod developers: You need to load your mod via 'ui.xml' and update your lua files to using Lua_Loader.define(\""..file_path.."\", function(require)\n ...\nend)")
+ end
+
+ if not success then
+ error(exports)
+ end
+
+ -- Removing the debug message; if a user really wants to know,
+ -- they can listen to the ui event.
+ --DebugError("LUA Loader API: loaded "..file_path..", package path:"..customPackagePath)
+
+ -- Generic signal that the load completed, for use when there
+ -- are inter-lua dependencies (to control loading order).
+ end
+
+ AddUITriggeredEvent("Lua_Loader", "Loaded "..file_path)
+end
+
+local function Init()
+ --DebugError("LUA Loader API: Running Init()")
+ -- Hook up an md->lua signal.
+ RegisterEvent("Lua_Loader.Load", on_Load_Lua_File)
+
+ -- Listen to md side timing on when to send Ready signals.
+ -- Priority ready is triggered on game start/load.
+ RegisterEvent("Lua_Loader.Send_Priority_Ready", Send_Priority_Ready)
+ RegisterEvent("Lua_Loader.Send_Ready", Send_Ready)
+
+ -- Also call the function once on ui reload itself, to catch /reloadui
+ -- commands while the md is running.
+ -- Only triggers priority ready; md will then signal Send_Ready for
+ -- the second part.
+ Send_Priority_Ready()
+end
+
+Lua_Loader.IsReserved = IsReserved
+Lua_Loader.IsWhitelistedInProtectedUI = IsWhitelistedInProtectedUI
+
+function Lua_Loader.require(name)
+ local success,exports,init = Lua_Loader_Require_Helper(name, "Lua_Loader.require()")
+
+ if init == nil then
+ init = function()
+ end
+ end
+
+ return success,exports,init
+end
+
+local baseRequire = require
+require = function(name)
+ local success,exports,init = Lua_Loader_Require_Helper(name, "Lua_Loader.require()")
+
+ if not success then
+ return baseRequire(name)
+ end
+
+ if init ~= nil and type(init) == "function" then
+ init()
+ end
+
+ return exports
+end
+
+function Lua_Loader.define(name, moduleFunction)
+ if type(name) ~= "string" then
+ error("Invalid call to Lua_Loader.define(). Given name must be a string but is '"..type(name).."''")
+ end
+ if type(moduleFunction) ~= "function" then
+ error("Invalid call to Lua_Loader.define(). Given moduleFunction must be a function but is '"..type(moduleFunction).."''")
+ end
+
+ local module = modules[name]
+
+ if module ~= nil then
+ DebugError("Redefining the module '"..name.."'")
+ elseif package ~= nil then
+ if IsReserved(name) then
+ DebugError("Redefining the build-in module '"..name.."'")
+ end
+ elseif IsWhitelistedInProtectedUI(name) then
+ DebugError("Redefining the build-in module '"..name.."'")
+ end
+
+ module = {
+ status = "executing",
+ exports = nil,
+ init = nil,
+ }
+
+ modules[name] = module
+
+ local ambientName = name
+
+ local dependencies = nil
+ local moduleFunctionRan = false
+
+ local function moduleRequire(name)
+ if moduleFunctionRan then
+ error("Invalid call to require() function in Lua_Loader.define(function(require). Call to moduleRequire method outside of define in '"..ambientName.."''")
+ end
+
+ local success,exports,init = Lua_Loader_Require_Helper(name, "require() function in Lua_Loader.define(function(require)", ambientName)
+
+ if not success then
+ return baseRequire(name)
+ end
+
+ if module.status == "executing" and init ~= nil and type(init) == "function" then
+ dependencies = dependencies or {}
+ table.insert(dependencies, init)
+ end
+
+ return exports,init
+ end
+
+ local success, exports, initFunction = pcall(moduleFunction, moduleRequire)
+
+ -- Prevent future 'require' from attempting to update the dependency list.
+ module.status = "executed"
+
+ if not success then
+ module.status = "faulted"
+ module.exports = exports
+ error("Failed to define module '"..name.."' due because of the following error: "..exports)
+ end
+
+ if initFunction ~= nil and type(initFunction) ~= "function" then
+ local err = "Invalid call to Lua_Loader.define(). Second return must be nil or the init function but is '"..type(initFunction).."''"
+ module.status = "faulted"
+ module.exports = err
+ error("Failed to define module '"..name.."' due because of the following error: "..err)
+ end
+
+ local init = nil
+
+ if type(initFunction) == "function" or dependencies ~= nil then
+ local initialized = false
+
+ init = function()
+ if not initialized then
+ if dependencies ~= nil then
+ for _, dependencyInit in ipairs(dependencies) do
+ dependencyInit()
+ end
+ end
+ if initFunction ~= nil and type(initFunction) == "function" then
+ initFunction()
+ end
+ initialized = true
+ end
+ end
+ end
+
+ module.exports = exports
+ module.init = init
+ module.status = "defined"
+
+ return exports,init
+end
+
+-- This script kicks everything off, so we actually need to run its init now.
+Init()
diff --git a/extensions/sn_mod_support_apis/ui/OnlineGetUserItemsPatch.lua b/extensions/sn_mod_support_apis/ui/OnlineGetUserItemsPatch.lua
new file mode 100644
index 0000000..e1b2942
--- /dev/null
+++ b/extensions/sn_mod_support_apis/ui/OnlineGetUserItemsPatch.lua
@@ -0,0 +1,9 @@
+local ego_OnlineGetUserItems = OnlineGetUserItems
+
+-- For some reason, this function returns `nil` in certain cases, which causes a bunch of scripts to start breaking when the interact menu code is injected.
+-- Inspection of uses of `OnlineGetUserItems` show that no code seems to check for a `nil` value so it's likely not important that it returns `nil`.
+function OnlineGetUserItems( ... )
+ local values = {ego_OnlineGetUserItems(...)}
+ values[1] = values[1] or {}
+ return unpack(values)
+end
diff --git a/extensions/sn_mod_support_apis/lua/Text.lua b/extensions/sn_mod_support_apis/ui/Text.lua
similarity index 86%
rename from extensions/sn_mod_support_apis/lua/Text.lua
rename to extensions/sn_mod_support_apis/ui/Text.lua
index 9c823a1..a98ea9d 100644
--- a/extensions/sn_mod_support_apis/lua/Text.lua
+++ b/extensions/sn_mod_support_apis/ui/Text.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.Text",function(require)
--[[
Wrapper for various text lookups from the t files, using ReadText.
Standardizes the text names for code management, and maybe even speeds
@@ -23,4 +24,5 @@ extension_options = readtext( new, 1000),
}
-return T
\ No newline at end of file
+return T
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/ui/addons/ego_debug/Lua_Loader.lua b/extensions/sn_mod_support_apis/ui/addons/ego_debug/Lua_Loader.lua
deleted file mode 100644
index 365f91f..0000000
--- a/extensions/sn_mod_support_apis/ui/addons/ego_debug/Lua_Loader.lua
+++ /dev/null
@@ -1,117 +0,0 @@
---[[
-Simple api for loading in mod lua files, and for accessing ui userdata.
-This works around a bug in the x4 ui.xml style lua loading which fails
-to initialize the globals table.
-
-Usage is kept simple:
- When the ui reloads or a game is loaded, a ui event is raised.
- User MD code will set up a cue to trigger on this event and signal to
- lua which file to load.
- Lua will then "require" the file, effectively loading it into the game.
-
-This lua file is itself included by modding an official ui.xml. Lua added
-in this way is imported correctly into X4, though there are limited
-official ui.xml files which can be modified in this way.
-
-
-Example from MD:
-
-
-
-
-
-
-
-
-
-
-Here, the cue name can be anything, and the param is the specific
-path to the lua file to load, without extension.
-The file extension may be ".lua" or ".txt", where the latter may be
-needed to distribute lua files through steam workshop.
-The lua file needs to be loose, not packed in a cat/dat.
-
-When a loading is complete, a message is printed to the debuglog, and
-a ui signal is raised. The "control" field will be "Loaded " followed
-by the original file_path. This can be used to set up loading
-dependencies, so that one lua file only loads after a prior one.
-
-Example dependency condition:
-
-
-
-
-
-
-This api also provides for saving data into the uidata.xml file.
-All such saved data is in the __MOD_USERDATA global table.
-Each individual mod should add a unique key to this table, and save its
-data under that key. Nested tables are supported.
-Care should be used in the top level key, to avoid cross-mod conflicts.
-
-To enable early loading of the Userdata handler, this will also support
-an early ready signal, which resolves before the normal ready.
-- On reloadui or md signalling Priority_Signal, send Priority_Ready.
-- Next frame, md cues which listen to this may signal to load their lua.
-- Md side will see Priority_Ready, and send Signal.
-- Back end of frame, priority lua files load, and api signals standard Ready.
-- Next frame, md cues which listen to Ready may signal to load their lua.
-
-TODO: allow for more md arguments, including specifying dependendencies
-which are resolved at this level (eg. store and delay the require until
-all dependencies are met).
-]]
-
-local function Send_Priority_Ready()
- --DebugError("LUA Loader API: Signalling 'Lua_Loader, Priority_Ready'")
- -- Send a ui signal, telling all md cues to rerun.
- AddUITriggeredEvent("Lua_Loader", "Priority_Ready")
-end
-
-local function Send_Ready()
- --DebugError("LUA Loader API: Signalling 'Lua_Loader, Ready'")
- -- Send a ui signal, telling all md cues to rerun.
- AddUITriggeredEvent("Lua_Loader", "Ready")
-end
-
-local function on_Load_Lua_File(_, file_path)
-
- -- Since lua files cannot be distributed with steam workshop stuff,
- -- but txt can, use a trick to change the package search path to
- -- also look for txt files (which can be put on steam).
- -- This is done on every load, since the package.path was observed to
- -- get reset after Init runs (noticed in x4 3.3hf1).
- if not string.find(package.path, "?.txt;") then
- package.path = "?.txt;"..package.path
- end
-
- require(file_path)
- -- Removing the debug message; if a user really wants to know,
- -- they can listen to the ui event.
- --DebugError("LUA Loader API: loaded "..file_path)
-
- -- Generic signal that the load completed, for use when there
- -- are inter-lua dependencies (to control loading order).
- AddUITriggeredEvent("Lua_Loader", "Loaded "..file_path)
-end
-
-local function Init()
- --DebugError("LUA Loader API: Running Init()")
- -- Hook up an md->lua signal.
- RegisterEvent("Lua_Loader.Load", on_Load_Lua_File)
-
- -- Listen to md side timing on when to send Ready signals.
- -- Priority ready is triggered on game start/load.
- RegisterEvent("Lua_Loader.Send_Priority_Ready", Send_Priority_Ready)
- RegisterEvent("Lua_Loader.Send_Ready", Send_Ready)
-
- -- Also call the function once on ui reload itself, to catch /reloadui
- -- commands while the md is running.
- -- Only triggers priority ready; md will then signal Send_Ready for
- -- the second part.
- Send_Priority_Ready()
-end
-
-Init()
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/ui/addons/ego_debug/ui.xml b/extensions/sn_mod_support_apis/ui/addons/ego_debug/ui.xml
deleted file mode 100644
index d7cf139..0000000
--- a/extensions/sn_mod_support_apis/ui/addons/ego_debug/ui.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/extensions/sn_mod_support_apis/lua/c_library/winpipe.lua b/extensions/sn_mod_support_apis/ui/c_library/winpipe.lua
similarity index 88%
rename from extensions/sn_mod_support_apis/lua/c_library/winpipe.lua
rename to extensions/sn_mod_support_apis/ui/c_library/winpipe.lua
index 4d39485..cbc3aec 100644
--- a/extensions/sn_mod_support_apis/lua/c_library/winpipe.lua
+++ b/extensions/sn_mod_support_apis/ui/c_library/winpipe.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.c_library.winpipe",function(require)
--[[
Wrapper for loading the winpipe dll file.
@@ -35,7 +36,7 @@ This is that wrapper.
-- Check if this is running on Windows.
-- First character in package.config is the separator, which
-- is backslash on windows.
-if package.config:sub(1,1) == "\\" then
+if package ~= nil and package.config:sub(1,1) == "\\" then
-- Note: as of x4 3.3 hotfix 1 (beta), the jit and lua dll are changed
-- such that the winpipe dll doesn't work between versions.
@@ -55,14 +56,14 @@ if package.config:sub(1,1) == "\\" then
if string.find(GetVersionString(), "406216") then
-- <= 3.3 release dll.
return package.loadlib(
- ".\\extensions\\sn_mod_support_apis\\lua\\c_library\\winpipe_64_pre3p3hf1.dll",
+ ".\\extensions\\sn_mod_support_apis\\ui\\c_library\\winpipe_64_pre3p3hf1.dll",
"luaopen_winpipe")()
else
-- 3.3 hf1 dll.
return package.loadlib(
- ".\\extensions\\sn_mod_support_apis\\lua\\c_library\\winpipe_64.dll",
+ ".\\extensions\\sn_mod_support_apis\\ui\\c_library\\winpipe_64.dll",
"luaopen_winpipe")()
end
end
-
+end)
diff --git a/extensions/sn_mod_support_apis/lua/c_library/winpipe_64.dll b/extensions/sn_mod_support_apis/ui/c_library/winpipe_64.dll
similarity index 100%
rename from extensions/sn_mod_support_apis/lua/c_library/winpipe_64.dll
rename to extensions/sn_mod_support_apis/ui/c_library/winpipe_64.dll
diff --git a/extensions/sn_mod_support_apis/lua/c_library/winpipe_64_pre3p3hf1.dll b/extensions/sn_mod_support_apis/ui/c_library/winpipe_64_pre3p3hf1.dll
similarity index 100%
rename from extensions/sn_mod_support_apis/lua/c_library/winpipe_64_pre3p3hf1.dll
rename to extensions/sn_mod_support_apis/ui/c_library/winpipe_64_pre3p3hf1.dll
diff --git a/extensions/sn_mod_support_apis/lua/chat_window/Interface.lua b/extensions/sn_mod_support_apis/ui/chat_window/Interface.lua
similarity index 98%
rename from extensions/sn_mod_support_apis/lua/chat_window/Interface.lua
rename to extensions/sn_mod_support_apis/ui/chat_window/Interface.lua
index fdbe6ba..4b4f4bf 100644
--- a/extensions/sn_mod_support_apis/lua/chat_window/Interface.lua
+++ b/extensions/sn_mod_support_apis/ui/chat_window/Interface.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.chat_window.Interface",function(require)
--[[
Lua interface between md and the chat window.
Primary goal is to intercept chat text and pass it back to md, with some
@@ -290,4 +291,5 @@ function L.rebuildWindowOutput()
end
-- Removed. TODO: overhaul for changes made in 6.0+.
---L.Init()
\ No newline at end of file
+return nil--,L.Init
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/lua/hotkey/Interface.lua b/extensions/sn_mod_support_apis/ui/hotkey/Interface.lua
similarity index 99%
rename from extensions/sn_mod_support_apis/lua/hotkey/Interface.lua
rename to extensions/sn_mod_support_apis/ui/hotkey/Interface.lua
index b42e16a..3edb446 100644
--- a/extensions/sn_mod_support_apis/lua/hotkey/Interface.lua
+++ b/extensions/sn_mod_support_apis/ui/hotkey/Interface.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.hotkey.Interface",function(require)
--[[
Lua side of the hotkey api.
This primarily aims to interface tightly with the egosoft menu system,
@@ -931,7 +932,6 @@ end
--end
-Init()
--[[
@@ -1103,4 +1103,8 @@ Possibly adding new keys:
- Add a custom section title.
- Call menu.displayControlRow() for each new key, matching args.
b) patch menu.remapInput to catch user assignments.
-]]
\ No newline at end of file
+]]
+
+return nil,Init
+
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/lua/interact_menu/Interface.lua b/extensions/sn_mod_support_apis/ui/interact_menu/Interface.lua
similarity index 99%
rename from extensions/sn_mod_support_apis/lua/interact_menu/Interface.lua
rename to extensions/sn_mod_support_apis/ui/interact_menu/Interface.lua
index 064bf45..c0844c4 100644
--- a/extensions/sn_mod_support_apis/lua/interact_menu/Interface.lua
+++ b/extensions/sn_mod_support_apis/ui/interact_menu/Interface.lua
@@ -1,4 +1,4 @@
-
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.interact_menu.Interface",function(require)
--[[
Module for adding new context menu actions.
Note: not dependent on the simple menu flow directly, except for
@@ -863,4 +863,5 @@ function L.Interact_Callback(keep_open, ret_table)
end
-L.Init()
\ No newline at end of file
+return nil,L.Init
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/ui/lua_interface.lua b/extensions/sn_mod_support_apis/ui/lua_interface.lua
new file mode 100644
index 0000000..daad8dc
--- /dev/null
+++ b/extensions/sn_mod_support_apis/ui/lua_interface.lua
@@ -0,0 +1,15 @@
+--[[
+Lightweight lua wrapper on some exported api functions.
+Other extensions using these lua apis should 'require' this file, as its
+path will be maintained between github development files and steam style
+release files.
+]]
+
+Lua_Loader.define("extensions.sn_mod_support_apis.lua_interface",function(require)
+ -- TODO: Need to determine if we need to Init this
+ return {
+ Library = require("extensions.sn_mod_support_apis.lua.Library"),
+ Pipes = require("extensions.sn_mod_support_apis.lua.named_pipes.Pipes"),
+ Time = require("extensions.sn_mod_support_apis.lua.time.Interface"),
+ }
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/lua/named_pipes/Interface.lua b/extensions/sn_mod_support_apis/ui/named_pipes/Interface.lua
similarity index 98%
rename from extensions/sn_mod_support_apis/lua/named_pipes/Interface.lua
rename to extensions/sn_mod_support_apis/ui/named_pipes/Interface.lua
index 1223698..58e2972 100644
--- a/extensions/sn_mod_support_apis/lua/named_pipes/Interface.lua
+++ b/extensions/sn_mod_support_apis/ui/named_pipes/Interface.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.named_pipes.Interface",function(require)
--[[
MD to Lua Pipe API
@@ -203,9 +204,6 @@ function L.Process_Command()
end
--- Finalize initial setup.
-Init()
-
-
-- On require(), just return the Pipes functions to other lua modules.
-return Pipes
\ No newline at end of file
+return Pipes, Init
+end)
diff --git a/extensions/sn_mod_support_apis/lua/named_pipes/Library.lua b/extensions/sn_mod_support_apis/ui/named_pipes/Library.lua
similarity index 94%
rename from extensions/sn_mod_support_apis/lua/named_pipes/Library.lua
rename to extensions/sn_mod_support_apis/ui/named_pipes/Library.lua
index 65cdb5e..ef33ae6 100644
--- a/extensions/sn_mod_support_apis/lua/named_pipes/Library.lua
+++ b/extensions/sn_mod_support_apis/ui/named_pipes/Library.lua
@@ -1,4 +1,4 @@
-
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.named_pipes.Library",function(require)
-- Table holding lib functions to be returned, or lib params that can
-- be modified.
local L = {
@@ -56,4 +56,5 @@ end
--end
-return L
\ No newline at end of file
+return L
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/lua/named_pipes/Pipes.lua b/extensions/sn_mod_support_apis/ui/named_pipes/Pipes.lua
similarity index 99%
rename from extensions/sn_mod_support_apis/lua/named_pipes/Pipes.lua
rename to extensions/sn_mod_support_apis/ui/named_pipes/Pipes.lua
index 71c7a39..6cba3a1 100644
--- a/extensions/sn_mod_support_apis/lua/named_pipes/Pipes.lua
+++ b/extensions/sn_mod_support_apis/ui/named_pipes/Pipes.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.named_pipes.Pipes",function(require)
--[[
Functionality for opening, reading, writing to pipes.
@@ -850,4 +851,5 @@ end
-- Pass all local functions back on require() for now.
-- TODO: maybe be selective.
-return L
\ No newline at end of file
+return L
+end)
diff --git a/extensions/sn_mod_support_apis/lua/simple_menu/Interface.lua b/extensions/sn_mod_support_apis/ui/simple_menu/Interface.lua
similarity index 99%
rename from extensions/sn_mod_support_apis/lua/simple_menu/Interface.lua
rename to extensions/sn_mod_support_apis/ui/simple_menu/Interface.lua
index 4eef7cf..8fe8fd0 100644
--- a/extensions/sn_mod_support_apis/lua/simple_menu/Interface.lua
+++ b/extensions/sn_mod_support_apis/ui/simple_menu/Interface.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.simple_menu.Interface",function(require)
--[[
Top level of the lua side of the simple menu api.
Interfaces with MD script commands which will populate the menu and
@@ -921,6 +922,6 @@ Standalone_Menu.onSelectElement = L.onSelectElement
--- Init once everything is ready.
-Init()
+return nil,Init
+end)
diff --git a/extensions/sn_mod_support_apis/lua/simple_menu/Library.lua b/extensions/sn_mod_support_apis/ui/simple_menu/Library.lua
similarity index 98%
rename from extensions/sn_mod_support_apis/lua/simple_menu/Library.lua
rename to extensions/sn_mod_support_apis/ui/simple_menu/Library.lua
index 71577fd..72c899d 100644
--- a/extensions/sn_mod_support_apis/lua/simple_menu/Library.lua
+++ b/extensions/sn_mod_support_apis/ui/simple_menu/Library.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.simple_menu.Library",function(require)
--[[
Misc functions split off into a library file.
Mostly string or table processing.
@@ -234,5 +235,5 @@ function L.Fix_Bool_Args(args, defaults)
end
end
-
-return L
\ No newline at end of file
+return L
+end)
diff --git a/extensions/sn_mod_support_apis/lua/simple_menu/Options_Menu.lua b/extensions/sn_mod_support_apis/ui/simple_menu/Options_Menu.lua
similarity index 99%
rename from extensions/sn_mod_support_apis/lua/simple_menu/Options_Menu.lua
rename to extensions/sn_mod_support_apis/ui/simple_menu/Options_Menu.lua
index 2a455a1..a238185 100644
--- a/extensions/sn_mod_support_apis/lua/simple_menu/Options_Menu.lua
+++ b/extensions/sn_mod_support_apis/ui/simple_menu/Options_Menu.lua
@@ -1,4 +1,4 @@
-
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.simple_menu.Options_Menu",function(require)
--[[
Interface into the ego options menu.
@@ -349,9 +349,6 @@ local function Init_Gameoptions_Link()
-- May require another monkey patch.
end
--- Run the above immediately.
-Init_Gameoptions_Link()
-
-- Register a custom options submenu provided by user.
function menu.Register_Options_Menu(args)
-- Verify the id appears unique, at least among registered submenus.
@@ -625,11 +622,6 @@ function menu.Handle_Delayed_Display()
menu_data.frame:display()
end
-
-return menu
-
-
-
--[[
Old development notes:
@@ -743,4 +735,7 @@ After having trouble getting submenus to be selected. Thoughts:
the main data table to be scrollable. Monkeypatching viewCreated may
be the only reliable way to handle this.
-]]
\ No newline at end of file
+]]
+
+return menu,Init_Gameoptions_Link
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/lua/simple_menu/Standalone_Menu.lua b/extensions/sn_mod_support_apis/ui/simple_menu/Standalone_Menu.lua
similarity index 99%
rename from extensions/sn_mod_support_apis/lua/simple_menu/Standalone_Menu.lua
rename to extensions/sn_mod_support_apis/ui/simple_menu/Standalone_Menu.lua
index 8a0be11..f53f373 100644
--- a/extensions/sn_mod_support_apis/lua/simple_menu/Standalone_Menu.lua
+++ b/extensions/sn_mod_support_apis/ui/simple_menu/Standalone_Menu.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.simple_menu.Standalone_Menu",function (require)
--[[
Methods specific to the standalone menu.
]]
@@ -451,8 +452,5 @@ function menu.onUpdate()
menu.infoFrame:update()
end
-
-
-Init()
-
-return menu
\ No newline at end of file
+return menu,Init
+end)
diff --git a/extensions/sn_mod_support_apis/lua/simple_menu/Tables.lua b/extensions/sn_mod_support_apis/ui/simple_menu/Tables.lua
similarity index 99%
rename from extensions/sn_mod_support_apis/lua/simple_menu/Tables.lua
rename to extensions/sn_mod_support_apis/ui/simple_menu/Tables.lua
index d859c0f..5d0126f 100644
--- a/extensions/sn_mod_support_apis/lua/simple_menu/Tables.lua
+++ b/extensions/sn_mod_support_apis/ui/simple_menu/Tables.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.simple_menu.Tables",function(require)
--[[
Container for data tables, shared by other active modules.
]]
@@ -644,7 +645,7 @@ local function Widget_Init()
end
end
-Widget_Init()
-- Export tables.
-return T
\ No newline at end of file
+return T,Widget_Init
+end)
diff --git a/extensions/sn_mod_support_apis/lua/time/Interface.lua b/extensions/sn_mod_support_apis/ui/time/Interface.lua
similarity index 99%
rename from extensions/sn_mod_support_apis/lua/time/Interface.lua
rename to extensions/sn_mod_support_apis/ui/time/Interface.lua
index 9c2c8b4..4f79b8d 100644
--- a/extensions/sn_mod_support_apis/lua/time/Interface.lua
+++ b/extensions/sn_mod_support_apis/ui/time/Interface.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.time.Interface",function(require)
--[[
This module adds real time support accessible from md.
@@ -543,7 +544,5 @@ function E.Unregister_NewFrame_Callback(callback)
end
end
-
-Init()
-
-return E
\ No newline at end of file
+return E,Init
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/lua/time/Pipe_Time.lua b/extensions/sn_mod_support_apis/ui/time/Pipe_Time.lua
similarity index 95%
rename from extensions/sn_mod_support_apis/lua/time/Pipe_Time.lua
rename to extensions/sn_mod_support_apis/ui/time/Pipe_Time.lua
index cccb914..983305f 100644
--- a/extensions/sn_mod_support_apis/lua/time/Pipe_Time.lua
+++ b/extensions/sn_mod_support_apis/ui/time/Pipe_Time.lua
@@ -1,3 +1,4 @@
+local module = Lua_Loader.define("extensions.sn_mod_support_apis.lua.time.Pipe_Time",function(require)
--[[
Python pipe interface functions.
Split into a separate file so that the pipe api can import the general
@@ -79,5 +80,5 @@ function L.Toc(_, id)
)
end
-
-Init()
\ No newline at end of file
+return nil,Init
+end)
\ No newline at end of file
diff --git a/extensions/sn_mod_support_apis/lua/userdata/Interface.lua b/extensions/sn_mod_support_apis/ui/userdata/Interface.lua
similarity index 90%
rename from extensions/sn_mod_support_apis/lua/userdata/Interface.lua
rename to extensions/sn_mod_support_apis/ui/userdata/Interface.lua
index 0af698e..c3eb1be 100644
--- a/extensions/sn_mod_support_apis/lua/userdata/Interface.lua
+++ b/extensions/sn_mod_support_apis/ui/userdata/Interface.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_mod_support_apis.lua.userdata.Interface",function(require)
--[[
Support for accessing userdata from uidata.xml, stored in the
__MOD_USERDATA global table.
@@ -28,21 +29,27 @@ local L = {
function L.Init()
-- Initial copy of userdata to the md blackboard.
- L.player_id = ConvertStringTo64Bit(tostring(ffi.C.GetPlayerID()))
+ local player_id = ConvertStringTo64Bit(tostring(ffi.C.GetPlayerID()))
+
+ if player_id == 0 then
+ player_id = nil
+ end
+
+ L.player_id = player_id
-- If userdata is empty, and the player blackboard has data, then leave
-- it in place, as a minor safety against the game deleting userdata,
-- utilizing data from the savegame as a backup.
if next(__MOD_USERDATA) == nil then
-- Look up what the md has stored.
- local md_userdata = GetNPCBlackboard(L.player_id, "$__MOD_USERDATA")
+ local md_userdata = GetNPCBlackboard(player_id, "$__MOD_USERDATA")
-- If something, copy it back.
if md_userdata ~= nil then
__MOD_USERDATA = md_userdata
end
end
--DebugError("Copying __MOD_USERDATA to player blackboard")
- SetNPCBlackboard(L.player_id, "$__MOD_USERDATA", __MOD_USERDATA)
+ SetNPCBlackboard(player_id, "$__MOD_USERDATA", __MOD_USERDATA)
-- Listen for md Userdata update signal.
RegisterEvent("Userdata.Update", L.Userdata_Update)
@@ -120,9 +127,10 @@ function L.Write_Userdata(owner, key, value)
--SetNPCBlackboard(L.player_id, "$__MOD_USERDATA", __MOD_USERDATA)
end
-L.Init()
-
-return {
+local exports = {
Read_Userdata = L.Read_Userdata,
Write_Userdata = L.Write_Userdata,
-}
\ No newline at end of file
+}
+return exports, L.Init
+
+end)
\ No newline at end of file
diff --git a/extensions/sn_script_profiler/ui.xml b/extensions/sn_script_profiler/ui.xml
new file mode 100644
index 0000000..2f66536
--- /dev/null
+++ b/extensions/sn_script_profiler/ui.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/extensions/sn_script_profiler/lua/Script_Profiler.lua b/extensions/sn_script_profiler/ui/Script_Profiler.lua
similarity index 99%
rename from extensions/sn_script_profiler/lua/Script_Profiler.lua
rename to extensions/sn_script_profiler/ui/Script_Profiler.lua
index f8b020e..cd63a63 100644
--- a/extensions/sn_script_profiler/lua/Script_Profiler.lua
+++ b/extensions/sn_script_profiler/ui/Script_Profiler.lua
@@ -1,3 +1,4 @@
+Lua_Loader.define("extensions.sn_script_profiler.lua.Script_Profiler",function(require)
--[[
Lua side of performance profiling.
@@ -336,4 +337,5 @@ function L.Deformat_Time(time_string)
end
-Init()
+return nil,Init
+)
\ No newline at end of file