Adds the ability to include MythicMobs in Blueprints. Fixes #2316

This commit is contained in:
tastybento 2024-03-10 10:40:26 -07:00
parent cb7c63a520
commit 4810c4c4ad
14 changed files with 455 additions and 48 deletions

12
pom.xml
View File

@ -189,6 +189,12 @@
<id>MG-Dev Jenkins CI Maven Repository</id> <id>MG-Dev Jenkins CI Maven Repository</id>
<url>https://ci.mg-dev.eu/plugin/repository/everything</url> <url>https://ci.mg-dev.eu/plugin/repository/everything</url>
</repository> </repository>
<!-- For MythicMobs -->
<repository>
<id>nexus</id>
<name>Lumine Releases</name>
<url>https://mvn.lumine.io/repository/maven-public/</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
@ -297,6 +303,12 @@
<version>${myworlds.version}</version> <version>${myworlds.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>io.lumine</groupId>
<artifactId>Mythic-Dist</artifactId>
<version>5.3.5</version>
<scope>provided</scope>
</dependency>
<!-- Shaded APIs --> <!-- Shaded APIs -->
<dependency> <dependency>
<groupId>com.github.TheBusyBiscuit</groupId> <groupId>com.github.TheBusyBiscuit</groupId>

View File

@ -27,6 +27,7 @@ import world.bentobox.bentobox.database.DatabaseSetup;
import world.bentobox.bentobox.hooks.ItemsAdderHook; import world.bentobox.bentobox.hooks.ItemsAdderHook;
import world.bentobox.bentobox.hooks.MultiverseCoreHook; import world.bentobox.bentobox.hooks.MultiverseCoreHook;
import world.bentobox.bentobox.hooks.MyWorldsHook; import world.bentobox.bentobox.hooks.MyWorldsHook;
import world.bentobox.bentobox.hooks.MythicMobsHook;
import world.bentobox.bentobox.hooks.SlimefunHook; import world.bentobox.bentobox.hooks.SlimefunHook;
import world.bentobox.bentobox.hooks.VaultHook; import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.bentobox.hooks.placeholders.PlaceholderAPIHook; import world.bentobox.bentobox.hooks.placeholders.PlaceholderAPIHook;
@ -185,6 +186,9 @@ public class BentoBox extends JavaPlugin implements Listener {
final long enableStart = System.currentTimeMillis(); final long enableStart = System.currentTimeMillis();
hooksManager.registerHook(new VaultHook()); hooksManager.registerHook(new VaultHook());
// MythicMobs
hooksManager.registerHook(new MythicMobsHook());
hooksManager.registerHook(new PlaceholderAPIHook()); hooksManager.registerHook(new PlaceholderAPIHook());
// Setup the Placeholders manager // Setup the Placeholders manager
placeholdersManager = new PlaceholdersManager(this); placeholdersManager = new PlaceholdersManager(this);

View File

@ -8,6 +8,7 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -43,6 +44,7 @@ import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock; import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintCreatureSpawner; import world.bentobox.bentobox.blueprints.dataobjects.BlueprintCreatureSpawner;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity; import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
import world.bentobox.bentobox.hooks.MythicMobsHook;
/** /**
* The clipboard provides the holding spot for an active blueprint that is being * The clipboard provides the holding spot for an active blueprint that is being
@ -67,6 +69,7 @@ public class BlueprintClipboard {
private final Map<Vector, BlueprintBlock> bpAttachable = new LinkedHashMap<>(); private final Map<Vector, BlueprintBlock> bpAttachable = new LinkedHashMap<>();
private final Map<Vector, BlueprintBlock> bpBlocks = new LinkedHashMap<>(); private final Map<Vector, BlueprintBlock> bpBlocks = new LinkedHashMap<>();
private final BentoBox plugin = BentoBox.getInstance(); private final BentoBox plugin = BentoBox.getInstance();
private Optional<MythicMobsHook> mmh;
/** /**
* Create a clipboard for blueprint * Create a clipboard for blueprint
@ -74,9 +77,16 @@ public class BlueprintClipboard {
*/ */
public BlueprintClipboard(@NonNull Blueprint blueprint) { public BlueprintClipboard(@NonNull Blueprint blueprint) {
this.blueprint = blueprint; this.blueprint = blueprint;
// MythicMobs
mmh = plugin.getHooks().getHook("MythicMobs").filter(hook -> hook instanceof MythicMobsHook)
.map(h -> (MythicMobsHook) h);
} }
public BlueprintClipboard() { } public BlueprintClipboard() {
// MythicMobs
mmh = plugin.getHooks().getHook("MythicMobs").filter(hook -> hook instanceof MythicMobsHook)
.map(h -> (MythicMobsHook) h);
}
/** /**
* Copy the blocks between pos1 and pos2 into the clipboard for a user. * Copy the blocks between pos1 and pos2 into the clipboard for a user.
@ -285,6 +295,7 @@ public class BlueprintClipboard {
List<BlueprintEntity> bpEnts = new ArrayList<>(); List<BlueprintEntity> bpEnts = new ArrayList<>();
for (LivingEntity entity: entities) { for (LivingEntity entity: entities) {
BlueprintEntity bpe = new BlueprintEntity(); BlueprintEntity bpe = new BlueprintEntity();
bpe.setType(entity.getType()); bpe.setType(entity.getType());
bpe.setCustomName(entity.getCustomName()); bpe.setCustomName(entity.getCustomName());
if (entity instanceof Villager villager) { if (entity instanceof Villager villager) {
@ -317,6 +328,10 @@ public class BlueprintClipboard {
if (entity instanceof Horse horse) { if (entity instanceof Horse horse) {
bpe.setStyle(horse.getStyle()); bpe.setStyle(horse.getStyle());
} }
mmh.filter(mm -> mm.isMythicMob(entity)).map(mm -> mm.getMythicMob(entity))
.ifPresent(mmr -> bpe.setMythicMobsRecord(mmr));
bpEnts.add(bpe); bpEnts.add(bpe);
} }
return bpEnts; return bpEnts;

View File

@ -24,6 +24,19 @@ import com.google.gson.annotations.Expose;
*/ */
public class BlueprintEntity { public class BlueprintEntity {
public record MythicMobRecord(String type, String displayName, double level, float power, String stance) {
};
// GSON can serialize records, but the record class needs to be know in advance. So this breaks out the record entries
@Expose
String MMtype;
@Expose
Double MMLevel;
@Expose
String MMStance;
@Expose
Float MMpower;
@Expose @Expose
private DyeColor color; private DyeColor color;
@Expose @Expose
@ -51,7 +64,6 @@ public class BlueprintEntity {
@Expose @Expose
private Villager.Type villagerType; private Villager.Type villagerType;
/** /**
* @since 1.8.0 * @since 1.8.0
*/ */
@ -85,7 +97,6 @@ public class BlueprintEntity {
if (style != null && e instanceof Horse horse) { if (style != null && e instanceof Horse horse) {
horse.setStyle(style); horse.setStyle(style);
} }
} }
/** /**
@ -271,4 +282,23 @@ public class BlueprintEntity {
this.domestication = domestication; this.domestication = domestication;
} }
/**
* @return the mythicMobsRecord
*/
public MythicMobRecord getMythicMobsRecord() {
return new MythicMobRecord(this.MMtype, this.getCustomName(), this.MMLevel, this.MMpower, this.MMStance);
}
/**
* @param mythicMobsRecord the mythicMobsRecord to set
* @since 2.1.0
*/
public void setMythicMobsRecord(MythicMobRecord mmr) {
this.setCustomName(mmr.displayName());
this.MMtype = mmr.type();
this.MMLevel = mmr.level();
this.MMStance = mmr.stance();
this.MMpower = mmr.power();
}
} }

View File

@ -0,0 +1,70 @@
package world.bentobox.bentobox.hooks;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.MythicBukkit;
import io.lumine.mythic.core.mobs.ActiveMob;
import world.bentobox.bentobox.api.hooks.Hook;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity.MythicMobRecord;
/**
* Provides implementation and interfacing to interact with MythicMobs.
*
* @author tastybento
* @since 2.2.0
*/
public class MythicMobsHook extends Hook {
public MythicMobsHook() {
super("MythicMobs", Material.CREEPER_HEAD);
}
public boolean isMythicMob(Entity bukkitEntity) {
return MythicBukkit.inst().getMobManager().isMythicMob(bukkitEntity);
}
public MythicMobRecord getMythicMob(Entity bukkitEntity) {
ActiveMob mm = MythicBukkit.inst().getMobManager().getActiveMob(bukkitEntity.getUniqueId()).orElse(null);
if (mm != null) {
return new MythicMobRecord(mm.getMobType(), mm.getDisplayName(), mm.getLevel(),
mm.getPower(),
mm.getStance());
}
return null;
}
@Override
public boolean hook() {
return true; // The hook process shouldn't fail
}
@Override
public String getFailureCause() {
return null; // The hook process shouldn't fail
}
/**
* Spawn a MythicMob
* @param mmr MythicMobRecord
* @param spawnLocation location
* @return true if spawn is successful
*/
public boolean spawnMythicMob(MythicMobRecord mmr, Location spawnLocation) {
return MythicBukkit.inst().getMobManager().getMythicMob(mmr.type()).map(mob -> {
// A delay is required before spawning, I assume because the blocks are pasted using NMS
Bukkit.getScheduler().runTaskLater(getPlugin(), () -> {
// spawns mob
ActiveMob activeMob = mob.spawn(BukkitAdapter.adapt(spawnLocation), mmr.level());
activeMob.setDisplayName(mmr.displayName());
activeMob.setPower(mmr.power());
activeMob.setStance(mmr.stance());
}, 40L);
return true;
}).orElse(false);
}
}

View File

@ -33,6 +33,7 @@ import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintCreatureSpawner; import world.bentobox.bentobox.blueprints.dataobjects.BlueprintCreatureSpawner;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity; import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.hooks.MythicMobsHook;
import world.bentobox.bentobox.nms.PasteHandler; import world.bentobox.bentobox.nms.PasteHandler;
/** /**
@ -172,15 +173,32 @@ public class DefaultPasteUtil {
public static CompletableFuture<Void> setEntity(Island island, Location location, List<BlueprintEntity> list) { public static CompletableFuture<Void> setEntity(Island island, Location location, List<BlueprintEntity> list) {
World world = location.getWorld(); World world = location.getWorld();
assert world != null; assert world != null;
return Util.getChunkAtAsync(location).thenRun(() -> list.stream().filter(k -> k.getType() != null).forEach(k -> { return Util.getChunkAtAsync(location).thenRun(() -> list.stream().filter(k -> k.getType() != null)
.forEach(k -> spawnBlueprintEntity(k, location, island)));
}
/**
* Spawn an entity
* @param k the blueprint entity definition
* @param location location
* @param island island
* @return true if Bukkit entity spawned, false if MythicMob entity spawned
*/
static boolean spawnBlueprintEntity(BlueprintEntity k, Location location, Island island) {
if (k.getMythicMobsRecord() != null && plugin.getHooks().getHook("MythicMobs")
.filter(mmh -> mmh instanceof MythicMobsHook)
.map(mmh -> ((MythicMobsHook) mmh).spawnMythicMob(k.getMythicMobsRecord(), location))
.orElse(false)) {
// MythicMob has spawned.
return false;
}
LivingEntity e = (LivingEntity) location.getWorld().spawnEntity(location, k.getType()); LivingEntity e = (LivingEntity) location.getWorld().spawnEntity(location, k.getType());
if (k.getCustomName() != null) { if (k.getCustomName() != null) {
String customName = k.getCustomName(); String customName = k.getCustomName();
if (island != null) { if (island != null) {
// Parse any placeholders in the entity's name, if the owner's connected (he should) // Parse any placeholders in the entity's name, if the owner's connected (he should)
Optional<Player> owner = Optional.ofNullable(island.getOwner()) Optional<Player> owner = Optional.ofNullable(island.getOwner()).map(User::getInstance)
.map(User::getInstance)
.map(User::getPlayer); .map(User::getPlayer);
if (owner.isPresent()) { if (owner.isPresent()) {
// Parse for the player's name first (in case placeholders might need it) // Parse for the player's name first (in case placeholders might need it)
@ -194,7 +212,7 @@ public class DefaultPasteUtil {
e.setCustomName(customName); e.setCustomName(customName);
} }
k.configureEntity(e); k.configureEntity(e);
})); return true;
} }
/** /**

View File

@ -1,7 +1,7 @@
name: BentoBox name: BentoBox
main: world.bentobox.bentobox.BentoBox main: world.bentobox.bentobox.BentoBox
version: ${project.version}${build.number} version: ${project.version}${build.number}
api-version: "1.18" api-version: "1.20"
authors: [tastybento, Poslovitch] authors: [tastybento, Poslovitch]
contributors: ["The BentoBoxWorld Community"] contributors: ["The BentoBoxWorld Community"]
@ -17,15 +17,13 @@ softdepend:
- Vault - Vault
- PlaceholderAPI - PlaceholderAPI
- dynmap - dynmap
- WorldBorderAPI
- BsbMongo - BsbMongo
- WorldGeneratorApi
- AdvancedChests - AdvancedChests
- LangUtils - LangUtils
- WildStacker - WildStacker
- LuckPerms - LuckPerms
- HolographicDisplays
- EconomyPlus - EconomyPlus
- MythicMobs
libraries: libraries:
- mysql:mysql-connector-java:${mysql.version} - mysql:mysql-connector-java:${mysql.version}

View File

@ -40,6 +40,7 @@ import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Blueprint; import world.bentobox.bentobox.blueprints.Blueprint;
import world.bentobox.bentobox.managers.BlueprintsManager; import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.managers.CommandsManager; import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.HooksManager;
import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.LocalesManager;
/** /**
@ -73,6 +74,11 @@ public class AdminBlueprintLoadCommandTest {
// Set up plugin // Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin); Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Hooks
HooksManager hooksManager = mock(HooksManager.class);
when(hooksManager.getHook(anyString())).thenReturn(Optional.empty());
when(plugin.getHooks()).thenReturn(hooksManager);
// Blueprints Manager // Blueprints Manager
when(plugin.getBlueprintsManager()).thenReturn(bm); when(plugin.getBlueprintsManager()).thenReturn(bm);

View File

@ -18,6 +18,7 @@ import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -41,6 +42,7 @@ import world.bentobox.bentobox.blueprints.Blueprint;
import world.bentobox.bentobox.blueprints.BlueprintClipboard; import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.managers.BlueprintsManager; import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.managers.CommandsManager; import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.HooksManager;
import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.LocalesManager;
/** /**
@ -58,7 +60,7 @@ public class AdminBlueprintSaveCommandTest {
private GameModeAddon addon; private GameModeAddon addon;
@Mock @Mock
private User user; private User user;
private BlueprintClipboard clip = new BlueprintClipboard(); private BlueprintClipboard clip;
private UUID uuid = UUID.randomUUID(); private UUID uuid = UUID.randomUUID();
private File blueprintsFolder; private File blueprintsFolder;
@Mock @Mock
@ -72,6 +74,12 @@ public class AdminBlueprintSaveCommandTest {
// Set up plugin // Set up plugin
BentoBox plugin = mock(BentoBox.class); BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin); Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Hooks
HooksManager hooksManager = mock(HooksManager.class);
when(hooksManager.getHook(anyString())).thenReturn(Optional.empty());
when(plugin.getHooks()).thenReturn(hooksManager);
clip = new BlueprintClipboard();
// Blueprints Manager // Blueprints Manager
when(plugin.getBlueprintsManager()).thenReturn(bm); when(plugin.getBlueprintsManager()).thenReturn(bm);
@ -109,7 +117,6 @@ public class AdminBlueprintSaveCommandTest {
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
absc = new AdminBlueprintSaveCommand(ac); absc = new AdminBlueprintSaveCommand(ac);
} }

View File

@ -4,11 +4,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.List; import java.util.List;
import java.util.Optional;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -29,6 +32,7 @@ import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.HooksManager;
/** /**
* @author tastybento * @author tastybento
@ -56,6 +60,10 @@ public class BlueprintClipboardTest {
public void setUp() throws Exception { public void setUp() throws Exception {
// Set up plugin // Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin); Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Hooks
HooksManager hooksManager = mock(HooksManager.class);
when(hooksManager.getHook(anyString())).thenReturn(Optional.empty());
when(plugin.getHooks()).thenReturn(hooksManager);
// User // User
when(user.getTranslation(Mockito.anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class)); when(user.getTranslation(Mockito.anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));

View File

@ -1,5 +1,6 @@
package world.bentobox.bentobox.blueprints.dataobjects; package world.bentobox.bentobox.blueprints.dataobjects;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.HashMap; import java.util.HashMap;
@ -26,6 +27,8 @@ import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity.MythicMobRecord;
/** /**
* @author tastybento * @author tastybento
* *
@ -84,10 +87,10 @@ public class BlueprintEntityTest {
blueprint.configureEntity(villager); blueprint.configureEntity(villager);
Assert.assertEquals(Profession.LIBRARIAN, villager.getProfession()); assertEquals(Profession.LIBRARIAN, villager.getProfession());
Assert.assertEquals(100, villager.getVillagerExperience()); assertEquals(100, villager.getVillagerExperience());
Assert.assertEquals(2, villager.getVillagerLevel()); assertEquals(2, villager.getVillagerLevel());
Assert.assertEquals(Villager.Type.PLAINS, villager.getVillagerType()); assertEquals(Villager.Type.PLAINS, villager.getVillagerType());
} }
@Test @Test
@ -99,7 +102,7 @@ public class BlueprintEntityTest {
blueprint.configureEntity(sheep); blueprint.configureEntity(sheep);
Assert.assertEquals(DyeColor.BLUE, sheep.getColor()); assertEquals(DyeColor.BLUE, sheep.getColor());
} }
@Test @Test
@ -147,7 +150,7 @@ public class BlueprintEntityTest {
blueprint.configureEntity(horse); blueprint.configureEntity(horse);
Assert.assertEquals(50, horse.getDomestication()); assertEquals(50, horse.getDomestication());
} }
@Test @Test
@ -159,7 +162,7 @@ public class BlueprintEntityTest {
blueprint.configureEntity(horse); blueprint.configureEntity(horse);
Assert.assertEquals(Style.WHITE_DOTS, horse.getStyle()); assertEquals(Style.WHITE_DOTS, horse.getStyle());
} }
@Test @Test
@ -167,13 +170,13 @@ public class BlueprintEntityTest {
BlueprintEntity blueprint = new BlueprintEntity(); BlueprintEntity blueprint = new BlueprintEntity();
blueprint.setColor(DyeColor.RED); blueprint.setColor(DyeColor.RED);
Assert.assertEquals(DyeColor.RED, blueprint.getColor()); assertEquals(DyeColor.RED, blueprint.getColor());
blueprint.setType(EntityType.CREEPER); blueprint.setType(EntityType.CREEPER);
Assert.assertEquals(EntityType.CREEPER, blueprint.getType()); assertEquals(EntityType.CREEPER, blueprint.getType());
blueprint.setCustomName("My Entity"); blueprint.setCustomName("My Entity");
Assert.assertEquals("My Entity", blueprint.getCustomName()); assertEquals("My Entity", blueprint.getCustomName());
blueprint.setTamed(true); blueprint.setTamed(true);
Assert.assertTrue(blueprint.getTamed()); Assert.assertTrue(blueprint.getTamed());
@ -185,27 +188,35 @@ public class BlueprintEntityTest {
Assert.assertFalse(blueprint.getAdult()); Assert.assertFalse(blueprint.getAdult());
blueprint.setDomestication(75); blueprint.setDomestication(75);
Assert.assertEquals(75, blueprint.getDomestication().intValue()); assertEquals(75, blueprint.getDomestication().intValue());
Map<Integer, ItemStack> inventory = new HashMap<>(); Map<Integer, ItemStack> inventory = new HashMap<>();
inventory.put(1, new ItemStack(Material.DIAMOND)); inventory.put(1, new ItemStack(Material.DIAMOND));
blueprint.setInventory(inventory); blueprint.setInventory(inventory);
Assert.assertEquals(inventory, blueprint.getInventory()); assertEquals(inventory, blueprint.getInventory());
blueprint.setStyle(Style.WHITE); blueprint.setStyle(Style.WHITE);
Assert.assertEquals(Style.WHITE, blueprint.getStyle()); assertEquals(Style.WHITE, blueprint.getStyle());
blueprint.setLevel(5); blueprint.setLevel(5);
Assert.assertEquals(5, blueprint.getLevel().intValue()); assertEquals(5, blueprint.getLevel().intValue());
blueprint.setProfession(Profession.FARMER); blueprint.setProfession(Profession.FARMER);
Assert.assertEquals(Profession.FARMER, blueprint.getProfession()); assertEquals(Profession.FARMER, blueprint.getProfession());
blueprint.setExperience(500); blueprint.setExperience(500);
Assert.assertEquals(500, blueprint.getExperience().intValue()); assertEquals(500, blueprint.getExperience().intValue());
blueprint.setVillagerType(Villager.Type.TAIGA); blueprint.setVillagerType(Villager.Type.TAIGA);
Assert.assertEquals(Villager.Type.TAIGA, blueprint.getVillagerType()); assertEquals(Villager.Type.TAIGA, blueprint.getVillagerType());
}
@Test
public void testMythicMobs() {
BlueprintEntity blueprint = new BlueprintEntity();
MythicMobRecord mmr = new MythicMobRecord("string", "string2", 10D, 1F, "string3");
blueprint.setMythicMobsRecord(mmr);
assertEquals(mmr, blueprint.getMythicMobsRecord());
} }
} }

View File

@ -0,0 +1,165 @@
package world.bentobox.bentobox.hooks;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
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;
import org.powermock.reflect.Whitebox;
import io.lumine.mythic.api.mobs.MythicMob;
import io.lumine.mythic.bukkit.MythicBukkit;
import io.lumine.mythic.core.mobs.ActiveMob;
import io.lumine.mythic.core.mobs.MobExecutor;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity.MythicMobRecord;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ BentoBox.class, Bukkit.class, MythicBukkit.class })
public class MythicMobsHookTest {
@Mock
private BentoBox plugin;
@Mock
private PluginManager pim;
@Mock
private Plugin mythicMobs;
@Mock
private Location location;
@Mock
private World world;
// DUT
MythicMobsHook hook;
@Mock
private MythicBukkit mythicBukkit;
@Mock
private MobExecutor mm;
@Mock
private MythicMob mythicMob;
@Mock
private ActiveMob activeMob;
@Mock
private Entity entity;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
// Set up plugin
plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Bukkit
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
when(Bukkit.getPluginManager()).thenReturn(pim);
when(pim.getPlugin("MythicMobs")).thenReturn(mythicMobs);
// Location
when(world.getName()).thenReturn("bskyblock");
when(location.getWorld()).thenReturn(world);
// Entity
when(entity.getUniqueId()).thenReturn(UUID.randomUUID());
// MythicMobs
PowerMockito.mockStatic(MythicBukkit.class, Mockito.RETURNS_MOCKS);
when(MythicBukkit.inst()).thenReturn(mythicBukkit);
when(mythicBukkit.getMobManager()).thenReturn(mm);
when(mm.getMythicMob(anyString())).thenReturn(Optional.of(mythicMob));
when(activeMob.getDisplayName()).thenReturn("Minion");
when(activeMob.getMobType()).thenReturn("GIANT");
when(activeMob.getStance()).thenReturn("default");
when(activeMob.getLevel()).thenReturn(2.5D);
when(activeMob.getPower()).thenReturn(33.2F);
when(mm.getActiveMob(any())).thenReturn(Optional.of(activeMob));
hook = new MythicMobsHook();
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link world.bentobox.bentobox.hooks.MythicMobsHook#hook()}.
*/
@Test
public void testHook() {
assertTrue(hook.hook());
}
/**
* Test method for {@link world.bentobox.bentobox.hooks.MythicMobsHook#getFailureCause()}.
*/
@Test
public void testGetFailureCause() {
assertNull(hook.getFailureCause());
}
/**
* Test method for {@link world.bentobox.bentobox.hooks.MythicMobsHook#MythicMobsHook()}.
*/
@Test
public void testMythicMobsHook() {
assertNotNull(hook);
assertEquals(Material.CREEPER_HEAD, hook.getIcon());
}
/**
* Test method for {@link world.bentobox.bentobox.hooks.MythicMobsHook#isMythicMob(org.bukkit.entity.Entity)}.
*/
@Test
public void testIsMythicMob() {
assertFalse(hook.isMythicMob(entity));
}
/**
* Test method for {@link world.bentobox.bentobox.hooks.MythicMobsHook#getMythicMob(org.bukkit.entity.Entity)}.
*/
@Test
public void testGetMythicMob() {
MythicMobRecord mmr = hook.getMythicMob(entity);
assertEquals("GIANT", mmr.type());
assertEquals("Minion", mmr.displayName());
assertEquals("default", mmr.stance());
assertEquals(2.5D, mmr.level(), 0D);
assertEquals(33.2F, mmr.power(), 0F);
}
/**
* Test method for {@link world.bentobox.bentobox.hooks.MythicMobsHook#spawnMythicMob(world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity.MythicMobRecord, org.bukkit.Location)}.
*/
@Test
public void testSpawnMythicMob() {
MythicMobRecord mmr = hook.getMythicMob(entity);
assertTrue(hook.spawnMythicMob(mmr, location));
verify(mm).getMythicMob("GIANT");
}
}

View File

@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -16,6 +17,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.Comparator; import java.util.Comparator;
import java.util.Optional;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -33,6 +35,7 @@ import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito; import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.api.user.User;
@ -128,13 +131,20 @@ public class BlueprintClipboardManagerTest {
blueprintFolder = new File("blueprints"); blueprintFolder = new File("blueprints");
// Clear any residual files // Clear any residual files
tearDown(); tearDown();
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Hooks
HooksManager hooksManager = mock(HooksManager.class);
when(hooksManager.getHook(anyString())).thenReturn(Optional.empty());
when(plugin.getHooks()).thenReturn(hooksManager);
PowerMockito.mockStatic(Bukkit.class); PowerMockito.mockStatic(Bukkit.class);
BlockData blockData = mock(BlockData.class); BlockData blockData = mock(BlockData.class);
when(Bukkit.createBlockData(any(Material.class))).thenReturn(blockData); when(Bukkit.createBlockData(any(Material.class))).thenReturn(blockData);
when(blockData.getAsString()).thenReturn("test123"); when(blockData.getAsString()).thenReturn("test123");
when(server.getBukkitVersion()).thenReturn("version"); when(server.getBukkitVersion()).thenReturn("version");
when(Bukkit.getServer()).thenReturn(server); when(Bukkit.getServer()).thenReturn(server);
} }
/** /**

View File

@ -1,9 +1,12 @@
package world.bentobox.bentobox.util; package world.bentobox.bentobox.util;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -25,10 +28,13 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.WallSign; import org.bukkit.block.data.type.WallSign;
import org.bukkit.block.sign.Side; import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide; import org.bukkit.block.sign.SignSide;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
@ -43,7 +49,11 @@ import world.bentobox.bentobox.api.addons.GameModeAddon;
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.blueprints.dataobjects.BlueprintBlock; import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity.MythicMobRecord;
import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.hooks.MythicMobsHook;
import world.bentobox.bentobox.managers.HooksManager;
import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.LocalesManager;
import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.bentobox.managers.PlayersManager;
@ -79,10 +89,20 @@ public class DefaultPasteUtilTest {
@Mock(extraInterfaces = {org.bukkit.block.Sign.class}) @Mock(extraInterfaces = {org.bukkit.block.Sign.class})
BlockState sign; BlockState sign;
@Mock
private PlayersManager pm;
@Mock
private MythicMobsHook mythicMobsHook;
@Mock
private BlueprintEntity blueprintEntity;
@Mock
private Location location;
@Mock
private LivingEntity livingEntity;
@Mock @Mock
private World world; private World world;
@Mock @Mock
private PlayersManager pm; private HooksManager hooksManager;
/** /**
@ -110,6 +130,11 @@ public class DefaultPasteUtilTest {
when(plugin.getLocalesManager()).thenReturn(localesManager); when(plugin.getLocalesManager()).thenReturn(localesManager);
when(localesManager.getOrDefault(any(), anyString(), anyString())).thenReturn("translated"); when(localesManager.getOrDefault(any(), anyString(), anyString())).thenReturn("translated");
when(location.getWorld()).thenReturn(world);
// Hooks
when(hooksManager.getHook("MythicMobs")).thenReturn(Optional.of(mythicMobsHook));
when(plugin.getHooks()).thenReturn(hooksManager);
when(plugin.getPlayers()).thenReturn(pm); when(plugin.getPlayers()).thenReturn(pm);
} }
@ -188,4 +213,32 @@ public class DefaultPasteUtilTest {
List<String> capturedLines = lineCaptor.getAllValues(); List<String> capturedLines = lineCaptor.getAllValues();
Assert.assertEquals(linesTranslated, capturedLines); Assert.assertEquals(linesTranslated, capturedLines);
} }
@Ignore
@Test
public void testSpawnBlueprintEntity_WithMythicMobs() {
// Set up conditions to satisfy the mythic mobs spawning logic
MythicMobRecord mmr = new MythicMobRecord("string", "string2", 10D, 1F, "string3");
when(blueprintEntity.getMythicMobsRecord()).thenReturn(mmr);
when(mythicMobsHook.spawnMythicMob(mmr, location)).thenReturn(true);
// This test works fine if there is a System.out.println() in the code. I assume some optimization is being done in compilation
assertFalse(DefaultPasteUtil.spawnBlueprintEntity(blueprintEntity, location, island));
// Verify the mythic mob was spawned, and the method returned early
verify(mythicMobsHook).spawnMythicMob(mmr, location);
verify(world, never()).spawnEntity(any(Location.class), any(EntityType.class));
}
@Test
public void testSpawnBlueprintEntity_WithoutMythicMobs() {
// Set up conditions where MythicMobs should not be spawned
when(hooksManager.getHook("MythicMobs")).thenReturn(Optional.empty());
assertTrue(DefaultPasteUtil.spawnBlueprintEntity(blueprintEntity, location, island));
// Verify a regular entity was spawned instead
verify(world).spawnEntity(location, blueprintEntity.getType());
}
} }