调试插件

平时我们很难定位插件里一个 Bug 的具体位置,重新编译并且加一大堆测试代码会让人想上天,因此,本节教程将教会你如何利用 Java 的 Debug 功能.

准备你的工作环境

由于我们将在你的 IDE 中运行 Sponge 和你的插件,所以您需要导入 SpongeForgeSpongeVanilla ,具体取决于你要使用哪个。相应项目的 GitHub 页面上提供了如何做的说明。在继续操作之前,请仔细按照这些说明进行操作。

现在,你需要确保您的插件项目对您刚刚创建的 SpongeForge/SpongeVanilla 项目可见。所需的步骤取决于你的 IDE。

IntelliJ IDEA

在 IntelliJ 中,每一个项目都有它自己的一个工作环境。所以如果你想要让你的项目对 Sponge(Vanilla) 可见,你需要将其作为一个 Module 。假设你已经按照 设置 IntelliJ IDEA 描述的方式创建了你自己的项目,那么请按下面的步骤做。

  • 打开 SpongeVanilla/SpongeForge 项目。

  • 单击 File ,然后单击 New ,然后单击 Module from Existing Sources...

  • 定位至你的插件的根目录。

    • 如果你正在使用 Gradle,请选择 build.gradle 文件,然后在下一步选择 Use auto-import 并点击确定。

    • 否则请直接选择整个目录并点击 Finish

  • 点击 Finish

小技巧

如果你还没有创建你自己的插件,请单击 Module... 而不是 Module from Existing Sources... ,并按照接下来的指示新建项目。

Eclipse

只需要直接按照 设置 Eclipse 中描述的方式创建项目。只要它和 SpongeVanilla/SpongeForge 在同一个工作区,那么你的插件项目就对它们可见。

将插件添加到 Sponge 的 CLASSPATH 中

这背后的想法是,我们将从你的 IDE 中像正常项目一样启动 Sponge,但区别在于我们将把你的插件添加到 CLASSPATH 中。由于 Sponge 将默认加载在 CLASSPATH 中找到的所有插件,将插件项目添加到 Sponge 的 CLASSPATH 中将会使你无需在每次更改后重建并将项目文件复制到你的 Sponge 服务器目录下。

首先你需要确认你的运行和调试配置都已设置好。请根据 Sponge 的 README.md 中的内容进行检查。

然后你需要编辑你的运行和调试配置使得你的工作目录已被加入到 CLASSPATH 中。请再次根据你的 IDE 进行这一操作:

