# 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="/files/2EFBaJm2y6ePPmslHgbh" %}

## ⚒️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="/files/vMIA3jRNAy7Xl8m4y5sS" %}

***

#### 🌍 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
        }
      ]
    }
  ]
}
```

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://horizons-cite-plugin.gitbook.io/horizons-cite-plugin/apis/api-java-and-modules.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
