NOTE自1.17之后, SpigotMC 开始提供 Mojang 混淆表版本的 Spigot 服务端,这意味着大大简化了开发难度 —— 不需要再对照混淆表一个一个看NMS 方法名
本篇我来粗浅介绍使用Paper API的插件如何使用Mojang mappings自定义实体
引入依赖
TIP官方的Gradle Kotlin例子
Waiting for api.github.com...
这里我使用Gradle Groovy讲解
一共要改两处地方,对了,1.4.1
版本记得修改
plugins {
...
id "io.papermc.paperweight.userdev" version "1.4.1"
}
dependencies {
...
paperweightDevelopmentBundle "io.papermc.paper:dev-bundle:1.19.3-R0.1-SNAPSHOT"
// compileOnly 'io.papermc.paper:paper-api:1.19.3-R0.1-SNAPSHOT'
}
pluginManagement {
repositories {
gradlePluginPortal()
maven{ url = "https://repo.papermc.io/repository/maven-public/"}
}
}
Then! 创建自定义实体
很明显,根据已有的API,甚至是Paper API,都没有向我们提供创建自定义实体的功能。因此,想要创建自定义实体,需要使用 Mojang mappings
我们刚才依赖引入的就是(1.17- 需要使用NMS
)
本例中,我们创建一个不会被破坏,只能坐一个玩家的船(不是箱船),来自我的项目 — IceBoat
继承已有实体
欸,既然要弄一个不一样的船,但总不可能凭空变出来吧,我们还是得继承游戏原来的Boat代码
所以,让我们创建 GameBoat 类,继承 net.minecraft.world.entity.vehicle.Boat 类
public class GameBoat extends Boat {}
接下来,初始化该实体,实现超类构造器
public class GameBoat extends Boat {
public GameBoat(EntityType<? extends Boat> type, Level world) {
super(type, world);
}
}
要想生成该实体,则应该调用 Boat#setPos(x,y,z)
设置坐标,然后调用 ServerLevel#addFreshEntityWithPassengers(Entity)
方法生成实体。为了简便流程,我们可以自定义一个可传入 Bukkit Location
的构造函数,使其调用后自动在设定坐标生成
public GameBoat(Location location) {
this(EntityType.BOAT, ((CraftWorld) location.getWorld()).getHandle());
this.setPos(location.getX(), location.getY(), location.getZ());
ServerLevel level = ((CraftWorld) location.getWorld()).getHandle();
level.addFreshEntityWithPassengers(this);
}
然后你就可以看到你自定义的船实体了,Great~
继续修改
只能一个玩家乘坐
我们观察 net.minecraft.world.entity.vehicle.Boat
的源码,可以发现乘坐调用的是 Boat#addPassenger(Entity)
,所以我们重写这个方法就行
@Override
public boolean addPassenger(@NotNull Entity entity) {
if (entity instanceof Player && this.getPassengers().size() == 0) {
return super.addPassenger(entity);
} return false;
}
既然Passengers(List<Entity>)
只有一个,那我们可以顺便写个获取获取乘坐者的方法
public org.bukkit.entity.Player getPassenger() {
List<Entity> passengers = this.getPassengers();
return passengers.size() == 1 ? (org.bukkit.entity.Player) passengers.get(0) : null;
}
哦,对了如果你想addPassenger
的话,我们可以再写个方法,这样玩家能否上船也在你的掌握之中了!
public void addPassenger(org.bukkit.entity.Player player) {
// org.bukkit.entity.Player to net.minecraft.world.entity.Entity
Entity entityPlayer = ((CraftPlayer) player).getHandle();
entityPlayer.startRiding(this);
}
修改Tick
重写tick()
就行,别忘记加上super.tick();
,除非你真的想彻底更改这个实体
@Override
public void tick() {
super.tick();
}
Tips: 一些有用的互转
Entity entityPlayer = ((CraftPlayer) xxx).getHandle();
ServerLevel level = ((CraftWorld) xxx.getWorld()).getHandle();
编译
(踩坑 +1) 小白本尊尝试了N多次,希望能让你避开这个坑
你现在不是用 gradle build
来编译插件了,应改用paperweight提供的reobfJar
也就是命令变成了 gradle reobfJar