Initial Nadmod Prop Protection commit, v1.3.1

This commit is contained in:
Nebual 2016-10-04 12:13:13 -07:00
commit 03f088ff55
3 changed files with 780 additions and 0 deletions

14
addon.json Normal file
View File

@ -0,0 +1,14 @@
{
"title" : "Nadmod Prop Protection",
"type" : "tool",
"tags" : [ "build" ],
"description": "NPP is a simple and efficient Prop Protection system. \n\n* Admins can touch all props (configurable)\n* All player spawned entities are protected by default from:\n- All Tools\n- Properties menu (right clicking props while holding C)\n- Gravity gun punt/pickup\n- Physgun pickup/reload\n* Has a friends system with cpanel that saves friends to file\n* Quick and easy buttons to cleanup either Disconnected Player's stuff or specific players, which also show the current # of entities that player owns\n* Autoclean Disconnected Player's props timer\n* Simple overlay shown on all entities shows owner, class, model, and entID\n* Freshly written for Gmod13, it includes blocking the new CanProperty (right click menu)\n* CPPI Compliant\n\nFor more information, see the Facepunch thread http://facepunch.com/showthread.php?t=1242185\nNote: Initially Protection is disabled serverwide, just tick on the Main Power Switch in the Admin CPanel and hit Apply.",
"ignore" :
[
".git/*",
"*.psd",
"*.vcproj",
"*.svn*",
"*.txt"
]
}

View File

