Objectif : Comprendre l'architecture réseau de Roblox et apprendre à faire communiquer le client (joueur) et le serveur de manière sécurisée.
Pourquoi c'est crucial de comprendre
Dans Roblox, le code peut tourner à deux endroits différents : sur l'ordinateur du joueur (Client) ou sur les serveurs Roblox (Serveur). Savoir où ton code s'exécute est essentiel pour la sécurité et le bon fonctionnement de ton jeu !
Dans ce module, la question la plus importante n'est pas "quel code écrire ?" mais où exécuter ce code. Commence chaque fonctionnalité en séparant les responsabilités : affichage et input côté client, validation et données côté serveur.
Si un joueur peut tricher en modifiant son client, alors la logique est mal placée. Le serveur doit rester l'autorité finale pour les coins, XP, inventaire, dégâts et récompenses.
1) Entrée utilisateur reçue côté serveur.
2) Validation des valeurs avant application.
3) Aucune récompense calculée uniquement côté client.
4) Communication client/serveur via RemoteEvent avec contrôle.
Pose ce filtre simple : si la donnée influence l'équité du jeu, elle doit être validée serveur. Si la donnée concerne l'affichage local, elle peut rester côté client.
Ce choix évite deux problèmes majeurs : triche côté client et scripts trop lents côté serveur pour des effets purement visuels.
Définition : Deux environnements d'exécution avec rôles distincts.
Pourquoi : Séparer affichage local et autorité de jeu.
Quand l'utiliser : Sur chaque feature, décider d'abord l'emplacement logique.
Anti-pattern : Calculer des données sensibles côté client.
Exercice guidé : Classe 10 actions de jeu en client ou serveur.
Résumé : Le bon placement du code évite bugs et triche.
Définition : Script, LocalScript et ModuleScript ont des usages complémentaires.
Pourquoi : Organiser proprement la logique et réutiliser le code.
Quand l'utiliser : Script serveur pour autorité, LocalScript pour UX, ModuleScript pour partage.
Anti-pattern : Mettre toute la logique dans un seul fichier.
Exercice guidé : Découpe une feature en 3 scripts selon les responsabilités.
Résumé : Le type de script choisi impacte sécurité et maintenabilité.
Définition : Message asynchrone entre client et serveur.
Pourquoi : Synchroniser l'intention joueur et la logique autorisée.
Quand l'utiliser : Actions sans retour immédiat obligatoire.
Anti-pattern : Accepter aveuglément les arguments reçus.
Exercice guidé : Crée un RemoteEvent d'achat avec validation serveur.
Résumé : Un événement réseau doit toujours être validé côté serveur.
Définition : Appel réseau avec réponse attendue.
Pourquoi : Obtenir une valeur autorisée avant de poursuivre.
Quand l'utiliser : Vérification d'accès, récupération de données ponctuelles.
Anti-pattern : Appels bloquants répétés qui dégradent la fluidité.
Exercice guidé : Demande au serveur si un joueur peut ouvrir une zone premium.
Résumé : RemoteFunction est utile mais doit rester ciblée et mesurée.
Imagine ton jeu comme un restaurant. Le serveur c'est la cuisine (prépare tout), le client c'est le client du restaurant (affiche et interagit).
ServerScriptServiceStarterPlayerScriptsNe fais JAMAIS confiance au client ! Un joueur peut modifier son propre client. Toute logique importante (argent, dégâts, inventaire) doit être calculée côté SERVEUR.
Roblox propose différents types de scripts selon où tu veux exécuter le code :
S'exécute côté SERVEUR.
Mettre dans ServerScriptService ou attaché aux objets.
S'exécute côté CLIENT du joueur.
Mettre dans StarterPlayerScripts ou StarterGui.
Code réutilisable (bibliothèque).
Peut être utilisé par Script ou LocalScript.
Dossier partagé visible par client ET serveur.
Idéal pour les RemoteEvents et modules communs.
Pour approfondir tes connaissances sur l'architecture Client-Serveur :
Les RemoteEvents sont le pont entre client et serveur. Ils permettent d'envoyer des messages dans les deux sens.
Le joueur veut acheter quelque chose ? Le client envoie une demande au serveur.
📱 LocalScript (Client)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local acheterEvent = ReplicatedStorage:WaitForChild("AcheterItem")
-- Quand le joueur clique sur le bouton "Acheter"
boutonAcheter.MouseButton1Click:Connect(function()
local itemVoulu = "Epee"
acheterEvent:FireServer(itemVoulu) -- Envoie au serveur
end)🖥️ Script (Serveur)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local acheterEvent = ReplicatedStorage:WaitForChild("AcheterItem")
acheterEvent.OnServerEvent:Connect(function(joueur, itemVoulu)
print(joueur.Name .. " veut acheter : " .. itemVoulu)
-- Vérifie si le joueur a assez d'argent (CÔTÉ SERVEUR !)
if joueur.leaderstats.Coins.Value >= 100 then
joueur.leaderstats.Coins.Value -= 100
-- Donne l'item...
print("Achat réussi !")
else
print("Pas assez de coins !")
end
end)Le serveur veut envoyer une notification à un joueur spécifique :
🖥️ Script (Serveur)
local notifEvent = ReplicatedStorage:WaitForChild("Notification")
-- Envoie une notif à UN joueur
notifEvent:FireClient(joueur, "Tu as gagné 100 XP !")
-- Envoie à TOUS les joueurs
notifEvent:FireAllClients("Un boss est apparu !")📱 LocalScript (Client)
local notifEvent = ReplicatedStorage:WaitForChild("Notification")
notifEvent.OnClientEvent:Connect(function(message)
print("Notification : " .. message)
-- Affiche dans l'interface...
end)| Direction | Méthode | Écoute |
|---|---|---|
| Client ? Serveur | :FireServer() | .OnServerEvent |
| Serveur ? Client | :FireClient() | .OnClientEvent |
| Serveur ? Tous | :FireAllClients() | .OnClientEvent |
Les RemoteFunctions permettent d'envoyer une requête ET d'attendre une réponse. Comme un appel téléphonique plutôt qu'un SMS.
Demander des données au serveur
-- CLIENT : Demande les stats du joueur
local getStats = ReplicatedStorage:WaitForChild("GetStats")
local mesStats = getStats:InvokeServer() -- Attend la réponse
print("J'ai " .. mesStats.coins .. " coins")
-- SERVEUR : Répond à la demande
getStats.OnServerInvoke = function(joueur)
return {
coins = joueur.leaderstats.Coins.Value,
level = joueur.leaderstats.Level.Value
}
endN'utilise JAMAIS :InvokeClient() depuis le serveur ! Un joueur malveillant pourrait bloquer ton serveur en ne répondant jamais. Préfère les RemoteEvents dans ce sens.
5 questions pour valider tes acquis
En mode multijoueur, chaque nouveau joueur apporte des ressources bonus ! Chaque visiteur qui rejoint = +10 ⚡ ! Plus vous êtes nombreux, plus vous survivez longtemps !
Modules 1 à 6 complétés (RemoteEvents, Client/Serveur)
Crée une Part avec un SurfaceGui pour afficher le compteur.
Dans ReplicatedStorage, crée un RemoteEvent et nomme-le "NouveauVisiteur".
Crée un Script dans ServerScriptService :
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local nouveauVisiteur = ReplicatedStorage:WaitForChild("NouveauVisiteur")
local compteur = 0
local panneau = workspace:FindFirstChild("PanneauVisiteurs")
local textLabel = panneau.SurfaceGui.TextLabel
-- Quand un client signale sa visite
nouveauVisiteur.OnServerEvent:Connect(function(player)
compteur = compteur + 1
textLabel.Text = "Visiteurs: " .. compteur
print("👤✅ " .. player.Name .. " a visité ! Total: " .. compteur)
end)Crée un LocalScript dans StarterPlayerScripts :
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local nouveauVisiteur = ReplicatedStorage:WaitForChild("NouveauVisiteur")
-- Attendre que le joueur soit chargé
task.wait(2)
-- Signaler la visite au serveur
nouveauVisiteur:FireServer()
print("📤 Visite signalée au serveur !")Ajoute une variable recordMax et affiche "🏆 Record: X" quand le compteur dépasse le record !
Prochaine étape → Module 8 : Système d'Inventaire
Crée une interface utilisateur (GUI) qui affiche en temps réel l'état de la station : ⚡ Énergie, 💎 Cristaux, et 🫁 Oxygène. Utilise la communication Client/Serveur !
Le HUD sera visible par chaque joueur individuellement. Voici la structure complète :
Va dans StarterGui, clic droit → Insert Object → ScreenGui. Renomme-le HUD_Station.
Dans HUD_Station, crée un Frame pour le fond de la barre :
Dans ReplicatedStorage, crée un RemoteEvent nommé MiseAJourHUD. C'est le "canal" de communication.
:FireClient(joueur, données) pour envoyer les ressources à chaque joueur !Crée un Script dans ServerScriptService. Il envoie les données aux clients :
-- GestionnaireRessources.lua (ServerScriptService) local ReplicatedStorage = game:GetService("ReplicatedStorage") local Players = game:GetService("Players") local miseAJourHUD = ReplicatedStorage:WaitForChild("MiseAJourHUD") -- Ressources de la station (partagées) local ressources = { energie = 50, energieMax = 100, oxygene = 80, oxygeneMax = 100, cristaux = 0 } -- FONCTION : Envoyer les données à tous les joueurs local function envoyerMiseAJour() for _, joueur in pairs(Players:GetPlayers()) do miseAJourHUD:FireClient(joueur, ressources) end end -- Simulation : ressources changent while true do task.wait(1) -- Consommation automatique ressources.energie = math.max(0, ressources.energie - 1) ressources.oxygene = math.max(0, ressources.oxygene - 0.5) -- Envoyer les nouvelles valeurs envoyerMiseAJour() endCrée un LocalScript dans le ScreenGui HUD_Station. Il reçoit les données et met à jour l'affichage :
-- HUD_Client.lua (LocalScript dans HUD_Station) local ReplicatedStorage = game:GetService("ReplicatedStorage") local miseAJourHUD = ReplicatedStorage:WaitForChild("MiseAJourHUD") -- Références aux éléments GUI local hud = script.Parent local barreEnergie = hud:WaitForChild("BarreEnergie") local remplissageEnergie = barreEnergie:WaitForChild("Remplissage") local labelEnergie = barreEnergie:WaitForChild("Label") -- FONCTION : Mettre à jour l'affichage local function updateHUD(ressources) -- Énergie local pctEnergie = ressources.energie / ressources.energieMax remplissageEnergie.Size = UDim2.new(pctEnergie, 0, 1, 0) labelEnergie.Text = "⚡ " .. math.floor(ressources.energie) .. "/" .. ressources.energieMax -- Changer la couleur selon le niveau if pctEnergie > 0.5 then remplissageEnergie.BackgroundColor3 = Color3.fromRGB(0, 255, 127) elseif pctEnergie > 0.25 then remplissageEnergie.BackgroundColor3 = Color3.fromRGB(255, 165, 0) else remplissageEnergie.BackgroundColor3 = Color3.fromRGB(255, 50, 50) end end -- ÉVÉNEMENT : Recevoir les données du serveur miseAJourHUD.OnClientEvent:Connect(function(ressources) updateHUD(ressources) end) print("📊 HUD prêt à recevoir les données!")FireClient(joueur, data) → Serveur envoie au clientOnClientEvent:Connect() → Client reçoitUDim2.new() → Positionnement GUI relatifLance le jeu avec F5 et observe :
Le joueur voit maintenant ses ressources en temps réel ! → Module 8 : Animations avec TweenService