package com.bergerkiller.bukkit.common.controller;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.bukkit.block.BlockFace;
import com.bergerkiller.bukkit.common.conversion.Conversion;
import com.bergerkiller.bukkit.common.entity.CommonEntity;
import com.bergerkiller.bukkit.common.internal.CommonNMS;
import com.bergerkiller.bukkit.common.utils.FaceUtil;
import com.bergerkiller.bukkit.common.utils.MathUtil;
import net.minecraft.server.AxisAlignedBB;
import net.minecraft.server.Block;
import net.minecraft.server.Entity;
/**
* Class that deals with AABB-collision resolving for Entity Controllers.
* This method is moved to hide it from the API - results in Class Hierarchy errors otherwise.
*/
class EntityControllerCollisionHelper {
private static final List<AxisAlignedBB> collisionBuffer = new ArrayList<AxisAlignedBB>();
/**
* Obtains all entities/blocks that can be collided with, checking collisions along the way.
* This is similar to NMS.World.getCubes, but with inserted events.
*
* @param bounds
* @return referenced list of collision cubes
*/
public static List<AxisAlignedBB> getCollisions(EntityController<?> controller, AxisAlignedBB bounds) {
final CommonEntity<?> entity = controller.getEntity();
final Entity handle = entity.getHandle(Entity.class);
collisionBuffer.clear();
final int xmin = MathUtil.floor(bounds.a);
final int ymin = MathUtil.floor(bounds.b);
final int zmin = MathUtil.floor(bounds.c);
final int xmax = MathUtil.floor(bounds.d + 1.0);
final int ymax = MathUtil.floor(bounds.e + 1.0);
final int zmax = MathUtil.floor(bounds.f + 1.0);
// Add block collisions
int x, y, z;
for (x = xmin; x < xmax; ++x) {
for (z = zmin; z < zmax; ++z) {
if (handle.world.isLoaded(x, 64, z)) {
for (y = ymin - 1; y < ymax; ++y) {
Block block = handle.world.getType(x, y, z);
if (block != null) {
block.a(handle.world, x, y, z, bounds, collisionBuffer, handle);
}
}
}
}
}
// Handle block collisions
BlockFace hitFace;
Iterator<AxisAlignedBB> iter = collisionBuffer.iterator();
AxisAlignedBB blockBounds;
double dx, dz;
while (iter.hasNext()) {
blockBounds = iter.next();
// Convert to block and block coordinates
org.bukkit.block.Block block = entity.getWorld().getBlockAt(MathUtil.floor(blockBounds.a), MathUtil.floor(blockBounds.b), MathUtil.floor(blockBounds.c));
// Find out what direction the block is hit
if (bounds.e > blockBounds.e) {
hitFace = BlockFace.UP;
} else if (bounds.b < blockBounds.b) {
hitFace = BlockFace.DOWN;
} else {
dx = entity.loc.getX() - block.getX() - 0.5;
dz = entity.loc.getZ() - block.getZ() - 0.5;
hitFace = FaceUtil.getDirection(dx, dz, false);
}
// Block collision event
if (!controller.onBlockCollision(block, hitFace)) {
iter.remove();
}
}
// Handle and add entities
AxisAlignedBB entityBounds;
for (Entity collider : CommonNMS.getEntitiesIn(handle.world, handle, bounds.grow(0.25, 0.25, 0.25))) {
/*
* This part is completely pointless as E() always returns null May
* this ever change, make sure E() is handled correctly.
*
* entityBounds = entity.E(); if (entityBounds != null &&
* entityBounds.a(bounds)) { collisionBuffer.add(entityBounds); }
*/
entityBounds = collider.boundingBox;
// Entity collision event after the null/inBounds check
if (entityBounds != null && entityBounds.b(bounds) && controller.onEntityCollision(Conversion.toEntity.convert(collider))) {
collisionBuffer.add(entityBounds);
}
}
// Done
return collisionBuffer;
}
}