use of me.deecaad.weaponmechanics.compatibility.IWeaponCompatibility in project MechanicsMain by WeaponMechanics.
the class Ray method trace.
/**
* Traces along this ray, colliding with block(s) and/or entity(s), depending on the given
* <code>collision</code>.
*
* @param collision What the ray collides with
* @param accuracy The distance (in blocks) between checks
* @param isShow Useful for debugging. Spawns redstone particles that are removed after 1 minute
* @return The collision data
*/
public TraceResult trace(@Nonnull TraceCollision collision, @Nonnegative double accuracy, boolean isShow) {
IWeaponCompatibility factory = WeaponCompatibilityAPI.getWeaponCompatibility();
// Store the entities between the starting and ending point of the ray. Map the
// entities to their hit box. If this ray is too long, this method becomes
// inefficient -- Ideally rays should be kept to 25 blocks max
Map<Entity, HitBox> availableEntities = collision.isHitEntity() ? getEntities(collision) : Collections.emptyMap();
// can hit, then we can take a shortcut and return an empty trace result, saving resources
if (!collision.isHitBlock() && availableEntities.isEmpty()) {
return new TraceResult(Collections.emptySet(), Collections.emptySet());
}
final LinkedHashSet<Block> blocks = new LinkedHashSet<>();
final LinkedHashSet<Entity> entities = new LinkedHashSet<>();
// Step is a number [0.0, 1.0] that defines a percentage of distance
// between our starting and stopping point. If step exceeds 1, that
// means the Ray is shorter than the accuracy allows.
double step = accuracy / directionLength;
if (step > 1.0) {
return new TraceResult(entities, blocks);
}
// We start i at step to skip the first trace step. Doing this will
// help prevent explosion rays from being blocks by minor floating
// point differences. See issue #26.
boolean collides = false;
for (double i = step; i <= 1; i += step) {
Vector point = VectorUtil.lerp(origin, end, i);
Block block = world.getBlockAt(point.getBlockX(), point.getBlockY(), point.getBlockZ());
// if this specific block can be hit, and if we actually collide with the block's hitbox
if (collision.isHitBlock() && collision.canHit(block) && contains(factory.getHitBox(block), point)) {
blocks.add(block);
collides = true;
}
// entity's hitbox
for (Map.Entry<Entity, HitBox> entry : availableEntities.entrySet()) {
Entity entity = entry.getKey();
HitBox hitbox = entry.getValue();
if (collision.isHitEntity() && collision.canHit(entity) && contains(hitbox, point)) {
entities.add(entity);
collides = true;
if (collision.isFirst()) {
break;
}
}
}
// once, then break out of the loop
if (collides && collision.isFirst()) {
break;
}
// particle for each point.
if (isShow) {
displayPoint(point, collides);
}
collides = false;
}
return new TraceResult(entities, blocks);
}
use of me.deecaad.weaponmechanics.compatibility.IWeaponCompatibility in project MechanicsMain by WeaponMechanics.
the class MoveTask method isInMidair.
/**
* Basically checks if entity is in mid air.
* Mid air is determined on if current block in player's position doesn't have hit box and block below that doesn't have hit box either
*/
private boolean isInMidair(LivingEntity livingEntity) {
IWeaponCompatibility weaponCompatibility = WeaponCompatibilityAPI.getWeaponCompatibility();
Block current = livingEntity.getLocation().getBlock();
Block below = current.getRelative(BlockFace.DOWN);
// Check for liquid as hit boxes are considered null if block is liquid
if (current.isLiquid() || below.isLiquid())
return false;
HitBox belowHitBox = weaponCompatibility.getHitBox(below);
HitBox currentHitBox = weaponCompatibility.getHitBox(current);
return belowHitBox == null && currentHitBox == null;
}
use of me.deecaad.weaponmechanics.compatibility.IWeaponCompatibility in project MechanicsMain by WeaponMechanics.
the class RayTraceCommand method execute.
@Override
public void execute(CommandSender sender, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(ChatColor.RED + "This command is only available for players.");
return;
}
Player player = (Player) sender;
boolean onlyHitPosition = args.length > 0 && Boolean.parseBoolean(args[0]);
int distance = (args.length > 1) ? Integer.parseInt(args[1]) : 5;
if (distance < 1) {
sender.sendMessage(ChatColor.RED + "Distance was less than 1");
return;
}
int time = (args.length > 2) ? Integer.parseInt(args[2]) : 200;
sender.sendMessage(ChatColor.GREEN + "Showing hitboxes in distance " + distance + " for " + time + " ticks");
IWeaponCompatibility weaponCompatibility = WeaponCompatibilityAPI.getWeaponCompatibility();
new BukkitRunnable() {
int ticker = 0;
@Override
public void run() {
Location location = player.getEyeLocation();
Vector direction = location.getDirection();
BlockIterator blocks = new BlockIterator(player.getWorld(), location.toVector(), direction, 0.0, distance);
while (blocks.hasNext()) {
Block block = blocks.next();
HitBox blockBox = weaponCompatibility.getHitBox(block);
if (blockBox == null)
continue;
RayTraceResult rayTraceResult = blockBox.rayTrace(location.toVector(), direction);
if (rayTraceResult == null)
continue;
if (onlyHitPosition) {
rayTraceResult.outlineOnlyHitPosition(player);
} else {
blockBox.outlineAllBoxes(player);
}
player.sendMessage("Block: " + block.getType());
break;
}
Collection<Entity> entities = player.getWorld().getNearbyEntities(location, distance, distance, distance);
if (!entities.isEmpty()) {
for (Entity entity : entities) {
if (!(entity instanceof LivingEntity) || entity.getEntityId() == player.getEntityId())
continue;
HitBox entityBox = weaponCompatibility.getHitBox(entity);
if (entityBox == null)
continue;
RayTraceResult rayTraceResult = entityBox.rayTrace(location.toVector(), direction);
if (rayTraceResult == null)
continue;
if (onlyHitPosition) {
rayTraceResult.outlineOnlyHitPosition(player);
} else {
entityBox.outlineAllBoxes(player);
}
player.sendMessage("Entity: " + entity.getType());
break;
}
}
if (++ticker >= time) {
cancel();
}
}
}.runTaskTimer(WeaponMechanics.getPlugin(), 0, 0);
}
Aggregations