Security.Areas=Workspace:FindFirstChild("\091\080\114\105\118\097\116\101 \066\117\105\108\100\105\110\103 \065\114\101\097\115\093")Workspace.ChildAdded:Connect(function(Q)if not Security.Areas and Q.Name=="\091\080\114\105\118\097\116\101 \066\117\105\108\100\105\110\103 \065\114\101\097\115\093"then Security.Areas=Q end end)Workspace.ChildRemoved:Connect(function(Q)if Security.Areas and Q.Name=="\091\080\114\105\118\097\116\101 \066\117\105\108\100\105\110\103 \065\114\101\097\115\093"then Security.Areas=nil end end)function Security.IsAreaAuthorizedForPlayer(Q,R)local Y=Q:FindFirstChild("\091\080\101\114\109\105\115\115\105\111\110\115\093")if not Y then return else Y=require(Y)end if not Y then return end for Q,Y in pairs(Y)do if Y.Type=="\071\114\111\117\112"then local Q=R:IsInGroup(Y.GroupId)if Q and not Y.Ranks then return true elseif Q and Y.Ranks then local Q,n=(tostring(Y.Ranks)):match("\040\091\060\062\093\063\061\063\041\040\091\048-\057\093\043\041")local x=R:GetRankInGroup(Y.GroupId)n=tonumber(n)if not Q and x==n then return true elseif Q=="\061"and x==n then return true elseif Q=="\062"and x>n then return true elseif Q=="\060"and x<n then return true elseif Q=="\062\061"and x>=n then return true elseif Q=="\060\061"and x<=n then return true end end elseif Y.Type=="\080\108\097\121\101\114"then if R.userId==Y.PlayerId or R.Name==Y.PlayerName then return true end elseif Y.Type=="\079\119\110\101\114"then if R.userId==Y.PlayerId or R.Name==Y.PlayerName then return true end elseif Y.Type=="\065\110\121\098\111\100\121"then return true elseif Y.Type=="\070\114\105\101\110\100\115"then if R:IsFriendsWith(Y.PlayerId)then return true end elseif Y.Type=="\065\115\115\101\116"then if MarketplaceService:PlayerOwnsAsset(R,Y.AssetId)then return true end elseif Y.Type=="\084\101\097\109"then if Y.Team and R.Team==Y.Team then return true elseif Y.TeamColor and(R.Team and R.Team.TeamColor==Y.TeamColor)then return true elseif Y.TeamName and(R.Team and R.Team.Name==Y.TeamName)then return true end elseif Y.Type=="\078\111\066\067"then if R.MembershipType==Enum.MembershipType.None then return true end elseif Y.Type=="\065\110\121\066\067"then if R.MembershipType~=Enum.MembershipType.None then return true end elseif Y.Type=="\066\067"then if R.MembershipType==Enum.MembershipType.BuildersClub then return true end elseif Y.Type=="\084\066\067"then if R.MembershipType==Enum.MembershipType.TurboBuildersClub then return true end elseif Y.Type=="\079\066\067"then if R.MembershipType==Enum.MembershipType.OutrageousBuildersClub then return true end elseif Y.Type=="\067\097\108\108\098\097\099\107"then return Y.Callback(R)end end return false end function Security.IsItemAllowed(Q,R)local Y=Q:IsA("\066\097\115\101\080\097\114\116")and not Q:IsA("\084\101\114\114\097\105\110")or Q:IsA("\077\111\100\101\108")and not Q:IsA("\087\111\114\107\115\112\097\099\101")or Q:IsA("\070\111\108\100\101\114")or Q:IsA("\083\109\111\107\101")or Q:IsA("\070\105\114\101")or Q:IsA("\083\112\097\114\107\108\101\115")or Q:IsA("\068\097\116\097\077\111\100\101\108\077\101\115\104")or Q:IsA("\068\101\099\097\108")or Q:IsA("\084\101\120\116\117\114\101")or Q:IsA("\076\105\103\104\116")if not Y then return false end for R,Y in pairs(Security.AllowedLocations)do if Q:IsDescendantOf(Y)then return true end end return true end function Security.IsLocationAllowed(Q,R)for R,Y in pairs(Security.AllowedLocations)do if Y==Q or Q:IsDescendantOf(Y)then return true end end return false end function Security.AreAreasEnabled()if Security.Areas and ToolMode=="\084\111\111\108"then return true else return false end end function Security.ArePartsViolatingAreas(Q,R,Y,n)if not Security.AreAreasEnabled()then return false end if not next(Q)then return false end n=n or{}local x,D=Security.GetSelectionAreas(Q,true)for x,s in pairs(x)do if n[s]==nil then n[s]=Security.IsAreaAuthorizedForPlayer(s,R)end if not Y and n[s]==false then return true end if Y and n[s]then for R,Y in pairs(D)do if R.Area==s then if Support.CountKeys(Q)==#Y then return false end end end end end if#x==0 then return not Security.AllowPublicBuilding elseif Y then return true elseif D and not Security.AllowPublicBuilding then local Q={}for R,Y in pairs(D)do for Y,n in pairs(Y)do Q[n]=Q[n]or 0 for Y,x in pairs(Support.GetPartCorners(n))do if R:CastPoint(x.p)then Q[n]=Q[n]+1 end end end end for Q,R in pairs(Q)do if R~=8 then return true end end end return false end function Security.GetSelectionAreas(Q,R)if not Security.AreAreasEnabled()then return{}end local Y=R and{}or nil local n={}for R,x in pairs(Security.Areas:GetChildren())do local D=RegionModule.new(x.CFrame*CFrame.new(0,Security.AreaHeight/2-x.Size.Y/2,0),Vector3.new(x.Size.X,Security.AreaHeight+x.Size.Y,x.Size.Z))D.Area=x local s=D:CastParts(Q)if#s>0 then table.insert(n,x)if Y then Y[D]=s end end end return n,Y end function Security.GetPermissions(Q,R)if not Security.AreAreasEnabled()then return end local Y={}for Q,n in pairs(Q)do Y[n]=Security.IsAreaAuthorizedForPlayer(n,R)end return Y end return Security

