arcadia-ah-1.21.1-1.4.0
Curse Maven Snippet
What's new
Added
Real item categories — The category filter only ever had two values,
petandmisc, derived from a single class-name check at listing time, so on any server selling something other than pets it filtered nothing.AuctionCategorynow buckets a listing into one of ten aisles (weapons, tools, armor, potions, food, redstone, resources, blocks, pets, misc), derived from the item itself using item tags, theFOODdata component and registry-path heuristics. Rows written before 1.4.0 all carrymisc, so their aisle is re-derived from the storeditem_typeat read time: the whole back catalogue gains categories with no data migration and no schema change.Result sorting — Newest, cheapest, most expensive, ending soon, and name. The paid featured block is always kept on top regardless of the mode, and a final listing-id tiebreak keeps paging stable, so two equally-priced rows cannot swap places between two cache refreshes and shift a slot under the player's cursor.
Search query language — The existing search box now accepts
seller:,type:,cat:,sort:,>minand<maxwithk/m/bsuffixes. Absurd values saturate instead of overflowing, a reversed price bracket is swapped rather than returning an empty page, and free-text terms must all match, sodiamond swordno longer matches a plain diamond. The search button's lore lists every active filter, so an empty page can no longer be mistaken for an empty auction house.Two-step purchase confirmation — The browser is a chest GUI where a single misclick spent real currency instantly, on a row that may have moved when the cache refreshed. Buying and cancelling now arm on the first click and commit on the second. The armed state is keyed by listing id, not by slot, so a refresh that moves the row invalidates the confirmation instead of transferring it. Cancelling is included: the listing fee is paid upfront and is not refunded, so a misclick there costs money too. New
[ui]section:buy_confirmation,confirm_timeout_seconds.Market price guidance when selling —
DynamicPriceEngine.suggestPricehad existed since 1.3.x and was never called from anywhere. The sell screen now shows the rolling 7-day average with its sample size and the enforced minimum, and offers a one-click button that fills the field with the engine's suggestion. Showing the floor up front is what stops a seller from typing a price, pressing Sell, and only then being told the listing is below the minimum.Bidding from the browser — Placing a bid required
/arcadia_ah bid <listingId> <amount>with a raw UUID that appears nowhere in the interface, so in practice nobody bid on anything. Right-clicking a listing now opens a bid screen showing the buy-now price, the standing bid and its holder, and the minimum winning amount pre-filled into the field. Listing lore gained the standing bid and the minimum, so a buyer can see a listing is contested before choosing between buying it outright and joining the bidding.Outbid notifications — An outbid bidder's escrow came back in silence; the only way to learn an auction was slipping away was to re-check the listing by hand. They are now told, with the new high bid and the amount returned.
Anti-sniping — A bid in the final seconds used to win uncontested. A bid inside the configured window now pushes the deadline out, so an auction only ends once a bid has stood unchallenged for the whole window. The extension is capped against the listing's own creation time so a bidding war cannot pin an item away from its seller indefinitely, and the database update is conditional on the stored expiry still being earlier, so two servers extending the same auction converge on the latest deadline instead of one truncating the other. Extensions are told to the seller and the bidder only.
Percentage bid increments — The minimum raise was a flat
+1, which made a 100,000-coin auction a clicking contest rather than an auction. It is now a configurable percentage of the current bid with a floor of 1 unit. New[bidding]section:bid_increment_percent,anti_snipe_window_minutes,anti_snipe_max_total_hours.Item watches —
/arcadia_ah watch add|remove|clear|listnotifies a player the moment a matching listing is created, optionally only under a price ceiling. Independent of the global broadcast, so it still reaches the watcher when broadcasts are off or the seller is on broadcast cooldown. Unknown item ids are rejected at the command edge, since a typo would otherwise create a watch that can never fire and say nothing. Backed by the newarcadia_ah_watchlisttable (composite-keyed so re-pricing a watch replaces its row) with a JSON fallback for solo play. New[watchlist]section.Login auction summary — Pending mailbox entries, coins waiting in them, and listings expiring within a day. Sent only when there is something to report, so it adds no noise for players who never touch the auction house.
Claim the whole mailbox at once — Emptying a mailbox was one click per row, up to the cap, and a full mailbox blocks new listings. Each entry still goes through the same per-entry atomic claim, so the 1.3.1 concurrency guarantee and the 1.3.2 corrupt-row handling are untouched; only the per-entry chat line is replaced by a single summary. The inventory-full notice stays loud, since it explains why an expected item is still in the mailbox.
/arcadia_ah stats— Active listings and their total value, the last 24 hours of sales with volume and average price, and the five most traded items of the week. The only market-wide view before this was the seller leaderboard, which says who is trading but nothing about prices or liquidity.Sales tax — New
listings.sales_tax_percent, withheld from the seller when a sale completes. Distinct fromlisting_fee_percent, which is charged upfront whether or not the item ever sells. Applies to won auctions as well as instant buys, since taxing only one would push every seller to list as an auction to dodge it. Defaults to 0, so an existing server keeps paying sellers 100% until an admin opts in.Offers and negotiation — With
bidding.offers_enabled, a bid may open below the asking price. A standing offer does not win at expiry: letting it settle would push a seller who never answered into selling under their own asking price, so it is refunded and the listing returns normally. Sellers accept with/arcadia_ah acceptor by right-clicking their own listing, through the same transaction the expiry sweep uses, so an acceptance racing the sweep cannot settle a listing twice.min_offer_percent(default 50) stops "make an offer" becoming "1 coin on every listing".Seller sale counts — Listings show the seller's completed-sale count as a light trust signal. Never queried inline: the count is served from cache and a miss queues a background fetch, so a crowded page cannot stall the tick to render a badge.
Player shops —
/arcadia_ah shop <seller>opens the browser filtered to one player's stock, built on theseller:search token so sort, category and price filters keep working inside a shop.Undercut warnings — A seller is told when someone lists the same item cheaper. Previously an undercut listing simply sat unsold until it expired with no signal at all.
Audit trail — New
arcadia_ah_audittable and/arcadia_ah admin audit [page]. Blacklists, price floors, mailbox purges, dynamic-pricing and emerald-wallet toggles, the global freeze and operator listing removals are all recorded with actor, target and time. Writes never block and never fail the action they record; every entry is mirrored to the server log so that line remains the trail if the database write fails.Operator listing removal —
/arcadia_ah admin remove <listingId> [reason]settles a listing through the same atomic claim a seller's cancel uses, refunds any escrowed bid, and returns the item to the seller, never to the operator.
Fixed
- Declared dependency was one version behind the API actually used — 1.3.4 introduced the emerald wallet commands, which call
EconomyService.isEmeraldFallbackEligible,depositEmeraldsand friends, and vendoredarcadia-lib1.2.15 for them — butneoforge.mods.tomlstill declaredarcadia_lib >= 1.2.14. A server running 1.2.14 would have loaded the mod and then failed when the command tree was built. The declared range now matches the API in use. - Price-history aggregate ran on the server thread on every listing attempt — The minimum-price check calls
PriceHistoryManager.getStats, which runs an aggregate query over the sales log, so every attempt to sell anything blocked the tick on a database round-trip. Results are now served from a 60-second cache, dropped for an item the moment that item sells and pruned by age from the existing refresh tick. - Mailbox badge ran a COUNT query on every tab build — Every page turn, category cycle, sort change and confirmation click re-counted the mailbox on the server thread. The badge is now served from a 5-second cache, invalidated whenever that player's mailbox changes. The listing cap check deliberately still queries directly: it decides whether a listing is allowed at all and must never run on a stale number.
- Outbid refund could destroy the bidder's escrow —
BidManager.placeBiddiscarded the return value ofEconomyService.addwhen refunding a displaced bidder who was online. 1.3.2 made that call failure-aware precisely because a swallowed deposit failure silently destroys currency, and every other payout path was updated then; this one was missed. A failed deposit left the bidder with nothing — escrow consumed, credit never landed, and the mailbox fallback sat in the branch that only runs when the player is offline. It now falls through to the mailbox, and the outbid notice is only sent when the coins genuinely came back. - Buyer refunds would have been short-changed by any sales tax — A single variable named
sellerPayoutcarried two different amounts in the buy path: what the seller receives, and what the buyer is refunded on each of the three failure paths. They are nowchargedToBuyerandsellerPayout. - Bid minimum was computed in two places and had drifted — The command edge recomputed its own threshold instead of asking the bid layer. Both now call
BidManager.minimumNextBid. - Bids were accepted on already-expired listings — Escrow could be taken for a listing the sweep had already picked a winner for. Such bids are now refused.
- Per-player browsing state was lost on every search — The dashboard tab handler is rebuilt each time the dashboard is reopened, which reset the category filter on every search round-trip. Browsing state moved to
AuctionManager, keyed by player. - Unbounded per-player maps — Search and browsing state are dropped on logout. The listing and broadcast cooldown maps deliberately are not, since clearing those on logout would let a player bypass both anti-spam timers by relogging; they are pruned by elapsed window instead.
Changed
- Dependency — Now requires
arcadia_lib >= 1.2.15.
Ajouts
Vraies catégories d'objets — Le filtre de catégorie n'a jamais eu que deux valeurs,
petetmisc, déduites d'un simple test de nom de classe à la mise en vente : sur un serveur vendant autre chose que des familiers, il ne filtrait rien.AuctionCategoryclasse désormais une annonce dans l'un de dix rayons (armes, outils, armures, potions, nourriture, redstone, ressources, blocs, familiers, divers), déduits de l'objet lui-même via les tags, le composantFOODet des heuristiques sur l'identifiant de registre. Les lignes antérieures à la 1.4.0 portent toutesmisc: leur rayon est recalculé à la lecture depuis l'item_typestocké, donc tout l'historique gagne des catégories sans migration de données ni changement de schéma.Tri des résultats — Plus récent, moins cher, plus cher, expire bientôt, nom. Le bloc mis en avant payant reste toujours en tête quel que soit le mode, et un départage final par identifiant d'annonce stabilise la pagination : deux annonces au même prix ne peuvent plus permuter entre deux rafraîchissements de cache et déplacer une case sous le curseur.
Langage de requête dans la recherche — La barre de recherche accepte désormais
seller:,type:,cat:,sort:,>minet<maxavec suffixesk/m/b. Les valeurs absurdes saturent au lieu de déborder, une fourchette de prix inversée est remise à l'endroit au lieu de renvoyer une page vide, et tous les termes libres doivent correspondre :diamond swordne remonte plus un simple diamant. Le bouton de recherche liste tous les filtres actifs, pour qu'une page vide ne soit plus prise pour un hôtel des ventes vide.Confirmation d'achat en deux temps — Le navigateur est une interface de coffre où un simple faux clic dépensait de la monnaie réelle instantanément, sur une ligne qui a pu bouger au rafraîchissement du cache. L'achat et l'annulation s'arment au premier clic et se valident au second. L'état armé est indexé par identifiant d'annonce et non par case : un rafraîchissement qui déplace la ligne invalide la confirmation au lieu de la transférer. L'annulation est incluse : les frais d'annonce sont payés d'avance et non remboursés, un faux clic y coûte donc aussi de l'argent. Nouvelle section
[ui]:buy_confirmation,confirm_timeout_seconds.Repères de prix à la vente —
DynamicPriceEngine.suggestPriceexistait depuis la 1.3.x et n'était appelé nulle part. L'écran de vente affiche désormais la moyenne glissante sur 7 jours avec sa taille d'échantillon et le prix plancher appliqué, et propose un bouton qui remplit le champ avec la suggestion. Afficher le plancher en amont évite au vendeur de saisir un prix, valider, et n'apprendre qu'ensuite que son annonce est sous le minimum.Enchérir depuis le navigateur — Placer une enchère exigeait
/arcadia_ah bid <listingId> <montant>avec un UUID brut qui n'apparaît nulle part dans l'interface : en pratique personne n'enchérissait. Un clic droit sur une annonce ouvre désormais un écran d'enchère affichant le prix d'achat direct, l'enchère en cours et son détenteur, et le montant minimum gagnant pré-rempli dans le champ. Le descriptif des annonces indique l'enchère en cours et le minimum, pour qu'un acheteur voie qu'une annonce est disputée avant de choisir entre l'achat direct et l'enchère.Notification de surenchère — L'escrow d'un enchérisseur surenchéri revenait en silence ; le seul moyen d'apprendre qu'une enchère lui échappait était de revérifier l'annonce à la main. Il est désormais prévenu, avec la nouvelle enchère et le montant rendu.
Anti-sniping — Une enchère dans les dernières secondes gagnait sans réplique. Une enchère dans la fenêtre configurée repousse désormais l'échéance : une vente ne se termine qu'une fois qu'une enchère est restée sans réponse pendant toute la fenêtre. La prolongation est bornée par rapport à la date de création de l'annonce, pour qu'une guerre d'enchères ne retienne pas indéfiniment un objet loin de son vendeur, et la mise à jour en base est conditionnée au fait que l'échéance stockée soit encore antérieure : deux serveurs prolongeant la même vente convergent vers l'échéance la plus tardive au lieu que l'un tronque l'autre. Les prolongations ne sont annoncées qu'au vendeur et à l'enchérisseur.
Incréments d'enchère en pourcentage — La hausse minimale était un
+1fixe, ce qui faisait d'une vente à 100 000 pièces un concours de clics plutôt qu'une enchère. C'est désormais un pourcentage configurable de l'enchère en cours, avec un plancher d'une unité. Nouvelle section[bidding]:bid_increment_percent,anti_snipe_window_minutes,anti_snipe_max_total_hours.Alertes d'objet —
/arcadia_ah watch add|remove|clear|listprévient un joueur dès qu'une annonce correspondante est créée, éventuellement sous un plafond de prix. Indépendant du broadcast global : l'alerte parvient au joueur même quand les broadcasts sont désactivés ou que le vendeur est en cooldown. Les identifiants d'objet inconnus sont rejetés à la saisie, car une faute de frappe créerait sinon une alerte qui ne peut jamais se déclencher, sans rien dire. Stocké dans la nouvelle tablearcadia_ah_watchlist(clé composite, pour qu'un changement de plafond remplace la ligne) avec repli JSON en solo. Nouvelle section[watchlist].Résumé à la connexion — Entrées en attente dans la boîte aux lettres, pièces qui y dorment, et annonces expirant dans moins d'un jour. Envoyé uniquement quand il y a quelque chose à signaler, donc sans bruit pour qui n'utilise pas l'hôtel des ventes.
Tout réclamer en boîte aux lettres — Vider une boîte se faisait ligne par ligne, jusqu'au plafond, et une boîte pleine bloque les nouvelles annonces. Chaque entrée passe toujours par la même réclamation atomique : la garantie de concurrence 1.3.1 et le traitement des lignes corrompues 1.3.2 sont intacts ; seule la ligne de chat par entrée est remplacée par un résumé unique. L'avertissement d'inventaire plein reste affiché, car il explique pourquoi un objet attendu est encore en boîte.
/arcadia_ah stats— Annonces actives et valeur totale, dernières 24 heures de ventes avec volume et prix moyen, et les cinq objets les plus échangés de la semaine. La seule vue globale jusqu'ici était le classement des vendeurs, qui dit qui échange mais rien sur les prix ni la liquidité.Taxe de vente — Nouveau
listings.sales_tax_percent, prélevé sur le vendeur à la conclusion d'une vente. Distinct delisting_fee_percent, facturé d'avance que l'objet se vende ou non. S'applique aux enchères gagnées comme aux achats directs, sinon tout vendeur passerait par l'enchère pour l'éviter. Vaut 0 par défaut : un serveur existant continue de payer 100 % aux vendeurs jusqu'à ce qu'un admin l'active.Offres et négociation — Avec
bidding.offers_enabled, une enchère peut démarrer sous le prix demandé. Une offre en cours ne gagne pas à l'expiration : la laisser aboutir forcerait un vendeur qui n'a jamais répondu à vendre sous son propre prix, elle est donc remboursée et l'annonce revient normalement. Le vendeur accepte via/arcadia_ah acceptou par clic droit sur sa propre annonce, à travers la transaction utilisée par la passe d'expiration, de sorte qu'une acceptation concurrente ne peut pas régler deux fois la même annonce.min_offer_percent(défaut 50) empêche « faire une offre » de devenir « 1 pièce sur chaque annonce ».Nombre de ventes du vendeur — Les annonces affichent le nombre de ventes conclues du vendeur, comme repère de confiance. Jamais interrogé en ligne : le compteur vient du cache et un défaut déclenche une récupération en tâche de fond, pour qu'une page chargée ne bloque pas le tick pour afficher un badge.
Boutiques de joueur —
/arcadia_ah shop <vendeur>ouvre le navigateur filtré sur le stock d'un joueur, construit sur le token de rechercheseller:pour que tri, catégorie et filtres de prix continuent de fonctionner dans une boutique.Alerte de sous-cotation — Un vendeur est prévenu quand quelqu'un met le même objet moins cher. Auparavant une annonce sous-cotée restait invendue jusqu'à expiration sans le moindre signal.
Journal d'audit — Nouvelle table
arcadia_ah_auditet/arcadia_ah admin audit [page]. Blacklists, prix planchers, purges de boîte, bascules de tarification dynamique et de portefeuille émeraude, gel global et retraits d'annonce par un opérateur sont enregistrés avec auteur, cible et horodatage. Les écritures ne bloquent jamais et ne font jamais échouer l'action enregistrée ; chaque entrée est aussi écrite dans le journal du serveur, qui reste la trace si l'écriture en base échoue.Retrait d'annonce par un opérateur —
/arcadia_ah admin remove <listingId> [raison]règle l'annonce via la même réclamation atomique qu'une annulation vendeur, rembourse toute enchère en escrow, et rend l'objet au vendeur, jamais à l'opérateur.
Correctifs
- La dépendance déclarée avait une version de retard sur l'API réellement utilisée — La 1.3.4 a introduit les commandes de portefeuille émeraude, qui appellent
EconomyService.isEmeraldFallbackEligible,depositEmeraldset consorts, et a embarquéarcadia-lib1.2.15 pour cela — maisneoforge.mods.tomldéclarait toujoursarcadia_lib >= 1.2.14. Un serveur en 1.2.14 aurait chargé le mod puis échoué à la construction de l'arbre de commandes. La plage déclarée correspond désormais à l'API utilisée. - L'agrégat d'historique de prix s'exécutait sur le thread serveur à chaque mise en vente — La vérification du prix plancher appelle
PriceHistoryManager.getStats, qui agrège le journal des ventes : chaque tentative de vente bloquait donc le tick sur un aller-retour base de données. Les résultats sont désormais servis depuis un cache de 60 secondes, invalidé pour un objet dès qu'il se vend et purgé par âge depuis le tick de rafraîchissement existant. - Le badge de boîte aux lettres lançait un COUNT à chaque construction d'onglet — Chaque changement de page, de catégorie, de tri et chaque clic de confirmation recomptait la boîte sur le thread serveur. Le badge est désormais servi depuis un cache de 5 secondes, invalidé dès que la boîte du joueur change. La vérification du plafond d'annonces continue délibérément d'interroger directement : elle décide si une annonce est autorisée et ne doit jamais s'appuyer sur un chiffre périmé.
- Le remboursement de surenchère pouvait détruire l'escrow de l'enchérisseur —
BidManager.placeBidignorait la valeur de retour d'EconomyService.adden remboursant un enchérisseur évincé connecté. La 1.3.2 avait rendu cet appel conscient des échecs précisément parce qu'un dépôt avalé détruit silencieusement de la monnaie, et tous les autres chemins de paiement avaient été corrigés alors ; celui-ci avait été oublié. Un dépôt échoué laissait l'enchérisseur sans rien : escrow consommé, crédit jamais arrivé, et le repli boîte aux lettres se trouvait dans la branche réservée aux joueurs hors ligne. Le remboursement passe désormais par la boîte, et la notification n'est envoyée que si les pièces sont réellement revenues. - Les remboursements acheteur auraient été amputés par toute taxe de vente — Une seule variable nommée
sellerPayoutportait deux montants différents dans le chemin d'achat : ce que reçoit le vendeur, et ce qui est rendu à l'acheteur sur chacun des trois chemins d'échec. Ils s'appellent désormaischargedToBuyeretsellerPayout. - Le minimum d'enchère était calculé à deux endroits et avait divergé — La commande recalculait son propre seuil au lieu d'interroger la couche d'enchères. Les deux appellent désormais
BidManager.minimumNextBid. - Les enchères étaient acceptées sur des annonces déjà expirées — De l'escrow pouvait être pris pour une annonce dont la passe d'expiration avait déjà désigné un gagnant. Ces enchères sont désormais refusées.
- L'état de navigation par joueur était perdu à chaque recherche — Le gestionnaire d'onglet est reconstruit à chaque réouverture du tableau de bord, ce qui réinitialisait le filtre de catégorie à chaque aller-retour de recherche. L'état de navigation est passé dans
AuctionManager, indexé par joueur. - Cartes par joueur sans borne — La recherche et l'état de navigation sont libérés à la déconnexion. Les cartes de cooldown d'annonce et de broadcast ne le sont délibérément pas : les vider à la déconnexion permettrait de contourner les deux anti-spam par reconnexion ; elles sont purgées par fenêtre écoulée.
Modifications
- Dépendance — Nécessite désormais
arcadia_lib >= 1.2.15.
All Relations
- All Relations
- Embedded Library
- Optional Dependency
- Required Dependency
- Tool
- Incompatible
- Include

