--- title: Pages Personnalisées type: docs weight: 2 --- Les pages personnalisées permettent aux plugins de créer des overlays UI interactifs qui peuvent recevoir des entrées utilisateur et afficher du contenu dynamique. **Package:** `com.hypixel.hytale.server.core.entity.entities.player.pages` ## Durées de Vie des Pages Contrôle comment les pages peuvent être fermées : | Durée de Vie | Description | |--------------|-------------| | `CustomPageLifetime.CantClose` | La page ne peut pas être fermée par le joueur | | `CustomPageLifetime.CanDismiss` | Le joueur peut fermer avec Échap | | `CustomPageLifetime.CanDismissOrCloseThroughInteraction` | Peut fermer via Échap ou interaction | ## Créer une Page Personnalisée Étendez `CustomUIPage` : ```java public class WelcomePage extends CustomUIPage { public WelcomePage(PlayerRef playerRef) { super(playerRef, CustomPageLifetime.CanDismiss); } @Override public void build(Ref ref, UICommandBuilder builder, UIEventBuilder events, Store store) { // Charger un template UI depuis les assets (extension .ui OBLIGATOIRE) builder.append("Pages/WelcomeScreen.ui"); // Définir des valeurs dynamiques builder.set("#player_name", playerRef.getUsername()); builder.set("#server_name", "Mon Serveur"); } } ``` ## UICommandBuilder Construire du contenu UI dynamiquement : ### Ajouter du Contenu ```java // Ajouter un template UI (extension .ui OBLIGATOIRE) builder.append("Pages/TemplatePath.ui"); // Ajouter à un sélecteur spécifique builder.append("#container", "Pages/ChildTemplate.ui"); // Ajouter du YAML/JSON inline builder.appendInline("#list", "{ type: text, content: 'Bonjour' }"); ``` ### Définir des Valeurs ```java // Définir du texte builder.set("#title", "Bienvenue !"); builder.set("#description", Message.translation("my.key")); // Définir des nombres builder.set("#score", 1500); builder.set("#progress", 0.75f); // Définir un booléen builder.set("#visible", true); // Mettre à null builder.setNull("#optional_field"); ``` ### Définir des Objets ```java // Définir un ItemStack ItemStack item = ...; builder.setObject("#item_display", item); // Définir une Zone UI Area area = new Area(0, 0, 100, 50); builder.setObject("#bounds", area); // Définir des tableaux/listes builder.set("#items", itemStackArray); builder.set("#options", stringList); ``` ### Supprimer du Contenu ```java // Vider les enfants d'un élément builder.clear("#container"); // Supprimer un élément entièrement builder.remove("#element_id"); // Insérer avant un élément builder.insertBefore("#existing", "Pages/NewElement.ui"); ``` ## UIEventBuilder Lier des événements aux éléments UI avec `addEventBinding` : ```java import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType; import com.hypixel.hytale.server.core.ui.builder.EventData; @Override public void build(Ref ref, UICommandBuilder builder, UIEventBuilder events, Store store) { builder.append("Pages/Menu.ui"); // Lier des événements de clic avec addEventBinding events.addEventBinding(CustomUIEventBindingType.Activating, "#button_start", EventData.of("Action", "start_game")); events.addEventBinding(CustomUIEventBindingType.Activating, "#button_settings", EventData.of("Action", "open_settings")); } ``` ### Types de Liaison d'Événements | Type | Description | |------|-------------| | `Activating` | Clic/activation de bouton | | `RightClicking` | Action clic droit | | `DoubleClicking` | Action double-clic | | `MouseEntered` | Entrée du survol souris | | `MouseExited` | Sortie du survol souris | | `ValueChanged` | Valeur d'entrée changée | | `FocusGained` | Élément focus | | `FocusLost` | Élément perd le focus | ## Gérer les Événements Surchargez `handleDataEvent` pour traiter les interactions utilisateur. Le paramètre `rawData` contient du JSON avec les données de l'événement : ```java public class MenuPage extends CustomUIPage { public MenuPage(PlayerRef ref) { super(ref, CustomPageLifetime.CanDismiss); } @Override public void build(Ref ref, UICommandBuilder builder, UIEventBuilder events, Store store) { builder.append("Pages/MainMenu.ui"); events.addEventBinding(CustomUIEventBindingType.Activating, "#play_button", EventData.of("Action", "play")); events.addEventBinding(CustomUIEventBindingType.Activating, "#quit_button", EventData.of("Action", "quit")); } @Override public void handleDataEvent(Ref ref, Store store, String rawData) { // rawData contient du JSON comme : {"Action":"play"} if (rawData.contains("\"Action\":\"play\"")) { startGame(); } else if (rawData.contains("\"Action\":\"quit\"")) { close(); } } private void startGame() { // Logique de jeu... close(); // Fermer la page } } ``` {{< callout type="info" >}} **Conseil :** Pour une gestion d'événements plus complexe, envisagez d'utiliser une bibliothèque de parsing JSON ou d'étendre `InteractiveCustomUIPage` avec une classe de données typée. {{< /callout >}} ## Ouvrir des Pages Utilisez `PageManager` pour ouvrir des pages : ```java Player player = ...; PageManager pageManager = player.getPageManager(); // Ouvrir une page personnalisée pageManager.openCustomPage( player.getReference(), player.getReference().getStore(), new MenuPage(player.getPlayerRef()) ); ``` ## Fermer des Pages ```java // Depuis l'intérieur de la page protected void close() { // Méthode héritée - ferme cette page } // Depuis l'extérieur pageManager.setPage(ref, store, Page.None); ``` ## Mettre à Jour des Pages Mettre à jour le contenu sans reconstruire : ```java // Envoyer une mise à jour avec de nouvelles commandes UICommandBuilder update = new UICommandBuilder(); update.set("#score", newScore); sendUpdate(update); // Reconstruction complète rebuild(); // Vider et mettre à jour sendUpdate(update, true); // clear=true ``` ## Page avec Fenêtres Ouvrir des pages avec des fenêtres d'inventaire : ```java // Ouvrir une page avec des fenêtres pageManager.openCustomPageWithWindows( ref, store, new CraftingPage(playerRef), craftingWindow, playerInventoryWindow ); ``` ## Exemple de Page Interactive ```java public class ShopPage extends CustomUIPage { private int selectedItem = -1; private final List items; public ShopPage(PlayerRef ref, List items) { super(ref, CustomPageLifetime.CanDismiss); this.items = items; } @Override public void build(Ref ref, UICommandBuilder builder, UIEventBuilder events, Store store) { builder.append("Pages/Shop.ui"); // Peupler les items for (int i = 0; i < items.size(); i++) { ShopItem item = items.get(i); builder.set("#item_" + i + "_name", item.getName()); builder.set("#item_" + i + "_price", item.getPrice()); events.addEventBinding(CustomUIEventBindingType.Activating, "#item_" + i, EventData.of("Action", "select").append("Index", String.valueOf(i))); } events.addEventBinding(CustomUIEventBindingType.Activating, "#buy_button", EventData.of("Action", "buy")); events.addEventBinding(CustomUIEventBindingType.Activating, "#close_button", EventData.of("Action", "close")); } @Override public void handleDataEvent(Ref ref, Store store, String rawData) { // Parser les données JSON de l'événement if (rawData.contains("\"Action\":\"select\"")) { // Extraire l'index du JSON int indexStart = rawData.indexOf("\"Index\":\"") + 9; int indexEnd = rawData.indexOf("\"", indexStart); selectedItem = Integer.parseInt(rawData.substring(indexStart, indexEnd)); updateSelection(); } else if (rawData.contains("\"Action\":\"buy\"") && selectedItem >= 0) { purchaseItem(selectedItem); } else if (rawData.contains("\"Action\":\"close\"")) { close(); } } private void updateSelection() { UICommandBuilder update = new UICommandBuilder(); update.set("#selected_index", selectedItem); update.set("#selected_name", items.get(selectedItem).getName()); sendUpdate(update); } private void purchaseItem(int index) { // Logique d'achat... rebuild(); // Rafraîchir l'UI } } ``` ## Pages Intégrées Types de pages disponibles : | Page | Description | |------|-------------| | `Page.None` | Pas de page ouverte (fermer la page courante) | | `Page.Bench` | Interface d'établi/crafting | | `Page.Inventory` | Inventaire du joueur | | `Page.ToolsSettings` | Paramètres des outils | | `Page.Map` | Carte du monde | | `Page.MachinimaEditor` | Éditeur de machinima | | `Page.ContentCreation` | Outils de création de contenu | | `Page.Custom` | Page UI personnalisée | ```java // Ouvrir une page intégrée pageManager.setPage(ref, store, Page.Inventory); ``` ## Bonnes Pratiques {{< callout type="info" >}} **Directives des Pages Personnalisées :** - Utilisez `CanDismiss` sauf si la page doit être modale - Gérez le callback `onDismiss` pour le nettoyage - Utilisez `sendUpdate()` pour les petits changements, `rebuild()` pour les changements majeurs - Stockez l'état de la page dans des champs d'instance - Fermez correctement les pages en utilisant `close()` ou `setPage(Page.None)` {{< /callout >}} {{< callout type="warning" >}} **Important :** Vérifiez toujours si `playerRef.getReference()` est null avant d'accéder au store, car le joueur peut s'être déconnecté. {{< /callout >}}