Package net.clementraynaud.skoice.common.api


package net.clementraynaud.skoice.common.api
Skoice Developer API

This package contains the main API entry points and event handling interfaces for developers building plugins that integrate with Skoice.

Overview

The Skoice API allows you to:

  • Check if players are connected to proximity voice chat
  • Query and manage Discord-Minecraft account links
  • Monitor proximity voice chat system status
  • Listen to events for player connections, account linking, and system state changes

Installation

Maven Dependency

Currently, Skoice is not published to a public Maven repository. You'll need to clone and compile Skoice locally, then install it into your local Maven repository.

For Spigot Plugins:

<dependency>
    <groupId>net.clementraynaud</groupId>
    <artifactId>skoice.spigot</artifactId>
    <version>3.2.9</version>
    <scope>provided</scope>
    <exclusions>
        <exclusion>
            <groupId>net.clementraynaud</groupId>
            <artifactId>skoice.common</artifactId>
        </exclusion>
    </exclusions>
</dependency>

For Velocity Plugins:

<dependency>
    <groupId>net.clementraynaud</groupId>
    <artifactId>skoice.common</artifactId>
    <version>3.2.9</version>
    <scope>provided</scope>
</dependency>

Plugin Configuration

Spigot (plugin.yml):

depend: [Skoice]

Velocity:

@Plugin(
    id = "your-plugin-id",
    name = "YourPlugin",
    version = "1.0.0",
    dependencies = {
        @Dependency(id = "skoice")
    }
)

Quick Start

Accessing the API

import net.clementraynaud.skoice.common.Skoice;
import net.clementraynaud.skoice.common.SkoiceAPI;
import net.clementraynaud.skoice.common.EventBus;

public class YourPlugin extends JavaPlugin {
    private SkoiceAPI skoice;
    private EventBus eventBus;

    @Override
    public void onEnable() {
        try {
            this.skoice = Skoice.api();
            this.eventBus = Skoice.eventBus();

            if (this.skoice == null || this.eventBus == null) {
                throw new RuntimeException("Skoice API is not available");
            }

            // API is ready to use
            setupEventListeners();
        } catch (Throwable t) {
            t.printStackTrace();
            getServer().getPluginManager().disablePlugin(this);
        }
    }
}

Checking Player Status

UUID playerUuid = player.getUniqueId();

// Check if player has linked their Discord account
if (skoice.isLinked(playerUuid)) {
    // Player has linked their account
}

// Check if player is connected to proximity chat
if (skoice.isProximityConnected(playerUuid)) {
    // Player is in proximity chat
}

// Check if proximity chat system is running
if (skoice.isSystemReady()) {
    // Proximity chat is active
}

Subscribing to Events

// Listen for players connecting to proximity chat
eventBus.subscribe(PlayerProximityConnectEvent.class, event -> {
    UUID playerId = event.getMinecraftId();
    String discordId = event.getDiscordId();
    // Player connected to proximity chat
});

// Listen for players disconnecting from proximity chat
eventBus.subscribe(PlayerProximityDisconnectEvent.class, event -> {
    UUID playerId = event.getMinecraftId();
    // Player disconnected from proximity chat
});

// Listen for system ready
eventBus.subscribe(SystemReadyEvent.class, event -> {
    // Proximity chat is now running
});

// Listen for system interruption
eventBus.subscribe(SystemInterruptionEvent.class, event -> {
    // Proximity chat stopped running
});

Complete Example: Proximity Chat Requirement Plugin

This example shows how to create a plugin that requires players to be in proximity chat, displaying alerts until they connect.

Spigot Implementation

public class ProximityChatRequired extends JavaPlugin implements Listener {
    private final Map<UUID, Integer> alertTasks = new HashMap<>();
    private SkoiceAPI skoice;

    @Override
    public void onEnable() {
        EventBus eventBus;
        try {
            this.skoice = Skoice.api();
            eventBus = Skoice.eventBus();
            if (this.skoice == null || eventBus == null) {
                throw new RuntimeException("Skoice API is not available");
            }
        } catch (Throwable t) {
            t.printStackTrace();
            getServer().getPluginManager().disablePlugin(this);
            return;
        }

        getServer().getPluginManager().registerEvents(this, this);

        eventBus.subscribe(PlayerProximityConnectEvent.class, event -> {
            if (isPlayerAlerted(event.getMinecraftId())) {
                getServer().getScheduler().cancelTask(alertTasks.get(event.getMinecraftId()));
                alertTasks.remove(event.getMinecraftId());
            }
        });

        eventBus.subscribe(PlayerProximityDisconnectEvent.class, event -> {
            if (skoice.isSystemReady()) {
                alert(getServer().getPlayer(event.getMinecraftId()));
            }
        });

        eventBus.subscribe(SystemReadyEvent.class, event -> {
            getServer().getOnlinePlayers().forEach(player -> {
                if (!skoice.isProximityConnected(player.getUniqueId())) {
                    alert(player);
                }
            });
        });

        eventBus.subscribe(SystemInterruptionEvent.class, event -> {
            alertTasks.keySet().forEach(uuid ->
                getServer().getScheduler().cancelTask(alertTasks.get(uuid))
            );
            alertTasks.clear();
        });
    }

    private boolean isPlayerAlerted(UUID uuid) {
        return alertTasks.containsKey(uuid);
    }

    private void alert(Player player) {
        if (player != null && player.isOnline() && !isPlayerAlerted(player.getUniqueId())) {
            int taskId = getServer().getScheduler().runTaskTimer(this, () -> {
                if (player.isOnline()) {
                    player.sendTitlePart(TitlePart.TITLE, Component.text("Proximity Chat is Required!"));
                    player.sendTitlePart(TitlePart.TIMES, Title.Times.times(
                            Duration.ofMillis(0), Duration.ofMillis(800), Duration.ofMillis(0)));
                } else {
                    getServer().getScheduler().cancelTask(alertTasks.get(player.getUniqueId()));
                    alertTasks.remove(player.getUniqueId());
                }
            }, 0, 8).getTaskId();
            alertTasks.put(player.getUniqueId(), taskId);
        }
    }

    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event) {
        getServer().getScheduler().runTaskLater(this, () -> {
            if (!skoice.isProximityConnected(event.getPlayer().getUniqueId())
                    && skoice.isSystemReady()) {
                alert(event.getPlayer());
            }
        }, 40);
    }

    @EventHandler
    public void onPlayerQuit(PlayerQuitEvent event) {
        if (isPlayerAlerted(event.getPlayer().getUniqueId())) {
            getServer().getScheduler().cancelTask(alertTasks.get(event.getPlayer().getUniqueId()));
            alertTasks.remove(event.getPlayer().getUniqueId());
        }
    }
}

API Reference

Main Classes

  • SkoiceAPI - Main API for querying player and system state
  • EventBus - Event subscription system
  • EventHandler - Handle for managing event subscriptions

Events

Best Practices

  • Always check if the API is not null before using it
  • Use isSystemReady() to determine if proximity chat is active before enforcing requirements
  • Subscribe to SystemReadyEvent and SystemInterruptionEvent to handle system state changes
  • Clean up event handlers and scheduled tasks when your plugin disables
  • Account link/unlink events are only fired for in-game operations, not for programmatic API calls
  • All event handlers are executed asynchronously on a dedicated event thread
See Also: