@@ -0,0 +1,178 @@
|
||||
# Hytale — Serveur & plugin MMORPG
|
||||
|
||||
Serveur Hytale de développement et plugin **com.disklexar:MMORPG** : profils joueurs persistants, progression, classes, métiers, groupes et fondations pour l'économie, les quêtes et les guildes.
|
||||
|
||||
## Prérequis
|
||||
|
||||
- **JDK 25+** (Java 26 recommandé si JDK 25 indisponible)
|
||||
- **Gradle** via le wrapper inclus (`./gradlew`)
|
||||
- Serveur Hytale (binaire ou `./gradlew runServer` via [ScaffoldIt](https://scaffoldit.dev))
|
||||
- Installation **Hytale** (launcher officiel) pour les assets du jeu
|
||||
|
||||
## Démarrage rapide
|
||||
|
||||
```bash
|
||||
# Depuis ce dossier (Hytale/)
|
||||
cp hytale.properties.example hytale.properties
|
||||
# Éditer hytale.home_path (voir exemples dans le fichier)
|
||||
|
||||
./start-server.sh
|
||||
```
|
||||
|
||||
Réinitialiser le monde de dev si le serveur a planté sans assets :
|
||||
|
||||
```bash
|
||||
HYTALE_RESET_DEVSERVER=1 ./start-server.sh
|
||||
```
|
||||
|
||||
Ou manuellement :
|
||||
|
||||
```bash
|
||||
JAVA_HOME=/usr/lib/jvm/java-25-openjdk ./gradlew build
|
||||
JAVA_HOME=/usr/lib/jvm/java-25-openjdk ./gradlew runServer
|
||||
```
|
||||
|
||||
Le JAR produit se trouve dans `build/libs/hytale-mmorpg-0.1.0.jar` (nom selon version Gradle).
|
||||
|
||||
### Déploiement manuel
|
||||
|
||||
1. Copier le JAR dans le dossier `mods/` du serveur Hytale
|
||||
2. Redémarrer le serveur
|
||||
3. La configuration est générée dans le répertoire de données du plugin : `mods/com.disklexar_MMORPG/config.json`
|
||||
|
||||
## Systèmes MMORPG
|
||||
|
||||
| Système | Contenu | Effet |
|
||||
|---------|---------|-------|
|
||||
| **Classes** | Chevalier (`knight`) | Armes : Épée longue, Hache de bataille. 3 capacités (Charge/dash+étourdissement 3s, Toupie 3s, Cri de guerre : repousse + −20% résistance 20s, bonus si étourdi). |
|
||||
| **Pouvoirs** (passifs, aucun par défaut) | Sprinteur (`sprinter`), Résilient (`resilient`) | +10% vitesse hors combat / +10% dégâts 5s après avoir été touché. |
|
||||
| **Métiers** | Tueur de monstre (`monster_slayer`), Mineur (`miner`) | +1 money par monstre tué / +1 money par bloc cassé. |
|
||||
| **Groupes** | Partage d'XP | Les membres reçoivent 40% de l'XP gagnée sur un kill. |
|
||||
| **Races** | Humain (`human`, par défaut) | XP ×2. |
|
||||
|
||||
> **Effets de combat** : dash, étourdissement, toupie, knockback et le buff de vitesse sont
|
||||
> implémentés via les APIs serveur (`Velocity`, `TransformComponent`, `MovementManager`,
|
||||
> `TargetUtil`, `DamageSystems`). Les valeurs (distances, forces, dégâts) sont des constantes à
|
||||
> ajuster en jeu.
|
||||
|
||||
## Commandes
|
||||
|
||||
| Commande | Description |
|
||||
|----------|-------------|
|
||||
| `/mmorpg help` | Affiche l'aide |
|
||||
| `/mmorpg profile` | Résumé court (niveau, XP) |
|
||||
| `/mmorpg info` | Toutes vos informations (chat) |
|
||||
| `/mmorpg menu` | Menu joueur MMORPG — onglets Personnage, Inventaire, Compétences |
|
||||
| `/mmorpg inventory` | Même menu, ouvert directement sur l'onglet Inventaire |
|
||||
| `/mmorpg class <choisir\|quitter\|info> [classe]` | Gérer votre classe |
|
||||
| `/mmorpg power <recevoir\|retirer\|info> [pouvoir]` | Gérer vos pouvoirs |
|
||||
| `/mmorpg job <rejoindre\|quitter\|info> [metier]` | Gérer vos métiers |
|
||||
| `/mmorpg group <inviter\|accepter\|quitter\|kick\|info> [joueur]` | Gérer votre groupe |
|
||||
| `/mmorpg ability <1\|2\|3>` | Utiliser une capacité de classe |
|
||||
| `/mmorpg password <mot_de_passe>` | Définir ou modifier le mot de passe web |
|
||||
| Touches **Use Ability 1/2/3** | Même effet que la commande ci-dessus (si vous avez une classe) |
|
||||
|
||||
### Capacités de classe (touches Ability 1/2/3)
|
||||
|
||||
Les armes vanilla possèdent leurs propres compétences sur les slots Ability. Le plugin les **remplace**
|
||||
dès qu'un joueur a choisi une classe MMORPG :
|
||||
|
||||
1. **Filtre de paquets** (`SyncInteractionChains`) — intercepte Ability 1/2/3 avant le moteur vanilla,
|
||||
envoie `CancelInteractionChain` au client et lance la capacité de classe.
|
||||
2. **Interaction native** (`mmorpg_cast_ability`) — enregistrée côté serveur ; les patches d'items dans
|
||||
`plugins/mmorpg/src/main/resources/Server/Item/Items/` remplacent Ability1/2/3 sur les armes de test (sync client/serveur).
|
||||
|
||||
Prérequis en jeu : `/mmorpg class choisir <classe>` puis équiper une arme autorisée pour cette classe.
|
||||
Sans classe, les compétences vanilla de l'arme s'appliquent normalement.
|
||||
|
||||
Pour ajouter d'autres armes, copiez un patch JSON existant (ex. `Weapon_Longsword_Mithril.json`) en
|
||||
ne gardant que `"Id"` et `"Interactions"`.
|
||||
|
||||
`/mmorpg menu` ouvre une `CustomUIPage` listant toutes les infos du joueur (classe, race, pouvoirs,
|
||||
métiers, groupe, money, temps de jeu, dates…). Un plugin **serveur seul** ne peut pas ajouter un
|
||||
bouton dans l'écran d'inventaire natif ; les équivalents fournis sont la commande `/mmorpg menu` et
|
||||
l'interaction `mmorpg_player_info` (voir `plugins/mmorpg/assetpack/README.md` pour brancher un asset `.ui`).
|
||||
|
||||
## Configuration
|
||||
|
||||
Fichier `config.json` (valeurs par défaut dans `plugins/mmorpg/src/main/resources/config.json`) :
|
||||
|
||||
| Clé | Description |
|
||||
|-----|-------------|
|
||||
| `Debug` | Logs détaillés |
|
||||
| `DefaultLevel` | Niveau initial des nouveaux joueurs |
|
||||
| `MaxPlayers` | Limite prévue (référence future) |
|
||||
| `BaseXpPerLevel` | XP de base requise par niveau |
|
||||
| `KillExperience` | XP de base accordée par monstre tué |
|
||||
| `Database.FileName` | Nom du fichier SQLite (`mmorpg.db`) |
|
||||
| `Database.UseMonorepoRoot` | Si `true`, place la base à la racine du dépôt (dossiers `Hytale/` + `Webapp/`) |
|
||||
| `Database.Path` | Chemin absolu ou relatif au dossier de données du plugin (prioritaire) |
|
||||
| `Features.Economy` | Active le module économie |
|
||||
| `Features.Quests` | Active le module quêtes (M3) |
|
||||
| `Features.Guilds` | Active le module guildes (M4) |
|
||||
|
||||
## Base de données
|
||||
|
||||
Le plugin persiste les données joueurs dans **SQLite**.
|
||||
|
||||
### Emplacement
|
||||
|
||||
| Contexte | Fichier |
|
||||
|----------|---------|
|
||||
| **Monorepo (dev)** | `../mmorpg.db` à la racine du dépôt (détection auto si `UseMonorepoRoot: true`) |
|
||||
| **Production** | `{dataDirectory}/mmorpg.db` ou chemin explicite via `Database.Path` |
|
||||
|
||||
Inspecter en local :
|
||||
|
||||
```bash
|
||||
sqlite3 ../mmorpg.db
|
||||
SELECT uuid, display_name, level, experience FROM player_profiles;
|
||||
```
|
||||
|
||||
Les fichiers `*.db` sont ignorés par Git.
|
||||
|
||||
### Schéma
|
||||
|
||||
`player_profiles` : `class_id`, `powers` (JSON), `jobs` (JSON), `guild_id`, `group_id`,
|
||||
`is_connected`, `total_time_play`, `last_date_connected`, `date_creation`, `money`, `race_id`.
|
||||
|
||||
Tables de référence : `classes`, `powers`, `jobs`, `races`, `groups`, `group_members`.
|
||||
|
||||
Migrations versionnées via `schema_migrations` — voir `plugins/mmorpg/src/main/resources/db/migrations/`.
|
||||
|
||||
## Structure du plugin
|
||||
|
||||
```
|
||||
plugins/mmorpg/src/main/java/com/disklexar/mmorpg/
|
||||
├── MmorpgPlugin.java # Point d'entrée (commandes + systèmes ECS)
|
||||
├── bootstrap/ # Initialisation et registre de services
|
||||
├── core/ # Config et contrats
|
||||
├── player/ # Sessions, profils, registre des joueurs en ligne
|
||||
├── persistence/ # SQLite (migrations versionnées, repositories)
|
||||
├── command/ # Commandes /mmorpg
|
||||
├── events/ # Connexion / déconnexion, filtre paquets Ability
|
||||
├── interaction/ # mmorpg_cast_ability (interaction native asset pack)
|
||||
├── progression/ # XP et niveaux (multiplicateurs de race)
|
||||
├── economy/ # Monnaie (money)
|
||||
├── rpg/ # clazz · power · job · race · group
|
||||
├── combat/ # Capacités, état de combat, effets passifs
|
||||
│ └── system/ # Systèmes ECS : dégâts, morts/kills, casse de bloc
|
||||
├── ui/ # AbilityBarHud, PlayerMenuPage, PlayerInfoPage
|
||||
├── quest/ # Stub (M3)
|
||||
└── social/ # Stub (M4)
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Interface utilisateur MMORPG (UI/UX)](docs/README-UI.md)
|
||||
- [Architecture](docs/ARCHITECTURE.md)
|
||||
- [Feuille de route](docs/ROADMAP.md)
|
||||
- [Guide de développement](docs/DEVELOPMENT.md)
|
||||
- [Contribution](../CONTRIBUTING.md)
|
||||
|
||||
### Custom UI (Hytale)
|
||||
|
||||
- [Custom UI — vue d'ensemble](https://hytalemodding.dev/en/docs/official-documentation/custom-ui)
|
||||
- [Layout](https://hytalemodding.dev/en/docs/official-documentation/custom-ui/layout)
|
||||
- [Common Styling](https://hytalemodding.dev/en/docs/official-documentation/custom-ui/common-styling)
|
||||
- [Guide plugin UI](https://hytalemodding.dev/en/docs/guides/plugin/ui)
|
||||
@@ -0,0 +1,45 @@
|
||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||
|
||||
plugins {
|
||||
id("com.gradleup.shadow") version "9.0.0-rc1"
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(25))
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.setSrcDirs(listOf("plugins/mmorpg/src/main/java"))
|
||||
resources.setSrcDirs(listOf("plugins/mmorpg/src/main/resources"))
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.xerial:sqlite-jdbc:3.47.2.0")
|
||||
implementation("com.google.code.gson:gson:2.11.0")
|
||||
implementation("at.favre.lib:bcrypt:0.10.2")
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveClassifier.set("")
|
||||
mergeServiceFiles()
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
tasks.assemble {
|
||||
dependsOn(tasks.shadowJar)
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
# Architecture
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Le projet est un **plugin monolithique** Java déployé sur le serveur Hytale officiel. Le serveur gère le monde, le réseau et l'ECS ; le plugin ajoute la couche MMORPG (persistance, progression, systèmes futurs).
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph server [Serveur Hytale]
|
||||
ECS[ECS / Mondes]
|
||||
Events[EventBus]
|
||||
Cmds[CommandRegistry]
|
||||
end
|
||||
|
||||
subgraph mmorpg [Plugin com.disklexar:MMORPG]
|
||||
Plugin[MmorpgPlugin]
|
||||
Boot[Bootstrap]
|
||||
Registry[ServiceRegistry]
|
||||
PlayerSvc[PlayerSessionService]
|
||||
DB[(SQLite)]
|
||||
end
|
||||
|
||||
Plugin --> Boot --> Registry
|
||||
Registry --> PlayerSvc
|
||||
PlayerSvc --> DB
|
||||
Plugin --> Events
|
||||
Plugin --> Cmds
|
||||
```
|
||||
|
||||
## Cycle de vie du plugin
|
||||
|
||||
| Phase | Responsabilité |
|
||||
|-------|----------------|
|
||||
| `setup()` | Charge la config, initialise `Bootstrap`, enregistre commandes et événements |
|
||||
| `start()` | Démarre les services (`DatabaseManager`, `PlayerSessionService`, …) |
|
||||
| `shutdown()` | Sauvegarde les sessions, ferme SQLite |
|
||||
|
||||
Le singleton `MmorpgPlugin.get()` est rafraîchi à chaque chargement pour rester compatible avec le hot-reload Hytale.
|
||||
|
||||
## Modules et dépendances
|
||||
|
||||
| Package | Dépend de | Rôle |
|
||||
|---------|-----------|------|
|
||||
| `bootstrap` | `core`, `persistence`, `player` | Câblage des services |
|
||||
| `core` | — | Config, interface `Service` |
|
||||
| `persistence` | `core` | SQLite, repositories |
|
||||
| `player` | `persistence`, `core` | Profils et sessions en ligne |
|
||||
| `command` | `player`, `bootstrap` | Interface joueur |
|
||||
| `events` | `player`, `bootstrap` | Connexion / déconnexion |
|
||||
| `economy`, `quest`, `social` | — (stubs) | Extensions futures |
|
||||
|
||||
**Règle** : les packages `economy`, `quest` et `social` ne doivent pas être importés par `core` ou `persistence` tant qu'ils ne sont pas implémentés. L'activation se fait via `Features.*` dans `config.json`.
|
||||
|
||||
## Persistance
|
||||
|
||||
- Fichier : `{monorepoRoot}/mmorpg.db` en dev (monorepo) ou `{dataDirectory}/mmorpg.db` en production
|
||||
- Migrations : `plugins/mmorpg/src/main/resources/db/migrations/*.sql`
|
||||
- Table initiale : `player_profiles` (uuid, display_name, level, experience, timestamps)
|
||||
|
||||
Les dépendances JDBC (SQLite) et JSON (Gson) sont **embarquées dans le JAR** via Shadow, car absentes du classpath serveur.
|
||||
|
||||
## Événements joueur
|
||||
|
||||
- **Connexion prête** : `PlayerReadyEvent` → chargement ou création du profil
|
||||
- **Déconnexion** : `PlayerDisconnectEvent` → sauvegarde et retrait de la session mémoire
|
||||
|
||||
## Conventions
|
||||
|
||||
- Identifiants joueur : `java.util.UUID`
|
||||
- Noms affichés : `PlayerRef.getUsername()` en priorité
|
||||
- Logs : `HytaleLogger` du plugin
|
||||
- Permissions futures : préfixe `com.disklexar.mmorpg.*`
|
||||
@@ -0,0 +1,69 @@
|
||||
# Guide de développement
|
||||
|
||||
## Environnement
|
||||
|
||||
1. Installer **JDK 25** (`java-25-openjdk`). Le script `start-server.sh` force `/usr/lib/jvm/java-25-openjdk`.
|
||||
2. Installer **Hytale** via le launcher et configurer `hytale.home_path` (copier `hytale.properties.example` → `hytale.properties` dans `Hytale/`).
|
||||
3. Cloner le dépôt et ouvrir le projet Gradle dans `Hytale/` (IntelliJ : `./gradlew openIdea` via ScaffoldIt).
|
||||
|
||||
## Commandes Gradle
|
||||
|
||||
Exécuter depuis le dossier `Hytale/` :
|
||||
|
||||
| Tâche | Description |
|
||||
|-------|-------------|
|
||||
| `./gradlew build` | Compile et produit le JAR (Shadow) |
|
||||
| `./gradlew runServer` | Serveur de dev local |
|
||||
| `./gradlew generateManifest` | Régénère `manifest.json` depuis `settings.gradle.kts` |
|
||||
| `./gradlew setupServer` | Prépare le répertoire `devserver/` |
|
||||
|
||||
## Workflow recommandé
|
||||
|
||||
1. Créer une branche depuis `main`
|
||||
2. Implémenter dans le package approprié (voir [ARCHITECTURE.md](ARCHITECTURE.md))
|
||||
3. Vérifier `./gradlew build`
|
||||
4. Tester en jeu avec `./gradlew runServer`
|
||||
5. Ouvrir une pull request
|
||||
|
||||
## Base de données locale
|
||||
|
||||
- **Monorepo** : `mmorpg.db` à la racine du dépôt (à côté de `Hytale/` et `Webapp/`), si `UseMonorepoRoot: true` dans `config.json`
|
||||
- **Sinon** : `devserver/.../com.disklexar_MMORPG/mmorpg.db` (chemin exact selon ScaffoldIt)
|
||||
- Inspecter avec `sqlite3 mmorpg.db`
|
||||
- Requête utile : `SELECT * FROM player_profiles;`
|
||||
|
||||
Les fichiers `*.db` sont ignorés par Git.
|
||||
|
||||
## Logs
|
||||
|
||||
Le plugin utilise `getLogger()` (HytaleLogger). Activer `Debug: true` dans `config.json` pour plus de détails sur les sessions.
|
||||
|
||||
Logs serveur de dev : `Hytale/devserver/logs/`.
|
||||
|
||||
## Dépannage runServer
|
||||
|
||||
| Symptôme | Cause | Solution |
|
||||
|----------|-------|----------|
|
||||
| `--assets=null` dans les logs Gradle | `hytale.home_path` non configuré | `hytale.properties` ou `HYTALE_HOME` |
|
||||
| `Missing default DamageCause assets` | Assets jeu absents | Installer Hytale + configurer le chemin |
|
||||
| `Env_Zone1_Plains doesn't exist` | `devserver` créé sans assets | `HYTALE_RESET_DEVSERVER=1 ./start-server.sh` |
|
||||
| `Task :runServer FAILED` exit 1 | Voir `devserver/logs/*.log` | Corriger la cause ci-dessus |
|
||||
|
||||
## API Hytale
|
||||
|
||||
La dépendance `com.hypixel.hytale:Server:+` est en **compileOnly** : ne pas l'inclure dans le JAR final. En cas d'erreur de compilation après mise à jour serveur :
|
||||
|
||||
- Vérifier les noms d'événements (`PlayerReadyEvent`, `PlayerDisconnectEvent`)
|
||||
- Consulter [doctale.dev](https://doctale.dev) et le template [HytaleModding/plugin-template](https://github.com/HytaleModding/plugin-template)
|
||||
|
||||
## Ajouter une migration SQL
|
||||
|
||||
1. Créer `plugins/mmorpg/src/main/resources/db/migrations/00X_description.sql`
|
||||
2. Étendre `SchemaInitializer` pour exécuter les nouveaux fichiers dans l'ordre
|
||||
3. Documenter le changement dans le changelog / PR
|
||||
|
||||
## Style de code
|
||||
|
||||
- Packages en minuscules, classes en PascalCase
|
||||
- Pas de logique métier dans `MmorpgPlugin` — déléguer aux services
|
||||
- Fermer les ressources JDBC dans try-with-resources
|
||||
@@ -0,0 +1,439 @@
|
||||
# Interface utilisateur MMORPG — conception UI/UX
|
||||
|
||||
Document de référence pour l'interface joueur du plugin **com.disklexar:MMORPG** sur Hytale.
|
||||
Objectif : une UI type MMORPG **moderne, ergonomique, immersive et intuitive**, compatible avec les
|
||||
contraintes d'un plugin **serveur** (assets `.ui` embarqués, `CustomUIHud`, `CustomUIPage`).
|
||||
|
||||
---
|
||||
|
||||
## Principes directeurs
|
||||
|
||||
| Principe | Application |
|
||||
|----------|-------------|
|
||||
| **Lisibilité en combat** | Contrastes élevés, tailles minimales 12 px, icônes + texte court |
|
||||
| **Hiérarchie visuelle** | HUD persistant discret ; menus modaux pour la gestion profonde |
|
||||
| **Feedback immédiat** | Cooldowns, buffs et dégâts reflétés en < 1 s côté client |
|
||||
| **Cohérence** | Palette sombre `#1a1c20` / accents `#c8a45c` (or MMORPG) sur tous les écrans |
|
||||
| **Responsive** | Ancres relatives (`Left`, `Right`, `Bottom`) + grilles flex, pas de pixels fixes centraux |
|
||||
| **Dégradation gracieuse** | Commandes chat (`/mmorpg info`, `/mmorpg profile`) si un asset `.ui` est invalide |
|
||||
|
||||
### Palette
|
||||
|
||||
```
|
||||
Fond HUD #1a1c20 @ 85 % Barre pleine vie #3d8f5a
|
||||
Fond slot #24262a Barre vide #2a2d32
|
||||
Texte primaire #e8e8ec Mana / énergie #4a8fd4
|
||||
Texte secondaire #878e9c XP / niveau #c8a45c
|
||||
Buff positif #5cb85c Debuff négatif #c9302c
|
||||
Bordure focus #c8a45c Overlay modal #1b1b1f @ 93 %
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture globale
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph hud [HUD persistant — en jeu]
|
||||
Vitals[Barres vie / mana / XP]
|
||||
Buffs[Buffs & debuffs]
|
||||
Hotbar[Barre d'action]
|
||||
AbilityBar[Barre capacités classe]
|
||||
end
|
||||
|
||||
subgraph menus [Menus joueur — modaux]
|
||||
Shell[Coquille MmorpgPlayerShell.ui]
|
||||
Char[Onglet Personnage]
|
||||
Inv[Onglet Inventaire]
|
||||
Skills[Onglet Arbre de compétences]
|
||||
end
|
||||
|
||||
subgraph server [Serveur Java]
|
||||
ABS[AbilityBarService]
|
||||
PIP[PlayerInfoPage]
|
||||
Future[HudVitalsService — M1]
|
||||
FutureMenu[PlayerMenuPage — M1]
|
||||
end
|
||||
|
||||
ABS --> AbilityBar
|
||||
Future --> Vitals
|
||||
Future --> Buffs
|
||||
Future --> Hotbar
|
||||
FutureMenu --> Shell
|
||||
Shell --> Char
|
||||
Shell --> Inv
|
||||
Shell --> Skills
|
||||
PIP -.->|fallback actuel| Char
|
||||
```
|
||||
|
||||
### Arborescence des assets (cible)
|
||||
|
||||
```
|
||||
src/main/resources/Common/UI/Custom/
|
||||
├── Huds/
|
||||
│ ├── MmorpgVitalsHud.ui # Vie, mana, XP (bas-gauche)
|
||||
│ ├── MmorpgBuffTrayHud.ui # Buffs / debuffs (sous les barres)
|
||||
│ ├── MmorpgHotbarHud.ui # Slots objets + raccourcis
|
||||
│ └── MmorpgAbilityBar.ui # ✅ Implémenté — 3 slots classe
|
||||
├── Pages/
|
||||
│ ├── MmorpgPlayerShell.ui # Fenêtre à onglets (coquille)
|
||||
│ ├── MmorpgCharacterTab.ui # Onglet Personnage
|
||||
│ ├── MmorpgInventoryPage.ui # 🟡 Début — inventaire MMORPG (coquille + grille)
|
||||
│ ├── MmorpgInventoryTab.ui # Onglet Inventaire (futur, dans coquille à onglets)
|
||||
│ └── MmorpgSkillTreeTab.ui # Onglet Arbre de compétences
|
||||
└── Widgets/
|
||||
├── MmorpgProgressBar.ui # Barre réutilisable (vie, mana, XP)
|
||||
├── MmorpgBuffIcon.ui # Icône buff avec timer
|
||||
└── MmorpgSkillNode.ui # Nœud d'arbre de compétences
|
||||
```
|
||||
|
||||
### Mapping code serveur
|
||||
|
||||
| Composant UI | Classe Java | Statut |
|
||||
|--------------|-------------|--------|
|
||||
| Barre capacités | `AbilityBarHud` + `AbilityBarService` | ✅ Actif |
|
||||
| Profil joueur (fallback) | `PlayerInfoPage` | ✅ Actif (`/mmorpg menucustom`) |
|
||||
| Menu à onglets | `PlayerMenuPage` | ✅ Actif (`/mmorpg menu`) |
|
||||
| Onglet Personnage | `MmorpgCharacterTab.ui` | ✅ Actif |
|
||||
| Onglet Inventaire | `MmorpgInventoryTab.ui` + `PlayerInventoryReader` | ✅ Actif |
|
||||
| Onglet Compétences | `MmorpgSkillsTab.ui` | ✅ Actif (capacités classe + branches M1) |
|
||||
| Barres vitales HUD | `VitalsHud` + `VitalsHudService` | 🔲 M1 |
|
||||
| Buff tray | `BuffTrayHud` | 🔲 M1 |
|
||||
| Hotbar étendue | `HotbarHud` | 🔲 M2 |
|
||||
|
||||
---
|
||||
|
||||
## 1. Affichage principal (HUD)
|
||||
|
||||
Le HUD reste **toujours visible** en exploration et en combat. Les éléments natifs Hytale
|
||||
(inventaire rapide, minimap) sont conservés ; le plugin ajoute des calques `CustomUIHud`
|
||||
(`z-order` croissant : vitals → buffs → hotbar → capacités).
|
||||
|
||||
### 1.1 Disposition écran (desktop 16:9)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ [Minimap native] [Quêtes]* │
|
||||
│ │
|
||||
│ MONDE / COMBAT │
|
||||
│ │
|
||||
│ │
|
||||
│ ┌─ Vitals ─────────────────┐ │
|
||||
│ │ ♥ ████████░░ 840/1000 │ ← Vie │
|
||||
│ │ ◆ ██████░░░░ 120/200 │ ← Mana / énergie │
|
||||
│ │ ★ Nv.42 ████░ 67 % │ ← Niveau + barre XP │
|
||||
│ └──────────────────────────┘ │
|
||||
│ [Buff][Buff][Debuff]... ← Buff tray (max 8 icônes visibles) │
|
||||
│ │
|
||||
│ [1][2][3][4][5][6][7][8][9][0] ← Hotbar objets │
|
||||
│ [Cap1][Cap2][Cap3] ← Barre capacités classe │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
* futur module quêtes
|
||||
```
|
||||
|
||||
### 1.2 Barres de vie, mana et XP
|
||||
|
||||
**Fichier cible :** `Huds/MmorpgVitalsHud.ui`
|
||||
|
||||
| Élément | ID serveur | Donnée source | Comportement |
|
||||
|---------|------------|---------------|--------------|
|
||||
| Barre de vie | `#HealthBar`, `#HealthText` | Composants entité joueur (vanilla) + bonus MMORPG futurs | Remplissage proportionnel ; flash rouge si < 25 % |
|
||||
| Barre de mana | `#ManaBar`, `#ManaText` | Attribut MMORPG (M1) | Masquée si classe sans mana (ex. Chevalier) |
|
||||
| Niveau | `#LevelLabel` | `PlayerProfile.level` | `Nv. {n}` |
|
||||
| Barre XP | `#XpBar`, `#XpText` | `ProgressionService` | `{current}/{required}` + pourcentage |
|
||||
|
||||
**Rafraîchissement :** toutes les 500 ms via `VitalsHudService` ; push immédiat sur gain d'XP ou dégâts.
|
||||
|
||||
**Widget réutilisable `MmorpgProgressBar.ui` :**
|
||||
|
||||
```
|
||||
Group #ProgressBar
|
||||
Group #Fill — largeur dynamique (ui.set Width ou FlexWeight)
|
||||
Label #ValueText — "840 / 1000"
|
||||
```
|
||||
|
||||
### 1.3 Buffs et debuffs actifs
|
||||
|
||||
**Fichier cible :** `Huds/MmorpgBuffTrayHud.ui`
|
||||
|
||||
| Propriété | Valeur |
|
||||
|-----------|--------|
|
||||
| Position | Au-dessus des barres vitales, aligné à gauche |
|
||||
| Capacité | 8 icônes visibles ; défilement horizontal si > 8 |
|
||||
| Par icône | Image, nom court, timer circulaire ou compte à rebours |
|
||||
| Sources serveur | `CombatBuffService`, `StunService`, effets de classe |
|
||||
|
||||
**IDs dynamiques :** `#BuffSlot0` … `#BuffSlot7` — le serveur injecte des instances de
|
||||
`Widgets/MmorpgBuffIcon.ui` via `appendInline`.
|
||||
|
||||
**Code couleur :** bordure verte = buff allié ; rouge = debuff ; or = effet neutre / passif.
|
||||
|
||||
### 1.4 Barre d'action (hotbar)
|
||||
|
||||
**Fichier cible :** `Huds/MmorpgHotbarHud.ui`
|
||||
|
||||
La hotbar MMORPG **complète** la barre native sans la remplacer :
|
||||
|
||||
| Zone | Slots | Contenu |
|
||||
|------|-------|---------|
|
||||
| Objets consommables | 1–0 (10) | Potions, nourriture, gadgets MMORPG |
|
||||
| Capacités classe | Ability 1–3 | Géré par `MmorpgAbilityBar.ui` (déjà séparé) |
|
||||
| Slot utilitaire | `U` (optionnel) | Monture, outil de métier |
|
||||
|
||||
**Par slot :**
|
||||
|
||||
- Icône de l'objet / compétence
|
||||
- Raccourci clavier (coin supérieur droit)
|
||||
- Overlay cooldown (assombrissement + texte secondes)
|
||||
- Bordure dorée si sélectionné
|
||||
|
||||
**Interaction :** les slots 1–3 déclenchent `mmorpg_cast_ability` ; les autres passent par
|
||||
l'inventaire natif ou des interactions custom futures.
|
||||
|
||||
### 1.5 Barre de capacités de classe (implémentée)
|
||||
|
||||
**Fichier :** `Common/UI/Custom/MmorpgAbilityBar.ui`
|
||||
**Service :** `AbilityBarService` — affichage automatique à la connexion si le joueur a une classe.
|
||||
|
||||
| Slot | ID | Touche | Mise à jour |
|
||||
|------|-----|--------|-------------|
|
||||
| 1 | `#Slot1Name`, `#Slot1Key` | Q (Use Ability 1) | Nom + cooldown (`Charge (3s)`) |
|
||||
| 2 | `#Slot2Name`, `#Slot2Key` | E (Use Ability 2) | idem |
|
||||
| 3 | `#Slot3Name`, `#Slot3Key` | R (Use Ability 3) | idem |
|
||||
|
||||
Les labels `#Slot*Key` / `#Ability*Key` sont remplis par `AbilitySlotKeys` avec les raccourcis
|
||||
Hytale par défaut (`[Q]`, `[E]`, `[R]`). Le serveur ne connaît pas les rebinding client.
|
||||
|
||||
**Commande debug :** `/mmorpg hud` — force la synchronisation.
|
||||
|
||||
---
|
||||
|
||||
## 2. Menus joueur
|
||||
|
||||
Ouverture : **`/mmorpg menu`** → coquille à onglets (`PlayerMenuPage`).
|
||||
Fallback chat : `/mmorpg info` si la page UI échoue.
|
||||
|
||||
### 2.1 Coquille — `MmorpgPlayerShell.ui`
|
||||
|
||||
```
|
||||
Panel (centré, max 900×600, fond #1b1b1fEE)
|
||||
├── Header
|
||||
│ ├── Portrait / icône classe #ClassPortrait
|
||||
│ ├── Nom joueur #PlayerName
|
||||
│ └── Monnaie #MoneyLabel
|
||||
├── TabBar (horizontal)
|
||||
│ ├── Button #TabCharacter "Personnage"
|
||||
│ ├── Button #TabInventory "Inventaire"
|
||||
│ └── Button #TabSkills "Compétences"
|
||||
├── ContentHost #TabContent (swap le document de l'onglet actif)
|
||||
└── Footer
|
||||
└── Button #CloseButton "Fermer"
|
||||
```
|
||||
|
||||
**Navigation :** `UIEventBuilder` lie chaque onglet ; le serveur charge le `.ui` de l'onglet
|
||||
dans `#TabContent` via `ui.clear` + `ui.append`.
|
||||
|
||||
### 2.2 Onglet Personnage
|
||||
|
||||
**Fichier cible :** `Pages/MmorpgCharacterTab.ui`
|
||||
|
||||
| Section | Champs | Source `PlayerProfile` |
|
||||
|---------|--------|------------------------|
|
||||
| Identité | Nom, race, classe | `displayName`, `raceId`, `classId` |
|
||||
| Progression | Niveau, XP, barre XP | `level`, `experience` |
|
||||
| Attributs* | Force, Agilité, Intelligence… | M1 — stats dérivées |
|
||||
| Pouvoirs passifs | Liste à puces | `powers` → `PowerCatalog` |
|
||||
| Métiers | Liste à puces | `jobs` → `JobCatalog` |
|
||||
| Social | Groupe, guilde | `groupId`, `guildId` |
|
||||
| Statistiques | Temps de jeu, argent, dates | `PlayerInfoView` (existant) |
|
||||
|
||||
\* Les attributs numériques sont un placeholder visuel jusqu'à l'implémentation M1.
|
||||
|
||||
**Layout :** deux colonnes sur grand écran — gauche : portrait + barres ; droite : listes
|
||||
pouvoirs / métiers / social.
|
||||
|
||||
### 2.3 Onglet Inventaire
|
||||
|
||||
**Fichier inventaire :** `Pages/MmorpgInventoryPage.ui` — document **racine** pour l'onglet Inventaire (`/mmorpg inventory`)
|
||||
**Fichier coquille :** `Pages/MmorpgPlayerShell.ui` — Personnage / Compétences uniquement
|
||||
|
||||
> Relié à l'inventaire **vanilla** via `ItemGrid.InventorySectionId` (sac, barre rapide, armure, utilitaire).
|
||||
> **`InventorySectionId` ne fonctionne pas** dans une coquille imbriquée : l'inventaire doit être le document
|
||||
> racine (`MmorpgInventoryPage.ui`). Changement d'onglet vers/depuis Inventaire → `rebuild()` complet.
|
||||
> Ne pas appeler `#Grid.Slots` depuis le serveur (tableau ou `#Grid.Slots.N`) — le client rejette
|
||||
> ces commandes et déconnecte. Les grilles utilisent `InventorySectionId` ; l'affichage passe par
|
||||
> des overlays `ItemSlot` (`ItemId` / `Quantity`).
|
||||
> Glisser-déposer synchronisé ; panneau détails au clic.
|
||||
|
||||
| Zone | ID | Section vanilla |
|
||||
|------|-----|-----------------|
|
||||
| Armure | `#ArmorGrid` | `ARMOR_SECTION_ID` (-3) |
|
||||
| Utilitaire | `#UtilityGrid` | `UTILITY_SECTION_ID` (-5) |
|
||||
| Sac | `#StorageGrid` | `STORAGE_SECTION_ID` (-2), 9×4 |
|
||||
| Barre rapide | `#HotbarGrid` | `HOTBAR_SECTION_ID` (-1) |
|
||||
| Détails | `#ItemDetails` | Clic / survol slot → `PlayerInventoryReader` |
|
||||
|
||||
**À venir :** filtres par catégorie, stats MMORPG sur items tagués, boutons Utiliser / Jeter.
|
||||
|
||||
**Ergonomie :**
|
||||
|
||||
- Clic gauche : sélection + détails
|
||||
- Double-clic : utiliser (si consommable)
|
||||
- Shift-clic : déplacer vers équipement (futur)
|
||||
- Recherche texte `#SearchField` en haut de grille
|
||||
|
||||
### 2.4 Onglet Arbre de compétences
|
||||
|
||||
**Fichier cible :** `Pages/MmorpgSkillTreeTab.ui`
|
||||
|
||||
| Élément | Description |
|
||||
|---------|-------------|
|
||||
| `#TreeCanvas` | Zone scrollable / zoomable (pincer sur mobile) |
|
||||
| `#SkillNode_*` | Nœuds : icône, rang actuel / max, prérequis |
|
||||
| `#PointsAvailable` | Points de compétence non dépensés |
|
||||
| `#NodeTooltip` | Survol : nom, effet, coût, prérequis |
|
||||
| `#ResetButton` | Réinitialisation (coût en monnaie, futur) |
|
||||
|
||||
**États visuels d'un nœud (`Widgets/MmorpgSkillNode.ui`) :**
|
||||
|
||||
| État | Apparence |
|
||||
|------|-----------|
|
||||
| Verrouillé | Grisé, cadenas |
|
||||
| Disponible | Bordure or clignotante légère |
|
||||
| Appris (rang 1–n) | Rempli, rang affiché |
|
||||
| Max | Bordure brillante, étoile |
|
||||
|
||||
**Données :** JSON ou table SQLite `skill_nodes` (M1+) ; rendu initial basé sur la classe active
|
||||
(`ClassCatalog` → 3 branches par classe en V1).
|
||||
|
||||
---
|
||||
|
||||
## 3. Responsive et multi-résolution
|
||||
|
||||
### Breakpoints (ratio largeur / hauteur viewport client)
|
||||
|
||||
| Profil | Condition | Adaptations |
|
||||
|--------|-----------|-------------|
|
||||
| **Desktop** | largeur ≥ 1280 px | Menus 900 px ; HUD complet ; 2 colonnes Personnage |
|
||||
| **Compact** | 1024–1279 px | Menus 720 px ; buff tray 6 icônes ; texte réduit 1 px |
|
||||
| **Small** | < 1024 px | Menus plein écran ; vitals empilés ; hotbar 6 slots visibles + scroll |
|
||||
| **Ultrawide** | ratio > 2.1 | HUD ancré aux tiers gauche/droite, pas aux bords extrêmes |
|
||||
|
||||
### Règles d'ancrage (fichiers `.ui`)
|
||||
|
||||
```
|
||||
# HUD bas
|
||||
Anchor: (Bottom: 24, Left: 24) — vitals
|
||||
Anchor: (Bottom: 28, Left: 0, Right: 0) — ability bar (centré)
|
||||
|
||||
# Menu modal
|
||||
Anchor: Center
|
||||
Style: (MaxWidth: 900, Width: 90%)
|
||||
```
|
||||
|
||||
- Préférer `FlexWeight`, `Padding: (Full: n)` et `LayoutMode: Top/Right` aux positions absolues.
|
||||
- Les groupes vides utilisent `Anchor: (Width: 6)` comme séparateurs (pattern `MmorpgAbilityBar.ui`).
|
||||
- Tester en 1920×1080, 1366×768 et 1280×720.
|
||||
|
||||
### Accessibilité
|
||||
|
||||
- Contraste texte / fond ≥ 4.5:1 (WCAG AA)
|
||||
- Taille police minimale 12 px (HUD) / 14 px (menus)
|
||||
- Les cooldowns affichent **chiffres + assombrissement** (pas la couleur seule)
|
||||
- Raccourcis clavier listés dans chaque infobulle de slot
|
||||
|
||||
---
|
||||
|
||||
## 4. Flux utilisateur
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant J as Joueur
|
||||
participant C as Client Hytale
|
||||
participant S as Serveur MMORPG
|
||||
|
||||
J->>C: Connexion
|
||||
C->>S: PlayerReadyEvent
|
||||
S->>S: loadOrCreate(profile)
|
||||
alt a une classe
|
||||
S->>C: addCustomHud(MmorpgAbilityBar)
|
||||
end
|
||||
S->>C: Message bienvenue (niveau, race)
|
||||
|
||||
J->>C: /mmorpg menu ou touche C
|
||||
C->>S: openCustomPage
|
||||
S->>C: PlayerInfoPage (puis PlayerMenuPage)
|
||||
|
||||
J->>C: Ability 1
|
||||
C->>S: SyncInteractionChains (filtré)
|
||||
S->>C: CancelInteractionChain + cast
|
||||
S->>C: update HUD cooldowns
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Commandes et raccourcis
|
||||
|
||||
| Action | Commande / touche | Écran |
|
||||
|--------|-------------------|-------|
|
||||
| Ouvrir profil | `/mmorpg menu` | Menu (liste → coquille) |
|
||||
| Profil chat | `/mmorpg info` | Fallback texte |
|
||||
| Résumé court | `/mmorpg profile` | Chat |
|
||||
| Forcer HUD capacités | `/mmorpg hud` | HUD |
|
||||
| Capacité 1–3 | Touches Ability 1/2/3 | HUD + exécution |
|
||||
| Fermer menu | Échap | — |
|
||||
|
||||
**Raccourcis cibles (M1) :** `C` → menu ; `K` → arbre de compétences ; `I` déjà natif inventaire.
|
||||
|
||||
---
|
||||
|
||||
## 6. Phases d'implémentation
|
||||
|
||||
| Phase | Livrables UI | Dépendances gameplay |
|
||||
|-------|--------------|----------------------|
|
||||
| **M0** ✅ | `MmorpgAbilityBar.ui`, `PlayerInfoPage`, `/mmorpg hud` | Classes, capacités |
|
||||
| **M1** | `MmorpgVitalsHud`, `MmorpgBuffTray`, `MmorpgPlayerShell` + onglet Personnage | Stats vie/mana, buffs |
|
||||
| **M2** | Onglet Inventaire MMORPG, `MmorpgHotbarHud` | Items tagués, équipement — **début** : `MmorpgInventoryPage.ui` |
|
||||
| **M3** | Onglet Arbre de compétences | Points de compétence, déblocages |
|
||||
| **M4** | Quêtes dans HUD, tooltips riches | Module quêtes |
|
||||
|
||||
---
|
||||
|
||||
## 7. Validation et tests
|
||||
|
||||
1. **Asset pack** : `IncludesAssetPack: true` dans `manifest.json` — chaque `.ui` doit être
|
||||
validé en jeu (un fichier invalide **crash le client** à la connexion).
|
||||
2. **Checklist par écran :**
|
||||
- [ ] Connexion sans crash client
|
||||
- [ ] HUD visible après choix de classe
|
||||
- [ ] Cooldowns décrémentent chaque seconde
|
||||
- [ ] Déconnexion retire le HUD (`AbilityBarService.dismiss`)
|
||||
- [ ] Menu s'ouvre et se ferme (Échap)
|
||||
- [ ] Responsive : pas de chevauchement à 1366×768
|
||||
3. **Logs serveur :** rechercher `Ability bar HUD` dans `devserver/logs/`.
|
||||
|
||||
---
|
||||
|
||||
## 8. Références
|
||||
|
||||
### Documentation Custom UI (officielle / guides)
|
||||
|
||||
- [Custom UI — vue d'ensemble](https://hytalemodding.dev/en/docs/official-documentation/custom-ui) — HUD vs pages, `append` / `set`, sélecteurs
|
||||
- [Layout](https://hytalemodding.dev/en/docs/official-documentation/custom-ui/layout) — `Anchor`, `LayoutMode`, `FlexWeight` (utilisé pour le panneau inventaire 3 colonnes)
|
||||
- [Common Styling](https://hytalemodding.dev/en/docs/official-documentation/custom-ui/common-styling) — `Common.ui`, styles vanilla réutilisables
|
||||
- [Guide plugin UI](https://hytalemodding.dev/en/docs/guides/plugin/ui) — chemin `Common/UI/Custom`, `IncludesAssetPack`, mode diagnostic client
|
||||
|
||||
**Rappels appris en production :**
|
||||
|
||||
- `CustomUIHud` : uniquement `append(document)` + `set()` — pas de `appendInline` / `clear` (crash client).
|
||||
- Propriétés dynamiques : préférer `ProgressBar.Value` plutôt que `Group.Width` (rejeté par le client).
|
||||
- Ancrage HUD : le groupe racine doit avoir `Anchor: (Left: …, Width: …)` sinon centrage écran.
|
||||
|
||||
### Fichiers projet
|
||||
|
||||
- Code UI : `src/main/java/com/disklexar/mmorpg/ui/`
|
||||
- HUD vitals + capacités : `src/main/resources/Common/UI/Custom/MmorpgAbilityBar.ui`
|
||||
- Inventaire (début) : `src/main/resources/Common/UI/Custom/Pages/MmorpgInventoryPage.ui`
|
||||
- Profil (scaffold) : `src/main/resources/Common/UI/Custom/Pages/MmorpgPlayerInfo.ui`
|
||||
- Guide asset pack : [assetpack/README.md](../assetpack/README.md)
|
||||
- Architecture : [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
@@ -0,0 +1,53 @@
|
||||
# Feuille de route
|
||||
|
||||
## M0 — Fondation (actuel)
|
||||
|
||||
- [x] Projet Gradle + ScaffoldIt
|
||||
- [x] Plugin `com.disklexar:MMORPG`
|
||||
- [x] SQLite + table `player_profiles`
|
||||
- [x] Sessions joueur (connexion / déconnexion)
|
||||
- [x] Commandes `/mmorpg help` et `/mmorpg profile`
|
||||
- [x] Packages stub : `economy`, `quest`, `social`
|
||||
- [x] Documentation et CI
|
||||
|
||||
## M1 — Personnage et progression
|
||||
|
||||
- [ ] Système d'expérience et montée de niveau
|
||||
- [ ] Statistiques de base (vie, mana, attributs)
|
||||
- [ ] Sauvegarde position / monde (spawn MMORPG)
|
||||
- [ ] Messages et UI côté client (si API disponible)
|
||||
|
||||
## M2 — Économie
|
||||
|
||||
- [ ] Monnaie serveur (wallets SQLite)
|
||||
- [ ] Transactions atomiques
|
||||
- [ ] Vendeurs NPC et tables de loot
|
||||
- [ ] Activer `Features.Economy` dans la config
|
||||
|
||||
## M3 — Quêtes
|
||||
|
||||
- [ ] Définitions de quêtes (JSON ou DB)
|
||||
- [ ] Objectifs : collecte, dialogue, zone
|
||||
- [ ] Récompenses XP / items / monnaie
|
||||
- [ ] Quêtes journalières
|
||||
- [ ] Activer `Features.Quests`
|
||||
|
||||
## M4 — Social et instances
|
||||
|
||||
- [ ] Groupes / parties
|
||||
- [ ] Guildes (création, rangs, banque)
|
||||
- [ ] Instances / donjons dédiés
|
||||
- [ ] Activer `Features.Guilds`
|
||||
|
||||
## M5 — Production
|
||||
|
||||
- [ ] Migration PostgreSQL optionnelle
|
||||
- [ ] Cache Redis pour sessions multi-serveur
|
||||
- [ ] Métriques et monitoring
|
||||
- [ ] Anti-triche basique (rate limits, validation serveur)
|
||||
|
||||
## Hors périmètre connu
|
||||
|
||||
- Asset pack custom (modèles, textures)
|
||||
- Interface web d'administration
|
||||
- Client modifié (hors API serveur)
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+93
@@ -0,0 +1,93 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1,10 @@
|
||||
# Copier ce fichier vers hytale.properties et adapter le chemin.
|
||||
# Dossier d'installation Hytale (doit contenir install/.../Assets.zip)
|
||||
#
|
||||
# Linux (Flatpak) :
|
||||
# hytale.home_path=/home/VOTRE_USER/.var/app/com.hypixel.HytaleLauncher/data/Hytale
|
||||
#
|
||||
# Windows :
|
||||
# hytale.home_path=C:/Users/VOTRE_USER/AppData/Roaming/Hytale
|
||||
|
||||
hytale.home_path=
|
||||
@@ -0,0 +1,54 @@
|
||||
# Asset pack (scaffold) — MMORPG
|
||||
|
||||
Server-only plugins **cannot inject a button into the native inventory screen** and cannot render
|
||||
a custom-designed page without a client-side asset (`.ui`). This folder is the scaffold to add one.
|
||||
|
||||
## What already works without this asset pack
|
||||
|
||||
- `/mmorpg menu` opens a real `CustomUIPage` (`PlayerInfoPage`) built with **inline UI markup**, so
|
||||
it renders without any bundled asset.
|
||||
- `/mmorpg info` prints the same data in chat (reliable fallback).
|
||||
- The `mmorpg_player_info` interaction is registered (`OpenCustomUIInteraction`) so the page can be
|
||||
opened from an item/block interaction once you wire one.
|
||||
|
||||
## Class ability keys (Ability 1/2/3)
|
||||
|
||||
Weapon ability slots are overridden in **`src/main/resources/Server/Item/Items/`** (bundled with the
|
||||
plugin JAR, not this scaffold folder). Each patch sets:
|
||||
|
||||
```json
|
||||
"Ability1": {
|
||||
"Interactions": [{ "Type": "mmorpg_cast_ability", "Slot": 1 }]
|
||||
}
|
||||
```
|
||||
|
||||
The Java interaction `mmorpg_cast_ability` is registered in `MmorpgPlugin`. Even without a patch
|
||||
for a given weapon, the **packet filter** still routes Ability 1/2/3 to class abilities when the
|
||||
player has a class.
|
||||
|
||||
To patch another weapon, add `Server/Item/Items/<ItemId>.json` with only `"Id"` and `"Interactions"`.
|
||||
|
||||
Shipped examples: longsword, battleaxe, staff, daggers, shortbow, crossbow (mithril/cobalt variants).
|
||||
|
||||
## Enabling the designed `.ui` template
|
||||
|
||||
1. Package this `assetpack/` content according to your Hytale/ScaffoldIt asset-pack layout and set
|
||||
`"IncludesAssetPack": true` in `src/main/resources/manifest.json`.
|
||||
2. Edit `com.disklexar.mmorpg.ui.PlayerInfoPage#build` to append the template and fill fields:
|
||||
|
||||
```java
|
||||
ui.append("Pages/MmorpgPlayerInfo.ui");
|
||||
ui.set("#Title.Text", "Profil MMORPG");
|
||||
for (PlayerInfoView.Entry e : PlayerInfoView.entries(profile)) {
|
||||
ui.append("#Content", "Label { Text: \"" + e.label() + " : " + e.value() + "\"; }");
|
||||
}
|
||||
events.addEventBinding(CustomUIEventBindingType.Click, "#CloseButton");
|
||||
```
|
||||
|
||||
3. Validate the `.ui` grammar in-game and adjust `MmorpgPlayerInfo.ui`.
|
||||
|
||||
## Inventory button
|
||||
|
||||
A literal button inside the native inventory UI requires a client UI mod/asset overriding the
|
||||
inventory screen, which is out of scope for a server-only plugin. The supported equivalents are the
|
||||
`/mmorpg menu` command and the `mmorpg_player_info` interaction above.
|
||||
@@ -0,0 +1,29 @@
|
||||
// Sample custom UI page template for the MMORPG player-info screen.
|
||||
//
|
||||
// This is a SCAFFOLD: the exact .ui markup grammar is defined by the Hytale client and must be
|
||||
// validated in-game. The plugin works today without this file because PlayerInfoPage builds its
|
||||
// layout with inline markup. Use this template when you want a richer designed layout, then have
|
||||
// PlayerInfoPage.build() append "Pages/MmorpgPlayerInfo.ui" and set the named fields below.
|
||||
//
|
||||
// Named fields the server can target via UICommandBuilder.set(...):
|
||||
// #Title.Text - page title
|
||||
// #Content - vertical container the server appends one Label per attribute into
|
||||
// #CloseButton - close/dismiss button (bind via UIEventBuilder)
|
||||
|
||||
Panel {
|
||||
Style: (Width: 420; Anchor: Center; Padding: 16; Background: (Color: #1b1b1fEE));
|
||||
|
||||
Label #Title {
|
||||
Text: "Profil MMORPG";
|
||||
Style: (Alignment: Center; FontSize: 20; MarginBottom: 12);
|
||||
}
|
||||
|
||||
VerticalList #Content {
|
||||
Style: (Spacing: 4);
|
||||
}
|
||||
|
||||
Button #CloseButton {
|
||||
Text: "Fermer";
|
||||
Style: (Alignment: Center; MarginTop: 12);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user