aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gamemode/nrequire.lua265
-rw-r--r--gamemode/zones.lua612
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