110000
我想实现让玩家右击一下任意方块(除了空气),就可以像用床一样睡觉,不是简单的躺下,而是让玩家进入睡眠状态(与床一样都得晚上),和床的功能一模一样,该怎么做?(判定右键点击没有问题,问题就是如何让玩家进入睡眠状态)
我之前去spigot或者bukkit的论坛里看到类似的问题,他们都说要用到数据包,然后我看到他们给出的代码都有用到PacketPlayOutBed这个类,但是我把他们给出的代码复制进去,运行的时候什么也没出现……

为什么要用到数据包呢?没有一个函数直接调用就让玩家睡觉?


q88724653
用ProtocolLib发数据包

DefineEvil
Use Bed

This packet tells that a player goes to bed.

The client with the matching Entity ID will go into bed mode.

This Packet is sent to all nearby players including the one sent to bed.

Any packets sent with a location not currently occupied by a bed will be ignored by clients.
Packet ID         State         Bound To         Field Name         Field Type         Notes
0x2F         Play         Client         Entity ID         VarInt         Sleeping player's EID
Location         Position         Block location of the head part of the bed

转自wiki.vg

好了,构造包吧

110000
DefineEvil 发表于 2017-6-21 21:44
Use Bed

This packet tells that a player goes to bed.

虽然说是找到用法了,但是按实例代码的步骤来弄,出现了Field index out of bounds. (Index: 1, Size: 1)的异常,而且把实例代码放进去测试一样出现这个异常。
我换了不同的protocollib版本,还是会抛出异常。

110000
这是实例代码,原地址:https://gist.github.com/aadnk/8611384
第56,57,58行会抛出Field index out of bounds. (Index: 1, Size: 1)异常
我是在1.8.3spigot上测试的,protocol版本是3.6.4

  1. package com.comphenix.example;

  2. import java.lang.reflect.InvocationTargetException;
  3. import java.util.Collections;
  4. import java.util.Set;
  5. import java.util.WeakHashMap;

  6. import org.bukkit.Location;
  7. import org.bukkit.command.Command;
  8. import org.bukkit.command.CommandSender;
  9. import org.bukkit.entity.Player;
  10. import org.bukkit.plugin.java.JavaPlugin;

  11. import com.comphenix.protocol.PacketType;
  12. import com.comphenix.protocol.ProtocolLibrary;
  13. import com.comphenix.protocol.ProtocolManager;
  14. import com.comphenix.protocol.events.PacketContainer;

  15. public class SleepingAnimation extends JavaPlugin {
  16.     private ProtocolManager manager;
  17.    
  18.     // Just a way to record if a player is asleep
  19.     private Set<Player> sleeping = Collections.newSetFromMap(new WeakHashMap<Player, Boolean>());
  20.    
  21.     @Override
  22.     public void onEnable() {
  23.         manager = ProtocolLibrary.getProtocolManager();
  24.     }
  25.    
  26.     @Override
  27.     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
  28.         if (sender instanceof Player) {
  29.             Player player = (Player) sender;
  30.             
  31.             if (sleeping.add(player)) {
  32.                 playSleepAnimation(player);
  33.             } else {
  34.                 stopSleepAnimation(player);
  35.                 sleeping.remove(player);
  36.             }
  37.         }
  38.         return true;
  39.     }
  40.    
  41.     /**
  42.      * Play the sleep animation for every nearby player.
  43.      * @param alseep - the player asleep.
  44.      */
  45.     private void playSleepAnimation(Player asleep) {
  46.         final PacketContainer bedPacket = manager.createPacket(PacketType.Play.Server.BED, false);
  47.         final Location loc = asleep.getLocation();
  48.         
  49.         // http://wiki.vg/Protocol#Use_Bed
  50.         bedPacket.getEntityModifier(asleep.getWorld()).
  51.             write(0, asleep);
  52.         bedPacket.getIntegers().
  53.             write(1, loc.getBlockX()).
  54.             write(2, loc.getBlockY() + 1).
  55.             write(3, loc.getBlockZ());
  56.         
  57.         broadcastNearby(asleep, bedPacket);
  58.     }
  59.    
  60.     private void stopSleepAnimation(Player sleeping) {
  61.         final PacketContainer animation = manager.createPacket(PacketType.Play.Server.ANIMATION, false);
  62.         
  63.         // http://wiki.vg/Protocol#Animation
  64.         animation.getEntityModifier(sleeping.getWorld()).
  65.             write(0, sleeping);
  66.         animation.getIntegers().
  67.             write(1, 2);
  68.         
  69.         broadcastNearby(sleeping, animation);
  70.     }

  71.     private void broadcastNearby(Player asleep, PacketContainer bedPacket) {
  72.         for (Player observer : manager.getEntityTrackers(asleep)) {
  73.             try {
  74.                 manager.sendServerPacket(observer, bedPacket);
  75.             } catch (InvocationTargetException e) {
  76.                 throw new RuntimeException("Cannot send packet.", e);
  77.             }
  78.         }
  79.     }
  80. }
复制代码