Minecraft Sponge 服务端 Universal Market 插件踩坑记录及修复汉化版本下载
2019-06-28
Minecraft 原版玩腻了~~(龙终于打过了)~~,想玩 Minecraft MOD ,于是乎我装了工业 2 模组。正想着联机,从 mcbbs 里找了半天,感觉靠谱的就没有几个。自己玩又太孤独,那就来搭建一个服吧。这是前言,具体细节不多讲了,总之坑很多,不过好在有前辈们的教程(比如 http://www.mcbbs.net/thread-786074-1-1.html ),路走的还算顺利。本着为人民服务的精神,在这里选取一个坑,总结一下过程,来帮助后来的小伙伴们。
简要介绍
Universal Market 是一个寄售市场,有着类似箱子的界面。
MCBBS 转载贴: http://www.mcbbs.net/thread-792152-1-1.html
Github 原始项目: https://github.com/Xwaffle1/UniversalMarket
下载
20190628 更新:修复了热加载不管用的问题,修复了空手将空气添加到市场的bug
UniversalMarket-master-Bug_fix_and_chinese_translation-source.7z
由于这个项目的各种提示文本是内置在代码里的,所以汉化需要重新编译,上面有项目源代码文件,如果不放心的话,可以按照下方的编译过程自己手动编译。汉化部分采用 Tollainmear 提供的翻译。
出现问题
我搭建的服务器版本为 Minecraft 1.12.2 , Forge 1.12.2-14.23.5.2825 , SpongeForge 1.12.2-2825-7.1.6 。在安装了 1.3 版本的 Universal Market 插件( https://github.com/Xwaffle1/UniversalMarket/releases/tag/1.3 )后发现无法正常进入商店,控制台报错如下:
[xx:xx:xx] [Server thread/ERROR] [Sponge]: Error occurred while executing command 'um' for source EntityPlayerMP['lookas2001'/248, l='world', x=302.00, y=64.00, z=229.00]: There's no NBT Data set in the provided container
org.spongepowered.api.data.persistence.InvalidDataException: There's no NBT Data set in the provided container
at net.minecraft.item.ItemStack.setRawData(ItemStack.java:2534) ~[aip.class:?]
at com.xwaffle.universalmarket.utils.ItemBuilder.<init>(ItemBuilder.java:38) ~[ItemBuilder.class:?]
at com.xwaffle.universalmarket.utils.ItemBuilder.<init>(ItemBuilder.java:31) ~[ItemBuilder.class:?]
at com.xwaffle.universalmarket.market.Market.openMarket(Market.java:247) ~[Market.class:?]
at com.xwaffle.universalmarket.market.Market.openMarket(Market.java:167) ~[Market.class:?]
at com.xwaffle.universalmarket.commands.MarketCommand.process(MarketCommand.java:45) ~[MarketCommand.class:?]
at org.spongepowered.api.command.dispatcher.SimpleDispatcher.process(SimpleDispatcher.java:340) ~[SimpleDispatcher.class:1.12.2-2825-7.1.6]
at org.spongepowered.common.command.SpongeCommandManager.process(SpongeCommandManager.java:337) [SpongeCommandManager.class:1.12.2-2825-7.1.6]
at net.minecraft.command.ServerCommandManager.func_71556_a(SourceFile:1156) [dh.class:?]
at net.minecraft.network.NetHandlerPlayServer.func_147361_d(NetHandlerPlayServer.java:960) [pa.class:?]
at net.minecraft.network.NetHandlerPlayServer.func_147354_a(NetHandlerPlayServer.java:939) [pa.class:?]
at net.minecraft.network.play.client.CPacketChatMessage.func_148833_a(SourceFile:37) [la.class:?]
at net.minecraft.network.play.client.CPacketChatMessage.func_148833_a(SourceFile:9) [la.class:?]
at org.spongepowered.common.event.tracking.phase.packet.PacketPhaseUtil.onProcessPacket(PacketPhaseUtil.java:193) [PacketPhaseUtil.class:1.12.2-2825-7.1.6]
at net.minecraft.network.PacketThreadUtil$1.redirect$onProcessPacket$zlk000(SourceFile:539) [hv$1.class:?]
at net.minecraft.network.PacketThreadUtil$1.run(SourceFile:13) [hv$1.class:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_74]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_74]
at net.minecraft.util.Util.func_181617_a(SourceFile:46) [h.class:?]
at org.spongepowered.common.SpongeImplHooks.onUtilRunTask(SpongeImplHooks.java:307) [SpongeImplHooks.class:1.12.2-2825-7.1.6]
at net.minecraft.server.MinecraftServer.redirect$onRun$zjo000(MinecraftServer.java:3970) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:723) [MinecraftServer.class:?]
at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:397) [nz.class:?]
at net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:668) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:526) [MinecraftServer.class:?]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_74]
这时候我有点慌了,因为我之前没有系统的接触过 Java ,只在研究锐捷网络 ESS/SMP 产品授权验证以及 Moegirl Android App 的时候稍微有所了解。
定位和解决
直接上搜索引擎,没找到...
由于这个项目是开源的~~(Open Source 大法好!)~~,我们可以将代码下载下来慢慢研究。
后来又到原始项目里找 issue 找到了这个 https://github.com/Xwaffle1/UniversalMarket/issues/20 ,通过一些方式联系上了一个已经对前面一个版本的 jar 打完补丁的 dalao Alone,感谢其作品在我没有思路时候对我的启发。
好在有 trace ,我们可以看到最后一个关于这个插件的错误发生在 com.xwaffle.universalmarket.utils.ItemBuilder.<init>(ItemBuilder.java:38) ~[ItemBuilder.class:?]
这里:
我们把 setRawData 这个函数扔到 Sponge Forum 上搜索一下 https://forums.spongepowered.org/t/set-get-modify-subid-of-itemstack/19048/9 ,发现这个函数与在物品上设置一些属性有关,是一个比较 hacky 的做法。
将这段代码对应的函数在项目全局搜索一下:
发现这段代码只跟 Market.java 这个文件相关,打开,查找调用地方。
我们发现实际通过 meta 变量传入设置了 UnsafeDamage (损坏值)的调用点只在这里:
加载了好使的插件后,可以发现这个是支付确认界面的确定按钮。
故推测,这可能是作者想要做的一个类似进度条相关的功能,但是最后可能因为各种原因最后咕咕咕了(人类的本质)。
那就直接把这一行以及相关的两行(即出现 bug 这一行的上面两行)移除掉试一试。
拦路虎——编译
Minecraft 使用 Java 8 作为其运行环境,相应的,其周围 Mod 开发都是在 Java 8 基础上进行的,推荐使用 Java 8 来进行接下来的工作。
我本地用的电脑是 MacBook 开发环境为 MacOS,相对 Windows 系统,在命令行上更加强大一些,周围配套设施也多一些。个人开发的话,平常使用 brew 作为包管理,安装软件快捷迅速。但是 Brew 默认不提供 Java 8 (大概是过时了?),而去 Oracle 官网上下载又是不可能的(下载居然还需要登录),在 StackOverflow 上有这么一个回答 https://stackoverflow.com/a/55774255 ,解决了 Java 8 安装的问题。
看到这个项目使用了 gradle 作为其依赖管理(或者讲构建工具?),依照这我之前用 composer ,npm 的经验,我寻思着应该需要用 brew 安装一下。事实上是不需要的,安装了反而多余。brew 上的 gradle 版本太高,并且项目本身提供了一个包管理命令,即 gradlew 。运行一下会在项目目录以及用户目录生成相应的文件。
于是乎,./gradlew
一下,在下载完必要的文件后,给出了一个提示,按照这个提示,我应该运行 ./gradlew tasks
。运行之,找到好像是构建的选项 ./gradlew build
。运行之,傻眼,提示错误:
:compileJava
/xxxxxx/UniversalMarket-master/build/sources/main/java/com/xwaffle/universalmarket/market/Market.java:30: 错误: 程序包org.spongepowered.common.item.inventory.adapter.impl.slots不存在
import org.spongepowered.common.item.inventory.adapter.impl.slots.SlotAdapter;
^
/xxxxxx/UniversalMarket-master/build/sources/main/java/com/xwaffle/universalmarket/market/Market.java:31: 错误: 程序包org.spongepowered.common.item.inventory.query.operation不存在
import org.spongepowered.common.item.inventory.query.operation.InventoryPropertyQueryOperation;
^
/xxxxxx/UniversalMarket-master/build/sources/main/java/com/xwaffle/universalmarket/market/Market.java:32: 错误: 程序包org.spongepowered.common.item.inventory.util不存在
import org.spongepowered.common.item.inventory.util.ItemStackUtil;
^
/xxxxxx/UniversalMarket-master/build/sources/main/java/com/xwaffle/universalmarket/market/MarketItem.java:10: 错误: 程序包org.spongepowered.common.item.inventory.util不存在
import org.spongepowered.common.item.inventory.util.ItemStackUtil;
^
/xxxxxx/UniversalMarket-master/build/sources/main/java/com/xwaffle/universalmarket/utils/ItemBuilder.java:11: 错误: 程序包org.spongepowered.common.item.inventory.util不存在
import org.spongepowered.common.item.inventory.util.ItemStackUtil;
^
注: Writing plugin metadata to file:/xxxxxx/UniversalMarket-master/build/classes/main/mcmod.info
5 个错误
:compileJava FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
翻找 Sponge 文档,看到官方给出的例子都是基于 IDE 的,但是由于我的 MacBook 空间不够,最后在另外一台电脑上(Windows)安装了Intellij IDEA Community ,然后使用 IDE 提供的构建按钮,又花费了很长的一段时间下载,最后提示了两个错误 "PKIX path building failed" 和 "unable to find valid certification path to requested target" (在 Windows 上使用命令构建不会出现这个问题,但是仍然会出现上述在 MacOS 已经出现的错误),看来不是 IDE 的问题,返回我的 MacBook 。
在前一个步骤中,我观察到了一个事情,为什么其他引入不会出现问题,而这些引入会出现问题,我发现这些包都是以 org.spongepowered.common.xxxx 开头。之前有查看过 build.gradle 这个文件,明明有通过 compile 'org.spongepowered:spongeapi:7.0.0'
引入 SpongeAPI 。在是 IDE 的问题排查完后,我决定去看看 Java 编译器到底在引入一些什么东西。
由于之前有过 gradle 相关的经历,知道 gradle 会在用户目录生成文件夹 ~/.gradle
,去之,然后搜索之 find . | grep sponge
。搜索结果中有一个 ./caches/modules-2/files-2.1/org.spongepowered/spongeapi/7.0.0/ada1f9981de3459b182ee16d6408173ef33a8943/spongeapi-7.0.0.jar
这一看就是 api 对应的包嘛。
解压之(反编译就不用了):
自闭了
哪来的 common 啊!!
回到 build.gradle 目光下移一行,compile files('libs/spongeforge-1.12.2-2555-7.1.0-BETA-2837.jar')
在结合 SpongeCommon 项目的描述,这作者 tm 直接把 SpongeForge 的发布版本当做依赖了啊!而且源代码还把这个目录给删了!!!结合利用偏门 API 的事情来看(Sponge 不推荐插件作者绕过 Sponge 等行为,这个插件作者直接引入了 net.minecraft.nbt.NBTTagCompound
),怪不得这个作者在发布 MOD 没在 Ore 上发啊(可能也跟 Sponge 没提供一些 API 有关)。
下载了现在最新的稳定版本 SpongeForge (spongeforge-1.12.2-2825-7.1.6.jar)(老的不想往后翻了),创建 libs 目录扔进去。然后修改一下 build.gradle 里对应的文件名(保持匹配)。再运行一下 ./gradlew build
小宝贝,终于看见你了:
最后经过测试,工作完美。