Plugin Spigot: forma genérica da classe principal do plugin

Oct 15 2020

Eu criei muitos plug-ins spigot em minha "carreira" como desenvolvedor para vários servidores do Minecraft, mas toda vez que começo a escrever um novo plug-in, basicamente "reinvento" a estrutura da minha classe de plug-in principal, sempre para que se encaixe melhor no que considero ser um plug-in legível, que também outros desenvolvedores que trabalharão com esses plug-ins depois de mim podem fazê-lo sem ter dor de cabeça.

Minha classe principal mais recente tem esta aparência:

package com.clanplugin;

import java.math.RoundingMode;
import java.util.HashMap;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scoreboard.Scoreboard;

import com.earth2me.essentials.api.UserDoesNotExistException;

import com.clanplugin.commands.ClanCommand;
import com.clanplugin.commands.CommandRegistry;
import com.clanplugin.commands.implementation.AcceptCommand;
import com.clanplugin.commands.implementation.CreateCommand;
import com.clanplugin.commands.implementation.DeleteCommand;
import com.clanplugin.commands.implementation.DerankCommand;
import com.clanplugin.commands.implementation.InfoCommand;
import com.clanplugin.commands.implementation.InviteCommand;
import com.clanplugin.commands.implementation.InvitesCommand;
import com.clanplugin.commands.implementation.KickCommand;
import com.clanplugin.commands.implementation.LeaveCommand;
import com.clanplugin.commands.implementation.ListCommand;
import com.clanplugin.commands.implementation.MoneyCommand;
import com.clanplugin.commands.implementation.UprankCommand;
import com.clanplugin.commands.implementation.RejectCommand;
import com.clanplugin.commands.implementation.RevokeCommand;
import com.clanplugin.commands.implementation.SetCbCommand;
import com.clanplugin.commands.implementation.SetLeaderCommand;
import com.clanplugin.commands.implementation.SetNameCommand;
import com.clanplugin.commands.implementation.SetTagCommand;
import com.clanplugin.commands.implementation.ShowMaxClanMemberCommand;
import com.clanplugin.commands.implementation.ToggleMoneyCommand;
import com.clanplugin.commands.implementation.ToplistCommand;
import com.clanplugin.database.DatabaseConnector;
import com.clanplugin.database.DatabaseMethods;
import com.clanplugin.listener.PlayerConnectListener;
import com.clanplugin.listener.PlayerDisconnectListener;
import com.clanplugin.listener.TagSetterListener;
import com.clanplugin..manager.ClantagCache;
import com.clanplugin..manager.MessageManager;
import net.ess3.api.Economy;

public class Main extends JavaPlugin {
    
    private static CommandRegistry commandRegistry;
    
    private static Main plugin;
    public static HashMap<Player, Long> lastUseOfCommand = new HashMap<Player, Long>();

    public void onEnable() {
        plugin = this;

        saveDefaultConfig();
        registerCommands();
        registerListeners();
        loadDatabase();
        setDataUponReload();
    }

    public void onDisable() {
        DatabaseConnector.disconnect();

        System.out.println(MessageManager.disabledPluginConsoleMessage());
        plugin = null;
    }

    public static Main getInstance() {
        return plugin;
    }

    private void loadDatabase() {
        DatabaseConnector.connect();
        DatabaseMethods.initialiseDatabaseTables();
    }
    
    private void registerCommands() {
        this.getCommand("clan").setExecutor(new ClanCommand());
        
        commandRegistry = new CommandRegistry();
        
        commandRegistry.registerCommand(new ShowMaxClanMemberCommand());
        commandRegistry.registerCommand(new ListCommand());
        commandRegistry.registerCommand(new LeaveCommand());
        commandRegistry.registerCommand(new DeleteCommand());
        commandRegistry.registerCommand(new InvitesCommand());
        commandRegistry.registerCommand(new ToplistCommand());
        commandRegistry.registerCommand(new MoneyCommand());
        commandRegistry.registerCommand(new ToggleMoneyCommand());
        
        commandRegistry.registerCommand(new InviteCommand());
        commandRegistry.registerCommand(new AcceptCommand());
        commandRegistry.registerCommand(new RejectCommand());
        commandRegistry.registerCommand(new KickCommand());
        commandRegistry.registerCommand(new RevokeCommand());
        commandRegistry.registerCommand(new InfoCommand());
        commandRegistry.registerCommand(new SetTagCommand());
        commandRegistry.registerCommand(new SetNameCommand());
        commandRegistry.registerCommand(new SetLeaderCommand());
        commandRegistry.registerCommand(new UprankCommand());
        commandRegistry.registerCommand(new DerankCommand());
        commandRegistry.registerCommand(new SetCbCommand());

        commandRegistry.registerCommand(new CreateCommand());
        
        
    }
    
    public static CommandRegistry getCommandRegistry() {
        return commandRegistry;
    }
    
    private void registerListeners() {
        getServer().getPluginManager().registerEvents(new PlayerConnectListener(), this);
        getServer().getPluginManager().registerEvents(new PlayerDisconnectListener(), this);
        getServer().getPluginManager().registerEvents(new TagSetterListener(), this);
    }
    
