1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-11-29 22:35:45 +00:00
Aquaria/files/scripts/compat/internal/old_1.1.lua
fgenesis 3b759294df Add support for mod script compatibility layers
This uses a new <Compatibility script="..." /> tag in a mod's XML file.
A compatbility layer is a script that runs before mod-init.lua is loaded,
and before any mod scripts are loaded when resuming a saved game.

This is a better solution than shipping a fragile wrapper
with every mod, that tends to break and then needs to be updated.
Now this wrapper is centralized, easy to use, and easy to update.

Closes #31.
2017-01-21 02:06:44 +01:00

107 lines
3.8 KiB
Lua

-- Compatibility wrapper [interface detouring]
-- allows to run scripts written for the old script interface (1.1.0, 1.1.1, 1.1.2)
-- on 1.1.3+ / OSE and its new scripting interface.
-- Note that this is a gross hack and a lot of guesswork is involved,
-- but any sanely written mod should run without changes.
-- Notes:
-- * Any assignment to the global "v" will break things. Like v = 0.
-- * Variables whose names only contain all-uppercase, underscores, and numbers are considered globals.
-- Assignments to those will not cause warnings and go to _G.
-- Assignments to non-globals will go to _G.v.
-- Undefined reads from either _G or v will cause a warning (in dev mode).
-- * Mods can provide their own compatibility hooks.
local rawset = rawset
local rawget = rawget
local _G = _G
local debug = rawget(_G, "debug") -- not present in some 1.1.3+ versions
local function looksLikeGlobal(s)
return not s:match("[^_%u%d]")
end
dofile("scripts/compat/internal/oldfunctions.lua")
-- loading entityinclude.lua is no longer necessary and would do more bad than good,
-- so make sure it's not loaded even if scripts explicitly load that file.
local o_dofile = dofile
local function dofileWrap(file)
if file:lower() ~= "scripts/entities/entityinclude.lua" then -- already in
--debugLog("dofile(" .. file .. ")")
return o_dofile(file)
end
end
rawset(_G, "dofile", dofileWrap)
-----------------------------------------------------
---- Fixup functions that differ in behavior now ----
-----------------------------------------------------
local createEntity_o = createEntity
rawset(_G, "createEntity", function(e, name, x, y)
if type(e) == "string" and #e > 0 then
return createEntity_o(e, name, x, y)
end
return 0
end)
-- Prepare interface function lookup table
local INTERFACE_LUT = {}
do
local names = getInterfaceFunctionNames()
--errorLog(table.concat(names, ", "))
for i = 1, #names do
INTERFACE_LUT[names[i]] = true
end
end
-- Detour global reads and writes to the currently active instance table
-- n = 0 will become v.n = 0
-- local x = entity_x(n) will become local x = entity_x(v.n)
-- important here is that no instance-local variables accidentally become globals.
-- globals that get written into the instance table are no problem. (if it ever happens - doubt it)
local _G_meta =
{
__index = function(tab, key)
if not INTERFACE_LUT[key] then
local v = rawget(_G, "v")
return v and v[key]
end
end,
__newindex = function(tab, key, val)
if key == "v" then -- v is set by the engine whenever script context is switched, this is no problem
if val ~= nil and type(val) ~= "table" then
errorLog("WARNING: COMPAT: Setting v to non-table (" .. type(v) .. ")! This is BAD and WILL break something!\n", 3)
-- but do it anyway.
end
rawset(tab, key, val)
return
end
if INTERFACE_LUT[key] then
--debugLog("Setting interface: " .. tostring(key) .. " = " .. tostring(val))
rawset(tab, key, val)
return
end
if type(key) == "string" and looksLikeGlobal(key) then
--debugLog("Setting global: " .. tostring(key) .. " = " .. tostring(val))
rawset(tab, key, val)
return
end
local v = rawget(_G, "v")
if v then
--debugLog("Setting v." .. tostring(key) .. " = " .. tostring(val))
v[key] = val
return
end
errorLog("Variable not set: " .. tostring(key) .. " = " .. tostring(val))
end
}
setmetatable(_G, _G_meta)
rawset(_G, "OLD_SCRIPT_INTERFACE_COMPATIBLE", true) -- mod-init.lua should check for this
debugLog("COMPAT/1.1: Redirecting global writes to v")