Перейти к содержимому

CloudWorks API

CloudWorks API — это открытый приватный API для модов DrownedCloud. Предоставляет разработчикам ряд полезных функций.

NeoForge
Загрузчики
NeoForge
Скачиваний на Modrinth
5,1 тыс.
Подписчиков на Modrinth
1
версии
4
Обновлён
8 августа 20268 авг.
Опубликован
в 2026
Это библиотека — она нужна другим модам и сама ничего не добавляет в игруНужна 1 модам. Скачайте её, если этого требует другой мод.

Коротко о моде

Библиотека — нужна другим модам: её требуют 1
Работает на NeoForge
Для Minecraft 1.21.1
Нужен и в игре, и на сервере
Последняя версия — 1.1.0 от 8 августа 2026
Лицензия GPL-3.0-or-later — бесплатно
Где нужен
В игреобязателенНа сервереобязателен

Нужен и в игре, и на сервере

Версии игры1.21.1
Описание переведено автоматическиПоказать оригинал (EN)

CloudWorks API

Универсальный интерфейс для разработки модов — предоставляет стандартизированные возможности для модов на NeoForge 1.21.1, включая систему прочных блоков, парсинг рецептов и захват логов консоли.

Версия: 1.1.0-1.21.1 | Платформа: NeoForge 1.21.1 | Java 21


Содержание

  1. Быстрый старт
  2. DurableBlock — система прочных блоков
  3. RecipeParser — парсинг рецептов
  4. ConsoleSeeker — захват логов консоли
  5. Отладочные команды
  6. Архитектура модулей
  7. Лицензия

Быстрый старт

Добавление зависимости

Добавьте следующее в ваш build.gradle:

repositories {
    maven { url = 'https://your-maven-repo' }
}

dependencies {
    implementation 'com.cloudworks:CloudWorksAPI:1.1.0-1.21.1'
}

Опциональная зависимость: интеграция с модом Jade

Если вам нужен показ прочности прочных блоков через Jade, добавьте зависимость Jade API:

repositories {
    maven { url = "https://api.modrinth.com/maven" }
}

dependencies {
    compileOnly "maven.modrinth:jade:15.10.5+neoforge"
}

Включение модулей

CloudWorks API использует аннотации для активации модулей по требованию. Добавьте соответствующую аннотацию к вашему главному классу мода:

@Mod("your_mod_id")
@CloudworksRecipeParser       // Включает модуль RecipeParser
@CloudWorksConsoleSeeker      // Включает ConsoleSeeker + API
public class YourMod {
    public YourMod(IEventBus modEventBus) {
        // ...
    }
}
  • С аннотацией: принудительно включает модуль, игнорируя переключатель в конфиге
  • Без аннотации: управляется через конфиг
  • Каждый модуль можно независимо включать/отключать, они не зависят друг от друга

DurableBlock — система прочных блоков

Основная идея

DurableBlock предоставляет полноценную систему прочных блоков, позволяющую блокам иметь значения прочности, сопротивление урону и автоматическое восстановление.

В отличие от традиционных решений, эта система не полагается на BlockEntity. Вместо этого она использует подкласс LivingEntity (DurableBlockEntity) для хранения данных о прочности и получения урона. Такая архитектура сочетает сохранение данных BlockEntity с возможностью получать атаки, как у LivingEntity.

Архитектура

DurableBlock (Block)
    │ Создаёт сущность при установке
    │ Свойства: maxDurability, baseResistance, сопротивления по типам
    ▼
DurableBlockEntity (LivingEntity)
    │ Сущность только на сервере (clientTrackingRange=0)
    │ Привязана к координатам блока (boundPos), каждый тик проверяет существование блока
    │ Расчёт прочности, обработка урона, сохранение в NBT
    │
    ├── Обычный поток: прочность достигает нуля → блок ломается → сущность самоуничтожается
    └── PersistentDurableBlockEntity (подкласс)
            └── Защита от читерского убийства: перехватывает атаки с мгновенным убийством → потеря 20% прочности

Основные классы

