CloudSphereChest — Сундук со сферами

Координаты падают в чат — и сервер срывается с места. Кто-то бросает шахту, кто-то стройку, все бегут в одну точку на карте, потому что там из ниоткуда вырастает сундук с фиолетовым свечением, лучом в небо и рёвом дракона на весь мир. Открыть его может не любой желающий — только тот, у кого в руке Сферический ключ. И даже с ключом успех не гарантирован никому.

CloudSphereChest — не лутбокс на кнопке, а полноценный ивент с анонсом, обратным отсчётом, охраной зоны и развязкой на весь сервер. Один сундук, один ключ на попытку — и то, повезёт или нет, решает не игрок.

Что это

Плагин ставит на карту сундук в теме Лавкрафта и Ктулху: фиолетово-чёрная подсветка, кольцо частиц «дыхания дракона», луч в небо над обычным блоком CHEST. Магии в блоке нет — это ванильный сундук без подмены модели, эффект держит связка менеджера ивента, приват-зоны и лут-таблицы вокруг него. Сменить облик можно только ресурспаком; поле custom-model-data в конфиге под это зарезервировано, но в коде не используется — конфиг сам предупреждает об этом комментарием.

Сундук появляется сам по таймеру или мгновенно по команде и ждёт, пока его не откроют единственно верным способом — Сферическим ключом. Плагин собран под Paper 1.19.4; автором в plugin.yml значится Виталий.

Механика ключа

Ключ должен лежать именно в основной руке: код всегда проверяет getItemInMainHand() и не смотрит в оффхенд — если ключ лежит там, клик по сундуку его не засчитает. Сам ключ — не название и не текстура, а метка внутри предмета: PersistentDataContainer с ключом spherechest:sphere_key. Переименовать в наковальне случайный tripwire hook и выдать его за ключ не выйдет — детектор проверяет именно PDC-метку, а не имя или lore.

Правый клик по ивент-сундуку никогда не открывает ванильный интерфейс — плагин отменяет это всегда, даже без ключа: игрок получает только сообщение «нужен Сферический ключ», заглянуть внутрь до вскрытия нельзя. С ключом происходит бросок: ключ тратится всегда, вне зависимости от исхода — из стопки снимается одна штука, а если он был последним, рука пустеет. И только после списания решается, повезло или нет: шанс задаёт event.unlock-chance (по умолчанию 0.25, то есть 25%).

Полный цикл ивента

Всё отсчитывается от паузы между ивентами — event.interval-minutes, по умолчанию 120 минут, считая не от анонса, а от момента, когда предыдущий ивент реально завершился (вскрытием или истечением). Точка следующего спавна выбирается сразу, в начале паузы, — сервер 105 минут молчит, прежде чем о ней объявить.

  • За 15 минут (announce.lead-minutes) до появления — первый бродкаст на весь сервер с координатами и временем ожидания.
  • Дальше — два обновления таймера с шагом announce.update-minutes (по умолчанию 5 минут): на отметках «10 минут» и «5 минут» до появления.
  • По истечении 15 минут сундук встаёт в точке, выбранной ещё в начале паузы.
  • Точка спавна — случайная в квадрате вокруг центра (spawn.center-x/z), а не в круге: смещение по X и Z независимо в пределах ±spawn.radius (по умолчанию 200) — то есть зона 400×400 блоков, а не круг радиусом 200 (в коде это прямо помечено как упрощение). Высота — верхний непустой блок колонны плюс один, так что на воде сундук встанет прямо на глади.
  • Окно на вскрытие — event.duration-minutes, по умолчанию 60 минут. Ключ можно пробовать сколько угодно раз, сколько угодно разным игрокам: лимита на попытки или кулдауна между ними нет.
  • Каждая попытка — независимый бросок с шансом event.unlock-chance (по умолчанию 25%).
  • Успех — сундук мгновенно наполняется лутом и открывается победителю, приват снимается в ту же секунду, но блок стоит ещё cleanup.after-open-seconds (по умолчанию 300 секунд, 5 минут) — время досмотреть добычу.
  • Если 60 минут прошли, а вскрыть не удалось, сундук пропадает сам, сервер получает сообщение о неудаче, и пауза до следующего ивента отсчитывается заново.

Голограмма над сундуком (нужен DecentHolograms) показывает статус: в ожидании — обратный отсчёт через %time%, пока сундук активен — подсказку использовать ключ. Нюанс: висит она не над будущей точкой спавна, а над центром зоны (spawn.center-x/z) — это постоянный ориентир, а не подсказка, куда бежать.

Лут: типы записей, веса, что выпадает

Успешное вскрытие заполняет сундук: инвентарь сначала очищается, затем по loot-slots (по умолчанию 12, диапазон 1–27) идёт столько же взвешенных бросков по всей таблице. Одна и та же запись может выпасть несколько раз подряд, другая — ни разу. Предметы ложатся не подряд слева направо, а в заранее перемешанный список из 27 ячеек — по паре первых слотов не угадать, что попалось.

