Initial commit
This commit is contained in:
commit
a0eedeec86
113
.gitignore
vendored
Normal file
113
.gitignore
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
# User-specific stuff
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
target/
|
||||||
|
|
||||||
|
pom.xml.tag
|
||||||
|
pom.xml.releaseBackup
|
||||||
|
pom.xml.versionsBackup
|
||||||
|
pom.xml.next
|
||||||
|
|
||||||
|
release.properties
|
||||||
|
dependency-reduced-pom.xml
|
||||||
|
buildNumber.properties
|
||||||
|
.mvn/timing.properties
|
||||||
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
|
.flattened-pom.xml
|
||||||
|
|
||||||
|
# Common working directory
|
||||||
|
run/
|
86
pom.xml
Normal file
86
pom.xml
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>net.knarcraft</groupId>
|
||||||
|
<artifactId>QuestMobSpawns</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>QuestMobSpawns</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>16</source>
|
||||||
|
<target>16</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.4</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spigotmc-repo</id>
|
||||||
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>codemc-repo</id>
|
||||||
|
<url>https://repo.codemc.io/repository/maven-public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot-api</artifactId>
|
||||||
|
<version>1.20.1-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.blackvein.quests</groupId>
|
||||||
|
<artifactId>quests-api</artifactId>
|
||||||
|
<version>4.8.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.blackvein.quests</groupId>
|
||||||
|
<artifactId>quests-core</artifactId>
|
||||||
|
<version>4.8.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
218
src/main/java/net/knarcraft/questmobspawns/QuestMobSpawns.java
Normal file
218
src/main/java/net/knarcraft/questmobspawns/QuestMobSpawns.java
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
package net.knarcraft.questmobspawns;
|
||||||
|
|
||||||
|
import me.blackvein.quests.QuestsAPI;
|
||||||
|
import me.blackvein.quests.player.IQuester;
|
||||||
|
import me.blackvein.quests.quests.IQuest;
|
||||||
|
import me.blackvein.quests.quests.IStage;
|
||||||
|
import net.knarcraft.questmobspawns.listener.MobBlockDamageListener;
|
||||||
|
import net.knarcraft.questmobspawns.listener.MobDeathListener;
|
||||||
|
import net.knarcraft.questmobspawns.util.QuestMobHelper;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.SoundCategory;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public final class QuestMobSpawns extends JavaPlugin {
|
||||||
|
|
||||||
|
private final Random random = new Random();
|
||||||
|
private static QuestMobSpawns plugin;
|
||||||
|
private QuestsAPI questsAPI;
|
||||||
|
|
||||||
|
public static QuestMobSpawns getPlugin() {
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
plugin = this;
|
||||||
|
// Plugin startup logic
|
||||||
|
questsAPI = (QuestsAPI) Bukkit.getServer().getPluginManager().getPlugin("Quests");
|
||||||
|
if (questsAPI == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Bukkit.getPluginManager().registerEvents(new MobDeathListener(), this);
|
||||||
|
Bukkit.getPluginManager().registerEvents(new MobBlockDamageListener(questsAPI), this);
|
||||||
|
|
||||||
|
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, this::spawnMobs, 200, 30 * 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
// Plugin shutdown logic
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawns mobs for all kill areas as necessary
|
||||||
|
*/
|
||||||
|
private void spawnMobs() {
|
||||||
|
// Find the players taking each quest
|
||||||
|
Set<IQuest> questsWithPlayers = new HashSet<>();
|
||||||
|
Map<IStage, Set<IQuester>> stagePlayerMap = new HashMap<>();
|
||||||
|
Collection<IQuester> onlineQuestTakers = questsAPI.getOnlineQuesters();
|
||||||
|
|
||||||
|
// If no quest takers are online, abort
|
||||||
|
if (onlineQuestTakers == null || onlineQuestTakers.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (IQuester questPlayer : onlineQuestTakers) {
|
||||||
|
for (IQuest quest : questPlayer.getQuestData().keySet()) {
|
||||||
|
questsWithPlayers.add(quest);
|
||||||
|
IStage playerStage = questPlayer.getCurrentStage(quest);
|
||||||
|
for (int i = 0; i < playerStage.getMobsToKill().size(); i++) {
|
||||||
|
// If the player has not killed enough mobs, spawn the mobs
|
||||||
|
if (questPlayer.getQuestData(quest).getMobNumKilled().get(i) >= playerStage.getMobNumToKill().get(i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stagePlayerMap.containsKey(playerStage)) {
|
||||||
|
stagePlayerMap.put(playerStage, new HashSet<>());
|
||||||
|
}
|
||||||
|
stagePlayerMap.get(playerStage).add(questPlayer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no players are online, abort
|
||||||
|
if (stagePlayerMap.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (IQuest quest : questsAPI.getLoadedQuests()) {
|
||||||
|
// Ignore quests with no players
|
||||||
|
if (!questsWithPlayers.contains(quest)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (IStage stage : quest.getStages()) {
|
||||||
|
for (int i = 0; i < stage.getLocationsToKillWithin().size(); i++) {
|
||||||
|
spawnMobsForStage(stagePlayerMap, quest, stage, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnMobsForStage(Map<IStage, Set<IQuester>> questPlayerMap, IQuest quest, IStage stage, int index) {
|
||||||
|
Location killLocation = stage.getLocationsToKillWithin().get(index).clone();
|
||||||
|
int radius = stage.getRadiiToKillWithin().get(index);
|
||||||
|
|
||||||
|
// TODO: De-spawn custom mobs if players are no longer in the area (should probably save the state)
|
||||||
|
|
||||||
|
// If no players are at this stage, abort
|
||||||
|
if (questPlayerMap.get(stage) == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the number of mobs to spawn at once
|
||||||
|
int maxMobs = radius / 2;
|
||||||
|
int mobsToSpawn = calculateMobNumber(questPlayerMap, quest, stage, index, killLocation, radius, maxMobs);
|
||||||
|
if (mobsToSpawn <= 0 || killLocation.getWorld() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are a bunch of mobs in the area, don't spawn more
|
||||||
|
EntityType entityType = stage.getMobsToKill().get(index);
|
||||||
|
int nearby = entitiesInKillZone(killLocation, radius, entityType);
|
||||||
|
if (nearby >= maxMobs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn entities
|
||||||
|
for (int counter = 0; counter < mobsToSpawn; counter++) {
|
||||||
|
int x = (int) Math.round((random.nextInt(radius * 2) - radius) + killLocation.getX());
|
||||||
|
int z = (int) Math.round((random.nextInt(radius * 2) - radius) + killLocation.getZ());
|
||||||
|
Block spawnBlock = killLocation.getWorld().getHighestBlockAt(x, z).getRelative(BlockFace.UP);
|
||||||
|
Entity spawnedEntity = killLocation.getWorld().spawnEntity(spawnBlock.getLocation(), entityType);
|
||||||
|
|
||||||
|
// Treat the spawned entity as the result of a spawner for plugins like mcMMO
|
||||||
|
if (spawnedEntity instanceof LivingEntity) {
|
||||||
|
CreatureSpawnEvent spawnEvent = new CreatureSpawnEvent((LivingEntity) spawnedEntity,
|
||||||
|
CreatureSpawnEvent.SpawnReason.SPAWNER);
|
||||||
|
Bukkit.getPluginManager().callEvent(spawnEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
QuestMobHelper.setSpawnedMob(spawnedEntity);
|
||||||
|
QuestMobHelper.setQuestData(spawnedEntity, quest.getId(), quest.getStages().indexOf(stage), index,
|
||||||
|
new int[]{killLocation.getBlockX(), killLocation.getBlockY(), killLocation.getBlockZ(), radius});
|
||||||
|
// Play a sound so players won't be too surprised
|
||||||
|
killLocation.getWorld().playSound(spawnBlock.getLocation(), Sound.ITEM_GOAT_HORN_SOUND_2,
|
||||||
|
SoundCategory.HOSTILE, 1F, 1F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts the number of entities of the necessary type already in the kill zone
|
||||||
|
*
|
||||||
|
* @param killLocation <p>The location of the kill location's centre</p>
|
||||||
|
* @param radius <p>The radius of the kill zone</p>
|
||||||
|
* @param entityType <p>The type of entity to kill in the kill zone</p>
|
||||||
|
* @return <p></p>
|
||||||
|
*/
|
||||||
|
private int entitiesInKillZone(Location killLocation, int radius, EntityType entityType) {
|
||||||
|
if (killLocation.getWorld() == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Collection<Entity> nearby = killLocation.getWorld().getNearbyEntities(killLocation, radius, 10, radius,
|
||||||
|
(entity -> entity.getType() == entityType));
|
||||||
|
List<Entity> tooFar = new ArrayList<>();
|
||||||
|
for (Entity entity : nearby) {
|
||||||
|
Location entityLocation = entity.getLocation().clone();
|
||||||
|
entityLocation.setY(0);
|
||||||
|
if (QuestMobHelper.get2dDistance(entityLocation, killLocation) > radius) {
|
||||||
|
tooFar.add(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nearby.removeAll(tooFar);
|
||||||
|
return nearby.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the number of mobs that should be spawned at once
|
||||||
|
*
|
||||||
|
* @param questPlayerMap <p>The map for which players are on which stage</p>
|
||||||
|
* @param quest <p>The quest a mob is spawned for</p>
|
||||||
|
* @param stage <p>The stage a mob is spawned for</p>
|
||||||
|
* @param index <p>The index of the task to spawn a mob for</p>
|
||||||
|
* @param killLocation <p>The centre of the kill location</p>
|
||||||
|
* @param radius <p>The radius of the kill location</p>
|
||||||
|
* @param maxMobs <p>The maximum amount of mobs allowed in the kill zone</p>
|
||||||
|
* @return <p>The number of mobs to spawn</p>
|
||||||
|
*/
|
||||||
|
private int calculateMobNumber(Map<IStage, Set<IQuester>> questPlayerMap, IQuest quest, IStage stage, int index,
|
||||||
|
Location killLocation, int radius, int maxMobs) {
|
||||||
|
int mobsToSpawn = 0;
|
||||||
|
for (IQuester player : questPlayerMap.get(stage)) {
|
||||||
|
Location playerLocation = player.getPlayer().getLocation().clone();
|
||||||
|
playerLocation.setY(0);
|
||||||
|
if (player.getQuestData(quest).getMobNumKilled().get(index) < stage.getMobNumToKill().get(index) &&
|
||||||
|
QuestMobHelper.get2dDistance(killLocation, playerLocation) < radius) {
|
||||||
|
mobsToSpawn++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mobsToSpawn < 1 || killLocation.getWorld() == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
mobsToSpawn *= radius / 5.0;
|
||||||
|
mobsToSpawn = Math.max(mobsToSpawn, 1);
|
||||||
|
mobsToSpawn = Math.min(maxMobs, mobsToSpawn);
|
||||||
|
return mobsToSpawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
package net.knarcraft.questmobspawns.listener;
|
||||||
|
|
||||||
|
import me.blackvein.quests.QuestsAPI;
|
||||||
|
import me.blackvein.quests.player.IQuester;
|
||||||
|
import me.blackvein.quests.quests.IQuest;
|
||||||
|
import me.blackvein.quests.quests.IStage;
|
||||||
|
import net.knarcraft.questmobspawns.util.QuestMobHelper;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.EntityBreakDoorEvent;
|
||||||
|
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||||
|
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||||
|
import org.bukkit.event.entity.EntityInteractEvent;
|
||||||
|
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
|
||||||
|
|
||||||
|
public class MobBlockDamageListener implements Listener {
|
||||||
|
|
||||||
|
private final QuestsAPI questsAPI;
|
||||||
|
|
||||||
|
public MobBlockDamageListener(QuestsAPI questsAPI) {
|
||||||
|
this.questsAPI = questsAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onExplode(EntityExplodeEvent event) {
|
||||||
|
if (QuestMobHelper.isSpawnedMob(event.getEntity())) {
|
||||||
|
event.blockList().clear();
|
||||||
|
event.setCancelled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
|
public void onBlockChange(EntityChangeBlockEvent event) {
|
||||||
|
cancelIfQuestMob(event, event.getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onDoorBreak(EntityBreakDoorEvent event) {
|
||||||
|
cancelIfQuestMob(event, event.getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onEntityTarget(EntityTargetLivingEntityEvent event) {
|
||||||
|
Entity entity = event.getEntity();
|
||||||
|
if (!QuestMobHelper.isSpawnedMob(entity) || !(event.getTarget() instanceof Player player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasQuest(entity, player)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
} else {
|
||||||
|
// Cancel the targeting if the player is outside the kill-zone
|
||||||
|
int[] killLocationData = QuestMobHelper.getKillZoneLocation(entity);
|
||||||
|
Location killLocation = new Location(entity.getWorld(), killLocationData[0], killLocationData[1],
|
||||||
|
killLocationData[2]);
|
||||||
|
event.setCancelled(QuestMobHelper.get2dDistance(player.getLocation(), killLocation) > killLocationData[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onTrample(EntityInteractEvent event) {
|
||||||
|
cancelIfQuestMob(event, event.getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onEntityDamage(EntityDamageByEntityEvent event) {
|
||||||
|
if (!QuestMobHelper.isSpawnedMob(event.getDamager())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity damagingEntity = event.getDamager();
|
||||||
|
if (event.getEntity() instanceof Player player) {
|
||||||
|
event.setCancelled(!hasQuest(damagingEntity, player));
|
||||||
|
} else {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given player has the quest the given entity was spawned for
|
||||||
|
*
|
||||||
|
* @param entity <p>The entity with stored quest data</p>
|
||||||
|
* @param player <p>A player</p>
|
||||||
|
* @return <p>True if the player has the quest stored in the entity</p>
|
||||||
|
*/
|
||||||
|
private Boolean hasQuest(Entity entity, Player player) {
|
||||||
|
IQuester questPlayer = questsAPI.getQuester(player.getUniqueId());
|
||||||
|
IQuest quest = getQuest(QuestMobHelper.getQuestId(entity));
|
||||||
|
if (quest == null) {
|
||||||
|
// Remove the entity if the quest it belongs to no longer exists
|
||||||
|
entity.remove();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
IStage stage = quest.getStage(QuestMobHelper.getStageId(entity));
|
||||||
|
int index = QuestMobHelper.getIndex(entity);
|
||||||
|
return questPlayer.getQuestData().containsKey(quest) && questPlayer.getCurrentStage(quest) == stage &&
|
||||||
|
questPlayer.getQuestData(quest).getMobNumKilled().get(index) < stage.getMobNumToKill().get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IQuest getQuest(String questId) {
|
||||||
|
for (IQuest quest : questsAPI.getLoadedQuests()) {
|
||||||
|
if (quest.getId().equalsIgnoreCase(questId)) {
|
||||||
|
return quest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelIfQuestMob(Cancellable cancellable, Entity entity) {
|
||||||
|
if (QuestMobHelper.isSpawnedMob(entity)) {
|
||||||
|
cancellable.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package net.knarcraft.questmobspawns.listener;
|
||||||
|
|
||||||
|
import net.knarcraft.questmobspawns.util.QuestMobHelper;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.EntityDeathEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDropItemEvent;
|
||||||
|
|
||||||
|
public class MobDeathListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
|
public void onMobDeath(EntityDeathEvent deathEvent) {
|
||||||
|
if (QuestMobHelper.isSpawnedMob(deathEvent.getEntity())) {
|
||||||
|
deathEvent.getDrops().clear();
|
||||||
|
deathEvent.setDroppedExp(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
|
public void onMobDrop(EntityDropItemEvent dropEvent) {
|
||||||
|
if (QuestMobHelper.isSpawnedMob(dropEvent.getEntity())) {
|
||||||
|
dropEvent.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package net.knarcraft.questmobspawns.util;
|
||||||
|
|
||||||
|
import net.knarcraft.questmobspawns.QuestMobSpawns;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
|
public class QuestMobHelper {
|
||||||
|
|
||||||
|
private static final NamespacedKey questMobKey = new NamespacedKey(QuestMobSpawns.getPlugin(), "questMob");
|
||||||
|
private static final NamespacedKey questIdKey = new NamespacedKey(QuestMobSpawns.getPlugin(), "questId");
|
||||||
|
private static final NamespacedKey stageIdKey = new NamespacedKey(QuestMobSpawns.getPlugin(), "stageId");
|
||||||
|
private static final NamespacedKey mobIndexKey = new NamespacedKey(QuestMobSpawns.getPlugin(), "mobIndex");
|
||||||
|
private static final NamespacedKey killZoneLocationKey = new NamespacedKey(QuestMobSpawns.getPlugin(), "killZoneLocationKey");
|
||||||
|
|
||||||
|
public static boolean isSpawnedMob(Entity entity) {
|
||||||
|
return Boolean.TRUE.equals(entity.getPersistentDataContainer().get(questMobKey, PersistentDataType.BOOLEAN));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setSpawnedMob(Entity entity) {
|
||||||
|
entity.getPersistentDataContainer().set(questMobKey, PersistentDataType.BOOLEAN, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getQuestId(Entity entity) {
|
||||||
|
return entity.getPersistentDataContainer().get(questIdKey, PersistentDataType.STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getStageId(Entity entity) {
|
||||||
|
return entity.getPersistentDataContainer().get(stageIdKey, PersistentDataType.INTEGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getIndex(Entity entity) {
|
||||||
|
return entity.getPersistentDataContainer().get(mobIndexKey, PersistentDataType.INTEGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets information about the mob's kill zone
|
||||||
|
*
|
||||||
|
* @param entity <p>The entity to get data for</p>
|
||||||
|
* @return <p>An array containing x,y,z,radius</p>
|
||||||
|
*/
|
||||||
|
public static int[] getKillZoneLocation(Entity entity) {
|
||||||
|
return entity.getPersistentDataContainer().get(killZoneLocationKey, PersistentDataType.INTEGER_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores quest info to a mob
|
||||||
|
*
|
||||||
|
* @param entity <p>The entity to store quest data to</p>
|
||||||
|
* @param questId <p>The id of the quest the mob was spawned for</p>
|
||||||
|
* @param killLocationInfo <p>Information about the kill location (x, y, z, range)</p>
|
||||||
|
*/
|
||||||
|
public static void setQuestData(Entity entity, String questId, int stageId, int mobIndex, int[] killLocationInfo) {
|
||||||
|
PersistentDataContainer persistentDataContainer = entity.getPersistentDataContainer();
|
||||||
|
persistentDataContainer.set(questIdKey, PersistentDataType.STRING, questId);
|
||||||
|
persistentDataContainer.set(stageIdKey, PersistentDataType.INTEGER, stageId);
|
||||||
|
persistentDataContainer.set(mobIndexKey, PersistentDataType.INTEGER, mobIndex);
|
||||||
|
persistentDataContainer.set(killZoneLocationKey, PersistentDataType.INTEGER_ARRAY, killLocationInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the 2d (x,z) distance between two locations
|
||||||
|
*
|
||||||
|
* @param location1 <p>The first location</p>
|
||||||
|
* @param location2 <p>The second location</p>
|
||||||
|
* @return <p>The 2d distance between the locations</p>
|
||||||
|
*/
|
||||||
|
public static double get2dDistance(Location location1, Location location2) {
|
||||||
|
return Math.sqrt(Math.pow(location2.getX() - location1.getX(), 2) +
|
||||||
|
Math.pow(location2.getZ() - location1.getZ(), 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
6
src/main/resources/plugin.yml
Normal file
6
src/main/resources/plugin.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
name: QuestMobSpawns
|
||||||
|
version: '${project.version}'
|
||||||
|
main: net.knarcraft.questmobspawns.QuestMobSpawns
|
||||||
|
api-version: '1.20'
|
||||||
|
depend:
|
||||||
|
- Quests
|
Loading…
Reference in New Issue
Block a user