Client vs Serveur

Objectif : Comprendre l'architecture réseau de Roblox et apprendre à faire communiquer le client (joueur) et le serveur de manière sécurisée.

Le Réseau dans Roblox

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 !

0. Réflexe architecture avant code

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.

Checklist sécurité simple

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.

0.5 Décider rapidement où placer le code

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.

  • Erreur fréquente : donner des coins depuis un LocalScript
  • Erreur fréquente : déclencher un RemoteEvent sans validation
  • Erreur fréquente : dupliquer la même logique des deux côtés
  • Erreur fréquente : ne pas traiter les cas de désynchronisation

0.8 Parcours pédagogique section par section

Section 1 - Client vs Serveur

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.

Section 2 - Types de scripts

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é.

Section 3 - RemoteEvents

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.

Section 4 - RemoteFunctions

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.

1. Client vs Serveur : Qui Fait Quoi ?

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).

SERVEUR

  • Gère les données importantes (coins, XP, inventaire)
  • Fait les calculs sensibles
  • Fait autorité sur ce qui se passe
  • Scripts dans ServerScriptService
  • UN seul serveur pour tous les joueurs

CLIENT

  • Affiche l'interface (GUI)
  • Gère les inputs (clavier, souris)
  • Joue les sons/effets locaux
  • Scripts dans StarterPlayerScripts
  • UN client par joueur

🚨 Règle d'Or de la Sécurité

Ne 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.

2. Les Types de Scripts

Roblox propose différents types de scripts selon où tu veux exécuter le code :

Script

S'exécute côté SERVEUR.

Mettre dans ServerScriptService ou attaché aux objets.

LocalScript

S'exécute côté CLIENT du joueur.

Mettre dans StarterPlayerScripts ou StarterGui.

ModuleScript

Code réutilisable (bibliothèque).

Peut être utilisé par Script ou LocalScript.

ReplicatedStorage

Dossier partagé visible par client ET serveur.

Idéal pour les RemoteEvents et modules communs.

📚 Documentation Officielle Roblox

Pour approfondir tes connaissances sur l'architecture Client-Serveur :

3. Communiquer : RemoteEvents

Les RemoteEvents sont le pont entre client et serveur. Ils permettent d'envoyer des messages dans les deux sens.

3.1 Client ? Serveur (FireServer)

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)

3.2 Serveur ? Client (FireClient)

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)
Récapitulatif
DirectionMéthodeÉcoute
Client ? Serveur:FireServer().OnServerEvent
Serveur ? Client:FireClient().OnClientEvent
Serveur ? Tous:FireAllClients().OnClientEvent

4. RemoteFunctions (Appels avec Réponse)

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
    }
end

⚠️ Attention aux RemoteFunctions

N'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.

💻 Sandbox Luau
Simulateur v2.0
1 2 3 4 5 6 7 8 9 10
👉 Simule des échanges client/serveur...

Quiz : Client vs Serveur

5 questions pour valider tes acquis

1. Où doit-on gérer l'argent des joueurs ?

  • Côté Client
  • Côté Serveur
  • Les deux
  • Ça n'a pas d'importance

2. Quel type de script s'exécute sur l'ordinateur du joueur ?

  • Script
  • LocalScript
  • ModuleScript
  • ServerScript

3. Quelle méthode envoie un message du client vers le serveur ?

  • :FireServer()
  • :FireClient()
  • :SendToServer()
  • :Connect()

4. Dans quel dossier met-on les RemoteEvents ?

  • ServerStorage
  • ReplicatedStorage
  • Workspace
  • StarterPack

5. Pourquoi ne faut-il pas utiliser :InvokeClient() depuis le serveur ?

  • Ça ne fonctionne pas
  • C'est trop lent
  • Un joueur pourrait bloquer le serveur
  • Ça utilise trop de mémoire
Exercice Pratique

Configure le RemoteEvent

Place les éléments dans le bon ordre pour créer un système client-serveur !

15-50 Points
OnServerEvent:Connect
Réception serveur
Créer RemoteEvent
Dans ReplicatedStorage
:FireServer()
Envoie du client
Référencer l'event
local remoteEvent = ...
1
Première étape...
2
Préparation...
3
Communication...
4
Réaction...
👥
Étape 7/10

Système Multijoueur

En mode multijoueur, chaque nouveau joueur apporte des ressources bonus ! Chaque visiteur qui rejoint = +10 ⚡ ! Plus vous êtes nombreux, plus vous survivez longtemps !

