promotional bannermobile promotional banner

CustomPerm

Granular server-side command permissions for NeoForge. Grant individual vanilla or modded commands to players who are not operators, with or without LuckPerms. Native admin interface, aliases, rate limits and multi-server cluster mode.
Back to Files

customperm-2.5.0.jar

File namecustomperm-2.5.0.jar
Uploaded
Nov 10, 2026
Downloads
0
Size
1.1 MB
Mod Loaders
NeoForge
File ID
9537278
Type
R
Release
Supported game versions
  • 1.21.1

Curse Maven Snippet

NeoForge

implementation "curse.maven:customperm-1539594:9537278"

Learn more about Curse Maven

What's new

English

Added

  • Public API for other mods — io.github.thefricadelle.customperm.api, in the mod jar, with its own version (CustomPermApi.API_MAJOR 1, API_MINOR 0). Other mods compile against the released jar (compileOnly) and keep CustomPerm optional. Reads answer from the active backend, LuckPerms included: explicit and effective checks, offline checks, grades held, grade details, meta, prefix, suffix and contexts. Writes cover grade assignment, ALLOW and DENY nodes, meta, prefixes and suffixes, track promotion and demotion, and grade creation and deletion, through the same code as the commands (validation, lockout guard, save, cluster, refresh). They are off by default: settings.json gains an api block, writes false and an empty writers list, editable with /customperm api; a settings.json without it loads unchanged. A mod refused raises one admin alert naming it, every change a mod makes is in the activity log as mod:<modid> (source api), and the first one is logged at INFO. Under LuckPerms every write is refused. Events on NeoForge.EVENT_BUS follow changes once they are final, whatever made them (command, interface, API, expiry, cluster, LuckPerms, reload, backend change). See docs/API.md.
  • Mod API page in the interface — a Mod API page manages API access in game: whether writes are on, the mods allowed (added by id with completion from the loaded mods, or removed), the mods refused and the mods that wrote since the server started. Allow on a refused mod lists it, and with writes off turns them on after a confirmation. Every action runs the code of /customperm api and is recorded in the activity log; reading needs customperm.view.config, changing customperm.manage.config. The page belongs to a new View switch, Mod API, so Simple hides it; while a mod is refused, the alert on the Dashboard opens the page and the sidebar shows it in every view. The View panel's switches shrink to fit thirteen at 854x480.
  • Interface view: Simple, Advanced, Custom — a View button beside Refresh chooses how much of the admin interface shows. Simple, the default, keeps the everyday controls; Advanced shows every control, as before; Custom ticks twelve groups (worlds and contexts, durations, inheritance, meta, tracks, weights and display names, prefix priorities and stacking, nicknames, alias parameters, cluster, rate-limit persistence, import and export). Hidden boxes send nothing, rows keep showing their context, time left, priority and weight, and the Help leaves out the topics and lines of hidden controls. The choice is per client, in config/customperm/client.json, and never grants anything: the sidebar also leaves out the pages the admin cannot read, and the Dashboard the tiles of hidden areas. The LuckPerms editor is not reduced.

