# API Java & Modules

***

## 📝 Introduction

Horizons expose une API Java complète via le package `org.metaloul.horizons.api`.\
Pour utiliser l'API, ajoutez le jar de Horizons à votre projet (scope `provided`).

### Point d'entrée

```java
import org.metaloul.horizons.api.Horizons;

if (Horizons.isEnabled()) {
    // Accès statique aux managers
    TeamManagerAPI teams = Horizons.getTeamAPI();
    ShopAPI shops = Horizons.getShopAPI();
}
```

***

## 🧩 Système de Modules

Le système de modules permet de créer des extensions qui tournent **à l'intérieur** de Horizons. Contrairement aux plugins Bukkit classiques, les modules bénéficient de :

* **Partage de ressources** : Connexion BDD partagée, système de configuration unifié.
* **Intégration profonde** : Accès direct aux managers internes.
* **Isolation** : ClassLoader dédié pour éviter les conflits de dépendances.
* **Hot-Reload** : Possibilité de recharger la configuration des modules sans redémarrer.

### Créer un module

Un module est un simple JAR contenant un fichier `module.yml` et une classe étendant `HorizonsModule`.

{% stepper %}
{% step %}

### Le descriptor (module.yml)

À placer à la racine du JAR :

```yaml
name: MonModule
version: 1.0.0
main: com.monpackage.MonModule
author: VotreNom
description: Un module exemple
dependencies: [] # Modules requis
```

{% endstep %}

{% step %}

### La classe principale

```java
import org.metaloul.horizons.api.module.HorizonsModule;

public class MonModule extends HorizonsModule {

    public MonModule() {
        super("MonModule", "1.0.0", "Auteur");
    }

    @Override
    public void onEnable() {
        getLogger().info("Mon module démarre !");
        
        // Enregistrement automatique (nettoyé au disable)
        registerCommand(new MaCommande());
        registerListener(new MonListener());
        
        // Configurable GUI item
        setConfigMetadata("options.welcome", Material.PAPER, "Welcome Msg", "Description");
    }

    @Override
    public void onDisable() {
        // Nettoyage automatique
    }
}
```

{% endstep %}
{% endstepper %}

### 🎨 Personnalisation du GUI de Configuration (Optionnel)

Les modules peuvent personnaliser l'apparence de leurs options dans le menu de configuration admin (`/horizons config`). Ceci est **purement optionnel** ; par défaut, Horizons affichera des items génériques.

Utilisez `setConfigMetadata` dans `onEnable` :

```java
// 1. Icône du module dans la liste principale
setConfigMetadata("", Material.DIAMOND_SWORD, "&bMon Module", "&7Description du module");

// 2. Icône pour une section de config spécifique
setConfigMetadata("database", Material.CHEST, "&eBase de données", "&7Configuration MySQL");

// 3. Icône pour une valeur spécifique
setConfigMetadata("database.host", Material.PAPER, "&fHôte Connexion", "&7IP du serveur");
```

**Syntaxe** : `setConfigMetadata(String path, Material icon, String name, String description)`

* `path` : Chemin dans le config.yml (ex: `category.setting`). Chaine vide `""` pour le module lui-même.
* `icon` : Material Bukkit à afficher.
* `name` & `description` : Supportent les codes couleurs (`&a`, `&l`, etc.).

***

## 😎Exemple de module

{% file src="<https://3398716199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fzsj8PIy5NManDncw6i9Z%2Fuploads%2FAd85zZh0JolljWOzGYgI%2FModerationModule.zip?alt=media&token=1387e1a7-a32c-4205-a473-343280635e90>" %}

## ⚒️Custom Item Providers

Horizons offre deux façons d'ajouter des items custom :

* Méthode Simplifiée (`SimpleCustomItemProvider`) : Pour ajouter rapidement vos propres items créés via code.
* Méthode Avancée (`CustomItemProvider`) : Pour intégrer un plugin d'items externe (comme MMOItems, ExecutableItems, etc).

Option A : Créer vos propres items (Simple)

```java
// 1. Initialiser le provider pour votre module
SimpleCustomItemProvider myProvider = new SimpleCustomItemProvider("mon_module");

// 2. Créer vos ItemStacks (Exemple avec ItemBuilder mais marche avec n'importe quel ItemStack)
ItemStack superEpée = new ItemStack(Material.DIAMOND_SWORD);
ItemMeta meta = superEpée.getItemMeta();
meta.setDisplayName("§cExcalibur");
superEpée.setItemMeta(meta);

// 3. Enregistrer les items dans votre provider
// Soit un par un :
myProvider.registerItem("excalibur", superEpée);
myProvider.registerItem("bouclier_magique", magicShield);

// Soit automatiquement depuis une classe (champs 'public static ItemStack') :
// L'ID sera le nom du champ en minuscule (ex: "EXCALIBUR" -> "excalibur")
myProvider.registerItemsFromClass(MyItems.class);

// 4. Enregistrer le provider dans Horizons
registerCustomItemProvider(myProvider);
```

