From 4879eb1d78520ce0ac9b0bb0ef5244cf65ad7c99 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Wed, 4 Jan 2017 23:27:36 -0500 Subject: Started refactoring item and inventory system --- gamemode/nrequire.lua | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 gamemode/nrequire.lua (limited to 'gamemode/nrequire.lua') diff --git a/gamemode/nrequire.lua b/gamemode/nrequire.lua new file mode 100644 index 0000000..ba71f17 --- /dev/null +++ b/gamemode/nrequire.lua @@ -0,0 +1,171 @@ +--[[ + 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) -- cgit v1.2.3-70-g09d2