--[[ A replacement for require ]] if nrequire ~= nil then return end print("hello from nrequire!") local path = (GM or GAMEMODE).Folder:gsub("gamemodes/","") .. "/gamemode" local function TraverseFolder(dir, func) local fpath = table.concat({path,dir,"/*"}) local files, directories = file.Find(fpath,"LUA") for k,v in pairs(files) do if string.GetExtensionFromFilename(v) == "lua" then local callpath = table.concat({path,dir,"/",v}) func(callpath) end end for k,v in pairs(directories) do local npath = table.concat({dir,"/",v}) TraverseFolder(npath,func) end end local function rebuild_include_table(f) local ret = {} for k,v in pairs(f) do local pathparts = {} for part in v:gmatch("/?[%w_]+/") do pathparts[#pathparts + 1] = part:gsub("/$",""):gsub("^/","") end local filename = v:gfind("[%w_]+%.lua$")() if ret[filename] == nil then ret[filename] = {} end local cursor = ret[filename] for folder = #pathparts, 2, -1 do if cursor[pathparts[folder]] == nil then cursor[pathparts[folder]] = {} end cursor = cursor[pathparts[folder]] end assert(cursor[pathparts[1]] == nil,string.format("Found 2 files with the same path:\n\t%s\n\t%s",cursor[pathparts[1]],pathparts[1])) cursor[pathparts[1]] = v end return ret end --Finds the number of elements in a table, even if it is not an array local function tbllen(tbl) local count = 0 for k,v in pairs(tbl) do count = count + 1 end return count end --[[ Finds all the paths from a pretable ]] local function collect_paths(pretbl) local ret = {} for k,v in pairs(pretbl) do if type(v) ~= "string" then local resp = collect_paths(v) for i,j in pairs(resp) do ret[#ret + 1] = j end else ret[#ret + 1] = v end end return ret end --[[ Scans the prefix table built by rebuild_include_table to find the file path for the partial name of an included file. ]] local function scan(pretbl, name) local pathparts = {} for part in name:gmatch("/?[%w_]+/") do pathparts[#pathparts + 1] = part:gsub("/$",""):gsub("^/","") end local filename = name:gfind("[%w_]+%.lua")() local cursor = pretbl[filename] assert(cursor ~= nil,string.format("Scan did not find a file named %q, valid files are:\n\t%s",filename,table.concat(pretbl,"\n\t"))) local rev = {} for i = 1, #pathparts do rev[#pathparts - i + 1] = pathparts[i] end for k,v in ipairs(rev) do cursor = cursor[v] end while type(cursor) ~= "string" do assert(type(cursor) ~= "nil",string.format("Could not find a valid file for path %q, file paths:\n\t%s",name,table.concat(collect_paths(pretbl),"\n\t"))) assert(tbllen(cursor) == 1,string.format("Ambiguous scan, there are two or more paths that match %q\n\t%s",name,table.concat(collect_paths(cursor),"\n\t"))) cursor = cursor[next(cursor)] end return cursor end local paths = {} local ins = function(n) paths[#paths + 1] = n end TraverseFolder("",ins) local ntbl = rebuild_include_table(paths) local reqtbl = {} for k,v in pairs(paths) do if SERVER and not v:match("/?sv_[%w_]+%.lua$") then print("Adding CS lua file",v) AddCSLuaFile(v) end end local pathstack = {} local incyields = {} function nrequire(req) print("nrequire") local tpath = scan(ntbl,req) if reqtbl[tpath] then print("nrequire cache hit") return reqtbl[tpath] end for k,v in pairs(pathstack) do assert(v ~= tpath,string.format("Circular dependancy detected:\n\t%s",table.concat(pathstack,"\n\t\t|\n\t\tv\n\t"))) end print(string.format("Including %q\n",tpath)) pathstack[#pathstack + 1] = tpath reqtbl[#reqtbl + 1] = include(tpath) print(string.format("Included %q\n",tpath)) return reqtbl[#reqtbl] --[[ incyields[#incyields + 1] = coroutine.create(function() print(string.format("Including %q\n",tpath)) reqtbl[#reqtbl + 1] = include(tpath) print(string.format("Included %q\n",tpath)) end) ]] end local function doincludes() print("doing includes") paths = {} TraverseFolder("",ins) ntbl = rebuild_include_table(paths) reqtbl = {} for k,v in pairs(paths) do if v:match("/?sv_[%w_]+%.lua$") then if SERVER then nrequire(v) end elseif v:match("/?cl_[%w_]+%.lua$") then if CLIENT then nrequire(v) end else nrequire(v) end pathstack = {} end while #incyields > 0 do for k,v in pairs(incyields) do if coroutine.status(v) == "dead" then incyields[k] = nil else coroutine.resume(v) end end end end doincludes() if SERVER then util.AddNetworkString("art_refresh") end if CLIENT then net.Receive("art_refresh",doincludes) end concommand.Add("art_manualrefresh",function(ply,cmd,args) doincludes() net.Start("art_refresh") net.Broadcast() end)