Fix issue when players could complete ISLAND type challenges near island border and complete, if outside border are required blocks.

This commit is contained in:
BONNe 2019-04-23 19:54:39 +03:00
parent 337defb452
commit 3b8b7129ad
1 changed files with 113 additions and 55 deletions

View File

@ -5,18 +5,21 @@ package world.bentobox.challenges.tasks;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector; import org.bukkit.util.BoundingBox;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon; import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager; import world.bentobox.challenges.ChallengesManager;
@ -693,69 +696,112 @@ public class TryToComplete
*/ */
private ChallengeResult checkSurrounding() private ChallengeResult checkSurrounding()
{ {
ChallengeResult result; Location playerLocation = this.user.getLocation();
if (!this.addon.getIslands().userIsOnIsland(this.user.getWorld(), this.user)) // Init location in player position.
BoundingBox boundingBox = new BoundingBox(playerLocation.getBlockX(),
playerLocation.getBlockY(),
playerLocation.getBlockZ(),
playerLocation.getBlockX(),
playerLocation.getBlockY(),
playerLocation.getBlockZ());
// Expand position with search radius.
boundingBox.expand(this.challenge.getSearchRadius());
if (ChallengesAddon.CHALLENGES_WORLD_PROTECTION.isSetForWorld(this.world))
{ {
// Player is not on island // Players should not be able to complete challenge if they stay near island with required blocks.
this.user.sendMessage("challenges.errors.not-on-island");
result = EMPTY_RESULT; Island island = this.addon.getIslands().getIsland(this.world, this.user);
if (boundingBox.getMinX() < island.getMinX())
{
boundingBox.expand(BlockFace.EAST, Math.abs(island.getMinX() - boundingBox.getMinX()));
}
if (boundingBox.getMinZ() < island.getMinZ())
{
boundingBox.expand(BlockFace.NORTH, Math.abs(island.getMinZ() - boundingBox.getMinZ()));
}
int range = island.getRange();
int islandMaxX = island.getMinX() + range * 2;
int islandMaxZ = island.getMinZ() + range * 2;
if (boundingBox.getMaxX() > islandMaxX)
{
boundingBox.expand(BlockFace.WEST, Math.abs(boundingBox.getMaxX() - islandMaxX));
}
if (boundingBox.getMaxZ() > islandMaxZ)
{
boundingBox.expand(BlockFace.SOUTH, Math.abs(boundingBox.getMaxZ() - islandMaxZ));
}
} }
else
ChallengeResult result = this.searchForEntities(this.challenge.getRequiredEntities(), boundingBox);
if (result.meetsRequirements && !this.challenge.getRequiredBlocks().isEmpty())
{ {
// Check for items or entities in the area // Search for items only if entities found
result = this.searchForBlocks(this.challenge.getRequiredBlocks(), boundingBox);
result = this.searchForEntities(this.challenge.getRequiredEntities(), this.challenge.getSearchRadius());
if (result.meetsRequirements && !this.challenge.getRequiredBlocks().isEmpty())
{
// Search for items only if entities found
result = this.searchForBlocks(this.challenge.getRequiredBlocks(), this.challenge.getSearchRadius());
}
if (result.meetsRequirements &&
this.challenge.isRemoveEntities() &&
!this.challenge.getRequiredEntities().isEmpty())
{
this.removeEntities();
}
if (result.meetsRequirements &&
this.challenge.isRemoveBlocks() &&
!this.challenge.getRequiredBlocks().isEmpty())
{
this.removeBlocks();
}
// Check if challenge is repeated.
result.setRepeat(this.manager.isChallengeComplete(this.user, this.world, this.challenge));
} }
if (result.meetsRequirements &&
this.challenge.isRemoveEntities() &&
!this.challenge.getRequiredEntities().isEmpty())
{
this.removeEntities(boundingBox);
}
if (result.meetsRequirements &&
this.challenge.isRemoveBlocks() &&
!this.challenge.getRequiredBlocks().isEmpty())
{
this.removeBlocks(boundingBox);
}
// Check if challenge is repeated.
result.setRepeat(this.manager.isChallengeComplete(this.user, this.world, this.challenge));
return result; return result;
} }
/** /**
* This method search required blocks in given radius from user position. * This method search required blocks in given challenge boundingBox.
* @param map RequiredBlock Map. * @param map RequiredBlock Map.
* @param searchRadius Search distance * @param boundingBox Bounding box of island challenge
* @return ChallengeResult * @return ChallengeResult
*/ */
private ChallengeResult searchForBlocks(Map<Material, Integer> map, int searchRadius) private ChallengeResult searchForBlocks(Map<Material, Integer> map, BoundingBox boundingBox)
{ {
Map<Material, Integer> blocks = new EnumMap<>(map); Map<Material, Integer> blocks = new EnumMap<>(map);
for (int x = -searchRadius; x <= searchRadius; x++) if (blocks.isEmpty())
{ {
for (int y = -searchRadius; y <= searchRadius; y++) return new ChallengeResult().setMeetsRequirements();
}
for (int x = (int) boundingBox.getMinX(); x <= boundingBox.getMaxX(); x++)
{
for (int y = (int) boundingBox.getMinY(); y <= boundingBox.getMaxY(); y++)
{ {
for (int z = -searchRadius; z <= searchRadius; z++) for (int z = (int) boundingBox.getMinZ(); z <= boundingBox.getMaxZ(); z++)
{ {
Material mat = this.user.getWorld().getBlockAt(this.user.getLocation().add(new Vector(x, y, z))).getType(); Material mat = this.user.getWorld().getBlockAt(x, y, z).getType();
// Remove one // Remove one
blocks.computeIfPresent(mat, (b, amount) -> amount - 1); blocks.computeIfPresent(mat, (b, amount) -> amount - 1);
// Remove any that have an amount of 0 // Remove any that have an amount of 0
blocks.entrySet().removeIf(en -> en.getValue() <= 0); blocks.entrySet().removeIf(en -> en.getValue() <= 0);
if (blocks.isEmpty())
{
// Return as soon as it s empty as no point to search more.
return new ChallengeResult().setMeetsRequirements();
}
} }
} }
} }
@ -765,7 +811,7 @@ public class TryToComplete
return new ChallengeResult().setMeetsRequirements(); return new ChallengeResult().setMeetsRequirements();
} }
this.user.sendMessage("challenges.errors.not-close-enough", "[number]", String.valueOf(searchRadius)); this.user.sendMessage("challenges.errors.not-close-enough", "[number]", String.valueOf(this.challenge.getSearchRadius()));
blocks.forEach((k, v) -> user.sendMessage("challenges.errors.you-still-need", blocks.forEach((k, v) -> user.sendMessage("challenges.errors.you-still-need",
"[amount]", String.valueOf(v), "[amount]", String.valueOf(v),
@ -776,19 +822,30 @@ public class TryToComplete
/** /**
* This method search required entities in given radius from user position. * This method search required entities in given radius from user position and entity is inside boundingBox.
* @param map RequiredEntities Map. * @param map RequiredEntities Map.
* @param searchRadius Search distance * @param boundingBox Bounding box of island challenge
* @return ChallengeResult * @return ChallengeResult
*/ */
private ChallengeResult searchForEntities(Map<EntityType, Integer> map, int searchRadius) private ChallengeResult searchForEntities(Map<EntityType, Integer> map, BoundingBox boundingBox)
{ {
Map<EntityType, Integer> entities = map.isEmpty() ? new EnumMap<>(EntityType.class) : new EnumMap<>(map); Map<EntityType, Integer> entities = map.isEmpty() ? new EnumMap<>(EntityType.class) : new EnumMap<>(map);
if (entities.isEmpty())
{
return new ChallengeResult().setMeetsRequirements();
}
int searchRadius = this.challenge.getSearchRadius();
this.user.getPlayer().getNearbyEntities(searchRadius, searchRadius, searchRadius).forEach(entity -> { this.user.getPlayer().getNearbyEntities(searchRadius, searchRadius, searchRadius).forEach(entity -> {
// Look through all the nearby Entities, filtering by type // Check if entity is inside challenge bounding box
entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1); if (boundingBox.contains(entity.getBoundingBox()))
entities.entrySet().removeIf(e -> e.getValue() == 0); {
// Look through all the nearby Entities, filtering by type
entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1);
entities.entrySet().removeIf(e -> e.getValue() == 0);
}
}); });
if (entities.isEmpty()) if (entities.isEmpty())
@ -806,19 +863,19 @@ public class TryToComplete
/** /**
* This method removes required block and set air instead of it. * This method removes required block and set air instead of it.
* @param boundingBox Bounding box of island challenge
*/ */
private void removeBlocks() private void removeBlocks(BoundingBox boundingBox)
{ {
Map<Material, Integer> blocks = new EnumMap<>(this.challenge.getRequiredBlocks()); Map<Material, Integer> blocks = new EnumMap<>(this.challenge.getRequiredBlocks());
int searchRadius = this.challenge.getSearchRadius();
for (int x = -searchRadius; x <= searchRadius; x++) for (int x = (int) boundingBox.getMinX(); x <= boundingBox.getMaxX(); x++)
{ {
for (int y = -searchRadius; y <= searchRadius; y++) for (int y = (int) boundingBox.getMinY(); y <= boundingBox.getMaxY(); y++)
{ {
for (int z = -searchRadius; z <= searchRadius; z++) for (int z = (int) boundingBox.getMinZ(); z <= boundingBox.getMaxZ(); z++)
{ {
Block block = this.user.getWorld().getBlockAt(this.user.getLocation().add(new Vector(x, y, z))); Block block = this.user.getWorld().getBlockAt(new Location(this.user.getWorld(), x, y, z));
if (blocks.containsKey(block.getType())) if (blocks.containsKey(block.getType()))
{ {
@ -835,8 +892,9 @@ public class TryToComplete
/** /**
* This method removes required entities. * This method removes required entities.
* @param boundingBox Bounding box of island challenge
*/ */
private void removeEntities() private void removeEntities(BoundingBox boundingBox)
{ {
Map<EntityType, Integer> entities = this.challenge.getRequiredEntities().isEmpty() ? Map<EntityType, Integer> entities = this.challenge.getRequiredEntities().isEmpty() ?
new EnumMap<>(EntityType.class) : new EnumMap<>(this.challenge.getRequiredEntities()); new EnumMap<>(EntityType.class) : new EnumMap<>(this.challenge.getRequiredEntities());
@ -846,7 +904,7 @@ public class TryToComplete
this.user.getPlayer().getNearbyEntities(searchRadius, searchRadius, searchRadius).forEach(entity -> { this.user.getPlayer().getNearbyEntities(searchRadius, searchRadius, searchRadius).forEach(entity -> {
// Look through all the nearby Entities, filtering by type // Look through all the nearby Entities, filtering by type
if (entities.containsKey(entity.getType())) if (entities.containsKey(entity.getType()) && boundingBox.contains(entity.getBoundingBox()))
{ {
entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1); entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1);
entities.entrySet().removeIf(e -> e.getValue() == 0); entities.entrySet().removeIf(e -> e.getValue() == 0);