Complemento Spigot: forma genérica de la clase principal del complemento

Oct 15 2020

He creado muchos complementos spigot en mi "carrera" como desarrollador para un grupo de servidores de Minecraft, pero cada vez que comienzo a escribir un nuevo complemento, básicamente "reinvento" la estructura de mi clase principal de complementos, siempre para que encaje. mejor en lo que considero que es un complemento legible, que también otros desarrolladores que trabajarán con estos complementos después de mí pueden hacerlo sin dolor de cabeza.

Mi clase principal más reciente se ve así:

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();
        }

    }

}

Sería genial tener una idea nueva de lo que se puede mejorar, tal vez no solo con respecto a las cosas relacionadas con el grifo, sino también con algunos malos hábitos generales que pueda tener. ¡Muchas gracias por adelantado! Si tiene alguna pregunta sobre alguna funcionalidad de las clases, no dude en consultarme en los comentarios :)

Respuestas

4 Bobby Oct 16 2020 at 02:01

Su formateo está parcialmente apagado, use un formateador de código.


public class Main extends JavaPlugin {

Ya no estoy familiarizado con las convenciones de nomenclatura de Bukkit, pero lo más probable es que esto se llame SpigotPlugin. Mainestá un poco reservado para las clases principales que son el principal punto de entrada para las aplicaciones.


¿Necesita el mecánico de instancias estáticas? Si puede, debe evitarlo.


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

Esto parece no usarse nunca.

Además, dado que es un mapa estático, lo más probable es que se pueda crear una API mejor cuando sea necesario. Por ejemplo, entregar la instancia actual a los oyentes creados.


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

Si recuerdo bien, Bukkit tiene una solución de registro, deberías usarla.


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

Eres inconsistente con respecto a tu thisuso.


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

No estoy seguro de si eso es parte de su código, pero tenga en cuenta que currentTimeMillises la hora del reloj de pared. Eso significa que observa los segundos intercalares, los cambios de zona horaria y similares. Así que dada la siguiente configuración:

long start = System.currentTimeMillis();

// Let 5 seconds pass.

long elapsed = System.currentTimeMillis() - start;

elapsed puede ser cualquier valor, desde "5000" hasta "500000" o incluso "-25000".


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

¿Cuáles son estos constructos? No soy amigo de los "moldes de cadenas vacías", si puede, sea explícito al respecto, por ejemplo Integer.toString(), con , o use String.format()o similar:

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) {

Realmente no tiene sentido observar esto solo para construir la cadena de manera diferente, solo use siempre la ruta else.


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

Como se dijo anteriormente, desea registrar los errores correctamente.

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

Igual que aquí.