Citymoon Dynamics logo - digital infrastructure and web solutionsCitymoon Dynamics
Serviços
Casos de Estudo
A Nossa História
Desenvolvedores
Preços
Docs
Fóruns
Contacto
EntrarRegistar

Documentação

Citymoon Dynamics

Citymoon Dynamics

Minecraft

DisBan6
authentication.ymlconfig.ymldiscord.ymllang.ymlantileak.ymlPermissões

Discord

Rymbo

Serviços Web

Ulises Licenses

Glossário

Glossário

Documentação Ulises Licenses

Documentação oficial

Referência completa para developers no site Ulises Licenses.

Abrir documentação oficial↗

Integração de Plugin Minecraft

1. Carregar Ficheiro de Configuração

private void loadAntileakConfig() {
    File myBestPluginDir = getDataFolder();
    if (!myBestPluginDir.exists()) {
        myBestPluginDir.mkdirs();
    }

    File antileakFile = new File(myBestPluginDir, "antileak.yml");
    if (!antileakFile.exists()) {
        try {
            antileakFile.createNewFile();
            this.antileakConfig = YamlConfiguration.loadConfiguration(antileakFile);
            this.antileakConfig.set("license.key", "your-license-key-here");
            this.antileakConfig.save(antileakFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    } else {
        this.antileakConfig = YamlConfiguration.loadConfiguration(antileakFile);
    }
}

2. Validação de Licença com Lógica de Retry

private void validateLicense() {
    UlisesLib ulib = new UlisesLib();
    String productId = "myproductid";
    String licenseKey = this.antileakConfig.getString("license.key", "");
   
    boolean licenseValid = false;
    while (!licenseValid) {
        if (ulib.isLicenseValid(productId, licenseKey)) {
            licenseValid = true;
            
            String discordId = ulib.getDiscordId(productId, licenseKey);
            String productName = ulib.getProductName(productId, licenseKey);
            String expiresAt = ulib.getExpirationDate(productId, licenseKey);
            String licenseStatus = ulib.getLicenseStatus(productId, licenseKey);
            
            Bukkit.getConsoleSender().sendMessage(
                ChatColor.GRAY + "[" + ChatColor.DARK_AQUA + "MyBestPlugin" + ChatColor.GRAY + "] " +
                ChatColor.DARK_AQUA + "✓ Authentication successful. Powering up MyBestPlugin..."
            );
            Bukkit.getConsoleSender().sendMessage(
                ChatColor.GRAY + "[" + ChatColor.DARK_AQUA + "MyBestPlugin" + ChatColor.GRAY + "] " +
                ChatColor.GRAY + " » Discord ID: " + ChatColor.AQUA + discordId
            );
            
            loadPlugin();
            
        } else {
            String lastError = ulib.getLastError();
            Bukkit.getConsoleSender().sendMessage(
                ChatColor.GRAY + "[" + ChatColor.DARK_AQUA + "MyBestPlugin" + ChatColor.GRAY + "] " +
                ChatColor.RED + "✗ License authentication failed: " + lastError
            );
            
            if (lastError != null && lastError.contains("Unable to connect to the backend server")) {
                Bukkit.getConsoleSender().sendMessage(
                    ChatColor.GRAY + "[" + ChatColor.DARK_AQUA + "MyBestPlugin" + ChatColor.GRAY + "] " +
                    ChatColor.YELLOW + "⚠ Retrying connection in 30 seconds..."
                );
                
                try {
                    Thread.sleep(30000);
                } catch (InterruptedException e) {
                    Bukkit.getPluginManager().disablePlugin(this);
                    return;
                }
            } else {
                Bukkit.getPluginManager().disablePlugin(this);
                return;
            }
        }
    }
}

3. Verificações Periódicas de Segurança

private void startSecurityChecks() {
    ScheduledExecutorService licenseService = Executors.newSingleThreadScheduledExecutor();
    
    licenseService.scheduleAtFixedRate(() -> {
        UlisesLib ulib = new UlisesLib();
        String productId = antileakConfig.getString("license.product-id", "");
        String licenseKey = antileakConfig.getString("license.key", "");
        
        if (!ulib.isLicenseValid(productId, licenseKey)) {
            String lastError = ulib.getLastError();
            Bukkit.getConsoleSender().sendMessage(
                ChatColor.GRAY + "[" + ChatColor.DARK_AQUA + "MyBestPlugin" + ChatColor.GRAY + "] " +
                ChatColor.RED + "✗ License validation failed during periodic check."
            );
            
            if (lastError != null && lastError.contains("Unable to connect to the backend server")) {
                Bukkit.getConsoleSender().sendMessage(
                    ChatColor.GRAY + "[" + ChatColor.DARK_AQUA + "MyBestPlugin" + ChatColor.GRAY + "] " +
                    ChatColor.YELLOW + "⚠ Will retry in next check cycle..."
                );
            } else {
                Bukkit.getScheduler().runTask(this, () -> Bukkit.getPluginManager().disablePlugin(this));
                licenseService.shutdown();
            }
        } else {
            Bukkit.getConsoleSender().sendMessage(
                ChatColor.GRAY + "[" + ChatColor.DARK_AQUA + "MyBestPlugin" + ChatColor.GRAY + "] " +
                ChatColor.GREEN + "✓ License check passed. Status: " + 
                ulib.getLicenseStatus(productId, licenseKey)
            );
        }
    }, 10L, 10L, TimeUnit.MINUTES);
}

Exemplo Completo de Plugin

public class MyBestPlugin extends JavaPlugin {
    private FileConfiguration antileakConfig;
    
    @Override
    public void onEnable() {
        loadAntileakConfig();
        
        String productId = antileakConfig.getString("license.product-id");
        String licenseKey = antileakConfig.getString("license.key");
        
        if (productId.equals("your-product-id-here") || licenseKey.equals("your-license-key-here")) {
            getLogger().severe("License details not configured. Please edit antileak.yml");
            Bukkit.getPluginManager().disablePlugin(this);
            return;
        }
        
        validateLicense(productId, licenseKey);
    }
    
    private void validateLicense(String productId, String licenseKey) {
        UlisesLib ulib = new UlisesLib();
        
        while (true) {
            if (ulib.isLicenseValid(productId, licenseKey)) {
                String discordId = ulib.getDiscordId(productId, licenseKey);
                String expiresAt = ulib.getExpirationDate(productId, licenseKey);
                
                getLogger().info("License validated for Discord ID: " + discordId);
                getLogger().info("License expires: " + expiresAt);
                
                loadFeatures();
                startPeriodicChecks();
                break;
                
            } else {
                String error = ulib.getLastError();
                getLogger().severe("License validation failed: " + error);
                
                if (error != null && error.contains("Unable to connect to the backend server")) {
                    getLogger().warning("Retrying connection in 30 seconds...");
                    try {
                        Thread.sleep(30000);
                    } catch (InterruptedException e) {
                        Bukkit.getPluginManager().disablePlugin(this);
                        break;
                    }
                } else {
                    Bukkit.getPluginManager().disablePlugin(this);
                    break;
                }
            }
        }
    }
    
    private void startPeriodicChecks() {
        Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> {
            UlisesLib ulib = new UlisesLib();
            String productId = antileakConfig.getString("license.product-id");
            String licenseKey = antileakConfig.getString("license.key");
            
            if (!ulib.isLicenseValid(productId, licenseKey)) {
                String error = ulib.getLastError();
                getLogger().severe("Periodic license check failed: " + error);
                
                if (!error.contains("Unable to connect to the backend server")) {
                    Bukkit.getScheduler().runTask(this, () -> 
                        Bukkit.getPluginManager().disablePlugin(this)
                    );
                }
            } else {
                getLogger().info("Periodic license check passed.");
            }
        }, 20L * 60 * 10, 20L * 60 * 10);
    }
}

Métodos API Avançados

String getDiscordId(String productId, String licenseKey)

Obtém o Discord ID associado à licença. Retorna null se a validação falhar.

String discordId = ulib.getDiscordId(productId, licenseKey);
// Returns: <span className="text-primary">"1216532655592439862"</span>

String getProductName(String productId, String licenseKey)

Obtém o nome do produto da licença. Retorna null se a validação falhar.

String productName = ulib.getProductName(productId, licenseKey);
// Returns: <span className="text-primary">"MyBestPlugin"</span>

String getExpirationDate(String productId, String licenseKey)

Obtém a data de expiração em formato ISO. Retorna null se a validação falhar.

String expiresAt = ulib.getExpirationDate(productId, licenseKey);
// Returns: <span className="text-primary">"2025-12-05T00:00:00.000Z"</span>

String getLicenseStatus(String productId, String licenseKey)

Obtém o estado da licença (ativa/revogada/expirada). Retorna null se a validação falhar.

String status = ulib.getLicenseStatus(productId, licenseKey);
// Returns: <span className="text-primary">"active"</span>

String getSubType(String productId, String licenseKey)

Obtém o subtipo da licença (Enterprise, Advanced, etc). Retorna null se a validação falhar.

String subType = ulib.getSubType(productId, licenseKey);
// Returns: <span className="text-primary">"Enterprise"</span>

String getLastError()

Retorna a última mensagem de erro. Útil para debug de ligação.

Gestão da Ligação

Reconexão Automática

A biblioteca trata problemas de ligação automaticamente

  • Retry Infinito: se o backend não responde, a biblioteca tenta a cada 30 segundos até conseguir
  • Mensagens Claras: a consola mostra "Unable to connect to the backend server" com contagem
  • Tratamento Elegante: só desativa o plugin por problemas reais de licença, não de ligação

Nota Importante para Plugin Developers

O teu plugin deve continuar a correr durante problemas de ligação. Desativa-o só por falhas reais de licença (expirada, revogada, inválida). Problemas de ligação pedem retry, não shutdown imediato.

Integração Auto-Update

UlisesLib inclui métodos para check de updates, download do último jar e verificação de integridade. Todas as validações (estado, HWID, limites IP) são automáticas.

boolean checkForUpdate(String productId, String licenseKey, String currentVersion)

Verifica se há versão mais recente do jar. Retorna true se houver update.

String currentVersion = "1.0.0";
if (ulib.checkForUpdate(productId, licenseKey, currentVersion)) {
    getLogger().info("Update available! Downloading...");
    ulib.downloadUpdate(productId, licenseKey, hwid);
}

File downloadUpdate(String productId, String licenseKey, String hwid)

Descarrega o último jar. Trata HWID binding no primeiro download. Retorna o File ou null se falhar.

String hwid = ulib._getHwid();
File updatedJar = ulib.downloadUpdate(productId, licenseKey, hwid);
if (updatedJar != null) {
    getLogger().info("Update downloaded: " + updatedJar.getName());
    if (ulib.verifyChecksum(productId, licenseKey, hwid, updatedJar)) {
        getLogger().info("Checksum verified!");
    }
}

boolean verifyChecksum(String productId, String licenseKey, String hwid, File jarFile)

Verifica o SHA-256 do jar descarregado para garantir integridade.

File jarFile = new File("plugins/MyPlugin.jar");
boolean valid = ulib.verifyChecksum(productId, licenseKey, hwid, jarFile);
if (!valid) {
    getLogger().warning("Checksum mismatch! File may be corrupted.");
}

String getCurrentVersion(String productId, String licenseKey)

Retorna a última versão do jar disponível no servidor.

String latestVersion = ulib.getCurrentVersion(productId, licenseKey);
getLogger().info("Latest version available: " + latestVersion);

Validações de Segurança

Todas as operações de update validam automaticamente:

  • Estado da Licença: só licenças ativas não expiradas podem descarregar updates
  • HWID Binding: Hardware ID validado e ligado à licença no primeiro download
  • Limite IP: respeita o limite IP configurado por licença

Exemplo Completo Auto-Update

private void checkAndApplyUpdate(String productId, String licenseKey) {
    String currentVersion = this.getDescription().getVersion();
    String hwid = ulib.getHardwareId();

    if (ulib.checkForUpdate(productId, licenseKey, currentVersion)) {
        String latestVersion = ulib.getCurrentVersion(productId, licenseKey);
        getLogger().info("New version available: " + latestVersion + " (current: " + currentVersion + ")");

        File updatedJar = ulib.downloadUpdate(productId, licenseKey, hwid);
        if (updatedJar != null) {
            if (ulib.verifyChecksum(productId, licenseKey, hwid, updatedJar)) {
                getLogger().info("Update downloaded and verified successfully!");
                getLogger().info("Restart the server to apply the update.");
            } else {
                getLogger().warning("Checksum verification failed. Update may be corrupted.");
            }
        }
    } else {
        getLogger().info("Plugin is up to date.");
    }
}

Boas Práticas

✓ A Fazer

  • Usa retry loops infinitos para problemas de ligação
  • Mostra info detalhada da licença em validação com sucesso
  • Implementa verificações periódicas (a cada 10 minutos)
  • Cria ficheiro de configuração com valores padrão

✗ A Evitar

  • Desativar o plugin em timeout de ligação
  • Hardcodar credenciais no código
  • Expor detalhes de erro aos utilizadores finais
  • Correr validação na main thread
←Rymbo
→Glossário
Citymoon Dynamics logo - digital infrastructure and web solutionsCitymoon Dynamics

Soluções avançadas para infraestrutura digital. Especialistas em Minecraft, Discord e Desenvolvimento Web.

Serviços relacionados

  • Ulises Licenses
  • Freewings Discord Bot
  • ResistanceCore Plugin
  • Synth | Enterprise Serverside Anticheat

More

  • Rymbo
  • Vulcan + Grim | Prime AC Configuration
  • DisBan | Sync and appeals made easier

Navegação

  • A Nossa História
  • Serviços
  • Casos de Estudo
  • Impacto
  • Contacto

Legal

  • Privacidade
  • Termos
  • Cookies
  • Reembolsos

© (2026) 2025-2030 Citymoon Dynamics S.R.L. (citymoon.org). Todos os direitos reservados. | Registered by Eric Martinez, Director.

An international service, made in Uruguay