Change /npc size to /npc slimesize, centralise item pickup check to EventListen, add /npc textdisplay

This commit is contained in:
fullwall 2024-10-05 17:07:34 +08:00
parent 8f7ae65d93
commit 0e62308ba0
25 changed files with 247 additions and 187 deletions

View File

@ -401,7 +401,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
if (!new File(getDataFolder(), "skins").exists()) {
new File(getDataFolder(), "skins").mkdir();
}
Bukkit.getPluginManager().registerEvents(new EventListen(), this);
Bukkit.getPluginManager().registerEvents(new EventListen(this), this);
Bukkit.getPluginManager().registerEvents(new Placeholders(), this);
Plugin papi = Bukkit.getPluginManager().getPlugin("PlaceholderAPI");
@ -467,6 +467,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
shops.loadFromDisk();
shops.load();
getServer().getPluginManager().callEvent(new CitizensReloadEvent());
}

View File

@ -30,6 +30,7 @@ import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.event.entity.EntityTameEvent;
import org.bukkit.event.entity.EntityTargetEvent;
@ -44,6 +45,7 @@ import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerShearEntityEvent;
@ -73,7 +75,6 @@ import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.ai.event.NavigationBeginEvent;
import net.citizensnpcs.api.ai.event.NavigationCompleteEvent;
import net.citizensnpcs.api.event.CitizensPreReloadEvent;
@ -123,11 +124,33 @@ import net.citizensnpcs.util.Util;
public class EventListen implements Listener {
private Listener chunkEventListener;
private SkinUpdateTracker skinUpdateTracker;
private Citizens plugin;
private final SkinUpdateTracker skinUpdateTracker;
private final ListMultimap<ChunkCoord, NPC> toRespawn = ArrayListMultimap.create(64, 4);
EventListen() {
EventListen(Citizens plugin) {
this.plugin = plugin;
skinUpdateTracker = new SkinUpdateTracker();
try {
Class.forName("org.bukkit.event.entity.EntityPickupItemEvent");
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler(priority = EventPriority.MONITOR)
public void onEntityPickupItem(EntityPickupItemEvent event) {
if (event.getItem() instanceof NPCHolder) {
event.setCancelled(true);
}
}
}, plugin);
} catch (Throwable ex) {
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler
public void onPlayerPickupItemEvent(PlayerPickupItemEvent event) {
if (event.getItem() instanceof NPCHolder) {
event.setCancelled(true);
}
}
}, plugin);
}
try {
Class.forName("org.bukkit.event.world.EntitiesLoadEvent");
Bukkit.getPluginManager().registerEvents(new Listener() {
@ -138,14 +161,13 @@ public class EventListen implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntitiesUnload(EntitiesUnloadEvent event) {
List<NPC> toDespawn = Lists
.newArrayList(CitizensAPI.getLocationLookup().getNearbyNPCs(event.getWorld(),
new double[] { (event.getChunk().getX() << 4) - 0.5, 0,
(event.getChunk().getZ() << 4) - 0.5 },
new double[] { (event.getChunk().getX() + 1 << 4) + 0.5, 256,
(event.getChunk().getZ() + 1 << 4) + 0.5 }));
List<NPC> toDespawn = Lists.newArrayList(plugin.getLocationLookup().getNearbyNPCs(event.getWorld(),
new double[] { (event.getChunk().getX() << 4) - 0.5, 0,
(event.getChunk().getZ() << 4) - 0.5 },
new double[] { (event.getChunk().getX() + 1 << 4) + 0.5, 256,
(event.getChunk().getZ() + 1 << 4) + 0.5 }));
for (Entity entity : event.getEntities()) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity);
NPC npc = plugin.getNPCRegistry().getNPC(entity);
// XXX npc#isSpawned() checks valid status which is now inconsistent on chunk unload
// between different server software so check for npc.getEntity() == null instead.
if (npc == null || npc.getEntity() == null || toDespawn.contains(npc))
@ -157,7 +179,7 @@ public class EventListen implements Listener {
return;
unloadNPCs(event, toDespawn);
}
}, CitizensAPI.getPlugin());
}, plugin);
} catch (Throwable ex) {
}
try {
@ -165,14 +187,14 @@ public class EventListen implements Listener {
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler
public void onEntityTransform(EntityTransformEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null)
return;
if (npc.isProtected()) {
event.setCancelled(true);
}
}
}, CitizensAPI.getPlugin());
}, plugin);
} catch (Throwable ex) {
}
Class<?> kbc = null;
@ -208,7 +230,7 @@ public class EventListen implements Listener {
if (limit < 0)
return;
int owned = 0;
for (NPC npc : CitizensAPI.getNPCRegistry()) {
for (NPC npc : plugin.getNPCRegistry()) {
if (!event.getNPC().equals(npc) && npc.hasTrait(Owner.class)
&& npc.getTraitNullable(Owner.class).isOwnedBy(event.getCreator())) {
owned++;
@ -222,7 +244,7 @@ public class EventListen implements Listener {
}
private Iterable<NPC> getAllNPCs() {
return Iterables.filter(Iterables.concat(CitizensAPI.getNPCRegistries()), Objects::nonNull);
return Iterables.filter(Iterables.concat(plugin.getNPCRegistries()), Objects::nonNull);
}
void loadNPCs(ChunkEvent event) {
@ -234,7 +256,7 @@ public class EventListen implements Listener {
if (event instanceof Cancellable) {
runnable.run();
} else {
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), runnable);
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, runnable);
}
}
@ -249,12 +271,12 @@ public class EventListen implements Listener {
public void onChunkUnload(ChunkUnloadEvent event) {
if (chunkEventListener != null)
return;
List<NPC> toDespawn = Lists.newArrayList(CitizensAPI.getLocationLookup().getNearbyNPCs(event.getWorld(),
List<NPC> toDespawn = Lists.newArrayList(plugin.getLocationLookup().getNearbyNPCs(event.getWorld(),
new double[] { (event.getChunk().getX() << 4) - 0.5, 0, (event.getChunk().getZ() << 4) - 0.5 },
new double[] { (event.getChunk().getX() + 1 << 4) + 0.5, 256,
(event.getChunk().getZ() + 1 << 4) + 0.5 }));
for (Entity entity : event.getChunk().getEntities()) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity);
NPC npc = plugin.getNPCRegistry().getNPC(entity);
// XXX npc#isSpawned() checks valid status which is now inconsistent on chunk unload
// between different server software so check for npc.getEntity() == null instead.
if (npc == null || npc.getEntity() == null || toDespawn.contains(npc))
@ -280,7 +302,7 @@ public class EventListen implements Listener {
@EventHandler
public void onEntityBlockForm(EntityBlockFormEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null)
return;
if (npc.getEntity() instanceof Snowman) {
@ -293,7 +315,7 @@ public class EventListen implements Listener {
@EventHandler
public void onEntityCombust(EntityCombustEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null)
return;
@ -310,10 +332,10 @@ public class EventListen implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onEntityDamage(EntityDamageEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null) {
if (event instanceof EntityDamageByEntityEvent) {
npc = CitizensAPI.getNPCRegistry().getNPC(((EntityDamageByEntityEvent) event).getDamager());
npc = plugin.getNPCRegistry().getNPC(((EntityDamageByEntityEvent) event).getDamager());
if (npc == null)
return;
event.setCancelled(!npc.data().get(NPC.Metadata.DAMAGE_OTHERS, true));
@ -351,7 +373,7 @@ public class EventListen implements Listener {
@EventHandler(ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null)
return;
@ -367,7 +389,7 @@ public class EventListen implements Listener {
return;
int deathAnimationTicks = event.getEntity() instanceof LivingEntity ? 20 : 2;
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
if (!npc.isSpawned() && npc.getOwningRegistry().getByUniqueId(npc.getUniqueId()) == npc) {
npc.spawn(location, SpawnReason.TIMED_RESPAWN);
}
@ -376,7 +398,7 @@ public class EventListen implements Listener {
@EventHandler
public void onEntityPortal(EntityPortalEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null || npc.getEntity().getType() != EntityType.PLAYER)
return;
@ -388,14 +410,14 @@ public class EventListen implements Listener {
@EventHandler(priority = EventPriority.HIGHEST)
public void onEntitySpawn(CreatureSpawnEvent event) {
if (event.isCancelled() && CitizensAPI.getNPCRegistry().isNPC(event.getEntity())) {
if (event.isCancelled() && plugin.getNPCRegistry().isNPC(event.getEntity())) {
event.setCancelled(false);
}
}
@EventHandler(ignoreCancelled = true)
public void onEntityTame(EntityTameEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null || !npc.isProtected())
return;
event.setCancelled(true);
@ -403,7 +425,7 @@ public class EventListen implements Listener {
@EventHandler
public void onEntityTarget(EntityTargetEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getTarget());
NPC npc = plugin.getNPCRegistry().getNPC(event.getTarget());
if (npc == null)
return;
@ -413,7 +435,7 @@ public class EventListen implements Listener {
@EventHandler(ignoreCancelled = true)
public void onItemDespawn(ItemDespawnEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null)
return;
@ -475,8 +497,7 @@ public class EventListen implements Listener {
}
if (npc.data().has(NPC.Metadata.HOLOGRAM_RENDERER)) {
HologramRenderer hr = npc.data().get(NPC.Metadata.HOLOGRAM_RENDERER);
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
() -> hr.onSeenByPlayer(npc, event.getPlayer()), 2);
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> hr.onSeenByPlayer(npc, event.getPlayer()), 2);
}
}
@ -489,12 +510,12 @@ public class EventListen implements Listener {
NMS.sendPositionUpdate(tracker, ImmutableList.of(event.getPlayer()), false, null, null,
NMS.getHeadYaw(tracker));
if (resetYaw) {
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin,
() -> PlayerAnimation.ARM_SWING.play((Player) tracker, event.getPlayer()));
}
return;
}
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
if (!tracker.isValid() || !event.getPlayer().isValid())
return;
@ -541,10 +562,10 @@ public class EventListen implements Listener {
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
skinUpdateTracker.removePlayer(event.getPlayer().getUniqueId());
skinUpdateTracker.updatePlayer(event.getPlayer(), 20, true);
if (CitizensAPI.getNPCRegistry().getNPC(event.getPlayer()) == null)
if (plugin.getNPCRegistry().getNPC(event.getPlayer()) == null)
return;
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
NMS.replaceTracker(event.getPlayer());
NMS.removeFromServerPlayerList(event.getPlayer());
}, 1);
@ -559,7 +580,7 @@ public class EventListen implements Listener {
@EventHandler(ignoreCancelled = true)
public void onPlayerDeath(PlayerDeathEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null)
return;
@ -570,15 +591,15 @@ public class EventListen implements Listener {
@EventHandler(ignoreCancelled = true)
public void onPlayerFish(PlayerFishEvent event) {
if (CitizensAPI.getNPCRegistry().isNPC(event.getCaught())
&& CitizensAPI.getNPCRegistry().getNPC(event.getCaught()).isProtected()) {
if (plugin.getNPCRegistry().isNPC(event.getCaught())
&& plugin.getNPCRegistry().getNPC(event.getCaught()).isProtected()) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getRightClicked());
NPC npc = plugin.getNPCRegistry().getNPC(event.getRightClicked());
if (npc == null || Util.isOffHand(event))
return;
@ -611,7 +632,7 @@ public class EventListen implements Listener {
if (SUPPORT_STOP_USE_ITEM) {
try {
PlayerAnimation.STOP_USE_ITEM.play(player);
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin,
() -> PlayerAnimation.STOP_USE_ITEM.play(player));
} catch (UnsupportedOperationException e) {
SUPPORT_STOP_USE_ITEM = false;
@ -624,12 +645,12 @@ public class EventListen implements Listener {
public void onPlayerJoin(PlayerJoinEvent event) {
skinUpdateTracker.updatePlayer(event.getPlayer(), Setting.INITIAL_PLAYER_JOIN_SKIN_PACKET_DELAY.asTicks(),
true);
CitizensAPI.getLocationLookup().onJoin(event);
plugin.getLocationLookup().onJoin(event);
}
@EventHandler(ignoreCancelled = true)
public void onPlayerLeashEntity(PlayerLeashEntityEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null)
return;
@ -650,13 +671,13 @@ public class EventListen implements Listener {
public void onPlayerQuit(PlayerQuitEvent event) {
Editor.leave(event.getPlayer());
if (event.getPlayer().isInsideVehicle()) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getPlayer().getVehicle());
NPC npc = plugin.getNPCRegistry().getNPC(event.getPlayer().getVehicle());
if (npc != null) {
event.getPlayer().leaveVehicle();
}
}
skinUpdateTracker.removePlayer(event.getPlayer().getUniqueId());
CitizensAPI.getLocationLookup().onQuit(event);
plugin.getLocationLookup().onQuit(event);
}
@EventHandler(priority = EventPriority.MONITOR)
@ -666,7 +687,7 @@ public class EventListen implements Listener {
@EventHandler
public void onPlayerShearEntityEvent(PlayerShearEntityEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
NPC npc = plugin.getNPCRegistry().getNPC(event.getEntity());
if (npc == null)
return;
if (npc.isProtected()) {
@ -676,11 +697,11 @@ public class EventListen implements Listener {
@EventHandler(ignoreCancelled = true)
public void onPlayerTeleport(PlayerTeleportEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getPlayer());
NPC npc = plugin.getNPCRegistry().getNPC(event.getPlayer());
if (event.getCause() == TeleportCause.PLUGIN && npc != null && !npc.data().has("citizens-force-teleporting")
&& Setting.PLAYER_TELEPORT_DELAY.asTicks() > 0) {
event.setCancelled(true);
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
npc.data().set("citizens-force-teleporting", true);
event.getPlayer().teleport(event.getTo());
npc.data().remove("citizens-force-teleporting");
@ -694,9 +715,9 @@ public class EventListen implements Listener {
// hack: Spigot now unloads plugin classes on disable in reverse order so prefer unloading at the start of
// plugin disable cycle
PluginDescriptionFile file = event.getPlugin().getDescription();
for (String plugin : Iterables.concat(file.getDepend(), file.getSoftDepend())) {
if (plugin.equalsIgnoreCase("citizens") && CitizensAPI.hasImplementation()) {
((Citizens) CitizensAPI.getPlugin()).onDependentPluginDisable();
for (String depend : Iterables.concat(file.getDepend(), file.getSoftDepend())) {
if (depend.equalsIgnoreCase("citizens") && plugin.isEnabled()) {
plugin.onDependentPluginDisable();
break;
}
}
@ -705,7 +726,7 @@ public class EventListen implements Listener {
@EventHandler(ignoreCancelled = true)
public void onPotionSplashEvent(PotionSplashEvent event) {
for (LivingEntity entity : event.getAffectedEntities()) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity);
NPC npc = plugin.getNPCRegistry().getNPC(entity);
if (npc == null) {
continue;
}
@ -725,18 +746,18 @@ public class EventListen implements Listener {
@Override
public void run() {
if (n++ > 5 || !CitizensAPI.hasImplementation()) {
if (n++ > 5 || !plugin.isEnabled()) {
cancel();
return;
}
NMS.removeHookIfNecessary((FishHook) event.getEntity());
}
}.runTaskTimer(CitizensAPI.getPlugin(), 0, 1);
}.runTaskTimer(plugin, 0, 1);
}
@EventHandler
public void onVehicleDamage(VehicleDamageEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getVehicle());
NPC npc = plugin.getNPCRegistry().getNPC(event.getVehicle());
if (npc == null)
return;
@ -759,7 +780,7 @@ public class EventListen implements Listener {
@EventHandler
public void onVehicleDestroy(VehicleDestroyEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getVehicle());
NPC npc = plugin.getNPCRegistry().getNPC(event.getVehicle());
if (npc == null)
return;
@ -768,8 +789,8 @@ public class EventListen implements Listener {
@EventHandler(ignoreCancelled = true)
public void onVehicleEnter(VehicleEnterEvent event) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getVehicle());
NPC rider = CitizensAPI.getNPCRegistry().getNPC(event.getEntered());
NPC npc = plugin.getNPCRegistry().getNPC(event.getVehicle());
NPC rider = plugin.getNPCRegistry().getNPC(event.getEntered());
if (npc == null) {
if (rider != null && rider.isProtected() && (event.getVehicle().getType().name().contains("BOAT")
|| event.getVehicle() instanceof Minecart)) {
@ -817,7 +838,7 @@ public class EventListen implements Listener {
Messaging.debug("Despawned", npc, "due to world unload at", event.getWorld().getName());
}
}
CitizensAPI.getLocationLookup().onWorldUnload(event);
plugin.getLocationLookup().onWorldUnload(event);
}
private void registerKnockbackEvent(Class<?> kbc) {
@ -845,7 +866,7 @@ public class EventListen implements Listener {
} catch (Throwable ex) {
ex.printStackTrace();
}
}, EventPriority.NORMAL, CitizensAPI.getPlugin(), true));
}, EventPriority.NORMAL, plugin, true));
} catch (Throwable ex) {
Messaging.severe("Error registering knockback event forwarder");
ex.printStackTrace();
@ -878,7 +899,7 @@ public class EventListen implements Listener {
} catch (Throwable ex) {
ex.printStackTrace();
}
}, EventPriority.NORMAL, CitizensAPI.getPlugin(), true));
}, EventPriority.NORMAL, plugin, true));
} catch (Throwable ex) {
Messaging.severe("Error registering push event forwarder");
ex.printStackTrace();
@ -948,7 +969,7 @@ public class EventListen implements Listener {
}
if (loadChunk) {
Messaging.idebug(() -> Joiner.on(' ').join("Loading chunk in 10 ticks due to forced chunk load at", coord));
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
if (!event.getChunk().isLoaded()) {
event.getChunk().load();
}

View File

@ -744,14 +744,16 @@ public class NPCCommands {
npc.getOrAddTrait(Controllable.class).setEnabled(false);
}
Controllable trait = npc.getOrAddTrait(Controllable.class);
if (controls != null) {
trait.setControls(controls);
Messaging.send(sender, Messages.CONTROLLABLE_CONTROLS_SET, controls);
return;
}
if (enabled != null) {
trait.setEnabled(enabled);
} else {
enabled = trait.toggle();
}
if (controls != null) {
trait.setControls(controls);
}
trait.setOwnerRequired(args.hasFlag('o'));
String key = enabled ? Messages.CONTROLLABLE_SET : Messages.CONTROLLABLE_REMOVED;
Messaging.sendTr(sender, key, npc.getName());
@ -1581,8 +1583,8 @@ public class NPCCommands {
}
if (mat == null && !args.hasFlag('h'))
throw new CommandException(Messages.UNKNOWN_MATERIAL);
ItemStack fstack = stack.clone();
npc.setItemProvider(() -> fstack);
ItemStack fstack = stack;
npc.setItemProvider(() -> fstack.clone());
if (npc.isSpawned()) {
npc.despawn(DespawnReason.PENDING_RESPAWN);
@ -3157,12 +3159,12 @@ public class NPCCommands {
@Command(
aliases = { "npc" },
usage = "size [size]",
usage = "slimesize [size]",
desc = "",
modifiers = { "size" },
modifiers = { "slimesize" },
min = 1,
max = 2,
permission = "citizens.npc.size")
permission = "citizens.npc.slimesize")
@Requirements(selected = true, ownership = true, types = { EntityType.MAGMA_CUBE, EntityType.SLIME })
public void slimeSize(CommandContext args, CommandSender sender, NPC npc) {
SlimeSize trait = npc.getOrAddTrait(SlimeSize.class);

View File

@ -88,7 +88,7 @@ public class CitizensNPCRegistry implements NPCRegistry {
npc.data().set(NPC.Metadata.ITEM_AMOUNT, item.getAmount());
npc.data().set(NPC.Metadata.ITEM_ID, item.getType().name());
npc.data().set(NPC.Metadata.ITEM_DATA, item.getData().getData());
npc.setItemProvider(() -> item);
npc.setItemProvider(() -> item.clone());
} else
throw new UnsupportedOperationException("Not an item entity type");
return npc;

View File

@ -350,8 +350,7 @@ public class Skin {
NPC npc = entity.getNPC();
SkinTrait skinTrait = npc.getOrAddTrait(SkinTrait.class);
// cache skins for faster initial skin availability and
// for use when the latest skin is not required.
// cache skins for faster initial skin availability and for use when the latest skin is not required.
npc.data().setPersistent(CACHED_SKIN_UUID_NAME_METADATA, skinName);
npc.data().setPersistent(CACHED_SKIN_UUID_METADATA, skinId.toString());
if (skinProperty.value != null) {
@ -365,8 +364,7 @@ public class Skin {
private static void setNPCTexture(SkinnableEntity entity, SkinProperty skinProperty) {
GameProfile profile = entity.getProfile();
// don't set property if already set since this sometimes causes
// packet errors that disconnect the client.
// don't set property if already set since this sometimes causes packet errors that disconnect the client.
SkinProperty current = SkinProperty.fromMojangProfile(profile);
if (current != null && current.value.equals(skinProperty.value) && current.signature != null
&& current.signature.equals(skinProperty.signature))

View File

@ -14,7 +14,6 @@ import net.citizensnpcs.api.command.CommandContext;
import net.citizensnpcs.api.command.Flag;
import net.citizensnpcs.api.command.Requirements;
import net.citizensnpcs.api.command.exception.CommandException;
import net.citizensnpcs.api.command.exception.CommandUsageException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
@ -40,6 +39,10 @@ public class DisplayTrait extends Trait {
@Persist
private Vector scale;
@Persist
private Float shadowRadius;
@Persist
private Float shadowStrength;
@Persist
private Integer skyLight;
@Persist
private Float viewRange;
@ -85,6 +88,12 @@ public class DisplayTrait extends Trait {
if (viewRange != null) {
display.setViewRange(viewRange);
}
if (shadowRadius != null) {
display.setShadowRadius(shadowRadius);
}
if (shadowStrength != null) {
display.setShadowStrength(shadowStrength);
}
}
public void setBillboard(Billboard billboard) {
@ -112,6 +121,14 @@ public class DisplayTrait extends Trait {
this.scale = scale;
}
public void setShadowRadius(Float shadowRadius) {
this.shadowRadius = shadowRadius;
}
public void setShadowStrength(Float shadowStrength) {
this.shadowStrength = shadowStrength;
}
public void setViewRange(Float viewRange) {
this.viewRange = viewRange;
}
@ -133,11 +150,12 @@ public class DisplayTrait extends Trait {
ownership = true,
types = { EntityType.ITEM_DISPLAY, EntityType.TEXT_DISPLAY, EntityType.BLOCK_DISPLAY })
public static void display(CommandContext args, CommandSender sender, NPC npc,
@Flag("billboard") Billboard billboard, @Flag("leftrotation") Quaternionf leftrotation,
@Flag("rightrotation") Quaternionf rightrotation, @Flag("scale") Vector scale,
@Flag("viewrange") Float viewRange, @Flag("brightness") String brightness,
@Flag("interpolationdelay") Integer interpolationDelay,
@Flag("interpolationduration") Integer interpolationDuration, @Flag("height") Float height,
@Flag("billboard") Billboard billboard, @Flag("left_rotation") Quaternionf leftrotation,
@Flag("right_rotation") Quaternionf rightrotation, @Flag("scale") Vector scale,
@Flag("view_range") Float viewRange, @Flag("brightness") String brightness,
@Flag("interpolation_delay") Integer interpolationDelay,
@Flag("interpolation_duration") Integer interpolationDuration, @Flag("height") Float height,
@Flag("shadow_radius") Float shadowRadius, @Flag("shadow_strength") Float shadowStrength,
@Flag("width") Float width) throws CommandException {
DisplayTrait trait = npc.getOrAddTrait(DisplayTrait.class);
String output = "";
@ -154,6 +172,12 @@ public class DisplayTrait extends Trait {
if (interpolationDuration != null) {
trait.setInterpolationDuration(interpolationDuration);
}
if (shadowStrength != null) {
trait.setShadowStrength(shadowStrength);
}
if (shadowRadius != null) {
trait.setShadowRadius(shadowRadius);
}
if (width != null) {
trait.setWidth(width);
}
@ -169,7 +193,6 @@ public class DisplayTrait extends Trait {
trait.onSpawn();
if (!output.isEmpty()) {
Messaging.send(sender, output.trim());
} else
throw new CommandUsageException();
}
}
}

View File

@ -0,0 +1,111 @@
package net.citizensnpcs.trait.versioned;
import org.bukkit.Color;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.TextDisplay;
import org.bukkit.entity.TextDisplay.TextAlignment;
import net.citizensnpcs.api.command.Command;
import net.citizensnpcs.api.command.CommandContext;
import net.citizensnpcs.api.command.Flag;
import net.citizensnpcs.api.command.Requirements;
import net.citizensnpcs.api.command.exception.CommandException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.Messaging;
@TraitName("textdisplaytrait")
public class TextDisplayTrait extends Trait {
@Persist
private TextAlignment alignment;
@Persist
private Color bgcolor;
@Persist
private Integer lineWidth;
@Persist
private Boolean seeThrough;
@Persist
private Boolean shadowed;
public TextDisplayTrait() {
super("textdisplaytrait");
}
@Override
public void onSpawn() {
TextDisplay display = (TextDisplay) npc.getEntity();
if (shadowed != null) {
display.setShadowed(shadowed);
}
if (seeThrough != null) {
display.setSeeThrough(seeThrough);
}
if (lineWidth != null) {
display.setLineWidth(lineWidth);
}
if (alignment != null) {
display.setAlignment(alignment);
}
if (bgcolor != null) {
display.setBackgroundColor(bgcolor);
}
}
public void setAlignment(TextAlignment alignment) {
this.alignment = alignment;
}
public void setBackgroundColor(Color bgcolor) {
this.bgcolor = bgcolor;
}
public void setLineWidth(Integer lineWidth) {
this.lineWidth = lineWidth;
}
public void setSeeThrough(Boolean seeThrough) {
this.seeThrough = seeThrough;
}
public void setShadowed(Boolean shadowed) {
this.shadowed = shadowed;
}
@Command(
aliases = { "npc" },
usage = "textdisplay --shadowed [true|false] --seethrough [true|false] --line_width [width]",
desc = "",
modifiers = { "textdisplay" },
min = 1,
max = 1,
permission = "citizens.npc.textdisplay")
@Requirements(selected = true, ownership = true, types = { EntityType.TEXT_DISPLAY })
public static void display(CommandContext args, CommandSender sender, NPC npc, @Flag("shadowed") Boolean shadowed,
@Flag("seethrough") Boolean seethrough, @Flag("line_width") Integer lineWidth,
@Flag("bgcolor") Color bgcolor, @Flag("alignment") TextAlignment alignment) throws CommandException {
TextDisplayTrait trait = npc.getOrAddTrait(TextDisplayTrait.class);
String output = "";
if (shadowed != null) {
trait.setShadowed(shadowed);
}
if (seethrough != null) {
trait.setSeeThrough(seethrough);
}
if (lineWidth != null) {
trait.setLineWidth(lineWidth);
}
if (alignment != null) {
trait.setAlignment(alignment);
}
if (bgcolor != null) {
trait.setBackgroundColor(bgcolor);
}
trait.onSpawn();
if (!output.isEmpty()) {
Messaging.send(sender, output.trim());
}
}
}

View File

@ -88,6 +88,7 @@ public class Messages {
public static final String COMMANDS_SEQUENTIAL_SET = "citizens.commands.npc.commands.sequential-set";
public static final String COMMANDS_SEQUENTIAL_UNSET = "citizens.commands.npc.commands.sequential-unset";
public static final String CONTRIBUTE_TO_TRANSLATION_PROMPT = "citizens.contribute-to-translations-prompt";
public static final Object CONTROLLABLE_CONTROLS_SET = "citizens.commands.npc.controllable.controls-set";
public static final String CONTROLLABLE_REMOVED = "citizens.commands.npc.controllable.removed";
public static final String CONTROLLABLE_SET = "citizens.commands.npc.controllable.set";
public static final String COPIER_EDITOR_BEGIN = "citizens.editors.copier.begin";

View File

@ -147,6 +147,7 @@
"citizens.commands.npc.controllable.not-controllable" : "[[{0}]] is not controllable.",
"citizens.commands.npc.controllable.removed" : "[[{0}]] can no longer be controlled.",
"citizens.commands.npc.controllable.set" : "[[{0}]] can now be controlled.",
"citizens.commands.npc.controllable.controls-set" : "Controls set to [[{0}]].",
"citizens.commands.npc.copier.description" : "Toggle the NPC copier",
"citizens.commands.npc.copier.help" : "",
"citizens.commands.npc.copy.copied" : "[[{0}]] has been copied.",

View File

@ -18,7 +18,6 @@ import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_10_R1.AxisAlignedBB;
import net.minecraft.server.v1_10_R1.EntityHuman;
import net.minecraft.server.v1_10_R1.EntityItem;
import net.minecraft.server.v1_10_R1.EntityPlayer;
import net.minecraft.server.v1_10_R1.ItemStack;
@ -80,13 +79,6 @@ public class ItemController extends AbstractEntityController {
}
}
@Override
public void d(EntityHuman entityhuman) {
if (npc == null) {
super.d(entityhuman);
}
}
@Override
public boolean d(NBTTagCompound save) {
return npc == null ? super.d(save) : false;

View File

@ -18,7 +18,6 @@ import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_11_R1.AxisAlignedBB;
import net.minecraft.server.v1_11_R1.EntityHuman;
import net.minecraft.server.v1_11_R1.EntityItem;
import net.minecraft.server.v1_11_R1.EntityPlayer;
import net.minecraft.server.v1_11_R1.ItemStack;
@ -89,13 +88,6 @@ public class ItemController extends AbstractEntityController {
}
}
@Override
public void d(EntityHuman entityhuman) {
if (npc == null) {
super.d(entityhuman);
}
}
@Override
public boolean d(NBTTagCompound save) {
return npc == null ? super.d(save) : false;

View File

@ -18,7 +18,6 @@ import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_12_R1.AxisAlignedBB;
import net.minecraft.server.v1_12_R1.EntityHuman;
import net.minecraft.server.v1_12_R1.EntityItem;
import net.minecraft.server.v1_12_R1.EntityPlayer;
import net.minecraft.server.v1_12_R1.EnumPistonReaction;
@ -90,13 +89,6 @@ public class ItemController extends AbstractEntityController {
}
}
@Override
public void d(EntityHuman entityhuman) {
if (npc == null) {
super.d(entityhuman);
}
}
@Override
public boolean d(NBTTagCompound save) {
return npc == null ? super.d(save) : false;

View File

@ -18,7 +18,6 @@ import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_13_R2.AxisAlignedBB;
import net.minecraft.server.v1_13_R2.EntityHuman;
import net.minecraft.server.v1_13_R2.EntityItem;
import net.minecraft.server.v1_13_R2.EntityPlayer;
import net.minecraft.server.v1_13_R2.EnumPistonReaction;
@ -94,13 +93,6 @@ public class ItemController extends AbstractEntityController {
}
}
@Override
public void d(EntityHuman entityhuman) {
if (npc == null) {
super.d(entityhuman);
}
}
@Override
public boolean d(NBTTagCompound save) {
return npc == null ? super.d(save) : false;

View File

@ -19,7 +19,6 @@ import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_14_R1.AxisAlignedBB;
import net.minecraft.server.v1_14_R1.EntityHuman;
import net.minecraft.server.v1_14_R1.EntityItem;
import net.minecraft.server.v1_14_R1.EntityPlayer;
import net.minecraft.server.v1_14_R1.EntityTypes;
@ -124,13 +123,6 @@ public class ItemController extends AbstractEntityController {
return Util.callPistonPushEvent(npc) ? EnumPistonReaction.IGNORE : super.getPushReaction();
}
@Override
public void pickup(EntityHuman entityhuman) {
if (npc == null) {
super.pickup(entityhuman);
}
}
@Override
public void tick() {
if (npc != null) {

View File

@ -19,7 +19,6 @@ import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_15_R1.AxisAlignedBB;
import net.minecraft.server.v1_15_R1.EntityHuman;
import net.minecraft.server.v1_15_R1.EntityItem;
import net.minecraft.server.v1_15_R1.EntityPlayer;
import net.minecraft.server.v1_15_R1.EntityTypes;
@ -124,13 +123,6 @@ public class ItemController extends AbstractEntityController {
}
}
@Override
public void pickup(EntityHuman entityhuman) {
if (npc == null) {
super.pickup(entityhuman);
}
}
@Override
public void tick() {
if (npc != null) {

View File

@ -19,7 +19,6 @@ import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_16_R3.AxisAlignedBB;
import net.minecraft.server.v1_16_R3.EntityHuman;
import net.minecraft.server.v1_16_R3.EntityItem;
import net.minecraft.server.v1_16_R3.EntityPlayer;
import net.minecraft.server.v1_16_R3.EntityTypes;
@ -124,13 +123,6 @@ public class ItemController extends AbstractEntityController {
}
}
@Override
public void pickup(EntityHuman entityhuman) {
if (npc == null) {
super.pickup(entityhuman);
}
}
@Override
public void tick() {
if (npc != null) {

View File

@ -24,7 +24,6 @@ import net.minecraft.tags.Tag;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.material.Fluid;
@ -96,13 +95,6 @@ public class ItemController extends AbstractEntityController {
return NMSBoundingBox.makeBB(npc, super.makeBoundingBox());
}
@Override
public void playerTouch(Player entityhuman) {
if (npc == null) {
super.playerTouch(entityhuman);
}
}
@Override
public void push(double x, double y, double z) {
Vector vector = Util.callPushEvent(npc, x, y, z);

View File

@ -26,7 +26,6 @@ import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.material.Fluid;
@ -98,13 +97,6 @@ public class ItemController extends AbstractEntityController {
return NMSBoundingBox.makeBB(npc, super.makeBoundingBox());
}
@Override
public void playerTouch(Player entityhuman) {
if (npc == null) {
super.playerTouch(entityhuman);
}
}
@Override
public void push(double x, double y, double z) {
Vector vector = Util.callPushEvent(npc, x, y, z);

View File

@ -26,7 +26,6 @@ import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.material.Fluid;
@ -98,13 +97,6 @@ public class ItemController extends AbstractEntityController {
return NMSBoundingBox.makeBB(npc, super.makeBoundingBox());
}
@Override
public void playerTouch(Player entityhuman) {
if (npc == null) {
super.playerTouch(entityhuman);
}
}
@Override
public void push(double x, double y, double z) {
Vector vector = Util.callPushEvent(npc, x, y, z);

View File

@ -243,6 +243,7 @@ import net.citizensnpcs.trait.versioned.ShulkerTrait;
import net.citizensnpcs.trait.versioned.SnifferTrait.SnifferState;
import net.citizensnpcs.trait.versioned.SnowmanTrait;
import net.citizensnpcs.trait.versioned.SpellcasterTrait;
import net.citizensnpcs.trait.versioned.TextDisplayTrait;
import net.citizensnpcs.trait.versioned.TropicalFishTrait;
import net.citizensnpcs.trait.versioned.VillagerTrait;
import net.citizensnpcs.trait.versioned.WardenTrait;
@ -952,6 +953,7 @@ public class NMSImpl implements NMSBridge {
registerTraitWithCommand(manager, SpellcasterTrait.class);
registerTraitWithCommand(manager, ShulkerTrait.class);
registerTraitWithCommand(manager, SnowmanTrait.class);
registerTraitWithCommand(manager, TextDisplayTrait.class);
registerTraitWithCommand(manager, TropicalFishTrait.class);
registerTraitWithCommand(manager, VillagerTrait.class);
registerTraitWithCommand(manager, WardenTrait.class);

View File

@ -24,7 +24,6 @@ import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.material.Fluid;
@ -96,13 +95,6 @@ public class ItemController extends AbstractEntityController {
return NMSBoundingBox.makeBB(npc, super.makeBoundingBox());
}
@Override
public void playerTouch(Player entityhuman) {
if (npc == null) {
super.playerTouch(entityhuman);
}
}
@Override
public void push(Entity entity) {
// this method is called by both the entities involved - cancelling

View File

@ -247,6 +247,7 @@ import net.citizensnpcs.trait.versioned.ShulkerTrait;
import net.citizensnpcs.trait.versioned.SnifferTrait.SnifferState;
import net.citizensnpcs.trait.versioned.SnowmanTrait;
import net.citizensnpcs.trait.versioned.SpellcasterTrait;
import net.citizensnpcs.trait.versioned.TextDisplayTrait;
import net.citizensnpcs.trait.versioned.TropicalFishTrait;
import net.citizensnpcs.trait.versioned.VillagerTrait;
import net.citizensnpcs.trait.versioned.WardenTrait;
@ -977,6 +978,7 @@ public class NMSImpl implements NMSBridge {
registerTraitWithCommand(manager, ShulkerTrait.class);
registerTraitWithCommand(manager, SnowmanTrait.class);
registerTraitWithCommand(manager, TropicalFishTrait.class);
registerTraitWithCommand(manager, TextDisplayTrait.class);
registerTraitWithCommand(manager, VillagerTrait.class);
registerTraitWithCommand(manager, WardenTrait.class);
}

View File

@ -23,7 +23,6 @@ import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.material.Fluid;
@ -103,13 +102,6 @@ public class ItemController extends AbstractEntityController {
return NMSBoundingBox.makeBB(npc, super.makeBoundingBox());
}
@Override
public void playerTouch(Player entityhuman) {
if (npc == null) {
super.playerTouch(entityhuman);
}
}
@Override
public void push(Entity entity) {
// this method is called by both the entities involved - cancelling

View File

@ -247,6 +247,7 @@ import net.citizensnpcs.trait.versioned.ShulkerTrait;
import net.citizensnpcs.trait.versioned.SnifferTrait.SnifferState;
import net.citizensnpcs.trait.versioned.SnowmanTrait;
import net.citizensnpcs.trait.versioned.SpellcasterTrait;
import net.citizensnpcs.trait.versioned.TextDisplayTrait;
import net.citizensnpcs.trait.versioned.TropicalFishTrait;
import net.citizensnpcs.trait.versioned.VillagerTrait;
import net.citizensnpcs.trait.versioned.WardenTrait;
@ -956,6 +957,7 @@ public class NMSImpl implements NMSBridge {
registerTraitWithCommand(manager, SpellcasterTrait.class);
registerTraitWithCommand(manager, ShulkerTrait.class);
registerTraitWithCommand(manager, SnowmanTrait.class);
registerTraitWithCommand(manager, TextDisplayTrait.class);
registerTraitWithCommand(manager, TropicalFishTrait.class);
registerTraitWithCommand(manager, VillagerTrait.class);
registerTraitWithCommand(manager, WardenTrait.class);

View File

@ -18,7 +18,6 @@ import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_8_R3.AxisAlignedBB;
import net.minecraft.server.v1_8_R3.EntityHuman;
import net.minecraft.server.v1_8_R3.EntityItem;
import net.minecraft.server.v1_8_R3.EntityPlayer;
import net.minecraft.server.v1_8_R3.ItemStack;
@ -80,13 +79,6 @@ public class ItemController extends AbstractEntityController {
}
}
@Override
public void d(EntityHuman entityhuman) {
if (npc == null) {
super.d(entityhuman);
}
}
@Override
public boolean d(NBTTagCompound save) {
return npc == null ? super.d(save) : false;