Menu
CoddyTech

Vertraue niemals dem Client

Lektion 7 von 18 im Kurs Roblox-Spiel: Haustiersimulator von Coddy.

Ein Spieler kontrolliert sein eigenes Gerät, daher kann ein Exploiter es dazu bringen, beliebige Remotes mit beliebigen Daten von überall aus so oft auszulösen, wie er möchte. Hit:FireServer(pile) quer über die Karte hundertmal pro Sekunde würde jeden Stapel im Spiel leeren.

Deshalb überprüft der Server jede Anfrage, bevor er handelt:

  • Es ist ein echter Stapel (eine Instance in workspace.Piles),
  • der Spieler steht höchstens Settings.Reach davon entfernt,
  • und der letzte Treffer liegt mindestens Settings.HitCooldown Sekunden zurück.
if typeof(pile) ~= "Instance" or pile.Parent ~= piles then
	return
end

Wenn du auf „Check“ drückst, führen die Tests das aus, was ein Exploiter tun würde. Die Regel für jedes Remote, das du schreibst: Der Client fragt, der Server entscheidet.

challenge icon

Aufgabe

Mittel

Gib in PetServer am Anfang des Hit-Handlers Folgendes zurück, ohne einen Treffer auszuführen, wenn:

  1. der Stapel keine Instance in piles ist,
  2. der Spieler keinen Charakter hat oder sein HumanoidRootPart mehr als Settings.Reach Studs vom Stapel entfernt ist,
  3. der letzte Treffer weniger als Settings.HitCooldown Sekunden zurückliegt (behalte local lastHit = {} nahe am Anfang bei und speichere time(), wenn ein Treffer zulässig ist).

Drücke Play und dann Check: Bei den Prüfungen wird der Exploiter gespielt.

Probier es selbst

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 = {} -- jeder Haufen -> der Platz, auf dem er steht

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

-- Jeder Spieler erhält Coins auf der Bestenliste
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)

-- Ein Münzhaufen auf einem Platz: eine Kopie von ServerStorage.CoinPile mit seiner Gesundheit
-- und seinem Wert als Attribute
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

-- Ein Treffer zieht der Gesundheit eines Haufens 1 ab;
-- bei 0 zerbricht der Haufen und zahlt seinen Wert aus
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()
	-- ein neuer Haufen auf demselben Platz, ein paar Sekunden später
	task.delay(Settings.RespawnTime, spawnPile, spot)
end

-- Ein Haufen auf jedem Platz in Meadow
for _, spot in workspace.Zones.Meadow.Spawns:GetChildren() do
	spawnPile(spot)
end

-- Der Client fordert an, einen Haufen zu treffen
remotes.Hit.OnServerEvent:Connect(function(player, pile)
	hitPile(player, pile)
end)
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Roblox-Spiel: Haustiersimulator