Записи трёх типов. material — обычный предмет с диапазоном количества (min–max). command — консольная команда с подстановкой %player%, которая не занимает слот вообще: эффект приходит игроку напрямую, в обход инвентаря. key — ещё один Сферический ключ, кладётся как обычный предмет. Отсюда момент: если среди 12 бросков несколько раз выпадет command-запись, физических предметов в сундуке окажется меньше двенадцати — команда «съедает» бросок, но не слот.

ЗаписьКатегорияВесШанс за бросок
sphere give coreСфера, пустой корпус30~12%
sphere give randomСфера со случайным эффектом20~8%
Сферический ключКлюч10~4%
Алмаз ×1–3Ценное15~6%
Изумруд ×1–4Ценное12~5%
Зачарованное золотое яблокоЦенное, редкое3~1%
Золотое яблоко ×1–2Ценное10~4%
Бутылка опыта ×5–20Ценное20~8%
Гнилая плоть ×2–8Тематический «мусор»25~10%
Кость ×2–6Тематический «мусор»20~8%
Нить ×3–10Тематический «мусор»18~7%
Отравленный картофель ×1–3Тематический «мусор»15~6%
Слиток железа ×2–8Тематический «мусор»25~10%
Слиток золота ×1–4Тематический «мусор»18~7%

Показательная деталь конфига: слитки железа и золота лежат в том же блоке комментариев, что гнилая плоть и картофель, — «тематический мусор». На фоне алмазов и сфер это балласт, не награда. Список, веса и loot-slots — обычные поля, набор из поставки лишь пример.

Звук, свет и огласка — три разных радиуса

Кольцо из 24 точек «дыхания дракона» вращается вокруг сундука, луч END ROD тянется на 30 блоков вверх — оба эффекта, как все частицы в Minecraft, видны только вблизи и дальностью не настраиваются. А вот три канала оповещения — чат, звук и титул — работают на разных радиусах, и это не всегда очевидно из простого описания ивента.

  • Чат. Анонсы, обратный отсчёт, победа и истечение времени идут через серверный бродкаст — на весь сервер целиком, включая другие миры, а не только spawn.world.
  • Звук. Рёв дракона при спавне и звон удачи при вскрытии звучат для каждого игрока в том же мире, что и сундук, — вне зависимости от расстояния: звук проигрывается у координат самого слушателя, а не сундука, так что затухания по дистанции нет вовсе.
  • Титул на экране. Единственный эффект с настоящим радиусом: заголовок с координатами при спавне получают только игроки в пределах effects.title-radius (по умолчанию 80 блоков) от точки появления.

Отсюда заметная асимметрия именно в провале попытки. Текст о неудаче («ключ рассыпался в прах») видит только сам неудачник — приватным сообщением, без бродкаста в чат. Но вопль эндермена в этот момент слышит весь мир целиком, а не только тот, кто стоит у сундука: крик разлетается по всей карте анонимно, и лишь игроки поблизости увидят своими глазами, кто именно попытал удачу и остался ни с чем.

Связь с CloudSpheres

Часть добычи — не предмет, а команда, которую плагин выполняет от консоли сервера следующим тиком после удачного броска. По умолчанию в таблице две такие записи: sphere give %player% core (пустой корпус сферы без эффекта, вес 30) и sphere give %player% random (случайная сфера со случайным эффектом, вес 20) — вместе около пятой части всех бросков лут-таблицы. %player% подставляется автоматически на ник вскрывшего, команда обходит инвентарь сундука полностью — сфера прилетает игроку напрямую через плагин Spheres.

Показательно, что сам CloudSpheres нигде не заявлен зависимостью — ни жёсткой, ни мягкой: в softdepend плагина числятся только WorldEdit и DecentHolograms. CloudSphereChest просто вызывает команду sphere по имени, полагаясь, что она где-то зарегистрирована; если CloudSpheres не установлен, консоль получит ошибку неизвестной команды, а остальной ивент отработает как ни в чём не бывало — сфера просто не долетит. Получается витрина-компаньон: сферы попадают в оборот не тихой строчкой в меню выдачи, а разовым событием — хотя связка между плагинами держится на честном слове конфига, не на зависимости.

Зона и защита

Приват — куб вокруг блока сундука, сторона которого зависит от region.size (по умолчанию 15). Считается через полуразмер: size ÷ 2 с округлением вниз (15 ÷ 2 = 7), а куб — ±7 блоков по всем осям от сундука, то есть 15×15×15 при значении по умолчанию. Нечётное число даёт ребро ровно таким же; чётное — всегда на блок больше (14 и 15 дают одинаковый куб, 16 — уже 17×17×17).

Внутри куба ProtectionListener блокирует разрушение и установку блоков, клики (кроме самого сундука — тем занимается отдельный листенер), вёдра, а из взрывов — блочных и от существ — вычёркивает задетые блоки из списка на снос, не отменяя взрыв целиком. Право spherechest.bypass (по умолчанию у op) снимает все запреты.

Защита не висит постоянно: включается ровно в момент появления блока и снимается сразу при завершении ивента. В фазе анонса (те 15 минут) её ещё нет — строить или ломать в будущей точке спавна можно свободно. После успеха — обратная картина: приват снимается мгновенно, а блок остаётся ещё cleanup.after-open-seconds (300 секунд по умолчанию) — всё это время это обычный, незащищённый сундук, который можно и разбить, а не только докрыть кликом. Несколько минут после победы — честная гонка за тем, что не забрал победитель.