Security.Areas = Workspace:FindFirstChild('[Private Building Areas]');
Workspace.ChildAdded:Connect(function (Child)
	if not Security.Areas and Child.Name == '[Private Building Areas]' then
		Security.Areas = Child;
	end;
end);
Workspace.ChildRemoved:Connect(function (Child)
	if Security.Areas and Child.Name == '[Private Building Areas]' then
		Security.Areas = nil;
	end;
end);

function Security.IsAreaAuthorizedForPlayer(Area, Player)
	-- Returns whether `Player` has permission to manipulate parts in this area

	-- Ensure area has permissions
	local Permissions = Area:FindFirstChild '[Permissions]';
	if not Permissions then
		return;
	else
		Permissions = require(Permissions);
	end;

	-- Ensure permissions are set up
	if not Permissions then
		return;
	end;

	-- Search for authorizing permission
	for _, Permission in pairs(Permissions) do

		-- Check group permissions
		if Permission.Type == 'Group' then

			-- Check player's group membership
			local PlayerInGroup = Player:IsInGroup(Permission.GroupId);

			-- If no specific rank is required, authorize
			if PlayerInGroup and not Permission.Ranks then
				return true;

			-- If specific rank is required, check player rank
			elseif PlayerInGroup and Permission.Ranks then
				local Symbol, RankNumber = tostring(Permission.Ranks):match('([<>]?=?)([0-9]+)');
				local PlayerRank = Player:GetRankInGroup(Permission.GroupId);
				RankNumber = tonumber(RankNumber);

				-- Check the player rank
				if not Symbol and (PlayerRank == RankNumber) then
					return true;
				elseif Symbol == '=' and (PlayerRank == RankNumber) then
					return true;
				elseif Symbol == '>' and (PlayerRank > RankNumber) then
					return true;
				elseif Symbol == '<' and (PlayerRank < RankNumber) then
					return true;
				elseif Symbol == '>=' and (PlayerRank >= RankNumber) then
					return true;
				elseif Symbol == '<=' and (PlayerRank <= RankNumber) then
					return true;
				end;
			end;

		-- Check player permissions
		elseif Permission.Type == 'Player' then
			if (Player.userId == Permission.PlayerId) or (Player.Name == Permission.PlayerName) then
				return true;
			end;

		-- Check owner permissions
		elseif Permission.Type == 'Owner' then
			if (Player.userId == Permission.PlayerId) or (Player.Name == Permission.PlayerName) then
				return true;
			end;

		-- Check auto-permissions
		elseif Permission.Type == 'Anybody' then
			return true;

		-- Check friend permissions
		elseif Permission.Type == 'Friends' then
			if Player:IsFriendsWith(Permission.PlayerId) then
				return true;
			end;

		-- Check asset permissions
		elseif Permission.Type == 'Asset' then
			if MarketplaceService:PlayerOwnsAsset(Player, Permission.AssetId) then
				return true;
			end;

		-- Check team permissions
		elseif Permission.Type == 'Team' then
			if Permission.Team and Player.Team == Permission.Team then
				return true;
			elseif Permission.TeamColor and Player.Team and Player.Team.TeamColor == Permission.TeamColor then
				return true;
			elseif Permission.TeamName and Player.Team and Player.Team.Name == Permission.TeamName then
				return true;
			end;
		
		-- Check BC permissions
		elseif Permission.Type == 'NoBC' then
			if Player.MembershipType == Enum.MembershipType.None then
				return true;
			end;
		elseif Permission.Type == 'AnyBC' then
			if Player.MembershipType ~= Enum.MembershipType.None then
				return true;
			end;
		elseif Permission.Type == 'BC' then
			if Player.MembershipType == Enum.MembershipType.BuildersClub then
				return true;
			end;
		elseif Permission.Type == 'TBC' then
			if Player.MembershipType == Enum.MembershipType.TurboBuildersClub then
				return true;
			end;
		elseif Permission.Type == 'OBC' then
			if Player.MembershipType == Enum.MembershipType.OutrageousBuildersClub then
				return true;
			end;

		-- Check custom permissions
		elseif Permission.Type == 'Callback' then
			return Permission.Callback(Player);
		end;

	end;

	-- If the player passes none of these conditions, deny access
	return false;
