I'm trying to do a plugin where guns can shoot ammo, and I want that when the ammo hit a block (= block of the location of the ammo isn't air), this ammo destroys the block
The problem is that the following code (Ammo class) has the 'moveFrom()' method calling itself infinitely.
I get an error in the console : StackOverflowError, so I'm pretty sure the problem comes from the recursive method.
Any suggestion is welcomed !
package fr.laponie.ShooterPlugin;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.util.Vector;
import net.minecraft.server.v1_8_R3.EnumParticle;
import net.minecraft.server.v1_8_R3.PacketPlayOutWorldParticles;
public class Ammo {
public Ammo(Player p,Weapon w) {
this.p = p;
this.w = w;
this.loc = p.getLocation();
}
Player p;
Weapon w;
Location loc;
public void moveFrom(Location init) {
Location eyeLoc = p.getEyeLocation();
Vector dir = eyeLoc.getDirection();
dir = dir.add(new Vector(1,1,1));
Vector distance = new Vector(0.4,0.4,0.4);
distance = distance.add(dir);
this.loc = distance.toLocation(p.getWorld());
EnumParticle trail = EnumParticle.CRIT;
Block target = this.loc.getBlock();
if (target.getType() == Material.SAND) {
p.sendMessage(ChatColor.DARK_AQUA + "" + ChatColor.BOLD + "HIT SAND");
target.setType(Material.AIR);
return;
}
Location particleLoc = this.loc;
PacketPlayOutWorldParticles packParticle = new PacketPlayOutWorldParticles(trail, false, (float) particleLoc.getX(),(float) particleLoc.getY(),(float) particleLoc.getZ(),
0,0,0,0,0, null);
CraftPlayer cp = (CraftPlayer) p;
cp.getHandle().playerConnection.sendPacket(packParticle);
moveFrom(loc);
}
public void moveTo(Location destination) {
this.loc = destination;
}
public void setLocation(Location loc) {
this.loc = loc;
}
}
And here is the PlayerInteractEvent() :
@EventHandler
public void onRightClickWeapon(PlayerInteractEvent e) {
Player p = e.getPlayer();
Action a = e.getAction();
ItemStack current = p.getItemInHand();
ItemStack rifle = new AssaultRifle().mat;
int count = 0;
Location eyeloc = p.getEyeLocation();
Vector defaultVector = new Vector(1,1,1);
Vector distance = new Vector(0.4,0.4,0.4);
Vector dir = eyeloc.getDirection();
if (a == Action.RIGHT_CLICK_AIR || a == Action.RIGHT_CLICK_BLOCK) {
if (current.getType() == rifle.getType() && current.getItemMeta().getDisplayName().equalsIgnoreCase(rifle.getItemMeta().getDisplayName())) {
Ammo ammo = new Ammo(p, this);
ammo.setLocation(p.getLocation());
while (ammo.loc.getBlock().getType() == Material.AIR) {
ammo.moveFrom(eyeloc);
}
}
}
}
EDIT: And even if i try with a for-loop like here : it does nothing
@EventHandler
public void onRightClickWeapon(PlayerInteractEvent e) {
Player p = e.getPlayer();
Action a = e.getAction();
ItemStack current = p.getItemInHand();
ItemStack rifle = new AssaultRifle().mat;
int count = 0;
Location eyeloc = p.getEyeLocation();
Vector defaultVector = new Vector(1,1,1);
Vector distance = new Vector(0.4,0.4,0.4);
Vector dir = eyeloc.getDirection();
if (a == Action.RIGHT_CLICK_AIR || a == Action.RIGHT_CLICK_BLOCK) {
if (current.getType() == rifle.getType() && current.getItemMeta().getDisplayName().equalsIgnoreCase(rifle.getItemMeta().getDisplayName())) {
Ammo ammo = new Ammo(p, this);
ammo.setLocation(p.getLocation());
while (ammo.loc.getBlock().getType() == Material.AIR) {
Location eyeLoc = p.getEyeLocation();
dir = eyeLoc.getDirection();
dir = dir.add(new Vector(1,1,1));
distance = new Vector(0.4,0.4,0.4);
distance = distance.add(dir);
ammo.loc = distance.toLocation(p.getWorld());
EnumParticle trail = EnumParticle.CRIT;
Block target = ammo.loc.getBlock();
if (target.getType() == Material.SAND) {
p.sendMessage(ChatColor.DARK_AQUA + "" + ChatColor.BOLD + "HIT SAND");
target.setType(Material.AIR);
return;
}
Location particleLoc = ammo.loc;
PacketPlayOutWorldParticles packParticle = new PacketPlayOutWorldParticles(trail, false, (float) particleLoc.getX(),(float) particleLoc.getY(),(float) particleLoc.getZ(),
0,0,0,0,0, null);
CraftPlayer cp = (CraftPlayer) p;
cp.getHandle().playerConnection.sendPacket(packParticle);
}
}
}
}
Firstly, you should refactor your
moveFrom(...)method to use a while loop instead of recursion. Recursion requires another stack frame for each recursive call and will use vastly more resources than a while loop.Secondly it seems that
moveFrom(...)will only exit whentarget.getType() == Material.SAND. I'm guessing you hit the max stack depth before you move to a sandy patch