@ -0,0 +1,205 @@
-- =================================
-- NADMOD PP - Prop Protection
-- By Nebual@nebtown.info 2012
-- Menus designed after SpaceTech's Simple Prop Protection
-- =================================
if !NADMOD then
NADMOD = {}
NADMOD.PropOwners = {}
NADMOD.PPConfig = {}
NADMOD.Friends = {}
end
local Props = NADMOD.PropOwners
net.Receive("nadmod_propowners",function(len)
local num = net.ReadUInt(16)
for k=1,num do
local id,str = net.ReadUInt(16), net.ReadString()
if str == "-" then Props[id] = nil
elseif str == "W" then Props[id] = "World"
elseif str == "O" then Props[id] = "Ownerless"
else Props[id] = str
end
end
end)
local font = "ChatFont"
hook.Add("HUDPaint", "NADMOD.HUDPaint", function()
local tr = LocalPlayer():GetEyeTrace()
if !tr.HitNonWorld then return end
local ent = tr.Entity
if ent:IsValid() && !ent:IsPlayer() then
local text = "Owner: " .. (Props[ent:EntIndex()] or "N/A")
local text2 = "'"..string.sub(table.remove(string.Explode("/", ent:GetModel() or "?")), 1,-5).."' ["..ent:EntIndex().."]"
local text3 = ent:GetClass()
surface.SetFont(font)
local Width, Height = surface.GetTextSize(text)
local w2,h2 = surface.GetTextSize(text2)
local w3,h3 = surface.GetTextSize(text3)
local boxHeight = Height + h2 + h3 + 16
local boxWidth = math.Max(Width,w2,w3) + 25
draw.RoundedBox(4, ScrW() - (boxWidth + 4), (ScrH()/2 - 200) - 16, boxWidth, boxHeight, Color(0, 0, 0, 150))
draw.SimpleText(text, font, ScrW() - (Width / 2) - 20, ScrH()/2 - 200, Color(255, 255, 255, 255), 1, 1)
draw.SimpleText(text2, font, ScrW() - (w2 / 2) - 20, ScrH()/2 - 200 + Height, Color(255, 255, 255, 255), 1, 1)
draw.SimpleText(text3, font, ScrW() - (w3 / 2) - 20, ScrH()/2 - 200 + Height + h2, Color(255, 255, 255, 255), 1, 1)
end
end)
function NADMOD.CleanCLRagdolls()
for k,v in pairs(ents.FindByClass("class C_ClientRagdoll")) do v:SetNoDraw(true) end
for k,v in pairs(ents.FindByClass("class C_BaseAnimating")) do v:SetNoDraw(true) end
end
net.Receive("nadmod_cleanclragdolls", NADMOD.CleanCLRagdolls)
-- =============================
-- NADMOD PP CPanels
-- =============================
net.Receive("nadmod_ppconfig",function(len)
NADMOD.PPConfig = net.ReadTable()
for k,v in pairs(NADMOD.PPConfig) do
local val = v
if isbool(v) then val = v and "1" or "0" end
CreateClientConVar("npp_"..k,val, false, false)
RunConsoleCommand("npp_"..k,val)
end
NADMOD.AdminPanel(NADMOD.AdminCPanel, true)
end)
concommand.Add("npp_apply",function(ply,cmd,args)
for k,v in pairs(NADMOD.PPConfig) do
if isbool(v) then NADMOD.PPConfig[k] = GetConVar("npp_"..k):GetBool()
elseif isnumber(v) then NADMOD.PPConfig[k] = GetConVarNumber("npp_"..k)
else NADMOD.PPConfig[k] = GetConVarString("npp_"..k)
end
end
net.Start("nadmod_ppconfig")
net.WriteTable(NADMOD.PPConfig)
net.SendToServer()
end)
function NADMOD.AdminPanel(Panel, runByNetReceive)
if Panel then
if !NADMOD.AdminCPanel then NADMOD.AdminCPanel = Panel end
end
if not runByNetReceive then
RunConsoleCommand("npp_refreshconfig")
timer.Create("NADMOD.AdminPanelCheckFail",0.75,1,function()
Panel:ClearControls()
Panel:Help("Waiting for the server to say you're an admin...")
end)
return
end
timer.Remove("NADMOD.AdminPanelCheckFail")
Panel:ClearControls()
Panel:SetName("NADMOD PP Admin Panel")
Panel:CheckBox( "Main PP Power Switch", "npp_toggle")
Panel:CheckBox( "Admins can touch anything", "npp_adminall")
local use_protection = Panel:CheckBox( "Use (E) Protection", "npp_use")
use_protection:SetToolTip("Stop nonfriends from entering vehicles, pushing buttons/doors")
local txt = Panel:Help("Autoclean Disconnected Players?")
txt:SetAutoStretchVertical(false)
txt:SetContentAlignment( TEXT_ALIGN_CENTER )
local autoclean_admins = Panel:CheckBox( "Autoclean Admins", "npp_autocdpadmins")
autoclean_admins:SetToolTip("Should Admin Props also be autocleaned?")
local autoclean_timer = Panel:NumSlider("Autoclean Timer", "npp_autocdp", 0, 1200, 0 )
autoclean_timer:SetToolTip("0 disables autocleaning")
Panel:Button( "Apply Settings", "npp_apply")
local txt = Panel:Help(" Cleanup Panel")
txt:SetContentAlignment( TEXT_ALIGN_CENTER )
txt:SetFont("DermaDefaultBold")
txt:SetAutoStretchVertical(false)
local counts = {}
for k,v in pairs(NADMOD.PropOwners) do
counts[v] = (counts[v] or 0) + 1
end
local dccount = 0
for k,v in pairs(counts) do
if k != "World" and k != "Ownerless" then dccount = dccount + v end
end
for k, ply in pairs(player.GetAll()) do
if IsValid(ply) then
Panel:Button( ply:Nick().." ("..(counts[ply:Nick()] or 0)..")", "nadmod_cleanupprops", ply:EntIndex() )
dccount = dccount - (counts[ply:Nick()] or 0)
end
end
Panel:Help(""):SetAutoStretchVertical(false) -- Spacer
Panel:Button("Cleanup Disconnected Players Props ("..dccount..")", "nadmod_cdp")
Panel:Button("Cleanup All NPCs", "nadmod_cleanclass", "npc_*")
Panel:Button("Cleanup All Ragdolls", "nadmod_cleanclass", "prop_ragdol*")
Panel:Button("Cleanup Clientside Ragdolls", "nadmod_cleanclragdolls")
Panel:Button("Cleanup World Ropes", "nadmod_cleanworldropes")
end
net.Receive("nadmod_ppfriends",function(len)
NADMOD.Friends = net.ReadTable()
for _,tar in pairs(player.GetAll()) do
CreateClientConVar("npp_friend_"..tar:UniqueID(),NADMOD.Friends[tar:SteamID()] and "1" or "0", false, false)
RunConsoleCommand("npp_friend_"..tar:UniqueID(),NADMOD.Friends[tar:SteamID()] and "1" or "0")
end
end)
concommand.Add("npp_applyfriends",function(ply,cmd,args)
for _,tar in pairs(player.GetAll()) do
NADMOD.Friends[tar:SteamID()] = GetConVar("npp_friend_"..tar:UniqueID()):GetBool()
end
net.Start("nadmod_ppfriends")
net.WriteTable(NADMOD.Friends)
net.SendToServer()
end)
function NADMOD.ClientPanel(Panel)
RunConsoleCommand("npp_refreshfriends")
Panel:ClearControls()
if !NADMOD.ClientCPanel then NADMOD.ClientCPanel = Panel end
Panel:SetName("NADMOD - Client Panel")
Panel:Button("Cleanup Props", "nadmod_cleanupprops")
Panel:Button("Clear Clientside Ragdolls", "nadmod_cleanclragdolls")
local txt = Panel:Help(" Friends Panel")
txt:SetContentAlignment( TEXT_ALIGN_CENTER )
txt:SetFont("DermaDefaultBold")
txt:SetAutoStretchVertical(false)
local Players = player.GetAll()
if(table.Count(Players) == 1) then
Panel:Help("No Other Players Are Online")
else
for _, tar in pairs(Players) do
if(IsValid(tar) and tar != LocalPlayer()) then
Panel:CheckBox(tar:Nick(), "npp_friend_"..tar:UniqueID())
end
end
Panel:Button("Apply Friends", "npp_applyfriends")
end
end
function NADMOD.SpawnMenuOpen()
if NADMOD.AdminCPanel then
NADMOD.AdminPanel(NADMOD.AdminCPanel)
end
if NADMOD.ClientCPanel then
NADMOD.ClientPanel(NADMOD.ClientCPanel)
end
end
hook.Add("SpawnMenuOpen", "NADMOD.SpawnMenuOpen", NADMOD.SpawnMenuOpen)
function NADMOD.PopulateToolMenu()
spawnmenu.AddToolMenuOption("Utilities", "NADMOD Prop Protection", "Admin", "Admin", "", "", NADMOD.AdminPanel)
spawnmenu.AddToolMenuOption("Utilities", "NADMOD Prop Protection", "Client", "Client", "", "", NADMOD.ClientPanel)
end
hook.Add("PopulateToolMenu", "NADMOD.PopulateToolMenu", NADMOD.PopulateToolMenu)
net.Receive("nadmod_notify", function(len)
local text = net.ReadString()
notification.AddLegacy(text, NOTIFY_GENERIC, 5)
surface.PlaySound("ambient/water/drip"..math.random(1, 4)..".wav")
print(text)
end)

