use of me.deecaad.weaponmechanics.weapon.projectile.HitBox in project MechanicsMain by WeaponMechanics.
the class WeaponProjectile method getHits.
private List<RayTraceResult> getHits(boolean disableEntityCollisions) {
List<RayTraceResult> hits = null;
Vector normalizedMotion = getNormalizedMotion();
Vector location = getLocation();
double distance = Math.ceil(getMotionLength());
// If distance is 0 or below, it will cause issues
if (NumberUtil.equals(distance, 0.0))
distance = 1;
BlockIterator blocks = new BlockIterator(getWorld(), location, normalizedMotion, 0.0, (int) distance);
int maximumBlockHits = through == null ? 1 : through.getMaximumThroughAmount() + 1;
while (blocks.hasNext()) {
Block block = blocks.next();
if (equalToLastHit(block))
continue;
HitBox blockBox = weaponCompatibility.getHitBox(block);
if (blockBox == null)
continue;
RayTraceResult rayTraceResult = blockBox.rayTrace(location, normalizedMotion);
// Didn't hit
if (rayTraceResult == null)
continue;
if (hits == null)
hits = new ArrayList<>(1);
hits.add(rayTraceResult);
// If through isn't used, it is enough to get one block hit
if (through == null)
break;
// projectile can't go through blocks anymore after this one.
if (--maximumBlockHits == 0)
break;
// If it isn't valid it can't go through
if (!through.quickValidCheck(block.getType()))
break;
}
if (!disableEntityCollisions) {
List<LivingEntity> entities = getPossibleEntities();
if (entities != null && !entities.isEmpty()) {
for (LivingEntity entity : entities) {
if (equalToLastHit(entity))
continue;
HitBox entityBox = weaponCompatibility.getHitBox(entity);
if (entityBox == null)
continue;
RayTraceResult rayTraceResult = entityBox.rayTrace(location, normalizedMotion);
// Didn't hit
if (rayTraceResult == null)
continue;
if (hits == null)
hits = new ArrayList<>(1);
hits.add(rayTraceResult);
}
}
}
// Sort based on the distance travelled before hit if there is more than 1 hits
if (hits != null && hits.size() > 1)
hits.sort((hit1, hit2) -> (int) (hit1.getDistanceTravelled() - hit2.getDistanceTravelled()));
return hits;
}
use of me.deecaad.weaponmechanics.weapon.projectile.HitBox in project MechanicsMain by WeaponMechanics.
the class Ray method getEntities.
public Map<Entity, HitBox> getEntities(TraceCollision collision) {
// The number 2.0 is taken from Mojang's code. It is probably big
// enough to include entities whose hit-box is within the bounds, but
// their actual location is not in the box.
Vector min = VectorUtil.add(VectorUtil.min(origin, end), -2.0, -2.0, -2.0);
Vector max = VectorUtil.add(VectorUtil.max(origin, end), 2.0, 2.0, 2.0);
int minChunkX = (int) Math.floor(min.getX() / 16.0);
int minChunkZ = (int) Math.floor(min.getZ() / 16.0);
int maxChunkX = (int) Math.ceil(max.getX() / 16.0);
int maxChunkZ = (int) Math.ceil(max.getZ() / 16.0);
// Using Map for O(1) lookup
Map<Entity, HitBox> temp = new HashMap<>();
// By reusing the same location, we stop spigot from instantiating a
// new location every time we grab an entity's location. This probably
// saves computing power.
Location reuse = new Location(null, 0, 0, 0);
for (int x = minChunkX; x <= maxChunkX; x++) {
for (int z = minChunkZ; z <= maxChunkZ; z++) {
Chunk chunk = world.getChunkAt(x, z);
for (Entity entity : chunk.getEntities()) {
if (contains(min, max, entity.getLocation(reuse)) && collision.canHit(entity)) {
temp.put(entity, WeaponCompatibilityAPI.getWeaponCompatibility().getHitBox(entity));
}
}
}
}
return temp;
}
use of me.deecaad.weaponmechanics.weapon.projectile.HitBox 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.weapon.projectile.HitBox in project MechanicsMain by WeaponMechanics.
the class MeleeHandler method getPossibleEntities.
private List<LivingEntity> getPossibleEntities(LivingEntity shooter, Location start, Vector end) {
// Get the box of current location to end of this iteration
HitBox hitBox = new HitBox(start.toVector(), end);
int minX = floor((hitBox.getMinX() - 2.0D) / 16.0D);
int maxX = floor((hitBox.getMaxX() + 2.0D) / 16.0D);
int minZ = floor((hitBox.getMinZ() - 2.0D) / 16.0D);
int maxZ = floor((hitBox.getMaxZ() + 2.0D) / 16.0D);
List<LivingEntity> entities = new ArrayList<>(8);
World world = start.getWorld();
for (int x = minX; x <= maxX; ++x) {
for (int z = minZ; z <= maxZ; ++z) {
Chunk chunk = world.getChunkAt(x, z);
for (final Entity entity : chunk.getEntities()) {
if (!entity.getType().isAlive() || entity.isInvulnerable() || entity.getEntityId() == shooter.getEntityId())
continue;
entities.add((LivingEntity) entity);
}
}
}
return entities.isEmpty() ? null : entities;
}
use of me.deecaad.weaponmechanics.weapon.projectile.HitBox in project MechanicsMain by WeaponMechanics.
the class DefaultExposure method getExposure.
/**
* Gets a double [0, 1] representing how exposed the entity is to the explosion
*
* @param vec3d The origin of the explosion
* @param entity The entity exposed to the explosion
* @return The level of exposure of the entity to the epxlosion
*/
private static double getExposure(Vector vec3d, Entity entity) {
HitBox box = WeaponCompatibilityAPI.getWeaponCompatibility().getHitBox(entity);
if (box == null) {
return 0.0;
}
// Get the dimensions of the bounding box
double width = box.getWidth();
double height = box.getHeight();
double depth = box.getDepth();
// Gets the size of the grid in each axis
double stepX = width * 2.0 + 1.0;
double stepY = height * 2.0 + 1.0;
double stepZ = depth * 2.0 + 1.0;
double gridX = 1.0 / stepX;
double gridY = 1.0 / stepY;
double gridZ = 1.0 / stepZ;
// Outside the grid
if (gridX < 0.0 || gridY < 0.0 || gridZ < 0.0)
return 0.0;
double d3 = (1.0 - Math.floor(stepX) * gridX) / 2.0;
double d4 = (1.0 - Math.floor(stepZ) * gridZ) / 2.0;
// Setup variables for the loop
World world = entity.getWorld();
int successfulTraces = 0;
int totalTraces = 0;
// For each grid on the bounding box
for (double x = 0; x <= 1; x += gridX) {
for (double y = 0; y <= 1; y += gridY) {
for (double z = 0; z <= 1; z += gridZ) {
double a = NumberUtil.lerp(box.getMinX(), box.getMaxX(), x);
double b = NumberUtil.lerp(box.getMinY(), box.getMaxY(), y);
double c = NumberUtil.lerp(box.getMinZ(), box.getMaxZ(), z);
// Calculates a path from the origin of the explosion
// (0, 0, 0) to the current grid on the entity's bounding
// box. The Vector is then ray traced to check for obstructions
Vector vector = new Vector(a + d3, b, c + d4).subtract(vec3d);
Ray ray = new Ray(vec3d.toLocation(world), vector);
TraceResult trace = ray.trace(TraceCollision.BLOCK, 0.3);
if (trace.getBlocks().isEmpty()) {
successfulTraces++;
}
totalTraces++;
}
}
}
// The percentage of successful traces
return ((double) successfulTraces) / totalTraces;
}
Aggregations