Rewrite raytracing methods and optimise their usage
This commit is contained in:
@@ -208,7 +208,6 @@ public final class WizardryClientEventHandler {
|
||||
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
WizardData properties = WizardData.get(mc.player);
|
||||
RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.world, mc.player, 16, false);
|
||||
RenderManager renderManager = event.getRenderer().getRenderManager();
|
||||
|
||||
ItemStack wand = mc.player.getHeldItemMainhand();
|
||||
@@ -218,45 +217,51 @@ public final class WizardryClientEventHandler {
|
||||
}
|
||||
|
||||
// Target selection pointer
|
||||
if(mc.player.isSneaking() && wand.getItem() instanceof ItemWand && rayTrace != null && !(event.getEntity() instanceof EntityArmorStand)
|
||||
&& rayTrace.entityHit == event.getEntity() && properties != null && properties.selectedMinion != null){
|
||||
if(mc.player.isSneaking() && wand.getItem() instanceof ItemWand && WizardryUtilities.isLiving(event.getEntity())
|
||||
&& properties != null && properties.selectedMinion != null){
|
||||
|
||||
// -> Moved this in here so it isn't called every tick
|
||||
RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.world, mc.player, 16, false);
|
||||
|
||||
if(rayTrace != null && rayTrace.entityHit == event.getEntity()){
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
// Disabling depth test allows it to be seen through everything.
|
||||
GlStateManager.disableDepth();
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
// Disabling depth test allows it to be seen through everything.
|
||||
GlStateManager.disableDepth();
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
|
||||
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ());
|
||||
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ());
|
||||
|
||||
// This counteracts the reverse rotation behaviour when in front f5 view.
|
||||
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
|
||||
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
|
||||
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
|
||||
// This counteracts the reverse rotation behaviour when in front f5 view.
|
||||
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
|
||||
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
|
||||
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
mc.renderEngine.bindTexture(targetPointerTexture);
|
||||
mc.renderEngine.bindTexture(targetPointerTexture);
|
||||
|
||||
buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex();
|
||||
buffer.pos(0.2, 0.24, 0).tex(9f / 16f, 0).endVertex();
|
||||
buffer.pos(0.2, -0.24, 0).tex(9f / 16f, 11f / 16f).endVertex();
|
||||
buffer.pos(-0.2, -0.24, 0).tex(0, 11f / 16f).endVertex();
|
||||
buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex();
|
||||
buffer.pos(0.2, 0.24, 0).tex(9f / 16f, 0).endVertex();
|
||||
buffer.pos(0.2, -0.24, 0).tex(9f / 16f, 11f / 16f).endVertex();
|
||||
buffer.pos(-0.2, -0.24, 0).tex(0, 11f / 16f).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.enableDepth();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
// Summoned creature selection pointer
|
||||
|
||||
@@ -70,6 +70,8 @@ public abstract class SpellRay extends Spell {
|
||||
protected boolean ignoreEntities = false;
|
||||
/** Whether liquids count as blocks when raytracing. Defaults to false. */
|
||||
protected boolean hitLiquids = false;
|
||||
/** The aim assist to use when raytracing. Defaults to 0. */
|
||||
protected float aimAssist = 0;
|
||||
|
||||
public SpellRay(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, boolean isContinuous, double baseRange, SoundEvent sound){
|
||||
this(Wizardry.MODID, name, tier, element, type, cost, cooldown, isContinuous, baseRange, sound);
|
||||
@@ -147,6 +149,17 @@ public abstract class SpellRay extends Spell {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aim assist to use when raytracing.
|
||||
* @param particleVelocity The aim assist to use when raytracing. See {@link WizardryUtilities#rayTrace(World, Vec3d,
|
||||
* Vec3d, float, boolean, Class, java.util.function.Predicate)} for more details.
|
||||
* @return The spell instance, allowing this method to be chained onto the constructor.
|
||||
*/
|
||||
public SpellRay aimAssist(float aimAssist){
|
||||
this.aimAssist = aimAssist;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public boolean canBeCastByNPCs(){ return true; }
|
||||
|
||||
// Finally everything in here is standardised and written in a form that's actually readable - it was long overdue!
|
||||
@@ -157,49 +170,7 @@ public abstract class SpellRay extends Spell {
|
||||
Vec3d origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight() - Y_OFFSET,
|
||||
caster.posZ);
|
||||
|
||||
double range = baseRange * modifiers.get(WizardryItems.range_upgrade);
|
||||
|
||||
// The first method will hit the first block it touches, passing through entities as if they weren't there.
|
||||
// The second method will hit the first thing it touches, whether that's a block or an entity.
|
||||
// Note that when it hits a block, the exact position hit is returned in hitVec, whereas when it hits an
|
||||
// entity, it just returns the entity's position in hitVec.
|
||||
RayTraceResult rayTrace = ignoreEntities
|
||||
? WizardryUtilities.standardBlockRayTrace(world, caster, range, hitLiquids)
|
||||
: WizardryUtilities.standardEntityRayTrace(world, caster, range, hitLiquids);
|
||||
|
||||
boolean flag = false;
|
||||
|
||||
if(rayTrace != null){
|
||||
// Doesn't matter which way round these are, they're mutually exclusive
|
||||
if(rayTrace.typeOfHit == RayTraceResult.Type.ENTITY){
|
||||
|
||||
Entity target = rayTrace.entityHit;
|
||||
// Do whatever the spell does when it hits an entity
|
||||
flag = onEntityHit(world, target, caster, ticksInUse, modifiers);
|
||||
// If the spell succeeded, clip the particles to the correct distance so they don't go through the entity
|
||||
if(flag){
|
||||
// The most pragmatic solution is to use the target's centre point for reasons explained earlier
|
||||
double dx = origin.x - target.posX;
|
||||
double dy = origin.y - (target.getEntityBoundingBox().minY + target.height/2);
|
||||
double dz = origin.z - target.posZ;
|
||||
range = MathHelper.sqrt(dx*dx + dy*dy + dz*dz);
|
||||
}
|
||||
|
||||
}else if(rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){
|
||||
// Do whatever the spell does when it hits an block
|
||||
flag = onBlockHit(world, rayTrace.getBlockPos(), rayTrace.sideHit, caster, ticksInUse, modifiers);
|
||||
// If the spell succeeded, clip the particles to the correct distance so they don't go through the block
|
||||
if(flag) range = origin.distanceTo(rayTrace.hitVec);
|
||||
}
|
||||
}
|
||||
|
||||
// If flag is false, either the spell missed or the relevant entity/block hit method returned false
|
||||
if(!flag && !onMiss(world, caster, ticksInUse, modifiers)) return false;
|
||||
|
||||
// Particle spawning
|
||||
if(world.isRemote){
|
||||
spawnParticleRay(world, origin, look, range);
|
||||
}
|
||||
if(!shootSpell(world, origin, look, caster, ticksInUse, modifiers)) return false;
|
||||
|
||||
if(!isContinuous) caster.swingArm(hand); // Bit of a dirty fix but I don't think it'll be a problem!
|
||||
if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f));
|
||||
@@ -253,6 +224,46 @@ public abstract class SpellRay extends Spell {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Player and dispenser casting are almost identical so this takes care of the shared stuff. */
|
||||
private boolean shootSpell(World world, Vec3d origin, Vec3d direction, @Nullable EntityPlayer caster, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
double range = baseRange * modifiers.get(WizardryItems.range_upgrade);
|
||||
Vec3d endpoint = origin.add(direction.scale(range));
|
||||
|
||||
// The first method will hit the first block it touches, passing through entities as if they weren't there.
|
||||
// The second method will hit the first thing it touches, whether that's a block or an entity. This method now
|
||||
// returns the exact hit position for entities as well as blocks.
|
||||
RayTraceResult rayTrace = WizardryUtilities.rayTrace(world, origin, endpoint, aimAssist, hitLiquids, Entity.class, e -> e == caster);
|
||||
|
||||
boolean flag = false;
|
||||
|
||||
if(rayTrace != null){
|
||||
// Doesn't matter which way round these are, they're mutually exclusive
|
||||
if(rayTrace.typeOfHit == RayTraceResult.Type.ENTITY){
|
||||
// Do whatever the spell does when it hits an entity
|
||||
flag = onEntityHit(world, rayTrace.entityHit, caster, ticksInUse, modifiers);
|
||||
// If the spell succeeded, clip the particles to the correct distance so they don't go through the entity
|
||||
if(flag) range = origin.distanceTo(rayTrace.hitVec);
|
||||
|
||||
}else if(rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){
|
||||
// Do whatever the spell does when it hits an block
|
||||
flag = onBlockHit(world, rayTrace.getBlockPos(), rayTrace.sideHit, caster, ticksInUse, modifiers);
|
||||
// If the spell succeeded, clip the particles to the correct distance so they don't go through the block
|
||||
if(flag) range = origin.distanceTo(rayTrace.hitVec);
|
||||
}
|
||||
}
|
||||
|
||||
// If flag is false, either the spell missed or the relevant entity/block hit method returned false
|
||||
if(!flag && !onMiss(world, caster, ticksInUse, modifiers)) return false;
|
||||
|
||||
// Particle spawning
|
||||
if(world.isRemote){
|
||||
spawnParticleRay(world, origin, direction, range);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Private helper method, no-one will need to override it since it's pretty much the whole point of this class.
|
||||
private void spawnParticleRay(World world, Vec3d origin, Vec3d direction, double distance){
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -553,118 +553,145 @@ public final class WizardryUtilities {
|
||||
// ===============================================================================================================
|
||||
|
||||
/**
|
||||
* Does a block ray trace (NOT entities) from an entity's eyes (i.e. properly...)
|
||||
* Helper method which performs a ray trace for <b>blocks only</b> from an entity's eye position in the direction
|
||||
* they are looking, over a specified range, using {@link World#rayTraceBlocks(Vec3d, Vec3d, boolean)}.
|
||||
*
|
||||
* @param world The world in which to perform the ray trace.
|
||||
* @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye
|
||||
* position and proceed in the direction the entity is looking.
|
||||
* @param range The distance over which the ray trace will be performed.
|
||||
* @param hitLiquids True to return hits on the surfaces of liquids, false to ignore liquid blocks as if they were
|
||||
* not there.
|
||||
* @return A {@link RayTraceResult} representing the object that was hit, which may be either a block or nothing.
|
||||
* Returns {@code null} only if the origin and endpoint are within the same block.
|
||||
*/
|
||||
@Nullable
|
||||
public static RayTraceResult standardBlockRayTrace(World world, EntityLivingBase entity, double range, boolean hitLiquids){
|
||||
|
||||
Vec3d start = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ);
|
||||
Vec3d look = entity.getLookVec();
|
||||
Vec3d end = start.addVector(look.x * range, look.y * range, look.z * range);
|
||||
return world.rayTraceBlocks(start, end, hitLiquids);
|
||||
// This method does not apply an offset like ray spells do, since it is not desirable in most other use cases.
|
||||
Vec3d origin = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ);
|
||||
Vec3d endpoint = origin.add(entity.getLookVec().scale(range));
|
||||
return world.rayTraceBlocks(origin, endpoint, hitLiquids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method which does a rayTrace for entities from an entity's eye level in the direction they are looking
|
||||
* with a specified range, using the tracePath method. Tidies up the code a bit. Border size defaults to 1.
|
||||
* Helper method which performs a ray trace for blocks and entities from an entity's eye position in the direction
|
||||
* they are looking, over a specified range, using {@link WizardryUtilities#rayTrace(World, Vec3d, Vec3d, float,
|
||||
* boolean, Class, Predicate)}. Aim assist is zero, the entity type is simply {@code Entity} (all entities), and the
|
||||
* filter removes the given entity and allows all others.
|
||||
*
|
||||
* @param world
|
||||
* @param entity
|
||||
* @param range
|
||||
* @return
|
||||
* @param world The world in which to perform the ray trace.
|
||||
* @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye
|
||||
* position and proceed in the direction the entity is looking. This entity will be ignored when ray tracing.
|
||||
* @param range The distance over which the ray trace will be performed.
|
||||
* @param hitLiquids True to return hits on the surfaces of liquids, false to ignore liquid blocks as if they were
|
||||
* not there.
|
||||
* @return A {@link RayTraceResult} representing the object that was hit, which may be an entity, a block or
|
||||
* nothing. Returns {@code null} only if the origin and endpoint are within the same block and no entity was hit.
|
||||
*/
|
||||
@Nullable
|
||||
public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range, boolean hitLiquids){
|
||||
return standardEntityRayTrace(world, entity, range, 1, hitLiquids);
|
||||
public static RayTraceResult standardEntityRayTrace(World world, Entity entity, double range, boolean hitLiquids){
|
||||
// This method does not apply an offset like ray spells do, since it is not desirable in most other use cases.
|
||||
Vec3d origin = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ);
|
||||
Vec3d endpoint = origin.add(entity.getLookVec().scale(range));
|
||||
return WizardryUtilities.rayTrace(world, origin, endpoint, 0, hitLiquids, Entity.class, e -> e == entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method which does a rayTrace for entities from a entity's eye level in the direction they are looking with
|
||||
* a specified range and radius, using the tracePath method. Tidies up the code a bit.
|
||||
* Performs a ray trace for blocks and entities, starting at the given origin and finishing at the given endpoint.
|
||||
* As of wizardry 4.2, the ray tracing methods have been rewritten to be more user-friendly and implement proper
|
||||
* aim assist.
|
||||
* <p>
|
||||
* <i>N.B. It is possible to ignore entities entirely by passing in a {@code Predicate} that is always false;
|
||||
* however, in this specific case it is more efficient to use
|
||||
* {@link World#rayTraceBlocks(Vec3d, Vec3d, boolean, boolean, boolean)} or one of its overloads.</i>
|
||||
*
|
||||
* @param world
|
||||
* @param entity
|
||||
* @param range
|
||||
* @param borderSize
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range, float borderSize, boolean hitLiquids){
|
||||
double dx = entity.getLookVec().x * range;
|
||||
double dy = entity.getLookVec().y * range;
|
||||
double dz = entity.getLookVec().z * range;
|
||||
HashSet<Entity> hashset = new HashSet<Entity>(1);
|
||||
hashset.add(entity);
|
||||
return WizardryUtilities.tracePath(world, (float)entity.posX,
|
||||
(float)(entity.getEntityBoundingBox().minY + entity.getEyeHeight()), (float)entity.posZ,
|
||||
(float)(entity.posX + dx), (float)(entity.posY + entity.getEyeHeight() + dy), (float)(entity.posZ + dz),
|
||||
borderSize, hashset, false, hitLiquids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for ray tracing entities. You can also use this for seeking.
|
||||
* @param <T> The type of entities to include; all other entities will be ignored.
|
||||
* @param world The world in which to perform the ray trace.
|
||||
* @param origin A vector representing the coordinates of the start point of the ray trace.
|
||||
* @param endpoint A vector representing the coordinates of the finish point of the ray trace.
|
||||
* @param aimAssist In addition to direct hits, the ray trace will also hit entities that are up to this distance
|
||||
* from its path. For a normal ray trace, this should be 0. Values greater than 0 will give an 'aim assist' effect.
|
||||
* @param hitLiquids Whether liquids should be ignored when ray tracing blocks
|
||||
* @param entityType The class of entities to include; all other entities will be ignored.
|
||||
* @param filter A {@link Predicate} which filters out entities that can be ignored; often used to exclude the
|
||||
* player that is performing the ray trace.
|
||||
*
|
||||
* @param world
|
||||
* @param x startX
|
||||
* @param y startY
|
||||
* @param z startZ
|
||||
* @param tx endX
|
||||
* @param ty endY
|
||||
* @param tz endZ
|
||||
* @param borderSize extra area to examine around line for entities
|
||||
* @param excluded any excluded entities (the player, etc)
|
||||
* @return a RayTraceResult of either the block hit (no entity hit), the entity hit (hit an entity), or null for
|
||||
* nothing hit
|
||||
* @return A {@link RayTraceResult} representing the object that was hit, which may be an entity, a block or
|
||||
* nothing. Returns {@code null} only if the origin and endpoint are within the same block and no entity was hit.
|
||||
*
|
||||
* @see WizardryUtilities#standardEntityRayTrace(World, Entity, double, boolean)
|
||||
* @see WizardryUtilities#standardBlockRayTrace(World, EntityLivingBase, double, boolean)
|
||||
*/
|
||||
// Interestingly enough, aimAssist can be negative, which means hits have to be in the middle of entities!
|
||||
@Nullable
|
||||
public static RayTraceResult tracePath(World world, float x, float y, float z, float tx, float ty, float tz,
|
||||
float borderSize, HashSet<Entity> excluded, boolean collideablesOnly, boolean hitLiquids){
|
||||
public static RayTraceResult rayTrace(World world, Vec3d origin, Vec3d endpoint, float aimAssist,
|
||||
boolean hitLiquids, Class<? extends Entity> entityType, Predicate<? super Entity> filter){
|
||||
|
||||
// 1 is the standard amount of extra search volume, and aim assist needs to increase this further as well as
|
||||
// expanding the entities' bounding boxes.
|
||||
float borderSize = 1 + aimAssist;
|
||||
|
||||
Vec3d startVec = new Vec3d(x, y, z);
|
||||
// Vec3d lookVec = new Vec3d(tx-x, ty-y, tz-z);
|
||||
Vec3d endVec = new Vec3d(tx, ty, tz);
|
||||
float minX = x < tx ? x : tx;
|
||||
float minY = y < ty ? y : ty;
|
||||
float minZ = z < tz ? z : tz;
|
||||
float maxX = x > tx ? x : tx;
|
||||
float maxY = y > ty ? y : ty;
|
||||
float maxZ = z > tz ? z : tz;
|
||||
AxisAlignedBB bb = new AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ).grow(borderSize, borderSize, borderSize);
|
||||
List<Entity> allEntities = world.getEntitiesWithinAABBExcludingEntity(null, bb);
|
||||
RayTraceResult blockHit = world.rayTraceBlocks(startVec, endVec, hitLiquids);
|
||||
startVec = new Vec3d(x, y, z);
|
||||
endVec = new Vec3d(tx, ty, tz);
|
||||
float maxDistance = (float)endVec.distanceTo(startVec);
|
||||
if(blockHit != null){
|
||||
maxDistance = (float)blockHit.hitVec.distanceTo(startVec);
|
||||
// The AxisAlignedBB constructor accepts min/max coords in either order.
|
||||
AxisAlignedBB searchVolume = new AxisAlignedBB(origin.x, origin.y, origin.z, endpoint.x, endpoint.y, endpoint.z)
|
||||
.grow(borderSize, borderSize, borderSize);
|
||||
|
||||
// Gets all of the entities in the bounding box that could be collided with.
|
||||
List<Entity> entities = world.getEntitiesWithinAABB(entityType, searchVolume);
|
||||
// Applies the given filter to remove entities that should be ignored.
|
||||
entities.removeIf(filter);
|
||||
|
||||
// Finds the first block hit by the ray trace, if any.
|
||||
RayTraceResult result = world.rayTraceBlocks(origin, endpoint, hitLiquids);
|
||||
|
||||
// Clips the entity search range to the part of the ray trace before the block hit, if it hit a block.
|
||||
if(result != null){
|
||||
endpoint = result.hitVec;
|
||||
}
|
||||
|
||||
// Search variables
|
||||
Entity closestHitEntity = null;
|
||||
float closestHit = maxDistance;
|
||||
float currentHit = 0.f;
|
||||
AxisAlignedBB entityBb;// = ent.getBoundingBox();
|
||||
Vec3d closestHitPosition = endpoint;
|
||||
AxisAlignedBB entityBounds;
|
||||
RayTraceResult intercept;
|
||||
for(Entity ent : allEntities){
|
||||
if((ent.canBeCollidedWith() || !collideablesOnly)
|
||||
&& ((excluded != null && !excluded.contains(ent)) || excluded == null)){
|
||||
float entBorder = ent.getCollisionBorderSize();
|
||||
entityBb = ent.getEntityBoundingBox();
|
||||
if(entityBb != null){
|
||||
entityBb = entityBb.grow(entBorder, entBorder, entBorder);
|
||||
intercept = entityBb.calculateIntercept(startVec, endVec);
|
||||
if(intercept != null){
|
||||
currentHit = (float)intercept.hitVec.distanceTo(startVec);
|
||||
if(currentHit < closestHit || currentHit == 0){
|
||||
closestHit = currentHit;
|
||||
closestHitEntity = ent;
|
||||
}
|
||||
|
||||
// Iterates through all the entities
|
||||
for(Entity entity : entities){
|
||||
|
||||
entityBounds = entity.getEntityBoundingBox();
|
||||
|
||||
if(entityBounds != null){
|
||||
|
||||
// This is zero for everything except fireballs...
|
||||
float entityBorderSize = entity.getCollisionBorderSize();
|
||||
// ... meaning the following line does nothing in all other cases.
|
||||
// -> Added the non-zero check to prevent unnecessary AABB object creation.
|
||||
if(entityBorderSize != 0) entityBounds = entityBounds.grow(entityBorderSize, entityBorderSize, entityBorderSize);
|
||||
|
||||
// Aim assist expands the bounding box to hit entities within the specified distance of the ray trace.
|
||||
if(aimAssist != 0) entityBounds = entityBounds.grow(aimAssist, aimAssist, aimAssist);
|
||||
|
||||
// Finds the first point at which the ray trace intercepts the entity's bounding box, if any.
|
||||
intercept = entityBounds.calculateIntercept(origin, endpoint);
|
||||
|
||||
// If the ray trace hit the entity...
|
||||
if(intercept != null){
|
||||
// Decides whether the entity that was hit is the closest so far, and if so, overwrites the old one.
|
||||
float currentHitDistance = (float)intercept.hitVec.distanceTo(origin);
|
||||
float closestHitDistance = (float)closestHitPosition.distanceTo(origin);
|
||||
if(currentHitDistance < closestHitDistance){
|
||||
closestHitEntity = entity;
|
||||
closestHitPosition = intercept.hitVec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the ray trace hit an entity, return that entity; otherwise return the result of the block ray trace.
|
||||
if(closestHitEntity != null){
|
||||
blockHit = new RayTraceResult(closestHitEntity);
|
||||
result = new RayTraceResult(closestHitEntity, closestHitPosition);
|
||||
}
|
||||
return blockHit;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// SECTION Rendering and GUIs
|
||||
|
||||
Reference in New Issue
Block a user