mirror of
https://github.com/CitizensDev/Citizens2.git
synced 2024-11-25 12:15:53 +01:00
Add /npc hologram viewrange, add /npc playerfilter --applywithin, work towards auto-hologram-sneak
This commit is contained in:
parent
de885501cd
commit
07fb13c284
@ -102,7 +102,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
||||
@Override
|
||||
public OfflinePlayer getPlayer(BlockCommandSender sender) {
|
||||
Entity entity = NMS.getSource(sender);
|
||||
return entity != null && entity instanceof OfflinePlayer ? (OfflinePlayer) entity : null;
|
||||
return entity instanceof OfflinePlayer ? (OfflinePlayer) entity : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -182,11 +182,9 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
||||
if (type.equalsIgnoreCase("nbt")) {
|
||||
saves = new NBTStorage(new File(folder, Setting.STORAGE_FILE.asString()), "Citizens NPC Storage");
|
||||
}
|
||||
|
||||
if (saves == null) {
|
||||
saves = new YamlStorage(new File(folder, Setting.STORAGE_FILE.asString()), "Citizens NPC Storage");
|
||||
}
|
||||
|
||||
if (!saves.load())
|
||||
return null;
|
||||
|
||||
@ -195,8 +193,9 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
||||
|
||||
private void despawnNPCs(boolean save) {
|
||||
for (NPCRegistry registry : Iterables.concat(Arrays.asList(npcRegistry), citizensBackedRegistries)) {
|
||||
if (registry == null)
|
||||
if (registry == null) {
|
||||
continue;
|
||||
}
|
||||
if (save) {
|
||||
if (registry == npcRegistry) {
|
||||
storeNPCs(false);
|
||||
@ -237,33 +236,27 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
||||
|
||||
@Override
|
||||
public Iterable<NPCRegistry> getNPCRegistries() {
|
||||
return new Iterable<NPCRegistry>() {
|
||||
return () -> new Iterator<NPCRegistry>() {
|
||||
Iterator<NPCRegistry> stored;
|
||||
|
||||
@Override
|
||||
public Iterator<NPCRegistry> iterator() {
|
||||
return new Iterator<NPCRegistry>() {
|
||||
Iterator<NPCRegistry> stored;
|
||||
public boolean hasNext() {
|
||||
return stored == null ? true : stored.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return stored == null ? true : stored.hasNext();
|
||||
}
|
||||
@Override
|
||||
public NPCRegistry next() {
|
||||
if (stored == null) {
|
||||
stored = Iterables.concat(storedRegistries.values(), anonymousRegistries, citizensBackedRegistries)
|
||||
.iterator();
|
||||
return npcRegistry;
|
||||
}
|
||||
return stored.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NPCRegistry next() {
|
||||
if (stored == null) {
|
||||
stored = Iterables
|
||||
.concat(storedRegistries.values(), anonymousRegistries, citizensBackedRegistries)
|
||||
.iterator();
|
||||
return npcRegistry;
|
||||
}
|
||||
return stored.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -392,7 +385,6 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
registerScriptHelpers();
|
||||
|
||||
saves = createStorage(getDataFolder());
|
||||
@ -402,15 +394,12 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
locationLookup = new LocationLookup();
|
||||
locationLookup.runTaskTimer(CitizensAPI.getPlugin(), 0, 5);
|
||||
|
||||
npcRegistry = new CitizensNPCRegistry(saves, "citizens");
|
||||
traitFactory = new CitizensTraitFactory(this);
|
||||
traitFactory.registerTrait(TraitInfo.create(ShopTrait.class).withSupplier(() -> {
|
||||
return new ShopTrait(shops);
|
||||
}));
|
||||
traitFactory.registerTrait(TraitInfo.create(ShopTrait.class).withSupplier(() -> new ShopTrait(shops)));
|
||||
selector = new NPCSelector(this);
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(new EventListen(), this);
|
||||
@ -426,7 +415,6 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
||||
if (papi != null && papi.isEnabled()) {
|
||||
new CitizensPlaceholders(selector).register();
|
||||
}
|
||||
|
||||
setupEconomy();
|
||||
|
||||
registerCommands();
|
||||
@ -506,12 +494,11 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
||||
|
||||
@Override
|
||||
public void setDefaultNPCDataStore(NPCDataStore store) {
|
||||
if (store == null) {
|
||||
if (store == null)
|
||||
throw new IllegalArgumentException("must be non-null");
|
||||
}
|
||||
despawnNPCs(true);
|
||||
this.saves = store;
|
||||
this.npcRegistry = new CitizensNPCRegistry(saves, "citizens-global-" + UUID.randomUUID().toString());
|
||||
saves = store;
|
||||
npcRegistry = new CitizensNPCRegistry(saves, "citizens-global-" + UUID.randomUUID().toString());
|
||||
saves.loadInto(npcRegistry);
|
||||
}
|
||||
|
||||
@ -614,7 +601,6 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saves.loadInto(npcRegistry);
|
||||
shops.load();
|
||||
|
||||
|
@ -55,7 +55,6 @@ public class CitizensPlaceholders extends PlaceholderExpansion {
|
||||
b.getEntity().getLocation().distanceSquared(location)));
|
||||
return closestNPC.isPresent() ? Integer.toString(closestNPC.get().getId()) : "";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -120,11 +120,11 @@ import net.citizensnpcs.util.Util;
|
||||
|
||||
public class EventListen implements Listener {
|
||||
private Listener chunkEventListener;
|
||||
private final SkinUpdateTracker skinUpdateTracker;
|
||||
private SkinUpdateTracker skinUpdateTracker;
|
||||
private final ListMultimap<ChunkCoord, NPC> toRespawn = ArrayListMultimap.create(64, 4);
|
||||
|
||||
EventListen() {
|
||||
this.skinUpdateTracker = new SkinUpdateTracker();
|
||||
skinUpdateTracker = new SkinUpdateTracker();
|
||||
try {
|
||||
Class.forName("org.bukkit.event.world.EntitiesLoadEvent");
|
||||
Bukkit.getPluginManager().registerEvents(new Listener() {
|
||||
@ -140,7 +140,6 @@ public class EventListen implements Listener {
|
||||
}, CitizensAPI.getPlugin());
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
Class.forName("org.bukkit.event.entity.EntityTransformEvent");
|
||||
Bukkit.getPluginManager().registerEvents(new Listener() {
|
||||
@ -156,23 +155,19 @@ public class EventListen implements Listener {
|
||||
}, CitizensAPI.getPlugin());
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
|
||||
Class<?> kbc = null;
|
||||
try {
|
||||
kbc = Class.forName("com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent");
|
||||
} catch (ClassNotFoundException e) {
|
||||
}
|
||||
|
||||
if (kbc != null) {
|
||||
registerKnockbackEvent(kbc);
|
||||
}
|
||||
|
||||
Class<?> pbeac = null;
|
||||
try {
|
||||
pbeac = Class.forName("io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent");
|
||||
} catch (ClassNotFoundException e) {
|
||||
}
|
||||
|
||||
if (pbeac != null) {
|
||||
registerPushEvent(pbeac);
|
||||
}
|
||||
@ -184,8 +179,9 @@ public class EventListen implements Listener {
|
||||
int limit = Setting.DEFAULT_NPC_LIMIT.asInt();
|
||||
int maxChecks = Setting.MAX_NPC_LIMIT_CHECKS.asInt();
|
||||
for (int i = maxChecks; i >= 0; i--) {
|
||||
if (!event.getCreator().hasPermission("citizens.npc.limit." + i))
|
||||
if (!event.getCreator().hasPermission("citizens.npc.limit." + i)) {
|
||||
continue;
|
||||
}
|
||||
limit = i;
|
||||
break;
|
||||
}
|
||||
@ -215,7 +211,6 @@ public class EventListen implements Listener {
|
||||
if (Messaging.isDebugging() && Setting.DEBUG_CHUNK_LOADS.asBoolean() && toRespawn.containsKey(coord)) {
|
||||
new Exception("CITIZENS CHUNK LOAD DEBUG " + coord).printStackTrace();
|
||||
}
|
||||
|
||||
if (event instanceof Cancellable) {
|
||||
runnable.run();
|
||||
} else {
|
||||
@ -231,7 +226,7 @@ public class EventListen implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onChunkUnload(final ChunkUnloadEvent event) {
|
||||
public void onChunkUnload(ChunkUnloadEvent event) {
|
||||
if (chunkEventListener != null)
|
||||
return;
|
||||
|
||||
@ -290,7 +285,6 @@ public class EventListen implements Listener {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(npc.isProtected());
|
||||
|
||||
if (event instanceof EntityDamageByEntityEvent) {
|
||||
@ -306,7 +300,6 @@ public class EventListen implements Listener {
|
||||
if (npc == null)
|
||||
return;
|
||||
}
|
||||
|
||||
NPCLeftClickEvent leftClickEvent = new NPCLeftClickEvent(npc, damager);
|
||||
Bukkit.getPluginManager().callEvent(leftClickEvent);
|
||||
if (npc.hasTrait(CommandTrait.class)) {
|
||||
@ -321,15 +314,14 @@ public class EventListen implements Listener {
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onEntityDeath(EntityDeathEvent event) {
|
||||
final NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
||||
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
||||
if (npc == null)
|
||||
return;
|
||||
|
||||
if (!npc.data().get(NPC.Metadata.DROPS_ITEMS, false)) {
|
||||
event.getDrops().clear();
|
||||
}
|
||||
|
||||
final Location location = npc.getStoredLocation();
|
||||
Location location = npc.getStoredLocation();
|
||||
Bukkit.getPluginManager().callEvent(new NPCDeathEvent(npc, event));
|
||||
npc.despawn(DespawnReason.DEATH);
|
||||
|
||||
@ -438,7 +430,6 @@ public class EventListen implements Listener {
|
||||
if (npc.isSpawned() && npc.getEntity().getType() == EntityType.PLAYER) {
|
||||
onNPCPlayerLinkToPlayer(event);
|
||||
}
|
||||
|
||||
ClickRedirectTrait crt = npc.getTraitNullable(ClickRedirectTrait.class);
|
||||
if (crt != null) {
|
||||
HologramTrait ht = crt.getRedirectNPC().getTraitNullable(HologramTrait.class);
|
||||
@ -468,7 +459,6 @@ public class EventListen implements Listener {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
||||
if (!tracker.isValid() || !event.getPlayer().isValid())
|
||||
return;
|
||||
@ -488,12 +478,15 @@ public class EventListen implements Listener {
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onNPCSeenByPlayer(NPCSeenByPlayerEvent event) {
|
||||
NPC npc = event.getNPC();
|
||||
PlayerFilter pf = npc.getTraitNullable(PlayerFilter.class);
|
||||
if (pf != null) {
|
||||
event.setCancelled(pf.onSeenByPlayer(event.getPlayer()));
|
||||
}
|
||||
ClickRedirectTrait crt = npc.getTraitNullable(ClickRedirectTrait.class);
|
||||
if (crt != null) {
|
||||
npc = crt.getRedirectNPC();
|
||||
}
|
||||
|
||||
PlayerFilter pf = npc.getTraitNullable(PlayerFilter.class);
|
||||
pf = npc.getTraitNullable(PlayerFilter.class);
|
||||
if (pf != null) {
|
||||
event.setCancelled(pf.onSeenByPlayer(event.getPlayer()));
|
||||
}
|
||||
@ -561,27 +554,22 @@ public class EventListen implements Listener {
|
||||
if (event.getPlayer().getItemInHand().getType() == Material.NAME_TAG) {
|
||||
rightClickEvent.setCancelled(npc.isProtected());
|
||||
}
|
||||
|
||||
Bukkit.getPluginManager().callEvent(rightClickEvent);
|
||||
if (rightClickEvent.isCancelled()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (npc.hasTrait(CommandTrait.class)) {
|
||||
npc.getTraitNullable(CommandTrait.class).dispatch(player, CommandTrait.Hand.RIGHT);
|
||||
rightClickEvent.setDelayedCancellation(true);
|
||||
}
|
||||
|
||||
if (npc.hasTrait(ShopTrait.class)) {
|
||||
npc.getTraitNullable(ShopTrait.class).onRightClick(player);
|
||||
rightClickEvent.setDelayedCancellation(true);
|
||||
}
|
||||
|
||||
if (rightClickEvent.isDelayedCancellation()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
if (SUPPORT_STOP_USE_ITEM) {
|
||||
try {
|
||||
@ -617,7 +605,7 @@ public class EventListen implements Listener {
|
||||
// recalculate player NPCs the first time a player moves and every time
|
||||
// a player moves a certain distance from their last position.
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerMove(final PlayerMoveEvent event) {
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
skinUpdateTracker.onPlayerMove(event.getPlayer());
|
||||
}
|
||||
|
||||
@ -630,7 +618,6 @@ public class EventListen implements Listener {
|
||||
event.getPlayer().leaveVehicle();
|
||||
}
|
||||
}
|
||||
|
||||
skinUpdateTracker.removePlayer(event.getPlayer().getUniqueId());
|
||||
CitizensAPI.getLocationLookup().onQuit(event);
|
||||
}
|
||||
@ -641,7 +628,7 @@ public class EventListen implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onPlayerTeleport(final PlayerTeleportEvent event) {
|
||||
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
||||
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getPlayer());
|
||||
if (event.getCause() == TeleportCause.PLUGIN && npc != null && !npc.data().has("citizens-force-teleporting")
|
||||
&& Setting.PLAYER_TELEPORT_DELAY.asTicks() > 0) {
|
||||
@ -652,7 +639,6 @@ public class EventListen implements Listener {
|
||||
npc.data().remove("citizens-force-teleporting");
|
||||
}, Setting.PLAYER_TELEPORT_DELAY.asTicks());
|
||||
}
|
||||
|
||||
skinUpdateTracker.updatePlayer(event.getPlayer(), 15, true);
|
||||
}
|
||||
|
||||
@ -673,9 +659,9 @@ public class EventListen implements Listener {
|
||||
public void onPotionSplashEvent(PotionSplashEvent event) {
|
||||
for (LivingEntity entity : event.getAffectedEntities()) {
|
||||
NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity);
|
||||
if (npc == null)
|
||||
if (npc == null) {
|
||||
continue;
|
||||
|
||||
}
|
||||
if (npc.isProtected()) {
|
||||
event.setIntensity(entity, 0);
|
||||
}
|
||||
@ -683,7 +669,7 @@ public class EventListen implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onProjectileHit(final ProjectileHitEvent event) {
|
||||
public void onProjectileHit(ProjectileHitEvent event) {
|
||||
if (!(event.getEntity() instanceof FishHook))
|
||||
return;
|
||||
NMS.removeHookIfNecessary((FishHook) event.getEntity());
|
||||
@ -696,7 +682,6 @@ public class EventListen implements Listener {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
NMS.removeHookIfNecessary((FishHook) event.getEntity());
|
||||
}
|
||||
}.runTaskTimer(CitizensAPI.getPlugin(), 0, 1);
|
||||
@ -735,7 +720,7 @@ public class EventListen implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onVehicleEnter(final VehicleEnterEvent event) {
|
||||
public void onVehicleEnter(VehicleEnterEvent event) {
|
||||
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getVehicle());
|
||||
NPC rider = CitizensAPI.getNPCRegistry().getNPC(event.getEntered());
|
||||
if (npc == null) {
|
||||
@ -743,10 +728,8 @@ public class EventListen implements Listener {
|
||||
|| event.getVehicle() instanceof Minecart)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (rider != null || !(npc instanceof Vehicle))
|
||||
return;
|
||||
|
||||
@ -758,8 +741,10 @@ public class EventListen implements Listener {
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onWorldLoad(WorldLoadEvent event) {
|
||||
for (ChunkCoord chunk : toRespawn.keySet()) {
|
||||
if (!chunk.worldUUID.equals(event.getWorld().getUID()) || !event.getWorld().isChunkLoaded(chunk.x, chunk.z))
|
||||
if (!chunk.worldUUID.equals(event.getWorld().getUID())
|
||||
|| !event.getWorld().isChunkLoaded(chunk.x, chunk.z)) {
|
||||
continue;
|
||||
}
|
||||
respawnAllFromCoord(chunk, event);
|
||||
}
|
||||
}
|
||||
@ -767,9 +752,9 @@ public class EventListen implements Listener {
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onWorldUnload(WorldUnloadEvent event) {
|
||||
for (NPC npc : getAllNPCs()) {
|
||||
if (npc == null || !npc.isSpawned() || !npc.getEntity().getWorld().equals(event.getWorld()))
|
||||
if (npc == null || !npc.isSpawned() || !npc.getEntity().getWorld().equals(event.getWorld())) {
|
||||
continue;
|
||||
|
||||
}
|
||||
boolean despawned = npc.despawn(DespawnReason.WORLD_UNLOAD);
|
||||
if (event.isCancelled() || !despawned) {
|
||||
for (ChunkCoord coord : toRespawn.keySet()) {
|
||||
@ -780,7 +765,6 @@ public class EventListen implements Listener {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (npc.isSpawned()) {
|
||||
toRespawn.put(new ChunkCoord(npc.getEntity().getLocation()), npc);
|
||||
Messaging.debug("Despawned", npc, "due to world unload at", event.getWorld().getName());
|
||||
@ -829,9 +813,7 @@ public class EventListen implements Listener {
|
||||
Method getAcceleration = clazz.getMethod("getAcceleration");
|
||||
handlers.register(new RegisteredListener(new Listener() {
|
||||
}, (listener, event) -> {
|
||||
if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0)
|
||||
return;
|
||||
if (event.getClass() != clazz)
|
||||
if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0 || event.getClass() != clazz)
|
||||
return;
|
||||
try {
|
||||
Entity entity = (Entity) getEntity.invoke(event);
|
||||
@ -858,26 +840,22 @@ public class EventListen implements Listener {
|
||||
if (ids.size() > 0) {
|
||||
Messaging.debug("Respawning all NPCs at", coord, "due to", event);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ids.size(); i++) {
|
||||
NPC npc = ids.get(i);
|
||||
if (npc.getOwningRegistry().getById(npc.getId()) != npc) {
|
||||
Messaging.idebug(() -> "Prevented deregistered NPC from respawning " + npc);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (npc.isSpawned()) {
|
||||
Messaging.idebug(() -> "Can't respawn NPC " + npc + ": already spawned");
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean success = spawn(npc);
|
||||
if (!success) {
|
||||
ids.remove(i--);
|
||||
Messaging.idebug(() -> Joiner.on(' ').join("Couldn't respawn", npc, "during", event, "at", coord));
|
||||
continue;
|
||||
}
|
||||
|
||||
Messaging.idebug(() -> Joiner.on(' ').join("Spawned", npc, "during", event, "at", coord));
|
||||
}
|
||||
for (NPC npc : ids) {
|
||||
@ -895,16 +873,16 @@ public class EventListen implements Listener {
|
||||
}
|
||||
|
||||
void unloadNPCs(ChunkEvent event, List<Entity> entities) {
|
||||
final List<NPC> toDespawn = Lists.newArrayList();
|
||||
List<NPC> toDespawn = Lists.newArrayList();
|
||||
for (Entity entity : entities) {
|
||||
NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity);
|
||||
// XXX : npc#isSpawned() checks entity valid status which is now inconsistent on chunk unload between
|
||||
// different server software (e.g. Paper and Spigot), so check for npc.getEntity() == null instead.
|
||||
if (npc == null || npc.getEntity() == null)
|
||||
if (npc == null || npc.getEntity() == null) {
|
||||
continue;
|
||||
}
|
||||
toDespawn.add(npc);
|
||||
}
|
||||
|
||||
if (toDespawn.isEmpty())
|
||||
return;
|
||||
|
||||
@ -918,7 +896,6 @@ public class EventListen implements Listener {
|
||||
toRespawn.put(coord, npc);
|
||||
continue;
|
||||
}
|
||||
|
||||
((Cancellable) event).setCancelled(true);
|
||||
Messaging.debug("Cancelled chunk unload at", coord);
|
||||
respawnAllFromCoord(coord, event);
|
||||
@ -930,7 +907,6 @@ public class EventListen implements Listener {
|
||||
if (Messaging.isDebugging() && Setting.DEBUG_CHUNK_LOADS.asBoolean()) {
|
||||
new Exception("CITIZENS CHUNK UNLOAD DEBUG " + coord).printStackTrace();
|
||||
}
|
||||
|
||||
if (loadChunk) {
|
||||
Messaging.idebug(() -> Joiner.on(' ').join("Loading chunk in 10 ticks due to forced chunk load at", coord));
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
||||
|
@ -91,7 +91,7 @@ public class Metrics {
|
||||
metricsBase = new MetricsBase("bukkit", serverUUID, serviceId, enabled, this::appendPlatformData,
|
||||
this::appendServiceData, submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask),
|
||||
plugin::isEnabled, (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error),
|
||||
(message) -> this.plugin.getLogger().log(Level.INFO, message), logErrors, logSentData,
|
||||
message -> this.plugin.getLogger().log(Level.INFO, message), logErrors, logSentData,
|
||||
logResponseStatusText);
|
||||
}
|
||||
|
||||
@ -156,10 +156,9 @@ public class Metrics {
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
if (map == null || map.isEmpty())
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||
if (entry.getValue().length == 0) {
|
||||
@ -169,10 +168,9 @@ public class Metrics {
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
if (allSkipped)
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
@ -198,10 +196,9 @@ public class Metrics {
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
if (map == null || map.isEmpty())
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
@ -211,10 +208,9 @@ public class Metrics {
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
if (allSkipped)
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
@ -224,9 +220,8 @@ public class Metrics {
|
||||
private final String chartId;
|
||||
|
||||
protected CustomChart(String chartId) {
|
||||
if (chartId == null) {
|
||||
if (chartId == null)
|
||||
throw new IllegalArgumentException("chartId must not be null");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
@ -238,10 +233,9 @@ public class Metrics {
|
||||
builder.appendField("chartId", chartId);
|
||||
try {
|
||||
JsonObjectBuilder.JsonObject data = getChartData();
|
||||
if (data == null) {
|
||||
if (data == null)
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
builder.appendField("data", data);
|
||||
} catch (Throwable t) {
|
||||
if (logErrors) {
|
||||
@ -274,10 +268,9 @@ public class Metrics {
|
||||
public JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
if (map == null || map.isEmpty())
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
JsonObjectBuilder valueBuilder = new JsonObjectBuilder();
|
||||
@ -291,10 +284,9 @@ public class Metrics {
|
||||
valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build());
|
||||
}
|
||||
}
|
||||
if (reallyAllSkipped) {
|
||||
if (reallyAllSkipped)
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
@ -339,9 +331,8 @@ public class Metrics {
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, int[] values) {
|
||||
if (values == null) {
|
||||
if (values == null)
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues = Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
@ -357,9 +348,8 @@ public class Metrics {
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject object) {
|
||||
if (object == null) {
|
||||
if (object == null)
|
||||
throw new IllegalArgumentException("JSON object must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, object.toString());
|
||||
return this;
|
||||
}
|
||||
@ -374,9 +364,8 @@ public class Metrics {
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject[] values) {
|
||||
if (values == null) {
|
||||
if (values == null)
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues = Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
@ -392,9 +381,8 @@ public class Metrics {
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String value) {
|
||||
if (value == null) {
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException("JSON value must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, "\"" + escape(value) + "\"");
|
||||
return this;
|
||||
}
|
||||
@ -409,9 +397,8 @@ public class Metrics {
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String[] values) {
|
||||
if (values == null) {
|
||||
if (values == null)
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues = Arrays.stream(values).map(value -> "\"" + escape(value) + "\"")
|
||||
.collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
@ -427,12 +414,10 @@ public class Metrics {
|
||||
* The escaped value of the field.
|
||||
*/
|
||||
private void appendFieldUnescaped(String key, String escapedValue) {
|
||||
if (builder == null) {
|
||||
if (builder == null)
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
if (key == null) {
|
||||
if (key == null)
|
||||
throw new IllegalArgumentException("JSON key must not be null");
|
||||
}
|
||||
if (hasAtLeastOneField) {
|
||||
builder.append(",");
|
||||
}
|
||||
@ -458,9 +443,8 @@ public class Metrics {
|
||||
* @return The built JSON string.
|
||||
*/
|
||||
public JsonObject build() {
|
||||
if (builder == null) {
|
||||
if (builder == null)
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
JsonObject object = new JsonObject(builder.append("}").toString());
|
||||
builder = null;
|
||||
return object;
|
||||
@ -499,7 +483,7 @@ public class Metrics {
|
||||
* @return The escaped value.
|
||||
*/
|
||||
private static String escape(String value) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char c = value.charAt(i);
|
||||
if (c == '"') {
|
||||
@ -605,7 +589,7 @@ public class Metrics {
|
||||
}
|
||||
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
this.customCharts.add(chart);
|
||||
customCharts.add(chart);
|
||||
}
|
||||
|
||||
/** Checks that the class was properly relocated. */
|
||||
@ -615,16 +599,14 @@ public class Metrics {
|
||||
|| !System.getProperty("bstats.relocatecheck").equals("false")) {
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this little
|
||||
// "trick" ... :D
|
||||
final String defaultPackage = new String(
|
||||
new byte[] { 'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's' });
|
||||
final String examplePackage = new String(
|
||||
String defaultPackage = new String(new byte[] { 'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's' });
|
||||
String examplePackage = new String(
|
||||
new byte[] { 'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e' });
|
||||
// We want to make sure no one just copy & pastes the example and uses the wrong package
|
||||
// names
|
||||
if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage)
|
||||
|| MetricsBase.class.getPackage().getName().startsWith(examplePackage)) {
|
||||
|| MetricsBase.class.getPackage().getName().startsWith(examplePackage))
|
||||
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -661,7 +643,7 @@ public class Metrics {
|
||||
}
|
||||
|
||||
private void startSubmitting() {
|
||||
final Runnable submitTask = () -> {
|
||||
Runnable submitTask = () -> {
|
||||
if (!enabled || !checkServiceEnabledSupplier.get()) {
|
||||
// Submitting data or service is disabled
|
||||
scheduler.shutdown();
|
||||
@ -670,7 +652,7 @@ public class Metrics {
|
||||
if (submitTaskConsumer != null) {
|
||||
submitTaskConsumer.accept(this::submitData);
|
||||
} else {
|
||||
this.submitData();
|
||||
submitData();
|
||||
}
|
||||
};
|
||||
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution
|
||||
@ -688,9 +670,9 @@ public class Metrics {
|
||||
}
|
||||
|
||||
private void submitData() {
|
||||
final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
|
||||
JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
|
||||
appendPlatformDataConsumer.accept(baseJsonBuilder);
|
||||
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
|
||||
JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
|
||||
appendServiceDataConsumer.accept(serviceJsonBuilder);
|
||||
JsonObjectBuilder.JsonObject[] chartData = customCharts.stream()
|
||||
.map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors))
|
||||
@ -721,10 +703,9 @@ public class Metrics {
|
||||
* The string to gzip.
|
||||
* @return The gzipped string.
|
||||
*/
|
||||
private static byte[] compress(final String str) throws IOException {
|
||||
if (str == null) {
|
||||
private static byte[] compress(String str) throws IOException {
|
||||
if (str == null)
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
@ -733,11 +714,11 @@ public class Metrics {
|
||||
}
|
||||
|
||||
/** The version of the Metrics class. */
|
||||
public static final String METRICS_VERSION = "3.0.0";
|
||||
public static String METRICS_VERSION = "3.0.0";
|
||||
|
||||
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
|
||||
private static String REPORT_URL = "https://bStats.org/api/v2/data/%s";
|
||||
|
||||
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1,
|
||||
private static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1,
|
||||
task -> new Thread(task, "bStats-Metrics"));
|
||||
}
|
||||
|
||||
@ -762,10 +743,9 @@ public class Metrics {
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
if (map == null || map.isEmpty())
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
@ -775,10 +755,9 @@ public class Metrics {
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
if (allSkipped)
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
@ -804,10 +783,9 @@ public class Metrics {
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
if (map == null || map.isEmpty())
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
valuesBuilder.appendField(entry.getKey(), new int[] { entry.getValue() });
|
||||
}
|
||||
@ -835,10 +813,9 @@ public class Metrics {
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
String value = callable.call();
|
||||
if (value == null || value.isEmpty()) {
|
||||
if (value == null || value.isEmpty())
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
@ -863,10 +840,9 @@ public class Metrics {
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
int value = callable.call();
|
||||
if (value == 0) {
|
||||
if (value == 0)
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ public class NPCNeedsRespawnEvent extends NPCEvent {
|
||||
|
||||
public NPCNeedsRespawnEvent(NPC npc, Location at) {
|
||||
super(npc);
|
||||
this.spawn = at;
|
||||
spawn = at;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -27,5 +27,5 @@ public class NPCNeedsRespawnEvent extends NPCEvent {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private static HandlerList handlers = new HandlerList();
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ import net.citizensnpcs.api.npc.NPC;
|
||||
import net.citizensnpcs.api.trait.trait.MobType;
|
||||
import net.citizensnpcs.api.util.Messaging;
|
||||
import net.citizensnpcs.npc.ai.NPCHolder;
|
||||
import net.citizensnpcs.trait.ClickRedirectTrait;
|
||||
import net.citizensnpcs.trait.HologramTrait;
|
||||
import net.citizensnpcs.trait.MirrorTrait;
|
||||
import net.citizensnpcs.trait.RotationTrait;
|
||||
import net.citizensnpcs.trait.RotationTrait.PacketRotationSession;
|
||||
@ -55,15 +57,15 @@ import net.citizensnpcs.util.NMS;
|
||||
import net.citizensnpcs.util.SkinProperty;
|
||||
|
||||
public class ProtocolLibListener implements Listener {
|
||||
private final Class<?> flagsClass;
|
||||
private final ProtocolManager manager;
|
||||
private Class<?> flagsClass;
|
||||
private ProtocolManager manager;
|
||||
private final Map<UUID, MirrorTrait> mirrorTraits = Maps.newConcurrentMap();
|
||||
private final Citizens plugin;
|
||||
private Citizens plugin;
|
||||
private final Map<Integer, RotationTrait> rotationTraits = Maps.newConcurrentMap();
|
||||
|
||||
public ProtocolLibListener(Citizens plugin) {
|
||||
this.plugin = plugin;
|
||||
this.manager = ProtocolLibrary.getProtocolManager();
|
||||
manager = ProtocolLibrary.getProtocolManager();
|
||||
flagsClass = MinecraftReflection.getMinecraftClass("RelativeMovement", "world.entity.RelativeMovement",
|
||||
"EnumPlayerTeleportFlags", "PacketPlayOutPosition$EnumPlayerTeleportFlags",
|
||||
"network.protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags");
|
||||
@ -72,50 +74,59 @@ public class ProtocolLibListener implements Listener {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
NPC npc = getNPCFromPacket(event);
|
||||
if (npc == null || !npc.data().has(NPC.Metadata.HOLOGRAM_LINE_SUPPLIER))
|
||||
if (npc == null)
|
||||
return;
|
||||
|
||||
Function<Player, String> hvs = npc.data().get(NPC.Metadata.HOLOGRAM_LINE_SUPPLIER);
|
||||
int version = manager.getProtocolVersion(event.getPlayer());
|
||||
PacketContainer packet = event.getPacket();
|
||||
if (version < 761) {
|
||||
List<WrappedWatchableObject> wwo = packet.getWatchableCollectionModifier().readSafely(0);
|
||||
if (wwo == null)
|
||||
return;
|
||||
|
||||
int version = manager.getProtocolVersion(event.getPlayer());
|
||||
if (npc.data().has(NPC.Metadata.HOLOGRAM_FOR) || npc.data().has(NPC.Metadata.HOLOGRAM_LINE_SUPPLIER)) {
|
||||
Function<Player, String> hvs = npc.data().get(NPC.Metadata.HOLOGRAM_LINE_SUPPLIER);
|
||||
Object fakeName = null;
|
||||
if (hvs != null) {
|
||||
String suppliedName = hvs.apply(event.getPlayer());
|
||||
fakeName = version <= 340 ? suppliedName
|
||||
: Optional.of(Messaging.minecraftComponentFromRawMessage(suppliedName));
|
||||
}
|
||||
boolean sneaking = npc.getOrAddTrait(ClickRedirectTrait.class).getRedirectNPC()
|
||||
.getOrAddTrait(HologramTrait.class).isHologramSneaking(npc, event.getPlayer());
|
||||
boolean delta = false;
|
||||
String text = hvs.apply(event.getPlayer());
|
||||
for (WrappedWatchableObject wo : wwo) {
|
||||
if (wo.getIndex() != 2)
|
||||
continue;
|
||||
if (version <= 340) {
|
||||
wo.setValue(text);
|
||||
} else {
|
||||
wo.setValue(Optional.of(Messaging.minecraftComponentFromRawMessage(text)));
|
||||
|
||||
if (version < 761) {
|
||||
List<WrappedWatchableObject> wwo = packet.getWatchableCollectionModifier().readSafely(0);
|
||||
if (wwo == null)
|
||||
return;
|
||||
|
||||
for (WrappedWatchableObject wo : wwo) {
|
||||
if (fakeName != null && wo.getIndex() == 2) {
|
||||
wo.setValue(fakeName);
|
||||
delta = true;
|
||||
} else if (sneaking && wo.getIndex() == 0) {
|
||||
byte b = (byte) (((Number) wo.getValue()).byteValue() | 0x02);
|
||||
wo.setValue(b);
|
||||
delta = true;
|
||||
}
|
||||
}
|
||||
delta = true;
|
||||
break;
|
||||
}
|
||||
if (delta) {
|
||||
packet.getWatchableCollectionModifier().write(0, wwo);
|
||||
}
|
||||
} else {
|
||||
List<WrappedDataValue> wdvs = packet.getDataValueCollectionModifier().readSafely(0);
|
||||
if (wdvs == null)
|
||||
return;
|
||||
|
||||
if (delta) {
|
||||
packet.getWatchableCollectionModifier().write(0, wwo);
|
||||
}
|
||||
} else {
|
||||
List<WrappedDataValue> wdvs = packet.getDataValueCollectionModifier().readSafely(0);
|
||||
if (wdvs == null)
|
||||
return;
|
||||
|
||||
boolean delta = false;
|
||||
String text = hvs.apply(event.getPlayer());
|
||||
for (WrappedDataValue wdv : wdvs) {
|
||||
if (wdv.getIndex() != 2)
|
||||
continue;
|
||||
wdv.setValue(Optional.of(Messaging.minecraftComponentFromRawMessage(text)));
|
||||
break;
|
||||
}
|
||||
|
||||
if (delta) {
|
||||
packet.getDataValueCollectionModifier().write(0, wdvs);
|
||||
for (WrappedDataValue wdv : wdvs) {
|
||||
if (fakeName != null && wdv.getIndex() == 2) {
|
||||
wdv.setValue(fakeName);
|
||||
delta = true;
|
||||
} else if (sneaking && wdv.getIndex() == 0) {
|
||||
byte b = (byte) (((Number) wdv.getValue()).byteValue() | 0x02);
|
||||
wdv.setValue(b);
|
||||
delta = true;
|
||||
}
|
||||
}
|
||||
if (delta) {
|
||||
packet.getDataValueCollectionModifier().write(0, wdvs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,7 +141,6 @@ public class ProtocolLibListener implements Listener {
|
||||
uuid -> mirrorTraits.get(uuid));
|
||||
return;
|
||||
}
|
||||
|
||||
List<PlayerInfoData> list = event.getPacket().getPlayerInfoDataLists().readSafely(0);
|
||||
if (list == null)
|
||||
return;
|
||||
@ -153,13 +163,11 @@ public class ProtocolLibListener implements Listener {
|
||||
wgp = WrappedGameProfile.fromPlayer(event.getPlayer());
|
||||
playerName = WrappedChatComponent.fromText(event.getPlayer().getDisplayName());
|
||||
}
|
||||
|
||||
if (trait.mirrorName()) {
|
||||
list.set(i, new PlayerInfoData(wgp.withId(npcInfo.getProfile().getId()), npcInfo.getLatency(),
|
||||
npcInfo.getGameMode(), playerName));
|
||||
continue;
|
||||
}
|
||||
|
||||
Collection<Property> textures = playerProfile.getProperties().get("textures");
|
||||
if (textures == null || textures.size() == 0)
|
||||
continue;
|
||||
@ -174,7 +182,6 @@ public class ProtocolLibListener implements Listener {
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
event.getPacket().getPlayerInfoDataLists().write(0, list);
|
||||
}
|
||||
@ -202,7 +209,6 @@ public class ProtocolLibListener implements Listener {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
RotationTrait trait = rotationTraits.get(eid);
|
||||
if (trait == null)
|
||||
return;
|
||||
@ -215,10 +221,8 @@ public class ProtocolLibListener implements Listener {
|
||||
PacketType type = event.getPacketType();
|
||||
if (type == Server.ENTITY_HEAD_ROTATION) {
|
||||
packet.getBytes().write(0, degToByte(session.getHeadYaw()));
|
||||
} else if (type == Server.ENTITY_LOOK) {
|
||||
packet.getBytes().write(0, degToByte(session.getBodyYaw()));
|
||||
packet.getBytes().write(1, degToByte(session.getPitch()));
|
||||
} else if (type == Server.ENTITY_MOVE_LOOK || type == Server.REL_ENTITY_MOVE_LOOK) {
|
||||
} else if (type == Server.ENTITY_LOOK || type == Server.ENTITY_MOVE_LOOK
|
||||
|| type == Server.REL_ENTITY_MOVE_LOOK) {
|
||||
packet.getBytes().write(0, degToByte(session.getBodyYaw()));
|
||||
packet.getBytes().write(1, degToByte(session.getPitch()));
|
||||
} else if (type == Server.POSITION) {
|
||||
@ -231,7 +235,6 @@ public class ProtocolLibListener implements Listener {
|
||||
packet.getFloat().write(0, session.getBodyYaw());
|
||||
packet.getFloat().write(1, session.getPitch());
|
||||
}
|
||||
|
||||
session.onPacketOverwritten();
|
||||
Messaging.debug("OVERWRITTEN " + type + " " + packet.getHandle());
|
||||
}
|
||||
@ -258,7 +261,6 @@ public class ProtocolLibListener implements Listener {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return entity instanceof NPCHolder ? ((NPCHolder) entity).getNPC() : null;
|
||||
}
|
||||
|
||||
@ -278,7 +280,6 @@ public class ProtocolLibListener implements Listener {
|
||||
rotationTraits.put(event.getNPC().getEntity().getEntityId(),
|
||||
event.getNPC().getTraitNullable(RotationTrait.class));
|
||||
}
|
||||
|
||||
if (event.getNPC().hasTrait(MirrorTrait.class)
|
||||
&& event.getNPC().getOrAddTrait(MobType.class).getType() == EntityType.PLAYER) {
|
||||
mirrorTraits.put(event.getNPC().getEntity().getUniqueId(),
|
||||
|
@ -147,7 +147,7 @@ public class Settings {
|
||||
DEFAULT_TEXT("npc.default.talk-close.text.0", "Hi, I'm <npc>!") {
|
||||
@Override
|
||||
public void loadFromKey(DataKey root) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
List<String> list = new ArrayList<>();
|
||||
for (DataKey key : root.getRelative("npc.default.talk-close.text").getSubKeys()) {
|
||||
list.add(key.getString(""));
|
||||
}
|
||||
@ -290,7 +290,7 @@ public class Settings {
|
||||
if (migrate.contains(".")) {
|
||||
this.migrate = migrate;
|
||||
} else {
|
||||
this.comments = migrate;
|
||||
comments = migrate;
|
||||
}
|
||||
this.path = path;
|
||||
this.value = value;
|
||||
@ -316,9 +316,8 @@ public class Settings {
|
||||
}
|
||||
|
||||
public int asInt() {
|
||||
if (value instanceof String) {
|
||||
if (value instanceof String)
|
||||
return Integer.parseInt(value.toString());
|
||||
}
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
|
||||
|
@ -38,9 +38,8 @@ public class StoredShops {
|
||||
}
|
||||
|
||||
public NPCShop getShop(String name) {
|
||||
if (npcShops.containsKey(name)) {
|
||||
if (npcShops.containsKey(name))
|
||||
return npcShops.get(name);
|
||||
}
|
||||
return getGlobalShop(name);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ import net.citizensnpcs.util.StringHelper;
|
||||
@Requirements
|
||||
public class AdminCommands {
|
||||
private final Citizens plugin;
|
||||
private final Map<CommandSender, Long> reloadTimeouts = new WeakHashMap<CommandSender, Long>();
|
||||
private final Map<CommandSender, Long> reloadTimeouts = new WeakHashMap<>();
|
||||
|
||||
public AdminCommands(Citizens plugin) {
|
||||
this.plugin = plugin;
|
||||
@ -51,7 +51,6 @@ public class AdminCommands {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Messaging.sendTr(sender, Messages.CITIZENS_RELOADING);
|
||||
try {
|
||||
plugin.reload();
|
||||
|
@ -60,7 +60,6 @@ public class EditorCommands {
|
||||
player.acceptConversationInput(args.getJoinedStrings(1));
|
||||
return;
|
||||
}
|
||||
|
||||
Editor.enterOrLeave(player, editor);
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class NPCCommandSelector extends NumericPrompt {
|
||||
|
||||
public NPCCommandSelector(Callback callback, List<NPC> possible) {
|
||||
this.callback = callback;
|
||||
this.choices = possible;
|
||||
choices = possible;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -86,7 +86,7 @@ public class NPCCommandSelector extends NumericPrompt {
|
||||
}
|
||||
|
||||
public static void start(Callback callback, Conversable player, List<NPC> possible) {
|
||||
final Conversation conversation = new ConversationFactory(CitizensAPI.getPlugin()).withLocalEcho(false)
|
||||
Conversation conversation = new ConversationFactory(CitizensAPI.getPlugin()).withLocalEcho(false)
|
||||
.withEscapeSequence("exit").withModality(false)
|
||||
.withFirstPrompt(new NPCCommandSelector(callback, possible)).buildConversation(player);
|
||||
conversation.begin();
|
||||
@ -100,7 +100,6 @@ public class NPCCommandSelector extends NumericPrompt {
|
||||
return;
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
|
||||
Integer id = Ints.tryParse(raw);
|
||||
if (id != null) {
|
||||
callback.run(npcRegistry.getById(id));
|
||||
@ -112,12 +111,12 @@ public class NPCCommandSelector extends NumericPrompt {
|
||||
if (args.hasValueFlag("range")) {
|
||||
range = Math.abs(args.getFlagDouble("range"));
|
||||
}
|
||||
|
||||
for (NPC test : npcRegistry) {
|
||||
if (test.getName().equalsIgnoreCase(name)) {
|
||||
if (range > 0 && test.isSpawned()
|
||||
&& !Util.locationWithinRange(args.getSenderLocation(), test.getEntity().getLocation(), range))
|
||||
&& !Util.locationWithinRange(args.getSenderLocation(), test.getEntity().getLocation(), range)) {
|
||||
continue;
|
||||
}
|
||||
possible.add(test);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -42,7 +42,6 @@ public class TraitCommands {
|
||||
failed.add(String.format("%s: No permission", traitName));
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<? extends Trait> clazz = CitizensAPI.getTraitFactory().getTraitClass(traitName);
|
||||
if (clazz == null) {
|
||||
failed.add(String.format("%s: Trait not found", traitName));
|
||||
@ -108,7 +107,6 @@ public class TraitCommands {
|
||||
failed.add(String.format("%s: No permission", traitName));
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<? extends Trait> clazz = CitizensAPI.getTraitFactory().getTraitClass(traitName);
|
||||
if (clazz == null) {
|
||||
failed.add(String.format("%s: Trait not found", traitName));
|
||||
@ -122,10 +120,12 @@ public class TraitCommands {
|
||||
removeTrait(npc, clazz, sender);
|
||||
removed.add(StringHelper.wrap(traitName));
|
||||
}
|
||||
if (removed.size() > 0)
|
||||
if (removed.size() > 0) {
|
||||
Messaging.sendTr(sender, Messages.TRAITS_REMOVED, Joiner.on(", ").join(removed));
|
||||
if (failed.size() > 0)
|
||||
}
|
||||
if (failed.size() > 0) {
|
||||
Messaging.sendTr(sender, Messages.FAILED_TO_REMOVE, Joiner.on(", ").join(failed));
|
||||
}
|
||||
}
|
||||
|
||||
private void removeTrait(NPC npc, Class<? extends Trait> clazz, CommandSender sender) {
|
||||
@ -150,7 +150,6 @@ public class TraitCommands {
|
||||
failed.add(String.format("%s: No permission", traitName));
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<? extends Trait> clazz = CitizensAPI.getTraitFactory().getTraitClass(traitName);
|
||||
if (clazz == null) {
|
||||
failed.add(String.format("%s: Trait not found", traitName));
|
||||
|
@ -130,8 +130,8 @@ public class WaypointCommands {
|
||||
waypoints.describeProviders(sender);
|
||||
return;
|
||||
}
|
||||
if (sender instanceof Player && Editor.hasEditor(((Player) sender))) {
|
||||
Editor.leave(((Player) sender));
|
||||
if (sender instanceof Player && Editor.hasEditor((Player) sender)) {
|
||||
Editor.leave((Player) sender);
|
||||
}
|
||||
boolean success = waypoints.setWaypointProvider(args.getString(1));
|
||||
if (!success)
|
||||
|
@ -20,7 +20,7 @@ import net.citizensnpcs.util.Util;
|
||||
|
||||
@Menu(title = "Configure NPC", type = InventoryType.CHEST, dimensions = { 5, 9 })
|
||||
public class NPCConfigurator extends InventoryMenuPage {
|
||||
private final NPC npc;
|
||||
private NPC npc;
|
||||
|
||||
private NPCConfigurator() {
|
||||
throw new UnsupportedOperationException();
|
||||
@ -36,7 +36,7 @@ public class NPCConfigurator extends InventoryMenuPage {
|
||||
ConfiguratorInfo info = entry.getValue();
|
||||
InventoryMenuSlot slot = ctx.getSlot(entry.getKey());
|
||||
slot.setItemStack(new ItemStack(info.material, 1));
|
||||
slot.setClickHandler((evt) -> info.clickHandler.accept(new ConfiguratorEvent(ctx, npc, slot, evt)));
|
||||
slot.setClickHandler(evt -> info.clickHandler.accept(new ConfiguratorEvent(ctx, npc, slot, evt)));
|
||||
info.clickHandler.accept(new ConfiguratorEvent(ctx, npc, slot, null));
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,7 @@ public class NPCConfigurator extends InventoryMenuPage {
|
||||
this.ctx = ctx;
|
||||
this.npc = npc;
|
||||
this.slot = slot;
|
||||
this.event = evt;
|
||||
event = evt;
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,18 +60,18 @@ public class NPCConfigurator extends InventoryMenuPage {
|
||||
private final Material material;
|
||||
|
||||
public ConfiguratorInfo(Material mat, Consumer<ConfiguratorEvent> con) {
|
||||
this.material = mat;
|
||||
this.clickHandler = con;
|
||||
material = mat;
|
||||
clickHandler = con;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<Integer, ConfiguratorInfo> SLOT_MAP = Maps.newHashMap();
|
||||
static {
|
||||
SLOT_MAP.put(0, new ConfiguratorInfo(Util.getFallbackMaterial("OAK_SIGN", "SIGN"), (evt) -> {
|
||||
SLOT_MAP.put(0, new ConfiguratorInfo(Util.getFallbackMaterial("OAK_SIGN", "SIGN"), evt -> {
|
||||
evt.slot.setDescription("Edit NPC name\n" + evt.npc.getName());
|
||||
if (evt.event != null) {
|
||||
evt.ctx.getMenu().transition(
|
||||
InputMenus.stringSetter(() -> evt.npc.getName(), (input) -> evt.npc.setName(input)));
|
||||
evt.ctx.getMenu()
|
||||
.transition(InputMenus.stringSetter(() -> evt.npc.getName(), input -> evt.npc.setName(input)));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ public class CreateNPCHistoryItem implements CommandHistoryItem {
|
||||
private final UUID uuid;
|
||||
|
||||
public CreateNPCHistoryItem(NPC npc) {
|
||||
this.uuid = npc.getUniqueId();
|
||||
uuid = npc.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,11 +19,11 @@ public class RemoveNPCHistoryItem implements CommandHistoryItem {
|
||||
private final UUID uuid;
|
||||
|
||||
public RemoveNPCHistoryItem(NPC from) {
|
||||
this.key = new MemoryDataKey();
|
||||
key = new MemoryDataKey();
|
||||
from.save(key);
|
||||
this.type = from.getOrAddTrait(MobType.class).getType();
|
||||
this.uuid = from.getUniqueId();
|
||||
this.id = from.getId();
|
||||
type = from.getOrAddTrait(MobType.class).getType();
|
||||
uuid = from.getUniqueId();
|
||||
id = from.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,7 +19,7 @@ public class CopierEditor extends Editor {
|
||||
public CopierEditor(Player player, NPC npc) {
|
||||
this.player = player;
|
||||
this.npc = npc;
|
||||
this.name = npc.getRawName();
|
||||
name = npc.getRawName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -41,7 +41,6 @@ public class CopierEditor extends Editor {
|
||||
if (!copy.getRawName().equals(name)) {
|
||||
copy.setName(name);
|
||||
}
|
||||
|
||||
if (copy.isSpawned() && player.isOnline()) {
|
||||
Location location = event.getClickedBlock().getLocation();
|
||||
location.setYaw(player.getLocation().getYaw());
|
||||
@ -50,7 +49,6 @@ public class CopierEditor extends Editor {
|
||||
copy.teleport(location, TeleportCause.PLUGIN);
|
||||
copy.getOrAddTrait(CurrentLocation.class).setLocation(location);
|
||||
}
|
||||
|
||||
Messaging.sendTr(player, Messages.NPC_COPIED, npc.getName());
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
@ -58,5 +58,5 @@ public abstract class Editor implements Listener {
|
||||
EDITING.clear();
|
||||
}
|
||||
|
||||
private static final Map<UUID, Editor> EDITING = new HashMap<UUID, Editor>();
|
||||
private static final Map<UUID, Editor> EDITING = new HashMap<>();
|
||||
}
|
@ -73,32 +73,32 @@ public class GenericEquipperGUI extends InventoryMenuPage {
|
||||
|
||||
@ClickHandler(slot = { 1, 5 })
|
||||
public void setBoots(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||
set(EquipmentSlot.BOOTS, event, (type) -> type == Material.AIR || type.name().endsWith("BOOTS"));
|
||||
set(EquipmentSlot.BOOTS, event, type -> type == Material.AIR || type.name().endsWith("BOOTS"));
|
||||
}
|
||||
|
||||
@ClickHandler(slot = { 1, 3 })
|
||||
public void setChest(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||
set(EquipmentSlot.CHESTPLATE, event,
|
||||
(type) -> type == Material.AIR || type.name().endsWith("CHESTPLATE") || type.name().equals("ELYTRA"));
|
||||
type -> type == Material.AIR || type.name().endsWith("CHESTPLATE") || type.name().equals("ELYTRA"));
|
||||
}
|
||||
|
||||
@ClickHandler(slot = { 1, 0 })
|
||||
public void setHand(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||
set(EquipmentSlot.HAND, event, (type) -> true);
|
||||
set(EquipmentSlot.HAND, event, type -> true);
|
||||
}
|
||||
|
||||
@ClickHandler(slot = { 1, 2 })
|
||||
public void setHelmet(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||
set(EquipmentSlot.HELMET, event, (type) -> true);
|
||||
set(EquipmentSlot.HELMET, event, type -> true);
|
||||
}
|
||||
|
||||
@ClickHandler(slot = { 1, 4 })
|
||||
public void setLeggings(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||
set(EquipmentSlot.LEGGINGS, event, (type) -> type == Material.AIR || type.name().endsWith("LEGGINGS"));
|
||||
set(EquipmentSlot.LEGGINGS, event, type -> type == Material.AIR || type.name().endsWith("LEGGINGS"));
|
||||
}
|
||||
|
||||
@ClickHandler(slot = { 1, 1 })
|
||||
public void setOffhand(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
|
||||
set(EquipmentSlot.OFF_HAND, event, (type) -> true);
|
||||
set(EquipmentSlot.OFF_HAND, event, type -> true);
|
||||
}
|
||||
}
|
||||
|
@ -43,11 +43,10 @@ public abstract class AbstractEntityController implements EntityController {
|
||||
if (bukkitEntity instanceof Player) {
|
||||
NMS.removeFromWorld(bukkitEntity);
|
||||
NMS.remove(bukkitEntity);
|
||||
bukkitEntity = null;
|
||||
} else {
|
||||
bukkitEntity.remove();
|
||||
bukkitEntity = null;
|
||||
}
|
||||
bukkitEntity = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,54 +82,44 @@ public class CitizensNPC extends AbstractNPC {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NPCDespawnEvent event = new NPCDespawnEvent(this, reason);
|
||||
if (reason == DespawnReason.CHUNK_UNLOAD) {
|
||||
event.setCancelled(data().get(NPC.Metadata.KEEP_CHUNK_LOADED, Setting.KEEP_CHUNKS_LOADED.asBoolean()));
|
||||
}
|
||||
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled() && reason != DespawnReason.DEATH) {
|
||||
Messaging.debug("Couldn't despawn", this, "due to despawn event cancellation. Will load chunk.",
|
||||
getEntity().isValid(), ", DespawnReason." + reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean keepSelected = getOrAddTrait(Spawned.class).shouldSpawn();
|
||||
if (!keepSelected) {
|
||||
data().remove("selectors");
|
||||
}
|
||||
|
||||
if (getEntity() != null) {
|
||||
getEntity().removeMetadata("NPC", CitizensAPI.getPlugin());
|
||||
getEntity().removeMetadata("NPC-ID", CitizensAPI.getPlugin());
|
||||
}
|
||||
|
||||
if (getEntity() instanceof Player) {
|
||||
PlayerUpdateTask.deregisterPlayer(getEntity());
|
||||
}
|
||||
|
||||
navigator.onDespawn();
|
||||
if (reason == DespawnReason.RELOAD) {
|
||||
unloadEvents();
|
||||
}
|
||||
|
||||
for (Trait trait : new ArrayList<Trait>(traits.values())) {
|
||||
for (Trait trait : new ArrayList<>(traits.values())) {
|
||||
trait.onDespawn(reason);
|
||||
}
|
||||
|
||||
Messaging.debug("Despawned", this, "DespawnReason." + reason);
|
||||
|
||||
if (getEntity() instanceof SkinnableEntity) {
|
||||
((SkinnableEntity) getEntity()).getSkinTracker().onRemoveNPC();
|
||||
}
|
||||
|
||||
if (reason == DespawnReason.DEATH) {
|
||||
entityController.die();
|
||||
} else {
|
||||
entityController.remove();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -190,7 +180,7 @@ public class CitizensNPC extends AbstractNPC {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(final DataKey root) {
|
||||
public void load(DataKey root) {
|
||||
super.load(root);
|
||||
|
||||
CurrentLocation spawnLocation = getOrAddTrait(CurrentLocation.class);
|
||||
@ -201,14 +191,13 @@ public class CitizensNPC extends AbstractNPC {
|
||||
Messaging.debug("Tried to spawn", this, "on load but world was null");
|
||||
}
|
||||
}
|
||||
|
||||
navigator.load(root.getRelative("navigator"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresNameHologram() {
|
||||
return super.requiresNameHologram()
|
||||
|| (Setting.ALWAYS_USE_NAME_HOLOGRAM.asBoolean() && !data().has(NPC.Metadata.HOLOGRAM_FOR));
|
||||
|| Setting.ALWAYS_USE_NAME_HOLOGRAM.asBoolean() && !data().has(NPC.Metadata.HOLOGRAM_FOR);
|
||||
}
|
||||
|
||||
private void resetCachedCoord() {
|
||||
@ -255,12 +244,10 @@ public class CitizensNPC extends AbstractNPC {
|
||||
prev = getEntity().getLocation();
|
||||
despawn(DespawnReason.PENDING_RESPAWN);
|
||||
}
|
||||
|
||||
PacketNPC packet = getTraitNullable(PacketNPC.class);
|
||||
if (packet != null) {
|
||||
newController = packet.wrap(newController);
|
||||
}
|
||||
|
||||
entityController = newController;
|
||||
if (wasSpawned) {
|
||||
spawn(prev, SpawnReason.RESPAWN);
|
||||
@ -315,7 +302,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
if (reason == SpawnReason.CHUNK_LOAD || reason == SpawnReason.COMMAND) {
|
||||
at.getChunk().load();
|
||||
}
|
||||
|
||||
getOrAddTrait(CurrentLocation.class).setLocation(at);
|
||||
entityController.create(at.clone(), this);
|
||||
getEntity().setMetadata("NPC", new FixedMetadataValue(CitizensAPI.getPlugin(), true));
|
||||
@ -324,7 +310,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
if (getEntity() instanceof SkinnableEntity && !hasTrait(SkinLayers.class)) {
|
||||
((SkinnableEntity) getEntity()).setSkinFlags(EnumSet.allOf(SkinLayers.Layer.class));
|
||||
}
|
||||
|
||||
Collection<Trait> onPreSpawn = traits.values();
|
||||
for (Trait trait : onPreSpawn.toArray(new Trait[onPreSpawn.size()])) {
|
||||
try {
|
||||
@ -334,7 +319,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
boolean loaded = Messaging.isDebugging() ? false : Util.isLoaded(at);
|
||||
boolean couldSpawn = entityController.spawn(at);
|
||||
|
||||
@ -343,30 +327,27 @@ public class CitizensNPC extends AbstractNPC {
|
||||
Messaging.debug("Retrying spawn of", this, "later, SpawnReason." + reason + ". Was loaded", loaded,
|
||||
"is loaded", Util.isLoaded(at));
|
||||
}
|
||||
|
||||
// we need to wait before trying to spawn
|
||||
entityController.remove();
|
||||
Bukkit.getPluginManager().callEvent(new NPCNeedsRespawnEvent(this, at));
|
||||
return false;
|
||||
}
|
||||
|
||||
// send skin packets, if applicable, before other NMS packets are sent
|
||||
SkinnableEntity skinnable = getEntity() instanceof SkinnableEntity ? ((SkinnableEntity) getEntity()) : null;
|
||||
SkinnableEntity skinnable = getEntity() instanceof SkinnableEntity ? (SkinnableEntity) getEntity() : null;
|
||||
if (skinnable != null) {
|
||||
skinnable.getSkinTracker().onSpawnNPC();
|
||||
}
|
||||
|
||||
NMS.setLocationDirectly(getEntity(), at);
|
||||
NMS.setHeadYaw(getEntity(), at.getYaw());
|
||||
NMS.setBodyYaw(getEntity(), at.getYaw());
|
||||
|
||||
final Location to = at;
|
||||
Location to = at;
|
||||
Consumer<Runnable> postSpawn = new Consumer<Runnable>() {
|
||||
private int timer;
|
||||
|
||||
@Override
|
||||
public void accept(Runnable cancel) {
|
||||
if (getEntity() == null || (!hasTrait(PacketNPC.class) && !getEntity().isValid())) {
|
||||
if (getEntity() == null || !hasTrait(PacketNPC.class) && !getEntity().isValid()) {
|
||||
if (timer++ > Setting.ENTITY_SPAWN_WAIT_DURATION.asTicks()) {
|
||||
Messaging.debug("Couldn't spawn ", CitizensNPC.this, "waited", timer,
|
||||
"ticks but entity not added to world");
|
||||
@ -374,10 +355,8 @@ public class CitizensNPC extends AbstractNPC {
|
||||
cancel.run();
|
||||
Bukkit.getPluginManager().callEvent(new NPCNeedsRespawnEvent(CitizensNPC.this, to));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the spawned state
|
||||
getOrAddTrait(CurrentLocation.class).setLocation(to);
|
||||
getOrAddTrait(Spawned.class).setSpawned(true);
|
||||
@ -392,7 +371,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
cancel.run();
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.onSpawn();
|
||||
|
||||
for (Trait trait : Iterables.toArray(traits.values(), Trait.class)) {
|
||||
@ -403,7 +381,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
EntityType type = getEntity().getType();
|
||||
NMS.replaceTracker(getEntity());
|
||||
|
||||
@ -414,13 +391,11 @@ public class CitizensNPC extends AbstractNPC {
|
||||
if (NMS.getStepHeight(entity) < 1) {
|
||||
NMS.setStepHeight(entity, 1);
|
||||
}
|
||||
|
||||
if (type == EntityType.PLAYER) {
|
||||
PlayerUpdateTask.registerPlayer(getEntity());
|
||||
} else if (data().has(NPC.Metadata.AGGRESSIVE)) {
|
||||
NMS.setAggressive(entity, data().<Boolean> get(NPC.Metadata.AGGRESSIVE));
|
||||
}
|
||||
|
||||
if (SUPPORT_NODAMAGE_TICKS && (Setting.DEFAULT_SPAWN_NODAMAGE_DURATION.asTicks() != 20
|
||||
|| data().has(NPC.Metadata.SPAWN_NODAMAGE_TICKS))) {
|
||||
try {
|
||||
@ -431,11 +406,9 @@ public class CitizensNPC extends AbstractNPC {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresNameHologram() && !hasTrait(HologramTrait.class)) {
|
||||
addTrait(HologramTrait.class);
|
||||
}
|
||||
|
||||
updateFlyableState();
|
||||
updateCustomNameVisibility();
|
||||
updateScoreboard();
|
||||
@ -451,11 +424,10 @@ public class CitizensNPC extends AbstractNPC {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
postSpawn.accept(() -> cancel());
|
||||
postSpawn.accept(this::cancel);
|
||||
}
|
||||
}.runTaskTimer(CitizensAPI.getPlugin(), 0, 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -467,13 +439,11 @@ public class CitizensNPC extends AbstractNPC {
|
||||
if (hasTrait(SitTrait.class) && getOrAddTrait(SitTrait.class).isSitting()) {
|
||||
getOrAddTrait(SitTrait.class).setSitting(location);
|
||||
}
|
||||
|
||||
Location npcLoc = getEntity().getLocation();
|
||||
if (isSpawned() && npcLoc.getWorld() == location.getWorld()) {
|
||||
if (npcLoc.distance(location) < 1) {
|
||||
NMS.setHeadYaw(getEntity(), location.getYaw());
|
||||
}
|
||||
|
||||
if (getEntity().getType() == EntityType.PLAYER && !getEntity().isInsideVehicle()
|
||||
&& NMS.getPassengers(getEntity()).size() == 0) {
|
||||
NPCTeleportEvent event = new NPCTeleportEvent(this, location);
|
||||
@ -484,7 +454,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.teleport(location, reason);
|
||||
}
|
||||
|
||||
@ -502,7 +471,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
resetCachedCoord();
|
||||
return;
|
||||
}
|
||||
|
||||
if (data().has(NPC.Metadata.ACTIVATION_RANGE)) {
|
||||
int range = data().get(NPC.Metadata.ACTIVATION_RANGE);
|
||||
if (range == -1 || CitizensAPI.getLocationLookup().getNearbyPlayers(getStoredLocation(), range)
|
||||
@ -510,7 +478,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
NMS.activate(getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
boolean shouldSwim = data().get(NPC.Metadata.SWIMMING, SwimmingExaminer.isWaterMob(getEntity()))
|
||||
&& MinecraftBlockExaminer.isLiquid(getEntity().getLocation().getBlock().getType());
|
||||
if (navigator.isNavigating()) {
|
||||
@ -528,7 +495,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
NMS.trySwim(getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
if (SUPPORT_GLOWING && data().has(NPC.Metadata.GLOWING)) {
|
||||
try {
|
||||
getEntity().setGlowing(data().get(NPC.Metadata.GLOWING, false));
|
||||
@ -536,7 +502,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
SUPPORT_GLOWING = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUPPORT_SILENT && data().has(NPC.Metadata.SILENT)) {
|
||||
try {
|
||||
getEntity().setSilent(Boolean.parseBoolean(data().get(NPC.Metadata.SILENT).toString()));
|
||||
@ -544,7 +509,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
SUPPORT_SILENT = false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isLiving = getEntity() instanceof LivingEntity;
|
||||
if (isUpdating(NPCUpdate.PACKET)) {
|
||||
if (data().get(NPC.Metadata.KEEP_CHUNK_LOADED, Setting.KEEP_CHUNKS_LOADED.asBoolean())) {
|
||||
@ -572,7 +536,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
SUPPORT_PICKUP_ITEMS = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (getEntity() instanceof Player) {
|
||||
updateUsingItemState((Player) getEntity());
|
||||
if (data().has(NPC.Metadata.SNEAKING) && !hasTrait(SneakTrait.class)) {
|
||||
@ -580,7 +543,6 @@ public class CitizensNPC extends AbstractNPC {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
navigator.run();
|
||||
|
||||
updateCounter++;
|
||||
@ -616,16 +578,12 @@ public class CitizensNPC extends AbstractNPC {
|
||||
return;
|
||||
|
||||
EntityType type = isSpawned() ? getEntity().getType() : getOrAddTrait(MobType.class).getType();
|
||||
if (type == null)
|
||||
return;
|
||||
|
||||
if (!Util.isAlwaysFlyable(type))
|
||||
if (type == null || !Util.isAlwaysFlyable(type))
|
||||
return;
|
||||
|
||||
if (!data().has(NPC.Metadata.FLYABLE)) {
|
||||
data().setPersistent(NPC.Metadata.FLYABLE, true);
|
||||
}
|
||||
|
||||
if (!hasTrait(Gravity.class)) {
|
||||
getOrAddTrait(Gravity.class).setEnabled(true);
|
||||
}
|
||||
@ -657,7 +615,7 @@ public class CitizensNPC extends AbstractNPC {
|
||||
}
|
||||
}
|
||||
|
||||
private static final SetMultimap<ChunkCoord, NPC> CHUNK_LOADERS = HashMultimap.create();
|
||||
private static SetMultimap<ChunkCoord, NPC> CHUNK_LOADERS = HashMultimap.create();
|
||||
private static boolean SUPPORT_GLOWING = true;
|
||||
private static boolean SUPPORT_NODAMAGE_TICKS = true;
|
||||
private static boolean SUPPORT_PICKUP_ITEMS = true;
|
||||
|
@ -2,6 +2,7 @@ package net.citizensnpcs.npc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -37,7 +38,7 @@ import net.citizensnpcs.util.NMS;
|
||||
|
||||
public class CitizensNPCRegistry implements NPCRegistry {
|
||||
private final String name;
|
||||
private final TIntObjectHashMap<NPC> npcs = new TIntObjectHashMap<NPC>();
|
||||
private final TIntObjectHashMap<NPC> npcs = new TIntObjectHashMap<>();
|
||||
private final NPCDataStore saves;
|
||||
private final Map<UUID, NPC> uniqueNPCs = Maps.newHashMap();
|
||||
|
||||
@ -74,11 +75,9 @@ public class CitizensNPCRegistry implements NPCRegistry {
|
||||
if (type == EntityType.ARMOR_STAND && !npc.hasTrait(ArmorStandTrait.class)) {
|
||||
npc.addTrait(ArmorStandTrait.class);
|
||||
}
|
||||
|
||||
if (Setting.DEFAULT_LOOK_CLOSE.asBoolean()) {
|
||||
npc.addTrait(LookClose.class);
|
||||
}
|
||||
|
||||
npc.addTrait(MountTrait.class);
|
||||
return npc;
|
||||
}
|
||||
@ -93,9 +92,8 @@ public class CitizensNPCRegistry implements NPCRegistry {
|
||||
npc.data().set(NPC.Metadata.ITEM_ID, item.getType().name());
|
||||
npc.data().set(NPC.Metadata.ITEM_DATA, item.getData().getData());
|
||||
npc.setItemProvider(() -> item);
|
||||
} else {
|
||||
} else
|
||||
throw new UnsupportedOperationException("Not an item entity type");
|
||||
}
|
||||
return npc;
|
||||
}
|
||||
|
||||
@ -174,14 +172,13 @@ public class CitizensNPCRegistry implements NPCRegistry {
|
||||
if (npc != null)
|
||||
return npc;
|
||||
for (NPCRegistry registry : CitizensAPI.getNPCRegistries()) {
|
||||
if (registry == this)
|
||||
if (registry == this) {
|
||||
continue;
|
||||
NPC other = registry.getByUniqueId(uuid);
|
||||
if (other != null) {
|
||||
return other;
|
||||
}
|
||||
NPC other = registry.getByUniqueId(uuid);
|
||||
if (other != null)
|
||||
return other;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -243,8 +240,8 @@ public class CitizensNPCRegistry implements NPCRegistry {
|
||||
|
||||
@Override
|
||||
public Iterable<NPC> sorted() {
|
||||
List<NPC> vals = new ArrayList<NPC>(npcs.valueCollection());
|
||||
Collections.sort(vals, (a, b) -> Integer.compare(a.getId(), b.getId()));
|
||||
List<NPC> vals = new ArrayList<>(npcs.valueCollection());
|
||||
Collections.sort(vals, Comparator.comparing(NPC::getId));
|
||||
return vals;
|
||||
}
|
||||
}
|
||||
|
@ -157,9 +157,8 @@ public class CitizensTraitFactory implements TraitFactory {
|
||||
@Override
|
||||
public <T extends Trait> T getTrait(Class<T> clazz) {
|
||||
for (TraitInfo entry : registered.values()) {
|
||||
if (clazz == entry.getTraitClass()) {
|
||||
if (clazz == entry.getTraitClass())
|
||||
return create(entry);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -183,9 +182,8 @@ public class CitizensTraitFactory implements TraitFactory {
|
||||
public void registerTrait(TraitInfo info) {
|
||||
Preconditions.checkNotNull(info, "info cannot be null");
|
||||
info.checkValid();
|
||||
if (registered.containsKey(info.getTraitName())) {
|
||||
if (registered.containsKey(info.getTraitName()))
|
||||
throw new IllegalArgumentException("Trait name " + info.getTraitName() + " already registered");
|
||||
}
|
||||
registered.put(info.getTraitName(), info);
|
||||
if (info.isDefaultTrait()) {
|
||||
defaultTraits.add(info);
|
||||
|
@ -37,6 +37,5 @@ public class EntityControllers {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<EntityType, Constructor<? extends EntityController>> TYPES = Maps
|
||||
.newEnumMap(EntityType.class);
|
||||
private static Map<EntityType, Constructor<? extends EntityController>> TYPES = Maps.newEnumMap(EntityType.class);
|
||||
}
|
||||
|
@ -57,11 +57,11 @@ public class NPCSelector implements Listener, net.citizensnpcs.api.npc.NPCSelect
|
||||
if (event.getSelected() != null)
|
||||
return event.getSelected();
|
||||
|
||||
if (sender instanceof Player) {
|
||||
if (sender instanceof Player)
|
||||
return getSelectedFromMetadatable((Player) sender);
|
||||
} else if (sender instanceof BlockCommandSender) {
|
||||
else if (sender instanceof BlockCommandSender)
|
||||
return getSelectedFromMetadatable(((BlockCommandSender) sender).getBlock());
|
||||
} else if (sender instanceof ConsoleCommandSender) {
|
||||
else if (sender instanceof ConsoleCommandSender) {
|
||||
if (consoleSelectedNPC == null)
|
||||
return null;
|
||||
return CitizensAPI.getNPCRegistry().getByUniqueIdGlobal(consoleSelectedNPC);
|
||||
@ -90,7 +90,7 @@ public class NPCSelector implements Listener, net.citizensnpcs.api.npc.NPCSelect
|
||||
if (value.equals("console")) {
|
||||
consoleSelectedNPC = null;
|
||||
} else if (value.startsWith("@")) {
|
||||
String[] parts = value.substring(1, value.length()).split(":");
|
||||
String[] parts = value.substring(1).split(":");
|
||||
World world = Bukkit.getWorld(parts[0]);
|
||||
if (world != null) {
|
||||
Block block = world.getBlockAt(Integer.parseInt(parts[1]), Integer.parseInt(parts[2]),
|
||||
@ -159,7 +159,6 @@ public class NPCSelector implements Listener, net.citizensnpcs.api.npc.NPCSelect
|
||||
consoleSelectedNPC = npc.getUniqueId();
|
||||
selectors.add("console");
|
||||
}
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new NPCSelectEvent(npc, sender));
|
||||
}
|
||||
|
||||
|
@ -50,9 +50,10 @@ public class Template {
|
||||
queue.add(new Node(fullKey, (Map<String, Object>) entry.getValue()));
|
||||
continue;
|
||||
}
|
||||
boolean overwrite = memoryKey.keyExists(fullKey) | override;
|
||||
if (!overwrite || fullKey.equals("uuid"))
|
||||
boolean overwrite = memoryKey.keyExists(fullKey) || override;
|
||||
if (!overwrite || fullKey.equals("uuid")) {
|
||||
continue;
|
||||
}
|
||||
memoryKey.setRaw(fullKey, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
@ -40,15 +40,15 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
|
||||
super(TargetType.LOCATION);
|
||||
List<Vector> list = Lists.newArrayList(path);
|
||||
this.params = params;
|
||||
this.destination = list.get(list.size() - 1).toLocation(npc.getStoredLocation().getWorld());
|
||||
destination = list.get(list.size() - 1).toLocation(npc.getStoredLocation().getWorld());
|
||||
this.npc = npc;
|
||||
this.plan = new Path(list);
|
||||
plan = new Path(list);
|
||||
}
|
||||
|
||||
public AStarNavigationStrategy(NPC npc, Location dest, NavigatorParameters params) {
|
||||
super(TargetType.LOCATION);
|
||||
this.params = params;
|
||||
this.destination = dest;
|
||||
destination = dest;
|
||||
this.npc = npc;
|
||||
}
|
||||
|
||||
@ -91,9 +91,8 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
|
||||
planner = null;
|
||||
}
|
||||
}
|
||||
if (getCancelReason() != null || plan == null || plan.isComplete()) {
|
||||
if (getCancelReason() != null || plan == null || plan.isComplete())
|
||||
return true;
|
||||
}
|
||||
if (vector == null) {
|
||||
vector = plan.getCurrentVector();
|
||||
}
|
||||
@ -116,23 +115,20 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
|
||||
double xzDistance = dX * dX + dZ * dZ;
|
||||
if (Math.abs(dY) < 1 && Math.sqrt(xzDistance) <= params.distanceMargin()) {
|
||||
plan.update(npc);
|
||||
if (plan.isComplete()) {
|
||||
if (plan.isComplete())
|
||||
return true;
|
||||
}
|
||||
vector = plan.getCurrentVector();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.debug()) {
|
||||
npc.getEntity().getWorld().playEffect(dest, Effect.ENDER_SIGNAL, 0);
|
||||
}
|
||||
|
||||
if (npc.getEntity() instanceof LivingEntity && !npc.getEntity().getType().name().contains("ARMOR_STAND")) {
|
||||
NMS.setDestination(npc.getEntity(), dest.getX(), dest.getY(), dest.getZ(), params.speed());
|
||||
} else {
|
||||
Vector dir = dest.toVector().subtract(npc.getEntity().getLocation().toVector()).normalize().multiply(0.2);
|
||||
boolean liquidOrInLiquid = MinecraftBlockExaminer.isLiquidOrInLiquid(loc.getBlock());
|
||||
if ((dY >= 1 && Math.sqrt(xzDistance) <= 0.4) || (dY >= 0.2 && liquidOrInLiquid)) {
|
||||
if (dY >= 1 && Math.sqrt(xzDistance) <= 0.4 || dY >= 0.2 && liquidOrInLiquid) {
|
||||
dir.add(new Vector(0, 0.75, 0));
|
||||
}
|
||||
npc.getEntity().setVelocity(dir);
|
||||
@ -176,18 +172,16 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
|
||||
}
|
||||
|
||||
public CancelReason tick(int iterationsPerTick, int maxIterations) {
|
||||
if (this.plan != null)
|
||||
if (plan != null)
|
||||
return null;
|
||||
Path plan = ASTAR.run(state, iterationsPerTick);
|
||||
if (plan == null) {
|
||||
if (state.isEmpty()) {
|
||||
if (state.isEmpty())
|
||||
return CancelReason.STUCK;
|
||||
}
|
||||
if (iterationsPerTick > 0 && maxIterations > 0) {
|
||||
iterations += iterationsPerTick;
|
||||
if (iterations > maxIterations) {
|
||||
if (iterations > maxIterations)
|
||||
return CancelReason.STUCK;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.plan = plan;
|
||||
@ -200,5 +194,5 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
private static final AStarMachine<VectorNode, Path> ASTAR = AStarMachine.createWithDefaultStorage();
|
||||
private static AStarMachine<VectorNode, Path> ASTAR = AStarMachine.createWithDefaultStorage();
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ public class BoundingBoxExaminer implements BlockExaminer {
|
||||
|
||||
public BoundingBoxExaminer(Entity entity) {
|
||||
if (entity != null) {
|
||||
this.height = NMS.getHeight(entity);
|
||||
this.width = NMS.getWidth(entity);
|
||||
height = NMS.getHeight(entity);
|
||||
width = NMS.getWidth(entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
!Setting.DEFAULT_STUCK_ACTION.asString().contains("teleport"))) {
|
||||
defaultParams.stuckAction(null);
|
||||
}
|
||||
|
||||
defaultParams.examiner(new SwimmingExaminer(npc));
|
||||
}
|
||||
|
||||
@ -116,9 +115,8 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
|
||||
@Override
|
||||
public NavigatorParameters getLocalParameters() {
|
||||
if (!isNavigating()) {
|
||||
if (!isNavigating())
|
||||
return defaultParams;
|
||||
}
|
||||
return localParams;
|
||||
}
|
||||
|
||||
@ -156,23 +154,18 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
if (root.keyExists("pathfindingrange")) {
|
||||
defaultParams.range((float) root.getDouble("pathfindingrange"));
|
||||
}
|
||||
|
||||
if (root.keyExists("stationaryticks")) {
|
||||
defaultParams.stationaryTicks(root.getInt("stationaryticks"));
|
||||
}
|
||||
|
||||
if (root.keyExists("distancemargin")) {
|
||||
defaultParams.distanceMargin(root.getDouble("distancemargin"));
|
||||
}
|
||||
|
||||
if (root.keyExists("destinationteleportmargin")) {
|
||||
defaultParams.destinationTeleportMargin(root.getDouble("destinationteleportmargin"));
|
||||
}
|
||||
|
||||
if (root.keyExists("updatepathrate")) {
|
||||
defaultParams.updatePathRate(root.getInt("updatepathrate"));
|
||||
}
|
||||
|
||||
defaultParams.speedModifier((float) root.getDouble("speedmodifier", 1F));
|
||||
defaultParams.avoidWater(root.getBoolean("avoidwater"));
|
||||
if (!root.getBoolean("usedefaultstuckaction") && defaultParams.stuckAction() == TeleportStuckAction.INSTANCE) {
|
||||
@ -188,7 +181,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
if (defaultParams.baseSpeed() == UNINITIALISED_SPEED) {
|
||||
defaultParams.baseSpeed(NMS.getSpeedFor(npc));
|
||||
}
|
||||
|
||||
updatePathfindingRange();
|
||||
}
|
||||
|
||||
@ -205,7 +197,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
stopNavigating(CancelReason.STUCK);
|
||||
return;
|
||||
}
|
||||
|
||||
if (updateStationaryStatus())
|
||||
return;
|
||||
|
||||
@ -214,7 +205,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
if (!finished) {
|
||||
localParams.run();
|
||||
}
|
||||
|
||||
if (localParams.lookAtFunction() != null) {
|
||||
if (session == null) {
|
||||
RotationTrait trait = npc.getOrAddTrait(RotationTrait.class);
|
||||
@ -223,14 +213,12 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
}
|
||||
session.getSession().rotateToFace(localParams.lookAtFunction().apply(this));
|
||||
}
|
||||
|
||||
if (localParams.destinationTeleportMargin() > 0
|
||||
&& npcLoc.distance(targetLoc) <= localParams.destinationTeleportMargin()) {
|
||||
// TODO: easing?
|
||||
npc.teleport(targetLoc, TeleportCause.PLUGIN);
|
||||
finished = true;
|
||||
}
|
||||
|
||||
if (!finished)
|
||||
return;
|
||||
|
||||
@ -252,37 +240,31 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
} else {
|
||||
root.removeKey("pathfindingrange");
|
||||
}
|
||||
|
||||
if (defaultParams.stationaryTicks() != Setting.DEFAULT_STATIONARY_DURATION.asTicks()) {
|
||||
root.setInt("stationaryticks", defaultParams.stationaryTicks());
|
||||
} else {
|
||||
root.removeKey("stationaryticks");
|
||||
}
|
||||
|
||||
if (defaultParams.destinationTeleportMargin() != Setting.DEFAULT_DESTINATION_TELEPORT_MARGIN.asDouble()) {
|
||||
root.setDouble("destinationteleportmargin", defaultParams.destinationTeleportMargin());
|
||||
} else {
|
||||
root.removeKey("destinationteleportmargin");
|
||||
}
|
||||
|
||||
if (defaultParams.distanceMargin() != Setting.DEFAULT_DISTANCE_MARGIN.asDouble()) {
|
||||
root.setDouble("distancemargin", defaultParams.distanceMargin());
|
||||
} else {
|
||||
root.removeKey("distancemargin");
|
||||
}
|
||||
|
||||
if (defaultParams.updatePathRate() != Setting.DEFAULT_PATHFINDER_UPDATE_PATH_RATE.asTicks()) {
|
||||
root.setInt("updatepathrate", defaultParams.updatePathRate());
|
||||
} else {
|
||||
root.removeKey("updatepathrate");
|
||||
}
|
||||
|
||||
if (defaultParams.useNewPathfinder() != Setting.USE_NEW_PATHFINDER.asBoolean()) {
|
||||
root.setBoolean("usenewpathfinder", defaultParams.useNewPathfinder());
|
||||
} else {
|
||||
root.removeKey("usenewpathfinder");
|
||||
}
|
||||
|
||||
root.setDouble("speedmodifier", defaultParams.speedModifier());
|
||||
root.setBoolean("avoidwater", defaultParams.avoidWater());
|
||||
root.setBoolean("usedefaultstuckaction", defaultParams.stuckAction() == TeleportStuckAction.INSTANCE);
|
||||
@ -305,7 +287,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
cancelNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
setTarget(params -> {
|
||||
params.straightLineTargetingDistance(100000);
|
||||
return new MCTargetStrategy(npc, target, aggressive, params);
|
||||
@ -321,7 +302,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
cancelNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
setTarget(params -> new StraightLineNavigationStrategy(npc, target.clone(), params));
|
||||
}
|
||||
|
||||
@ -334,7 +314,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
cancelNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
setTarget(params -> new MCTargetStrategy(npc, target, aggressive, params));
|
||||
}
|
||||
|
||||
@ -354,15 +333,13 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
cancelNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
setTarget(params -> {
|
||||
if (npc.isFlyable()) {
|
||||
if (npc.isFlyable())
|
||||
return new FlyingAStarNavigationStrategy(npc, path, params);
|
||||
} else if (params.useNewPathfinder() || !(npc.getEntity() instanceof LivingEntity)) {
|
||||
else if (params.useNewPathfinder() || !(npc.getEntity() instanceof LivingEntity))
|
||||
return new AStarNavigationStrategy(npc, path, params);
|
||||
} else {
|
||||
else
|
||||
return new MCNavigationStrategy(npc, path, params);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -374,16 +351,14 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
cancelNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
final Location target = targetIn.clone();
|
||||
Location target = targetIn.clone();
|
||||
setTarget(params -> {
|
||||
if (npc.isFlyable()) {
|
||||
if (npc.isFlyable())
|
||||
return new FlyingAStarNavigationStrategy(npc, target, params);
|
||||
} else if (params.useNewPathfinder() || !(npc.getEntity() instanceof LivingEntity)) {
|
||||
else if (params.useNewPathfinder() || !(npc.getEntity() instanceof LivingEntity))
|
||||
return new AStarNavigationStrategy(npc, target, params);
|
||||
} else {
|
||||
else
|
||||
return new MCNavigationStrategy(npc, target, params);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -391,7 +366,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
if (executing != null) {
|
||||
executing.stop();
|
||||
}
|
||||
|
||||
executing = null;
|
||||
|
||||
localParams = defaultParams;
|
||||
@ -402,16 +376,11 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
npc.getEntity().setVelocity(velocity);
|
||||
NMS.cancelMoveDestination(npc.getEntity());
|
||||
}
|
||||
|
||||
if (!SUPPORT_CHUNK_TICKETS || !CitizensAPI.hasImplementation() || !CitizensAPI.getPlugin().isEnabled())
|
||||
return;
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateTicket(isNavigating() ? executing.getTargetAsLocation() : null);
|
||||
}
|
||||
}, 10);
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
|
||||
() -> updateTicket(isNavigating() ? executing.getTargetAsLocation() : null), 10);
|
||||
|
||||
// Location loc = npc.getEntity().getLocation(STATIONARY_LOCATION);
|
||||
// NMS.look(npc.getEntity(), loc.getYaw(), 0);
|
||||
@ -424,28 +393,23 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
if (reason == CancelReason.STUCK && Messaging.isDebugging()) {
|
||||
Messaging.debug(npc, "navigation ended, stuck", executing);
|
||||
}
|
||||
|
||||
if (session != null) {
|
||||
session.end();
|
||||
session = null;
|
||||
}
|
||||
|
||||
Iterator<NavigatorCallback> itr = localParams.callbacks().iterator();
|
||||
List<NavigatorCallback> callbacks = new ArrayList<NavigatorCallback>();
|
||||
List<NavigatorCallback> callbacks = new ArrayList<>();
|
||||
while (itr.hasNext()) {
|
||||
callbacks.add(itr.next());
|
||||
itr.remove();
|
||||
}
|
||||
|
||||
for (NavigatorCallback callback : callbacks) {
|
||||
callback.onCompletion(reason);
|
||||
}
|
||||
|
||||
if (reason == null) {
|
||||
stopNavigating();
|
||||
return;
|
||||
}
|
||||
|
||||
if (reason == CancelReason.STUCK) {
|
||||
StuckAction action = localParams.stuckAction();
|
||||
NavigationStuckEvent event = new NavigationStuckEvent(this, action);
|
||||
@ -458,7 +422,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NavigationCancelEvent event = new NavigationCancelEvent(this, reason);
|
||||
PathStrategy old = executing;
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
@ -534,7 +497,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
stopNavigating(CancelReason.STUCK);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lastX == current.getBlockX() && lastY == current.getBlockY() && lastZ == current.getBlockZ()) {
|
||||
if (++stationaryTicks >= localParams.stationaryTicks()) {
|
||||
stopNavigating(CancelReason.STUCK);
|
||||
@ -543,7 +505,6 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
} else {
|
||||
stationaryTicks = 0;
|
||||
}
|
||||
|
||||
lastX = current.getBlockX();
|
||||
lastY = current.getBlockY();
|
||||
lastZ = current.getBlockZ();
|
||||
@ -554,32 +515,29 @@ public class CitizensNavigator implements Navigator, Runnable {
|
||||
if (!SUPPORT_CHUNK_TICKETS || !CitizensAPI.hasImplementation() || !CitizensAPI.getPlugin().isEnabled())
|
||||
return;
|
||||
|
||||
if (target != null && this.activeTicket != null
|
||||
&& new ChunkCoord(target.getChunk()).equals(new ChunkCoord(this.activeTicket.getChunk()))) {
|
||||
this.activeTicket = target.clone();
|
||||
if (target != null && activeTicket != null
|
||||
&& new ChunkCoord(target.getChunk()).equals(new ChunkCoord(activeTicket.getChunk()))) {
|
||||
activeTicket = target.clone();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.activeTicket != null) {
|
||||
if (activeTicket != null) {
|
||||
try {
|
||||
this.activeTicket.getChunk().removePluginChunkTicket(CitizensAPI.getPlugin());
|
||||
activeTicket.getChunk().removePluginChunkTicket(CitizensAPI.getPlugin());
|
||||
} catch (NoSuchMethodError e) {
|
||||
SUPPORT_CHUNK_TICKETS = false;
|
||||
this.activeTicket = null;
|
||||
activeTicket = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == null) {
|
||||
this.activeTicket = null;
|
||||
activeTicket = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.activeTicket = target.clone();
|
||||
activeTicket = target.clone();
|
||||
try {
|
||||
this.activeTicket.getChunk().addPluginChunkTicket(CitizensAPI.getPlugin());
|
||||
activeTicket.getChunk().addPluginChunkTicket(CitizensAPI.getPlugin());
|
||||
} catch (NoSuchMethodError e) {
|
||||
SUPPORT_CHUNK_TICKETS = false;
|
||||
this.activeTicket = null;
|
||||
activeTicket = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,16 +43,16 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy {
|
||||
public FlyingAStarNavigationStrategy(NPC npc, Iterable<Vector> path, NavigatorParameters params) {
|
||||
super(TargetType.LOCATION);
|
||||
List<Vector> list = Lists.newArrayList(path);
|
||||
this.target = list.get(list.size() - 1).toLocation(npc.getStoredLocation().getWorld());
|
||||
this.parameters = params;
|
||||
target = list.get(list.size() - 1).toLocation(npc.getStoredLocation().getWorld());
|
||||
parameters = params;
|
||||
this.npc = npc;
|
||||
setPlan(new Path(list));
|
||||
}
|
||||
|
||||
public FlyingAStarNavigationStrategy(final NPC npc, Location dest, NavigatorParameters params) {
|
||||
public FlyingAStarNavigationStrategy(NPC npc, Location dest, NavigatorParameters params) {
|
||||
super(TargetType.LOCATION);
|
||||
this.target = dest;
|
||||
this.parameters = params;
|
||||
target = dest;
|
||||
parameters = params;
|
||||
this.npc = npc;
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy {
|
||||
}
|
||||
|
||||
public void setPlan(Path path) {
|
||||
this.plan = path;
|
||||
plan = path;
|
||||
if (plan == null || plan.isComplete()) {
|
||||
setCancelReason(CancelReason.STUCK);
|
||||
} else {
|
||||
@ -133,15 +133,13 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy {
|
||||
setPlan(plan);
|
||||
}
|
||||
}
|
||||
if (getCancelReason() != null || plan == null || plan.isComplete()) {
|
||||
if (getCancelReason() != null || plan == null || plan.isComplete())
|
||||
return true;
|
||||
}
|
||||
Location current = npc.getEntity().getLocation();
|
||||
if (current.toVector().distance(vector) <= parameters.distanceMargin()) {
|
||||
plan.update(npc);
|
||||
if (plan.isComplete()) {
|
||||
if (plan.isComplete())
|
||||
return true;
|
||||
}
|
||||
vector = plan.getCurrentVector();
|
||||
}
|
||||
if (parameters.debug()) {
|
||||
@ -159,7 +157,6 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy {
|
||||
// 1.8 compatibility
|
||||
}
|
||||
}
|
||||
|
||||
Vector centeredDest = new Vector(vector.getX() + 0.5D, vector.getY() + 0.1D, vector.getZ() + 0.5D);
|
||||
double d0 = centeredDest.getX() - current.getX();
|
||||
double d1 = centeredDest.getY() - current.getY();
|
||||
@ -178,10 +175,9 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy {
|
||||
NMS.setVerticalMovement(npc.getEntity(), 0.5);
|
||||
Util.faceLocation(npc.getEntity(), centeredDest.toLocation(npc.getEntity().getWorld()));
|
||||
}
|
||||
|
||||
plan.run(npc);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final AStarMachine<VectorNode, Path> ASTAR = AStarMachine.createWithDefaultStorage();
|
||||
private static AStarMachine<VectorNode, Path> ASTAR = AStarMachine.createWithDefaultStorage();
|
||||
}
|
||||
|
@ -23,24 +23,24 @@ public class MCNavigationStrategy extends AbstractPathStrategy {
|
||||
private final NavigatorParameters parameters;
|
||||
private final Location target;
|
||||
|
||||
MCNavigationStrategy(final NPC npc, Iterable<Vector> path, NavigatorParameters params) {
|
||||
MCNavigationStrategy(NPC npc, Iterable<Vector> path, NavigatorParameters params) {
|
||||
super(TargetType.LOCATION);
|
||||
List<Vector> list = Lists.newArrayList(path);
|
||||
this.target = list.get(list.size() - 1).toLocation(npc.getStoredLocation().getWorld());
|
||||
this.parameters = params;
|
||||
target = list.get(list.size() - 1).toLocation(npc.getStoredLocation().getWorld());
|
||||
parameters = params;
|
||||
entity = npc.getEntity();
|
||||
this.navigator = NMS.getTargetNavigator(npc.getEntity(), list, params);
|
||||
navigator = NMS.getTargetNavigator(npc.getEntity(), list, params);
|
||||
}
|
||||
|
||||
MCNavigationStrategy(final NPC npc, Location dest, NavigatorParameters params) {
|
||||
MCNavigationStrategy(NPC npc, Location dest, NavigatorParameters params) {
|
||||
super(TargetType.LOCATION);
|
||||
if (!MinecraftBlockExaminer.canStandIn(dest.getBlock())) {
|
||||
dest = MinecraftBlockExaminer.findValidLocationAbove(dest, 2);
|
||||
}
|
||||
this.target = Util.getCenterLocation(dest.getBlock());
|
||||
this.parameters = params;
|
||||
target = Util.getCenterLocation(dest.getBlock());
|
||||
parameters = params;
|
||||
entity = npc.getEntity();
|
||||
this.navigator = NMS.getTargetNavigator(entity, target, params);
|
||||
navigator = NMS.getTargetNavigator(entity, target, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,17 +31,17 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
|
||||
|
||||
public MCTargetStrategy(NPC npc, org.bukkit.entity.Entity target, boolean aggro, NavigatorParameters params) {
|
||||
this.npc = npc;
|
||||
this.parameters = params;
|
||||
this.handle = npc.getEntity();
|
||||
parameters = params;
|
||||
handle = npc.getEntity();
|
||||
this.target = target;
|
||||
TargetNavigator nms = NMS.getTargetNavigator(npc.getEntity(), target, params);
|
||||
this.targetNavigator = nms != null && !params.useNewPathfinder() ? nms : new AStarTargeter();
|
||||
targetNavigator = nms != null && !params.useNewPathfinder() ? nms : new AStarTargeter();
|
||||
this.aggro = aggro;
|
||||
}
|
||||
|
||||
private boolean canAttack() {
|
||||
BoundingBox handleBB = NMS.getBoundingBox(handle), targetBB = NMS.getBoundingBox(target);
|
||||
return attackTicks <= 0 && (handleBB.maxY > targetBB.minY && handleBB.minY < targetBB.maxY)
|
||||
return attackTicks <= 0 && handleBB.maxY > targetBB.minY && handleBB.minY < targetBB.maxY
|
||||
&& distance() <= parameters.attackRange() && ((LivingEntity) handle).hasLineOfSight(target);
|
||||
}
|
||||
|
||||
@ -105,19 +105,16 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
|
||||
cancelReason = CancelReason.TARGET_DIED;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target.getWorld() != handle.getWorld()) {
|
||||
cancelReason = CancelReason.TARGET_MOVED_WORLD;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cancelReason != null)
|
||||
return true;
|
||||
|
||||
if (parameters.straightLineTargetingDistance() > 0 && !(targetNavigator instanceof StraightLineTargeter)) {
|
||||
targetNavigator = new StraightLineTargeter(targetNavigator);
|
||||
}
|
||||
|
||||
if (!aggro && distance() <= parameters.distanceMargin()) {
|
||||
stop();
|
||||
return false;
|
||||
@ -125,7 +122,6 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
|
||||
targetNavigator.setPath();
|
||||
updateCounter = 0;
|
||||
}
|
||||
|
||||
targetNavigator.update();
|
||||
|
||||
NMS.look(handle, target);
|
||||
@ -137,11 +133,9 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
|
||||
}
|
||||
attackTicks = parameters.attackDelayTicks();
|
||||
}
|
||||
|
||||
if (attackTicks > 0) {
|
||||
attackTicks--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -179,9 +173,8 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
|
||||
|
||||
private void setStrategy() {
|
||||
Location location = parameters.entityTargetLocationMapper().apply(target);
|
||||
if (location == null) {
|
||||
if (location == null)
|
||||
throw new IllegalStateException("mapper should not return null");
|
||||
}
|
||||
if (!npc.isFlyable()) {
|
||||
Block block = location.getBlock();
|
||||
while (!MinecraftBlockExaminer.canStandOn(block.getRelative(BlockFace.DOWN))) {
|
||||
@ -239,7 +232,6 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
|
||||
active = new StraightLineNavigationStrategy(npc, target, parameters);
|
||||
return;
|
||||
}
|
||||
|
||||
active = null;
|
||||
fallback.setPath();
|
||||
}
|
||||
|
@ -27,13 +27,13 @@ public class StraightLineNavigationStrategy extends AbstractPathStrategy {
|
||||
this.params = params;
|
||||
this.target = target;
|
||||
this.npc = npc;
|
||||
this.destination = params.entityTargetLocationMapper().apply(target);
|
||||
destination = params.entityTargetLocationMapper().apply(target);
|
||||
}
|
||||
|
||||
public StraightLineNavigationStrategy(NPC npc, Location dest, NavigatorParameters params) {
|
||||
super(TargetType.LOCATION);
|
||||
this.params = params;
|
||||
this.destination = dest;
|
||||
destination = dest;
|
||||
this.npc = npc;
|
||||
}
|
||||
|
||||
@ -68,7 +68,6 @@ public class StraightLineNavigationStrategy extends AbstractPathStrategy {
|
||||
if (target != null) {
|
||||
destination = params.entityTargetLocationMapper().apply(target);
|
||||
}
|
||||
|
||||
Vector destVector = currLoc.toVector().add(destination.toVector().subtract(currLoc.toVector()).normalize());
|
||||
Location destLoc = destVector.toLocation(destination.getWorld());
|
||||
if (!npc.isFlyable() && destVector.getBlockY() > currLoc.getBlockY()) {
|
||||
@ -84,7 +83,6 @@ public class StraightLineNavigationStrategy extends AbstractPathStrategy {
|
||||
destLoc = block.getLocation();
|
||||
destVector = destLoc.toVector();
|
||||
}
|
||||
|
||||
double dX = destVector.getX() - currLoc.getX();
|
||||
double dZ = destVector.getZ() - currLoc.getZ();
|
||||
double dY = destVector.getY() - currLoc.getY();
|
||||
@ -105,11 +103,9 @@ public class StraightLineNavigationStrategy extends AbstractPathStrategy {
|
||||
while (normalisedTargetYaw >= 180.0F) {
|
||||
normalisedTargetYaw -= 360.0F;
|
||||
}
|
||||
|
||||
while (normalisedTargetYaw < -180.0F) {
|
||||
normalisedTargetYaw += 360.0F;
|
||||
}
|
||||
|
||||
if (npc.getEntity().getType() != EntityType.ENDER_DRAGON) {
|
||||
NMS.setVerticalMovement(npc.getEntity(), 0.5);
|
||||
NMS.setHeadYaw(npc.getEntity(), currLoc.getYaw() + normalisedTargetYaw);
|
||||
@ -121,7 +117,7 @@ public class StraightLineNavigationStrategy extends AbstractPathStrategy {
|
||||
Vector dir = destVector.subtract(currLoc.toVector()).normalize().multiply(0.2);
|
||||
Block in = currLoc.getBlock();
|
||||
if (distance > 0 && dY >= 1 && xzDistance <= 2.75
|
||||
|| (dY >= 0.2 && MinecraftBlockExaminer.isLiquidOrInLiquid(in))) {
|
||||
|| dY >= 0.2 && MinecraftBlockExaminer.isLiquidOrInLiquid(in)) {
|
||||
dir.add(new Vector(0, 0.75, 0));
|
||||
}
|
||||
Util.faceLocation(npc.getEntity(), destLoc);
|
||||
|
@ -4,14 +4,6 @@ package net.citizensnpcs.npc.profile;
|
||||
* The result status of a profile fetch.
|
||||
*/
|
||||
public enum ProfileFetchResult {
|
||||
/**
|
||||
* The profile has not been fetched yet.
|
||||
*/
|
||||
PENDING,
|
||||
/**
|
||||
* The profile was successfully fetched.
|
||||
*/
|
||||
SUCCESS,
|
||||
/**
|
||||
* The profile request failed for unknown reasons.
|
||||
*/
|
||||
@ -20,6 +12,14 @@ public enum ProfileFetchResult {
|
||||
* The profile request failed because the profile was not found.
|
||||
*/
|
||||
NOT_FOUND,
|
||||
/**
|
||||
* The profile has not been fetched yet.
|
||||
*/
|
||||
PENDING,
|
||||
/**
|
||||
* The profile was successfully fetched.
|
||||
*/
|
||||
SUCCESS,
|
||||
/**
|
||||
* The profile request failed because too many requests were sent.
|
||||
*/
|
||||
|
@ -31,8 +31,8 @@ import net.citizensnpcs.util.NMS;
|
||||
* @see ProfileFetcher
|
||||
*/
|
||||
class ProfileFetchThread implements Runnable {
|
||||
private final Deque<ProfileRequest> queue = new ArrayDeque<ProfileRequest>();
|
||||
private final Map<String, ProfileRequest> requested = new HashMap<String, ProfileRequest>(40);
|
||||
private final Deque<ProfileRequest> queue = new ArrayDeque<>();
|
||||
private final Map<String, ProfileRequest> requested = new HashMap<>(40);
|
||||
private final Object sync = new Object(); // sync for queue & requested fields
|
||||
|
||||
ProfileFetchThread() {
|
||||
@ -65,7 +65,6 @@ class ProfileFetchThread implements Runnable {
|
||||
queue.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
if (handler != null) {
|
||||
if (request.getResult() == ProfileFetchResult.PENDING
|
||||
|| request.getResult() == ProfileFetchResult.TOO_MANY_REQUESTS) {
|
||||
@ -100,7 +99,6 @@ class ProfileFetchThread implements Runnable {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (handler != null) {
|
||||
if (request.getResult() == ProfileFetchResult.PENDING
|
||||
|| request.getResult() == ProfileFetchResult.TOO_MANY_REQUESTS) {
|
||||
@ -117,7 +115,7 @@ class ProfileFetchThread implements Runnable {
|
||||
* @param requests
|
||||
* The profile requests.
|
||||
*/
|
||||
private void fetchRequests(final Collection<ProfileRequest> requests) {
|
||||
private void fetchRequests(Collection<ProfileRequest> requests) {
|
||||
Preconditions.checkNotNull(requests);
|
||||
|
||||
String[] playerNames = new String[requests.size()];
|
||||
@ -126,7 +124,6 @@ class ProfileFetchThread implements Runnable {
|
||||
for (ProfileRequest request : requests) {
|
||||
playerNames[i++] = request.getPlayerName();
|
||||
}
|
||||
|
||||
NMS.findProfilesByNames(playerNames, new ProfileLookupCallback() {
|
||||
@SuppressWarnings("unused")
|
||||
public void onProfileLookupFailed(GameProfile profile, Exception e) {
|
||||
@ -139,7 +136,6 @@ class ProfileFetchThread implements Runnable {
|
||||
Messaging.debug("Profile lookup for player '" + profileName + "' failed: " + getExceptionMsg(e));
|
||||
Messaging.debug(Throwables.getStackTraceAsString(e));
|
||||
}
|
||||
|
||||
ProfileRequest request = findRequest(profileName, requests);
|
||||
if (request == null)
|
||||
return;
|
||||
@ -154,7 +150,7 @@ class ProfileFetchThread implements Runnable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProfileLookupSucceeded(final GameProfile profile) {
|
||||
public void onProfileLookupSucceeded(GameProfile profile) {
|
||||
Messaging.idebug(() -> "Fetched profile " + profile.getId() + " for player " + profile.getName());
|
||||
|
||||
ProfileRequest request = findRequest(profile.getName(), requests);
|
||||
@ -169,7 +165,6 @@ class ProfileFetchThread implements Runnable {
|
||||
+ getExceptionMsg(e) + " " + isTooManyRequests(e));
|
||||
Messaging.debug(Throwables.getStackTraceAsString(e));
|
||||
}
|
||||
|
||||
if (isTooManyRequests(e)) {
|
||||
request.setResult(null, ProfileFetchResult.TOO_MANY_REQUESTS);
|
||||
} else {
|
||||
@ -188,10 +183,9 @@ class ProfileFetchThread implements Runnable {
|
||||
if (queue.isEmpty())
|
||||
return;
|
||||
|
||||
requests = new ArrayList<ProfileRequest>(queue);
|
||||
requests = new ArrayList<>(queue);
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
try {
|
||||
fetchRequests(requests);
|
||||
} catch (Exception ex) {
|
||||
@ -202,7 +196,7 @@ class ProfileFetchThread implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private static void addHandler(final ProfileRequest request, final ProfileFetchHandler handler) {
|
||||
private static void addHandler(ProfileRequest request, ProfileFetchHandler handler) {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> request.addHandler(handler), 1);
|
||||
}
|
||||
|
||||
@ -211,9 +205,8 @@ class ProfileFetchThread implements Runnable {
|
||||
name = name.toLowerCase();
|
||||
|
||||
for (ProfileRequest request : requests) {
|
||||
if (request.getPlayerName().equals(name)) {
|
||||
if (request.getPlayerName().equals(name))
|
||||
return request;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -226,19 +219,18 @@ class ProfileFetchThread implements Runnable {
|
||||
String message = e.getMessage();
|
||||
String cause = e.getCause() != null ? e.getCause().getMessage() : null;
|
||||
|
||||
return (message != null && message.contains("did not find"))
|
||||
|| (cause != null && cause.contains("did not find"));
|
||||
return message != null && message.contains("did not find") || cause != null && cause.contains("did not find");
|
||||
}
|
||||
|
||||
private static boolean isTooManyRequests(Throwable e) {
|
||||
String message = e.getMessage();
|
||||
String cause = e.getCause() != null ? e.getCause().getMessage() : null;
|
||||
|
||||
return (message != null && message.contains("too many requests"))
|
||||
|| (cause != null && cause.contains("too many requests"));
|
||||
return message != null && message.contains("too many requests")
|
||||
|| cause != null && cause.contains("too many requests");
|
||||
}
|
||||
|
||||
private static void sendResult(final ProfileFetchHandler handler, final ProfileRequest request) {
|
||||
private static void sendResult(ProfileFetchHandler handler, ProfileRequest request) {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> handler.onResult(request), 1);
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,6 @@ public class ProfileFetcher {
|
||||
if (THREAD_TASK != null) {
|
||||
THREAD_TASK.cancel();
|
||||
}
|
||||
|
||||
PROFILE_THREAD = new ProfileFetchThread();
|
||||
THREAD_TASK = Bukkit.getScheduler().runTaskTimerAsynchronously(CitizensAPI.getPlugin(), PROFILE_THREAD, 21, 20);
|
||||
}
|
||||
|
@ -61,10 +61,9 @@ public class ProfileRequest {
|
||||
handler.onResult(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (handlers == null)
|
||||
handlers = new ArrayDeque<ProfileFetchHandler>();
|
||||
|
||||
if (handlers == null) {
|
||||
handlers = new ArrayDeque<>();
|
||||
}
|
||||
handlers.addLast(handler);
|
||||
}
|
||||
|
||||
@ -105,24 +104,20 @@ public class ProfileRequest {
|
||||
* @param result
|
||||
* The result of the request.
|
||||
*/
|
||||
void setResult(final @Nullable GameProfile profile, final ProfileFetchResult result) {
|
||||
void setResult(@Nullable GameProfile profile, ProfileFetchResult result) {
|
||||
if (!CitizensAPI.hasImplementation())
|
||||
return;
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ProfileRequest.this.profile = profile;
|
||||
ProfileRequest.this.result = result;
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
||||
ProfileRequest.this.profile = profile;
|
||||
ProfileRequest.this.result = result;
|
||||
|
||||
if (handlers == null)
|
||||
return;
|
||||
if (handlers == null)
|
||||
return;
|
||||
|
||||
while (!handlers.isEmpty()) {
|
||||
handlers.removeFirst().onResult(ProfileRequest.this);
|
||||
}
|
||||
|
||||
handlers = null;
|
||||
while (!handlers.isEmpty()) {
|
||||
handlers.removeFirst().onResult(ProfileRequest.this);
|
||||
}
|
||||
handlers = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,7 @@ import net.citizensnpcs.api.event.DespawnReason;
|
||||
import net.citizensnpcs.api.event.SpawnReason;
|
||||
import net.citizensnpcs.api.npc.NPC;
|
||||
import net.citizensnpcs.api.util.Messaging;
|
||||
import net.citizensnpcs.npc.profile.ProfileFetchHandler;
|
||||
import net.citizensnpcs.npc.profile.ProfileFetcher;
|
||||
import net.citizensnpcs.npc.profile.ProfileRequest;
|
||||
import net.citizensnpcs.trait.SkinTrait;
|
||||
import net.citizensnpcs.util.SkinProperty;
|
||||
|
||||
@ -36,7 +34,7 @@ public class Skin {
|
||||
private int fetchRetries = -1;
|
||||
private boolean hasFetched;
|
||||
private volatile boolean isValid = true;
|
||||
private final Map<SkinnableEntity, Void> pending = new WeakHashMap<SkinnableEntity, Void>(15);
|
||||
private final Map<SkinnableEntity, Void> pending = new WeakHashMap<>(15);
|
||||
private BukkitTask retryTask;
|
||||
private volatile SkinProperty skinData;
|
||||
private volatile UUID skinId;
|
||||
@ -58,7 +56,6 @@ public class Skin {
|
||||
|
||||
CACHE.put(this.skinName, this);
|
||||
}
|
||||
|
||||
// fetch();
|
||||
}
|
||||
|
||||
@ -84,29 +81,27 @@ public class Skin {
|
||||
// If npc requires latest skin, cache is used for faster availability until the latest skin can be loaded.
|
||||
String cachedName = npc.data().get(CACHED_SKIN_UUID_NAME_METADATA);
|
||||
String texture = skinTrait.getTexture();
|
||||
if (this.skinName.equals(cachedName) && texture != null && !texture.equals("cache")) {
|
||||
if (skinName.equals(cachedName) && texture != null && !texture.equals("cache")) {
|
||||
setNPCTexture(entity, new SkinProperty("textures", texture, skinTrait.getSignature()));
|
||||
|
||||
// check if NPC prefers to use cached skin over the latest skin.
|
||||
if (entity.getNPC().data().has("player-skin-use-latest")) {
|
||||
entity.getNPC().data().remove("player-skin-use-latest");
|
||||
}
|
||||
if (!skinTrait.shouldUpdateSkins()) {
|
||||
if (!skinTrait.shouldUpdateSkins())
|
||||
// cache preferred
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasSkinData()) {
|
||||
String defaultSkinName = ChatColor.stripColor(npc.getName()).toLowerCase();
|
||||
|
||||
if (npc.hasTrait(SkinTrait.class) && this.skinName.equals(defaultSkinName)
|
||||
if (npc.hasTrait(SkinTrait.class) && skinName.equals(defaultSkinName)
|
||||
&& !npc.getOrAddTrait(SkinTrait.class).fetchDefaultSkin())
|
||||
return false;
|
||||
|
||||
if (hasFetched) {
|
||||
if (hasFetched)
|
||||
return true;
|
||||
} else {
|
||||
else {
|
||||
if (!fetching) {
|
||||
fetch();
|
||||
}
|
||||
@ -114,7 +109,6 @@ public class Skin {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
setNPCSkinData(entity, skinName, skinId, skinData);
|
||||
|
||||
return true;
|
||||
@ -144,64 +138,54 @@ public class Skin {
|
||||
}
|
||||
|
||||
private void fetch() {
|
||||
final int maxRetries = Setting.MAX_NPC_SKIN_RETRIES.asInt();
|
||||
int maxRetries = Setting.MAX_NPC_SKIN_RETRIES.asInt();
|
||||
if (maxRetries > -1 && fetchRetries >= maxRetries) {
|
||||
if (Messaging.isDebugging()) {
|
||||
Messaging.debug("Reached max skin fetch retries for '" + skinName + "'");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (skinName.length() < 3 || skinName.length() > 16) {
|
||||
if (Messaging.isDebugging()) {
|
||||
Messaging.debug("Skin name invalid length '" + skinName + "'");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (skinName.toLowerCase().startsWith("cit-")) {
|
||||
if (skinName.toLowerCase().startsWith("cit-"))
|
||||
return;
|
||||
}
|
||||
|
||||
fetching = true;
|
||||
|
||||
ProfileFetcher.fetch(this.skinName, new ProfileFetchHandler() {
|
||||
@Override
|
||||
public void onResult(ProfileRequest request) {
|
||||
hasFetched = true;
|
||||
ProfileFetcher.fetch(skinName, request -> {
|
||||
hasFetched = true;
|
||||
|
||||
switch (request.getResult()) {
|
||||
case NOT_FOUND:
|
||||
isValid = false;
|
||||
switch (request.getResult()) {
|
||||
case NOT_FOUND:
|
||||
isValid = false;
|
||||
break;
|
||||
case TOO_MANY_REQUESTS:
|
||||
if (maxRetries == 0) {
|
||||
break;
|
||||
case TOO_MANY_REQUESTS:
|
||||
if (maxRetries == 0) {
|
||||
break;
|
||||
}
|
||||
fetchRetries++;
|
||||
long delay = Setting.NPC_SKIN_RETRY_DELAY.asTicks();
|
||||
retryTask = Bukkit.getScheduler().runTaskLater(CitizensAPI.getPlugin(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fetch();
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
fetchRetries++;
|
||||
long delay = Setting.NPC_SKIN_RETRY_DELAY.asTicks();
|
||||
retryTask = Bukkit.getScheduler().runTaskLater(CitizensAPI.getPlugin(), (Runnable) this::fetch,
|
||||
delay);
|
||||
|
||||
Messaging.idebug(() -> "Retrying skin fetch for '" + skinName + "' in " + delay + " ticks.");
|
||||
break;
|
||||
case SUCCESS:
|
||||
GameProfile profile = request.getProfile();
|
||||
setData(profile);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Messaging.idebug(() -> "Retrying skin fetch for '" + skinName + "' in " + delay + " ticks.");
|
||||
break;
|
||||
case SUCCESS:
|
||||
GameProfile profile = request.getProfile();
|
||||
setData(profile);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fetchForced() {
|
||||
final int maxRetries = Setting.MAX_NPC_SKIN_RETRIES.asInt();
|
||||
int maxRetries = Setting.MAX_NPC_SKIN_RETRIES.asInt();
|
||||
if (maxRetries > -1 && fetchRetries >= maxRetries) {
|
||||
Messaging.idebug(() -> "Reached max skin fetch retries for '" + skinName + "'");
|
||||
return;
|
||||
@ -210,44 +194,35 @@ public class Skin {
|
||||
Messaging.idebug(() -> "Skin name invalid length '" + skinName + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
if (skinName.toLowerCase().startsWith("cit-")) {
|
||||
if (skinName.toLowerCase().startsWith("cit-"))
|
||||
return;
|
||||
}
|
||||
|
||||
fetching = true;
|
||||
|
||||
ProfileFetcher.fetchForced(this.skinName, new ProfileFetchHandler() {
|
||||
@Override
|
||||
public void onResult(ProfileRequest request) {
|
||||
hasFetched = true;
|
||||
ProfileFetcher.fetchForced(skinName, request -> {
|
||||
hasFetched = true;
|
||||
|
||||
switch (request.getResult()) {
|
||||
case NOT_FOUND:
|
||||
isValid = false;
|
||||
switch (request.getResult()) {
|
||||
case NOT_FOUND:
|
||||
isValid = false;
|
||||
break;
|
||||
case TOO_MANY_REQUESTS:
|
||||
if (maxRetries == 0) {
|
||||
break;
|
||||
case TOO_MANY_REQUESTS:
|
||||
if (maxRetries == 0) {
|
||||
break;
|
||||
}
|
||||
fetchRetries++;
|
||||
int delay = Setting.NPC_SKIN_RETRY_DELAY.asTicks();
|
||||
retryTask = Bukkit.getScheduler().runTaskLater(CitizensAPI.getPlugin(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fetchForced();
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
fetchRetries++;
|
||||
int delay = Setting.NPC_SKIN_RETRY_DELAY.asTicks();
|
||||
retryTask = Bukkit.getScheduler().runTaskLater(CitizensAPI.getPlugin(),
|
||||
(Runnable) this::fetchForced, delay);
|
||||
|
||||
Messaging.idebug(() -> "Retrying skin fetch for '" + skinName + "' in " + delay + " ticks.");
|
||||
break;
|
||||
case SUCCESS:
|
||||
GameProfile profile = request.getProfile();
|
||||
setData(profile);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Messaging.idebug(() -> "Retrying skin fetch for '" + skinName + "' in " + delay + " ticks.");
|
||||
break;
|
||||
case SUCCESS:
|
||||
GameProfile profile = request.getProfile();
|
||||
setData(profile);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -288,16 +263,14 @@ public class Skin {
|
||||
isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!profile.getName().toLowerCase().equals(skinName)) {
|
||||
Messaging.debug("GameProfile name (" + profile.getName() + ") and " + "skin name (" + skinName
|
||||
+ ") do not match. Has the user renamed recently?");
|
||||
}
|
||||
|
||||
skinId = profile.getId();
|
||||
skinData = SkinProperty.fromMojangProfile(profile);
|
||||
|
||||
List<SkinnableEntity> entities = new ArrayList<SkinnableEntity>(pending.keySet());
|
||||
List<SkinnableEntity> entities = new ArrayList<>(pending.keySet());
|
||||
for (SkinnableEntity entity : entities) {
|
||||
applyAndRespawn(entity);
|
||||
}
|
||||
@ -371,13 +344,11 @@ public class Skin {
|
||||
synchronized (CACHE) {
|
||||
skin = CACHE.get(skinName);
|
||||
}
|
||||
|
||||
if (skin == null) {
|
||||
skin = new Skin(skinName);
|
||||
} else if (forceUpdate) {
|
||||
skin.fetchForced();
|
||||
}
|
||||
|
||||
return skin;
|
||||
}
|
||||
|
||||
@ -405,14 +376,13 @@ public class Skin {
|
||||
// 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)) {
|
||||
&& current.signature.equals(skinProperty.signature))
|
||||
return;
|
||||
}
|
||||
|
||||
skinProperty.apply(profile);
|
||||
}
|
||||
|
||||
private static final Map<String, Skin> CACHE = new HashMap<String, Skin>(20);
|
||||
public static final String CACHED_SKIN_UUID_METADATA = "cached-skin-uuid";
|
||||
public static final String CACHED_SKIN_UUID_NAME_METADATA = "cached-skin-uuid-name";
|
||||
private static Map<String, Skin> CACHE = new HashMap<>(20);
|
||||
public static String CACHED_SKIN_UUID_METADATA = "cached-skin-uuid";
|
||||
public static String CACHED_SKIN_UUID_NAME_METADATA = "cached-skin-uuid-name";
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ import net.citizensnpcs.util.NMS;
|
||||
*/
|
||||
public class SkinPacketTracker {
|
||||
private final SkinnableEntity entity;
|
||||
private final Map<UUID, PlayerEntry> inProgress = new HashMap<UUID, PlayerEntry>(
|
||||
private final Map<UUID, PlayerEntry> inProgress = new HashMap<>(
|
||||
Math.max(128, Math.min(1024, Bukkit.getMaxPlayers() / 2)));
|
||||
private boolean isRemoved;
|
||||
private Skin skin;
|
||||
@ -43,7 +43,7 @@ public class SkinPacketTracker {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
this.entity = entity;
|
||||
this.skin = Skin.get(entity);
|
||||
skin = Skin.get(entity);
|
||||
|
||||
if (LISTENER == null) {
|
||||
LISTENER = new PlayerListener();
|
||||
@ -76,10 +76,7 @@ public class SkinPacketTracker {
|
||||
*/
|
||||
void notifyRemovePacketSent(UUID playerId) {
|
||||
PlayerEntry entry = inProgress.get(playerId);
|
||||
if (entry == null)
|
||||
return;
|
||||
|
||||
if (entry.removeCount == 0)
|
||||
if (entry == null || entry.removeCount == 0)
|
||||
return;
|
||||
|
||||
entry.removeCount -= 1;
|
||||
@ -94,7 +91,7 @@ public class SkinPacketTracker {
|
||||
* Notify that the NPC skin has been changed.
|
||||
*/
|
||||
public void notifySkinChange(boolean forceUpdate) {
|
||||
this.skin = Skin.get(entity, forceUpdate);
|
||||
skin = Skin.get(entity, forceUpdate);
|
||||
skin.applyAndRespawn(entity);
|
||||
}
|
||||
|
||||
@ -111,9 +108,9 @@ public class SkinPacketTracker {
|
||||
Collection<? extends Player> players = Bukkit.getOnlinePlayers();
|
||||
|
||||
for (Player player : players) {
|
||||
if (player.hasMetadata("NPC"))
|
||||
if (player.hasMetadata("NPC")) {
|
||||
continue;
|
||||
|
||||
}
|
||||
// send packet now and later to ensure removal from player list
|
||||
NMS.sendTabListRemove(player, entity.getBukkitEntity());
|
||||
TAB_LIST_REMOVER.sendPacket(player, entity);
|
||||
@ -137,7 +134,7 @@ public class SkinPacketTracker {
|
||||
}.runTaskLater(CitizensAPI.getPlugin(), 15);
|
||||
}
|
||||
|
||||
private void scheduleRemovePacket(final PlayerEntry entry) {
|
||||
private void scheduleRemovePacket(PlayerEntry entry) {
|
||||
if (isRemoved || !CitizensAPI.hasImplementation() || !CitizensAPI.getPlugin().isEnabled()
|
||||
|| !shouldRemoveFromTabList())
|
||||
return;
|
||||
@ -177,7 +174,7 @@ public class SkinPacketTracker {
|
||||
* @param player
|
||||
* The player.
|
||||
*/
|
||||
public void updateViewer(final Player player) {
|
||||
public void updateViewer(Player player) {
|
||||
Preconditions.checkNotNull(player);
|
||||
|
||||
if (isRemoved || player.hasMetadata("NPC"))
|
||||
@ -189,7 +186,6 @@ public class SkinPacketTracker {
|
||||
} else {
|
||||
entry = new PlayerEntry(player);
|
||||
}
|
||||
|
||||
TAB_LIST_REMOVER.cancelPackets(player, entity);
|
||||
|
||||
inProgress.put(player.getUniqueId(), entry);
|
||||
@ -199,7 +195,7 @@ public class SkinPacketTracker {
|
||||
}
|
||||
}
|
||||
|
||||
private class PlayerEntry {
|
||||
private static class PlayerEntry {
|
||||
Player player;
|
||||
int removeCount;
|
||||
BukkitTask removeTask;
|
||||
@ -228,6 +224,6 @@ public class SkinPacketTracker {
|
||||
}
|
||||
|
||||
private static PlayerListener LISTENER;
|
||||
private static final int PACKET_DELAY_REMOVE = 2;
|
||||
private static final TabListRemover TAB_LIST_REMOVER = new TabListRemover();
|
||||
private static int PACKET_DELAY_REMOVE = 2;
|
||||
private static TabListRemover TAB_LIST_REMOVER = new TabListRemover();
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ import net.citizensnpcs.util.Util;
|
||||
* @see net.citizensnpcs.EventListen
|
||||
*/
|
||||
public class SkinUpdateTracker {
|
||||
private final Map<SkinnableEntity, Void> navigating = new WeakHashMap<SkinnableEntity, Void>(25);
|
||||
private final Map<UUID, PlayerTracker> playerTrackers = new HashMap<UUID, PlayerTracker>(
|
||||
private final Map<SkinnableEntity, Void> navigating = new WeakHashMap<>(25);
|
||||
private final Map<UUID, PlayerTracker> playerTrackers = new HashMap<>(
|
||||
Math.max(128, Math.min(1024, Bukkit.getMaxPlayers() / 2)));
|
||||
private final NPCNavigationUpdater updater = new NPCNavigationUpdater();
|
||||
|
||||
@ -57,13 +57,7 @@ public class SkinUpdateTracker {
|
||||
// skinnable entity is within the player's field of view.
|
||||
private boolean canSee(Player player, SkinnableEntity skinnable, boolean checkFov) {
|
||||
Player entity = skinnable.getBukkitEntity();
|
||||
if (entity == null)
|
||||
return false;
|
||||
|
||||
if (!player.canSee(entity))
|
||||
return false;
|
||||
|
||||
if (!player.getWorld().equals(entity.getWorld()))
|
||||
if (entity == null || !player.canSee(entity) || !player.getWorld().equals(entity.getWorld()))
|
||||
return false;
|
||||
|
||||
Location playerLoc = player.getLocation();
|
||||
@ -92,7 +86,6 @@ public class SkinUpdateTracker {
|
||||
}
|
||||
return hasMoved;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -101,17 +94,14 @@ public class SkinUpdateTracker {
|
||||
}
|
||||
|
||||
private List<SkinnableEntity> getNearbyNPCs(Player player, boolean reset, boolean checkFov) {
|
||||
List<SkinnableEntity> results = new ArrayList<SkinnableEntity>();
|
||||
List<SkinnableEntity> results = new ArrayList<>();
|
||||
PlayerTracker tracker = getTracker(player, reset);
|
||||
for (NPC npc : getAllNPCs()) {
|
||||
SkinnableEntity skinnable = getSkinnable(npc);
|
||||
if (skinnable == null)
|
||||
continue;
|
||||
|
||||
// if checking field of view, don't add skins that have already been updated for FOV
|
||||
if (checkFov && tracker.fovVisibleSkins.contains(skinnable))
|
||||
if (skinnable == null || checkFov && tracker.fovVisibleSkins.contains(skinnable)) {
|
||||
continue;
|
||||
|
||||
}
|
||||
if (canSee(player, skinnable, checkFov)) {
|
||||
results.add(skinnable);
|
||||
}
|
||||
@ -126,9 +116,9 @@ public class SkinUpdateTracker {
|
||||
for (SkinnableEntity skinnable : navigating.keySet()) {
|
||||
// make sure player hasn't already been updated to prevent excessive tab list flashing
|
||||
// while NPC's are navigating and to reduce the number of times #canSee is invoked.
|
||||
if (tracker.fovVisibleSkins.contains(skinnable))
|
||||
if (tracker.fovVisibleSkins.contains(skinnable)) {
|
||||
continue;
|
||||
|
||||
}
|
||||
if (canSee(player, skinnable, true)) {
|
||||
output.add(skinnable);
|
||||
}
|
||||
@ -231,10 +221,7 @@ public class SkinUpdateTracker {
|
||||
public void onPlayerMove(Player player) {
|
||||
Preconditions.checkNotNull(player);
|
||||
PlayerTracker updateTracker = playerTrackers.get(player.getUniqueId());
|
||||
if (updateTracker == null)
|
||||
return;
|
||||
|
||||
if (!updateTracker.shouldUpdate(player))
|
||||
if (updateTracker == null || !updateTracker.shouldUpdate(player))
|
||||
return;
|
||||
|
||||
updatePlayer(player, 10, false);
|
||||
@ -277,14 +264,13 @@ public class SkinUpdateTracker {
|
||||
Location location = entity.getLocation();
|
||||
List<Player> players = entity.getWorld().getPlayers();
|
||||
for (Player player : players) {
|
||||
if (player.hasMetadata("NPC"))
|
||||
if (player.hasMetadata("NPC")) {
|
||||
continue;
|
||||
}
|
||||
Location ploc = player.getLocation();
|
||||
if (ploc.getWorld() != location.getWorld())
|
||||
if (ploc.getWorld() != location.getWorld() || ploc.distance(location) > viewDistance) {
|
||||
continue;
|
||||
if (ploc.distance(location) > viewDistance)
|
||||
continue;
|
||||
|
||||
}
|
||||
PlayerTracker tracker = playerTrackers.get(player.getUniqueId());
|
||||
if (tracker != null) {
|
||||
tracker.hardReset(player);
|
||||
@ -302,7 +288,7 @@ public class SkinUpdateTracker {
|
||||
* @param reset
|
||||
* True to hard reset the players tracking info, otherwise false.
|
||||
*/
|
||||
public void updatePlayer(final Player player, long delay, final boolean reset) {
|
||||
public void updatePlayer(Player player, long delay, boolean reset) {
|
||||
if (player.hasMetadata("NPC"))
|
||||
return;
|
||||
|
||||
@ -328,13 +314,13 @@ public class SkinUpdateTracker {
|
||||
if (navigating.isEmpty() || playerTrackers.isEmpty())
|
||||
return;
|
||||
|
||||
List<SkinnableEntity> nearby = new ArrayList<SkinnableEntity>(10);
|
||||
List<SkinnableEntity> nearby = new ArrayList<>(10);
|
||||
Set<UUID> seen = Sets.newHashSet();
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
seen.add(player.getUniqueId());
|
||||
if (player.hasMetadata("NPC"))
|
||||
if (player.hasMetadata("NPC")) {
|
||||
continue;
|
||||
|
||||
}
|
||||
getNewVisibleNavigating(player, nearby);
|
||||
|
||||
for (SkinnableEntity skinnable : nearby) {
|
||||
@ -342,7 +328,6 @@ public class SkinUpdateTracker {
|
||||
tracker.fovVisibleSkins.add(skinnable);
|
||||
updater.queue.offer(new UpdateInfo(player, skinnable));
|
||||
}
|
||||
|
||||
nearby.clear();
|
||||
}
|
||||
playerTrackers.keySet().removeIf(uuid -> !seen.contains(uuid));
|
||||
@ -351,8 +336,8 @@ public class SkinUpdateTracker {
|
||||
|
||||
// Updates players. Repeating task used to schedule updates without
|
||||
// causing excessive scheduling.
|
||||
private class NPCNavigationUpdater extends BukkitRunnable {
|
||||
Queue<UpdateInfo> queue = new ArrayDeque<UpdateInfo>(20);
|
||||
private static class NPCNavigationUpdater extends BukkitRunnable {
|
||||
Queue<UpdateInfo> queue = new ArrayDeque<>(20);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@ -365,10 +350,10 @@ public class SkinUpdateTracker {
|
||||
|
||||
// Tracks player location and yaw to determine when the player should be updated
|
||||
// with nearby skins.
|
||||
private class PlayerTracker {
|
||||
final Set<SkinnableEntity> fovVisibleSkins = new HashSet<SkinnableEntity>(10);
|
||||
private static class PlayerTracker {
|
||||
Set<SkinnableEntity> fovVisibleSkins = new HashSet<>(10);
|
||||
boolean hasMoved;
|
||||
final Location location = new Location(null, 0, 0, 0);
|
||||
Location location = new Location(null, 0, 0, 0);
|
||||
float lowerBound;
|
||||
int rotationCount;
|
||||
float startYaw;
|
||||
@ -380,22 +365,22 @@ public class SkinUpdateTracker {
|
||||
|
||||
// reset all
|
||||
void hardReset(Player player) {
|
||||
this.hasMoved = false;
|
||||
this.rotationCount = 0;
|
||||
this.lowerBound = this.upperBound = this.startYaw = 0;
|
||||
this.fovVisibleSkins.clear();
|
||||
hasMoved = false;
|
||||
rotationCount = 0;
|
||||
lowerBound = upperBound = startYaw = 0;
|
||||
fovVisibleSkins.clear();
|
||||
reset(player);
|
||||
}
|
||||
|
||||
// resets initial yaw and location to the players current location and yaw.
|
||||
void reset(Player player) {
|
||||
player.getLocation(this.location);
|
||||
player.getLocation(location);
|
||||
if (rotationCount < 3) {
|
||||
float rotationDegrees = Setting.NPC_SKIN_ROTATION_UPDATE_DEGREES.asFloat();
|
||||
float yaw = Util.clamp(this.location.getYaw());
|
||||
this.startYaw = yaw;
|
||||
this.upperBound = Util.clamp(yaw + rotationDegrees);
|
||||
this.lowerBound = Util.clamp(yaw - rotationDegrees);
|
||||
float yaw = Util.clamp(location.getYaw());
|
||||
startYaw = yaw;
|
||||
upperBound = Util.clamp(yaw + rotationDegrees);
|
||||
lowerBound = Util.clamp(yaw - rotationDegrees);
|
||||
if (upperBound == -180.0 && startYaw > 0) {
|
||||
upperBound = 0;
|
||||
}
|
||||
@ -406,16 +391,14 @@ public class SkinUpdateTracker {
|
||||
Location currentLoc = player.getLocation();
|
||||
|
||||
// make sure player is in same world
|
||||
if (!currentLoc.getWorld().equals(this.location.getWorld())) {
|
||||
if (!currentLoc.getWorld().equals(location.getWorld())) {
|
||||
hardReset(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!hasMoved) {
|
||||
hasMoved = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rotationCount < 3) {
|
||||
float yaw = Util.clamp(currentLoc.getYaw());
|
||||
boolean hasRotated;
|
||||
@ -424,7 +407,6 @@ public class SkinUpdateTracker {
|
||||
} else {
|
||||
hasRotated = yaw < lowerBound || yaw > upperBound;
|
||||
}
|
||||
|
||||
// update the first 3 times the player rotates. helps load skins around player
|
||||
// after the player logs/teleports.
|
||||
if (hasRotated) {
|
||||
@ -433,14 +415,12 @@ public class SkinUpdateTracker {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// update every time a player moves a certain distance
|
||||
if (currentLoc.distance(this.location) > MOVEMENT_SKIN_UPDATE_DISTANCE) {
|
||||
if (currentLoc.distance(location) > MOVEMENT_SKIN_UPDATE_DISTANCE) {
|
||||
reset(player);
|
||||
return true;
|
||||
} else {
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,6 +434,6 @@ public class SkinUpdateTracker {
|
||||
}
|
||||
}
|
||||
|
||||
private static final float FIELD_OF_VIEW = 70F;
|
||||
private static final int MOVEMENT_SKIN_UPDATE_DISTANCE = 25;
|
||||
private static float FIELD_OF_VIEW = 70F;
|
||||
private static int MOVEMENT_SKIN_UPDATE_DISTANCE = 25;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ import net.citizensnpcs.util.NMS;
|
||||
* </p>
|
||||
*/
|
||||
public class TabListRemover {
|
||||
private final Map<UUID, PlayerEntry> pending = new HashMap<UUID, PlayerEntry>(
|
||||
private final Map<UUID, PlayerEntry> pending = new HashMap<>(
|
||||
Math.max(128, Math.min(1024, Bukkit.getMaxPlayers() / 2)));
|
||||
|
||||
TabListRemover() {
|
||||
@ -70,7 +70,6 @@ public class TabListRemover {
|
||||
if (entry.toRemove.remove(skinnable)) {
|
||||
skinnable.getSkinTracker().notifyRemovePacketCancelled(player.getUniqueId());
|
||||
}
|
||||
|
||||
if (entry.toRemove.isEmpty()) {
|
||||
pending.remove(player.getUniqueId());
|
||||
}
|
||||
@ -82,7 +81,6 @@ public class TabListRemover {
|
||||
entry = new PlayerEntry(player);
|
||||
pending.put(player.getUniqueId(), entry);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -103,9 +101,9 @@ public class TabListRemover {
|
||||
entry.toRemove.add(entity);
|
||||
}
|
||||
|
||||
private class PlayerEntry {
|
||||
private static class PlayerEntry {
|
||||
Player player;
|
||||
Set<SkinnableEntity> toRemove = new HashSet<SkinnableEntity>(20);
|
||||
Set<SkinnableEntity> toRemove = new HashSet<>(20);
|
||||
|
||||
PlayerEntry(Player player) {
|
||||
this.player = player;
|
||||
@ -125,30 +123,27 @@ public class TabListRemover {
|
||||
int listSize = Math.min(maxPacketEntries, entry.toRemove.size());
|
||||
boolean sendAll = listSize == entry.toRemove.size();
|
||||
|
||||
List<SkinnableEntity> skinnableList = new ArrayList<SkinnableEntity>(listSize);
|
||||
List<SkinnableEntity> skinnableList = new ArrayList<>(listSize);
|
||||
|
||||
int i = 0;
|
||||
Iterator<SkinnableEntity> skinIterator = entry.toRemove.iterator();
|
||||
while (skinIterator.hasNext()) {
|
||||
if (i >= maxPacketEntries)
|
||||
if (i >= maxPacketEntries) {
|
||||
break;
|
||||
|
||||
}
|
||||
SkinnableEntity skinnable = skinIterator.next();
|
||||
skinnableList.add(skinnable);
|
||||
|
||||
skinIterator.remove();
|
||||
i++;
|
||||
}
|
||||
|
||||
if (entry.player.isOnline()) {
|
||||
NMS.sendTabListRemove(entry.player, skinnableList);
|
||||
}
|
||||
|
||||
// notify skin trackers that a remove packet has been sent to a player
|
||||
for (SkinnableEntity entity : skinnableList) {
|
||||
entity.getSkinTracker().notifyRemovePacketSent(entry.player.getUniqueId());
|
||||
}
|
||||
|
||||
if (sendAll) {
|
||||
entryIterator.remove();
|
||||
}
|
||||
|
@ -50,13 +50,12 @@ public class Age extends Trait implements Toggleable {
|
||||
entity.setAge(age);
|
||||
entity.setAgeLock(locked);
|
||||
ageable = entity;
|
||||
} else if (npc.getEntity() instanceof Zombie) {
|
||||
((Zombie) npc.getEntity()).setBaby(age < 0);
|
||||
ageable = null;
|
||||
} else if (npc.isSpawned() && npc.getEntity().getType().name().equals("TADPOLE")) {
|
||||
((Tadpole) npc.getEntity()).setAge(age);
|
||||
ageable = null;
|
||||
} else {
|
||||
if (npc.getEntity() instanceof Zombie) {
|
||||
((Zombie) npc.getEntity()).setBaby(age < 0);
|
||||
} else if (npc.isSpawned() && npc.getEntity().getType().name().equals("TADPOLE")) {
|
||||
((Tadpole) npc.getEntity()).setAge(age);
|
||||
}
|
||||
ageable = null;
|
||||
}
|
||||
}
|
||||
@ -78,7 +77,6 @@ public class Age extends Trait implements Toggleable {
|
||||
if (isAgeable()) {
|
||||
ageable.setAgeLock(locked);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,7 +21,7 @@ import net.citizensnpcs.util.Messages;
|
||||
*/
|
||||
@TraitName("anchors")
|
||||
public class Anchors extends Trait {
|
||||
private final List<Anchor> anchors = new ArrayList<Anchor>();
|
||||
private final List<Anchor> anchors = new ArrayList<>();
|
||||
|
||||
public Anchors() {
|
||||
super("anchors");
|
||||
@ -61,8 +61,8 @@ public class Anchors extends Trait {
|
||||
String[] parts = sub.getString("").split(";");
|
||||
Location location;
|
||||
try {
|
||||
location = new Location(Bukkit.getServer().getWorld(parts[1]), Double.valueOf(parts[2]),
|
||||
Double.valueOf(parts[3]), Double.valueOf(parts[4]));
|
||||
location = new Location(Bukkit.getServer().getWorld(parts[1]), Double.parseDouble(parts[2]),
|
||||
Double.parseDouble(parts[3]), Double.parseDouble(parts[4]));
|
||||
anchors.add(new Anchor(parts[0], location));
|
||||
} catch (NumberFormatException e) {
|
||||
Messaging.logTr(Messages.SKIPPING_INVALID_ANCHOR, sub.name(), e.getMessage());
|
||||
@ -85,8 +85,9 @@ public class Anchors extends Trait {
|
||||
@Override
|
||||
public void save(DataKey key) {
|
||||
key.removeKey("list");
|
||||
for (int i = 0; i < anchors.size(); i++)
|
||||
for (int i = 0; i < anchors.size(); i++) {
|
||||
key.setString("list." + String.valueOf(i), anchors.get(i).stringValue());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -158,14 +158,14 @@ public class ArmorStandTrait extends Trait {
|
||||
* @see ArmorStand#setArms(boolean)
|
||||
*/
|
||||
public void setHasArms(boolean arms) {
|
||||
this.hasarms = arms;
|
||||
hasarms = arms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ArmorStand#setBasePlate(boolean)
|
||||
*/
|
||||
public void setHasBaseplate(boolean baseplate) {
|
||||
this.hasbaseplate = baseplate;
|
||||
hasbaseplate = baseplate;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,7 +67,7 @@ public class BoundingBoxTrait extends Trait implements Supplier<BoundingBox> {
|
||||
}
|
||||
|
||||
public void setBoundingBoxFunction(Function<EntityDim, BoundingBox> func) {
|
||||
this.function = func;
|
||||
function = func;
|
||||
}
|
||||
|
||||
public void setHeight(float height) {
|
||||
|
@ -25,7 +25,7 @@ public class ClickRedirectTrait extends Trait {
|
||||
|
||||
public ClickRedirectTrait(NPC npc) {
|
||||
this();
|
||||
this.redirectNPC = npc;
|
||||
redirectNPC = npc;
|
||||
if (redirectNPC != null && redirectNPC.hasTrait(PlayerFilter.class)) {
|
||||
redirectNPC.getOrAddTrait(PlayerFilter.class).addChildNPC(npc);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.citizensnpcs.trait;
|
||||
import java.time.Duration;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@ -218,13 +219,11 @@ public class CommandTrait extends Trait {
|
||||
} else {
|
||||
outputList.add(0, executionMode.toString());
|
||||
}
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
for (String item : outputList) {
|
||||
output.append(item);
|
||||
output.append(" ");
|
||||
}
|
||||
|
||||
Messaging.send(sender, output.toString().trim());
|
||||
}
|
||||
|
||||
@ -252,9 +251,9 @@ public class CommandTrait extends Trait {
|
||||
return output;
|
||||
}
|
||||
|
||||
public void dispatch(final Player player, Hand handIn) {
|
||||
final Hand hand = player.isSneaking()
|
||||
? (handIn == CommandTrait.Hand.LEFT ? CommandTrait.Hand.SHIFT_LEFT : CommandTrait.Hand.SHIFT_RIGHT)
|
||||
public void dispatch(Player player, Hand handIn) {
|
||||
Hand hand = player.isSneaking()
|
||||
? handIn == CommandTrait.Hand.LEFT ? CommandTrait.Hand.SHIFT_LEFT : CommandTrait.Hand.SHIFT_RIGHT
|
||||
: handIn;
|
||||
NPCCommandDispatchEvent event = new NPCCommandDispatchEvent(npc, player);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
@ -266,9 +265,8 @@ public class CommandTrait extends Trait {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
List<NPCCommand> commandList = Lists.newArrayList(Iterables.filter(commands.values(), command -> {
|
||||
return command.hand == hand || command.hand == Hand.BOTH;
|
||||
}));
|
||||
List<NPCCommand> commandList = Lists.newArrayList(Iterables.filter(commands.values(),
|
||||
command -> (command.hand == hand || command.hand == Hand.BOTH)));
|
||||
if (executionMode == ExecutionMode.RANDOM) {
|
||||
if (commandList.size() > 0) {
|
||||
runCommand(player, commandList.get(Util.getFastRandom().nextInt(commandList.size())));
|
||||
@ -277,7 +275,7 @@ public class CommandTrait extends Trait {
|
||||
}
|
||||
int max = -1;
|
||||
if (executionMode == ExecutionMode.SEQUENTIAL) {
|
||||
Collections.sort(commandList, (o1, o2) -> Integer.compare(o1.id, o2.id));
|
||||
Collections.sort(commandList, Comparator.comparing(o1 -> o1.id));
|
||||
max = commandList.size() > 0 ? commandList.get(commandList.size() - 1).id : -1;
|
||||
}
|
||||
if (executionMode == ExecutionMode.LINEAR) {
|
||||
@ -299,13 +297,13 @@ public class CommandTrait extends Trait {
|
||||
}
|
||||
}
|
||||
runCommand(player, command);
|
||||
if (executionMode == ExecutionMode.SEQUENTIAL || (charged != null && charged == false)) {
|
||||
if (executionMode == ExecutionMode.SEQUENTIAL || charged != null && !charged) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void runCommand(final Player player, NPCCommand command) {
|
||||
private void runCommand(Player player, NPCCommand command) {
|
||||
Runnable runnable = () -> {
|
||||
PlayerNPCCommand info = playerTracking.get(player.getUniqueId());
|
||||
if (info == null && (executionMode == ExecutionMode.SEQUENTIAL
|
||||
@ -320,14 +318,12 @@ public class CommandTrait extends Trait {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (info != null && !info.canUse(CommandTrait.this, player, command))
|
||||
return;
|
||||
|
||||
if (charged == null) {
|
||||
charge.run();
|
||||
}
|
||||
|
||||
if (temporaryPermissions.size() > 0) {
|
||||
PermissionAttachment attachment = player.addAttachment(CitizensAPI.getPlugin());
|
||||
if (attachment != null) {
|
||||
@ -434,9 +430,8 @@ public class CommandTrait extends Trait {
|
||||
|
||||
private void sendErrorMessage(Player player, CommandTraitError msg, Function<String, String> transform,
|
||||
Object... objects) {
|
||||
if (hideErrorMessages) {
|
||||
if (hideErrorMessages)
|
||||
return;
|
||||
}
|
||||
Set<CommandTraitError> sent = executionErrors.get(player.getUniqueId().toString());
|
||||
if (sent != null) {
|
||||
if (sent.contains(msg))
|
||||
@ -465,7 +460,7 @@ public class CommandTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setExecutionMode(ExecutionMode mode) {
|
||||
this.executionMode = mode;
|
||||
executionMode = mode;
|
||||
}
|
||||
|
||||
public void setExperienceCost(int experienceCost) {
|
||||
@ -477,7 +472,7 @@ public class CommandTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setHideErrorMessages(boolean hide) {
|
||||
this.hideErrorMessages = hide;
|
||||
hideErrorMessages = hide;
|
||||
}
|
||||
|
||||
public void setItemCost(List<ItemStack> itemCost, int id) {
|
||||
@ -550,7 +545,7 @@ public class CommandTrait extends Trait {
|
||||
|
||||
@Override
|
||||
public void initialise(MenuContext ctx) {
|
||||
this.inventory = ctx.getInventory();
|
||||
inventory = ctx.getInventory();
|
||||
if (id == -1) {
|
||||
for (ItemStack stack : trait.itemRequirements) {
|
||||
inventory.addItem(stack.clone());
|
||||
@ -576,10 +571,10 @@ public class CommandTrait extends Trait {
|
||||
}
|
||||
}
|
||||
if (id == -1) {
|
||||
this.trait.itemRequirements.clear();
|
||||
this.trait.itemRequirements.addAll(requirements);
|
||||
trait.itemRequirements.clear();
|
||||
trait.itemRequirements.addAll(requirements);
|
||||
} else {
|
||||
this.trait.setItemCost(requirements, id);
|
||||
trait.setItemCost(requirements, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -649,7 +644,7 @@ public class CommandTrait extends Trait {
|
||||
}
|
||||
|
||||
public NPCCommandBuilder addPerm(String permission) {
|
||||
this.perms.add(permission);
|
||||
perms.add(permission);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -697,7 +692,7 @@ public class CommandTrait extends Trait {
|
||||
}
|
||||
|
||||
public NPCCommandBuilder globalCooldown(int cooldown) {
|
||||
this.globalCooldown = cooldown;
|
||||
globalCooldown = cooldown;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -739,8 +734,8 @@ public class CommandTrait extends Trait {
|
||||
double cost = root.keyExists("cost") ? root.getDouble("cost") : -1;
|
||||
int exp = root.keyExists("experienceCost") ? root.getInt("experienceCost") : -1;
|
||||
return new NPCCommand(Integer.parseInt(root.name()), root.getString("command"),
|
||||
Hand.valueOf(root.getString("hand")), Boolean.valueOf(root.getString("player")),
|
||||
Boolean.valueOf(root.getString("op")), root.getInt("cooldown"), perms, root.getInt("n"),
|
||||
Hand.valueOf(root.getString("hand")), Boolean.parseBoolean(root.getString("player")),
|
||||
Boolean.parseBoolean(root.getString("op")), root.getInt("cooldown"), perms, root.getInt("n"),
|
||||
root.getInt("delay"), root.getInt("globalcooldown"), cost, exp, items);
|
||||
}
|
||||
|
||||
@ -848,14 +843,12 @@ public class CommandTrait extends Trait {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> diff = Sets.newHashSet(lastUsed.keySet());
|
||||
diff.removeAll(commandKeys);
|
||||
for (String key : diff) {
|
||||
lastUsed.remove(key);
|
||||
nUsed.remove(key);
|
||||
}
|
||||
|
||||
if (globalCooldowns != null) {
|
||||
diff = Sets.newHashSet(globalCooldowns.keySet());
|
||||
diff.removeAll(commandKeys);
|
||||
@ -867,7 +860,7 @@ public class CommandTrait extends Trait {
|
||||
|
||||
public static boolean requiresTracking(NPCCommand command) {
|
||||
return command.globalCooldown > 0 || command.cooldown > 0 || command.n > 0
|
||||
|| (command.perms != null && command.perms.size() > 0)
|
||||
|| command.perms != null && command.perms.size() > 0
|
||||
|| Setting.NPC_COMMAND_GLOBAL_COMMAND_COOLDOWN.asSeconds() > 0;
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,6 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
} else if (args.hasValueFlag("explicittype")) {
|
||||
explicitType = Util.matchEnum(EntityType.values(), args.getFlag("explicittype"));
|
||||
}
|
||||
|
||||
if (npc.isSpawned()) {
|
||||
loadController();
|
||||
}
|
||||
@ -90,10 +89,8 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
}
|
||||
if (!player.hasPermission(
|
||||
"citizens.npc.controllable." + npc.getEntity().getType().name().toLowerCase().replace("_", ""))
|
||||
|| !player.hasPermission("citizens.npc.controllable"))
|
||||
return;
|
||||
|
||||
if (ownerRequired && !npc.getOrAddTrait(Owner.class).isOwnedBy(player))
|
||||
|| !player.hasPermission("citizens.npc.controllable")
|
||||
|| ownerRequired && !npc.getOrAddTrait(Owner.class).isOwnedBy(player))
|
||||
return;
|
||||
|
||||
NMS.mount(npc.getEntity(), player);
|
||||
@ -146,9 +143,8 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
*/
|
||||
public boolean mount(Player toMount) {
|
||||
List<Entity> passengers = NMS.getPassengers(npc.getEntity());
|
||||
if (passengers.size() != 0) {
|
||||
if (passengers.size() != 0)
|
||||
return false;
|
||||
}
|
||||
boolean found = false;
|
||||
for (Entity passenger : passengers) {
|
||||
if (passenger != null && passenger == toMount) {
|
||||
@ -156,9 +152,8 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if (found)
|
||||
return false;
|
||||
}
|
||||
enterOrLeaveVehicle(toMount);
|
||||
return true;
|
||||
}
|
||||
@ -232,7 +227,7 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
* the explicit type
|
||||
*/
|
||||
public void setExplicitType(EntityType type) {
|
||||
this.explicitType = type;
|
||||
explicitType = type;
|
||||
}
|
||||
|
||||
private void setMountedYaw(Entity entity) {
|
||||
@ -240,9 +235,8 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
return; // EnderDragon handles this separately
|
||||
Location loc = entity.getLocation();
|
||||
Vector vel = entity.getVelocity();
|
||||
if (vel.lengthSquared() == 0) {
|
||||
if (vel.lengthSquared() == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
double tX = loc.getX() + vel.getX();
|
||||
double tZ = loc.getZ() + vel.getZ();
|
||||
@ -287,7 +281,6 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
|
||||
vel = vel.setX(dXcos * speed * speedMod).setZ(dXsin * speed * speedMod);
|
||||
}
|
||||
|
||||
vel = vel.add(new Vector(
|
||||
passenger.getVelocity().getX() * speedMod * Setting.CONTROLLABLE_GROUND_DIRECTION_MODIFIER.asDouble(),
|
||||
0D,
|
||||
@ -301,11 +294,10 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
}
|
||||
handle.setVelocity(vel);
|
||||
|
||||
if (newSpeed > oldSpeed && speed < maxSpeed) {
|
||||
return (float) Math.min(maxSpeed, (speed + ((maxSpeed - speed) / 50.0D)));
|
||||
} else {
|
||||
return (float) Math.max(0, (speed - (speed / 50.0D)));
|
||||
}
|
||||
if (newSpeed > oldSpeed && speed < maxSpeed)
|
||||
return (float) Math.min(maxSpeed, speed + (maxSpeed - speed) / 50.0D);
|
||||
else
|
||||
return (float) Math.max(0, speed - speed / 50.0D);
|
||||
}
|
||||
|
||||
public class GroundController implements MovementController {
|
||||
@ -329,13 +321,12 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
public void run(Player rider) {
|
||||
boolean onGround = NMS.isOnGround(npc.getEntity());
|
||||
float speedMod = npc.getNavigator().getDefaultParameters()
|
||||
.modifiedSpeed((onGround ? GROUND_SPEED : AIR_SPEED));
|
||||
.modifiedSpeed(onGround ? GROUND_SPEED : AIR_SPEED);
|
||||
if (!Util.isHorse(npc.getEntity().getType())) {
|
||||
// use minecraft horse physics
|
||||
speed = updateHorizontalSpeed(npc.getEntity(), rider, speed, speedMod,
|
||||
Setting.MAX_CONTROLLABLE_GROUND_SPEED.asDouble());
|
||||
}
|
||||
|
||||
boolean shouldJump = NMS.shouldJump(rider);
|
||||
if (shouldJump) {
|
||||
if (onGround && jumpTicks == 0) {
|
||||
@ -420,14 +411,12 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
npc.getEntity().setVelocity(npc.getEntity().getVelocity().setY(0.001F));
|
||||
return;
|
||||
}
|
||||
|
||||
speed = updateHorizontalSpeed(npc.getEntity(), rider, speed, 1F,
|
||||
Setting.MAX_CONTROLLABLE_FLIGHT_SPEED.asDouble());
|
||||
boolean shouldJump = NMS.shouldJump(rider);
|
||||
if (shouldJump) {
|
||||
npc.getEntity().setVelocity(npc.getEntity().getVelocity().setY(0.25F));
|
||||
}
|
||||
|
||||
npc.getEntity().setVelocity(npc.getEntity().getVelocity().multiply(new Vector(1, 0.98, 1)));
|
||||
setMountedYaw(npc.getEntity());
|
||||
}
|
||||
@ -461,7 +450,7 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<EntityType, Constructor<? extends MovementController>> CONTROLLER_TYPES = Maps
|
||||
private static Map<EntityType, Constructor<? extends MovementController>> CONTROLLER_TYPES = Maps
|
||||
.newEnumMap(EntityType.class);
|
||||
|
||||
static {
|
||||
|
@ -51,7 +51,7 @@ public class CurrentLocation extends Trait {
|
||||
}
|
||||
|
||||
public void setLocation(Location loc) {
|
||||
this.location = loc.clone();
|
||||
location = loc.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,7 +70,7 @@ public class DropsTrait extends Trait {
|
||||
|
||||
@Override
|
||||
public void initialise(MenuContext ctx) {
|
||||
this.inventory = ctx.getInventory();
|
||||
inventory = ctx.getInventory();
|
||||
int k = 0;
|
||||
for (int i = 1; i < 5; i += 2) {
|
||||
for (int j = 0; j < 9; j++) {
|
||||
@ -87,7 +87,7 @@ public class DropsTrait extends Trait {
|
||||
InventoryMenuSlot slot = ctx.getSlot(i * 9 + j);
|
||||
slot.setItemStack(new ItemStack(Util.getFallbackMaterial("BARRIER", "FIRE")),
|
||||
"Drop chance <e>" + chance + "%");
|
||||
slot.setClickHandler(new PercentageSlotHandler((pct) -> {
|
||||
slot.setClickHandler(new PercentageSlotHandler(pct -> {
|
||||
if (chances.containsKey(islot)) {
|
||||
chances.put(islot, pct / 100.0);
|
||||
}
|
||||
@ -116,12 +116,13 @@ public class DropsTrait extends Trait {
|
||||
for (int j = 0; j < 9; j++) {
|
||||
int slot = i * 9 + j;
|
||||
ItemStack stack = inventory.getItem(slot);
|
||||
if (stack == null || stack.getType() == Material.AIR)
|
||||
if (stack == null || stack.getType() == Material.AIR) {
|
||||
continue;
|
||||
}
|
||||
drops.add(new ItemDrop(stack.clone(), chances.getOrDefault(slot, 1.0)));
|
||||
}
|
||||
}
|
||||
this.trait.drops = drops;
|
||||
trait.drops = drops;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ public class FollowTrait extends Trait {
|
||||
* Sets the {@link Entity} to follow
|
||||
*/
|
||||
public void follow(Entity entity) {
|
||||
this.followingUUID = entity == null ? null : entity.getUniqueId();
|
||||
followingUUID = entity == null ? null : entity.getUniqueId();
|
||||
if (npc.getNavigator().isNavigating() && this.entity != null && npc.getNavigator().getEntityTarget() != null
|
||||
&& this.entity == npc.getNavigator().getEntityTarget().getTarget()) {
|
||||
npc.getNavigator().cancelNavigation();
|
||||
@ -112,13 +112,11 @@ public class FollowTrait extends Trait {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!npc.getNavigator().isNavigating()) {
|
||||
npc.getNavigator().setTarget(entity, false);
|
||||
if (margin > 0) {
|
||||
npc.getNavigator().getLocalParameters().distanceMargin(margin);
|
||||
}
|
||||
|
||||
} else {
|
||||
flock.run();
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class Gravity extends Trait implements Toggleable {
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.nogravity = enabled;
|
||||
nogravity = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,7 +35,6 @@ import net.citizensnpcs.api.persistence.Persist;
|
||||
import net.citizensnpcs.api.trait.Trait;
|
||||
import net.citizensnpcs.api.trait.TraitName;
|
||||
import net.citizensnpcs.api.util.DataKey;
|
||||
import net.citizensnpcs.api.util.Messaging;
|
||||
import net.citizensnpcs.api.util.Placeholders;
|
||||
import net.citizensnpcs.api.util.SpigotUtil;
|
||||
import net.citizensnpcs.util.NMS;
|
||||
@ -59,6 +58,8 @@ public class HologramTrait extends Trait {
|
||||
private final NPCRegistry registry = CitizensAPI.createCitizensBackedNPCRegistry(new MemoryNPCDataStore());
|
||||
private int t;
|
||||
private boolean useDisplayEntities = Setting.DISPLAY_ENTITY_HOLOGRAMS.asBoolean();
|
||||
@Persist
|
||||
private int viewRange = -1;
|
||||
|
||||
public HologramTrait() {
|
||||
super("hologramtrait");
|
||||
@ -109,12 +110,13 @@ public class HologramTrait extends Trait {
|
||||
hologramNPC = registry.createNPC(EntityType.ARMOR_STAND, line);
|
||||
hologramNPC.getOrAddTrait(ArmorStandTrait.class).setAsHelperEntityWithName(npc);
|
||||
}
|
||||
|
||||
if (Setting.PACKET_HOLOGRAMS.asBoolean()) {
|
||||
hologramNPC.addTrait(PacketNPC.class);
|
||||
}
|
||||
|
||||
hologramNPC.data().set(NPC.Metadata.HOLOGRAM_FOR, npc.getUniqueId().toString());
|
||||
if (viewRange != -1) {
|
||||
hologramNPC.data().set(NPC.Metadata.TRACKING_RANGE, viewRange);
|
||||
}
|
||||
hologramNPC.spawn(currentLoc.clone().add(0, getEntityHeight() + heightOffset, 0));
|
||||
|
||||
Matcher itemMatcher = ITEM_MATCHER.matcher(line);
|
||||
@ -122,7 +124,7 @@ public class HologramTrait extends Trait {
|
||||
Material item = SpigotUtil.isUsing1_13API() ? Material.matchMaterial(itemMatcher.group(1), false)
|
||||
: Material.matchMaterial(itemMatcher.group(1));
|
||||
ItemStack itemStack = new ItemStack(item, 1);
|
||||
final NPC itemNPC = registry.createNPCUsingItem(EntityType.DROPPED_ITEM, "", itemStack);
|
||||
NPC itemNPC = registry.createNPCUsingItem(EntityType.DROPPED_ITEM, "", itemStack);
|
||||
itemNPC.data().setPersistent(NPC.Metadata.NAMEPLATE_VISIBLE, false);
|
||||
if (itemMatcher.group(2) != null) {
|
||||
if (itemMatcher.group(2).charAt(1) == '{') {
|
||||
@ -135,14 +137,13 @@ public class HologramTrait extends Trait {
|
||||
}
|
||||
itemNPC.getOrAddTrait(MountTrait.class).setMountedOn(hologramNPC.getUniqueId());
|
||||
itemNPC.spawn(currentLoc);
|
||||
final NPC hn = hologramNPC;
|
||||
NPC hn = hologramNPC;
|
||||
itemNPC.addRunnable(() -> {
|
||||
if (!itemNPC.isSpawned() || !hn.isSpawned()) {
|
||||
itemNPC.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
lastEntityHeight = getEntityHeight();
|
||||
return hologramNPC;
|
||||
}
|
||||
@ -152,7 +153,7 @@ public class HologramTrait extends Trait {
|
||||
}
|
||||
|
||||
private double getHeight(int lineNumber) {
|
||||
double base = (lastNameplateVisible ? 0 : -getLineHeight());
|
||||
double base = lastNameplateVisible ? 0 : -getLineHeight();
|
||||
for (int i = 0; i <= lineNumber; i++) {
|
||||
HologramLine line = lines.get(i);
|
||||
base += line.mb + getLineHeight();
|
||||
@ -192,6 +193,17 @@ public class HologramTrait extends Trait {
|
||||
return nameLine != null && nameLine.hologram.isSpawned() ? nameLine.hologram.getEntity() : null;
|
||||
}
|
||||
|
||||
public double getViewRange() {
|
||||
return viewRange;
|
||||
}
|
||||
|
||||
public boolean isHologramSneaking(NPC hologram, Player player) {
|
||||
if (nameLine != null && hologram == nameLine.hologram && npc.getEntity() instanceof Player
|
||||
&& ((Player) npc.getEntity()).isSneaking())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(DataKey root) {
|
||||
clear();
|
||||
@ -210,7 +222,6 @@ public class HologramTrait extends Trait {
|
||||
nameLine.removeNPC();
|
||||
nameLine = null;
|
||||
}
|
||||
|
||||
for (HologramLine line : lines) {
|
||||
line.removeNPC();
|
||||
}
|
||||
@ -229,11 +240,9 @@ public class HologramTrait extends Trait {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (height == -1)
|
||||
return;
|
||||
|
||||
Messaging.debug(npc, "hologram interaction ", hologram.getEntity(), "height offset set to", height);
|
||||
NMS.linkTextInteraction(player, hologram.getEntity(), npc.getEntity(), height);
|
||||
}
|
||||
}
|
||||
@ -255,7 +264,6 @@ public class HologramTrait extends Trait {
|
||||
nameLine = new HologramLine(npc.getRawName(), false);
|
||||
nameLine.spawnNPC(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
lines.get(i).spawnNPC(getHeight(i));
|
||||
}
|
||||
@ -265,7 +273,6 @@ public class HologramTrait extends Trait {
|
||||
for (HologramLine line : lines) {
|
||||
line.removeNPC();
|
||||
}
|
||||
|
||||
if (!npc.isSpawned())
|
||||
return;
|
||||
|
||||
@ -294,11 +301,9 @@ public class HologramTrait extends Trait {
|
||||
onDespawn();
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentLoc == null) {
|
||||
currentLoc = npc.getStoredLocation().clone();
|
||||
}
|
||||
|
||||
boolean nameplateVisible = Boolean
|
||||
.parseBoolean(npc.data().<Object> get(NPC.Metadata.NAMEPLATE_VISIBLE, true).toString());
|
||||
if (npc.requiresNameHologram()) {
|
||||
@ -310,7 +315,6 @@ public class HologramTrait extends Trait {
|
||||
nameLine.spawnNPC(0);
|
||||
}
|
||||
}
|
||||
|
||||
Location npcLoc = npc.getStoredLocation();
|
||||
boolean updatePosition = Setting.HOLOGRAM_ALWAYS_UPDATE_POSITION.asBoolean()
|
||||
|| currentLoc.getWorld() != npcLoc.getWorld() || currentLoc.distance(npcLoc) >= 0.001
|
||||
@ -321,59 +325,50 @@ public class HologramTrait extends Trait {
|
||||
t = 0;
|
||||
updateName = true;
|
||||
}
|
||||
|
||||
lastNameplateVisible = nameplateVisible;
|
||||
|
||||
if (updatePosition) {
|
||||
currentLoc = npcLoc.clone();
|
||||
lastEntityHeight = getEntityHeight();
|
||||
}
|
||||
|
||||
if (nameLine != null && nameLine.hologram.isSpawned()) {
|
||||
if (updatePosition && !useDisplayEntities) {
|
||||
nameLine.hologram.teleport(npcLoc.clone().add(0, getEntityHeight(), 0), TeleportCause.PLUGIN);
|
||||
}
|
||||
|
||||
if (updateName) {
|
||||
nameLine.setText(npc.getRawName());
|
||||
}
|
||||
|
||||
if (useDisplayEntities && nameLine.hologram.getEntity().getVehicle() == null) {
|
||||
npc.getEntity().addPassenger(nameLine.hologram.getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
HologramLine line = lines.get(i);
|
||||
NPC hologramNPC = line.hologram;
|
||||
|
||||
if (hologramNPC == null || !hologramNPC.isSpawned())
|
||||
if (hologramNPC == null || !hologramNPC.isSpawned()) {
|
||||
continue;
|
||||
|
||||
}
|
||||
if (line.ticks > 0 && --line.ticks == 0) {
|
||||
line.removeNPC();
|
||||
lines.remove(i--);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (updatePosition && !useDisplayEntities) {
|
||||
Location tp = npcLoc.clone().add(0, lastEntityHeight + getHeight(i), 0);
|
||||
hologramNPC.teleport(tp, TeleportCause.PLUGIN);
|
||||
}
|
||||
|
||||
if (useDisplayEntities && hologramNPC.getEntity().getVehicle() == null) {
|
||||
npc.getEntity().addPassenger(hologramNPC.getEntity());
|
||||
}
|
||||
|
||||
String text = line.text;
|
||||
if (ITEM_MATCHER.matcher(text).matches()) {
|
||||
hologramNPC.data().set(NPC.Metadata.NAMEPLATE_VISIBLE, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!updateName)
|
||||
if (!updateName) {
|
||||
continue;
|
||||
|
||||
}
|
||||
line.setText(text);
|
||||
}
|
||||
}
|
||||
@ -383,8 +378,9 @@ public class HologramTrait extends Trait {
|
||||
root.removeKey("lines");
|
||||
int i = 0;
|
||||
for (HologramLine line : lines) {
|
||||
if (!line.persist)
|
||||
if (!line.persist) {
|
||||
continue;
|
||||
}
|
||||
root.setString("lines." + i + ".text", line.text);
|
||||
root.setDouble("lines." + i + ".margin.top", line.mt);
|
||||
root.setDouble("lines." + i + ".margin.bottom", line.mb);
|
||||
@ -405,7 +401,6 @@ public class HologramTrait extends Trait {
|
||||
addLine(text);
|
||||
return;
|
||||
}
|
||||
|
||||
HologramLine line = lines.get(idx);
|
||||
line.setText(text);
|
||||
if (line.hologram == null) {
|
||||
@ -441,7 +436,6 @@ public class HologramTrait extends Trait {
|
||||
} else if (type.equalsIgnoreCase("bottom")) {
|
||||
lines.get(idx).mb = margin;
|
||||
}
|
||||
|
||||
reloadLineHolograms();
|
||||
}
|
||||
|
||||
@ -449,11 +443,16 @@ public class HologramTrait extends Trait {
|
||||
* Implementation-specific method: {@see NPC.Metadata#HOLOGRAM_LINE_SUPPLIER}
|
||||
*/
|
||||
public void setPerPlayerTextSupplier(BiFunction<String, Player, String> nameSupplier) {
|
||||
this.customHologramSupplier = nameSupplier;
|
||||
customHologramSupplier = nameSupplier;
|
||||
}
|
||||
|
||||
public void setUseDisplayEntities(boolean use) {
|
||||
this.useDisplayEntities = use;
|
||||
useDisplayEntities = use;
|
||||
reloadLineHolograms();
|
||||
}
|
||||
|
||||
public void setViewRange(int range) {
|
||||
this.viewRange = range;
|
||||
reloadLineHolograms();
|
||||
}
|
||||
|
||||
@ -508,7 +507,7 @@ public class HologramTrait extends Trait {
|
||||
|
||||
public void spawnNPC(double height) {
|
||||
String name = Placeholders.replace(text, null, npc);
|
||||
this.hologram = createHologram(name, height);
|
||||
hologram = createHologram(name, height);
|
||||
if (customHologramSupplier != null) {
|
||||
hologram.data().set(NPC.Metadata.HOLOGRAM_LINE_SUPPLIER,
|
||||
(Function<Player, String>) p -> customHologramSupplier.apply(text, p));
|
||||
@ -529,8 +528,8 @@ public class HologramTrait extends Trait {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static final List<String> LINE_ARGS = ImmutableList.of("set", "remove", "margintop", "marginbottom");
|
||||
private static List<String> LINE_ARGS = ImmutableList.of("set", "remove", "margintop", "marginbottom");
|
||||
}
|
||||
|
||||
private static final Pattern ITEM_MATCHER = Pattern.compile("<item:(.*?)([:].*?)?>");
|
||||
private static Pattern ITEM_MATCHER = Pattern.compile("<item:(.*?)([:].*?)?>");
|
||||
}
|
||||
|
@ -125,7 +125,6 @@ public class LookClose extends Trait implements Toggleable {
|
||||
}
|
||||
sessions.clear();
|
||||
}
|
||||
|
||||
if (lookingAt != null && !isValid(lookingAt)) {
|
||||
NPCLookCloseChangeTargetEvent event = new NPCLookCloseChangeTargetEvent(npc, lookingAt, null);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
@ -135,7 +134,6 @@ public class LookClose extends Trait implements Toggleable {
|
||||
lookingAt = null;
|
||||
}
|
||||
}
|
||||
|
||||
Player old = lookingAt;
|
||||
if (lookingAt != null) {
|
||||
if (randomSwitchTargets && t <= 0) {
|
||||
@ -150,19 +148,18 @@ public class LookClose extends Trait implements Toggleable {
|
||||
Location npcLoc = npc.getStoredLocation();
|
||||
for (Player player : getNearbyPlayers()) {
|
||||
double dist = player.getLocation().distance(npcLoc);
|
||||
if (dist > min)
|
||||
if (dist > min) {
|
||||
continue;
|
||||
}
|
||||
min = dist;
|
||||
lookingAt = player;
|
||||
}
|
||||
}
|
||||
|
||||
if (old != lookingAt) {
|
||||
NPCLookCloseChangeTargetEvent event = new NPCLookCloseChangeTargetEvent(npc, old, lookingAt);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if (lookingAt != event.getNewTarget() && event.getNewTarget() != null && !isValid(event.getNewTarget())) {
|
||||
if (lookingAt != event.getNewTarget() && event.getNewTarget() != null && !isValid(event.getNewTarget()))
|
||||
return;
|
||||
}
|
||||
lookingAt = event.getNewTarget();
|
||||
}
|
||||
}
|
||||
@ -176,11 +173,12 @@ public class LookClose extends Trait implements Toggleable {
|
||||
.map(e -> (Player) e).collect(Collectors.toList())
|
||||
: CitizensAPI.getLocationLookup().getNearbyPlayers(npcLoc, range);
|
||||
for (Player player : nearby) {
|
||||
if (player == lookingAt || (!targetNPCs && CitizensAPI.getNPCRegistry().getNPC(player) != null))
|
||||
if (player == lookingAt || !targetNPCs && CitizensAPI.getNPCRegistry().getNPC(player) != null) {
|
||||
continue;
|
||||
if (player.getLocation().getWorld() != npcLoc.getWorld() || isInvisible(player))
|
||||
}
|
||||
if (player.getLocation().getWorld() != npcLoc.getWorld() || isInvisible(player)) {
|
||||
continue;
|
||||
|
||||
}
|
||||
options.add(player);
|
||||
}
|
||||
return options;
|
||||
@ -221,9 +219,8 @@ public class LookClose extends Trait implements Toggleable {
|
||||
|
||||
private boolean isPluginVanished(Player player) {
|
||||
for (MetadataValue meta : player.getMetadata("vanished")) {
|
||||
if (meta.asBoolean()) {
|
||||
if (meta.asBoolean())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -274,7 +271,6 @@ public class LookClose extends Trait implements Toggleable {
|
||||
lookingAt = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (enableRandomLook) {
|
||||
if (!npc.getNavigator().isNavigating() && lookingAt == null && t <= 0) {
|
||||
randomLook();
|
||||
@ -283,22 +279,15 @@ public class LookClose extends Trait implements Toggleable {
|
||||
}
|
||||
t--;
|
||||
|
||||
if (!enabled) {
|
||||
if (!enabled || npc.getNavigator().isNavigating() && disableWhileNavigating()) {
|
||||
lookingAt = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (npc.getNavigator().isNavigating() && disableWhileNavigating()) {
|
||||
lookingAt = null;
|
||||
return;
|
||||
}
|
||||
|
||||
findNewTarget();
|
||||
|
||||
if (npc.getNavigator().isNavigating() || npc.getNavigator().isPaused()) {
|
||||
npc.getNavigator().setPaused(lookingAt != null);
|
||||
}
|
||||
|
||||
if (lookingAt == null)
|
||||
return;
|
||||
|
||||
@ -348,15 +337,15 @@ public class LookClose extends Trait implements Toggleable {
|
||||
* Sets the delay between random looking in ticks
|
||||
*/
|
||||
public void setRandomLookDelay(int delay) {
|
||||
this.randomLookDelay = delay;
|
||||
randomLookDelay = delay;
|
||||
}
|
||||
|
||||
public void setRandomLookPitchRange(float min, float max) {
|
||||
this.randomPitchRange = new float[] { min, max };
|
||||
randomPitchRange = new float[] { min, max };
|
||||
}
|
||||
|
||||
public void setRandomLookYawRange(float min, float max) {
|
||||
this.randomYawRange = new float[] { min, max };
|
||||
randomYawRange = new float[] { min, max };
|
||||
}
|
||||
|
||||
public void setRandomlySwitchTargets(boolean randomSwitchTargets) {
|
||||
@ -374,11 +363,11 @@ public class LookClose extends Trait implements Toggleable {
|
||||
* Enables/disables realistic looking (using line of sight checks). More computationally expensive.
|
||||
*/
|
||||
public void setRealisticLooking(boolean realistic) {
|
||||
this.realisticLooking = realistic;
|
||||
realisticLooking = realistic;
|
||||
}
|
||||
|
||||
public void setTargetNPCs(boolean target) {
|
||||
this.targetNPCs = target;
|
||||
targetNPCs = target;
|
||||
}
|
||||
|
||||
public boolean targetNPCs() {
|
||||
|
@ -35,7 +35,7 @@ public class OcelotModifiers extends Trait {
|
||||
}
|
||||
|
||||
public void setSitting(boolean sit) {
|
||||
this.sitting = sit;
|
||||
sitting = sit;
|
||||
updateModifiers();
|
||||
}
|
||||
|
||||
|
@ -64,9 +64,8 @@ public class PacketNPC extends Trait {
|
||||
}
|
||||
|
||||
public EntityController wrap(EntityController controller) {
|
||||
if (!(controller instanceof PacketController)) {
|
||||
if (!(controller instanceof PacketController))
|
||||
return new PacketController(controller);
|
||||
}
|
||||
return controller;
|
||||
}
|
||||
|
||||
@ -74,7 +73,7 @@ public class PacketNPC extends Trait {
|
||||
private final EntityController base;
|
||||
|
||||
public PacketController(EntityController controller) {
|
||||
this.base = controller;
|
||||
base = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,9 +43,7 @@ public class PausePathfindingTrait extends Trait {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (playerRange == -1 || !npc.isSpawned())
|
||||
return;
|
||||
if (unpauseTaskId == -1 && !npc.getNavigator().isNavigating())
|
||||
if (playerRange == -1 || !npc.isSpawned() || unpauseTaskId == -1 && !npc.getNavigator().isNavigating())
|
||||
return;
|
||||
if (CitizensAPI.getLocationLookup().getNearbyPlayers(npc.getStoredLocation(), playerRange).iterator()
|
||||
.hasNext()) {
|
||||
@ -58,7 +56,7 @@ public class PausePathfindingTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setPlayerRangeBlocks(double range) {
|
||||
this.playerRange = range;
|
||||
playerRange = range;
|
||||
}
|
||||
|
||||
public void setRightClick(boolean rightclick) {
|
||||
|
@ -93,10 +93,8 @@ public class Poses extends Trait {
|
||||
paginator.addLine(line);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!paginator.sendPage(sender, page)) {
|
||||
if (!paginator.sendPage(sender, page))
|
||||
throw new CommandException(Messages.COMMAND_PAGE_MISSING, page);
|
||||
}
|
||||
}
|
||||
|
||||
public Pose getPose(String name) {
|
||||
@ -115,7 +113,8 @@ public class Poses extends Trait {
|
||||
for (DataKey sub : key.getRelative("list").getIntegerSubKeys()) {
|
||||
try {
|
||||
String[] parts = sub.getString("").split(";");
|
||||
poses.put(parts[0].toLowerCase(), new Pose(parts[0], Float.valueOf(parts[1]), Float.valueOf(parts[2])));
|
||||
poses.put(parts[0].toLowerCase(),
|
||||
new Pose(parts[0], Float.parseFloat(parts[1]), Float.parseFloat(parts[2])));
|
||||
} catch (NumberFormatException e) {
|
||||
Messaging.logTr(Messages.SKIPPING_INVALID_POSE, sub.name(), e.getMessage());
|
||||
}
|
||||
@ -149,6 +148,6 @@ public class Poses extends Trait {
|
||||
}
|
||||
|
||||
public void setDefaultPose(String pose) {
|
||||
this.defaultPose = pose;
|
||||
defaultPose = pose;
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,10 @@ public class Powered extends Trait implements Toggleable {
|
||||
super("powered");
|
||||
}
|
||||
|
||||
public boolean isPowered() {
|
||||
return powered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpawn() {
|
||||
if (npc.getEntity() instanceof Creeper) {
|
||||
@ -27,10 +31,6 @@ public class Powered extends Trait implements Toggleable {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPowered() {
|
||||
return powered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean toggle() {
|
||||
powered = !powered;
|
||||
|
@ -60,7 +60,6 @@ public class RotationTrait extends Trait {
|
||||
} else {
|
||||
packetSessions.add(lrs);
|
||||
}
|
||||
|
||||
return lrs;
|
||||
}
|
||||
|
||||
@ -82,11 +81,9 @@ public class RotationTrait extends Trait {
|
||||
return lrs;
|
||||
|
||||
for (PacketRotationSession session : packetSessions) {
|
||||
if (session.accepts(player) && session.triple != null) {
|
||||
if (session.accepts(player) && session.triple != null)
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -102,31 +99,28 @@ public class RotationTrait extends Trait {
|
||||
if (npc.data().get(NPC.Metadata.RESET_PITCH_ON_TICK, false)) {
|
||||
NMS.setPitch(npc.getEntity(), 0);
|
||||
}
|
||||
|
||||
Set<PacketRotationSession> ran = Sets.newHashSet();
|
||||
for (Iterator<PacketRotationSession> itr = Iterables.concat(packetSessions, packetSessionsByUUID.values())
|
||||
.iterator(); itr.hasNext();) {
|
||||
PacketRotationSession session = itr.next();
|
||||
if (ran.contains(session))
|
||||
if (ran.contains(session)) {
|
||||
continue;
|
||||
|
||||
}
|
||||
ran.add(session);
|
||||
session.run(npc.getEntity());
|
||||
if (!session.isActive()) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (npc.getNavigator().isNavigating()) {
|
||||
if (npc.getNavigator().isNavigating())
|
||||
// npc.yHeadRot = rotateIfNecessary(npc.yHeadRot, npc.yBodyRot, 75);
|
||||
return;
|
||||
}
|
||||
|
||||
globalSession.run(new EntityRotation(npc.getEntity()));
|
||||
}
|
||||
|
||||
private static class EntityRotation extends RotationTriple {
|
||||
protected final Entity entity;
|
||||
protected Entity entity;
|
||||
|
||||
public EntityRotation(Entity entity) {
|
||||
super(NMS.getYaw(entity), NMS.getHeadYaw(entity), entity.getLocation().getPitch());
|
||||
@ -158,7 +152,7 @@ public class RotationTrait extends Trait {
|
||||
}
|
||||
|
||||
public void end() {
|
||||
this.ended = true;
|
||||
ended = true;
|
||||
}
|
||||
|
||||
public float getBodyYaw() {
|
||||
@ -193,7 +187,6 @@ public class RotationTrait extends Trait {
|
||||
if (triple == null) {
|
||||
triple = new PacketRotationTriple(entity);
|
||||
}
|
||||
|
||||
session.run(triple);
|
||||
if (!session.isActive()) {
|
||||
triple = null;
|
||||
@ -265,7 +258,7 @@ public class RotationTrait extends Trait {
|
||||
}
|
||||
|
||||
public RotationParams linkedBody(boolean linked) {
|
||||
this.linkedBody = linked;
|
||||
linkedBody = linked;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -297,12 +290,12 @@ public class RotationTrait extends Trait {
|
||||
}
|
||||
|
||||
public RotationParams maxPitchPerTick(float val) {
|
||||
this.maxPitchPerTick = val;
|
||||
maxPitchPerTick = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RotationParams maxYawPerTick(float val) {
|
||||
this.maxYawPerTick = val;
|
||||
maxYawPerTick = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -312,7 +305,7 @@ public class RotationTrait extends Trait {
|
||||
}
|
||||
|
||||
public RotationParams pitchRange(float[] val) {
|
||||
this.pitchRange = val;
|
||||
pitchRange = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -343,29 +336,24 @@ public class RotationTrait extends Trait {
|
||||
if (headOnly) {
|
||||
key.setBoolean("headOnly", headOnly);
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
key.setBoolean("immediate", immediate);
|
||||
}
|
||||
|
||||
if (maxPitchPerTick != 10) {
|
||||
key.setDouble("maxPitchPerTick", maxPitchPerTick);
|
||||
} else {
|
||||
key.removeKey("maxPitchPerTick");
|
||||
}
|
||||
|
||||
if (maxYawPerTick != 40) {
|
||||
key.setDouble("maxYawPerTick", maxYawPerTick);
|
||||
} else {
|
||||
key.removeKey("maxYawPerTick");
|
||||
}
|
||||
|
||||
if (pitchRange[0] != -180 || pitchRange[1] != 180) {
|
||||
key.setString("pitchRange", pitchRange[0] + "," + pitchRange[1]);
|
||||
} else {
|
||||
key.removeKey("pitchRange");
|
||||
}
|
||||
|
||||
if (yawRange[0] != -180 || yawRange[1] != 180) {
|
||||
key.setString("yawRange", yawRange[0] + "," + yawRange[1]);
|
||||
} else {
|
||||
@ -374,7 +362,7 @@ public class RotationTrait extends Trait {
|
||||
}
|
||||
|
||||
public RotationParams uuidFilter(List<UUID> uuids) {
|
||||
this.uuidFilter = uuids;
|
||||
uuidFilter = uuids;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -383,7 +371,7 @@ public class RotationTrait extends Trait {
|
||||
}
|
||||
|
||||
public RotationParams yawRange(float[] val) {
|
||||
this.yawRange = val;
|
||||
yawRange = val;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -489,21 +477,18 @@ public class RotationTrait extends Trait {
|
||||
rot.bodyYaw = Math.abs(body - lo) > Math.abs(body - hi) ? hi : lo;
|
||||
}
|
||||
}
|
||||
|
||||
rot.pitch = params.immediate ? getTargetPitch() : params.rotatePitchTowards(t, rot.pitch, getTargetPitch());
|
||||
t++;
|
||||
|
||||
if (params.linkedBody) {
|
||||
rot.bodyYaw = rot.headYaw;
|
||||
}
|
||||
|
||||
if (Math.abs(rot.pitch - getTargetPitch()) + Math.abs(rot.headYaw - getTargetYaw()) < 0.1) {
|
||||
t = -1;
|
||||
if (!params.headOnly) {
|
||||
rot.bodyYaw = rot.headYaw;
|
||||
}
|
||||
}
|
||||
|
||||
rot.apply();
|
||||
}
|
||||
}
|
||||
|
@ -35,18 +35,20 @@ public class ScoreboardTrait extends Trait {
|
||||
private final PerPlayerMetadata<Boolean> metadata;
|
||||
private ChatColor previousGlowingColor;
|
||||
@Persist
|
||||
private Set<String> tags = new HashSet<String>();
|
||||
private Set<String> tags = new HashSet<>();
|
||||
|
||||
public ScoreboardTrait() {
|
||||
super("scoreboardtrait");
|
||||
metadata = CitizensAPI.getLocationLookup().<Boolean> registerMetadata("scoreboard", (meta, event) -> {
|
||||
for (NPC npc : CitizensAPI.getNPCRegistry()) {
|
||||
ScoreboardTrait trait = npc.getTraitNullable(ScoreboardTrait.class);
|
||||
if (trait == null)
|
||||
if (trait == null) {
|
||||
continue;
|
||||
}
|
||||
Team team = trait.getTeam();
|
||||
if (team == null || meta.has(event.getPlayer().getUniqueId(), team.getName()))
|
||||
if (team == null || meta.has(event.getPlayer().getUniqueId(), team.getName())) {
|
||||
continue;
|
||||
}
|
||||
NMS.sendTeamPacket(event.getPlayer(), team, 0);
|
||||
meta.set(event.getPlayer().getUniqueId(), team.getName(), true);
|
||||
}
|
||||
@ -161,13 +163,11 @@ public class ScoreboardTrait extends Trait {
|
||||
npc.data().remove(NPC.Metadata.SCOREBOARD_FAKE_TEAM_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (npc.isSpawned()) {
|
||||
lastName = npc.getEntity() instanceof Player && npc.getEntity().getName() != null
|
||||
? npc.getEntity().getName()
|
||||
: npc.getUniqueId().toString();
|
||||
}
|
||||
|
||||
if (SUPPORT_TAGS) {
|
||||
try {
|
||||
if (!npc.getEntity().getScoreboardTags().equals(tags)) {
|
||||
@ -177,7 +177,6 @@ public class ScoreboardTrait extends Trait {
|
||||
SUPPORT_TAGS = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUPPORT_TEAM_SETOPTION) {
|
||||
try {
|
||||
OptionStatus visibility = nameVisibility ? OptionStatus.ALWAYS : OptionStatus.NEVER;
|
||||
@ -193,7 +192,6 @@ public class ScoreboardTrait extends Trait {
|
||||
} else {
|
||||
NMS.setTeamNameTagVisible(team, nameVisibility);
|
||||
}
|
||||
|
||||
if (SUPPORT_COLLIDABLE_SETOPTION) {
|
||||
try {
|
||||
OptionStatus collide = npc.data().<Boolean> get(NPC.Metadata.COLLIDABLE, !npc.isProtected())
|
||||
@ -209,7 +207,6 @@ public class ScoreboardTrait extends Trait {
|
||||
SUPPORT_COLLIDABLE_SETOPTION = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (color != null) {
|
||||
if (SUPPORT_GLOWING_COLOR && SpigotUtil.getMinecraftPackage().contains("1_12_R1")) {
|
||||
SUPPORT_GLOWING_COLOR = false;
|
||||
@ -217,7 +214,7 @@ public class ScoreboardTrait extends Trait {
|
||||
if (SUPPORT_GLOWING_COLOR) {
|
||||
try {
|
||||
if (team.getColor() == null || previousGlowingColor == null
|
||||
|| (previousGlowingColor != null && color != previousGlowingColor)) {
|
||||
|| previousGlowingColor != null && color != previousGlowingColor) {
|
||||
team.setColor(color);
|
||||
previousGlowingColor = color;
|
||||
changed = true;
|
||||
@ -225,22 +222,19 @@ public class ScoreboardTrait extends Trait {
|
||||
} catch (NoSuchMethodError err) {
|
||||
SUPPORT_GLOWING_COLOR = false;
|
||||
}
|
||||
} else {
|
||||
if (team.getPrefix() == null || team.getPrefix().length() == 0 || previousGlowingColor == null
|
||||
|| (previousGlowingColor != null
|
||||
&& !team.getPrefix().equals(previousGlowingColor.toString()))) {
|
||||
team.setPrefix(color.toString());
|
||||
previousGlowingColor = color;
|
||||
changed = true;
|
||||
}
|
||||
} else if (team.getPrefix() == null || team.getPrefix().length() == 0 || previousGlowingColor == null
|
||||
|| previousGlowingColor != null && !team.getPrefix().equals(previousGlowingColor.toString())) {
|
||||
team.setPrefix(color.toString());
|
||||
previousGlowingColor = color;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
return;
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (player.hasMetadata("NPC"))
|
||||
if (player.hasMetadata("NPC")) {
|
||||
continue;
|
||||
}
|
||||
if (metadata.has(player.getUniqueId(), team.getName())) {
|
||||
NMS.sendTeamPacket(player, team, 2);
|
||||
} else {
|
||||
|
@ -34,7 +34,7 @@ public class SheepTrait extends Trait {
|
||||
|
||||
@EventHandler
|
||||
private void onPlayerShearEntityEvent(PlayerShearEntityEvent event) {
|
||||
if (npc != null && npc.equals(CitizensAPI.getNPCRegistry().getNPC(event.getEntity()))) {
|
||||
if (npc != null && npc.isProtected() && npc.equals(CitizensAPI.getNPCRegistry().getNPC(event.getEntity()))) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ public class SitTrait extends Trait {
|
||||
((Sittable) npc.getEntity()).setSitting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chair != null) {
|
||||
if (chair.getEntity() != null) {
|
||||
chair.getEntity().eject();
|
||||
@ -72,7 +71,6 @@ public class SitTrait extends Trait {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (chair == null) {
|
||||
NPCRegistry registry = CitizensAPI.getNamedNPCRegistry("SitRegistry");
|
||||
if (registry == null) {
|
||||
@ -85,22 +83,19 @@ public class SitTrait extends Trait {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (chair.isSpawned() && !NMS.getPassengers(chair.getEntity()).contains(npc.getEntity())) {
|
||||
NMS.mount(chair.getEntity(), npc.getEntity());
|
||||
}
|
||||
|
||||
if (chair.getStoredLocation() != null && chair.getStoredLocation().distance(sittingAt) >= 0.03) {
|
||||
chair.teleport(sittingAt.clone(), TeleportCause.PLUGIN);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSitting(Location at) {
|
||||
this.sittingAt = at != null ? at.clone() : null;
|
||||
sittingAt = at != null ? at.clone() : null;
|
||||
if (requiresPassengerOffsetCorrection()) {
|
||||
sittingAt = sittingAt.add(0, 0.3, 0);
|
||||
}
|
||||
|
||||
if (at == null) {
|
||||
onDespawn();
|
||||
}
|
||||
|
@ -258,10 +258,10 @@ public class SkinLayers extends Trait {
|
||||
RIGHT_PANTS(5),
|
||||
RIGHT_SLEEVE(3);
|
||||
|
||||
final int flag;
|
||||
int flag;
|
||||
|
||||
Layer(int offset) {
|
||||
this.flag = 1 << offset;
|
||||
flag = 1 << offset;
|
||||
}
|
||||
|
||||
public static byte toByte(Set<Layer> flags) {
|
||||
|
@ -109,14 +109,14 @@ public class SkinTrait extends Trait {
|
||||
* @see #fetchDefaultSkin
|
||||
*/
|
||||
public void setFetchDefaultSkin(boolean fetch) {
|
||||
this.fetchDefaultSkin = fetch;
|
||||
fetchDefaultSkin = fetch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #shouldUpdateSkins()
|
||||
*/
|
||||
public void setShouldUpdateSkins(boolean update) {
|
||||
this.updateSkins = update;
|
||||
updateSkins = update;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,14 +170,14 @@ public class SkinTrait extends Trait {
|
||||
throw new IllegalArgumentException("Invalid texture data");
|
||||
|
||||
this.signature = signature;
|
||||
this.textureRaw = data;
|
||||
this.updateSkins = false;
|
||||
textureRaw = data;
|
||||
updateSkins = false;
|
||||
npc.data().setPersistent(Skin.CACHED_SKIN_UUID_NAME_METADATA, skinName.toLowerCase());
|
||||
onSkinChange(false);
|
||||
}
|
||||
|
||||
public void setTexture(String value, String signature) {
|
||||
this.textureRaw = value;
|
||||
textureRaw = value;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,6 @@ public class SleepTrait extends Trait {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (SUPPORT_BLOCKDATA == null) {
|
||||
try {
|
||||
SUPPORT_BLOCKDATA = true;
|
||||
@ -45,14 +44,13 @@ public class SleepTrait extends Trait {
|
||||
SUPPORT_BLOCKDATA = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (npc.getEntity() instanceof Player) {
|
||||
Player player = (Player) npc.getEntity();
|
||||
if (!SUPPORT_BLOCKSTATE) {
|
||||
NMS.sleep(player, true);
|
||||
} else {
|
||||
try {
|
||||
if ((SUPPORT_BLOCKDATA && at.getBlock().getBlockData() instanceof Bed)
|
||||
if (SUPPORT_BLOCKDATA && at.getBlock().getBlockData() instanceof Bed
|
||||
|| at.getBlock().getState() instanceof Bed) {
|
||||
player.sleep(at, true);
|
||||
} else {
|
||||
|
@ -39,7 +39,7 @@ public class SneakTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setSneaking(boolean sneak) {
|
||||
this.sneaking = sneak;
|
||||
sneaking = sneak;
|
||||
apply();
|
||||
}
|
||||
}
|
@ -54,7 +54,7 @@ public class WolfModifiers extends Trait {
|
||||
}
|
||||
|
||||
public void setCollarColor(DyeColor color) {
|
||||
this.collarColor = color;
|
||||
collarColor = color;
|
||||
updateModifiers();
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ public class CommandAction extends NPCShopAction {
|
||||
@Override
|
||||
public void initialise(MenuContext ctx) {
|
||||
for (int i = 0; i < 3 * 9; i++) {
|
||||
final int idx = i;
|
||||
int idx = i;
|
||||
ctx.getSlot(i).clear();
|
||||
if (i < base.commands.size()) {
|
||||
ctx.getSlot(i).setItemStack(new ItemStack(Material.FEATHER), "<f>Set command",
|
||||
@ -114,7 +114,7 @@ public class CommandAction extends NPCShopAction {
|
||||
return;
|
||||
}
|
||||
ctx.getMenu().transition(InputMenus
|
||||
.stringSetter(() -> idx < base.commands.size() ? base.commands.get(idx) : "", (res) -> {
|
||||
.stringSetter(() -> idx < base.commands.size() ? base.commands.get(idx) : "", res -> {
|
||||
if (res == null) {
|
||||
if (idx < base.commands.size()) {
|
||||
base.commands.remove(idx);
|
||||
@ -131,11 +131,11 @@ public class CommandAction extends NPCShopAction {
|
||||
}
|
||||
ctx.getSlot(3 * 9 + 3).setItemStack(new ItemStack(Util.getFallbackMaterial("COMMAND_BLOCK", "COMMAND")),
|
||||
"Run commands as server", base.server ? ChatColor.GREEN + "On" : ChatColor.RED + "OFF");
|
||||
ctx.getSlot(3 * 9 + 3).addClickHandler(InputMenus.toggler((res) -> base.server = res, base.server));
|
||||
ctx.getSlot(3 * 9 + 3).addClickHandler(InputMenus.toggler(res -> base.server = res, base.server));
|
||||
ctx.getSlot(3 * 9 + 4).setItemStack(
|
||||
new ItemStack(Util.getFallbackMaterial("COMPARATOR", "REDSTONE_COMPARATOR")), "Run commands as op",
|
||||
base.op ? ChatColor.GREEN + "On" : ChatColor.RED + "OFF");
|
||||
ctx.getSlot(3 * 9 + 4).addClickHandler(InputMenus.clickToggle((res) -> {
|
||||
ctx.getSlot(3 * 9 + 4).addClickHandler(InputMenus.clickToggle(res -> {
|
||||
base.op = res;
|
||||
return res ? ChatColor.GREEN + "On" : ChatColor.RED + "Off";
|
||||
}, base.server));
|
||||
|
@ -20,7 +20,7 @@ public class ExperienceAction extends NPCShopAction {
|
||||
}
|
||||
|
||||
public ExperienceAction(int cost) {
|
||||
this.exp = cost;
|
||||
exp = cost;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -32,6 +32,7 @@ public class ExperienceAction extends NPCShopAction {
|
||||
public int getMaxRepeats(Entity entity) {
|
||||
if (!(entity instanceof Player))
|
||||
return 0;
|
||||
|
||||
return ((Player) entity).getLevel() / exp;
|
||||
}
|
||||
|
||||
@ -39,11 +40,10 @@ public class ExperienceAction extends NPCShopAction {
|
||||
public Transaction grant(Entity entity, int repeats) {
|
||||
if (!(entity instanceof Player))
|
||||
return Transaction.fail();
|
||||
|
||||
Player player = (Player) entity;
|
||||
int amount = exp * repeats;
|
||||
return Transaction.create(() -> {
|
||||
return true;
|
||||
}, () -> {
|
||||
return Transaction.create(() -> true, () -> {
|
||||
player.setLevel(player.getLevel() + amount);
|
||||
}, () -> {
|
||||
player.setLevel(player.getLevel() - amount);
|
||||
@ -54,11 +54,10 @@ public class ExperienceAction extends NPCShopAction {
|
||||
public Transaction take(Entity entity, int repeats) {
|
||||
if (!(entity instanceof Player))
|
||||
return Transaction.fail();
|
||||
|
||||
Player player = (Player) entity;
|
||||
int amount = exp * repeats;
|
||||
return Transaction.create(() -> {
|
||||
return player.getLevel() >= amount;
|
||||
}, () -> {
|
||||
return Transaction.create(() -> (player.getLevel() >= amount), () -> {
|
||||
player.setLevel(player.getLevel() - amount);
|
||||
}, () -> {
|
||||
player.setLevel(player.getLevel() + amount);
|
||||
@ -68,12 +67,13 @@ public class ExperienceAction extends NPCShopAction {
|
||||
public static class ExperienceActionGUI implements GUI {
|
||||
@Override
|
||||
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
|
||||
final ExperienceAction action = previous == null ? new ExperienceAction() : (ExperienceAction) previous;
|
||||
ExperienceAction action = previous == null ? new ExperienceAction() : (ExperienceAction) previous;
|
||||
return InputMenus.filteredStringSetter(() -> Integer.toString(action.exp), s -> {
|
||||
try {
|
||||
int result = Integer.parseInt(s);
|
||||
if (result < 0)
|
||||
return false;
|
||||
|
||||
action.exp = result;
|
||||
} catch (NumberFormatException nfe) {
|
||||
return false;
|
||||
|
@ -56,18 +56,18 @@ public class ItemAction extends NPCShopAction {
|
||||
ItemStack[] contents = source.getContents();
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
ItemStack toMatch = contents[i];
|
||||
if (toMatch == null || toMatch.getType() == Material.AIR)
|
||||
continue;
|
||||
if (tooDamaged(toMatch))
|
||||
if (toMatch == null || toMatch.getType() == Material.AIR || tooDamaged(toMatch)) {
|
||||
continue;
|
||||
}
|
||||
toMatch = toMatch.clone();
|
||||
for (int j = 0; j < items.size(); j++) {
|
||||
if (toMatch == null)
|
||||
if (toMatch == null) {
|
||||
break;
|
||||
}
|
||||
ItemStack item = items.get(j);
|
||||
if (req.get(j) <= 0 || !matches(item, toMatch))
|
||||
if (req.get(j) <= 0 || !matches(item, toMatch)) {
|
||||
continue;
|
||||
|
||||
}
|
||||
int remaining = req.get(j);
|
||||
int taken = toMatch.getAmount() > remaining ? remaining : toMatch.getAmount();
|
||||
|
||||
@ -76,7 +76,6 @@ public class ItemAction extends NPCShopAction {
|
||||
} else {
|
||||
toMatch.setAmount(toMatch.getAmount() - taken);
|
||||
}
|
||||
|
||||
if (modify) {
|
||||
if (toMatch == null) {
|
||||
source.clear(i);
|
||||
@ -92,9 +91,8 @@ public class ItemAction extends NPCShopAction {
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
if (items.size() == 1) {
|
||||
if (items.size() == 1)
|
||||
return items.get(0).getAmount() + " " + Util.prettyEnum(items.get(0).getType());
|
||||
}
|
||||
String description = items.size() + " items";
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
ItemStack item = items.get(i);
|
||||
@ -113,24 +111,25 @@ public class ItemAction extends NPCShopAction {
|
||||
return 0;
|
||||
|
||||
Inventory source = ((InventoryHolder) entity).getInventory();
|
||||
List<Integer> req = items.stream().map(i -> i.getAmount()).collect(Collectors.toList());
|
||||
List<Integer> req = items.stream().map(ItemStack::getAmount).collect(Collectors.toList());
|
||||
List<Integer> has = items.stream().map(i -> 0).collect(Collectors.toList());
|
||||
ItemStack[] contents = source.getContents();
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
ItemStack toMatch = contents[i];
|
||||
if (toMatch == null || toMatch.getType() == Material.AIR)
|
||||
continue;
|
||||
if (tooDamaged(toMatch))
|
||||
if (toMatch == null || toMatch.getType() == Material.AIR || tooDamaged(toMatch))
|
||||
continue;
|
||||
|
||||
toMatch = toMatch.clone();
|
||||
for (int j = 0; j < items.size(); j++) {
|
||||
if (!matches(items.get(j), toMatch))
|
||||
continue;
|
||||
|
||||
int remaining = req.get(j);
|
||||
int taken = toMatch.getAmount() > remaining ? remaining : toMatch.getAmount();
|
||||
has.set(j, has.get(j) + taken);
|
||||
if (toMatch.getAmount() - taken <= 0)
|
||||
if (toMatch.getAmount() - taken <= 0) {
|
||||
break;
|
||||
}
|
||||
toMatch.setAmount(toMatch.getAmount() - taken);
|
||||
}
|
||||
}
|
||||
@ -164,12 +163,12 @@ public class ItemAction extends NPCShopAction {
|
||||
}
|
||||
|
||||
private boolean matches(ItemStack a, ItemStack b) {
|
||||
if (a.getType() != b.getType())
|
||||
return false;
|
||||
if (metaFilter.size() > 0 && !metaMatches(a, b, metaFilter))
|
||||
if (a.getType() != b.getType() || metaFilter.size() > 0 && !metaMatches(a, b, metaFilter))
|
||||
return false;
|
||||
|
||||
if (compareSimilarity && !a.isSimilar(b))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -181,22 +180,20 @@ public class ItemAction extends NPCShopAction {
|
||||
Tag acc = source;
|
||||
Tag cmp = compare;
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
if (acc == null)
|
||||
return false;
|
||||
if (cmp == null)
|
||||
if (acc == null || cmp == null)
|
||||
return false;
|
||||
if (i < parts.length - 1) {
|
||||
if (!(acc instanceof CompoundTag) || !(cmp instanceof CompoundTag))
|
||||
return false;
|
||||
if (parts[i].equals(acc.getName()) && acc.getName().equals(cmp.getName()))
|
||||
if (parts[i].equals(acc.getName()) && acc.getName().equals(cmp.getName())) {
|
||||
continue;
|
||||
}
|
||||
acc = ((CompoundTag) acc).getValue().get(parts[i]);
|
||||
cmp = ((CompoundTag) cmp).getValue().get(parts[i]);
|
||||
continue;
|
||||
}
|
||||
if (!acc.getName().equals(parts[i]) || !cmp.getName().equals(parts[i]))
|
||||
return false;
|
||||
if (!acc.getValue().equals(cmp.getValue()))
|
||||
if (!acc.getName().equals(parts[i]) || !cmp.getName().equals(parts[i])
|
||||
|| !acc.getValue().equals(cmp.getValue()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -207,10 +204,9 @@ public class ItemAction extends NPCShopAction {
|
||||
public Transaction take(Entity entity, int repeats) {
|
||||
if (!(entity instanceof InventoryHolder))
|
||||
return Transaction.fail();
|
||||
|
||||
Inventory source = ((InventoryHolder) entity).getInventory();
|
||||
return Transaction.create(() -> {
|
||||
return containsItems(source, repeats, false);
|
||||
}, () -> {
|
||||
return Transaction.create(() -> containsItems(source, repeats, false), () -> {
|
||||
containsItems(source, repeats, true);
|
||||
}, () -> {
|
||||
source.addItem(items.stream().map(ItemStack::clone).toArray(ItemStack[]::new));
|
||||
@ -220,8 +216,10 @@ public class ItemAction extends NPCShopAction {
|
||||
private boolean tooDamaged(ItemStack toMatch) {
|
||||
if (!requireUndamaged)
|
||||
return false;
|
||||
|
||||
if (SpigotUtil.isUsing1_13API())
|
||||
return toMatch.getItemMeta() instanceof Damageable && ((Damageable) toMatch.getItemMeta()).getDamage() != 0;
|
||||
|
||||
return toMatch.getDurability() == toMatch.getType().getMaxDurability();
|
||||
}
|
||||
|
||||
@ -253,20 +251,19 @@ public class ItemAction extends NPCShopAction {
|
||||
event.setCancelled(true);
|
||||
});
|
||||
}
|
||||
|
||||
ctx.getSlot(3 * 9 + 1).setItemStack(new ItemStack(Material.ANVIL), "Must have no damage",
|
||||
base.requireUndamaged ? ChatColor.GREEN + "On" : ChatColor.RED + "Off");
|
||||
ctx.getSlot(3 * 9 + 1)
|
||||
.addClickHandler(InputMenus.toggler((res) -> base.requireUndamaged = res, base.requireUndamaged));
|
||||
.addClickHandler(InputMenus.toggler(res -> base.requireUndamaged = res, base.requireUndamaged));
|
||||
ctx.getSlot(3 * 9 + 2).setItemStack(
|
||||
new ItemStack(Util.getFallbackMaterial("COMPARATOR", "REDSTONE_COMPARATOR")),
|
||||
"Compare item similarity", base.compareSimilarity ? ChatColor.GREEN + "On" : ChatColor.RED + "Off");
|
||||
ctx.getSlot(3 * 9 + 2)
|
||||
.addClickHandler(InputMenus.toggler((res) -> base.compareSimilarity = res, base.compareSimilarity));
|
||||
.addClickHandler(InputMenus.toggler(res -> base.compareSimilarity = res, base.compareSimilarity));
|
||||
ctx.getSlot(3 * 9 + 3).setItemStack(new ItemStack(Material.BOOK), "NBT comparison filter",
|
||||
Joiner.on("\n").join(base.metaFilter));
|
||||
ctx.getSlot(3 * 9 + 3)
|
||||
.addClickHandler((event) -> ctx.getMenu()
|
||||
.addClickHandler(event -> ctx.getMenu()
|
||||
.transition(InputMenus.stringSetter(() -> Joiner.on(',').join(base.metaFilter),
|
||||
res -> base.metaFilter = res == null ? null : Arrays.asList(res.split(",")))));
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ public class MoneyAction extends NPCShopAction {
|
||||
}
|
||||
|
||||
public MoneyAction(double cost) {
|
||||
this.money = cost;
|
||||
money = cost;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -35,6 +35,7 @@ public class MoneyAction extends NPCShopAction {
|
||||
public int getMaxRepeats(Entity entity) {
|
||||
if (!(entity instanceof Player))
|
||||
return 0;
|
||||
|
||||
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
|
||||
return (int) Math.floor(economy.getBalance((Player) entity) / money);
|
||||
}
|
||||
@ -43,12 +44,12 @@ public class MoneyAction extends NPCShopAction {
|
||||
public Transaction grant(Entity entity, int repeats) {
|
||||
if (!(entity instanceof Player))
|
||||
return Transaction.fail();
|
||||
|
||||
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
|
||||
Player player = (Player) entity;
|
||||
double amount = money * repeats;
|
||||
return Transaction.create(() -> {
|
||||
return true;
|
||||
}, () -> {
|
||||
|
||||
return Transaction.create(() -> true, () -> {
|
||||
economy.depositPlayer(player, amount);
|
||||
}, () -> {
|
||||
economy.withdrawPlayer(player, amount);
|
||||
@ -59,12 +60,12 @@ public class MoneyAction extends NPCShopAction {
|
||||
public Transaction take(Entity entity, int repeats) {
|
||||
if (!(entity instanceof Player))
|
||||
return Transaction.fail();
|
||||
|
||||
Economy economy = Bukkit.getServicesManager().getRegistration(Economy.class).getProvider();
|
||||
Player player = (Player) entity;
|
||||
double amount = money * repeats;
|
||||
return Transaction.create(() -> {
|
||||
return economy.has(player, amount);
|
||||
}, () -> {
|
||||
|
||||
return Transaction.create(() -> economy.has(player, amount), () -> {
|
||||
economy.withdrawPlayer(player, amount);
|
||||
}, () -> {
|
||||
economy.depositPlayer(player, amount);
|
||||
@ -76,12 +77,13 @@ public class MoneyAction extends NPCShopAction {
|
||||
|
||||
@Override
|
||||
public InventoryMenuPage createEditor(NPCShopAction previous, Consumer<NPCShopAction> callback) {
|
||||
final MoneyAction action = previous == null ? new MoneyAction() : (MoneyAction) previous;
|
||||
return InputMenus.filteredStringSetter(() -> Double.toString(action.money), (s) -> {
|
||||
MoneyAction action = previous == null ? new MoneyAction() : (MoneyAction) previous;
|
||||
return InputMenus.filteredStringSetter(() -> Double.toString(action.money), s -> {
|
||||
try {
|
||||
double result = Double.parseDouble(s);
|
||||
if (result < 0)
|
||||
return false;
|
||||
|
||||
action.money = result;
|
||||
} catch (NumberFormatException nfe) {
|
||||
return false;
|
||||
@ -100,9 +102,9 @@ public class MoneyAction extends NPCShopAction {
|
||||
supported = false;
|
||||
}
|
||||
}
|
||||
if (!supported) {
|
||||
if (!supported)
|
||||
return null;
|
||||
}
|
||||
|
||||
String description = null;
|
||||
if (previous != null) {
|
||||
MoneyAction old = (MoneyAction) previous;
|
||||
|
@ -45,7 +45,7 @@ public abstract class NPCShopAction implements Cloneable {
|
||||
private final Runnable rollback;
|
||||
|
||||
public Transaction(Supplier<Boolean> isPossible, Runnable execute, Runnable rollback) {
|
||||
this.possible = isPossible;
|
||||
possible = isPossible;
|
||||
this.execute = execute;
|
||||
this.rollback = rollback;
|
||||
}
|
||||
@ -88,7 +88,6 @@ public abstract class NPCShopAction implements Cloneable {
|
||||
GUI.add(gui);
|
||||
}
|
||||
|
||||
private static final List<GUI> GUI = Lists.newArrayList();
|
||||
private static final PersisterRegistry<NPCShopAction> REGISTRY = PersistenceLoader
|
||||
.createRegistry(NPCShopAction.class);
|
||||
private static List<GUI> GUI = Lists.newArrayList();
|
||||
private static PersisterRegistry<NPCShopAction> REGISTRY = PersistenceLoader.createRegistry(NPCShopAction.class);
|
||||
}
|
@ -56,9 +56,7 @@ public class PermissionAction extends NPCShopAction {
|
||||
return Transaction.fail();
|
||||
Player player = (Player) entity;
|
||||
Permission perm = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider();
|
||||
return Transaction.create(() -> {
|
||||
return true;
|
||||
}, () -> {
|
||||
return Transaction.create(() -> true, () -> {
|
||||
for (String permission : permissions) {
|
||||
perm.playerAdd(null, player, Placeholders.replace(permission, player));
|
||||
}
|
||||
@ -77,9 +75,8 @@ public class PermissionAction extends NPCShopAction {
|
||||
Permission perm = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider();
|
||||
return Transaction.create(() -> {
|
||||
for (String permission : permissions) {
|
||||
if (!perm.playerHas(player, Placeholders.replace(permission, player))) {
|
||||
if (!perm.playerHas(player, Placeholders.replace(permission, player)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, () -> {
|
||||
@ -109,7 +106,7 @@ public class PermissionAction extends NPCShopAction {
|
||||
@Override
|
||||
public void initialise(MenuContext ctx) {
|
||||
for (int i = 0; i < 3 * 9; i++) {
|
||||
final int idx = i;
|
||||
int idx = i;
|
||||
ctx.getSlot(i).clear();
|
||||
if (i < base.permissions.size()) {
|
||||
ctx.getSlot(i).setItemStack(new ItemStack(Material.FEATHER), "<f>Set permission",
|
||||
@ -124,8 +121,8 @@ public class PermissionAction extends NPCShopAction {
|
||||
}
|
||||
return;
|
||||
}
|
||||
ctx.getMenu().transition(InputMenus.stringSetter(
|
||||
() -> idx < base.permissions.size() ? base.permissions.get(idx) : "", (res) -> {
|
||||
ctx.getMenu().transition(InputMenus
|
||||
.stringSetter(() -> idx < base.permissions.size() ? base.permissions.get(idx) : "", res -> {
|
||||
if (res == null) {
|
||||
if (idx < base.permissions.size()) {
|
||||
base.permissions.remove(idx);
|
||||
@ -166,9 +163,8 @@ public class PermissionAction extends NPCShopAction {
|
||||
supported = false;
|
||||
}
|
||||
}
|
||||
if (!supported) {
|
||||
if (!supported)
|
||||
return null;
|
||||
}
|
||||
String description = null;
|
||||
if (previous != null) {
|
||||
PermissionAction old = (PermissionAction) previous;
|
||||
|
@ -55,11 +55,11 @@ public class Text extends Trait implements Runnable, Listener {
|
||||
private boolean speechBubbles;
|
||||
@Persist(value = "talk-close")
|
||||
private boolean talkClose = Setting.DEFAULT_TALK_CLOSE.asBoolean();
|
||||
private final List<String> text = new ArrayList<String>();
|
||||
private final List<String> text = new ArrayList<>();
|
||||
|
||||
public Text() {
|
||||
super("text");
|
||||
this.plugin = CitizensAPI.getPlugin();
|
||||
plugin = CitizensAPI.getPlugin();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,10 +87,10 @@ public class Text extends Trait implements Runnable, Listener {
|
||||
/**
|
||||
* Builds a text editor in game for the supplied {@link Player}.
|
||||
*/
|
||||
public Editor getEditor(final Player player) {
|
||||
final Conversation conversation = new ConversationFactory(plugin).withLocalEcho(false)
|
||||
.withEscapeSequence("/npc text").withEscapeSequence("exit").withModality(false)
|
||||
.withFirstPrompt(new TextBasePrompt(this)).buildConversation(player);
|
||||
public Editor getEditor(Player player) {
|
||||
Conversation conversation = new ConversationFactory(plugin).withLocalEcho(false).withEscapeSequence("/npc text")
|
||||
.withEscapeSequence("exit").withModality(false).withFirstPrompt(new TextBasePrompt(this))
|
||||
.buildConversation(player);
|
||||
return new Editor() {
|
||||
@Override
|
||||
public void begin() {
|
||||
@ -142,11 +142,9 @@ public class Text extends Trait implements Runnable, Listener {
|
||||
for (DataKey sub : key.getRelative("text").getIntegerSubKeys()) {
|
||||
text.add(sub.getString(""));
|
||||
}
|
||||
|
||||
if (text.isEmpty()) {
|
||||
populateDefaultText();
|
||||
}
|
||||
|
||||
range = key.getDouble("range");
|
||||
}
|
||||
|
||||
@ -178,8 +176,9 @@ public class Text extends Trait implements Runnable, Listener {
|
||||
return;
|
||||
|
||||
for (Player player : CitizensAPI.getLocationLookup().getNearbyPlayers(npc.getEntity().getLocation(), range)) {
|
||||
if (player.getGameMode() == GameMode.SPECTATOR)
|
||||
if (player.getGameMode() == GameMode.SPECTATOR) {
|
||||
continue;
|
||||
}
|
||||
talk(player);
|
||||
}
|
||||
}
|
||||
@ -216,7 +215,6 @@ public class Text extends Trait implements Runnable, Listener {
|
||||
}
|
||||
index = currentIndex++;
|
||||
}
|
||||
|
||||
if (speechBubbles) {
|
||||
HologramTrait trait = npc.getOrAddTrait(HologramTrait.class);
|
||||
trait.addTemporaryLine(Placeholders.replace(text.get(index), player, npc),
|
||||
@ -271,7 +269,6 @@ public class Text extends Trait implements Runnable, Listener {
|
||||
|
||||
cooldowns.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
sendText(player);
|
||||
|
||||
int delay = this.delay == -1
|
||||
@ -280,35 +277,35 @@ public class Text extends Trait implements Runnable, Listener {
|
||||
: this.delay;
|
||||
if (delay <= 0)
|
||||
return;
|
||||
cooldowns.put(player.getUniqueId(), System.currentTimeMillis() + (delay * 50));
|
||||
cooldowns.put(player.getUniqueId(), System.currentTimeMillis() + delay * 50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles talking at random intervals.
|
||||
*/
|
||||
public boolean toggleRandomTalker() {
|
||||
return (randomTalker = !randomTalker);
|
||||
return randomTalker = !randomTalker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles requiring line of sight before talking.
|
||||
*/
|
||||
public boolean toggleRealisticLooking() {
|
||||
return (realisticLooker = !realisticLooker);
|
||||
return realisticLooker = !realisticLooker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles using speech bubbles instead of messages.
|
||||
*/
|
||||
public boolean toggleSpeechBubbles() {
|
||||
return (speechBubbles = !speechBubbles);
|
||||
return speechBubbles = !speechBubbles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles talking to nearby Players.
|
||||
*/
|
||||
public boolean toggleTalkClose() {
|
||||
return (talkClose = !talkClose);
|
||||
return talkClose = !talkClose;
|
||||
}
|
||||
|
||||
public boolean useRealisticLooking() {
|
||||
@ -319,5 +316,5 @@ public class Text extends Trait implements Runnable, Listener {
|
||||
return speechBubbles;
|
||||
}
|
||||
|
||||
private static final Random RANDOM = Util.getFastRandom();
|
||||
private static Random RANDOM = Util.getFastRandom();
|
||||
}
|
@ -60,7 +60,6 @@ public class TextBasePrompt extends StringPrompt {
|
||||
Messaging.sendErrorTr(sender, Messages.TEXT_EDITOR_INVALID_PAGE);
|
||||
}
|
||||
}
|
||||
|
||||
Messaging.send(sender, getPromptText(context));
|
||||
|
||||
if (input.equalsIgnoreCase("delay")) {
|
||||
@ -100,9 +99,7 @@ public class TextBasePrompt extends StringPrompt {
|
||||
}
|
||||
} else {
|
||||
Messaging.sendErrorTr(sender, Messages.TEXT_EDITOR_INVALID_EDIT_TYPE);
|
||||
return this;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -117,7 +114,7 @@ public class TextBasePrompt extends StringPrompt {
|
||||
colorToggleableText(text.isRandomTalker()), colorToggleableText(text.useSpeechBubbles()),
|
||||
colorToggleableText(text.useRealisticLooking())));
|
||||
int page = context.getSessionData("page") == null ? 1 : (int) context.getSessionData("page");
|
||||
text.sendPage(((Player) context.getForWhom()), page);
|
||||
text.sendPage((Player) context.getForWhom(), page);
|
||||
return "";
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@ public class AllayTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setDancing(boolean dance) {
|
||||
this.dancing = dance;
|
||||
dancing = dance;
|
||||
}
|
||||
|
||||
@Command(
|
||||
@ -61,8 +61,7 @@ public class AllayTrait extends Trait {
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output.trim());
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,10 +71,9 @@ public class AxolotlTrait extends Trait {
|
||||
AxolotlTrait trait = npc.getOrAddTrait(AxolotlTrait.class);
|
||||
String output = "";
|
||||
if (args.hasValueFlag("variant")) {
|
||||
if (variant == null) {
|
||||
if (variant == null)
|
||||
throw new CommandException(Messages.INVALID_AXOLOTL_VARIANT,
|
||||
Util.listValuesPretty(Axolotl.Variant.values()));
|
||||
}
|
||||
trait.setVariant(variant);
|
||||
output += ' ' + Messaging.tr(Messages.AXOLOTL_VARIANT_SET, args.getFlag("variant"));
|
||||
}
|
||||
@ -85,8 +84,7 @@ public class AxolotlTrait extends Trait {
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output.trim());
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,9 +75,8 @@ public class BeeTrait extends Trait {
|
||||
BeeTrait trait = npc.getOrAddTrait(BeeTrait.class);
|
||||
String output = "";
|
||||
if (anger != null) {
|
||||
if (anger < 0) {
|
||||
if (anger < 0)
|
||||
throw new CommandException(Messages.INVALID_BEE_ANGER);
|
||||
}
|
||||
trait.setAnger(anger);
|
||||
output += ' ' + Messaging.tr(Messages.BEE_ANGER_SET, args.getFlag("anger"));
|
||||
}
|
||||
@ -93,8 +92,7 @@ public class BeeTrait extends Trait {
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output.trim());
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,6 @@ public class BossBarTrait extends Trait {
|
||||
barCache = Bukkit.getServer().createBossBar(npc.getFullName(), color, style,
|
||||
flags.toArray(new BarFlag[flags.size()]));
|
||||
}
|
||||
|
||||
return barCache;
|
||||
}
|
||||
|
||||
@ -106,7 +105,6 @@ public class BossBarTrait extends Trait {
|
||||
if (isBoss) {
|
||||
onDespawn();
|
||||
}
|
||||
|
||||
return isBoss;
|
||||
}
|
||||
|
||||
@ -164,35 +162,30 @@ public class BossBarTrait extends Trait {
|
||||
bar.setProgress(Math.max(0, Math.min(1, number)));
|
||||
}
|
||||
}
|
||||
|
||||
bar.setTitle(title);
|
||||
bar.setVisible(visible);
|
||||
if (progressProvider != null) {
|
||||
bar.setProgress(progressProvider.get());
|
||||
}
|
||||
|
||||
if (style != null) {
|
||||
bar.setStyle(style);
|
||||
}
|
||||
|
||||
if (color != null) {
|
||||
bar.setColor(color);
|
||||
}
|
||||
|
||||
for (BarFlag flag : BarFlag.values()) {
|
||||
bar.removeFlag(flag);
|
||||
}
|
||||
|
||||
for (BarFlag flag : flags) {
|
||||
bar.addFlag(flag);
|
||||
}
|
||||
|
||||
bar.removeAll();
|
||||
|
||||
for (Player player : CitizensAPI.getLocationLookup().getNearbyPlayers(npc.getEntity().getLocation(),
|
||||
range > 0 ? range : Setting.BOSSBAR_RANGE.asInt())) {
|
||||
if (viewPermission != null && !player.hasPermission(viewPermission))
|
||||
if (viewPermission != null && !player.hasPermission(viewPermission)) {
|
||||
continue;
|
||||
}
|
||||
bar.addPlayer(player);
|
||||
}
|
||||
}
|
||||
@ -210,7 +203,7 @@ public class BossBarTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setProgressProvider(Supplier<Double> provider) {
|
||||
this.progressProvider = provider;
|
||||
progressProvider = provider;
|
||||
}
|
||||
|
||||
public void setRange(int range) {
|
||||
@ -226,11 +219,11 @@ public class BossBarTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setTrackVariable(String variable) {
|
||||
this.track = variable;
|
||||
track = variable;
|
||||
}
|
||||
|
||||
public void setViewPermission(String viewpermission) {
|
||||
this.viewPermission = viewpermission;
|
||||
viewPermission = viewpermission;
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
@ -253,31 +246,24 @@ public class BossBarTrait extends Trait {
|
||||
if (style != null) {
|
||||
trait.setStyle(style);
|
||||
}
|
||||
|
||||
if (color != null) {
|
||||
trait.setColor(color);
|
||||
}
|
||||
|
||||
if (track != null) {
|
||||
trait.setTrackVariable(track);
|
||||
}
|
||||
|
||||
if (title != null) {
|
||||
trait.setTitle(Messaging.parseComponents(title));
|
||||
}
|
||||
|
||||
if (visible != null) {
|
||||
trait.setVisible(visible);
|
||||
}
|
||||
|
||||
if (range != null) {
|
||||
trait.setRange(range);
|
||||
}
|
||||
|
||||
if (viewpermission != null) {
|
||||
trait.setViewPermission(viewpermission);
|
||||
}
|
||||
|
||||
if (flags != null) {
|
||||
List<BarFlag> parsed = Lists.newArrayList();
|
||||
for (String s : Splitter.on(',').omitEmptyStrings().trimResults().split(flags)) {
|
||||
|
@ -64,7 +64,6 @@ public class CamelTrait extends Trait {
|
||||
trait.setPose(pose);
|
||||
output += Messaging.tr(Messages.CAMEL_POSE_SET, pose);
|
||||
}
|
||||
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ public class CatTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setCollarColor(DyeColor color) {
|
||||
this.collarColor = color;
|
||||
collarColor = color;
|
||||
}
|
||||
|
||||
public void setLyingDown(boolean lying) {
|
||||
@ -74,21 +74,21 @@ public class CatTrait extends Trait {
|
||||
|
||||
public void setType(Type type2) {
|
||||
if (type2 == null) {
|
||||
this.type = Cat.Type.BLACK;
|
||||
type = Cat.Type.BLACK;
|
||||
return;
|
||||
}
|
||||
switch (type2) {
|
||||
case WILD_OCELOT:
|
||||
this.type = Cat.Type.CALICO;
|
||||
type = Cat.Type.CALICO;
|
||||
break;
|
||||
case BLACK_CAT:
|
||||
this.type = Cat.Type.BLACK;
|
||||
type = Cat.Type.BLACK;
|
||||
break;
|
||||
case RED_CAT:
|
||||
this.type = Cat.Type.RED;
|
||||
type = Cat.Type.RED;
|
||||
break;
|
||||
case SIAMESE_CAT:
|
||||
this.type = Cat.Type.SIAMESE;
|
||||
type = Cat.Type.SIAMESE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -108,22 +108,18 @@ public class CatTrait extends Trait {
|
||||
CatTrait trait = npc.getOrAddTrait(CatTrait.class);
|
||||
String output = "";
|
||||
if (args.hasValueFlag("type")) {
|
||||
if (type == null) {
|
||||
if (type == null)
|
||||
throw new CommandUsageException(Messages.INVALID_CAT_TYPE, Util.listValuesPretty(Cat.Type.values()));
|
||||
}
|
||||
trait.setType(type);
|
||||
output += ' ' + Messaging.tr(Messages.CAT_TYPE_SET, args.getFlag("type"));
|
||||
}
|
||||
|
||||
if (args.hasValueFlag("ccolor")) {
|
||||
if (ccolor == null) {
|
||||
if (ccolor == null)
|
||||
throw new CommandUsageException(Messages.INVALID_CAT_COLLAR_COLOR,
|
||||
Util.listValuesPretty(DyeColor.values()));
|
||||
}
|
||||
trait.setCollarColor(ccolor);
|
||||
output += ' ' + Messaging.tr(Messages.CAT_COLLAR_COLOR_SET, args.getFlag("ccolor"));
|
||||
}
|
||||
|
||||
if (args.hasFlag('s')) {
|
||||
trait.setSitting(true);
|
||||
output += ' ' + Messaging.tr(Messages.CAT_STARTED_SITTING, npc.getName());
|
||||
@ -131,17 +127,14 @@ public class CatTrait extends Trait {
|
||||
trait.setSitting(false);
|
||||
output += ' ' + Messaging.tr(Messages.CAT_STOPPED_SITTING, npc.getName());
|
||||
}
|
||||
|
||||
if (args.hasFlag('l')) {
|
||||
trait.setLyingDown(!trait.isLyingDown());
|
||||
output += ' ' + Messaging.tr(trait.isLyingDown() ? Messages.CAT_STARTED_LYING : Messages.CAT_STOPPED_LYING,
|
||||
npc.getName());
|
||||
}
|
||||
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output.trim());
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,10 +92,9 @@ public class FoxTrait extends Trait {
|
||||
String output = "";
|
||||
if (rawtype != null) {
|
||||
Fox.Type type = Util.matchEnum(Fox.Type.values(), args.getFlag("type"));
|
||||
if (type == null) {
|
||||
if (type == null)
|
||||
throw new CommandUsageException(
|
||||
Messaging.tr(Messages.INVALID_FOX_TYPE, Util.listValuesPretty(Fox.Type.values())), null);
|
||||
}
|
||||
trait.setType(type);
|
||||
output += ' ' + Messaging.tr(Messages.FOX_TYPE_SET, args.getFlag("type"), npc.getName());
|
||||
}
|
||||
@ -116,8 +115,7 @@ public class FoxTrait extends Trait {
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output.trim());
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +57,8 @@ public class FrogTrait extends Trait {
|
||||
FrogTrait trait = npc.getOrAddTrait(FrogTrait.class);
|
||||
String output = "";
|
||||
if (args.hasValueFlag("variant")) {
|
||||
if (variant == null) {
|
||||
if (variant == null)
|
||||
throw new CommandException(Messages.INVALID_FROG_VARIANT, Util.listValuesPretty(Frog.Variant.values()));
|
||||
}
|
||||
trait.setVariant(variant);
|
||||
output += Messaging.tr(Messages.FROG_VARIANT_SET, Util.prettyEnum(variant));
|
||||
}
|
||||
|
@ -50,11 +50,11 @@ public class GoatTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setLeftHorn(boolean horn) {
|
||||
this.leftHorn = horn;
|
||||
leftHorn = horn;
|
||||
}
|
||||
|
||||
public void setRightHorn(boolean horn) {
|
||||
this.rightHorn = horn;
|
||||
rightHorn = horn;
|
||||
}
|
||||
|
||||
@Command(
|
||||
|
@ -81,12 +81,10 @@ public class LlamaTrait extends Trait {
|
||||
trait.setColor(color);
|
||||
output += Messaging.tr(Messages.LLAMA_COLOR_SET, Util.prettyEnum(color));
|
||||
}
|
||||
|
||||
if (strength != null) {
|
||||
trait.setStrength(Math.max(1, Math.min(5, strength)));
|
||||
output += Messaging.tr(Messages.LLAMA_STRENGTH_SET, trait.getStrength());
|
||||
}
|
||||
|
||||
if (args.hasFlag('c')) {
|
||||
npc.getOrAddTrait(HorseModifiers.class).setCarryingChest(true);
|
||||
output += Messaging.tr(Messages.HORSE_CHEST_SET) + " ";
|
||||
@ -94,7 +92,6 @@ public class LlamaTrait extends Trait {
|
||||
npc.getOrAddTrait(HorseModifiers.class).setCarryingChest(false);
|
||||
output += Messaging.tr(Messages.HORSE_CHEST_UNSET) + " ";
|
||||
}
|
||||
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output);
|
||||
}
|
||||
|
@ -71,8 +71,7 @@ public class MushroomCowTrait extends Trait {
|
||||
Messaging.sendTr(sender, Messages.MUSHROOM_COW_VARIANT_SET, npc.getName(), variant);
|
||||
hasArg = true;
|
||||
}
|
||||
if (!hasArg) {
|
||||
if (!hasArg)
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,11 +88,11 @@ public class PandaTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setHiddenGene(Panda.Gene gene) {
|
||||
this.hiddenGene = gene;
|
||||
hiddenGene = gene;
|
||||
}
|
||||
|
||||
public void setMainGene(Panda.Gene gene) {
|
||||
this.mainGene = gene;
|
||||
mainGene = gene;
|
||||
}
|
||||
|
||||
public void setRolling(boolean rolling) {
|
||||
@ -138,18 +138,16 @@ public class PandaTrait extends Trait {
|
||||
PandaTrait trait = npc.getOrAddTrait(PandaTrait.class);
|
||||
String output = "";
|
||||
if (args.hasValueFlag("gene")) {
|
||||
if (gene == null) {
|
||||
if (gene == null)
|
||||
throw new CommandUsageException(Messages.INVALID_PANDA_GENE,
|
||||
Util.listValuesPretty(Panda.Gene.values()));
|
||||
}
|
||||
trait.setMainGene(gene);
|
||||
output += ' ' + Messaging.tr(Messages.PANDA_MAIN_GENE_SET, args.getFlag("gene"));
|
||||
}
|
||||
if (args.hasValueFlag("hiddengene")) {
|
||||
if (hiddengene == null) {
|
||||
if (hiddengene == null)
|
||||
throw new CommandUsageException(Messages.INVALID_PANDA_GENE,
|
||||
Util.listValuesPretty(Panda.Gene.values()));
|
||||
}
|
||||
trait.setHiddenGene(hiddengene);
|
||||
output += ' ' + Messaging.tr(Messages.PANDA_HIDDEN_GENE_SET, hiddengene);
|
||||
}
|
||||
@ -175,9 +173,8 @@ public class PandaTrait extends Trait {
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output.trim());
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean SUPPORT_ROLLING_SNEEZING = true;
|
||||
|
@ -57,9 +57,8 @@ public class ParrotTrait extends Trait {
|
||||
ParrotTrait trait = npc.getOrAddTrait(ParrotTrait.class);
|
||||
String output = "";
|
||||
if (args.hasValueFlag("variant")) {
|
||||
if (variant == null) {
|
||||
if (variant == null)
|
||||
throw new CommandException(Messages.INVALID_PARROT_VARIANT, Util.listValuesPretty(Variant.values()));
|
||||
}
|
||||
trait.setVariant(variant);
|
||||
output += Messaging.tr(Messages.PARROT_VARIANT_SET, Util.prettyEnum(variant));
|
||||
}
|
||||
|
@ -56,16 +56,14 @@ public class PhantomTrait extends Trait {
|
||||
PhantomTrait trait = npc.getOrAddTrait(PhantomTrait.class);
|
||||
String output = "";
|
||||
if (size != null) {
|
||||
if (size <= 0) {
|
||||
if (size <= 0)
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
trait.setSize(size);
|
||||
output += Messaging.tr(Messages.PHANTOM_STATE_SET, size);
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output);
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,9 +61,8 @@ public class PiglinTrait extends Trait {
|
||||
npc.getName());
|
||||
hasArg = true;
|
||||
}
|
||||
if (!hasArg) {
|
||||
if (!hasArg)
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -62,8 +62,7 @@ public class PolarBearTrait extends Trait {
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output);
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class PufferFishTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setPuffState(int state) {
|
||||
this.puffState = state;
|
||||
puffState = state;
|
||||
}
|
||||
|
||||
@Command(
|
||||
|
@ -95,8 +95,7 @@ public class ShulkerTrait extends Trait {
|
||||
Messaging.sendTr(sender, Messages.SHULKER_COLOR_SET, npc.getName(), Util.prettyEnum(color));
|
||||
hasArg = true;
|
||||
}
|
||||
if (!hasArg) {
|
||||
if (!hasArg)
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +71,7 @@ public class SnifferTrait extends Trait {
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output.trim());
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class SnowmanTrait extends Trait {
|
||||
}
|
||||
|
||||
public boolean toggleDerp() {
|
||||
return this.derp = !this.derp;
|
||||
return derp = !derp;
|
||||
}
|
||||
|
||||
@Command(
|
||||
@ -62,8 +62,7 @@ public class SnowmanTrait extends Trait {
|
||||
Messaging.sendTr(sender, isDerp ? Messages.SNOWMAN_DERP_SET : Messages.SNOWMAN_DERP_STOPPED, npc.getName());
|
||||
hasArg = true;
|
||||
}
|
||||
if (!hasArg) {
|
||||
if (!hasArg)
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ public class SpellcasterTrait extends Trait {
|
||||
if (spell != null) {
|
||||
((Spellcaster) npc.getEntity()).setSpell(spell);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setSpell(Spell spell) {
|
||||
@ -65,8 +64,7 @@ public class SpellcasterTrait extends Trait {
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output.trim());
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class TropicalFishTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setBodyColor(DyeColor color) {
|
||||
this.bodyColor = color;
|
||||
bodyColor = color;
|
||||
}
|
||||
|
||||
public void setPattern(Pattern pattern) {
|
||||
@ -64,7 +64,7 @@ public class TropicalFishTrait extends Trait {
|
||||
}
|
||||
|
||||
public void setPatternColor(DyeColor color) {
|
||||
this.patternColor = color;
|
||||
patternColor = color;
|
||||
}
|
||||
|
||||
@Command(
|
||||
@ -81,33 +81,29 @@ public class TropicalFishTrait extends Trait {
|
||||
TropicalFishTrait trait = npc.getOrAddTrait(TropicalFishTrait.class);
|
||||
String output = "";
|
||||
if (args.hasValueFlag("body")) {
|
||||
if (body == null) {
|
||||
if (body == null)
|
||||
throw new CommandException(Messages.INVALID_TROPICALFISH_COLOR,
|
||||
Util.listValuesPretty(DyeColor.values()));
|
||||
}
|
||||
trait.setBodyColor(body);
|
||||
output += Messaging.tr(Messages.TROPICALFISH_BODY_COLOR_SET, Util.prettyEnum(body));
|
||||
}
|
||||
if (args.hasValueFlag("patterncolor")) {
|
||||
if (patterncolor == null) {
|
||||
if (patterncolor == null)
|
||||
throw new CommandException(Messages.INVALID_TROPICALFISH_COLOR,
|
||||
Util.listValuesPretty(DyeColor.values()));
|
||||
}
|
||||
trait.setPatternColor(patterncolor);
|
||||
output += Messaging.tr(Messages.TROPICALFISH_PATTERN_COLOR_SET, Util.prettyEnum(patterncolor));
|
||||
}
|
||||
if (args.hasValueFlag("pattern")) {
|
||||
if (pattern == null) {
|
||||
if (pattern == null)
|
||||
throw new CommandException(Messages.INVALID_TROPICALFISH_PATTERN,
|
||||
Util.listValuesPretty(Pattern.values()));
|
||||
}
|
||||
trait.setPattern(pattern);
|
||||
output += Messaging.tr(Messages.TROPICALFISH_PATTERN_SET, Util.prettyEnum(pattern));
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output);
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,25 +76,22 @@ public class VillagerTrait extends Trait {
|
||||
VillagerTrait trait = npc.getOrAddTrait(VillagerTrait.class);
|
||||
String output = "";
|
||||
if (level != null) {
|
||||
if (level < 0) {
|
||||
if (level < 0)
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
trait.setLevel(level);
|
||||
output += " " + Messaging.tr(Messages.VILLAGER_LEVEL_SET, level);
|
||||
}
|
||||
if (args.hasValueFlag("type")) {
|
||||
if (type == null) {
|
||||
if (type == null)
|
||||
throw new CommandException(Messages.INVALID_VILLAGER_TYPE,
|
||||
Util.listValuesPretty(Villager.Type.values()));
|
||||
}
|
||||
trait.setType(type);
|
||||
output += " " + Messaging.tr(Messages.VILLAGER_TYPE_SET, args.getFlag("type"));
|
||||
}
|
||||
if (args.hasValueFlag("profession")) {
|
||||
if (profession == null) {
|
||||
if (profession == null)
|
||||
throw new CommandException(Messages.INVALID_PROFESSION, args.getFlag("profession"),
|
||||
Joiner.on(',').join(Profession.values()));
|
||||
}
|
||||
npc.getOrAddTrait(VillagerProfession.class).setProfession(profession);
|
||||
output += " " + Messaging.tr(Messages.PROFESSION_SET, npc.getName(), args.getFlag("profession"));
|
||||
}
|
||||
@ -103,8 +100,7 @@ public class VillagerTrait extends Trait {
|
||||
}
|
||||
if (!output.isEmpty()) {
|
||||
Messaging.send(sender, output.trim());
|
||||
} else {
|
||||
} else
|
||||
throw new CommandUsageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user