Init
This commit is contained in:
341
content/ui-systems/custom-pages.fr.md
Normal file
341
content/ui-systems/custom-pages.fr.md
Normal file
@@ -0,0 +1,341 @@
|
||||
---
|
||||
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<EntityStore> ref, UICommandBuilder builder,
|
||||
UIEventBuilder events, Store<EntityStore> 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<EntityStore> ref, UICommandBuilder builder,
|
||||
UIEventBuilder events, Store<EntityStore> 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<EntityStore> ref, UICommandBuilder builder,
|
||||
UIEventBuilder events, Store<EntityStore> 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<EntityStore> ref, Store<EntityStore> 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<T>` 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<ShopItem> items;
|
||||
|
||||
public ShopPage(PlayerRef ref, List<ShopItem> items) {
|
||||
super(ref, CustomPageLifetime.CanDismiss);
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(Ref<EntityStore> ref, UICommandBuilder builder,
|
||||
UIEventBuilder events, Store<EntityStore> 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<EntityStore> ref, Store<EntityStore> 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 >}}
|
||||
Reference in New Issue
Block a user