Как провести: сценарии

  • Фоновый цикл на автопилоте. Оставить event.auto-enabled: true и не трогать — плагин сам держит ритм: анонс, спавн, час на вскрытие, пауза, по кругу. Стоит заранее сверить центр и радиус зоны спавна, чтобы точка не улетела в океан или за границы обжитой территории: высота берётся по верхнему блоку колонны, а это может быть и вода. Центр — заодно точка, над которой висит голограмма ожидания.
  • Ивент здесь и сейчас. /spherechest start без координат — мгновенный спавн в случайной точке зоны, минуя 15-минутный анонс. /spherechest start 250 -400 — то же самое, но в конкретной точке: например, у только что отстроенной локации или посреди отдельного события. Если в этот момент уже шла фаза ожидания автоивента, ручной запуск сбрасывает её расписание — второй сундук поверх первого не встанет, плагин откажет и попросит сперва stop.
  • Ключ как приз. /spherechest key ИмяИгрока 3 выдаёт ключи в обход обычной находки сундука — удобная награда за отдельный конкурс: игрок получает не гарантированный лут, а именно попытки, каждая всё равно с тем же шансом 25%, так что элемент риска остаётся даже в подарке.
  • После ручной остановки — не забыть про автоцикл. /spherechest stop глушит текущий ивент и вместе с ним весь таймер автозапуска: следующий цикл сам не подхватится, потому что пересчёт паузы прописан только в точках «успех» и «истёк срок», а не в ручной остановке. Чтобы вернуть автопилот, нужно либо довести до конца ещё один ивент — любым исходом, оба варианта сами перезаведут таймер, — либо перезагрузить плагин или сервер.

Команды

КомандаЧто делает
/spherechest start [x z]Запустить ивент мгновенно — с указанными координатами или в случайной точке зоны
/spherechest stopПринудительно завершить активный ивент (и заодно заглушить автотаймер, см. сценарии выше)
/spherechest reloadПеречитать конфиг и лут-таблицу без рестарта сервера
/spherechest key <игрок> [n]Выдать игроку Сферический ключ (по умолчанию один, максимум 64 за раз)
/spherechest infoСтатус: активен ли сундук, его точка и мир, сводка по региону, включён ли автоивент, текущий шанс вскрытия

Короткие алиасы — /sc и /schest. Пример: /sc key Виталий 5 выдаст пять ключей игроку Виталий, а /sc start 100 -50 поставит сундук на X=100 Z=−50 — высота посчитается по рельефу. Без аргументов команда печатает список подкоманд. Все подкоманды, включая info, требуют право spherechest.admin — без него плагин откажет ещё до разбора аргументов.

Стоит помнить, что info в режиме ожидания не считает реальное время до следующего спавна — команда лишь отсылает свериться с event.interval-minutes в конфиге. Живой обратный отсчёт по %time% показывает только голограмма, если стоит DecentHolograms.

Права

  • spherechest.admin — доступ ко всем подкомандам /spherechest (по умолчанию — у op)
  • spherechest.bypass — игнорирует приват-защиту зоны вокруг сундука, пока ивент активен (по умолчанию — у op)

Настройка и совместимость

Плагин собран под Paper 1.19.4 (api-version: "1.19"). DecentHolograms не обязателен, но включает голограмму-таймер, если стоит, — плагин сам проверяет её наличие при старте. WorldEdit числится мягкой зависимостью в plugin.yml, но в коде не вызывается — историческая заготовка. Оба не нужны, чтобы ивент запускался и работал целиком.

В конфиге меняется почти всё, что видит игрок: event (авто-запуск, интервал, шанс, длительность), spawn (мир, центр, радиус зоны), announce (когда и как часто анонс), region (размер приват-куба), cleanup (время после вскрытия), key (материал, имя, lore ключа), loot-slots и loot (сама таблица), effects (голограмма, частицы, звуки на фазу, радиус и текст титула). В java-полях кэшируются только размер региона и лут-таблица — их явно пересобирает reload; остальное читается из конфига на лету, так что один /spherechest reload обновляет всё разом, без рестарта.

Лицензионная проверка встроена так же, как у прочих плагинов Cloud Delight, и стоит первой строкой при запуске плагина — раньше инициализации любых менеджеров. При license.enabled: true плагин шлёт POST на license.url с ключом и именем плагина, ждёт ответ до 5 секунд; если сервер лицензий недоступен или отвечает ошибкой — в ход идёт локальный кэш в папке плагина, но не дольше license.grace-hours (по умолчанию 24 часа) с последней успешной проверки. Явный отказ сервера — ключ неверен, занят другим IP, отозван — отключает плагин сразу, без грейс-периода. Для приватного сервера защита выключается одной строкой: license.enabled: false.

CloudSphereChest превращает обычный лут в событие на весь сервер: анонс, обратный отсчёт, честный риск потерять ключ впустую — и добыча тому, кто добежал и рискнул первым.