Network GUI
Communication client ↔ serveur pour les GUIs EriAPI — envoyer des actions, recevoir des donnees, et ouvrir des ecrans depuis le serveur.
Introduction
Le module Network fournit un systeme simplifie pour communiquer entre tes GUIs EriAPI et le serveur Minecraft. Sans lui, les GUIs sont purement visuelles — elles ne peuvent pas lire des donnees serveur ni declencher des actions cote serveur.
Minecraft fait tourner deux cotes simultanement : le client (ce que le joueur voit — la fenetre de jeu, les GUIs, le rendu) et le serveur (ce qui gere le monde, les items, les joueurs, l'economie). Ils communiquent via des paquets.
Quand un joueur clique sur "Acheter" dans ta GUI, le clic a lieu cote client. Mais le transfert d'item doit avoir lieu cote serveur. Tu dois envoyer un paquet pour dire au serveur "ce joueur a clique sur Acheter". C'est a ca que sert le systeme reseau.
Quand as-tu besoin du systeme reseau ?
- Quand un clic sur un bouton doit donner ou retirer des items a un joueur
- Quand tu dois lire des donnees cote serveur (les stats d'un autre joueur, une base de donnees, etc.)
- Quand tu veux ouvrir une GUI a distance (le serveur demande au client d'ouvrir un ecran)
- Quand plusieurs joueurs doivent voir les memes donnees se mettre a jour en temps reel
Si ta GUI affiche uniquement des informations stockees localement (un tableau de scores, un ecran de parametres), tu n'as pas besoin de ce module du tout. Le systeme reseau n'est necessaire que quand des actions doivent etre validees ou executees sur le serveur.
| Classe / Interface | Role |
|---|---|
GuiNetworkHandler |
Point central — initialisation, envoi/reception de paquets, registres |
IGuiDataReceiver |
Interface a implementer dans une GUI pour recevoir des donnees du serveur |
PacketGuiAction |
Paquet client → serveur pour les actions (clic de bouton, etc.) |
PacketGuiData |
Paquet bidirectionnel pour la synchronisation de donnees cle/valeur |
PacketGuiOpen |
Paquet serveur → client pour ouvrir une GUI avec des donnees initiales |
Initialisation
Le systeme reseau doit etre initialise exactement une fois dans
FMLPreInitializationEvent. Enregistre ensuite tes factories de GUI et handlers
d'actions dans FMLInitializationEvent.
@Mod(modid = "monmod")
public class MonMod {
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
// Initialiser le systeme reseau en premier
GuiNetworkHandler.init("monmod");
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
// Enregistrer une factory de GUI (cote client)
// Quand le serveur appelle openGuiFor("boutique", ...), cette factory cree la GUI
GuiNetworkHandler.registerGui("boutique", data ->
new GuiBoutique(data.getInteger("type_boutique"))
);
// Enregistrer un handler d'action (cote serveur)
// Quand un client appelle sendAction("boutique", "btn_acheter", "acheter_item", "42"),
// ce handler est appele sur le serveur
GuiNetworkHandler.registerActionHandler("boutique", (player, params) -> {
String action = params.get("action"); // "acheter_item"
String data = params.get("data"); // "42"
String compId = params.get("component"); // "btn_acheter"
if ("acheter_item".equals(action)) {
GestionBoutique.acheterItem((EntityPlayerMP) player, Integer.parseInt(data));
}
});
}
}
GuiNetworkHandler.init(modId) doit etre appele dans
FMLPreInitializationEvent avant qu'un paquet soit envoye. Appeler
sendAction() ou openGuiFor() avant l'initialisation provoque une NullPointerException.
GuiNetworkHandler
Point central du systeme reseau GUI. Toutes les methodes sont statiques.
Le canal reseau est cree sous le nom {modId}_gui.
fr.eri.eriapi.network.GuiNetworkHandler
Initialisation
| Signature | Description |
|---|---|
static void init(String modId) |
Initialise le systeme reseau et enregistre les 4 paquets internes (action,
donnees serveur, donnees client, ouverture). Doit etre appele exactement une fois dans
FMLPreInitializationEvent. Le canal sera nomme {modId}_gui.
|
static boolean isInitialized() |
Retourne true si le systeme a ete initialise. Utile pour les verifications defensives. |
Registres
| Signature | Description |
|---|---|
static void registerGui(String guiId, |
[Cote client] Enregistre une factory de GUI identifiee par guiId.
Quand le serveur appelle openGuiFor(player, guiId, data), la factory est invoquee
avec les donnees NBT et le GuiScreen retourne est affiche.
Enregistrer dans FMLInitializationEvent.
|
static void registerActionHandler(String guiId, |
[Cote serveur] Enregistre un handler pour les actions envoyees depuis une GUI.
La Map<String,String> params contient :
"component" (identifiant du composant source),
"action" (type d'action),
"data" (payload supplementaire).
|
static void registerDataHandler(String guiId, |
[Cote serveur] Enregistre un handler pour les donnees envoyees depuis une GUI.
La Map<String,String> params contient :
"component", "key", "value".
|
Envoi — Client vers Serveur
| Signature | Description |
|---|---|
static void sendAction(String guiId, String componentId, |
[Client uniquement — @SideOnly(CLIENT)]
Envoie une action au serveur. guiId identifie la GUI (doit correspondre a un handler enregistre).
componentId identifie le composant source (ex. "btn_acheter").
action est le type d'action (ex. "acheter_item").
data est le payload supplementaire — converti en String via toString(),
ou chaine vide si null.
|
static void sendData(String guiId, String componentId, |
[Client uniquement]
Envoie une paire cle/valeur au serveur. Utile pour les champs de saisie (ex. la valeur
d'un TextField quand l'utilisateur valide).
value est converti en String via toString().
|
Envoi — Serveur vers Client
| Signature | Description |
|---|---|
static void openGuiFor(EntityPlayerMP player, |
[Serveur uniquement]
Envoie un PacketGuiOpen au joueur. Cote client, la factory enregistree
sous guiId est appelee avec data et la GUI resultante est affichee.
data peut etre un new NBTTagCompound() vide si aucune donnee initiale n'est necessaire.
|
static void sendDataToClient(EntityPlayerMP player, |
[Serveur uniquement]
Envoie une paire cle/valeur au client du joueur. Si la GUI actuellement ouverte chez le joueur
implemente IGuiDataReceiver, sa methode
onDataUpdate(componentId, key, value) est appelee.
value est converti en String.
|
Les handlers enregistres via registerActionHandler et registerDataHandler
sont appeles sur le thread principal du serveur (via addScheduledTask dans le
PacketHandler). Tu peux modifier les donnees joueur directement sans blocs
synchronized supplementaires.
De meme, la distribution des donnees cote client est appelee sur le thread principal Minecraft
(via addScheduledTask). Tu peux modifier les composants GUI directement.
IGuiDataReceiver
Interface a implementer dans un EriGuiScreen pour recevoir des mises a jour
de donnees envoyees par le serveur via sendDataToClient().
Quand le serveur envoie un PacketGuiData au client,
GuiNetworkHandler verifie si la GUI actuellement ouverte implemente
IGuiDataReceiver et appelle onDataUpdate().
fr.eri.eriapi.network.IGuiDataReceiver
Methode a implementer
| Signature | Description |
|---|---|
void onDataUpdate(String componentId, String key, String value) |
Appelee cote client quand des donnees sont recues du serveur.
componentId : identifiant du composant cible (tel que passe a sendDataToClient).
key : cle de la donnee.
value : valeur de la donnee (toujours une String).
|
public class GuiBoutique extends EriGuiScreen implements IGuiDataReceiver {
private Label labelSolde;
private Label labelStatut;
@Override
protected void buildGui() {
labelSolde = new Label(20, 20, 400, 30, "Chargement...")
.scale(1.4f)
.color(0xFFFFD700);
getRoot().add(labelSolde);
labelStatut = new Label(20, 60, 400, 24, "")
.scale(1.0f)
.color(0xFFFFFFFF);
getRoot().add(labelStatut);
}
@Override
public void onDataUpdate(String componentId, String key, String value) {
// Filtrer par ID de composant (utile quand plusieurs composants recoivent des donnees)
if ("affichage_solde".equals(componentId)) {
if ("or".equals(key)) {
labelSolde.text("Or : " + value);
}
} else if ("resultat_achat".equals(componentId)) {
if ("succes".equals(key)) {
boolean ok = Boolean.parseBoolean(value);
labelStatut.text(ok ? "Achat reussi !" : "Fonds insuffisants.")
.color(ok ? 0xFF44FF88 : 0xFFFF4444);
}
}
}
}
Packets
Le systeme utilise trois paquets internes. En general tu n'interagis jamais directement avec les
classes de paquets — passe toujours par GuiNetworkHandler.
Cette section documente leur format pour reference.
PacketGuiAction — Client → Serveur
Envoye par GuiNetworkHandler.sendAction() quand un composant client declenche
une action (clic de bouton, etc.).
| Champ | Type | Description |
|---|---|---|
guiId | String | Identifiant de la GUI source (ex. "boutique") |
componentId | String | Identifiant du composant source (ex. "btn_acheter") |
action | String | Type d'action (ex. "acheter_item", "annuler") |
data | String | Payload supplementaire (ex. "42" pour un ID d'item) |
Le handler serveur recoit une Map<String, String> avec les cles
"component", "action", "data".
PacketGuiData — Bidirectionnel
Utilise par sendData() (client → serveur) et
sendDataToClient() (serveur → client) pour synchroniser une paire cle/valeur.
| Champ | Type | Description |
|---|---|---|
guiId | String | Identifiant de la GUI concernee |
componentId | String | Identifiant du composant concerne |
key | String | Cle de la donnee |
value | String | Valeur (toujours une String) |
PacketGuiOpen — Serveur → Client
Envoye par openGuiFor() pour ouvrir une GUI cote client.
| Champ | Type | Description |
|---|---|---|
guiId | String | Identifiant de la GUI a ouvrir (doit etre enregistree via registerGui) |
initialData | NBTTagCompound | Donnees initiales passees a la factory de GUI |
Tous les paquets utilisent ByteBufUtils.writeUTF8String /
readUTF8String pour les champs String, et
ByteBufUtils.writeTag / readTag pour le NBT.
La taille maximale d'une String est limitee par le MTU des paquets Minecraft
(environ 32 767 caracteres).
Exemple complet — Boutique Client/Serveur
Un exemple complet montrant les deux cotes : la GUI client envoie une action, le serveur la traite et repond avec des donnees mises a jour.
1. Configuration (dans la classe @Mod)
@Mod(modid = "monmod")
public class MonMod {
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
GuiNetworkHandler.init("monmod");
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
// Factory de GUI : le serveur peut ouvrir cette GUI cote client
GuiNetworkHandler.registerGui("boutique", data -> {
String nomBoutique = data.getString("nom");
int orInitial = data.getInteger("or");
return new GuiBoutique(nomBoutique, orInitial);
});
// Handler d'action : le serveur traite les achats
GuiNetworkHandler.registerActionHandler("boutique", (player, params) -> {
EntityPlayerMP mp = (EntityPlayerMP) player;
String action = params.get("action");
String data = params.get("data");
if ("acheter".equals(action)) {
int itemId = Integer.parseInt(data);
boolean ok = GestionBoutique.traiterAchat(mp, itemId);
int nouvelOr = GestionBoutique.getOr(mp);
// Repondre au client
GuiNetworkHandler.sendDataToClient(mp, "boutique", "resultat", "succes", String.valueOf(ok));
GuiNetworkHandler.sendDataToClient(mp, "boutique", "solde", "or", String.valueOf(nouvelOr));
}
});
}
}
2. Ouvrir la GUI depuis le serveur
// Quand un joueur fait un clic droit sur le PNJ Boutique cote serveur :
NBTTagCompound data = new NBTTagCompound();
data.setString("nom", "Boutique de Pierre");
data.setInteger("or", GestionBoutique.getOr(player));
GuiNetworkHandler.openGuiFor(player, "boutique", data);
3. GUI cote client
public class GuiBoutique extends EriGuiScreen implements IGuiDataReceiver {
private final String nomBoutique;
private int orActuel;
private Label labelOr;
private Label labelStatut;
public GuiBoutique(String nomBoutique, int orInitial) {
this.nomBoutique = nomBoutique;
this.orActuel = orInitial;
}
@Override
protected void buildGui() {
ContainerComponent root = getRoot();
// Fond
root.add(new Rectangle(0, 0, 1920, 1080).fillColor(0x88000000));
// Panneau central
ContainerComponent panel = new ContainerComponent(660, 240, 600, 600);
panel.add(new Rectangle(0, 0, 600, 600).fillColor(0xCC1A1A2E).cornerRadius(16));
panel.add(new Label(0, 24, 600, 40, nomBoutique).scale(2.0f).color(0xFFFFD700)
.align(Label.Align.CENTER));
// Solde en or
labelOr = new Label(20, 80, 560, 30, "Or : " + orActuel);
labelOr.scale(1.3f).color(0xFFFFD700);
panel.add(labelOr);
// Label de statut
labelStatut = new Label(20, 120, 560, 24, "");
labelStatut.scale(1.0f).color(0xFFFFFFFF);
panel.add(labelStatut);
// Bouton acheter
panel.add(new Button(200, 180, 200, 44, "Acheter Epee (100 or)")
.colorScheme(0xFF1A6A3A)
.cornerRadius(8)
.onClick(() -> {
GuiNetworkHandler.sendAction("boutique", "btn_acheter", "acheter", "1");
})
);
root.add(panel);
}
@Override
public void onDataUpdate(String componentId, String key, String value) {
if ("resultat".equals(componentId) && "succes".equals(key)) {
boolean ok = Boolean.parseBoolean(value);
labelStatut.text(ok ? "Achat reussi !" : "Or insuffisant !")
.color(ok ? 0xFF44FF88 : 0xFFFF4444);
} else if ("solde".equals(componentId) && "or".equals(key)) {
orActuel = Integer.parseInt(value);
labelOr.text("Or : " + orActuel);
}
}
}
- Le joueur interagit avec le PNJ → le serveur appelle
openGuiFor() - Le client recoit
PacketGuiOpen→ la factory creeGuiBoutique - Le joueur clique "Acheter" →
sendAction()envoiePacketGuiAction - Le serveur recoit l'action → le handler traite l'achat
- Le serveur appelle
sendDataToClient()deux fois (resultat + solde) - Le client recoit
PacketGuiData→onDataUpdate()met a jour la GUI