Option B : Support d'un Plugin Externe (Avancé)

```java
public class MonPluginProvider implements CustomItemProvider {
    @Override
    public String getProviderId() { return "mon_plugin_externe"; }
    
    @Override
    public Optional<ItemStack> getItemStack(String id, int amount) {
        // Logique pour récupérer l'item depuis l'API externe
        return ExternalApi.getItem(id);
    }
    
    // ... implémenter les autres méthodes (isCustomItem, etc)
}

// Enregistrement
registerCustomItemProvider(new MonPluginProvider());
```

Utilisation dans les configs (Shop, Kits, etc) : Une fois enregistrés, vos items sont accessibles partout dans Horizons via le format : `provider_id:item_id`.\
Exemple : `mon_module:excalibur` ou `oraxen:hyper_sword`.

## 😎Exemple d'item custom simple

{% file src="<https://3398716199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fzsj8PIy5NManDncw6i9Z%2Fuploads%2Fn2bBh6NC02afY8StQcAo%2Fsrc.zip?alt=media&token=a7fd6d8e-5e4c-4810-9941-4ded1a59ef54>" %}

***

#### 🌍 Système de Traduction (I18n)

Horizons fournit un système de langue natif et automatisé pour vos modules.

**1. Structure des Fichiers** Dans votre projet (JAR), placez vos fichiers YAML de langue dans `src/main/resources/languages/` :

* `fr_FR.yml` (Français)
* `en_US.yml` (Anglais - Fallback par défaut)

Exemple de contenu `fr_FR.yml` :

```yaml
mon-module:
  welcome: "&aBienvenue sur mon module, {player} !"
  error: "&cUne erreur est survenue."
```

**2. Utilisation dans le Code** Votre classe principale (`HorizonsModule`) possède la méthode `msg()` pour récupérer les messages traduits.

```java
// String msg(String key, String... placeholders)

// Simple
player.sendMessage(msg("mon-module.error"));

// Avec placeholders ({player} -> "Bob")
player.sendMessage(msg("mon-module.welcome", "{player}", player.getName()));
```

**3. Automatisation**

* **Installation** : Au premier lancement, vos fichiers `.yml` sont extraits automatiquement dans `plugins/Horizons/modules/<votre-module>/languages/`.
* **Synchronisation** : Votre module utilise automatiquement la langue définie dans la config globale de Horizons.
* **Reload** : La commande `/hz reload` recharge aussi vos langues instantanément.

***

## 🛠 APIs Principales

Cette section présente les concepts. Pour la liste complète des méthodes, voir la section Référence Syntaxique Complète ci-dessous.

### TeamManagerAPI

Gère les équipes, scores et joueurs.

```java
TeamManagerAPI api = Horizons.getTeamAPI();
api.addTeamScore("Red", 100);
```

### ShopAPI

Gère l'économie, les shops et le marché noir.

```java
ShopAPI api = Horizons.getShopAPI();
double price = api.getItemPrice("minerals::miner", Material.DIAMOND);
```

### WebAPIManager

Permet d'interroger les données du serveur via HTTP/JSON.

***

## 📚 Référence Syntaxique Complète

Voici la liste exhaustive des méthodes disponibles pour chaque API.

### TeamManagerAPI Référence

**Package** : `org.metaloul.horizons.api`\
**Accès** : `Horizons.getTeamAPI()`

#### Vérifications & Lecture

| Retour                 | Méthode                                          | Description                                     |
| ---------------------- | ------------------------------------------------ | ----------------------------------------------- |
| `boolean`              | `teamExists(String teamName)`                    | Vérifie si une équipe existe.                   |
| `boolean`              | `isPlayerInTeam(Player player, String teamName)` | Vérifie si le joueur est dans l'équipe donnée.  |
| `String`               | `getTeamPrefix(String teamName)`                 | Retourne le préfixe (couleur/tag).              |
| `String`               | `getTeamDisplayName(String teamName)`            | Retourne le nom d'affichage.                    |
| `int`                  | `getTeamScore(String teamName)`                  | Retourne le score actuel.                       |
| `String`               | `getPlayerTeam(Player player)`                   | Retourne le nom de l'équipe du joueur.          |
| `List<String>`         | `getAllTeams()`                                  | Retourne tous les noms d'équipes.               |
| `List<Player>`         | `getTeamPlayers(String teamName)`                | Retourne les joueurs **en ligne**.              |
| `List<UUID>`           | `getTeamPlayerUUIDs(String teamName)`            | Retourne **tous** les joueurs (offline inclus). |
| `Map<String, Integer>` | `getAllTeamScores()`                             | Retourne une map Equipe -> Score.               |
| `List<String>`         | `getTeamsSortedByScore()`                        | Retourne les équipes triées par score.          |

#### Modification (Écriture)

