mirror of
https://github.com/BentoBoxWorld/AcidIsland.git
synced 2024-11-22 10:36:07 +01:00
Merge remote-tracking branch 'origin/develop'
Conflicts: pom.xml
This commit is contained in:
commit
c896925201
2
pom.xml
2
pom.xml
@ -65,7 +65,7 @@
|
||||
<!-- Do not change unless you want different name for local builds. -->
|
||||
<build.number>-LOCAL</build.number>
|
||||
<!-- This allows to change between versions. -->
|
||||
<build.version>1.14.1</build.version>
|
||||
<build.version>1.14.2</build.version>
|
||||
</properties>
|
||||
|
||||
<!-- Profiles will allow to automatically change build version. -->
|
||||
|
@ -1,34 +1,33 @@
|
||||
package world.bentobox.acidisland.world;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Animals;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.MagmaCube;
|
||||
import org.bukkit.entity.Monster;
|
||||
import org.bukkit.entity.WaterMob;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import world.bentobox.acidisland.AcidIsland;
|
||||
import world.bentobox.acidisland.listeners.AcidEffect;
|
||||
|
||||
public class AcidTask {
|
||||
private final AcidIsland addon;
|
||||
private static final List<EntityType> IMMUNE = Arrays.asList(EntityType.GUARDIAN, EntityType.ELDER_GUARDIAN,
|
||||
EntityType.SQUID, EntityType.TURTLE, EntityType.POLAR_BEAR, EntityType.DROWNED);
|
||||
private Set<Entity> itemsInWater = Collections.newSetFromMap(new WeakHashMap<Entity, Boolean>());
|
||||
private int entityBurnTask = -1;
|
||||
private int itemBurnTask = -1;
|
||||
private static final List<EntityType> IMMUNE = Arrays.asList(EntityType.TURTLE, EntityType.POLAR_BEAR, EntityType.DROWNED);
|
||||
private Map<Entity, Long> itemsInWater = new ConcurrentHashMap<>();
|
||||
private BukkitTask findMobsTask;
|
||||
|
||||
/**
|
||||
* Runs repeating tasks to deliver acid damage to mobs, etc.
|
||||
@ -36,85 +35,91 @@ public class AcidTask {
|
||||
*/
|
||||
public AcidTask(AcidIsland addon) {
|
||||
this.addon = addon;
|
||||
burnEntities();
|
||||
runAcidItemRemovalTask();
|
||||
findMobsTask = Bukkit.getScheduler().runTaskTimerAsynchronously(addon.getPlugin(), () -> findEntities(), 0L, 20L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the entity burning task
|
||||
*/
|
||||
private void burnEntities() {
|
||||
// This part will kill monsters if they fall into the water because it is acid
|
||||
entityBurnTask = Bukkit.getScheduler().scheduleSyncRepeatingTask(addon.getPlugin(), () -> getEntityStream()
|
||||
// These entities are immune to acid
|
||||
.filter(e -> !IMMUNE.contains(e.getType()))
|
||||
// Only burn if the chunk is loaded
|
||||
.filter(e -> e.getLocation().getChunk().isLoaded())
|
||||
.filter(w -> w.getLocation().getBlock().getType().equals(Material.WATER))
|
||||
.forEach(e -> {
|
||||
if ((e instanceof Monster || e instanceof MagmaCube) && addon.getSettings().getAcidDamageMonster() > 0D) {
|
||||
applyDamage((LivingEntity) e, addon.getSettings().getAcidDamageMonster());
|
||||
} else if ((e instanceof Animals) && addon.getSettings().getAcidDamageAnimal() > 0D
|
||||
&& (!e.getType().equals(EntityType.CHICKEN) || addon.getSettings().isAcidDamageChickens())) {
|
||||
((LivingEntity) e).damage(addon.getSettings().getAcidDamageAnimal());
|
||||
void findEntities() {
|
||||
Map<Entity, Long> burnList = new WeakHashMap<>();
|
||||
for (Entity e : getEntityStream()) {
|
||||
if (e instanceof Item || (!IMMUNE.contains(e.getType()) && !(e instanceof WaterMob))) {
|
||||
int x = e.getLocation().getBlockX() >> 4;
|
||||
int z = e.getLocation().getBlockZ() >> 4;
|
||||
if (e.getWorld().isChunkLoaded(x,z)) {
|
||||
if (e.getLocation().getBlock().getType().equals(Material.WATER)) {
|
||||
if ((e instanceof Monster || e instanceof MagmaCube) && addon.getSettings().getAcidDamageMonster() > 0D) {
|
||||
burnList.put(e, (long)addon.getSettings().getAcidDamageMonster());
|
||||
|
||||
} else if ((e instanceof Animals) && addon.getSettings().getAcidDamageAnimal() > 0D
|
||||
&& (!e.getType().equals(EntityType.CHICKEN) || addon.getSettings().isAcidDamageChickens())) {
|
||||
burnList.put(e, (long)addon.getSettings().getAcidDamageAnimal());
|
||||
} else if (addon.getSettings().getAcidDestroyItemTime() > 0 && e instanceof Item) {
|
||||
burnList.put(e, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
}), 0L, 20L);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove any entities not on the burn list
|
||||
itemsInWater.keySet().removeIf(i -> !burnList.keySet().contains(i));
|
||||
|
||||
if (!burnList.isEmpty()) {
|
||||
Bukkit.getScheduler().runTask(addon.getPlugin(), () ->
|
||||
// Burn everything
|
||||
burnList.forEach(this::applyDamage));
|
||||
}
|
||||
}
|
||||
|
||||
private void applyDamage(LivingEntity e, double damage) {
|
||||
e.damage(Math.max(0, damage - damage * AcidEffect.getDamageReduced(e)));
|
||||
void applyDamage(Entity e, long damage) {
|
||||
if (e instanceof LivingEntity) {
|
||||
((LivingEntity)e).damage(Math.max(0, damage - damage * AcidEffect.getDamageReduced((LivingEntity)e)));
|
||||
} else if (addon.getSettings().getAcidDestroyItemTime() > 0){
|
||||
// Item
|
||||
if (e.getLocation().getBlock().getType().equals(Material.WATER)) {
|
||||
itemsInWater.putIfAbsent(e, damage + addon.getSettings().getAcidDestroyItemTime() * 1000);
|
||||
if (System.currentTimeMillis() > itemsInWater.get(e)) {
|
||||
e.getWorld().playSound(e.getLocation(), Sound.ENTITY_CREEPER_PRIMED, 3F, 3F);
|
||||
e.remove();
|
||||
itemsInWater.remove(e);
|
||||
}
|
||||
} else {
|
||||
itemsInWater.remove(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a stream of all entities in this world and the nether and end if those are island worlds too.
|
||||
*/
|
||||
private Stream<Entity> getEntityStream() {
|
||||
Stream<Entity> entityStream = addon.getOverWorld().getEntities().stream();
|
||||
List<Entity> getEntityStream() {
|
||||
List<Entity> entityStream = new ArrayList<>(addon.getOverWorld().getEntities());
|
||||
// Nether and end
|
||||
if (addon.getSettings().isNetherGenerate() && addon.getSettings().isNetherIslands()) {
|
||||
entityStream = Stream.concat(entityStream, addon.getNetherWorld().getEntities().stream());
|
||||
entityStream.addAll(addon.getNetherWorld().getEntities());
|
||||
}
|
||||
if (addon.getSettings().isEndGenerate() && addon.getSettings().isEndIslands()) {
|
||||
entityStream = Stream.concat(entityStream, addon.getEndWorld().getEntities().stream());
|
||||
entityStream.addAll(addon.getEndWorld().getEntities());
|
||||
}
|
||||
return entityStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the item removal in acid task
|
||||
*/
|
||||
private void runAcidItemRemovalTask() {
|
||||
if (addon.getSettings().getAcidDestroyItemTime() <= 0) {
|
||||
return;
|
||||
}
|
||||
itemBurnTask = Bukkit.getScheduler().scheduleSyncRepeatingTask(addon.getPlugin(), () -> {
|
||||
Set<Entity> newItemsInWater = new HashSet<>();
|
||||
getEntityStream()
|
||||
.filter(e -> e.getType().equals(EntityType.DROPPED_ITEM))
|
||||
.filter(e -> e.getLocation().getChunk().isLoaded())
|
||||
.filter(e -> e.getLocation().getBlock().getType().equals(Material.WATER)
|
||||
|| (e.getLocation().getY() > 0 && e.getLocation().getBlock().getRelative(BlockFace.DOWN).getType().equals(Material.WATER)))
|
||||
.forEach(e -> {
|
||||
if (itemsInWater.contains(e)) {
|
||||
e.getWorld().playSound(e.getLocation(), Sound.ENTITY_CREEPER_PRIMED, 3F, 3F);
|
||||
e.remove();
|
||||
} else {
|
||||
newItemsInWater.add(e);
|
||||
}
|
||||
});
|
||||
itemsInWater = newItemsInWater;
|
||||
}, addon.getSettings().getAcidDestroyItemTime() * 20L, addon.getSettings().getAcidDestroyItemTime() * 20L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel tasks running
|
||||
*/
|
||||
public void cancelTasks() {
|
||||
if (entityBurnTask >= 0) {
|
||||
Bukkit.getScheduler().cancelTask(entityBurnTask);
|
||||
}
|
||||
if (itemBurnTask >= 0) {
|
||||
Bukkit.getScheduler().cancelTask(itemBurnTask);
|
||||
}
|
||||
if (findMobsTask != null) findMobsTask.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the itemsInWater
|
||||
*/
|
||||
Map<Entity, Long> getItemsInWater() {
|
||||
return itemsInWater;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemsInWater the itemsInWater to set
|
||||
*/
|
||||
void setItemsInWater(Map<Entity, Long> itemsInWater) {
|
||||
this.itemsInWater = itemsInWater;
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,43 @@
|
||||
package world.bentobox.acidisland.world;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Cod;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.Skeleton;
|
||||
import org.bukkit.entity.Squid;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
@ -20,53 +45,198 @@ import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import world.bentobox.acidisland.AISettings;
|
||||
import world.bentobox.acidisland.AcidIsland;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({Bukkit.class})
|
||||
public class AcidTaskTest {
|
||||
|
||||
@Mock
|
||||
private BukkitScheduler scheduler;
|
||||
@Mock
|
||||
private AISettings settings;
|
||||
@Mock
|
||||
private AcidIsland addon;
|
||||
|
||||
// CUT
|
||||
private AcidTask at;
|
||||
|
||||
private @Nullable AISettings settings;
|
||||
|
||||
@Mock
|
||||
private World world;
|
||||
|
||||
private List<Entity> mob;
|
||||
|
||||
@Mock
|
||||
private @Nullable World nether;
|
||||
@Mock
|
||||
private @Nullable World end;
|
||||
|
||||
@Mock
|
||||
private BukkitScheduler scheduler;
|
||||
|
||||
@Mock
|
||||
private BukkitTask task;
|
||||
@Mock
|
||||
private Location l;
|
||||
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
|
||||
when(Bukkit.getScheduler()).thenReturn(scheduler);
|
||||
when(settings.getAcidDestroyItemTime()).thenReturn(0L);
|
||||
when(scheduler.runTaskTimerAsynchronously(any(), any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
|
||||
|
||||
when(addon.getOverWorld()).thenReturn(world);
|
||||
when(addon.getNetherWorld()).thenReturn(nether);
|
||||
when(addon.getEndWorld()).thenReturn(end);
|
||||
|
||||
when(world.isChunkLoaded(anyInt(), anyInt())).thenReturn(true);
|
||||
|
||||
Block block = mock(Block.class);
|
||||
when(block.getType()).thenReturn(Material.WATER);
|
||||
when(l.getBlock()).thenReturn(block);
|
||||
|
||||
|
||||
// Default squid
|
||||
mob = new ArrayList<>();
|
||||
Squid squid = mock(Squid.class);
|
||||
when(squid.getType()).thenReturn(EntityType.SQUID);
|
||||
when(squid.getLocation()).thenReturn(l);
|
||||
when(squid.getWorld()).thenReturn(world);
|
||||
mob.add(squid);
|
||||
Skeleton s = mock(Skeleton.class);
|
||||
when(s.getLocation()).thenReturn(l);
|
||||
when(s.getType()).thenReturn(EntityType.SKELETON);
|
||||
when(s.getWorld()).thenReturn(world);
|
||||
mob.add(s);
|
||||
Cod c = mock(Cod.class);
|
||||
when(c.getLocation()).thenReturn(l);
|
||||
when(c.getType()).thenReturn(EntityType.COD);
|
||||
when(c.getWorld()).thenReturn(world);
|
||||
mob.add(mock(Cod.class));
|
||||
Item i = mock(Item.class);
|
||||
when(i.getLocation()).thenReturn(l);
|
||||
when(i.getType()).thenReturn(EntityType.DROPPED_ITEM);
|
||||
when(i.getWorld()).thenReturn(world);
|
||||
mob.add(i);
|
||||
when(world.getEntities()).thenReturn(mob);
|
||||
when(nether.getEntities()).thenReturn(mob);
|
||||
when(end.getEntities()).thenReturn(mob);
|
||||
|
||||
settings = new AISettings();
|
||||
settings.setNetherGenerate(true);
|
||||
settings.setEndGenerate(true);
|
||||
settings.setEndIslands(true);
|
||||
settings.setNetherIslands(true);
|
||||
settings.setAcidDestroyItemTime(1);
|
||||
settings.setAcidDamageAnimal(10);
|
||||
settings.setAcidDamageMonster(10);
|
||||
settings.setAcidDamageChickens(true);
|
||||
when(addon.getSettings()).thenReturn(settings);
|
||||
|
||||
at = new AcidTask(addon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.acidisland.world.AcidTask#AcidTask(world.bentobox.acidisland.AcidIsland)}.
|
||||
*/
|
||||
@Test
|
||||
public void testAcidTaskDoNotDestroyItems() {
|
||||
new AcidTask(addon);
|
||||
verify(scheduler).scheduleSyncRepeatingTask(any(), any(Runnable.class), eq(0L), eq(20L));
|
||||
public void testAcidTask() {
|
||||
verify(scheduler).runTaskTimerAsynchronously(eq(null), any(Runnable.class), eq(0L), eq(20L));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.acidisland.world.AcidTask#findEntities()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAcidTaskDestroyItems() {
|
||||
when(settings.getAcidDestroyItemTime()).thenReturn(5L);
|
||||
new AcidTask(addon);
|
||||
verify(scheduler).scheduleSyncRepeatingTask(any(), any(Runnable.class), eq(0L), eq(20L));
|
||||
verify(scheduler).scheduleSyncRepeatingTask(any(), any(Runnable.class), eq(100L), eq(100L));
|
||||
public void testFindEntities() {
|
||||
|
||||
at.findEntities();
|
||||
verify(scheduler).runTask(eq(null), any(Runnable.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.acidisland.world.AcidTask#applyDamage(org.bukkit.entity.Entity, long)}.
|
||||
*/
|
||||
@Test
|
||||
public void testAcidTaskCancelTasks() {
|
||||
AcidTask task = new AcidTask(addon);
|
||||
task.cancelTasks();
|
||||
verify(scheduler).cancelTask(anyInt());
|
||||
public void testApplyDamageRemoveItems() {
|
||||
Item e = mock(Item.class);
|
||||
when(e.getLocation()).thenReturn(l);
|
||||
when(e.getWorld()).thenReturn(world);
|
||||
// Put the item in the water
|
||||
|
||||
Map<Entity, Long> map = new HashMap<>();
|
||||
map.put(e, 0L);
|
||||
at.setItemsInWater(map);
|
||||
at.applyDamage(e, 0);
|
||||
|
||||
verify(world).playSound(eq(l), any(Sound.class), anyFloat(), anyFloat());
|
||||
verify(e).remove();
|
||||
assertTrue(map.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.acidisland.world.AcidTask#applyDamage(org.bukkit.entity.Entity, long)}.
|
||||
*/
|
||||
@Test
|
||||
public void testAcidTaskCancelBothTasks() {
|
||||
when(settings.getAcidDestroyItemTime()).thenReturn(5L);
|
||||
AcidTask task = new AcidTask(addon);
|
||||
task.cancelTasks();
|
||||
verify(scheduler, times(2)).cancelTask(anyInt());
|
||||
public void testApplyDamageNoItemDamage() {
|
||||
settings.setAcidDestroyItemTime(0L);
|
||||
Item e = mock(Item.class);
|
||||
at.applyDamage(e, 0);
|
||||
|
||||
verify(world, never()).playSound(any(), any(Sound.class), anyFloat(), anyFloat());
|
||||
verify(e, never()).remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.acidisland.world.AcidTask#applyDamage(org.bukkit.entity.Entity, long)}.
|
||||
*/
|
||||
@Test
|
||||
public void testApplyDamageKeepItems() {
|
||||
Item e = mock(Item.class);
|
||||
Location l = mock(Location.class);
|
||||
Block block = mock(Block.class);
|
||||
when(block.getType()).thenReturn(Material.AIR);
|
||||
when(l.getBlock()).thenReturn(block);
|
||||
when(e.getLocation()).thenReturn(l);
|
||||
when(e.getWorld()).thenReturn(world);
|
||||
// Put the item in the water
|
||||
|
||||
Map<Entity, Long> map = new HashMap<>();
|
||||
map.put(e, 0L);
|
||||
at.setItemsInWater(map);
|
||||
at.applyDamage(e, 0);
|
||||
|
||||
verify(world, never()).playSound(any(), any(Sound.class), anyFloat(), anyFloat());
|
||||
verify(e, never()).remove();
|
||||
assertTrue(map.isEmpty());
|
||||
}
|
||||
/**
|
||||
* Test method for {@link world.bentobox.acidisland.world.AcidTask#getEntityStream()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetEntityStream() {
|
||||
List<Entity> es = at.getEntityStream();
|
||||
assertEquals(12, es.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.acidisland.world.AcidTask#cancelTasks()}.
|
||||
*/
|
||||
@Test
|
||||
public void testCancelTasks() {
|
||||
at.cancelTasks();
|
||||
verify(task).cancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user