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

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;