Changed

  • Interface network protocol 3 — the interface payloads changed (the page context carries the areas the admin may read, and the Mod API page is new), so the protocol moves from 2 to 3 and every channel name now carries it (customperm:gui_page_v3). NeoForge refuses a connection when both sides know a channel at different versions, even an optional one; with the version in the name, a player whose client still runs CustomPerm 2.0.x joins a 2.5.0 server normally, the interface simply being off until CustomPerm is updated on that client, and the other way round. /customperm gui says which protocol the server uses.
  • Java package io.github.thefricadelle.customperm — the code moved out of com.arcadia.customperm. Nothing changes for servers: the mod id, the permission nodes, the config folder and the files stay the same. Mods using the API compile against io.github.thefricadelle.customperm.api, the only package the API has ever had.
  • License 3.1: mods may use the API — compiling another mod against the unmodified official jar and calling io.github.thefricadelle.customperm.api is permitted (§3(d)); modifying, bundling or re-uploading the Mod stays forbidden. Releases already published keep the license they shipped with.
  • Read permissions per area (breaking for admins without customperm.*) — customperm.admin used to let an admin read every area: every page of the interface, every list, the logs and the diagnostics. It is now the entry only: the Dashboard, Help, /customperm status, modcheck and admin alerts. Reading an area needs the new customperm.view.<area> node (commands, aliases, ratelimits, grades, luckperms, logs, config), and customperm.manage.<area> reads its area too; customperm.view.* reads them all, customperm.* still grants everything. The server enforces it: a page the admin cannot read is not sent, read subcommands (grade list, user list, track list, alias list, command list, scan, debug, test, ratelimit list, log admin, contexts, names and the like) are absent from their command tree, completions no longer propose the names of a hidden area, the Dashboard and status leave out the figures of hidden areas, and the LuckPerms editor refuses a snapshot without customperm.view.luckperms. contexts and names now read with customperm.view.config and change with customperm.manage.config. Players page and track list need customperm.view.grades, a track node alone still moving players by command. An admin who held customperm.admin with only some manage nodes now reads only those areas: grant customperm.view.* to keep the former reading. The start-up log and MIGRATION.md say so; the configuration format is unchanged.
  • Cluster changes answered without waiting for the database — a change made in a cluster waited up to 250 ms on the server thread for the database to take it, a tick spike per admin change with a slow database. The change now applies at once and is sent without waiting: the command and the interface status line say <change> — waiting for the cluster database..., then, once the database answered, <change> — applied, published to the cluster. or [CustomPerm] Refused: <reason> Undone: <change>, and the interface page is refreshed with the final state. The operators online are still told of a refusal. An API write completes, on the server thread, only with the final outcome (REFUSED_CLUSTER for a refusal), and the API events and the activity log entry follow that outcome. A change still unanswered when the server leaves the cluster is reported as not confirmed. Outside a cluster nothing changes.
  • Config files written off the server thread — every admin change wrote the five config files on the server thread (temporary file, move, about 2.7 s over an hour of cluster bench, more on a slow or scanned disk). The text of each file is still made where the change happens, then handed to one writer thread that keeps only the latest text of each file, so a burst of changes costs one write and a file never goes back to an older text. A write that fails keeps the change in memory, raises the new CONFIG_SAVE_FAILED alert naming the file and the cause, and is tried again at the next change or reload; the next change's answer says the files are not being written. /customperm reload first waits for the writes handed over (5 s at most) and is refused, memory kept, while one cannot be written. A stop waits for them the same way and logs any file left unwritten.

