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

Formula Loader

Загрузка Json в Formula для моддеров и пользователей датапаков.

FabricNeoForgeForge
Загрузчики
FabricNeoForgeForge
Скачиваний на Modrinth
4,5 тыс.
Подписчиков на Modrinth
0
версий
37
Обновлён
18 июня 202618 июн.
Опубликован
в 2026
Это библиотека — она нужна другим модам и сама ничего не добавляет в игруНужна 1 модам. Скачайте её, если этого требует другой мод.
Benchmark — Time consumption of different formula categories in the JavaTest environment. Sufficient for gameplay. · свайп

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

Библиотека — нужна другим модам: её требуют 1
Работает на Fabric, NeoForge и Forge
Для Minecraft 1.20.1, 1.21.1–26.1.2 …
Нужен на сервере; в игре — по желанию
Последняя версия — 3.0.6 от 18 июня 2026
Лицензия LGPL-2.1-only — бесплатно
Где нужен
В игренеобязателенНа сервереобязателен

Нужен на сервере; в игре — по желанию

Версии игры1.19.2–1.19.4, 1.20.1, 1.21.1–26.1.2 …
Описание переведено автоматическиПоказать оригинал (EN)

Мод для разработчиков и создателей датапаков. Читает пользовательские формулы из JSON-файлов и вычисляет их с параметрами, переданными через игровую команду:

/formula <namespace:name> <parameters...>

или Java-метод.

Поддерживаемые операции

Арифметические операторы: +, -, *, /, % (остаток с округлением вниз: a - floor(a / b) * b)

Формулы с двумя аргументами: min(x, y), max(x, y), pow(x, y), log(x, y) (логарифм по основанию x от y), div(x, y) (деление с округлением вниз к минус бесконечности)

Формулы с одним аргументом: round(x), floor(x), ceil(x), abs(x), exp(x), trunc(x) (отбрасывание дробной части к нулю)

Тригонометрические формулы: sin(x), cos(x), tan(x), asin(x), acos(x), atan(x)

Особая — rem(x, y): возвращает остаток x - floor(x / y) * y и одновременно записывает частное floor(x / y) обратно в x. Учтите, что если написать #a = rem(#a, #b), присваивание #a = ... перезапишет частное, которое rem только что сохранил в #a, возвращаемым значением (остатком), так что в итоге #a будет содержать остаток, а не частное.

Унарный минус поддерживается без обязательных скобок: -3, -x, -min(a, b), 1 + -x — всё работает.

Производительность

Формулы предкомпилируются при загрузке в оптимизированную стековую байткод-виртуальную машину. Короткие формулы (4 операции или меньше) выигрывают от развёртки циклов и объединения супер-инструкций (например, бинарные операции переменная-переменная становятся едиными опкодами). Свёртка констант применяется на этапе компиляции. Бенчмарки на типичной настольной JVM:

  • Простая арифметика: ~9 нс на вычисление
  • Цепочка условий (3 ветки): ~15 нс на вычисление
  • Последовательные шаги (3 шага): ~14 нс на вычисление
  • Тригонометрия с округлением: ~40 нс на вычисление

На практике даже 3 миллиона вызовов завершаются менее чем за 120 мс. Производительность не вызывает беспокойства.

Установка на клиенте

