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.Reachdavon entfernt, - und der letzte Treffer liegt mindestens
Settings.HitCooldownSekunden zurück.
if typeof(pile) ~= "Instance" or pile.Parent ~= piles then
return
endWenn 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.
Aufgabe
MittelGib in PetServer am Anfang des Hit-Handlers Folgendes zurück, ohne einen Treffer auszuführen, wenn:
- der Stapel keine Instance in
pilesist, - der Spieler keinen Charakter hat oder sein
HumanoidRootPartmehr alsSettings.ReachStuds vom Stapel entfernt ist, - der letzte Treffer weniger als
Settings.HitCooldownSekunden zurückliegt (behaltelocal lastHit = {}nahe am Anfang bei und speicheretime(), 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)
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
2Client und Server
Münzen auf dem Bildschirm