Menu
CoddyTech

Délais de récupération côté serveur

Leçon 7 sur 20 du cours Jeu Roblox : Arènes de combat de Coddy.

Un exploiteur contrôle son propre appareil ; il peut donc déclencher Remotes.Ability cent fois par seconde, avec n’importe quel nom. Un temps de recharge dans le LocalScript n’arrêterait que les joueurs honnêtes : c’est au serveur de l’imposer.

Le serveur conserve, pour chaque joueur et chaque capacité, le moment où elle sera de nouveau prête, sous forme d’attribut du joueur (la leçon suivante l’affiche à l’écran). workspace:GetServerTimeNow() est une horloge sur laquelle le serveur et chaque client s’accordent :

local now = workspace:GetServerTimeNow()
if now < (player:GetAttribute(name .. "ReadyAt") or 0) then
	return
end
player:SetAttribute(name .. "ReadyAt", now + Settings.Cooldowns[name])

Et il vérifie ce qui lui a été envoyé : une chaîne désignant une capacité réelle, provenant d’un joueur en vie.

challenge icon

Défi

Moyen

Dans le gestionnaire Ability, avant d'exécuter la capacité, faites un retour lorsque :

  1. le nom n'est pas une chaîne désignant une capacité,
  2. le joueur n'a pas de racine de personnage, ou la santé de son Humanoid est de 0,
  3. GetServerTimeNow() est antérieur au moment où le joueur pourra de nouveau utiliser cette capacité, l'attribut name .. "ReadyAt".

Sinon, définissez cet attribut sur maintenant plus Settings.Cooldowns[name], puis exécutez la capacité. Appuyez sur Play, puis sur Check : les vérifications déclenchent le remote comme le ferait un pirate.

Essayez vous-même

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

local remotes = game.ReplicatedStorage.Remotes
local lastSwing = {} -- player -> moment de son dernier coup d’épée

-- Les animations d’épée propres à Roblox
local slash = Instance.new("Animation")
slash.AnimationId = "rbxassetid://522635514"

print("Swords deal " .. Settings.SwordDamage .. " damage")

-- Un coup d’épée : l’animation se joue, puis tous ceux qui se trouvent dans la boîte devant toi sont touchés
local function swing(player)
	local character = player.Character
	local root = character and character:FindFirstChild("HumanoidRootPart")
	if not root or character.Humanoid.Health <= 0 then
		return
	end
	local now = time()
	if lastSwing[player] and now - lastSwing[player] < Settings.SwingCooldown then
		return
	end
	lastSwing[player] = now
	character.Humanoid.Animator:LoadAnimation(slash):Play()
	-- la boîte devant toi, jamais ton propre corps
	local params = OverlapParams.new()
	params.FilterDescendantsInstances = { character }
	local box = root.CFrame * CFrame.new(0, 0, -3)
	local hit = {} -- chaque humanoïde une seule fois par coup d’épée
	for _, part in workspace:GetPartBoundsInBox(box, Settings.HitboxSize, params) do
		local humanoid = part.Parent:FindFirstChildOfClass("Humanoid")
		if humanoid and not hit[humanoid] then
			hit[humanoid] = true
			humanoid:TakeDamage(Settings.SwordDamage)
		end
	end
end

-- Les capacités, classées par nom : ce que chacune fait
local abilities = {}

function abilities.Dash(player, character, root)
	root.AssemblyLinearVelocity = root.CFrame.LookVector * Settings.DashSpeed + Vector3.new(0, 15, 0)
end

-- Le client demande une capacité par son nom ; le serveur l’exécute
remotes.Ability.OnServerEvent:Connect(function(player, name)
	local character = player.Character
	local root = character and character:FindFirstChild("HumanoidRootPart")
	if abilities[name] and root then
		abilities[name](player, character, root)
	end
end)

-- Chaque joueur reçoit Kills dans le classement, et une épée à chaque vie
Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local kills = Instance.new("IntValue")
	kills.Name = "Kills"
	kills.Parent = leaderstats

	player.CharacterAdded:Connect(function()
		local sword = ServerStorage.Sword:Clone()
		sword.Parent = player.Backpack
		sword.Activated:Connect(function()
			swing(player)
		end)
	end)
end)

-- Le mannequin d’entraînement : sa barre de vie reflète sa santé, et un mannequin
-- vaincu réapparaît après un instant, sous forme d’une nouvelle copie au même endroit
local function setupDummy(dummy)
	local humanoid = dummy.Humanoid
	humanoid.HealthChanged:Connect(function(health)
		dummy.HealthBar.Back.Fill.Size = UDim2.fromScale(health / humanoid.MaxHealth, 1)
	end)
	humanoid.Died:Connect(function()
		local spot = dummy:GetPivot()
		task.wait(0.5)
		dummy:Destroy()
		task.wait(Settings.DummyRespawn)
		local fresh = ServerStorage.Dummy:Clone()
		fresh:PivotTo(spot)
		fresh.Parent = workspace
		setupDummy(fresh)
	end)
end
setupDummy(workspace.Dummy)
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Jeu Roblox : Arènes de combat