IntelliJ IDEA

  • 打开你的项目的 Project Structure。

    • 单击 File ,然后单击 Project Structure...

    • 或者直接点击 Project Structure 按钮,该按钮位于你的 IDE 的右上角, Search 按钮的旁边。

  • 单击 Modules 并展开 SpongeForgeSpongeVanilla 组(取决于你选择了什么)。

  • 确定你已选择了 SpongeForge_mainSpongeVanilla_main 中的一个。

  • 在右侧列中选择 Dependencies 选项卡。

  • 点击底侧的 + (添加)按钮,然后选择 Module Dependency

  • 选择你的插件项目( yourplugin_main

  • 在添加后 不要 检查 Export 选项。

警告

因为 Intellij IDEA 的一个 Bug(IDEA-194641),你的插件的所有依赖(比如 Kotlin 标准库、GSON 等)不能通过上述方式添加到你的 classpath 中。这会导致你的插件虽然能成功编译,但在调试中访问这些类时抛出 ClassNotFoundException

这个问题只会影响你在 Intellij IDEA 中以一个模块的形式运行你的插件。你最终构建出的插件仍然可以在 Intellij IDEA 和生产服务器上正常工作。

如果你的插件有外部依赖,你需要按以下步骤操作以能在 Intellij IDEA 中正常运行你的插件:

  • 新建新的 Java 模块。依次点击 File -> New -> Module...,命名为 SpongeForgeContainer

  • 打开之前新建的 SpongeForgeContainer 的模块设定。

  • SpongeForgeContainer 的依赖选项中,添加对 SpongeForge_main 的模块依赖。

  • 编辑服务器的启动配置。将 Use classpath of module:SpongeForge_main 改为 SpongeForgeContainer

其他选项保持不变。现在,你的插件所有的依赖都应该能正常添加到服务器的启动 classpath 中了。

Eclipse

  • 找到你的运行或调试配置

    • 单击 Run ,然后单击 Run Configurations...

    • 或者,请分别点击 Run/Debug 图标对应的下拉菜单后的 Run Configurations...Debug Configurations...

  • 在左侧栏选择关于 Sponge(服务端)的运行或调试配置。

  • 切换到 Classpath 选项卡。

  • 选择 User Entries ,然后单击 Add Projects... 按钮。

  • 选择你的插件项目。

  • 单击确定按钮。

  • 单击右下角的应用按钮。

运行你的配置

在你执行了上面的操作步骤后,你就可以开始调试你的插件了。如果你从你的 IDE 启动你的服务器,那么它的运行目录应为你的 SpongeForge/SpongeVanilla 下的 run 目录。所有服务端创建的文件(包括世界、配置等)都将存储于该目录并且每次都将从该目录启动服务器,就像你手动将服务端的 JAR 复制到了该目录下并启动一样。

IntelliJ IDEA

如果你想要调试,请不要点击表示运行或调试的两个按钮的绿色小箭头,而应点击旁边的绿色 Debug 按钮。

Eclipse

如果你想要调试,请不要点击表示运行或调试的两个按钮的绿色小箭头,而应点击 Debug 按钮旁边的下拉小箭头(因为一个 BUG)弹出一个下拉菜单,然后再点击 Test (Server) 配置。如果它并不存在在下拉菜单中,请点击 Debug Configurations ,然后点击 Test (Server) 配置并点击右下角的 Debug 按钮。

使用调试器

现在你的服务端(和你的插件)都在以调试器的方式运行了。你可以开始利用调试器的种种特性。下面简要介绍最明显的用法,尽管它们不属于 Sponge,而属于 IDE 使用的 Java Debugger 的特性。

断点

若要仔细看看代码,断点是一个很有用的工具。断点可以在代码行或方法的开头设置。当到达断点时,调试器将停止代码执行,同时 IDE 将打开一个视图,允许您检查当前范围中所有变量的内容。代码执行将不会还原,除非您在 IDE 的调试视图中按相应的按钮。

在调试的过程中,你可以任意地添加、移除、或者临时禁用断点。

小技巧

一旦单个服务器检查需要超过给定的时间,监视器(Watchdog)将会认为服务器崩溃并强制关闭它。当使用断点时这件事就可能会发生了,因此建议您编辑测试环境的 server.properties 文件,并将``max-tick-time`` (毫秒)的值设置为一个非常大的数字,或干脆直接设置为 -1 (完全禁用监视器)。

IntelliJ IDEA

若要添加或移除断点,只需在你的 IDE 的文本编辑器界面左侧的空白区域左键单击。

或者,将光标放在要添加或删除断点的行中,然后单击 Run 并单击 Toggle Line Breakpoint

Eclipse

若要添加或移除断点,只需在你的 IDE 的文本编辑器界面左侧的空白区域右键单击并点击 Toggle Breakpoint

或者,将光标放在要添加或删除断点的行中,然后单击 Run 并单击 Toggle Breakpoint

代码热替换

调试器的另一个主要特点是,你不必为每一个小的变化重新启动服务器,因为我们可以进行代码热替换。这意味着您可以在调试器中运行代码时重新编译部分代码。当然,这有几个限制,其中最重要的是:

  • 你不能添加或移除方法。

    • 对方法的改变仅限于方法 的代码。也就是你甚至连方法的签名(Signature)都不可以改变(这包括方法名称、返回值以及参数类型)。

  • 你不能移除一个类。

    • 你不能修改一个类的名称、父类、以及它实现的接口列表。

    • 你可以添加类。不过,它一旦添加并通过代码热替换的方式进行加载,你就不能对这个类做上面提到的操作了。

你可以测试这个功能:在插件中引入一个简单的命令,而且该命令的作用只是输出一个词,比如 Sponge ,然后保存并启动服务器,如上所述。运行命令。它会输出 Sponge 。现在改变命令,使其输出一个不同的词到控制台,保存文件。更改后,请执行以下操作以将更改传送到正在运行的程序:

IntelliJ IDEA

  • 从 IDE 的顶部打开 Run 菜单。

  • 在第一个分组的分隔线后,单击 Reload Changed Classes

Eclipse

不需要任何操作。你一旦保存这个文件,它将被重新生成,然后热替换到当前运行的调试器中。除非你改变了这种特定的默认行为,否则你不需要手动触发代码热替换。