diff options
Diffstat (limited to 'gamemode/nrequire.lua')
| -rw-r--r-- | gamemode/nrequire.lua | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/gamemode/nrequire.lua b/gamemode/nrequire.lua index 6595fed..1fc70bd 100644 --- a/gamemode/nrequire.lua +++ b/gamemode/nrequire.lua @@ -1,12 +1,15 @@ --[[ A thing that kinda works like require, or at least, works how I wish require worked. + calls hooks: + 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 print("hello from nrequire!") local path = (GM or GAMEMODE).Folder:gsub("gamemodes/","") .. "/gamemode" --[[ - Calls func on all the files under dir + Calls func on all the files under dir. ]] local function TraverseFolder(dir, func) local fpath = table.concat({path,dir,"/*"}) @@ -102,6 +105,7 @@ local function scan(pretbl, name) pathparts[#pathparts + 1] = part:gsub("/$",""):gsub("^/","") end local filename = name:gfind("[%w_]+%.lua")() + 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"))) local rev = {} @@ -126,39 +130,58 @@ 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) + --print("Adding CS lua file",v) AddCSLuaFile(v) end end 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) - if reqtbl[tpath] then - --print("Cache hit! returning",reqtbl[tpath]) - --for k,v in pairs(reqtbl[tpath]) do print(k,":",v) end + 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] end + --Otherwise, make sure we don't have a circular dependancy 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)) 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)) + --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) + 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) + end + + --Undo the crazy print print = oldprint - print(string.format("%sIncluded %q",table.concat(tab_rep),tpath)) + --print(string.format("%sIncluded %q",table.concat(tab_rep),tpath)) return reqtbl[tpath] 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. |
