Плагин Магазин Другое zAuctionHouse [4.0.1.6]

  • Добавлено | Опция dialog.enabled для ZAUCTIONHOUSE_SEARCH: при нажатии на кнопку открывается стандартное диалоговое окно Paper (через zMenu) с текстовым полем, в котором уже указан текущий поисковый запрос, и кнопками Search, Clear и Cancel. Вместо ввода сообщения в чат используется это окно. По умолчанию отключено. Если диалоговое окно не удаётся загрузить, используется ввод через чат. Настройки диалога (заголовок, описание и названия кнопок) находятся в новом файле dialogs/search.yml, доступном на всех языках. Благодарность LIUZAZA007 (#41).
  • Исправлено | При нажатии ПКМ на объявление с шалкером (или другим контейнером) запускался процесс покупки. Из-за этого игрок без достаточного количества денег не мог просмотреть содержимое контейнера (регрессия, появившаяся в V3). Теперь содержимое открывается напрямую через shulker-content.yml — без проверки баланса и резервирования объявления. В config.yml добавлена новая опция action.container-preview (параметры enable, click, значение по умолчанию — RIGHT) (#44).
  • Исправлено | После горячей перезагрузки плагина (PlugMan и аналогичные инструменты) zMenu мог сохранять кнопки и инвентари старого экземпляра плагина. Теперь они снимаются с регистрации при отключении плагина и очищаются при следующей загрузке. Нажатия на интерфейсы, оставшиеся открытыми от старого экземпляра, игнорируются.
Автор: bobobo
  • Исправлено: при enable-sell-inventory: true количество, указанное в команде /ah sell <price> <amount>, игнорировалось, и выставлялся весь стак в руке. Теперь указанное количество учитывается при подтверждении продажи и не может превышать количество предметов у игрока.
  • Исправлено: при purchased-item.give-item: true и player-inventory-must-have-free-space: false, если покупка не помещалась в инвентарь, предметы выбрасывались на землю. Теперь вся покупка отправляется в раздел «Купленные предметы» (как в V3), а игроку показывается новое сообщение purchase-inventory-full. Если player-inventory-must-have-free-space: true, покупка по-прежнему блокируется при нехватке места. Если инвентарь заполняется между нажатием и выдачей предметов, покупка также отправляется в раздел «Купленные предметы», а не выбрасывается на землю.
  • Исправлено: перезарядка команды /ah sell запускалась даже тогда, когда продажа не состоялась (инвентарь продажи закрыли или продажа была отклонена). Теперь перезарядка начинается только после успешного завершения продажи. Для остальных команд поведение перезарядки не изменилось.
  • Исправлено: если для сообщения в messages.yml было задано значение "", вместо отключения отправлялась строка, содержащая только префикс. Теперь такие сообщения действительно отключаются.
  • Исправлено: сообщения о налоге с продажи (tax-sell-applied, tax-reduced, tax-exempt) отправлялись до сохранения объявления, даже если продажа впоследствии завершалась ошибкой и налог возвращался. Теперь сообщения отправляются только после публикации объявления.
  • Добавлено: плейсхолдеры %tax% и %percentage% в сообщении item-sold. Теперь налог можно указать в одном сообщении, отключив tax-sell-applied.
  • Добавлена: опция open-when-empty для ZAUCTIONHOUSE_EXPIRED_INVENTORY, ZAUCTIONHOUSE_PURCHASED_INVENTORY и ZAUCTIONHOUSE_SELLING_INVENTORY. Кнопка открывает инвентарь, даже если список пуст. В стандартном auction.yml эта опция используется для кнопок else.
  • Добавлена: опция economy для ZAUCTIONHOUSE_SELL_CONFIRM, позволяющая всегда продавать предметы за выбранную экономику. Каждая кнопка для отдельной экономики теперь позволяет выставить предмет одним нажатием. Это возвращает поведение из V3. Такая же опция добавлена для ZAUCTIONHOUSE_SELL_ECONOMY: она выбирает указанную экономику вместо переключения между ними. Добавлен новый плейсхолдер %selected%.
  • Добавлено: значение SELL_ECONOMY теперь можно задавать командой /ah admin cache set.
  • Добавлены плейсхолдеры PlaceholderAPI для текущей продажи: %zauctionhouse_sell_price%, %zauctionhouse_sell_price_formatted%, %zauctionhouse_sell_economy%, %zauctionhouse_sell_economy_name%, %zauctionhouse_sell_amount%.
  • API: AuctionSellService#openSellCommandInventory(Player, BigDecimal, AuctionEconomy, int), CommandManager#applyCooldown(Player, VCommand) и VCommand#setDeferredCooldown(boolean).
  • Обновлено: Sarah до версии 1.26. Добавлен параметр database-configuration.max-lifetime.
Автор: bobobo
Read this before updating a network. This release closes a long list of item and money duplication paths. Two setups that used to start are now refused, and operations that used to silently overwrite the database now fail with a message. That is intended, but your players and your staff will see it on day one.

Before you update
  • SQLite + the Redis addon is now refused at startup. Each server kept its own SQLite file, so nothing was ever synchronised while every node claimed to be clustered. Switch storage-type to MYSQL or MARIADB first
  • A server that loses Redis now blocks sales, purchases and removals instead of quietly running on its own and duplicating items. If you run a single server with the addon installed "just in case", uninstall it
  • Operations that lose a race now fail instead of overwriting. Two servers, or two clicks on the same listing, can no longer both succeed. Players will start seeing an "item no longer available" message they had never seen
  • Item tax rules now apply on purchase for every economy type. A PURCHASE or CAPITALISM rule declared on a type: SELL economy used to do nothing at purchase time. Review tax.item-rules in economies.yml before updating, or your buyers will suddenly pay more
  • Four database indexes are created on the first start. On a MySQL database that already holds hundreds of thousands of rows this can block startup for several minutes, and every node of a network will try at once. Plan a maintenance window, or create them by hand beforehand
  • Expired listings are now swept automatically, every 60 seconds by default. If you have a large backlog of listings nobody ever collected, hundreds of them will move to the expired tab right after the restart and their sellers will get a flood of items to claim. Set maintenance.expiration-sweep-interval-seconds to 0 to disable it
  • Keep write-itemstack-format-marker at false until every server of the network runs this version. Items written with the marker cannot be read back by an older jar, so until you flip it you can still roll back
  • The update also adds a few nullable columns and one table. Downgrading the jar simply ignores them, the schema is not a one-way door
Money
  • Fixed A purchase could take more money than the amount that had been checked, because item tax rules were ignored by the check but applied by the payment
  • Fixed A CAPITALISM item tax rule on a PURCHASE or BOTH economy paid the seller more than the buyer spent, creating money out of nothing on every sale
  • Fixed A payment refused by the economy plugin was never checked: the buyer still received the item, or the seller's money silently disappeared
  • Fixed Sellers paid in LEVEL, EXPERIENCE, ITEM or ZMENUITEMS lost their money when they were offline. Those payments are now claimable, and must-be-online is forced on for those economies with a warning in console
  • Fixed The sell tax could be reported as paid without ever being taken
  • Fixed An error while writing the purchase history cancelled the purchase after the buyer had paid and the seller had been credited
  • Fixed Pending money could be marked as claimed without ever being paid — a missing economy, a failed deposit or an offline player each destroyed the money
  • Fixed The same pending payment could be claimed twice by racing /ah claim, the claim button and the auto-claim on join
  • Changed For a listing holding several stacks, the purchase tax now uses the highest matching item rule, like the selling side already did
Item duplication
  • Fixed Taking back a listed, selling, expired or purchased item could duplicate it on a network. The item is now re-checked against the database while the server holds the cluster lock, exactly like a purchase already did
  • Fixed A purchase handed the item over before the database confirmed it: if the write failed, the buyer kept the item and the listing stayed on sale. This one needed no cluster at all
  • Fixed Buttons still armed in an already-open interface could act on an item that had been sold or removed in the meantime
  • Fixed /ah admin removal ignored a lock held by another server, announced the removal before saving it — other servers then put the item back on sale — and never released its lock on failure
  • Fixed Taking back a listing with give-item: true and a nearly full inventory could store it as expired on one server and deleted on the others, making it impossible to claim anywhere
  • Fixed "Retrieve everything" abandoned the rest of the batch on the first error without a word. It now finishes and tells the player how many items were actually processed
  • Changed With give-item: true, an inventory that fills up between the click and the execution now drops the overflow on the ground instead of silently sending the item to the expired tab
  • Changed An admin removing an expired or purchased item is now final across the whole network, other servers no longer put the row back
Selling
  • Fixed A crash during a sale could destroy the items: the stacks left the seller's inventory before the listing was saved. The listing is now written first, and any failure refunds both the items and the sell tax
  • Added A startup check that cleans up listings left half-created by a crash. Either the seller never lost their items and the orphan row is deleted, or they did and the listing becomes claimable in their expired tab. Both cases are logged
  • Fixed The sell selection is limited to what the interface can actually display and give back, instead of silently swallowing the surplus
  • Fixed A listing whose content can no longer be read — a Minecraft downgrade, a removed custom-item plugin — is now hidden and logged instead of showing up as an empty or BARRIER item that could still be bought. The database row is left untouched, so an older server can never destroy items that are perfectly valid for the others
Items stuck in a confirmation
  • Added An item left locked in a confirmation screen is now released automatically after maintenance.confirmation-timeout-seconds (60 by default). Quitting or dying releases it immediately. A player who disconnected with a confirmation open used to leave the item unbuyable on every server
  • Fixed Confirming and cancelling went through different code paths, and one of them could leave the item locked
  • Fixed /ah admin cache clear released items that were legitimately locked inside a confirmation
Stability and performance
  • Fixed Database writes that had already been decided could be dropped silently. They are now queued on a dedicated pool, drained on shutdown, and a refused write is logged loudly instead of vanishing
  • Fixed The per-player cache was not safe under concurrent access and could come back after the player had disconnected
  • Fixed The inventory refresh stopped at the first skipped player, so only a fraction of the connected players saw the auction house update after a sale or a removal
  • Fixed Category counters returned 0 for any category whose name in categories.yml contained uppercase letters
  • Fixed Search, sorting and category counters no longer copy the whole item list on every evaluation
  • Fixed Loading the auction house no longer half-loads on a database error, and reloading the items is a real reset instead of an additive load that resurrected ghosts
  • Fixed Admin logs handled multi-stack items and counted their deletions incorrectly
  • Added A server-shutting-down message, shown when a purchase or a sale is attempted while the server is stopping, instead of letting it start and be cut in half
Migration and admin commands
  • Fixed /ah admin migrate announced a full success on a migration that had destroyed money: on MySQL, every seller's pending balance from V3 was refused by the database and the error was never seen. The command now reports the real result
  • Fixed Running the migration twice duplicated every item and every pending balance. It is now blocked once completed, and an explicit force argument is needed to override it
  • Fixed The migration now runs on its own thread, only one at a time, and refuses to start while players are connected
  • Fixed The migration overwrote the name of players who already existed in V4
  • Fixed /ah admin logs clear-migrated reported a success having purged nothing
  • Fixed /ah admin add destroyed the item held by the administrator when the write failed, created expired and purchased items that were immediately unclaimable, and never announced its listings to the other servers
  • Fixed /ah admin generate froze the main thread and could hand its generated listings to real players
  • Fixed The three log purge commands reported a success when the deletion had failed
Multi-server (Redis addon)
  • Added Locks are now renewed while a purchase or a removal is running, so redis-config.lock-ttl-seconds no longer needs to be oversized to survive a slow economy plugin or a slow database. Turn it off with redis-config.lock-renew-enabled: false
  • Fixed Every message published while a server was reconnecting was lost, leaving items sold elsewhere as buyable ghosts. Listings are now re-synchronised against Redis after each interruption
  • Fixed Messages could be applied out of order, an outdated status overwriting a newer one
  • Fixed Shutting the addon down released nothing: locks stayed held, the listener thread kept running, and a saturated connection pool could freeze it
  • Fixed The addon started listening to the network before the cluster was ready
  • Fixed A seller connected to another server was not paid by auto-claim when their item sold
  • Fixed An auction house left open on another server kept clickable ghosts after an item was bought or removed there
  • Fixed A single unreadable field no longer discards an entire synchronisation message
  • Fixed The addon's update checker never reported anything
  • Changed A server that cannot register itself in Redis now refuses to start instead of joining with an identity it cannot vouch for, and two servers sharing an identity are now detected
Configuration and messages
  • Added A maintenance section in config.yml for the expiration sweep and the confirmation timeout, plus the write-itemstack-format-marker key, in all six languages (en/fr/es/it/id/th)
  • Added action.save-profile-on-sell (default true) — saves the seller's profile right after their items leave their inventory, so a crash cannot hand them back a copy of what they are already selling. It is a disk write on every sale: turn it off on a heavily loaded server, or when another plugin already handles inventory persistence
  • Added admin-item-not-available, server-shutting-down, item-no-longer-available, sell-error-invalid-item, sell-inventory-full and remove-all-items-partial messages, in all six languages
  • Added redis-config.lock-renew-enabled in the addon, and lock-ttl-seconds is re-documented as a renewable lease
  • Changed economies.yml now documents the offline payment and purchase tax changes above, in all six languages
Known limitations
  • On a purchase the money still moves before the listing is committed. If another server sold the same listing first, the buyer is charged and the seller keeps both the item and a claimable payment. The incident is logged with everything needed to fix it by hand, but it is not refunded automatically. That is the next piece of work
  • The listing limit counts listings, not stacks: a rank limited to five listings can still hold thirty-six stacks in each of them
  • The addon has no compatibility check at startup, so always update the plugin first and the addon second, never the reverse
Автор: bobobo
  • Добавлено: интеграция метрик FastStats в дополнение к уже используемому bStats. Клиент FastStats включён в итоговый JAR и перемещён в отдельный пакет, запускается после инициализации плагина и корректно завершается вместе с ним.
  • Исправлено: в итоговом JAR находились три дубликата META-INF/faststats.properties. FastStats теперь находится только в корневом модуле плагина, а Shadow сохраняет единственную копию идентичной информации о версии.
  • Добавлено: индонезийская локализация (id) с переводом конфигурации, сообщений, правил, категорий, настроек Discord, инвентарей и паттернов. Автоматическое определение языка теперь выбирает индонезийский для серверов, расположенных в Индонезии.
  • Исправлено: инвентари администратора для просроченных, купленных и выставленных на продажу предметов не отображали настроенный в YAML предмет для пустого состояния, если у выбранного игрока не было подходящих предметов.
Автор: bobobo
  • Обновлено: зависимость CurrenciesAPI обновлена с версии 1.0.13 до 1.0.14. Неправильно написанный тип экономики EXCELLENTEECONOMY переименован в EXCELLENTECONOMY. Теперь оба варианта принимаются в качестве типа в economies.yml; старый вариант помечен как устаревший и будет удалён в одном из будущих обновлений CurrenciesAPI.
  • Добавлено:права для кнопок администратора:
    • admin_expired_items_remove — позволяет удалять просроченные предметы с аукциона.
    • admin_logs_give_item_to_player — позволяет выдавать предметы другим игрокам из логов аукциона.
    • admin_purchased_items_remove — позволяет удалять купленные предметы с аукциона.
    • admin_listed_items_remov — позволяет удалять выставленные предметы с аукциона.
Автор: bobobo
  • Добавлена настройка allow-decimal-prices в config.yml (по умолчанию true).
    При значении false игроки больше не смогут выставлять предметы на продажу по цене с десятичными значениями (например, 10.5). Разрешены только целые числа.
  • Проверка применяется ко всем способам продажи через SellService:
    • команда /ah sell;
    • кнопка подтверждения продажи в меню инвентаря.
  • Добавлено новое сообщение price-decimal-not-allowed, которое отображается при попытке указать дробную цену.
  • Настройка и сообщение синхронизированы во всех языковых файлах (en/fr/es/it/th).
  • Добавлена миграция данных из CrazyAuction.
Автор: bobobo
  • Исправлено Критическое дублирование между серверами, при котором проданный предмет снова появлялся у продавца (мультисервер / Redis). Когда purchased-item.give-item: true, после покупки строка предмета в базе данных переводилась в DELETED до отправки события ItemBought; на всех остальных серверах ItemBoughtListener заново получал предмет через selectItem (который исключает строки DELETED), получал null и прекращал выполнение до удаления объявления из своего хранилища в памяти. Из-за этого призрачное объявление оставалось на всех серверах, кроме сервера покупателя, и продавец всё ещё видел его в /ah selling. Теперь слушатель безусловно удаляет объявление из хранилища в памяти (как ItemRemovedListener), независимо от результата запроса к базе данных. ItemBoughtMessage дополнен UUID/именем продавца, отображением предмета, ценой и именем покупателя, поэтому уведомление продавца в реальном времени (включая %buyer%, которое уже не работало на удалённых серверах) теперь работает без дополнительного обращения к базе данных
  • Исправлено Отсутствие купленных предметов на других серверах при purchased-item.give-item: false (мультисервер / Redis). ItemBoughtListener удалял предмет из LISTED на удалённых серверах, но никогда не добавлял его в их хранилище PURCHASED в памяти, поэтому при переходе покупателя на другой сервер покупка была недоступна до перезапуска. Теперь удалённые серверы повторно добавляют предмет в PURCHASED (сервер покупателя уже делал это локально; он игнорирует собственное сообщение). Для give-item: true сообщение теперь содержит флаг givenToBuyer, поэтому удалённые серверы полностью пропускают бесполезный (всегда null) запрос к базе данных
  • Исправлено Сломанная/прерванная покупка могла оставить предмет навсегда недоступным для покупки в мультисерверных (Redis) конфигурациях. Ключ блокировки auction:lock:<id> удаляется через TTL, но поле состояния предмета state=LOCKED в хэше Redis оставалось (до TTL предмета, примерно 30 дней), поэтому checkAvailability считал предмет заблокированным навсегда. Теперь состояние LOCKED зависит от существования ключа блокировки: если LOCKED установлен, но активного ключа блокировки нет — это считается устаревшей блокировкой и выполняется восстановление. Чтобы это восстановление никогда не приводило к двойной покупке, PurchaseService теперь повторно проверяет актуальное состояние базы данных под блокировкой перед списанием денег — если строка уже DELETED или у неё есть покупатель, покупка отменяется без списания средств
  • Исправлено Истечение срока действия теперь учитывает кластер в мультисерверных (Redis) конфигурациях. Ранее ExpireService переводил предметы LISTED -> EXPIRED только локально, без координации между серверами, поэтому оставшийся призрак предмета, который был продан на другом сервере, мог снова появиться как EXPIRED у продавца (и быть возвращённым обратно = дублирование). Теперь в распределённых конфигурациях переход LISTED -> EXPIRED блокирует предмет, повторно читает актуальное состояние из базы данных (пропуская предметы, проданные на другом сервере), выполняет перенос и отправляет обновление всем узлам, чтобы все серверы пришли к одному состоянию. Односерверные конфигурации продолжают использовать быстрый старый путь
  • Исправлено ItemRepository мог перезаписывать уже проданный/удалённый предмет при истечении срока действия. Обновление LISTED -> EXPIRED теперь защищено условием WHERE storage_type = 'LISTED', поэтому запрос на истечение срока больше никогда не сможет затереть строку, которую другой сервер уже перевёл в DELETED/PURCHASED
  • Добавлено Миграция DonutAuction — перенос данных из плагина DonutAuction (от EliVB) в zAuctionHouse V4 через команду /ah admin migrate donutauction confirm (алиасы donut, donutsmp, da). Данные напрямую читаются из plugins/DonutAuction/ah.data, поэтому настройка базы данных не требуется; активные аукционы импортируются как выставленные предметы, а завершённые аукционы с истёкшим сроком — как доступные для возврата предметы. Невостребованные ожидающие выплаты (деньги, не предметы) пропускаются. Старые Base64 itemstack'и проходят десериализацию через защищённый список разрешённых классов для защиты от вредоносных файлов данных
  • Исправлено Покупки между серверами могли завершаться ошибкой IllegalArgumentException: name cannot be null (мультисервер / Redis). Когда покупатель приобретал предмет, продавец которого никогда не заходил на конкретный серверный узел, getSellerName() возвращал null и напрямую передавался в withdraw() экономического провайдера (а также в плейсхолдер %seller% уведомлений о покупке), из-за чего покупка отменялась. Теперь имя продавца сначала берётся из общей базы данных, а если даже этот запрос неудачен — используется UUID продавца с предупреждением в консоли о необходимости проверить, что все серверы используют одну MySQL базу. Таким образом, null больше никогда не попадёт в последующий код
  • Исправлено Покупки могли ломаться или списывать неверную сумму при использовании налога CAPITALISM (налог в стиле НДС). Проверка баланса перед покупкой учитывала только цену предмета, но не цену с добавленным налогом CAPITALISM, поэтому игрок с балансом ровно равным цене проходил проверку, а списание с налогом позже могло завершиться ошибкой. Теперь PurchaseService и кнопка ZAUCTIONHOUSE_LISTED_ITEMS проверяют необходимый баланс с учётом налога, если включён CAPITALISM
  • Исправлено Предметы могли застревать в состоянии "покупается" после неудачной покупки из-за недостатка средств. Предмет переводился в IS_BEING_PURCHASED до проверки денег, но при ошибке только разблокировался без восстановления статуса, поэтому в мультисерверных (Redis) конфигурациях он оставался зависшим и больше не мог быть куплен. Теперь статус восстанавливается и отправляется в кластер до снятия блокировки
  • Исправлено Потеря денег при ошибках экономики во время покупки или возврата. Списание у покупателя, начисление продавцу и выплаты при возврате теперь обрабатываются через систему ошибок: если деньги у покупателя списались, но перевод продавцу завершился ошибкой — покупатель автоматически получает возврат. Ошибки выплат при возврате теперь записываются в лог и пропускаются вместо тихой потери денег
  • Исправлено Истёкшие объявления всё ещё могли отображаться и учитываться в аукционе. Так как обработка истечения срока выполняется лениво, предмет мог оставаться AVAILABLE после окончания срока (особенно при устаревшем кеше) и продолжал отображаться в основном списке, категориях и плейсхолдере %zauctionhouse_listed_items%. Теперь единая проверка Item.isActivelyListed() (доступен и не просрочен) применяется во всех местах отображения, а взаимодействие с уже просроченным объявлением теперь перемещает его в просроченные предметы игрока вместо открытия меню подтверждения или повторного отображения
  • Исправлено Кнопки списков продаваемых, просроченных, купленных, выставленных и объединённых предметов игнорировали настройку инвентаря player-inventory. Пагинация предметов и пустой слот всегда отображались в сундук GUI даже когда инвентарь был настроен как инвентарь игрока. Теперь эти кнопки отображают предметы в области собственного инвентаря игрока при соответствующей настройке (PR #25)
  • Исправлено Кнопка поиска аукциона всегда показывала жёстко заданное английское None в %search_query%, когда поиск не был активен, игнорируя язык сервера. Кнопка ZAUCTIONHOUSE_SEARCH теперь использует настраиваемое значение none-value из inventories/auction.yml, с локализованным значением по умолчанию для каждого языка (None / Aucune / Ninguna / Nessuna / ไม่มี), поэтому текст пустого поиска теперь можно переводить и изменять
  • Добавлено Настраиваемое значение %search_active% для кнопки поиска аукциона. Кнопка ZAUCTIONHOUSE_SEARCH теперь использует параметры active-value (по умолчанию true) и inactive-value (по умолчанию false) из inventories/auction.yml, поэтому значение %search_active% при активном/неактивном поиске можно изменять (например Enabled/Disabled, Yes/No) вместо фиксированных true/false
  • Изменено Обновлена требуемая версия API zMenu до 1.1.1.6 — убедитесь, что ваш сервер использует zMenu версии 1.1.1.6 или новее
Автор: bobobo
  • Исправлен спам предупреждениями Item not found for log ID в истории продаж. Логи, перенесённые из V3, создавались с item_id = 0 (так как прямого соответствия предметам V4 нет), из-за чего для каждой записи выводилось предупреждение. Теперь такие записи отфильтровываются на уровне SQL.
  • Добавлены настройки истории в config.yml:
    • history.max-entries — ограничивает количество отображаемых записей истории на игрока (по умолчанию: 500, 0 — без ограничений).
    • history.expire-after-days — скрывает записи старше указанного количества дней (по умолчанию: 0 — не истекают).
    • Полезно для серверов с большим количеством транзакций, чтобы снизить нагрузку на базу данных и ускорить загрузку истории.
  • Добавлены команды управления логами для администраторов:
    • /ah admin logs purge <days> — удаляет все логи старше указанного количества дней.
    • /ah admin logs player <player> — удаляет все логи конкретного игрока.
    • /ah admin logs clear-migrated — удаляет все логи, перенесённые из V3 (item_id = 0).
    • Все операции выполняются асинхронно и сообщают количество удалённых записей.
  • Исправлены «призрачные» предметы в /ah selling на мультисерверных (Redis) сборках. Ранее, если игрок удалял предмет на сервере №1 и переходил на сервер №2, предмет мог оставаться в продаже с пометкой «покупается» и блокировать слот продажи. Внесены три исправления:
    • ItemRemovedListener теперь сразу удаляет предмет из памяти после получения сообщения, не дожидаясь асинхронного запроса к БД.
    • RemoveService больше не восстанавливает статус предмета через Redis, если локальное удаление уже завершилось.
    • getPlayerSellingItems теперь дополнительно отфильтровывает предметы со статусом DELETED.
  • Изменён плейсхолдер Discord webhook %expires_at%: теперь он использует динамическую метку времени Discord (<t:unix_seconds:f>) вместо заранее отформатированной даты. Discord автоматически покажет дату в локальном часовом поясе каждого пользователя. Для предметов без срока действия по-прежнему используется обычная дата.
  • Добавлена поддержка кастомных изображений предметов для Discord webhook:
    • В discord.yml появилась новая секция custom-images.
    • Можно переопределить %item_image_url% для конкретных предметов.
    • Поддерживаются правила в том же формате, что и categories.yml / rules.yml: material, name, lore, custom-model-data, oraxen, itemsadder, nexo, mmoitems и другие.
    • Используется первое совпавшее правило.
    • Если совпадений нет, применяется стандартное изображение по материалу предмета.
    • Цвет изображения теперь кэшируется по URL, поэтому разные кастомные предметы с одинаковым материалом больше не конфликтуют между собой.
Автор: bobobo
  • Исправлена критическая ошибка дублирования предметов в мульти-серверных (Redis) сетапах: при удалении предмета из интерфейса продажи он корректно выдавался игроку и помечался как DELETED в базе данных, но другие серверы получали общее событие удаления (LISTED) и ошибочно восстанавливали предмет в кеше EXPIRED, что позволяло получить его повторно на другом сервере.
  • Исправлена проблема в ItemRepository.select(int id), из-за которой запрос по одному предмету не фильтровал записи со статусом DELETED, в то время как массовый select() корректно их исключал. Это приводило к повторной загрузке удалённых предметов через Redis ItemRemovedListener.
  • Добавлен параметр destinationStorageType в метод удаления cluster bridge: теперь ItemRemovedMessage передаёт точный тип назначения (DELETED или EXPIRED), чтобы другие серверы не определяли его «наугад». Обратная совместимость сохранена через дефолтный метод в AuctionClusterBridge.
  • Полностью переработан ItemRemovedListener (Redis addon) с усиленной защитой: теперь используется явный тип из сообщения, затем проверка состояния в базе данных, и больше не предполагается автоматическое восстановление в EXPIRED.
  • Исправлена ошибка миграции CreateOptionsMigration, вызывавшая сбой MySQL errno: 150 "Foreign key constraint is incorrectly formed" — колонка player_unique_id использовала тип uuid(), что могло создавать несовместимую коллацию (особенно на MySQL 8.0+). Изменено на string(36), чтобы совпадать с остальными внешними ключами, ссылающимися на players.unique_id.
Автор: bobobo
  • Добавлена поддержка banned-rules для категорий — позволяет исключать конкретные предметы из категории даже если они соответствуют правилам включения (material, tag, lore, custom-model-data и т.д.). Например, нетеритовая мотыга обычно попадает в категорию Tools, но может быть исключена по CustomModelData (например, 300)
  • Добавлена система Broadcast — отправляет сообщения всем онлайн-игрокам при продаже или покупке предметов
    • Настраивается отдельно для sell/purchase
    • Можно исключать продавца/покупателя
    • Поддерживает переопределение сообщений по категориям (MiniMessage)
    • Плейсхолдеры: %seller%, %buyer%, %items%, %price%, %category%
    • По умолчанию выключено (включается в config.yml → broadcast)
  • Добавлена система Player options — расширяемые настройки игрока с хранением в базе данных
    • Управление через /ah option (GUI) или /ah option <option_name> [value]
    • Значения кэшируются в памяти и сохраняются в БД только если отличаются от дефолта
    • Сейчас поддерживаются: broadcast_sell, broadcast_purchase (отключение broadcast-сообщений)
  • Добавлено GUI /ah option — инвентарь 27 слотов с переключателями опций и отображением текущего состояния (вкл/выкл)
  • Добавлены админ-команды для опций:
    • /ah admin option set <player> <option> <value> — установка значения
    • /ah admin option list <player> — просмотр опций игрока
    • /ah admin option reset <player> — сброс на значения по умолчанию
  • Добавлен PlaceholderAPI плейсхолдер %zauctionhouse_option_<option_name>% — возвращает true/false для конкретной опции игрока (например %zauctionhouse_option_broadcast_sell%)
Автор: bobobo
ВерхНиз