diff options
Diffstat (limited to 'gamemode')
| -rw-r--r-- | gamemode/nrequire.lua | 265 | ||||
| -rw-r--r-- | gamemode/zones.lua | 612 |
2 files changed, 216 insertions, 661 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") diff --git a/gamemode/zones.lua b/gamemode/zones.lua deleted file mode 100644 index 5d6d781..0000000 --- a/gamemode/zones.lua +++ /dev/null @@ -1,612 +0,0 @@ -do return end -local version = 1.20 -- Older versions will not run if a newer version is used in another script. ---[[ - ZONES - by Bobbleheadbob with help from Zeh Matt - WARNING: If you edit any of these files, make them use a different namespace. Multiple scripts may depend on this library so modifying it can break other scripts. - - Purpose: - For easy in-game designation of persistent polygonal zones which are used by any script. - - How to Use: - All zones are saved in zones.List; see an example below. - Zone creation is handled with weapon_zone_designator and ent_zone_point, but can be done in code as well. - When a zone is created, changed, or removed all zones are synced to clients. When clients join they are also synced. - Any extra details can be saved to a zone. Everything is written to a txt file and is persistent to the map. - - Since multiple scripts might use the zones system, don't assume that every zone is related to your script. - To register a zone class, use zones.RegisterClass(class, color); use a unique string like "Scriptname Room". - When a zone class is registered, admins can use the tool to create new ones. - When a new zone is created, the "OnZoneCreated" hook is called serverside. See the example file for documentation. - When a zone is loaded into the game, the "OnZoneLoaded" hook is called serverside. See the example file for documentation. - When a player edits a zone's properties, the "ShowZoneOptions" hook is called clientside. See the example file for documentation. - - Use zones.FindByClass() to find all zones which are of a given class. - Use ply:GetCurrentZone() to find the zone that a player is standing in. - - Installation: - This is a shared file so include it in any shared environment. Also include ent_zone_point and weapon_zone_designator as a shared ent and weapon. - You should not put this file directly in lua/autorun. - - License: - YOU MAY use/edit this however you want, as long as you give proper attribution. - YOU MAY distribute this with other scripts whether they are paid or free. - YOU MAY NOT distribute this on its own. It must accompany another script. - - Enjoy! ~Bobbleheadbob -]] - -local table, math, Vector, pairs, ipairs, ents, bit = table, math, Vector, pairs, ipairs, ents, bit - -if zones then - local diff = math.abs(math.floor(version)-math.floor(zones.version)) > 0 - if diff then - ErrorNoHalt("WARNING! Two scripts use VERY different versions of the zones API. Please tell one of them to update their script!\n") - end - if zones.version > version then - if diff then - print("The outdated version of zones is located at: "..debug.getinfo(1,"S").short_src) - end - print("A new version of zones exists. Using version "..zones.version.." instead of "..version) - return - elseif zones.version < version then - if diff then - print("The outdated version of zones is located at: "..debug.getinfo(zones.RegisterClass,"S").short_src) - end - print("A new version of zones exists. Using version "..version.." instead of "..zones.version) - end - -else - print("Loaded zones " ..version) -end - -zones = zones or {} -zones.version = version - -zones.Classes = zones.Classes or {} -zones.List = zones.List or {} -zones.Map = zones.Map or {} - - -//Common interface functions: - --- Registers a zone class which can then be created using weapon_zone_designator -function zones.RegisterClass(class,color) - zones.Classes[class] = color -end - - -local plymeta = FindMetaTable("Player") ---returns one of the zones a player is found in. Also returns that zone's ID. Class is optional to filter the search. -function plymeta:GetCurrentZone(class) - local c = zones.Cache[self][class or "___"] - if c then return unpack(c) end - local z,id = zones.GetZoneAt(self:GetPos(), class) - zones.Cache[self][class or "___"] = {z,id} - return z,id -end - ---returns a table of zones the player is in. Class is optional to filter the search. -function plymeta:GetCurrentZones(class) - return zones.GetZonesAt(self:GetPos(),class) -end - -function zones.GetZoneAt(pos,class) --works like above, except uses any point. - - local nearby = zones.GetNearbyZones(pos) - - for k,zone in pairs(nearby) do - - if class and class != zone.class then continue end - if not pos:WithinAABox(zone.bounds.mins, zone.bounds.maxs) then - continue - end - - for k1, points in pairs(zone.points) do - if zones.PointInPoly(pos,points) then - local z = points[1].z - if pos.z >= z and pos.z < z + zone.height[k1] then - return zone,k - end - end - end - end - - return nil, -1 - -end - -function zones.GetZonesAt(pos,class) --works like above, except uses any point. - local tbl = {} - local nearby = zones.GetNearbyZones(pos) - for k,zone in pairs(nearby) do - if class and class != zone.class then continue end - if not pos:WithinAABox(zone.bounds.mins,zone.bounds.maxs) then continue end - for k1, points in pairs(zone.points) do - if zones.PointInPoly(pos,points) then - local z = points[1].z - if pos.z >= z and pos.z < z + zone.height[k1] then - tbl[k] = zone - end - end - end - end - return tbl -end - ---Gets a list of all zones which are of the specified class. -function zones.FindByClass(class) - local tbl = {} - - for k,v in pairs(zones.List) do - if v.class == class then - tbl[k] = v - end - end - - return tbl -end - ---Returns the numerical ID of a zone. -function zones.GetID(zone) - return table.KeyFromValue(zones.List,zone) -end - - - - -//Getting into the meat of the API: -local mapMins = -16000 -local mapMaxs = 16000 -local mapSize = 32000 -local chunkSize = 128 - -local function GetZoneIndex(pos) - - local x = pos.x + mapMaxs - local y = pos.y + mapMaxs - local z = pos.z + mapMaxs - - local idxX = math.floor(x / chunkSize) - local idxY = math.floor(y / chunkSize) - local idxZ = math.floor(z / chunkSize) - local idx = bit.bor(bit.lshift(idxX, 24), bit.lshift(idxY, 14), idxZ) - - return idx - -end - -local function Floor(x,to) - return math.floor(x / to) * to -end -local function Ceil(x,to) - return math.ceil(x / to) * to -end - -function zones.CreateZoneMapping() - zones.Map = {} - for _, zone in pairs(zones.List) do - local mins = zone.bounds.mins - local maxs = zone.bounds.maxs - for x = Floor(mins.x,chunkSize), Ceil(maxs.x + 1,chunkSize), chunkSize do - for y = Floor(mins.y,chunkSize), Ceil(maxs.y + 1,chunkSize), chunkSize do - for z = Floor(mins.z,chunkSize), Ceil(maxs.z + 1,chunkSize), chunkSize do - local idx = GetZoneIndex(Vector(x, y, z)) - zones.Map[idx] = zones.Map[idx] or {} - table.insert(zones.Map[idx], zone) - end - end - end - end -end - -function zones.GetNearbyZones(pos) - //This system isn't working. - -- local idx = GetZoneIndex(pos) - -- return zones.Map[idx] or {} - return zones.List -end - -zones.Cache = {} -local function ClearCache() - for k,v in pairs(player.GetAll()) do - zones.Cache[v] = {} - end -end -ClearCache() -hook.Add("Tick","zones_cache",ClearCache) - -if SERVER then - util.AddNetworkString("zones_sync") - util.AddNetworkString("zones_class") - - function zones.SaveZones() - if not file.Exists("zones","DATA") then - file.CreateDir("zones") - end - file.Write("zones/"..game.GetMap():gsub("_","-"):lower()..".txt", util.TableToJSON(zones.List)) - end - concommand.Add("zone_save",function(ply,c,a) - if not ply:IsAdmin() then return end - zones.SaveZones() - end) - - function zones.LoadZones() - local tbl = file.Read("zones/"..game.GetMap():gsub("_","-"):lower()..".txt", "DATA") - zones.List = tbl and util.JSONToTable(tbl) or {} - - //Update legacy files: - for k,v in pairs(zones.List)do - if not v.bounds then - zones.CalcBounds(v) - end - - hook.Run("OnZoneLoaded",v,v.class,k) - end - end - - local sync = false - local syncply - - function zones.Sync(ply) - sync = true - syncply = ply - end - - hook.Add("Tick","zones_sync",function() - if sync then - net.Start("zones_sync") - net.WriteTable(zones.List) - if syncply then - net.Send(syncply) - syncply = nil - else - net.Broadcast() - zones.CreateZoneMapping() - end - sync = false - end - end) - - function zones.CreateZoneFromPoint(ent) - - local zone = { - points = {{}}, --only 1 area when creating a new zone. - height = {ent:GetTall()}, - class = ent:GetZoneClass(), - bounds = {} - } - - local id = table.maxn(zones.List) + 1 - local cur = ent - repeat - local pos = cur:GetPos() - Vector(0,0,2) - zone.points[1][#zone.points[1]+1] = pos - - cur:SetZoneID(id) - cur = cur:GetNext() - - until (cur == ent) - - zones.CalcBounds(zone,true) - - zones.List[id] = zone - hook.Run("OnZoneCreated",zone,zone.class,id) - - zones.Sync() - - - return zone, id - - end - - function zones.CalcBounds(zone,newZone) - local mins,maxs = Vector(10000000,10000000,10000000), Vector(-10000000,-10000000,-10000000) - for areanum,area in pairs(zone.points)do - for k,pos in pairs(area) do - maxs.x = math.max(pos.x, maxs.x) - maxs.y = math.max(pos.y, maxs.y) - maxs.z = math.max(pos.z+zone.height[areanum], maxs.z) - mins.x = math.min(pos.x, mins.x) - mins.y = math.min(pos.y, mins.y) - mins.z = math.min(pos.z, mins.z) - end - end - zone.bounds = {["mins"]=mins,["maxs"]=maxs} - if not newZone then - hook.Run("OnZoneChanged",zone,zone.class,zones.GetID(zone)) - end - end - - function zones.Remove(id) - hook.Run("OnZoneRemoved",zones.List[id],zones.List[id].class,id) - zones.List[id] = nil - zones.Sync() - end - - function zones.CreatePointEnts(removeThese) --removeThese is optional. - for k,v in pairs(removeThese or ents.FindByClass("ent_zone_point")) do --remove old - v:Remove() - end - - --create new - for id,zone in pairs(zones.List)do - - for k, area in pairs(zone.points) do - - local first - local curr - for k2,point in ipairs(area)do - - local next = ents.Create("ent_zone_point") - - if IsValid(curr) then - next:SetPos(point+Vector(0,0,1)) - curr:SetNext(next) - -- curr:DeleteOnRemove(next) - else - first = next - next:SetPos(point+Vector(0,0,1)) - end - - next.LastPoint = curr - curr = next - next:SetTall(zone.height[k]) - next:SetZoneClass(zone.class) - next:Spawn() - next:SetZoneID(id) - next:SetAreaNumber(k) - - end - - curr:SetNext(first) - -- curr:DeleteOnRemove(first) - first.LastPoint = curr - - end - end - - end - - function zones.Merge(from,to) - - local zfrom, zto = zones.List[from], zones.List[to] - - table.Add(zto.points, zfrom.points) - table.Add(zto.height, zfrom.height) - - zones.CalcBounds(zto) - zones.Remove(from) - - hook.Run("OnZoneMerged",zto,zto.class,to,zfrom,zfrom.class,from) - - zones.Sync() - - end - - function zones.Split(id,areanum) - local zone = zones.List[id] - local pts, h, bound = zone.points[areanum], zone.height[areanum] - - table.remove(zone.points,areanum) - table.remove(zone.height,areanum) - - if #zone.points == 0 then - zones.Remove(id) - end - - local new = table.Copy(zone) - new.points = {pts} - new.height = {h} - - local id = table.maxn(zones.List)+1 - zones.List[id] = new - - zones.CalcBounds(zone) - zones.CalcBounds(new) - - hook.Run("OnZoneSplit",new,new.class,id,zone,id) - - zones.Sync() - - return new,id - - end - - function zones.ChangeClass(id,class) - local zone,new = zones.List[id],{} - new.points = zone.points - new.height = zone.height - new.bounds = zone.bounds - new.class = class - - zones.List[id] = new - - hook.Run("OnZoneCreated",new,class,id) - - zones.Sync() - end - - - local mapMins = -16000 - local mapMaxs = 16000 - local mapSize = 32000 - local chunkSize = 128 - - function zones.GetZoneIndex(pos) - - local x = math.Remap(pos.x, mapMins, mapMaxs, 0, mapSize) - local y = math.Remap(pos.y, mapMins, mapMaxs, 0, mapSize) - local z = math.Remap(pos.z, mapMins, mapMaxs, 0, mapSize) - - local idxX = math.floor(x / chunkSize) - local idxY = math.floor(y / chunkSize) - local idxZ = math.floor(z / chunkSize) - local idx = bit.bor(bit.lshift(idxX, 24), bit.lshift(idxY, 14), idxZ) - - return idx - - end - - hook.Add("InitPostEntity","zones_load",function() - zones.LoadZones() - end) - hook.Add("PlayerInitialSpawn","zones_sync",function(ply) - zones.Sync(ply) - end) - - net.Receive("zones_class",function(len,ply) - if not ply:IsAdmin() then return end - local id = net.ReadFloat() - local class = net.ReadString() - - for k,v in pairs(ents.FindByClass("ent_zone_point"))do - if v:GetZoneID() == id then - v:SetZoneClass(class) - end - end - - zones.ChangeClass(id,class) - - end) - -else - net.Receive("zones_sync",function(len) - zones.List = net.ReadTable() - zones.CreateZoneMapping() - end) - - function zones.ShowOptions(id) - - local zone = zones.List[id] - local class = zone.class - - local frame = vgui.Create("DFrame") - zones.optionsFrame = frame - frame:MakePopup() - frame:SetTitle("Zone Settings") - - local ztitle = vgui.Create("DLabel",frame) - ztitle:Dock(TOP) - ztitle:DockMargin(2,0,5,5) - ztitle:SetText("Zone Class:") - ztitle:SizeToContents() - - local zclass = vgui.Create("DComboBox",frame) - zclass:Dock(TOP) - zclass:DockMargin(0,0,0,5) - for k,v in pairs(zones.Classes) do - zclass:AddChoice(k,nil,k == class) - end - function zclass:OnSelect(i,class) - net.Start("zones_class") - net.WriteFloat(id) - net.WriteString(class) - net.SendToServer() - - frame.content:Remove() - - frame.content = vgui.Create("DPanel",frame) - frame.content:Dock(FILL) - frame.content:DockPadding(5,5,5,5) - - local w,h = hook.Run("ShowZoneOptions",zone,class,frame.content,id,frame) - frame:SizeTo((w or 100)+8,(h or 2)+78, .2) - frame:MoveTo(ScrW()/2-((w or 292)+8)/2,ScrH()/2-((h or 422)+78)/2, .2) - end - - frame.content = vgui.Create("DPanel",frame) - frame.content:Dock(FILL) - frame.content:DockPadding(5,5,5,5) - - local w,h = hook.Run("ShowZoneOptions",zone,class,frame.content,id,frame) - frame:SetSize((w or 100)+8,(h or 2)+78) - frame:Center() - - end - -end - - - -//returns the point of intersection between two infinite lines. -local function IntersectPoint(line1, line2) - - local x1,y1,x2,y2,x3,y3,x4,y4 = line1.x1,line1.y1,line1.x2,line1.y2,line2.x1,line2.y1,line2.x2,line2.y2 - - local m1,m2 = (y1-y2)/((x1-x2)+.001),(y3-y4)/((x3-x4)+.001) --get the slopes - local yint1,yint2 = (-m1*x1)+y1,(-m2*x3)+y3 --get the y-intercepts - local x = (yint1-yint2)/(m2-m1) --calculate x pos - local y = m1*x+yint1 --plug in x pos to get y pos - - return x,y - -end -//Returns a bool if two SEGEMENTS intersect or not. -local function Intersect(line1, line2) - - local x,y = IntersectPoint(line1, line2) - - local sx,sy = tostring(x), tostring(y) - if (sx == "-inf" or sx == "inf" or sx == "nan") then - return false - end - - local minx1, maxx1 = math.min(line1.x1,line1.x2)-.1, math.max(line1.x1,line1.x2)+.1 - local minx2, maxx2 = math.min(line2.x1,line2.x2)-.1, math.max(line2.x1,line2.x2)+.1 - local miny1, maxy1 = math.min(line1.y1,line1.y2)-.1, math.max(line1.y1,line1.y2)+.1 - local miny2, maxy2 = math.min(line2.y1,line2.y2)-.1, math.max(line2.y1,line2.y2)+.1 - - if (x >= minx1) and (x <= maxx1) and (x >= minx2) and (x <= maxx2) then - - if (y >= miny1) and (y <= maxy1) and (y >= miny2) and (y <= maxy2) then - - --debugoverlay.Sphere( Vector(x,y,LocalPlayer():GetPos().z), 3, FrameTime()+.01, Color(255,0,0), true) - - return true - - end - - end - - return false - -end -function zones.PointInPoly(point,poly) //True if point is within a polygon. - - local ray = { - x1 = point.x, - y1 = point.y, - x2 = 100000, - y2 = 100000 - } - - local inside = false - - local line = { - x1 = 0, - y1 = 0, - x2 = 0, - y2 = 0 - } - - //Perform ray test - for k1, v in pairs(poly) do - - local v2 = poly[k1+1] - if not v2 then - v2 = poly[1] - end - - line["x1"] = v.x - line["y1"] = v.y - line["x2"] = v2.x - line["y2"] = v2.y - - if Intersect(ray,line) then - inside = !inside - end - - end - - return inside -end |
