FPP = FPP or {} util.AddNetworkString("FPP_Groups") util.AddNetworkString("FPP_GroupMembers") util.AddNetworkString("FPP_RestrictedToolList") util.AddNetworkString("FPP_BlockedModels") FPP.Blocked = FPP.Blocked or {} FPP.Blocked.Physgun1 = FPP.Blocked.Physgun1 or {} FPP.Blocked.Spawning1 = FPP.Blocked.Spawning1 or {} FPP.Blocked.Gravgun1 = FPP.Blocked.Gravgun1 or {} FPP.Blocked.Toolgun1 = FPP.Blocked.Toolgun1 or {} FPP.Blocked.PlayerUse1 = FPP.Blocked.PlayerUse1 or {} FPP.Blocked.EntityDamage1 = FPP.Blocked.EntityDamage1 or {} FPP.BlockedModels = FPP.BlockedModels or {} FPP.RestrictedTools = FPP.RestrictedTools or {} FPP.RestrictedToolsPlayers = FPP.RestrictedToolsPlayers or {} FPP.Groups = FPP.Groups or {} FPP.GroupMembers = FPP.GroupMembers or {} function FPP.Notify(ply, text, bool, total_time) if ply:EntIndex() == 0 then ServerLog(text) return end umsg.Start("FPP_Notify", ply) umsg.String(text) umsg.Bool(bool) umsg.Float(total_time or 6) umsg.End() ply:PrintMessage(HUD_PRINTCONSOLE, text) end function FPP.NotifyAll(text, bool, total_time) umsg.Start("FPP_Notify") umsg.String(text) umsg.Bool(bool) umsg.Float(total_time or 6) umsg.End() for _, ply in ipairs(player.GetAll()) do ply:PrintMessage(HUD_PRINTCONSOLE, text) end end local function getSettingsChangedEntities(settingsType, setting) local plys, entities = {}, {} local blockedString = string.sub(settingsType, 5, 5) .. string.lower(string.sub(settingsType, 6)) blockedString = blockedString == "Playeruse1" and "PlayerUse1" or blockedString -- dirty hack for stupid naming system. blockedString = blockedString == "Entitydamage1" and "EntityDamage1" or blockedString -- dirty hack for stupid naming system. if setting == "adminall" then for _, v in ipairs(ents.GetAll()) do if not IsValid(v) then continue end local owner = v:CPPIGetOwner() if IsValid(owner) then table.insert(entities, v) end end for _, v in ipairs(player.GetAll()) do v.FPP_Privileges = v.FPP_Privileges or {} if v.FPP_Privileges.FPP_TouchOtherPlayersProps then table.insert(plys, v) end end return plys, entities elseif setting == "worldprops" or setting == "adminworldprops" then for _, v in ipairs(ents.GetAll()) do if FPP.Blocked[blockedString][string.lower(v:GetClass())] then continue end local owner = v:CPPIGetOwner() if not IsValid(owner) then table.insert(entities, v) end end for _, v in ipairs(player.GetAll()) do v.FPP_Privileges = v.FPP_Privileges or {} if v.FPP_Privileges.FPP_TouchOtherPlayersProps then table.insert(plys, v) end end return setting == "adminworldprops" and plys or player.GetAll(), entities elseif setting == "canblocked" or setting == "admincanblocked" then for _, v in ipairs(ents.GetAll()) do if not FPP.Blocked[blockedString][string.lower(v:GetClass())] then continue end table.insert(entities, v) end for _, v in ipairs(player.GetAll()) do v.FPP_Privileges = v.FPP_Privileges or {} if v.FPP_Privileges.FPP_TouchOtherPlayersProps then table.insert(plys, v) end end return setting == "admincanblocked" and plys or player.GetAll(), entities elseif setting == "iswhitelist" then return player.GetAll(), ents.GetAll() end end util.AddNetworkString("FPP_Settings") local function SendSettings(ply) net.Start("FPP_Settings") FPP.ForAllSettings(function(k, s, v) net.WriteDouble(v) end) net.Send(ply) end util.AddNetworkString("FPP_Settings_Update") local function updateFPPSetting(kind, setting, value) local skipKind, skipSetting = 0, 0 FPP.Settings[kind][setting] = value local finalSkipKind FPP.ForAllSettings(function(k, s) skipKind = skipKind + 1 if k ~= kind then return true end finalSkipKind = skipKind - skipSetting skipSetting = skipSetting + 1 if s ~= setting then return end return true end) net.Start("FPP_Settings_Update") net.WriteUInt(finalSkipKind, 8) net.WriteUInt(skipSetting, 8) net.WriteDouble(value) net.Broadcast() end local function runIfAccess(priv, f) return function(ply, cmd, args) CAMI.PlayerHasAccess(ply, priv, function(allowed, _) if allowed then return f(ply, cmd, args) end FPP.Notify(ply, string.format("You need the '%s' privilege in order to be able to use this command", priv), false) end) end end local function FPP_SetSetting(ply, cmd, args) if not args[1] then FPP.Notify(ply, "FPP_setting: First argument (setting name) not given!", false) return end if not args[3] then FPP.Notify(ply, "FPP_setting: Third argument (the value of the setting) not given", false) return end if not FPP.Settings[args[1]] then FPP.Notify(ply, ("FPP_setting: Setting %s does not exist! Settings that DO exist:"):format(args[1]), false) for setting, _ in pairs(FPP.Settings) do FPP.Notify(ply, setting, false) end return end if not FPP.Settings[args[1]][args[2]] then FPP.Notify(ply, ("FPP_setting: Setting %s.%s does not exist!"):format(args[1], args[2]), false) return end updateFPPSetting(args[1], args[2], tonumber(args[3])) MySQLite.queryValue("SELECT var FROM " .. args[1] .. " WHERE var = " .. sql.SQLStr(args[2]) .. ";", function(data) if not data then MySQLite.query("INSERT INTO " .. args[1] .. " VALUES(" .. sql.SQLStr(args[2]) .. ", " .. args[3] .. ");") elseif tonumber(data) ~= args[3] then MySQLite.query("UPDATE " .. args[1] .. " SET setting = " .. args[3] .. " WHERE var = " .. sql.SQLStr(args[2]) .. ";") end FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " set " .. string.lower(string.gsub(args[1], "FPP_", "")) .. " " .. args[2] .. " to " .. tostring(args[3]), tobool(tonumber(args[3]))) end) FPP.calculatePlayerPrivilege("FPP_TouchOtherPlayersProps", function() local plys, entities = getSettingsChangedEntities(args[1], args[2]) if not plys or not entities or #plys == 0 or #entities == 0 then return end FPP.recalculateCanTouch(plys, entities) end) end concommand.Add("FPP_setting", runIfAccess("FPP_Settings", FPP_SetSetting)) local function AddBlocked(ply, cmd, args) if not args[1] then FPP.Notify(ply, "FPP_AddBlocked: Block list not given", false) return end if not args[2] then FPP.Notify(ply, "FPP_AddBlocked: Entity to block not given", false) return end if not FPP.Blocked[args[1]] then FPP.Notify(ply, ("FPP_AddBlocked: Block list %s does not exist"):format(args[1]), false) return end args[2] = string.lower(args[2]) if FPP.Blocked[args[1]][args[2]] then return end FPP.Blocked[args[1]][args[2]] = true MySQLite.query(string.format("INSERT INTO FPP_BLOCKED1 (var, setting) VALUES(%s, %s);", sql.SQLStr(args[1]), sql.SQLStr(args[2]))) FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " added " .. args[2] .. " to the " .. args[1] .. " black/whitelist", true) FPP.recalculateCanTouch(player.GetAll(), ents.FindByClass(args[2])) end concommand.Add("FPP_AddBlocked", runIfAccess("FPP_Settings", AddBlocked)) -- Models can differ between server and client. Famous example being: -- models/props_phx/cannonball_solid.mdl <-- serverside -- models/props_phx/cannonball.mdl <-- clientside -- Similar problems occur with effects local function getIntendedBlockedModels(model, ent) model = string.Replace(string.lower(model), "\\", "/") if not IsValid(ent) then return {model} end if ent:GetClass() == "prop_effect" then return {ent.AttachedEntity:GetModel()} end if model ~= ent:GetModel() then return {model, ent:GetModel()} end return {model} end local function AddBlockedModel(ply, cmd, args) if not args[1] then FPP.Notify(ply, "FPP_AddBlockedModel: Model not given", false) return end local models = getIntendedBlockedModels(args[1], tonumber(args[2]) and Entity(args[2]) or nil) for _, model in pairs(models) do if FPP.BlockedModels[model] then FPP.Notify(ply, string.format([["%s" is already in the black/whitelist]], model), false) continue end FPP.BlockedModels[model] = true MySQLite.query("REPLACE INTO FPP_BLOCKEDMODELS1 VALUES(" .. sql.SQLStr(model) .. ");") FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " added " .. model .. " to the blocked models black/whitelist", true) end end concommand.Add("FPP_AddBlockedModel", runIfAccess("FPP_Settings", AddBlockedModel)) local function RemoveBlocked(ply, cmd, args) if not args[1] then FPP.Notify(ply, "FPP_RemoveBlocked: Block list not given", false) return end if not args[2] then FPP.Notify(ply, "FPP_RemoveBlocked: Entity to block not given", false) return end if not FPP.Blocked[args[1]] then FPP.Notify(ply, ("FPP_RemoveBlocked: Block list %s does not exist"):format(args[1]), false) return end FPP.Blocked[args[1]][args[2]] = nil MySQLite.query("DELETE FROM FPP_BLOCKED1 WHERE var = " .. sql.SQLStr(args[1]) .. " AND setting = " .. sql.SQLStr(args[2]) .. ";") FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " removed " .. args[2] .. " from the " .. args[1] .. " black/whitelist", false) FPP.recalculateCanTouch(player.GetAll(), ents.FindByClass(args[2])) end concommand.Add("FPP_RemoveBlocked", runIfAccess("FPP_Settings", RemoveBlocked)) local function RemoveBlockedModel(ply, cmd, args) if not args[1] then FPP.Notify(ply, "FPP_RemoveBlockedModel: Model not given", false) return end local models = getIntendedBlockedModels(args[1], tonumber(args[2]) and Entity(args[2]) or nil) for _, model in pairs(models) do FPP.BlockedModels[model] = nil MySQLite.query("DELETE FROM FPP_BLOCKEDMODELS1 WHERE model = " .. sql.SQLStr(model) .. ";") FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " removed " .. model .. " from the blocked models black/whitelist", false) end end concommand.Add("FPP_RemoveBlockedModel", runIfAccess("FPP_Settings", RemoveBlockedModel)) local allowedShares = { SharePhysgun1 = true, ShareGravgun1 = true, SharePlayerUse1 = true, ShareEntityDamage1 = true, ShareToolgun1 = true } local function ShareProp(ply, cmd, args) if not args[1] then FPP.Notify(ply, "FPP_ShareProp: Entity not given", false) return end if not IsValid(Entity(args[1])) then FPP.Notify(ply, "FPP_ShareProp: Entity not valid", false) return end if not args[2] then FPP.Notify(ply, "FPP_ShareProp: Player to share with not given", false) return end local ent = Entity(args[1]) if ent:CPPIGetOwner() ~= ply then FPP.Notify(ply, "You do not have the right to share this entity.", false) return end if not tonumber(args[2]) or not IsValid(Player(tonumber(args[2]))) then -- This is for sharing prop per utility if not allowedShares[args[2]] then FPP.Notify(ply, "FPP_ShareProp: Player to share with doesn't exist", false) return end ent[args[2]] = tobool(args[3]) else -- This is for sharing prop per player local target = Player(tonumber(args[2])) local toggle = tobool(args[3]) -- Make the table if it isn't there if not ent.AllowedPlayers and toggle then ent.AllowedPlayers = {target} else if toggle and not table.HasValue(ent.AllowedPlayers, target) then table.insert(ent.AllowedPlayers, target) FPP.Notify(target, ply:Nick() .. " shared an entity with you!", true) elseif not toggle then for k, v in pairs(ent.AllowedPlayers or {}) do if v == target then table.remove(ent.AllowedPlayers, k) FPP.Notify(target, ply:Nick() .. " unshared an entity with you!", false) end end end end end FPP.recalculateCanTouch(player.GetAll(), {ent}) end concommand.Add("FPP_ShareProp", ShareProp) local function RetrieveSettings() MySQLite.begin() for k in pairs(FPP.Settings) do MySQLite.queueQuery("SELECT setting, var FROM " .. k .. ";", function(data) if not data then return end for _, value in pairs(data) do if FPP.Settings[k][value.var] == nil then -- Likely an old setting that has since been removed from FPP. -- This setting however still exists in the DB. Time to remove it. MySQLite.query("DELETE FROM " .. k .. " WHERE var = " .. sql.SQLStr(value.var) .. ";") continue end FPP.Settings[k][value.var] = tonumber(value.setting) end end) end MySQLite.commit(function() SendSettings(player.GetAll()) end) end local defaultBlocked = { Physgun1 = { ["func_breakable_surf"] = true, ["func_brush"] = true, ["func_button"] = true, ["func_door"] = true, ["prop_door_rotating"] = true, ["func_door_rotating"] = true }, Spawning1 = { ["func_breakable_surf"] = true, ["player"] = true, ["func_door"] = true, ["prop_door_rotating"] = true, ["func_door_rotating"] = true, ["ent_explosivegrenade"] = true, ["ent_mad_grenade"] = true, ["ent_flashgrenade"] = true, ["gmod_wire_field_device"] = true }, Gravgun1 = {["func_breakable_surf"] = true, ["vehicle_"] = true}, Toolgun1 = { ["func_breakable_surf"] = true, ["func_button"] = true, ["player"] = true, ["func_door"] = true, ["prop_door_rotating"] = true, ["func_door_rotating"] = true }, PlayerUse1 = {}, EntityDamage1 = {} } -- Fills the FPP blocked table with default things that are to be blocked function FPP.FillDefaultBlocked() local count = 0 MySQLite.begin() -- All values that are to be inserted local allValues = {} for k, v in pairs(defaultBlocked) do for a in pairs(v) do FPP.Blocked[k][a] = true count = count + 1 if not MySQLite.isMySQL() then MySQLite.query("REPLACE INTO FPP_BLOCKED1 VALUES(" .. count .. ", " .. sql.SQLStr(k) .. ", " .. sql.SQLStr(a) .. ");") else table.insert(allValues, string.format("(%i, %s, %s)", count, sql.SQLStr(k), sql.SQLStr(a))) end end end -- Run it all in a single query if using MySQL. if MySQLite.isMySQL() then MySQLite.query(string.format("INSERT IGNORE INTO FPP_BLOCKED1 VALUES %s", table.concat(allValues, ","))) end MySQLite.commit() end local function RetrieveBlocked() MySQLite.query("SELECT * FROM FPP_BLOCKED1;", function(data) if istable(data) then for _, v in pairs(data) do if not FPP.Blocked[v.var] then ErrorNoHalt((v.var or "(nil var)") .. " blocked type does not exist! (Setting: " .. (v.setting or "") .. ")") continue end FPP.Blocked[v.var][string.lower(v.setting)] = true end else -- Give third party addons 5 seconds to add default blocked items timer.Simple(5, FPP.FillDefaultBlocked) end end) end --[[------------------------------------------------------------------------- Default blocked entities Only save in the database on first start ---------------------------------------------------------------------------]] function FPP.AddDefaultBlocked(types, classname) classname = string.lower(classname) if isstring(types) then defaultBlocked[types] = defaultBlocked[types] or {} defaultBlocked[types][classname] = true return end for _, v in pairs(types) do defaultBlocked[v] = defaultBlocked[v] or {} defaultBlocked[v][classname] = true end end local function RetrieveBlockedModels() FPP.BlockedModels = FPP.BlockedModels or {} -- Sometimes when the database retrieval is corrupt, -- only parts of the table will be retrieved -- This is a workaround if not MySQLite.isMySQL() then local count = MySQLite.queryValue("SELECT COUNT(*) FROM FPP_BLOCKEDMODELS1;") or 0 if tonumber(count) == 0 then FPP.AddDefaultBlockedModels() -- Load the default blocked models on first run end -- Select with offsets of a thousand. -- That's about the maximum it can receive properly at once for i = 0, count, 1000 do MySQLite.query("SELECT * FROM FPP_BLOCKEDMODELS1 LIMIT 1000 OFFSET " .. i .. ";", function(data) for _, v in ipairs(data or {}) do FPP.BlockedModels[v.model] = true end end) end return end -- Retrieve the data normally from MySQL MySQLite.query("SELECT * FROM FPP_BLOCKEDMODELS1;", function(data) if not data or #data == 0 then FPP.AddDefaultBlockedModels() -- Load the default blocked models on first run end for _, v in ipairs(data or {}) do if not v.model then continue end FPP.BlockedModels[v.model] = true end end) end local function RetrieveRestrictedTools() MySQLite.query("SELECT * FROM FPP_TOOLADMINONLY;", function(data) if istable(data) then for _, v in ipairs(data) do FPP.RestrictedTools[v.toolname] = {} FPP.RestrictedTools[v.toolname]["admin"] = tonumber(v.adminonly) end end end) MySQLite.query("SELECT * FROM FPP_TOOLRESTRICTPERSON1;", function(perplayerData) if not istable(perplayerData) then return end for _, v in ipairs(perplayerData) do FPP.RestrictedToolsPlayers[v.toolname] = FPP.RestrictedToolsPlayers[v.toolname] or {} FPP.RestrictedToolsPlayers[v.toolname][v.steamid] = tobool(v.allow) end end) MySQLite.query("SELECT * FROM FPP_TOOLTEAMRESTRICT;", function(data) if not data then return end for _, v in ipairs(data) do FPP.RestrictedTools[v.toolname] = FPP.RestrictedTools[v.toolname] or {} FPP.RestrictedTools[v.toolname]["team"] = FPP.RestrictedTools[v.toolname]["team"] or {} table.insert(FPP.RestrictedTools[v.toolname]["team"], tonumber(v.team)) end end) end local function RetrieveGroups() MySQLite.query("SELECT * FROM FPP_GROUPS3;", function(data) if not istable(data) then MySQLite.query("REPLACE INTO FPP_GROUPS3 VALUES('default', 1);") FPP.Groups["default"] = {} FPP.Groups["default"].tools = {} FPP.Groups["default"].allowdefault = true return end -- if there are no groups then there isn't much to load for _, v in ipairs(data) do FPP.Groups[v.groupname] = {} FPP.Groups[v.groupname].tools = {} FPP.Groups[v.groupname].allowdefault = tobool(v.allowdefault) end MySQLite.query("SELECT * FROM FPP_GROUPTOOL;", function(grouptooldata) if not grouptooldata then return end for _, v in ipairs(grouptooldata) do FPP.Groups[v.groupname] = FPP.Groups[v.groupname] or {} FPP.Groups[v.groupname].tools = FPP.Groups[v.groupname].tools or {} table.insert(FPP.Groups[v.groupname].tools, v.tool) end end) MySQLite.query("SELECT * FROM FPP_GROUPMEMBERS1;", function(members) if not istable(members) then return end for _, v in ipairs(members) do FPP.GroupMembers[v.steamid] = v.groupname end end) end) end hook.Add("PlayerInitialSpawn", "FPP_SendSettings", SendSettings) local function AddGroup(ply, cmd, args) if not args[1] then FPP.Notify(ply, "Invalid argument(s)", false) return end-- Args: 1 = name, optional: 2 = allowdefault local name = string.lower(args[1]) local allowdefault = tonumber(args[2]) or 1 if FPP.Groups[name] then FPP.Notify(ply, "Group already exists", false) return end FPP.Groups[name] = {} FPP.Groups[name].allowdefault = tobool(allowdefault) FPP.Groups[name].tools = {} MySQLite.query("REPLACE INTO FPP_GROUPS3 VALUES(" .. sql.SQLStr(name) .. ", " .. sql.SQLStr(allowdefault) .. ");") FPP.Notify(ply, "Group added successfully", true) end concommand.Add("FPP_AddGroup", runIfAccess("FPP_Settings", AddGroup)) hook.Add("InitPostEntity", "FPP_Load_CAMI", function() if not CAMI then return end for groupName, _ in pairs(CAMI.GetUsergroups()) do if FPP.Groups[groupName] then continue end FPP.Groups[groupName] = {} FPP.Groups[groupName].allowdefault = true FPP.Groups[groupName].tools = {} end end) local function RemoveGroup(ply, cmd, args) if not args[1] then FPP.Notify(ply, "Invalid argument(s)", false) return end-- Args: 1 = name local name = string.lower(args[1]) if not FPP.Groups[name] then FPP.Notify(ply, "Group does not exists", false) return end if name == "default" then FPP.Notify(ply, "Can not remove default group", false) return end FPP.Groups[name] = nil MySQLite.query("DELETE FROM FPP_GROUPS3 WHERE groupname = " .. sql.SQLStr(name) .. ";") MySQLite.query("DELETE FROM FPP_GROUPTOOL WHERE groupname = " .. sql.SQLStr(name) .. ";") for k, v in pairs(FPP.GroupMembers) do if v == name then FPP.GroupMembers[k] = nil -- Set group to standard if group is removed end end FPP.Notify(ply, "Group removed successfully", true) end concommand.Add("FPP_RemoveGroup", runIfAccess("FPP_Settings", RemoveGroup)) local function GroupChangeAllowDefault(ply, cmd, args) if not args[2] then FPP.Notify(ply, "Invalid argument(s)", false) return end-- Args: 1 = groupname, 2 = new value 1/0 local name = string.lower(args[1]) local newval = tonumber(args[2]) if not FPP.Groups[name] then FPP.Notify(ply, "Group does not exists", false) return end FPP.Groups[name].allowdefault = tobool(newval) MySQLite.query("REPLACE INTO FPP_GROUPS3 VALUES(" .. sql.SQLStr(name) .. ", " .. sql.SQLStr(newval) .. ");") FPP.Notify(ply, "Group status changed successfully", true) end concommand.Add("FPP_ChangeGroupStatus", runIfAccess("FPP_Settings", GroupChangeAllowDefault)) local function GroupAddTool(ply, cmd, args) if not args[2] then FPP.Notify(ply, "Invalid argument(s)", false) return end-- Args: 1 = groupname, 2 = tool local name = args[1] local tool = string.lower(args[2]) if not FPP.Groups[name] then FPP.Notify(ply, "Group does not exists", false) return end FPP.Groups[name].tools = FPP.Groups[name].tools or {} if table.HasValue(FPP.Groups[name].tools, tool) then FPP.Notify(ply, "Tool is already in group!", false) return end table.insert(FPP.Groups[name].tools, tool) MySQLite.query("REPLACE INTO FPP_GROUPTOOL VALUES(" .. sql.SQLStr(name) .. ", " .. sql.SQLStr(tool) .. ");") FPP.Notify(ply, "Tool added successfully", true) end concommand.Add("FPP_AddGroupTool", runIfAccess("FPP_Settings", GroupAddTool)) local function GroupRemoveTool(ply, cmd, args) if not args[2] then FPP.Notify(ply, "Invalid argument(s)", false) return end-- Args: 1 = groupname, 2 = tool local name = args[1] local tool = string.lower(args[2]) if not FPP.Groups[name] then FPP.Notify(ply, "Group does not exists", false) return end if not table.HasValue(FPP.Groups[name].tools, tool) then FPP.Notify(ply, "Tool does not exist in group!", false) return end for k, v in pairs(FPP.Groups[name].tools) do if v == tool then table.remove(FPP.Groups[name].tools, k) end end MySQLite.query("DELETE FROM FPP_GROUPTOOL WHERE groupname = " .. sql.SQLStr(name) .. " AND tool = " .. sql.SQLStr(tool) .. ";") FPP.Notify(ply, "Tool removed successfully", true) end concommand.Add("FPP_RemoveGroupTool", runIfAccess("FPP_Settings", GroupRemoveTool)) -- Args: 1 = player, 2 = group local function PlayerSetGroup(ply, cmd, args) if not args[2] then FPP.Notify(ply, "Group not given", false) return end local name = args[1] local group = string.lower(args[2]) if IsValid(Player(tonumber(name) or 0)) then name = Player(tonumber(name)):SteamID() elseif not string.find(name, "STEAM") and name ~= "UNKNOWN" and name ~= "BOT" then FPP.Notify(ply, "Player not found", false) return end if not FPP.Groups[group] and (not CAMI or not CAMI.GetUsergroup(group)) then FPP.Notify(ply, "Group does not exists", false) return end if group ~= "default" then MySQLite.query("REPLACE INTO FPP_GROUPMEMBERS1 VALUES(" .. sql.SQLStr(name) .. ", " .. sql.SQLStr(group) .. ");") FPP.GroupMembers[name] = group else FPP.GroupMembers[name] = nil MySQLite.query("DELETE FROM FPP_GROUPMEMBERS1 WHERE steamid = " .. sql.SQLStr(name) .. ";") end FPP.Notify(ply, "Player group successfully set", true) end concommand.Add("FPP_SetPlayerGroup", runIfAccess("FPP_Settings", PlayerSetGroup)) local function SendGroupData(ply, cmd, args) net.Start("FPP_Groups") net.WriteTable(FPP.Groups) net.Send(ply) end concommand.Add("FPP_SendGroups", runIfAccess("FPP_Settings", SendGroupData)) local function SendGroupMemberData(ply, cmd, args) net.Start("FPP_GroupMembers") net.WriteTable(FPP.GroupMembers) net.Send(ply) end concommand.Add("FPP_SendGroupMembers", runIfAccess("FPP_Settings", SendGroupMemberData)) local function SendBlocked(ply, cmd, args) if not args[1] or not FPP.Blocked[args[1]] then return end ply.FPPUmsg1 = ply.FPPUmsg1 or {} ply.FPPUmsg1[args[1]] = ply.FPPUmsg1[args[1]] or 0 if ply.FPPUmsg1[args[1]] > CurTime() - 5 then return end ply.FPPUmsg1[args[1]] = CurTime() for k in pairs(FPP.Blocked[args[1]]) do umsg.Start("FPP_blockedlist", ply) umsg.String(args[1]) umsg.String(k) umsg.End() end end concommand.Add("FPP_sendblocked", SendBlocked) local function SendBlockedModels(ply, cmd, args) ply.FPPUmsg2 = ply.FPPUmsg2 or 0 if ply.FPPUmsg2 > CurTime() - 10 then return end ply.FPPUmsg2 = CurTime() local models = {} for k in pairs(FPP.BlockedModels) do table.insert(models, k) end local data = util.Compress(table.concat(models, "\0")) if not data then return end net.Start("FPP_BlockedModels") net.WriteData(data, #data) net.Send(ply) end concommand.Add("FPP_sendblockedmodels", SendBlockedModels) local function SendRestrictedTools(ply, cmd, args) ply.FPPUmsg3 = ply.FPPUmsg3 or 0 if ply.FPPUmsg3 > CurTime() - 5 then return end ply.FPPUmsg3 = CurTime() if not args[1] then return end net.Start("FPP_RestrictedToolList") net.WriteString(args[1]) -- tool name net.WriteUInt(FPP.RestrictedTools[args[1]] and FPP.RestrictedTools[args[1]].admin or 0, 2) -- user, admin or superadmin local teams = FPP.RestrictedTools[args[1]] and FPP.RestrictedTools[args[1]].team or {} net.WriteUInt(#teams, 10) for _, t in pairs(teams) do net.WriteUInt(t, 10) end net.Send(ply) end concommand.Add("FPP_SendRestrictTool", SendRestrictedTools) -- Fallback owner, will own entities after disconnect local function setFallbackOwner(ply, fallback) ply.FPPFallbackOwner = fallback:SteamID() end local function changeFallbackOwner(ply, _, args) local fallback = tonumber(args[1]) and Player(tonumber(args[1])) if tonumber(args[1]) == -1 then ply.FPPFallbackOwner = nil FPP.Notify(ply, "Fallback owner set", true) return end if not IsValid(fallback) or not fallback:IsPlayer() or fallback == ply then FPP.Notify(ply, "Player invalid", false) return end setFallbackOwner(ply, fallback) FPP.Notify(ply, "Fallback owner set", true) end concommand.Add("FPP_FallbackOwner", changeFallbackOwner) --Buddies! local function changeBuddies(ply, buddy, settings) if not IsValid(ply) then return end ply.Buddies = ply.Buddies or {} ply.Buddies[buddy] = settings local CPPIBuddies = {} for k, v in pairs(ply.Buddies) do if table.HasValue(v, true) then table.insert(CPPIBuddies, k) end end -- Also run at player spawn because clients send their buddies through this command hook.Run("CPPIFriendsChanged", ply, CPPIBuddies) -- Update the prop protection local affectedProps = {} for _, v in ipairs(ents.GetAll()) do local owner = v:CPPIGetOwner() if owner ~= ply then continue end table.insert(affectedProps, v) end FPP.recalculateCanTouch({buddy}, affectedProps) FPP.RecalculateConstrainedEntities({buddy}, affectedProps) end local function SetBuddy(ply, cmd, args) if not args[6] then FPP.Notify(ply, "FPP_SetBuddy: Not enough arguments given!", false) return end local buddy = tonumber(args[1]) and Player(tonumber(args[1])) if not IsValid(buddy) then FPP.Notify(ply, "Player invalid", false) return end for k, v in pairs(args) do args[k] = tonumber(v) end local settings = {Physgun = tobool(args[2]), Gravgun = tobool(args[3]), Toolgun = tobool(args[4]), PlayerUse = tobool(args[5]), EntityDamage = tobool(args[6])} -- Antispam measure timer.Create("FPP_BuddiesUpdate" .. ply:UserID() .. ", " .. buddy:UserID(), 1, 1, function() changeBuddies(ply, buddy, settings) end) end concommand.Add("FPP_SetBuddy", SetBuddy) local function CleanupDisconnected(ply, cmd, args) if not args[1] then FPP.Notify(ply, "Invalid argument", false) return end if args[1] == "disconnected" then for _, v in ipairs(ents.GetAll()) do local owner = v:CPPIGetOwner() if owner and not IsValid(owner) then v:Remove() end end FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " removed all disconnected players' props", true) return elseif not tonumber(args[1]) or not IsValid(Player(tonumber(args[1]))) then FPP.Notify(ply, "Invalid player", false) return end local target_ply = Player(args[1]) for _, v in ipairs(ents.GetAll()) do local owner = v:CPPIGetOwner() if owner == target_ply then if v:IsWeapon() and IsValid(v:GetOwner()) then continue end v:Remove() end end FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " removed " .. target_ply:Nick() .. "'s entities", true) end concommand.Add("FPP_Cleanup", runIfAccess("FPP_Cleanup", CleanupDisconnected)) local function SetToolRestrict(ply, cmd, args) if not args[3] then FPP.Notify(ply, "Invalid argument(s)", false) return end--FPP_restricttool local toolname = args[1] local RestrictWho = tonumber(args[2]) or args[2]-- "team" or "admin" local teamtoggle = tonumber(args[4]) --this argument only exists when restricting a tool for a team FPP.RestrictedTools[toolname] = FPP.RestrictedTools[toolname] or {} if RestrictWho == "admin" then FPP.RestrictedTools[toolname].admin = args[3] --weapons.Get("gmod_tool").Tool --Save to database! MySQLite.query("REPLACE INTO FPP_TOOLADMINONLY VALUES(" .. sql.SQLStr(toolname) .. ", " .. sql.SQLStr(args[3]) .. ");") FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " changed the admin status of " .. toolname , true) elseif RestrictWho == "team" then FPP.RestrictedTools[toolname]["team"] = FPP.RestrictedTools[toolname]["team"] or {} if teamtoggle == 0 then for k, v in pairs(FPP.RestrictedTools[toolname]["team"]) do if v == tonumber(args[3]) then table.remove(FPP.RestrictedTools[toolname]["team"], k) break end end elseif not table.HasValue(FPP.RestrictedTools[toolname]["team"], tonumber(args[3])) and teamtoggle == 1 then table.insert(FPP.RestrictedTools[toolname]["team"], tonumber(args[3])) end --Remove from the table if it's in there AND it's 0 otherwise do nothing if tobool(teamtoggle) then -- if the team restrict is enabled FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " restricted " .. toolname .. " to certain teams", true) MySQLite.query("REPLACE INTO FPP_TOOLTEAMRESTRICT VALUES(" .. sql.SQLStr(toolname) .. ", " .. tonumber(args[3]) .. ");") else -- otherwise if the restriction for the team is being removed FPP.NotifyAll(((ply.Nick and ply:Nick()) or "Console") .. " removed teamrestrictions from " .. toolname, true) MySQLite.query("DELETE FROM FPP_TOOLTEAMRESTRICT WHERE toolname = " .. sql.SQLStr(toolname) .. " AND team = " .. tonumber(args[3])) end end end concommand.Add("FPP_restricttool", runIfAccess("FPP_Settings", SetToolRestrict)) local function RestrictToolPerson(ply, cmd, args) if not args[3] then FPP.Notify(ply, "Invalid argument(s)", false) return end--FPP_restricttoolperson local toolname = args[1] local target = Player(tonumber(args[2])) local access = tonumber(args[3]) if not target:IsValid() then FPP.Notify(ply, "Invalid argument(s)", false) return end if access < 0 or access > 2 then FPP.Notify(ply, "Invalid argument(s)", false) return end FPP.RestrictedToolsPlayers[toolname] = FPP.RestrictedToolsPlayers[toolname] or {} -- Disallow, even if other people can use it if access == 0 or access == 1 then FPP.RestrictedToolsPlayers[toolname][target:SteamID()] = access == 1 MySQLite.query("REPLACE INTO FPP_TOOLRESTRICTPERSON1 VALUES(" .. sql.SQLStr(toolname) .. ", " .. sql.SQLStr(target:SteamID()) .. ", " .. access .. ");") elseif access == 2 then -- reset tool status(make him like everyone else) FPP.RestrictedToolsPlayers[toolname][target:SteamID()] = nil MySQLite.query("DELETE FROM FPP_TOOLRESTRICTPERSON1 WHERE toolname = " .. sql.SQLStr(toolname) .. " AND steamid = " .. sql.SQLStr(target:SteamID()) .. ";") end FPP.Notify(ply, "Tool restrictions set successfully", true) end concommand.Add("FPP_restricttoolplayer", runIfAccess("FPP_Settings", RestrictToolPerson)) local function resetAllSetting(ply) MySQLite.begin() MySQLite.queueQuery("DELETE FROM FPP_PHYSGUN1") MySQLite.queueQuery("DELETE FROM FPP_GRAVGUN1") MySQLite.queueQuery("DELETE FROM FPP_TOOLGUN1") MySQLite.queueQuery("DELETE FROM FPP_PLAYERUSE1") MySQLite.queueQuery("DELETE FROM FPP_ENTITYDAMAGE1") MySQLite.queueQuery("DELETE FROM FPP_GLOBALSETTINGS1") MySQLite.queueQuery("DELETE FROM FPP_ANTISPAM1") MySQLite.queueQuery("DELETE FROM FPP_BLOCKMODELSETTINGS1") MySQLite.commit(function() FPP.Settings = nil FPP.Settings = table.Copy(FPP.InitialSettings) SendSettings(player.GetAll()) if not IsValid(ply) then return end FPP.Notify(ply, "Settings successfully reset.", true) end) end concommand.Add("FPP_ResetAllSettings", runIfAccess("FPP_Settings", resetAllSetting)) local function resetBlockedModels(ply) FPP.BlockedModels = {} MySQLite.query("DELETE FROM FPP_BLOCKEDMODELS1", FPP.AddDefaultBlockedModels) FPP.Notify(ply, "Settings successfully reset.", true) end concommand.Add("FPP_ResetBlockedModels", runIfAccess("FPP_Settings", resetBlockedModels)) local function refreshPrivatePlayerSettings(ply) timer.Remove("FPP_RefreshPrivatePlayerSettings" .. ply:EntIndex()) timer.Create("FPP_RefreshPrivatePlayerSettings" .. ply:EntIndex(), 4, 1, function() FPP.recalculateCanTouch({ply}, ents.GetAll()) end) end concommand.Add("_FPP_RefreshPrivatePlayerSettings", refreshPrivatePlayerSettings) --[[------------------------------------------------------------------------- Load all FPP settings ---------------------------------------------------------------------------]] function FPP.Init(callback) MySQLite.begin() MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_BLOCKED1(id INTEGER NOT NULL, var VARCHAR(40) NOT NULL, setting VARCHAR(100) NOT NULL, PRIMARY KEY(id));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_PHYSGUN1(var VARCHAR(40) NOT NULL, setting INTEGER NOT NULL, PRIMARY KEY(var));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_GRAVGUN1(var VARCHAR(40) NOT NULL, setting INTEGER NOT NULL, PRIMARY KEY(var));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_TOOLGUN1(var VARCHAR(40) NOT NULL, setting INTEGER NOT NULL, PRIMARY KEY(var));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_PLAYERUSE1(var VARCHAR(40) NOT NULL, setting INTEGER NOT NULL, PRIMARY KEY(var));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_ENTITYDAMAGE1(var VARCHAR(40) NOT NULL, setting INTEGER NOT NULL, PRIMARY KEY(var));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_GLOBALSETTINGS1(var VARCHAR(40) NOT NULL, setting INTEGER NOT NULL, PRIMARY KEY(var));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_BLOCKMODELSETTINGS1(var VARCHAR(40) NOT NULL, setting INTEGER NOT NULL, PRIMARY KEY(var));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_ANTISPAM1(var VARCHAR(40) NOT NULL, setting INTEGER NOT NULL, PRIMARY KEY(var));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_TOOLADMINONLY(toolname VARCHAR(40) NOT NULL, adminonly INTEGER NOT NULL, PRIMARY KEY(toolname));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_TOOLTEAMRESTRICT(toolname VARCHAR(40) NOT NULL, team INTEGER NOT NULL, PRIMARY KEY(toolname, team));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_TOOLRESTRICTPERSON1(toolname VARCHAR(40) NOT NULL, steamid VARCHAR(40) NOT NULL, allow INTEGER NOT NULL, PRIMARY KEY(steamid, toolname));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_GROUPS3(groupname VARCHAR(40) NOT NULL, allowdefault INTEGER NOT NULL, PRIMARY KEY(groupname));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_GROUPTOOL(groupname VARCHAR(40) NOT NULL, tool VARCHAR(45) NOT NULL, PRIMARY KEY(groupname, tool));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_GROUPMEMBERS1(steamid VARCHAR(40) NOT NULL, groupname VARCHAR(40) NOT NULL, PRIMARY KEY(steamid));") MySQLite.queueQuery("CREATE TABLE IF NOT EXISTS FPP_BLOCKEDMODELS1(model VARCHAR(140) NOT NULL PRIMARY KEY);") if MySQLite.isMySQL() then MySQLite.queueQuery("ALTER TABLE FPP_BLOCKED1 CHANGE id id INTEGER AUTO_INCREMENT;") end MySQLite.commit(function() RetrieveBlocked() RetrieveBlockedModels() RetrieveRestrictedTools() RetrieveGroups() RetrieveSettings() -- Callback when FPP is done creating the tables if callback then callback() end end) end local assbackup = ASS_RegisterPlugin -- Suddenly after witing this code, ASS spamprotection and propprotection broke. I have no clue why. I guess you should use FPP then if assbackup then function ASS_RegisterPlugin(plugin, ...) if plugin.Name == "Sandbox Spam Protection" or plugin.Name == "Sandbox Prop Protection" then return end return assbackup(plugin, ...) end end