Bonsoir,
Le but d'un manager est de gérer un ensemble homogène d'objets, par ex.
BookManager
représenterait une bibliothèque, et s'occuperait de rajouter les nouveaux livres au bon endroit (les tomes 2 à droite des tomes 1, et non dans le premier trou qu'il trouve).
Dire que
TestGui
est un
GUItestManager
revient à dire qu'un livre est un gestionnaire de livres/une bibliothèque, ce qui n'a pas beaucoup de sens en soit.
Il est possible en Java de créer des fonctions qui ne sont pas liées à des objets avec le mot-clef
static
, par ex. :
Java:
public class Math {
// La constante π
public static final float PI = 3.14f;
// Renvoie la valeur absolue d'un nombre à virgule flottante
public static float abs(float x) {
if(x < 0) {
return -x;
else {
return x;
}
}
}
float f = Math.abs(Math.PI);
System.out.println(f); // 3.14
Donc ce que tu veux serait plutôt une classe utilitaire (c'est-à-dire qu'on ne créer jamais ; tu ne feras jamais un
new Math().cos(0)
) :
Java:
public class GuiHelper {
private static final List<ItemStack> ITEM_STACKS = new ArrayList();
public static void init() {
ItemStack empty = new ItemStack(Material.BLACK_STAINED_GLASS_PANE);
ItemMeta meta = empty.getItemMeta();
meta.setDisplayName(" ");
empty.setItemMeta(meta);
ITEM_STACKS.add(empty);
}
public static ItemStack getItem(int i) {
return ITEM_STACKS.get(i);
}
}
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
GuiHelper.init();
this.getLogger().info(GuiHelper.getItem(0));
}
}
Et pour en revenir à ta question de pourquoi ce que tu avais fait ne marchait pas :
Java:
public class GUItestManager {
private List<ItemStack> listItemStack = new ArrayList<>();
public void initGui() {
// créer un nouvel objet héritant de GUItestManager
TestGui testGui = new TestGui();
// modifie this.listItemStack
testLoadItemStack();
// testGui.listItemStack n'a jamais été modifié
testGui.SetupConfirmGUI();
}
}
Chaque instance de GUItestManager (et par conséquent TestGui, vu que c'est un GUItestManager) a sa propre variable
listItemStack
, et tu n'as jamais appelé la fonction
testLoadItemStack()
sur l'objet
testGui
que tu viens de créer. Même si un chat engendre un chaton, ceux-ci ont deux corps différents et ce n'est pas en puçant un parent que tu puceras le chaton ; si tu veux que toutes les instances d'une classe partagent une même variable, il faut la préfixer du mot-clef
static
.
Après il se trouve qu'en Java, il existe une fonction qui est automatiquement appelée lorsqu'une classe est chargée en mémoire pour la première fois ; c'est ce qu'on appelle le constructeur de classe ou initialiseur statique :
Java:
public class GuiHelper {
// @Unmodifiable
private static final List<ItemStack> ITEM_STACKS;
static {
ItemStack empty = new ItemStack(Material.BLACK_STAINED_GLASS_PANE);
ItemMeta meta = empty.getItemMeta();
meta.setDisplayName(" ");
empty.setItemMeta(meta);
ITEM_STACKS = new ImmutableList.Builder<ItemStack>().add(empty).build();
}
public static ItemStack getItem(int i) {
return ITEM_STACKS.get(i);
}
}
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
// accéder à GuiHelper pour la première fois appelera automatiquement
// le constructeur de classe `static { ... }` de GuiHelper
this.getLogger().info(GuiHelper.getItem(0));
}
}
Ensuite, l'idée en programmant est quand même de s'approcher d'un langage naturel ;
Java:
System.out.println(getItemFromList(0));
Moi je lis « afficher le premier élément de la liste ». Or tu veux « afficher l'item vide/la bordure ».
Dans trois mois, tu vas rouvrir ton code pour voir ce genre de monstre :
Java:
ItemStack item = getItemFromList(666);
Et donc tu vas être obligé de relire comment est faite ta liste, récupérer le numéro de la ligne où est le premier élement, additionner 666 à ce nombre, puis regarder quel item se situe à cette nouvelle ligne pour savoir de quoi on parle.
C'est ce qu'on appelle les nombres magiques, c'est une très mauvaise idée d'en avoir, donc créer une constante magique pour y remédier :
Java:
public class GuiHelper {
private static final List<ItemStack> ITEM_STACKS;
public static final int ITEM_EMPTY_BORDER;
static {
ItemStack empty = new ItemStack(Material.BLACK_STAINED_GLASS_PANE);
ItemMeta meta = empty.getItemMeta();
meta.setDisplayName(" ");
empty.setItemMeta(meta);
ITEM_STACKS = new ImmutableList.Builder<ItemStack>().add(empty).build();
ITEM_EMPTY_BORDER = ITEM_STACKS.indexOf(empty);
}
public static ItemStack getItem(int i) {
return ITEM_STACKS.get(i);
}
}
ItemStack item = GuiHelper.getItem(GuiHelper.ITEM_EMPTY_BORDER);
Et en soit je ne sais pas trop pourquoi tu t'emmerdes avec une liste :
Java:
public class GuiHelper {
public static final ItemStack ITEM_EMPTY_BORDER;
static {
ItemMeta meta;
ITEM_EMPTY_BORDER = new ItemStack(Material.BLACK_STAINED_GLASS_PANE);
meta = ITEM_EMPTY_BORDER.getItemMeta();
meta.setDisplayName(" ");
ITEM_EMPTY_BORDER.setItemMeta(meta);
}
}
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
this.getLogger().info(GuiHelper.ITEM_EMPTY_BORDER);
}
}
Après il faut noter que si jamais tu modifies l'item tu le modifieras pour tout le monde, donc n'oublie pas de dupliquer l'objet si jamais tu veux le modifier :
Java:
ItemStack stack = GuiHelper.ITEM_EMPTY_BORDER.clone();
stack.setAmount(64);
Mais en théorie si l'objet change en cours de route il faudrait plutôt en faire une fonction :
Java:
// Dans GuiHelper
public static ItemStack getPlayerHead(Player p) {
// ...
}
Et ce serait aussi pas mal de créer deux classes utilitaires :
GuiItems
avec tous les items globaux
GuiHelper
avec tout ce qui touche l'inventaire (style remplir une ligne avec un même item)
Ça permettra d'écrire un code plus concis :
Java:
GuiHelper.fillLine(inventory, 0, GuiItems.BORDER);
Mais dans ce cas là, ce serait plus intéressant de faire une classe parente qui gèrera les évènements en plus :
Java:
public class Gui {
private static final Map<Player, Gui> OPEN_GUIS = new WeakHashMap<>();
protected final Inventory inventory;
private final IntObjectMap<Consumer<Player>> events = new IntObjectHashMap<>();
protected Gui(Inventory inventory) {
if(inventory.getType() != InventoryType.CHEST) {
throw new UnsupportedOperationException("Only chest inventories are supported");
}
this.inventory = inventory;
}
protected final void registerClickEvent(int slot, Consumer<Player> handler) {
this.events.put(slot, handler);
}
protected final void fillBorder(@Nullable ItemStack stack) {
final int rows = this.inventory.getSize() / 9;
if(rows < 3) {
throw new IllegalArgumentException("At least three rows are required for a border to be drawn");
}
for(int i = 0; i < 9; ++i) {
this.inventory.setItem(i, stack);
}
for(int row = 1; row < (rows - 1); ++row) {
final int rowStart = 9 * row;
final int rowEnd = rowStart + 8;
this.inventory.setItem(rowStart, stack);
this.inventory.setItem(rowEnd, stack);
}
final int lastRowBegin = 9 * (rows - 1);
final int lastRowEnd = lastRowBegin + 9;
for(int i = lastRowBegin; i < lastRowEnd; ++i) {
this.inventory.setItem(i, stack);
}
}
public final void open(Player p) {
OPEN_GUIS.put(p, this);
p.openInventory(this.inventory);
}
public static void handleEvent(InventoryClickEvent e) {
Gui gui;
if(e.getWhoClicked() instanceof Player p && (gui = OPEN_GUIS.get(p)) != null) {
e.setCancelled(true);
Consumer<Player> handler;
if((handler = gui.events.get(e.getSlot())) != null) {
handler.accept(p);
}
}
}
}
public class MyGui extends Gui {
public static final MyGui INSTANCE;
private static final ItemStack HELLO_ITEM;
static {
ItemMeta meta;
HELLO_ITEM = new ItemStack(Material.OAK_SIGN);
meta = HELLO_ITEM.getItemMeta();
meta.setDisplayName("Hello");
HELLO_ITEM.setItemMeta(meta);
INSTANCE = new MyGui();
}
private MyGui() {
super(Bukkit.createInventory(null, 27, "My GUI"));
this.fillBorder(MyItems.BORDER);
this.inventory.setItem(14, HELLO_ITEM);
this.registerClickEvent(14, MyGui::sayHello);
}
private static void sayHello(Player p) {
p.sendMessage("Hello !");
}
}
public class MyPlugin extends JavaPlugin implements Listener {
@Override
public void onEnable() {
this.getServer().getPluginManager().registerEvents(this, this);
}
@EventHandler
public void onPlayerJoinEvent(PlayerJoinEvent e) {
MyGui.INSTANCE.open(e.getPlayer());
}
@EventHandler
public void onInventoryClickEvent(InventoryClickEvent e) {
Gui.handleEvent(e);
}
}
Aucune idée de si ça marche, mais l'idée est là, et il faut aussi que tu l'adaptes à ta sauce.
Cordialement,
ShE3py