Главное правило
Клиент — источник запросов, а не решений. Он говорит «я нажал кнопку», а не «начисли мне тысячу монет». Сервер решает, можно ли, и только он меняет состояние игры.
Типовые дыры
- RemoteEvent без проверок: сервер верит любым аргументам от клиента
- Цена и количество приходят с клиента вместо того, чтобы лежать на сервере
- Ценные данные хранятся в объектах, доступных клиенту
- Нет ограничения частоты: один игрок вызывает событие тысячу раз в секунду
- Проверка «можно ли» сделана в LocalScript и на сервере не повторяется
Как проверять аргументы
local ReplicatedStorage = game:GetService("ReplicatedStorage")local buy = ReplicatedStorage:WaitForChild("BuyItem")local PRICES = {sword = 100,shield = 150,}buy.OnServerEvent:Connect(function(player, itemName)if typeof(itemName) ~= "string" thenreturnendlocal price = PRICES[itemName]if not price thenreturnendlocal coins = player:FindFirstChild("leaderstats")and player.leaderstats:FindFirstChild("Coins")if not coins or coins.Value < price thenreturnendcoins.Value -= price-- выдать предметend)
Цена лежит на сервере, тип аргумента проверен, баланс сверен. Клиент не передаёт ни цену, ни количество монет.
Чего этот раздел не делает
Здесь нет ни одного примера «как получить преимущество в чужой игре»: это запрещено правилами Roblox и правилами портала. Как устроены такие программы и чем заканчиваются, разобрано в разделе о безопасности игрока.