Menu
CoddyTech

Non fidarti mai del client

Lezione 7 di 18 del corso Gioco Roblox: Simulatore di animali domestici di Coddy.

Un giocatore controlla il proprio dispositivo, quindi un exploit può fargli attivare qualsiasi remote, con qualsiasi cosa e da qualsiasi luogo, alla velocità che preferisce. Hit:FireServer(pile) dall'altra parte della mappa, cento volte al secondo, svuoterebbe ogni mucchio nel gioco.

Perciò il server controlla ogni richiesta prima di agire:

  • è un mucchio valido (un'Instance in workspace.Piles),
  • il giocatore si trova entro Settings.Reach da esso,
  • e l'ultimo colpo risale ad almeno Settings.HitCooldown secondi fa.
if typeof(pile) ~= "Instance" or pile.Parent ~= piles then
	return
end

Quando premi Check, i test fanno quello che farebbe un exploit. La regola per ogni remote che scrivi: il client chiede, il server decide.

challenge icon

Sfida

Medio

In PetServer, all'inizio del gestore Hit, esegui un return senza colpire quando:

  1. il mucchio non è un'istanza in piles,
  2. il giocatore non ha un personaggio, oppure il suo HumanoidRootPart si trova a più di Settings.Reach stud dal mucchio,
  3. ha colpito meno di Settings.HitCooldown secondi fa (tieni local lastHit = {} vicino all'inizio e registra time() quando un colpo è consentito).

Premi Play, poi Check: i controlli simulano l'exploiter.

Provalo tu

local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Settings = require(game.ReplicatedStorage.Settings)

local remotes = game.ReplicatedStorage.Remotes
local piles = workspace.Piles
local pileSpot = {} -- ogni pila -> il punto in cui si trova

print("A Meadow pile gives " .. Settings.PileValue .. " coins")

-- Ogni giocatore riceve Coins nella classifica
Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local coins = Instance.new("IntValue")
	coins.Name = "Coins"
	coins.Parent = leaderstats
end)

-- Una pila di monete su un punto: una copia di ServerStorage.CoinPile con la sua salute
-- e il suo valore come attributi
local function spawnPile(spot)
	local pile = ServerStorage.CoinPile:Clone()
	pile.Position = spot.Position
	pile:SetAttribute("MaxHealth", Settings.PileHealth)
	pile:SetAttribute("Health", Settings.PileHealth)
	pile:SetAttribute("Value", Settings.PileValue)
	pileSpot[pile] = spot
	pile.Parent = piles
	return pile
end

-- Un colpo riduce di 1 la salute di una pila;
-- a 0 la pila si rompe e assegna il suo valore
local function hitPile(player, pile)
	local health = pile:GetAttribute("Health") - 1
	if health > 0 then
		pile:SetAttribute("Health", health)
		return
	end
	player.leaderstats.Coins.Value += pile:GetAttribute("Value")
	local spot = pileSpot[pile]
	pileSpot[pile] = nil
	pile:Destroy()
	-- una nuova pila nello stesso punto, pochi secondi dopo
	task.delay(Settings.RespawnTime, spawnPile, spot)
end

-- Una pila in ogni punto di Meadow
for _, spot in workspace.Zones.Meadow.Spawns:GetChildren() do
	spawnPile(spot)
end

-- Il client chiede di colpire una pila
remotes.Hit.OnServerEvent:Connect(function(player, pile)
	hitPile(player, pile)
end)
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Gioco Roblox: Simulatore di animali domestici