Files
wnsrc/lua/weapons/gmod_tool/stools/advdupe2.lua
lifestorm 6a58f406b1 Upload
2024-08-04 23:54:45 +03:00

1919 lines
60 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[
Title: Adv. Dupe 2 Tool
Desc: Defines the AD2 tool and assorted functionalities.
Author: TB
Version: 1.0
]]
TOOL.Category = "Construction"
TOOL.Name = "#Tool.advdupe2.name"
cleanup.Register( "AdvDupe2" )
require( "controlpanel" )
if(SERVER) then
CreateConVar("sbox_maxgmod_contr_spawners",5)
local phys_constraint_system_types = {
Weld = true,
Rope = true,
Elastic = true,
Slider = true,
Axis = true,
AdvBallsocket = true,
Motor = true,
Pulley = true,
Ballsocket = true,
Winch = true,
Hydraulic = true,
WireMotor = true,
WireHydraulic = true
}
--Orders constraints so that the dupe uses as little constraint systems as possible
local function GroupConstraintOrder( ply, constraints )
--First separate the nocollides, sorted, and unsorted constraints
local sorted, unsorted = {}, {}
for k, v in pairs(constraints) do
if phys_constraint_system_types[v.Type] then
sorted[#sorted+1] = v
else
unsorted[#unsorted+1] = v
end
end
local sortingSystems = {}
local fullSystems = {}
local function buildSystems(input)
while next(input) ~= nil do
for k, v in pairs(input) do
for systemi, system in pairs(sortingSystems) do
for _, target in pairs(system) do
for x = 1, 4 do
if v.Entity[x] then
for y = 1, 4 do
if target.Entity[y] and v.Entity[x].Index == target.Entity[y].Index then
system[#system + 1] = v
if #system == 100 then
fullSystems[#fullSystems + 1] = system
table.remove(sortingSystems, systemi)
end
input[k] = nil
goto super_loopbreak
end
end
end
end
end
end
end
--Normally skipped by the goto unless no cluster is found. If so, make a new one.
local k = next(input)
sortingSystems[#sortingSystems + 1] = {input[k]}
input[k] = nil
::super_loopbreak::
end
end
buildSystems(sorted)
local ret = {}
for _, system in pairs(fullSystems) do
for _, v in pairs(system) do
ret[#ret + 1] = v
end
end
for _, system in pairs(sortingSystems) do
for _, v in pairs(system) do
ret[#ret + 1] = v
end
end
for k, v in pairs(unsorted) do
ret[#ret + 1] = v
end
if #fullSystems ~= 0 then
ply:ChatPrint("DUPLICATOR: WARNING, Number of constraints exceeds 100: (".. #ret .."). Constraint sorting might not work as expected.")
end
return ret
end
local function CreationConstraintOrder( constraints )
local ret = {}
for k, v in pairs( constraints ) do
ret[#ret + 1] = k
end
table.sort(ret)
for i = 1, #ret do
ret[i] = constraints[ret[i]]
end
return ret
end
local function GetSortedConstraints( ply, constraints )
if ply:GetInfo("advdupe2_sort_constraints") ~= "0" then
return GroupConstraintOrder( ply, constraints )
else
return CreationConstraintOrder( constraints )
end
end
local areacopy_classblacklist = {
gmod_anchor = true
}
local function PlayerCanDupeCPPI(ply, ent)
if not AdvDupe2.duplicator.IsCopyable(ent) or areacopy_classblacklist[ent:GetClass()] then return false end
return ent:CPPIGetOwner()==ply
end
-- Code from WireLib.CanTool
local zero = Vector(0, 0, 0)
local norm = Vector(1, 0, 0)
local tr = { ---@type TraceResult
Hit = true, HitNonWorld = true, HitNoDraw = false, HitSky = false, AllSolid = true,
HitNormal = zero, Normal = norm,
Fraction = 1, FractionLeftSolid = 0,
HitBox = 0, HitGroup = 0, HitTexture = "**studio**",
MatType = 0, PhysicsBone = 0, SurfaceProps = 0, DispFlags = 0, Contents = 0,
Entity = NULL, HitPos = zero, StartPos = zero,
}
local function PlayerCanDupeTool(ply, ent)
if not AdvDupe2.duplicator.IsCopyable(ent) or areacopy_classblacklist[ent:GetClass()] then return false end
local pos = ent:GetPos()
tr.Entity, tr.HitPos, tr.StartPos = ent, pos, pos
return hook.Run( "CanTool", ply, tr, "advdupe2" ) ~= false
end
--Find all the entities in a box, given the adjacent corners and the player
local function FindInBox(min, max, ply)
local PPCheck = (tobool(ply:GetInfo("advdupe2_copy_only_mine")) and ply.CPPIGetOwner~=nil) and PlayerCanDupeCPPI or PlayerCanDupeTool
local EntTable = {}
for _, ent in ents.Iterator() do
local pos = ent:GetPos()
if (pos.X>=min.X) and (pos.X<=max.X) and
(pos.Y>=min.Y) and (pos.Y<=max.Y) and
(pos.Z>=min.Z) and (pos.Z<=max.Z) and PPCheck( ply, ent ) then
EntTable[ent:EntIndex()] = ent
end
end
return EntTable
end
--[[
Name: GetDupeAngleOffset
Desc: Retrieves duplication angle offsets from player
Returns: <angle> Created angle
]]
local function GetDupeAngleOffset(ply)
local p = math.Clamp(ply:GetInfoNum("advdupe2_offset_pitch", 0), -180, 180)
local y = math.Clamp(ply:GetInfoNum("advdupe2_offset_yaw" , 0), -180, 180)
local r = math.Clamp(ply:GetInfoNum("advdupe2_offset_roll" , 0), -180, 180)
return Angle(p, y, r)
end
--[[
Name: GetDupeElevation
Desc: Retrieves duplication Z elevation
Returns: <number> Dupe elevation
]]
local function GetDupeElevation(ply)
local con = ply:GetInfoNum("advdupe2_offset_z", 0)
local enz = (tonumber(ply.AdvDupe2.HeadEnt.Z) or 0)
return math.Clamp(con + enz, -32000, 32000)
end
--[[
Name: LeftClick
Desc: Defines the tool's behavior when the player left-clicks.
Params: <trace> trace
Returns: <boolean> success
]]
function TOOL:LeftClick( trace )
if(not trace) then return false end
local ply = self:GetOwner()
local dupe = ply.AdvDupe2
if not (dupe and dupe.Entities) then return false end
if(dupe.Pasting or dupe.Downloading) then
AdvDupe2.Notify(ply,"Advanced Duplicator 2 is busy.",NOTIFY_ERROR)
return false
end
dupe.Angle = GetDupeAngleOffset(ply)
dupe.Position = Vector(trace.HitPos)
dupe.Position.z = dupe.Position.z + GetDupeElevation(ply)
if(tobool(ply:GetInfo("advdupe2_offset_world"))) then
dupe.Angle = dupe.Angle - dupe.Entities[dupe.HeadEnt.Index].PhysicsObjects[0].Angle
end
dupe.Pasting = true
AdvDupe2.Notify(ply,"Pasting...")
local origin
if(tobool(ply:GetInfo("advdupe2_original_origin"))) then
origin = dupe.HeadEnt.Pos
end
AdvDupe2.InitPastingQueue(ply, dupe.Position, dupe.Angle, origin,
tobool(ply:GetInfo("advdupe2_paste_constraints")),
tobool(ply:GetInfo("advdupe2_paste_parents")),
tobool(ply:GetInfo("advdupe2_paste_disparents")),
tobool(ply:GetInfo("advdupe2_paste_protectoveride")))
return true
end
--[[
Name: RightClick
Desc: Defines the tool's behavior when the player right-clicks.
Params: <trace> trace
Returns: <boolean> success
]]
function TOOL:RightClick( trace )
local ply = self:GetOwner()
local dupe = ply.AdvDupe2
if not dupe then dupe = {}; ply.AdvDupe2 = dupe end
if(dupe.Pasting or dupe.Downloading) then
AdvDupe2.Notify(ply,"Advanced Duplicator 2 is busy.", NOTIFY_ERROR)
return false
end
--Set Area Copy on or off
if( ply:KeyDown(IN_SPEED) and not ply:KeyDown(IN_WALK) ) then
if(self:GetStage()==0) then
AdvDupe2.DrawSelectBox(ply)
self:SetStage(1)
return false
elseif(self:GetStage()==1) then
AdvDupe2.RemoveSelectBox(ply)
self:SetStage(0)
return false
end
end
if(not trace or not trace.Hit) then return false end
local Entities, Constraints, AddOne
local HeadEnt = {}
--If area copy is on
if(self:GetStage()==1) then
local area_size = math.Clamp(tonumber(ply:GetInfo("advdupe2_area_copy_size")) or 50, 0, 30720)
local Pos = trace.HitNonWorld and trace.Entity:GetPos() or trace.HitPos
local T = (Vector(area_size,area_size,area_size)+Pos)
local B = (Vector(-area_size,-area_size,-area_size)+Pos)
local Ents = FindInBox(B,T, ply)
local _, Ent = next(Ents)
if not Ent then
self:SetStage(0)
AdvDupe2.RemoveSelectBox(ply)
return true
end
Ent = trace.HitNonWorld and trace.Entity or Ent
HeadEnt.Index = Ent:EntIndex()
HeadEnt.Pos = Ent:GetPos()
Entities, Constraints = AdvDupe2.duplicator.AreaCopy(ply, Ents, HeadEnt.Pos, tobool(ply:GetInfo("advdupe2_copy_outside")))
self:SetStage(0)
AdvDupe2.RemoveSelectBox(ply)
elseif trace.HitNonWorld then --Area Copy is off
-- Filter duplicator blocked entities out.
if not AdvDupe2.duplicator.IsCopyable( trace.Entity ) then
return false
end
--If Alt is being held, add a prop to the dupe
if(ply:KeyDown(IN_WALK) and dupe.Entities~=nil and next(dupe.Entities)~=nil) then
Entities = dupe.Entities
Constraints = dupe.Constraints
HeadEnt = dupe.HeadEnt
AdvDupe2.duplicator.Copy( ply, trace.Entity, Entities, Constraints, HeadEnt.Pos)
--Only add the one ghost
AddOne = Entities[trace.Entity:EntIndex()]
else
Entities = {}
Constraints = {}
HeadEnt.Index = trace.Entity:EntIndex()
HeadEnt.Pos = trace.HitPos
AdvDupe2.duplicator.Copy( ply, trace.Entity, Entities, Constraints, trace.HitPos )
end
else --Non valid entity or clicked the world
if dupe.Entities then
--clear the dupe
net.Start("AdvDupe2_RemoveGhosts")
net.Send(ply)
dupe.Entities = nil
dupe.Constraints = nil
net.Start("AdvDupe2_ResetDupeInfo")
net.Send(ply)
AdvDupe2.ResetOffsets(ply)
return true
else
--select all owned props
Entities = {}
local PPCheck = (tobool(ply:GetInfo("advdupe2_copy_only_mine")) and CPPI~=nil) and PlayerCanDupeCPPI or PlayerCanDupeTool
for _, ent in ents.Iterator() do
if PPCheck( ply, ent ) then
Entities[ent:EntIndex()] = ent
end
end
local _, Ent = next(Entities)
if not Ent then
net.Start("AdvDupe2_RemoveGhosts")
net.Send(ply)
return true
end
HeadEnt.Index = Ent:EntIndex()
HeadEnt.Pos = Ent:GetPos()
Entities, Constraints = AdvDupe2.duplicator.AreaCopy(ply, Entities, HeadEnt.Pos, tobool(ply:GetInfo("advdupe2_copy_outside")))
end
end
if not HeadEnt.Z then
local WorldTrace = util.TraceLine({
mask = MASK_NPCWORLDSTATIC,
start = HeadEnt.Pos + Vector(0,0,1),
endpos = HeadEnt.Pos-Vector(0,0,50000)
})
HeadEnt.Z = WorldTrace.Hit and math.abs(HeadEnt.Pos.Z - WorldTrace.HitPos.Z) or 0
end
dupe.HeadEnt = HeadEnt
dupe.Entities = Entities
dupe.Constraints = GetSortedConstraints(ply, Constraints)
dupe.Revision = AdvDupe2.CodecRevision
net.Start("AdvDupe2_SetDupeInfo")
net.WriteString("")
net.WriteString(ply:Nick())
net.WriteString(os.date("%d %B %Y"))
net.WriteString(os.date("%I:%M %p"))
net.WriteString("")
net.WriteString("")
net.WriteString(table.Count(dupe.Entities))
net.WriteString(#dupe.Constraints)
net.Send(ply)
if AddOne then
AdvDupe2.SendGhost(ply, AddOne)
else
AdvDupe2.SendGhosts(ply)
end
AdvDupe2.ResetOffsets(ply)
return true
end
--Checks table, re-draws loading bar, and recreates ghosts when tool is pulled out
function TOOL:Deploy()
local ply = self:GetOwner()
local dupe = ply.AdvDupe2
if not dupe then dupe = {}; ply.AdvDupe2 = dupe end
if(not dupe.Entities) then return end
net.Start("AdvDupe2_StartGhosting")
net.Send(ply)
if(dupe.Queued) then
AdvDupe2.InitProgressBar(ply, "Queued: ")
return
end
if(dupe.Pasting) then
AdvDupe2.InitProgressBar(ply, "Pasting: ")
return
else
if(dupe.Uploading) then
AdvDupe2.InitProgressBar(ply, "Opening: ")
return
elseif(dupe.Downloading) then
AdvDupe2.InitProgressBar(ply, "Saving: ")
return
end
end
end
--Removes progress bar
function TOOL:Holster()
AdvDupe2.RemoveProgressBar(self:GetOwner())
end
--[[
Name: Reload
Desc: Creates an Advance Contraption Spawner.
Params: <trace> trace
Returns: <boolean> success
]]
function TOOL:Reload( trace )
if(not trace.Hit) then return false end
local ply = self:GetOwner()
local dupe = ply.AdvDupe2
if not dupe then dupe = {}; ply.AdvDupe2 = dupe end
if(self:GetStage()==1) then
local areasize = math.Clamp(tonumber(ply:GetInfo("advdupe2_area_copy_size")) or 50, 0, 30720)
net.Start("AdvDupe2_CanAutoSave")
net.WriteVector(trace.HitPos)
net.WriteFloat(areasize)
if(trace.Entity) then
net.WriteUInt(trace.Entity:EntIndex(), 16)
else
net.WriteUInt(0, 16)
end
net.Send(ply)
self:SetStage(0)
AdvDupe2.RemoveSelectBox(ply)
dupe.TempAutoSavePos = trace.HitPos
dupe.TempAutoSaveSize = areasize
dupe.TempAutoSaveOutSide = tobool(ply:GetInfo("advdupe2_copy_outside"))
return true
end
--If a contraption spawner was clicked then update it with the current settings
if(trace.Entity:GetClass()=="gmod_contr_spawner") then
local delay = tonumber(ply:GetInfo("advdupe2_contr_spawner_delay"))
local undo_delay = tonumber(ply:GetInfo("advdupe2_contr_spawner_undo_delay"))
local min
local max
if(not delay) then
delay = tonumber(GetConVarString("AdvDupe2_MinContraptionSpawnDelay")) or 0.2
else
if(not game.SinglePlayer()) then
min = tonumber(GetConVarString("AdvDupe2_MinContraptionSpawnDelay")) or 0.2
if (delay < min) then
delay = min
end
elseif(delay<0) then
delay = 0
end
end
if(not undo_delay) then
undo_delay = tonumber(GetConVarString("AdvDupe2_MinContraptionUndoDelay"))
else
if(not game.SinglePlayer()) then
min = tonumber(GetConVarString("AdvDupe2_MinContraptionUndoDelay")) or 0.1
max = tonumber(GetConVarString("AdvDupe2_MaxContraptionUndoDelay")) or 60
if(undo_delay < min) then
undo_delay = min
elseif(undo_delay > max) then
undo_delay = max
end
elseif(undo_delay < 0) then
undo_delay = 0
end
end
trace.Entity:GetTable():SetOptions(
ply, delay, undo_delay,
tonumber(ply:GetInfo("advdupe2_contr_spawner_key")),
tonumber(ply:GetInfo("advdupe2_contr_spawner_undo_key")),
tonumber(ply:GetInfo("advdupe2_contr_spawner_disgrav")) or 0,
tonumber(ply:GetInfo("advdupe2_contr_spawner_disdrag")) or 0,
tonumber(ply:GetInfo("advdupe2_contr_spawner_addvel")) or 1 )
return true
end
--Create a contraption spawner
if dupe and dupe.Entities then
local headent = dupe.Entities[dupe.HeadEnt.Index]
local Pos, Ang
if(headent) then
if(tobool(ply:GetInfo("advdupe2_original_origin"))) then
Pos = dupe.HeadEnt.Pos + headent.PhysicsObjects[0].Pos
Ang = headent.PhysicsObjects[0].Angle
else
local EntAngle = headent.PhysicsObjects[0].Angle
if(tobool(ply:GetInfo("advdupe2_offset_world"))) then EntAngle = Angle(0,0,0) end
trace.HitPos.Z = trace.HitPos.Z + GetDupeElevation(ply)
Pos, Ang = LocalToWorld(headent.PhysicsObjects[0].Pos, EntAngle, trace.HitPos, GetDupeAngleOffset(ply))
end
else
AdvDupe2.Notify(ply, "Invalid head entity to spawn contraption spawner.")
return false
end
if(headent.Class=="gmod_contr_spawner") then
AdvDupe2.Notify(ply, "Cannot make a contraption spawner from a contraption spawner.")
return false
end
local spawner = MakeContraptionSpawner(
ply, Pos, Ang, dupe.HeadEnt.Index,
table.Copy(dupe.Entities),
table.Copy(dupe.Constraints),
tonumber(ply:GetInfo("advdupe2_contr_spawner_delay")),
tonumber(ply:GetInfo("advdupe2_contr_spawner_undo_delay")), headent.Model,
tonumber(ply:GetInfo("advdupe2_contr_spawner_key")),
tonumber(ply:GetInfo("advdupe2_contr_spawner_undo_key")),
tonumber(ply:GetInfo("advdupe2_contr_spawner_disgrav")) or 0,
tonumber(ply:GetInfo("advdupe2_contr_spawner_disdrag")) or 0,
tonumber(ply:GetInfo("advdupe2_contr_spawner_addvel")) or 1,
tonumber(ply:GetInfo("advdupe2_contr_spawner_hideprops")) or 0)
ply:AddCleanup( "AdvDupe2", spawner )
undo.Create("gmod_contr_spawner")
undo.AddEntity( spawner )
undo.SetPlayer( ply )
undo.Finish()
return true
end
end
--Called to clean up the tool when pasting is finished or undo during pasting
function AdvDupe2.FinishPasting(Player, Paste)
Player.AdvDupe2.Pasting=false
AdvDupe2.RemoveProgressBar(Player)
if(Paste) then AdvDupe2.Notify(Player,"Finished Pasting!") end
end
--function for creating a contraption spawner
function MakeContraptionSpawner( ply, Pos, Ang, HeadEnt, EntityTable, ConstraintTable, delay, undo_delay, model, key, undo_key, disgrav, disdrag, addvel, hideprops)
if not ply:CheckLimit("gmod_contr_spawners") then return nil end
if(not game.SinglePlayer()) then
if(table.Count(EntityTable)>tonumber(GetConVarString("AdvDupe2_MaxContraptionEntities"))) then
AdvDupe2.Notify(ply,"Contraption Spawner exceeds the maximum amount of "..GetConVarString("AdvDupe2_MaxContraptionEntities").." entities for a spawner!",NOTIFY_ERROR)
return false
end
if(#ConstraintTable>tonumber(GetConVarString("AdvDupe2_MaxContraptionConstraints"))) then
AdvDupe2.Notify(ply,"Contraption Spawner exceeds the maximum amount of "..GetConVarString("AdvDupe2_MaxContraptionConstraints").." constraints for a spawner!",NOTIFY_ERROR)
return false
end
end
local spawner = ents.Create("gmod_contr_spawner")
if not IsValid(spawner) then return end
spawner:SetPos(Pos)
spawner:SetAngles(Ang)
spawner:SetModel(model)
spawner:SetRenderMode(RENDERMODE_TRANSALPHA)
spawner:SetCreator(ply)
spawner:Spawn()
duplicator.ApplyEntityModifiers(ply, spawner)
if IsValid(spawner:GetPhysicsObject()) then
spawner:GetPhysicsObject():EnableMotion(false)
end
local min
local max
if(not delay) then
delay = tonumber(GetConVarString("AdvDupe2_MinContraptionSpawnDelay")) or 0.2
else
if(not game.SinglePlayer()) then
min = tonumber(GetConVarString("AdvDupe2_MinContraptionSpawnDelay")) or 0.2
if (delay < min) then
delay = min
end
elseif(delay<0) then
delay = 0
end
end
if(not undo_delay) then
undo_delay = tonumber(GetConVarString("AdvDupe2_MinContraptionUndoDelay"))
else
if(not game.SinglePlayer()) then
min = tonumber(GetConVarString("AdvDupe2_MinContraptionUndoDelay")) or 0.1
max = tonumber(GetConVarString("AdvDupe2_MaxContraptionUndoDelay")) or 60
if(undo_delay < min) then
undo_delay = min
elseif(undo_delay > max) then
undo_delay = max
end
elseif(undo_delay < 0) then
undo_delay = 0
end
end
-- Set options
spawner:SetPlayer(ply)
spawner:GetTable():SetOptions(ply, delay, undo_delay, key, undo_key, disgrav, disdrag, addvel, hideprops)
local tbl = {
ply = ply,
delay = delay,
undo_delay = undo_delay,
disgrav = disgrav,
disdrag = disdrag,
addvel = addvel,
hideprops = hideprops
}
table.Merge(spawner:GetTable(), tbl)
spawner:SetDupeInfo(HeadEnt, EntityTable, ConstraintTable)
spawner:AddGhosts(ply)
ply:AddCount("gmod_contr_spawners", spawner)
ply:AddCleanup("gmod_contr_spawner", spawner)
return spawner
end
duplicator.RegisterEntityClass("gmod_contr_spawner", MakeContraptionSpawner,
"Pos", "Ang", "HeadEnt", "EntityTable", "ConstraintTable", "delay",
"undo_delay", "model", "key", "undo_key", "disgrav", "disdrag", "addvel", "hideprops")
function AdvDupe2.InitProgressBar(ply,label)
net.Start("AdvDupe2_InitProgressBar")
net.WriteString(label)
net.Send(ply)
end
function AdvDupe2.DrawSelectBox(ply)
net.Start("AdvDupe2_DrawSelectBox")
net.Send(ply)
end
function AdvDupe2.RemoveSelectBox(ply)
net.Start("AdvDupe2_RemoveSelectBox")
net.Send(ply)
end
function AdvDupe2.UpdateProgressBar(ply,percent)
net.Start("AdvDupe2_UpdateProgressBar")
net.WriteFloat(percent)
net.Send(ply)
end
function AdvDupe2.RemoveProgressBar(ply)
net.Start("AdvDupe2_RemoveProgressBar")
net.Send(ply)
end
--Reset the offsets of height, pitch, yaw, and roll back to default
function AdvDupe2.ResetOffsets(ply, keep)
if(not keep) then
ply.AdvDupe2.Name = nil
end
net.Start("AdvDupe2_ResetOffsets")
net.Send(ply)
end
net.Receive("AdvDupe2_CanAutoSave", function(len, ply, len2)
local desc = net.ReadString()
local ent = net.ReadInt(16)
local dupe = ply.AdvDupe2
if(ent~=0) then
dupe.AutoSaveEnt = ent
if(ply:GetInfo("advdupe2_auto_save_contraption")=="1") then
dupe.AutoSaveEnt = ents.GetByIndex( dupe.AutoSaveEnt )
end
else
if(ply:GetInfo("advdupe2_auto_save_contraption")=="1") then
AdvDupe2.Notify(ply, "No entity selected to auto save contraption.", NOTIFY_ERROR)
return
end
dupe.AutoSaveEnt = nil
end
dupe.AutoSavePos = dupe.TempAutoSavePos
dupe.AutoSaveSize = dupe.TempAutoSaveSize
dupe.AutoSaveOutSide = dupe.TempAutoSaveOutSide
dupe.AutoSaveContr = ply:GetInfo("advdupe2_auto_save_contraption")=="1"
dupe.AutoSaveDesc = desc
local time = math.Clamp(tonumber(ply:GetInfo("advdupe2_auto_save_time")) or 2, 2, 30)
if(game.SinglePlayer()) then
dupe.AutoSavePath = net.ReadString()
end
AdvDupe2.Notify(ply, "Your area will be auto saved every "..(time*60).." seconds.")
local name = "AdvDupe2_AutoSave_"..ply:UniqueID()
if(timer.Exists(name)) then
timer.Adjust(name, time*60, 0)
return
end
timer.Create(name, time*60, 0, function()
if(not IsValid(ply)) then
timer.Remove(name)
return
end
local dupe = ply.AdvDupe2
if(dupe.Downloading) then
AdvDupe2.Notify(ply, "Skipping auto save, tool is busy.", NOTIFY_ERROR)
return
end
local Tab = {Entities={}, Constraints={}, HeadEnt={}}
if(dupe.AutoSaveContr) then
if(not IsValid(dupe.AutoSaveEnt)) then
timer.Remove(name)
AdvDupe2.Notify(ply, "Head entity for auto save no longer valid; stopping auto save.", NOTIFY_ERROR)
return
end
Tab.HeadEnt.Index = dupe.AutoSaveEnt:EntIndex()
Tab.HeadEnt.Pos = dupe.AutoSaveEnt:GetPos()
local WorldTrace = util.TraceLine({
mask = MASK_NPCWORLDSTATIC,
start = Tab.HeadEnt.Pos + Vector(0,0,1),
endpos = Tab.HeadEnt.Pos - Vector(0,0,50000)
})
Tab.HeadEnt.Z = WorldTrace.Hit and math.abs(Tab.HeadEnt.Pos.Z - WorldTrace.HitPos.Z) or 0
AdvDupe2.duplicator.Copy( ply, dupe.AutoSaveEnt, Tab.Entities, Tab.Constraints, Tab.HeadEnt.Pos )
else
local i = dupe.AutoSaveSize
local Pos = dupe.AutoSavePos
local T = Vector( i, i, i); T:Add(Pos)
local B = Vector(-i,-i,-i); B:Add(Pos)
local Entities = FindInBox(B,T, ply)
local _, HeadEnt = next(Entities)
if not HeadEnt then
AdvDupe2.Notify(ply, "Area Auto Save copied 0 entities; be sure to turn it off.", NOTIFY_ERROR)
return
end
if(dupe.AutoSaveEnt and Entities[dupe.AutoSaveEnt]) then
Tab.HeadEnt.Index = dupe.AutoSaveEnt
else
Tab.HeadEnt.Index = HeadEnt:EntIndex()
end
Tab.HeadEnt.Pos = HeadEnt:GetPos()
local WorldTrace = util.TraceLine({
mask = MASK_NPCWORLDSTATIC,
start = Tab.HeadEnt.Pos + Vector(0,0,1),
endpos = Tab.HeadEnt.Pos - Vector(0,0,50000)
})
Tab.HeadEnt.Z = WorldTrace.Hit and math.abs(Tab.HeadEnt.Pos.Z - WorldTrace.HitPos.Z) or 0
Tab.Entities, Tab.Constraints = AdvDupe2.duplicator.AreaCopy(ply, Entities, Tab.HeadEnt.Pos, dupe.AutoSaveOutSide)
end
Tab.Constraints = GetSortedConstraints(ply, Tab.Constraints)
Tab.Description = dupe.AutoSaveDesc
AdvDupe2.Encode( Tab, AdvDupe2.GenerateDupeStamp(ply), function(data)
AdvDupe2.SendToClient(ply, data, 1)
end)
dupe.FileMod = CurTime()+tonumber(GetConVarString("AdvDupe2_FileModificationDelay"))
end)
timer.Start(name)
end)
concommand.Add("AdvDupe2_SetStage", function(ply, cmd, args)
ply:GetTool("advdupe2"):SetStage(1)
end)
concommand.Add("AdvDupe2_RemoveAutoSave", function(ply, cmd, args)
timer.Remove("AdvDupe2_AutoSave_"..ply:UniqueID())
end)
concommand.Add("AdvDupe2_SaveMap", function(ply, cmd, args)
if(not ply:IsAdmin()) then
AdvDupe2.Notify(ply, "You do not have permission to this function.", NOTIFY_ERROR)
return
end
local Entities = {}
for _, v in ents.Iterator() do
if not v:CreatedByMap() and AdvDupe2.duplicator.IsCopyable(v) then
Entities[v:EntIndex()] = v
end
end
local _, HeadEnt = next(Entities)
if not HeadEnt then return end
local Tab = {Entities={}, Constraints={}, HeadEnt={}, Description=""}
Tab.HeadEnt.Index = HeadEnt:EntIndex()
Tab.HeadEnt.Pos = HeadEnt:GetPos()
local WorldTrace = util.TraceLine({
mask = MASK_NPCWORLDSTATIC,
start = Tab.HeadEnt.Pos + Vector(0,0,1),
endpos = Tab.HeadEnt.Pos - Vector(0,0,50000)
})
Tab.HeadEnt.Z = WorldTrace.Hit and math.abs(Tab.HeadEnt.Pos.Z - WorldTrace.HitPos.Z) or 0
Tab.Entities, Tab.Constraints = AdvDupe2.duplicator.AreaCopy(ply, Entities, Tab.HeadEnt.Pos, true)
Tab.Constraints = GetSortedConstraints(ply, Tab.Constraints)
Tab.Map = true
AdvDupe2.Encode( Tab, AdvDupe2.GenerateDupeStamp(ply), function(data)
if #data > AdvDupe2.MaxDupeSize then
AdvDupe2.Notify(ply, "Copied duplicator filesize is too big!",NOTIFY_ERROR)
return
end
if(not file.IsDir("advdupe2_maps", "DATA")) then
file.CreateDir("advdupe2_maps")
end
file.Write("advdupe2_maps/"..args[1]..".txt", data)
AdvDupe2.Notify(ply, "Map save, saved successfully.")
end)
end)
end
if(CLIENT) then
function TOOL:LeftClick(trace)
if(trace and AdvDupe2.HeadGhost) then
return true
end
return false
end
function TOOL:RightClick(trace)
if( self:GetOwner():KeyDown(IN_SPEED) and not self:GetOwner():KeyDown(IN_WALK) ) then
return false
end
return true
end
--Removes progress bar and removes ghosts when tool is put away
function TOOL:ReleaseGhostEntity()
AdvDupe2.RemoveGhosts()
AdvDupe2.RemoveSelectBox()
if(AdvDupe2.Rotation) then
hook.Remove("PlayerBindPress", "AdvDupe2_BindPress")
hook.Remove("CreateMove", "AdvDupe2_MouseControl")
end
return
end
function TOOL:Reload( trace )
if(trace and (AdvDupe2.HeadGhost or self:GetStage() == 1)) then
return true
end
return false
end
--Take control of the mouse wheel bind so the player can modify the height of the dupe
local function MouseWheelScrolled(ply, bind, pressed)
if(bind == "invprev") then
if(ply:GetTool("advdupe2"):GetStage() == 1) then
local size = math.min(tonumber(ply:GetInfo("advdupe2_area_copy_size")) + 25, 30720)
RunConsoleCommand("advdupe2_area_copy_size",size)
else
local Z = tonumber(ply:GetInfo("advdupe2_offset_z")) + 5
RunConsoleCommand("advdupe2_offset_z",Z)
end
return true
elseif(bind == "invnext") then
if(ply:GetTool("advdupe2"):GetStage() == 1) then
local size = math.max(tonumber(ply:GetInfo("advdupe2_area_copy_size")) - 25, 25)
RunConsoleCommand("advdupe2_area_copy_size",size)
else
local Z = tonumber(ply:GetInfo("advdupe2_offset_z")) - 5
RunConsoleCommand("advdupe2_offset_z",Z)
end
return true
end
GAMEMODE:PlayerBindPress(ply, bind, pressed)
end
local YawTo = 0
local BsAng = Angle()
local function GetRotationSign(ply)
local VY = tonumber(ply:GetInfo("advdupe2_offset_yaw")) or 0
BsAng:Zero(); BsAng:RotateAroundAxis(BsAng:Up(), VY)
local PR = ply:GetRight()
local DP = BsAng:Right():Dot(PR)
local DR = BsAng:Forward():Dot(PR)
if(math.abs(DR) > math.abs(DP)) then -- Roll priority
if(DR >= 0) then return -1, 1 else return 1, -1 end
else -- Pitch axis takes priority. Normal X-Y map
if(DP >= 0) then return 1, 1 else return -1, -1 end
end
end
local function MouseControl( cmd )
local ply = LocalPlayer()
local X = cmd:GetMouseX() / 20
local Y = -cmd:GetMouseY() / 20
local ru = ply:KeyDown(IN_SPEED)
local mm = input.IsMouseDown(MOUSE_MIDDLE)
if(mm) then
if(ru) then
YawTo = 0 -- Reset total integrated yaw
RunConsoleCommand("advdupe2_offset_pitch", 0)
RunConsoleCommand("advdupe2_offset_yaw" , 0)
RunConsoleCommand("advdupe2_offset_roll" , 0)
else
if(Y ~= 0) then
local VR = tonumber(ply:GetInfo("advdupe2_offset_roll")) or 0
local VP = tonumber(ply:GetInfo("advdupe2_offset_pitch")) or 0
local SP, SR, P, R = GetRotationSign(ply)
if(SP ~= SR) then
P = math.NormalizeAngle(VP + X * SR)
R = math.NormalizeAngle(VR + Y * SP)
else
P = math.NormalizeAngle(VP + Y * SP)
R = math.NormalizeAngle(VR + X * SR)
end
RunConsoleCommand("advdupe2_offset_pitch", P)
RunConsoleCommand("advdupe2_offset_roll" , R)
end
end
else
if(X ~= 0) then
VY = tonumber(ply:GetInfo("advdupe2_offset_yaw")) or 0
if(ru) then
YawTo = YawTo + X -- Integrate the mouse on the X value from the mouse
RunConsoleCommand("advdupe2_offset_yaw", math.SnapTo(math.NormalizeAngle(YawTo), 45))
else
YawTo = VY + X -- Update the last yaw with the current value from the mouse
RunConsoleCommand("advdupe2_offset_yaw", math.NormalizeAngle(YawTo))
end
end
end
end
--Checks binds to modify dupes position and angles
function TOOL:Think()
if AdvDupe2.HeadGhost then
AdvDupe2.UpdateGhosts()
end
if(LocalPlayer():KeyDown(IN_USE)) then
if(not AdvDupe2.Rotation) then
hook.Add("PlayerBindPress", "AdvDupe2_BindPress", MouseWheelScrolled)
hook.Add("CreateMove", "AdvDupe2_MouseControl", MouseControl)
AdvDupe2.Rotation = true
end
else
if(AdvDupe2.Rotation) then
AdvDupe2.Rotation = false
hook.Remove("PlayerBindPress", "AdvDupe2_BindPress")
hook.Remove("CreateMove", "AdvDupe2_MouseControl")
end
end
end
--Hinder the player from looking to modify offsets with the mouse
function TOOL:FreezeMovement()
return AdvDupe2.Rotation
end
language.Add( "Tool.advdupe2.name", "Advanced Duplicator 2" )
language.Add( "Tool.advdupe2.desc", "Duplicate things." )
language.Add( "Tool.advdupe2.0", "Primary: Paste, Secondary: Copy, Secondary+World: Select/Deselect All, Secondary+Shift: Area copy." )
language.Add( "Tool.advdupe2.1", "Primary: Paste, Secondary: Copy an area, Reload: Autosave an area, Secondary+Shift: Cancel." )
language.Add( "Undone_AdvDupe2", "Undone AdvDupe2 paste" )
language.Add( "Cleanup_AdvDupe2", "AdvDupe2 Duplications" )
language.Add( "Cleaned_AdvDupe2", "Cleaned up all AdvDupe2 Duplications" )
language.Add( "SBoxLimit_AdvDupe2", "You've reached the AdvDupe2 Duplicator limit!" )
CreateClientConVar("advdupe2_offset_world", 0, false, true)
CreateClientConVar("advdupe2_offset_z", 0, false, true)
CreateClientConVar("advdupe2_offset_pitch", 0, false, true)
CreateClientConVar("advdupe2_offset_yaw", 0, false, true)
CreateClientConVar("advdupe2_offset_roll", 0, false, true)
CreateClientConVar("advdupe2_original_origin", 0, false, true)
CreateClientConVar("advdupe2_paste_constraints", 1, false, true)
CreateClientConVar("advdupe2_sort_constraints", 1, true, true)
CreateClientConVar("advdupe2_paste_parents", 1, false, true)
CreateClientConVar("advdupe2_paste_unfreeze", 0, false, true)
CreateClientConVar("advdupe2_preserve_freeze", 0, false, true)
CreateClientConVar("advdupe2_copy_outside", 0, false, true)
CreateClientConVar("advdupe2_copy_only_mine", 1, false, true)
CreateClientConVar("advdupe2_limit_ghost", 100, false, true)
CreateClientConVar("advdupe2_area_copy_size", 300, false, true)
CreateClientConVar("advdupe2_auto_save_contraption", 0, false, true)
CreateClientConVar("advdupe2_auto_save_overwrite", 1, false, true)
CreateClientConVar("advdupe2_auto_save_time", 2, false, true)
--Contraption Spawner
CreateClientConVar("advdupe2_contr_spawner_key", -1, false, true)
CreateClientConVar("advdupe2_contr_spawner_undo_key", -1, false, true)
CreateClientConVar("advdupe2_contr_spawner_delay", 0, false, true)
CreateClientConVar("advdupe2_contr_spawner_undo_delay", 10, false, true)
CreateClientConVar("advdupe2_contr_spawner_disgrav", 0, false, true)
CreateClientConVar("advdupe2_contr_spawner_disdrag", 0, false, true)
CreateClientConVar("advdupe2_contr_spawner_addvel", 1, false, true)
CreateClientConVar("advdupe2_contr_spawner_hideprops", 0, false, true)
--Experimental
CreateClientConVar("advdupe2_paste_disparents", 0, false, true)
CreateClientConVar("advdupe2_paste_protectoveride", 1, false, true)
CreateClientConVar("advdupe2_debug_openfile", 1, false, true)
local function BuildCPanel(CPanel)
CPanel:ClearControls()
local FileBrowser = vgui.Create("advdupe2_browser")
CPanel:AddItem(FileBrowser)
FileBrowser:SetSize(CPanel:GetWide(), 405)
AdvDupe2.FileBrowser = FileBrowser
local Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Paste at original position" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_original_origin" )
Check:SetValue( 0 )
Check:SetToolTip("Paste at the position originally copied")
CPanel:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Paste with constraints" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_paste_constraints" )
Check:SetValue( 1 )
Check:SetToolTip("Paste with or without constraints")
CPanel:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Paste with parenting" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_paste_parents" )
Check:SetValue( 1 )
Check:SetToolTip("Paste with or without parenting")
CPanel:AddItem(Check)
local Check_1 = vgui.Create("DCheckBoxLabel")
local Check_2 = vgui.Create("DCheckBoxLabel")
Check_1:SetText( "Unfreeze all after paste" )
Check_1:SetDark(true)
Check_1:SetConVar( "advdupe2_paste_unfreeze" )
Check_1:SetValue( 0 )
Check_1.OnChange = function()
if(Check_1:GetChecked() and Check_2:GetChecked()) then
Check_2:SetValue(0)
end
end
Check_1:SetToolTip("Unfreeze all props after pasting")
CPanel:AddItem(Check_1)
Check_2:SetText( "Preserve frozen state after paste" )
Check_2:SetDark(true)
Check_2:SetConVar( "advdupe2_preserve_freeze" )
Check_2:SetValue( 0 )
Check_2.OnChange = function()
if(Check_2:GetChecked() and Check_1:GetChecked()) then
Check_1:SetValue(0)
end
end
Check_2:SetToolTip("Makes props have the same frozen state as when they were copied")
CPanel:AddItem(Check_2)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Area copy constrained props outside of box" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_copy_outside" )
Check:SetValue( 0 )
Check:SetToolTip("Copy entities outside of the area copy that are constrained to entities insde")
CPanel:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "World/Area copy only your own props" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_copy_only_mine" )
Check:SetValue( 1 )
Check:SetToolTip("Copy entities outside of the area copy that are constrained to entities insde")
CPanel:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Sort constraints by their connections" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_sort_constraints" )
Check:SetValue( GetConVarNumber("advdupe2_sort_constraints") )
Check:SetToolTip( "Orders constraints so that they build a rigid constraint system." )
CPanel:AddItem(Check)
local NumSlider = vgui.Create( "DNumSlider" )
NumSlider:SetText( "Ghost Percentage:" )
NumSlider.Label:SetDark(true)
NumSlider:SetMin( 0 )
NumSlider:SetMax( 100 )
NumSlider:SetDecimals( 0 )
NumSlider:SetConVar( "advdupe2_limit_ghost" )
NumSlider:SetToolTip("Change the percent of ghosts to spawn")
--If these funcs are not here, problems occur for each
local func = NumSlider.Slider.OnMouseReleased
NumSlider.Slider.OnMouseReleased = function(self, mcode) func(self, mcode) AdvDupe2.StartGhosting() end
local func2 = NumSlider.Slider.Knob.OnMouseReleased
NumSlider.Slider.Knob.OnMouseReleased = function(self, mcode) func2(self, mcode) AdvDupe2.StartGhosting() end
local func3 = NumSlider.Wang.Panel.OnLoseFocus
NumSlider.Wang.Panel.OnLoseFocus = function(txtBox) func3(txtBox) AdvDupe2.StartGhosting() end
CPanel:AddItem(NumSlider)
NumSlider = vgui.Create( "DNumSlider" )
NumSlider:SetText( "Area Copy Size:" )
NumSlider.Label:SetDark(true)
NumSlider:SetMin( 0 )
NumSlider:SetMax( 30720 )
NumSlider:SetDecimals( 0 )
NumSlider:SetConVar( "advdupe2_area_copy_size" )
NumSlider:SetToolTip("Change the size of the area copy")
CPanel:AddItem(NumSlider)
local Category1 = vgui.Create("DCollapsibleCategory")
CPanel:AddItem(Category1)
Category1:SetLabel("Offsets")
Category1:SetExpanded(0)
local parent = FileBrowser:GetParent():GetParent():GetParent():GetParent()
--[[Offsets]]--
local CategoryContent1 = vgui.Create( "DPanelList" )
CategoryContent1:SetAutoSize( true )
CategoryContent1:SetDrawBackground( false )
CategoryContent1:SetSpacing( 1 )
CategoryContent1:SetPadding( 2 )
CategoryContent1.OnMouseWheeled = function(self, dlta) parent:OnMouseWheeled(dlta) end --Fix the damned mouse not scrolling when it's over the catagories
Category1:SetContents( CategoryContent1 )
NumSlider = vgui.Create( "DNumSlider" )
NumSlider:SetText( "Height Offset" )
NumSlider.Label:SetDark(true)
NumSlider:SetMin( -2500 )
NumSlider:SetMax( 2500 )
NumSlider:SetDefaultValue( 0 )
NumSlider:SetDecimals( 3 )
NumSlider:SetConVar("advdupe2_offset_z")
NumSlider:SetToolTip("Changes the dupe Z offset")
CategoryContent1:AddItem(NumSlider)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Use World Angles" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_offset_world" )
Check:SetValue( 0 )
Check:SetToolTip("Use world angles for the offset instead of the main entity")
CategoryContent1:AddItem(Check)
NumSlider = vgui.Create( "DNumSlider" )
NumSlider:SetText( "Pitch Offset" )
NumSlider.Label:SetDark(true)
NumSlider:SetMin( -180 )
NumSlider:SetMax( 180 )
NumSlider:SetDefaultValue( 0 )
NumSlider:SetDecimals( 3 )
NumSlider:SetToolTip("Changes the dupe pitch offset")
NumSlider:SetConVar("advdupe2_offset_pitch")
CategoryContent1:AddItem(NumSlider)
NumSlider = vgui.Create( "DNumSlider" )
NumSlider:SetText( "Yaw Offset" )
NumSlider.Label:SetDark(true)
NumSlider:SetMin( -180 )
NumSlider:SetMax( 180 )
NumSlider:SetDefaultValue( 0 )
NumSlider:SetDecimals( 3 )
NumSlider:SetToolTip("Changes the dupe yaw offset")
NumSlider:SetConVar("advdupe2_offset_yaw")
CategoryContent1:AddItem(NumSlider)
NumSlider = vgui.Create( "DNumSlider" )
NumSlider:SetText( "Roll Offset" )
NumSlider.Label:SetDark(true)
NumSlider:SetMin( -180 )
NumSlider:SetMax( 180 )
NumSlider:SetDefaultValue( 0 )
NumSlider:SetDecimals( 3 )
NumSlider:SetToolTip("Changes the dupe roll offset")
NumSlider:SetConVar("advdupe2_offset_roll")
CategoryContent1:AddItem(NumSlider)
local Btn = vgui.Create("DButton")
Btn:SetText("Reset")
Btn.DoClick = function()
RunConsoleCommand("advdupe2_offset_z", 0)
RunConsoleCommand("advdupe2_offset_pitch", 0)
RunConsoleCommand("advdupe2_offset_yaw", 0)
RunConsoleCommand("advdupe2_offset_roll", 0)
end
CategoryContent1:AddItem(Btn)
--[[Dupe Information]]--
local Category2 = vgui.Create("DCollapsibleCategory")
CPanel:AddItem(Category2)
Category2:SetLabel("Dupe Information")
Category2:SetExpanded(0)
local CategoryContent2 = vgui.Create( "DPanelList" )
CategoryContent2:SetAutoSize( true )
CategoryContent2:SetDrawBackground( false )
CategoryContent2:SetSpacing( 3 )
CategoryContent2:SetPadding( 2 )
Category2:SetContents( CategoryContent2 )
CategoryContent2.OnMouseWheeled = function(self, dlta) parent:OnMouseWheeled(dlta) end
AdvDupe2.Info = {}
local lbl = vgui.Create( "DLabel" )
lbl:SetText(AdvDupe2.InfoText.File or "File: ")
lbl:SetDark(true)
CategoryContent2:AddItem(lbl)
AdvDupe2.Info.File = lbl
lbl = vgui.Create( "DLabel" )
lbl:SetText(AdvDupe2.InfoText.Creator or "Creator:")
lbl:SetDark(true)
CategoryContent2:AddItem(lbl)
AdvDupe2.Info.Creator = lbl
lbl = vgui.Create( "DLabel" )
lbl:SetText(AdvDupe2.InfoText.Date or "Date:")
lbl:SetDark(true)
CategoryContent2:AddItem(lbl)
AdvDupe2.Info.Date = lbl
lbl = vgui.Create( "DLabel" )
lbl:SetText(AdvDupe2.InfoText.Time or "Time:")
lbl:SetDark(true)
CategoryContent2:AddItem(lbl)
AdvDupe2.Info.Time = lbl
lbl = vgui.Create( "DLabel" )
lbl:SetText(AdvDupe2.InfoText.Size or "Size:")
lbl:SetDark(true)
CategoryContent2:AddItem(lbl)
AdvDupe2.Info.Size = lbl
lbl = vgui.Create( "DLabel" )
lbl:SetText(AdvDupe2.InfoText.Desc or "Desc:")
lbl:SetDark(true)
CategoryContent2:AddItem(lbl)
AdvDupe2.Info.Desc = lbl
lbl = vgui.Create( "DLabel" )
lbl:SetText(AdvDupe2.InfoText.Entities or "Entities:")
lbl:SetDark(true)
CategoryContent2:AddItem(lbl)
AdvDupe2.Info.Entities = lbl
lbl = vgui.Create( "DLabel" )
lbl:SetText(AdvDupe2.InfoText.Constraints or "Constraints:")
lbl:SetDark(true)
CategoryContent2:AddItem(lbl)
AdvDupe2.Info.Constraints = lbl
--[[Contraption Spawner]]--
local Category3 = vgui.Create("DCollapsibleCategory")
CPanel:AddItem(Category3)
Category3:SetLabel("Contraption Spawner")
Category3:SetExpanded(0)
local CategoryContent3 = vgui.Create( "DPanelList" )
CategoryContent3:SetAutoSize( true )
CategoryContent3:SetDrawBackground( false )
CategoryContent3:SetSpacing( 3 )
CategoryContent3:SetPadding( 2 )
Category3:SetContents( CategoryContent3 )
CategoryContent3.OnMouseWheeled = function(self, dlta) parent:OnMouseWheeled(dlta) end
local ctrl = vgui.Create( "CtrlNumPad" )
ctrl:SetConVar1( "advdupe2_contr_spawner_key" )
ctrl:SetConVar2( "advdupe2_contr_spawner_undo_key" )
ctrl:SetLabel1( "Spawn Key")
ctrl:SetLabel2( "Undo Key" )
CategoryContent3:AddItem(ctrl)
NumSlider = vgui.Create( "DNumSlider" )
NumSlider:SetText( "Spawn Delay" )
NumSlider.Label:SetDark(true)
if(game.SinglePlayer()) then
NumSlider:SetMin( 0 )
else
local min = tonumber(GetConVarString("AdvDupe2_MinContraptionSpawnDelay")) or 0.2
if(tonumber(LocalPlayer():GetInfo("advdupe2_contr_spawner_delay"))<min) then
RunConsoleCommand("advdupe2_contr_spawner_delay", tostring(min))
end
NumSlider:SetMin( min )
end
NumSlider:SetMax(60)
NumSlider:SetDecimals( 1 )
NumSlider:SetConVar("advdupe2_contr_spawner_delay")
CategoryContent3:AddItem(NumSlider)
NumSlider = vgui.Create( "DNumSlider" )
NumSlider:SetText( "Undo Delay" )
NumSlider.Label:SetDark(true)
if(game.SinglePlayer()) then
NumSlider:SetMin( 0 )
NumSlider:SetMax( 60 )
else
local min = tonumber(GetConVarString("AdvDupe2_MinContraptionUndoDelay")) or 10
local max = tonumber(GetConVarString("AdvDupe2_MaxContraptionUndoDelay")) or 60
if(tonumber(LocalPlayer():GetInfo("advdupe2_contr_spawner_undo_delay")) < min) then
RunConsoleCommand("advdupe2_contr_spawner_undo_delay", tostring(min))
elseif(tonumber(LocalPlayer():GetInfo("advdupe2_contr_spawner_undo_delay")) > max) then
RunConsoleCommand("advdupe2_contr_spawner_undo_delay", tostring(max))
end
NumSlider:SetMin( min )
NumSlider:SetMax( max )
end
NumSlider:SetDecimals( 1 )
NumSlider:SetConVar("advdupe2_contr_spawner_undo_delay")
CategoryContent3:AddItem(NumSlider)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Disable gravity for all spawned props" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_contr_spawner_disgrav" )
Check:SetValue( 0 )
CategoryContent3:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Disable drag for all spawned props" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_contr_spawner_disdrag" )
Check:SetValue( 0 )
CategoryContent3:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Add spawner's velocity to contraption" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_contr_spawner_addvel" )
Check:SetValue( 1 )
CategoryContent3:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Disable drawing spawner props" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_contr_spawner_hideprops" )
Check:SetValue( 0 )
CategoryContent3:AddItem(Check)
--[[Area Auto Save]]--
local Category4 = vgui.Create("DCollapsibleCategory")
CPanel:AddItem(Category4)
Category4:SetLabel("Area Auto Save")
Category4:SetExpanded(0)
local CategoryContent4 = vgui.Create( "DPanelList" )
CategoryContent4:SetAutoSize( true )
CategoryContent4:SetDrawBackground( false )
CategoryContent4:SetSpacing( 3 )
CategoryContent4:SetPadding( 2 )
Category4:SetContents( CategoryContent4 )
CategoryContent4.OnMouseWheeled = function(self, dlta) parent:OnMouseWheeled(dlta) end
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Only copy contraption" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_auto_save_contraption" )
Check:SetValue( 0 )
Check:SetToolTip("Only copy a contraption instead of an area")
CategoryContent4:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Overwrite File" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_auto_save_overwrite" )
Check:SetValue( 1 )
Check:SetToolTip("Overwrite the file instead of creating a new one everytime")
CategoryContent4:AddItem(Check)
NumSlider = vgui.Create( "DNumSlider" )
NumSlider:SetText( "Minutes to Save:" )
NumSlider.Label:SetDark(true)
NumSlider:SetMin( 2 )
NumSlider:SetMax( 30 )
NumSlider:SetDecimals( 0 )
NumSlider:SetConVar( "advdupe2_auto_save_time" )
NumSlider:SetToolTip("Interval time to save in minutes")
CategoryContent4:AddItem(NumSlider)
local pnl = vgui.Create("Panel")
pnl:SetWide(CPanel:GetWide()-40)
pnl:SetTall(75)
pnl:SetPos(0, 50)
CategoryContent4:AddItem(pnl)
local label = vgui.Create("DLabel", pnl)
label:SetText("Directory: ")
label:SizeToContents()
label:SetDark(true)
label:SetPos(5,7)
AdvDupe2.AutoSavePath = ""
local txtbox = vgui.Create("DTextEntry", pnl)
txtbox:SetWide(pnl:GetWide()-100)
txtbox:SetPos(60, 5)
txtbox:SetUpdateOnType(true)
txtbox.OnTextChanged = function(self)
self:SetValue(AdvDupe2.AutoSavePath)
end
local btn = vgui.Create("DImageButton", pnl)
local x, y = txtbox:GetPos()
btn:SetPos(x + txtbox:GetWide() + 5, 7)
btn:SetMaterial("icon16/folder_explore.png")
btn:SizeToContents()
btn:SetToolTip("Browse")
btn.DoClick = function()
local ScrollBar = parent.VBar
ScrollBar:AnimateTo(0, 1, 0, 0.2)
FileBrowser.Submit:SetMaterial("icon16/disk.png")
FileBrowser.Submit:SetTooltip("Directory for Area Auto Save")
if(FileBrowser.FileName:GetValue()=="Folder_Name...") then
FileBrowser.FileName:SetValue("File_Name...")
end
FileBrowser.Desc:SetVisible(true)
FileBrowser.Info:SetVisible(false)
FileBrowser.FileName:SetVisible(true)
FileBrowser.FileName:SelectAllOnFocus(true)
FileBrowser.FileName:OnMousePressed()
FileBrowser.FileName:RequestFocus()
FileBrowser.Expanding=true
FileBrowser:Slide(true)
FileBrowser.Submit.DoClick = function()
local name = FileBrowser.FileName:GetValue()
if(name=="" or name=="File_Name...") then
AdvDupe2.Notify("Name field is blank.", NOTIFY_ERROR)
FileBrowser.FileName:SelectAllOnFocus(true)
FileBrowser.FileName:OnGetFocus()
FileBrowser.FileName:RequestFocus()
return
end
local desc = FileBrowser.Desc:GetValue()
if(desc=="Description...") then desc="" end
if(not IsValid(FileBrowser.Browser.pnlCanvas.m_pSelectedItem) or FileBrowser.Browser.pnlCanvas.m_pSelectedItem.Derma.ClassName~="advdupe2_browser_folder") then
AdvDupe2.Notify("Folder to save Area Auto Save not selected.", NOTIFY_ERROR)
return
end
FileBrowser.AutoSaveNode = FileBrowser.Browser.pnlCanvas.m_pSelectedItem
txtbox:SetValue(FileBrowser:GetFullPath(FileBrowser.Browser.pnlCanvas.m_pSelectedItem)..name)
AdvDupe2.AutoSavePath = txtbox:GetValue()
txtbox:SetToolTip(txtbox:GetValue())
AdvDupe2.AutoSaveDesc = desc
FileBrowser:Slide(false)
ScrollBar:AnimateTo(ScrollBar.CanvasSize, 1, 0, 0.2)
RunConsoleCommand("AdvDupe2_SetStage")
hook.Add("HUDPaint", "AdvDupe2_DrawSelectionBox", AdvDupe2.DrawSelectionBox)
end
FileBrowser.FileName.OnEnter = function()
FileBrowser.FileName:KillFocus()
FileBrowser.Desc:SelectAllOnFocus(true)
FileBrowser.Desc.OnMousePressed()
FileBrowser.Desc:RequestFocus()
end
FileBrowser.Desc.OnEnter = FileBrowser.Submit.DoClick
end
btn = vgui.Create("DButton", pnl)
btn:SetSize(50, 35)
btn:SetPos(pnl:GetWide()/4-10, 30)
btn:SetText("Show")
btn.DoClick = function()
if(AdvDupe2.AutoSavePos) then
RunConsoleCommand("advdupe2_area_copy_size", AdvDupe2.AutoSaveSize)
LocalPlayer():SetEyeAngles( (AdvDupe2.AutoSavePos - LocalPlayer():GetShootPos()):Angle() )
RunConsoleCommand("AdvDupe2_SetStage")
hook.Add("HUDPaint", "AdvDupe2_DrawSelectionBox", AdvDupe2.DrawSelectionBox)
end
end
btn = vgui.Create("DButton", pnl)
btn:SetSize(50, 35)
btn:SetPos((pnl:GetWide()/4)*3-40, 30)
btn:SetText("Turn Off")
btn:SetDisabled(true)
btn.DoClick = function(self)
RunConsoleCommand("AdvDupe2_RemoveAutoSave")
self:SetDisabled(true)
AdvDupe2.AutoSavePos = nil
end
AdvDupe2.OffButton = btn
--[[Experimental Section]]--
local Category5 = vgui.Create("DCollapsibleCategory")
CPanel:AddItem(Category5)
Category5:SetLabel("Experimental Section")
Category5:SetExpanded(0)
local CategoryContent5 = vgui.Create( "DPanelList" )
CategoryContent5:SetAutoSize( true )
CategoryContent5:SetDrawBackground( false )
CategoryContent5:SetSpacing( 3 )
CategoryContent5:SetPadding( 2 )
Category5:SetContents( CategoryContent5 )
CategoryContent5.OnMouseWheeled = function(self, dlta) parent:OnMouseWheeled(dlta) end
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Disable parented props physics interaction" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_paste_disparents" )
Check:SetValue( 0 )
CategoryContent5:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Disable Dupe Spawn Protection" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_paste_protectoveride" )
Check:SetValue( 1 )
Check:SetToolTip("Check this if you things don't look right after pasting.")
CategoryContent5:AddItem(Check)
Check = vgui.Create("DCheckBoxLabel")
Check:SetText( "Open file after Saving" )
Check:SetDark(true)
Check:SetConVar( "advdupe2_debug_openfile" )
Check:SetValue( 1 )
Check:SetToolTip("Check this if you want your files to be opened after saving them.")
CategoryContent5:AddItem(Check)
--[[Save Map]]--
if(LocalPlayer():IsAdmin()) then
local Category6 = vgui.Create("DCollapsibleCategory")
CPanel:AddItem(Category6)
Category6:SetLabel("Save Map")
Category6:SetExpanded(0)
local CategoryContent6 = vgui.Create( "DPanelList" )
CategoryContent6:SetAutoSize( true )
CategoryContent6:SetDrawBackground( false )
CategoryContent6:SetSpacing( 3 )
CategoryContent6:SetPadding( 2 )
Category6:SetContents( CategoryContent6 )
CategoryContent6.OnMouseWheeled = function(self, dlta) parent:OnMouseWheeled(dlta) end
pnl = vgui.Create("Panel")
pnl:SetWide(CPanel:GetWide()-40)
pnl:SetTall(75)
pnl:SetPos(0, 50)
CategoryContent6:AddItem(pnl)
label = vgui.Create("DLabel", pnl)
label:SetText("File Name: ")
label:SizeToContents()
label:SetDark(true)
label:SetPos(5,7)
AdvDupe2.AutoSavePath = ""
local txtbox2 = vgui.Create("DTextEntry", pnl)
txtbox2:SetWide(pnl:GetWide()-100)
txtbox2:SetPos(60, 5)
local btn2 = vgui.Create("DImageButton", pnl)
x, y = txtbox2:GetPos()
btn2:SetPos(x + txtbox2:GetWide() + 5, 7)
btn2:SetMaterial("icon16/disk.png")
btn2:SizeToContents()
btn2:SetToolTip("Save Map")
btn2.DoClick = function()
if(txtbox2:GetValue()=="") then return end
RunConsoleCommand("AdvDupe2_SaveMap", txtbox2:GetValue())
end
txtbox2.OnEnter = function()
btn2:DoClick()
end
end
end
function TOOL.BuildCPanel(panel)
panel:ClearControls()
panel:AddControl("Header", {
Text = "Advanced Duplicator 2",
Description = "Duplicate stuff."
})
local function tryToBuild()
local CPanel = controlpanel.Get("advdupe2")
if CPanel and CPanel:GetWide()>16 then
BuildCPanel(CPanel)
else
timer.Simple(0.1,tryToBuild)
end
end
tryToBuild()
end
local StColor = {r=130, g=25, b=40, a=255}
local NoColor = {r=25, g=100, b=40, a=255}
local CurColor = {r=25, g=100, b=40, a=255}
local CWhite = Color(255,255,255,255)
surface.CreateFont ("AD2Font", {font="Arial", size=40, weight=1000}) ---Remember to use gm_clearfonts
surface.CreateFont ("AD2TitleFont", {font="Arial", size=24, weight=1000})
function TOOL:DrawToolScreen()
if(not AdvDupe2) then return true end
local text = "Ready"
local state, co = false
local ply = LocalPlayer()
if(AdvDupe2.Preview) then
text = "Preview"
end
if(AdvDupe2.ProgressBar.Text) then
state = true
text = AdvDupe2.ProgressBar.Text
end
cam.Start2D()
surface.SetDrawColor(32, 32, 32, 255)
surface.DrawRect(0, 0, 256, 256)
if(state) then
co = StColor
else
co = NoColor
end
local rate = FrameTime() * 160
CurColor.r = math.Approach( CurColor.r, co.r, rate )
CurColor.g = math.Approach( CurColor.g, co.g, rate )
surface.SetDrawColor(CurColor)
surface.DrawRect(13, 13, 230, 230)
surface.SetTextColor( 255, 255, 255, 255 )
draw.SimpleText("Advanced Duplicator 2", "AD2TitleFont", 128, 50, CWhite, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
draw.SimpleText(text, "AD2Font", 128, 128, CWhite, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
if(state) then
draw.RoundedBox( 6, 32, 178, 192, 28, Color( 255, 255, 255, 150 ) )
draw.RoundedBox( 6, 34, 180, 188*(AdvDupe2.ProgressBar.Percent / 100), 24, Color( 0, 255, 0, 255 ) )
elseif(ply:KeyDown(IN_USE)) then
local font, align = "AD2TitleFont", TEXT_ALIGN_BOTTOM
draw.SimpleText("H: "..ply:GetInfo("advdupe2_offset_z") , font, 20, 210, CWhite, TEXT_ALIGN_LEFT , align)
draw.SimpleText("P: "..ply:GetInfo("advdupe2_offset_pitch"), font, 236, 210, CWhite, TEXT_ALIGN_RIGHT, align)
draw.SimpleText("Y: "..ply:GetInfo("advdupe2_offset_yaw") , font, 20 , 240, CWhite, TEXT_ALIGN_LEFT , align)
draw.SimpleText("R: "..ply:GetInfo("advdupe2_offset_roll") , font, 236, 240, CWhite, TEXT_ALIGN_RIGHT, align)
end
cam.End2D()
end
local function FindInBox(min, max, ply)
local EntTable = {}
for _,ent in ents.Iterator() do
local pos = ent:GetPos()
if (pos.X>=min.X) and (pos.X<=max.X) and (pos.Y>=min.Y) and (pos.Y<=max.Y) and (pos.Z>=min.Z) and (pos.Z<=max.Z) then
--if(ent:GetClass()~="C_BaseFlexclass") then
EntTable[ent:EntIndex()] = ent
--end
end
end
return EntTable
end
local GreenSelected = Color(0, 255, 0, 255)
function AdvDupe2.DrawSelectionBox()
local TraceRes = util.TraceLine(util.GetPlayerTrace(LocalPlayer()))
local i = math.Clamp(tonumber(LocalPlayer():GetInfo("advdupe2_area_copy_size")) or 50, 0, 30720)
--Bottom Points
local B1 = (Vector(-i,-i,-i) + TraceRes.HitPos)
local B2 = (Vector(-i, i,-i) + TraceRes.HitPos)
local B3 = (Vector( i, i,-i) + TraceRes.HitPos)
local B4 = (Vector( i,-i,-i) + TraceRes.HitPos)
--Top Points
local T1 = (Vector(-i,-i, i) + TraceRes.HitPos):ToScreen()
local T2 = (Vector(-i, i, i) + TraceRes.HitPos):ToScreen()
local T3 = (Vector( i, i, i) + TraceRes.HitPos):ToScreen()
local T4 = (Vector( i,-i, i) + TraceRes.HitPos):ToScreen()
if(not AdvDupe2.LastUpdate or CurTime()>=AdvDupe2.LastUpdate) then
if AdvDupe2.ColorEntities then
for k,v in pairs(AdvDupe2.EntityColors)do
local ent = AdvDupe2.ColorEntities[k]
if(IsValid(ent)) then
AdvDupe2.ColorEntities[k]:SetColor(v)
end
end
end
local Entities = FindInBox(B1, (Vector(i,i,i)+TraceRes.HitPos), LocalPlayer())
AdvDupe2.ColorEntities = Entities
AdvDupe2.EntityColors = {}
for k,v in pairs(Entities)do
AdvDupe2.EntityColors[k] = v:GetColor()
v:SetColor(GreenSelected)
end
AdvDupe2.LastUpdate = CurTime()+0.25
end
local tracedata = {}
tracedata.mask = MASK_NPCWORLDSTATIC
local WorldTrace
tracedata.start = B1+Vector(0,0,i*2)
tracedata.endpos = B1
WorldTrace = util.TraceLine( tracedata )
B1 = WorldTrace.HitPos:ToScreen()
tracedata.start = B2+Vector(0,0,i*2)
tracedata.endpos = B2
WorldTrace = util.TraceLine( tracedata )
B2 = WorldTrace.HitPos:ToScreen()
tracedata.start = B3+Vector(0,0,i*2)
tracedata.endpos = B3
WorldTrace = util.TraceLine( tracedata )
B3 = WorldTrace.HitPos:ToScreen()
tracedata.start = B4+Vector(0,0,i*2)
tracedata.endpos = B4
WorldTrace = util.TraceLine( tracedata )
B4 = WorldTrace.HitPos:ToScreen()
surface.SetDrawColor( 0, 255, 0, 255 )
--Draw Sides
surface.DrawLine(B1.x, B1.y, T1.x, T1.y)
surface.DrawLine(B2.x, B2.y, T2.x, T2.y)
surface.DrawLine(B3.x, B3.y, T3.x, T3.y)
surface.DrawLine(B4.x, B4.y, T4.x, T4.y)
--Draw Bottom
surface.DrawLine(B1.x, B1.y, B2.x, B2.y)
surface.DrawLine(B2.x, B2.y, B3.x, B3.y)
surface.DrawLine(B3.x, B3.y, B4.x, B4.y)
surface.DrawLine(B4.x, B4.y, B1.x, B1.y)
--Draw Top
surface.DrawLine(T1.x, T1.y, T2.x, T2.y)
surface.DrawLine(T2.x, T2.y, T3.x, T3.y)
surface.DrawLine(T3.x, T3.y, T4.x, T4.y)
surface.DrawLine(T4.x, T4.y, T1.x, T1.y)
end
net.Receive("AdvDupe2_DrawSelectBox", function()
hook.Add("HUDPaint", "AdvDupe2_DrawSelectionBox", AdvDupe2.DrawSelectionBox)
end)
function AdvDupe2.RemoveSelectBox()
hook.Remove("HUDPaint", "AdvDupe2_DrawSelectionBox")
if AdvDupe2.ColorEntities then
for k,v in pairs(AdvDupe2.EntityColors)do
if(not IsValid(AdvDupe2.ColorEntities[k])) then
AdvDupe2.ColorEntities[k]=nil
else
AdvDupe2.ColorEntities[k]:SetColor(v)
end
end
AdvDupe2.ColorEntities={}
AdvDupe2.EntityColors={}
end
end
net.Receive("AdvDupe2_RemoveSelectBox",function()
AdvDupe2.RemoveSelectBox()
end)
function AdvDupe2.InitProgressBar(label)
AdvDupe2.ProgressBar = {}
AdvDupe2.ProgressBar.Text = label
AdvDupe2.ProgressBar.Percent = 0
AdvDupe2.BusyBar = true
end
net.Receive("AdvDupe2_InitProgressBar", function()
AdvDupe2.InitProgressBar(net.ReadString())
end)
net.Receive("AdvDupe2_UpdateProgressBar", function()
AdvDupe2.ProgressBar.Percent = net.ReadFloat()
end)
function AdvDupe2.RemoveProgressBar()
AdvDupe2.ProgressBar = {}
AdvDupe2.BusyBar = false
if(AdvDupe2.Ghosting) then
AdvDupe2.InitProgressBar("Ghosting: ")
AdvDupe2.BusyBar = false
AdvDupe2.ProgressBar.Percent = AdvDupe2.CurrentGhost/AdvDupe2.TotalGhosts*100
end
end
net.Receive("AdvDupe2_RemoveProgressBar", function()
AdvDupe2.RemoveProgressBar()
end)
net.Receive("AdvDupe2_ResetOffsets", function()
RunConsoleCommand("advdupe2_original_origin", "0")
RunConsoleCommand("advdupe2_paste_constraints","1")
RunConsoleCommand("advdupe2_offset_z","0")
RunConsoleCommand("advdupe2_offset_pitch","0")
RunConsoleCommand("advdupe2_offset_yaw","0")
RunConsoleCommand("advdupe2_offset_roll","0")
RunConsoleCommand("advdupe2_paste_parents","1")
RunConsoleCommand("advdupe2_paste_disparents","0")
end)
net.Receive("AdvDupe2_ReportModel", function()
print("Advanced Duplicator 2: Invalid Model: "..net.ReadString())
end)
net.Receive("AdvDupe2_ReportClass", function()
print("Advanced Duplicator 2: Invalid Class: "..net.ReadString())
end)
net.Receive("AdvDupe2_ResetDupeInfo", function()
if not AdvDupe2.Info then return end
AdvDupe2.Info.File:SetText("File:")
AdvDupe2.Info.Creator:SetText("Creator:")
AdvDupe2.Info.Date:SetText("Date:")
AdvDupe2.Info.Time:SetText("Time:")
AdvDupe2.Info.Size:SetText("Size:")
AdvDupe2.Info.Desc:SetText("Desc:")
AdvDupe2.Info.Entities:SetText("Entities:")
AdvDupe2.Info.Constraints:SetText("Constraints:")
end)
net.Receive("AdvDupe2_CanAutoSave", function()
if(AdvDupe2.AutoSavePath~="") then
AdvDupe2.AutoSavePos = net.ReadVector()
AdvDupe2.AutoSaveSize = net.ReadFloat()
local ent = net.ReadUInt(16)
AdvDupe2.OffButton:SetDisabled(false)
net.Start("AdvDupe2_CanAutoSave")
net.WriteString(AdvDupe2.AutoSaveDesc)
net.WriteInt(ent, 16)
if(game.SinglePlayer()) then
net.WriteString(string.sub(AdvDupe2.AutoSavePath, 10, #AdvDupe2.AutoSavePath))
end
net.SendToServer()
else
AdvDupe2.Notify("Select a directory for the Area Auto Save.", NOTIFY_ERROR)
end
end)
net.Receive("AdvDupe2_SetDupeInfo", function(len, ply, len2)
if AdvDupe2.Info then
AdvDupe2.Info.File:SetText("File: "..net.ReadString())
AdvDupe2.Info.Creator:SetText("Creator: "..net.ReadString())
AdvDupe2.Info.Date:SetText("Date: "..net.ReadString())
AdvDupe2.Info.Time:SetText("Time: "..net.ReadString())
AdvDupe2.Info.Size:SetText("Size: "..net.ReadString())
AdvDupe2.Info.Desc:SetText("Desc: "..net.ReadString())
AdvDupe2.Info.Entities:SetText("Entities: "..net.ReadString())
AdvDupe2.Info.Constraints:SetText("Constraints: "..net.ReadString())
else
AdvDupe2.InfoText.File = "File: "..net.ReadString()
AdvDupe2.InfoText.Creator = "Creator: "..net.ReadString()
AdvDupe2.InfoText.Date = "Date: "..net.ReadString()
AdvDupe2.InfoText.Time = "Time: "..net.ReadString()
AdvDupe2.InfoText.Size = "Size: "..net.ReadString()
AdvDupe2.InfoText.Desc = "Desc: "..net.ReadString()
AdvDupe2.InfoText.Entities = "Entities: "..net.ReadString()
AdvDupe2.InfoText.Constraints = "Constraints: "..net.ReadString()
end
end)
end