Fixed

  • Alias word choices a player can type — a word argument accepted choices such as minecraft:bread, which it then offered but the command parser refused. A choice must now be made of letters, digits and _ - . +; choices already saved keep loading.
  • A denied view node hides its area — an admin holding customperm.*, or the manage node of an area, could still read that area when its customperm.view.<area> node was set to DENY. An explicit DENY of a view node now wins over both, for the pages and the read commands; changing the area still follows its manage node.
  • LuckPerms that never started says restart — in singleplayer, or when LuckPerms failed to enable, the alert promised that /customperm reload could bring it back, which it cannot. It now says that only a restart helps; a LuckPerms that failed during play still recovers on reload.
  • Dashboard alerts are read whole — a long alert stopped after two or three lines, and in a short window its last line was cut in half. It now scrolls through every line, and the row fits the space the window leaves.
  • /customperm test on an admin node — it reported customperm.admin, customperm.view.*, customperm.manage.* and customperm.track.* as granted to any operator, while those nodes need an explicit ALLOW. It now says so, and names the world host, who holds them without a node.
  • A cluster that cannot join says why — when the database refused the join at start (a user without the write grants, a table missing or changed), the alert only said the database "could not be reached, or refused". It now names the table and the grants to give.
  • Long texts in the interface scroll instead of being cut — a banner or a command's explanation longer than its box used to stop mid-sentence (the Grades banner in deny mode, a long node name on the Commands page). They now scroll up slowly and come back, pausing at both ends.
  • LuckPerms editor read-only note — for an admin without customperm.manage.luckperms, the note was drawn over the Tracks tab. It now sits beside the tabs, shortened to "Read-only" when the window is narrow.
  • LuckPerms recovers without a restart — a single LuckPerms failure during play (a storage timeout, an error in a check) used to keep CustomPerm on its fallback until the server restarted. /customperm reload now asks LuckPerms again: when it answers, the LuckPerms backend is back in charge, its hooks are subscribed if they never were, the admin alert is resolved, and the reload message says so. A LuckPerms that was incompatible or never started at boot still needs a restart, and the alert says which case applies.
  • Activity log kept whole at start — the retention purge could delete an old file while the server was reading the log back at start, which stopped the read at that file and left the newer entries out of the interface until the next restart. A file that disappears is now skipped and the rest is read.
  • Rate-limit history never overwritten when it cannot be read — any read error on <world>/data/customperm_ratelimits.json was taken for corruption: a briefly locked file was renamed aside and every counter reset, and when the rename failed too, the next world save replaced the history with the few uses counted since. Only a file that is not JSON is now renamed aside. One that cannot be read is left in place, saves are suspended, a new admin alert names the file, and /customperm reload reads it again once fixed, adding the uses counted meanwhile.
  • Damaged activity log files — one byte that is not UTF-8, or one log file that could not be read, emptied a whole tab of the Logs page and hid every older file. Each file is now read on its own and decoded leniently, so only the damaged lines are skipped, and the server log names the file. A line cut short by a crash no longer swallows the next entry.
  • Unreadable cluster entries are held back — a row of the cluster store that did not decode (cut short, wrong shape) left the entries applied before it changed in memory without being saved or taking effect, and stopped the poll there; a row of a kind this version does not know was deleted from the store at the next change. Such a row is now left untouched in the store, the entry keeps this server's copy, a new admin alert names it, and changing that entry on this server writes over it. A poll that fails midway still applies the activity log entries and shared rate-limit uses it had read.
  • Config load errors name the file and the cause — a config file that could not be read (locked, no access) was reported as invalid JSON, without its path. The server log now gives the path, the cause and what to do, and the admin alert and the /customperm reload answer say invalid or empty or unreadable with the file names.
  • Unknown tls value no longer means plaintext — cluster.database.tls set to anything but off, trust or verify (a typo of verify) was read as off and the direct connection sent its password in clear. Such a value is now kept in the file, cluster mode connects to nothing, and the server log and an admin alert name the value and the accepted ones. An unknown cluster.connection is refused the same way instead of falling back to Arcadia Lib.
  • Cluster never blocks the server thread — a change made in a cluster was written to the database on the server thread, joining ran there (sleeping 12 s when a previous run's heartbeat was found) and so did the stop: a silent database drop could hold the game for the connection and socket timeouts. Every database call now runs on the cluster thread. Joining happens in the background (the dashboard says connecting, changes are refused meanwhile); a change waits 250 ms at most for its answer, and a refusal that comes later undoes it and tells the operators; a stop waits 2 s at most and logs what it could not send.
  • Cluster clock skew — liveness, the duplicate name check and the purges of the shared log and shared rate-limit uses compared each server's own clock with times written by the others: a server ahead in time deleted the uses others had just counted, which let a shared limit be bypassed. Times are now kept and compared in the database's clock.
  • Cluster table dropped or changed while running — reported as "unreachable" and only recreated by a restart. The alert now names the missing or changed table and what to do; a missing table is created again at the next attempt when the database user may, and servers join again as at a start if the rows were lost. A changed table is never altered.
  • Cluster alert that came and went — a database user that may only read, or a missing counter row, raised the alert at each change and cleared it at the next read, every few seconds. The alert is now raised once with its cause ("the database user may not write: grant ...") and cleared only when a write goes through; refused log writes back off instead of being retried at every poll. A missing counter row is put back at the highest number stored.
  • Impossible numbers in the cluster store — a row edited to a huge number made every later row unread, and a row of version 0 made every change of that entry conflict forever. The read position never moves past the counter, a version of 0 or below is written over by the next change, and a new admin alert names such rows.
  • Negative expiry no longer permanent — an expires below zero in grades.json (prefix, suffix or any ...Expiries value) used to read as permanent, like 0. It now reads as already expired: the entry grants and shows nothing, the expiry sweep removes it, and the load names it in the server log. See MIGRATION.md.
  • Future-dated activity log entries purged — an entry dated after today (clock set back, cluster peer ahead) was written to a day file named after that future date, which retention never deleted. It now goes to today's file and keeps its own time.
  • Normalised config values reported — an impossible value replaced at load in settings.json, ratelimits.json or grades.json (for example cluster.pollSeconds -4, a port out of range, a grade listed as its own parent) is now logged once as a warning naming the file, the key and the value kept.

Français

Ajouts

  • API publique pour les autres mods — io.github.thefricadelle.customperm.api, dans le jar du mod, avec sa propre version (CustomPermApi.API_MAJOR 1, API_MINOR 0). Les autres mods compilent contre le jar publié (compileOnly) et gardent CustomPerm optionnel. Les lectures répondent depuis le backend actif, LuckPerms compris : vérifications explicites et effectives, vérifications hors ligne, grades détenus, détail des grades, méta, préfixe, suffixe et contextes. Les écritures couvrent l'attribution de grades, les nœuds ALLOW et DENY, les méta, préfixes et suffixes, la promotion et la rétrogradation sur une track, ainsi que la création et la suppression de grades, par le même code que les commandes (validation, garde anti-verrouillage, sauvegarde, cluster, rafraîchissement). Elles sont désactivées par défaut : settings.json gagne un bloc api, writes à false et une liste writers vide, modifiable avec /customperm api ; un settings.json sans ce bloc se charge sans changement. Un mod refusé lève une alerte admin qui le nomme, chaque changement fait par un mod figure dans le journal d'activité sous mod:<modid> (source api), et le premier est journalisé en INFO. Sous LuckPerms, toute écriture est refusée. Des événements sur NeoForge.EVENT_BUS suivent les changements une fois définitifs, quelle qu'en soit l'origine (commande, interface, API, expiration, cluster, LuckPerms, rechargement, changement de backend). Voir docs/API.md.
  • Page Mod API dans l'interface — une page Mod API gère l'accès à l'API en jeu : si les écritures sont actives, les mods autorisés (ajoutés par identifiant avec complétion parmi les mods chargés, ou retirés), les mods refusés et les mods qui ont écrit depuis le démarrage du serveur. Allow sur un mod refusé l'ajoute à la liste et, si les écritures sont désactivées, les active après confirmation. Chaque action exécute le code de /customperm api et est enregistrée dans le journal d'activité ; la lecture demande customperm.view.config, la modification customperm.manage.config. La page appartient à un nouvel interrupteur de vue, Mod API, que Simple masque donc ; tant qu'un mod est refusé, l'alerte du tableau de bord ouvre la page et la barre latérale l'affiche dans toutes les vues. Les interrupteurs du panneau View se réduisent pour en loger treize en 854x480.
  • Vue de l'interface : Simple, Advanced, Custom — un bouton View à côté de Refresh choisit ce que montre l'interface d'administration. Simple, par défaut, garde les contrôles du quotidien ; Advanced montre tous les contrôles, comme avant ; Custom coche douze groupes (mondes et contextes, durées, héritage, méta, tracks, poids et noms d'affichage, priorités et empilement des préfixes, surnoms, paramètres d'alias, cluster, persistance des limites d'usage, import et export). Les champs masqués n'envoient rien, les lignes continuent d'afficher leur contexte, temps restant, priorité et poids, et l'aide omet les sujets et lignes des contrôles masqués. Le choix est propre à chaque client, dans config/customperm/client.json, et n'accorde jamais rien : la barre latérale omet aussi les pages que l'admin ne peut pas lire, et le tableau de bord les tuiles des domaines masqués. L'éditeur LuckPerms n'est pas réduit.

