Skip to content

Commit

Permalink
Merge pull request #2576 from BentoBoxWorld/2569_general_display_enti…
Browse files Browse the repository at this point in the history
…tiy_support

2569 general display entitiy support
  • Loading branch information
tastybento authored Dec 28, 2024
2 parents 6673d46 + f406025 commit 11bd46e
Show file tree
Hide file tree
Showing 17 changed files with 660 additions and 216 deletions.
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,13 @@
<version>2.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- FancyHolograms -->
<dependency>
<groupId>de.oliver</groupId>
<artifactId>FancyHolograms</artifactId>
<version>2.4.1</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/world/bentobox/bentobox/api/hooks/NPCHook.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package world.bentobox.bentobox.api.hooks;

import java.util.List;
import java.util.Map;

import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;

import de.oliver.fancynpcs.api.Npc;
import lol.pyr.znpcsplus.api.npc.NpcEntry;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;

/**
* NPC Hooks
* @author tastybento
* @since 3.2.0
*/
public abstract class NPCHook extends Hook {

protected NPCHook(@NonNull String pluginName, @NonNull Material icon) {
super(pluginName, icon);
}

public abstract boolean spawnNpc(String yaml, Location pos) throws InvalidConfigurationException;

public abstract Map<? extends Vector, ? extends List<BlueprintEntity>> getNpcsInArea(World world,
List<Vector> vectorsToCopy, @Nullable Vector origin);

/**
* Remove all NPCs in chunk
* @param chunk chunk
*/
public abstract void removeNPCsInChunk(Chunk chunk);

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,20 @@
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.block.Banner;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.Sign;
import org.bukkit.block.data.Attachable;
import org.bukkit.block.sign.Side;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Player;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Villager;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.Attachable;
import org.bukkit.material.Colorable;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
Expand All @@ -57,6 +52,10 @@
*/
public class BlueprintClipboard {

/**
* Used to filter out hidden DisplayEntity armor stands when copying
*/
private static final NamespacedKey KEY = new NamespacedKey(BentoBox.getInstance(), "associatedDisplayEntity");
private @Nullable Blueprint blueprint;
private @Nullable Location pos1;
private @Nullable Location pos2;
Expand All @@ -74,6 +73,7 @@ public class BlueprintClipboard {
private Optional<FancyNpcsHook> npc;
private Optional<ZNPCsPlusHook> znpc;


/**
* Create a clipboard for blueprint
* @param blueprint - the blueprint to load into the clipboard
Expand Down Expand Up @@ -148,6 +148,7 @@ private void copyAsync(World world, User user, List<Vector> vectorsToCopy, int s
// Add all the citizens for the area in one go. This is pretty fast.
bpEntities.putAll(npc.get().getNpcsInArea(world, vectorsToCopy, origin));
}
// ZNPCsPlus NPCs
if (znpc.isPresent()) {
bpEntities.putAll(znpc.get().getNpcsInArea(world, vectorsToCopy, origin));
}
Expand All @@ -162,9 +163,9 @@ private void copyAsync(World world, User user, List<Vector> vectorsToCopy, int s
List<Entity> ents = world.getEntities().stream()
.filter(Objects::nonNull)
.filter(e -> !(e instanceof Player))
.filter(e -> new Vector(Math.rint(e.getLocation().getX()),
Math.rint(e.getLocation().getY()),
Math.rint(e.getLocation().getZ())).equals(v))
.filter(e -> !e.getPersistentDataContainer().has(KEY, PersistentDataType.STRING)) // Do not copy hidden display entities
.filter(e -> new Vector(e.getLocation().getBlockX(), e.getLocation().getBlockY(),
e.getLocation().getBlockZ()).equals(v))
.toList();
if (copyBlock(v.toLocation(world), copyAir, copyBiome, ents)) {
count++;
Expand Down Expand Up @@ -230,7 +231,6 @@ private boolean copyBlock(Location l, boolean copyAir, boolean copyBiome, List<E
if (!copyAir && block.getType().equals(Material.AIR) && !ents.isEmpty()) {
return true;
}

BlueprintBlock b = bluePrintBlock(pos, block, copyBiome);
if (b != null) {
this.bpBlocks.put(pos, b);
Expand All @@ -256,7 +256,7 @@ private BlueprintBlock bluePrintBlock(Vector pos, Block block, boolean copyBiome
}
}
// Set block data
if (blockState.getData() instanceof Attachable) {
if (blockState.getBlockData() instanceof Attachable) {
// Placeholder for attachment
bpBlocks.put(pos, new BlueprintBlock("minecraft:air"));
bpAttachable.put(pos, b);
Expand All @@ -273,7 +273,6 @@ private BlueprintBlock bluePrintBlock(Vector pos, Block block, boolean copyBiome
}
}
}

// Chests
if (blockState instanceof InventoryHolder ih) {
b.setInventory(new HashMap<>());
Expand All @@ -284,11 +283,9 @@ private BlueprintBlock bluePrintBlock(Vector pos, Block block, boolean copyBiome
}
}
}

if (blockState instanceof CreatureSpawner spawner) {
b.setCreatureSpawner(getSpawner(spawner));
}

// Banners
if (blockState instanceof Banner banner) {
b.setBannerPatterns(banner.getPatterns());
Expand Down Expand Up @@ -317,62 +314,15 @@ private BlueprintCreatureSpawner getSpawner(CreatureSpawner spawner) {
private List<BlueprintEntity> setEntities(List<Entity> ents) {
List<BlueprintEntity> bpEnts = new ArrayList<>();
for (Entity entity : ents) {
BlueprintEntity bpe = new BlueprintEntity();

bpe.setType(entity.getType());
bpe.setCustomName(entity.getCustomName());
if (entity instanceof Villager villager) {
setVillager(villager, bpe);
}
if (entity instanceof Colorable c && c.getColor() != null) {
bpe.setColor(c.getColor());
}
if (entity instanceof Tameable tameable) {
bpe.setTamed(tameable.isTamed());
}
if (entity instanceof ChestedHorse chestedHorse) {
bpe.setChest(chestedHorse.isCarryingChest());
}
// Only set if child. Most animals are adults
if (entity instanceof Ageable ageable && !ageable.isAdult()) {
bpe.setAdult(false);
}
if (entity instanceof AbstractHorse horse) {
bpe.setDomestication(horse.getDomestication());
bpe.setInventory(new HashMap<>());
for (int i = 0; i < horse.getInventory().getSize(); i++) {
ItemStack item = horse.getInventory().getItem(i);
if (item != null) {
bpe.getInventory().put(i, item);
}
}
}

if (entity instanceof Horse horse) {
bpe.setStyle(horse.getStyle());
}

BlueprintEntity bpe = new BlueprintEntity(entity);
// Mythic mob check
mmh.filter(mm -> mm.isMythicMob(entity)).map(mm -> mm.getMythicMob(entity))
.ifPresent(bpe::setMythicMobsRecord);

bpEnts.add(bpe);
}
return bpEnts;
}

/**
* Set the villager stats
* @param v - villager
* @param bpe - Blueprint Entity
*/
private void setVillager(Villager v, BlueprintEntity bpe) {
bpe.setExperience(v.getVillagerExperience());
bpe.setLevel(v.getVillagerLevel());
bpe.setProfession(v.getProfession());
bpe.setVillagerType(v.getVillagerType());
}

/**
* @return the origin
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package world.bentobox.bentobox.blueprints;

import java.util.UUID;

import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Display;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.persistence.PersistentDataType;

import world.bentobox.bentobox.BentoBox;

/**
* Provides a listener for the Display Objects pasted when a hologram is interacted with
* https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/event/player/PlayerInteractAtEntityEvent.html
*/
public class DisplayListener implements Listener {

@EventHandler
public void onPlayerInteractEntity(PlayerInteractAtEntityEvent event) {
if (event.getRightClicked() instanceof ArmorStand) {
ArmorStand armorStand = (ArmorStand) event.getRightClicked();
NamespacedKey key = new NamespacedKey(BentoBox.getInstance(), "associatedDisplayEntity");

if (armorStand.getPersistentDataContainer().has(key, PersistentDataType.STRING)) {
String displayEntityUUID = armorStand.getPersistentDataContainer().get(key, PersistentDataType.STRING);

// Fetch the associated DisplayEntity by UUID
World world = armorStand.getWorld();
world.getEntitiesByClass(Display.class).stream()
.filter(e -> e.getUniqueId().equals(UUID.fromString(displayEntityUUID))).findFirst()
.ifPresent(e -> {
event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.BLOCK_GLASS_BREAK, 1F,
1F);
e.remove();

});
}
}
}
}
Loading

0 comments on commit 11bd46e

Please sign in to comment.