/** Updates the status if the entity is currently swimming (in water). */ private void updateSwimStatus() { ArrayList<BlockPosition> blockPositions = gatherAdjacentBlockPositions(getPosition()); boolean swimming = false, headUnderWater = false; for (int i = 0; i < blockPositions.size(); i++) { BlockPosition p = blockPositions.get(i); byte blockType = _parent.getWorldProvider().getBlockAtPosition(new Vector3d(p.x, p.y, p.z)); AABB blockAABB = Block.AABBForBlockAt(p.x, p.y, p.z); if (BlockManager.getInstance().getBlock(blockType).isLiquid() && getAABB().overlaps(blockAABB)) { swimming = true; } Vector3d eyePos = calcEyePosition(); eyePos.y += 0.25; if (BlockManager.getInstance().getBlock(blockType).isLiquid() && blockAABB.contains(eyePos)) { headUnderWater = true; } } _headUnderWater = headUnderWater; _isSwimming = swimming; }
/** * Checks for blocks around the entity. * * @param origin The original position of the entity * @return True if the entity is colliding horizontally */ private boolean horizontalHitTest(Vector3d origin) { boolean result = false; ArrayList<BlockPosition> blockPositions = gatherAdjacentBlockPositions(origin); // Check each block position for collision for (int i = 0; i < blockPositions.size(); i++) { BlockPosition p = blockPositions.get(i); byte blockType = _parent.getWorldProvider().getBlockAtPosition(new Vector3d(p.x, p.y, p.z)); AABB blockAABB = Block.AABBForBlockAt(p.x, p.y, p.z); if (!BlockManager.getInstance().getBlock(blockType).isPenetrable()) { if (getAABB().overlaps(blockAABB)) { result = true; // Calculate the direction from the origin to the current position Vector3d direction = new Vector3d(getPosition().x, 0f, getPosition().z); direction.x -= origin.x; direction.z -= origin.z; // Calculate the point of intersection on the block's AABB Vector3d blockPoi = blockAABB.closestPointOnAABBToPoint(origin); Vector3d entityPoi = generateAABBForPosition(origin).closestPointOnAABBToPoint(blockPoi); Vector3d planeNormal = blockAABB.normalForPlaneClosestToOrigin(blockPoi, origin, true, false, true); // Find a vector parallel to the surface normal Vector3d slideVector = new Vector3d(planeNormal.z, 0, -planeNormal.x); Vector3d pushBack = new Vector3d(); pushBack.sub(blockPoi, entityPoi); // Calculate the intensity of the diversion alongside the block double length = slideVector.dot(direction); Vector3d newPosition = new Vector3d(); newPosition.z = origin.z + pushBack.z * 0.2 + length * slideVector.z; newPosition.x = origin.x + pushBack.x * 0.2 + length * slideVector.x; newPosition.y = origin.y; // Update the position getPosition().set(newPosition); } } } return result; }
public void render() { // Update the viewing direction setViewingDirection(_yaw, _pitch); if ((Boolean) ConfigurationManager.getInstance().getConfig().get("System.Debug.debugCollision")) { getAABB().render(2f); ArrayList<BlockPosition> blocks = gatherAdjacentBlockPositions(getPosition()); for (int i = 0; i < blocks.size(); i++) { BlockPosition p = blocks.get(i); AABB blockAABB = Block.AABBForBlockAt(p.x, p.y, p.z); blockAABB.render(2f); } } }
/** * Checks for blocks below and above the entity. * * @param origin The origin position of the entity * @return True if a vertical collision was detected */ private boolean verticalHitTest(Vector3d origin) { ArrayList<BlockPosition> blockPositions = gatherAdjacentBlockPositions(origin); for (int i = 0; i < blockPositions.size(); i++) { BlockPosition p = blockPositions.get(i); byte blockType1 = _parent.getWorldProvider().getBlockAtPosition(new Vector3d(p.x, p.y, p.z)); AABB entityAABB = getAABB(); if (BlockManager.getInstance().getBlock(blockType1).isPenetrable() || !entityAABB.overlaps(Block.AABBForBlockAt(p.x, p.y, p.z))) continue; double direction = origin.y - getPosition().y; if (direction >= 0) getPosition().y = p.y + 0.50001f + entityAABB.getDimensions().y; else getPosition().y = p.y - 0.50001f - entityAABB.getDimensions().y; return true; } return false; }
/** * Returns true if this AABB overlaps the given AABB. * * @param aabb2 The AABB to check for overlapping * @return True if overlapping */ public boolean overlaps(AABB aabb2) { if (maxX() < aabb2.minX() || minX() > aabb2.maxX()) return false; if (maxY() < aabb2.minY() || minY() > aabb2.maxY()) return false; if (maxZ() < aabb2.minZ() || minZ() > aabb2.maxZ()) return false; return true; }