Minecraft add new potion effects from custom potion effect - java

Currently trying to create a potion effect that once it runs out of time, applies other potion effects to the player. Seemed simple enough yet I found a few errors and bugs trying to accomplish this,
Directly trying to add the effect
#Override
public void performEffect(EntityLivingBase entity, int amplifier){
if (entity instanceof EntityPlayer)
{
EntityPlayer player = (EntityPlayer)entity;
if(player != null){
if(player.getActivePotionEffect(PotionRegistry.effectBuzz) != null){
int duraction = player.getActivePotionEffect(PotionRegistry.effectBuzz).getDuration();
if(duration <= 2){
player.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 1200));
}
}
}
}
}
Needless to say this produces this error
[16:10:04] [Server thread/ERROR]: Encountered an unexpected exception
net.minecraft.util.ReportedException: Ticking player
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:212)
~[NetworkSystem.class:?]
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:807)
~[MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:688)
~[MinecraftServer.class:?]
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:156)
~[IntegratedServer.class:?]
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:537)
[MinecraftServer.class:?]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_161]
Caused by: java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(Unknown Source) ~[?:1.8.0_161]
at java.util.HashMap$KeyIterator.next(Unknown Source) ~[?:1.8.0_161]
at net.minecraft.entity.EntityLivingBase.updatePotionEffects(EntityLivingBase.java:650)
~[EntityLivingBase.class:?]
at net.minecraft.entity.EntityLivingBase.onEntityUpdate(EntityLivingBase.java:383)
~[EntityLivingBase.class:?]
at net.minecraft.entity.Entity.onUpdate(Entity.java:436) ~[Entity.class:?]
at net.minecraft.entity.EntityLivingBase.onUpdate(EntityLivingBase.java:2144)
~[EntityLivingBase.class:?]
at net.minecraft.entity.player.EntityPlayer.onUpdate(EntityPlayer.java:260)
~[EntityPlayer.class:?]
at net.minecraft.entity.player.EntityPlayerMP.onUpdateEntity(EntityPlayerMP.java:345)
~[EntityPlayerMP.class:?]
at net.minecraft.network.NetHandlerPlayServer.update(NetHandlerPlayServer.java:174)
~[NetHandlerPlayServer.class:?]
at net.minecraftforge.fml.common.network.handshake.NetworkDispatcher$1.update(NetworkDispatcher.java:216)
~[NetworkDispatcher$1.class:?]
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:309)
~[NetworkManager.class:?]
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:197)
~[NetworkSystem.class:?]
... 5 more
Where as if I run this in a tick event
In CommonProxy
MinecraftForge.EVENT_BUS.register(new EventManager());
And then For the EventManager itself
public class EventManager {
public static PotionEffect potion = new PotionEffect(MobEffects.WEAKNESS, 1200);
public static PotionEffect potion2 = new PotionEffect(MobEffects.HUNGER, 600);
public static PotionEffect potion3 = new PotionEffect(MobEffects.UNLUCK, 1200);
#SubscribeEvent
public void onTick(WorldTickEvent event){
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
World world = Minecraft.getMinecraft().theWorld;
if(player != null){
boolean hasEffect = player.isPotionActive(PotionRegistry.effectBuzz);
int applyIt = 0;
if(hasEffect){
applyIt = 1;
} else if(!player.isPotionActive(potion.getPotion()) && applyIt == 1){
applyIt = 2;
} else {
applyIt = 0;
}
if(player != null && applyIt == 2){
player.addPotionEffect(potion);
}
}
}
}
This works, yet the effects are infinite.

