aboutsummaryrefslogtreecommitdiff
path: root/gamemode/nrequire.lua
diff options
context:
space:
mode:
authorAlexander Pickering <alexandermpickering@gmail.com>2018-01-09 18:19:26 -0500
committerAlexander Pickering <alexandermpickering@gmail.com>2018-01-09 18:21:21 -0500
commite2dc5bf1fec1e634a60801aca3acf41422e0c880 (patch)
treed532e6e81a33c08c773d1e017335eca249fca822 /gamemode/nrequire.lua
parent6d46bb53c056bc42856ff8a0365843ef108ee9a5 (diff)
downloadartery-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.lua256
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)