Modifications

  • Protocole réseau 3 de l'interface — les paquets de l'interface ont changé (le contexte de page porte les domaines que l'admin peut lire, et la page Mod API est nouvelle), le protocole passe donc de 2 à 3 et chaque nom de canal le porte désormais (customperm:gui_page_v3). NeoForge refuse une connexion quand les deux côtés connaissent un canal dans des versions différentes, même optionnel ; avec la version dans le nom, un joueur dont le client tourne encore sous CustomPerm 2.0.x rejoint normalement un serveur 2.5.0, l'interface étant simplement désactivée jusqu'à la mise à jour de CustomPerm sur ce client, et inversement. /customperm gui indique le protocole utilisé par le serveur.
  • Paquet Java io.github.thefricadelle.customperm — le code a quitté com.arcadia.customperm. Rien ne change pour les serveurs : l'identifiant du mod, les nœuds de permission, le dossier de configuration et les fichiers restent les mêmes. Les mods qui utilisent l'API compilent contre io.github.thefricadelle.customperm.api, le seul paquet que l'API ait jamais eu.
  • Licence 3.1 : les mods peuvent utiliser l'API — compiler un autre mod contre le jar officiel non modifié et appeler io.github.thefricadelle.customperm.api est permis (§3(d)) ; modifier, empaqueter ou republier le Mod reste interdit. Les versions déjà publiées gardent la licence avec laquelle elles sont sorties.
  • Permissions de lecture par domaine (rupture pour les admins sans customperm.*) — customperm.admin permettait à un admin de lire tous les domaines : chaque page de l'interface, chaque liste, les journaux et les diagnostics. Ce n'est plus que l'entrée : le tableau de bord, l'aide, /customperm status, modcheck et les alertes admin. Lire un domaine demande le nouveau nœud customperm.view.<area> (commands, aliases, ratelimits, grades, luckperms, logs, config), et customperm.manage.<area> lit aussi son domaine ; customperm.view.* les lit tous, customperm.* accorde toujours tout. Le serveur l'applique : une page que l'admin ne peut pas lire n'est pas envoyée, les sous-commandes de lecture (grade list, user list, track list, alias list, command list, scan, debug, test, ratelimit list, log admin, contexts, names et les autres) sont absentes de leur arbre de commandes, les complétions ne proposent plus les noms d'un domaine masqué, le tableau de bord et status omettent les chiffres des domaines masqués, et l'éditeur LuckPerms refuse un instantané sans customperm.view.luckperms. contexts et names se lisent désormais avec customperm.view.config et se modifient avec customperm.manage.config. La page Players et track list demandent customperm.view.grades, un nœud de track seul permettant toujours de déplacer des joueurs par commande. Un admin qui détenait customperm.admin avec seulement quelques nœuds manage ne lit plus que ces domaines : accordez customperm.view.* pour garder l'ancienne lecture. Le journal de démarrage et MIGRATION.md le signalent ; le format de configuration ne change pas.
  • Changements en cluster répondus sans attendre la base de données — un changement fait en cluster attendait jusqu'à 250 ms sur le thread serveur que la base l'accepte, un pic de tick par changement admin avec une base lente. Le changement s'applique désormais tout de suite et est envoyé sans attendre : la commande et la ligne d'état de l'interface affichent <change> — waiting for the cluster database..., puis, une fois la base répondue, <change> — applied, published to the cluster. ou [CustomPerm] Refused: <reason> Undone: <change>, et la page de l'interface est rafraîchie avec l'état final. Les opérateurs en ligne sont toujours prévenus d'un refus. Une écriture par l'API ne se termine, sur le thread serveur, qu'avec le résultat final (REFUSED_CLUSTER pour un refus), et les événements de l'API et l'entrée du journal d'activité suivent ce résultat. Un changement encore sans réponse quand le serveur quitte le cluster est signalé comme non confirmé. Hors cluster, rien ne change.
  • Fichiers de configuration écrits hors du thread serveur — chaque changement admin écrivait les cinq fichiers de configuration sur le thread serveur (fichier temporaire, déplacement, environ 2,7 s sur une heure de banc cluster, plus sur un disque lent ou analysé). Le texte de chaque fichier est toujours produit là où le changement a lieu, puis confié à un unique thread d'écriture qui ne garde que le dernier texte de chaque fichier : une rafale de changements coûte une seule écriture et un fichier ne revient jamais à un texte plus ancien. Une écriture qui échoue garde le changement en mémoire, lève la nouvelle alerte CONFIG_SAVE_FAILED qui nomme le fichier et la cause, et est retentée au changement ou au rechargement suivant ; la réponse au changement suivant indique que les fichiers ne sont pas écrits. /customperm reload attend d'abord les écritures confiées (5 s au plus) et est refusé, mémoire conservée, tant qu'une ne peut pas être écrite. Un arrêt les attend de la même façon et journalise tout fichier resté non écrit.

Correctifs

  • Choix de mots d'alias qu'un joueur peut taper — un argument word acceptait des choix comme minecraft:bread, qu'il proposait ensuite mais que l'analyseur de commandes refusait. Un choix ne peut désormais contenir que des lettres, des chiffres et _ - . + ; les choix déjà enregistrés continuent de se charger.
  • Un nœud de vue refusé masque son domaine — un admin détenant customperm.*, ou le nœud manage d'un domaine, pouvait encore lire ce domaine quand son nœud customperm.view.<area> était en DENY. Un DENY explicite d'un nœud de vue l'emporte désormais sur les deux, pour les pages et les commandes de lecture ; modifier le domaine suit toujours son nœud manage.
  • Un LuckPerms jamais démarré demande un redémarrage — en solo, ou quand LuckPerms n'a pas pu s'activer, l'alerte promettait que /customperm reload pouvait le ramener, ce qui est impossible. Elle indique maintenant que seul un redémarrage aide ; un LuckPerms tombé en cours de partie se rétablit toujours au rechargement.
  • Les alertes du tableau de bord se lisent en entier — une longue alerte s'arrêtait après deux ou trois lignes, et dans une petite fenêtre sa dernière ligne était coupée en deux. Elle défile maintenant sur toutes ses lignes, et la ligne s'adapte à l'espace que laisse la fenêtre.
  • /customperm test sur un nœud admin — il annonçait customperm.admin, customperm.view.*, customperm.manage.* et customperm.track.* comme accordés à tout opérateur, alors que ces nœuds demandent un ALLOW explicite. Il le dit maintenant, et nomme l'hôte du monde, qui les détient sans nœud.
  • Un cluster qui ne peut pas rejoindre dit pourquoi — quand la base refusait la connexion au démarrage (un utilisateur sans les droits d'écriture, une table manquante ou modifiée), l'alerte disait seulement que la base « n'a pas pu être jointe, ou a refusé ». Elle nomme maintenant la table et les droits à accorder.
  • Les textes longs de l'interface défilent au lieu d'être coupés — une bannière ou l'explication d'une commande plus longue que sa zone s'arrêtait au milieu d'une phrase (la bannière Grades en mode deny, un long nom de nœud sur la page Commands). Elles défilent maintenant lentement vers le haut puis reviennent, avec une pause à chaque extrémité.
  • Note lecture seule de l'éditeur LuckPerms — pour un admin sans customperm.manage.luckperms, la note était dessinée par-dessus l'onglet Tracks. Elle se place maintenant à côté des onglets, abrégée en « Read-only » quand la fenêtre est étroite.
  • LuckPerms se rétablit sans redémarrage — une seule défaillance de LuckPerms en cours de partie (un délai de stockage dépassé, une erreur lors d'une vérification) laissait CustomPerm sur son repli jusqu'au redémarrage du serveur. /customperm reload interroge maintenant LuckPerms à nouveau : s'il répond, le backend LuckPerms reprend la main, ses hooks sont abonnés s'ils ne l'avaient jamais été, l'alerte admin est résolue, et le message de rechargement le dit. Un LuckPerms incompatible ou jamais démarré au lancement demande toujours un redémarrage, et l'alerte indique quel cas s'applique.
  • Journal d'activité gardé entier au démarrage — la purge de rétention pouvait supprimer un ancien fichier pendant que le serveur relisait le journal au démarrage, ce qui arrêtait la lecture à ce fichier et laissait les entrées plus récentes hors de l'interface jusqu'au redémarrage suivant. Un fichier qui disparaît est maintenant ignoré et le reste est lu.
  • Historique des limites d'usage jamais écrasé s'il ne peut être lu — toute erreur de lecture sur <world>/data/customperm_ratelimits.json était prise pour une corruption : un fichier brièvement verrouillé était renommé de côté et tous les compteurs remis à zéro, et si le renommage échouait aussi, la sauvegarde suivante du monde remplaçait l'historique par les quelques usages comptés depuis. Seul un fichier qui n'est pas du JSON est désormais renommé de côté. Un fichier illisible est laissé en place, les sauvegardes sont suspendues, une nouvelle alerte admin nomme le fichier, et /customperm reload le relit une fois réparé, en ajoutant les usages comptés entre-temps.
  • Fichiers du journal d'activité endommagés — un seul octet non UTF-8, ou un seul fichier de journal illisible, vidait tout un onglet de la page Logs et masquait tous les fichiers plus anciens. Chaque fichier est maintenant lu séparément et décodé avec tolérance : seules les lignes endommagées sont ignorées, et le journal du serveur nomme le fichier. Une ligne tronquée par un crash n'avale plus l'entrée suivante.
  • Les entrées de cluster illisibles sont tenues à l'écart — une ligne du stockage du cluster qui ne se décodait pas (tronquée, de mauvaise forme) laissait les entrées appliquées avant elle modifiées en mémoire sans être sauvegardées ni prendre effet, et arrêtait la lecture périodique à cet endroit ; une ligne d'un type inconnu de cette version était supprimée du stockage au changement suivant. Une telle ligne est maintenant laissée intacte dans le stockage, l'entrée garde la copie de ce serveur, une nouvelle alerte admin la nomme, et modifier cette entrée sur ce serveur l'écrase. Une lecture périodique qui échoue en cours de route applique quand même les entrées du journal d'activité et les usages partagés de limites qu'elle avait lus.
  • Les erreurs de chargement de la configuration nomment le fichier et la cause — un fichier de configuration illisible (verrouillé, sans accès) était signalé comme JSON invalide, sans son chemin. Le journal du serveur donne maintenant le chemin, la cause et la marche à suivre, et l'alerte admin et la réponse de /customperm reload indiquent invalid or empty ou unreadable avec les noms des fichiers.
  • Une valeur tls inconnue ne signifie plus texte en clair — cluster.database.tls réglé sur autre chose que off, trust ou verify (une faute de frappe de verify) était lu comme off et la connexion directe envoyait son mot de passe en clair. Une telle valeur est maintenant conservée dans le fichier, le mode cluster ne se connecte à rien, et le journal du serveur et une alerte admin nomment la valeur et celles acceptées. Un cluster.connection inconnu est refusé de la même façon au lieu de se rabattre sur Arcadia Lib.
  • Le cluster ne bloque jamais le thread serveur — un changement fait en cluster était écrit dans la base sur le thread serveur, la connexion au cluster s'y déroulait (avec une attente de 12 s quand le battement de cœur d'une exécution précédente était trouvé) et l'arrêt aussi : une coupure silencieuse de la base pouvait bloquer le jeu pendant les délais de connexion et de socket. Chaque appel à la base passe maintenant par le thread du cluster. La connexion se fait en arrière-plan (le tableau de bord indique la connexion en cours, les changements sont refusés pendant ce temps) ; un changement attend sa réponse 250 ms au plus, et un refus qui arrive plus tard l'annule et prévient les opérateurs ; un arrêt attend 2 s au plus et journalise ce qu'il n'a pas pu envoyer.
  • Décalage d'horloge du cluster — la détection des serveurs actifs, la vérification des noms en double et les purges du journal partagé et des usages partagés de limites comparaient l'horloge de chaque serveur à des heures écrites par les autres : un serveur en avance supprimait les usages que les autres venaient de compter, ce qui permettait de contourner une limite partagée. Les heures sont maintenant conservées et comparées selon l'horloge de la base.
  • Table du cluster supprimée ou modifiée en cours de route — signalée comme « injoignable » et recréée seulement par un redémarrage. L'alerte nomme maintenant la table manquante ou modifiée et la marche à suivre ; une table manquante est recréée à la tentative suivante quand l'utilisateur de la base en a le droit, et les serveurs rejoignent à nouveau comme au démarrage si les lignes ont été perdues. Une table modifiée n'est jamais altérée.
  • Alerte de cluster qui allait et venait — un utilisateur de base qui ne peut que lire, ou une ligne de compteur manquante, levait l'alerte à chaque changement et l'effaçait à la lecture suivante, toutes les quelques secondes. L'alerte est maintenant levée une fois avec sa cause (« the database user may not write: grant ... ») et effacée seulement quand une écriture passe ; les écritures de journal refusées espacent leurs tentatives au lieu d'être retentées à chaque lecture périodique. Une ligne de compteur manquante est remise au plus grand numéro stocké.
  • Nombres impossibles dans le stockage du cluster — une ligne modifiée avec un nombre énorme rendait illisibles toutes les lignes suivantes, et une ligne en version 0 faisait entrer en conflit pour toujours chaque changement de cette entrée. La position de lecture ne dépasse jamais le compteur, une version de 0 ou moins est écrasée par le changement suivant, et une nouvelle alerte admin nomme ces lignes.
  • Une expiration négative n'est plus permanente — un expires inférieur à zéro dans grades.json (préfixe, suffixe ou toute valeur ...Expiries) se lisait comme permanent, comme 0. Il se lit maintenant comme déjà expiré : l'entrée n'accorde et n'affiche rien, le balayage des expirations la retire, et le chargement la nomme dans le journal du serveur. Voir MIGRATION.md.
  • Entrées du journal d'activité datées du futur purgées — une entrée datée après aujourd'hui (horloge reculée, pair du cluster en avance) était écrite dans un fichier du jour portant cette date future, que la rétention ne supprimait jamais. Elle va maintenant dans le fichier du jour et garde sa propre heure.
  • Valeurs de configuration normalisées signalées — une valeur impossible remplacée au chargement dans settings.json, ratelimits.json ou grades.json (par exemple cluster.pollSeconds -4, un port hors limites, un grade listé comme son propre parent) est maintenant journalisée une fois en avertissement, avec le fichier, la clé et la valeur retenue.

This mod has no additional files