diff options
| author | Alexander Pickering <alexandermpickering@gmail.com> | 2018-01-09 18:19:26 -0500 |
|---|---|---|
| committer | Alexander Pickering <alexandermpickering@gmail.com> | 2018-01-09 18:21:21 -0500 |
| commit | e2dc5bf1fec1e634a60801aca3acf41422e0c880 (patch) | |
| tree | d532e6e81a33c08c773d1e017335eca249fca822 /gamemode/nrequire.lua | |
| parent | 6d46bb53c056bc42856ff8a0365843ef108ee9a5 (diff) | |
| download | artery-e2dc5bf1fec1e634a60801aca3acf41422e0c880.tar.gz artery-e2dc5bf1fec1e634a60801aca3acf41422e0c880.tar.bz2 artery-e2dc5bf1fec1e634a60801aca3acf41422e0c880.zip | |
Changed nrequire() to do the job of dataloader
As a side effect, this means that mods can now nrequire() from other
mods, and that the dataloader is depriciated.
Diffstat (limited to 'gamemode/nrequire.lua')
| -rw-r--r-- | gamemode/nrequire.lua | 256 |
1 files changed, 111 insertions, 145 deletions
diff --git a/gamemode/nrequire.lua b/gamemode/nrequire.lua index 29e350d..24f0266 100644 --- a/gamemode/nrequire.lua +++ b/gamemode/nrequire.lua @@ -4,69 +4,53 @@ artery_nrequire_defined artery_core_loaded ]] ---Don't run ourselves, or we'll get stuck in a recursive loop! if nrequire ~= nil then return end -local path = (GM or GAMEMODE).Folder:gsub("gamemodes/","") .. "/gamemode" ---[[ - Calls func on all the files under dir. -]] -local function TraverseFolder(dir, func) - local fpath = table.concat({path,dir,"/*"}) - local files, directories = file.Find(fpath,"LUA") + +local searchpaths = { + {"gamemodes/artery/gamemode","GAME"}, + {"artery/global","DATA"}, + {"data/artery/global","GAME"}, +} + +--dir is a table of {string_path, string_directory} +local function TraverseFolder(dir,func) + local find_path = table.concat({dir[1],"/*"},"") + local files,directories = file.Find(find_path,dir[2]) for k,v in pairs(files) do - if string.GetExtensionFromFilename(v) == "lua" then - local callpath = table.concat({path,dir,"/",v}) - func(callpath) - end + local callpath = table.concat({dir[1],"/",v},"") + func({callpath,dir[2]}) end for k,v in pairs(directories) do - local npath = table.concat({dir,"/",v}) - TraverseFolder(npath,func) + local npath = table.concat({dir[1],"/",v},"") + TraverseFolder({npath,dir[2]},func) end end ---[[ - Creates a funny kind of tree. The root points to tables with file names, each file name points to a table containing the folder name it is under. If that folder is under more folders, then the folder table points to more tables in reverse order. The leaf contains the file path. - Ex: - { - [file.lua] = { - [some] = { - [foldername] = "foldername/some/file.lua" - } - [other] = { - [foldername] = "foldername/other/file.lua" - } - } - } - is created from - foldername/ - some/ - file.lua - other/ - file.lua -]] -local function rebuild_include_table(f) - local ret = {} - for k,v in pairs(f) do +local function BuildIncludeTable(tbl) + local output = {} + for k,v in pairs(tbl) do + local filepath = v[1] + local fileloc = v[2] local pathparts = {} - for part in v:gmatch("/?[%w_]+/") do - pathparts[#pathparts + 1] = part:gsub("/$",""):gsub("^/","") + for part in filepath:gmatch("/?[%w_]+/") do + local foldername = part:gsub("/$",""):gsub("^/","") + pathparts[#pathparts+1] = foldername end - local filename = v:gfind("[%w_]+%.lua$")() - if ret[filename] == nil then - ret[filename] = {} + local filename = filepath:gfind("[%w_]+%.[%w_]+$")() + if output[filename] == nil then + output[filename] = {} end - local cursor = ret[filename] - for folder = #pathparts, 2, -1 do + local cursor = output[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])) + assert(cursor[pathparts[1]] == nil, string.format("Found 2 files with the same path:\n\t%q",pathparts[1])) cursor[pathparts[1]] = v end - return ret + return output end --Finds the number of elements in a table, even if it is not an array @@ -82,13 +66,13 @@ end local function collect_paths(pretbl) local ret = {} for k,v in pairs(pretbl) do - if type(v) ~= "string" then + if v[1] == nil then local resp = collect_paths(v) for i,j in pairs(resp) do ret[#ret + 1] = j end else - ret[#ret + 1] = v + ret[#ret + 1] = string.format("%s (%s)",v[1],v[2]) end end return ret @@ -103,136 +87,127 @@ local function scan(pretbl, name) for part in name:gmatch("/?[%w_]+/") do pathparts[#pathparts + 1] = part:gsub("/$",""):gsub("^/","") end - local filename = name:gfind("[%w_]+%.lua")() + local filename = name:gfind("[%w_]+%.[%w_]+$")() assert(filename ~= nil,string.format("Could not file a filename for %q from parts: %s valid files are:\n\t%s",name,table.concat(pathparts,","),table.concat(collect_paths(pretbl),"\n\t"))) 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(collect_paths(pretbl),"\n\t"))) + assert(cursor ~= nil,string.format("Scan did not find a file named %q.\n",filename)) local rev = {} for i = 1, #pathparts do rev[#pathparts - i + 1] = pathparts[i] end for k,v in ipairs(rev) do if cursor == nil then error(string.format("Scan could not complete file path translation while translateing %q at %s",table.concat(rev,","),v)) end cursor = cursor[v] end - while type(cursor) ~= "string" do + while cursor ~= nil and #cursor ~= 2 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\nSpecify more of the file path.",name,table.concat(collect_paths(cursor),"\n\t"))) cursor = cursor[next(cursor)] end + assert(type(cursor) ~= "nil", string.format("Could not find %s under %s, found under\n\t %s",filename,name, table.concat(collect_paths(pretbl[filename]),"\n\t"))) 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 +for k,v in pairs(searchpaths) do + TraverseFolder(v,function(n) + paths[#paths + 1] = n + end) end +local ntbl = BuildIncludeTable(paths) - +local reqtbl = {} --Holds already nrequire()'d things +local lastcall = {} --Holds when things were loaded +local deptbl = {} --Holds the dependencies between files local pathstack = {} ---local coroutines = {} ---[[ - Returns the table returned by executing a file. The table is cached after is is loaded, so calling nrequire() on a file twice will only run it once. -]] -function nrequire(req) - local tpath = scan(ntbl,req) --Find the full path from partial path - if reqtbl[tpath] then --And just return it if we've already included it. - return reqtbl[tpath] +function nrequire(req,...) + + + local tpath = scan(ntbl,req) -- Find the full path for the nrequired() module + + local trace = debug.getinfo(1,"flnSu") + local source = trace.source + deptbl[source] = tpath + + --If we've already run it, just return it + if reqtbl[tpath[1]] then + return reqtbl[tpath[1]] end - --Otherwise, make sure we don't have a circular dependancy + + --Otherwise, make sure we don't have a circular depedency for k,v in pairs(pathstack) do - assert(v ~= tpath,string.format("Circular dependancy detected:\n\t%s\n\t\t|\n\t\tV\n\t%s",table.concat(pathstack,"\n\t\t|\n\t\tV\n\t"),v)) + assert(v ~= tpath[1],string.format("Circular dependancy detected:\n\t%s\n\t\t|\n\t\tV\n\t%s",table.concat(pathstack,"\n\t\t|\n\t\tV\n\t"),v)) end - - --Override print so it's easy to see what file is printing what - --local tab_rep = {} - --for k = 1, #pathstack do tab_rep[k] = "\t" end - --print(string.format("%sIncluding %q",table.concat(tab_rep),tpath)) - --local oldprint = print - --print = function(...) oldprint(" ",unpack({...})) end - - --Deal with bookkeeping dealing with circular dependancies, and include - pathstack[#pathstack + 1] = tpath - reqtbl[tpath] = include(tpath) - hook.Call("artery_file_included",nil,tpah) - --[[ - co = coroutine.create(function() - reqtbl[tpath] = include(tpath) - --print("Finished ", tpath) - end) - coroutines[#coroutines + 1] = co - coroutine.resume(co) - ]] - pathstack[#pathstack] = nil - - --[[ - --Try to resume everyone else waiting on something - for k,v in pairs(coroutines) do - --V will be nil when the coroutine finishes, which removes it from the list, nifty. - coroutine.resume(v) + + --Actually run the file + pathstack[#pathstack + 1] = tpath[1] + local filetxt = file.Read(tpath[1],tpath[2]) + local filetime = file.Time(tpath[1],tpath[2]) + local filefunc = CompileString(filetxt,tpath[1],false) + if type(filefunc) ~= "function" then + error(filefunc) + else + xpcall(function() + local m = filefunc() + hook.Run("artery_file_included",tpath,m) + reqtbl[tpath[1]] = m + lastcall[tpath[1]] = filetime + end,function(err) + MsgC(Color(209,96,196),"nrequire Error:",err,"\n") + end) end - ]] - - --Undo the crazy print - --print = oldprint - --print(string.format("%sIncluded %q",table.concat(tab_rep),tpath)) - return reqtbl[tpath] + pathstack[#pathstack] = nil + + return reqtbl[tpath[1]] + end -hook.Call("artery_nrequire_defined") - --[[ Automatically include all the files in the gamemode directory based on the file name. If the file starts with cl_ it will only be included on the client, if it starts with sv_ it will only be included on the server. If it starts with anything else, it will be shared. Will detect and error on circuar dependancy. ]] local function doincludes() paths = {} - TraverseFolder("",ins) - ntbl = rebuild_include_table(paths) + for k,v in pairs(searchpaths) do + TraverseFolder(v,function(n) + paths[#paths + 1] = n + end) + end + ntbl = BuildIncludeTable(paths) reqtbl = reqtbl or {} for k,v in pairs(paths) do - if v:match("/?sv_[%w_]+%.lua$") then + local filename = v[1] + MsgN("Filename:",filename) + if filename == "gamemodes/artery/gamemode/init.lua" then + continue + end + if filename:match("/?sv_[%w_]+%.[%w_]+$") then if SERVER then - nrequire(v) + nrequire(filename) end - elseif v:match("/?cl_[%w_]+%.lua$") then + elseif filename:match("/?cl_[%w_]+%.[%w_]+$") then if CLIENT then - nrequire(v) + nrequire(filename) + else + AddCSLuaFile(filename) end else - nrequire(v) + if SERVER then + AddCSLuaFile(filename) + end + nrequire(filename) end pathstack = {} end end -local function refresh(filename) - local filepath = scan(ntbl,filename) - if filepath:match("/?sv_[%w_]+%.lua$") then - if SERVER then - reqtbl[filepath] = nil - nrequire(filepath) - end - elseif filepath:match("/?cl_[%w_]+%.lua$") then - if CLIENT then - reqtbl[filepath] = nil - nrequire(filepath) - end - else - reqtbl[filepath] = nil - nrequire(filepath) - end -end +doincludes() -doincludes() --Do it the first time through +concommand.Add("PrintDepTbl",function(ply,cmd,args) + PrintTable(deptbl) +end) +concommand.Add("PrintReqTbl",function(ply,cmd,args) + PrintTable(reqtbl) +end) ---Totaly refresh all files server and client side if SERVER then util.AddNetworkString("art_refresh") concommand.Add("art_manualrefresh",function(ply,cmd,args) @@ -245,15 +220,6 @@ if SERVER then end if CLIENT then net.Receive("art_refresh",doincludes) end - -if SERVER then - util.AddNetworkString("art_reffile") - concommand.Add("art_refreshfile", function(ply,cmd,args) - if not ply:IsAdmin() then return end - refresh(args[1]) - net.Start("art_reffile") - net.WriteString(args[1]) - net.Broadcast() - end) -end -if CLIENT then net.Receive("art_reffile",function() refresh(net.ReadString()) end) end +concommand.Add("artery_manualrefresh",function(ply,cmd,args) + doincludes() +end) |
