Skip to content

Instantly share code, notes, and snippets.

@Python1320
Last active February 15, 2022 22:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Python1320/931281b126f8cfc89df0aa475979fd40 to your computer and use it in GitHub Desktop.
Save Python1320/931281b126f8cfc89df0aa475979fd40 to your computer and use it in GitHub Desktop.
GMod require is broken, let's attempt a quick hack
-- 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