# 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` | | **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 unknown = new HashMap(); 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` (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** |