All versions
1.2.14+neoforge-1.21.1
Release
Arcadia Lib 1.2.14 (NeoForge 1.21.1)5 months ago 534
Uploaded by
Compatibility
Minecraft: Java Edition
1.21.1
Platform
NeoForge
Supported environments
Client and server
Changes
Fixed
- Staff/ranked players lost ALL cosmetics when LuckPerms bound late (regression) —
LuckPermsBackend.createOrFallback()ran atServerAboutToStartEvent; if LuckPerms had not finished registering its provider yet,LuckPermsProvider.get()threw, the backend resolved tonull, andPermissionServicefell back toDENY(fail-closed) for the whole session. Everyarcadia.cosmetic.*check — wildcard included — then returnedfalse, so staff and VIP/MVP players saw all cosmetics locked. The backend now binds lazily: when LuckPerms is not ready at init it defers and re-resolves the provider on first use, so wildcard and grade nodes work again as soon as LuckPerms is up. No hard-coded staff bypass introduced. - Permission checks raced ahead of LuckPerms' user cache —
LuckPermsBackendreturnedfalse/defaultwhengetUserManager().getUser()returnednull(user not yet cached, e.g. a GUI built on the same tick as join). It now loads the user synchronously (loadUser().join()) as a fallback before checking. - Real LuckPerms init failure cause is now logged —
createOrFallback()logs the exception message (not just the class name) and distinguishes "not ready yet" from "genuinely absent". AchievementManager.loadedvisibility — Madevolatile: it is written byinit()and read viaisLoaded()from background DB/scheduler threads, so a reader could observe a stale value.
Performance
LuckPermsBackend.getGrade()resolves permission data once — was re-resolvingQueryOptionscontext up to three times per call (MVP/VIP+/VIP probes); now probes all three grade nodes against a single resolvedPermissionData.DashboardScreenno longer recomputes carousel neighbours every frame — prev/next nav targets (each doing a list alloc + sort) were recomputed inrender()andmouseClicked(); now cached and refreshed only when the observed tab changes.ArcadiaHubScreen.drawCard()drops redundantComponentallocations — label/sub-label were wrapped in aComponent.literal(translatable.getString())every frame per card; now kept as translatables (language-correct) and resolved lazily only on the text-wrap path.TextFormatter.format()single-pass placeholder replacement — replaced the per-keyString.replace()loop (a full scan + newStringeach key) with one regex pass; values are inserted literally viaquoteReplacementand unknown{keys}are preserved, matching the old semantics.
Correctifs
- Les joueurs staff/gradés perdaient TOUS leurs cosmétiques quand LuckPerms se liait tard (régression) —
LuckPermsBackend.createOrFallback()s'exécutait auServerAboutToStartEvent; si LuckPerms n'avait pas fini d'enregistrer son provider,LuckPermsProvider.get()levait une exception, le backend valaitnull, etPermissionServiceretombait surDENY(fail-closed) pour toute la session. Toute vérificationarcadia.cosmetic.*— wildcard inclus — renvoyait alorsfalse, donc le staff et les VIP/MVP voyaient tous les cosmétiques verrouillés. Le backend se lie désormais paresseusement : si LuckPerms n'est pas prêt à l'init, il diffère et re-résout le provider au premier usage, donc les nodes wildcard et de grade refonctionnent dès que LuckPerms est disponible. Aucun bypass staff codé en dur introduit. - Les vérifications de permission devançaient le cache utilisateur de LuckPerms —
LuckPermsBackendrenvoyaitfalse/defaultquandgetUserManager().getUser()renvoyaitnull(utilisateur pas encore en cache, ex. un GUI construit au tick de la connexion). Il charge désormais l'utilisateur de façon synchrone (loadUser().join()) en repli avant de vérifier. - La vraie cause d'échec d'init LuckPerms est désormais journalisée —
createOrFallback()journalise le message de l'exception (pas seulement le nom de classe) et distingue « pas encore prêt » de « réellement absent ». - Visibilité de
AchievementManager.loaded— Passé envolatile: écrit parinit()et lu viaisLoaded()depuis des threads DB/scheduler en arrière-plan, un lecteur pouvait voir une valeur périmée.
Performance
LuckPermsBackend.getGrade()résout les données de permission une seule fois — re-résolvait le contexteQueryOptionsjusqu'à trois fois par appel (sondes MVP/VIP+/VIP) ; sonde désormais les trois nodes de grade contre une uniquePermissionDatarésolue.DashboardScreenne recalcule plus les voisins du carrousel à chaque frame — les cibles nav prev/next (chacune avec une allocation de liste + tri) étaient recalculées dansrender()etmouseClicked(); désormais mises en cache et rafraîchies seulement quand l'onglet observé change.ArcadiaHubScreen.drawCard()supprime des allocationsComponentredondantes — le label/sous-label était enveloppé dans unComponent.literal(translatable.getString())à chaque frame par carte ; conservé désormais en translatable (correct pour la langue) et résolu paresseusement uniquement sur le chemin de retour à la ligne.TextFormatter.format()remplacement des placeholders en une passe — remplacé la boucleString.replace()par clé (un scan complet + une nouvelleStringpar clé) par une unique passe regex ; les valeurs sont insérées littéralement viaquoteReplacementet les{clés}inconnues sont préservées, conformément à l'ancienne sémantique.
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:ig2OziLX:Fmig7X9E"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:ig2OziLX:Fmig7X9E"
}

