-- src/ServerScriptService/AntiCheatManager.server.lua local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") -- Rate limiting tracker local rateLimits = {} -- [userId] = { [eventName] = { count, lastReset } } local MAX_EVENTS_PER_SECOND = 10 local RATE_WINDOW = 1 -- seconds local function getRateData(player, eventName) if not rateLimits[player.UserId] then rateLimits[player.UserId] = {} end if not rateLimits[player.UserId][eventName] then rateLimits[player.UserId][eventName] = { count = 0, lastReset = tick(), } end return rateLimits[player.UserId][eventName] end -- Check if a player is rate limited _G.IsRateLimited = function(player, eventName) local data = getRateData(player, eventName) local now = tick() if now - data.lastReset > RATE_WINDOW then data.count = 0 data.lastReset = now end data.count = data.count + 1 if data.count > MAX_EVENTS_PER_SECOND then warn("Rate limit exceeded for " .. player.Name .. " on event " .. eventName) return true end return false end -- Validate distance between player and target _G.ValidateDistance = function(player, targetPosition, maxDistance) local character = player.Character if not character then return false end local rootPart = character:FindFirstChild("HumanoidRootPart") if not rootPart then return false end local distance = (rootPart.Position - targetPosition).Magnitude return distance <= maxDistance end -- Validate player has enough cash _G.ValidateCash = function(player, amount) local leaderstats = player:FindFirstChild("leaderstats") if not leaderstats then return false end local cash = leaderstats:FindFirstChild("Cash") if not cash then return false end return cash.Value >= amount end -- Cleanup on player leave Players.PlayerRemoving:Connect(function(player) rateLimits[player.UserId] = nil end) print("Anti-Cheat Manager initialized")