Этот мод необязателен на клиенте. Если вам нужны только серверные вычисления, установка на клиенте не требуется. Если нужно отображать значения в элементах интерфейса, установите на клиент, чтобы формулы были доступны локально. Когда другой мод, требующий обе стороны (например, Tinkers' Armor Extension), глубоко интегрирует этот мод, он становится транзитивной зависимостью и тоже должен быть установлен на клиенте.

Для разработчиков

  1. Получайте загруженные формулы через FormulaManager.getOrNull(ResourceLocation) и вычисляйте с помощью formula.accept(double...).
  2. Используйте FormulaBuilder для программного построения JSON формул. Формулы загружаются из `data//formula/` при запуске.

Для создателей датапаков

Используйте команду /formula для вычисления формул с параметрами прямо в игре. Это заменяет вычисления на основе scoreboard, которые потребовали бы десятков команд, одним вызовом, значительно улучшая производительность и читаемость датапаков.

Справочник по формату JSON

Простая формула

{
    "inputs": ["result", "left", "right"],
    "formula": "#result = #left + #right * 2"
}

Последовательные шаги

{
    "inputs": ["a", "b", "c"],
    "formula": [
        "#a = #b + #c",
        "#b = #a * #c",
        "#a = #b + 1"
    ]
}

Ветвление if/else

{
    "inputs": ["score", "kills", "deaths"],
    "formula": {
        "if": "#kills > #deaths",
        "formula": "#score = #kills * 3 - #deaths * 2",
        "else": "#score = max(0, #kills - #deaths)"
    }
}

Цепочка условий (if / else-if / else)

{
    "inputs": ["result", "value"],
    "formula": {
        "chain": [
            {"condition": "#value >= 100", "formula": "#result = #value * 2"},
            {"condition": "#value >= 50",  "formula": "#result = #value * 1.5"},
            {"condition": "#value >= 10",  "formula": "#result = #value"}
        ],
        "default": "#result = 0"
    }
}

### Смешанная вложенность (последовательная + условная)

{ "inputs": ["result", "base", "modifier"], "caches": ["scaled"], "formula": [ "#scaled = log(2, #base + 1)", { "chain": [ {"condition": "#modifier > 10", "formula": "#result = #scaled * #modifier * 2"}, {"condition": "#modifier > 0", "formula": "#result = #scaled * #modifier"} ], "default": "#result = #scaled" } ] }


### Явный слот вывода

По умолчанию возвращается результат последнего шага. Используйте `"output"`, чтобы указать другую переменную:

{ "inputs": ["dummy", "x", "y"], "caches": ["tmp", "extra"], "output": "#extra", "formula": [ "#tmp = #x * #y", "#dummy = #tmp + #x", "#extra = #tmp * 2 + #y" ] }


### Числовой режим (сокращённый)

{ "input": 3, "cache": 2, "output": "#4", "formula": [ "#0 = #1 + #2", "#3 = #0 * #1", "#4 = #3 + #2" ] }


## FormulaBuilder — руководство для разработчика

`FormulaBuilder` — это fluent API для генерации JSON формул на Java. Он автоматически добавляет префикс `#` к именованным переменным.

### I. Быстрый старт

```java
// Именованные переменные — автоматический префикс #. "result = x + y" превращается в "#result = #x + #y"
String json = FormulaBuilder
    .inputs("result", "x", "y")
    .flat("result = x + y + 2")
    .build();

// Числовой режим — пишите # вручную
String json = FormulaBuilder
    .input(3)
    .flat("#0 = #1 + #2 + 2")
    .build();

II. Определение входов

// Именованные входы (рекомендуется) — автоматический префикс #
FormulaBuilder.inputs("result", "amount", "tick")

// Числовой вход — генерирует "input": 3; пишите #0, #1, #2 вручную
FormulaBuilder.input(3)

III. Определение кэшей (промежуточных переменных)

// Именованные кэши — автоматический префикс #
.caches("tmp1", "tmp2")    // генерирует "caches": ["tmp1","tmp2"]

// Числовые кэши — пишите #3, #4 вручную
.cache(2)                  // генерирует "cache": 2

IV. Поле вывода

.output("#result")    // указать, какую переменную возвращать
// Если опущено, возвращается результат последнего шага.

V. Формы формул

flat — одна строка формулы. Возвращает FormulaBuilder.

.flat("result = x + y + 2")

array — последовательные шаги. Каждый шаг может читать результаты предыдущих шагов. Возвращает FormulaBuilder.

.array(
    "a = b + c",
    "b = a * 2"
)

ifelse — сокращение для одного if/else. Возвращает FormulaBuilder.

.ifelse(
    "kills > deaths",           // условие
    "score = kills * 3",        // ветка если истина
    "score = deaths"            // ветка иначе
)
mixed() — входит в `MixedBlock

. Записи выполняются последовательно и могут включать плоские формулы, встроенные условия и вложенные блоки. Вызовите .exit(), чтобы вернуться в родительский контекст (параметр типа P`).

b.inputs("a", "b").mixed()
    .flat("a = b + 1")                       // обычная формула
    .cond("b > 10", "a = b * 2")             // сокращение для встроенного условия
    .exit()                                   // возврат к FormulaBuilder
.build();

Внутри MixedBlock доступны следующие методы:

  • .flat(String) — одна формула
  • .array(String...) — последовательные формулы
  • .cond(String condition, String formula) — сокращение для встроенного условия
  • .cond(String condition) — входит в `CondBlock<MixedBlock

    >` для сложного тела

  • .ifelse(String cond, String ifTrue, String ifFalse) — сокращение if/else
  • .chain() — входит в `ChainBlock<MixedBlock

    >`

  • .mixed() — входит во вложенный `MixedBlock<MixedBlock

    >`

cond(String) — Входит в `CondBlock

, представляющий одну запись {"condition":..., "formula":...}. Поддерживает .flat(), .array(), .mixed(). .exit()` возвращает к родителю.

b.inputs("a", "b").mixed()
    .cond("b > 10").mixed()                  // сложное тело через вложенный mixed
        .flat("a = b * 2")
        .flat("a = a + 1")
    .exit()                                   // выход из вложенного mixed
    .exit()                                   // выход из CondBlock, обратно в MixedBlock
.exit()
.build();
chain() — Входит в `ChainBlock

. Условия проверяются сверху вниз; выполняется первое совпавшее. Если ни одно не совпало, выполняется ветка def. .exit()` возвращает к родителю.

b.inputs("result", "value").chain()
    .cond("value >= 100", "result = value * 2")   // инлайн: cond(c, f)
    .cond("value >= 50").mixed()                   // CondBlock со сложным телом
        .flat("result = value * 1.5")
    .exit()
    .def("result = 0")                              // ветка по умолчанию
.exit()
.build();

Внутри ChainBlock доступны следующие методы:

  • .cond(String condition, String formula) — сокращение для инлайн-условия
  • .cond(String condition) — входит в `CondBlock<ChainBlock

    >`

  • .def(String formula) — одна формула как значение по умолчанию
  • .defArray(String... formulas) — последовательные формулы как значение по умолчанию
  • .defMixed() — входит в `MixedBlock<ChainBlock

    >` как значение по умолчанию

VI. Сводка по вложенным блокам

Точка входаВозвращаетДоступные методыВозврат при exit
.mixed()`MixedBlock

`

.flat() .array() .cond() .ifelse() .chain() .mixed()P
.cond(String)`CondBlock

`

.flat() .array() .mixed()P
.chain()`ChainBlock

`

.cond() .def() .defArray() .defMixed()P

Параметризованный тип P отслеживает родительский контекст на этапе компиляции — .exit() всегда возвращает правильный родительский тип без приведения.

VII. Построение вывода

.build()          // Возвращает String — отформатированный JSON, для записи в файлы
.buildFormula()   // Возвращает JsonFormula — для прямого вычисления в коде

VIII. Автоматические правила префикса

После объявления inputs("result","x","y") эти строки обрабатываются автоматически:

ВходВыход
"result = x + y""#result = #x + #y"
"max(0, min(1, x))""max(0, min(1, #x))"
"x >= 10" (условие)"#x >= 10"

Префикс # НЕ добавляется повторно, если он уже есть: "#result = #x + #y" остаётся как есть, а числовые ссылки вроде "#0 = #1 + #2" не затрагиваются.

Важно: Не называйте переменные именами формул (избегайте min, max, pow, log и т.п. в качестве идентификаторов переменных).

IX. Соответствие формату JSON

Метод билдераГенерируемый JSON
.flat("x")"formula": "..."
.array("a","b")"formula": ["...", "..."]
.chain() ... .exit()"formula": {"chain": [...], "default": ...}
.ifelse(c,a,b)"formula": {"if": "...", "formula": ..., "else": ...}
.output("x")"output": "#x"
.inputs("a","b")"inputs": ["a", "b"]
.input(3)"input": 3
.caches("a","b")"caches": ["a", "b"]
.cache(2)"cache": 2

X. Типичные случаи использования

// Базовая арифметика
FormulaBuilder.inputs("r", "a", "b")
    .flat("r = a + b * 2")
    .build();

// Последовательное вычисление с кэшем
FormulaBuilder.inputs("r", "base", "mod")
    .caches("logval")
    .array(
        "logval = log(2, base + 1)",
        "r = logval * mod"
    )
    .build();

// Цепочка с несколькими условиями
FormulaBuilder.inputs("result", "val").chain()
    .cond("val >= 100", "result = val * 2")
    .cond("val >= 50", "result = val")
    .def("result = 0")
.exit().build();

// Сокращение if/else
FormulaBuilder.inputs("score", "kills", "deaths")
    .ifelse(
        "kills > deaths",
        "score = kills * 3 - deaths * 2",
        "score = max(0, kills - deaths)"
    )
    .build();

// Числовой режим (без именованных переменных)
FormulaBuilder.input(3).cache(1).output("#3")
    .array(
        "#0 = #1 + #2",
        "#3 = #0 * 2 + #1"
    )
    .build();

// Смешанный блок с условием и цепочкой
FormulaBuilder.inputs("a", "b", "c").mixed()
    .flat("a = b + c")
    .cond("b > 10", "a = a * 2")
    .chain()
        .cond("a > 100", "a = 100")
        .def("a = a")
    .exit()
.exit().build();

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

Как установить Formula Loader?

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

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

У Formula Loader есть сборки для Minecraft 1.18.2, 1.19.2–1.19.4, 1.20.1, 1.21.1–26.1.2.

Нужен ли Formula Loader на сервере?

Нужен на сервере; в игре — по желанию

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

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