diff options
Diffstat (limited to 'gamemode/nrequire.lua')
| -rw-r--r-- | gamemode/nrequire.lua | 265 |
1 files changed, 216 insertions, 49 deletions
diff --git a/gamemode/nrequire.lua b/gamemode/nrequire.lua index d704907..94f7215 100644 --- a/gamemode/nrequire.lua +++ b/gamemode/nrequire.lua @@ -6,6 +6,8 @@ ]] if nrequire ~= nil then return end +local clienttoload = {} + local searchpaths = { {"gamemodes/artery/gamemode","GAME"}, {"artery/global","DATA"}, @@ -36,7 +38,7 @@ local function BuildIncludeTable(tbl) local foldername = part:gsub("/$",""):gsub("^/","") pathparts[#pathparts+1] = foldername end - local filename = filepath:gfind("[%w_]+%.[%w_]+$")() + local filename = filepath:gfind("[%w_%.]+%.[%w_]+$")() if output[filename] == nil then output[filename] = {} end @@ -47,7 +49,7 @@ local function BuildIncludeTable(tbl) end cursor = cursor[pathparts[folder]] end - assert(cursor[pathparts[1]] == nil, string.format("Found 2 files with the same path:\n\t%q",pathparts[1])) + assert(cursor[pathparts[1]] == nil, string.format("Found 2 files with the same path:\n\t%s",table.ToString(pathparts,"pathparts",true))) cursor[pathparts[1]] = v end return output @@ -87,7 +89,7 @@ local function scan(pretbl, name) for part in name:gmatch("/?[%w_]+/") do pathparts[#pathparts + 1] = part:gsub("/$",""):gsub("^/","") end - local filename = name:gfind("[%w_]+%.[%w_]+$")() + 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.\n",filename)) @@ -107,27 +109,32 @@ local function scan(pretbl, name) end local paths = {} -for k,v in pairs(searchpaths) do - TraverseFolder(v,function(n) - paths[#paths + 1] = n - end) -end -local ntbl = BuildIncludeTable(paths) +local ntbl = {} local reqtbl = {} --Holds already nrequire()'d things local lastcall = {} --Holds when things were loaded local deptbl = {} --Holds the dependencies between files local pathstack = {} function nrequire(req,...) - - local tpath = scan(ntbl,req) -- Find the full path for the nrequired() module + local varargs = {...} + local tpath + if CLIENT then + xpcall(function() + tpath = scan(ntbl,req) + end,function() + tpath = scan(ntbl,req .. ".txt") + end) + else + tpath = scan(ntbl,req) + end + -- local tpath = scan(ntbl,req) -- Find the full path for the nrequired() module local trace = debug.getinfo(2,"flnSu") local source = trace.source deptbl[source] = tpath --If we've already run it (and its up to date), just return it - if reqtbl[tpath[1]] and lastcall[tpath[1]] >= file.Time(tpath[1],tpath[2]) then + if reqtbl[tpath[1]] --[[and lastcall[tpath[1] ] >= file.Time(tpath[1],tpath[2])]] then return reqtbl[tpath[1]] end @@ -144,19 +151,28 @@ function nrequire(req,...) return end 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) + if lastcall[tpath[1]] and lastcall[tpath[1]] < filetime then + goto cleanup + end + + do -- Needed to follow the scoping rules of lua in regards to goto + local filefunc = CompileString(filetxt,tpath[1],false) + if type(filefunc) ~= "function" then + error(filefunc) + else + xpcall(function() + local m = filefunc(varargs) + hook.Run("artery_file_included",tpath,m) + reqtbl[tpath[1]] = m + lastcall[tpath[1]] = CurTime() + end,function(err) + MsgC(Color(209,96,196),debug.traceback(),"\n") + MsgC(Color(209,96,196),"nrequire Error:",err,"\n") + end) + end end + + ::cleanup:: pathstack[#pathstack] = nil return reqtbl[tpath[1]] @@ -189,11 +205,18 @@ else local function run_csfile(txt,name) assert(#txt > 0, "File was size 0 on: " .. name) local ptr = CompileString(txt,name,false) + local ret = nil if type(ptr) == "function" then - ptr() + xpcall(function() + ret = ptr() + end,function(err) + MsgC(Color(209,96,196),debug.traceback(),"\n") + MsgC(Color(209,96,196),"nrequire Error:",err,"\n") + end) else - log.error(ptr) + error(ptr) end + return ret end net.Receive("artery_loadfile",function() local filename = net.ReadString() @@ -220,17 +243,18 @@ else end) net.Receive("artery_respondfile",function() local filename = net.ReadString() + local filepath = net.ReadString() local filetext = net.ReadString() local dirname = string.GetPathFromFilename(filename) file.CreateDir("artery/client/files/" .. dirname) assert(#filetext > 0, "Retreived a size 0 file: " .. filename) file.Write("artery/client/files/" .. filename,filetext) - run_csfile(filetext,filename) + local mod = run_csfile(filetext,filename) + reqtbl[filepath] = mod + lastcall[filepath] = CurTime() end) end -local clienttoload = {} - --[[ 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. @@ -278,22 +302,142 @@ local function doincludes() end end -doincludes() -hook.Call("artery_core_loaded") -local function loadclient(who) - local routine = coroutine.create(function() - for k,v in pairs(clienttoload) do - print("Asking client to load",k) - net.Start("artery_loadfile") - net.WriteString(v.name) - net.WriteUInt(v.hash,32) - net.WriteString(v.directory) - net.Send(who) - coroutine.yield() +local function redoincludes() + print("redoing includes") + paths = {} -- Defined above somewhere + for k,v in pairs(searchpaths) do + print("Searching path:") + PrintTable(v) + TraverseFolder(v,function(n) + print("found file:") + PrintTable(n) + paths[#paths + 1] = n + end) + end + ntbl = BuildIncludeTable(paths) + doincludes() + hook.Call("artery_core_loaded") +end + +if SERVER then + redoincludes() + concommand.Add("artery_doincludes",function(ply,cmd,args) + redoincludes() + end) +end +local runclient = nil +if SERVER then + util.AddNetworkString("artery_downloadfile") + util.AddNetworkString("art_downloadfiles") + util.AddNetworkString("art_requestfile") + util.AddNetworkString("art_respondfile") + util.AddNetworkString("artery_request_client_download") + local function downloadclient(who) + print("Loading client",who) + net.Start("art_downloadfiles") + net.WriteTable(clienttoload) + net.Send(who) + -- local routine = coroutine.create(function() + -- for k,v in pairs(clienttoload) do + -- print("Asking client to load",k) + -- net.Start("artery_downloadfile") + -- net.WriteString(v.name) + -- net.WriteUInt(v.hash,32) + -- net.WriteString(v.directory) + -- net.WriteString(file.Read(v.name,v.directory)) + -- net.Send(who) + -- coroutine.yield() + -- end + -- end) + -- timer.Create("artery_downloadload_client_timer",1,#clienttoload,function() + -- coroutine.resume(routine) + -- end) + end + net.Receive("artery_request_client_download",function(ln,pl) + print("artery_request_client_download received by server") + downloadclient(pl) + end) + net.Receive("art_requestfile",function(ln,pl) + local filedata = net.ReadTable() + local filetxt = file.Read(filedata.name,filedata.directory) + net.Start("art_respondfile") + net.WriteTable({ + name = filedata.name, + directory = filedata.directory, + text = filetxt + }) + net.Send(pl) + end) +else + net.Receive("art_downloadfiles",function(ln,pl) + local clientfiles = net.ReadTable() + local todownload = {} + + for k,v in pairs(clientfiles) do + local fullpath = "artery/client/" .. v.directory .. "/" .. v.name .. ".txt" + if not file.Exists(fullpath,"DATA") then + local thisdownload = { + name = v.name, + directory = v.directory + } + todownload[#todownload + 1] = thisdownload + elseif util.CRC(file.Read(fullpath,"DATA")) ~= v.hash then + local thisdownload = { + name = v.name, + directory = v.directory + } + todownload[#todownload + 1] = thisdownload + -- else file is up to date and dosn't need re-downloading. + end end + + local routine = coroutine.create(function() + for k,v in pairs(todownload) do + net.Start("art_requestfile") + net.WriteTable(v) + net.SendToServer() + coroutine.yield() + end + runclient() + end) + timer.Create("artery_download_files_timer",0.1,#todownload,function() + coroutine.resume(routine) + end) end) - timer.Create("artery_load_client_timer",1,#clienttoload,function() - coroutine.resume(routine) + + net.Receive("art_respondfile",function(ln,pl) + local tbl = net.ReadTable() + print("Received response file:",tbl.name) + local fullpath = "artery/client/" .. tbl.directory .. "/" .. tbl.name .. ".txt" + local path = string.GetPathFromFilename(fullpath) + file.CreateDir(path) + print("Writing to ", fullpath) + file.Write(fullpath,tbl.text) + end) + + net.Receive("artery_downloadfile",function(ln,pl) + print("Asked to download file") + local clientfiles = net.ReadTable() + -- local filename = net.ReadString() + -- local filehash = net.ReadUInt(32) + -- local filedir = net.ReadString() + -- local filetext = net.ReadString() + -- print("got filename:",filename,"and filedir:",filedir) + -- local dirname = string.GetPathFromFilename(filename) + -- file.CreateDir("artery/client/files/" .. dirname) + -- assert(#filetext > 0, "Retreived a size 0 file: " .. filename) + -- file.Write("artery/client/files/" .. filename,"") + end) + local function request_file_download() + print("Requesting to download client files") + net.Start("artery_request_client_download") + net.SendToServer() + end + timer.Simple(0,function() + request_file_download() + end) + concommand.Add("artery_DownloadClient",function(ply,cmd,args) + request_file_download() end) end @@ -303,12 +447,35 @@ end) concommand.Add("PrintReqTbl",function(ply,cmd,args) PrintTable(reqtbl) end) -concommand.Add("PrintClientToLoad",function(ply,cmd,args) - PrintTable(clienttoload) -end) -concommand.Add("Loadclient",function(ply,cmd,args) - loadclient(ply) -end) +if SERVER then + concommand.Add("PrintClientToLoad",function(ply,cmd,args) + PrintTable(clienttoload) + end) +end + +if SERVER then + util.AddNetworkString("art_requestclientreload") + net.Receive("art_requestclientreload",function(ln,pl) + loadclient(pl) + end) +else + concommand.Add("artery_LoadClient",function(ply,cmd,args) + net.Start("art_requestclientreload") + net.SendToServer() + --loadclient(ply) + end) + runclient = function() + searchpaths = { + {"artery/client/game/","DATA"}, + {"artery/client/" .. game.GetMap() .. "/", "DATA"} + } + redoincludes() + end + runclient() + concommand.Add("artery_RunClient",function(ply,cmd,args) + runclient() + end) +end if SERVER then util.AddNetworkString("art_refresh") |
