Last active
February 15, 2022 22:52
-
-
Save Python1320/931281b126f8cfc89df0aa475979fd40 to your computer and use it in GitHub Desktop.
GMod require is broken, let's attempt a quick hack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Adapted from https://github.com/battlemesh/openwrt-packages/blob/ebd07d9f65f1044875cfe9e6d035732603a4b2f9/lang/luaexpat/files/compat-5.1r5/compat-5.1.lua | |
-- and https://github.com/danielga/gmod_require/blob/master/includes/modules/require.lua | |
-- and mostly from https://github.com/hoelzro/lua-procure | |
-- Combined license unknown | |
-- This file should not even be required... | |
if SERVER then AddCSLuaFile() return end -- not useful on server due to metaman require override but could/should probably be loaded anyway | |
local _require = _G.require_rqoverride or require | |
_G.require_rqoverride = _require | |
local sentinel | |
do | |
local function errhandler() | |
error("the require() sentinel can't be indexed or updated", 2) | |
end | |
sentinel = newproxy and newproxy() or setmetatable({}, { | |
__index = errhandler, | |
__newindex = errhandler, | |
__metatable = false | |
}) | |
end | |
sentinel = package.REQUIRE_SENTINEL or sentinel | |
package.REQUIRE_SENTINEL = sentinel | |
package.path = package.path or "lua/libraries/?.lua;lua/includes/modules/?.lua;lua/libraries/?/init.lua" | |
if not package.path:find"includes/modules" then | |
package.path = 'lua/includes/modules/?.lua;' .. package.path | |
end | |
local function loadfile(path_withlua, mode) | |
if mode then return nil, "attempt to load chunk with wrong mode" end | |
local path=path_withlua:gsub("^lua/","") -- TODO | |
-- CompileFile cannot be pcalled | |
if not file.Exists(path,'LUA') and not file.Exists(path_withlua,'GAME') then | |
return nil,"cannot open " .. path .. ": file not found" | |
end | |
local ok,data = pcall(CompileFile,path) | |
if not ok or not data then | |
local err = "cannot open " .. path .. ": code syntax error or file corrupt" | |
return nil, err | |
end | |
return data | |
end | |
local meta = {} | |
local _M = setmetatable({}, meta) | |
local function preload_loader(name) | |
if package.preload[name] then | |
return package.preload[name] | |
else | |
return string.format("no field package.preload['%s']\n", name) | |
end | |
end | |
local function path_loader(name, paths, loader_func) | |
local errors = {} | |
local loader | |
for path in string.gmatch(paths, '[^;]+') do | |
-- Try Garry require compatible path | |
path = path:gsub('%?', name) | |
local errmsg | |
loader, errmsg = loader_func(path) | |
if loader then | |
break | |
else | |
-- TODO error for when file isn't readable? | |
-- TODO error for when file isn't valid Lua (or loadable?) | |
table.insert(errors, string.format("no file '%s'", path)) | |
end | |
-- Try lua native path | |
local name = name:gsub('%.', '/') | |
path = string.gsub(path, '%?', name) | |
local errmsg | |
loader, errmsg = loader_func(path) | |
if loader then | |
break | |
else | |
-- TODO error for when file isn't readable? | |
-- TODO error for when file isn't valid Lua (or loadable?) | |
table.insert(errors, string.format("no file '%s'", path)) | |
end | |
end | |
if loader then | |
return loader | |
else | |
return table.concat(errors, '\n') .. '\n' | |
end | |
end | |
local function lua_loader(name) | |
return path_loader(name, package.path, loadfile) | |
end | |
local function get_init_function_name(name) | |
name = string.gsub(name, '^.*%-', '', 1) | |
name = string.gsub(name, '%.', '_') | |
return 'luaopen_' .. name | |
end | |
local function findchunk(name) | |
local errors = {string.format("module '%s' not found\n", name)} | |
local found | |
for _, loader in ipairs(_M.loaders) do | |
local chunk = loader(name) | |
if type(chunk) == 'function' then | |
return chunk | |
elseif type(chunk) == 'string' then | |
errors[#errors + 1] = chunk | |
end | |
end | |
return nil, table.concat(errors, '') | |
end | |
local function require(name) | |
--print("REQUIRE",name,debug.traceback()) | |
if package.loaded[name] == sentinel then | |
error(("loop or previous error loading module %q"):format(name)) | |
end | |
if package.loaded[name] ~= nil then return package.loaded[name] end | |
local chunk, errors = findchunk(name) | |
if not chunk then | |
error(errors, 2) | |
end | |
package.loaded[name] = sentinel | |
local result = chunk(name) | |
if result ~= nil then | |
package.loaded[name] = result | |
elseif package.loaded[name] == nil or package.loaded[name] == sentinel then | |
package.loaded[name] = true | |
end | |
if package.loaded[name] == sentinel then | |
error(("loop or previous error loading module %q"):format(name)) | |
end | |
return package.loaded[name] | |
end | |
local loadermeta = {} | |
function loadermeta:__call(...) | |
return self.impl(...) | |
end | |
local function makeloader(loader_func, name) | |
return setmetatable({ | |
impl = loader_func, | |
name = name | |
}, loadermeta) | |
end | |
local function original_loader(name) | |
local ok, ret = pcall(_require, name) | |
if not ok then return name .. ': ' .. ret .. '\n' end | |
return function() return ret or true end | |
end | |
-- TODO make sure that any added loaders are preserved | |
_M.loaders = { | |
makeloader(preload_loader, 'preload'), | |
makeloader(lua_loader, 'lua'), | |
makeloader(original_loader, 'garryloader'), | |
} | |
_G.package_x=_M | |
_G.require = require | |
return _M |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment