当打开PlayerInventory或更改内容时,我需要一个调用的事件。InventoryOpenEvent只适用于箱子、家具等,而不适用于PlayerInventory。我使用的是Java1.6SDK和1.7API。
我在我的TheWalls服务器上安装了插件TheWalls。现在我正在编写一个自己的插件,它应该扩展这个plulgin。我的插件应该简单地让用户在游戏开始之前选择一个工具包,当游戏开始时,所有玩家都被传送到他们的开始位置,我的插件应该添加之前选择的工具包项目。
我现在的问题是,当玩家被传送到产卵点时,我需要那个时刻。我第一次在PlayerTeleportEvent上试了一下,但这还为时过早。在ProWalls清除库存并添加自己的项目之前,项目将被添加。
现在,我想尝试使用一个名为“事件”的事件,当一个项目被添加到播放器的库存中时。然后我可以检查添加的项目是否是由ProWalls在游戏开始时添加的项目,如果这是真的,我将添加我自己的项目。
ProWalls在开始时调用initGameSettings()方法来保存库存,清除它并添加他自己的项目。因此,另一个可能的解决方案是,在插件ProWalls调用自己的方法initGameSettings()时创建一个事件。但我不知道这是否可能。用我当前的代码,我会在库存中看到从工具包中添加的项目,但是几毫秒后,这些项目将被删除。如果没有其他解决方案,我可能不得不使用计时器,定时器等待几毫秒,并添加项目比。但我发现,这不是个好办法.
为了更好地理解这个顺序: Player joins Game,ProWalls plugin调用initGameSettings(),plugin清除播放器库存并添加自己的项目,现在我的插件应该添加工具包的项目。
发布于 2014-07-25 11:35:54
专业编辑:在原始文章下面包括NMS / OBC,以演示如何使用反射.完成此操作。
Player
库存是由Mojang选择缓存的客户端。它在打开时不需要请求任何数据,所以除了服务器连接上的初始请求之外,它不向服务器发送任何请求。没有办法测试库存何时打开,只有在修改时才能进行测试。
我不太清楚为什么你会需要那个事件,而不是一些关键的按下扳机。如果不调用InvetoryClickEvent
,库存就不会改变,因此当玩家加入/进入需要跟踪库存的状态时,只需扫描一次库存,并侦听InventoryClickEvent
处理更改。
编辑:存储的不正确,因为服务器处理更改,缓存是一个更好的术语。
使用NMS /OBC的:
这是可能的使用反射和CraftBukkit / NMS类,但这样做经常会改变,并将导致您的插件中断每一个更新,除非您的未来-证明您的反射(这方面的教程非常丰富)。
目前的问题是:
Bukkit不允许您侦听来自发出命令或直接代码库存管理的库存更改。因此,我们需要添加一种方式来侦听这些更改。这样做的最佳方法是覆盖更改库存的方法,或者添加事件以便于将来的更改,或者在那里进行计算。我将解释后者,因为它更容易处理,而且还存在各种自定义事件教程。
建立环境:
在使用NMS / OBC时,需要导入CraftBukkit以获得所需的类。下载CraftBukkit jar并将其导入到您的项目中,但是您通常是这样做的。如果收到一些方法签名方法,请确保Bukkit对导入具有更高的优先级。同样,教程可以向您展示如何在大多数IDE上修复该错误。
覆盖球员清单:
我们需要做的第一件事是创建一个球员库存类的子类。查看CraftPlayer
实例,我们看到它存储了一个CraftInventoryPlayer
类,而不是一个PlayerInventory
,因此,这是我们必须扩展的类。创建扩展CraftInventoryPlayer
的新类。确保它有一个接受net.minecraft.server.VERSION.PlayerInventory
的构造函数。该版本应由当前NMS / OBC版本字符串替换。当前的1.7.10版本是v1_7_R4
。随着几乎每一个“我的世界”版本的更改,这都会发生变化,并且是大多数版本错误的根源。通过类的扩展和构造函数调用超级构造函数,您有了一个基本的自定义清单。现在我们必须决定要覆盖哪些方法。
覆盖addAll
方法:
假设Essentials
和其他插件使用addAll
方法,这就是我们需要监视的方法。我们要做的是覆盖addAll
方法,并围绕我们希望进行的检查包装它的功能。在您的自定义库存类中,我们执行以下操作。
public HashMap<Integer, ItemStack> addItem(ItemStack... items) {
HashMap<Integer, ItemStack> leftovers = super.addItem(items);
//Examination code
return leftovers;
}
此方法将调用原始的addItem
方法,但允许您检查返回值并检查实际添加到播放机库存中的内容。通过检查items
和leftovers
中的差异,您可以确切地知道哪些项目以及其中有多少项被添加到库存中,并在发生重要事情时调用您自己的事件和方法。我让你来写考试代码,因为我不太清楚你想要完成什么。
用我们的自定义类替换播放机的库存:
我不知道该在哪里进行替换,但我已经提供了我能想到的最好的选择。当我们的插件启用时,我们想要替换播放器的库存,但是一旦它被禁用,我们需要撤销我们所做的更改,这样我们的自定义类就可以被正确地卸载。我们将听取PlayerJoinEvent
和PlayerQuitEvent
来进行这些更改。
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
CraftPlayer craftPlayer = (CraftPlayer) event.getPlayer();
//I am not actually typing this code in an IDE, so feel free to change
//the try-catch block to only catch what is needed
try {
Field field = CraftHumanEntity.class.getDeclaredField("inventory");
field.setAccessible(true);
CraftInventoryPlayer originalInventory = (CraftInventoryPlayer) field.get(craftPlayer);
//Store inventory here, I will use a Map that would be declared above.
originalInventories.put(craftPlayer, originalInventory);
field.set(craftPlayer, new CustomInventory(craftPlayer.getHandle().inventory));
} catch (Exception e) {
Bukkit.getLogger.log(Level.SEVERE, "Error creating custom player inventory", e);
}
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
CraftPlayer craftPlayer = (CraftPlayer) event.getPlayer();
//I am not actually typing this code in an IDE, so feel free to change
//the try-catch block to only catch what is needed
try {
Field field = CraftHumanEntity.class.getDeclaredField("inventory");
field.setAccessible(true);
CraftInventoryPlayer originalInventory = originalInventories.get(craftPlayer);
//Store inventory here, I will use a Map that would be declared above.
field.set(craftPlayer, originalInventory);
} catch (Exception e) {
Bukkit.getLogger.log(Level.SEVERE, "Error replacing player inventory with original", e);
}
}
这两个部分的反射有点复杂,但我会尽可能地解释它们。几乎每个Bukkit
接口在CraftBukkit
中都有一个相应的实现,该实现在接口名称前加上"Craft“。有时词序也会发生变化。在PlayerJoinEvent
侦听器中,我们获取CraftHumanEntity
类并获取它的inventory
字段。这是存储玩家库存的字段。它是私有的,所以我们使用getDeclaredField
方法而不是getField
方法,并且必须提供声明它的确切类。然后,我们让字段可以访问并操作它的数据。对于player joins,我们get
存储在该字段中的当前CraftInventoryPlayer
,然后将其存储在其他地方以供以后检索。然后,我们将该字段set
到自定义库存对象。请注意,构造函数接受了一个net.minecraft.server.PlayerInventory
,因此我们向构造函数提供该清单。我们终于捕捉到了所有可能发生的异常,我们已经成功地覆盖了玩家的清单。在PlayerQuitEvent
中,我们所做的正好相反,我们用原来的库存来代替我们的定制库存,因为我们不再需要管理它了。
,如果我上面概述的任何东西不起作用,请随时通知我。这大部分都是理论上的,但从以往处理相关问题的经验来看,它应该可以工作。
发布于 2016-12-02 10:08:32
您可以使用InventoryOpenEvent:
@EventHandler
public void onInvOpen(InventoryOpenEvent e)
也许你得检查一下玩家:
if(!(e.getPlayer().equals(anotherplayer)))
return;
然后,您可以检查库存是否是玩家的库存:
if(e.getInventory() !instanceof PlayerInventory
return;
(这只是为了检查库存是否是,播放器的库存)
您还可以通过检查库存持有者来检查哪个玩家的库存:
Player invholder = (Player) e.getInventory().getHolder();
if(!invholder.equals(*anotherplayer*))
return;
那你就有你的活动了!
(我没有测试它,但类似的代码对我有用.)
https://stackoverflow.com/questions/24962864
复制相似问题