    private void setDataUponReload() {
        for(Player player : Bukkit.getOnlinePlayers()) {
            if (DatabaseMethods.isPlayerInClan(player.getUniqueId())) {
                String playerUUID = DatabaseMethods.getPlayerUUID(player.getUniqueId());
                if (playerUUID.equals(player.getUniqueId().toString()))
                    DatabaseMethods.addPlayerName(player.getName(), player.getUniqueId());

                ClantagCache.put(player, DatabaseMethods.getClanTagByClanID(DatabaseMethods.getClanIDByPlayerUuid(player.getUniqueId())));
            }
            
            PlayerConnectListener.joinTimes.put(player, System.currentTimeMillis());
        }
    }
    
    @SuppressWarnings("deprecation")
    public static void updateScoreBoard(Player player) {
        try {

        if (player == null || player.getScoreboard() == null) {
            return;
        }

        Scoreboard board = player.getScoreboard();

        if (Bukkit.getOnlinePlayers().size() == 0) {

            board.getTeam("onlineplayers").setPrefix(" " + "0" + "/" + "" + Bukkit.getServer().getMaxPlayers());

        } else {

            board.getTeam("onlineplayers")
                    .setPrefix("" + Bukkit.getOnlinePlayers().size() + "/" + Bukkit.getServer().getMaxPlayers());

        }

        try {
            board.getTeam("Kontostandcheck")
                    .setPrefix("" + Economy.getMoneyExact(player.getName()).setScale(2, RoundingMode.DOWN) + "$");
        } catch (IllegalStateException | IllegalArgumentException | UserDoesNotExistException e) {
            e.printStackTrace();
        }
        
        } catch (Exception e) {
            System.out.println("[ClanSystem] This is not the live environement or the scoreboard configuration has changed. Please review carefully.");
            e.printStackTrace();
        }

    }

}

Seria ótimo ter uma ideia nova do que pode ser melhorado, talvez não apenas em relação ao material relacionado à torneira, mas também talvez alguns maus hábitos gerais que eu possa ter. Muito obrigado antecipadamente! Se você tiver alguma dúvida sobre alguma funcionalidade das aulas sinta-se à vontade para me perguntar nos comentários :)

Respostas

4 Bobby Oct 16 2020 at 02:01

Sua formatação está parcialmente incorreta, use um formatador de código.


public class Main extends JavaPlugin {

Não estou mais familiarizado com as convenções de nomenclatura do Bukkit, mas isso provavelmente deve ser chamado SpigotPlugin. Mainé meio reservado para classes principais que são o principal ponto de entrada para aplicativos.


Você precisa do mecânico da instância estática? Se você puder, você deve evitá-lo.


public static HashMap<Player, Long> lastUseOfCommand = new HashMap<Player, Long>();

Isso parece nunca ser usado.

Além disso, como se trata de um mapa estático, muito provavelmente pode-se criar uma API melhor quando necessário. Por exemplo, entregar a instância atual aos ouvintes criados.


System.out.println(MessageManager.disabledPluginConsoleMessage());

Se bem me lembro, o Bukkit oferece uma solução de registro em log, você deve usá-la.


this.getCommand("clan").setExecutor(new ClanCommand());

Você é inconsistente em relação ao seu thisuso.


PlayerConnectListener.joinTimes.put(player, System.currentTimeMillis());

Não tenho certeza se isso faz parte do seu código, mas esteja ciente de que currentTimeMillisé hora do relógio. Isso significa que ele observa segundos bissextos, alterações de fuso horário e assim por diante. Portanto, dada a seguinte configuração:

long start = System.currentTimeMillis();

// Let 5 seconds pass.

long elapsed = System.currentTimeMillis() - start;

elapsed pode ser qualquer valor, provavelmente de "5000" a "500000" ou mesmo "-25000".


board.getTeam("onlineplayers").setPrefix(" " + "0" + "/" + "" + Bukkit.getServer().getMaxPlayers());
// ...
board.getTeam("onlineplayers")
                    .setPrefix("" + Bukkit.getOnlinePlayers().size() + "/" + Bukkit.getServer().getMaxPlayers());

Quais são essas construções? Não sou amigo de "casts de strings vazias", se você puder, seja explícito sobre isso, por exemplo Integer.toString(), com , ou use String.format()ou semelhante:

board.getTeam("onlineplayers").setPrefix(String.format("0/%i",
    Bukkit.getServer().getMaxPlayers()));
// ...
board.getTeam("onlineplayers").setPrefix(String.format("%i/%i",
    Integer.valueOf(Bukkit.getOnlinePlayers().size()),
    Integer.valueOf(Bukkit.getServer().getMaxPlayers()));

if (Bukkit.getOnlinePlayers().size() == 0) {

Não há realmente um ponto em observar isso apenas para construir a string de forma diferente, apenas use sempre o caminho else.


        try {
            board.getTeam("Kontostandcheck")
                    .setPrefix("" + Economy.getMoneyExact(player.getName()).setScale(2, RoundingMode.DOWN) + "$");
        } catch (IllegalStateException | IllegalArgumentException | UserDoesNotExistException e) {
            e.printStackTrace();
        }

Como dito anteriormente, você deseja registrar os erros corretamente.

        } catch (Exception e) {
            System.out.println("[ClanSystem] This is not the live environement or the scoreboard configuration has changed. Please review carefully.");
            e.printStackTrace();
        }

O mesmo aqui.