版本信息
你使用的系统:win10 x64
你是用的JDK: 8u251 x64
你使用的IDE:IntelliJ IDEA
你使用的IDE版本:2020.2
Forge版本: 31.2.36
Minecraft版本: 1.15.2
Mapping 文件版本: 20200901
错误情况简述
依照Neutrino的教程做了一套Capability,额外做了一个用于测试的方块(右击时为附加的capability赋值)和一个用于测试的物品(右击时在控制台输出这个能力包含的值)。目前情况是玩家重生后使用物品或右击方块均会报空值的警告(见报错日志)。但是在控制台输出有
[Server thread/DEBUG] [ne.mi.fm.FMLWorldPersistenceHook/WP]: Gathering id map for writing to world save Rainbow6 Test
这句之后(表面看起来是这样),就一切正常不会报空了。(顺便:这句话的背后做了些什么?
报错日志
右击方块
[11:50:34] [Server thread/WARN] [ne.mi.co.ut.LazyOptional/CATCHING]: Catching
java.lang.NullPointerException: Supplier should not return null value
at net.minecraftforge.common.util.LazyOptional.getValue(LazyOptional.java:119) ~[?:?] {re:classloading}
at net.minecraftforge.common.util.LazyOptional.ifPresent(LazyOptional.java:159) ~[?:?] {re:classloading}
at com.ussshenzhou.rainbow6.blocks.CapabilityTestBlock.onBlockActivated(CapabilityTestBlock.java:28) ~[?:?] {re:classloading}
at net.minecraft.block.BlockState.onBlockActivated(BlockState.java:294) ~[?:?] {re:classloading}
at net.minecraft.server.management.PlayerInteractionManager.func_219441_a(PlayerInteractionManager.java:343) ~[?:?] {re:classloading}
at net.minecraft.network.play.ServerPlayNetHandler.processTryUseItemOnBlock(ServerPlayNetHandler.java:881) ~[?:?] {re:classloading}
at net.minecraft.network.play.client.CPlayerTryUseItemOnBlockPacket.processPacket(CPlayerTryUseItemOnBlockPacket.java:45) ~[?:?] {re:classloading}
at net.minecraft.network.play.client.CPlayerTryUseItemOnBlockPacket.processPacket(CPlayerTryUseItemOnBlockPacket.java:12) ~[?:?] {re:classloading}
at net.minecraft.network.PacketThreadUtil.lambda$checkThreadAndEnqueue$0(PacketThreadUtil.java:19) ~[?:?] {re:classloading}
at net.minecraft.util.concurrent.TickDelayedTask.run(TickDelayedTask.java:20) [?:?] {re:classloading}
at net.minecraft.util.concurrent.ThreadTaskExecutor.run(ThreadTaskExecutor.java:140) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.util.concurrent.RecursiveEventLoop.run(RecursiveEventLoop.java:22) [?:?] {re:classloading}
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:759) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:141) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.util.concurrent.ThreadTaskExecutor.driveOne(ThreadTaskExecutor.java:110) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.driveOneInternal(MinecraftServer.java:742) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.driveOne(MinecraftServer.java:736) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.util.concurrent.ThreadTaskExecutor.driveUntil(ThreadTaskExecutor.java:123) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.runScheduledTasks(MinecraftServer.java:722) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:666) [?:?] {re:classloading,pl:accesstransformer:B}
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_251] {}
使用物品
[11:50:35] [Server thread/WARN] [ne.mi.co.ut.LazyOptional/CATCHING]: Catching
java.lang.NullPointerException: Supplier should not return null value
at net.minecraftforge.common.util.LazyOptional.getValue(LazyOptional.java:119) ~[?:?] {re:classloading}
at net.minecraftforge.common.util.LazyOptional.ifPresent(LazyOptional.java:159) ~[?:?] {re:classloading}
at com.ussshenzhou.rainbow6.items.CapabilityTestItem.onItemRightClick(CapabilityTestItem.java:29) ~[?:?] {re:classloading}
at net.minecraft.item.ItemStack.useItemRightClick(ItemStack.java:206) ~[?:?] {re:classloading}
at net.minecraft.server.management.PlayerInteractionManager.processRightClick(PlayerInteractionManager.java:293) ~[?:?] {re:classloading}
at net.minecraft.network.play.ServerPlayNetHandler.processTryUseItem(ServerPlayNetHandler.java:905) ~[?:?] {re:classloading}
at net.minecraft.network.play.client.CPlayerTryUseItemPacket.processPacket(CPlayerTryUseItemPacket.java:37) ~[?:?] {re:classloading}
at net.minecraft.network.play.client.CPlayerTryUseItemPacket.processPacket(CPlayerTryUseItemPacket.java:9) ~[?:?] {re:classloading}
at net.minecraft.network.PacketThreadUtil.lambda$checkThreadAndEnqueue$0(PacketThreadUtil.java:19) ~[?:?] {re:classloading}
at net.minecraft.util.concurrent.TickDelayedTask.run(TickDelayedTask.java:20) [?:?] {re:classloading}
at net.minecraft.util.concurrent.ThreadTaskExecutor.run(ThreadTaskExecutor.java:140) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.util.concurrent.RecursiveEventLoop.run(RecursiveEventLoop.java:22) [?:?] {re:classloading}
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:759) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:141) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.util.concurrent.ThreadTaskExecutor.driveOne(ThreadTaskExecutor.java:110) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.driveOneInternal(MinecraftServer.java:742) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.driveOne(MinecraftServer.java:736) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.util.concurrent.ThreadTaskExecutor.driveUntil(ThreadTaskExecutor.java:123) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.runScheduledTasks(MinecraftServer.java:722) [?:?] {re:classloading,pl:accesstransformer:B}
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:666) [?:?] {re:classloading,pl:accesstransformer:B}
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_251] {}
不会出现报错的情况:
[16:26:50] [Server thread/INFO] [minecraft/MinecraftServer]: Dev试图在熔岩里游泳
[16:26:50] [Render thread/INFO] [minecraft/NewChatGui]: [CHAT] Dev试图在熔岩里游泳
[16:27:00] [Server thread/WARN] [ne.mi.co.ut.LazyOptional/CATCHING]:
......
[16:27:27] [Server thread/DEBUG] [ne.mi.fm.FMLWorldPersistenceHook/WP]: Gathering id map for writing to world save Rainbow6 Test
[16:27:28] [Server thread/INFO] [co.us.ra.it.CapabilityTestItem/]: operatorless,teamless
[16:27:29] [Server thread/INFO] [co.us.ra.it.CapabilityTestItem/]: operatorless,teamless
相关代码
CapabilityTestBlock
@Override
public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) {
if (!worldIn.isRemote){
LazyOptional<IR6PlayerCapability> r6PlayerCap = player.getCapability(ModCapabilities.R6_PLAYER_CAPABILITY);
r6PlayerCap.ifPresent((cap)->{
cap.setR6Team("attacker");
cap.setOperator("mira");
}
);
}
return ActionResultType.SUCCESS;
}
CapabilityTestItem
@Override
public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) {
ItemStack itemstack = playerIn.getHeldItem(handIn);
if (!worldIn.isRemote){
LazyOptional<IR6PlayerCapability> r6PlayerCap = playerIn.getCapability(ModCapabilities.R6_PLAYER_CAPABILITY);
r6PlayerCap.ifPresent((cap)->{
String operator = cap.getOperator();
String r6Team = cap.getR6Team();
LogManager.getLogger().info(operator+","+r6Team);
}
);
}
return new ActionResult<>(ActionResultType.SUCCESS, itemstack);
}
ModCapabilityAttachEvent
@Mod.EventBusSubscriber()
public class ModCapabilityAttachEvent {
@SubscribeEvent
public static void onAttachCapability(AttachCapabilitiesEvent<Entity> event){
Entity entity = event.getObject();
if (entity instanceof PlayerEntity){
event.addCapability(new ResourceLocation("rainbow6","r6player"),new R6PlayerCapabilityProvider());
}
}
@SubscribeEvent
public static void onPlayerCloned(PlayerEvent.Clone event){
if (!event.isWasDeath()){
LazyOptional<IR6PlayerCapability> oldR6Cap = event.getOriginal().getCapability(ModCapabilities.R6_PLAYER_CAPABILITY);
LazyOptional<IR6PlayerCapability> newR6Cap = event.getPlayer().getCapability(ModCapabilities.R6_PLAYER_CAPABILITY);
if (oldR6Cap.isPresent()&& newR6Cap.isPresent()){
newR6Cap.ifPresent((newCap)->{
oldR6Cap.ifPresent((oldCap)->{
newCap.deserializeNBT(oldCap.serializeNBT());
}
);
}
);
}
}
}
}
R6PlayerCapabilityProvider
private IR6PlayerCapability r6PlayerCapability;
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nonnull Direction side) {
return cap ==ModCapabilities.R6_PLAYER_CAPABILITY ? LazyOptional.of(()-> this.r6PlayerCapability).cast():LazyOptional.empty();
}
@Nonnull
IR6PlayerCapability getOrCreateCapability(){
if (r6PlayerCapability==null){
this.r6PlayerCapability = new R6PlayerCapability("operatorless","teamless");
}
return this.r6PlayerCapability;
}
@Override
public CompoundNBT serializeNBT() {
return getOrCreateCapability().serializeNBT();
}
@Override
public void deserializeNBT(CompoundNBT nbt) {
getOrCreateCapability().deserializeNBT(nbt);
}
}