add sborka

This commit is contained in:
2026-03-31 10:27:04 +03:00
commit f5e5f56c84
2345 changed files with 382127 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
function AdvDupe2.ReceiveFile(data, autoSave)
AdvDupe2.RemoveProgressBar()
if not data then
AdvDupe2.Notify("File was not saved! (No data)",NOTIFY_ERROR,5)
return
end
local path
if autoSave then
if(LocalPlayer():GetInfo("advdupe2_auto_save_overwrite")~="0")then
path = AdvDupe2.GetFilename(AdvDupe2.AutoSavePath, true)
else
path = AdvDupe2.GetFilename(AdvDupe2.AutoSavePath)
end
else
path = AdvDupe2.GetFilename(AdvDupe2.SavePath)
end
path = AdvDupe2.SanitizeFilename(path)
local dupefile = file.Open(path, "wb", "DATA")
if not dupefile then
AdvDupe2.Notify("File was not saved! (Could not open file for writing)",NOTIFY_ERROR,5)
return
end
dupefile:Write(data)
dupefile:Close()
local errored = false
if(LocalPlayer():GetInfo("advdupe2_debug_openfile")=="1")then
if(not file.Exists(path, "DATA"))then AdvDupe2.Notify("File does not exist", NOTIFY_ERROR) return end
local readFile = file.Open(path, "rb", "DATA")
if not readFile then AdvDupe2.Notify("File could not be read", NOTIFY_ERROR) return end
local readData = readFile:Read(readFile:Size())
readFile:Close()
local success, dupe, _info, _moreinfo = AdvDupe2.Decode(readData)
if(success)then
AdvDupe2.Notify("DEBUG CHECK: File successfully opens. No EOF errors.")
else
AdvDupe2.Notify("DEBUG CHECK: " .. dupe, NOTIFY_ERROR)
errored = true
end
end
local filename = string.StripExtension(string.GetFileFromFilename( path ))
if autoSave then
if(IsValid(AdvDupe2.FileBrowser.AutoSaveNode))then
local add = true
for i=1, #AdvDupe2.FileBrowser.AutoSaveNode.Files do
if(filename==AdvDupe2.FileBrowser.AutoSaveNode.Files[i].Label:GetText())then
add=false
break
end
end
if(add)then
AdvDupe2.FileBrowser.AutoSaveNode:AddFile(filename)
AdvDupe2.FileBrowser.Browser.pnlCanvas:Sort(AdvDupe2.FileBrowser.AutoSaveNode)
end
end
else
AdvDupe2.FileBrowser.Browser.pnlCanvas.ActionNode:AddFile(filename)
AdvDupe2.FileBrowser.Browser.pnlCanvas:Sort(AdvDupe2.FileBrowser.Browser.pnlCanvas.ActionNode)
end
if not errored then
AdvDupe2.Notify("File successfully saved!",NOTIFY_GENERIC, 5)
end
end
net.Receive("AdvDupe2_ReceiveFile", function()
local autoSave = net.ReadBool()
net.ReadStream(nil, function(data)
AdvDupe2.ReceiveFile(data, autoSave)
end)
end)
AdvDupe2.Uploading = false
function AdvDupe2.SendFile(name, data)
net.Start("AdvDupe2_ReceiveFile")
net.WriteString(name)
AdvDupe2.Uploading = net.WriteStream(data, function()
AdvDupe2.Uploading = nil
AdvDupe2.File = nil
AdvDupe2.RemoveProgressBar()
end)
net.SendToServer()
end
function AdvDupe2.UploadFile(ReadPath, ReadArea)
if AdvDupe2.Uploading then AdvDupe2.Notify("Already opening file, please wait.", NOTIFY_ERROR) return end
if(ReadArea==0)then
ReadPath = AdvDupe2.DataFolder.."/"..ReadPath..".txt"
elseif(ReadArea==1)then
ReadPath = AdvDupe2.DataFolder.."/-Public-/"..ReadPath..".txt"
else
ReadPath = "adv_duplicator/"..ReadPath..".txt"
end
if(not file.Exists(ReadPath, "DATA"))then AdvDupe2.Notify("File does not exist", NOTIFY_ERROR) return end
local read = file.Read(ReadPath)
if not read then AdvDupe2.Notify("File could not be read", NOTIFY_ERROR) return end
local name = string.Explode("/", ReadPath)
name = name[#name]
name = string.sub(name, 1, #name-4)
local success, dupe, info, moreinfo = AdvDupe2.Decode(read)
if(success)then
AdvDupe2.SendFile(name, read)
AdvDupe2.LoadGhosts(dupe, info, moreinfo, name)
else
AdvDupe2.Notify("File could not be decoded. ("..dupe..") Upload Canceled.", NOTIFY_ERROR)
end
end

View File

@@ -0,0 +1,353 @@
function AdvDupe2.LoadGhosts(dupe, info, moreinfo, name, preview)
AdvDupe2.RemoveGhosts()
AdvDupe2.Ghosting = true
AdvDupe2.GhostToSpawn = {}
local count = 0
local time, desc, date, creator
if(info.ad1) then
local z = dupe.HeadEnt.Z
local Pos, Ang
time = moreinfo.Time or ""
desc = info.Description or ""
date = info.Date or ""
creator = info.Creator or ""
AdvDupe2.HeadEnt = dupe.HeadEnt.Index
AdvDupe2.HeadPos = dupe.HeadEnt.Pos
AdvDupe2.HeadZPos = z
AdvDupe2.HeadPos.Z = AdvDupe2.HeadPos.Z + z
for k, v in pairs(dupe.Entities) do
if(v.SavedParentIdx) then
if(not v.BuildDupeInfo) then v.BuildDupeInfo = {} end
v.BuildDupeInfo.DupeParentID = v.SavedParentIdx
Pos = v.LocalPos
Ang = v.LocalAngle
else
Pos, Ang = nil, nil
end
for i, p in pairs(v.PhysicsObjects) do
p.Pos = Pos or p.LocalPos
p.Pos.Z = p.Pos.Z - z
p.Angle = Ang or p.LocalAngle
p.LocalPos = nil
p.LocalAngle = nil
end
v.LocalPos = nil
v.LocalAngle = nil
AdvDupe2.GhostToSpawn[count] =
{
Model = v.Model,
PhysicsObjects = v.PhysicsObjects
}
if(AdvDupe2.HeadEnt == k) then
AdvDupe2.HeadEnt = count
end
count = count + 1
end
AdvDupe2.HeadOffset = AdvDupe2.GhostToSpawn[AdvDupe2.HeadEnt].PhysicsObjects[0].Pos
AdvDupe2.HeadAngle = AdvDupe2.GhostToSpawn[AdvDupe2.HeadEnt].PhysicsObjects[0].Angle
else
time = info.time or ""
desc = dupe.Description or ""
date = info.date or ""
creator = info.name or ""
AdvDupe2.HeadEnt = dupe.HeadEnt.Index
AdvDupe2.HeadZPos = dupe.HeadEnt.Z
AdvDupe2.HeadPos = dupe.HeadEnt.Pos
AdvDupe2.HeadOffset = dupe.Entities[AdvDupe2.HeadEnt].PhysicsObjects[0].Pos
AdvDupe2.HeadAngle = dupe.Entities[AdvDupe2.HeadEnt].PhysicsObjects[0].Angle
for k, v in pairs(dupe.Entities) do
AdvDupe2.GhostToSpawn[count] =
{
Model = v.Model,
PhysicsObjects = v.PhysicsObjects
}
if(AdvDupe2.HeadEnt == k) then
AdvDupe2.HeadEnt = count
end
count = count + 1
end
end
if(not preview) then
AdvDupe2.Info.File:SetText("File: "..name)
AdvDupe2.Info.Creator:SetText("Creator: "..creator)
AdvDupe2.Info.Date:SetText("Date: "..date)
AdvDupe2.Info.Time:SetText("Time: "..time)
AdvDupe2.Info.Size:SetText("Size: "..string.NiceSize(tonumber(info.size) or 0))
AdvDupe2.Info.Desc:SetText("Desc: "..(desc or ""))
AdvDupe2.Info.Entities:SetText("Entities: "..table.Count(dupe.Entities))
AdvDupe2.Info.Constraints:SetText("Constraints: "..table.Count(dupe.Constraints))
end
AdvDupe2.StartGhosting()
AdvDupe2.Preview = preview
end
function AdvDupe2.RemoveGhosts()
if(AdvDupe2.Ghosting) then
hook.Remove("Tick", "AdvDupe2_SpawnGhosts")
AdvDupe2.Ghosting = false
if(not AdvDupe2.BusyBar) then
AdvDupe2.RemoveProgressBar()
end
end
if(AdvDupe2.GhostEntities) then
for k, v in pairs(AdvDupe2.GhostEntities) do
if(IsValid(v))then
v:Remove()
end
end
end
if(IsValid(AdvDupe2.HeadGhost))then
AdvDupe2.HeadGhost:Remove()
end
AdvDupe2.CurrentGhost = 1
AdvDupe2.HeadGhost = nil
AdvDupe2.GhostEntities = nil
AdvDupe2.Preview = false
end
--Creates a ghost from the given entity's table
local function MakeGhostsFromTable(EntTable)
if(not EntTable) then return end
if(not EntTable.Model or EntTable.Model:sub(-4,-1) ~= ".mdl") then
EntTable.Model = "models/error.mdl"
end
local GhostEntity = ClientsideModel(EntTable.Model, RENDERGROUP_TRANSLUCENT)
-- If there are too many entities we might not spawn..
if not IsValid(GhostEntity) then
AdvDupe2.RemoveGhosts()
AdvDupe2.Notify("Too many entities to spawn ghosts!", NOTIFY_ERROR)
return
end
GhostEntity:SetRenderMode( RENDERMODE_TRANSALPHA ) --Was broken, making ghosts invisible
GhostEntity:SetColor( Color(255, 255, 255, 150) )
GhostEntity.Phys = EntTable.PhysicsObjects[0]
if util.IsValidRagdoll(EntTable.Model) then
local ref, parents, angs = {}, {}, {}
GhostEntity:SetupBones()
for k, v in pairs(EntTable.PhysicsObjects) do
local bone = GhostEntity:TranslatePhysBoneToBone(k)
local bonp = GhostEntity:GetBoneParent(bone)
if bonp == -1 then
ref[bone] = GhostEntity:GetBoneMatrix(bone):GetInverseTR()
else
bonp = GhostEntity:TranslatePhysBoneToBone(GhostEntity:TranslateBoneToPhysBone(bonp))
parents[bone] = bonp
ref[bone] = GhostEntity:GetBoneMatrix(bone):GetInverseTR() * GhostEntity:GetBoneMatrix(bonp)
end
local m = Matrix() m:SetAngles(v.Angle)
angs[bone] = m
end
for bone, ang in pairs( angs ) do
if parents[bone] and angs[parents[bone]] then
local localrotation = angs[parents[bone]]:GetInverseTR() * ang
local m = ref[bone] * localrotation
GhostEntity:ManipulateBoneAngles(bone, m:GetAngles())
else
local pos = GhostEntity:GetBonePosition(bone)
GhostEntity:ManipulateBonePosition(bone, -pos)
GhostEntity:ManipulateBoneAngles(bone, ref[bone]:GetAngles())
end
end
end
return GhostEntity
end
local function StopGhosting()
AdvDupe2.Ghosting = false
hook.Remove( "Tick", "AdvDupe2_SpawnGhosts" )
if not BusyBar then AdvDupe2.RemoveProgressBar() end
end
local function SpawnGhosts()
local ghostsPerTick = GetConVar( "advdupe2_ghost_rate" ):GetInt()
local ghostPercentLimit = GetConVar( "advdupe2_limit_ghost" ):GetFloat()
local finalGhost = math.min( AdvDupe2.TotalGhosts, math.max( math.Round( (ghostPercentLimit / 100) * AdvDupe2.TotalGhosts ), 0 ) )
local finalGhostInFrame = math.min( AdvDupe2.CurrentGhost + ghostsPerTick - 1, finalGhost )
for i = AdvDupe2.CurrentGhost, finalGhostInFrame do
local g = AdvDupe2.GhostToSpawn[i]
if g and i ~= AdvDupe2.HeadEnt then AdvDupe2.GhostEntities[i] = MakeGhostsFromTable( g ) end
end
AdvDupe2.CurrentGhost = finalGhostInFrame + 1
AdvDupe2.UpdateGhosts( true )
if not AdvDupe2.BusyBar then
AdvDupe2.ProgressBar.Percent = (AdvDupe2.CurrentGhost / AdvDupe2.TotalGhosts) * 100
end
if AdvDupe2.CurrentGhost > finalGhost then
StopGhosting()
end
end
net.Receive("AdvDupe2_SendGhosts", function(len, ply, len2)
AdvDupe2.RemoveGhosts()
AdvDupe2.GhostToSpawn = {}
AdvDupe2.HeadEnt = net.ReadInt(16)
AdvDupe2.HeadZPos = net.ReadFloat()
AdvDupe2.HeadPos = net.ReadVector()
local cache = {}
for i = 1, net.ReadInt(16) do
cache[i] = net.ReadString()
end
for i = 1, net.ReadInt(16) do
AdvDupe2.GhostToSpawn[i] =
{
Model = cache[net.ReadInt(16)],
PhysicsObjects = {}
}
for k = 0, net.ReadInt(8) do
AdvDupe2.GhostToSpawn[i].PhysicsObjects[k] =
{
Angle = net.ReadAngle(),
Pos = net.ReadVector()
}
end
end
AdvDupe2.CurrentGhost = 1
AdvDupe2.GhostEntities = {}
AdvDupe2.HeadGhost = MakeGhostsFromTable(AdvDupe2.GhostToSpawn[AdvDupe2.HeadEnt])
AdvDupe2.HeadOffset = AdvDupe2.GhostToSpawn[AdvDupe2.HeadEnt].PhysicsObjects[0].Pos
AdvDupe2.HeadAngle = AdvDupe2.GhostToSpawn[AdvDupe2.HeadEnt].PhysicsObjects[0].Angle
AdvDupe2.GhostEntities[AdvDupe2.HeadEnt] = AdvDupe2.HeadGhost
AdvDupe2.TotalGhosts = #AdvDupe2.GhostToSpawn
if(AdvDupe2.TotalGhosts > 1) then
AdvDupe2.Ghosting = true
if(not AdvDupe2.BusyBar) then
AdvDupe2.InitProgressBar("Ghosting: ")
AdvDupe2.BusyBar = false
end
hook.Add("Tick", "AdvDupe2_SpawnGhosts", SpawnGhosts)
else
AdvDupe2.Ghosting = false
end
end)
net.Receive("AdvDupe2_AddGhost", function(len, ply, len2)
local ghost = {Model = net.ReadString(), PhysicsObjects = {}}
for k = 0, net.ReadInt(8) do
ghost.PhysicsObjects[k] = {Angle = net.ReadAngle(), Pos = net.ReadVector()}
end
AdvDupe2.GhostEntities[AdvDupe2.CurrentGhost] = MakeGhostsFromTable(ghost)
AdvDupe2.CurrentGhost = AdvDupe2.CurrentGhost + 1
end)
function AdvDupe2.StartGhosting()
AdvDupe2.RemoveGhosts()
if(not AdvDupe2.GhostToSpawn) then return end
AdvDupe2.CurrentGhost = 1
AdvDupe2.GhostEntities = {}
AdvDupe2.Ghosting = true
AdvDupe2.HeadGhost = MakeGhostsFromTable(AdvDupe2.GhostToSpawn[AdvDupe2.HeadEnt])
AdvDupe2.GhostEntities[AdvDupe2.HeadEnt] = AdvDupe2.HeadGhost
AdvDupe2.TotalGhosts = #AdvDupe2.GhostToSpawn
if AdvDupe2.TotalGhosts > 1 then
if not AdvDupe2.BusyBar then
AdvDupe2.InitProgressBar("Ghosting: ")
AdvDupe2.BusyBar = false
end
hook.Add("Tick", "AdvDupe2_SpawnGhosts", SpawnGhosts)
else
AdvDupe2.Ghosting = false
end
end
net.Receive("AdvDupe2_StartGhosting", function()
AdvDupe2.StartGhosting()
end)
net.Receive("AdvDupe2_RemoveGhosts", AdvDupe2.RemoveGhosts)
--Update the ghost's postion and angles based on where the player is looking and the offsets
local Lheadpos, Lheadang = Vector(), Angle()
function AdvDupe2.UpdateGhosts(force)
if not IsValid(AdvDupe2.HeadGhost) then
AdvDupe2.RemoveGhosts()
AdvDupe2.Notify("Invalid ghost parent!", NOTIFY_ERROR)
return
end
local trace = LocalPlayer():GetEyeTrace()
if (not trace.Hit) then return end
local originpos, originang, headpos, headang
local worigin = GetConVar("advdupe2_offset_world"):GetBool()
if(GetConVar("advdupe2_original_origin"):GetBool())then
originang = Angle()
originpos = Vector(AdvDupe2.HeadPos)
headpos = AdvDupe2.HeadPos + AdvDupe2.HeadOffset
headang = AdvDupe2.HeadAngle
else
local hangle = worigin and Angle(0,0,0) or AdvDupe2.HeadAngle
local pz = math.Clamp(AdvDupe2.HeadZPos + GetConVar("advdupe2_offset_z"):GetFloat() or 0, -16000, 16000)
local ap = math.Clamp(GetConVar("advdupe2_offset_pitch"):GetFloat() or 0, -180, 180)
local ay = math.Clamp(GetConVar("advdupe2_offset_yaw" ):GetFloat() or 0, -180, 180)
local ar = math.Clamp(GetConVar("advdupe2_offset_roll" ):GetFloat() or 0, -180, 180)
originang = Angle(ap, ay, ar)
originpos = Vector(trace.HitPos); originpos.z = originpos.z + pz
headpos, headang = LocalToWorld(AdvDupe2.HeadOffset, hangle, originpos, originang)
end
if math.abs(Lheadpos.x - headpos.x) > 0.01 or
math.abs(Lheadpos.y - headpos.y) > 0.01 or
math.abs(Lheadpos.z - headpos.z) > 0.01 or
math.abs(Lheadang.p - headang.p) > 0.01 or
math.abs(Lheadang.y - headang.y) > 0.01 or
math.abs(Lheadang.r - headang.r) > 0.01 or force then
Lheadpos = headpos
Lheadang = headang
AdvDupe2.HeadGhost:SetPos(headpos)
AdvDupe2.HeadGhost:SetAngles(headang)
for k, ghost in ipairs(AdvDupe2.GhostEntities) do
local phys = ghost.Phys
if phys then
local pos, ang = LocalToWorld(phys.Pos, phys.Angle, originpos, originang)
ghost:SetPos(pos)
ghost:SetAngles(ang)
end
end
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,564 @@
--[[
Title: Adv. Dupe 2 Codec
Desc: Dupe encoder/decoder.
Author: emspike
Version: 2.0
]]
local REVISION = 5
AdvDupe2.CodecRevision = REVISION
AdvDupe2.MaxDupeSize = 32e6 -- 32 MB
include( "sh_codec_legacy.lua" )
AddCSLuaFile( "sh_codec_legacy.lua" )
local pairs = pairs
local error = error
local Vector = Vector
local Angle = Angle
local format = string.format
local char = string.char
local concat = table.concat
local compress = util.Compress
local decompress = util.Decompress
--[[
Name: GenerateDupeStamp
Desc: Generates an info table.
Params: <player> ply
Return: <table> stamp
]]
function AdvDupe2.GenerateDupeStamp(ply)
local stamp = {}
stamp.name = ply:GetName()
stamp.time = os.date("%I:%M %p")
stamp.date = os.date("%d %B %Y")
stamp.timezone = os.date("%z")
hook.Call("AdvDupe2_StampGenerated",GAMEMODE,stamp)
return stamp
end
function AdvDupe2.SanitizeFilename(filename)
filename = string.gsub( filename, "[\":]", "_" )
filename = string.gsub( filename, "%s+", " " )
filename = string.gsub( filename, "%s*([\\/%.])%s*", "%1" )
return filename
end
local function makeInfo(tbl)
local info = ""
for k, v in pairs(tbl) do
info = concat{info,k,"\1",v,"\1"}
end
return info.."\2"
end
local AD2FF = "AD2F%s\n%s\n%s"
local tables, buff
local function noserializer() end
local enc = {}
for i = 1, 255 do enc[i] = noserializer end
local function isArray(tbl)
local ret = true
local m = 0
for k, v in pairs(tbl) do
m = m + 1
if k ~= m or enc[TypeID(v)] == noserializer then
ret = false
break
end
end
return ret
end
local function write(obj)
enc[TypeID(obj)](obj)
end
local len, tables, tablesLookup
enc[TYPE_TABLE] = function(obj) --table
if not tablesLookup[obj] then
tables = tables + 1
tablesLookup[obj] = tables
else
buff:WriteByte(247)
buff:WriteShort(tablesLookup[obj])
return
end
if isArray(obj) then
buff:WriteByte(254)
for i, v in pairs(obj) do
write(v)
end
else
buff:WriteByte(255)
for k, v in pairs(obj) do
if(enc[TypeID(k)] ~= noserializer and enc[TypeID(v)] ~= noserializer) then
write(k)
write(v)
end
end
end
buff:WriteByte(246)
end
enc[TYPE_BOOL] = function(obj) --boolean
buff:WriteByte(obj and 253 or 252)
end
enc[TYPE_NUMBER] = function(obj) --number
buff:WriteByte(251)
buff:WriteDouble(obj)
end
enc[TYPE_VECTOR] = function(obj) --vector
buff:WriteByte(250)
buff:WriteDouble(obj.x)
buff:WriteDouble(obj.y)
buff:WriteDouble(obj.z)
end
enc[TYPE_ANGLE] = function(obj) --angle
buff:WriteByte(249)
buff:WriteDouble(obj.p)
buff:WriteDouble(obj.y)
buff:WriteDouble(obj.r)
end
enc[TYPE_STRING] = function(obj) --string
len = #obj
if len < 246 then
buff:WriteByte(len)
buff:Write(obj)
else
buff:WriteByte(248)
buff:WriteULong(len)
buff:Write(obj)
end
end
local function error_nodeserializer()
buff:Seek(buff:Tell()-1)
error(format("Couldn't find deserializer for type {typeid:%d}!", buff:ReadByte()))
end
local reference = 0
local read4, read5
do --Version 4
local dec = {}
for i = 1, 255 do dec[i] = error_nodeserializer end
local function read()
local tt = buff:ReadByte()
if not tt then
error("Expected value, got EOF!")
end
if tt == 0 then
return nil
end
return dec[tt]()
end
read4 = read
dec[255] = function() --table
local t = {}
local k
reference = reference + 1
local ref = reference
repeat
k = read()
if k ~= nil then
t[k] = read()
end
until (k == nil)
tables[ref] = t
return t
end
dec[254] = function() --array
local t = {}
local k = 0
local v
reference = reference + 1
local ref = reference
repeat
k = k + 1
v = read()
if(v ~= nil) then
t[k] = v
end
until (v == nil)
tables[ref] = t
return t
end
dec[253] = function()
return true
end
dec[252] = function()
return false
end
dec[251] = function()
return buff:ReadDouble()
end
dec[250] = function()
return Vector(buff:ReadDouble(),buff:ReadDouble(),buff:ReadDouble())
end
dec[249] = function()
return Angle(buff:ReadDouble(),buff:ReadDouble(),buff:ReadDouble())
end
dec[248] = function() --null-terminated string
local start = buff:Tell()
local slen = 0
while buff:ReadByte() ~= 0 do
slen = slen + 1
end
buff:Seek(start)
local retv = buff:Read(slen)
if(not retv) then retv="" end
buff:ReadByte()
return retv
end
dec[247] = function() --table reference
reference = reference + 1
return tables[buff:ReadShort()]
end
for i = 1, 246 do dec[i] = function() return buff:Read(i) end end
end
do --Version 5
local dec = {}
for i = 1, 255 do dec[i] = error_nodeserializer end
local function read()
local tt = buff:ReadByte()
if not tt then
error("Expected value, got EOF!")
end
return dec[tt]()
end
read5 = read
dec[255] = function() --table
local t = {}
reference = reference + 1
tables[reference] = t
for k in read do
t[k] = read()
end
return t
end
dec[254] = function() --array
local t = {}
reference = reference + 1
tables[reference] = t
local k = 1
for v in read do
t[k] = v
k = k + 1
end
return t
end
dec[253] = function()
return true
end
dec[252] = function()
return false
end
dec[251] = function()
return buff:ReadDouble()
end
dec[250] = function()
return Vector(buff:ReadDouble(),buff:ReadDouble(),buff:ReadDouble())
end
dec[249] = function()
return Angle(buff:ReadDouble(),buff:ReadDouble(),buff:ReadDouble())
end
dec[248] = function() -- Length>246 string
local slen = buff:ReadULong()
local retv = buff:Read(slen)
if(not retv) then retv = "" end
return retv
end
dec[247] = function() --table reference
return tables[buff:ReadShort()]
end
dec[246] = function() --nil
return
end
for i = 1, 245 do dec[i] = function() return buff:Read(i) end end
dec[0] = function() return "" end
end
local function serialize(tbl)
tables = 0
tablesLookup = {}
buff = file.Open("ad2temp.txt", "wb", "DATA")
if not buff then error("Failed to open file data/ad2temp.txt for writing!") end
write(tbl)
buff:Close()
buff = file.Open("ad2temp.txt","rb","DATA")
if not buff then error("Failed to open file data/ad2temp.txt for reading!") end
local ret = buff:Read(buff:Size())
buff:Close()
return ret
end
local function deserialize(str, read)
if(str == nil) then
error("File could not be decompressed!")
return {}
end
tables = {}
reference = 0
buff = file.Open("ad2temp.txt","wb","DATA")
if not buff then error("Failed to open file data/ad2temp.txt for writing!") end
buff:Write(str)
buff:Flush()
buff:Close()
buff = file.Open("ad2temp.txt","rb", "DATA")
if not buff then error("Failed to open file data/ad2temp.txt for reading!") end
local success, tbl = pcall(read)
buff:Close()
if success then
return tbl
else
error(tbl)
end
end
--[[
Name: Encode
Desc: Generates the string for a dupe file with the given data.
Params: <table> dupe, <table> info, <function> callback, <...> args
Return: runs callback(<string> encoded_dupe, <...> args)
]]
function AdvDupe2.Encode(dupe, info, callback, ...)
local encodedTable = compress(serialize(dupe))
info.check = "\r\n\t\n"
info.size = #encodedTable
callback(AD2FF:format(char(REVISION), makeInfo(info), encodedTable),...)
end
--seperates the header and body and converts the header to a table
local function getInfo(str)
local last = str:find("\2")
if not last then
error("Attempt to read AD2 file with malformed info block!")
end
local info = {}
local ss = str:sub(1, last - 1)
for k, v in ss:gmatch("(.-)\1(.-)\1") do
info[k] = v
end
if info.check ~= "\r\n\t\n" then
if info.check == "\10\9\10" then
error("Detected AD2 file corrupted in file transfer (newlines homogenized)(when using FTP, transfer AD2 files in image/binary mode, not ASCII/text mode)!")
elseif info.check ~= nil then
error("Detected AD2 file corrupted by newline replacements (copy/pasting the data in various editors can cause this!)")
else
error("Attempt to read AD2 file with malformed info block!")
end
end
return info, str:sub(last+2)
end
--decoders for individual versions go here
local versions = {}
versions[1] = AdvDupe2.LegacyDecoders[1]
versions[2] = AdvDupe2.LegacyDecoders[2]
versions[3] = function(encodedDupe)
encodedDupe = encodedDupe:Replace("\r\r\n\t\r\n", "\t\t\t\t")
encodedDupe = encodedDupe:Replace("\r\n\t\n", "\t\t\t\t")
encodedDupe = encodedDupe:Replace("\r\n", "\n")
encodedDupe = encodedDupe:Replace("\t\t\t\t", "\r\n\t\n")
return versions[4](encodedDupe)
end
versions[4] = function(encodedDupe)
local info, dupestring = getInfo(encodedDupe:sub(7))
return deserialize(decompress(dupestring, AdvDupe2.MaxDupeSize), read4), info
end
versions[5] = function(encodedDupe)
local info, dupestring = getInfo(encodedDupe:sub(7))
return deserialize(decompress(dupestring, AdvDupe2.MaxDupeSize), read5), info
end
function AdvDupe2.CheckValidDupe(dupe, info)
if not dupe.HeadEnt then return false, "Missing HeadEnt table" end
if not dupe.Entities then return false, "Missing Entities table" end
if not dupe.Constraints then return false, "Missing Constraints table" end
if not dupe.HeadEnt.Z then return false, "Missing HeadEnt.Z" end
if not dupe.HeadEnt.Pos then return false, "Missing HeadEnt.Pos" end
if not dupe.HeadEnt.Index then return false, "Missing HeadEnt.Index" end
if not dupe.Entities[dupe.HeadEnt.Index] then return false, "Missing HeadEnt index ["..dupe.HeadEnt.Index.."] from Entities table" end
for key, data in pairs(dupe.Entities) do
if not data.PhysicsObjects then return false, "Missing PhysicsObject table from Entity ["..key.."]["..data.Class.."]["..data.Model.."]" end
if not data.PhysicsObjects[0] then return false, "Missing PhysicsObject[0] table from Entity ["..key.."]["..data.Class.."]["..data.Model.."]" end
if info.ad1 then -- Advanced Duplicator 1
if not data.PhysicsObjects[0].LocalPos then return false, "Missing PhysicsObject[0].LocalPos from Entity ["..key.."]["..data.Class.."]["..data.Model.."]" end
if not data.PhysicsObjects[0].LocalAngle then return false, "Missing PhysicsObject[0].LocalAngle from Entity ["..key.."]["..data.Class.."]["..data.Model.."]" end
else -- Advanced Duplicator 2
if not data.PhysicsObjects[0].Pos then return false, "Missing PhysicsObject[0].Pos from Entity ["..key.."]["..data.Class.."]["..data.Model.."]" end
if not data.PhysicsObjects[0].Angle then return false, "Missing PhysicsObject[0].Angle from Entity ["..key.."]["..data.Class.."]["..data.Model.."]" end
end
end
return true, dupe
end
--[[
Name: Decode
Desc: Generates the table for a dupe from the given string. Inverse of Encode
Params: <string> encodedDupe, <function> callback, <...> args
Return: runs callback(<boolean> success, <table/string> tbl, <table> info)
]]
function AdvDupe2.Decode(encodedDupe)
local sig, rev = encodedDupe:match("^(....)(.)")
if not rev then
return false, "Malformed dupe (wtf <5 chars long)!"
end
rev = rev:byte()
if sig ~= "AD2F" then
if sig == "[Inf" then --legacy support, ENGAGE (AD1 dupe detected)
local success, tbl, info, moreinfo = pcall(AdvDupe2.LegacyDecoders[0], encodedDupe)
if success then
info.ad1 = true
info.size = #encodedDupe
info.revision = 0
local index = tonumber(moreinfo.Head) or (istable(tbl.Entities) and next(tbl.Entities))
if not index then return false, "Missing head index" end
local pos
if isstring(moreinfo.StartPos) then
local spx,spy,spz = moreinfo.StartPos:match("^(.-),(.-),(.+)$")
pos = Vector(tonumber(spx) or 0, tonumber(spy) or 0, tonumber(spz) or 0)
else
pos = Vector()
end
local z
if isstring(moreinfo.HoldPos) then
z = (tonumber(moreinfo.HoldPos:match("^.-,.-,(.+)$")) or 0)*-1
else
z = 0
end
tbl.HeadEnt = {
Index = index,
Pos = pos,
Z = z
}
else
ErrorNoHalt(tbl)
end
if success then
success, tbl = AdvDupe2.CheckValidDupe(tbl, info)
end
return success, tbl, info, moreinfo
else
return false, "Unknown duplication format!"
end
elseif rev > REVISION then
return false, format("Newer codec needed. (have rev %u, need rev %u) Update Advdupe2.",REVISION,rev)
elseif rev < 1 then
return false, format("Attempt to use an invalid format revision (rev %d)!", rev)
else
local success, tbl, info = pcall(versions[rev], encodedDupe)
if success then
success, tbl = AdvDupe2.CheckValidDupe(tbl, info)
end
if success then
info.revision = rev
end
return success, tbl, info
end
end
if CLIENT then
concommand.Add("advdupe2_to_json", function(_,_,arg)
if not arg[1] then print("Need AdvDupe2 file name argument!") return end
local readFileName = "advdupe2/"..arg[1]
local writeFileName = "advdupe2/"..string.StripExtension(arg[1])..".json"
writeFileName = AdvDupe2.SanitizeFilename(writeFileName)
local readFile = file.Open(readFileName, "rb", "DATA")
if not readFile then print("File could not be read or found! ("..readFileName..")") return end
local readData = readFile:Read(readFile:Size())
readFile:Close()
local ok, tbl = AdvDupe2.Decode(readData)
local writeFile = file.Open(writeFileName, "wb", "DATA")
if not writeFile then print("File could not be written! ("..writeFileName..")") return end
writeFile:Write(util.TableToJSON(tbl))
writeFile:Close()
print("File written! ("..writeFileName..")")
end)
concommand.Add("advdupe2_from_json", function(_,_,arg)
if not arg[1] then print("Need json file name argument!") return end
local readFileName = "advdupe2/"..arg[1]
local writeFileName = "advdupe2/"..string.StripExtension(arg[1])..".txt"
local readFile = file.Open(readFileName, "rb", "DATA")
if not readFile then print("File could not be read or found! ("..readFileName..")") return end
local readData = readFile:Read(readFile:Size())
readFile:Close()
AdvDupe2.Encode(util.JSONToTable(readData), {}, function(data)
local writeFile = file.Open(writeFileName, "wb", "DATA")
if not writeFile then print("File could not be written! ("..writeFileName..")") return end
writeFile:Write(data)
writeFile:Close()
print("File written! ("..writeFileName..")")
end)
end)
end

View File

@@ -0,0 +1,559 @@
--[[
Title: Adv. Dupe 2 Codec Legacy Support
Desc: Facilitates opening of dupes from AD1 and earlier AD2 versions.
Author: emspike
Version: 2.0
]]
local pairs = pairs
local type = type
local tonumber = tonumber
local error = error
local Vector = Vector
local Angle = Angle
local format = string.format
local char = string.char
local byte = string.byte
local sub = string.sub
local gsub = string.gsub
local find = string.find
local gmatch = string.gmatch
local match = string.match
local concat = table.concat
--[[
Name: GenerateDupeStamp
Desc: Generates an info table.
Params: <player> ply
Return: <table> stamp
]]
function AdvDupe2.GenerateDupeStamp(ply)
local stamp = {}
stamp.name = ply:GetName()
stamp.time = os.date("%I:%M %p")
stamp.date = os.date("%d %B %Y")
stamp.timezone = os.date("%z")
hook.Call("AdvDupe2_StampGenerated",GAMEMODE,stamp)
return stamp
end
local AD2FF = "AD2F%s\n%s\n%s"
local decode_types_v1, decode_types_v2
local tables = 0
local str,pos
local a,b,c,m,n,w,tblref
local function read_v2()
local t = byte(str, pos+1)
if t then
local dt = decode_types_v2[t]
if dt then
pos = pos + 1
return dt()
else
error(format("encountered invalid data type (%u)\n",t))
end
else
error("expected value, got EOF\n")
end
end
decode_types_v2 = {
[1 ] = function()
error("expected value, got terminator\n")
end,
[2 ] = function() -- table
m = find(str, "\1", pos)
if m then
w = sub(str, pos+1, m-1)
pos = m
else
error("expected table identifier, got EOF\n")
end
local t = {}
tables[w] = t
while true do
if byte(str, pos+1) == 1 then
pos = pos + 1
return t
else
t[read_v2()] = read_v2()
end
end
end,
[3 ] = function() -- array
m = find(str, "\1", pos)
if m then
w = sub(str, pos+1, m-1)
pos = m
else
error("expected table identifier, got EOF\n")
end
local t, i = {}, 1
tables[w] = t
while true do
if byte(str,pos+1) == 1 then
pos = pos+1
return t
else
t[i] = read_v2()
i = i + 1
end
end
end,
[4 ] = function() -- false boolean
return false
end,
[5 ] = function() -- true boolean
return true
end,
[6 ] = function() -- number
m = find(str, "\1", pos)
if m then
a = tonumber(sub(str, pos+1, m-1)) or 0
pos = m
return a
else
error("expected number, got EOF\n")
end
end,
[7 ] = function() -- string
m = find(str,"\1",pos)
if m then
w = sub(str, pos+1, m-1)
pos = m
return w
else
error("expected string, got EOF\n")
end
end,
[8 ] = function() -- Vector
m,n = find(str,".-\1.-\1.-\1", pos)
if m then
a,b,c = match(str,"^(.-)\1(.-)\1(.-)\1",pos+1)
pos = n
return Vector(tonumber(a), tonumber(b), tonumber(c))
else
error("expected vector, got EOF\n")
end
end,
[9 ] = function() -- Angle
m,n = find(str, ".-\1.-\1.-\1", pos)
if m then
a,b,c = match(str, "^(.-)\1(.-)\1(.-)\1",pos+1)
pos = n
return Angle(tonumber(a), tonumber(b), tonumber(c))
else
error("expected angle, got EOF\n")
end
end,
[10 ] = function() -- Table Reference
m = find(str,"\1",pos)
if m then
w = sub(str,pos+1,m-1)
pos = m
else
error("expected table identifier, got EOF\n")
end
tblref = tables[w]
if tblref then
return tblref
else
error(format("table identifier %s points to nil\n", w))
end
end
}
local function read_v1()
local t = byte(str,pos+1)
if t then
local dt = decode_types_v1[t]
if dt then
pos = pos + 1
return dt()
else
error(format("encountered invalid data type (%u)\n",t))
end
else
error("expected value, got EOF\n")
end
end
decode_types_v1 = {
[1 ] = function()
error("expected value, got terminator\n")
end,
[2 ] = function() -- table
local t = {}
while true do
if byte(str,pos+1) == 1 then
pos = pos+1
return t
else
t[read_v1()] = read_v1()
end
end
end,
[3 ] = function() -- array
local t, i = {}, 1
while true do
if byte(str,pos+1) == 1 then
pos = pos+1
return t
else
t[i] = read_v1()
i = i + 1
end
end
end,
[4 ] = function() -- false boolean
return false
end,
[5 ] = function() -- true boolean
return true
end,
[6 ] = function() -- number
m = find(str,"\1",pos)
if m then
a = tonumber(sub(str,pos+1,m-1)) or 0
pos = m
return a
else
error("expected number, got EOF\n")
end
end,
[7 ] = function() -- string
m = find(str,"\1",pos)
if m then
w = sub(str,pos+1,m-1)
pos = m
return w
else
error("expected string, got EOF\n")
end
end,
[8 ] = function() -- Vector
m,n = find(str,".-\1.-\1.-\1",pos)
if m then
a,b,c = match(str,"^(.-)\1(.-)\1(.-)\1",pos+1)
pos = n
return Vector(tonumber(a), tonumber(b), tonumber(c))
else
error("expected vector, got EOF\n")
end
end,
[9 ] = function() -- Angle
m,n = find(str,".-\1.-\1.-\1",pos)
if m then
a,b,c = match(str,"^(.-)\1(.-)\1(.-)\1",pos+1)
pos = n
return Angle(tonumber(a), tonumber(b), tonumber(c))
else
error("expected angle, got EOF\n")
end
end
}
local function deserialize_v1(data)
str = data
pos = 0
tables = {}
return read_v1()
end
local function deserialize_v2(data)
str = data
pos = 0
tables = {}
return read_v2()
end
local function lzwDecode(encoded)
local dictionary_length = 256
local dictionary = {}
for i = 0, 255 do
dictionary[i] = char(i)
end
local pos = 2
local decompressed = {}
local decompressed_length = 1
local index = byte(encoded)
local word = dictionary[index]
decompressed[decompressed_length] = dictionary[index]
local entry
local encoded_length = #encoded
local firstbyte --of an index
while pos <= encoded_length do
firstbyte = byte(encoded,pos)
if firstbyte > 252 then --now we know it's a length indicator for a multibyte index
index = 0
firstbyte = 256 - firstbyte
--[[if pos+firstbyte > encoded_length then --will test for performance impact
error("expected index got EOF")
end]]
for i = pos+firstbyte, pos+1, -1 do
index = bit.bor(bit.lshift(index, 8), byte(encoded,i))
end
pos = pos + firstbyte + 1
else
index = firstbyte
pos = pos + 1
end
entry = dictionary[index] or (word..sub(word,1,1))
decompressed_length = decompressed_length + 1
decompressed[decompressed_length] = entry
dictionary[dictionary_length] = word..sub(entry,1,1)
dictionary_length = dictionary_length + 1
word = entry
end
return concat(decompressed)
end
--http://en.wikipedia.org/wiki/Huffman_coding#Decompression
local invcodes = {[2]={[0]="\254"},[5]={[22]="\1",[11]="\2"},[6]={[13]="\7",[35]="\6",[37]="\5",[58]="\3",[31]="\8",[9]="\13",[51]="\9",[55]="\10",[57]="\4",[59]="\15"},[7]={[1]="\14",[15]="\16",[87]="\31",[89]="\30",[62]="\26",[17]="\27",[97]="\19",[19]="\43",[10]="\12",[39]="\33",[41]="\24",[82]="\40",[3]="\32",[46]="\41",[47]="\38",[94]="\25",[65]="\23",[50]="\39",[26]="\11",[7]="\28",[33]="\18",[61]="\17",[25]="\42"},[8]={[111]="\101",[162]="\29",[2]="\34",[133]="\21",[142]="\36",[5]="\20",[21]="\37",[170]="\44",[130]="\22",[66]="\35"},[9]={[241]="\121",[361]="\104",[365]="\184",[125]="\227",[373]="\198",[253]="\117",[381]="\57",[270]="\49",[413]="\80",[290]="\47",[294]="\115",[38]="\112",[429]="\74",[433]="\0",[437]="\48",[158]="\183",[453]="\107",[166]="\111",[469]="\182",[477]="\241",[45]="\86",[489]="\69",[366]="\100",[497]="\61",[509]="\76",[49]="\53",[390]="\78",[279]="\196",[283]="\70",[414]="\98",[53]="\55",[422]="\109",[233]="\79",[349]="\89",[369]="\52",[14]="\105",[238]="\56",[319]="\162",[323]="\83",[327]="\63",[458]="\65",[335]="\231",[339]="\225",[337]="\114",[347]="\193",[493]="\139",[23]="\209",[359]="\250",[490]="\68",[42]="\54",[63]="\91",[286]="\97",[254]="\50",[510]="\108",[109]="\73",[67]="\103",[255]="\122",[69]="\170",[70]="\110",[407]="\176",[411]="\119",[110]="\120",[83]="\146",[149]="\163",[151]="\224",[85]="\51",[155]="\177",[79]="\251",[27]="\118",[447]="\159",[451]="\228",[455]="\175",[383]="\174",[463]="\243",[467]="\157",[173]="\210",[475]="\167",[177]="\84",[90]="\45",[487]="\206",[93]="\226",[495]="\245",[207]="\64",[127]="\147",[191]="\155",[511]="\153",[195]="\208",[197]="\85",[199]="\178",[181]="\82",[102]="\116",[103]="\71",[285]="\144",[105]="\102",[211]="\199",[213]="\123",[301]="\66",[305]="\46",[219]="\137",[81]="\67",[91]="\88",[157]="\130",[325]="\95",[29]="\58",[231]="\201",[117]="\99",[341]="\222",[237]="\77",[239]="\211",[71]="\223"},[10]={[710]="\149",[245]="\60",[742]="\172",[774]="\81",[134]="\151",[917]="\145",[274]="\216",[405]="\242",[146]="\194",[838]="\246",[298]="\248",[870]="\189",[1013]="\150",[894]="\190",[326]="\244",[330]="\166",[334]="\217",[465]="\179",[346]="\59",[354]="\180",[966]="\212",[974]="\143",[370]="\148",[998]="\154",[625]="\138",[382]="\161",[194]="\141",[198]="\126",[402]="\96",[206]="\185",[586]="\129",[721]="\187",[610]="\135",[618]="\181",[626]="\72",[226]="\62",[454]="\127",[658]="\113",[462]="\164",[234]="\214",[474]="\140",[242]="\106",[714]="\188",[730]="\87",[498]="\237",[746]="\125",[754]="\229",[786]="\128",[202]="\93",[18]="\255",[810]="\173",[846]="\131",[74]="\192",[842]="\142",[977]="\252",[858]="\235",[78]="\134",[874]="\234",[882]="\90",[646]="\92",[1006]="\160",[126]="\165",[914]="\221",[718]="\94",[738]="\238",[638]="\197",[482]="\230",[34]="\220",[962]="\133",[6]="\213",[706]="\219",[986]="\171",[994]="\233",[866]="\200",[1010]="\247",[98]="\169",[518]="\236",[494]="\207",[230]="\205",[542]="\191",[501]="\202",[530]="\203",[450]="\204",[209]="\158",[106]="\186",[590]="\136",[218]="\232",[733]="\124",[309]="\168",[221]="\152",[757]="\240",[113]="\215",[114]="\156",[362]="\239",[486]="\132",[358]="\249",[262]="\75",[30]="\218",[821]="\195",[546]="\253"}}
local function huffmanDecode(encoded)
local h1,h2,h3 = byte(encoded, 1, 3)
if (not h3) or (#encoded < 4) then
error("invalid input")
end
local original_length = bit.bor(bit.lshift(h3,16), bit.lshift(h2,8), h1)
local encoded_length = #encoded+1
local decoded = {}
local decoded_length = 0
local buffer = 0
local buffer_length = 0
local code
local code_len = 2
local temp
local pos = 4
while decoded_length < original_length do
if code_len <= buffer_length then
temp = invcodes[code_len]
code = bit.band(buffer, bit.lshift(1, code_len)-1)
if temp and temp[code] then --most of the time temp is nil
decoded_length = decoded_length + 1
decoded[decoded_length] = temp[code]
buffer = bit.rshift(buffer, code_len)
buffer_length = buffer_length - code_len
code_len = 2
else
code_len = code_len + 1
if code_len > 10 then
error("malformed code")
end
end
else
buffer = bit.bor(buffer, bit.lshift(byte(encoded, pos), buffer_length))
buffer_length = buffer_length + 8
pos = pos + 1
if pos > encoded_length then
error("malformed code")
end
end
end
return concat(decoded)
end
local function invEscapeSub(str)
local escseq,body = match(str,"^(.-)\n(.-)$")
if not escseq then error("invalid input") end
return gsub(body,escseq,"\26")
end
local dictionary
local subtables
local function deserializeChunk(chunk)
local ctype,val = byte(chunk),sub(chunk,3)
if ctype == 89 then return dictionary[ val ]
elseif ctype == 86 then
local a,b,c = match(val,"^(.-),(.-),(.+)$")
return Vector( tonumber(a), tonumber(b), tonumber(c) )
elseif ctype == 65 then
local a,b,c = match(val,"^(.-),(.-),(.+)$")
return Angle( tonumber(a), tonumber(b), tonumber(c) )
elseif ctype == 84 then
local t = {}
local tv = subtables[val]
if not tv then
tv = {}
subtables[ val ] = tv
end
tv[#tv+1] = t
return t
elseif ctype == 78 then return tonumber(val)
elseif ctype == 83 then return gsub(sub(val,2,-2),"»",";")
elseif ctype == 66 then return val == "t"
elseif ctype == 80 then return 1
end
error(format("AD1 deserialization failed: invalid chunk (%u:%s)",ctype,val))
end
local function deserializeAD1(dupestring)
dupestring = dupestring:Replace("\r\n", "\n")
local header, extraHeader, dupeBlock, dictBlock = dupestring:match("%[Info%]\n(.+)\n%[More Information%]\n(.+)\n%[Save%]\n(.+)\n%[Dict%]\n(.+)")
if not header then
error("unknown duplication format")
end
local info = {}
for k,v in header:gmatch("([^\n:]+):([^\n]+)") do
info[k] = v
end
local moreinfo = {}
for k,v in extraHeader:gmatch("([^\n:]+):([^\n]+)") do
moreinfo[k] = v
end
dictionary = {}
for k,v in dictBlock:gmatch("(.-):\"(.-)\"\n") do
dictionary[k] = v
end
local dupe = {}
for key,block in dupeBlock:gmatch("([^\n:]+):([^\n]+)") do
local tables = {}
subtables = {}
local head
for id,chunk in block:gmatch('(%w+){(.-)}') do
--check if this table is the trunk
if byte(id) == 72 then
id = sub(id,2)
head = id
end
tables[id] = {}
for kv in gmatch(chunk,'[^;]+') do
local k,v = match(kv,'(.-)=(.+)')
if k then
k = deserializeChunk( k )
v = deserializeChunk( v )
tables[id][k] = v
else
v = deserializeChunk( kv )
local tid = tables[id]
tid[#tid+1]=v
end
end
end
--Restore table references
for id,tbls in pairs( subtables ) do
for _,tbl in pairs( tbls ) do
if not tables[id] then error("attempt to reference a nonexistent table") end
for k,v in pairs(tables[id]) do
tbl[k] = v
end
end
end
dupe[key] = tables[ head ]
end
return dupe, info, moreinfo
end
--seperates the header and body and converts the header to a table
local function getInfo(str)
local last = str:find("\2")
if not last then
error("attempt to read AD2 file with malformed info block error 1")
end
local info = {}
local ss = str:sub(1,last-1)
for k,v in ss:gmatch("(.-)\1(.-)\1") do
info[k] = v
end
if info.check ~= "\r\n\t\n" then
if info.check == "\10\9\10" then
error("detected AD2 file corrupted in file transfer (newlines homogenized)(when using FTP, transfer AD2 files in image/binary mode, not ASCII/text mode)")
else
error("attempt to read AD2 file with malformed info block error 2")
end
end
return info, str:sub(last+2)
end
--decoders for individual versions go here
local versions = {}
versions[2] = function(encodedDupe)
encodedDupe = encodedDupe:Replace("\r\r\n\t\r\n", "\t\t\t\t")
encodedDupe = encodedDupe:Replace("\r\n\t\n", "\t\t\t\t")
encodedDupe = encodedDupe:Replace("\r\n", "\n")
encodedDupe = encodedDupe:Replace("\t\t\t\t", "\r\n\t\n")
local info, dupestring = getInfo(encodedDupe:sub(7))
return deserialize_v2(
lzwDecode(
huffmanDecode(
invEscapeSub(dupestring)
)
)
), info
end
versions[1] = function(encodedDupe)
encodedDupe = encodedDupe:Replace("\r\r\n\t\r\n", "\t\t\t\t")
encodedDupe = encodedDupe:Replace("\r\n\t\n", "\t\t\t\t")
encodedDupe = encodedDupe:Replace("\r\n", "\n")
encodedDupe = encodedDupe:Replace("\t\t\t\t", "\r\n\t\n")
local info, dupestring = getInfo(encodedDupe:sub(7))
return deserialize_v1(
lzwDecode(
huffmanDecode(
invEscapeSub(dupestring)
)
)
), info
end
versions[0] = deserializeAD1
AdvDupe2.LegacyDecoders = versions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
--Save a file to the client
local function SaveFile(ply, cmd, args)
if(not ply.AdvDupe2 or not ply.AdvDupe2.Entities or next(ply.AdvDupe2.Entities)==nil)then AdvDupe2.Notify(ply,"Duplicator is empty, nothing to save.", NOTIFY_ERROR) return end
if(not game.SinglePlayer() and CurTime()-(ply.AdvDupe2.FileMod or 0) < 0)then
AdvDupe2.Notify(ply,"Cannot save at the moment. Please Wait...", NOTIFY_ERROR)
return
end
if(ply.AdvDupe2.Pasting || ply.AdvDupe2.Downloading)then
AdvDupe2.Notify(ply,"Advanced Duplicator 2 is busy.",NOTIFY_ERROR)
return false
end
ply.AdvDupe2.FileMod = CurTime()+tonumber(GetConVarString("AdvDupe2_FileModificationDelay")+2)
local name = string.Explode("/", args[1])
ply.AdvDupe2.Name = name[#name]
net.Start("AdvDupe2_SetDupeInfo")
net.WriteString(ply.AdvDupe2.Name)
net.WriteString(ply:Nick())
net.WriteString(os.date("%d %B %Y"))
net.WriteString(os.date("%I:%M %p"))
net.WriteString("")
net.WriteString(args[2] or "")
net.WriteString(table.Count(ply.AdvDupe2.Entities))
net.WriteString(#ply.AdvDupe2.Constraints)
net.Send(ply)
local Tab = {Entities = ply.AdvDupe2.Entities, Constraints = ply.AdvDupe2.Constraints, HeadEnt = ply.AdvDupe2.HeadEnt, Description=args[2]}
AdvDupe2.Encode( Tab, AdvDupe2.GenerateDupeStamp(ply), function(data)
AdvDupe2.SendToClient(ply, data, false)
end)
end
concommand.Add("AdvDupe2_SaveFile", SaveFile)
function AdvDupe2.SendToClient(ply, data, autosave)
if(not IsValid(ply))then return end
if #data > AdvDupe2.MaxDupeSize then
AdvDupe2.Notify(ply,"Copied duplicator filesize is too big!",NOTIFY_ERROR)
return
end
ply.AdvDupe2.Downloading = true
AdvDupe2.InitProgressBar(ply,"Saving:")
net.Start("AdvDupe2_ReceiveFile")
net.WriteBool(autosave)
net.WriteStream(data, function()
ply.AdvDupe2.Downloading = false
end)
net.Send(ply)
end
function AdvDupe2.LoadDupe(ply,success,dupe,info,moreinfo)
if(not IsValid(ply))then return end
if not success then
AdvDupe2.Notify(ply,"Could not open "..dupe,NOTIFY_ERROR)
return
end
if(not game.SinglePlayer())then
if(tonumber(GetConVarString("AdvDupe2_MaxConstraints"))~=0 and #dupe["Constraints"]>tonumber(GetConVarString("AdvDupe2_MaxConstraints")))then
AdvDupe2.Notify(ply,"Amount of constraints is greater than "..GetConVarString("AdvDupe2_MaxConstraints"),NOTIFY_ERROR)
return false
end
end
ply.AdvDupe2.Entities = {}
ply.AdvDupe2.Constraints = {}
ply.AdvDupe2.HeadEnt={}
ply.AdvDupe2.Revision = info.revision
if(info.ad1)then
ply.AdvDupe2.HeadEnt.Index = tonumber(moreinfo.Head)
local spx,spy,spz = moreinfo.StartPos:match("^(.-),(.-),(.+)$")
ply.AdvDupe2.HeadEnt.Pos = Vector(tonumber(spx) or 0, tonumber(spy) or 0, tonumber(spz) or 0)
local z = (tonumber(moreinfo.HoldPos:match("^.-,.-,(.+)$")) or 0)*-1
ply.AdvDupe2.HeadEnt.Z = z
ply.AdvDupe2.HeadEnt.Pos.Z = ply.AdvDupe2.HeadEnt.Pos.Z + z
local Pos
local Ang
for k,v in pairs(dupe["Entities"])do
Pos = nil
Ang = nil
if(v.SavedParentIdx)then
if(not v.BuildDupeInfo)then v.BuildDupeInfo = {} end
v.BuildDupeInfo.DupeParentID = v.SavedParentIdx
Pos = v.LocalPos*1
Ang = v.LocalAngle*1
end
for i,p in pairs(v.PhysicsObjects)do
p.Pos = Pos or (p.LocalPos*1)
p.Pos.Z = p.Pos.Z - z
p.Angle = Ang or (p.LocalAngle*1)
p.LocalPos = nil
p.LocalAngle = nil
p.Frozen = not p.Frozen -- adv dupe 2 does this wrong way
end
v.LocalPos = nil
v.LocalAngle = nil
end
ply.AdvDupe2.Entities = dupe["Entities"]
ply.AdvDupe2.Constraints = dupe["Constraints"]
else
ply.AdvDupe2.Entities = dupe["Entities"]
ply.AdvDupe2.Constraints = dupe["Constraints"]
ply.AdvDupe2.HeadEnt = dupe["HeadEnt"]
end
AdvDupe2.ResetOffsets(ply, true)
end
local function AdvDupe2_ReceiveFile(len, ply)
if not IsValid(ply) then return end
if not ply.AdvDupe2 then ply.AdvDupe2 = {} end
ply.AdvDupe2.Name = string.match(net.ReadString(), "([%w_ ]+)") or "Advanced Duplication"
local stream = net.ReadStream(ply, function(data)
if data then
AdvDupe2.LoadDupe(ply, AdvDupe2.Decode(data))
else
AdvDupe2.Notify(ply, "Duplicator Upload Failed!", NOTIFY_ERROR, 5)
end
ply.AdvDupe2.Uploading = false
end)
if ply.AdvDupe2.Uploading then
if stream then
stream:Remove()
end
AdvDupe2.Notify(ply, "Duplicator is Busy!", NOTIFY_ERROR, 5)
elseif stream then
ply.AdvDupe2.Uploading = true
AdvDupe2.InitProgressBar(ply, "Uploading: ")
end
end
net.Receive("AdvDupe2_ReceiveFile", AdvDupe2_ReceiveFile)

View File

@@ -0,0 +1,70 @@
util.AddNetworkString("AdvDupe2_SendGhosts")
util.AddNetworkString("AdvDupe2_AddGhost")
function AdvDupe2.SendGhost(ply, AddOne)
net.Start("AdvDupe2_AddGhost")
net.WriteString(AddOne.Model)
net.WriteInt(#AddOne.PhysicsObjects, 8)
for i=0, #AddOne.PhysicsObjects do
net.WriteAngle(AddOne.PhysicsObjects[i].Angle)
net.WriteVector(AddOne.PhysicsObjects[i].Pos)
end
net.Send(ply)
end
function AdvDupe2.SendGhosts(ply)
if(not ply.AdvDupe2.Entities)then return end
local cache = {}
local temp = {}
local mdls = {}
local cnt = 1
local add = true
local head
for k,v in pairs(ply.AdvDupe2.Entities)do
temp[cnt] = v
for i=1,#cache do
if(cache[i]==v.Model)then
mdls[cnt] = i
add=false
break
end
end
if(add)then
mdls[cnt] = table.insert(cache, v.Model)
else
add = true
end
if(k==ply.AdvDupe2.HeadEnt.Index)then
head = cnt
end
cnt = cnt+1
end
if(!head)then
AdvDupe2.Notify(ply, "Invalid head entity for ghosts.", NOTIFY_ERROR);
return
end
net.Start("AdvDupe2_SendGhosts")
net.WriteInt(head, 16)
net.WriteFloat(ply.AdvDupe2.HeadEnt.Z)
net.WriteVector(ply.AdvDupe2.HeadEnt.Pos)
net.WriteInt(#cache, 16)
for i=1,#cache do
net.WriteString(cache[i])
end
net.WriteInt(cnt-1, 16)
for i=1, #temp do
net.WriteInt(mdls[i], 16)
net.WriteInt(#temp[i].PhysicsObjects, 8)
for k=0, #temp[i].PhysicsObjects do
net.WriteAngle(temp[i].PhysicsObjects[k].Angle)
net.WriteVector(temp[i].PhysicsObjects[k].Pos)
end
end
net.Send(ply)
end

View File

@@ -0,0 +1,104 @@
--[[
Title: Miscellaneous
Desc: Contains miscellaneous (serverside) things AD2 needs to function that don't fit anywhere else.
Author: TB
Version: 1.0
]]
--[[
Name: SavePositions
Desc: Save the position of the entities to prevent sagging on dupe.
Params: <entity> Constraint
Returns: nil
]]
local function SavePositions( Constraint )
if IsValid(Constraint) then
if Constraint.BuildDupeInfo then return end
local BuildDupeInfo = {}
Constraint.BuildDupeInfo = BuildDupeInfo
local Ent1, Ent2
if IsValid(Constraint.Ent) then
if Constraint.Ent:GetPhysicsObjectCount()>1 then
BuildDupeInfo.Ent1Ang = Constraint.Ent:GetAngles()
else
BuildDupeInfo.Ent1Ang = Constraint.Ent:GetPhysicsObject():GetAngles()
end
end
if IsValid(Constraint.Ent1) then
if Constraint.Ent1:GetPhysicsObjectCount()>1 then
local Bone = Constraint.Ent1:GetPhysicsObjectNum(Constraint.Bone1)
BuildDupeInfo.Ent1Ang = Constraint.Ent1:GetAngles()
BuildDupeInfo.Ent1Pos = Constraint.Ent1:GetPos()
BuildDupeInfo.Bone1 = Constraint.Bone1
BuildDupeInfo.Bone1Pos = Bone:GetPos() - Constraint.Ent1:GetPos()
BuildDupeInfo.Bone1Angle = Bone:GetAngles()
else
local Bone = Constraint.Ent1:GetPhysicsObject()
BuildDupeInfo.Ent1Ang = Bone:GetAngles()
BuildDupeInfo.Ent1Pos = Bone:GetPos()
end
if IsValid(Constraint.Ent2) then
if Constraint.Ent2:GetPhysicsObjectCount()>1 then
local Bone = Constraint.Ent2:GetPhysicsObjectNum(Constraint.Bone2)
BuildDupeInfo.EntityPos = BuildDupeInfo.Ent1Pos - Constraint.Ent2:GetPos()
BuildDupeInfo.Ent2Ang = Constraint.Ent2:GetAngles()
BuildDupeInfo.Bone2 = Constraint.Bone2
BuildDupeInfo.Bone2Pos = Bone:GetPos() - Constraint.Ent2:GetPos()
BuildDupeInfo.Bone2Angle = Bone:GetAngles()
else
local Bone = Constraint.Ent2:GetPhysicsObject()
BuildDupeInfo.EntityPos = BuildDupeInfo.Ent1Pos - Bone:GetPos()
BuildDupeInfo.Ent2Ang = Bone:GetAngles()
end
elseif IsValid(Constraint.Ent4) then
if Constraint.Ent4:GetPhysicsObjectCount()>1 then
local Bone = Constraint.Ent4:GetPhysicsObjectNum(Constraint.Bone4)
BuildDupeInfo.Bone2 = Constraint.Bone4
BuildDupeInfo.EntityPos = BuildDupeInfo.Ent1Pos - Constraint.Ent4:GetPos()
BuildDupeInfo.Ent2Ang = Constraint.Ent4:GetAngles()
BuildDupeInfo.Bone2Pos = Bone:GetPos() - Constraint.Ent4:GetPos()
BuildDupeInfo.Bone2Angle = Bone:GetAngles()
else
local Bone = Constraint.Ent4:GetPhysicsObject()
BuildDupeInfo.EntityPos = BuildDupeInfo.Ent1Pos - Bone:GetPos()
BuildDupeInfo.Ent2Ang = Bone:GetAngles()
end
end
end
end
end
local function monitorConstraint(name)
local oldFunc = constraint[name]
constraint[name] = function(...)
local Constraint, b, c = oldFunc(...)
if Constraint and Constraint:IsValid() then
SavePositions(Constraint)
end
return Constraint, b, c
end
end
monitorConstraint("AdvBallsocket")
monitorConstraint("Axis")
monitorConstraint("Ballsocket")
monitorConstraint("Elastic")
monitorConstraint("Hydraulic")
monitorConstraint("Keepupright")
monitorConstraint("Motor")
monitorConstraint("Muscle")
monitorConstraint("Pulley")
monitorConstraint("Rope")
monitorConstraint("Slider")
monitorConstraint("Weld")
monitorConstraint("Winch")

View File

@@ -0,0 +1,145 @@
include("shared.lua")
surface.CreateFont( "InfoRUS2", { font = "Enhanced Dot Digital-7", extended = true, size = 90, weight = 800, antialias = true })
surface.CreateFont( "InfoRUS3", { font = "Enhanced Dot Digital-7", extended = true, size = 50, weight = 800, antialias = true })
local font = "InfoRUS2"
local sizetable = {
[3] = {350, 0.5},
[4] = {470, -11.5},
[5] = {590, -11.5},
[6] = {710, 0.5},
[7] = {830, 0.5},
[8] = {950, 0.5},
}
function ENT:Initialize()
self.OldWide = self:GetWide()
self.frame = vgui.Create( "DPanel" )
self.frame:SetSize( sizetable[self:GetWide()][1], 120 )
self.frame.Text = self:GetText()
self.frame.Type = self:GetType()
self.frame.col = self:GetTColor()
self.frame.damage = 0
self.frame.appr = nil
self.frame.FX = self:GetFX()
self.frame.On = self:GetOn()
self.frame.alfa = 0
self.frame.speed = self:GetSpeed()
self.frame:SetPaintedManually( true )
self.frame.Paint = function(self,w,h)
if self.On <= 0 then
if self.alfa < 1 then return end
self.alfa = Lerp(FrameTime() * 5,self.alfa,0)
else
if self.FX > 0 then
self.alfa = math.random(100,220)
else
self.alfa = 255
end
end
surface.DisableClipping( false )
surface.SetFont(font)
local ww,hh = surface.GetTextSize(self.Text)
local multiplier = self.speed * 100
self.static = false
if self.damage < CurTime() and self.On then
if self.Type == 1 then
local xs = (math.fmod(SysTime() * multiplier,w+ww)) - ww
draw.DrawText(self.Text,font,xs,10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, self.alfa),0)
elseif self.Type == 2 then
if !self.appr or self.appr > ww then
self.appr = -w
else
self.appr = math.Approach(self.appr, ww+w, FrameTime() * multiplier)
end
draw.DrawText(self.Text,font,self.appr * -1,10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, self.alfa),0)
else
if !self.appr then
self.appr = 0
end
if w > ww then
if self.Type == 3 then
if self.appr < w-ww and !self.refl then
self.appr = math.Approach(self.appr, ww+w, FrameTime() * multiplier)
else
if self.appr <= 0 then
self.refl = nil
else
self.refl = true
self.appr = math.Approach(self.appr, 0, FrameTime() * multiplier)
end
end
else
self.static = true
end
else
if self.appr > w-ww-50 and !self.refl then
self.appr = math.Approach(self.appr, w-ww-50, FrameTime() * multiplier)
else
if self.appr >= 50 then
self.refl = nil
else
self.refl = true
self.appr = math.Approach(self.appr, 50, FrameTime() * multiplier)
end
end
end
if self.static then
draw.DrawText(self.Text,font,w/2,10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, self.alfa),1)
else
draw.DrawText(self.Text,font,self.appr,10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, self.alfa),0)
end
end
else
draw.DrawText(self.Text,font,math.random(0,w-ww),10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, math.random(0,255)),0)
end
surface.DisableClipping( true )
end
end
function ENT:Draw()
self:DrawModel()
if self.frame then
self.frame.Text = self:GetText()
self.frame.Type = self:GetType()
self.frame.col = self:GetTColor()
self.frame.FX = self:GetFX()
self.frame.On = self:GetOn()
self.frame.damage = self:GetNWInt("LastDamaged")
self.frame.speed = self:GetSpeed()
end
local Pos = self:GetPos()
local Ang = self:GetAngles()
local hight = 12
if self.OldWide != self:GetWide() then
self.frame:SetSize( sizetable[self:GetWide()][1], 120 )
self.OldWide = self:GetWide()
end
if self:GetWide() == 3 then
hight = 6
end
cam.Start3D2D(Pos + Ang:Up() * 1.1 - Ang:Right() * hight + Ang:Forward() * sizetable[self:GetWide()][2], Ang, 0.1)
self.frame:PaintManual()
cam.End3D2D()
end

View File

@@ -0,0 +1,54 @@
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
util.AddNetworkString("LEDDamaged")
function ENT:Initialize()
self:SetText("Made by Mac with <3")
self:SetTColor(Vector(2.55,2,0))
self:SetType(1)
self:SetSpeed(1.5)
self:SetWide(6)
self:SetFX(1)
self:SetOn(1)
self:SetModel("models/squad/sf_plates/sf_plate1x"..self:GetWide()..".mdl")
self:PhysicsInit(SOLID_VPHYSICS)
self:SetMaterial("phoenix_storms/mat/mat_phx_carbonfiber")
self:SetColor(Color(0,0,0))
self:SetMoveType(MOVETYPE_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS)
self:SetUseType(SIMPLE_USE)
self:SetNWInt("LastDamaged", 0)
local phys = self:GetPhysicsObject()
self.nodupe = true
self.ShareGravgun = true
phys:Wake()
end
function ENT:Think()
if self:GetModel() != "models/squad/sf_plates/sf_plate1x"..self:GetWide()..".mdl" then
self:SetModel("models/squad/sf_plates/sf_plate1x"..self:GetWide()..".mdl")
end
self:NextThink( CurTime() + 1 )
return true
end
function ENT:OnTakeDamage(data)
if data:GetDamagePosition() then
self:EmitSound("ambient/energy/spark".. math.random(1,6) ..".wav")
local effectdata = EffectData()
effectdata:SetOrigin( data:GetDamagePosition() )
util.Effect( "StunstickImpact", effectdata )
self:SetNWInt("LastDamaged", math.Round(CurTime()+2))
end
end

View File

@@ -0,0 +1,16 @@
ENT.Type = "anim"
ENT.Base = "base_gmodentity"
ENT.PrintName = "Spawned Sign"
ENT.Author = "Mac"
ENT.Spawnable = false
ENT.AdminSpawnable = true
function ENT:SetupDataTables()
self:NetworkVar("String", 0, "Text")
self:NetworkVar("Vector", 0, "TColor")
self:NetworkVar("Int", 0, "Type")
self:NetworkVar("Int", 1, "Speed")
self:NetworkVar("Int", 2, "Wide")
self:NetworkVar("Int", 3, "On")
self:NetworkVar("Int", 4, "FX")
end

View File

@@ -0,0 +1,142 @@
include("shared.lua")
local font = "InfoRUS2"
local sizetable = {
[3] = {350, 0.5},
[4] = {470, -11.5},
[5] = {590, -11.5},
[6] = {710, 0.5},
[7] = {830, 0.5},
[8] = {950, 0.5},
}
function ENT:Initialize()
self.OldWide = self:GetWide()
self.frame = vgui.Create( "DPanel" )
self.frame:SetSize( sizetable[self:GetWide()][1], 120 )
self.frame.Text = self:GetText()
self.frame.Type = self:GetType()
self.frame.col = self:GetTColor()
self.frame.damage = 0
self.frame.appr = nil
self.frame.FX = self:GetFX()
self.frame.On = self:GetOn()
self.frame.alfa = 0
self.frame.speed = self:GetSpeed()
self.frame:SetPaintedManually( true )
self.frame.Paint = function(self,w,h)
if self.On <= 0 then
if self.alfa < 1 then return end
self.alfa = Lerp(FrameTime() * 5,self.alfa,0)
else
if self.FX > 0 then
self.alfa = math.random(100,220)
else
self.alfa = 255
end
end
surface.DisableClipping( false )
surface.SetFont(font)
local ww,hh = surface.GetTextSize(self.Text)
local multiplier = self.speed * 100
self.static = false
if self.damage < CurTime() and self.On then
if self.Type == 1 then
local xs = (math.fmod(SysTime() * multiplier,w+ww)) - ww
draw.DrawText(self.Text,font,xs,10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, self.alfa),0)
elseif self.Type == 2 then
if !self.appr or self.appr > ww then
self.appr = -w
else
self.appr = math.Approach(self.appr, ww+w, FrameTime() * multiplier)
end
draw.DrawText(self.Text,font,self.appr * -1,10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, self.alfa),0)
else
if !self.appr then
self.appr = 0
end
if w > ww then
if self.Type == 3 then
if self.appr < w-ww and !self.refl then
self.appr = math.Approach(self.appr, ww+w, FrameTime() * multiplier)
else
if self.appr <= 0 then
self.refl = nil
else
self.refl = true
self.appr = math.Approach(self.appr, 0, FrameTime() * multiplier)
end
end
else
self.static = true
end
else
if self.appr > w-ww-50 and !self.refl then
self.appr = math.Approach(self.appr, w-ww-50, FrameTime() * multiplier)
else
if self.appr >= 50 then
self.refl = nil
else
self.refl = true
self.appr = math.Approach(self.appr, 50, FrameTime() * multiplier)
end
end
end
if self.static then
draw.DrawText(self.Text,font,w/2,10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, self.alfa),1)
else
draw.DrawText(self.Text,font,self.appr,10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, self.alfa),0)
end
end
else
draw.DrawText(self.Text,font,math.random(0,w-ww),10,Color(self.col.x * 100, self.col.y * 100, self.col.z * 100, math.random(0,255)),0)
end
surface.DisableClipping( true )
end
end
function ENT:Draw()
self:DrawModel()
if self.frame then
self.frame.Text = self:GetText()
self.frame.Type = self:GetType()
self.frame.col = self:GetTColor()
self.frame.FX = self:GetFX()
self.frame.On = self:GetOn()
self.frame.damage = self:GetNWInt("LastDamaged")
self.frame.speed = self:GetSpeed()
end
local Pos = self:GetPos()
local Ang = self:GetAngles()
local hight = 12
if self.OldWide != self:GetWide() then
self.frame:SetSize( sizetable[self:GetWide()][1], 120 )
self.OldWide = self:GetWide()
end
if self:GetWide() == 3 then
hight = 6
end
cam.Start3D2D(Pos + Ang:Up() * 1.1 - Ang:Right() * hight + Ang:Forward() * sizetable[self:GetWide()][2], Ang, 0.1)
self.frame:PaintManual()
cam.End3D2D()
end

View File

@@ -0,0 +1,70 @@
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
util.AddNetworkString("LEDDamaged")
function ENT:Initialize()
self:SetText("Made by Mac with Wire and <3")
self:SetTColor(Vector(2.55,2,0))
self:SetType(1)
self:SetSpeed(1.5)
self:SetWide(6)
self:SetFX(1)
self:SetOn(1)
self:SetModel("models/squad/sf_plates/sf_plate1x"..self:GetWide()..".mdl")
self:PhysicsInit(SOLID_VPHYSICS)
self:SetMaterial("phoenix_storms/mat/mat_phx_carbonfiber")
self:SetColor(Color(0,0,0))
self:SetMoveType(MOVETYPE_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS)
self:SetUseType(SIMPLE_USE)
self:SetNWInt("LastDamaged", 0)
local phys = self:GetPhysicsObject()
self.nodupe = true
self.ShareGravgun = true
phys:Wake()
self.Inputs = WireLib.CreateSpecialInputs(self, { "Text", "Type", "Speed", "Color", "Flicker", "On" }, { "STRING", "NORMAL", "NORMAL", "VECTOR", "NORMAL", "NORMAL" })
end
function ENT:TriggerInput(iname, value)
if iname == "Text" then
self:SetText(value)
elseif iname == "Type" then
self:SetType(math.Clamp(math.Round(value), 1, 4))
elseif iname == "Speed" then
self:SetSpeed(math.Clamp(value, 1, 10))
elseif iname == "Color" then
self:SetTColor(Vector(value.x/100, value.y/100, value.z/100))
elseif iname == "On" then
self:SetOn(value)
elseif iname == "Flicker" then
self:SetFX(math.Clamp(value, 0, 1))
end
end
function ENT:Think()
if self:GetModel() != "models/squad/sf_plates/sf_plate1x"..self:GetWide()..".mdl" then
self:SetModel("models/squad/sf_plates/sf_plate1x"..self:GetWide()..".mdl")
end
end
function ENT:OnTakeDamage(data)
if data:GetDamagePosition() then
self:EmitSound("ambient/energy/spark".. math.random(1,6) ..".wav")
local effectdata = EffectData()
effectdata:SetOrigin( data:GetDamagePosition() )
util.Effect( "StunstickImpact", effectdata )
self:SetNWInt("LastDamaged", math.Round(CurTime()+2))
end
end

View File

@@ -0,0 +1,17 @@
ENT.Type = "anim"
ENT.Base = "base_wire_entity"
ENT.PrintName = "Spawned Sign Wire"
ENT.WireDebugName = "LED Screen"
ENT.Author = "Mac"
ENT.Spawnable = false
ENT.AdminSpawnable = true
function ENT:SetupDataTables()
self:NetworkVar("String", 0, "Text")
self:NetworkVar("Vector", 0, "TColor")
self:NetworkVar("Int", 0, "Type")
self:NetworkVar("Int", 1, "Speed")
self:NetworkVar("Int", 2, "Wide")
self:NetworkVar("Int", 3, "On")
self:NetworkVar("Int", 4, "FX")
end

View File

@@ -0,0 +1,6 @@
include( "shared.lua" )
function ENT:Draw()
self.BaseClass.Draw(self)
self.Entity:DrawModel()
end

View File

@@ -0,0 +1,291 @@
--[[
Title: Adv. Dupe 2 Contraption Spawner
Desc: A mobile duplicator
Author: TB
Version: 1.0
]]
AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
if(WireLib)then
include( "entities/base_wire_entity.lua" )
end
include( "shared.lua" )
function ENT:Initialize()
self.Entity:SetMoveType( MOVETYPE_NONE )
self.Entity:PhysicsInit( SOLID_VPHYSICS )
self.Entity:SetCollisionGroup( COLLISION_GROUP_WORLD )
self.Entity:DrawShadow( false )
local phys = self.Entity:GetPhysicsObject()
if phys:IsValid() then
phys:Wake()
end
self.UndoList = {}
self.Ghosts = {}
self.SpawnLastValue = 0
self.UndoLastValue = 0
self.LastSpawnTime = 0
self.DupeName = ""
self.CurrentPropCount = 0
if WireLib then
self.Inputs = Wire_CreateInputs(self.Entity, {"Spawn", "Undo"})
self.Outputs = WireLib.CreateSpecialOutputs(self.Entity, {"Out"}, { "NORMAL" })
end
end
/*-----------------------------------------------------------------------*
* Sets options for this spawner
*-----------------------------------------------------------------------*/
function ENT:SetOptions(ply, delay, undo_delay, key, undo_key, disgrav, disdrag, addvel, hideprops )
self.delay = delay
self.undo_delay = undo_delay
--Key bindings
self.key = key
self.undo_key = undo_key
numpad.Remove( self.CreateKey )
numpad.Remove( self.UndoKey )
self.CreateKey = numpad.OnDown( ply, self.key , "ContrSpawnerCreate", self.Entity, true )
self.UndoKey = numpad.OnDown( ply, self.undo_key, "ContrSpawnerUndo" , self.Entity, true )
-- Other parameters
self.DisableGravity = disgrav
self.DisableDrag = disdrag
self.AddVelocity = addvel
self.HideProps = hideprops
-- Store the player's current dupe name
self.DupeName = tostring(ply.AdvDupe2.Name)
self:ShowOutput()
end
function ENT:UpdateOptions( options )
self:SetOptions( options["delay"], options["undo_delay"], options["key"], options["undo_key"])
end
function ENT:AddGhosts()
if self.HideProps then return end
local moveable = self:GetPhysicsObject():IsMoveable()
self:GetPhysicsObject():EnableMotion(false)
local EntTable, GhostEntity, Phys
local Offset = self.DupeAngle - self.EntAngle
for EntIndex,v in pairs(self.EntityTable)do
if(EntIndex!=self.HeadEnt)then
if(self.EntityTable[EntIndex].Class=="gmod_contr_spawner")then self.EntityTable[EntIndex] = nil continue end
EntTable = table.Copy(self.EntityTable[EntIndex])
if(EntTable.BuildDupeInfo && EntTable.BuildDupeInfo.PhysicsObjects)then
Phys = EntTable.BuildDupeInfo.PhysicsObjects[0]
else
if(!v.BuildDupeInfo)then v.BuildDupeInfo = {} end
v.BuildDupeInfo.PhysicsObjects = table.Copy(v.PhysicsObjects)
Phys = EntTable.PhysicsObjects[0]
end
GhostEntity = nil
if(EntTable.Model==nil || !util.IsValidModel(EntTable.Model)) then EntTable.Model="models/error.mdl" end
if ( EntTable.Model:sub( 1, 1 ) == "*" ) then
GhostEntity = ents.Create( "func_physbox" )
else
GhostEntity = ents.Create( "gmod_ghost" )
end
// If there are too many entities we might not spawn..
if ( !GhostEntity || GhostEntity == NULL ) then return end
duplicator.DoGeneric( GhostEntity, EntTable )
GhostEntity:Spawn()
GhostEntity:DrawShadow( false )
GhostEntity:SetMoveType( MOVETYPE_NONE )
GhostEntity:SetSolid( SOLID_VPHYSICS );
GhostEntity:SetNotSolid( true )
GhostEntity:SetRenderMode( RENDERMODE_TRANSALPHA )
GhostEntity:SetColor( Color(255, 255, 255, 150) )
GhostEntity:SetAngles(Phys.Angle)
GhostEntity:SetPos(self:GetPos() + Phys.Pos - self.Offset)
self:SetAngles(self.EntAngle)
GhostEntity:SetParent( self )
self:SetAngles(self.DupeAngle)
self.Ghosts[EntIndex] = GhostEntity
end
end
self:SetAngles(self.DupeAngle)
self:GetPhysicsObject():EnableMotion(moveable)
end
function ENT:GetCreationDelay() return self.delay end
function ENT:GetDeletionDelay() return self.undo_delay end
function ENT:OnTakeDamage( dmginfo ) self.Entity:TakePhysicsDamage( dmginfo ) end
function ENT:SetDupeInfo( HeadEnt, EntityTable, ConstraintTable )
self.HeadEnt = HeadEnt
self.EntityTable = EntityTable
self.ConstraintTable = ConstraintTable
if(!self.DupeAngle)then self.DupeAngle = self:GetAngles() end
if(!self.EntAngle)then self.EntAngle = EntityTable[HeadEnt].PhysicsObjects[0].Angle end
if(!self.Offset)then self.Offset = self.EntityTable[HeadEnt].PhysicsObjects[0].Pos end
local headpos, headang = EntityTable[HeadEnt].PhysicsObjects[0].Pos, EntityTable[HeadEnt].PhysicsObjects[0].Angle
for k, v in pairs(EntityTable) do
for o, p in pairs(v.PhysicsObjects) do
p.LPos, p.LAngle = WorldToLocal(p.Pos, p.Angle, headpos, headang)
end
end
end
function ENT:DoSpawn( ply )
-- Explicitly allow spawning if no player is provided, but an invalid player gets denied. This can happen when a player leaves the server.
if not (ply and ply:IsValid()) then return end
for k, v in pairs(self.EntityTable) do
for o, p in pairs(v.PhysicsObjects) do
p.Pos, p.Angle = self:LocalToWorld(p.LPos), self:LocalToWorldAngles(p.LAngle)
end
end
/*local AngleOffset = self.EntAngle
AngleOffset = self:GetAngles() - AngleOffset
local AngleOffset2 = Angle(0,0,0)
//AngleOffset2.y = AngleOffset.y
AngleOffset2:RotateAroundAxis(self:GetUp(), AngleOffset.y)
AngleOffset2:RotateAroundAxis(self:GetRight(),AngleOffset.p)
AngleOffset2:RotateAroundAxis(self:GetForward(),AngleOffset.r)*/
local Ents, Constrs = AdvDupe2.duplicator.Paste(ply, self.EntityTable, self.ConstraintTable, nil, nil, Vector(0,0,0), true)
local i = #self.UndoList+1
self.UndoList[i] = Ents
local undotxt = "AdvDupe2: Contraption ("..tostring(self.DupeName)..")"
undo.Create(undotxt)
local phys
for k,ent in pairs(Ents)do
phys = ent:GetPhysicsObject()
if IsValid(phys) then
phys:Wake()
if(self.DisableGravity==1)then phys:EnableGravity(false) end
if(self.DisableDrag==1)then phys:EnableDrag(false) end
phys:EnableMotion(true)
if(ent.SetForce)then ent.SetForce(ent, ent.force, ent.mul) end
if(self.AddVelocity==1)then
phys:SetVelocity( self:GetVelocity() )
phys:AddAngleVelocity( self:GetPhysicsObject():GetAngleVelocity() )
end
end
undo.AddEntity(ent)
end
undo.SetPlayer(ply)
undo.Finish()
if(self.undo_delay>0)then
timer.Simple(self.undo_delay, function()
if(self.UndoList && self.UndoList[i])then
for k,ent in pairs(self.UndoList[i]) do
if(IsValid(ent)) then
ent:Remove()
end
end
end
end)
end
end
function ENT:DoUndo( ply )
if(!self.UndoList || #self.UndoList == 0)then return end
local entities = self.UndoList[ #self.UndoList ]
self.UndoList[ #self.UndoList ] = nil
for _,ent in pairs(entities) do
if (IsValid(ent)) then
ent:Remove()
end
end
end
function ENT:TriggerInput(iname, value)
local ply = self:GetPlayer()
if(iname == "Spawn")then
if ((value > 0) == self.SpawnLastValue) then return end
self.SpawnLastValue = (value > 0)
if(self.SpawnLastValue)then
local delay = self:GetCreationDelay()
if (delay == 0) then self:DoSpawn( ply ) return end
if(CurTime() < self.LastSpawnTime)then return end
self:DoSpawn( ply )
self.LastSpawnTime=CurTime()+delay
end
elseif (iname == "Undo") then
// Same here
if((value > 0) == self.UndoLastValue)then return end
self.UndoLastValue = (value > 0)
if(self.UndoLastValue)then self:DoUndo(ply) end
end
end
local flags = {"Enabled", "Disabled"}
function ENT:ShowOutput()
local text = "\nGravity: "..((self.DisableGravity == 1) and flags[1] or flags[2])
text = text.."\nDrag: " ..((self.DisableDrag == 1) and flags[1] or flags[2])
text = text.."\nVelocity: "..((self.AddVelocity == 1) and flags[1] or flags[2])
self.Entity:SetOverlayText(
"Spawn Name: " .. tostring(self.DupeName) ..
"\nSpawn Delay: " .. tostring(self:GetCreationDelay()) ..
"\nUndo Delay: ".. tostring(self:GetDeletionDelay()) ..
text
)
end
/*-----------------------------------------------------------------------*
* Handler for spawn keypad input
*-----------------------------------------------------------------------*/
function SpawnContrSpawner( ply, ent )
if (!ent || !ent:IsValid()) then return end
local delay = ent:GetTable():GetCreationDelay()
if(delay == 0) then
ent:DoSpawn( ply )
return
end
if(CurTime() < ent.LastSpawnTime)then return end
ent:DoSpawn( ply )
ent.LastSpawnTime=CurTime()+delay
end
/*-----------------------------------------------------------------------*
* Handler for undo keypad input
*-----------------------------------------------------------------------*/
function UndoContrSpawner( ply, ent )
if (!ent || !ent:IsValid()) then return end
ent:DoUndo( ply, true )
end
numpad.Register( "ContrSpawnerCreate", SpawnContrSpawner )
numpad.Register( "ContrSpawnerUndo" , UndoContrSpawner )

View File

@@ -0,0 +1,10 @@
ENT.Type = "anim"
ENT.Base = WireLib and "base_wire_entity" or "base_gmodentity"
ENT.PrintName = "Contraption Spawner"
ENT.Author = "TB"
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = ""
ENT.Spawnable = false
ENT.AdminSpawnable = false

View File

@@ -0,0 +1,141 @@
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = ""
ENT.Author = ""
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = ""
ENT.Spawnable = false
ENT.AdminOnly = false
--[[---------------------------------------------------------
Name: Initialize
-----------------------------------------------------------]]
function ENT:Initialize()
local Radius = 6
local min = Vector( 1, 1, 1 ) * Radius * -0.5
local max = Vector( 1, 1, 1 ) * Radius * 0.5
if ( SERVER ) then
self.AttachedEntity = ents.Create( "prop_dynamic" )
self.AttachedEntity:SetModel( self:GetModel() )
self.AttachedEntity:SetAngles( self:GetAngles() )
self.AttachedEntity:SetPos( self:GetPos() )
self.AttachedEntity:SetSkin( self:GetSkin() )
self.AttachedEntity:Spawn()
self.AttachedEntity:SetParent( self.Entity )
self.AttachedEntity:DrawShadow( false )
self:SetModel( "models/props_junk/watermelon01.mdl" )
self:DeleteOnRemove( self.AttachedEntity )
-- Don't use the model's physics - create a box instead
self:PhysicsInitBox( min, max )
-- Set up our physics object here
local phys = self:GetPhysicsObject()
if ( IsValid( phys ) ) then
phys:Wake()
phys:EnableGravity( false )
phys:EnableDrag( false )
end
self:DrawShadow( false )
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
else
self.GripMaterial = Material( "sprites/grip" )
-- Get the attached entity so that clientside functions like properties can interact with it
local tab = ents.FindByClassAndParent( "prop_dynamic", self )
if ( tab && IsValid( tab[ 1 ] ) ) then self.AttachedEntity = tab[ 1 ] end
end
-- Set collision bounds exactly
self:SetCollisionBounds( min, max )
end
--[[---------------------------------------------------------
Name: Draw
-----------------------------------------------------------]]
function ENT:Draw()
render.SetMaterial( self.GripMaterial )
end
--[[---------------------------------------------------------
Name: PhysicsUpdate
-----------------------------------------------------------]]
function ENT:PhysicsUpdate( physobj )
if ( CLIENT ) then return end
-- Don't do anything if the player isn't holding us
if ( !self:IsPlayerHolding() && !self:IsConstrained() ) then
physobj:SetVelocity( Vector( 0, 0, 0 ) )
physobj:Sleep()
end
end
--[[---------------------------------------------------------
Name: Called after entity 'copy'
-----------------------------------------------------------]]
function ENT:OnEntityCopyTableFinish( tab )
-- We need to store the model of the attached entity
-- Not the one we have here.
tab.Model = self.AttachedEntity:GetModel()
-- Store the attached entity's table so we can restore it after being pasted
tab.AttachedEntityInfo = table.Copy( duplicator.CopyEntTable( self.AttachedEntity ) )
tab.AttachedEntityInfo.Pos = nil -- Don't even save angles and position, we are a parented entity
tab.AttachedEntityInfo.Angle = nil
-- Do NOT store the attached entity itself in our table!
-- Otherwise, if we copy-paste the prop with the duplicator, its AttachedEntity value will point towards the original prop's attached entity instead, and that'll break stuff
tab.AttachedEntity = nil
end
--[[---------------------------------------------------------
Name: PostEntityPaste
-----------------------------------------------------------]]
function ENT:PostEntityPaste( ply )
-- Restore the attached entity using the information we've saved
if ( IsValid( self.AttachedEntity ) ) and ( self.AttachedEntityInfo ) then
-- Apply skin, bodygroups, bone manipulator, etc.
duplicator.DoGeneric( self.AttachedEntity, self.AttachedEntityInfo )
if ( self.AttachedEntityInfo.EntityMods ) then
self.AttachedEntity.EntityMods = table.Copy( self.AttachedEntityInfo.EntityMods )
duplicator.ApplyEntityModifiers( ply, self.AttachedEntity )
end
if ( self.AttachedEntityInfo.BoneMods ) then
self.AttachedEntity.BoneMods = table.Copy( self.AttachedEntityInfo.BoneMods )
duplicator.ApplyBoneModifiers( ply, self.AttachedEntity )
end
self.AttachedEntityInfo = nil
end
end

View File

@@ -0,0 +1,386 @@
--A net extension which allows sending large streams of data without overflowing the reliable channel
--Keep it in lua/autorun so it will be shared between addons
AddCSLuaFile()
net.Stream = {}
net.Stream.SendSize = 20000 --This is the size of each packet to send
net.Stream.Timeout = 30 --How long to wait for client response before cleaning up
net.Stream.MaxWriteStreams = 1024 --The maximum number of write data items to store
net.Stream.MaxReadStreams = 128 --The maximum number of queued read data items to store
net.Stream.MaxChunks = 3200 --Maximum number of pieces the stream can send to the server. 64 MB
net.Stream.MaxSize = net.Stream.SendSize*net.Stream.MaxChunks
net.Stream.MaxTries = 3 --Maximum times the client may retry downloading the whole data
local WriteStreamQueue = {
__index = {
Add = function(self, stream)
local identifier = self.curidentifier
local startid = identifier
while self.queue[identifier] do
identifier = identifier % net.Stream.MaxWriteStreams + 1
if identifier == startid then
ErrorNoHalt("Netstream is full of WriteStreams!")
net.WriteUInt(0, 32)
return
end
end
self.curidentifier = identifier % net.Stream.MaxWriteStreams + 1
if next(self.queue)==nil then
self.activitytimeout = CurTime()+net.Stream.Timeout
timer.Create("netstream_queueclean", 5, 0, function() self:Clean() end)
end
self.queue[identifier] = stream
stream.identifier = identifier
return stream
end,
Write = function(self, ply)
local identifier = net.ReadUInt(32)
local chunkidx = net.ReadUInt(32)
local stream = self.queue[identifier]
--print("Got request", identifier, chunkidx, stream)
if stream then
if stream:Write(ply, chunkidx) then
self.activitytimeout = CurTime()+net.Stream.Timeout
stream.timeout = CurTime()+net.Stream.Timeout
end
else
-- Tell them the stream doesn't exist
net.Start("NetStreamRead")
net.WriteUInt(identifier, 32)
net.WriteUInt(0, 32)
if SERVER then net.Send(ply) else net.SendToServer() end
end
end,
Clean = function(self)
local t = CurTime()
for k, stream in pairs(self.queue) do
if (next(stream.clients)~=nil and t >= stream.timeout) or t >= self.activitytimeout then
stream:Remove()
self.queue[k] = nil
end
end
if next(self.queue)==nil then
timer.Remove("netstream_queueclean")
end
end,
},
__call = function(t)
return setmetatable({
activitytimeout = CurTime()+net.Stream.Timeout,
curidentifier = 1,
queue = {}
}, t)
end
}
setmetatable(WriteStreamQueue, WriteStreamQueue)
net.Stream.WriteStreams = WriteStreamQueue()
local ReadStreamQueue = {
__index = {
Add = function(self, stream)
local queue = self.queues[stream.player]
if #queue == net.Stream.MaxReadStreams then
ErrorNoHalt("Receiving too many ReadStream requests!")
return
end
for _, v in ipairs(queue) do
if v.identifier == stream.identifier then
ErrorNoHalt("Tried to start a new ReadStream for an already existing stream!")
return
end
end
queue[#queue+1] = stream
if #queue == 1 then
stream:Request()
end
return stream
end,
Remove = function(self, stream)
local queue = rawget(self.queues, stream.player)
if queue then
if stream == queue[1] then
table.remove(queue, 1)
local nextInQueue = queue[1]
if nextInQueue then
nextInQueue:Request()
else
self.queues[stream.player] = nil
end
else
for k, v in ipairs(queue) do
if v == stream then
table.remove(queue, k)
break
end
end
end
end
end,
Read = function(self, ply)
local identifier = net.ReadUInt(32)
local queue = rawget(self.queues, ply)
if queue and queue[1] then
queue[1]:Read(identifier)
end
end
},
__call = function(t)
return setmetatable({
queues = setmetatable({}, {__index = function(t,k) local r={} t[k]=r return r end})
}, t)
end
}
setmetatable(ReadStreamQueue, ReadStreamQueue)
net.Stream.ReadStreams = ReadStreamQueue()
local WritingDataItem = {
__index = {
Write = function(self, ply, chunkidx)
local client = self.clients[ply]
if client.finished then return false end
if chunkidx == #self.chunks+1 then self:Finished(ply) return true end
if client.downloads+#self.chunks-client.progress >= net.Stream.MaxTries * #self.chunks then self:Finished(ply) return false end
client.downloads = client.downloads + 1
local chunk = self.chunks[chunkidx]
if not chunk then return false end
client.progress = chunkidx
--print("Sending", "NetStreamRead", self.identifier, #chunk.data, chunkidx, chunk.crc)
net.Start("NetStreamRead")
net.WriteUInt(self.identifier, 32)
net.WriteUInt(#chunk.data, 32)
net.WriteUInt(chunkidx, 32)
net.WriteString(chunk.crc)
net.WriteData(chunk.data, #chunk.data)
if CLIENT then net.SendToServer() else net.Send(ply) end
return true
end,
Finished = function(self, ply)
self.clients[ply].finished = true
if self.callback then
local ok, err = xpcall(self.callback, debug.traceback, ply)
if not ok then ErrorNoHalt(err) end
end
end,
GetProgress = function(self, ply)
return self.clients[ply].progress / #self.chunks
end,
Remove = function(self)
local sendTo = {}
for ply, client in pairs(self.clients) do
if not client.finished then
client.finished = true
if CLIENT or ply:IsValid() then sendTo[#sendTo+1] = ply end
end
end
if next(sendTo)~=nil then
--print("Sending", "NetStreamRead", self.identifier, 0)
net.Start("NetStreamRead")
net.WriteUInt(self.identifier, 32)
net.WriteUInt(0, 32)
if SERVER then net.Send(sendTo) else net.SendToServer() end
end
end
},
__call = function(t, data, callback)
local chunks = {}
for i=1, math.ceil(#data / net.Stream.SendSize) do
local datachunk = string.sub(data, (i - 1) * net.Stream.SendSize + 1, i * net.Stream.SendSize)
chunks[i] = { data = datachunk, crc = util.CRC(datachunk) }
end
return setmetatable({
timeout = CurTime()+net.Stream.Timeout,
chunks = chunks,
callback = callback,
lasttouched = 0,
clients = setmetatable({},{__index = function(t,k)
local r = {
finished = false,
downloads = 0,
progress = 0,
} t[k]=r return r
end})
}, t)
end
}
setmetatable(WritingDataItem, WritingDataItem)
local ReadingDataItem = {
__index = {
Request = function(self)
if self.downloads+self.numchunks-#self.chunks >= net.Stream.MaxTries*self.numchunks then self:Remove() return end
self.downloads = self.downloads + 1
timer.Create("NetStreamReadTimeout" .. self.identifier, net.Stream.Timeout*0.5, 1, function() self:Request() end)
self:WriteRequest()
end,
WriteRequest = function(self)
--print("Requesting", self.identifier, #self.chunks)
net.Start("NetStreamWrite")
net.WriteUInt(self.identifier, 32)
net.WriteUInt(#self.chunks+1, 32)
if CLIENT then net.SendToServer() else net.Send(self.player) end
end,
Read = function(self, identifier)
if self.identifier ~= identifier then self:Request() return end
local size = net.ReadUInt(32)
if size == 0 then self:Remove() return end
local chunkidx = net.ReadUInt(32)
if chunkidx ~= #self.chunks+1 then self:Request() return end
local crc = net.ReadString()
local data = net.ReadData(size)
if crc ~= util.CRC(data) then self:Request() return end
self.chunks[chunkidx] = data
if #self.chunks == self.numchunks then self:Remove(true) return end
self:Request()
end,
GetProgress = function(self)
return #self.chunks/self.numchunks
end,
Remove = function(self, finished)
timer.Remove("NetStreamReadTimeout" .. self.identifier)
local data
if finished then
data = table.concat(self.chunks)
if self.compressed then
data = util.Decompress(data, net.Stream.MaxSize)
end
self:WriteRequest() -- Notify we finished
end
local ok, err = xpcall(self.callback, debug.traceback, data)
if not ok then ErrorNoHalt(err) end
net.Stream.ReadStreams:Remove(self)
end
},
__call = function(t, ply, callback, numchunks, identifier, compressed)
return setmetatable({
identifier = identifier,
chunks = {},
compressed = compressed,
numchunks = numchunks,
callback = callback,
player = ply,
downloads = 0
}, t)
end
}
setmetatable(ReadingDataItem, ReadingDataItem)
function net.WriteStream(data, callback, dontcompress)
if not isstring(data) then
error("bad argument #1 to 'WriteStream' (string expected, got " .. type(data) .. ")", 2)
end
if callback ~= nil and not isfunction(callback) then
error("bad argument #2 to 'WriteStream' (function expected, got " .. type(callback) .. ")", 2)
end
local compressed = not dontcompress
if compressed then
data = util.Compress(data) or ""
end
if #data == 0 then
net.WriteUInt(0, 32)
return
end
if #data > net.Stream.MaxSize then
ErrorNoHalt("net.WriteStream request is too large! ", #data/1048576, "MiB")
net.WriteUInt(0, 32)
return
end
local stream = net.Stream.WriteStreams:Add(WritingDataItem(data, callback, compressed))
if not stream then return end
--print("WriteStream", #stream.chunks, stream.identifier, compressed)
net.WriteUInt(#stream.chunks, 32)
net.WriteUInt(stream.identifier, 32)
net.WriteBool(compressed)
return stream
end
--If the receiver is a player then add it to a queue.
--If the receiver is the server then add it to a queue for each individual player
function net.ReadStream(ply, callback)
if CLIENT then
ply = NULL
else
if type(ply) ~= "Player" then
error("bad argument #1 to 'ReadStream' (Player expected, got " .. type(ply) .. ")", 2)
elseif not ply:IsValid() then
error("bad argument #1 to 'ReadStream' (Tried to use a NULL entity!)", 2)
end
end
if not isfunction(callback) then
error("bad argument #2 to 'ReadStream' (function expected, got " .. type(callback) .. ")", 2)
end
local numchunks = net.ReadUInt(32)
if numchunks == nil then
return
elseif numchunks == 0 then
local ok, err = xpcall(callback, debug.traceback, "")
if not ok then ErrorNoHalt(err) end
return
end
local identifier = net.ReadUInt(32)
local compressed = net.ReadBool()
if numchunks > net.Stream.MaxChunks then
ErrorNoHalt("ReadStream requests from ", ply, " is too large! ", numchunks * net.Stream.SendSize / 1048576, "MiB")
return
end
--print("ReadStream", numchunks, identifier, compressed)
return net.Stream.ReadStreams:Add(ReadingDataItem(ply, callback, numchunks, identifier, compressed))
end
if SERVER then
util.AddNetworkString("NetStreamWrite")
util.AddNetworkString("NetStreamRead")
end
--Send requested stream data
net.Receive("NetStreamWrite", function(len, ply)
net.Stream.WriteStreams:Write(ply or NULL)
end)
--Download the sent stream data
net.Receive("NetStreamRead", function(len, ply)
net.Stream.ReadStreams:Read(ply or NULL)
end)

View File

@@ -0,0 +1,46 @@
/*
____ _ _ ____ __ __ _ _
/ ___|___ __| | ___ __| | | __ ) _ _ | \/ | __ _| | |__ ___ _ __ ___
| | / _ \ / _` |/ _ \/ _` | | _ \| | | | | |\/| |/ _` | | '_ \ / _ \| '__/ _ \
| |__| (_) | (_| | __/ (_| | | |_) | |_| | | | | | (_| | | |_) | (_) | | | (_) |
\____\___/ \__,_|\___|\__,_| |____/ \__, | |_| |_|\__,_|_|_.__/ \___/|_| \___/
|___/
*/
local function PermaPropsViewer()
if not LocalPlayer().DrawPPEnt or not istable(LocalPlayer().DrawPPEnt) then return end
local pos = LocalPlayer():EyePos() + LocalPlayer():EyeAngles():Forward() * 10
local ang = LocalPlayer():EyeAngles()
ang = Angle(ang.p + 90, ang.y, 0)
for k, v in pairs(LocalPlayer().DrawPPEnt) do
if not v or not v:IsValid() then LocalPlayer().DrawPPEnt[k] = nil continue end
render.ClearStencil()
render.SetStencilEnable(true)
render.SetStencilWriteMask(255)
render.SetStencilTestMask(255)
render.SetStencilReferenceValue(15)
render.SetStencilFailOperation(STENCILOPERATION_REPLACE)
render.SetStencilZFailOperation(STENCILOPERATION_REPLACE)
render.SetStencilPassOperation(STENCILOPERATION_KEEP)
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_ALWAYS)
render.SetBlend(0)
v:DrawModel()
render.SetBlend(1)
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL)
cam.Start3D2D(pos, ang, 1)
surface.SetDrawColor(255, 0, 0, 255)
surface.DrawRect(-ScrW(), -ScrH(), ScrW() * 2, ScrH() * 2)
cam.End3D2D()
v:DrawModel()
render.SetStencilEnable(false)
end
end
hook.Add("PostDrawOpaqueRenderables", "PermaPropsViewer", PermaPropsViewer)

View File

@@ -0,0 +1,468 @@
/*
____ _ _ ____ __ __ _ _
/ ___|___ __| | ___ __| | | __ ) _ _ | \/ | __ _| | |__ ___ _ __ ___
| | / _ \ / _` |/ _ \/ _` | | _ \| | | | | |\/| |/ _` | | '_ \ / _ \| '__/ _ \
| |__| (_) | (_| | __/ (_| | | |_) | |_| | | | | | (_| | | |_) | (_) | | | (_) |
\____\___/ \__,_|\___|\__,_| |____/ \__, | |_| |_|\__,_|_|_.__/ \___/|_| \___/
|___/
*/
surface.CreateFont( "pp_font", {
font = "Arial",
size = 20,
weight = 700,
shadow = false
} )
local function pp_open_menu()
local Len = net.ReadFloat()
local Data = net.ReadData( Len )
local UnCompress = util.Decompress( Data )
local Content = util.JSONToTable( UnCompress )
local Main = vgui.Create( "DFrame" )
Main:SetSize( 600, 355 )
Main:Center()
Main:SetTitle("")
Main:SetVisible( true )
Main:SetDraggable( true )
Main:ShowCloseButton( true )
Main:MakePopup()
Main.Paint = function(self)
draw.RoundedBox( 0, 0, 0, self:GetWide(), self:GetTall(), Color(155, 155, 155, 220) )
surface.SetDrawColor( 17, 148, 240, 255 )
surface.DrawOutlinedRect( 0, 0, self:GetWide(), self:GetTall() )
draw.RoundedBox( 0, 0, 0, self:GetWide(), 25, Color(17, 148, 240, 200) )
surface.SetDrawColor( 17, 148, 240, 255 )
surface.DrawOutlinedRect( 0, 0, self:GetWide(), 25 )
draw.DrawText( "PermaProps Config", "pp_font", 10, 2.2, Color(255, 255, 255, 255), TEXT_ALIGN_LEFT )
end
local BSelect
local PSelect
local MainPanel = vgui.Create( "DPanel", Main )
MainPanel:SetPos( 190, 51 )
MainPanel:SetSize( 390, 275 )
MainPanel.Paint = function( self )
surface.SetDrawColor( 50, 50, 50, 200 )
surface.DrawRect( 0, 0, self:GetWide(), self:GetTall() )
surface.DrawOutlinedRect(0, 15, self:GetWide(), 40)
end
PSelect = MainPanel
local MainLabel = vgui.Create("DLabel", MainPanel)
MainLabel:SetFont("pp_font")
MainLabel:SetPos(140, 25)
MainLabel:SetColor(Color(50, 50, 50, 255))
MainLabel:SetText("Hey ".. LocalPlayer():Nick() .." !")
MainLabel:SizeToContents()
local MainLabel2 = vgui.Create("DLabel", MainPanel)
MainLabel2:SetFont("pp_font")
MainLabel2:SetPos(80, 80)
MainLabel2:SetColor(Color(50, 50, 50, 255))
MainLabel2:SetText("There are ".. ( Content.MProps or 0 ) .." props on this map.\n\nThere are ".. ( Content.TProps or 0 ) .." props in the DB.")
MainLabel2:SizeToContents()
local RemoveMapProps = vgui.Create( "DButton", MainPanel )
RemoveMapProps:SetText( " Clear map props " )
RemoveMapProps:SetFont("pp_font")
RemoveMapProps:SetSize( 370, 30)
RemoveMapProps:SetPos( 10, 160 )
RemoveMapProps:SetTextColor( Color( 50, 50, 50, 255 ) )
RemoveMapProps.DoClick = function()
net.Start("pp_info_send")
net.WriteTable({CMD = "CLR_MAP"})
net.SendToServer()
end
RemoveMapProps.Paint = function(self)
surface.SetDrawColor(50, 50, 50, 255)
surface.DrawOutlinedRect(0, 0, self:GetWide(), self:GetTall())
end
local ClearMapProps = vgui.Create( "DButton", MainPanel )
ClearMapProps:SetText( " Clear map props in the DB " )
ClearMapProps:SetFont("pp_font")
ClearMapProps:SetSize( 370, 30)
ClearMapProps:SetPos( 10, 200 )
ClearMapProps:SetTextColor( Color( 50, 50, 50, 255 ) )
ClearMapProps.DoClick = function()
Derma_Query("Are you sure you want clear map props in the db ?\nYou can't undo this action !", "PermaProps 4.0", "Yes", function() net.Start("pp_info_send") net.WriteTable({CMD = "DEL_MAP"}) net.SendToServer() end, "Cancel")
end
ClearMapProps.Paint = function(self)
surface.SetDrawColor(50, 50, 50, 255)
surface.DrawOutlinedRect(0, 0, self:GetWide(), self:GetTall())
end
local ClearAllProps = vgui.Create( "DButton", MainPanel )
ClearAllProps:SetText( " Clear all props in the DB " )
ClearAllProps:SetFont("pp_font")
ClearAllProps:SetSize( 370, 30)
ClearAllProps:SetPos( 10, 240 )
ClearAllProps:SetTextColor( Color( 50, 50, 50, 255 ) )
ClearAllProps.DoClick = function()
Derma_Query("Are you sure you want clear all props in the db ?\nYou can't undo this action !", "PermaProps 4.0", "Yes", function() net.Start("pp_info_send") net.WriteTable({CMD = "DEL_ALL"}) net.SendToServer() end, "Cancel")
end
ClearAllProps.Paint = function(self)
surface.SetDrawColor(50, 50, 50, 255)
surface.DrawOutlinedRect(0, 0, self:GetWide(), self:GetTall())
end
local BMain = vgui.Create("DButton", Main)
BSelect = BMain
BMain:SetText("Main")
BMain:SetFont("pp_font")
BMain:SetSize(160, 50)
BMain:SetPos(15, 27 + 25)
BMain:SetTextColor( Color( 255, 255, 255, 255 ) )
BMain.PaintColor = Color(17, 148, 240, 100)
BMain.Paint = function(self)
draw.RoundedBox(0, 0, 0, self:GetWide(), self:GetTall(), self.PaintColor)
surface.SetDrawColor(17, 148, 240, 255)
surface.DrawOutlinedRect(0, 0, self:GetWide(), self:GetTall())
end
BMain.DoClick = function( self )
if BSelect then BSelect.PaintColor = Color(0, 0, 0, 0) end
BSelect = self
self.PaintColor = Color(17, 148, 240, 100)
if PSelect then PSelect:Hide() end
MainPanel:Show()
PSelect = MainPanel
end
local ConfigPanel = vgui.Create( "DPanel", Main )
ConfigPanel:SetPos( 190, 51 )
ConfigPanel:SetSize( 390, 275 )
ConfigPanel.Paint = function( self )
surface.SetDrawColor( 50, 50, 50, 200 )
surface.DrawRect( 0, 0, self:GetWide(), self:GetTall() )
end
ConfigPanel:Hide()
local CheckCustom = vgui.Create( "DCheckBoxLabel", ConfigPanel )
CheckCustom:SetPos( 5, 30 )
CheckCustom:SetText( "Custom permissions" )
CheckCustom:SetValue( 0 )
CheckCustom:SizeToContents()
CheckCustom:SetTextColor( Color( 0, 0, 0, 255) )
CheckCustom:SetDisabled( true )
local GroupsList = vgui.Create( "DComboBox", ConfigPanel )
GroupsList:SetPos( 5, 5 )
GroupsList:SetSize( 125, 20 )
GroupsList:SetValue( "Select a group..." )
local CheckBox1 = vgui.Create( "DCheckBoxLabel", ConfigPanel )
CheckBox1:SetPos( 150, 10 )
CheckBox1:SetText( "Menu" )
CheckBox1:SizeToContents()
CheckBox1:SetTextColor( Color( 0, 0, 0, 255) )
CheckBox1:SetDisabled( true )
CheckBox1.OnChange = function(Self, Value)
net.Start("pp_info_send")
net.WriteTable({CMD = "VAR", Val = Value, Data = "Menu", Name = GroupsList:GetValue()})
net.SendToServer()
end
local CheckBox2 = vgui.Create( "DCheckBoxLabel", ConfigPanel )
CheckBox2:SetPos( 150, 30 )
CheckBox2:SetText( "Edit permissions" )
CheckBox2:SizeToContents()
CheckBox2:SetTextColor( Color( 0, 0, 0, 255) )
CheckBox2:SetDisabled( true )
CheckBox2.OnChange = function(Self, Value)
net.Start("pp_info_send")
net.WriteTable({CMD = "VAR", Val = Value, Data = "Permissions", Name = GroupsList:GetValue()})
net.SendToServer()
end
local CheckBox3 = vgui.Create( "DCheckBoxLabel", ConfigPanel )
CheckBox3:SetPos( 150, 50 )
CheckBox3:SetText( "Physgun permaprops" )
CheckBox3:SizeToContents()
CheckBox3:SetTextColor( Color( 0, 0, 0, 255) )
CheckBox3:SetDisabled( true )
CheckBox3.OnChange = function(Self, Value)
net.Start("pp_info_send")
net.WriteTable({CMD = "VAR", Val = Value, Data = "Physgun", Name = GroupsList:GetValue()})
net.SendToServer()
end
local CheckBox4 = vgui.Create( "DCheckBoxLabel", ConfigPanel )
CheckBox4:SetPos( 150, 70 )
CheckBox4:SetText( "Tool permaprops" )
CheckBox4:SizeToContents()
CheckBox4:SetTextColor( Color( 0, 0, 0, 255) )
CheckBox4:SetDisabled( true )
CheckBox4.OnChange = function(Self, Value)
net.Start("pp_info_send")
net.WriteTable({CMD = "VAR", Val = Value, Data = "Tool", Name = GroupsList:GetValue()})
net.SendToServer()
end
local CheckBox5 = vgui.Create( "DCheckBoxLabel", ConfigPanel )
CheckBox5:SetPos( 150, 90 )
CheckBox5:SetText( "Property permaprops" )
CheckBox5:SizeToContents()
CheckBox5:SetTextColor( Color( 0, 0, 0, 255) )
CheckBox5:SetDisabled( true )
CheckBox5.OnChange = function(Self, Value)
net.Start("pp_info_send")
net.WriteTable({CMD = "VAR", Val = Value, Data = "Property", Name = GroupsList:GetValue()})
net.SendToServer()
end
local CheckBox6 = vgui.Create( "DCheckBoxLabel", ConfigPanel )
CheckBox6:SetPos( 150, 110 )
CheckBox6:SetText( "Save props" )
CheckBox6:SizeToContents()
CheckBox6:SetTextColor( Color( 0, 0, 0, 255) )
CheckBox6:SetDisabled( true )
CheckBox6.OnChange = function(Self, Value)
net.Start("pp_info_send")
net.WriteTable({CMD = "VAR", Val = Value, Data = "Save", Name = GroupsList:GetValue()})
net.SendToServer()
end
local CheckBox7 = vgui.Create( "DCheckBoxLabel", ConfigPanel )
CheckBox7:SetPos( 150, 130 )
CheckBox7:SetText( "Delete permaprops" )
CheckBox7:SizeToContents()
CheckBox7:SetTextColor( Color( 0, 0, 0, 255) )
CheckBox7:SetDisabled( true )
CheckBox7.OnChange = function(Self, Value)
net.Start("pp_info_send")
net.WriteTable({CMD = "VAR", Val = Value, Data = "Delete", Name = GroupsList:GetValue()})
net.SendToServer()
end
local CheckBox8 = vgui.Create( "DCheckBoxLabel", ConfigPanel )
CheckBox8:SetPos( 150, 150 )
CheckBox8:SetText( "Update permaprops" )
CheckBox8:SizeToContents()
CheckBox8:SetTextColor( Color( 0, 0, 0, 255) )
CheckBox8:SetDisabled( true )
CheckBox8.OnChange = function(Self, Value)
net.Start("pp_info_send")
net.WriteTable({CMD = "VAR", Val = Value, Data = "Update", Name = GroupsList:GetValue()})
net.SendToServer()
end
GroupsList.OnSelect = function( panel, index, value )
CheckCustom:SetDisabled( false )
CheckCustom:SetChecked( Content.Permissions[value].Custom )
CheckBox1:SetDisabled( !Content.Permissions[value].Custom )
CheckBox1:SetChecked( Content.Permissions[value].Menu )
CheckBox2:SetDisabled( !Content.Permissions[value].Custom )
CheckBox2:SetChecked( Content.Permissions[value].Permissions )
CheckBox3:SetDisabled( !Content.Permissions[value].Custom )
CheckBox3:SetChecked( Content.Permissions[value].Physgun )
CheckBox4:SetDisabled( !Content.Permissions[value].Custom )
CheckBox4:SetChecked( Content.Permissions[value].Tool )
CheckBox5:SetDisabled( !Content.Permissions[value].Custom )
CheckBox5:SetChecked( Content.Permissions[value].Property )
CheckBox6:SetDisabled( !Content.Permissions[value].Custom )
CheckBox6:SetChecked( Content.Permissions[value].Save )
CheckBox7:SetDisabled( !Content.Permissions[value].Custom )
CheckBox7:SetChecked( Content.Permissions[value].Delete )
CheckBox8:SetDisabled( !Content.Permissions[value].Custom )
CheckBox8:SetChecked( Content.Permissions[value].Update )
end
for k, v in pairs(Content.Permissions) do
GroupsList:AddChoice(k)
end
CheckCustom.OnChange = function(Self, Value)
CheckBox1:SetDisabled( !Value )
CheckBox2:SetDisabled( !Value )
CheckBox3:SetDisabled( !Value )
CheckBox4:SetDisabled( !Value )
CheckBox5:SetDisabled( !Value )
CheckBox6:SetDisabled( !Value )
CheckBox7:SetDisabled( !Value )
CheckBox8:SetDisabled( !Value )
net.Start("pp_info_send")
net.WriteTable({CMD = "VAR", Val = Value, Data = "Custom", Name = GroupsList:GetValue()})
net.SendToServer()
end
local BConfig = vgui.Create("DButton", Main)
BConfig:SetText("Configuration")
BConfig:SetFont("pp_font")
BConfig:SetSize(160, 50)
BConfig:SetPos(15, 71 + 55)
BConfig:SetTextColor( Color( 255, 255, 255, 255 ) )
BConfig.PaintColor = Color(0, 0, 0, 0)
BConfig.Paint = function(self)
draw.RoundedBox(0, 0, 0, self:GetWide(), self:GetTall(), self.PaintColor)
surface.SetDrawColor(17, 148, 240, 255)
surface.DrawOutlinedRect(0, 0, self:GetWide(), self:GetTall())
end
BConfig.DoClick = function( self )
if BSelect then BSelect.PaintColor = Color(0, 0, 0, 0) end
BSelect = self
self.PaintColor = Color(17, 148, 240, 100)
if PSelect then PSelect:Hide() end
ConfigPanel:Show()
PSelect = ConfigPanel
end
local PropsPanel = vgui.Create( "DPanel", Main )
PropsPanel:SetPos( 190, 51 )
PropsPanel:SetSize( 390, 275 )
PropsPanel.Paint = function( self )
surface.SetDrawColor( 50, 50, 50, 200 )
surface.DrawRect( 0, 0, self:GetWide(), self:GetTall() )
end
PropsPanel:Hide()
local PropsList = vgui.Create( "DListView", PropsPanel )
PropsList:SetMultiSelect( false )
PropsList:SetSize( 390, 275 )
local ColID = PropsList:AddColumn( "ID" )
local ColEnt = PropsList:AddColumn( "Entity" )
local ColMdl = PropsList:AddColumn( "Model" )
ColID:SetMinWidth(50)
ColID:SetMaxWidth(50)
PropsList.Paint = function( self )
surface.SetDrawColor(17, 148, 240, 255)
end
PropsList.OnRowRightClick = function(panel, line)
local MenuButtonOptions = DermaMenu()
MenuButtonOptions:AddOption("Draw entity", function()
if not LocalPlayer().DrawPPEnt or not istable(LocalPlayer().DrawPPEnt) then LocalPlayer().DrawPPEnt = {} end
if LocalPlayer().DrawPPEnt[PropsList:GetLine(line):GetValue(1)] and LocalPlayer().DrawPPEnt[PropsList:GetLine(line):GetValue(1)]:IsValid() then return end
local ent = ents.CreateClientProp( Content.PropsList[PropsList:GetLine(line):GetValue(1)].Model )
ent:SetPos( Content.PropsList[PropsList:GetLine(line):GetValue(1)].Pos )
ent:SetAngles( Content.PropsList[PropsList:GetLine(line):GetValue(1)].Angle )
LocalPlayer().DrawPPEnt[PropsList:GetLine(line):GetValue(1)] = ent
end )
if LocalPlayer().DrawPPEnt and LocalPlayer().DrawPPEnt[PropsList:GetLine(line):GetValue(1)] then
MenuButtonOptions:AddOption("Stop Drawing", function()
LocalPlayer().DrawPPEnt[PropsList:GetLine(line):GetValue(1)]:Remove()
LocalPlayer().DrawPPEnt[PropsList:GetLine(line):GetValue(1)] = nil
end )
end
if LocalPlayer().DrawPPEnt != nil and istable(LocalPlayer().DrawPPEnt) and table.Count(LocalPlayer().DrawPPEnt) > 0 then
MenuButtonOptions:AddOption("Stop Drawing All", function()
for k, v in pairs(LocalPlayer().DrawPPEnt) do
LocalPlayer().DrawPPEnt[k]:Remove()
LocalPlayer().DrawPPEnt[k] = nil
end
end )
end
MenuButtonOptions:AddOption("Remove", function()
net.Start("pp_info_send")
net.WriteTable({CMD = "DEL", Val = PropsList:GetLine(line):GetValue(1)})
net.SendToServer()
if LocalPlayer().DrawPPEnt and LocalPlayer().DrawPPEnt[PropsList:GetLine(line):GetValue(1)] != nil then
LocalPlayer().DrawPPEnt[PropsList:GetLine(line):GetValue(1)]:Remove()
LocalPlayer().DrawPPEnt[PropsList:GetLine(line):GetValue(1)] = nil
end
PropsList:RemoveLine(line)
end )
MenuButtonOptions:Open()
end
for k, v in pairs(Content.PropsList) do
PropsList:AddLine(k, v.Class, v.Model)
end
local BProps = vgui.Create("DButton", Main)
BProps:SetText("Props List")
BProps:SetFont("pp_font")
BProps:SetSize(160, 50)
BProps:SetPos(15, 115 + 85)
BProps:SetTextColor( Color( 255, 255, 255, 255 ) )
BProps.PaintColor = Color(0, 0, 0, 0)
BProps.Paint = function(self)
draw.RoundedBox(0, 0, 0, self:GetWide(), self:GetTall(), self.PaintColor)
surface.SetDrawColor(17, 148, 240, 255)
surface.DrawOutlinedRect(0, 0, self:GetWide(), self:GetTall())
end
BProps.DoClick = function( self )
if BSelect then BSelect.PaintColor = Color(0, 0, 0, 0) end
BSelect = self
self.PaintColor = Color(17, 148, 240, 100)
if PSelect then PSelect:Hide() end
PropsPanel:Show()
PSelect = PropsPanel
end
end
net.Receive("pp_open_menu", pp_open_menu)

View File

@@ -0,0 +1,323 @@
/*
____ _ _ ____ __ __ _ _
/ ___|___ __| | ___ __| | | __ ) _ _ | \/ | __ _| | |__ ___ _ __ ___
| | / _ \ / _` |/ _ \/ _` | | _ \| | | | | |\/| |/ _` | | '_ \ / _ \| '__/ _ \
| |__| (_) | (_| | __/ (_| | | |_) | |_| | | | | | (_| | | |_) | (_) | | | (_) |
\____\___/ \__,_|\___|\__,_| |____/ \__, | |_| |_|\__,_|_|_.__/ \___/|_| \___/
|___/
*/
if not PermaProps then PermaProps = {} end
function PermaProps.PPGetEntTable( ent )
if !ent or !ent:IsValid() then return false end
local content = {}
content.Class = ent:GetClass()
content.Pos = ent:GetPos()
content.Angle = ent:GetAngles()
content.Model = ent:GetModel()
content.Skin = ent:GetSkin()
//content.Mins, content.Maxs = ent:GetCollisionBounds()
content.ColGroup = ent:GetCollisionGroup()
content.Name = ent:GetName()
content.ModelScale = ent:GetModelScale()
content.Color = ent:GetColor()
content.Material = ent:GetMaterial()
content.Solid = ent:GetSolid()
content.RenderMode = ent:GetRenderMode()
if PermaProps.SpecialENTSSave[ent:GetClass()] != nil and isfunction(PermaProps.SpecialENTSSave[ent:GetClass()]) then
local othercontent = PermaProps.SpecialENTSSave[ent:GetClass()](ent)
if not othercontent then return false end
if othercontent != nil and istable(othercontent) then
table.Merge(content, othercontent)
end
end
do
local othercontent = hook.Run("PermaProps.OnEntitySaved", ent)
if othercontent and istable(othercontent) then
table.Merge(content, othercontent)
end
end
if ( ent.GetNetworkVars ) then
content.DT = ent:GetNetworkVars()
end
local sm = ent:GetMaterials()
if ( sm and istable(sm) ) then
for k, v in pairs( sm ) do
if ( ent:GetSubMaterial( k )) then
content.SubMat = content.SubMat or {}
content.SubMat[ k ] = ent:GetSubMaterial( k-1 )
end
end
end
local bg = ent:GetBodyGroups()
if ( bg ) then
for k, v in pairs( bg ) do
if ( ent:GetBodygroup( v.id ) > 0 ) then
content.BodyG = content.BodyG or {}
content.BodyG[ v.id ] = ent:GetBodygroup( v.id )
end
end
end
if ent:GetPhysicsObject() and ent:GetPhysicsObject():IsValid() then
content.Frozen = !ent:GetPhysicsObject():IsMoveable()
end
if content.Class == "prop_dynamic" then
content.Class = "prop_physics"
end
--content.Table = PermaProps.UselessContent( ent:GetTable() )
return content
end
function PermaProps.PPEntityFromTable( data, id )
if not id or not isnumber(id) then return false end
if not data or not istable(data) then return false end
if data.Class == "prop_physics" and data.Frozen then
data.Class = "prop_dynamic" -- Can reduce lags
end
local ent = ents.Create(data.Class)
if !ent then return false end
if !ent:IsVehicle() then if !ent:IsValid() then return false end end
ent:SetPos( data.Pos or Vector(0, 0, 0) )
ent:SetAngles( data.Angle or Angle(0, 0, 0) )
ent:SetModel( data.Model or "models/error.mdl" )
ent:SetSkin( data.Skin or 0 )
//ent:SetCollisionBounds( ( data.Mins or 0 ), ( data.Maxs or 0 ) )
ent:SetCollisionGroup( data.ColGroup or 0 )
ent:SetName( data.Name or "" )
ent:SetModelScale( data.ModelScale or 1 )
ent:SetMaterial( data.Material or "" )
ent:SetSolid( data.Solid or 6 )
if PermaProps.SpecialENTSSpawn[data.Class] != nil and isfunction(PermaProps.SpecialENTSSpawn[data.Class]) then
PermaProps.SpecialENTSSpawn[data.Class](ent, data.Other)
else
ent:Spawn()
end
hook.Run("PermaProps.OnEntityCreated", ent, data)
ent:SetRenderMode( data.RenderMode or RENDERMODE_NORMAL )
ent:SetColor( data.Color or Color(255, 255, 255, 255) )
if data.EntityMods != nil and istable(data.EntityMods) then -- OLD DATA
if data.EntityMods.material then
ent:SetMaterial( data.EntityMods.material["MaterialOverride"] or "")
end
if data.EntityMods.colour then
ent:SetColor( data.EntityMods.colour.Color or Color(255, 255, 255, 255))
end
end
if data.DT then
for k, v in pairs( data.DT ) do
if ( data.DT[ k ] == nil ) then continue end
if !isfunction(ent[ "Set" .. k ]) then continue end
ent[ "Set" .. k ]( ent, data.DT[ k ] )
end
end
if data.BodyG then
for k, v in pairs( data.BodyG ) do
ent:SetBodygroup( k, v )
end
end
if data.SubMat then
for k, v in pairs( data.SubMat ) do
if type(k) != "number" or type(v) != "string" then continue end
ent:SetSubMaterial( k-1, v )
end
end
if data.Frozen != nil then
local phys = ent:GetPhysicsObject()
if phys and phys:IsValid() then
phys:EnableMotion(!data.Frozen)
end
end
/*if data.Table then
table.Merge(ent:GetTable(), data.Table)
end*/
ent.PermaProps_ID = id
ent.PermaProps = true
// For all idiots who don't know how to config FPP, FUCK YOU
function ent:CanTool( ply, trace, tool )
if trace and IsValid(trace.Entity) and trace.Entity.PermaProps then
if tool == "permaprops" then
return true
end
return PermaProps.HasPermission( ply, "Tool")
end
end
return ent
end
function PermaProps.ReloadPermaProps()
for k, v in pairs( ents.GetAll() ) do
if v.PermaProps == true then
v:Remove()
end
end
local content = PermaProps.SQL.Query( "SELECT * FROM permaprops WHERE map = ".. sql.SQLStr(game.GetMap()) .. ";" )
if not content or content == nil then return end
for k, v in pairs( content ) do
local data = util.JSONToTable(v.content)
local e = PermaProps.PPEntityFromTable(data, tonumber(v.id))
if !e or !e:IsValid() then continue end
end
end
hook.Add("InitPostEntity", "InitializePermaProps", PermaProps.ReloadPermaProps)
hook.Add("PostCleanupMap", "WhenCleanUpPermaProps", PermaProps.ReloadPermaProps) -- #MOMO
timer.Simple(5, function() PermaProps.ReloadPermaProps() end) -- When the hook isn't call ...
function PermaProps.SparksEffect( ent )
local effectdata = EffectData()
effectdata:SetOrigin(ent:GetPos())
effectdata:SetMagnitude(2.5)
effectdata:SetScale(2)
effectdata:SetRadius(3)
util.Effect("Sparks", effectdata, true, true)
end
function PermaProps.IsUserGroup( ply, name )
if not ply:IsValid() then return false end
return ply:GetNetworkedString("UserGroup") == name
end
function PermaProps.IsAdmin( ply )
if ( PermaProps.IsUserGroup(ply, "superadmin") or false ) then return true end
if ( PermaProps.IsUserGroup(ply, "admin") or false ) then return true end
return false
end
function PermaProps.IsSuperAdmin( ply )
return ( PermaProps.IsUserGroup(ply, "superadmin") or false )
end
function PermaProps.UselessContent( tbl )
local function SortFcn( tbl2 )
for k, v in pairs( tbl2 ) do
if isfunction( v ) or isentity( v ) then
tbl2[k] = nil
elseif istable( v ) then
SortFcn( v )
end
end
return tbl2
end
for k, v in pairs( tbl ) do
if isfunction( v ) or isentity( v ) then
tbl[k] = nil
elseif istable( v ) then
SortFcn( v )
end
end
return tbl
end

View File

@@ -0,0 +1,185 @@
/*
____ _ _ ____ __ __ _ _
/ ___|___ __| | ___ __| | | __ ) _ _ | \/ | __ _| | |__ ___ _ __ ___
| | / _ \ / _` |/ _ \/ _` | | _ \| | | | | |\/| |/ _` | | '_ \ / _ \| '__/ _ \
| |__| (_) | (_| | __/ (_| | | |_) | |_| | | | | | (_| | | |_) | (_) | | | (_) |
\____\___/ \__,_|\___|\__,_| |____/ \__, | |_| |_|\__,_|_|_.__/ \___/|_| \___/
|___/
*/
util.AddNetworkString("pp_open_menu")
util.AddNetworkString("pp_info_send")
local function PermissionLoad()
if not PermaProps then PermaProps = {} end
if not PermaProps.Permissions then PermaProps.Permissions = {} end
PermaProps.Permissions["superadmin"] = { Physgun = true, Tool = true, Property = true, Save = true, Delete = true, Update = true, Menu = true, Permissions = true, Inherits = "admin", Custom = true }
PermaProps.Permissions["admin"] = { Physgun = false, Tool = false, Property = false, Save = true, Delete = true, Update = true, Menu = true, Permissions = false, Inherits = "user", Custom = true }
PermaProps.Permissions["user"] = { Physgun = false, Tool = false, Property = false, Save = false, Delete = false, Update = false, Menu = false, Permissions = false, Inherits = "user", Custom = true }
if CAMI then
for k, v in pairs(CAMI.GetUsergroups()) do
if k == "superadmin" or k == "admin" or k == "user" then continue end
PermaProps.Permissions[k] = { Physgun = false, Tool = false, Property = false, Save = false, Delete = false, Update = false, Menu = false, Permissions = false, Inherits = v.Inherits, Custom = false }
end
end
if file.Exists( "permaprops_config.txt", "DATA" ) then
file.Delete( "permaprops_config.txt" )
end
if file.Exists( "permaprops_permissions.txt", "DATA" ) then
local content = file.Read("permaprops_permissions.txt", "DATA")
local tablecontent = util.JSONToTable( content )
for k, v in pairs(tablecontent) do
if PermaProps.Permissions[k] == nil then
tablecontent[k] = nil
end
end
table.Merge(PermaProps.Permissions, ( tablecontent or {} ))
end
end
hook.Add("Initialize", "PermaPropPermLoad", PermissionLoad)
hook.Add("CAMI.OnUsergroupRegistered", "PermaPropPermLoadCAMI", PermissionLoad) -- In case something changes
local function PermissionSave()
file.Write( "permaprops_permissions.txt", util.TableToJSON(PermaProps.Permissions) )
end
local function pp_open_menu( ply )
if !PermaProps.HasPermission( ply, "Menu") then ply:ChatPrint("Access denied !") return end
local SendTable = {}
local Data_PropsList = sql.Query( "SELECT * FROM permaprops WHERE map = ".. sql.SQLStr(game.GetMap()) .. ";" )
if Data_PropsList and #Data_PropsList < 200 then
for k, v in pairs( Data_PropsList ) do
local data = util.JSONToTable(v.content)
SendTable[v.id] = {Model = data.Model, Class = data.Class, Pos = data.Pos, Angle = data.Angle}
end
elseif Data_PropsList and #Data_PropsList > 200 then -- Too much props dude :'(
for i = 1, 199 do
local data = util.JSONToTable(Data_PropsList[i].content)
SendTable[Data_PropsList[i].id] = {Model = data.Model, Class = data.Class, Pos = data.Pos, Angle = data.Angle}
end
end
local Content = {}
Content.MProps = tonumber(sql.QueryValue("SELECT COUNT(*) FROM permaprops WHERE map = ".. sql.SQLStr(game.GetMap()) .. ";"))
Content.TProps = tonumber(sql.QueryValue("SELECT COUNT(*) FROM permaprops;"))
Content.PropsList = SendTable
Content.Permissions = PermaProps.Permissions
local Data = util.TableToJSON( Content )
local Compressed = util.Compress( Data )
net.Start( "pp_open_menu" )
net.WriteFloat( Compressed:len() )
net.WriteData( Compressed, Compressed:len() )
net.Send( ply )
end
concommand.Add("pp_cfg_open", pp_open_menu)
local function pp_info_send( um, ply )
if !PermaProps.HasPermission( ply, "Menu") then ply:ChatPrint("Access denied !") return end
local Content = net.ReadTable()
if Content["CMD"] == "DEL" then
Content["Val"] = tonumber(Content["Val"])
if Content["Val"] != nil and Content["Val"] <= 0 then return end
sql.Query("DELETE FROM permaprops WHERE id = ".. sql.SQLStr(Content["Val"]) .. ";")
for k, v in pairs(ents.GetAll()) do
if v.PermaProps_ID == Content["Val"] then
ply:ChatPrint("You erased " .. v:GetClass() .. " with a model of " .. v:GetModel() .. " from the database.")
v:Remove()
break
end
end
elseif Content["CMD"] == "VAR" then
if PermaProps.Permissions[Content["Name"]] == nil or PermaProps.Permissions[Content["Name"]][Content["Data"]] == nil then return end
if !isbool(Content["Val"]) then return end
if Content["Name"] == "superadmin" and ( Content["Data"] == "Custom" or Content["Data"] == "Permissions" or Content["Data"] == "Menu" ) then return end
if !PermaProps.HasPermission( ply, "Permissions") then ply:ChatPrint("Access denied !") return end
PermaProps.Permissions[Content["Name"]][Content["Data"]] = Content["Val"]
PermissionSave()
elseif Content["CMD"] == "DEL_MAP" then
sql.Query( "DELETE FROM permaprops WHERE map = ".. sql.SQLStr(game.GetMap()) .. ";" )
PermaProps.ReloadPermaProps()
ply:ChatPrint("You erased all props from the map !")
elseif Content["CMD"] == "DEL_ALL" then
sql.Query( "DELETE FROM permaprops;" )
PermaProps.ReloadPermaProps()
ply:ChatPrint("You erased all props !")
elseif Content["CMD"] == "CLR_MAP" then
for k, v in pairs( ents.GetAll() ) do
if v.PermaProps == true then
v:Remove()
end
end
ply:ChatPrint("You have removed all props !")
end
end
net.Receive("pp_info_send", pp_info_send)

View File

@@ -0,0 +1,73 @@
/*
____ _ _ ____ __ __ _ _
/ ___|___ __| | ___ __| | | __ ) _ _ | \/ | __ _| | |__ ___ _ __ ___
| | / _ \ / _` |/ _ \/ _` | | _ \| | | | | |\/| |/ _` | | '_ \ / _ \| '__/ _ \
| |__| (_) | (_| | __/ (_| | | |_) | |_| | | | | | (_| | | |_) | (_) | | | (_) |
\____\___/ \__,_|\___|\__,_| |____/ \__, | |_| |_|\__,_|_|_.__/ \___/|_| \___/
|___/
Thanks to ARitz Cracker for this part
*/
function PermaProps.HasPermission( ply, name )
if !PermaProps or !PermaProps.Permissions or !PermaProps.Permissions[ply:GetUserGroup()] then return false end
if PermaProps.Permissions[ply:GetUserGroup()].Custom == false and PermaProps.Permissions[ply:GetUserGroup()].Inherits and PermaProps.Permissions[PermaProps.Permissions[ply:GetUserGroup()].Inherits] then
return PermaProps.Permissions[PermaProps.Permissions[ply:GetUserGroup()].Inherits][name]
end
return PermaProps.Permissions[ply:GetUserGroup()][name]
end
local function PermaPropsPhys( ply, ent, phys )
if ent.PermaProps then
return PermaProps.HasPermission( ply, "Physgun")
end
end
hook.Add("PhysgunPickup", "PermaPropsPhys", PermaPropsPhys)
hook.Add( "CanPlayerUnfreeze", "PermaPropsUnfreeze", PermaPropsPhys) -- Prevents people from pressing RELOAD on the physgun
local function PermaPropsTool( ply, tr, tool )
if IsValid(tr.Entity) then
if tr.Entity.PermaProps then
if tool == "permaprops" then
return true
end
return PermaProps.HasPermission( ply, "Tool")
end
if tr.Entity:GetClass() == "sammyservers_textscreen" and tool == "permaprops" then -- Let people use PermaProps on textscreen
return true
end
end
end
hook.Add( "CanTool", "PermaPropsTool", PermaPropsTool)
local function PermaPropsProperty( ply, property, ent )
if IsValid(ent) and ent.PermaProps and tool ~= "permaprops" then
return PermaProps.HasPermission( ply, "Property")
end
end
hook.Add( "CanProperty", "PermaPropsProperty", PermaPropsProperty)

View File

@@ -0,0 +1,345 @@
/*
____ _ _ ____ __ __ _ _
/ ___|___ __| | ___ __| | | __ ) _ _ | \/ | __ _| | |__ ___ _ __ ___
| | / _ \ / _` |/ _ \/ _` | | _ \| | | | | |\/| |/ _` | | '_ \ / _ \| '__/ _ \
| |__| (_) | (_| | __/ (_| | | |_) | |_| | | | | | (_| | | |_) | (_) | | | (_) |
\____\___/ \__,_|\___|\__,_| |____/ \__, | |_| |_|\__,_|_|_.__/ \___/|_| \___/
|___/
*/
if not PermaProps then PermaProps = {} end
PermaProps.SpecialENTSSpawn = {}
PermaProps.SpecialENTSSpawn["gmod_lamp"] = function( ent, data)
ent:SetFlashlightTexture( data["Texture"] )
ent:SetLightFOV( data["fov"] )
ent:SetColor( Color( data["r"], data["g"], data["b"], 255 ) )
ent:SetDistance( data["distance"] )
ent:SetBrightness( data["brightness"] )
ent:Switch( true )
ent:Spawn()
ent.Texture = data["Texture"]
ent.KeyDown = data["KeyDown"]
ent.fov = data["fov"]
ent.distance = data["distance"]
ent.r = data["r"]
ent.g = data["g"]
ent.b = data["b"]
ent.brightness = data["brightness"]
return true
end
PermaProps.SpecialENTSSpawn["prop_vehicle_jeep"] = function( ent, data)
if ( ent:GetModel() == "models/buggy.mdl" ) then ent:SetKeyValue( "vehiclescript", "scripts/vehicles/jeep_test.txt" ) end
if ( ent:GetModel() == "models/vehicle.mdl" ) then ent:SetKeyValue( "vehiclescript", "scripts/vehicles/jalopy.txt" ) end
if ( data["VehicleTable"] && data["VehicleTable"].KeyValues ) then
for k, v in pairs( data["VehicleTable"].KeyValues ) do
ent:SetKeyValue( k, v )
end
end
ent:Spawn()
ent:Activate()
ent:SetVehicleClass( data["VehicleName"] )
ent.VehicleName = data["VehicleName"]
ent.VehicleTable = data["VehicleTable"]
ent.ClassOverride = data["Class"]
return true
end
PermaProps.SpecialENTSSpawn["prop_vehicle_jeep_old"] = PermaProps.SpecialENTSSpawn["prop_vehicle_jeep"]
PermaProps.SpecialENTSSpawn["prop_vehicle_airboat"] = PermaProps.SpecialENTSSpawn["prop_vehicle_jeep"]
PermaProps.SpecialENTSSpawn["prop_vehicle_prisoner_pod"] = PermaProps.SpecialENTSSpawn["prop_vehicle_jeep"]
PermaProps.SpecialENTSSpawn["prop_ragdoll"] = function( ent, data )
if !data or !istable( data ) then return end
ent:Spawn()
ent:Activate()
if data["Bones"] then
for objectid, objectdata in pairs( data["Bones"] ) do
local Phys = ent:GetPhysicsObjectNum( objectid )
if !IsValid( Phys ) then continue end
if ( isvector( objectdata.Pos ) && isangle( objectdata.Angle ) ) then
local pos, ang = LocalToWorld( objectdata.Pos, objectdata.Angle, Vector(0, 0, 0), Angle(0, 0, 0) )
Phys:SetPos( pos )
Phys:SetAngles( ang )
Phys:Wake()
if objectdata.Frozen then
Phys:EnableMotion( false )
end
end
end
end
if data["BoneManip"] and ent:IsValid() then
for k, v in pairs( data["BoneManip"] ) do
if ( v.s ) then ent:ManipulateBoneScale( k, v.s ) end
if ( v.a ) then ent:ManipulateBoneAngles( k, v.a ) end
if ( v.p ) then ent:ManipulateBonePosition( k, v.p ) end
end
end
if data["Flex"] and ent:IsValid() then
for k, v in pairs( data["Flex"] ) do
ent:SetFlexWeight( k, v )
end
if ( Scale ) then
ent:SetFlexScale( Scale )
end
end
return true
end
PermaProps.SpecialENTSSpawn["sammyservers_textscreen"] = function( ent, data )
if !data or !istable( data ) then return end
ent:Spawn()
ent:Activate()
if data["Lines"] then
for k, v in pairs(data["Lines"] or {}) do
ent:SetLine(k, v.text, Color(v.color.r, v.color.g, v.color.b, v.color.a), v.size, v.font, v.rainbow or 0)
end
end
return true
end
PermaProps.SpecialENTSSpawn["NPC"] = function( ent, data )
if data and istable( data ) then
if data["Equipment"] then
local valid = false
for _, v in pairs( list.Get( "NPCUsableWeapons" ) ) do
if v.class == data["Equipment"] then valid = true break end
end
if ( data["Equipment"] && data["Equipment"] != "none" && valid ) then
ent:SetKeyValue( "additionalequipment", data["Equipment"] )
ent.Equipment = data["Equipment"]
end
end
end
ent:Spawn()
ent:Activate()
return true
end
if list.Get( "NPC" ) and istable(list.Get( "NPC" )) then
for k, v in pairs(list.Get( "NPC" )) do
PermaProps.SpecialENTSSpawn[k] = PermaProps.SpecialENTSSpawn["NPC"]
end
end
PermaProps.SpecialENTSSpawn["item_ammo_crate"] = function( ent, data )
if data and istable(data) and data["type"] then
ent.type = data["type"]
ent:SetKeyValue( "AmmoType", math.Clamp( data["type"], 0, 9 ) )
end
ent:Spawn()
ent:Activate()
return true
end
PermaProps.SpecialENTSSave = {}
PermaProps.SpecialENTSSave["gmod_lamp"] = function( ent )
local content = {}
content.Other = {}
content.Other["Texture"] = ent.Texture
content.Other["KeyDown"] = ent.KeyDown
content.Other["fov"] = ent.fov
content.Other["distance"] = ent.distance
content.Other["r"] = ent.r
content.Other["g"] = ent.g
content.Other["b"] = ent.b
content.Other["brightness"] = ent.brightness
return content
end
PermaProps.SpecialENTSSave["prop_vehicle_jeep"] = function( ent )
if not ent.VehicleTable then return false end
local content = {}
content.Other = {}
content.Other["VehicleName"] = ent.VehicleName
content.Other["VehicleTable"] = ent.VehicleTable
content.Other["ClassOverride"] = ent.ClassOverride
return content
end
PermaProps.SpecialENTSSave["prop_vehicle_jeep_old"] = PermaProps.SpecialENTSSave["prop_vehicle_jeep"]
PermaProps.SpecialENTSSave["prop_vehicle_airboat"] = PermaProps.SpecialENTSSave["prop_vehicle_jeep"]
PermaProps.SpecialENTSSave["prop_vehicle_prisoner_pod"] = PermaProps.SpecialENTSSave["prop_vehicle_jeep"]
PermaProps.SpecialENTSSave["prop_ragdoll"] = function( ent )
local content = {}
content.Other = {}
content.Other["Bones"] = {}
local num = ent:GetPhysicsObjectCount()
for objectid = 0, num - 1 do
local obj = ent:GetPhysicsObjectNum( objectid )
if ( !obj:IsValid() ) then continue end
content.Other["Bones"][ objectid ] = {}
content.Other["Bones"][ objectid ].Pos = obj:GetPos()
content.Other["Bones"][ objectid ].Angle = obj:GetAngles()
content.Other["Bones"][ objectid ].Frozen = !obj:IsMoveable()
if ( obj:IsAsleep() ) then content.Other["Bones"][ objectid ].Sleep = true end
content.Other["Bones"][ objectid ].Pos, content.Other["Bones"][ objectid ].Angle = WorldToLocal( content.Other["Bones"][ objectid ].Pos, content.Other["Bones"][ objectid ].Angle, Vector( 0, 0, 0 ), Angle( 0, 0, 0 ) )
end
if ( ent:HasBoneManipulations() ) then
content.Other["BoneManip"] = {}
for i = 0, ent:GetBoneCount() do
local t = {}
local s = ent:GetManipulateBoneScale( i )
local a = ent:GetManipulateBoneAngles( i )
local p = ent:GetManipulateBonePosition( i )
if ( s != Vector( 1, 1, 1 ) ) then t[ 's' ] = s end -- scale
if ( a != Angle( 0, 0, 0 ) ) then t[ 'a' ] = a end -- angle
if ( p != Vector( 0, 0, 0 ) ) then t[ 'p' ] = p end -- position
if ( table.Count( t ) > 0 ) then
content.Other["BoneManip"][ i ] = t
end
end
end
content.Other["FlexScale"] = ent:GetFlexScale()
for i = 0, ent:GetFlexNum() do
local w = ent:GetFlexWeight( i )
if ( w != 0 ) then
content.Other["Flex"] = content.Other["Flex"] or {}
content.Other["Flex"][ i ] = w
end
end
return content
end
PermaProps.SpecialENTSSave["sammyservers_textscreen"] = function( ent )
local content = {}
content.Other = {}
content.Other["Lines"] = ent.lines or {}
return content
end
PermaProps.SpecialENTSSave["prop_effect"] = function( ent )
local content = {}
content.Class = "pp_prop_effect"
content.Model = ent.AttachedEntity:GetModel()
return content
end
PermaProps.SpecialENTSSave["pp_prop_effect"] = PermaProps.SpecialENTSSave["prop_effect"]
PermaProps.SpecialENTSSave["NPC"] = function( ent )
if !ent.Equipment then return {} end
local content = {}
content.Other = {}
content.Other["Equipment"] = ent.Equipment
return content
end
if list.Get( "NPC" ) and istable(list.Get( "NPC" )) then
for k, v in pairs(list.Get( "NPC" )) do
PermaProps.SpecialENTSSave[k] = PermaProps.SpecialENTSSave["NPC"]
end
end
PermaProps.SpecialENTSSave["item_ammo_crate"] = function( ent )
local content = {}
content.Other = {}
content.Other["type"] = ent.type
return content
end

View File

@@ -0,0 +1,30 @@
/*
____ _ _ ____ __ __ _ _
/ ___|___ __| | ___ __| | | __ ) _ _ | \/ | __ _| | |__ ___ _ __ ___
| | / _ \ / _` |/ _ \/ _` | | _ \| | | | | |\/| |/ _` | | '_ \ / _ \| '__/ _ \
| |__| (_) | (_| | __/ (_| | | |_) | |_| | | | | | (_| | | |_) | (_) | | | (_) |
\____\___/ \__,_|\___|\__,_| |____/ \__, | |_| |_|\__,_|_|_.__/ \___/|_| \___/
|___/
*/
sql.Query("CREATE TABLE IF NOT EXISTS permaprops('id' INTEGER NOT NULL, 'map' TEXT NOT NULL, 'content' TEXT NOT NULL, PRIMARY KEY('id'));")
if not PermaProps then PermaProps = {} end
PermaProps.SQL = {}
/* NOT WORKS AT THE MOMENT
PermaProps.SQL.MySQL = false
PermaProps.SQL.Host = "127.0.0.1"
PermaProps.SQL.Username = "username"
PermaProps.SQL.Password = "password"
PermaProps.SQL.Database_name = "PermaProps"
PermaProps.SQL.Database_port = 3306
PermaProps.SQL.Preferred_module = "mysqloo"
*/
function PermaProps.SQL.Query( data )
return sql.Query( data )
end

View File

@@ -0,0 +1,80 @@
PLUGIN.name = "Build Tools"
PLUGIN.author = "Various (Портирован для Helix)"
PLUGIN.description = "Набор строительных инструментов: AdvDupe2, Permaprops, Precision Tool"
-- Устанавливаем высокий приоритет загрузки, чтобы плагин загрузился раньше инструментов
PLUGIN.priority = 100
-- Конфигурация
ix.config.Add("buildToolsEnabled", true, "Включить строительные инструменты", nil, {
category = "Build Tools"
})
ix.config.Add("buildToolsAdvDupe2", true, "Включить AdvDupe2 (дублирование)", nil, {
category = "Build Tools"
})
ix.config.Add("buildToolsPermaprops", true, "Включить Permaprops (постоянные пропы)", nil, {
category = "Build Tools"
})
ix.config.Add("buildToolsPrecision", true, "Включить Precision Tool (точное позиционирование)", nil, {
category = "Build Tools"
})
ix.config.Add("buildToolsNoCollideWorld", true, "Включить NoCollide World (отключение коллизий с миром)", nil, {
category = "Build Tools"
})
-- Загрузка NetStream (библиотека для сетевых сообщений)
ix.util.Include("netstream.lua")
-- Загрузка AdvDupe2
if ix.config.Get("buildToolsAdvDupe2", true) then
-- Инициализация глобальной таблицы AdvDupe2
AdvDupe2 = AdvDupe2 or {}
print("[Build Tools] Initializing AdvDupe2...")
-- Shared
ix.util.Include("advdupe2/sh_codec_legacy.lua")
ix.util.Include("advdupe2/sh_codec.lua")
-- Server
ix.util.Include("advdupe2/sv_file.lua")
ix.util.Include("advdupe2/sv_ghost.lua")
ix.util.Include("advdupe2/sv_clipboard.lua")
ix.util.Include("advdupe2/sv_misc.lua")
-- Client
ix.util.Include("advdupe2/cl_file.lua")
ix.util.Include("advdupe2/cl_ghost.lua")
ix.util.Include("advdupe2/file_browser.lua")
print("[Build Tools] AdvDupe2 loaded successfully")
end
-- Загрузка Permaprops
if ix.config.Get("buildToolsPermaprops", true) then
-- Server
ix.util.Include("permaprops/sv_lib.lua")
ix.util.Include("permaprops/sv_menu.lua")
ix.util.Include("permaprops/sv_permissions.lua")
ix.util.Include("permaprops/sv_specialfcn.lua")
ix.util.Include("permaprops/sv_sql.lua")
-- Client
ix.util.Include("permaprops/cl_drawent.lua")
ix.util.Include("permaprops/cl_menu.lua")
end
function PLUGIN:Initialize()
print("[Build Tools] Загружены строительные инструменты!")
if ix.config.Get("buildToolsAdvDupe2", true) then
print("[Build Tools] AdvDupe2 активирован")
end
if ix.config.Get("buildToolsPermaprops", true) then
print("[Build Tools] Permaprops активирован")
end
end