1
2
3
4
5
6
7
8
9
10
Prérequis

Modules 1 à 6 complétés (RemoteEvents, Client/Serveur)

Construction du Compteur Multijoueur

1
Crée le Panneau

Crée une Part avec un SurfaceGui pour afficher le compteur.

Part Size6, 4, 0.5
Nom"PanneauVisiteurs"
EnfantsSurfaceGui ? TextLabel
2
Crée le RemoteEvent

Dans ReplicatedStorage, crée un RemoteEvent et nomme-le "NouveauVisiteur".

3
Script Serveur

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)
4
Script Client (LocalScript)

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 !")
Bonus : Record de Visiteurs

Ajoute une variable recordMax et affiche "🏆 Record: X" quand le compteur dépasse le record !

Système multijoueur actif !

Prochaine étape → Module 8 : Système d'Inventaire

📊
🚀 SURVIE SPATIALE - Étape 7/10

HUD de la Station

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 !

1
2
3
4
5
6
7
8
9
10
Contexte : Ta station fonctionne ! Mais le joueur ne voit pas ses ressources. Il faut un HUD (Head-Up Display) comme dans les vrais jeux de survie !
1
📐 Architecture du Système GUI

Le HUD sera visible par chaque joueur individuellement. Voici la structure complète :

▼ StarterGui
▼ 📺 HUD_Station
📊 BarreEnergie
🏷️ TextLabel
📦 BarreRemplissage
📊 BarreOxygene
💎 CompteurCristaux
📜 HUD_Client (LocalScript)
▼ ReplicatedStorage
📡 MiseAJourHUD (RemoteEvent)
▼ ServerScriptService
📜 GestionnaireRessources
Client vs Serveur : Le serveur stocke les vraies valeurs et les envoie au client via RemoteEvent. Le client affiche seulement !
2
📺 Créer le ScreenGui dans StarterGui

Va dans StarterGui, clic droit → Insert Object → ScreenGui. Renomme-le HUD_Station.

NameHUD_Station
ResetOnSpawnfalse
IgnoreGuiInsettrue
ResetOnSpawn = false garde le HUD même quand le joueur meurt et respawn !
3
⚡ Créer la Barre d'Énergie

Dans HUD_Station, crée un Frame pour le fond de la barre :

Frame "BarreEnergie" (conteneur)

NameBarreEnergie
Position{0.02, 0}, {0.05, 0}
Size{0.2, 0}, {0.03, 0}
BackgroundColor3[30, 30, 40]
BorderSizePixel0

Frame "Remplissage" (dans BarreEnergie)

NameRemplissage
Position{0, 0}, {0, 0}
Size{0.5, 0}, {1, 0}
BackgroundColor3[0, 255, 127]

TextLabel "Label" (dans BarreEnergie)

NameLabel
Size{1, 0}, {1, 0}
Text⚡ 50/100
TextColor3[255, 255, 255]
BackgroundTransparency1
4
📡 Créer le RemoteEvent

Dans ReplicatedStorage, crée un RemoteEvent nommé MiseAJourHUD. C'est le "canal" de communication.

RemoteEvent : Le serveur utilisera :FireClient(joueur, données) pour envoyer les ressources à chaque joueur !
5
📜 Script Serveur - GestionnaireRessources

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() end
6
📜 LocalScript - HUD_Client

Cré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!")
Concepts du cours appliqués :
FireClient(joueur, data) → Serveur envoie au client
OnClientEvent:Connect() → Client reçoit
UDim2.new() → Positionnement GUI relatif
• Table de données → Envoyer plusieurs valeurs d'un coup
7
🎮 Tester le HUD

Lance le jeu avec F5 et observe :

  • 📊 La barre d'énergie apparaît en haut à gauche
  • ⬇️ Elle diminue progressivement (consommation)
  • 🎨 La couleur change : vert → orange → rouge
  • 🔢 Le texte affiche les valeurs exactes
Bonus : Complète le HUD !
  • Ajoute une barre d'oxygène (bleue) en dessous
  • Ajoute un compteur de cristaux avec icône 💎
  • Fais clignoter la barre quand une ressource est critique !
  • Utilise UICorner pour arrondir les barres
📊

HUD de la station opérationnel !

Le joueur voit maintenant ses ressources en temps réel ! → Module 8 : Animations avec TweenService