| Retour    | Méthode                                                  | Description                |
| --------- | -------------------------------------------------------- | -------------------------- |
| `void`    | `createTeam(String name, String prefix, String display)` | Crée une nouvelle équipe.  |
| `void`    | `removeTeam(String teamName)`                            | Supprime une équipe.       |
| `void`    | `addPlayerToTeam(Player player, String teamName)`        | Ajoute un joueur.          |
| `boolean` | `removePlayerFromTeam(String playerName)`                | Retire un joueur.          |
| `void`    | `setTeamPrefix(String teamName, String prefix)`          | Change le préfixe.         |
| `void`    | `setTeamDisplayName(String teamName, String name)`       | Change le nom d'affichage. |
| `void`    | `setTeamScore(String teamName, int score)`               | Définit le score.          |
| `void`    | `addTeamScore(String teamName, int points)`              | Ajoute des points.         |
| `void`    | `removeTeamScore(String teamName, int points)`           | Retire des points.         |

***

### ShopAPI Référence

**Package** : `org.metaloul.horizons.api`\
**Accès** : `Horizons.getShopAPI()`

#### Ouverture de Shop

| Retour        | Méthode                                  | Description                                              |
| ------------- | ---------------------------------------- | -------------------------------------------------------- |
| `boolean`     | `openShop(Player player, String shopId)` | Ouvre un shop pour un joueur. Retourne `true` si succès. |
| `Set<String>` | `getAllShopIds()`                        | Retourne tous les IDs de shops disponibles.              |

#### Lecture des Prix & Items

| Retour           | Méthode                                                  | Description                        |
| ---------------- | -------------------------------------------------------- | ---------------------------------- |
| `boolean`        | `shopExists(String shopId)`                              | Vérifie l'existence d'un shop.     |
| `List<Material>` | `getShopItems(String shopId)`                            | Liste des matériaux vendus.        |
| `double`         | `getItemPrice(String shopId, Material material)`         | Prix global actuel.                |
| `double`         | `getItemPrice(String shopId, Material mat, String team)` | Prix pour une équipe spécifique.   |
| `double`         | `getCustomItemPrice(String shopId, String itemKey)`      | Prix d'un item custom.             |
| `PriceTrend`     | `getPriceTrend(String shopId, Material material)`        | Tendance (`UP`, `DOWN`, `STABLE`). |

#### Marché Noir

| Retour           | Méthode                                            | Description           |
| ---------------- | -------------------------------------------------- | --------------------- |
| `boolean`        | `blackMarketExists(String marketId)`               | Vérifie l'existence.  |
| `List<Material>` | `getBlackMarketItems(String marketId)`             | Items disponibles.    |
| `int`            | `getBlackMarketItemPrice(String id, Material mat)` | Prix actuel (entier). |

#### Configuration des Scopes (Global vs Per-Team)

| Retour   | Méthode                                                      | Description                           |
| -------- | ------------------------------------------------------------ | ------------------------------------- |
| `String` | `getPriceScope(String shopId, String itemKey)`               | Scope effectif (`GLOBAL`/`PER_TEAM`). |
| `String` | `getShopPriceScope(String shopId)`                           | Scope configuré pour le shop.         |
| `String` | `getGlobalPriceScope()`                                      | Scope par défaut du serveur.          |
| `void`   | `setItemPriceScope(String shopId, String key, String scope)` | Configure le scope d'un item.         |
| `void`   | `setShopPriceScope(String shopId, String scope)`             | Configure le scope d'un shop.         |

***

### WebAPIManager (HTTP API)

**Authentification** : Toutes les requêtes HTTP nécessitent le paramètre `?secret=VOTRE_SECRET_API`.\
**Port par défaut** : `8080` (Configurable dans config.yml).\
**Format** : Réponse JSON UTF-8.

#### Endpoints HTTP

1. Liste des Équipes\
   GET /api/teams?secret=...

Retourne la liste complète des équipes, scores et joueurs.

```json
{
  "teams": [
    {
      "name": "red",
      "displayName": "&cRouge",
      "displayNameClean": "Rouge",
      "prefix": "&c[R]",
      "score": 150,
      "players": [
        { "uuid": "...", "name": "Player1", "online": true },
        { "uuid": "...", "name": "Player2", "online": false }
      ]
    }
  ]
}
```

2. Liste des Joueurs\
   GET /api/players?secret=...

Retourne tous les joueurs connus avec leur équipe et score personnel.

```json
{
  "players": [
    {
      "uuid": "...",
      "name": "Player1",
      "score": 10,
      "team": "red",
      "online": true
    }
  ]
}
```

3. Données des Shops\
   GET /api/shops?secret=...

Retourne la configuration et les prix actuels de tous les shops.

```json
{
  "shops": [
    {
      "id": "minerals::miner",
      "name": "Miner Shop",
      "items": [
        {
          "material": "DIAMOND",
          "currentPrice": 45.5,
          "pricingType": "DYNAMIC",
          "basePrice": 50.0
        }
      ]
    }
  ]
}
```

***
