This commit is contained in:
2026-01-20 20:33:59 +01:00
commit b16a40e431
583 changed files with 87339 additions and 0 deletions

View File

@@ -0,0 +1,761 @@
# Patch Notes: Hytale Server
## Version 2026.01.13-50e69c385 → 2026.01.15-c04fdfe10
**Date de release** : 15 janvier 2026
**Build précédent** : `50e69c385` (13 janvier 2026)
**Build actuel** : `c04fdfe10` (15 janvier 2026)
---
### Statistiques
| Métrique | Valeur |
|----------|--------|
| Fichiers modifiés | 9 |
| Insertions | +55 |
| Suppressions | -18 |
| Delta net | +37 lignes |
---
## Table des matières
1. [Authentification & Sécurité JWT](#1-authentification--sécurité-jwt)
2. [Gestion d'échec d'authentification serveur](#2-gestion-déchec-dauthentification-serveur)
3. [Transport QUIC - Optimisations réseau](#3-transport-quic---optimisations-réseau)
4. [Timeout Setup Handler](#4-timeout-setup-handler)
5. [Physique des Items - Collisions latérales](#5-physique-des-items---collisions-latérales)
6. [Nouvelle raison d'arrêt MISSING_ASSETS](#6-nouvelle-raison-darrêt-missing_assets)
7. [Validation des Asset Packs](#7-validation-des-asset-packs)
8. [Télémétrie Sentry enrichie](#8-télémétrie-sentry-enrichie)
9. [Fix NullPointerException CraftingManager](#9-fix-nullpointerexception-craftingmanager)
---
## 1. Authentification & Sécurité JWT
**Fichier** : `com/hypixel/hytale/server/core/auth/JWTValidator.java`
**Lignes modifiées** : 31, 87-99, 293-309, 355-372
### 1.1 Nouvelle constante (non utilisée)
```java
private static final long CLOCK_SKEW_SECONDS = 300L;
```
Une constante a été ajoutée pour centraliser la valeur du clock skew, mais elle n'est **pas encore utilisée** dans le code - les valeurs `300L` sont hardcodées directement dans les méthodes de validation.
### 1.2 Augmentation du Clock Skew : 60s → 300s
Le **clock skew** (tolérance de désynchronisation d'horloge entre client et serveur) passe de **1 minute à 5 minutes**. Cette modification affecte la validation de trois types de tokens JWT :
#### Méthode `validateToken()` (lignes 87-99)
| Claim | Avant | Après | Comportement |
|-------|-------|-------|--------------|
| `exp` (expires at) | `now >= exp + 60` | `now >= exp + 300` | Token accepté jusqu'à 5 min après expiration |
| `nbf` (not before) | `now < nbf - 60` | `now < nbf - 300` | Token accepté 5 min avant validité |
| `iat` (issued at) | **Non vérifié** | `iat > now + 300` | **NOUVEAU** : Rejette tokens du futur |
**Code ajouté** (lignes 96-99) :
```java
if (claims.issuedAt != null && claims.issuedAt > nowSeconds + 300L) {
LOGGER.at(Level.WARNING).log("Token issued in the future (iat: %d, now: %d)",
(Object)claims.issuedAt, nowSeconds);
return null;
}
```
#### Méthode `validateIdentityToken()` (lignes 293-309)
| Claim | Avant | Après |
|-------|-------|-------|
| `exp` | `now >= exp + 60` | `now >= exp + 300` |
| `nbf` | `now < nbf - 60` | `now < nbf - 300` |
| `iat` | `iat > now + 60` | `iat > now + 300` |
La validation `iat` existait déjà pour les identity tokens, seule la valeur du clock skew a changé.
#### Méthode `validateSessionToken()` (lignes 355-372)
| Claim | Avant | Après | Comportement |
|-------|-------|-------|--------------|
| `exp` | `now >= exp + 60` | `now >= exp + 300` | Token accepté jusqu'à 5 min après expiration |
| `nbf` | `now < nbf - 60` | `now < nbf - 300` | Token accepté 5 min avant validité |
| `iat` | **Non vérifié** | `iat > now + 300` | **NOUVEAU** : Rejette tokens du futur |
**Code ajouté** (lignes 368-371) :
```java
if (claims.issuedAt != null && claims.issuedAt > nowSeconds + 300L) {
LOGGER.at(Level.WARNING).log("Session token issued in the future (iat: %d, now: %d)",
(Object)claims.issuedAt, nowSeconds);
return null;
}
```
### 1.3 Impact
| Aspect | Effet |
|--------|-------|
| **Compatibilité** | Meilleure tolérance pour clients avec horloge désynchronisée |
| **Sécurité** | Protection contre tokens pré-générés pour utilisation future |
| **Stabilité** | Réduction des erreurs de validation dues au décalage horaire |
### 1.4 Contexte technique
Le `JWTValidator` gère trois types de tokens avec des rôles distincts :
1. **Auth Token (JWTClaims)** : Authentification client, contient username, IP, certificate fingerprint
2. **Identity Token (IdentityTokenClaims)** : Identité du joueur, requiert scopes `hytale:client` ou `hytale:editor`
3. **Session Token (SessionTokenClaims)** : Sessions serveur, validation minimale
Le système utilise un cache JWKS (JSON Web Key Set) avec durée de 1 heure et mécanisme de retry intelligent en cas d'échec de vérification de signature.
---
## 2. Gestion d'échec d'authentification serveur
**Fichier** : `com/hypixel/hytale/server/core/io/handlers/login/HandshakeHandler.java`
**Lignes modifiées** : 291-298 (dans le callback `exceptionally`)
### 2.1 Modification du comportement
Dans la méthode `exchangeServerAuthGrant()`, le callback `.exceptionally()` (gestion des erreurs async) a été modifié. Lorsqu'une exception se produit pendant l'échange de server token (`AuthState.EXCHANGING_SERVER_TOKEN`) :
**Avant** :
```java
.exceptionally(ex -> {
LOGGER.at(Level.WARNING).withCause(ex).log("Error exchanging server auth grant");
this.channel.eventLoop().execute(() -> {
if (this.authState != AuthState.EXCHANGING_SERVER_TOKEN) {
return;
}
byte[] passwordChallenge = this.generatePasswordChallengeIfNeeded();
this.completeAuthentication(passwordChallenge);
});
return null;
});
```
**Après** :
```java
.exceptionally(ex -> {
LOGGER.at(Level.WARNING).withCause(ex).log("Error exchanging server auth grant");
this.channel.eventLoop().execute(() -> {
if (this.authState != AuthState.EXCHANGING_SERVER_TOKEN) {
return;
}
this.disconnect("Server authentication failed - please try again later");
});
return null;
});
```
### 2.2 Impact sur la sécurité
| Aspect | Avant | Après |
|--------|-------|-------|
| Échec server token exchange | Authentification continuait silencieusement | Déconnexion immédiate |
| Bypass potentiel | Possible dans certains cas de timeout | Impossible |
| Message utilisateur | Aucun | Message explicite |
### 2.3 Contexte : Flow d'authentification mutuelle
Le `HandshakeHandler` orchestre un flow d'authentification mutuelle (mTLS) avec les états suivants :
```
REQUESTING_AUTH_GRANT (30s timeout)
AWAITING_AUTH_TOKEN (30s timeout)
PROCESSING_AUTH_TOKEN
EXCHANGING_SERVER_TOKEN (15s timeout) ← Changement ici
AUTHENTICATED
```
**Étapes détaillées** :
1. **Validation Identity Token** : Vérifie le token du client, UUID, scopes
2. **Demande Auth Grant** : Récupère le server session token, appel async au `SessionServiceClient`
3. **Traitement Token Client** : Vérifie JWT signature, certificate binding, UUID/username
4. **Échange Server Token** : Échange auth grant contre token avec fingerprint serveur
5. **Complétion** : Crée `PlayerAuthentication`, passe au `SetupPacketHandler`
Le changement garantit qu'un échec à l'étape 4 ne permet plus de compléter l'authentification.
---
## 3. Transport QUIC - Optimisations réseau
**Fichier** : `com/hypixel/hytale/server/core/io/transport/QUICTransport.java`
**Lignes modifiées** : 30, 128
### 3.1 Nouvel import
```java
import io.netty.handler.codec.quic.QuicCongestionControlAlgorithm;
```
### 3.2 Activation de PMTU Discovery
**Ajout** : `.discoverPmtu(true)`
Le **Path MTU Discovery** permet au serveur de :
| Fonctionnalité | Description |
|----------------|-------------|
| Détection automatique | Découvre la taille maximale de paquet sur chaque chemin réseau |
| Évitement fragmentation | Prévient la fragmentation IP qui dégrade les performances |
| Optimisation throughput | Utilise des paquets de taille optimale par connexion |
### 3.3 Changement d'algorithme de congestion : BBR
**Ajout** : `.congestionControlAlgorithm(QuicCongestionControlAlgorithm.BBR)`
#### Comparaison des algorithmes
| Aspect | Cubic (implicite avant) | BBR (nouveau) |
|--------|-------------------------|---------------|
| **Approche** | Loss-based | Model-based |
| **Réaction aux pertes** | Réduit agressivement le débit | Maintient le débit estimé |
| **Latence** | Variable, peut augmenter | Minimisée activement |
| **Réseaux lossy** | Performances dégradées | Meilleures performances |
| **Bufferbloat** | Peut remplir les buffers | Évite le bufferbloat |
| **WiFi/Mobile** | Sous-optimal | Optimisé |
**BBR (Bottleneck Bandwidth and Round-trip propagation time)** est l'algorithme développé par Google qui :
- Estime continuellement la bande passante disponible
- Maintient un RTT minimal
- Offre de meilleures performances sur réseaux modernes
### 3.4 Configuration QUIC complète après modification
```java
QuicServerCodecBuilder()
.sslContext(sslContext)
.tokenHandler(InsecureQuicTokenHandler.INSTANCE)
.maxIdleTimeout(playTimeout.toMillis(), TimeUnit.MILLISECONDS)
.ackDelayExponent(3L) // 8ms entre acks
.initialMaxData(524288L) // 512 KB total
.initialMaxStreamDataUnidirectional(0L) // Désactivé
.initialMaxStreamsUnidirectional(0L) // Désactivé
.initialMaxStreamDataBidirectionalLocal(131072L) // 128 KB par stream
.initialMaxStreamDataBidirectionalRemote(131072L) // 128 KB par stream
.initialMaxStreamsBidirectional(1L) // 1 stream
.discoverPmtu(true) // NOUVEAU
.congestionControlAlgorithm(QuicCongestionControlAlgorithm.BBR) // NOUVEAU
```
### 3.5 Contexte technique
Le `QUICTransport` configure également :
- **mTLS obligatoire** : `ClientAuth.REQUIRE`
- **Certificat auto-signé** : Généré au démarrage
- **IPv4/IPv6 dual-stack** : Bootstraps séparés
- **Options socket** : `SO_REUSEADDR`, `IP_DONTFRAGMENT`
- **Certificate fingerprinting** : Pour validation JWT
---
## 4. Timeout Setup Handler
**Fichier** : `com/hypixel/hytale/server/core/io/handlers/SetupPacketHandler.java`
**Ligne modifiée** : 102
### 4.1 Modification du timeout
```java
// Avant
this.setTimeout("send-world-settings", () -> this.assets != null, 1L, TimeUnit.SECONDS);
// Après
this.setTimeout("send-world-settings", () -> this.assets != null, 10L, TimeUnit.SECONDS);
```
### 4.2 Contexte
Ce timeout attend que les assets soient prêts (`this.assets != null`) avant d'envoyer les paramètres du monde (`WorldSettings`) au client.
### 4.3 Raisons du changement
| Scénario | Impact avec 1s | Impact avec 10s |
|----------|----------------|-----------------|
| Connexion haute latence | Timeout fréquent | Toléré |
| Serveur avec nombreux asset packs | Timeout possible | Toléré |
| Charge serveur élevée | Timeout possible | Toléré |
| Démarrage lent des assets | Déconnexion | Attente correcte |
### 4.4 Autres timeouts dans le SetupPacketHandler
| Timeout | Durée | Condition | Usage |
|---------|-------|-----------|-------|
| `send-world-settings` | **10s** (modifié) | `this.assets != null` | Attente chargement assets |
| `receive-assets-request` | 120s | Packet `RequestAssets` reçu | Négociation d'assets |
| `send-assets` | 120s | `SendCommonAssetsEvent` terminé | Envoi assets + translations |
| `add-to-universe` | 60s | `Universe.addPlayer()` terminé | Création joueur dans monde |
### 4.5 Phases du Setup Handler
```
[Post-Auth] → registered0()
[WorldSettings + ServerInfo envoyés]
[Client envoie RequestAssets] (120s max)
[Envoi CommonAssets + Translations] (120s max)
[Client envoie PlayerOptions]
[AddToUniverse] (60s max)
[Joueur connecté au monde]
```
---
## 5. Physique des Items - Collisions latérales
**Fichier** : `com/hypixel/hytale/server/core/modules/entity/item/ItemPhysicsSystem.java`
**Lignes modifiées** : 84-97
### 5.1 Architecture du système
| Élément | Description |
|---------|-------------|
| **Classe parente** | `EntityTickingSystem<EntityStore>` |
| **Pattern** | Entity Component System (ECS) |
| **Tick rate** | Appelé à chaque tick du monde |
### 5.2 Composants utilisés
| Composant | Rôle |
|-----------|------|
| `ItemPhysicsComponent` | État physique spécifique aux items |
| `BoundingBox` | Boîte de collision 3D |
| `Velocity` (VelocityComponent) | Vecteur de vélocité |
| `TransformComponent` | Position et rotation |
### 5.3 Modification de la gestion des collisions
**Avant** : Seules les collisions verticales (sol) étaient gérées
```java
BlockCollisionData blockCollisionData = collisionResult.getFirstBlockCollision();
if (blockCollisionData != null && blockCollisionData.collisionNormal.equals(Vector3d.UP)) {
velocityComponent.setZero();
position.assign(blockCollisionData.collisionPoint);
} else {
velocityComponent.assignVelocityTo(scaledVelocity).scale(dt);
position.add(scaledVelocity);
}
```
**Après** : Gestion complète de toutes les directions de collision
```java
BlockCollisionData blockCollisionData = collisionResult.getFirstBlockCollision();
if (blockCollisionData != null) {
if (blockCollisionData.collisionNormal.equals(Vector3d.UP)) {
// Collision avec le sol : arrêt complet
velocityComponent.setZero();
position.assign(blockCollisionData.collisionPoint);
} else {
// Collision latérale : annulation de la composante perpendiculaire
Vector3d velocity = velocityComponent.getVelocity();
double dot = velocity.dot(blockCollisionData.collisionNormal);
Vector3d velocityToCancel = blockCollisionData.collisionNormal.clone().scale(dot);
velocity.subtract(velocityToCancel);
}
} else {
velocityComponent.assignVelocityTo(scaledVelocity).scale(dt);
position.add(scaledVelocity);
}
```
### 5.4 Explication mathématique
Pour une collision latérale (mur, escalier, pente) :
1. **Calcul du produit scalaire** : `dot = velocity · normal`
- Mesure la composante de vélocité perpendiculaire à la surface
2. **Calcul du vecteur à annuler** : `velocityToCancel = normal × dot`
- Vecteur perpendiculaire à la surface avec magnitude égale à la composante perpendiculaire
3. **Soustraction** : `velocity = velocity - velocityToCancel`
- Projette la vélocité sur le plan tangent à la surface
**Formule vectorielle** : `v' = v - (v · n) × n`
### 5.5 Impact sur le gameplay
| Comportement | Avant | Après |
|--------------|-------|-------|
| Item lancé contre un mur | Traversait ou s'arrêtait net | Glisse le long du mur |
| Item tombant sur une pente | Comportement incohérent | Roule correctement |
| Item dans un coin | Pouvait se bloquer/traverser | Réagit physiquement |
### 5.6 Méthodes de détection de collision
Le système utilise deux méthodes selon la magnitude de vitesse :
| Méthode | Condition | Usage |
|---------|-----------|-------|
| `findBlockCollisionsShortDistance()` | Mouvement faible | Optimisation pour petits mouvements |
| `findBlockCollisionsIterative()` | Mouvement important | Précision pour grandes vitesses |
---
## 6. Nouvelle raison d'arrêt MISSING_ASSETS
**Fichier** : `com/hypixel/hytale/server/core/ShutdownReason.java`
**Ligne ajoutée** : 17
### 6.1 Nouvelle constante
```java
public static final ShutdownReason MISSING_ASSETS = new ShutdownReason(7);
```
### 6.2 Liste complète des ShutdownReason
| Constante | Exit Code | Description | Utilisation |
|-----------|-----------|-------------|-------------|
| `SIGINT` | 130 | Signal d'interruption | Ctrl+C ou SIGINT reçu |
| `SHUTDOWN` | 0 | Arrêt gracieux | Commande `/stop` ou shutdown normal |
| `CRASH` | 1 | Crash serveur | Erreur non gérée pendant le boot |
| `AUTH_FAILED` | 2 | Échec authentification | Impossible de s'authentifier auprès des services |
| `WORLD_GEN` | 3 | Erreur génération monde | WorldGenLoadException |
| `CLIENT_GONE` | 4 | Client singleplayer disparu | Mode singleplayer, client déconnecté |
| `MISSING_REQUIRED_PLUGIN` | 5 | Plugin core manquant | Plugin requis non trouvé |
| `VALIDATE_ERROR` | 6 | Validation assets échouée | Erreur de validation des assets |
| **`MISSING_ASSETS`** | **7** | **Aucun asset pack** | **NOUVEAU : Aucun pack chargé** |
### 6.3 Pattern d'utilisation
```java
// Utilisation simple
HytaleServer.get().shutdownServer(ShutdownReason.MISSING_ASSETS);
// Avec message personnalisé
HytaleServer.get().shutdownServer(
ShutdownReason.MISSING_ASSETS.withMessage("Failed to load any asset packs")
);
```
La méthode `withMessage(String)` crée une nouvelle instance de `ShutdownReason` avec le même code de sortie mais un message additionnel pour les logs.
---
## 7. Validation des Asset Packs
**Fichier** : `com/hypixel/hytale/server/core/asset/AssetModule.java`
**Lignes modifiées** : 24, 104-106
### 7.1 Nouvel import
```java
import com.hypixel.hytale.server.core.ShutdownReason;
```
### 7.2 Nouvelle vérification
Après le chargement des asset packs depuis tous les répertoires de mods :
```java
for (Path modsPath : Options.getOptionSet().valuesOf(Options.MODS_DIRECTORIES)) {
this.loadPacksFromDirectory(modsPath);
}
// NOUVEAU : Vérification des assets
if (this.assetPacks.isEmpty()) {
HytaleServer.get().shutdownServer(
ShutdownReason.MISSING_ASSETS.withMessage("Failed to load any asset packs")
);
return;
}
```
### 7.3 Cycle de vie de l'AssetModule
```
setup()
[Création AssetMonitor si --disable-file-watcher absent]
[Chargement packs CLI]
[Chargement packs mods/]
[NOUVEAU: Vérification assetPacks.isEmpty()] ← Shutdown si vide
[Registration event listeners]
LoadAssetEvent dispatch
[AssetRegistryLoader charge tous les assets]
BootEvent
[Log nombre total d'assets]
```
### 7.4 Sources de chargement des asset packs
| Source | Méthode | Description |
|--------|---------|-------------|
| CLI `--assets` | `loadPacksFromDirectory()` | Chemins spécifiés en ligne de commande |
| Dossier `mods/` | `loadPacksFromDirectory()` | Packs dans le dossier mods par défaut |
| Autres `--mods-directories` | `loadPacksFromDirectory()` | Répertoires additionnels |
### 7.5 Types de packs supportés
| Type | Détection | Immutabilité |
|------|-----------|--------------|
| ZIP/JAR | Contient `manifest.json` | Toujours immutable |
| Répertoire | Contient `manifest.json` | Immutable si `CommonAssetsIndex.hashes` présent |
| Répertoire sans hash | Contient `manifest.json` | Mutable (rechargement possible) |
### 7.6 AssetMonitor (rechargement temps réel)
Si `--disable-file-watcher` n'est pas passé, un `AssetMonitor` est créé pour :
- Surveiller les modifications de fichiers dans les packs mutables
- Déclencher un rechargement automatique des assets modifiés
- Permettre le développement itératif sans redémarrage serveur
---
## 8. Télémétrie Sentry enrichie
**Fichier** : `com/hypixel/hytale/server/core/HytaleServer.java`
**Lignes modifiées** : 30, 51, 155-170
### 8.1 Nouveaux imports
```java
import com.hypixel.hytale.server.core.auth.SessionServiceClient;
import io.sentry.protocol.User;
```
### 8.2 Nouvelles données utilisateur collectées
Dans le callback `beforeSend` de Sentry, un objet `User` est maintenant créé et attaché à chaque événement :
```java
User user = new User();
HashMap<String, Object> unknown = new HashMap<String, Object>();
user.setUnknown(unknown);
// 1. Hardware UUID
UUID hardwareUUID = HardwareUtil.getUUID();
if (hardwareUUID != null) {
unknown.put("hardware-uuid", hardwareUUID.toString());
}
// 2. Mode d'authentification
ServerAuthManager authManager = ServerAuthManager.getInstance();
unknown.put("auth-mode", authManager.getAuthMode().toString());
// 3. Profil utilisateur (si authentifié)
SessionServiceClient.GameProfile profile = authManager.getSelectedProfile();
if (profile != null) {
user.setUsername(profile.username);
user.setId(profile.uuid.toString());
}
// 4. Adresse IP (auto-détection Sentry)
user.setIpAddress("{{auto}}");
event.setUser(user);
```
### 8.3 Données collectées par Sentry
#### Données utilisateur (nouvelles)
| Champ Sentry | Source | Type | Description |
|--------------|--------|------|-------------|
| `user.username` | `GameProfile.username` | String | Nom d'utilisateur du compte |
| `user.id` | `GameProfile.uuid` | UUID String | Identifiant unique du compte |
| `user.ip_address` | Auto-détecté | IP | Adresse IP du serveur |
| `user.unknown.hardware-uuid` | `HardwareUtil.getUUID()` | UUID String | Identifiant matériel unique |
| `user.unknown.auth-mode` | `ServerAuthManager.getAuthMode()` | String | Mode d'auth (ONLINE/OFFLINE/etc.) |
#### Données contextuelles (existantes)
| Contexte | Données |
|----------|---------|
| **server** | Nom, max-players, listeners |
| **universe** | Chemin, nombre joueurs, liste worlds |
| **plugins** | Version et état de chaque plugin |
### 8.4 Conditions de collecte
Les données Sentry sont collectées **uniquement si** :
- Aucun early plugin avec transformer n'est chargé
- Le flag `--disable-sentry` n'est pas passé
- Une erreur se produit (beforeSend callback)
### 8.5 Filtrage des erreurs
Les erreurs provenant de plugins tiers sont filtrées avant envoi :
```java
if (PluginClassLoader.isFromThirdPartyPlugin(event.getThrowable())) {
return null; // Ne pas envoyer
}
```
### 8.6 Configuration Sentry
| Paramètre | Valeur |
|-----------|--------|
| DSN | `https://...@sentry.hytale.com/4` |
| Environnement | `release` |
| Tags | `patchline` |
| Server name | Hostname du serveur |
---
## 9. Fix NullPointerException CraftingManager
**Fichier** : `com/hypixel/hytale/builtin/crafting/component/CraftingManager.java`
**Ligne modifiée** : 500
### 9.1 Modification
**Avant** :
```java
if (!itemResourceType.id.equals(slotCraftingMaterial.getResourceTypeId())) continue;
```
**Après** :
```java
if (!slotCraftingMaterial.getResourceTypeId().equals(itemResourceType.id)) continue;
```
### 9.2 Contexte du code
Cette ligne se trouve dans une méthode de comparaison des matériaux de craft, dans une boucle imbriquée :
```java
// Ligne ~497-502
if (slotCraftingMaterial.getResourceTypeId() == null ||
slotItemStack.getItem().getResourceTypes() == null) continue;
for (ItemResourceType itemResourceType : slotItemStack.getItem().getResourceTypes()) {
if (!slotCraftingMaterial.getResourceTypeId().equals(itemResourceType.id)) continue;
return true;
}
```
### 9.3 Analyse du problème
| Variable | Peut être null ? | Raison |
|----------|------------------|--------|
| `slotCraftingMaterial.getResourceTypeId()` | Non | Vérifié 2 lignes avant |
| `itemResourceType.id` | **Oui** | Pas de vérification préalable |
**Problème** : Appeler `.equals()` sur `itemResourceType.id` quand celui-ci est `null` lance un `NullPointerException`.
**Solution** : Inverser l'ordre de comparaison pour appeler `.equals()` sur la valeur garantie non-null.
### 9.4 Architecture du CraftingManager
| Élément | Description |
|---------|-------------|
| **Interface** | `Component<EntityStore>` (ECS) |
| **Attaché à** | Joueurs |
| **Rôle** | Gestion complète du crafting |
### 9.5 Classes internes
| Classe | Rôle |
|--------|------|
| `CraftingJob` | Représente un travail de crafting en cours |
| `BenchUpgradingJob` | Représente une amélioration d'établi |
### 9.6 Flow de crafting
```
queueCraft()
[Job ajouté à BlockingQueue]
tick() [appelé chaque tick]
[Vérifie matériaux disponibles] ← Fix NPE ici
[Retire matériaux de l'inventaire]
[Accumule temps]
[Si terminé: giveOutput()]
[Items craftés donnés au joueur]
```
### 9.7 Impact
| Aspect | Avant | Après |
|--------|-------|-------|
| Items avec `ResourceType.id = null` | Crash du crafting | Comparaison correcte |
| Stabilité serveur | NPE possible | Stable |
| Crafting avec ressources custom | Potentiellement cassé | Fonctionnel |
---
## Résumé des impacts
### Performance
| Changement | Impact |
|------------|--------|
| BBR congestion control | Amélioration significative du débit réseau |
| PMTU Discovery | Réduction de la fragmentation, meilleur throughput |
| Timeout setup 10s | Négligeable |
### Sécurité
| Changement | Impact |
|------------|--------|
| Clock skew 300s | Plus permissif mais toujours sécurisé |
| Validation iat | Protection contre tokens futurs |
| Échec auth → disconnect | Fermeture d'une faille potentielle |
### Stabilité
| Changement | Impact |
|------------|--------|
| MISSING_ASSETS shutdown | Erreur claire au lieu de comportement indéfini |
| Fix NPE CraftingManager | Élimination d'un crash potentiel |
| Collisions latérales items | Comportement physique cohérent |
### Télémétrie
| Changement | Impact |
|------------|--------|
| User data Sentry | Meilleur debugging des erreurs |
| Hardware UUID | Identification des problèmes matériels |
| Auth mode tracking | Corrélation erreurs/mode d'auth |
---
## Fichiers modifiés
| Fichier | Insertions | Suppressions |
|---------|------------|--------------|
| `server/core/auth/JWTValidator.java` | +11 | -6 |
| `server/core/HytaleServer.java` | +18 | 0 |
| `server/core/ShutdownReason.java` | +1 | 0 |
| `server/core/asset/AssetModule.java` | +5 | 0 |
| `server/core/io/handlers/SetupPacketHandler.java` | +1 | -1 |
| `server/core/io/handlers/login/HandshakeHandler.java` | +1 | -2 |
| `server/core/io/transport/QUICTransport.java` | +2 | -1 |
| `server/core/modules/entity/item/ItemPhysicsSystem.java` | +11 | -3 |
| `builtin/crafting/component/CraftingManager.java` | +1 | -1 |
| **Total** | **+55** | **-18** |