You're performing your action whilst the potion effects are being looped. This is akin to modifying an array whilst iterating it. Don't do that.
Also, don't perform actions like potion effects client side.
The ONLY thing to do client side is graphics and user input/output.
Things like potions must be handled on the server, otherwise the server will overwrite your actions on the next update packet.
Just set a flag in your ExtendPlayer entity, and then onTick or player update event check for that flag existance and then add the potions.
#Override
public void performEffect(EntityLivingBase entity, int amplifier){
if (entity instanceof EntityPlayer)
{
EntityPlayer player = (EntityPlayer)entity;
if(player != null){
if(player.getActivePotionEffect(PotionRegistry.effectBuzz) != null){
int duraction = player.getActivePotionEffect(PotionRegistry.effectBuzz).getDuration();
if(duration <= 2){
ExtendedPlayer ePlayer = ExtendedPlayer.get(player);
ePlayer.enableBuzz();
}
}
}
}
}
Something akin to your Extended player
public class ExtendedPlayer implements IExtendedEntityProperties {
... Extended player setup here
protected boolean startBuzz = false;
public void enableBuzz()
{
this.startBuzz = true;
}
public static final ExtendedPlayer get(EntityPlayer player) {
return (ExtendedPlayer) player.getExtendedProperties("MuddymansExtendedPlayer");
}
public EntityPlayer getPlayer() {
return this.player;
}
/**
* Updates anything that needs to be updated each tick
* NOT called automatically, so you must call it yourself from LivingUpdateEvent or a TickHandler
*/
public void onUpdate() {
if(!player.worldObj.isRemote) {
if(this.enableBuzz) {
Player player = this.getPlayer()
player.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 1200));
player.addPotionEffect(new PotionEffect(MobEffects.HUNGER, 600));
player.addPotionEffect(new PotionEffect(MobEffects.UNLUCK, 1200));
this.startBuzz = false;
}
}
}
}
Call the exteded player update event from an event handler
#SubscribeEvent
public void livingTick(final LivingUpdateEvent event) {
if (event.entity != null && event.entity instanceof EntityPlayer) {
if(!event.entity.isDead) {
ExtendedPlayer.get((EntityPlayer)event.entity).onUpdate();
}
}

Related

How to modify sharpness damage in minecraft 1.12.2

How can I change the damage of the enchant sharpness in minecraft 1.12.2? I have tried this method but I don't understand how to go on
private RubySharpnessFixer plugin;
public EnchantmentWeaponDamageCustom(RubySharpnessFixer plugin, Rarity rarity, int i, EnumItemSlot... enumItemSlots) {
super(rarity, i, enumItemSlots);
this.plugin = plugin;
}
public float a(int i, EnumMonsterType enummonstertype) {
return (this.a == 0) ? (float)(Math.max(1, i) * plugin.getConfig().getDouble("damage-per-level")) : ((this.a == 1 && enummonstertype == EnumMonsterType.UNDEAD) ? (i * 2.5F) : ((this.a == 2 && enummonstertype == EnumMonsterType.ARTHROPOD) ? (i * 2.5F) : 0.0F));
}
public boolean hook() {
EnchantmentWeaponDamageCustom enchantmentWeaponDamageCustom = new EnchantmentWeaponDamageCustom(plugin, Rarity.COMMON, 16, EnumItemSlot.MAINHAND);
}
} ```
There is multiple ways :
1. In-game: Command
attribute #s minecraft:generic.attack_damage modifier add 0-0-0-0-0 attribute_name .25 add
(replace the 0-0-0-0-0 by a valid UUID)
There is a reddit post that explain it.
But I think it's not what you are looking for.
2. Plugin: NMS & reflection
Firstly, you have to change the enchant currently registered. Such as it's not authorized by default, we have to use reflection.
// import
import java.lang.reflect.Field;
import org.bukkit.craftbukkit.v1_12_R1.enchantments.CraftEnchantment;
import org.bukkit.enchantments.Enchantment;
// now the code :
try {
Enchantment enchantToChange = Enchantment.DAMAGE_ALL; // the enchant that we want to change
// SharpnessModifier is a class that is showed after
SharpnessModifier sharpness = new SharpnessModifier(0);
net.minecraft.server.v1_12_R1.Enchantment.enchantments.a(16, new MinecraftKey("sharpness"), sharpness); // add enchants to NMS class
CraftEnchantment newEnchant = new CraftEnchantment(sharpness);
Field byNameField = Enchantment.class.getDeclaredField("byName"); // enchant by name
byNameField.setAccessible(true);
Map<String, Enchantment> byName = (Map<String, Enchantment>) byNameField.get(null);
byName.put(enchantToChange.getName(), newEnchant);
Field byIdField = Enchantment.class.getDeclaredField("byId"); // enchant by ID
byIdField.setAccessible(true);
Map<Integer, Enchantment> byId = (Map<Integer, Enchantment>) byIdField.get(null);
byId.put(enchantToChange.getId(), newEnchant);
} catch (Exception e) {
e.printStackTrace();
}
Then, you have to create a new class that will manage all rules that you want to define for this enchant.
import net.minecraft.server.v1_12_R1.EnchantmentWeaponDamage;
import net.minecraft.server.v1_12_R1.EnumMonsterType;
import net.minecraft.server.v1_12_R1.ItemStack;
public class SharpnessModifier extends EnchantmentWeaponDamage {
public SharpnessModifier(int i){
super(Rarity.COMMON, i);
}
#Override
public int getMaxLevel() {
return 200;
}
#Override
public float a(int i, EnumMonsterType enumMonsterType){
// it's here that you will have what you want. You can calculate the damage
// default calculation :
/*
if (a == 0)
return (float) i * 5.0F;
if (a == 1 && enumMonsterType == EnumMonsterType.UNDEAD)
return (float) i * 2.5F;
if (a == 2 && enumMonsterType == EnumMonsterType.ARTHROPOD)
return (float) i * 2.5F;
else
return 0.0F;
*/
return Float.MAX_VALUE; // max damage, just to try. I just OS a wither
}
#Override
public boolean canEnchant(ItemStack item) {
return true; // allow for all item
}
}
3. Plugin: Damage event
This can also be done with packet.
You have to intercept damage event, and change damage value if player have sharpness.
#EventHandler
public void a(EntityDamageByEntityEvent e) {
if(e.getDamager() instanceof Player) {
Player p = (Player) e.getDamager();
ItemStack item = p.getItemInHand();
if(item.containsEnchantment(Enchantment.DAMAGE_ALL)) {
// manage damage with "e.setDamage(damage);"
}
}
}
It's not a very good solution because other things can interact with damage: critical, time (1.9+ pvp) ...

How can i conditionally prevent a user from navigating to a different view/part in eclipse E4 RCP application?

I am trying to prevent a user from going to a different view/part in a perspective of eclipse E4 application.When i am trying to navigate to the same perspective and view,I am facing a stackOverflow exception due to recursively calling the showPart method by the framework.
NavigationHelper.showPerspective(CommonConstants.PERSPECTIVE1, getEclipseContext());
NavigationHelper.showPart(CommonConstants.VIEW1, getEclipseContext());
NavigationHelper.showPart(CommonConstants.VIEW2, getEclipseContext());
My showPart method lokks like this,
public static boolean showPart(String partId, IEclipseContext eclipseContext) {
logger.debug("showPart::STARTED::" + partId);
if (null == eclipseContext) {
eclipseContext = getEclipseContext();
}
if (Model.getInstance().hasDataChanged()) {
if (partId.equalsIgnoreCase(CommonConstants.VIEW1)
|| partId.equalsIgnoreCase(CommonConstants.VIEW2)) {
isNavigationSuccessful = true;
} else {
isNavigationSuccessful = false;
Navigation.showWarning();
}
}
if (isNavigationSuccessful) {
findPartAndActivate(partId, eclipseContext, true);
}
logger.debug("isNavigationSuccessful = " + isNavigationSuccessful);
logger.debug("showPart::END::" + partId);
return isNavigationSuccessful;
}
The findPartAndActivate looks like this
private static boolean findPartAndActivate(String partId, IEclipseContext eclipseContext, boolean giveFocus) {
MTrimmedWindow applicationWindow = ((MTrimmedWindow) ((MApplication) eclipseContext.get(MApplication.class))
.getChildren().get(0));
IEclipseContext currentContext = applicationWindow.getContext();
EPartService partService = currentContext.get(EPartService.class);
EModelService modelService = currentContext.get(EModelService.class);
MPart part = (MPart) modelService.find(partId, eclipseContext.get(MApplication.class).getChildren().get(0));
partService.activate(part, giveFocus);
return true;
}
The partDeactivated is invoked,once a user leaves from a part/View
public void partDeactivated(#Active MPart part) {
if (partInstance.getElementId() != part.getElementId()) {
return;
}
if (transactionButton != null && !transactionButton.isDisposed() && transactionButton.isEnabled()
&& isTransactionCompleted && NavigationHelper.getEditableViewInstance() != null && !partDeactivateFlag) {
doTransaction();
partDeactivateFlag = true;
}
if (Navigation.isPerspective()) {
if (EModel.getInstance().hasDataChanged()/*&& !Model.getInstance().isSwitchFlag()*/) {
System.out.println("Changes");
//Model.getInstance().setSwitchFlag(true);
//partDeactivateFlag = true;
NavigationHelper.showPerspective(CommonConstants.PERSPECTIVE1, getEclipseContext());
NavigationHelper.showPart(CommonConstants.VIEW1, getEclipseContext());
NavigationHelper.showPart(CommonConstants.VIEW2, getEclipseContext());
}
}
viewDeactivated();
}
};
java.lang.StackOverflowError : null
org.eclipse.e4.ui.workbench.modeling.ElementMatcher.select(ElementMatcher.java:71)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElementsRecursive(ModelServiceImpl.java:182)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElementsRecursive(ModelServiceImpl.java:317)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElementsRecursive(ModelServiceImpl.java:271)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElementsRecursive(ModelServiceImpl.java:271)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElementsRecursive(ModelServiceImpl.java:271)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElementsRecursive(ModelServiceImpl.java:251)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElementsRecursive(ModelServiceImpl.java:271)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElements(ModelServiceImpl.java:428)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElements(ModelServiceImpl.java:409)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.findElements(ModelServiceImpl.java:414)
org.eclipse.e4.ui.internal.workbench.ModelServiceImpl.find(ModelServiceImpl.java:448)
This is the StackOverflow trace..
How can I solve this..?
Well the stack trace shows this is an error in your code. You are running NavigationHelper.showPart in a part deactivated listener, but your code is causing another part deactivate event which calls the deactivate listener again which calls showPart again and so on.
You can't try to show a different part in the the part deactivate listener directly.
One possibility is to use Display.asyncExec in the part deactivate listener to run the showPart after the deactivate event has completed.

Healing/Damage Blocks are outputting twice?

#EventHandler
public void playerInteraction(PlayerInteractEvent event)
{
Action action = event.getAction();
Player player = event.getPlayer();
Block block = event.getClickedBlock();
if (action.equals(Action.RIGHT_CLICK_BLOCK))
{
if (block.getType().equals(Material.NETHER_WART_BLOCK))
{
player.setHealth(player.getHealth() -1);
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_HURT, 10, 1);
}
else if (block.getType().equals(Material.DIAMOND_BLOCK))
{
player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 1000, 2));
player.playSound(player.getLocation(), Sound.ENTITY_SPLASH_POTION_BREAK, 10, 1);
}
else if(block.getType().equals(Material.EMERALD_BLOCK))
{
if (player.getHealth() != 20)
{
player.setHealth(player.getHealth() + 1);
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 10, 1);;
}
if (player.getHealth() == 20)
{
player.sendMessage(ChatColor.DARK_RED + "You are already at full health!");
}
}
}
}
For some reason, all of these things happen twice whenever I right click the designated blocks. Anyone know why? I have posted the entire method, it's a player interaction event.
Thanks :)
First of all, make sure yo haven't registered the Listener class containing the event handler twice.
If that's not the case, according to this thread on the spigot forums, since Mojang added the left hand slot to Minecraft some events like PlayerInteractEvent or InventoryClickEvent will be called twice (once for each hand).
One possible fix is to "disable" the left hand on the event handler:
#EventHandler
public void onPlayerInteraction(PlayerInteractEvent event) {
if(event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getHand() == EquipmentSlot.HAND) {
//Do something once
}
}
If you require that both hands could be used to trigger the event you could do the following:
First time the code gets executed you add the player to a list.
Before executing the code you check if the player is in the list. If it's in the list it means the code was executed once so you can skip it.
Schedule a task to remove the player from the list some ticks later.
The code could be as follows:
public class Foo implements Listener {
//An instance of the main plugin class
private MainClass plugin;
private List<UUID> playerBlacklist = new ArrayList<>();
#EventHandler
public void onPlayerInteractEvent(PlayerInteractEvent event) {
if(playerBlacklist.contains(event.getPlayer().getUniqueId)) {
return;
} else {
blacklistPlayer(event.getPlayer());
}
//Do something
}
private void blacklistPlayer(UUID uuid) {
playerBlacklist.add(uuid);
BukkitRunnable runnable = new BukkitRunnable(){
#Override
public void run() {
playerBlacklist.remove(uuid);
}
}
runnable.runTaskLaterAsynchronously(plugin, 5L);
}
}
Let me know if this solved your issue.

Inventory ClickEvent not working

When I click the Item in the Inventory, it simply does nothing and I can drag it anywhere I want. Then I re-open the inventory and the Item is back. I want the item a click (The Notify item in this case) to toggle the notify boolean and close the Inventory. Please help. It may be a stupid solution but sometimes the simple stuff can escape me. Thanks.
This is the Inventory:
public class GUI extends JavaPlugin implements Listener
{
private API api;
AlphaCommand command = new AlphaCommand();
public static Inventory inv = Bukkit.createInventory(null, 9, ChatColor.AQUA + "Alpha Config");
public static boolean isNotifyEnabled()
{
return AlphaCommand.notify;
}
protected String getCheckName()
{
return this.getCheckName();
}
public static void openGUI(Player player, Inventory inv)
{
ItemStack checks = new ItemStack(Material.DIAMOND_SWORD);
ItemStack banPlayer = new ItemStack(Material.GOLD_AXE);
ItemStack autoBan = new ItemStack(Material.DIAMOND_AXE);
ItemStack notify = new ItemStack(Material.SLIME_BALL);
ItemMeta checksMeta = checks.getItemMeta();
ItemMeta autoBanMeta = autoBan.getItemMeta();
ItemMeta notifyMeta = notify.getItemMeta();
ItemMeta banPlayerMeta = banPlayer.getItemMeta();
checksMeta.setDisplayName(ChatColor.BLUE + "Checks");
autoBanMeta.setDisplayName(ChatColor.BLUE + "AutoBan");
notifyMeta.setDisplayName(ChatColor.BLUE + "Notify");
banPlayerMeta.setDisplayName(ChatColor.BLUE + "Ban Player");
checks.setItemMeta(checksMeta);
autoBan.setItemMeta(autoBanMeta);
notify.setItemMeta(notifyMeta);
banPlayer.setItemMeta(banPlayerMeta);
inv.setItem(7, banPlayer);
inv.setItem(1, checks);
inv.setItem(3, autoBan);
inv.setItem(5, notify);
player.openInventory(inv);
}
public static void open(Player player, Inventory inv)
{
if(player instanceof Player)
{
player.openInventory(inv);
}
}
public static Inventory getGUI(){
return inv;
}
#EventHandler
public void onInventoryClick(InventoryClickEvent e)
{
Bukkit.getPluginManager().registerEvents(this, Bukkit.getPluginManager().getPlugins()[0]);
String invName = ChatColor.stripColor(e.getClickedInventory().getName());
Player player = (Player) e.getWhoClicked(); // The player that clicked the item
ItemStack clicked = e.getCurrentItem(); // The item that was clicked
#SuppressWarnings("unused")
Inventory inventory = e.getInventory(); // The inventory that was clicked in
if(invName.equalsIgnoreCase(inv.getName()))
{
if((clicked == null) || (clicked.getType() == Material.AIR) || (!clicked.hasItemMeta()))
{
player.closeInventory();
return;
}
if(clicked.getItemMeta().getDisplayName().equalsIgnoreCase("AutoBan"))
{
Configuration config = this.api.getConfiguration();
boolean autoBan = config.readBoolean("checks." + getCheckName() + ".AutoBan");
if (config.readBoolean("checks." + getCheckName() + ".AutoBan") == true)
{
autoBan = false;
e.setCancelled(true);
player.closeInventory();
return;
}
else if(autoBan == false)
{
autoBan = true;
e.setCancelled(true);
player.closeInventory();
return;
}
else
{
e.setCancelled(true);
player.closeInventory();
return;
}
}
if(clicked.getItemMeta().getDisplayName().equalsIgnoreCase("Notify"))
{
boolean notify = isNotifyEnabled();
if(notify == true)
{
notify = false;
e.setCancelled(true);
player.closeInventory();
return;
}
else if(notify == false)
{
notify = true;
e.setCancelled(true);
player.closeInventory();
return;
}
}
if(clicked.getItemMeta().getDisplayName().equalsIgnoreCase("Checks"))
{
player.sendMessage(ChatColor.RED + "This Feature is coming soon to Alpha.");
e.setCancelled(true);
player.closeInventory();
return;
}
if(e.getCurrentItem().getItemMeta().getDisplayName().equalsIgnoreCase("Ban Player"))
{
player.sendMessage("This Feature is coming soon to Alpha V.4");
e.setCancelled(true);
player.closeInventory();
return;
}else
{
player.closeInventory();
e.setCancelled(true);
return;
}
}
}
}
There seems to be multiple issues in the code that you have provided above that will cause the expected result to not be seen.
#1
Firstly you register the events for this class, inside the event itself, which means it'll never get registered unless the event get's called, which will never happen unless you register it... See the problem? So what you need to do is move the following line of code into your onEnable method.
Bukkit.getPluginManager().registerEvents(this, Bukkit.getPluginManager().getPlugins()[0]);
You need to make a few changes to this line of code. You need to replace this with a new instance of the listener object, new GUI(). It's also recommended that you register the listener with the plugin that your calling it from, but fortunately, if you put this in your onEnable, your onEnable method is inside your plugin class. This means that you can change your plugin to this. You new line of code will look like this.
Bukkit.getPluginManager().registerEvents(new GUI(), this);
Put that in your onEnable and that issue here should be resolved.
#2
The second issue is that when you're checking your item names and you're not stripping colour. This get's rid of an colours in the string. This is because your item names are ChatColor.BLUE + "AutoBan" however you're checking if it equals "AutoBan" which is different. All you need to do to fix this issue is exactly the same with what you did with the inventory name, and use ChatColor.stripColor(itemName) to get a string you can check against.
For example:
String itemName = ChatColor.stripColor(clicked.getItemMeta().getDisplayName());
if (itemName.equals("AutoBan")){
Note: I also replaced equalsIgnoreCase with equals as the cases always matched, so was an unnecessary check.

How to check if a player right-clicked another player

Looking for the right event to work with. I want to check if a player right-clicked another player.
This is what i have so far (doesn't work. Not getting into the if or the else statement:
public void onPlayerRightClicks(PlayerInteractEntityEvent e) {
Player p=e.getPlayer();
if(e.getRightClicked() instanceof Player) p.sendMessage("You have rightclicked a player.");
else p.sendMessage("You didn't hit anyone with your spell");
}
Found the answer to the question by combining my own code with codes from another answer on a similar question:
#SuppressWarnings("deprecation")
#EventHandler
public void onPlayerClick(PlayerInteractEvent e) {
Player p=e.getPlayer();
NBTItem item = new NBTItem(p.getItemInHand());
Entity en=getNearestEntityInSight(p,5);
if(e.getAction()==Action.RIGHT_CLICK_AIR && en instanceof Player) p.sendMessage("You have rightclicked a player.");
else p.sendMessage("You didn't hit anyone with your spell");
}
public static Entity getNearestEntityInSight(Player player, int range) {
ArrayList<Entity> entities = (ArrayList<Entity>) player.getNearbyEntities(range, range, range);
ArrayList<Block> sightBlock = (ArrayList<Block>) player.getLineOfSight(null, range);
ArrayList<Location> sight = new ArrayList<Location>();
for (int i = 0;i<sightBlock.size();i++)
sight.add(sightBlock.get(i).getLocation());
for (int i = 0;i<sight.size();i++) {
for (int k = 0;k<entities.size();k++) {
if (Math.abs(entities.get(k).getLocation().getX()-sight.get(i).getX())<1.3) {
if (Math.abs(entities.get(k).getLocation().getY()-sight.get(i).getY())<1.5) {
if (Math.abs(entities.get(k).getLocation().getZ()-sight.get(i).getZ())<1.3) {
return entities.get(k);
}
}
}
}
}
return null;
}
Even though it works, i don't think it's an optimal answer, as there should be an event that can check whether or not a player rightclicked or at least leftclicked another player. The getNearestEntitySight method finds the closest entity in the player's sight. I combined it with my code which runs when a player rightclicks, using the PlayerInteractEvent.
Try this:
#EventHandler
public void onPlayerInteractEntity(final PlayerInteractAtEntityEvent e) {
final Player p = e.getPlayer();
if (e.getRightClicked() instanceof Player) {
final Player clicked = (Player) e.getRightClicked();
// DO STUFF
}
}

Categories

Resources