1. Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.
    Скрыть объявление
Скрыть объявление
В преддверии глобального обновления, мы проводим исследования, которые помогут нам сделать опыт пользования форумом ещё удобнее. Помогите нам, примите участие!

Стартап [Туториал] Удобная работа с NMS на Paper/Purpur/Folia 1.17+ (paperweight)

Тема в разделе "Разработка плагинов для новичков", создана пользователем Dymeth, 14 ноя 2021.

  1. Автор темы
    Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Здравствуйте!

    Сразу хочу показать вам пример кода на NMS с использованием технологии paperweight:
    upload_2021-11-14_18-55-40.png
    Как вы можете увидеть, больше нет никаких однобуквенных названий. Весь код читабельный и выглядит так, будто это и вовсе не NMS. Тем не менее, это он - обратите внимание на импорты.

    Заинтересовало? Тогда продолжаем...

    Предисловие:
    Использование NMS - это крайняя мера, к которой стоит прибегать только в крайнем случае. Если у какой-то функции есть апи - лучше использовать это апи.
    Если же нужной вам функции в апи нет - стоит предложить её разработчикам Spigot или Paper на гитхабе данных проектов.

    Для начала предлагаю вам ознакомиться с моей темой о том, что такое маппинги:
    http://rubukkit.org/threads/165824/

    Итак, с версии 1.14 Mojang начали публиковать официальные маппинги, включающие в себя всё кроме локальных переменных методов.
    На версии 1.17 мы наконец-то дождались внедрения этих маппингов в Spigot и Paper 1.17.
    Настало время использовать их в полную силу!

    Использовать будем следующие технологии:
    - Среда разработки Intellij IDEA
    - Система сборки Gradle (с использованием Groovy DSL или Kotlin DSL)
    - Ядро Paper/Purpur/Folia 1.17 или новее
    - paperweight - система сборки ядра Paper и плагинов с использованием маппингов Mojang

    Данная статья подходит исключительно для проектов с системой сборки Gradle. Тут вы найдёте необходимо информацию по переводу проекта с Maven на Gradle: https://docs.gradle.org/current/userguide/migrating_from_maven.html

    Но если же вы хотите использовать Maven и дальше, то вам придётся разбираться самостоятельно. Я лишь дам наводку.

    Зависимость с NMS (спасибо imDaniX за наводку):
    https://docs.codemc.io/faq/#what-is-the-nms-maven-repository
    PHP:
    <dependency>
        <
    groupId>org.spigotmc</groupId>
        <
    artifactId>spigot</artifactId>
        <
    version>1.19.2-R0.1-SNAPSHOT</version>
        <
    classifier>remapped-mojang</classifier>
        <
    scope>provided</scope>
    </
    dependency>

    При необходимости вы можете самостоятельно добавить зависимость в локальный мавен- репозиторий, для этого используется BuildTools с флагом "--remapped".

    Подробности можно найти тут: https://blog.jeff-media.com/nms-use-mojang-mappings-for-your-spigot-plugins/

    Для применения маппинов при сборке можно использовать SpecialSource:
    https://github.com/md-5/SpecialSource
    PHP:
    <plugin>
        <
    groupId>net.md-5</groupId>
        <
    artifactId>specialsource-maven-plugin</artifactId>
        <
    version>1.2.2</version>
        <
    executions>
            <
    execution>
                <
    phase>package</phase>
                <
    goals>
                    <
    goal>remap</goal>
                </
    goals>
                <
    id>remap-obf</id>
                <
    configuration>
                    <
    srgIn>org.spigotmc:minecraft-server:1.19.2-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
                    <
    reverse>true</reverse>
                    <
    remappedDependencies>org.spigotmc:spigot:1.19.2-R0.1-SNAPSHOT:jar:remapped-mojang</remappedDependencies>
                    <
    remappedArtifactAttached>true</remappedArtifactAttached>
                    <
    remappedClassifierName>remapped-obf</remappedClassifierName>
                </
    configuration>
            </
    execution>
            <
    execution>
                <
    phase>package</phase>
                <
    goals>
                    <
    goal>remap</goal>
                </
    goals>
                <
    id>remap-spigot</id>
                <
    configuration>
                    <
    inputFile>${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar</inputFile>
                    <
    srgIn>org.spigotmc:minecraft-server:1.19.2-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
                    <
    remappedDependencies>org.spigotmc:spigot:1.19.2-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies>
                </
    configuration>
            </
    execution>
        </
    executions>
    </
    plugin>

    Помимо этого, существует плагин, позволяющий использовать paperweight на мавене. Спасибо Huze за ссылку:
    https://github.com/Alvinn8/paper-nms-maven-plugin

    Внимание!
    Я не гарантирую оперативное обновление туториала. Пожалуйста, убедитесь, что используете актуальные версии плагинов, библиотек и прочих зависимостей. Также при необходимости ознакомьтесь с официальной документацией и сообщите в этой теме об изменениях. Полноценного официального гайда по paperweight до сих пор нет, но есть официальная документация репозитория:
    https://github.com/PaperMC/paperweight

    Приступаем.

    1) Для начала необходимо определиться, какую систему сборки вы хотите использовать. Paperweight поддерживает только Gradle, поэтому вы можете использовать либо Groovy DSL, либо Kotlin DSL. В статье указаны примеры для обеих систем. Если же вы не знакомы с понятием "система сборки" - вам придётся изучить эту тему самостоятельно.

    2) Далее нужно убедиться, что в нашем проекте используется JDK 17 или новее.
    Если у вас возникнут с этим вопросы или сложности - привожу полный список мест, в которых может понадобиться указать целевые версии Java. Данный список поможет вам решить ошибки вида "java: error: release version 17 not supported".
    1) В параметрах сборщика:
    PHP:
    compileJava {
        
    sourceCompatibility targetCompatibility JavaVersion.VERSION_17
    }
    PHP:
    java {
        
    sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility 
    JavaVersion.VERSION_17
        toolchain 
    {
            
    languageVersion.set(JavaLanguageVersion.of(17))
        }
    }

    tasks.withType<JavaCompile> {
        
    options.release.set(17)
    }
    2) Project Structure > Platform Settings > SDKs
    3) Project Structure > Project Settings > Project > Project SDK
    4) Project Structure > Project Settings > Project > Project language level
    5) Project Structure > Project Settings > Modules > Sources > Language level
    6) Project Structure > Project Settings > Modules > Dependencies > Module SDK
    7) Settings > Build, Execution, Deployment > Java Compiler > Project bytecode version
    8) Settings > Build, Execution, Deployment > Java Compiler > Module > Target bytecode version
    9) Settings > Build, Execution, Deployment > Build Tools > Gradle > Gradle JVM

    3) Следующим пунктом необходимо проверить, что в нашем проекте используется Gradle 7-й версии или новее. На данный момент последняя версия Gradle - это 8.1.1. Следить за релизами можно тут.
    Версия 7+ требуется для раз для поддержки Java 17 и новее, однако рекомендую придерживаться именно 8+, поэтому именно под неё указаны все куски кода.

    Версия Gradle указывается в файле /gradle/wrapper/gradle-wrapper.properties в строке distributionUrl.
    Кстати, папку wrapper'а не рекомендуется добавлять в .gitignore проекта, а загружать в гит вместе со всеми исходниками.

    После выполнения 3-го пункта рекомендую вам убедиться, что ваш плагин корректно собирается и запускается на сервере с использованием Java 17+.

    4) Последний этап подготовки. Необходимо удалить из проекта все зависимости от всех компонентов ядра: nms/craftbukkit/bukkit/spigot/paper - абсолютно всё. Не имеет значения, подключена ли зависимость из maven-репозитория или локальным jar-файлом. Это нужно для того, чтобы в дальнейшем избежать различных разногласий при работе с классами ядра и не ловить в рантайме NoClassDefFoundError, NoSuchMethodError и прочие.

    Пора переходить непосредственно к подключению paperweight. Предлагаю обратить внимание на примеры:

    Пример простого paper-плагина на Kotlin DSL:
    https://github.com/PaperMC/paperweight-test-plugin
    Всегда актуальная версия, обновляется командой PaperMC.

    Пример простого paper-плагина на Groovy DSL:
    https://github.com/Dymeth/paperweight-test-plugin-groovy
    Мой форк, обновляется по мере возможностей.

    Не забывайте ставить звёздочки!
    Я помогу вам и разберу каждый необходимый компонент настройки.

    5) Для начала подключаем Gradle-плагин paperweight к проекту. Делается это в блоке plugins в файле build.gradle (build.gradle.kts для Kotlin DSL):
    PHP:
    plugins {
      
    id("java-library")
      
    id("io.papermc.paperweight.userdev"version "1.5.5"
    }
    Блок plugins должен располагаться, как правило, в самом верху файла.

    Список версий paperweight находится тут.
    Указывать репозиторий плагина не требуется, поскольку релизы paperweight находятся в Gradle plugin portal, который используется по-умолчанию.

    Как видно из примера, мы также подключили плагин java-library. Указывать версию у него не требуется. Данный плагин требуется для указания параметров java, для работы с задачами сборщика и другого базового функционала.

    Помимо этого, по желанию вы можете использовать плагин run-paper от jpenilla, позволяющий для тестирования своего плагина запускать сервер на базе Paper при помощи задач runServer и runMojangMappedServer:
    PHP:
    id("xyz.jpenilla.run-paper"version "2.1.0"
    В рамках текущей статьи это НЕобязательный шаг.

    6) Настраиваем скрипт сборки так, чтобы при билде проекта наш код обфусцировался обратно и корректно работал на сервере:
    PHP:
    tasks {
        
    assemble {
            
    dependsOn(reobfJar// Run reobfJar on build
        
    }
    }
    7) Наконец-то мы можем добавить в наш проект зависимость для подключения ядра вместе с заветным NMS с маппингами:
    PHP:
    dependencies {
      
    paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20-R0.1-SNAPSHOT")
    }
    PHP:
    dependencies {
      
    paperDevBundle("1.20-R0.1-SNAPSHOT")
    }

    Groovy DSL - build.gradle:
    PHP:
    paperweightDevelopmentBundle("dev.folia:dev-bundle:1.20-R0.1-SNAPSHOT")
    Kotlin DSL - build.gradle.kts:
    PHP:
    paperweight.foliaDevBundle("1.20-R0.1-SNAPSHOT")
    Groovy DSL - build.gradle:
    PHP:
    paperweightDevelopmentBundle("com.example.paperfork:dev-bundle:1.20-R0.1-SNAPSHOT")
    Kotlin DSL - build.gradle.kts:
    PHP:
    paperweight.devBundle("com.example.paperfork""1.20-R0.1-SNAPSHOT")

    После этого не забываем обновить зависимости проекта.

    Готово! На данном этапе вы уже можете писать плагин с использованием NMS с маппингами от Mojang.

    Но есть несколько подводных камней, о которых вам стоит знать:

    1) Плагин, собранный под одну версию ядра, не обязан работать на другой. Дело в том, что в самом ядре, которое используется на серверах, по-прежнему находится обфусцированный NMS. Фактически при сборке вашего плагина paperweight применяет к коду маппинги, чтобы привести код в обфусцированный вид. Т.е. обфускация отсутствует исключительно на этапе разработки. Это сделано с целью избежать юридических проблем с Microsoft.
    Таким образом, если вы хотите добавить в свой плагин поддержку разных версий ядра - вам придётся создавать несколько модулей с разными версиями зависимостей paperweightDevelopmentBundle (для Groovy DSL) или paperDevBundle (для KotlinDSL). Но сам я не проверял, работает ли такая структура.

    2) При использовании нескольких модулей в проекте вы, вероятно, столкнётесь с тем, что Gradle просто не позволит подключить paperweight в этих самых модулях. Насколько мне известно, это связано с недоработкой Gradle: https://github.com/gradle/gradle/issues/14697
    Решение данной проблемы элементарное - достаточно удалить указание версии из дочерних модулей:
    PHP:
    id("io.papermc.paperweight.userdev")
    После чего перенести указание версии плагина в скрипт сборки главного (родительского) модуля следующим образом:
    PHP:
    id("io.papermc.paperweight.userdev"version "1.5.5" apply false
    Напоминаю, что блок plugins должен находиться в верхней части файла.

    3) Ошибка "The paperweight development bundle you are attempting to use is of data version '1', but the currently running version of paperweight only supports data version '2'"
    Данная проблема связана то ли с багом в Gradle, то ли в paperweight. Так или иначе, мне удалось решить её банальным удалением директории %userprofile%/.gradle/caches/<версия>/md-rule
    Перед удалением рекомендую закрыть все окна IDE

    На этом всё. Материал подготовлен Dymeth.

    Есть вопросы или дополнения?
    Тема открыта, не стесняйтесь
     
    Последнее редактирование: 12 янв 2024
  2. Автор темы
    Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Резерв
     
  3. imDaniX

    imDaniX Активный участник Пользователь

    Баллы:
    96
    Имя в Minecraft:
    imDaniX
    Годный гайд. Жаль, что использование Gradle убивает мой дряхлый ноутбук.
     
  4. Автор темы
    Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Под Maven + Spigot существует specialsource. Он тоже позволяет вести разработку с использованием маппингов. Но не знаю, не будет ли конфлитов, если в этот котёл подключить ещё и Paper API.

    Также я без понятия, реально ли подружить Maven и paperweight. Подозреваю, что нереально
     
  5. CraftCoder

    CraftCoder Старожил Пользователь

    Баллы:
    108
    Имя в Minecraft:
    CraftCoderr
  6. imDaniX

    imDaniX Активный участник Пользователь

    Баллы:
    96
    Имя в Minecraft:
    imDaniX
    В курсе, но учитывая планы Paper на хардфорк, это немного не рентабельно. Впрочем, на самом деле я практически не пишу под NMS, так что не критично.
    Да, по-моему там нужно переписывать всё это дело с нуля. Проще уж купить нормальное железо.
     
  7. mirrerror

    mirrerror Активный участник Пользователь

    Баллы:
    76
    Имя в Minecraft:
    mirrerror
    Полезно
     
  8. CraftCoder

    CraftCoder Старожил Пользователь

    Баллы:
    108
    Имя в Minecraft:
    CraftCoderr
    А мэппинги разве не раньше 1.17 начали публиковать? Можно как-то на более старых версиях использовать?
     
  9. Автор темы
    Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Маппинги начали публиковать с версии 1.14. Но, по словам electronicboy, использовать paperweight с версиями старше 1.17 не представляется возможным. Посмотрим, останется ли поддержка 1.17.1 с выходом 1.18
     
  10. Автор темы
    Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Тема актуальна, на 1.18.2 paperweight продолжает работать.
    Но не забывайте указывать актуальную версию плагина userdev
     
  11. MrJarousek

    MrJarousek Активный участник Пользователь

    Баллы:
    76
    Имя в Minecraft:
    RitaSister
    "Следить за релизами можно тут."
    Ты куда-то потерял ссылку, указал что тут но куда?
     
  12. Автор темы
    Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Спасибо, подправил эту и другие ссылки. Релизы Gradle: https://gradle.org/releases/

    Помимо этого, актуализировал версии технологий, используемых в статье. Но не забывайте периодически проверять их актуальность самостоятельно:
    - JDK
    - Gradle
    - Плагин io.papermc.paperweight.userdev
    - Плагин xyz.jpenilla.run-paper, если используете
    - paperDevBundle (API Paper'а)

    Сейчас это особенно актуально, потому что совсем недавно вышел Minecraft 1.19
     
    Последнее редактирование: 8 июн 2022
  13. MrJarousek

    MrJarousek Активный участник Пользователь

    Баллы:
    76
    Имя в Minecraft:
    RitaSister
    я подрубила NMS на 1.18.2(на данный момент когда написала это сообщение), то в ожидании 1.19 вместе с NMS тоже и пока не знаю что можно с него было бы получить то)
     
  14. Huze

    Huze Активный участник

    Баллы:
    61
    Имя в Minecraft:
    TheHuze
  15. imDaniX

    imDaniX Активный участник Пользователь

    Баллы:
    96
    Имя в Minecraft:
    imDaniX
    Наткнулся на репо NMS от CodeMC. Не очень легально, но думаю, прикроют нескоро.
     
  16. Автор темы
    Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Вопрос в том, какой резон использовать голый NMS, если можно использовать NMS с маппингами?
     
  17. Автор темы
    Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
  18. imDaniX

    imDaniX Активный участник Пользователь

    Баллы:
    96
    Имя в Minecraft:
    imDaniX
    Так там и с маппингами доступен. Достаточно добавить классификатор remapped-mojang. На мавене выглядит так
    HTML:
    <dependency>
        <groupId>org.spigotmc</groupId>
        <artifactId>spigot</artifactId>
        <version>1.19.2-R0.1-SNAPSHOT</version>
        <classifier>remapped-mojang</classifier>
        <scope>provided</scope>
    </dependency>
     
  19. Автор темы
    Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Тогда другой вопрос - будет ли обфускация обратно применена при сборке? Судя по всему, нет
     
  20. imDaniX

    imDaniX Активный участник Пользователь

    Баллы:
    96
    Имя в Minecraft:
    imDaniX
    Конечно не будет - просто зависимость ведь - но тут в целом пойдут те же инструкции, что при использовании specialsource.
    Странный ход конём получается, но таким образом переносимость проектов с места на место несколько легче должна быть. Что с paperweight, что с buildtools, нам всегда необходимо проделать пару дополнительных шагов перед началом работы.
     

Поделиться этой страницей