9.9 KiB
title, type, weight
| title | type | weight |
|---|---|---|
| Pages Personnalisées | docs | 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 :
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
// 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
// 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
// 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
// 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 :
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 :
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 :
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
// 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 :
// 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 :
// Ouvrir une page avec des fenêtres
pageManager.openCustomPageWithWindows(
ref, store,
new CraftingPage(playerRef),
craftingWindow,
playerInventoryWindow
);
Exemple de Page Interactive
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 |
// Ouvrir une page intégrée
pageManager.setPage(ref, store, Page.Inventory);
Bonnes Pratiques
{{< callout type="info" >}} Directives des Pages Personnalisées :
- Utilisez
CanDismisssauf si la page doit être modale - Gérez le callback
onDismisspour 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()ousetPage(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 >}}