end;

function Security.IsItemAllowed(Item, Player)
	-- Returns whether instance `Item` can be accessed

	-- Ensure `Item` is a part or a model
	local IsItemClassAllowed = (Item:IsA 'BasePart' and not Item:IsA 'Terrain') or
		(Item:IsA 'Model' and not Item:IsA 'Workspace') or
		Item:IsA 'Folder' or
		Item:IsA 'Smoke' or
		Item:IsA 'Fire' or
		Item:IsA 'Sparkles' or
		Item:IsA 'DataModelMesh' or
		Item:IsA 'Decal' or
		Item:IsA 'Texture' or
		Item:IsA 'Light'
	if not IsItemClassAllowed then
		return false
	end

	-- Check if `Item` descendants from any allowed location
	for _, AllowedLocation in pairs(Security.AllowedLocations) do
		if Item:IsDescendantOf(AllowedLocation) then
			return true
		end
	end

	-- Deny if `Item` is not a descendant of any allowed location
	return true -- changed this

end

function Security.IsLocationAllowed(Location, Player)
	-- Returns whether location `Location` can be accessed

	-- Check if within allowed locations
	for _, AllowedLocation in pairs(Security.AllowedLocations) do
		if (AllowedLocation == Location) or Location:IsDescendantOf(AllowedLocation) then
			return true
		end
	end

	-- Deny if not within allowed locations
	return false
end

function Security.AreAreasEnabled()
	-- Returns whether areas are enabled

	-- Base whether areas are enabled depending on area container presence and tool mode
	if Security.Areas and (ToolMode == 'Tool') then
		return true;
	else
		return false;
	end;
end;