View File

@ -0,0 +1,561 @@
-- Nebual 2012 (nebual@nebtown.info) presents:
-- NADMOD Prop Protection
-- Inspired by Spacetech's Simple Prop Protection, <3's
-- Bugs? Feature requests? Email me or poke the Facepunch http://www.facepunch.com/showthread.php?t=1221183
if not NADMOD then
-- User is running without my Admin mod NADMOD, lets just copy some required initialization stuff over here
concommand.Add("nadmod_reload", function(ply,cmd,args)
if ply:IsValid() and not NADMOD.IsPPAdmin(ply) then return end
if args[1] == "full" then NADMOD = nil end
include("autorun/server/nadmod_pp.lua")
end)
NADMOD = util.JSONToTable(file.Read("nadmod_config.txt","DATA") or "") or {Users = {}, Groups = {}, Bans = {}, PPConfig = {}}
function NADMOD.Save()
file.Write("nadmod_config.txt", util.TableToJSON({Users = NADMOD.Users, Groups = NADMOD.Groups, Bans = NADMOD.Bans, PPConfig = NADMOD.PPConfig}))
end
hook.Add("Shutdown","NADMOD.Save",NADMOD.Save)
function NADMOD.FindPlayer(nick)
if not nick or nick == "" then return end
nick = string.lower(nick)
local num = tonumber(nick)
for _,v in pairs(player.GetAll()) do
if string.lower(v:Nick()) == nick then return v -- Exact name match
elseif v:UserID() == num then return v -- UserID match (from status)
end
end
-- If the above two exact searches fail, try doing a partial search
for _,v in pairs(player.GetAll()) do
if string.find(string.lower(v:Nick()), nick) then return v end
end
end
end
if not NADMOD.Props then
-- NADMOD PP Initialization
NADMOD.PPVersion = "1.3.1"
NADMOD.Props = {} // {entid = {Ent = ent, Owner = ply, SteamID = ply:SteamID(), Name = ply:Nick() or "W" or "O"}}
NADMOD.PropOwnersSmall = {} // A smaller buffer of PropOwner names to send to current players
NADMOD.AutoCDPTimers = {}
local oldCPPI = CPPI
CPPI = {}
-- Copy over default settings if they aren't present in the disk's PPConfig
for k,v in pairs({toggle=true,use=false,adminall=true,autocdp=0,autocdpadmins=false}) do
if NADMOD.PPConfig[k] == nil then NADMOD.PPConfig[k] = v end
end
AddCSLuaFile("autorun/client/cl_nadmodpp.lua")
util.AddNetworkString("nadmod_propowners")
util.AddNetworkString("nadmod_ppfriends")
util.AddNetworkString("nadmod_ppconfig")
util.AddNetworkString("nadmod_cleanclragdolls")
util.AddNetworkString("nadmod_notify")
timer.Create("WarnOtherPPs", 0, 1, function()
//Print a harmless error if we detect other PP's active, since this often leads to confusion. NPP'll still load fine
//Known CPPI plugins: FPP, SPP, NPP, ULX's UPS
if not oldCPPI or (oldCPPI.GetName and oldCPPI:GetName() == "Nadmod Prop Protection") then oldCPPI = CPPI end
if oldCPPI and (not oldCPPI.GetName or oldCPPI:GetName() ~= "Nadmod Prop Protection") then Error("NPP has detected "..(oldCPPI.GetName and oldCPPI:GetName() or "another CPPI PP").." is installed, you probably only want one PP active at a time!!\n")
elseif PP_Settings then Error("NPP has detected Evolve's PP plugin, you probably only want one PP active at a time!!\n")
end
end)
end
local metaply = FindMetaTable("Player")
local metaent = FindMetaTable("Entity")
-- Does your admin mod not seem to work with Nadmod PP? Try overriding this function!
function NADMOD.IsPPAdmin(ply)
if NADMOD.HasPermission then
return NADMOD.HasPermission(ply, "PP_All")
else
-- If the admin mod NADMOD isn't present, just default to using IsAdmin
return ply:IsAdmin()
end
end
function NADMOD.PPInitPlayer(ply)
local steamid = ply:SteamID()
for _,v in pairs(NADMOD.Props) do
if v.SteamID == steamid then
v.Owner = ply
v.Ent.SPPOwner = ply
if v.Ent.SetPlayer then v.Ent:SetPlayer(ply) end
end
end
net.Start("nadmod_propowners")
net.WriteUInt(table.Count(NADMOD.Props),16)
for k,v in pairs(NADMOD.Props) do
net.WriteUInt(k,16)
net.WriteString(v.Name)
end
net.Send(ply)
end
hook.Add("PlayerInitialSpawn", "NADMOD.PPInitPlayer", NADMOD.PPInitPlayer)
function NADMOD.PPOwnWeapons(ply)
timer.Create("NADMOD.PPOwnWeapons", 0.2, 1, function()
if not IsValid(ply) then return end
for k,v in pairs(ply:GetWeapons()) do
if not IsValid(v) then continue end
NADMOD.SetOwnerWorld(v)
end
end)
end
hook.Add("PlayerSpawn", "NADMOD.PPOwnWeapons", NADMOD.PPOwnWeapons)
function NADMOD.RefreshOwners()
if next(NADMOD.PropOwnersSmall) then
net.Start("nadmod_propowners")
net.WriteUInt(table.Count(NADMOD.PropOwnersSmall),16)
for k,v in pairs(NADMOD.PropOwnersSmall) do
net.WriteUInt(k,16)
net.WriteString(v)
end
//net.WriteTable(NADMOD.PropOwnersSmall)
net.Broadcast()
table.Empty(NADMOD.PropOwnersSmall)
end
end
timer.Create("NADMOD.RefreshOwners", 1, 0, NADMOD.RefreshOwners)
function NADMOD.IsFriendProp(ply, ent)
if IsValid(ent) && IsValid(ply) && ply:IsPlayer() && NADMOD.Props[ent:EntIndex()] then
local ownerSteamID = NADMOD.Props[ent:EntIndex()].SteamID
if NADMOD.Users[ownerSteamID] then
local friends = NADMOD.Users[ownerSteamID].Friends
return friends && friends[ply:SteamID()]
end
end
return false
end
function NADMOD.PlayerCanTouch(ply, ent)
-- If PP is off or the ent is worldspawn, let them touch it
if not tobool(NADMOD.PPConfig["toggle"]) or ent:IsWorld() then return true end
if !IsValid(ent) or !IsValid(ply) or ent:IsPlayer() or !ply:IsPlayer() then return false end
if not NADMOD.Props[ent:EntIndex()] then
local class = ent:GetClass()
if(string.find(class, "stone_") == 1 or string.find(class, "rock_") == 1 or string.find(class, "stargate_") == 0 or string.find(class, "dhd_") == 0 or class == "flag" or class == "item" or class == "predicted_viewmodel" or class == "gmod_hands" or class == "physgun_beam") then
NADMOD.SetOwnerWorld(ent)
elseif ent.GetPlayer and IsValid(ent:GetPlayer()) then
NADMOD.PlayerMakePropOwner(ent:GetPlayer(), ent)
elseif ent.GetOwner and (IsValid(ent:GetOwner()) or ent:GetOwner():IsWorld()) then
NADMOD.PlayerMakePropOwner(ent:GetOwner(), ent)
elseif ent:EntIndex() == 0 then
-- Players cannot take ownership of EntIndex 0 ents (constraints, func_'s, map lights)
return false
else
NADMOD.PlayerMakePropOwner(ply, ent)
NADMOD.Notify(ply, "You now own this " .. class .. " (" .. string.sub(table.remove(string.Explode("/", ent:GetModel() or "?")), 1,-5) .. ")" )
return true
end
end
if !NADMOD.Props[ent:EntIndex()] then
-- To get here implies the ent has a 'valid' GetPlayer()/GetOwner(), but still couldn't get set properly
-- For example, if an NPC is sitting in jeep (??), the jeep's GetPlayer returns the driver? or something
ent:CPPISetOwnerless(true)
if !NADMOD.Props[ent:EntIndex()] then return end
end
-- Ownerless props can be touched by all
if NADMOD.Props[ent:EntIndex()].Name == "O" then return true end
-- Admins can touch anyones props + world
if NADMOD.PPConfig["adminall"] and NADMOD.IsPPAdmin(ply) then return true end
-- Players can touch their own props and friends
if NADMOD.Props[ent:EntIndex()].SteamID == ply:SteamID() or NADMOD.IsFriendProp(ply, ent) then return true end
return false
end
-- We could hook directly to PlayerCanTouch, but returning true stops other hooks from being called
function NADMOD.PlayerCanTouchSafe(ply, ent)
if !IsValid(ent) or ent:IsPlayer() then return end
if !NADMOD.PlayerCanTouch(ply,ent) then return false end
end
hook.Add("PhysgunPickup", "NADMOD.PhysgunPickup", NADMOD.PlayerCanTouchSafe)
hook.Add("CanProperty", "NADMOD.CanProperty", function(ply, mode, ent) return NADMOD.PlayerCanTouchSafe(ply, ent) end)
hook.Add("CanEditVariable", "NADMOD.CanEditVariable", function(ent, ply, key, val, editor) return NADMOD.PlayerCanTouchSafe(ply, ent) end)
function NADMOD.OnPhysgunReload(weapon, ply)
local tr = util.TraceLine(util.GetPlayerTrace(ply))
if not tr.HitNonWorld or !tr.Entity:IsValid() or tr.Entity:IsPlayer() then return end
if !NADMOD.PlayerCanTouch(ply, tr.Entity) then return false end
end
hook.Add("OnPhysgunReload", "NADMOD.OnPhysgunReload", NADMOD.OnPhysgunReload)
-- Basically just PlayerCanTouchSafe, but world props are fine to gravgun
function NADMOD.GravGunPickup(ply, ent)
if !IsValid(ent) or ent:IsPlayer() then return end
if NADMOD.Props[ent:EntIndex()] and NADMOD.Props[ent:EntIndex()].Name == "W" then return end
if !NADMOD.PlayerCanTouch(ply,ent) then return false end
end
hook.Add("GravGunPunt", "NADMOD.GravGunPunt", NADMOD.GravGunPickup)
hook.Add("GravGunPickupAllowed", "NADMOD.GravGunPickupAllowed", NADMOD.GravGunPickup)
NADMOD.PPWeirdTraces = {"wire_winch","wire_hydraulic","slider","hydraulic","winch","muscle"}
function NADMOD.CanTool(ply, tr, mode)
local ent = tr.Entity
if !ent:IsWorld() and (!ent:IsValid() or ent:IsPlayer()) then return false end
if !NADMOD.PlayerCanTouch(ply, ent) then
if not ((NADMOD.Props[ent:EntIndex()] or {}).Name == "W" and (mode == "wire_debugger" or mode == "wire_adv")) then
return false
end
elseif(mode == "nail") then
local Trace = {}
Trace.start = tr.HitPos
Trace.endpos = tr.HitPos + (ply:GetAimVector() * 16.0)
Trace.filter = {ply, tr.Entity}
local tr2 = util.TraceLine(Trace)
if(tr2.Hit and IsValid(tr2.Entity) and !tr2.Entity:IsPlayer()) then
if(!NADMOD.PlayerCanTouch(ply, tr2.Entity)) then
return false
end
end
elseif(table.HasValue(NADMOD.PPWeirdTraces, mode)) then
local Trace = {}
Trace.start = tr.HitPos
Trace.endpos = Trace.start + (tr.HitNormal * 16384)
Trace.filter = {ply}
local tr2 = util.TraceLine(Trace)
if(tr2.Hit and IsValid(tr2.Entity) and !tr2.Entity:IsPlayer()) then
if(!NADMOD.PlayerCanTouch(ply, tr2.Entity)) then
return false
end
end
elseif(mode == "remover") then
if(ply:KeyDown(IN_ATTACK2) or ply:KeyDownLast(IN_ATTACK2)) then
for k,v in pairs(constraint.GetAllConstrainedEntities(ent) or {}) do
if !NADMOD.PlayerCanTouch(ply, v) then
return false
end
end
end
end
end
hook.Add("CanTool", "NADMOD.CanTool", NADMOD.CanTool)
function NADMOD.PlayerUse(ply, ent)
if !NADMOD.PPConfig["use"] or NADMOD.PlayerCanTouch(ply, ent) or (ent:IsValid() and NADMOD.Props[ent:EntIndex()].Name == "W") then
return
end
return false
end
hook.Add("PlayerUse", "NADMOD.PlayerUse", NADMOD.PlayerUse)
--==========================================================--
-- Ownership Setting Functions --
--==========================================================--
function NADMOD.PlayerMakePropOwner(ply,ent)
if !IsValid(ent) or ent:IsPlayer() then return end
if ply:IsWorld() then return NADMOD.SetOwnerWorld(ent) end
if !IsValid(ply) or !ply:IsPlayer() then return end
NADMOD.Props[ent:EntIndex()] = {
Ent = ent,
Owner = ply,
SteamID = ply:SteamID(),
Name = ply:Nick()
}
NADMOD.PropOwnersSmall[ent:EntIndex()] = ply:Nick()
ent.SPPOwner = ply
end
-- Hook into the cleanup and sbox-limit adding functions to catch most props
if(cleanup) then
local backupcleanupAdd = cleanup.Add
function cleanup.Add(ply, enttype, ent)
if IsValid(ent) and ply:IsPlayer() then
NADMOD.PlayerMakePropOwner(ply, ent)
end
backupcleanupAdd(ply, enttype, ent)
end
end
if(metaply.AddCount) then
local backupAddCount = metaply.AddCount
function metaply:AddCount(enttype, ent)
NADMOD.PlayerMakePropOwner(self, ent)
backupAddCount(self, enttype, ent)
end
end
hook.Add("PlayerSpawnedSENT", "NADMOD.PlayerSpawnedSENT", NADMOD.PlayerMakePropOwner)
hook.Add("PlayerSpawnedVehicle", "NADMOD.PlayerSpawnedVehicle", NADMOD.PlayerMakePropOwner)
hook.Add("PlayerSpawnedSWEP", "NADMOD.PlayerSpawnedSWEP", NADMOD.PlayerMakePropOwner)
function metaent:CPPISetOwnerless(bool)
if !IsValid(self) or self:IsPlayer() then return end
if(bool) then
NADMOD.Props[self:EntIndex()] = {
Ent = self,
Owner = game.GetWorld(),
SteamID = "O",
Name = "O"
}
NADMOD.PropOwnersSmall[self:EntIndex()] = "O"
self.SPPOwner = game.GetWorld()
else
NADMOD.EntityRemoved(self)
end
end
function NADMOD.SetOwnerWorld(ent)
NADMOD.Props[ent:EntIndex()] = {
Ent = ent,
Owner = game.GetWorld(),
SteamID = "W",
Name = "W"
}
NADMOD.PropOwnersSmall[ent:EntIndex()] = "W"
ent.SPPOwner = game.GetWorld()
end
-- Loop through all entities that exist when the map is loaded, these are all "world owned" entities
function NADMOD.WorldOwner()
local WorldEnts = 0
for k,v in pairs(ents.FindByClass("*")) do
if(!v:IsPlayer() and (v:EntIndex() == 0 or !NADMOD.Props[v:EntIndex()])) and not IsValid(v.SPPOwner) then
if game.GetMap() == "gm_construct" and v:GetClass() == "func_brush" then
v:CPPISetOwnerless(true)
else
NADMOD.SetOwnerWorld(v)
end
WorldEnts = WorldEnts + 1
end
end
print("Nadmod Prop Protection: "..WorldEnts.." props belong to world")
end
if CurTime() < 5 then timer.Create("NADMOD.PPFindWorldProps",7,1,NADMOD.WorldOwner) end
function NADMOD.EntityRemoved(ent)
NADMOD.Props[ent:EntIndex()] = nil
NADMOD.PropOwnersSmall[ent:EntIndex()] = "-"
if ent:IsValid() and ent:IsPlayer() and not ent:IsBot() then
-- This is more reliable than PlayerDisconnect
local steamid, nick = ent:SteamID(), ent:Nick()
if NADMOD.PPConfig.autocdp > 0 and (NADMOD.PPConfig.autocdpadmins or not NADMOD.IsPPAdmin(ent)) then
timer.Create("NADMOD.AutoCDP_"..steamid, NADMOD.PPConfig.autocdp, 1, function()
local count = NADMOD.CleanupPlayerProps(steamid)
if count > 0 then NADMOD.Notify(nick.."'s props ("..count..") have been autocleaned.") end
end)
NADMOD.AutoCDPTimers[nick] = steamid
end
end
end
hook.Add("EntityRemoved", "NADMOD.EntityRemoved", NADMOD.EntityRemoved)
-- AutoCDP timer removal
function NADMOD.ClearAutoCDP( ply, steamid, uniqueid )
timer.Remove("NADMOD.AutoCDP_"..steamid)
end
hook.Add( "PlayerAuthed", "NADMOD.ClearAutoCDP", NADMOD.ClearAutoCDP ) -- This occurs at PlayerInitialSpawn, late
hook.Add( "PlayerConnect", "NADMOD.ClearAutoCDP", function(nick, address) -- This occurs early but is unreliable
NADMOD.ClearAutoCDP(nil, NADMOD.AutoCDPTimers[nick] or "")
end)
--==========================================================--
-- Useful Concommands --
--==========================================================--
function NADMOD.CleanupPlayerProps(steamid)
local count = 0
for k,v in pairs(NADMOD.Props) do
if(v.SteamID == steamid) then
if IsValid(v.Ent) then
if !v.Ent:GetPersistent() then
v.Ent:Remove()
count = count + 1
end
else
NADMOD.EntityRemoved(v.Ent)
end
end
end
return count
end
function NADMOD.CleanPlayer(tar)
if IsValid(tar) and tar:IsPlayer() then
local count = NADMOD.CleanupPlayerProps(tar:SteamID())
NADMOD.Notify(tar:Nick().."'s props have been cleaned up ("..count..")")
end
end
function NADMOD.CleanupProps(ply, cmd, args)
local EntIndex = args[1]
if not EntIndex or EntIndex == "" then
local count = NADMOD.CleanupPlayerProps(ply:SteamID())
NADMOD.Notify(ply,"Your props have been cleaned up ("..count..")")
elseif !ply:IsValid() or NADMOD.IsPPAdmin(ply) then
NADMOD.CleanPlayer(Entity(EntIndex))
end
end
concommand.Add("nadmod_cleanupprops", NADMOD.CleanupProps)
function NADMOD.CleanPlayerConCommand(ply, cmd, args, fullstr)
if ply:IsValid() and not NADMOD.IsPPAdmin(ply) then return end
NADMOD.CleanPlayer(NADMOD.FindPlayer(fullstr))
end
concommand.Add("nadmod_cleanplayer", NADMOD.CleanPlayerConCommand)
-- Cleans all props whose owner's name contained arg1. nadmod_cleanplayer is better, but only works on online players
function NADMOD.CleanName(ply, cmd, args, fullstr)
if ply:IsValid() and not NADMOD.IsPPAdmin(ply) then return end
if fullstr == "" or fullstr == "W" then return end
local tarname = string.lower(fullstr)
local count = 0
for k,v in pairs(NADMOD.Props) do
if IsValid(v.Ent) and string.find(string.lower(v.Name),tarname,1,true) then
v.Ent:Remove()
count = count + 1
end
end
NADMOD.Notify(fullstr.."'s props ("..count..") have been cleaned up")
end
concommand.Add("nadmod_cleanname",NADMOD.CleanName)
function NADMOD.CDP(ply, cmd, args)
if ply:IsValid() and not NADMOD.IsPPAdmin(ply) then return end
local count = 0
for k,v in pairs(NADMOD.Props) do
if not v.Ent:IsValid() then
NADMOD.EntityRemoved(v.Ent)
elseif not IsValid(v.Owner) and (v.Name != "O" and v.Name != "W") and !v.Ent:GetPersistent() then
v.Ent:Remove()
count = count + 1
end
end
NADMOD.Notify("Disconnected players props ("..count..") have been cleaned up")
end
concommand.Add("nadmod_cdp",NADMOD.CDP)
function NADMOD.CleanClass(ply,cmd,args)
if ply:IsValid() and not NADMOD.IsPPAdmin(ply) then return end
if args[1] == "npc_*" then NADMOD.Notify("NPCs have been cleaned up")
elseif args[1] == "prop_ragdol*" then NADMOD.Notify("Ragdolls have been cleaned up")
else NADMOD.Notify(args[1].." have been cleaned up")
end
for _,v in ipairs(ents.FindByClass(args[1])) do v:Remove() end
end
concommand.Add("nadmod_cleanclass", NADMOD.CleanClass)
function NADMOD.CleanCLRagdolls(ply,cmd,args)
if ply:IsValid() and not NADMOD.IsPPAdmin(ply) then return end
NADMOD.Notify("Clientside Ragdolls have been cleaned up")
net.Start("nadmod_cleanclragdolls") net.Broadcast()
game.RemoveRagdolls()
end
concommand.Add("nadmod_cleanclragdolls", NADMOD.CleanCLRagdolls)
function NADMOD.CleanWorldRopes(ply,cmd,args)
if ply:IsValid() and not NADMOD.IsPPAdmin(ply) then return end
NADMOD.Notify("World ropes have been cleaned up")
for k,v in pairs(ents.FindByClass("keyframe_rope")) do
if v.Ent1 and v.Ent1:IsWorld() and v.Ent2 and v.Ent2:IsWorld() then v:Remove() end
end
end
concommand.Add("nadmod_cleanworldropes", NADMOD.CleanWorldRopes)
-- Sends a Hint to the player specified
-- If only one argument, broadcast to all players
function NADMOD.Notify(ply, text)
net.Start("nadmod_notify")
if not text then
net.WriteString(ply)
net.Broadcast()
print("NADMOD: "..ply)
else
net.WriteString(text)
net.Send(ply)
end
end
function NADMOD.DebugTotals(ply,cmd,args)
-- Prints out a list of how many props are owned by each player.
-- This information is available in the clientside admin panel, but this is nice for rcon
if IsValid(ply) then return end -- PrintTable only shows in serverconsole
local tab = {}
for k,v in pairs(NADMOD.Props) do
local name = v.Name
if name == "O" then name = "Ownerless"
elseif name == "W" then name = "World"
elseif not v.SPPOwner:IsValid() then name = "[Disconnected]"..name
end
tab[name] = (tab[name] or 0) + 1
end
PrintTable(tab)
end
concommand.Add("nadmod_totals", NADMOD.DebugTotals)
--=========================================================--
-- Clientside Callbacks for the Friends/Options panels --
--=========================================================--
concommand.Add("npp_refreshconfig",function(ply,cmd,args)
if not ply:IsValid() or not NADMOD.IsPPAdmin(ply) then return end
net.Start("nadmod_ppconfig")
net.WriteTable(NADMOD.PPConfig)
net.Send(ply)
end)
net.Receive("nadmod_ppconfig",function(len,ply)
if not ply:IsValid() or not NADMOD.IsPPAdmin(ply) then return end
NADMOD.PPConfig = net.ReadTable()
NADMOD.Save()
NADMOD.Notify(ply, "Settings received!")
end)
concommand.Add("npp_refreshfriends",function(ply,cmd,args)
if not ply:IsValid() then return end
local friends = {}
if NADMOD.Users[ply:SteamID()] then friends = table.Copy(NADMOD.Users[ply:SteamID()].Friends) or {} end
if NADMOD.PPConfig["adminall"] then
for _,v in pairs(player.GetAll()) do
if NADMOD.IsPPAdmin(v) then friends[v:SteamID()] = true end
end
end
net.Start("nadmod_ppfriends")
net.WriteTable(friends)
net.Send(ply)
end)
net.Receive("nadmod_ppfriends",function(len,ply)
if not ply:IsValid() then return end
if !NADMOD.Users[ply:SteamID()] then NADMOD.Users[ply:SteamID()] = {Rank = 1} end
NADMOD.Users[ply:SteamID()].Friends = NADMOD.Users[ply:SteamID()].Friends or {}
local outtab = NADMOD.Users[ply:SteamID()].Friends
local players = {}
for _,v in pairs(player.GetAll()) do players[v:SteamID()] = v end
for steamid,bool in pairs(net.ReadTable()) do
if players[steamid] and (not bool or not (NADMOD.IsPPAdmin(players[steamid]) and NADMOD.PPConfig["adminall"])) then -- Users may not add admins to their friends list
if bool then outtab[steamid] = true else outtab[steamid] = nil end -- Don't bother storing falses
end
end
NADMOD.Save()
NADMOD.Notify(ply, "Friends received!")
end)
function CPPI:GetName() return "Nadmod Prop Protection" end
function CPPI:GetVersion() return NADMOD.PPVersion end
function metaply:CPPIGetFriends()
if not self:IsValid() then return {} end
local ret = {}
local friends = (NADMOD.Users[self:SteamID()] or {Friends={}}).Friends or {}
for _,v in pairs(player.GetAll()) do
if NADMOD.IsPPAdmin(v) or friends[v:SteamID()] then table.insert(ret,v) end
end
return ret
end
function metaent:CPPIGetOwner() return self.SPPOwner end
function metaent:CPPISetOwner(ply) return NADMOD.PlayerMakePropOwner(ply, self) end
function metaent:CPPICanTool(ply,mode) return NADMOD.CanTool(ply,{Entity=self},mode) != false end
function metaent:CPPICanPhysgun(ply) return NADMOD.PlayerCanTouch(ply,self) == true end
function metaent:CPPICanPickup(ply) return NADMOD.GravGunPickup(ply, self) != false end
function metaent:CPPICanPunt(ply) return NADMOD.GravGunPickup(ply, self) != false end
if E2Lib and E2Lib.replace_function then
E2Lib.replace_function("isOwner", function(ply, entity)
return NADMOD.PlayerCanTouch(ply,entity)
end)
end
print("[NADMOD PP - NADMOD Prop Protection Module v"..NADMOD.PPVersion.." Loaded]")