КлассОтветственность
DurableBlockБазовый класс прочного блока, задаёт атрибуты прочности и параметры сопротивления, управляет созданием сущности
DurableBlockEntityЗамена блок-энтити (LivingEntity), обрабатывает урон, расчёт прочности, сохранение данных
PersistentDurableBlockПостоянный прочный блок, расширяет DurableBlock, использует PersistentDurableBlockEntity
PersistentDurableBlockEntityПостоянная сущность, перехватывает атаки с мгновенным убийством, преобразует их в потерю прочности
DurableBlockDamageTypeПеречисление типов урона (EXPLOSION / PHYSICAL / MAGIC)

Использование

Базовый прочный блок
public class MyConcreteBlock extends DurableBlock {
    public MyConcreteBlock() {
        super(Properties.of()
                .strength(3.0f)
                .requiresCorrectToolForDrops(),
            200,    // maxBlockDurability: Максимальная прочность
            2,      // baseResistance: Плоское снижение урона
            0.3f,   // explosionResistance: Снижение урона от взрывов (0.0 ~ 1.0)
            0.5f,   // physicalResistance: Снижение физического урона (0.0 ~ 1.0)
            0.1f,   // magicResistance: Снижение магического урона (0.0 ~ 1.0)
            0       // recoveryRate: Автовосстановление в секунду (0 = нет)
        );
    }
}

#### Persistent Durable Block (with Code Game Protection)