function Security.ArePartsViolatingAreas(Parts, Player, ExemptPartial, AreaPermissions)
	-- Returns whether the given parts are inside any unauthorized areas

	-- Make sure area security is being enforced
	if not Security.AreAreasEnabled() then
		return false;
	end;

	-- If no parts, no violations exist
	if not next(Parts) then
		return false
	end

	-- Make sure there is a permissions cache
	AreaPermissions = AreaPermissions or {};

	-- Check which areas the parts are in
	local Areas, RegionMap = Security.GetSelectionAreas(Parts, true);

	-- Check authorization for each relevant area
	for _, Area in pairs(Areas) do

		-- Determine authorization if not in given permissions cache
		if AreaPermissions[Area] == nil then
			AreaPermissions[Area] = Security.IsAreaAuthorizedForPlayer(Area, Player);
		end;

		-- If unauthorized and partial violations aren't exempt, declare violation
		if not ExemptPartial and AreaPermissions[Area] == false then
			return true;
		end;

		-- If authorized and partial violations are allowed, check if all parts match area
		if ExemptPartial and AreaPermissions[Area] then

			-- Get parts matched to this area
			for Region, RegionParts in pairs(RegionMap) do
				if Region.Area == Area then

					-- If all parts are on this authorized area, call off any violation
					if Support.CountKeys(Parts) == #RegionParts then
						return false
					end

				end
			end

		end;

	end;

	-- If not in a private area, determine violation based on public building policy
	if #Areas == 0 then
		return not Security.AllowPublicBuilding;

	-- If authorization for a partial violation-exempt check on an area failed, indicate a violation
	elseif ExemptPartial then
		return true;

	-- If in authorized areas, determine violation based on public building policy compliance
	elseif RegionMap and not Security.AllowPublicBuilding then

		-- Check area residence of each part's corner
		local PartCornerCompliance = {};
		for AreaRegion, Parts in pairs(RegionMap) do
			for _, Part in pairs(Parts) do
				PartCornerCompliance[Part] = PartCornerCompliance[Part] or 0;

				-- Track the number of corners that `Part` has in this region
				for _, Corner in pairs(Support.GetPartCorners(Part)) do
					if AreaRegion:CastPoint(Corner.p) then
						PartCornerCompliance[Part] = PartCornerCompliance[Part] + 1;
					end;
				end;

			end;
		end;

		-- Ensure all corners of the part are contained within areas
		for _, CornersContained in pairs(PartCornerCompliance) do
			if CornersContained ~= 8 then
				return true;
			end;
		end;

	end;

	-- If no violations occur, indicate no violations
	return false;
end;

function Security.GetSelectionAreas(Selection, ReturnMap)
	-- Returns a list of areas that the selection of parts is in

	-- Make sure areas are enabled
	if not Security.AreAreasEnabled() then
		return {};
	end;

	-- Start a map if requested
	local Map = ReturnMap and {} or nil;

	-- Check each area to find out if any of the parts are within
	local Areas = {};
	for _, Area in pairs(Security.Areas:GetChildren()) do

		-- Get all parts from the selection within this area
		local Region = RegionModule.new(
			Area.CFrame * CFrame.new(0, Security.AreaHeight / 2 - Area.Size.Y / 2, 0),
			Vector3.new(Area.Size.X, Security.AreaHeight + Area.Size.Y, Area.Size.Z)
		);
		Region.Area = Area
		local ContainedParts = Region:CastParts(Selection);

		-- If parts are in this area, remember the area
		if #ContainedParts > 0 then
			table.insert(Areas, Area);

			-- Map out the parts for each area region
			if Map then
				Map[Region] = ContainedParts;
			end;
		end;

	end;

	-- Return the areas where any of the given parts exist
	return Areas, Map;
end;

function Security.GetPermissions(Areas, Player)
	-- Returns a cache of the current player's authorization to the given areas

	-- Make sure security is enabled
	if not Security.AreAreasEnabled() then
		return;
	end;

	-- Build the cache of permissions for each area
	local Cache = {};
	for _, Area in pairs(Areas) do
		Cache[Area] = Security.IsAreaAuthorizedForPlayer(Area, Player);
	end;

	-- Return the permissions cache
	return Cache;
end;

return Security;
