Bonjour,
Certaines parties ont déjà été dites par Detobel, mais bon vu que c'est dit autrement je ne me suis pas amusé à les supprimer.
Sur ce bonne lecture :3
Java:
ArrayList<ItemStack> items = new ArrayList<ItemStack>();
Tu n'as pas spécifié de niveau d'accès pour ta variable, donc là est elle en
package
— dans ton cas elle devrait sans doute être privée :
Java:
private ArrayList<ItemStack> items = new ArrayList<ItemStack>();
Ensuite, elle n'est pas statique — c'est à dire que chaque instance de
Report
a sa propre variable
items
. Or tu fais :
Java:
@Override
public void onEnable() {
this.saveDefaultConfig();
this.getCommand("report").setExecutor(new Report(this));
this.getCommand("reports").setExecutor(new Report(this));
}
Ce qui équivaut à faire :
Java:
@Override
public void onEnable() {
this.saveDefaultConfig();
Report reportA = new Report(this);
Report reportB = new Report(this);
this.getCommand("report").setExecutor(reportA);
this.getCommand("reports").setExecutor(reportB);
}
Donc la commande
/report
modifie uniquement
reportA.items
; et
/reports
lit uniquement
reportB.items
.
Mais ce sont deux variables différentes, donc oui, ton inventaire est vide puis que
reportB.items
n'est jamais modifiée.
Si tu veux que tes deux commandes utilisent la même variable
items
, il faut que tu leurs donne le même exécuteur :
Java:
@Override
public void onEnable() {
this.saveDefaultConfig();
Report report = new Report(this);
this.getCommand("report").setExecutor(report);
this.getCommand("reports").setExecutor(report);
}
Comme ça,
/report
modifiera
report.items
et
/reports
lira
report.items
, donc la même variable.
C'est pour ça que Detobel dans son spoiler a mit :
Java:
private static final ArrayList<ItemStack> items = new ArrayList<ItemStack>();
Le mot-clef
static
indique que la variable est liée à la classe et non à l'objet ; chaque instance de
Report
utilisera la même variable
items
, et tu peux accéder à la variable sans passer par une instance :
Ensuite, derniers points ;
- Tu n'es pas obligé d'écrire deux fois le type de la classe générique :
Java:
private static final ArrayList<ItemStack> items = new ArrayList<>();
C'est plus lisible, notamment avec des List<Foo<Bar<Baz>>>
.
- C'est généralement mieux d'utiliser l'interface :
Java:
private static final List<ItemStack> items = new ArrayList<>();
https://stackoverflow.com/questions/2279030/type-list-vs-type-arraylist-in-java
- Vu le contexte et que tu n'as pas besoin d'un accès aléatoire, une liste chaînée serait plus rapide :
Java:
private static final List<ItemStack> items = new LinkedList<>();
Y a pas de "brouillon" quand on développe
Sinon tu dis toujours "ce sera pour plus tard", tu oublies et tu reviens jamais dessus... Si tu veux faire des "test" avant, tu fais juste un script en une class. Mais faut bien comprend ce qu'on fait. Le mieux c'est vraiment d'essayer de directement faire les choses bien. De ne pas tout développé. De ne faire qu'une partie. Mais la partie que tu fais, tu l'as fait bien
Bizu parlait optimisation mais de ce côté-là il faut s'attaquer avec parcimonie, parce qu'en soit il ne faut pas vraiment tout optimiser — mieux vaut un code lisible qu'un code illisible mais qui prend une nanoseconde de moins.
La règle est plutôt de regarder quelles fonctions prennent le plus de temps cumulé et d'optimiser celles-ci ; c'est plus intéressant de gagner une microseconde sur une fonction appelée 50 000 fois par seconde que de gagner une milliseconde sur une fonction qui n'est appelée qu'une fois au démarrage.
Bon après il y a toujours des lignes qui détruisent les yeux —
while(i < len(L)) L.get(i++)
sur une liste chaînée — mais je ne pense pas que le
final
change grand-chose dans les paramètres ou aux variables locales, sauf pour éventuellement les littéraux. Et le compilateur doit être assez intelligent pour savoir que la variable est effectivement
final
même sans le mot-clef.
IntelliJ affiche par défaut un avertissement lorsqu'un field peut être
final
parce qu'il dit que c'est prit en compte par l'optimisateur, et il y a aussi un autre avertissement pour justement les paramètres ou les variables locales qui peuvent être
final
, mais qui lui est désactivé par défaut et la description ne cite pas d'optimisation, donc je pense que c'est plutôt pour le code style.
Et de la même manière aucun paramètre des fonctions de Java n'est
final
, alors ça ne doit pas changer grand-chose.
Bon après c'est que pour le mot-clef
final
dans certains cas, personellement je ne l'utilise que dans les fields parce que je trouve ça un peu trop lourd dans les paramètres/variables locales — surtout que les objets ne sont pas constants, seul le pointeur l'est.
Bref pour le reste du code :
Java:
// `Report` sous-entend que command est un signalement d'un seul joueur,
// or il y en a plusieurs ;
//
// un meilleur nom serait `Reports` ou `CommandReport`
public class CommandReport implements CommandExecutor {
// convention: les classes commencent par une majuscule, donc `Main`
// + main veut dire tout et n'importe quoi, préfère mettre le nom de ton plugin
private MyPlugin plugin;
private static final List<ItemStack> items = new LinkedList<>();
public CommandReport(MyPlugin plugin) {
// le nom du paramètre `test` n'a aucun sens
this.plugin = plugin;
}
@Override
public boolean onKommand(CommandSender sender, Command command, String label, String[] args) {
// c'est plus élégant de `return` tout de suite que 15km après
if(!(sender instanceof Player)) {
sender.sendMessage("§cVous devez être un joueur pour pouvoir exécuter cette commande.");
return true; // `return false` affiche l'usage, or ce n'est pas le problème
}
Player author = (Player) sender;
// optimisation: le paramètre `label` indique déjà la commande ou l'alias utilisé
// optimisation: le nom du `label` ne peux pas être autre chose que ce que tu as écrit dans ton `plugin.yml`,
// on est sûr de la casse
if(label.equals("report")) {
// optimisation: équivaut à < 2
if(args.length < 2) {
// convention: les commandes sont en anglais
// convention: les paramètres requis sont entre chevrons
// + c'est mieux de commencer avec `Usage:` ou équivalent
author.sendMessage("Usage: /report <who> <reason>");
return true;
}
// optimisation: aucun autre cas possible, `else`
// or comme nous avons `return` dans le `if`,
// pas besoin de `else`
// ¿t?
Player target = Bukkit.getPlayer(args[0]);
// plus lisible de faire le check juste après que l'on ait récupéré `args[0]`
if(target == null) {
// français: “to report” se traduit par « signaler »
// anglais: “offline” ne prend pas de majuscule
// français: “offline” se traduit par « hors-ligne »
// convention: les messages d'erreurs sont en rouge
author.sendMessage(ChatColor.RED + "Tu ne peux pas signaler un joueur hors-ligne");
return true;
}
// ¿bc?
StringBuilder sb = new StringBuilder();
sb.append("Le joueur « ")
.append(author.getName())
.append(" » a signalé « ")
.append(target.getName())
.append(" » pour: ");
// args contient le nom du joueur signalé `args[0]`
for(int i = 1; i < args.length; ++i) {
sb.append(parts[i]);
}
// convention: si `getItem` créer un item, ce n'est pas un get
items.add(getItem(Material.PAPER, author.getName() /* ??? */, sb.toString() /* inutile d'utiliser un `StringBuilder` si tu + après */));
return true;
}
if(label.equals("reports" /* ¿majuscule? */)) {
if(author.hasPermission("rest.modo" /* ¿majuscule? */)) {
// ¿new?
new ScrollerInventory(items, ChatColor.RED + "Reports", author);
} else {
// rouge
author.sendMessage("§cTu n'as pas la permission de faire ceci !");
}
return true;
}
// ni `/report`, ni `/reports`
throw new RuntimeException("entered unreachable code: " + label); // ne devrait pas se produire
}
}
Ensuite, tu sauvegardes les signalements sous la forme d'un item ; NON. Tu dois créer une classe
Report
qui représentera un signalement avec :
Variable | Type | Description |
reportedPlayer | UUID | Le joueur signalé |
authorPlayer | UUID | Le joueur qui a fait le signalement |
reason | String | La raison du signalement |
date | long | La date du signalement |
Puis tu rajouteras ensuite une fonction
createRenderItem()
pour créer un item à partir de ces informations.
Cela te permettra de mieux sauvegarder les signalements, et que si tu veux changer les items que tu utilises dans
/reports
, tu auras juste à modifier la fonction sans à avoir besoin de modifier les données sauvegardées.
De plus, travailler avec des joueurs sous forme d'
UUID
s et non d'entités
Player
te permettra de supporter les joueurs hors-lignes
OfflinePlayer
.
Cordialement,
ShE3py