```java
public class MyPersistentBlock extends PersistentDurableBlock {
    public MyPersistentBlock() {
        super(Properties.of().strength(3.0f),
            200, 2, 0.3f, 0.5f, 0.1f, 0);
    }
}

Расчёт урона

actualDamage = max(0, rawDamage - baseResistance) × (1 - typeResistance)
  1. Базовое сопротивление: Плоское снижение сырого урона (минимум 0)
  2. Сопротивление типу: Применяет соответствующий коэффициент снижения в зависимости от типа урона (взрыв/физический/магический)
  3. Классификация типов урона:

    • Взрыв: TNT, криперы, кристаллы Края, взрывы кровати/якоря возрождения
    • Физический: Атаки в ближнем бою, стрелы, трезубцы, снаряды
    • Магический: Зелья, дыхание дракона, эффект иссушения, урон от пустоты, огонь/молния

Сущность только на стороне сервера

Сущности прочных блоков регистрируются с clientTrackingRange(0), то есть сущность существует только на сервере. Клиент ничего не знает о её существовании. Это даёт следующие преимущества:

  • Игроки не могут атаковать сущность в ближнем бою: На стороне клиента нет цели; блок можно только сломать
  • Не мешает взаимодействию с блоками: Не препятствует установке блоков сверху или добыче левым кликом
  • Атаки мобов и дальние атаки работают как обычно: Иссушители, зомби и дальние атаки по-прежнему могут наносить урон сущности на сервере
  • Синхронизация не нужна: Нет проблем с синхронизацией данных сущности между клиентом и сервером

Code Game Protection (Persistent)

PersistentDurableBlockEntity использует многослойный механизм перехвата для защиты от атак мгновенного убийства:

  1. Перехват remove(): Проверяет флаг internalRemoval; внешние вызовы вместо этого вызывают потерю 20% прочности
  2. Перехват setHealth(): Предотвращает обнуление здоровья извне
  3. Перехват setPose(): Предотвращает состояние Pose.DYING
  4. Обнаружение в hurt(): Проверяет тег instant_kill_weapon, отменяет события урона от оружия мгновенного убийства
  5. Коррекция состояния dead: Проверяет и исправляет поле dead каждый тик
  6. Кадры неуязвимости: 3 тика неуязвимости после каждого попадания, ограничивая попадания до 5 в секунду

Тег оружия мгновенного убийства

Тег предметов cloudworks_api:instant_kill_weapon помечает оружие мгновенного убийства. Когда сущность с предметом из этого тега атакует, PersistentDurableBlockEntity напрямую отменяет событие урона.

Содержимое по умолчанию:

{
  "values": [
    "avaritia:infinity_sword"
  ]
}

Авторы сборок могут добавлять больше оружия в этот тег через датапак.

Управление жизненным циклом

  • Установка блока: DurableBlock.setPlacedBy() создаёт сущность на позиции блока
  • Разрушение блока: Сущность больше не удаляется событиями разрушения блока; она сама управляет своим жизненным циклом
  • Проверка каждый тик: Сущность каждый тик проверяет, существует ли ещё её привязанный блок; если нет — самоуничтожается
  • Истощение прочности: onDurabilityZero() ломает блок и удаляет сущность
  • Сохранение в NBT: Данные прочности сохраняются в чанки через addAdditionalSaveData / readAdditionalSaveData

Механизм привязанной позиции

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

Интеграция с модом Jade

DurableBlock включает встроенную интеграцию с Jade (DurableBlockJadePlugin), которая отображает информацию о прочности блока в подсказках Jade:

  • Показывает Durability: current / max строкой ниже названия блока
  • Текущая прочность отображается с 2 знаками после запятой
  • Поскольку сущность использует подход только на стороне сервера, данные о прочности собираются на сервере через IServerDataProvider и синхронизируются с клиентом через пакеты данных Jade

Дизайн хитбокса

Хитбокс сущности — 1.02×1.02 (чуть больше блока 1×1), центрирован по центру блока (y+0.5), выступает на 0.01 блока со всех шести сторон. Это позволяет мобам атаковать сущность с любой стороны, при этом сущность не мешает установке блоков или передвижению.


RecipeParser — Парсинг рецептов

Основные концепции

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

Recipe JSON  -->  serializeRecipe()  -->  JsonElement
                                              |
                                              v
DSL Template (.rpml)  -->  TemplateParser  -->  TemplateNode (AST)
                                              |
                                              v
                              RecipeExtractor.extract()
                                              |
                                              v
                                       RecipeData
                                   (Ingredient[], Product[])
  1. Сериализация: сериализовать рецепт в JSON через Minecraft Codec
  2. Парсинг шаблона: распарсить DSL-шаблон .rpml в AST
  3. Извлечение данных: извлечь структурированные данные из JSON согласно AST

Основные классы

КлассОтветственность
RecipeParserСинглтон-ядро, управляет загрузкой шаблонов, парсингом рецептов и переносом жидкостей
RecipeParserAPIСтатический фасадный класс, предоставляет все API наружу
RecipeDataРезультат парсинга, содержит inputs и outputs
IngredientВходной материал: id, count, unit, type
ProductВыходной продукт: id, count, unit, type, rate (вероятность)

Справочник по API

Все API вызываются через статические методы RecipeParserAPI.

Базовые запросы
МетодОписание
getRecipeData(ResourceLocation, RecipeManager)Распарсить один рецепт
getRecipeDataBatch(Collection, RecipeManager)Пакетный парсинг рецептов
isRecipeParsable(ResourceLocation, RecipeManager)Проверить, можно ли распарсить рецепт
getParsableRecipes(String modId, String recipeType, RecipeManager)Получить все парсируемые рецепты заданного типа
Расширенные запросы
// Найти рецепты, производящие цель
List<RecipeParseResult> parseProduceRecipe(
    ResourceLocation targetId,  // ID целевого предмета/жидкости
    QueryMode mode,             // ITEM или FLUID
    RecipeManager recipeManager
)

// Найти рецепты, использующие цель как вход
List<RecipeParseResult> parseUsageRecipe(
    ResourceLocation targetId,
    QueryMode mode,
    RecipeManager recipeManager
)
modeЛогика сопоставления (produce)Логика сопоставления (usage)
ITEMСовпадает с прямым выходом + переносом жидкость→предметСовпадает с ингредиентами, где unit=item
FLUIDСовпадает с выходами жидкостей + обратным переносомСовпадает с ингредиентами, где unit=fluid
Асинхронные методы API

Все асинхронные API вызываются через статические методы RecipeParserAPI. Тяжёлая работа по сканированию и парсингу рецептов выполняется на выделенных рабочих потоках (пул потоков AsyncRecipeParser, 2 демон-потока), а результаты возвращаются в серверный поток через колбэк MinecraftServer.

RecipeParserAPI.parseProduceRecipeAsync(
    ResourceLocation.parse("minecraft:oak_planks"),
    QueryMode.ITEM,
    recipeManager,
    results -> {
        // Этот колбэк выполняется в серверном потоке -- безопасно манипулировать объектами Minecraft
        for (RecipeParseResult r : results) {
            sendSuccess("Found recipe: " + r.getRecipeId());
        }
    },
    errorMsg -> sendFailure("Query failed: " + errorMsg),
    server
);

Сигнатуры асинхронных методов:

| Метод | Описание |
|---|---|
| `getRecipeDataAsync(id, mgr, cb, err, server)` | Асинхронно разбирает один рецепт |
| `getRecipeDataBatchAsync(ids, mgr, cb, err, server)` | Асинхронно разбирает рецепты пакетом |
| `parseProduceRecipeAsync(id, mode, mgr, cb, err, server)` | Асинхронно ищет рецепты производства |
| `parseUsageRecipeAsync(id, mode, mgr, cb, err, server)` | Асинхронно ищет рецепты использования |

#### Модели данных

**Ingredient**

| Поле | Тип | Описание |
|---|---|---|
| `id` | `String` | ID предмета/жидкости/тега |
| `count` | `double` | Количество |
| `unit` | `String` | `"item"` / `"fluid"` |
| `type` | `String` | `"solid"` / `"tag"` / `"fluid"` |

**Product**

| Поле | Тип | Описание |
|---|---|---|
| `id` | `String` | ID продукта |
| `count` | `double` | Количество |
| `unit` | `String` | `"item"` / `"fluid"` |
| `type` | `String` | `"solid"` / `"tag"` / `"fluid"` |
| `rate` | `double` | Вероятность выпадения (0.0 ~ 1.0, по умолчанию 1.0) |

### Шаблоны рецептов DSL

Шаблоны рецептов (файлы `.rpml`) находятся в `cloudworks/recipe_parser/templates/`, именуются в формате `{modid}_{recipetype}.rpml`.

#### Типы маркеров

| Маркер | Синтаксис | Описание |
|---|---|---|
| `input` | `<input,id=foo,count=1,unit=item,type=solid>` | Объявляет входной ингредиент |
| `output` | `<output,id=bar,count=1,unit=item,type=solid>` | Объявляет выходной продукт |
| `object` | `<object,id=myObj>` | Объявляет узел JSON-объекта |
| `key` | `<key,id=myKey>` | Динамический обход ключей JSON |
| `io_attribute` | `<count,output_id=bar>` | Внедряет атрибуты в маркеры |
| `symbol` | `<symbol,id=sym,input_id=keyIng>` | Объявляет символ для shaped-крафта |
| `patternline` | `<patternline,id=line>` | Объявляет строку шаблона для shaped-крафта |
| `duplicate` | `<duplicate,id=dupX,structure=X>` | Объявляет повторяемую структуру JSON-объекта |
| `script` | `<script,set_global_fluid_transfer=true>` | Скрипт глобальных настроек |
| `optional` | `<optional,id=opt>` | Необязательное поле |
| `variable` | `<variable,id=var>` | Ссылка на переменную |

#### Примеры шаблонов

**Ванильный верстак (shaped)**

```json
{
  "type": "minecraft:crafting_shaped",
  <script,set_global_fluid_transfer=true,set_global_default_transfer_rate=250>
  "pattern": [
    <patternline,id=line>
  ],
  "key": <object,id=keyObj>
    <key,id=key>
      <object,id=keyIng>
        "item": <input,id=keyIng,count=1,unit=item,type=solid>
        "tag": <input,id=keyIng,count=1,unit=item,type=tag>
      <symbol,id=sym,input_id=keyIng>
    <count,id=keyIng_count,input_id=keyIng>
    <patternline,id=line,input_id=sym>
  "result": <object,id=res>
    "count": <count,output_id=res>
    "id": <type,output_id=res>
    "item": <output,id=res,count=1,unit=item,type=solid>

Ванильный верстак (shapeless)

{
  "type": "minecraft:crafting_shapeless",
  "ingredients": [
    <object,id=ingStruct>
      "item": <input,id=ingItem,count=1,unit=item,type=solid>
      "tag": <input,id=ingItem,count=1,unit=item,type=tag>
    <count,id=ingCount,input_id=ingItem>
    <duplicate,id=ingStruct>
  ],
  "result": <object,id=res>
    "count": <count,output_id=res>
    "id": <type,output_id=res>
    "item": <output,id=res,count=1,unit=item,type=solid>

Перевод жидкости в предмет

Когда рецепт выдаёт жидкость, её можно преобразовать в эквивалентный предмет — тогда рецепт можно будет найти и по ID предмета.

Логика перевода: Всего жидкости (mB) ÷ rate → округление (по стратегии округления) × количество продукта за единицу

Глобальные настройки (задаются через `

ПараметрТипПо умолчаниюОписание
global_fluid_transferbooleanfalseВключён ли перевод жидкости в предмет
global_default_transfer_ratedouble100Сколько mB переводится в 1 предмет
global_default_transfer_resultstringnullID предмета-результата перевода по умолчанию
global_default_transfer_extra_inputmap{}Дополнительные ингредиенты
global_default_transfer_float_roundenumdefaultround_up / round_down / default
global_enable_template_configbooleantrueВключены ли внешние файлы конфигурации шаблонов

Конфиг на уровне рецепта (cloudworks/recipe_parser/templates_config/{modid}_{recipetype}.json):

{
  "recipe:id": {
    "enable_transfer": true,
    "transfer_blacklist": ["fluid:to_skip"],
    "methods": [{
      "rate": 100,
      "round": "default",
      "extra_input": {"minecraft:item": 1},
      "result": {"minecraft:output_item": 2}
    }]
  }
}

Механизм обновления шаблонов

cloudworks/recipe_parser/config.json:

{
  "version": "1.1.0-1.21.1",
  "enable_update": true,
  "force_update": false,
  "update_ignore": ["minecraft_crafting.rpml"]
}
  • force_update=true → Пропустить все проверки, выпустить все файлы
  • enable_update=false → Пропустить обновление
  • version совпадает → Пропустить обновление
  • Иначе → Обновить версию, выпустить файлы, кроме тех, что в update_ignore

ConsoleSeeker — захват консольных логов

ConsoleSeeker выводит консольные логи в игровой чат в реальном времени и предоставляет полный конвейер событий, чтобы другие моды могли фильтровать и обрабатывать логи.

Включение

@CloudWorksConsoleSeeker  // Принудительно включает ConsoleSeeker + API

Или настройте в cloudworks/console_seeker/config.json:

{
  "enable_module": true,
  "enable_api": false,
  "enable_command_for_any_operator": true,
  "list_type": "whitelist",
  "player_list": [],
  "max_log_length": 150,
  "enable_timestamp": false
}
ПолеТипПо умолчаниюОписание
enable_modulebooleantrueВключать ли модуль ConsoleSeeker
enable_apibooleanfalseВключать ли API событий (аннотации переопределяют это)
enable_command_for_any_operatorbooleantrueРазрешать ли всем операторам использовать команды
list_typestring"whitelist""whitelist" / "blacklist"
player_liststring[][]Список имён игроков
max_log_lengthint150Максимальная длина лога (0 = без обрезки)
enable_timestampbooleanfalseПоказывать ли метки времени

Архитектура

Log4j2 Logger
    │
    ▼
ChatAppender (Log4j2 Appender)
    │ Фильтрует подстроку [CHAT]
    ▼
LogToChatManager
    │ Фильтрует по уровню лога и подписке игрока
    ▼
ConsoleSeekerEventManager
    │ Внутренние фильтрующие блоки → собирает tagSet
    ▼
NeoForge EVENT_BUS
    │ Рассылает ConsoleSeekerInfoEvent / WarnEvent / ErrorEvent
    ▼
ExternalLogFilter (подписывается другими модами)
    │ Сопоставляет tagSet → parse() → onReceive()
    ▼
Пользовательская логика других модов

Конвейер событий

Три независимых конвейера событий для разных уровней логов:

Класс событияУровень лога
ConsoleSeekerInfoEventINFO
ConsoleSeekerWarnEventWARN
ConsoleSeekerErrorEventERROR

Все события наследуются от ConsoleSeekerLogEvent со следующими полями:

ПолеТипОписание
loggerNameStringИмя логгера
levelLevelУровень лога
messageStringОтформатированное сообщение (ANSI-коды цвета удалены)
timestamplongUnix-время (миллисекунды)
threadNameStringИмя потока
thrownStringStringТрассировка стека исключения (null, если исключения нет)
tagSet`Set`Набор тегов направленной доставки

Внутренние фильтры (активная фильтрация)

Регистрируйте внутренние фильтрующие блоки через ConsoleSeekerEventManager, чтобы ConsoleSeeker активно фильтровал логи:

// Реализуйте интерфейс InternalFilterUnit
InternalFilterUnit myUnit = new InternalFilterUnit() {
    public DirectedDeliveryTag getTag() {
        return new DirectedDeliveryTag("mymod", "cpu_alert");
    }
    public boolean test(LogEvent event) {
        return event.getLoggerName().startsWith("com.example");
    }
};

// Зарегистрируйте во списке внутренних фильтрующих блоков
ConsoleSeekerEventManager.addInternalFilterUnit(myUnit);

**Правила фильтрации**:
- Пустой список → все события лога публикуются напрямую, tagSet пуст
- Непустой список → хотя бы один юнит должен пройти для публикации; собирает теги из прошедших юнитов в tagSet
- Все юниты не прошли → событие отбрасывается

### Теги направленной доставки

Использует формат `"modid:tagName"` для предотвращения конфликтов между модами:

```java
// Создать тег
DirectedDeliveryTag tag = new DirectedDeliveryTag("mymod", "cpu_alert");

// Правила сопоставления: пустой тег совпадает со всем, непустой тег требует точного совпадения
tag.matches(otherTag);

Внешние фильтры (пассивная фильтрация)

Моды-потребители расширяют `ExternalLogFilter` для кастомного парсинга логов:

public class MyCpuFilter extends ExternalLogFilter<Integer> {
    public MyCpuFilter() {
        super(new DirectedDeliveryTag("mymod", "cpu_alert"));
    }

    @Override
    protected Integer parse(ConsoleSeekerLogEvent event) {
        // Кастомная логика парсинга
        return Integer.parseInt(event.getMessage());
    }

    @Override
    protected void onReceive(Integer value) {
        // Обработка результата парсинга
        System.out.println("CPU usage: " + value);
    }
}

// Зарегистрировать, чтобы начать получать события
MyCpuFilter filter = new MyCpuFilter();
filter.register();

Порядок работы:

  1. Сопоставить tagSet события с тегом фильтра (совпадение по пересечению, пустой набор тегов совпадает со всем)
  2. parse() преобразует сырое событие в кастомный тип (по умолчанию возвращает сырую строку лога)
  3. onReceive() обрабатывает результат парсинга

Команды отладки

Префикс команд: /cloudworks. Требуется OP-уровень 4 (для некоторых команд).

Модуль рецептов

/cloudworks recipe parse produce item [id]     — Найти рецепты, создающие указанный предмет
/cloudworks recipe parse produce liquid [id]   — Найти рецепты, создающие указанную жидкость
/cloudworks recipe parse usage item [id]       — Найти рецепты, использующие указанный предмет
/cloudworks recipe parse usage liquid [id]     — Найти рецепты, использующие указанную жидкость
/cloudworks recipe parsebatch <modid> <type>   — Пакетный парсинг
/cloudworks recipe listtemplates               — Список загруженных шаблонов

Модуль консоли

/cloudworks console <info|warn|error> <on|off>             — Переключить вывод логов в чат
/cloudworks config console player_list add <player_name>   — Добавить игрока в список
/cloudworks config console player_list remove <player_name> — Удалить игрока из списка
/cloudworks config console player_list query               — Просмотреть список игроков

Запрос статуса

/cloudworks status   — Просмотреть статус всех модулей

Вывод включает: количество шаблонов RecipeParser, включённые уровни ConsoleSeeker/статус API/количество юнитов фильтра.


Архитектура модулей

src/main/java/com/cloudworks/api/
├── CloudWorksAPI.java                    # Точка входа мода NeoForge
├── annotation/
│   ├── CloudworksRecipeParser.java       # Включает RecipeParser
│   └── CloudWorksConsoleSeeker.java      # Включает ConsoleSeeker
├── command/
│   └── DebugCommand.java                 # Единая точка входа отладочных команд
│
├── durableblock/                         # Модуль DurableBlock
│   ├── DurableBlock.java                 # Базовый класс прочного блока
│   ├── DurableBlockEntity.java           # Замена block entity (LivingEntity)
│   ├── PersistentDurableBlock.java       # Постоянный прочный блок
│   ├── PersistentDurableBlockEntity.java # Сущность защиты кода игры
│   ├── DurableBlockDamageType.java       # Перечисление типов урона
│   └── jade/
│       └── DurableBlockJadePlugin.java   # Плагин интеграции с модом Jade
│
├── recipeparser/                         # Модуль RecipeParser
│   ├── RecipeParser.java                 # Ядро-синглтон
│   ├── RecipeParserAPI.java              # Статический фасад API
│   ├── AsyncRecipeParser.java            # Асинхронный пул потоков
│   ├── ApiSelfTest.java                  # Автотест
│   ├── DebugOutputWriter.java            # Экспорт отладочного JSON
│   ├── dsl/                              # Движок шаблонов DSL
│   │   ├── Template.java, TemplateNode.java
│   │   ├── TemplateParser.java, TemplateTokenizer.java
│   │   ├── TemplateValidator.java, RecipeExtractor.java
│   │   ├── GlobalSettings.java, TemplateConfig.java
│   │   └── ...
│   └── model/                            # Модели данных
│       ├── RecipeData.java, Ingredient.java, Product.java
│       └── QueryMode.java, RecipeParseResult.java
│
└── consoleseeker/                        # Модуль ConsoleSeeker
    ├── ChatAppender.java                 # Appender Log4j2
    ├── LogToChatManager.java             # Менеджер вывода логов в чат
    ├── ConsoleSeekerConfig.java          # Управление файлом конфигурации
    ├── ConsoleSeekerEventManager.java    # Ядро конвейера событий
    ├── ConsoleSeekerCommand.java         # Обработчик команд
    ├── InternalFilterUnit.java           # Интерфейс внутреннего юнита фильтра
    ├── ExternalLogFilter.java            # Абстрактный класс внешнего фильтра
    ├── DirectedDeliveryTag.java          # Тег направленной доставки
    ├── LogFilter.java                    # Утилита логов (обрезка/удаление цвета)
    └── event/                            # Классы событий
        ├── ConsoleSeekerLogEvent.java     # Базовый класс события
        ├── ConsoleSeekerInfoEvent.java
        ├── ConsoleSeekerWarnEvent.java
        └── ConsoleSeekerErrorEvent.java

---

## Лицензия

Этот проект распространяется с открытым исходным кодом под лицензией GNU General Public License v3.0. Полный текст см. в [LICENSE](LICENSE).

CloudWorks API — Unified Mod Development Interface
Copyright (C) 2026 CloudWorks Team

Эта программа является свободным программным обеспечением: вы можете распространять её и/или изменять на условиях GNU General Public License, опубликованной Фондом свободного программного обеспечения, либо версии 3 лицензии, либо (на ваше усмотрение) любой более поздней версии.

Эта программа распространяется в надежде, что она будет полезной, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, даже без подразумеваемой гарантии ТОВАРНОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ. Подробности см. в GNU General Public License.

Вы должны были получить копию GNU General Public License вместе с этой программой. Если нет, см. <https://www.gnu.org/licenses/>.

Частые вопросы

Как установить CloudWorks API?

Установите NeoForge под свою версию Minecraft, скачайте CloudWorks API под ту же версию и загрузчик, положите файл в папку mods и запустите игру с профилем загрузчика.

Для каких версий Minecraft есть CloudWorks API?

У CloudWorks API есть сборки для Minecraft 1.21.1.

Нужен ли CloudWorks API на сервере?

Нужен и в игре, и на сервере

Лицензия и источник
GNU General Public License v3.0 or laterможно использовать и распространять; изменённые версии — под той же лицензией и с исходным кодом
Оригинал — Modrinth↗Файлы — без изменений, проверены по SHA-512Это ваш мод? Правообладателям

Сайт использует cookie: необходимые — для входа и темы, а также счётчики посещений Яндекс Метрика и LiveInternet — по ним мы видим, как пользуются сайтом. Рекламных cookie у нас нет. Подробнее