diff --git a/lua/advdupe2/cl_ghost.lua b/lua/advdupe2/cl_ghost.lua index a7554de..1d5d5d1 100644 --- a/lua/advdupe2/cl_ghost.lua +++ b/lua/advdupe2/cl_ghost.lua @@ -184,7 +184,18 @@ local function StopGhosting() AdvDupe2.Ghosting = false hook.Remove( "Tick", "AdvDupe2_SpawnGhosts" ) - if not BusyBar then AdvDupe2.RemoveProgressBar() end + if not AdvDupe2.BusyBar then AdvDupe2.RemoveProgressBar() end +end + +local function GetHeadGhostData() + local head = AdvDupe2.GhostToSpawn and AdvDupe2.GhostToSpawn[AdvDupe2.HeadEnt] + if not head or not head.PhysicsObjects or not head.PhysicsObjects[0] then + AdvDupe2.RemoveGhosts() + AdvDupe2.Notify("Invalid ghost parent!", NOTIFY_ERROR) + return + end + + return head, head.PhysicsObjects[0] end local function SpawnGhosts() @@ -196,7 +207,11 @@ local function SpawnGhosts() for i = AdvDupe2.CurrentGhost, finalGhostInFrame do local g = AdvDupe2.GhostToSpawn[i] - if g and i ~= AdvDupe2.HeadEnt then AdvDupe2.GhostEntities[i] = MakeGhostsFromTable( g ) end + if g and i ~= AdvDupe2.HeadEnt then + local ghost_entity = MakeGhostsFromTable( g ) + if not IsValid(ghost_entity) then return end + AdvDupe2.GhostEntities[i] = ghost_entity + end end AdvDupe2.CurrentGhost = finalGhostInFrame + 1 @@ -240,9 +255,12 @@ net.Receive("AdvDupe2_SendGhosts", function(len, ply, len2) 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 + local head, head_phys = GetHeadGhostData() + if not head then return end + AdvDupe2.HeadGhost = MakeGhostsFromTable(head) + if not IsValid(AdvDupe2.HeadGhost) then return end + AdvDupe2.HeadOffset = head_phys.Pos + AdvDupe2.HeadAngle = head_phys.Angle AdvDupe2.GhostEntities[AdvDupe2.HeadEnt] = AdvDupe2.HeadGhost AdvDupe2.TotalGhosts = #AdvDupe2.GhostToSpawn @@ -266,7 +284,10 @@ net.Receive("AdvDupe2_AddGhost", function(len, ply, len2) ghost.PhysicsObjects[k] = {Angle = net.ReadAngle(), Pos = net.ReadVector()} end - AdvDupe2.GhostEntities[AdvDupe2.CurrentGhost] = MakeGhostsFromTable(ghost) + if not AdvDupe2.GhostEntities or not AdvDupe2.CurrentGhost then return end + local ghost_entity = MakeGhostsFromTable(ghost) + if not IsValid(ghost_entity) then return end + AdvDupe2.GhostEntities[AdvDupe2.CurrentGhost] = ghost_entity AdvDupe2.CurrentGhost = AdvDupe2.CurrentGhost + 1 end) @@ -276,7 +297,10 @@ function AdvDupe2.StartGhosting() AdvDupe2.CurrentGhost = 1 AdvDupe2.GhostEntities = {} AdvDupe2.Ghosting = true - AdvDupe2.HeadGhost = MakeGhostsFromTable(AdvDupe2.GhostToSpawn[AdvDupe2.HeadEnt]) + local head = GetHeadGhostData() + if not head then return end + AdvDupe2.HeadGhost = MakeGhostsFromTable(head) + if not IsValid(AdvDupe2.HeadGhost) then return end AdvDupe2.GhostEntities[AdvDupe2.HeadEnt] = AdvDupe2.HeadGhost AdvDupe2.TotalGhosts = #AdvDupe2.GhostToSpawn @@ -322,7 +346,8 @@ function AdvDupe2.UpdateGhosts(force) 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 + originpos = Vector(trace.HitPos) + originpos.z = originpos.z + pz headpos, headang = LocalToWorld(AdvDupe2.HeadOffset, hangle, originpos, originang) end @@ -339,8 +364,8 @@ function AdvDupe2.UpdateGhosts(force) AdvDupe2.HeadGhost:SetPos(headpos) AdvDupe2.HeadGhost:SetAngles(headang) - for k, ghost in ipairs(AdvDupe2.GhostEntities) do - local phys = ghost.Phys + for k, ghost in pairs(AdvDupe2.GhostEntities or {}) do + local phys = IsValid(ghost) and ghost.Phys if phys then local pos, ang = LocalToWorld(phys.Pos, phys.Angle, originpos, originang) diff --git a/lua/advdupe2/sh_codec.lua b/lua/advdupe2/sh_codec.lua index 4e2810c..74e09f9 100644 --- a/lua/advdupe2/sh_codec.lua +++ b/lua/advdupe2/sh_codec.lua @@ -374,7 +374,7 @@ function AdvDupe2.Encode(dupe, info, callback, ...) callback(AD2FF:format(char(REVISION), makeInfo(info), encodedTable),...) end ---seperates the header and body and converts the header to a table +--separates the header and body and converts the header to a table local function getInfo(str) local last = str:find("\2") if not last then @@ -423,22 +423,26 @@ versions[5] = function(encodedDupe) 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 istable(dupe) then return false, "Malformed dupe table" end + info = info or {} + if not istable(dupe.HeadEnt) then return false, "Missing HeadEnt table" end + if not istable(dupe.Entities) then return false, "Missing Entities table" end + if not istable(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 + if not dupe.Entities[dupe.HeadEnt.Index] then return false, "Missing HeadEnt index ["..tostring(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 not istable(data) then return false, "Malformed Entity ["..tostring(key).."]" end + local label = "Entity ["..tostring(key).."]["..tostring(data.Class).."]["..tostring(data.Model).."]" + if not istable(data.PhysicsObjects) then return false, "Missing PhysicsObject table from "..label end + if not istable(data.PhysicsObjects[0]) then return false, "Missing PhysicsObject[0] table from "..label 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 + if not data.PhysicsObjects[0].LocalPos then return false, "Missing PhysicsObject[0].LocalPos from "..label end + if not data.PhysicsObjects[0].LocalAngle then return false, "Missing PhysicsObject[0].LocalAngle from "..label 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 + if not data.PhysicsObjects[0].Pos then return false, "Missing PhysicsObject[0].Pos from "..label end + if not data.PhysicsObjects[0].Angle then return false, "Missing PhysicsObject[0].Angle from "..label end end end return true, dupe @@ -452,6 +456,10 @@ end ]] function AdvDupe2.Decode(encodedDupe) + if not isstring(encodedDupe) then + return false, "Malformed dupe!" + end + local sig, rev = encodedDupe:match("^(....)(.)") if not rev then @@ -533,6 +541,7 @@ if CLIENT then local readData = readFile:Read(readFile:Size()) readFile:Close() local ok, tbl = AdvDupe2.Decode(readData) + if not ok then print("File could not be decoded! ("..tostring(tbl)..")") return end 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)) @@ -550,7 +559,10 @@ if CLIENT then local readData = readFile:Read(readFile:Size()) readFile:Close() - AdvDupe2.Encode(util.JSONToTable(readData), {}, function(data) + local tbl = util.JSONToTable(readData) + if not istable(tbl) then print("File could not be decoded from JSON! ("..readFileName..")") return end + + AdvDupe2.Encode(tbl, {}, 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)