use of net.countercraft.movecraft.events.CraftCollisionEvent in project Movecraft by APDevTeam.
the class TranslationTask method execute.
@Override
protected void execute() throws InterruptedException, ExecutionException {
// Check if theres anything to move
if (oldHitBox.isEmpty())
return;
if (getCraft().getDisabled() && !(craft instanceof SinkingCraft)) {
fail(I18nSupport.getInternationalisedString("Translation - Failed Craft Is Disabled"));
return;
}
// call event
final CraftPreTranslateEvent preTranslateEvent = new CraftPreTranslateEvent(craft, dx, dy, dz, world);
Bukkit.getServer().getPluginManager().callEvent(preTranslateEvent);
if (preTranslateEvent.isCancelled()) {
fail(preTranslateEvent.getFailMessage(), preTranslateEvent.isPlayingFailSound());
return;
}
if (dx != preTranslateEvent.getDx())
dx = preTranslateEvent.getDx();
if (dy != preTranslateEvent.getDy())
dy = preTranslateEvent.getDy();
if (dz != preTranslateEvent.getDz())
dz = preTranslateEvent.getDz();
world = preTranslateEvent.getWorld();
final int minY = oldHitBox.getMinY();
final int maxY = oldHitBox.getMaxY();
// proccess nether portals
if (Settings.CraftsUseNetherPortals && craft.getWorld().getEnvironment() != Environment.THE_END && world.equals(craft.getWorld())) {
// ensure chunks are loaded for portal checking only if change in location is
// large
Set<MovecraftChunk> chunksToLoad = ChunkManager.getChunks(oldHitBox, world, dx, dy, dz);
MovecraftChunk.addSurroundingChunks(chunksToLoad, 2);
ChunkManager.checkChunks(chunksToLoad);
if (!chunksToLoad.isEmpty())
ChunkManager.syncLoadChunks(chunksToLoad).get();
for (MovecraftLocation oldLocation : oldHitBox) {
Location location = oldLocation.translate(dx, dy, dz).toBukkit(craft.getWorld());
Block block = craft.getWorld().getBlockAt(location);
if (block.getType() == Material.NETHER_PORTAL) {
if (processNetherPortal(block)) {
sound = Sound.BLOCK_PORTAL_TRAVEL;
volume = 0.25f;
break;
}
}
}
}
// ensure chunks are loaded only if world is different or change in location is
// large
Set<MovecraftChunk> chunksToLoad = ChunkManager.getChunks(oldHitBox, craft.getWorld());
chunksToLoad.addAll(ChunkManager.getChunks(oldHitBox, world, dx, dy, dz));
MovecraftChunk.addSurroundingChunks(chunksToLoad, 1);
ChunkManager.checkChunks(chunksToLoad);
if (!chunksToLoad.isEmpty())
ChunkManager.syncLoadChunks(chunksToLoad).get();
// Check if the craft is too high
if (world.equals(craft.getWorld()) && (int) craft.getType().getPerWorldProperty(CraftType.PER_WORLD_MAX_HEIGHT_LIMIT, craft.getWorld()) < craft.getHitBox().getMinY())
dy = Math.min(dy, -1);
else if (world.equals(craft.getWorld()) && (int) craft.getType().getPerWorldProperty(CraftType.PER_WORLD_MAX_HEIGHT_ABOVE_GROUND, craft.getWorld()) > 0) {
final MovecraftLocation middle = oldHitBox.getMidPoint();
int testY = minY;
while (testY > 0) {
testY--;
if (!craft.getWorld().getBlockAt(middle.getX(), testY, middle.getZ()).getType().isAir())
break;
}
if (maxY - testY > (int) craft.getType().getPerWorldProperty(CraftType.PER_WORLD_MAX_HEIGHT_ABOVE_GROUND, world))
dy = Math.min(dy, -1);
}
// Process gravity
if (world.equals(craft.getWorld()) && craft.getType().getBoolProperty(CraftType.USE_GRAVITY) && !(craft instanceof SinkingCraft)) {
int incline = inclineCraft(oldHitBox);
if (incline > 0) {
boolean tooSteep = craft.getType().getIntProperty(CraftType.GRAVITY_INCLINE_DISTANCE) > -1 && incline > craft.getType().getIntProperty(CraftType.GRAVITY_INCLINE_DISTANCE);
if (tooSteep && craft.getType().getFloatProperty(CraftType.COLLISION_EXPLOSION) <= 0F) {
fail(I18nSupport.getInternationalisedString("Translation - Failed Incline too steep"));
return;
}
dy = tooSteep ? 0 : incline;
} else if (!isOnGround(oldHitBox) && craft.getType().getBoolProperty(CraftType.CAN_HOVER)) {
MovecraftLocation midPoint = oldHitBox.getMidPoint();
int centreMinY = oldHitBox.getMinYAt(midPoint.getX(), midPoint.getZ());
int groundY = centreMinY;
World w = craft.getWorld();
while (groundY - 1 >= WorldUtils.getWorldMinHeightLimit(w) && (w.getBlockAt(midPoint.getX(), groundY - 1, midPoint.getZ()).getType().isAir() || craft.getType().getMaterialSetProperty(CraftType.PASSTHROUGH_BLOCKS).contains(w.getBlockAt(midPoint.getX(), groundY - 1, midPoint.getZ()).getType()))) {
groundY--;
}
if (centreMinY - groundY > craft.getType().getIntProperty(CraftType.HOVER_LIMIT))
dy = -1;
} else if (!isOnGround(oldHitBox))
dy = dropDistance(oldHitBox);
}
// Fail the movement if the craft is too high and if the craft is not explosive
int maxHeightLimit = (int) craft.getType().getPerWorldProperty(CraftType.PER_WORLD_MAX_HEIGHT_LIMIT, world);
int minHeightLimit = (int) craft.getType().getPerWorldProperty(CraftType.PER_WORLD_MIN_HEIGHT_LIMIT, world);
if (dy > 0 && maxY + dy > maxHeightLimit && craft.getType().getFloatProperty(CraftType.COLLISION_EXPLOSION) <= 0F) {
fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit height limit"));
return;
} else if (dy > 0 && maxY + dy > maxHeightLimit) {
// If explosive and too high, set dy to 0
dy = 0;
} else if (minY + dy < minHeightLimit && dy < 0 && !(craft instanceof SinkingCraft) && !craft.getType().getBoolProperty(CraftType.USE_GRAVITY)) {
fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit minimum height limit"));
return;
} else if (minY + dy < minHeightLimit && dy < 0 && craft.getType().getBoolProperty(CraftType.USE_GRAVITY))
// if a craft using gravity hits the minimum height limit, set dy = 0 instead of failing
dy = 0;
if (!(dy < 0 && dx == 0 && dz == 0) && !checkFuel()) {
fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel"));
return;
}
final EnumSet<Material> harvestBlocks = craft.getType().getMaterialSetProperty(CraftType.HARVEST_BLOCKS);
final List<MovecraftLocation> harvestedBlocks = new ArrayList<>();
final EnumSet<Material> harvesterBladeBlocks = craft.getType().getMaterialSetProperty(CraftType.HARVESTER_BLADE_BLOCKS);
final SetHitBox collisionBox = new SetHitBox();
for (MovecraftLocation oldLocation : oldHitBox) {
final MovecraftLocation newLocation = oldLocation.translate(dx, dy, dz);
// itself
if (world.equals(craft.getWorld()) && oldHitBox.contains(newLocation)) {
newHitBox.add(newLocation);
continue;
}
final Material testMaterial = newLocation.toBukkit(world).getBlock().getType();
if (Tags.CHESTS.contains(testMaterial) && checkChests(testMaterial, newLocation)) {
// prevent chests collision
fail(String.format(I18nSupport.getInternationalisedString("Translation - Failed Craft is obstructed") + " @ %d,%d,%d,%s", newLocation.getX(), newLocation.getY(), newLocation.getZ(), newLocation.toBukkit(craft.getWorld()).getBlock().getType()));
return;
}
if (!withinWorldBorder(world, newLocation)) {
fail(I18nSupport.getInternationalisedString("Translation - Failed Craft cannot pass world border") + String.format(" @ %d,%d,%d", newLocation.getX(), newLocation.getY(), newLocation.getZ()));
return;
}
boolean blockObstructed;
if (craft instanceof SinkingCraft)
blockObstructed = !Tags.FALL_THROUGH_BLOCKS.contains(testMaterial);
else
blockObstructed = !testMaterial.equals(Material.AIR) && !craft.getType().getMaterialSetProperty(CraftType.PASSTHROUGH_BLOCKS).contains(testMaterial);
boolean ignoreBlock = oldLocation.toBukkit(craft.getWorld()).getBlock().getType().isAir() && blockObstructed;
if (blockObstructed && !harvestBlocks.isEmpty() && harvestBlocks.contains(testMaterial)) {
Material tmpType = oldLocation.toBukkit(craft.getWorld()).getBlock().getType();
if (harvesterBladeBlocks.size() > 0 && harvesterBladeBlocks.contains(tmpType)) {
blockObstructed = false;
harvestedBlocks.add(newLocation);
}
}
if (blockObstructed) {
if (!(craft instanceof SinkingCraft) && craft.getType().getFloatProperty(CraftType.COLLISION_EXPLOSION) <= 0F) {
fail(String.format(I18nSupport.getInternationalisedString("Translation - Failed Craft is obstructed") + " @ %d,%d,%d,%s", newLocation.getX(), newLocation.getY(), newLocation.getZ(), testMaterial));
return;
}
collisionBox.add(newLocation);
} else if (!ignoreBlock)
newHitBox.add(newLocation);
}
if (!oldFluidList.isEmpty()) {
for (MovecraftLocation fluidLoc : oldFluidList) {
newFluidList.add(fluidLoc.translate(dx, dy, dz));
}
}
if (craft.getType().getMaterialSetProperty(CraftType.FORBIDDEN_HOVER_OVER_BLOCKS).size() > 0) {
MovecraftLocation test = new MovecraftLocation(newHitBox.getMidPoint().getX(), newHitBox.getMinY(), newHitBox.getMidPoint().getZ());
test = test.translate(0, -1, 0);
while (test.toBukkit(world).getBlock().getType().isAir()) {
test = test.translate(0, -1, 0);
}
Material testType = test.toBukkit(world).getBlock().getType();
if (craft.getType().getMaterialSetProperty(CraftType.FORBIDDEN_HOVER_OVER_BLOCKS).contains(testType)) {
fail(String.format(I18nSupport.getInternationalisedString("Translation - Failed Craft over block"), testType.name().toLowerCase().replace("_", " ")));
}
}
// call event
CraftTranslateEvent translateEvent = new CraftTranslateEvent(craft, oldHitBox, newHitBox, world);
Bukkit.getServer().getPluginManager().callEvent(translateEvent);
if (translateEvent.isCancelled()) {
this.fail(translateEvent.getFailMessage(), translateEvent.isPlayingFailSound());
return;
}
// do not switch world if sinking
if (craft instanceof SinkingCraft) {
List<MovecraftLocation> air = new ArrayList<>();
for (MovecraftLocation location : oldHitBox) {
if (location.toBukkit(craft.getWorld()).getBlock().getType().isAir()) {
air.add(location.translate(dx, dy, dz));
}
}
newHitBox.removeAll(air);
for (MovecraftLocation location : collisionBox) {
if (craft.getType().getFloatProperty(CraftType.EXPLODE_ON_CRASH) > 0F) {
if (System.currentTimeMillis() - craft.getOrigPilotTime() <= 1000) {
continue;
}
Location loc = location.toBukkit(craft.getWorld());
if (!loc.getBlock().getType().isAir() && ThreadLocalRandom.current().nextDouble(1) < .05) {
updates.add(new ExplosionUpdateCommand(loc, craft.getType().getFloatProperty(CraftType.EXPLODE_ON_CRASH)));
collisionExplosion = true;
}
}
SetHitBox toRemove = new SetHitBox();
MovecraftLocation next = location.translate(-dx, -dy, -dz);
while (oldHitBox.contains(next)) {
toRemove.add(next);
next = next.translate(0, 1, 0);
}
craft.getCollapsedHitBox().addAll(toRemove);
newHitBox.removeAll(toRemove);
}
} else if ((craft.getType().getFloatProperty(CraftType.COLLISION_EXPLOSION) > 0F) && System.currentTimeMillis() - craft.getOrigPilotTime() > Settings.CollisionPrimer) {
for (MovecraftLocation location : collisionBox) {
float explosionForce = craft.getType().getFloatProperty(CraftType.COLLISION_EXPLOSION);
if (craft.getType().getBoolProperty(CraftType.FOCUSED_EXPLOSION)) {
explosionForce *= Math.min(oldHitBox.size(), craft.getType().getIntProperty(CraftType.MAX_SIZE));
}
// TODO: Account for underwater explosions
/*if (location.getY() < waterLine) { // underwater explosions require more force to do anything
explosionForce += 25;//TODO: find the correct amount
}*/
Location oldLocation = location.translate(-dx, -dy, -dz).toBukkit(craft.getWorld());
Location newLocation = location.toBukkit(world);
if (!oldLocation.getBlock().getType().isAir()) {
CraftCollisionExplosionEvent e = new CraftCollisionExplosionEvent(craft, newLocation, craft.getWorld());
Bukkit.getServer().getPluginManager().callEvent(e);
if (!e.isCancelled()) {
updates.add(new ExplosionUpdateCommand(newLocation, explosionForce));
collisionExplosion = true;
}
}
if (craft.getType().getBoolProperty(CraftType.FOCUSED_EXPLOSION)) {
// don't handle any further collisions if it is set to focusedexplosion
break;
}
}
}
if (!collisionBox.isEmpty() && craft.getType().getBoolProperty(CraftType.CRUISE_ON_PILOT)) {
CraftManager.getInstance().release(craft, CraftReleaseEvent.Reason.EMPTY, false);
for (MovecraftLocation location : oldHitBox) {
BlockData phaseBlock = craft.getPhaseBlocks().getOrDefault(location.toBukkit(craft.getWorld()), Material.AIR.createBlockData());
updates.add(new BlockCreateCommand(craft.getWorld(), location, phaseBlock));
}
newHitBox = new SetHitBox();
}
if (!collisionBox.isEmpty()) {
Bukkit.getServer().getPluginManager().callEvent(new CraftCollisionEvent(craft, collisionBox, world));
}
updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz), world));
// prevents torpedo and rocket pilots
if (!(craft instanceof SinkingCraft && craft.getType().getBoolProperty(CraftType.ONLY_MOVE_PLAYERS)) && craft.getType().getBoolProperty(CraftType.MOVE_ENTITIES)) {
Location midpoint = new Location(craft.getWorld(), (oldHitBox.getMaxX() + oldHitBox.getMinX()) / 2.0, (oldHitBox.getMaxY() + oldHitBox.getMinY()) / 2.0, (oldHitBox.getMaxZ() + oldHitBox.getMinZ()) / 2.0);
for (Entity entity : craft.getWorld().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1)) {
if (entity.getType() == EntityType.PLAYER) {
if (craft instanceof SinkingCraft)
continue;
EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0, world, sound, volume);
updates.add(eUp);
} else if (!craft.getType().getBoolProperty(CraftType.ONLY_MOVE_PLAYERS) || entity.getType() == EntityType.PRIMED_TNT) {
EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0, world);
updates.add(eUp);
}
}
} else {
// add releaseTask without playermove to manager
if (!craft.getType().getBoolProperty(CraftType.CRUISE_ON_PILOT) && !(craft instanceof SinkingCraft))
// not necessary to release cruiseonpilot crafts, because they will already be released
CraftManager.getInstance().addReleaseTask(craft);
}
captureYield(harvestedBlocks);
}
Aggregations